Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright 2007-2012 Siemens AG
0004  *
0005  * Written by:
0006  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
0007  * Sergey Lapin <slapin@ossfans.org>
0008  * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
0009  * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
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, &params, 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     /* lowpan need to be down for update
0121      * SLAAC address after ifup
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     /* update lowpan interface mac address when
0136      * wpan mac has been changed
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     /* might already be clear but that doesn't matter */
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     /* we hold the RTNL here so can safely walk the list */
0272     list_for_each_entry(nsdata, &local->interfaces, list) {
0273         if (nsdata != sdata && ieee802154_sdata_running(nsdata)) {
0274             int ret;
0275 
0276             /* TODO currently we don't support multiple node types
0277              * we need to run skb_clone at rx path. Check if there
0278              * exist really an use case if we need to support
0279              * multiple node types at the same time.
0280              */
0281             if (wpan_dev->iftype == NL802154_IFTYPE_NODE &&
0282                 nsdata->wpan_dev.iftype == NL802154_IFTYPE_NODE)
0283                 return -EBUSY;
0284 
0285             /* check all phy mac sublayer settings are the same.
0286              * We have only one phy, different values makes trouble.
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, &params);
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 /* This header create functionality assumes a 8 byte array for
0421  * source and destination pointer at maximum. To adapt this for
0422  * the 802.15.4 dataframe header we use extended address handling
0423  * here only and intra pan connection. fc fields are mostly fallback
0424  * handling. For provide dev_hard_header for dgram sockets.
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     /* TODO currently a workaround to give zero cb block to set
0448      * security parameters defaults according MIB.
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     /* Let hard_header_len set to IEEE802154_MIN_HEADER_LEN. AF_PACKET
0528      * will not send frames without any payload, but ack frames
0529      * has no payload, so substract one that we can send a 3 bytes
0530      * frame. The xmit callback assumes at least a hard header where two
0531      * bytes fc and sequence field are set.
0532      */
0533     dev->hard_header_len    = IEEE802154_MIN_HEADER_LEN - 1;
0534     /* The auth_tag header is for security and places in private payload
0535      * room of mac frame which stucks between payload and FCS field.
0536      */
0537     dev->needed_tailroom    = IEEE802154_MAX_AUTH_TAG_LEN +
0538                   IEEE802154_FCS_LEN;
0539     /* The mtu size is the payload without mac header in this case.
0540      * We have a dynamic length header with a minimum header length
0541      * which is hard_header_len. In this case we let mtu to the size
0542      * of maximum payload which is IEEE802154_MTU - IEEE802154_FCS_LEN -
0543      * hard_header_len. The FCS which is set by hardware or ndo_start_xmit
0544      * and the minimum mac header which can be evaluated inside driver
0545      * layer. The rest of mac header will be part of payload if greater
0546      * than hard_header_len.
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     /* set some type-dependent values */
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     /* defaults per 802.15.4-2011 */
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     /* TODO check this */
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     /* setup type-dependent data */
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 }