hard-interface.c 19.0 KB
Newer Older
1
/* Copyright (C) 2007-2013 B.A.T.M.A.N. contributors:
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * Marek Lindner, Simon Wunderlich
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of version 2 of the GNU General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA
 */

#include "main.h"
21
#include "distributed-arp-table.h"
22 23 24 25 26
#include "hard-interface.h"
#include "soft-interface.h"
#include "send.h"
#include "translation-table.h"
#include "routing.h"
27
#include "sysfs.h"
28 29
#include "originator.h"
#include "hash.h"
30
#include "bridge_loop_avoidance.h"
31 32

#include <linux/if_arp.h>
A
Antonio Quartulli 已提交
33
#include <linux/if_ether.h>
34

35
void batadv_hardif_free_rcu(struct rcu_head *rcu)
36
{
37
	struct batadv_hard_iface *hard_iface;
38

39
	hard_iface = container_of(rcu, struct batadv_hard_iface, rcu);
40 41
	dev_put(hard_iface->net_dev);
	kfree(hard_iface);
42 43
}

44 45
struct batadv_hard_iface *
batadv_hardif_get_by_netdev(const struct net_device *net_dev)
46
{
47
	struct batadv_hard_iface *hard_iface;
48 49

	rcu_read_lock();
50
	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
51 52
		if (hard_iface->net_dev == net_dev &&
		    atomic_inc_not_zero(&hard_iface->refcount))
53 54 55
			goto out;
	}

56
	hard_iface = NULL;
57 58 59

out:
	rcu_read_unlock();
60
	return hard_iface;
61 62
}

63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
/**
 * batadv_is_on_batman_iface - check if a device is a batman iface descendant
 * @net_dev: the device to check
 *
 * If the user creates any virtual device on top of a batman-adv interface, it
 * is important to prevent this new interface to be used to create a new mesh
 * network (this behaviour would lead to a batman-over-batman configuration).
 * This function recursively checks all the fathers of the device passed as
 * argument looking for a batman-adv soft interface.
 *
 * Returns true if the device is descendant of a batman-adv mesh interface (or
 * if it is a batman-adv interface itself), false otherwise
 */
static bool batadv_is_on_batman_iface(const struct net_device *net_dev)
{
	struct net_device *parent_dev;
	bool ret;

	/* check if this is a batman-adv mesh interface */
	if (batadv_softif_is_valid(net_dev))
		return true;

	/* no more parents..stop recursion */
	if (net_dev->iflink == net_dev->ifindex)
		return false;

	/* recurse over the parent device */
	parent_dev = dev_get_by_index(&init_net, net_dev->iflink);
	/* if we got a NULL parent_dev there is something broken.. */
	if (WARN(!parent_dev, "Cannot find parent device"))
		return false;

	ret = batadv_is_on_batman_iface(parent_dev);

	if (parent_dev)
		dev_put(parent_dev);
	return ret;
}

102
static int batadv_is_valid_iface(const struct net_device *net_dev)
103 104 105 106 107 108 109 110 111 112 113
{
	if (net_dev->flags & IFF_LOOPBACK)
		return 0;

	if (net_dev->type != ARPHRD_ETHER)
		return 0;

	if (net_dev->addr_len != ETH_ALEN)
		return 0;

	/* no batman over batman */
114
	if (batadv_is_on_batman_iface(net_dev))
115 116 117 118 119
		return 0;

	return 1;
}

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
/**
 * batadv_is_wifi_netdev - check if the given net_device struct is a wifi
 *  interface
 * @net_device: the device to check
 *
 * Returns true if the net device is a 802.11 wireless device, false otherwise.
 */
static bool batadv_is_wifi_netdev(struct net_device *net_device)
{
#ifdef CONFIG_WIRELESS_EXT
	/* pre-cfg80211 drivers have to implement WEXT, so it is possible to
	 * check for wireless_handlers != NULL
	 */
	if (net_device->wireless_handlers)
		return true;
#endif

	/* cfg80211 drivers have to set ieee80211_ptr */
	if (net_device->ieee80211_ptr)
		return true;

	return false;
}

/**
 * batadv_is_wifi_iface - check if the given interface represented by ifindex
 *  is a wifi interface
 * @ifindex: interface index to check
 *
 * Returns true if the interface represented by ifindex is a 802.11 wireless
 * device, false otherwise.
 */
bool batadv_is_wifi_iface(int ifindex)
{
	struct net_device *net_device = NULL;
	bool ret = false;

	if (ifindex == BATADV_NULL_IFINDEX)
		goto out;

	net_device = dev_get_by_index(&init_net, ifindex);
	if (!net_device)
		goto out;

	ret = batadv_is_wifi_netdev(net_device);

out:
	if (net_device)
		dev_put(net_device);
	return ret;
}

172
static struct batadv_hard_iface *
173
batadv_hardif_get_active(const struct net_device *soft_iface)
174
{
175
	struct batadv_hard_iface *hard_iface;
176 177

	rcu_read_lock();
178
	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
179
		if (hard_iface->soft_iface != soft_iface)
180 181
			continue;

182
		if (hard_iface->if_status == BATADV_IF_ACTIVE &&
183
		    atomic_inc_not_zero(&hard_iface->refcount))
184 185 186
			goto out;
	}

187
	hard_iface = NULL;
188 189 190

out:
	rcu_read_unlock();
191
	return hard_iface;
192 193
}

194 195
static void batadv_primary_if_update_addr(struct batadv_priv *bat_priv,
					  struct batadv_hard_iface *oldif)
196
{
197
	struct batadv_vis_packet *vis_packet;
198
	struct batadv_hard_iface *primary_if;
199
	struct sk_buff *skb;
200

201
	primary_if = batadv_primary_if_get_selected(bat_priv);
202 203
	if (!primary_if)
		goto out;
204

205 206
	batadv_dat_init_own_addr(bat_priv, primary_if);

207 208
	skb = bat_priv->vis.my_info->skb_packet;
	vis_packet = (struct batadv_vis_packet *)skb->data;
209
	memcpy(vis_packet->vis_orig, primary_if->net_dev->dev_addr, ETH_ALEN);
210
	memcpy(vis_packet->sender_orig,
211 212
	       primary_if->net_dev->dev_addr, ETH_ALEN);

213
	batadv_bla_update_orig_address(bat_priv, primary_if, oldif);
214 215
out:
	if (primary_if)
216
		batadv_hardif_free_ref(primary_if);
217 218
}

219 220
static void batadv_primary_if_select(struct batadv_priv *bat_priv,
				     struct batadv_hard_iface *new_hard_iface)
221
{
222
	struct batadv_hard_iface *curr_hard_iface;
223

224
	ASSERT_RTNL();
225

226 227
	if (new_hard_iface && !atomic_inc_not_zero(&new_hard_iface->refcount))
		new_hard_iface = NULL;
228

229
	curr_hard_iface = rcu_dereference_protected(bat_priv->primary_if, 1);
230
	rcu_assign_pointer(bat_priv->primary_if, new_hard_iface);
231

232
	if (!new_hard_iface)
233
		goto out;
234

235
	bat_priv->bat_algo_ops->bat_primary_iface_set(new_hard_iface);
236
	batadv_primary_if_update_addr(bat_priv, curr_hard_iface);
237 238 239

out:
	if (curr_hard_iface)
240
		batadv_hardif_free_ref(curr_hard_iface);
241 242
}

243 244
static bool
batadv_hardif_is_iface_up(const struct batadv_hard_iface *hard_iface)
245
{
246
	if (hard_iface->net_dev->flags & IFF_UP)
247 248 249 250 251
		return true;

	return false;
}

252
static void batadv_check_known_mac_addr(const struct net_device *net_dev)
253
{
254
	const struct batadv_hard_iface *hard_iface;
255 256

	rcu_read_lock();
257
	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
258 259
		if ((hard_iface->if_status != BATADV_IF_ACTIVE) &&
		    (hard_iface->if_status != BATADV_IF_TO_BE_ACTIVATED))
260 261
			continue;

262
		if (hard_iface->net_dev == net_dev)
263 264
			continue;

265 266
		if (!batadv_compare_eth(hard_iface->net_dev->dev_addr,
					net_dev->dev_addr))
267 268
			continue;

269 270 271
		pr_warn("The newly added mac address (%pM) already exists on: %s\n",
			net_dev->dev_addr, hard_iface->net_dev->name);
		pr_warn("It is strongly recommended to keep mac addresses unique to avoid problems!\n");
272 273 274 275
	}
	rcu_read_unlock();
}

276
int batadv_hardif_min_mtu(struct net_device *soft_iface)
277
{
278 279
	const struct batadv_priv *bat_priv = netdev_priv(soft_iface);
	const struct batadv_hard_iface *hard_iface;
280
	/* allow big frames if all devices are capable to do so
281 282
	 * (have MTU > 1500 + BAT_HEADER_LEN)
	 */
283 284 285 286 287 288
	int min_mtu = ETH_DATA_LEN;

	if (atomic_read(&bat_priv->fragmentation))
		goto out;

	rcu_read_lock();
289
	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
290 291
		if ((hard_iface->if_status != BATADV_IF_ACTIVE) &&
		    (hard_iface->if_status != BATADV_IF_TO_BE_ACTIVATED))
292 293
			continue;

294
		if (hard_iface->soft_iface != soft_iface)
295 296
			continue;

297 298
		min_mtu = min_t(int,
				hard_iface->net_dev->mtu - BATADV_HEADER_LEN,
299 300 301 302 303 304 305 306
				min_mtu);
	}
	rcu_read_unlock();
out:
	return min_mtu;
}

/* adjusts the MTU if a new interface with a smaller MTU appeared. */
307
void batadv_update_min_mtu(struct net_device *soft_iface)
308 309 310
{
	int min_mtu;

311
	min_mtu = batadv_hardif_min_mtu(soft_iface);
312 313 314 315
	if (soft_iface->mtu != min_mtu)
		soft_iface->mtu = min_mtu;
}

316 317
static void
batadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface)
318
{
319 320
	struct batadv_priv *bat_priv;
	struct batadv_hard_iface *primary_if = NULL;
321

322
	if (hard_iface->if_status != BATADV_IF_INACTIVE)
323
		goto out;
324

325
	bat_priv = netdev_priv(hard_iface->soft_iface);
326

327
	bat_priv->bat_algo_ops->bat_iface_update_mac(hard_iface);
328
	hard_iface->if_status = BATADV_IF_TO_BE_ACTIVATED;
329

330
	/* the first active interface becomes our primary interface or
331
	 * the next active interface after the old primary interface was removed
332
	 */
333
	primary_if = batadv_primary_if_get_selected(bat_priv);
334
	if (!primary_if)
335
		batadv_primary_if_select(bat_priv, hard_iface);
336

337 338
	batadv_info(hard_iface->soft_iface, "Interface activated: %s\n",
		    hard_iface->net_dev->name);
339

340
	batadv_update_min_mtu(hard_iface->soft_iface);
341 342 343

out:
	if (primary_if)
344
		batadv_hardif_free_ref(primary_if);
345 346
}

347 348
static void
batadv_hardif_deactivate_interface(struct batadv_hard_iface *hard_iface)
349
{
350 351
	if ((hard_iface->if_status != BATADV_IF_ACTIVE) &&
	    (hard_iface->if_status != BATADV_IF_TO_BE_ACTIVATED))
352 353
		return;

354
	hard_iface->if_status = BATADV_IF_INACTIVE;
355

356 357
	batadv_info(hard_iface->soft_iface, "Interface deactivated: %s\n",
		    hard_iface->net_dev->name);
358

359
	batadv_update_min_mtu(hard_iface->soft_iface);
360 361
}

362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
/**
 * batadv_master_del_slave - remove hard_iface from the current master interface
 * @slave: the interface enslaved in another master
 * @master: the master from which slave has to be removed
 *
 * Invoke ndo_del_slave on master passing slave as argument. In this way slave
 * is free'd and master can correctly change its internal state.
 * Return 0 on success, a negative value representing the error otherwise
 */
static int batadv_master_del_slave(struct batadv_hard_iface *slave,
				   struct net_device *master)
{
	int ret;

	if (!master)
		return 0;

	ret = -EBUSY;
	if (master->netdev_ops->ndo_del_slave)
		ret = master->netdev_ops->ndo_del_slave(master, slave->net_dev);

	return ret;
}

386
int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
387
				   const char *iface_name)
388
{
389
	struct batadv_priv *bat_priv;
390
	struct net_device *soft_iface, *master;
A
Antonio Quartulli 已提交
391
	__be16 ethertype = __constant_htons(ETH_P_BATMAN);
392
	int ret;
393

394
	if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
395 396
		goto out;

397
	if (!atomic_inc_not_zero(&hard_iface->refcount))
398 399
		goto out;

400
	soft_iface = dev_get_by_name(&init_net, iface_name);
401

402
	if (!soft_iface) {
403
		soft_iface = batadv_softif_create(iface_name);
404

405 406
		if (!soft_iface) {
			ret = -ENOMEM;
407
			goto err;
408
		}
409 410

		/* dev_get_by_name() increases the reference counter for us */
411 412 413
		dev_hold(soft_iface);
	}

414
	if (!batadv_softif_is_valid(soft_iface)) {
415
		pr_err("Can't create batman mesh interface %s: already exists as regular interface\n",
416 417
		       soft_iface->name);
		ret = -EINVAL;
418
		goto err_dev;
419 420
	}

421 422 423 424 425 426 427 428
	/* check if the interface is enslaved in another virtual one and
	 * in that case unlink it first
	 */
	master = netdev_master_upper_dev_get(hard_iface->net_dev);
	ret = batadv_master_del_slave(hard_iface, master);
	if (ret)
		goto err_dev;

429
	hard_iface->soft_iface = soft_iface;
430
	bat_priv = netdev_priv(hard_iface->soft_iface);
431

432 433 434 435
	ret = netdev_master_upper_dev_link(hard_iface->net_dev, soft_iface);
	if (ret)
		goto err_dev;

436
	ret = bat_priv->bat_algo_ops->bat_iface_enable(hard_iface);
437
	if (ret < 0)
438
		goto err_upper;
439

440
	hard_iface->if_num = bat_priv->num_ifaces;
441
	bat_priv->num_ifaces++;
442
	hard_iface->if_status = BATADV_IF_INACTIVE;
443 444 445 446 447
	ret = batadv_orig_hash_add_if(hard_iface, bat_priv->num_ifaces);
	if (ret < 0) {
		bat_priv->bat_algo_ops->bat_iface_disable(hard_iface);
		bat_priv->num_ifaces--;
		hard_iface->if_status = BATADV_IF_NOT_IN_USE;
448
		goto err_upper;
449
	}
450

451
	hard_iface->batman_adv_ptype.type = ethertype;
452
	hard_iface->batman_adv_ptype.func = batadv_batman_skb_recv;
453 454
	hard_iface->batman_adv_ptype.dev = hard_iface->net_dev;
	dev_add_pack(&hard_iface->batman_adv_ptype);
455

456
	atomic_set(&hard_iface->frag_seqno, 1);
457 458
	batadv_info(hard_iface->soft_iface, "Adding interface: %s\n",
		    hard_iface->net_dev->name);
459

460 461
	if (atomic_read(&bat_priv->fragmentation) &&
	    hard_iface->net_dev->mtu < ETH_DATA_LEN + BATADV_HEADER_LEN)
462 463 464
		batadv_info(hard_iface->soft_iface,
			    "The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. Packets going over this interface will be fragmented on layer2 which could impact the performance. Setting the MTU to %zi would solve the problem.\n",
			    hard_iface->net_dev->name, hard_iface->net_dev->mtu,
465
			    ETH_DATA_LEN + BATADV_HEADER_LEN);
466

467 468
	if (!atomic_read(&bat_priv->fragmentation) &&
	    hard_iface->net_dev->mtu < ETH_DATA_LEN + BATADV_HEADER_LEN)
469 470 471
		batadv_info(hard_iface->soft_iface,
			    "The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. If you experience problems getting traffic through try increasing the MTU to %zi.\n",
			    hard_iface->net_dev->name, hard_iface->net_dev->mtu,
472
			    ETH_DATA_LEN + BATADV_HEADER_LEN);
473

474 475
	if (batadv_hardif_is_iface_up(hard_iface))
		batadv_hardif_activate_interface(hard_iface);
476
	else
477 478 479
		batadv_err(hard_iface->soft_iface,
			   "Not using interface %s (retrying later): interface not active\n",
			   hard_iface->net_dev->name);
480 481

	/* begin scheduling originator messages on that interface */
482
	batadv_schedule_bat_ogm(hard_iface);
483 484 485 486

out:
	return 0;

487 488
err_upper:
	netdev_upper_dev_unlink(hard_iface->net_dev, soft_iface);
489
err_dev:
490
	hard_iface->soft_iface = NULL;
491
	dev_put(soft_iface);
492
err:
493
	batadv_hardif_free_ref(hard_iface);
494
	return ret;
495 496
}

497 498
void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
				     enum batadv_hard_if_cleanup autodel)
499
{
500 501
	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
	struct batadv_hard_iface *primary_if = NULL;
502

503
	if (hard_iface->if_status == BATADV_IF_ACTIVE)
504
		batadv_hardif_deactivate_interface(hard_iface);
505

506
	if (hard_iface->if_status != BATADV_IF_INACTIVE)
507
		goto out;
508

509 510
	batadv_info(hard_iface->soft_iface, "Removing interface: %s\n",
		    hard_iface->net_dev->name);
511
	dev_remove_pack(&hard_iface->batman_adv_ptype);
512 513

	bat_priv->num_ifaces--;
514
	batadv_orig_hash_del_if(hard_iface, bat_priv->num_ifaces);
515

516
	primary_if = batadv_primary_if_get_selected(bat_priv);
517
	if (hard_iface == primary_if) {
518
		struct batadv_hard_iface *new_if;
519

520 521
		new_if = batadv_hardif_get_active(hard_iface->soft_iface);
		batadv_primary_if_select(bat_priv, new_if);
522 523

		if (new_if)
524
			batadv_hardif_free_ref(new_if);
525 526
	}

527
	bat_priv->bat_algo_ops->bat_iface_disable(hard_iface);
528
	hard_iface->if_status = BATADV_IF_NOT_IN_USE;
529

530
	/* delete all references to this hard_iface */
531
	batadv_purge_orig_ref(bat_priv);
532
	batadv_purge_outstanding_packets(bat_priv, hard_iface);
533
	dev_put(hard_iface->soft_iface);
534 535

	/* nobody uses this interface anymore */
536
	if (!bat_priv->num_ifaces && autodel == BATADV_IF_CLEANUP_AUTO)
537
		batadv_softif_destroy_sysfs(hard_iface->soft_iface);
538

539
	netdev_upper_dev_unlink(hard_iface->net_dev, hard_iface->soft_iface);
540
	hard_iface->soft_iface = NULL;
541
	batadv_hardif_free_ref(hard_iface);
542 543 544

out:
	if (primary_if)
545
		batadv_hardif_free_ref(primary_if);
546 547
}

548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
/**
 * batadv_hardif_remove_interface_finish - cleans up the remains of a hardif
 * @work: work queue item
 *
 * Free the parts of the hard interface which can not be removed under
 * rtnl lock (to prevent deadlock situations).
 */
static void batadv_hardif_remove_interface_finish(struct work_struct *work)
{
	struct batadv_hard_iface *hard_iface;

	hard_iface = container_of(work, struct batadv_hard_iface,
				  cleanup_work);

	batadv_sysfs_del_hardif(&hard_iface->hardif_obj);
	batadv_hardif_free_ref(hard_iface);
}

566
static struct batadv_hard_iface *
567
batadv_hardif_add_interface(struct net_device *net_dev)
568
{
569
	struct batadv_hard_iface *hard_iface;
570 571
	int ret;

572 573
	ASSERT_RTNL();

574
	ret = batadv_is_valid_iface(net_dev);
575 576 577 578 579
	if (ret != 1)
		goto out;

	dev_hold(net_dev);

580
	hard_iface = kzalloc(sizeof(*hard_iface), GFP_ATOMIC);
581
	if (!hard_iface)
582 583
		goto release_dev;

584
	ret = batadv_sysfs_add_hardif(&hard_iface->hardif_obj, net_dev);
585 586 587
	if (ret)
		goto free_if;

588 589 590
	hard_iface->if_num = -1;
	hard_iface->net_dev = net_dev;
	hard_iface->soft_iface = NULL;
591
	hard_iface->if_status = BATADV_IF_NOT_IN_USE;
592
	INIT_LIST_HEAD(&hard_iface->list);
593 594 595
	INIT_WORK(&hard_iface->cleanup_work,
		  batadv_hardif_remove_interface_finish);

596 597 598 599
	hard_iface->num_bcasts = BATADV_NUM_BCASTS_DEFAULT;
	if (batadv_is_wifi_netdev(net_dev))
		hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS;

600
	/* extra reference for return */
601
	atomic_set(&hard_iface->refcount, 2);
602

603
	batadv_check_known_mac_addr(hard_iface->net_dev);
604
	list_add_tail_rcu(&hard_iface->list, &batadv_hardif_list);
605

606
	return hard_iface;
607 608

free_if:
609
	kfree(hard_iface);
610 611 612 613 614 615
release_dev:
	dev_put(net_dev);
out:
	return NULL;
}

616
static void batadv_hardif_remove_interface(struct batadv_hard_iface *hard_iface)
617
{
618 619
	ASSERT_RTNL();

620
	/* first deactivate interface */
621
	if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
622 623
		batadv_hardif_disable_interface(hard_iface,
						BATADV_IF_CLEANUP_AUTO);
624

625
	if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
626 627
		return;

628
	hard_iface->if_status = BATADV_IF_TO_BE_REMOVED;
629
	queue_work(batadv_event_workqueue, &hard_iface->cleanup_work);
630 631
}

632
void batadv_hardif_remove_interfaces(void)
633
{
634
	struct batadv_hard_iface *hard_iface, *hard_iface_tmp;
635

636
	rtnl_lock();
637
	list_for_each_entry_safe(hard_iface, hard_iface_tmp,
638
				 &batadv_hardif_list, list) {
639
		list_del_rcu(&hard_iface->list);
640
		batadv_hardif_remove_interface(hard_iface);
641 642 643 644
	}
	rtnl_unlock();
}

645 646
static int batadv_hard_if_event(struct notifier_block *this,
				unsigned long event, void *ptr)
647
{
648
	struct net_device *net_dev = netdev_notifier_info_to_dev(ptr);
649 650 651
	struct batadv_hard_iface *hard_iface;
	struct batadv_hard_iface *primary_if = NULL;
	struct batadv_priv *bat_priv;
652

653 654 655 656 657
	if (batadv_softif_is_valid(net_dev) && event == NETDEV_REGISTER) {
		batadv_sysfs_add_meshif(net_dev);
		return NOTIFY_DONE;
	}

658
	hard_iface = batadv_hardif_get_by_netdev(net_dev);
659
	if (!hard_iface && event == NETDEV_REGISTER)
660
		hard_iface = batadv_hardif_add_interface(net_dev);
661

662
	if (!hard_iface)
663 664 665 666
		goto out;

	switch (event) {
	case NETDEV_UP:
667
		batadv_hardif_activate_interface(hard_iface);
668 669 670
		break;
	case NETDEV_GOING_DOWN:
	case NETDEV_DOWN:
671
		batadv_hardif_deactivate_interface(hard_iface);
672 673
		break;
	case NETDEV_UNREGISTER:
674
		list_del_rcu(&hard_iface->list);
675

676
		batadv_hardif_remove_interface(hard_iface);
677 678
		break;
	case NETDEV_CHANGEMTU:
679
		if (hard_iface->soft_iface)
680
			batadv_update_min_mtu(hard_iface->soft_iface);
681 682
		break;
	case NETDEV_CHANGEADDR:
683
		if (hard_iface->if_status == BATADV_IF_NOT_IN_USE)
684 685
			goto hardif_put;

686
		batadv_check_known_mac_addr(hard_iface->net_dev);
687

688
		bat_priv = netdev_priv(hard_iface->soft_iface);
689
		bat_priv->bat_algo_ops->bat_iface_update_mac(hard_iface);
690

691
		primary_if = batadv_primary_if_get_selected(bat_priv);
692 693 694 695
		if (!primary_if)
			goto hardif_put;

		if (hard_iface == primary_if)
696
			batadv_primary_if_update_addr(bat_priv, NULL);
697 698 699
		break;
	default:
		break;
J
Joe Perches 已提交
700
	}
701 702

hardif_put:
703
	batadv_hardif_free_ref(hard_iface);
704
out:
705
	if (primary_if)
706
		batadv_hardif_free_ref(primary_if);
707 708 709
	return NOTIFY_DONE;
}

710
struct notifier_block batadv_hard_if_notifier = {
711
	.notifier_call = batadv_hard_if_event,
712
};