1 // SPDX-License-Identifier: GPL-2.0-only
3 * HWSIM IEEE 802.15.4 interface
6 * Copyright 2007-2012 Siemens AG
8 * Based on fakelb, original Written by:
14 #include <linux/module.h>
15 #include <linux/timer.h>
16 #include <linux/platform_device.h>
17 #include <linux/rtnetlink.h>
18 #include <linux/netdevice.h>
19 #include <linux/device.h>
20 #include <linux/spinlock.h>
21 #include <net/mac802154.h>
22 #include <net/cfg802154.h>
23 #include <net/genetlink.h>
24 #include "mac802154_hwsim.h"
26 MODULE_DESCRIPTION("Software simulator of IEEE 802.15.4 radio(s) for mac802154");
27 MODULE_LICENSE("GPL");
29 static LIST_HEAD(hwsim_phys);
30 static DEFINE_MUTEX(hwsim_phys_lock);
32 static struct platform_device *mac802154hwsim_dev;
34 /* MAC802154_HWSIM netlink family */
35 static struct genl_family hwsim_genl_family;
37 static int hwsim_radio_idx;
39 enum hwsim_multicast_groups {
43 static const struct genl_multicast_group hwsim_mcgrps[] = {
44 [HWSIM_MCGRP_CONFIG] = { .name = "config", },
54 struct hwsim_edge_info {
61 struct hwsim_phy *endpoint;
62 struct hwsim_edge_info __rcu *info;
64 struct list_head list;
69 struct ieee802154_hw *hw;
72 struct hwsim_pib __rcu *pib;
75 struct list_head edges;
77 struct list_head list;
80 static int hwsim_add_one(struct genl_info *info, struct device *dev,
82 static void hwsim_del(struct hwsim_phy *phy);
84 static int hwsim_hw_ed(struct ieee802154_hw *hw, u8 *level)
91 static int hwsim_hw_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
93 struct hwsim_phy *phy = hw->priv;
94 struct hwsim_pib *pib, *pib_old;
96 pib = kzalloc(sizeof(*pib), GFP_KERNEL);
101 pib->channel = channel;
103 pib_old = rtnl_dereference(phy->pib);
104 rcu_assign_pointer(phy->pib, pib);
105 kfree_rcu(pib_old, rcu);
109 static int hwsim_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
111 struct hwsim_phy *current_phy = hw->priv;
112 struct hwsim_pib *current_pib, *endpoint_pib;
113 struct hwsim_edge_info *einfo;
114 struct hwsim_edge *e;
116 WARN_ON(current_phy->suspended);
119 current_pib = rcu_dereference(current_phy->pib);
120 list_for_each_entry_rcu(e, ¤t_phy->edges, list) {
121 /* Can be changed later in rx_irqsafe, but this is only a
122 * performance tweak. Received radio should drop the frame
123 * in mac802154 stack anyway... so we don't need to be
124 * 100% of locking here to check on suspended
126 if (e->endpoint->suspended)
129 endpoint_pib = rcu_dereference(e->endpoint->pib);
130 if (current_pib->page == endpoint_pib->page &&
131 current_pib->channel == endpoint_pib->channel) {
132 struct sk_buff *newskb = pskb_copy(skb, GFP_ATOMIC);
134 einfo = rcu_dereference(e->info);
136 ieee802154_rx_irqsafe(e->endpoint->hw, newskb,
142 ieee802154_xmit_complete(hw, skb, false);
146 static int hwsim_hw_start(struct ieee802154_hw *hw)
148 struct hwsim_phy *phy = hw->priv;
150 phy->suspended = false;
154 static void hwsim_hw_stop(struct ieee802154_hw *hw)
156 struct hwsim_phy *phy = hw->priv;
158 phy->suspended = true;
162 hwsim_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
167 static const struct ieee802154_ops hwsim_ops = {
168 .owner = THIS_MODULE,
169 .xmit_async = hwsim_hw_xmit,
171 .set_channel = hwsim_hw_channel,
172 .start = hwsim_hw_start,
173 .stop = hwsim_hw_stop,
174 .set_promiscuous_mode = hwsim_set_promiscuous_mode,
177 static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
179 return hwsim_add_one(info, &mac802154hwsim_dev->dev, false);
182 static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info)
184 struct hwsim_phy *phy, *tmp;
187 if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID])
190 idx = nla_get_u32(info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID]);
192 mutex_lock(&hwsim_phys_lock);
193 list_for_each_entry_safe(phy, tmp, &hwsim_phys, list) {
194 if (idx == phy->idx) {
196 mutex_unlock(&hwsim_phys_lock);
200 mutex_unlock(&hwsim_phys_lock);
205 static int append_radio_msg(struct sk_buff *skb, struct hwsim_phy *phy)
207 struct nlattr *nl_edges, *nl_edge;
208 struct hwsim_edge_info *einfo;
209 struct hwsim_edge *e;
212 ret = nla_put_u32(skb, MAC802154_HWSIM_ATTR_RADIO_ID, phy->idx);
217 if (list_empty(&phy->edges)) {
222 nl_edges = nla_nest_start_noflag(skb,
223 MAC802154_HWSIM_ATTR_RADIO_EDGES);
229 list_for_each_entry_rcu(e, &phy->edges, list) {
230 nl_edge = nla_nest_start_noflag(skb,
231 MAC802154_HWSIM_ATTR_RADIO_EDGE);
234 nla_nest_cancel(skb, nl_edges);
238 ret = nla_put_u32(skb, MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID,
242 nla_nest_cancel(skb, nl_edge);
243 nla_nest_cancel(skb, nl_edges);
247 einfo = rcu_dereference(e->info);
248 ret = nla_put_u8(skb, MAC802154_HWSIM_EDGE_ATTR_LQI,
252 nla_nest_cancel(skb, nl_edge);
253 nla_nest_cancel(skb, nl_edges);
257 nla_nest_end(skb, nl_edge);
261 nla_nest_end(skb, nl_edges);
266 static int hwsim_get_radio(struct sk_buff *skb, struct hwsim_phy *phy,
268 struct netlink_callback *cb, int flags)
273 hdr = genlmsg_put(skb, portid, seq, &hwsim_genl_family, flags,
274 MAC802154_HWSIM_CMD_GET_RADIO);
279 genl_dump_check_consistent(cb, hdr);
281 res = append_radio_msg(skb, phy);
285 genlmsg_end(skb, hdr);
289 genlmsg_cancel(skb, hdr);
293 static int hwsim_get_radio_nl(struct sk_buff *msg, struct genl_info *info)
295 struct hwsim_phy *phy;
297 int idx, res = -ENODEV;
299 if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID])
301 idx = nla_get_u32(info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID]);
303 mutex_lock(&hwsim_phys_lock);
304 list_for_each_entry(phy, &hwsim_phys, list) {
308 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
314 res = hwsim_get_radio(skb, phy, info->snd_portid,
315 info->snd_seq, NULL, 0);
321 res = genlmsg_reply(skb, info);
326 mutex_unlock(&hwsim_phys_lock);
331 static int hwsim_dump_radio_nl(struct sk_buff *skb,
332 struct netlink_callback *cb)
334 int idx = cb->args[0];
335 struct hwsim_phy *phy;
338 mutex_lock(&hwsim_phys_lock);
340 if (idx == hwsim_radio_idx)
343 list_for_each_entry(phy, &hwsim_phys, list) {
347 res = hwsim_get_radio(skb, phy, NETLINK_CB(cb->skb).portid,
348 cb->nlh->nlmsg_seq, cb, NLM_F_MULTI);
358 mutex_unlock(&hwsim_phys_lock);
362 /* caller need to held hwsim_phys_lock */
363 static struct hwsim_phy *hwsim_get_radio_by_id(uint32_t idx)
365 struct hwsim_phy *phy;
367 list_for_each_entry(phy, &hwsim_phys, list) {
375 static const struct nla_policy hwsim_edge_policy[MAC802154_HWSIM_EDGE_ATTR_MAX + 1] = {
376 [MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID] = { .type = NLA_U32 },
377 [MAC802154_HWSIM_EDGE_ATTR_LQI] = { .type = NLA_U8 },
380 static struct hwsim_edge *hwsim_alloc_edge(struct hwsim_phy *endpoint, u8 lqi)
382 struct hwsim_edge_info *einfo;
383 struct hwsim_edge *e;
385 e = kzalloc(sizeof(*e), GFP_KERNEL);
389 einfo = kzalloc(sizeof(*einfo), GFP_KERNEL);
396 rcu_assign_pointer(e->info, einfo);
397 e->endpoint = endpoint;
402 static void hwsim_free_edge(struct hwsim_edge *e)
404 struct hwsim_edge_info *einfo;
407 einfo = rcu_dereference(e->info);
410 kfree_rcu(einfo, rcu);
414 static int hwsim_new_edge_nl(struct sk_buff *msg, struct genl_info *info)
416 struct nlattr *edge_attrs[MAC802154_HWSIM_EDGE_ATTR_MAX + 1];
417 struct hwsim_phy *phy_v0, *phy_v1;
418 struct hwsim_edge *e;
421 if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID] &&
422 !info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE])
425 if (nla_parse_nested_deprecated(edge_attrs, MAC802154_HWSIM_EDGE_ATTR_MAX, info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE], hwsim_edge_policy, NULL))
428 if (!edge_attrs[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID])
431 v0 = nla_get_u32(info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID]);
432 v1 = nla_get_u32(edge_attrs[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID]);
437 mutex_lock(&hwsim_phys_lock);
438 phy_v0 = hwsim_get_radio_by_id(v0);
440 mutex_unlock(&hwsim_phys_lock);
444 phy_v1 = hwsim_get_radio_by_id(v1);
446 mutex_unlock(&hwsim_phys_lock);
451 list_for_each_entry_rcu(e, &phy_v0->edges, list) {
452 if (e->endpoint->idx == v1) {
453 mutex_unlock(&hwsim_phys_lock);
460 e = hwsim_alloc_edge(phy_v1, 0xff);
462 mutex_unlock(&hwsim_phys_lock);
465 list_add_rcu(&e->list, &phy_v0->edges);
466 /* wait until changes are done under hwsim_phys_lock lock
467 * should prevent of calling this function twice while
468 * edges list has not the changes yet.
471 mutex_unlock(&hwsim_phys_lock);
476 static int hwsim_del_edge_nl(struct sk_buff *msg, struct genl_info *info)
478 struct nlattr *edge_attrs[MAC802154_HWSIM_EDGE_ATTR_MAX + 1];
479 struct hwsim_phy *phy_v0;
480 struct hwsim_edge *e;
483 if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID] &&
484 !info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE])
487 if (nla_parse_nested_deprecated(edge_attrs, MAC802154_HWSIM_EDGE_ATTR_MAX, info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE], hwsim_edge_policy, NULL))
490 if (!edge_attrs[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID])
493 v0 = nla_get_u32(info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID]);
494 v1 = nla_get_u32(edge_attrs[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID]);
496 mutex_lock(&hwsim_phys_lock);
497 phy_v0 = hwsim_get_radio_by_id(v0);
499 mutex_unlock(&hwsim_phys_lock);
504 list_for_each_entry_rcu(e, &phy_v0->edges, list) {
505 if (e->endpoint->idx == v1) {
507 list_del_rcu(&e->list);
509 /* same again - wait until list changes are done */
511 mutex_unlock(&hwsim_phys_lock);
517 mutex_unlock(&hwsim_phys_lock);
522 static int hwsim_set_edge_lqi(struct sk_buff *msg, struct genl_info *info)
524 struct nlattr *edge_attrs[MAC802154_HWSIM_EDGE_ATTR_MAX + 1];
525 struct hwsim_edge_info *einfo;
526 struct hwsim_phy *phy_v0;
527 struct hwsim_edge *e;
531 if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID] &&
532 !info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE])
535 if (nla_parse_nested_deprecated(edge_attrs, MAC802154_HWSIM_EDGE_ATTR_MAX, info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE], hwsim_edge_policy, NULL))
538 if (!edge_attrs[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID] &&
539 !edge_attrs[MAC802154_HWSIM_EDGE_ATTR_LQI])
542 v0 = nla_get_u32(info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID]);
543 v1 = nla_get_u32(edge_attrs[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID]);
544 lqi = nla_get_u8(edge_attrs[MAC802154_HWSIM_EDGE_ATTR_LQI]);
546 mutex_lock(&hwsim_phys_lock);
547 phy_v0 = hwsim_get_radio_by_id(v0);
549 mutex_unlock(&hwsim_phys_lock);
553 einfo = kzalloc(sizeof(*einfo), GFP_KERNEL);
555 mutex_unlock(&hwsim_phys_lock);
560 list_for_each_entry_rcu(e, &phy_v0->edges, list) {
561 if (e->endpoint->idx == v1) {
563 rcu_assign_pointer(e->info, einfo);
565 mutex_unlock(&hwsim_phys_lock);
572 mutex_unlock(&hwsim_phys_lock);
577 /* MAC802154_HWSIM netlink policy */
579 static const struct nla_policy hwsim_genl_policy[MAC802154_HWSIM_ATTR_MAX + 1] = {
580 [MAC802154_HWSIM_ATTR_RADIO_ID] = { .type = NLA_U32 },
581 [MAC802154_HWSIM_ATTR_RADIO_EDGE] = { .type = NLA_NESTED },
582 [MAC802154_HWSIM_ATTR_RADIO_EDGES] = { .type = NLA_NESTED },
585 /* Generic Netlink operations array */
586 static const struct genl_ops hwsim_nl_ops[] = {
588 .cmd = MAC802154_HWSIM_CMD_NEW_RADIO,
589 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
590 .doit = hwsim_new_radio_nl,
591 .flags = GENL_UNS_ADMIN_PERM,
594 .cmd = MAC802154_HWSIM_CMD_DEL_RADIO,
595 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
596 .doit = hwsim_del_radio_nl,
597 .flags = GENL_UNS_ADMIN_PERM,
600 .cmd = MAC802154_HWSIM_CMD_GET_RADIO,
601 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
602 .doit = hwsim_get_radio_nl,
603 .dumpit = hwsim_dump_radio_nl,
606 .cmd = MAC802154_HWSIM_CMD_NEW_EDGE,
607 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
608 .doit = hwsim_new_edge_nl,
609 .flags = GENL_UNS_ADMIN_PERM,
612 .cmd = MAC802154_HWSIM_CMD_DEL_EDGE,
613 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
614 .doit = hwsim_del_edge_nl,
615 .flags = GENL_UNS_ADMIN_PERM,
618 .cmd = MAC802154_HWSIM_CMD_SET_EDGE,
619 .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
620 .doit = hwsim_set_edge_lqi,
621 .flags = GENL_UNS_ADMIN_PERM,
625 static struct genl_family hwsim_genl_family __ro_after_init = {
626 .name = "MAC802154_HWSIM",
628 .maxattr = MAC802154_HWSIM_ATTR_MAX,
629 .policy = hwsim_genl_policy,
630 .module = THIS_MODULE,
632 .n_ops = ARRAY_SIZE(hwsim_nl_ops),
633 .mcgrps = hwsim_mcgrps,
634 .n_mcgrps = ARRAY_SIZE(hwsim_mcgrps),
637 static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb,
638 struct genl_info *info)
641 genl_notify(&hwsim_genl_family, mcast_skb, info,
642 HWSIM_MCGRP_CONFIG, GFP_KERNEL);
644 genlmsg_multicast(&hwsim_genl_family, mcast_skb, 0,
645 HWSIM_MCGRP_CONFIG, GFP_KERNEL);
648 static void hwsim_mcast_new_radio(struct genl_info *info, struct hwsim_phy *phy)
650 struct sk_buff *mcast_skb;
653 mcast_skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
657 data = genlmsg_put(mcast_skb, 0, 0, &hwsim_genl_family, 0,
658 MAC802154_HWSIM_CMD_NEW_RADIO);
662 if (append_radio_msg(mcast_skb, phy) < 0)
665 genlmsg_end(mcast_skb, data);
667 hwsim_mcast_config_msg(mcast_skb, info);
671 genlmsg_cancel(mcast_skb, data);
672 nlmsg_free(mcast_skb);
675 static void hwsim_edge_unsubscribe_me(struct hwsim_phy *phy)
677 struct hwsim_phy *tmp;
678 struct hwsim_edge *e;
681 /* going to all phy edges and remove phy from it */
682 list_for_each_entry(tmp, &hwsim_phys, list) {
683 list_for_each_entry_rcu(e, &tmp->edges, list) {
684 if (e->endpoint->idx == phy->idx) {
685 list_del_rcu(&e->list);
695 static int hwsim_subscribe_all_others(struct hwsim_phy *phy)
697 struct hwsim_phy *sub;
698 struct hwsim_edge *e;
700 list_for_each_entry(sub, &hwsim_phys, list) {
701 e = hwsim_alloc_edge(sub, 0xff);
705 list_add_rcu(&e->list, &phy->edges);
708 list_for_each_entry(sub, &hwsim_phys, list) {
709 e = hwsim_alloc_edge(phy, 0xff);
713 list_add_rcu(&e->list, &sub->edges);
720 list_for_each_entry_rcu(e, &phy->edges, list) {
721 list_del_rcu(&e->list);
726 hwsim_edge_unsubscribe_me(phy);
730 static int hwsim_add_one(struct genl_info *info, struct device *dev,
733 struct ieee802154_hw *hw;
734 struct hwsim_phy *phy;
735 struct hwsim_pib *pib;
739 idx = hwsim_radio_idx++;
741 hw = ieee802154_alloc_hw(sizeof(*phy), &hwsim_ops);
748 /* 868 MHz BPSK 802.15.4-2003 */
749 hw->phy->supported.channels[0] |= 1;
750 /* 915 MHz BPSK 802.15.4-2003 */
751 hw->phy->supported.channels[0] |= 0x7fe;
752 /* 2.4 GHz O-QPSK 802.15.4-2003 */
753 hw->phy->supported.channels[0] |= 0x7FFF800;
754 /* 868 MHz ASK 802.15.4-2006 */
755 hw->phy->supported.channels[1] |= 1;
756 /* 915 MHz ASK 802.15.4-2006 */
757 hw->phy->supported.channels[1] |= 0x7fe;
758 /* 868 MHz O-QPSK 802.15.4-2006 */
759 hw->phy->supported.channels[2] |= 1;
760 /* 915 MHz O-QPSK 802.15.4-2006 */
761 hw->phy->supported.channels[2] |= 0x7fe;
762 /* 2.4 GHz CSS 802.15.4a-2007 */
763 hw->phy->supported.channels[3] |= 0x3fff;
764 /* UWB Sub-gigahertz 802.15.4a-2007 */
765 hw->phy->supported.channels[4] |= 1;
766 /* UWB Low band 802.15.4a-2007 */
767 hw->phy->supported.channels[4] |= 0x1e;
768 /* UWB High band 802.15.4a-2007 */
769 hw->phy->supported.channels[4] |= 0xffe0;
770 /* 750 MHz O-QPSK 802.15.4c-2009 */
771 hw->phy->supported.channels[5] |= 0xf;
772 /* 750 MHz MPSK 802.15.4c-2009 */
773 hw->phy->supported.channels[5] |= 0xf0;
774 /* 950 MHz BPSK 802.15.4d-2009 */
775 hw->phy->supported.channels[6] |= 0x3ff;
776 /* 950 MHz GFSK 802.15.4d-2009 */
777 hw->phy->supported.channels[6] |= 0x3ffc00;
779 ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
781 /* hwsim phy channel 13 as default */
782 hw->phy->current_channel = 13;
783 pib = kzalloc(sizeof(*pib), GFP_KERNEL);
789 rcu_assign_pointer(phy->pib, pib);
791 INIT_LIST_HEAD(&phy->edges);
793 hw->flags = IEEE802154_HW_PROMISCUOUS;
796 err = ieee802154_register_hw(hw);
800 mutex_lock(&hwsim_phys_lock);
802 err = hwsim_subscribe_all_others(phy);
804 mutex_unlock(&hwsim_phys_lock);
808 list_add_tail(&phy->list, &hwsim_phys);
809 mutex_unlock(&hwsim_phys_lock);
811 hwsim_mcast_new_radio(info, phy);
816 ieee802154_unregister_hw(phy->hw);
820 ieee802154_free_hw(phy->hw);
824 static void hwsim_del(struct hwsim_phy *phy)
826 struct hwsim_pib *pib;
828 hwsim_edge_unsubscribe_me(phy);
830 list_del(&phy->list);
833 pib = rcu_dereference(phy->pib);
838 ieee802154_unregister_hw(phy->hw);
839 ieee802154_free_hw(phy->hw);
842 static int hwsim_probe(struct platform_device *pdev)
844 struct hwsim_phy *phy, *tmp;
847 for (i = 0; i < 2; i++) {
848 err = hwsim_add_one(NULL, &pdev->dev, true);
853 dev_info(&pdev->dev, "Added 2 mac802154 hwsim hardware radios\n");
857 mutex_lock(&hwsim_phys_lock);
858 list_for_each_entry_safe(phy, tmp, &hwsim_phys, list)
860 mutex_unlock(&hwsim_phys_lock);
864 static int hwsim_remove(struct platform_device *pdev)
866 struct hwsim_phy *phy, *tmp;
868 mutex_lock(&hwsim_phys_lock);
869 list_for_each_entry_safe(phy, tmp, &hwsim_phys, list)
871 mutex_unlock(&hwsim_phys_lock);
876 static struct platform_driver mac802154hwsim_driver = {
877 .probe = hwsim_probe,
878 .remove = hwsim_remove,
880 .name = "mac802154_hwsim",
884 static __init int hwsim_init_module(void)
888 rc = genl_register_family(&hwsim_genl_family);
892 mac802154hwsim_dev = platform_device_register_simple("mac802154_hwsim",
894 if (IS_ERR(mac802154hwsim_dev)) {
895 rc = PTR_ERR(mac802154hwsim_dev);
899 rc = platform_driver_register(&mac802154hwsim_driver);
906 platform_device_unregister(mac802154hwsim_dev);
908 genl_unregister_family(&hwsim_genl_family);
912 static __exit void hwsim_remove_module(void)
914 genl_unregister_family(&hwsim_genl_family);
915 platform_driver_unregister(&mac802154hwsim_driver);
916 platform_device_unregister(mac802154hwsim_dev);
919 module_init(hwsim_init_module);
920 module_exit(hwsim_remove_module);