xref: /openbmc/linux/net/mac802154/main.c (revision ee1cd5048959de496cd005c50b137212a5b62062)
11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
262eb01f5SAlexander Aring /*
362eb01f5SAlexander Aring  * Copyright (C) 2007-2012 Siemens AG
462eb01f5SAlexander Aring  *
562eb01f5SAlexander Aring  * Written by:
662eb01f5SAlexander Aring  * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
762eb01f5SAlexander Aring  */
862eb01f5SAlexander Aring 
962eb01f5SAlexander Aring #include <linux/kernel.h>
1062eb01f5SAlexander Aring #include <linux/module.h>
1162eb01f5SAlexander Aring #include <linux/netdevice.h>
1262eb01f5SAlexander Aring 
1362eb01f5SAlexander Aring #include <net/netlink.h>
14944742a3SAlexander Aring #include <net/nl802154.h>
1562eb01f5SAlexander Aring #include <net/mac802154.h>
1662eb01f5SAlexander Aring #include <net/ieee802154_netdev.h>
1762eb01f5SAlexander Aring #include <net/route.h>
185ad60d36SAlexander Aring #include <net/cfg802154.h>
1962eb01f5SAlexander Aring 
200f1556bcSAlexander Aring #include "ieee802154_i.h"
211201cd22SAlexander Aring #include "cfg.h"
2262eb01f5SAlexander Aring 
ieee802154_tasklet_handler(struct tasklet_struct * t)23b5bd8b62SAllen Pais static void ieee802154_tasklet_handler(struct tasklet_struct *t)
24c5c47e67SAlexander Aring {
25b5bd8b62SAllen Pais 	struct ieee802154_local *local = from_tasklet(local, t, tasklet);
26c5c47e67SAlexander Aring 	struct sk_buff *skb;
27c5c47e67SAlexander Aring 
28c5c47e67SAlexander Aring 	while ((skb = skb_dequeue(&local->skb_queue))) {
29c5c47e67SAlexander Aring 		switch (skb->pkt_type) {
30c5c47e67SAlexander Aring 		case IEEE802154_RX_MSG:
31c5c47e67SAlexander Aring 			/* Clear skb->pkt_type in order to not confuse kernel
32c5c47e67SAlexander Aring 			 * netstack.
33c5c47e67SAlexander Aring 			 */
34c5c47e67SAlexander Aring 			skb->pkt_type = 0;
35d10270ceSVarka Bhadram 			ieee802154_rx(local, skb);
36c5c47e67SAlexander Aring 			break;
37c5c47e67SAlexander Aring 		default:
38c5c47e67SAlexander Aring 			WARN(1, "mac802154: Packet is of unknown type %d\n",
39c5c47e67SAlexander Aring 			     skb->pkt_type);
40c5c47e67SAlexander Aring 			kfree_skb(skb);
41c5c47e67SAlexander Aring 			break;
42c5c47e67SAlexander Aring 		}
43c5c47e67SAlexander Aring 	}
44c5c47e67SAlexander Aring }
45c5c47e67SAlexander Aring 
465a504397SAlexander Aring struct ieee802154_hw *
ieee802154_alloc_hw(size_t priv_data_len,const struct ieee802154_ops * ops)4716301861SAlexander Aring ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
4862eb01f5SAlexander Aring {
4962eb01f5SAlexander Aring 	struct wpan_phy *phy;
50a5e1ec53SAlexander Aring 	struct ieee802154_local *local;
5162eb01f5SAlexander Aring 	size_t priv_size;
5262eb01f5SAlexander Aring 
538f451829SVarka Bhadram 	if (WARN_ON(!ops || !(ops->xmit_async || ops->xmit_sync) || !ops->ed ||
548f451829SVarka Bhadram 		    !ops->start || !ops->stop || !ops->set_channel))
5562eb01f5SAlexander Aring 		return NULL;
5662eb01f5SAlexander Aring 
5762eb01f5SAlexander Aring 	/* Ensure 32-byte alignment of our private data and hw private data.
58a5e1ec53SAlexander Aring 	 * We use the wpan_phy priv data for both our ieee802154_local and for
5962eb01f5SAlexander Aring 	 * the driver's private data
6062eb01f5SAlexander Aring 	 *
6162eb01f5SAlexander Aring 	 * in memory it'll be like this:
6262eb01f5SAlexander Aring 	 *
63a5e1ec53SAlexander Aring 	 * +-------------------------+
6462eb01f5SAlexander Aring 	 * | struct wpan_phy         |
65a5e1ec53SAlexander Aring 	 * +-------------------------+
66a5e1ec53SAlexander Aring 	 * | struct ieee802154_local |
67a5e1ec53SAlexander Aring 	 * +-------------------------+
6862eb01f5SAlexander Aring 	 * | driver's private data   |
69a5e1ec53SAlexander Aring 	 * +-------------------------+
7062eb01f5SAlexander Aring 	 *
7162eb01f5SAlexander Aring 	 * Due to ieee802154 layer isn't aware of driver and MAC structures,
7262eb01f5SAlexander Aring 	 * so lets align them here.
7362eb01f5SAlexander Aring 	 */
7462eb01f5SAlexander Aring 
75a5e1ec53SAlexander Aring 	priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len;
7662eb01f5SAlexander Aring 
77f601379fSAlexander Aring 	phy = wpan_phy_new(&mac802154_config_ops, priv_size);
7862eb01f5SAlexander Aring 	if (!phy) {
7962eb01f5SAlexander Aring 		pr_err("failure to allocate master IEEE802.15.4 device\n");
8062eb01f5SAlexander Aring 		return NULL;
8162eb01f5SAlexander Aring 	}
8262eb01f5SAlexander Aring 
836322d50dSAlexander Aring 	phy->privid = mac802154_wpan_phy_privid;
846322d50dSAlexander Aring 
85a5e1ec53SAlexander Aring 	local = wpan_phy_priv(phy);
86a5e1ec53SAlexander Aring 	local->phy = phy;
87a5e1ec53SAlexander Aring 	local->hw.phy = local->phy;
88a5e1ec53SAlexander Aring 	local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);
89a5e1ec53SAlexander Aring 	local->ops = ops;
9062eb01f5SAlexander Aring 
91d98be45bSAlexander Aring 	INIT_LIST_HEAD(&local->interfaces);
9257588c71SMiquel Raynal 	INIT_LIST_HEAD(&local->rx_beacon_list);
93d021d218SMiquel Raynal 	INIT_LIST_HEAD(&local->rx_mac_cmd_list);
94d98be45bSAlexander Aring 	mutex_init(&local->iflist_mtx);
9562eb01f5SAlexander Aring 
96b5bd8b62SAllen Pais 	tasklet_setup(&local->tasklet, ieee802154_tasklet_handler);
97c5c47e67SAlexander Aring 
98c5c47e67SAlexander Aring 	skb_queue_head_init(&local->skb_queue);
99c5c47e67SAlexander Aring 
100983a974bSMiquel Raynal 	INIT_WORK(&local->sync_tx_work, ieee802154_xmit_sync_worker);
10157588c71SMiquel Raynal 	INIT_DELAYED_WORK(&local->scan_work, mac802154_scan_worker);
10257588c71SMiquel Raynal 	INIT_WORK(&local->rx_beacon_work, mac802154_rx_beacon_worker);
1033accf476SMiquel Raynal 	INIT_DELAYED_WORK(&local->beacon_work, mac802154_beacon_worker);
104d021d218SMiquel Raynal 	INIT_WORK(&local->rx_mac_cmd_work, mac802154_rx_mac_cmd_worker);
105c22ff7b4SLennert Buytenhek 
106fea3318dSAlexander Aring 	/* init supported flags with 802.15.4 default ranges */
107fea3318dSAlexander Aring 	phy->supported.max_minbe = 8;
108fea3318dSAlexander Aring 	phy->supported.min_maxbe = 3;
109fea3318dSAlexander Aring 	phy->supported.max_maxbe = 8;
11089c7d788SAlexander Aring 	phy->supported.min_frame_retries = 0;
111fea3318dSAlexander Aring 	phy->supported.max_frame_retries = 7;
112fea3318dSAlexander Aring 	phy->supported.max_csma_backoffs = 5;
113fea3318dSAlexander Aring 	phy->supported.lbt = NL802154_SUPPORTED_BOOL_FALSE;
114fea3318dSAlexander Aring 
11565318680SAlexander Aring 	/* always supported */
1162622e785SMiquel Raynal 	phy->supported.iftypes = BIT(NL802154_IFTYPE_NODE) | BIT(NL802154_IFTYPE_COORD);
11765318680SAlexander Aring 
118a5e1ec53SAlexander Aring 	return &local->hw;
11962eb01f5SAlexander Aring }
1205a504397SAlexander Aring EXPORT_SYMBOL(ieee802154_alloc_hw);
12162eb01f5SAlexander Aring 
ieee802154_configure_durations(struct wpan_phy * phy,unsigned int page,unsigned int channel)1225755cd4dSMiquel Raynal void ieee802154_configure_durations(struct wpan_phy *phy,
1235755cd4dSMiquel Raynal 				    unsigned int page, unsigned int channel)
124781830c8SMiquel Raynal {
125781830c8SMiquel Raynal 	u32 duration = 0;
126781830c8SMiquel Raynal 
1275755cd4dSMiquel Raynal 	switch (page) {
128781830c8SMiquel Raynal 	case 0:
1295755cd4dSMiquel Raynal 		if (BIT(channel) & 0x1)
130781830c8SMiquel Raynal 			/* 868 MHz BPSK 802.15.4-2003: 20 ksym/s */
131781830c8SMiquel Raynal 			duration = 50 * NSEC_PER_USEC;
1325755cd4dSMiquel Raynal 		else if (BIT(channel) & 0x7FE)
133781830c8SMiquel Raynal 			/* 915 MHz BPSK	802.15.4-2003: 40 ksym/s */
134781830c8SMiquel Raynal 			duration = 25 * NSEC_PER_USEC;
1355755cd4dSMiquel Raynal 		else if (BIT(channel) & 0x7FFF800)
136781830c8SMiquel Raynal 			/* 2400 MHz O-QPSK 802.15.4-2006: 62.5 ksym/s */
137781830c8SMiquel Raynal 			duration = 16 * NSEC_PER_USEC;
138781830c8SMiquel Raynal 		break;
139781830c8SMiquel Raynal 	case 2:
1405755cd4dSMiquel Raynal 		if (BIT(channel) & 0x1)
141781830c8SMiquel Raynal 			/* 868 MHz O-QPSK 802.15.4-2006: 25 ksym/s */
142781830c8SMiquel Raynal 			duration = 40 * NSEC_PER_USEC;
1435755cd4dSMiquel Raynal 		else if (BIT(channel) & 0x7FE)
144781830c8SMiquel Raynal 			/* 915 MHz O-QPSK 802.15.4-2006: 62.5 ksym/s */
145781830c8SMiquel Raynal 			duration = 16 * NSEC_PER_USEC;
146781830c8SMiquel Raynal 		break;
147781830c8SMiquel Raynal 	case 3:
1485755cd4dSMiquel Raynal 		if (BIT(channel) & 0x3FFF)
149781830c8SMiquel Raynal 			/* 2.4 GHz CSS 802.15.4a-2007: 1/6 Msym/s */
150781830c8SMiquel Raynal 			duration = 6 * NSEC_PER_USEC;
151781830c8SMiquel Raynal 		break;
152781830c8SMiquel Raynal 	default:
153781830c8SMiquel Raynal 		break;
154781830c8SMiquel Raynal 	}
155781830c8SMiquel Raynal 
156781830c8SMiquel Raynal 	if (!duration) {
157781830c8SMiquel Raynal 		pr_debug("Unknown PHY symbol duration\n");
158781830c8SMiquel Raynal 		return;
159781830c8SMiquel Raynal 	}
160781830c8SMiquel Raynal 
161781830c8SMiquel Raynal 	phy->symbol_duration = duration;
162*61707579SDmitry Antipov 	phy->lifs_period =
163*61707579SDmitry Antipov 		(IEEE802154_LIFS_PERIOD * phy->symbol_duration) / NSEC_PER_USEC;
164*61707579SDmitry Antipov 	phy->sifs_period =
165*61707579SDmitry Antipov 		(IEEE802154_SIFS_PERIOD * phy->symbol_duration) / NSEC_PER_USEC;
166781830c8SMiquel Raynal }
167781830c8SMiquel Raynal EXPORT_SYMBOL(ieee802154_configure_durations);
168781830c8SMiquel Raynal 
ieee802154_free_hw(struct ieee802154_hw * hw)1695a504397SAlexander Aring void ieee802154_free_hw(struct ieee802154_hw *hw)
17062eb01f5SAlexander Aring {
17160741361SAlexander Aring 	struct ieee802154_local *local = hw_to_local(hw);
17262eb01f5SAlexander Aring 
173d98be45bSAlexander Aring 	BUG_ON(!list_empty(&local->interfaces));
17462eb01f5SAlexander Aring 
175d98be45bSAlexander Aring 	mutex_destroy(&local->iflist_mtx);
17662eb01f5SAlexander Aring 
177a5e1ec53SAlexander Aring 	wpan_phy_free(local->phy);
17862eb01f5SAlexander Aring }
1795a504397SAlexander Aring EXPORT_SYMBOL(ieee802154_free_hw);
18062eb01f5SAlexander Aring 
ieee802154_setup_wpan_phy_pib(struct wpan_phy * wpan_phy)18161f2dcbaSAlexander Aring static void ieee802154_setup_wpan_phy_pib(struct wpan_phy *wpan_phy)
18261f2dcbaSAlexander Aring {
18361f2dcbaSAlexander Aring 	/* TODO warn on empty symbol_duration
18461f2dcbaSAlexander Aring 	 * Should be done when all drivers sets this value.
18561f2dcbaSAlexander Aring 	 */
18661f2dcbaSAlexander Aring 
187*61707579SDmitry Antipov 	wpan_phy->lifs_period =	(IEEE802154_LIFS_PERIOD *
188*61707579SDmitry Antipov 				 wpan_phy->symbol_duration) / NSEC_PER_USEC;
189*61707579SDmitry Antipov 	wpan_phy->sifs_period =	(IEEE802154_SIFS_PERIOD *
190*61707579SDmitry Antipov 				 wpan_phy->symbol_duration) / NSEC_PER_USEC;
19161f2dcbaSAlexander Aring }
19261f2dcbaSAlexander Aring 
ieee802154_register_hw(struct ieee802154_hw * hw)1935a504397SAlexander Aring int ieee802154_register_hw(struct ieee802154_hw *hw)
19462eb01f5SAlexander Aring {
19560741361SAlexander Aring 	struct ieee802154_local *local = hw_to_local(hw);
19657588c71SMiquel Raynal 	char mac_wq_name[IFNAMSIZ + 10] = {};
197e4962a14SAlexander Aring 	struct net_device *dev;
19862eb01f5SAlexander Aring 	int rc = -ENOSYS;
19962eb01f5SAlexander Aring 
200f7730542SAlexander Aring 	local->workqueue =
201a5e1ec53SAlexander Aring 		create_singlethread_workqueue(wpan_phy_name(local->phy));
202f7730542SAlexander Aring 	if (!local->workqueue) {
20362eb01f5SAlexander Aring 		rc = -ENOMEM;
20462eb01f5SAlexander Aring 		goto out;
20562eb01f5SAlexander Aring 	}
20662eb01f5SAlexander Aring 
20757588c71SMiquel Raynal 	snprintf(mac_wq_name, IFNAMSIZ + 10, "%s-mac-cmds", wpan_phy_name(local->phy));
20857588c71SMiquel Raynal 	local->mac_wq =	create_singlethread_workqueue(mac_wq_name);
20957588c71SMiquel Raynal 	if (!local->mac_wq) {
21057588c71SMiquel Raynal 		rc = -ENOMEM;
21157588c71SMiquel Raynal 		goto out_wq;
21257588c71SMiquel Raynal 	}
21357588c71SMiquel Raynal 
21461f2dcbaSAlexander Aring 	hrtimer_init(&local->ifs_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
21561f2dcbaSAlexander Aring 	local->ifs_timer.function = ieee802154_xmit_ifs_timer;
21661f2dcbaSAlexander Aring 
217a5e1ec53SAlexander Aring 	wpan_phy_set_dev(local->phy, local->hw.parent);
21862eb01f5SAlexander Aring 
21961f2dcbaSAlexander Aring 	ieee802154_setup_wpan_phy_pib(local->phy);
22061f2dcbaSAlexander Aring 
2215755cd4dSMiquel Raynal 	ieee802154_configure_durations(local->phy, local->phy->current_page,
2225755cd4dSMiquel Raynal 				       local->phy->current_channel);
223781830c8SMiquel Raynal 
224fea3318dSAlexander Aring 	if (!(hw->flags & IEEE802154_HW_CSMA_PARAMS)) {
225fea3318dSAlexander Aring 		local->phy->supported.min_csma_backoffs = 4;
226fea3318dSAlexander Aring 		local->phy->supported.max_csma_backoffs = 4;
227fea3318dSAlexander Aring 		local->phy->supported.min_maxbe = 5;
228fea3318dSAlexander Aring 		local->phy->supported.max_maxbe = 5;
229fea3318dSAlexander Aring 		local->phy->supported.min_minbe = 3;
230fea3318dSAlexander Aring 		local->phy->supported.max_minbe = 3;
231fea3318dSAlexander Aring 	}
232fea3318dSAlexander Aring 
233fea3318dSAlexander Aring 	if (!(hw->flags & IEEE802154_HW_FRAME_RETRIES)) {
23489c7d788SAlexander Aring 		local->phy->supported.min_frame_retries = 3;
23589c7d788SAlexander Aring 		local->phy->supported.max_frame_retries = 3;
236fea3318dSAlexander Aring 	}
237fea3318dSAlexander Aring 
23865318680SAlexander Aring 	if (hw->flags & IEEE802154_HW_PROMISCUOUS)
23965318680SAlexander Aring 		local->phy->supported.iftypes |= BIT(NL802154_IFTYPE_MONITOR);
24065318680SAlexander Aring 
241a5e1ec53SAlexander Aring 	rc = wpan_phy_register(local->phy);
24262eb01f5SAlexander Aring 	if (rc < 0)
24357588c71SMiquel Raynal 		goto out_mac_wq;
24462eb01f5SAlexander Aring 
245e4962a14SAlexander Aring 	rtnl_lock();
246e4962a14SAlexander Aring 
2475b4a1039SVarka Bhadram 	dev = ieee802154_if_add(local, "wpan%d", NET_NAME_ENUM,
2485b4a1039SVarka Bhadram 				NL802154_IFTYPE_NODE,
2490e57547eSAlexander Aring 				cpu_to_le64(0x0000000000000000ULL));
250e4962a14SAlexander Aring 	if (IS_ERR(dev)) {
251e4962a14SAlexander Aring 		rtnl_unlock();
252e4962a14SAlexander Aring 		rc = PTR_ERR(dev);
2532b4d413cSAlexander Aring 		goto out_phy;
254e4962a14SAlexander Aring 	}
255e4962a14SAlexander Aring 
256e4962a14SAlexander Aring 	rtnl_unlock();
257e4962a14SAlexander Aring 
25862eb01f5SAlexander Aring 	return 0;
25962eb01f5SAlexander Aring 
2602b4d413cSAlexander Aring out_phy:
2612b4d413cSAlexander Aring 	wpan_phy_unregister(local->phy);
26257588c71SMiquel Raynal out_mac_wq:
26357588c71SMiquel Raynal 	destroy_workqueue(local->mac_wq);
26462eb01f5SAlexander Aring out_wq:
265f7730542SAlexander Aring 	destroy_workqueue(local->workqueue);
26662eb01f5SAlexander Aring out:
26762eb01f5SAlexander Aring 	return rc;
26862eb01f5SAlexander Aring }
2695a504397SAlexander Aring EXPORT_SYMBOL(ieee802154_register_hw);
27062eb01f5SAlexander Aring 
ieee802154_unregister_hw(struct ieee802154_hw * hw)2715a504397SAlexander Aring void ieee802154_unregister_hw(struct ieee802154_hw *hw)
27262eb01f5SAlexander Aring {
27360741361SAlexander Aring 	struct ieee802154_local *local = hw_to_local(hw);
27462eb01f5SAlexander Aring 
275c5c47e67SAlexander Aring 	tasklet_kill(&local->tasklet);
276f7730542SAlexander Aring 	flush_workqueue(local->workqueue);
27762eb01f5SAlexander Aring 
27862eb01f5SAlexander Aring 	rtnl_lock();
27962eb01f5SAlexander Aring 
280592dfbfcSAlexander Aring 	ieee802154_remove_interfaces(local);
28162eb01f5SAlexander Aring 
28262eb01f5SAlexander Aring 	rtnl_unlock();
28362eb01f5SAlexander Aring 
28457588c71SMiquel Raynal 	destroy_workqueue(local->mac_wq);
285aef00c15SKoen Zandberg 	destroy_workqueue(local->workqueue);
286a5e1ec53SAlexander Aring 	wpan_phy_unregister(local->phy);
28762eb01f5SAlexander Aring }
2885a504397SAlexander Aring EXPORT_SYMBOL(ieee802154_unregister_hw);
28962eb01f5SAlexander Aring 
ieee802154_init(void)290be4fd8e5SAlexander Aring static int __init ieee802154_init(void)
291be4fd8e5SAlexander Aring {
292be4fd8e5SAlexander Aring 	return ieee802154_iface_init();
293be4fd8e5SAlexander Aring }
294be4fd8e5SAlexander Aring 
ieee802154_exit(void)295be4fd8e5SAlexander Aring static void __exit ieee802154_exit(void)
296be4fd8e5SAlexander Aring {
297be4fd8e5SAlexander Aring 	ieee802154_iface_exit();
298be4fd8e5SAlexander Aring 
299be4fd8e5SAlexander Aring 	rcu_barrier();
300be4fd8e5SAlexander Aring }
301be4fd8e5SAlexander Aring 
302be4fd8e5SAlexander Aring subsys_initcall(ieee802154_init);
303be4fd8e5SAlexander Aring module_exit(ieee802154_exit);
304be4fd8e5SAlexander Aring 
305912f67aeSAlexander Aring MODULE_DESCRIPTION("IEEE 802.15.4 subsystem");
30662eb01f5SAlexander Aring MODULE_LICENSE("GPL v2");
307