xref: /openbmc/linux/net/mac802154/iface.c (revision aad29a73199b7fbccfbabea3f1ee627ad1924f52)
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, &params, 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, &params);
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