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 const struct net_device_ops virt_wifi_ops = {
440	.ndo_start_xmit = virt_wifi_start_xmit,
441	.ndo_open = virt_wifi_net_device_open,
442	.ndo_stop = virt_wifi_net_device_stop,
443};
444
445/* Invoked as part of rtnl lock release. */
446static void virt_wifi_net_device_destructor(struct net_device *dev)
447{
448	/* Delayed past dellink to allow nl80211 to react to the device being
449	 * deleted.
450	 */
451	kfree(dev->ieee80211_ptr);
452	dev->ieee80211_ptr = NULL;
453	free_netdev(dev);
454}
455
456/* No lock interaction. */
457static void virt_wifi_setup(struct net_device *dev)
458{
459	ether_setup(dev);
460	dev->netdev_ops = &virt_wifi_ops;
461	dev->priv_destructor = virt_wifi_net_device_destructor;
462}
463
464/* Called in a RCU read critical section from netif_receive_skb */
465static rx_handler_result_t virt_wifi_rx_handler(struct sk_buff **pskb)
466{
467	struct sk_buff *skb = *pskb;
468	struct virt_wifi_netdev_priv *priv =
469		rcu_dereference(skb->dev->rx_handler_data);
470
471	if (!priv->is_connected)
472		return RX_HANDLER_PASS;
473
474	/* GFP_ATOMIC because this is a packet interrupt handler. */
475	skb = skb_share_check(skb, GFP_ATOMIC);
476	if (!skb) {
477		dev_err(&priv->upperdev->dev, "can't skb_share_check\n");
478		return RX_HANDLER_CONSUMED;
479	}
480
481	*pskb = skb;
482	skb->dev = priv->upperdev;
483	skb->pkt_type = PACKET_HOST;
484	return RX_HANDLER_ANOTHER;
485}
486
487/* Called with rtnl lock held. */
488static int virt_wifi_newlink(struct net *src_net, struct net_device *dev,
489			     struct nlattr *tb[], struct nlattr *data[],
490			     struct netlink_ext_ack *extack)
491{
492	struct virt_wifi_netdev_priv *priv = netdev_priv(dev);
493	int err;
494
495	if (!tb[IFLA_LINK])
496		return -EINVAL;
497
498	netif_carrier_off(dev);
499
500	priv->upperdev = dev;
501	priv->lowerdev = __dev_get_by_index(src_net,
502					    nla_get_u32(tb[IFLA_LINK]));
503
504	if (!priv->lowerdev)
505		return -ENODEV;
506	if (!tb[IFLA_MTU])
507		dev->mtu = priv->lowerdev->mtu;
508	else if (dev->mtu > priv->lowerdev->mtu)
509		return -EINVAL;
510
511	err = netdev_rx_handler_register(priv->lowerdev, virt_wifi_rx_handler,
512					 priv);
513	if (err) {
514		dev_err(&priv->lowerdev->dev,
515			"can't netdev_rx_handler_register: %d\n", err);
516		return err;
517	}
518
519	eth_hw_addr_inherit(dev, priv->lowerdev);
520	netif_stacked_transfer_operstate(priv->lowerdev, dev);
521
522	SET_NETDEV_DEV(dev, &priv->lowerdev->dev);
523	dev->ieee80211_ptr = kzalloc(sizeof(*dev->ieee80211_ptr), GFP_KERNEL);
524
525	if (!dev->ieee80211_ptr) {
526		err = -ENOMEM;
527		goto remove_handler;
528	}
529
530	dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
531	dev->ieee80211_ptr->wiphy = common_wiphy;
532
533	err = register_netdevice(dev);
534	if (err) {
535		dev_err(&priv->lowerdev->dev, "can't register_netdevice: %d\n",
536			err);
537		goto free_wireless_dev;
538	}
539
540	err = netdev_upper_dev_link(priv->lowerdev, dev, extack);
541	if (err) {
542		dev_err(&priv->lowerdev->dev, "can't netdev_upper_dev_link: %d\n",
543			err);
544		goto unregister_netdev;
545	}
546
547	priv->being_deleted = false;
548	priv->is_connected = false;
549	priv->is_up = false;
550	INIT_DELAYED_WORK(&priv->connect, virt_wifi_connect_complete);
551	__module_get(THIS_MODULE);
552
553	return 0;
554unregister_netdev:
555	unregister_netdevice(dev);
556free_wireless_dev:
557	kfree(dev->ieee80211_ptr);
558	dev->ieee80211_ptr = NULL;
559remove_handler:
560	netdev_rx_handler_unregister(priv->lowerdev);
561
562	return err;
563}
564
565/* Called with rtnl lock held. */
566static void virt_wifi_dellink(struct net_device *dev,
567			      struct list_head *head)
568{
569	struct virt_wifi_netdev_priv *priv = netdev_priv(dev);
570
571	if (dev->ieee80211_ptr)
572		virt_wifi_cancel_scan(dev->ieee80211_ptr->wiphy);
573
574	priv->being_deleted = true;
575	virt_wifi_cancel_connect(dev);
576	netif_carrier_off(dev);
577
578	netdev_rx_handler_unregister(priv->lowerdev);
579	netdev_upper_dev_unlink(priv->lowerdev, dev);
580
581	unregister_netdevice_queue(dev, head);
582	module_put(THIS_MODULE);
583
584	/* Deleting the wiphy is handled in the module destructor. */
585}
586
587static struct rtnl_link_ops virt_wifi_link_ops = {
588	.kind		= "virt_wifi",
589	.setup		= virt_wifi_setup,
590	.newlink	= virt_wifi_newlink,
591	.dellink	= virt_wifi_dellink,
592	.priv_size	= sizeof(struct virt_wifi_netdev_priv),
593};
594
595static bool netif_is_virt_wifi_dev(const struct net_device *dev)
596{
597	return rcu_access_pointer(dev->rx_handler) == virt_wifi_rx_handler;
598}
599
600static int virt_wifi_event(struct notifier_block *this, unsigned long event,
601			   void *ptr)
602{
603	struct net_device *lower_dev = netdev_notifier_info_to_dev(ptr);
604	struct virt_wifi_netdev_priv *priv;
605	struct net_device *upper_dev;
606	LIST_HEAD(list_kill);
607
608	if (!netif_is_virt_wifi_dev(lower_dev))
609		return NOTIFY_DONE;
610
611	switch (event) {
612	case NETDEV_UNREGISTER:
613		priv = rtnl_dereference(lower_dev->rx_handler_data);
614		if (!priv)
615			return NOTIFY_DONE;
616
617		upper_dev = priv->upperdev;
618
619		upper_dev->rtnl_link_ops->dellink(upper_dev, &list_kill);
620		unregister_netdevice_many(&list_kill);
621		break;
622	}
623
624	return NOTIFY_DONE;
625}
626
627static struct notifier_block virt_wifi_notifier = {
628	.notifier_call = virt_wifi_event,
629};
630
631/* Acquires and releases the rtnl lock. */
632static int __init virt_wifi_init_module(void)
633{
634	int err;
635
636	/* Guaranteed to be locallly-administered and not multicast. */
637	eth_random_addr(fake_router_bssid);
638
639	err = register_netdevice_notifier(&virt_wifi_notifier);
640	if (err)
641		return err;
642
643	err = -ENOMEM;
644	common_wiphy = virt_wifi_make_wiphy();
645	if (!common_wiphy)
646		goto notifier;
647
648	err = rtnl_link_register(&virt_wifi_link_ops);
649	if (err)
650		goto destroy_wiphy;
651
652	return 0;
653
654destroy_wiphy:
655	virt_wifi_destroy_wiphy(common_wiphy);
656notifier:
657	unregister_netdevice_notifier(&virt_wifi_notifier);
658	return err;
659}
660
661/* Acquires and releases the rtnl lock. */
662static void __exit virt_wifi_cleanup_module(void)
663{
664	/* Will delete any devices that depend on the wiphy. */
665	rtnl_link_unregister(&virt_wifi_link_ops);
666	virt_wifi_destroy_wiphy(common_wiphy);
667	unregister_netdevice_notifier(&virt_wifi_notifier);
668}
669
670module_init(virt_wifi_init_module);
671module_exit(virt_wifi_cleanup_module);
672
673MODULE_LICENSE("GPL v2");
674MODULE_AUTHOR("Cody Schuffelen <schuffelen@google.com>");
675MODULE_DESCRIPTION("Driver for a wireless wrapper of ethernet devices");
676MODULE_ALIAS_RTNL_LINK("virt_wifi");