11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
215859a5eSAlexander Aring /*
315859a5eSAlexander Aring * Copyright 2007-2012 Siemens AG
415859a5eSAlexander Aring *
515859a5eSAlexander Aring * Written by:
615859a5eSAlexander Aring * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
715859a5eSAlexander Aring * Sergey Lapin <slapin@ossfans.org>
815859a5eSAlexander Aring * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
915859a5eSAlexander Aring * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
1015859a5eSAlexander Aring */
1115859a5eSAlexander Aring
1215859a5eSAlexander Aring #include <linux/netdevice.h>
1315859a5eSAlexander Aring #include <linux/module.h>
1415859a5eSAlexander Aring #include <linux/if_arp.h>
154ca24acaSAlexander Aring #include <linux/ieee802154.h>
1615859a5eSAlexander Aring
17944742a3SAlexander Aring #include <net/nl802154.h>
1815859a5eSAlexander Aring #include <net/mac802154.h>
1915859a5eSAlexander Aring #include <net/ieee802154_netdev.h>
205ad60d36SAlexander Aring #include <net/cfg802154.h>
2115859a5eSAlexander Aring
2215859a5eSAlexander Aring #include "ieee802154_i.h"
2359cb300fSAlexander Aring #include "driver-ops.h"
2415859a5eSAlexander Aring
mac802154_wpan_update_llsec(struct net_device * dev)25d77b4852SAlexander Aring int mac802154_wpan_update_llsec(struct net_device *dev)
2615859a5eSAlexander Aring {
2759d19cd7SAlexander Aring struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
2815859a5eSAlexander Aring struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
29863e88f2SAlexander Aring struct wpan_dev *wpan_dev = &sdata->wpan_dev;
3015859a5eSAlexander Aring int rc = 0;
3115859a5eSAlexander Aring
3215859a5eSAlexander Aring if (ops->llsec) {
3315859a5eSAlexander Aring struct ieee802154_llsec_params params;
3415859a5eSAlexander Aring int changed = 0;
3515859a5eSAlexander Aring
36863e88f2SAlexander Aring params.pan_id = wpan_dev->pan_id;
3715859a5eSAlexander Aring changed |= IEEE802154_LLSEC_PARAM_PAN_ID;
3815859a5eSAlexander Aring
39863e88f2SAlexander Aring params.hwaddr = wpan_dev->extended_addr;
4015859a5eSAlexander Aring changed |= IEEE802154_LLSEC_PARAM_HWADDR;
4115859a5eSAlexander Aring
4215859a5eSAlexander Aring rc = ops->llsec->set_params(dev, ¶ms, changed);
4315859a5eSAlexander Aring }
4415859a5eSAlexander Aring
4515859a5eSAlexander Aring return rc;
4615859a5eSAlexander Aring }
4715859a5eSAlexander Aring
4815859a5eSAlexander Aring static int
mac802154_wpan_ioctl(struct net_device * dev,struct ifreq * ifr,int cmd)4915859a5eSAlexander Aring mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
5015859a5eSAlexander Aring {
5159d19cd7SAlexander Aring struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
52863e88f2SAlexander Aring struct wpan_dev *wpan_dev = &sdata->wpan_dev;
5315859a5eSAlexander Aring struct sockaddr_ieee802154 *sa =
5415859a5eSAlexander Aring (struct sockaddr_ieee802154 *)&ifr->ifr_addr;
5515859a5eSAlexander Aring int err = -ENOIOCTLCMD;
5615859a5eSAlexander Aring
57e34fd879SLennert Buytenhek if (cmd != SIOCGIFADDR && cmd != SIOCSIFADDR)
58e34fd879SLennert Buytenhek return err;
59e34fd879SLennert Buytenhek
604a669f7dSAlexander Aring rtnl_lock();
6115859a5eSAlexander Aring
6215859a5eSAlexander Aring switch (cmd) {
6315859a5eSAlexander Aring case SIOCGIFADDR:
6415859a5eSAlexander Aring {
6515859a5eSAlexander Aring u16 pan_id, short_addr;
6615859a5eSAlexander Aring
67863e88f2SAlexander Aring pan_id = le16_to_cpu(wpan_dev->pan_id);
68863e88f2SAlexander Aring short_addr = le16_to_cpu(wpan_dev->short_addr);
6915859a5eSAlexander Aring if (pan_id == IEEE802154_PANID_BROADCAST ||
7015859a5eSAlexander Aring short_addr == IEEE802154_ADDR_BROADCAST) {
7115859a5eSAlexander Aring err = -EADDRNOTAVAIL;
7215859a5eSAlexander Aring break;
7315859a5eSAlexander Aring }
7415859a5eSAlexander Aring
7515859a5eSAlexander Aring sa->family = AF_IEEE802154;
7615859a5eSAlexander Aring sa->addr.addr_type = IEEE802154_ADDR_SHORT;
7715859a5eSAlexander Aring sa->addr.pan_id = pan_id;
7815859a5eSAlexander Aring sa->addr.short_addr = short_addr;
7915859a5eSAlexander Aring
8015859a5eSAlexander Aring err = 0;
8115859a5eSAlexander Aring break;
8215859a5eSAlexander Aring }
8315859a5eSAlexander Aring case SIOCSIFADDR:
84f7cb96f1SAlexander Aring if (netif_running(dev)) {
854a669f7dSAlexander Aring rtnl_unlock();
86f7cb96f1SAlexander Aring return -EBUSY;
87f7cb96f1SAlexander Aring }
88f7cb96f1SAlexander Aring
8915859a5eSAlexander Aring dev_warn(&dev->dev,
9015859a5eSAlexander Aring "Using DEBUGing ioctl SIOCSIFADDR isn't recommended!\n");
9115859a5eSAlexander Aring if (sa->family != AF_IEEE802154 ||
9215859a5eSAlexander Aring sa->addr.addr_type != IEEE802154_ADDR_SHORT ||
9315859a5eSAlexander Aring sa->addr.pan_id == IEEE802154_PANID_BROADCAST ||
9415859a5eSAlexander Aring sa->addr.short_addr == IEEE802154_ADDR_BROADCAST ||
9515859a5eSAlexander Aring sa->addr.short_addr == IEEE802154_ADDR_UNDEF) {
9615859a5eSAlexander Aring err = -EINVAL;
9715859a5eSAlexander Aring break;
9815859a5eSAlexander Aring }
9915859a5eSAlexander Aring
100863e88f2SAlexander Aring wpan_dev->pan_id = cpu_to_le16(sa->addr.pan_id);
101863e88f2SAlexander Aring wpan_dev->short_addr = cpu_to_le16(sa->addr.short_addr);
10215859a5eSAlexander Aring
10315859a5eSAlexander Aring err = mac802154_wpan_update_llsec(dev);
10415859a5eSAlexander Aring break;
10515859a5eSAlexander Aring }
10615859a5eSAlexander Aring
1074a669f7dSAlexander Aring rtnl_unlock();
10815859a5eSAlexander Aring return err;
10915859a5eSAlexander Aring }
11015859a5eSAlexander Aring
mac802154_wpan_mac_addr(struct net_device * dev,void * p)11115859a5eSAlexander Aring static int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
11215859a5eSAlexander Aring {
113776e59deSAlexander Aring struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
11415859a5eSAlexander Aring struct sockaddr *addr = p;
115ea7053c1SAlexander Aring __le64 extended_addr;
11615859a5eSAlexander Aring
11715859a5eSAlexander Aring if (netif_running(dev))
11815859a5eSAlexander Aring return -EBUSY;
11915859a5eSAlexander Aring
12009095fdcSAlexander Aring /* lowpan need to be down for update
12109095fdcSAlexander Aring * SLAAC address after ifup
12209095fdcSAlexander Aring */
12309095fdcSAlexander Aring if (sdata->wpan_dev.lowpan_dev) {
12409095fdcSAlexander Aring if (netif_running(sdata->wpan_dev.lowpan_dev))
12509095fdcSAlexander Aring return -EBUSY;
12609095fdcSAlexander Aring }
12709095fdcSAlexander Aring
128705cbbbeSAlexander Aring ieee802154_be64_to_le64(&extended_addr, addr->sa_data);
129daf4e2c8SLennert Buytenhek if (!ieee802154_is_valid_extended_unicast_addr(extended_addr))
130ea7053c1SAlexander Aring return -EINVAL;
131ea7053c1SAlexander Aring
132659f4e02SJakub Kicinski dev_addr_set(dev, addr->sa_data);
133863e88f2SAlexander Aring sdata->wpan_dev.extended_addr = extended_addr;
134776e59deSAlexander Aring
13509095fdcSAlexander Aring /* update lowpan interface mac address when
13609095fdcSAlexander Aring * wpan mac has been changed
13709095fdcSAlexander Aring */
13809095fdcSAlexander Aring if (sdata->wpan_dev.lowpan_dev)
13908bb7516SJakub Kicinski dev_addr_set(sdata->wpan_dev.lowpan_dev, dev->dev_addr);
14009095fdcSAlexander Aring
14115859a5eSAlexander Aring return mac802154_wpan_update_llsec(dev);
14215859a5eSAlexander Aring }
14315859a5eSAlexander Aring
ieee802154_setup_hw(struct ieee802154_sub_if_data * sdata)14495c0aa15SAlexander Aring static int ieee802154_setup_hw(struct ieee802154_sub_if_data *sdata)
14595c0aa15SAlexander Aring {
14695c0aa15SAlexander Aring struct ieee802154_local *local = sdata->local;
14795c0aa15SAlexander Aring struct wpan_dev *wpan_dev = &sdata->wpan_dev;
14895c0aa15SAlexander Aring int ret;
14995c0aa15SAlexander Aring
150ac8037c3SAlexander Aring sdata->required_filtering = sdata->iface_default_filtering;
15195c0aa15SAlexander Aring
15295c0aa15SAlexander Aring if (local->hw.flags & IEEE802154_HW_AFILT) {
153ac8037c3SAlexander Aring local->addr_filt.pan_id = wpan_dev->pan_id;
154ac8037c3SAlexander Aring local->addr_filt.ieee_addr = wpan_dev->extended_addr;
155ac8037c3SAlexander Aring local->addr_filt.short_addr = wpan_dev->short_addr;
15695c0aa15SAlexander Aring }
15795c0aa15SAlexander Aring
15895c0aa15SAlexander Aring if (local->hw.flags & IEEE802154_HW_LBT) {
15995c0aa15SAlexander Aring ret = drv_set_lbt_mode(local, wpan_dev->lbt);
16095c0aa15SAlexander Aring if (ret < 0)
16195c0aa15SAlexander Aring return ret;
16295c0aa15SAlexander Aring }
16395c0aa15SAlexander Aring
16495c0aa15SAlexander Aring if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) {
16595c0aa15SAlexander Aring ret = drv_set_csma_params(local, wpan_dev->min_be,
16695c0aa15SAlexander Aring wpan_dev->max_be,
16795c0aa15SAlexander Aring wpan_dev->csma_retries);
16895c0aa15SAlexander Aring if (ret < 0)
16995c0aa15SAlexander Aring return ret;
17095c0aa15SAlexander Aring }
17195c0aa15SAlexander Aring
17295c0aa15SAlexander Aring if (local->hw.flags & IEEE802154_HW_FRAME_RETRIES) {
17395c0aa15SAlexander Aring ret = drv_set_max_frame_retries(local, wpan_dev->frame_retries);
17495c0aa15SAlexander Aring if (ret < 0)
17595c0aa15SAlexander Aring return ret;
17695c0aa15SAlexander Aring }
17795c0aa15SAlexander Aring
17895c0aa15SAlexander Aring return 0;
17995c0aa15SAlexander Aring }
18095c0aa15SAlexander Aring
mac802154_slave_open(struct net_device * dev)18119ec690aSAlexander Aring static int mac802154_slave_open(struct net_device *dev)
18219ec690aSAlexander Aring {
18319ec690aSAlexander Aring struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
18419ec690aSAlexander Aring struct ieee802154_local *local = sdata->local;
1855c698e8bSAlexander Aring int res;
18619ec690aSAlexander Aring
18719ec690aSAlexander Aring ASSERT_RTNL();
18819ec690aSAlexander Aring
1890ea3da64SAlexander Aring set_bit(SDATA_STATE_RUNNING, &sdata->state);
19019ec690aSAlexander Aring
19174457641SAlexander Aring if (!local->open_count) {
19295c0aa15SAlexander Aring res = ieee802154_setup_hw(sdata);
19395c0aa15SAlexander Aring if (res)
19495c0aa15SAlexander Aring goto err;
19595c0aa15SAlexander Aring
196ac8037c3SAlexander Aring res = drv_start(local, sdata->required_filtering,
197ac8037c3SAlexander Aring &local->addr_filt);
19819ec690aSAlexander Aring if (res)
19919ec690aSAlexander Aring goto err;
20019ec690aSAlexander Aring }
20119ec690aSAlexander Aring
20274457641SAlexander Aring local->open_count++;
20319ec690aSAlexander Aring netif_start_queue(dev);
20419ec690aSAlexander Aring return 0;
20519ec690aSAlexander Aring err:
2060ea3da64SAlexander Aring /* might already be clear but that doesn't matter */
2070ea3da64SAlexander Aring clear_bit(SDATA_STATE_RUNNING, &sdata->state);
20819ec690aSAlexander Aring
20919ec690aSAlexander Aring return res;
21019ec690aSAlexander Aring }
21119ec690aSAlexander Aring
212bd37a78dSAlexander Aring static int
ieee802154_check_mac_settings(struct ieee802154_local * local,struct ieee802154_sub_if_data * sdata,struct ieee802154_sub_if_data * nsdata)213bd37a78dSAlexander Aring ieee802154_check_mac_settings(struct ieee802154_local *local,
214ac8037c3SAlexander Aring struct ieee802154_sub_if_data *sdata,
215ac8037c3SAlexander Aring struct ieee802154_sub_if_data *nsdata)
216bd37a78dSAlexander Aring {
217ac8037c3SAlexander Aring struct wpan_dev *nwpan_dev = &nsdata->wpan_dev;
218ac8037c3SAlexander Aring struct wpan_dev *wpan_dev = &sdata->wpan_dev;
219ac8037c3SAlexander Aring
220bd37a78dSAlexander Aring ASSERT_RTNL();
221bd37a78dSAlexander Aring
222ac8037c3SAlexander Aring if (sdata->iface_default_filtering != nsdata->iface_default_filtering)
223bd37a78dSAlexander Aring return -EBUSY;
224bd37a78dSAlexander Aring
225bd37a78dSAlexander Aring if (local->hw.flags & IEEE802154_HW_AFILT) {
2268bf9538aSAlexander Aring if (wpan_dev->pan_id != nwpan_dev->pan_id ||
2278bf9538aSAlexander Aring wpan_dev->short_addr != nwpan_dev->short_addr ||
2288bf9538aSAlexander Aring wpan_dev->extended_addr != nwpan_dev->extended_addr)
229bd37a78dSAlexander Aring return -EBUSY;
230bd37a78dSAlexander Aring }
231bd37a78dSAlexander Aring
232bd37a78dSAlexander Aring if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) {
2338bf9538aSAlexander Aring if (wpan_dev->min_be != nwpan_dev->min_be ||
2348bf9538aSAlexander Aring wpan_dev->max_be != nwpan_dev->max_be ||
2358bf9538aSAlexander Aring wpan_dev->csma_retries != nwpan_dev->csma_retries)
236bd37a78dSAlexander Aring return -EBUSY;
237bd37a78dSAlexander Aring }
238bd37a78dSAlexander Aring
239bd37a78dSAlexander Aring if (local->hw.flags & IEEE802154_HW_FRAME_RETRIES) {
240bd37a78dSAlexander Aring if (wpan_dev->frame_retries != nwpan_dev->frame_retries)
241bd37a78dSAlexander Aring return -EBUSY;
242bd37a78dSAlexander Aring }
243bd37a78dSAlexander Aring
244bd37a78dSAlexander Aring if (local->hw.flags & IEEE802154_HW_LBT) {
245bd37a78dSAlexander Aring if (wpan_dev->lbt != nwpan_dev->lbt)
246bd37a78dSAlexander Aring return -EBUSY;
247bd37a78dSAlexander Aring }
248bd37a78dSAlexander Aring
249bd37a78dSAlexander Aring return 0;
250bd37a78dSAlexander Aring }
251bd37a78dSAlexander Aring
252bd37a78dSAlexander Aring static int
ieee802154_check_concurrent_iface(struct ieee802154_sub_if_data * sdata,enum nl802154_iftype iftype)253bd37a78dSAlexander Aring ieee802154_check_concurrent_iface(struct ieee802154_sub_if_data *sdata,
254bd37a78dSAlexander Aring enum nl802154_iftype iftype)
255bd37a78dSAlexander Aring {
256bd37a78dSAlexander Aring struct ieee802154_local *local = sdata->local;
257bd37a78dSAlexander Aring struct ieee802154_sub_if_data *nsdata;
258bd37a78dSAlexander Aring
259bd37a78dSAlexander Aring /* we hold the RTNL here so can safely walk the list */
260bd37a78dSAlexander Aring list_for_each_entry(nsdata, &local->interfaces, list) {
261bd37a78dSAlexander Aring if (nsdata != sdata && ieee802154_sdata_running(nsdata)) {
262bd37a78dSAlexander Aring int ret;
263bd37a78dSAlexander Aring
2642622e785SMiquel Raynal /* TODO currently we don't support multiple node/coord
2652622e785SMiquel Raynal * types we need to run skb_clone at rx path. Check if
2662622e785SMiquel Raynal * there exist really an use case if we need to support
2672622e785SMiquel Raynal * multiple node/coord types at the same time.
268cd1c5665SAlexander Aring */
2692622e785SMiquel Raynal if (sdata->wpan_dev.iftype != NL802154_IFTYPE_MONITOR &&
2702622e785SMiquel Raynal nsdata->wpan_dev.iftype != NL802154_IFTYPE_MONITOR)
271cd1c5665SAlexander Aring return -EBUSY;
272cd1c5665SAlexander Aring
273bd37a78dSAlexander Aring /* check all phy mac sublayer settings are the same.
274bd37a78dSAlexander Aring * We have only one phy, different values makes trouble.
275bd37a78dSAlexander Aring */
276ac8037c3SAlexander Aring ret = ieee802154_check_mac_settings(local, sdata, nsdata);
277bd37a78dSAlexander Aring if (ret < 0)
278bd37a78dSAlexander Aring return ret;
279bd37a78dSAlexander Aring }
280bd37a78dSAlexander Aring }
281bd37a78dSAlexander Aring
282bd37a78dSAlexander Aring return 0;
283bd37a78dSAlexander Aring }
284bd37a78dSAlexander Aring
mac802154_wpan_open(struct net_device * dev)28515859a5eSAlexander Aring static int mac802154_wpan_open(struct net_device *dev)
28615859a5eSAlexander Aring {
28715859a5eSAlexander Aring int rc;
28859d19cd7SAlexander Aring struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
289863e88f2SAlexander Aring struct wpan_dev *wpan_dev = &sdata->wpan_dev;
29015859a5eSAlexander Aring
291ed65963bSAlexander Aring rc = ieee802154_check_concurrent_iface(sdata, wpan_dev->iftype);
292bd37a78dSAlexander Aring if (rc < 0)
293bd37a78dSAlexander Aring return rc;
294bd37a78dSAlexander Aring
29595c0aa15SAlexander Aring return mac802154_slave_open(dev);
29615859a5eSAlexander Aring }
29715859a5eSAlexander Aring
mac802154_slave_close(struct net_device * dev)29819ec690aSAlexander Aring static int mac802154_slave_close(struct net_device *dev)
29919ec690aSAlexander Aring {
30019ec690aSAlexander Aring struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
30119ec690aSAlexander Aring struct ieee802154_local *local = sdata->local;
30219ec690aSAlexander Aring
30319ec690aSAlexander Aring ASSERT_RTNL();
30419ec690aSAlexander Aring
30557588c71SMiquel Raynal if (mac802154_is_scanning(local))
30657588c71SMiquel Raynal mac802154_abort_scan_locked(local, sdata);
30757588c71SMiquel Raynal
3083accf476SMiquel Raynal if (mac802154_is_beaconing(local))
3093accf476SMiquel Raynal mac802154_stop_beacons_locked(local, sdata);
3103accf476SMiquel Raynal
31119ec690aSAlexander Aring netif_stop_queue(dev);
31274457641SAlexander Aring local->open_count--;
31319ec690aSAlexander Aring
3140ea3da64SAlexander Aring clear_bit(SDATA_STATE_RUNNING, &sdata->state);
31519ec690aSAlexander Aring
316c4227c8aSAlexander Aring if (!local->open_count)
317c4227c8aSAlexander Aring ieee802154_stop_device(local);
31819ec690aSAlexander Aring
31919ec690aSAlexander Aring return 0;
32019ec690aSAlexander Aring }
32119ec690aSAlexander Aring
mac802154_set_header_security(struct ieee802154_sub_if_data * sdata,struct ieee802154_hdr * hdr,const struct ieee802154_mac_cb * cb)322036562f9SAlexander Aring static int mac802154_set_header_security(struct ieee802154_sub_if_data *sdata,
32315859a5eSAlexander Aring struct ieee802154_hdr *hdr,
32415859a5eSAlexander Aring const struct ieee802154_mac_cb *cb)
32515859a5eSAlexander Aring {
32615859a5eSAlexander Aring struct ieee802154_llsec_params params;
32715859a5eSAlexander Aring u8 level;
32815859a5eSAlexander Aring
329036562f9SAlexander Aring mac802154_llsec_get_params(&sdata->sec, ¶ms);
33015859a5eSAlexander Aring
33115859a5eSAlexander Aring if (!params.enabled && cb->secen_override && cb->secen)
33215859a5eSAlexander Aring return -EINVAL;
33315859a5eSAlexander Aring if (!params.enabled ||
33415859a5eSAlexander Aring (cb->secen_override && !cb->secen) ||
33515859a5eSAlexander Aring !params.out_level)
33615859a5eSAlexander Aring return 0;
33715859a5eSAlexander Aring if (cb->seclevel_override && !cb->seclevel)
33815859a5eSAlexander Aring return -EINVAL;
33915859a5eSAlexander Aring
34015859a5eSAlexander Aring level = cb->seclevel_override ? cb->seclevel : params.out_level;
34115859a5eSAlexander Aring
34215859a5eSAlexander Aring hdr->fc.security_enabled = 1;
34315859a5eSAlexander Aring hdr->sec.level = level;
34415859a5eSAlexander Aring hdr->sec.key_id_mode = params.out_key.mode;
34515859a5eSAlexander Aring if (params.out_key.mode == IEEE802154_SCF_KEY_SHORT_INDEX)
34615859a5eSAlexander Aring hdr->sec.short_src = params.out_key.short_source;
34715859a5eSAlexander Aring else if (params.out_key.mode == IEEE802154_SCF_KEY_HW_INDEX)
34815859a5eSAlexander Aring hdr->sec.extended_src = params.out_key.extended_source;
34915859a5eSAlexander Aring hdr->sec.key_id = params.out_key.id;
35015859a5eSAlexander Aring
35115859a5eSAlexander Aring return 0;
35215859a5eSAlexander Aring }
35315859a5eSAlexander Aring
ieee802154_header_create(struct sk_buff * skb,struct net_device * dev,const struct ieee802154_addr * daddr,const struct ieee802154_addr * saddr,unsigned len)354838b83d6SAlexander Aring static int ieee802154_header_create(struct sk_buff *skb,
35515859a5eSAlexander Aring struct net_device *dev,
356838b83d6SAlexander Aring const struct ieee802154_addr *daddr,
357838b83d6SAlexander Aring const struct ieee802154_addr *saddr,
35815859a5eSAlexander Aring unsigned len)
35915859a5eSAlexander Aring {
36015859a5eSAlexander Aring struct ieee802154_hdr hdr;
36159d19cd7SAlexander Aring struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
362863e88f2SAlexander Aring struct wpan_dev *wpan_dev = &sdata->wpan_dev;
36315859a5eSAlexander Aring struct ieee802154_mac_cb *cb = mac_cb(skb);
36415859a5eSAlexander Aring int hlen;
36515859a5eSAlexander Aring
36615859a5eSAlexander Aring if (!daddr)
36715859a5eSAlexander Aring return -EINVAL;
36815859a5eSAlexander Aring
36915859a5eSAlexander Aring memset(&hdr.fc, 0, sizeof(hdr.fc));
37015859a5eSAlexander Aring hdr.fc.type = cb->type;
37115859a5eSAlexander Aring hdr.fc.security_enabled = cb->secen;
37215859a5eSAlexander Aring hdr.fc.ack_request = cb->ackreq;
373344f8c11SAlexander Aring hdr.seq = atomic_inc_return(&dev->ieee802154_ptr->dsn) & 0xFF;
37415859a5eSAlexander Aring
375036562f9SAlexander Aring if (mac802154_set_header_security(sdata, &hdr, cb) < 0)
37615859a5eSAlexander Aring return -EINVAL;
37715859a5eSAlexander Aring
37815859a5eSAlexander Aring if (!saddr) {
379863e88f2SAlexander Aring if (wpan_dev->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) ||
380863e88f2SAlexander Aring wpan_dev->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
381863e88f2SAlexander Aring wpan_dev->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
38215859a5eSAlexander Aring hdr.source.mode = IEEE802154_ADDR_LONG;
383863e88f2SAlexander Aring hdr.source.extended_addr = wpan_dev->extended_addr;
38415859a5eSAlexander Aring } else {
38515859a5eSAlexander Aring hdr.source.mode = IEEE802154_ADDR_SHORT;
386863e88f2SAlexander Aring hdr.source.short_addr = wpan_dev->short_addr;
38715859a5eSAlexander Aring }
38815859a5eSAlexander Aring
389863e88f2SAlexander Aring hdr.source.pan_id = wpan_dev->pan_id;
39015859a5eSAlexander Aring } else {
39115859a5eSAlexander Aring hdr.source = *(const struct ieee802154_addr *)saddr;
39215859a5eSAlexander Aring }
39315859a5eSAlexander Aring
39415859a5eSAlexander Aring hdr.dest = *(const struct ieee802154_addr *)daddr;
39515859a5eSAlexander Aring
39615859a5eSAlexander Aring hlen = ieee802154_hdr_push(skb, &hdr);
39715859a5eSAlexander Aring if (hlen < 0)
39815859a5eSAlexander Aring return -EINVAL;
39915859a5eSAlexander Aring
40015859a5eSAlexander Aring skb_reset_mac_header(skb);
40115859a5eSAlexander Aring skb->mac_len = hlen;
40215859a5eSAlexander Aring
40315859a5eSAlexander Aring if (len > ieee802154_max_payload(&hdr))
40415859a5eSAlexander Aring return -EMSGSIZE;
40515859a5eSAlexander Aring
40615859a5eSAlexander Aring return hlen;
40715859a5eSAlexander Aring }
40815859a5eSAlexander Aring
409838b83d6SAlexander Aring static const struct wpan_dev_header_ops ieee802154_header_ops = {
410838b83d6SAlexander Aring .create = ieee802154_header_create,
411838b83d6SAlexander Aring };
412838b83d6SAlexander Aring
413838b83d6SAlexander Aring /* This header create functionality assumes a 8 byte array for
414838b83d6SAlexander Aring * source and destination pointer at maximum. To adapt this for
415838b83d6SAlexander Aring * the 802.15.4 dataframe header we use extended address handling
416838b83d6SAlexander Aring * here only and intra pan connection. fc fields are mostly fallback
417838b83d6SAlexander Aring * handling. For provide dev_hard_header for dgram sockets.
418838b83d6SAlexander Aring */
mac802154_header_create(struct sk_buff * skb,struct net_device * dev,unsigned short type,const void * daddr,const void * saddr,unsigned len)419838b83d6SAlexander Aring static int mac802154_header_create(struct sk_buff *skb,
420838b83d6SAlexander Aring struct net_device *dev,
421838b83d6SAlexander Aring unsigned short type,
422838b83d6SAlexander Aring const void *daddr,
423838b83d6SAlexander Aring const void *saddr,
424838b83d6SAlexander Aring unsigned len)
425838b83d6SAlexander Aring {
426838b83d6SAlexander Aring struct ieee802154_hdr hdr;
427838b83d6SAlexander Aring struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
428838b83d6SAlexander Aring struct wpan_dev *wpan_dev = &sdata->wpan_dev;
429838b83d6SAlexander Aring struct ieee802154_mac_cb cb = { };
430838b83d6SAlexander Aring int hlen;
431838b83d6SAlexander Aring
432838b83d6SAlexander Aring if (!daddr)
433838b83d6SAlexander Aring return -EINVAL;
434838b83d6SAlexander Aring
435838b83d6SAlexander Aring memset(&hdr.fc, 0, sizeof(hdr.fc));
436838b83d6SAlexander Aring hdr.fc.type = IEEE802154_FC_TYPE_DATA;
437838b83d6SAlexander Aring hdr.fc.ack_request = wpan_dev->ackreq;
438838b83d6SAlexander Aring hdr.seq = atomic_inc_return(&dev->ieee802154_ptr->dsn) & 0xFF;
439838b83d6SAlexander Aring
440838b83d6SAlexander Aring /* TODO currently a workaround to give zero cb block to set
441838b83d6SAlexander Aring * security parameters defaults according MIB.
442838b83d6SAlexander Aring */
443838b83d6SAlexander Aring if (mac802154_set_header_security(sdata, &hdr, &cb) < 0)
444838b83d6SAlexander Aring return -EINVAL;
445838b83d6SAlexander Aring
446838b83d6SAlexander Aring hdr.dest.pan_id = wpan_dev->pan_id;
447838b83d6SAlexander Aring hdr.dest.mode = IEEE802154_ADDR_LONG;
448c2d5ecfaSAlexander Aring ieee802154_be64_to_le64(&hdr.dest.extended_addr, daddr);
449838b83d6SAlexander Aring
450838b83d6SAlexander Aring hdr.source.pan_id = hdr.dest.pan_id;
451838b83d6SAlexander Aring hdr.source.mode = IEEE802154_ADDR_LONG;
452838b83d6SAlexander Aring
453838b83d6SAlexander Aring if (!saddr)
454838b83d6SAlexander Aring hdr.source.extended_addr = wpan_dev->extended_addr;
455838b83d6SAlexander Aring else
456c2d5ecfaSAlexander Aring ieee802154_be64_to_le64(&hdr.source.extended_addr, saddr);
457838b83d6SAlexander Aring
458838b83d6SAlexander Aring hlen = ieee802154_hdr_push(skb, &hdr);
459838b83d6SAlexander Aring if (hlen < 0)
460838b83d6SAlexander Aring return -EINVAL;
461838b83d6SAlexander Aring
462838b83d6SAlexander Aring skb_reset_mac_header(skb);
463838b83d6SAlexander Aring skb->mac_len = hlen;
464838b83d6SAlexander Aring
465838b83d6SAlexander Aring if (len > ieee802154_max_payload(&hdr))
466838b83d6SAlexander Aring return -EMSGSIZE;
467838b83d6SAlexander Aring
468838b83d6SAlexander Aring return hlen;
469838b83d6SAlexander Aring }
470838b83d6SAlexander Aring
47115859a5eSAlexander Aring static int
mac802154_header_parse(const struct sk_buff * skb,unsigned char * haddr)47215859a5eSAlexander Aring mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
47315859a5eSAlexander Aring {
47415859a5eSAlexander Aring struct ieee802154_hdr hdr;
47515859a5eSAlexander Aring
47615859a5eSAlexander Aring if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) {
47715859a5eSAlexander Aring pr_debug("malformed packet\n");
47815859a5eSAlexander Aring return 0;
47915859a5eSAlexander Aring }
48015859a5eSAlexander Aring
481838b83d6SAlexander Aring if (hdr.source.mode == IEEE802154_ADDR_LONG) {
482c2d5ecfaSAlexander Aring ieee802154_le64_to_be64(haddr, &hdr.source.extended_addr);
483838b83d6SAlexander Aring return IEEE802154_EXTENDED_ADDR_LEN;
48415859a5eSAlexander Aring }
48515859a5eSAlexander Aring
486838b83d6SAlexander Aring return 0;
487838b83d6SAlexander Aring }
488838b83d6SAlexander Aring
489838b83d6SAlexander Aring static const struct header_ops mac802154_header_ops = {
49015859a5eSAlexander Aring .create = mac802154_header_create,
49115859a5eSAlexander Aring .parse = mac802154_header_parse,
49215859a5eSAlexander Aring };
49315859a5eSAlexander Aring
49415859a5eSAlexander Aring static const struct net_device_ops mac802154_wpan_ops = {
49515859a5eSAlexander Aring .ndo_open = mac802154_wpan_open,
49615859a5eSAlexander Aring .ndo_stop = mac802154_slave_close,
497e5e584fcSAlexander Aring .ndo_start_xmit = ieee802154_subif_start_xmit,
49815859a5eSAlexander Aring .ndo_do_ioctl = mac802154_wpan_ioctl,
49915859a5eSAlexander Aring .ndo_set_mac_address = mac802154_wpan_mac_addr,
50015859a5eSAlexander Aring };
50115859a5eSAlexander Aring
502b9ff77e5SAlexander Aring static const struct net_device_ops mac802154_monitor_ops = {
50338130c31SAlexander Aring .ndo_open = mac802154_wpan_open,
504b9ff77e5SAlexander Aring .ndo_stop = mac802154_slave_close,
505b9ff77e5SAlexander Aring .ndo_start_xmit = ieee802154_monitor_start_xmit,
506b9ff77e5SAlexander Aring };
507b9ff77e5SAlexander Aring
mac802154_wpan_free(struct net_device * dev)50815859a5eSAlexander Aring static void mac802154_wpan_free(struct net_device *dev)
50915859a5eSAlexander Aring {
51059d19cd7SAlexander Aring struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
51115859a5eSAlexander Aring
512036562f9SAlexander Aring mac802154_llsec_destroy(&sdata->sec);
51315859a5eSAlexander Aring }
51415859a5eSAlexander Aring
ieee802154_if_setup(struct net_device * dev)515d5ae67baSAlexander Aring static void ieee802154_if_setup(struct net_device *dev)
51615859a5eSAlexander Aring {
517e57a8946SAlexander Aring dev->addr_len = IEEE802154_EXTENDED_ADDR_LEN;
518e57a8946SAlexander Aring memset(dev->broadcast, 0xff, IEEE802154_EXTENDED_ADDR_LEN);
51915859a5eSAlexander Aring
52087a93e4eSAlexander Aring /* Let hard_header_len set to IEEE802154_MIN_HEADER_LEN. AF_PACKET
52187a93e4eSAlexander Aring * will not send frames without any payload, but ack frames
52287a93e4eSAlexander Aring * has no payload, so substract one that we can send a 3 bytes
52387a93e4eSAlexander Aring * frame. The xmit callback assumes at least a hard header where two
52487a93e4eSAlexander Aring * bytes fc and sequence field are set.
52587a93e4eSAlexander Aring */
52687a93e4eSAlexander Aring dev->hard_header_len = IEEE802154_MIN_HEADER_LEN - 1;
52787a93e4eSAlexander Aring /* The auth_tag header is for security and places in private payload
52887a93e4eSAlexander Aring * room of mac frame which stucks between payload and FCS field.
52987a93e4eSAlexander Aring */
53087a93e4eSAlexander Aring dev->needed_tailroom = IEEE802154_MAX_AUTH_TAG_LEN +
53187a93e4eSAlexander Aring IEEE802154_FCS_LEN;
532b40988c4SAlexander Aring /* The mtu size is the payload without mac header in this case.
533b40988c4SAlexander Aring * We have a dynamic length header with a minimum header length
534b40988c4SAlexander Aring * which is hard_header_len. In this case we let mtu to the size
535b40988c4SAlexander Aring * of maximum payload which is IEEE802154_MTU - IEEE802154_FCS_LEN -
536b40988c4SAlexander Aring * hard_header_len. The FCS which is set by hardware or ndo_start_xmit
537b40988c4SAlexander Aring * and the minimum mac header which can be evaluated inside driver
538b40988c4SAlexander Aring * layer. The rest of mac header will be part of payload if greater
539b40988c4SAlexander Aring * than hard_header_len.
540b40988c4SAlexander Aring */
541b40988c4SAlexander Aring dev->mtu = IEEE802154_MTU - IEEE802154_FCS_LEN -
542b40988c4SAlexander Aring dev->hard_header_len;
54315859a5eSAlexander Aring dev->tx_queue_len = 300;
54415859a5eSAlexander Aring dev->flags = IFF_NOARP | IFF_BROADCAST;
545d5ae67baSAlexander Aring }
54615859a5eSAlexander Aring
547d5ae67baSAlexander Aring static int
ieee802154_setup_sdata(struct ieee802154_sub_if_data * sdata,enum nl802154_iftype type)548944742a3SAlexander Aring ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata,
549944742a3SAlexander Aring enum nl802154_iftype type)
550d5ae67baSAlexander Aring {
551863e88f2SAlexander Aring struct wpan_dev *wpan_dev = &sdata->wpan_dev;
552d77b4852SAlexander Aring int ret;
553344f8c11SAlexander Aring u8 tmp;
554863e88f2SAlexander Aring
555d5ae67baSAlexander Aring /* set some type-dependent values */
556190ac1caSAlexander Aring sdata->wpan_dev.iftype = type;
55715859a5eSAlexander Aring
558344f8c11SAlexander Aring get_random_bytes(&tmp, sizeof(tmp));
559344f8c11SAlexander Aring atomic_set(&wpan_dev->bsn, tmp);
560344f8c11SAlexander Aring get_random_bytes(&tmp, sizeof(tmp));
561344f8c11SAlexander Aring atomic_set(&wpan_dev->dsn, tmp);
56215859a5eSAlexander Aring
56315859a5eSAlexander Aring /* defaults per 802.15.4-2011 */
5645fb3f026SAlexander Aring wpan_dev->min_be = 3;
5655fb3f026SAlexander Aring wpan_dev->max_be = 5;
5665fb3f026SAlexander Aring wpan_dev->csma_retries = 4;
56789c7d788SAlexander Aring wpan_dev->frame_retries = 3;
56815859a5eSAlexander Aring
569863e88f2SAlexander Aring wpan_dev->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
570863e88f2SAlexander Aring wpan_dev->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
57115859a5eSAlexander Aring
572d5ae67baSAlexander Aring switch (type) {
5732622e785SMiquel Raynal case NL802154_IFTYPE_COORD:
574944742a3SAlexander Aring case NL802154_IFTYPE_NODE:
575b03c9cccSAlexander Aring ieee802154_be64_to_le64(&wpan_dev->extended_addr,
576b03c9cccSAlexander Aring sdata->dev->dev_addr);
577b03c9cccSAlexander Aring
578d5ae67baSAlexander Aring sdata->dev->header_ops = &mac802154_header_ops;
579cf124db5SDavid S. Miller sdata->dev->needs_free_netdev = true;
580cf124db5SDavid S. Miller sdata->dev->priv_destructor = mac802154_wpan_free;
581d5ae67baSAlexander Aring sdata->dev->netdev_ops = &mac802154_wpan_ops;
582d5ae67baSAlexander Aring sdata->dev->ml_priv = &mac802154_mlme_wpan;
583ac8037c3SAlexander Aring sdata->iface_default_filtering = IEEE802154_FILTERING_4_FRAME_FIELDS;
584838b83d6SAlexander Aring wpan_dev->header_ops = &ieee802154_header_ops;
58538130c31SAlexander Aring
586d5ae67baSAlexander Aring mutex_init(&sdata->sec_mtx);
587d5ae67baSAlexander Aring
588036562f9SAlexander Aring mac802154_llsec_init(&sdata->sec);
589d77b4852SAlexander Aring ret = mac802154_wpan_update_llsec(sdata->dev);
590d77b4852SAlexander Aring if (ret < 0)
591d77b4852SAlexander Aring return ret;
592d77b4852SAlexander Aring
593d5ae67baSAlexander Aring break;
594944742a3SAlexander Aring case NL802154_IFTYPE_MONITOR:
595cf124db5SDavid S. Miller sdata->dev->needs_free_netdev = true;
596d5ae67baSAlexander Aring sdata->dev->netdev_ops = &mac802154_monitor_ops;
597ac8037c3SAlexander Aring sdata->iface_default_filtering = IEEE802154_FILTERING_NONE;
598d5ae67baSAlexander Aring break;
599d5ae67baSAlexander Aring default:
600d5ae67baSAlexander Aring BUG();
601b9ff77e5SAlexander Aring }
602b210b187SAlexander Aring
603986a8abfSAlexander Aring return 0;
604986a8abfSAlexander Aring }
605986a8abfSAlexander Aring
606986a8abfSAlexander Aring struct net_device *
ieee802154_if_add(struct ieee802154_local * local,const char * name,unsigned char name_assign_type,enum nl802154_iftype type,__le64 extended_addr)607986a8abfSAlexander Aring ieee802154_if_add(struct ieee802154_local *local, const char *name,
6085b4a1039SVarka Bhadram unsigned char name_assign_type, enum nl802154_iftype type,
6095b4a1039SVarka Bhadram __le64 extended_addr)
610986a8abfSAlexander Aring {
61108bb7516SJakub Kicinski u8 addr[IEEE802154_EXTENDED_ADDR_LEN];
612d5ae67baSAlexander Aring struct net_device *ndev = NULL;
613d5ae67baSAlexander Aring struct ieee802154_sub_if_data *sdata = NULL;
6140f77f2deSColin Ian King int ret;
615986a8abfSAlexander Aring
616d5ae67baSAlexander Aring ASSERT_RTNL();
617d5ae67baSAlexander Aring
618ed65963bSAlexander Aring ndev = alloc_netdev(sizeof(*sdata), name,
6195b4a1039SVarka Bhadram name_assign_type, ieee802154_if_setup);
620d5ae67baSAlexander Aring if (!ndev)
621d5ae67baSAlexander Aring return ERR_PTR(-ENOMEM);
622d5ae67baSAlexander Aring
62387a93e4eSAlexander Aring ndev->needed_headroom = local->hw.extra_tx_headroom +
62487a93e4eSAlexander Aring IEEE802154_MAX_HEADER_LEN;
625d5ae67baSAlexander Aring
626d5ae67baSAlexander Aring ret = dev_alloc_name(ndev, ndev->name);
627d5ae67baSAlexander Aring if (ret < 0)
628986a8abfSAlexander Aring goto err;
629986a8abfSAlexander Aring
6300e57547eSAlexander Aring ieee802154_le64_to_be64(ndev->perm_addr,
6310e57547eSAlexander Aring &local->hw.phy->perm_extended_addr);
632d5ae67baSAlexander Aring switch (type) {
6332622e785SMiquel Raynal case NL802154_IFTYPE_COORD:
634944742a3SAlexander Aring case NL802154_IFTYPE_NODE:
635d5ae67baSAlexander Aring ndev->type = ARPHRD_IEEE802154;
63608bb7516SJakub Kicinski if (ieee802154_is_valid_extended_unicast_addr(extended_addr)) {
63708bb7516SJakub Kicinski ieee802154_le64_to_be64(addr, &extended_addr);
63808bb7516SJakub Kicinski dev_addr_set(ndev, addr);
63908bb7516SJakub Kicinski } else {
64008bb7516SJakub Kicinski dev_addr_set(ndev, ndev->perm_addr);
64108bb7516SJakub Kicinski }
642d5ae67baSAlexander Aring break;
643944742a3SAlexander Aring case NL802154_IFTYPE_MONITOR:
644d5ae67baSAlexander Aring ndev->type = ARPHRD_IEEE802154_MONITOR;
645d5ae67baSAlexander Aring break;
646d5ae67baSAlexander Aring default:
647d5ae67baSAlexander Aring ret = -EINVAL;
648d5ae67baSAlexander Aring goto err;
649d5ae67baSAlexander Aring }
650986a8abfSAlexander Aring
651d5ae67baSAlexander Aring /* TODO check this */
652d5ae67baSAlexander Aring SET_NETDEV_DEV(ndev, &local->phy->dev);
653abbcc341SAlexander Aring dev_net_set(ndev, wpan_phy_net(local->hw.phy));
654d5ae67baSAlexander Aring sdata = netdev_priv(ndev);
655d5ae67baSAlexander Aring ndev->ieee802154_ptr = &sdata->wpan_dev;
656d5ae67baSAlexander Aring memcpy(sdata->name, ndev->name, IFNAMSIZ);
657d5ae67baSAlexander Aring sdata->dev = ndev;
658d5ae67baSAlexander Aring sdata->wpan_dev.wpan_phy = local->hw.phy;
659d5ae67baSAlexander Aring sdata->local = local;
660b3d72d31SWei Yongjun INIT_LIST_HEAD(&sdata->wpan_dev.list);
661986a8abfSAlexander Aring
662d5ae67baSAlexander Aring /* setup type-dependent data */
663d5ae67baSAlexander Aring ret = ieee802154_setup_sdata(sdata, type);
664d5ae67baSAlexander Aring if (ret)
665d5ae67baSAlexander Aring goto err;
666d5ae67baSAlexander Aring
667d5ae67baSAlexander Aring ret = register_netdevice(ndev);
668d5ae67baSAlexander Aring if (ret < 0)
669d5ae67baSAlexander Aring goto err;
670d5ae67baSAlexander Aring
671d5ae67baSAlexander Aring mutex_lock(&local->iflist_mtx);
672d5ae67baSAlexander Aring list_add_tail_rcu(&sdata->list, &local->interfaces);
673d5ae67baSAlexander Aring mutex_unlock(&local->iflist_mtx);
674d5ae67baSAlexander Aring
675d5ae67baSAlexander Aring return ndev;
676d5ae67baSAlexander Aring
677986a8abfSAlexander Aring err:
678d5ae67baSAlexander Aring free_netdev(ndev);
679d5ae67baSAlexander Aring return ERR_PTR(ret);
680986a8abfSAlexander Aring }
681986a8abfSAlexander Aring
ieee802154_if_remove(struct ieee802154_sub_if_data * sdata)682b210b187SAlexander Aring void ieee802154_if_remove(struct ieee802154_sub_if_data *sdata)
683b210b187SAlexander Aring {
684b210b187SAlexander Aring ASSERT_RTNL();
685b210b187SAlexander Aring
686b210b187SAlexander Aring mutex_lock(&sdata->local->iflist_mtx);
687*2e41e98cSLizhi Xu if (list_empty(&sdata->local->interfaces)) {
688*2e41e98cSLizhi Xu mutex_unlock(&sdata->local->iflist_mtx);
689*2e41e98cSLizhi Xu return;
690*2e41e98cSLizhi Xu }
691b210b187SAlexander Aring list_del_rcu(&sdata->list);
692b210b187SAlexander Aring mutex_unlock(&sdata->local->iflist_mtx);
693b210b187SAlexander Aring
694b210b187SAlexander Aring synchronize_rcu();
695b210b187SAlexander Aring unregister_netdevice(sdata->dev);
696b210b187SAlexander Aring }
697592dfbfcSAlexander Aring
ieee802154_remove_interfaces(struct ieee802154_local * local)698592dfbfcSAlexander Aring void ieee802154_remove_interfaces(struct ieee802154_local *local)
699592dfbfcSAlexander Aring {
700d14e1c71SAlexander Aring struct ieee802154_sub_if_data *sdata, *tmp;
701592dfbfcSAlexander Aring
7022789e629SAlexander Aring mutex_lock(&local->iflist_mtx);
703d14e1c71SAlexander Aring list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
704592dfbfcSAlexander Aring list_del(&sdata->list);
705592dfbfcSAlexander Aring
706592dfbfcSAlexander Aring unregister_netdevice(sdata->dev);
707592dfbfcSAlexander Aring }
7082789e629SAlexander Aring mutex_unlock(&local->iflist_mtx);
709592dfbfcSAlexander Aring }
710be4fd8e5SAlexander Aring
netdev_notify(struct notifier_block * nb,unsigned long state,void * ptr)711be4fd8e5SAlexander Aring static int netdev_notify(struct notifier_block *nb,
712be4fd8e5SAlexander Aring unsigned long state, void *ptr)
713be4fd8e5SAlexander Aring {
714be4fd8e5SAlexander Aring struct net_device *dev = netdev_notifier_info_to_dev(ptr);
715be4fd8e5SAlexander Aring struct ieee802154_sub_if_data *sdata;
716be4fd8e5SAlexander Aring
717be4fd8e5SAlexander Aring if (state != NETDEV_CHANGENAME)
718be4fd8e5SAlexander Aring return NOTIFY_DONE;
719be4fd8e5SAlexander Aring
720be4fd8e5SAlexander Aring if (!dev->ieee802154_ptr || !dev->ieee802154_ptr->wpan_phy)
721be4fd8e5SAlexander Aring return NOTIFY_DONE;
722be4fd8e5SAlexander Aring
723be4fd8e5SAlexander Aring if (dev->ieee802154_ptr->wpan_phy->privid != mac802154_wpan_phy_privid)
724be4fd8e5SAlexander Aring return NOTIFY_DONE;
725be4fd8e5SAlexander Aring
726be4fd8e5SAlexander Aring sdata = IEEE802154_DEV_TO_SUB_IF(dev);
727be4fd8e5SAlexander Aring memcpy(sdata->name, dev->name, IFNAMSIZ);
728be4fd8e5SAlexander Aring
729be4fd8e5SAlexander Aring return NOTIFY_OK;
730be4fd8e5SAlexander Aring }
731be4fd8e5SAlexander Aring
732be4fd8e5SAlexander Aring static struct notifier_block mac802154_netdev_notifier = {
733be4fd8e5SAlexander Aring .notifier_call = netdev_notify,
734be4fd8e5SAlexander Aring };
735be4fd8e5SAlexander Aring
ieee802154_iface_init(void)736be4fd8e5SAlexander Aring int ieee802154_iface_init(void)
737be4fd8e5SAlexander Aring {
738be4fd8e5SAlexander Aring return register_netdevice_notifier(&mac802154_netdev_notifier);
739be4fd8e5SAlexander Aring }
740be4fd8e5SAlexander Aring
ieee802154_iface_exit(void)741be4fd8e5SAlexander Aring void ieee802154_iface_exit(void)
742be4fd8e5SAlexander Aring {
743be4fd8e5SAlexander Aring unregister_netdevice_notifier(&mac802154_netdev_notifier);
744be4fd8e5SAlexander Aring }
745