0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/netdevice.h>
0013 #include <linux/module.h>
0014 #include <linux/if_arp.h>
0015 #include <linux/ieee802154.h>
0016
0017 #include <net/nl802154.h>
0018 #include <net/mac802154.h>
0019 #include <net/ieee802154_netdev.h>
0020 #include <net/cfg802154.h>
0021
0022 #include "ieee802154_i.h"
0023 #include "driver-ops.h"
0024
0025 int mac802154_wpan_update_llsec(struct net_device *dev)
0026 {
0027 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
0028 struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
0029 struct wpan_dev *wpan_dev = &sdata->wpan_dev;
0030 int rc = 0;
0031
0032 if (ops->llsec) {
0033 struct ieee802154_llsec_params params;
0034 int changed = 0;
0035
0036 params.pan_id = wpan_dev->pan_id;
0037 changed |= IEEE802154_LLSEC_PARAM_PAN_ID;
0038
0039 params.hwaddr = wpan_dev->extended_addr;
0040 changed |= IEEE802154_LLSEC_PARAM_HWADDR;
0041
0042 rc = ops->llsec->set_params(dev, ¶ms, changed);
0043 }
0044
0045 return rc;
0046 }
0047
0048 static int
0049 mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
0050 {
0051 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
0052 struct wpan_dev *wpan_dev = &sdata->wpan_dev;
0053 struct sockaddr_ieee802154 *sa =
0054 (struct sockaddr_ieee802154 *)&ifr->ifr_addr;
0055 int err = -ENOIOCTLCMD;
0056
0057 if (cmd != SIOCGIFADDR && cmd != SIOCSIFADDR)
0058 return err;
0059
0060 rtnl_lock();
0061
0062 switch (cmd) {
0063 case SIOCGIFADDR:
0064 {
0065 u16 pan_id, short_addr;
0066
0067 pan_id = le16_to_cpu(wpan_dev->pan_id);
0068 short_addr = le16_to_cpu(wpan_dev->short_addr);
0069 if (pan_id == IEEE802154_PANID_BROADCAST ||
0070 short_addr == IEEE802154_ADDR_BROADCAST) {
0071 err = -EADDRNOTAVAIL;
0072 break;
0073 }
0074
0075 sa->family = AF_IEEE802154;
0076 sa->addr.addr_type = IEEE802154_ADDR_SHORT;
0077 sa->addr.pan_id = pan_id;
0078 sa->addr.short_addr = short_addr;
0079
0080 err = 0;
0081 break;
0082 }
0083 case SIOCSIFADDR:
0084 if (netif_running(dev)) {
0085 rtnl_unlock();
0086 return -EBUSY;
0087 }
0088
0089 dev_warn(&dev->dev,
0090 "Using DEBUGing ioctl SIOCSIFADDR isn't recommended!\n");
0091 if (sa->family != AF_IEEE802154 ||
0092 sa->addr.addr_type != IEEE802154_ADDR_SHORT ||
0093 sa->addr.pan_id == IEEE802154_PANID_BROADCAST ||
0094 sa->addr.short_addr == IEEE802154_ADDR_BROADCAST ||
0095 sa->addr.short_addr == IEEE802154_ADDR_UNDEF) {
0096 err = -EINVAL;
0097 break;
0098 }
0099
0100 wpan_dev->pan_id = cpu_to_le16(sa->addr.pan_id);
0101 wpan_dev->short_addr = cpu_to_le16(sa->addr.short_addr);
0102
0103 err = mac802154_wpan_update_llsec(dev);
0104 break;
0105 }
0106
0107 rtnl_unlock();
0108 return err;
0109 }
0110
0111 static int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
0112 {
0113 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
0114 struct sockaddr *addr = p;
0115 __le64 extended_addr;
0116
0117 if (netif_running(dev))
0118 return -EBUSY;
0119
0120
0121
0122
0123 if (sdata->wpan_dev.lowpan_dev) {
0124 if (netif_running(sdata->wpan_dev.lowpan_dev))
0125 return -EBUSY;
0126 }
0127
0128 ieee802154_be64_to_le64(&extended_addr, addr->sa_data);
0129 if (!ieee802154_is_valid_extended_unicast_addr(extended_addr))
0130 return -EINVAL;
0131
0132 dev_addr_set(dev, addr->sa_data);
0133 sdata->wpan_dev.extended_addr = extended_addr;
0134
0135
0136
0137
0138 if (sdata->wpan_dev.lowpan_dev)
0139 dev_addr_set(sdata->wpan_dev.lowpan_dev, dev->dev_addr);
0140
0141 return mac802154_wpan_update_llsec(dev);
0142 }
0143
0144 static int ieee802154_setup_hw(struct ieee802154_sub_if_data *sdata)
0145 {
0146 struct ieee802154_local *local = sdata->local;
0147 struct wpan_dev *wpan_dev = &sdata->wpan_dev;
0148 int ret;
0149
0150 if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) {
0151 ret = drv_set_promiscuous_mode(local,
0152 wpan_dev->promiscuous_mode);
0153 if (ret < 0)
0154 return ret;
0155 }
0156
0157 if (local->hw.flags & IEEE802154_HW_AFILT) {
0158 ret = drv_set_pan_id(local, wpan_dev->pan_id);
0159 if (ret < 0)
0160 return ret;
0161
0162 ret = drv_set_extended_addr(local, wpan_dev->extended_addr);
0163 if (ret < 0)
0164 return ret;
0165
0166 ret = drv_set_short_addr(local, wpan_dev->short_addr);
0167 if (ret < 0)
0168 return ret;
0169 }
0170
0171 if (local->hw.flags & IEEE802154_HW_LBT) {
0172 ret = drv_set_lbt_mode(local, wpan_dev->lbt);
0173 if (ret < 0)
0174 return ret;
0175 }
0176
0177 if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) {
0178 ret = drv_set_csma_params(local, wpan_dev->min_be,
0179 wpan_dev->max_be,
0180 wpan_dev->csma_retries);
0181 if (ret < 0)
0182 return ret;
0183 }
0184
0185 if (local->hw.flags & IEEE802154_HW_FRAME_RETRIES) {
0186 ret = drv_set_max_frame_retries(local, wpan_dev->frame_retries);
0187 if (ret < 0)
0188 return ret;
0189 }
0190
0191 return 0;
0192 }
0193
0194 static int mac802154_slave_open(struct net_device *dev)
0195 {
0196 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
0197 struct ieee802154_local *local = sdata->local;
0198 int res;
0199
0200 ASSERT_RTNL();
0201
0202 set_bit(SDATA_STATE_RUNNING, &sdata->state);
0203
0204 if (!local->open_count) {
0205 res = ieee802154_setup_hw(sdata);
0206 if (res)
0207 goto err;
0208
0209 res = drv_start(local);
0210 if (res)
0211 goto err;
0212 }
0213
0214 local->open_count++;
0215 netif_start_queue(dev);
0216 return 0;
0217 err:
0218
0219 clear_bit(SDATA_STATE_RUNNING, &sdata->state);
0220
0221 return res;
0222 }
0223
0224 static int
0225 ieee802154_check_mac_settings(struct ieee802154_local *local,
0226 struct wpan_dev *wpan_dev,
0227 struct wpan_dev *nwpan_dev)
0228 {
0229 ASSERT_RTNL();
0230
0231 if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) {
0232 if (wpan_dev->promiscuous_mode != nwpan_dev->promiscuous_mode)
0233 return -EBUSY;
0234 }
0235
0236 if (local->hw.flags & IEEE802154_HW_AFILT) {
0237 if (wpan_dev->pan_id != nwpan_dev->pan_id ||
0238 wpan_dev->short_addr != nwpan_dev->short_addr ||
0239 wpan_dev->extended_addr != nwpan_dev->extended_addr)
0240 return -EBUSY;
0241 }
0242
0243 if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) {
0244 if (wpan_dev->min_be != nwpan_dev->min_be ||
0245 wpan_dev->max_be != nwpan_dev->max_be ||
0246 wpan_dev->csma_retries != nwpan_dev->csma_retries)
0247 return -EBUSY;
0248 }
0249
0250 if (local->hw.flags & IEEE802154_HW_FRAME_RETRIES) {
0251 if (wpan_dev->frame_retries != nwpan_dev->frame_retries)
0252 return -EBUSY;
0253 }
0254
0255 if (local->hw.flags & IEEE802154_HW_LBT) {
0256 if (wpan_dev->lbt != nwpan_dev->lbt)
0257 return -EBUSY;
0258 }
0259
0260 return 0;
0261 }
0262
0263 static int
0264 ieee802154_check_concurrent_iface(struct ieee802154_sub_if_data *sdata,
0265 enum nl802154_iftype iftype)
0266 {
0267 struct ieee802154_local *local = sdata->local;
0268 struct wpan_dev *wpan_dev = &sdata->wpan_dev;
0269 struct ieee802154_sub_if_data *nsdata;
0270
0271
0272 list_for_each_entry(nsdata, &local->interfaces, list) {
0273 if (nsdata != sdata && ieee802154_sdata_running(nsdata)) {
0274 int ret;
0275
0276
0277
0278
0279
0280
0281 if (wpan_dev->iftype == NL802154_IFTYPE_NODE &&
0282 nsdata->wpan_dev.iftype == NL802154_IFTYPE_NODE)
0283 return -EBUSY;
0284
0285
0286
0287
0288 ret = ieee802154_check_mac_settings(local, wpan_dev,
0289 &nsdata->wpan_dev);
0290 if (ret < 0)
0291 return ret;
0292 }
0293 }
0294
0295 return 0;
0296 }
0297
0298 static int mac802154_wpan_open(struct net_device *dev)
0299 {
0300 int rc;
0301 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
0302 struct wpan_dev *wpan_dev = &sdata->wpan_dev;
0303
0304 rc = ieee802154_check_concurrent_iface(sdata, wpan_dev->iftype);
0305 if (rc < 0)
0306 return rc;
0307
0308 return mac802154_slave_open(dev);
0309 }
0310
0311 static int mac802154_slave_close(struct net_device *dev)
0312 {
0313 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
0314 struct ieee802154_local *local = sdata->local;
0315
0316 ASSERT_RTNL();
0317
0318 netif_stop_queue(dev);
0319 local->open_count--;
0320
0321 clear_bit(SDATA_STATE_RUNNING, &sdata->state);
0322
0323 if (!local->open_count)
0324 ieee802154_stop_device(local);
0325
0326 return 0;
0327 }
0328
0329 static int mac802154_set_header_security(struct ieee802154_sub_if_data *sdata,
0330 struct ieee802154_hdr *hdr,
0331 const struct ieee802154_mac_cb *cb)
0332 {
0333 struct ieee802154_llsec_params params;
0334 u8 level;
0335
0336 mac802154_llsec_get_params(&sdata->sec, ¶ms);
0337
0338 if (!params.enabled && cb->secen_override && cb->secen)
0339 return -EINVAL;
0340 if (!params.enabled ||
0341 (cb->secen_override && !cb->secen) ||
0342 !params.out_level)
0343 return 0;
0344 if (cb->seclevel_override && !cb->seclevel)
0345 return -EINVAL;
0346
0347 level = cb->seclevel_override ? cb->seclevel : params.out_level;
0348
0349 hdr->fc.security_enabled = 1;
0350 hdr->sec.level = level;
0351 hdr->sec.key_id_mode = params.out_key.mode;
0352 if (params.out_key.mode == IEEE802154_SCF_KEY_SHORT_INDEX)
0353 hdr->sec.short_src = params.out_key.short_source;
0354 else if (params.out_key.mode == IEEE802154_SCF_KEY_HW_INDEX)
0355 hdr->sec.extended_src = params.out_key.extended_source;
0356 hdr->sec.key_id = params.out_key.id;
0357
0358 return 0;
0359 }
0360
0361 static int ieee802154_header_create(struct sk_buff *skb,
0362 struct net_device *dev,
0363 const struct ieee802154_addr *daddr,
0364 const struct ieee802154_addr *saddr,
0365 unsigned len)
0366 {
0367 struct ieee802154_hdr hdr;
0368 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
0369 struct wpan_dev *wpan_dev = &sdata->wpan_dev;
0370 struct ieee802154_mac_cb *cb = mac_cb(skb);
0371 int hlen;
0372
0373 if (!daddr)
0374 return -EINVAL;
0375
0376 memset(&hdr.fc, 0, sizeof(hdr.fc));
0377 hdr.fc.type = cb->type;
0378 hdr.fc.security_enabled = cb->secen;
0379 hdr.fc.ack_request = cb->ackreq;
0380 hdr.seq = atomic_inc_return(&dev->ieee802154_ptr->dsn) & 0xFF;
0381
0382 if (mac802154_set_header_security(sdata, &hdr, cb) < 0)
0383 return -EINVAL;
0384
0385 if (!saddr) {
0386 if (wpan_dev->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) ||
0387 wpan_dev->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
0388 wpan_dev->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
0389 hdr.source.mode = IEEE802154_ADDR_LONG;
0390 hdr.source.extended_addr = wpan_dev->extended_addr;
0391 } else {
0392 hdr.source.mode = IEEE802154_ADDR_SHORT;
0393 hdr.source.short_addr = wpan_dev->short_addr;
0394 }
0395
0396 hdr.source.pan_id = wpan_dev->pan_id;
0397 } else {
0398 hdr.source = *(const struct ieee802154_addr *)saddr;
0399 }
0400
0401 hdr.dest = *(const struct ieee802154_addr *)daddr;
0402
0403 hlen = ieee802154_hdr_push(skb, &hdr);
0404 if (hlen < 0)
0405 return -EINVAL;
0406
0407 skb_reset_mac_header(skb);
0408 skb->mac_len = hlen;
0409
0410 if (len > ieee802154_max_payload(&hdr))
0411 return -EMSGSIZE;
0412
0413 return hlen;
0414 }
0415
0416 static const struct wpan_dev_header_ops ieee802154_header_ops = {
0417 .create = ieee802154_header_create,
0418 };
0419
0420
0421
0422
0423
0424
0425
0426 static int mac802154_header_create(struct sk_buff *skb,
0427 struct net_device *dev,
0428 unsigned short type,
0429 const void *daddr,
0430 const void *saddr,
0431 unsigned len)
0432 {
0433 struct ieee802154_hdr hdr;
0434 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
0435 struct wpan_dev *wpan_dev = &sdata->wpan_dev;
0436 struct ieee802154_mac_cb cb = { };
0437 int hlen;
0438
0439 if (!daddr)
0440 return -EINVAL;
0441
0442 memset(&hdr.fc, 0, sizeof(hdr.fc));
0443 hdr.fc.type = IEEE802154_FC_TYPE_DATA;
0444 hdr.fc.ack_request = wpan_dev->ackreq;
0445 hdr.seq = atomic_inc_return(&dev->ieee802154_ptr->dsn) & 0xFF;
0446
0447
0448
0449
0450 if (mac802154_set_header_security(sdata, &hdr, &cb) < 0)
0451 return -EINVAL;
0452
0453 hdr.dest.pan_id = wpan_dev->pan_id;
0454 hdr.dest.mode = IEEE802154_ADDR_LONG;
0455 ieee802154_be64_to_le64(&hdr.dest.extended_addr, daddr);
0456
0457 hdr.source.pan_id = hdr.dest.pan_id;
0458 hdr.source.mode = IEEE802154_ADDR_LONG;
0459
0460 if (!saddr)
0461 hdr.source.extended_addr = wpan_dev->extended_addr;
0462 else
0463 ieee802154_be64_to_le64(&hdr.source.extended_addr, saddr);
0464
0465 hlen = ieee802154_hdr_push(skb, &hdr);
0466 if (hlen < 0)
0467 return -EINVAL;
0468
0469 skb_reset_mac_header(skb);
0470 skb->mac_len = hlen;
0471
0472 if (len > ieee802154_max_payload(&hdr))
0473 return -EMSGSIZE;
0474
0475 return hlen;
0476 }
0477
0478 static int
0479 mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
0480 {
0481 struct ieee802154_hdr hdr;
0482
0483 if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) {
0484 pr_debug("malformed packet\n");
0485 return 0;
0486 }
0487
0488 if (hdr.source.mode == IEEE802154_ADDR_LONG) {
0489 ieee802154_le64_to_be64(haddr, &hdr.source.extended_addr);
0490 return IEEE802154_EXTENDED_ADDR_LEN;
0491 }
0492
0493 return 0;
0494 }
0495
0496 static const struct header_ops mac802154_header_ops = {
0497 .create = mac802154_header_create,
0498 .parse = mac802154_header_parse,
0499 };
0500
0501 static const struct net_device_ops mac802154_wpan_ops = {
0502 .ndo_open = mac802154_wpan_open,
0503 .ndo_stop = mac802154_slave_close,
0504 .ndo_start_xmit = ieee802154_subif_start_xmit,
0505 .ndo_do_ioctl = mac802154_wpan_ioctl,
0506 .ndo_set_mac_address = mac802154_wpan_mac_addr,
0507 };
0508
0509 static const struct net_device_ops mac802154_monitor_ops = {
0510 .ndo_open = mac802154_wpan_open,
0511 .ndo_stop = mac802154_slave_close,
0512 .ndo_start_xmit = ieee802154_monitor_start_xmit,
0513 };
0514
0515 static void mac802154_wpan_free(struct net_device *dev)
0516 {
0517 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
0518
0519 mac802154_llsec_destroy(&sdata->sec);
0520 }
0521
0522 static void ieee802154_if_setup(struct net_device *dev)
0523 {
0524 dev->addr_len = IEEE802154_EXTENDED_ADDR_LEN;
0525 memset(dev->broadcast, 0xff, IEEE802154_EXTENDED_ADDR_LEN);
0526
0527
0528
0529
0530
0531
0532
0533 dev->hard_header_len = IEEE802154_MIN_HEADER_LEN - 1;
0534
0535
0536
0537 dev->needed_tailroom = IEEE802154_MAX_AUTH_TAG_LEN +
0538 IEEE802154_FCS_LEN;
0539
0540
0541
0542
0543
0544
0545
0546
0547
0548 dev->mtu = IEEE802154_MTU - IEEE802154_FCS_LEN -
0549 dev->hard_header_len;
0550 dev->tx_queue_len = 300;
0551 dev->flags = IFF_NOARP | IFF_BROADCAST;
0552 }
0553
0554 static int
0555 ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata,
0556 enum nl802154_iftype type)
0557 {
0558 struct wpan_dev *wpan_dev = &sdata->wpan_dev;
0559 int ret;
0560 u8 tmp;
0561
0562
0563 sdata->wpan_dev.iftype = type;
0564
0565 get_random_bytes(&tmp, sizeof(tmp));
0566 atomic_set(&wpan_dev->bsn, tmp);
0567 get_random_bytes(&tmp, sizeof(tmp));
0568 atomic_set(&wpan_dev->dsn, tmp);
0569
0570
0571 wpan_dev->min_be = 3;
0572 wpan_dev->max_be = 5;
0573 wpan_dev->csma_retries = 4;
0574 wpan_dev->frame_retries = 3;
0575
0576 wpan_dev->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
0577 wpan_dev->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
0578
0579 switch (type) {
0580 case NL802154_IFTYPE_NODE:
0581 ieee802154_be64_to_le64(&wpan_dev->extended_addr,
0582 sdata->dev->dev_addr);
0583
0584 sdata->dev->header_ops = &mac802154_header_ops;
0585 sdata->dev->needs_free_netdev = true;
0586 sdata->dev->priv_destructor = mac802154_wpan_free;
0587 sdata->dev->netdev_ops = &mac802154_wpan_ops;
0588 sdata->dev->ml_priv = &mac802154_mlme_wpan;
0589 wpan_dev->promiscuous_mode = false;
0590 wpan_dev->header_ops = &ieee802154_header_ops;
0591
0592 mutex_init(&sdata->sec_mtx);
0593
0594 mac802154_llsec_init(&sdata->sec);
0595 ret = mac802154_wpan_update_llsec(sdata->dev);
0596 if (ret < 0)
0597 return ret;
0598
0599 break;
0600 case NL802154_IFTYPE_MONITOR:
0601 sdata->dev->needs_free_netdev = true;
0602 sdata->dev->netdev_ops = &mac802154_monitor_ops;
0603 wpan_dev->promiscuous_mode = true;
0604 break;
0605 default:
0606 BUG();
0607 }
0608
0609 return 0;
0610 }
0611
0612 struct net_device *
0613 ieee802154_if_add(struct ieee802154_local *local, const char *name,
0614 unsigned char name_assign_type, enum nl802154_iftype type,
0615 __le64 extended_addr)
0616 {
0617 u8 addr[IEEE802154_EXTENDED_ADDR_LEN];
0618 struct net_device *ndev = NULL;
0619 struct ieee802154_sub_if_data *sdata = NULL;
0620 int ret;
0621
0622 ASSERT_RTNL();
0623
0624 ndev = alloc_netdev(sizeof(*sdata), name,
0625 name_assign_type, ieee802154_if_setup);
0626 if (!ndev)
0627 return ERR_PTR(-ENOMEM);
0628
0629 ndev->needed_headroom = local->hw.extra_tx_headroom +
0630 IEEE802154_MAX_HEADER_LEN;
0631
0632 ret = dev_alloc_name(ndev, ndev->name);
0633 if (ret < 0)
0634 goto err;
0635
0636 ieee802154_le64_to_be64(ndev->perm_addr,
0637 &local->hw.phy->perm_extended_addr);
0638 switch (type) {
0639 case NL802154_IFTYPE_NODE:
0640 ndev->type = ARPHRD_IEEE802154;
0641 if (ieee802154_is_valid_extended_unicast_addr(extended_addr)) {
0642 ieee802154_le64_to_be64(addr, &extended_addr);
0643 dev_addr_set(ndev, addr);
0644 } else {
0645 dev_addr_set(ndev, ndev->perm_addr);
0646 }
0647 break;
0648 case NL802154_IFTYPE_MONITOR:
0649 ndev->type = ARPHRD_IEEE802154_MONITOR;
0650 break;
0651 default:
0652 ret = -EINVAL;
0653 goto err;
0654 }
0655
0656
0657 SET_NETDEV_DEV(ndev, &local->phy->dev);
0658 dev_net_set(ndev, wpan_phy_net(local->hw.phy));
0659 sdata = netdev_priv(ndev);
0660 ndev->ieee802154_ptr = &sdata->wpan_dev;
0661 memcpy(sdata->name, ndev->name, IFNAMSIZ);
0662 sdata->dev = ndev;
0663 sdata->wpan_dev.wpan_phy = local->hw.phy;
0664 sdata->local = local;
0665
0666
0667 ret = ieee802154_setup_sdata(sdata, type);
0668 if (ret)
0669 goto err;
0670
0671 ret = register_netdevice(ndev);
0672 if (ret < 0)
0673 goto err;
0674
0675 mutex_lock(&local->iflist_mtx);
0676 list_add_tail_rcu(&sdata->list, &local->interfaces);
0677 mutex_unlock(&local->iflist_mtx);
0678
0679 return ndev;
0680
0681 err:
0682 free_netdev(ndev);
0683 return ERR_PTR(ret);
0684 }
0685
0686 void ieee802154_if_remove(struct ieee802154_sub_if_data *sdata)
0687 {
0688 ASSERT_RTNL();
0689
0690 mutex_lock(&sdata->local->iflist_mtx);
0691 list_del_rcu(&sdata->list);
0692 mutex_unlock(&sdata->local->iflist_mtx);
0693
0694 synchronize_rcu();
0695 unregister_netdevice(sdata->dev);
0696 }
0697
0698 void ieee802154_remove_interfaces(struct ieee802154_local *local)
0699 {
0700 struct ieee802154_sub_if_data *sdata, *tmp;
0701
0702 mutex_lock(&local->iflist_mtx);
0703 list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
0704 list_del(&sdata->list);
0705
0706 unregister_netdevice(sdata->dev);
0707 }
0708 mutex_unlock(&local->iflist_mtx);
0709 }
0710
0711 static int netdev_notify(struct notifier_block *nb,
0712 unsigned long state, void *ptr)
0713 {
0714 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
0715 struct ieee802154_sub_if_data *sdata;
0716
0717 if (state != NETDEV_CHANGENAME)
0718 return NOTIFY_DONE;
0719
0720 if (!dev->ieee802154_ptr || !dev->ieee802154_ptr->wpan_phy)
0721 return NOTIFY_DONE;
0722
0723 if (dev->ieee802154_ptr->wpan_phy->privid != mac802154_wpan_phy_privid)
0724 return NOTIFY_DONE;
0725
0726 sdata = IEEE802154_DEV_TO_SUB_IF(dev);
0727 memcpy(sdata->name, dev->name, IFNAMSIZ);
0728
0729 return NOTIFY_OK;
0730 }
0731
0732 static struct notifier_block mac802154_netdev_notifier = {
0733 .notifier_call = netdev_notify,
0734 };
0735
0736 int ieee802154_iface_init(void)
0737 {
0738 return register_netdevice_notifier(&mac802154_netdev_notifier);
0739 }
0740
0741 void ieee802154_iface_exit(void)
0742 {
0743 unregister_netdevice_notifier(&mac802154_netdev_notifier);
0744 }