iface.c 16.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * Copyright 2007-2012 Siemens AG
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * 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.
 *
 * Written by:
 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
 * Sergey Lapin <slapin@ossfans.org>
 * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
 * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
 */

#include <linux/netdevice.h>
#include <linux/module.h>
#include <linux/if_arp.h>
23
#include <linux/ieee802154.h>
24

25
#include <net/nl802154.h>
26 27
#include <net/mac802154.h>
#include <net/ieee802154_netdev.h>
28
#include <net/cfg802154.h>
29

30
#include "ieee802154_i.h"
31
#include "driver-ops.h"
32

33 34
static int mac802154_wpan_update_llsec(struct net_device *dev)
{
35
	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
36
	struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
37
	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
38 39 40 41 42 43
	int rc = 0;

	if (ops->llsec) {
		struct ieee802154_llsec_params params;
		int changed = 0;

44
		params.pan_id = wpan_dev->pan_id;
45 46
		changed |= IEEE802154_LLSEC_PARAM_PAN_ID;

47
		params.hwaddr = wpan_dev->extended_addr;
48 49 50 51 52 53 54 55
		changed |= IEEE802154_LLSEC_PARAM_HWADDR;

		rc = ops->llsec->set_params(dev, &params, changed);
	}

	return rc;
}

56 57 58
static int
mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
59
	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
60
	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
61 62 63 64
	struct sockaddr_ieee802154 *sa =
		(struct sockaddr_ieee802154 *)&ifr->ifr_addr;
	int err = -ENOIOCTLCMD;

65 66
	ASSERT_RTNL();

67
	spin_lock_bh(&sdata->mib_lock);
68 69 70

	switch (cmd) {
	case SIOCGIFADDR:
71 72 73
	{
		u16 pan_id, short_addr;

74 75
		pan_id = le16_to_cpu(wpan_dev->pan_id);
		short_addr = le16_to_cpu(wpan_dev->short_addr);
76 77
		if (pan_id == IEEE802154_PANID_BROADCAST ||
		    short_addr == IEEE802154_ADDR_BROADCAST) {
78 79 80 81 82 83
			err = -EADDRNOTAVAIL;
			break;
		}

		sa->family = AF_IEEE802154;
		sa->addr.addr_type = IEEE802154_ADDR_SHORT;
84 85
		sa->addr.pan_id = pan_id;
		sa->addr.short_addr = short_addr;
86 87 88

		err = 0;
		break;
89
	}
90
	case SIOCSIFADDR:
91 92 93 94 95
		if (netif_running(dev)) {
			spin_unlock_bh(&sdata->mib_lock);
			return -EBUSY;
		}

96
		dev_warn(&dev->dev,
M
Masanari Iida 已提交
97
			 "Using DEBUGing ioctl SIOCSIFADDR isn't recommended!\n");
98 99 100 101 102 103 104 105 106
		if (sa->family != AF_IEEE802154 ||
		    sa->addr.addr_type != IEEE802154_ADDR_SHORT ||
		    sa->addr.pan_id == IEEE802154_PANID_BROADCAST ||
		    sa->addr.short_addr == IEEE802154_ADDR_BROADCAST ||
		    sa->addr.short_addr == IEEE802154_ADDR_UNDEF) {
			err = -EINVAL;
			break;
		}

107 108
		wpan_dev->pan_id = cpu_to_le16(sa->addr.pan_id);
		wpan_dev->short_addr = cpu_to_le16(sa->addr.short_addr);
109

110
		err = mac802154_wpan_update_llsec(dev);
111 112 113
		break;
	}

114
	spin_unlock_bh(&sdata->mib_lock);
115 116 117 118 119
	return err;
}

static int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
{
120
	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
121
	struct sockaddr *addr = p;
122
	__le64 extended_addr;
123 124 125 126

	if (netif_running(dev))
		return -EBUSY;

127
	ieee802154_be64_to_le64(&extended_addr, addr->sa_data);
128 129 130
	if (!ieee802154_is_valid_extended_addr(extended_addr))
		return -EINVAL;

131
	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
132
	sdata->wpan_dev.extended_addr = extended_addr;
133

134
	return mac802154_wpan_update_llsec(dev);
135 136
}

137 138 139 140 141 142 143 144 145
static int mac802154_slave_open(struct net_device *dev)
{
	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
	struct ieee802154_sub_if_data *subif;
	struct ieee802154_local *local = sdata->local;
	int res = 0;

	ASSERT_RTNL();

146
	if (sdata->vif.type == NL802154_IFTYPE_NODE) {
147 148
		mutex_lock(&sdata->local->iflist_mtx);
		list_for_each_entry(subif, &sdata->local->interfaces, list) {
149 150
			if (subif != sdata &&
			    subif->vif.type == sdata->vif.type &&
151
			    ieee802154_sdata_running(subif)) {
152 153 154 155 156 157 158
				mutex_unlock(&sdata->local->iflist_mtx);
				return -EBUSY;
			}
		}
		mutex_unlock(&sdata->local->iflist_mtx);
	}

159
	set_bit(SDATA_STATE_RUNNING, &sdata->state);
160

161
	if (!local->open_count) {
162
		res = drv_start(local);
163 164 165 166 167
		WARN_ON(res);
		if (res)
			goto err;
	}

168
	local->open_count++;
169 170 171
	netif_start_queue(dev);
	return 0;
err:
172 173
	/* might already be clear but that doesn't matter */
	clear_bit(SDATA_STATE_RUNNING, &sdata->state);
174 175 176 177

	return res;
}

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
static int
ieee802154_check_mac_settings(struct ieee802154_local *local,
			      struct wpan_dev *wpan_dev,
			      struct wpan_dev *nwpan_dev)
{
	ASSERT_RTNL();

	if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) {
		if (wpan_dev->promiscuous_mode != nwpan_dev->promiscuous_mode)
			return -EBUSY;
	}

	if (local->hw.flags & IEEE802154_HW_AFILT) {
		if (wpan_dev->pan_id != nwpan_dev->pan_id)
			return -EBUSY;

		if (wpan_dev->short_addr != nwpan_dev->short_addr)
			return -EBUSY;

		if (wpan_dev->extended_addr != nwpan_dev->extended_addr)
			return -EBUSY;
	}

	if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) {
		if (wpan_dev->min_be != nwpan_dev->min_be)
			return -EBUSY;

		if (wpan_dev->max_be != nwpan_dev->max_be)
			return -EBUSY;

		if (wpan_dev->csma_retries != nwpan_dev->csma_retries)
			return -EBUSY;
	}

	if (local->hw.flags & IEEE802154_HW_FRAME_RETRIES) {
		if (wpan_dev->frame_retries != nwpan_dev->frame_retries)
			return -EBUSY;
	}

	if (local->hw.flags & IEEE802154_HW_LBT) {
		if (wpan_dev->lbt != nwpan_dev->lbt)
			return -EBUSY;
	}

	return 0;
}

static int
ieee802154_check_concurrent_iface(struct ieee802154_sub_if_data *sdata,
				  enum nl802154_iftype iftype)
{
	struct ieee802154_local *local = sdata->local;
	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
	struct ieee802154_sub_if_data *nsdata;

	/* we hold the RTNL here so can safely walk the list */
	list_for_each_entry(nsdata, &local->interfaces, list) {
		if (nsdata != sdata && ieee802154_sdata_running(nsdata)) {
			int ret;

			/* check all phy mac sublayer settings are the same.
			 * We have only one phy, different values makes trouble.
			 */
			ret = ieee802154_check_mac_settings(local, wpan_dev,
							    &nsdata->wpan_dev);
			if (ret < 0)
				return ret;
		}
	}

	return 0;
}

251
static int mac802154_wpan_open(struct net_device *dev)
252 253
{
	int rc;
254
	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
255
	struct ieee802154_local *local = sdata->local;
256
	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
257
	struct wpan_phy *phy = sdata->local->phy;
258

259 260 261 262
	rc = ieee802154_check_concurrent_iface(sdata, sdata->vif.type);
	if (rc < 0)
		return rc;

263 264 265 266 267 268
	rc = mac802154_slave_open(dev);
	if (rc < 0)
		return rc;

	mutex_lock(&phy->pib_lock);

269
	if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) {
270 271
		rc = drv_set_promiscuous_mode(local,
					      wpan_dev->promiscuous_mode);
272 273 274 275
		if (rc < 0)
			goto out;
	}

276
	if (local->hw.flags & IEEE802154_HW_AFILT) {
277
		rc = drv_set_pan_id(local, wpan_dev->pan_id);
278 279 280
		if (rc < 0)
			goto out;

281
		rc = drv_set_extended_addr(local, wpan_dev->extended_addr);
282 283
		if (rc < 0)
			goto out;
284

285
		rc = drv_set_short_addr(local, wpan_dev->short_addr);
286 287
		if (rc < 0)
			goto out;
288 289
	}

290
	if (local->hw.flags & IEEE802154_HW_LBT) {
291
		rc = drv_set_lbt_mode(local, wpan_dev->lbt);
292 293 294 295
		if (rc < 0)
			goto out;
	}

296
	if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) {
297 298 299
		rc = drv_set_csma_params(local, wpan_dev->min_be,
					 wpan_dev->max_be,
					 wpan_dev->csma_retries);
300 301 302 303
		if (rc < 0)
			goto out;
	}

304
	if (local->hw.flags & IEEE802154_HW_FRAME_RETRIES) {
305
		rc = drv_set_max_frame_retries(local, wpan_dev->frame_retries);
306 307 308 309 310 311 312 313 314 315 316 317
		if (rc < 0)
			goto out;
	}

	mutex_unlock(&phy->pib_lock);
	return 0;

out:
	mutex_unlock(&phy->pib_lock);
	return rc;
}

318 319 320 321 322 323 324
static int mac802154_slave_close(struct net_device *dev)
{
	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
	struct ieee802154_local *local = sdata->local;

	ASSERT_RTNL();

325 326
	hrtimer_cancel(&local->ifs_timer);

327
	netif_stop_queue(dev);
328
	local->open_count--;
329

330
	clear_bit(SDATA_STATE_RUNNING, &sdata->state);
331

332
	if (!local->open_count)
333
		drv_stop(local);
334 335 336 337

	return 0;
}

338
static int mac802154_set_header_security(struct ieee802154_sub_if_data *sdata,
339 340 341 342 343 344
					 struct ieee802154_hdr *hdr,
					 const struct ieee802154_mac_cb *cb)
{
	struct ieee802154_llsec_params params;
	u8 level;

345
	mac802154_llsec_get_params(&sdata->sec, &params);
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369

	if (!params.enabled && cb->secen_override && cb->secen)
		return -EINVAL;
	if (!params.enabled ||
	    (cb->secen_override && !cb->secen) ||
	    !params.out_level)
		return 0;
	if (cb->seclevel_override && !cb->seclevel)
		return -EINVAL;

	level = cb->seclevel_override ? cb->seclevel : params.out_level;

	hdr->fc.security_enabled = 1;
	hdr->sec.level = level;
	hdr->sec.key_id_mode = params.out_key.mode;
	if (params.out_key.mode == IEEE802154_SCF_KEY_SHORT_INDEX)
		hdr->sec.short_src = params.out_key.short_source;
	else if (params.out_key.mode == IEEE802154_SCF_KEY_HW_INDEX)
		hdr->sec.extended_src = params.out_key.extended_source;
	hdr->sec.key_id = params.out_key.id;

	return 0;
}

370 371 372
static int mac802154_header_create(struct sk_buff *skb,
				   struct net_device *dev,
				   unsigned short type,
373 374
				   const void *daddr,
				   const void *saddr,
375 376
				   unsigned len)
{
377
	struct ieee802154_hdr hdr;
378
	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
379
	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
380
	struct ieee802154_mac_cb *cb = mac_cb(skb);
381
	int hlen;
382 383 384 385

	if (!daddr)
		return -EINVAL;

386
	memset(&hdr.fc, 0, sizeof(hdr.fc));
387 388 389 390
	hdr.fc.type = cb->type;
	hdr.fc.security_enabled = cb->secen;
	hdr.fc.ack_request = cb->ackreq;
	hdr.seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
391

392
	if (mac802154_set_header_security(sdata, &hdr, cb) < 0)
393 394
		return -EINVAL;

395
	if (!saddr) {
396
		spin_lock_bh(&sdata->mib_lock);
397

398 399 400
		if (wpan_dev->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) ||
		    wpan_dev->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
		    wpan_dev->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
401
			hdr.source.mode = IEEE802154_ADDR_LONG;
402
			hdr.source.extended_addr = wpan_dev->extended_addr;
403
		} else {
404
			hdr.source.mode = IEEE802154_ADDR_SHORT;
405
			hdr.source.short_addr = wpan_dev->short_addr;
406 407
		}

408
		hdr.source.pan_id = wpan_dev->pan_id;
409

410
		spin_unlock_bh(&sdata->mib_lock);
411 412
	} else {
		hdr.source = *(const struct ieee802154_addr *)saddr;
413 414
	}

415
	hdr.dest = *(const struct ieee802154_addr *)daddr;
416

417 418 419
	hlen = ieee802154_hdr_push(skb, &hdr);
	if (hlen < 0)
		return -EINVAL;
420

421
	skb_reset_mac_header(skb);
422
	skb->mac_len = hlen;
423

424
	if (len > ieee802154_max_payload(&hdr))
425 426
		return -EMSGSIZE;

427
	return hlen;
428 429 430 431 432
}

static int
mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
{
433 434
	struct ieee802154_hdr hdr;
	struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr;
435

436 437 438
	if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) {
		pr_debug("malformed packet\n");
		return 0;
439 440
	}

441 442
	*addr = hdr.source;
	return sizeof(*addr);
443 444 445 446 447 448 449 450
}

static struct header_ops mac802154_header_ops = {
	.create		= mac802154_header_create,
	.parse		= mac802154_header_parse,
};

static const struct net_device_ops mac802154_wpan_ops = {
451
	.ndo_open		= mac802154_wpan_open,
452
	.ndo_stop		= mac802154_slave_close,
453
	.ndo_start_xmit		= ieee802154_subif_start_xmit,
454 455 456 457
	.ndo_do_ioctl		= mac802154_wpan_ioctl,
	.ndo_set_mac_address	= mac802154_wpan_mac_addr,
};

458
static const struct net_device_ops mac802154_monitor_ops = {
459
	.ndo_open		= mac802154_wpan_open,
460 461 462 463
	.ndo_stop		= mac802154_slave_close,
	.ndo_start_xmit		= ieee802154_monitor_start_xmit,
};

464 465
static void mac802154_wpan_free(struct net_device *dev)
{
466
	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
467

468
	mac802154_llsec_destroy(&sdata->sec);
469 470 471 472

	free_netdev(dev);
}

473
static void ieee802154_if_setup(struct net_device *dev)
474
{
475 476
	dev->addr_len		= IEEE802154_EXTENDED_ADDR_LEN;
	memset(dev->broadcast, 0xff, IEEE802154_EXTENDED_ADDR_LEN);
477 478

	dev->hard_header_len	= MAC802154_FRAME_HARD_HEADER_LEN;
479
	dev->needed_tailroom	= 2 + 16; /* FCS + MIC */
480
	dev->mtu		= IEEE802154_MTU;
A
Alan Ott 已提交
481
	dev->tx_queue_len	= 300;
482
	dev->flags		= IFF_NOARP | IFF_BROADCAST;
483
}
484

485
static int
486 487
ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata,
		       enum nl802154_iftype type)
488
{
489 490
	struct wpan_dev *wpan_dev = &sdata->wpan_dev;

491
	/* set some type-dependent values */
492
	sdata->vif.type = type;
493
	sdata->wpan_dev.iftype = type;
494

495 496
	get_random_bytes(&wpan_dev->bsn, 1);
	get_random_bytes(&wpan_dev->dsn, 1);
497

498
	/* defaults per 802.15.4-2011 */
499 500 501
	wpan_dev->min_be = 3;
	wpan_dev->max_be = 5;
	wpan_dev->csma_retries = 4;
502
	/* for compatibility, actual default is 3 */
503
	wpan_dev->frame_retries = -1;
504

505 506
	wpan_dev->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
	wpan_dev->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
507

508
	switch (type) {
509
	case NL802154_IFTYPE_NODE:
510 511 512
		ieee802154_be64_to_le64(&wpan_dev->extended_addr,
					sdata->dev->dev_addr);

513 514 515 516
		sdata->dev->header_ops = &mac802154_header_ops;
		sdata->dev->destructor = mac802154_wpan_free;
		sdata->dev->netdev_ops = &mac802154_wpan_ops;
		sdata->dev->ml_priv = &mac802154_mlme_wpan;
517
		wpan_dev->promiscuous_mode = false;
518

519 520
		spin_lock_init(&sdata->mib_lock);
		mutex_init(&sdata->sec_mtx);
521

522 523
		mac802154_llsec_init(&sdata->sec);
		break;
524
	case NL802154_IFTYPE_MONITOR:
525 526
		sdata->dev->destructor = free_netdev;
		sdata->dev->netdev_ops = &mac802154_monitor_ops;
527
		wpan_dev->promiscuous_mode = true;
528 529 530 531
		break;
	default:
		BUG();
	}
532 533 534 535 536 537

	return 0;
}

struct net_device *
ieee802154_if_add(struct ieee802154_local *local, const char *name,
538
		  enum nl802154_iftype type, __le64 extended_addr)
539
{
540 541 542 543 544 545
	struct net_device *ndev = NULL;
	struct ieee802154_sub_if_data *sdata = NULL;
	int ret = -ENOMEM;

	ASSERT_RTNL();

546 547
	ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, name,
			    NET_NAME_UNKNOWN, ieee802154_if_setup);
548 549 550 551 552 553 554 555
	if (!ndev)
		return ERR_PTR(-ENOMEM);

	ndev->needed_headroom = local->hw.extra_tx_headroom;

	ret = dev_alloc_name(ndev, ndev->name);
	if (ret < 0)
		goto err;
556

557 558
	ieee802154_le64_to_be64(ndev->perm_addr,
				&local->hw.phy->perm_extended_addr);
559
	switch (type) {
560
	case NL802154_IFTYPE_NODE:
561
		ndev->type = ARPHRD_IEEE802154;
562 563 564 565 566
		if (ieee802154_is_valid_extended_addr(extended_addr))
			ieee802154_le64_to_be64(ndev->dev_addr, &extended_addr);
		else
			memcpy(ndev->dev_addr, ndev->perm_addr,
			       IEEE802154_EXTENDED_ADDR_LEN);
567
		break;
568
	case NL802154_IFTYPE_MONITOR:
569
		ndev->type = ARPHRD_IEEE802154_MONITOR;
570
		break;
571 572 573
	default:
		ret = -EINVAL;
		goto err;
574
	}
575 576 577 578 579 580 581 582 583 584 585 586 587

	/* TODO check this */
	SET_NETDEV_DEV(ndev, &local->phy->dev);
	sdata = netdev_priv(ndev);
	ndev->ieee802154_ptr = &sdata->wpan_dev;
	memcpy(sdata->name, ndev->name, IFNAMSIZ);
	sdata->dev = ndev;
	sdata->wpan_dev.wpan_phy = local->hw.phy;
	sdata->local = local;

	/* setup type-dependent data */
	ret = ieee802154_setup_sdata(sdata, type);
	if (ret)
588 589
		goto err;

590 591 592
	ret = register_netdevice(ndev);
	if (ret < 0)
		goto err;
593 594 595 596

	mutex_lock(&local->iflist_mtx);
	list_add_tail_rcu(&sdata->list, &local->interfaces);
	mutex_unlock(&local->iflist_mtx);
597

598
	return ndev;
599 600

err:
601 602
	free_netdev(ndev);
	return ERR_PTR(ret);
603 604
}

605 606 607 608 609 610 611 612 613 614 615
void ieee802154_if_remove(struct ieee802154_sub_if_data *sdata)
{
	ASSERT_RTNL();

	mutex_lock(&sdata->local->iflist_mtx);
	list_del_rcu(&sdata->list);
	mutex_unlock(&sdata->local->iflist_mtx);

	synchronize_rcu();
	unregister_netdevice(sdata->dev);
}
616 617 618

void ieee802154_remove_interfaces(struct ieee802154_local *local)
{
619
	struct ieee802154_sub_if_data *sdata, *tmp;
620

621
	mutex_lock(&local->iflist_mtx);
622
	list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
623 624 625 626
		list_del(&sdata->list);

		unregister_netdevice(sdata->dev);
	}
627
	mutex_unlock(&local->iflist_mtx);
628
}
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663

static int netdev_notify(struct notifier_block *nb,
			 unsigned long state, void *ptr)
{
	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
	struct ieee802154_sub_if_data *sdata;

	if (state != NETDEV_CHANGENAME)
		return NOTIFY_DONE;

	if (!dev->ieee802154_ptr || !dev->ieee802154_ptr->wpan_phy)
		return NOTIFY_DONE;

	if (dev->ieee802154_ptr->wpan_phy->privid != mac802154_wpan_phy_privid)
		return NOTIFY_DONE;

	sdata = IEEE802154_DEV_TO_SUB_IF(dev);
	memcpy(sdata->name, dev->name, IFNAMSIZ);

	return NOTIFY_OK;
}

static struct notifier_block mac802154_netdev_notifier = {
	.notifier_call = netdev_notify,
};

int ieee802154_iface_init(void)
{
	return register_netdevice_notifier(&mac802154_netdev_notifier);
}

void ieee802154_iface_exit(void)
{
	unregister_netdevice_notifier(&mac802154_netdev_notifier);
}