Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1// SPDX-License-Identifier: GPL-2.0
  2/* drivers/net/wireless/virt_wifi.c
  3 *
  4 * A fake implementation of cfg80211_ops that can be tacked on to an ethernet
  5 * net_device to make it appear as a wireless connection.
  6 *
  7 * Copyright (C) 2018 Google, Inc.
  8 *
  9 * Author: schuffelen@google.com
 10 */
 11
 12#include <net/cfg80211.h>
 13#include <net/rtnetlink.h>
 14#include <linux/etherdevice.h>
 15#include <linux/module.h>
 16
 17static struct wiphy *common_wiphy;
 18
 19struct virt_wifi_wiphy_priv {
 20	struct delayed_work scan_result;
 21	struct cfg80211_scan_request *scan_request;
 22	bool being_deleted;
 23};
 24
 25static struct ieee80211_channel channel_2ghz = {
 26	.band = NL80211_BAND_2GHZ,
 27	.center_freq = 2432,
 28	.hw_value = 2432,
 29	.max_power = 20,
 30};
 31
 32static struct ieee80211_rate bitrates_2ghz[] = {
 33	{ .bitrate = 10 },
 34	{ .bitrate = 20 },
 35	{ .bitrate = 55 },
 36	{ .bitrate = 110 },
 37	{ .bitrate = 60 },
 38	{ .bitrate = 120 },
 39	{ .bitrate = 240 },
 40};
 41
 42static struct ieee80211_supported_band band_2ghz = {
 43	.channels = &channel_2ghz,
 44	.bitrates = bitrates_2ghz,
 45	.band = NL80211_BAND_2GHZ,
 46	.n_channels = 1,
 47	.n_bitrates = ARRAY_SIZE(bitrates_2ghz),
 48	.ht_cap = {
 49		.ht_supported = true,
 50		.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
 51		       IEEE80211_HT_CAP_GRN_FLD |
 52		       IEEE80211_HT_CAP_SGI_20 |
 53		       IEEE80211_HT_CAP_SGI_40 |
 54		       IEEE80211_HT_CAP_DSSSCCK40,
 55		.ampdu_factor = 0x3,
 56		.ampdu_density = 0x6,
 57		.mcs = {
 58			.rx_mask = {0xff, 0xff},
 59			.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
 60		},
 61	},
 62};
 63
 64static struct ieee80211_channel channel_5ghz = {
 65	.band = NL80211_BAND_5GHZ,
 66	.center_freq = 5240,
 67	.hw_value = 5240,
 68	.max_power = 20,
 69};
 70
 71static struct ieee80211_rate bitrates_5ghz[] = {
 72	{ .bitrate = 60 },
 73	{ .bitrate = 120 },
 74	{ .bitrate = 240 },
 75};
 76
 77#define RX_MCS_MAP (IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | \
 78		    IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 | \
 79		    IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 | \
 80		    IEEE80211_VHT_MCS_SUPPORT_0_9 << 6 | \
 81		    IEEE80211_VHT_MCS_SUPPORT_0_9 << 8 | \
 82		    IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 | \
 83		    IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 | \
 84		    IEEE80211_VHT_MCS_SUPPORT_0_9 << 14)
 85
 86#define TX_MCS_MAP (IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | \
 87		    IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 | \
 88		    IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 | \
 89		    IEEE80211_VHT_MCS_SUPPORT_0_9 << 6 | \
 90		    IEEE80211_VHT_MCS_SUPPORT_0_9 << 8 | \
 91		    IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 | \
 92		    IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 | \
 93		    IEEE80211_VHT_MCS_SUPPORT_0_9 << 14)
 94
 95static struct ieee80211_supported_band band_5ghz = {
 96	.channels = &channel_5ghz,
 97	.bitrates = bitrates_5ghz,
 98	.band = NL80211_BAND_5GHZ,
 99	.n_channels = 1,
100	.n_bitrates = ARRAY_SIZE(bitrates_5ghz),
101	.ht_cap = {
102		.ht_supported = true,
103		.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
104		       IEEE80211_HT_CAP_GRN_FLD |
105		       IEEE80211_HT_CAP_SGI_20 |
106		       IEEE80211_HT_CAP_SGI_40 |
107		       IEEE80211_HT_CAP_DSSSCCK40,
108		.ampdu_factor = 0x3,
109		.ampdu_density = 0x6,
110		.mcs = {
111			.rx_mask = {0xff, 0xff},
112			.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
113		},
114	},
115	.vht_cap = {
116		.vht_supported = true,
117		.cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
118		       IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
119		       IEEE80211_VHT_CAP_RXLDPC |
120		       IEEE80211_VHT_CAP_SHORT_GI_80 |
121		       IEEE80211_VHT_CAP_SHORT_GI_160 |
122		       IEEE80211_VHT_CAP_TXSTBC |
123		       IEEE80211_VHT_CAP_RXSTBC_1 |
124		       IEEE80211_VHT_CAP_RXSTBC_2 |
125		       IEEE80211_VHT_CAP_RXSTBC_3 |
126		       IEEE80211_VHT_CAP_RXSTBC_4 |
127		       IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK,
128		.vht_mcs = {
129			.rx_mcs_map = cpu_to_le16(RX_MCS_MAP),
130			.tx_mcs_map = cpu_to_le16(TX_MCS_MAP),
131		}
132	},
133};
134
135/* Assigned at module init. Guaranteed locally-administered and unicast. */
136static u8 fake_router_bssid[ETH_ALEN] __ro_after_init = {};
137
138/* Called with the rtnl lock held. */
139static int virt_wifi_scan(struct wiphy *wiphy,
140			  struct cfg80211_scan_request *request)
141{
142	struct virt_wifi_wiphy_priv *priv = wiphy_priv(wiphy);
143
144	wiphy_debug(wiphy, "scan\n");
145
146	if (priv->scan_request || priv->being_deleted)
147		return -EBUSY;
148
149	priv->scan_request = request;
150	schedule_delayed_work(&priv->scan_result, HZ * 2);
151
152	return 0;
153}
154
155/* Acquires and releases the rdev BSS lock. */
156static void virt_wifi_scan_result(struct work_struct *work)
157{
158	struct {
159		u8 tag;
160		u8 len;
161		u8 ssid[8];
162	} __packed ssid = {
163		.tag = WLAN_EID_SSID, .len = 8, .ssid = "VirtWifi",
164	};
165	struct cfg80211_bss *informed_bss;
166	struct virt_wifi_wiphy_priv *priv =
167		container_of(work, struct virt_wifi_wiphy_priv,
168			     scan_result.work);
169	struct wiphy *wiphy = priv_to_wiphy(priv);
170	struct cfg80211_scan_info scan_info = { .aborted = false };
171
172	informed_bss = cfg80211_inform_bss(wiphy, &channel_5ghz,
173					   CFG80211_BSS_FTYPE_PRESP,
174					   fake_router_bssid,
175					   ktime_get_boottime_ns(),
176					   WLAN_CAPABILITY_ESS, 0,
177					   (void *)&ssid, sizeof(ssid),
178					   DBM_TO_MBM(-50), GFP_KERNEL);
179	cfg80211_put_bss(wiphy, informed_bss);
180
181	/* Schedules work which acquires and releases the rtnl lock. */
182	cfg80211_scan_done(priv->scan_request, &scan_info);
183	priv->scan_request = NULL;
184}
185
186/* May acquire and release the rdev BSS lock. */
187static void virt_wifi_cancel_scan(struct wiphy *wiphy)
188{
189	struct virt_wifi_wiphy_priv *priv = wiphy_priv(wiphy);
190
191	cancel_delayed_work_sync(&priv->scan_result);
192	/* Clean up dangling callbacks if necessary. */
193	if (priv->scan_request) {
194		struct cfg80211_scan_info scan_info = { .aborted = true };
195		/* Schedules work which acquires and releases the rtnl lock. */
196		cfg80211_scan_done(priv->scan_request, &scan_info);
197		priv->scan_request = NULL;
198	}
199}
200
201struct virt_wifi_netdev_priv {
202	struct delayed_work connect;
203	struct net_device *lowerdev;
204	struct net_device *upperdev;
205	u32 tx_packets;
206	u32 tx_failed;
207	u8 connect_requested_bss[ETH_ALEN];
208	bool is_up;
209	bool is_connected;
210	bool being_deleted;
211};
212
213/* Called with the rtnl lock held. */
214static int virt_wifi_connect(struct wiphy *wiphy, struct net_device *netdev,
215			     struct cfg80211_connect_params *sme)
216{
217	struct virt_wifi_netdev_priv *priv = netdev_priv(netdev);
218	bool could_schedule;
219
220	if (priv->being_deleted || !priv->is_up)
221		return -EBUSY;
222
223	could_schedule = schedule_delayed_work(&priv->connect, HZ * 2);
224	if (!could_schedule)
225		return -EBUSY;
226
227	if (sme->bssid)
228		ether_addr_copy(priv->connect_requested_bss, sme->bssid);
229	else
230		eth_zero_addr(priv->connect_requested_bss);
231
232	wiphy_debug(wiphy, "connect\n");
233
234	return 0;
235}
236
237/* Acquires and releases the rdev event lock. */
238static void virt_wifi_connect_complete(struct work_struct *work)
239{
240	struct virt_wifi_netdev_priv *priv =
241		container_of(work, struct virt_wifi_netdev_priv, connect.work);
242	u8 *requested_bss = priv->connect_requested_bss;
243	bool has_addr = !is_zero_ether_addr(requested_bss);
244	bool right_addr = ether_addr_equal(requested_bss, fake_router_bssid);
245	u16 status = WLAN_STATUS_SUCCESS;
246
247	if (!priv->is_up || (has_addr && !right_addr))
248		status = WLAN_STATUS_UNSPECIFIED_FAILURE;
249	else
250		priv->is_connected = true;
251
252	/* Schedules an event that acquires the rtnl lock. */
253	cfg80211_connect_result(priv->upperdev, requested_bss, NULL, 0, NULL, 0,
254				status, GFP_KERNEL);
255	netif_carrier_on(priv->upperdev);
256}
257
258/* May acquire and release the rdev event lock. */
259static void virt_wifi_cancel_connect(struct net_device *netdev)
260{
261	struct virt_wifi_netdev_priv *priv = netdev_priv(netdev);
262
263	/* If there is work pending, clean up dangling callbacks. */
264	if (cancel_delayed_work_sync(&priv->connect)) {
265		/* Schedules an event that acquires the rtnl lock. */
266		cfg80211_connect_result(priv->upperdev,
267					priv->connect_requested_bss, NULL, 0,
268					NULL, 0,
269					WLAN_STATUS_UNSPECIFIED_FAILURE,
270					GFP_KERNEL);
271	}
272}
273
274/* Called with the rtnl lock held. Acquires the rdev event lock. */
275static int virt_wifi_disconnect(struct wiphy *wiphy, struct net_device *netdev,
276				u16 reason_code)
277{
278	struct virt_wifi_netdev_priv *priv = netdev_priv(netdev);
279
280	if (priv->being_deleted)
281		return -EBUSY;
282
283	wiphy_debug(wiphy, "disconnect\n");
284	virt_wifi_cancel_connect(netdev);
285
286	cfg80211_disconnected(netdev, reason_code, NULL, 0, true, GFP_KERNEL);
287	priv->is_connected = false;
288	netif_carrier_off(netdev);
289
290	return 0;
291}
292
293/* Called with the rtnl lock held. */
294static int virt_wifi_get_station(struct wiphy *wiphy, struct net_device *dev,
295				 const u8 *mac, struct station_info *sinfo)
296{
297	struct virt_wifi_netdev_priv *priv = netdev_priv(dev);
298
299	wiphy_debug(wiphy, "get_station\n");
300
301	if (!priv->is_connected || !ether_addr_equal(mac, fake_router_bssid))
302		return -ENOENT;
303
304	sinfo->filled = BIT_ULL(NL80211_STA_INFO_TX_PACKETS) |
305		BIT_ULL(NL80211_STA_INFO_TX_FAILED) |
306		BIT_ULL(NL80211_STA_INFO_SIGNAL) |
307		BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
308	sinfo->tx_packets = priv->tx_packets;
309	sinfo->tx_failed = priv->tx_failed;
310	/* For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_ */
311	sinfo->signal = -50;
312	sinfo->txrate = (struct rate_info) {
313		.legacy = 10, /* units are 100kbit/s */
314	};
315	return 0;
316}
317
318/* Called with the rtnl lock held. */
319static int virt_wifi_dump_station(struct wiphy *wiphy, struct net_device *dev,
320				  int idx, u8 *mac, struct station_info *sinfo)
321{
322	struct virt_wifi_netdev_priv *priv = netdev_priv(dev);
323
324	wiphy_debug(wiphy, "dump_station\n");
325
326	if (idx != 0 || !priv->is_connected)
327		return -ENOENT;
328
329	ether_addr_copy(mac, fake_router_bssid);
330	return virt_wifi_get_station(wiphy, dev, fake_router_bssid, sinfo);
331}
332
333static const struct cfg80211_ops virt_wifi_cfg80211_ops = {
334	.scan = virt_wifi_scan,
335
336	.connect = virt_wifi_connect,
337	.disconnect = virt_wifi_disconnect,
338
339	.get_station = virt_wifi_get_station,
340	.dump_station = virt_wifi_dump_station,
341};
342
343/* Acquires and releases the rtnl lock. */
344static struct wiphy *virt_wifi_make_wiphy(void)
345{
346	struct wiphy *wiphy;
347	struct virt_wifi_wiphy_priv *priv;
348	int err;
349
350	wiphy = wiphy_new(&virt_wifi_cfg80211_ops, sizeof(*priv));
351
352	if (!wiphy)
353		return NULL;
354
355	wiphy->max_scan_ssids = 4;
356	wiphy->max_scan_ie_len = 1000;
357	wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
358
359	wiphy->bands[NL80211_BAND_2GHZ] = &band_2ghz;
360	wiphy->bands[NL80211_BAND_5GHZ] = &band_5ghz;
361	wiphy->bands[NL80211_BAND_60GHZ] = NULL;
362
363	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
364
365	priv = wiphy_priv(wiphy);
366	priv->being_deleted = false;
367	priv->scan_request = NULL;
368	INIT_DELAYED_WORK(&priv->scan_result, virt_wifi_scan_result);
369
370	err = wiphy_register(wiphy);
371	if (err < 0) {
372		wiphy_free(wiphy);
373		return NULL;
374	}
375
376	return wiphy;
377}
378
379/* Acquires and releases the rtnl lock. */
380static void virt_wifi_destroy_wiphy(struct wiphy *wiphy)
381{
382	struct virt_wifi_wiphy_priv *priv;
383
384	WARN(!wiphy, "%s called with null wiphy", __func__);
385	if (!wiphy)
386		return;
387
388	priv = wiphy_priv(wiphy);
389	priv->being_deleted = true;
390	virt_wifi_cancel_scan(wiphy);
391
392	if (wiphy->registered)
393		wiphy_unregister(wiphy);
394	wiphy_free(wiphy);
395}
396
397/* Enters and exits a RCU-bh critical section. */
398static netdev_tx_t virt_wifi_start_xmit(struct sk_buff *skb,
399					struct net_device *dev)
400{
401	struct virt_wifi_netdev_priv *priv = netdev_priv(dev);
402
403	priv->tx_packets++;
404	if (!priv->is_connected) {
405		priv->tx_failed++;
406		return NET_XMIT_DROP;
407	}
408
409	skb->dev = priv->lowerdev;
410	return dev_queue_xmit(skb);
411}
412
413/* Called with rtnl lock held. */
414static int virt_wifi_net_device_open(struct net_device *dev)
415{
416	struct virt_wifi_netdev_priv *priv = netdev_priv(dev);
417
418	priv->is_up = true;
419	return 0;
420}
421
422/* Called with rtnl lock held. */
423static int virt_wifi_net_device_stop(struct net_device *dev)
424{
425	struct virt_wifi_netdev_priv *n_priv = netdev_priv(dev);
426
427	n_priv->is_up = false;
428
429	if (!dev->ieee80211_ptr)
430		return 0;
431
432	virt_wifi_cancel_scan(dev->ieee80211_ptr->wiphy);
433	virt_wifi_cancel_connect(dev);
434	netif_carrier_off(dev);
435
436	return 0;
437}
438
439static int virt_wifi_net_device_get_iflink(const struct net_device *dev)
440{
441	struct virt_wifi_netdev_priv *priv = netdev_priv(dev);
442
443	return priv->lowerdev->ifindex;
444}
445
446static const struct net_device_ops virt_wifi_ops = {
447	.ndo_start_xmit = virt_wifi_start_xmit,
448	.ndo_open	= virt_wifi_net_device_open,
449	.ndo_stop	= virt_wifi_net_device_stop,
450	.ndo_get_iflink = virt_wifi_net_device_get_iflink,
451};
452
453/* Invoked as part of rtnl lock release. */
454static void virt_wifi_net_device_destructor(struct net_device *dev)
455{
456	/* Delayed past dellink to allow nl80211 to react to the device being
457	 * deleted.
458	 */
459	kfree(dev->ieee80211_ptr);
460	dev->ieee80211_ptr = NULL;
461}
462
463/* No lock interaction. */
464static void virt_wifi_setup(struct net_device *dev)
465{
466	ether_setup(dev);
467	dev->netdev_ops = &virt_wifi_ops;
468	dev->needs_free_netdev  = true;
469}
470
471/* Called in a RCU read critical section from netif_receive_skb */
472static rx_handler_result_t virt_wifi_rx_handler(struct sk_buff **pskb)
473{
474	struct sk_buff *skb = *pskb;
475	struct virt_wifi_netdev_priv *priv =
476		rcu_dereference(skb->dev->rx_handler_data);
477
478	if (!priv->is_connected)
479		return RX_HANDLER_PASS;
480
481	/* GFP_ATOMIC because this is a packet interrupt handler. */
482	skb = skb_share_check(skb, GFP_ATOMIC);
483	if (!skb) {
484		dev_err(&priv->upperdev->dev, "can't skb_share_check\n");
485		return RX_HANDLER_CONSUMED;
486	}
487
488	*pskb = skb;
489	skb->dev = priv->upperdev;
490	skb->pkt_type = PACKET_HOST;
491	return RX_HANDLER_ANOTHER;
492}
493
494/* Called with rtnl lock held. */
495static int virt_wifi_newlink(struct net *src_net, struct net_device *dev,
496			     struct nlattr *tb[], struct nlattr *data[],
497			     struct netlink_ext_ack *extack)
498{
499	struct virt_wifi_netdev_priv *priv = netdev_priv(dev);
500	int err;
501
502	if (!tb[IFLA_LINK])
503		return -EINVAL;
504
505	netif_carrier_off(dev);
506
507	priv->upperdev = dev;
508	priv->lowerdev = __dev_get_by_index(src_net,
509					    nla_get_u32(tb[IFLA_LINK]));
510
511	if (!priv->lowerdev)
512		return -ENODEV;
513	if (!tb[IFLA_MTU])
514		dev->mtu = priv->lowerdev->mtu;
515	else if (dev->mtu > priv->lowerdev->mtu)
516		return -EINVAL;
517
518	err = netdev_rx_handler_register(priv->lowerdev, virt_wifi_rx_handler,
519					 priv);
520	if (err) {
521		dev_err(&priv->lowerdev->dev,
522			"can't netdev_rx_handler_register: %d\n", err);
523		return err;
524	}
525
526	eth_hw_addr_inherit(dev, priv->lowerdev);
527	netif_stacked_transfer_operstate(priv->lowerdev, dev);
528
529	SET_NETDEV_DEV(dev, &priv->lowerdev->dev);
530	dev->ieee80211_ptr = kzalloc(sizeof(*dev->ieee80211_ptr), GFP_KERNEL);
531
532	if (!dev->ieee80211_ptr) {
533		err = -ENOMEM;
534		goto remove_handler;
535	}
536
537	dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
538	dev->ieee80211_ptr->wiphy = common_wiphy;
539
540	err = register_netdevice(dev);
541	if (err) {
542		dev_err(&priv->lowerdev->dev, "can't register_netdevice: %d\n",
543			err);
544		goto free_wireless_dev;
545	}
546
547	err = netdev_upper_dev_link(priv->lowerdev, dev, extack);
548	if (err) {
549		dev_err(&priv->lowerdev->dev, "can't netdev_upper_dev_link: %d\n",
550			err);
551		goto unregister_netdev;
552	}
553
554	dev->priv_destructor = virt_wifi_net_device_destructor;
555	priv->being_deleted = false;
556	priv->is_connected = false;
557	priv->is_up = false;
558	INIT_DELAYED_WORK(&priv->connect, virt_wifi_connect_complete);
559	__module_get(THIS_MODULE);
560
561	return 0;
562unregister_netdev:
563	unregister_netdevice(dev);
564free_wireless_dev:
565	kfree(dev->ieee80211_ptr);
566	dev->ieee80211_ptr = NULL;
567remove_handler:
568	netdev_rx_handler_unregister(priv->lowerdev);
569
570	return err;
571}
572
573/* Called with rtnl lock held. */
574static void virt_wifi_dellink(struct net_device *dev,
575			      struct list_head *head)
576{
577	struct virt_wifi_netdev_priv *priv = netdev_priv(dev);
578
579	if (dev->ieee80211_ptr)
580		virt_wifi_cancel_scan(dev->ieee80211_ptr->wiphy);
581
582	priv->being_deleted = true;
583	virt_wifi_cancel_connect(dev);
584	netif_carrier_off(dev);
585
586	netdev_rx_handler_unregister(priv->lowerdev);
587	netdev_upper_dev_unlink(priv->lowerdev, dev);
588
589	unregister_netdevice_queue(dev, head);
590	module_put(THIS_MODULE);
591
592	/* Deleting the wiphy is handled in the module destructor. */
593}
594
595static struct rtnl_link_ops virt_wifi_link_ops = {
596	.kind		= "virt_wifi",
597	.setup		= virt_wifi_setup,
598	.newlink	= virt_wifi_newlink,
599	.dellink	= virt_wifi_dellink,
600	.priv_size	= sizeof(struct virt_wifi_netdev_priv),
601};
602
603static bool netif_is_virt_wifi_dev(const struct net_device *dev)
604{
605	return rcu_access_pointer(dev->rx_handler) == virt_wifi_rx_handler;
606}
607
608static int virt_wifi_event(struct notifier_block *this, unsigned long event,
609			   void *ptr)
610{
611	struct net_device *lower_dev = netdev_notifier_info_to_dev(ptr);
612	struct virt_wifi_netdev_priv *priv;
613	struct net_device *upper_dev;
614	LIST_HEAD(list_kill);
615
616	if (!netif_is_virt_wifi_dev(lower_dev))
617		return NOTIFY_DONE;
618
619	switch (event) {
620	case NETDEV_UNREGISTER:
621		priv = rtnl_dereference(lower_dev->rx_handler_data);
622		if (!priv)
623			return NOTIFY_DONE;
624
625		upper_dev = priv->upperdev;
626
627		upper_dev->rtnl_link_ops->dellink(upper_dev, &list_kill);
628		unregister_netdevice_many(&list_kill);
629		break;
630	}
631
632	return NOTIFY_DONE;
633}
634
635static struct notifier_block virt_wifi_notifier = {
636	.notifier_call = virt_wifi_event,
637};
638
639/* Acquires and releases the rtnl lock. */
640static int __init virt_wifi_init_module(void)
641{
642	int err;
643
644	/* Guaranteed to be locallly-administered and not multicast. */
645	eth_random_addr(fake_router_bssid);
646
647	err = register_netdevice_notifier(&virt_wifi_notifier);
648	if (err)
649		return err;
650
651	err = -ENOMEM;
652	common_wiphy = virt_wifi_make_wiphy();
653	if (!common_wiphy)
654		goto notifier;
655
656	err = rtnl_link_register(&virt_wifi_link_ops);
657	if (err)
658		goto destroy_wiphy;
659
660	return 0;
661
662destroy_wiphy:
663	virt_wifi_destroy_wiphy(common_wiphy);
664notifier:
665	unregister_netdevice_notifier(&virt_wifi_notifier);
666	return err;
667}
668
669/* Acquires and releases the rtnl lock. */
670static void __exit virt_wifi_cleanup_module(void)
671{
672	/* Will delete any devices that depend on the wiphy. */
673	rtnl_link_unregister(&virt_wifi_link_ops);
674	virt_wifi_destroy_wiphy(common_wiphy);
675	unregister_netdevice_notifier(&virt_wifi_notifier);
676}
677
678module_init(virt_wifi_init_module);
679module_exit(virt_wifi_cleanup_module);
680
681MODULE_LICENSE("GPL v2");
682MODULE_AUTHOR("Cody Schuffelen <schuffelen@google.com>");
683MODULE_DESCRIPTION("Driver for a wireless wrapper of ethernet devices");
684MODULE_ALIAS_RTNL_LINK("virt_wifi");