2 * HWSIM IEEE 802.15.4 interface
4 * (C) 2018 Mojatau, Alexander Aring <aring@mojatau.com>
5 * Copyright 2007-2012 Siemens AG
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2
9 * as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * Based on fakelb, original Written by:
17 * Sergey Lapin <slapin@ossfans.org>
18 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
19 * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
22 #include <linux/module.h>
23 #include <linux/timer.h>
24 #include <linux/platform_device.h>
25 #include <linux/rtnetlink.h>
26 #include <linux/netdevice.h>
27 #include <linux/device.h>
28 #include <linux/spinlock.h>
29 #include <net/mac802154.h>
30 #include <net/cfg802154.h>
31 #include <net/genetlink.h>
32 #include "mac802154_hwsim.h"
34 MODULE_DESCRIPTION("Software simulator of IEEE 802.15.4 radio(s) for mac802154");
35 MODULE_LICENSE("GPL");
37 static LIST_HEAD(hwsim_phys
);
38 static DEFINE_MUTEX(hwsim_phys_lock
);
40 static struct platform_device
*mac802154hwsim_dev
;
42 /* MAC802154_HWSIM netlink family */
43 static struct genl_family hwsim_genl_family
;
45 static int hwsim_radio_idx
;
47 enum hwsim_multicast_groups
{
51 static const struct genl_multicast_group hwsim_mcgrps
[] = {
52 [HWSIM_MCGRP_CONFIG
] = { .name
= "config", },
62 struct hwsim_edge_info
{
69 struct hwsim_phy
*endpoint
;
70 struct hwsim_edge_info __rcu
*info
;
72 struct list_head list
;
77 struct ieee802154_hw
*hw
;
80 struct hwsim_pib __rcu
*pib
;
83 struct list_head edges
;
85 struct list_head list
;
88 static int hwsim_add_one(struct genl_info
*info
, struct device
*dev
,
90 static void hwsim_del(struct hwsim_phy
*phy
);
92 static int hwsim_hw_ed(struct ieee802154_hw
*hw
, u8
*level
)
99 static int hwsim_hw_channel(struct ieee802154_hw
*hw
, u8 page
, u8 channel
)
101 struct hwsim_phy
*phy
= hw
->priv
;
102 struct hwsim_pib
*pib
, *pib_old
;
104 pib
= kzalloc(sizeof(*pib
), GFP_KERNEL
);
109 pib
->channel
= channel
;
111 pib_old
= rtnl_dereference(phy
->pib
);
112 rcu_assign_pointer(phy
->pib
, pib
);
113 kfree_rcu(pib_old
, rcu
);
117 static int hwsim_hw_xmit(struct ieee802154_hw
*hw
, struct sk_buff
*skb
)
119 struct hwsim_phy
*current_phy
= hw
->priv
;
120 struct hwsim_pib
*current_pib
, *endpoint_pib
;
121 struct hwsim_edge_info
*einfo
;
122 struct hwsim_edge
*e
;
124 WARN_ON(current_phy
->suspended
);
127 current_pib
= rcu_dereference(current_phy
->pib
);
128 list_for_each_entry_rcu(e
, ¤t_phy
->edges
, list
) {
129 /* Can be changed later in rx_irqsafe, but this is only a
130 * performance tweak. Received radio should drop the frame
131 * in mac802154 stack anyway... so we don't need to be
132 * 100% of locking here to check on suspended
134 if (e
->endpoint
->suspended
)
137 endpoint_pib
= rcu_dereference(e
->endpoint
->pib
);
138 if (current_pib
->page
== endpoint_pib
->page
&&
139 current_pib
->channel
== endpoint_pib
->channel
) {
140 struct sk_buff
*newskb
= pskb_copy(skb
, GFP_ATOMIC
);
142 einfo
= rcu_dereference(e
->info
);
144 ieee802154_rx_irqsafe(e
->endpoint
->hw
, newskb
,
150 ieee802154_xmit_complete(hw
, skb
, false);
154 static int hwsim_hw_start(struct ieee802154_hw
*hw
)
156 struct hwsim_phy
*phy
= hw
->priv
;
158 phy
->suspended
= false;
162 static void hwsim_hw_stop(struct ieee802154_hw
*hw
)
164 struct hwsim_phy
*phy
= hw
->priv
;
166 phy
->suspended
= true;
170 hwsim_set_promiscuous_mode(struct ieee802154_hw
*hw
, const bool on
)
175 static const struct ieee802154_ops hwsim_ops
= {
176 .owner
= THIS_MODULE
,
177 .xmit_async
= hwsim_hw_xmit
,
179 .set_channel
= hwsim_hw_channel
,
180 .start
= hwsim_hw_start
,
181 .stop
= hwsim_hw_stop
,
182 .set_promiscuous_mode
= hwsim_set_promiscuous_mode
,
185 static int hwsim_new_radio_nl(struct sk_buff
*msg
, struct genl_info
*info
)
187 return hwsim_add_one(info
, &mac802154hwsim_dev
->dev
, false);
190 static int hwsim_del_radio_nl(struct sk_buff
*msg
, struct genl_info
*info
)
192 struct hwsim_phy
*phy
, *tmp
;
195 if (!info
->attrs
[MAC802154_HWSIM_ATTR_RADIO_ID
])
198 idx
= nla_get_u32(info
->attrs
[MAC802154_HWSIM_ATTR_RADIO_ID
]);
200 mutex_lock(&hwsim_phys_lock
);
201 list_for_each_entry_safe(phy
, tmp
, &hwsim_phys
, list
) {
202 if (idx
== phy
->idx
) {
204 mutex_unlock(&hwsim_phys_lock
);
208 mutex_unlock(&hwsim_phys_lock
);
213 static int append_radio_msg(struct sk_buff
*skb
, struct hwsim_phy
*phy
)
215 struct nlattr
*nl_edges
, *nl_edge
;
216 struct hwsim_edge_info
*einfo
;
217 struct hwsim_edge
*e
;
220 ret
= nla_put_u32(skb
, MAC802154_HWSIM_ATTR_RADIO_ID
, phy
->idx
);
225 if (list_empty(&phy
->edges
)) {
230 nl_edges
= nla_nest_start(skb
, MAC802154_HWSIM_ATTR_RADIO_EDGES
);
236 list_for_each_entry_rcu(e
, &phy
->edges
, list
) {
237 nl_edge
= nla_nest_start(skb
, MAC802154_HWSIM_ATTR_RADIO_EDGE
);
240 nla_nest_cancel(skb
, nl_edges
);
244 ret
= nla_put_u32(skb
, MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID
,
248 nla_nest_cancel(skb
, nl_edge
);
249 nla_nest_cancel(skb
, nl_edges
);
253 einfo
= rcu_dereference(e
->info
);
254 ret
= nla_put_u8(skb
, MAC802154_HWSIM_EDGE_ATTR_LQI
,
258 nla_nest_cancel(skb
, nl_edge
);
259 nla_nest_cancel(skb
, nl_edges
);
263 nla_nest_end(skb
, nl_edge
);
267 nla_nest_end(skb
, nl_edges
);
272 static int hwsim_get_radio(struct sk_buff
*skb
, struct hwsim_phy
*phy
,
274 struct netlink_callback
*cb
, int flags
)
279 hdr
= genlmsg_put(skb
, portid
, seq
, &hwsim_genl_family
, flags
,
280 MAC802154_HWSIM_CMD_GET_RADIO
);
285 genl_dump_check_consistent(cb
, hdr
);
287 res
= append_radio_msg(skb
, phy
);
291 genlmsg_end(skb
, hdr
);
295 genlmsg_cancel(skb
, hdr
);
299 static int hwsim_get_radio_nl(struct sk_buff
*msg
, struct genl_info
*info
)
301 struct hwsim_phy
*phy
;
303 int idx
, res
= -ENODEV
;
305 if (!info
->attrs
[MAC802154_HWSIM_ATTR_RADIO_ID
])
307 idx
= nla_get_u32(info
->attrs
[MAC802154_HWSIM_ATTR_RADIO_ID
]);
309 mutex_lock(&hwsim_phys_lock
);
310 list_for_each_entry(phy
, &hwsim_phys
, list
) {
314 skb
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_ATOMIC
);
320 res
= hwsim_get_radio(skb
, phy
, info
->snd_portid
,
321 info
->snd_seq
, NULL
, 0);
327 genlmsg_reply(skb
, info
);
332 mutex_unlock(&hwsim_phys_lock
);
337 static int hwsim_dump_radio_nl(struct sk_buff
*skb
,
338 struct netlink_callback
*cb
)
340 int idx
= cb
->args
[0];
341 struct hwsim_phy
*phy
;
344 mutex_lock(&hwsim_phys_lock
);
346 if (idx
== hwsim_radio_idx
)
349 list_for_each_entry(phy
, &hwsim_phys
, list
) {
353 res
= hwsim_get_radio(skb
, phy
, NETLINK_CB(cb
->skb
).portid
,
354 cb
->nlh
->nlmsg_seq
, cb
, NLM_F_MULTI
);
364 mutex_unlock(&hwsim_phys_lock
);
368 /* caller need to held hwsim_phys_lock */
369 static struct hwsim_phy
*hwsim_get_radio_by_id(uint32_t idx
)
371 struct hwsim_phy
*phy
;
373 list_for_each_entry(phy
, &hwsim_phys
, list
) {
381 static const struct nla_policy hwsim_edge_policy
[MAC802154_HWSIM_EDGE_ATTR_MAX
+ 1] = {
382 [MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID
] = { .type
= NLA_U32
},
383 [MAC802154_HWSIM_EDGE_ATTR_LQI
] = { .type
= NLA_U8
},
386 static struct hwsim_edge
*hwsim_alloc_edge(struct hwsim_phy
*endpoint
, u8 lqi
)
388 struct hwsim_edge_info
*einfo
;
389 struct hwsim_edge
*e
;
391 e
= kzalloc(sizeof(*e
), GFP_KERNEL
);
395 einfo
= kzalloc(sizeof(*einfo
), GFP_KERNEL
);
402 rcu_assign_pointer(e
->info
, einfo
);
403 e
->endpoint
= endpoint
;
408 static void hwsim_free_edge(struct hwsim_edge
*e
)
410 struct hwsim_edge_info
*einfo
;
413 einfo
= rcu_dereference(e
->info
);
416 kfree_rcu(einfo
, rcu
);
420 static int hwsim_new_edge_nl(struct sk_buff
*msg
, struct genl_info
*info
)
422 struct nlattr
*edge_attrs
[MAC802154_HWSIM_EDGE_ATTR_MAX
+ 1];
423 struct hwsim_phy
*phy_v0
, *phy_v1
;
424 struct hwsim_edge
*e
;
427 if (!info
->attrs
[MAC802154_HWSIM_ATTR_RADIO_ID
] &&
428 !info
->attrs
[MAC802154_HWSIM_ATTR_RADIO_EDGE
])
431 if (nla_parse_nested(edge_attrs
, MAC802154_HWSIM_EDGE_ATTR_MAX
,
432 info
->attrs
[MAC802154_HWSIM_ATTR_RADIO_EDGE
],
433 hwsim_edge_policy
, NULL
))
436 if (!edge_attrs
[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID
])
439 v0
= nla_get_u32(info
->attrs
[MAC802154_HWSIM_ATTR_RADIO_ID
]);
440 v1
= nla_get_u32(edge_attrs
[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID
]);
445 mutex_lock(&hwsim_phys_lock
);
446 phy_v0
= hwsim_get_radio_by_id(v0
);
448 mutex_unlock(&hwsim_phys_lock
);
452 phy_v1
= hwsim_get_radio_by_id(v1
);
454 mutex_unlock(&hwsim_phys_lock
);
459 list_for_each_entry_rcu(e
, &phy_v0
->edges
, list
) {
460 if (e
->endpoint
->idx
== v1
) {
461 mutex_unlock(&hwsim_phys_lock
);
468 e
= hwsim_alloc_edge(phy_v1
, 0xff);
470 mutex_unlock(&hwsim_phys_lock
);
473 list_add_rcu(&e
->list
, &phy_v0
->edges
);
474 /* wait until changes are done under hwsim_phys_lock lock
475 * should prevent of calling this function twice while
476 * edges list has not the changes yet.
479 mutex_unlock(&hwsim_phys_lock
);
484 static int hwsim_del_edge_nl(struct sk_buff
*msg
, struct genl_info
*info
)
486 struct nlattr
*edge_attrs
[MAC802154_HWSIM_EDGE_ATTR_MAX
+ 1];
487 struct hwsim_phy
*phy_v0
;
488 struct hwsim_edge
*e
;
491 if (!info
->attrs
[MAC802154_HWSIM_ATTR_RADIO_ID
] &&
492 !info
->attrs
[MAC802154_HWSIM_ATTR_RADIO_EDGE
])
495 if (nla_parse_nested(edge_attrs
, MAC802154_HWSIM_EDGE_ATTR_MAX
+ 1,
496 info
->attrs
[MAC802154_HWSIM_ATTR_RADIO_EDGE
],
497 hwsim_edge_policy
, NULL
))
500 if (!edge_attrs
[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID
])
503 v0
= nla_get_u32(info
->attrs
[MAC802154_HWSIM_ATTR_RADIO_ID
]);
504 v1
= nla_get_u32(edge_attrs
[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID
]);
506 mutex_lock(&hwsim_phys_lock
);
507 phy_v0
= hwsim_get_radio_by_id(v0
);
509 mutex_unlock(&hwsim_phys_lock
);
514 list_for_each_entry_rcu(e
, &phy_v0
->edges
, list
) {
515 if (e
->endpoint
->idx
== v1
) {
517 list_del_rcu(&e
->list
);
519 /* same again - wait until list changes are done */
521 mutex_unlock(&hwsim_phys_lock
);
527 mutex_unlock(&hwsim_phys_lock
);
532 static int hwsim_set_edge_lqi(struct sk_buff
*msg
, struct genl_info
*info
)
534 struct nlattr
*edge_attrs
[MAC802154_HWSIM_EDGE_ATTR_MAX
+ 1];
535 struct hwsim_edge_info
*einfo
;
536 struct hwsim_phy
*phy_v0
;
537 struct hwsim_edge
*e
;
541 if (!info
->attrs
[MAC802154_HWSIM_ATTR_RADIO_ID
] &&
542 !info
->attrs
[MAC802154_HWSIM_ATTR_RADIO_EDGE
])
545 if (nla_parse_nested(edge_attrs
, MAC802154_HWSIM_EDGE_ATTR_MAX
+ 1,
546 info
->attrs
[MAC802154_HWSIM_ATTR_RADIO_EDGE
],
547 hwsim_edge_policy
, NULL
))
550 if (!edge_attrs
[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID
] &&
551 !edge_attrs
[MAC802154_HWSIM_EDGE_ATTR_LQI
])
554 v0
= nla_get_u32(info
->attrs
[MAC802154_HWSIM_ATTR_RADIO_ID
]);
555 v1
= nla_get_u32(edge_attrs
[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID
]);
556 lqi
= nla_get_u8(edge_attrs
[MAC802154_HWSIM_EDGE_ATTR_LQI
]);
558 mutex_lock(&hwsim_phys_lock
);
559 phy_v0
= hwsim_get_radio_by_id(v0
);
561 mutex_unlock(&hwsim_phys_lock
);
565 einfo
= kzalloc(sizeof(*einfo
), GFP_KERNEL
);
567 mutex_unlock(&hwsim_phys_lock
);
572 list_for_each_entry_rcu(e
, &phy_v0
->edges
, list
) {
573 if (e
->endpoint
->idx
== v1
) {
575 rcu_assign_pointer(e
->info
, einfo
);
577 mutex_unlock(&hwsim_phys_lock
);
584 mutex_unlock(&hwsim_phys_lock
);
589 /* MAC802154_HWSIM netlink policy */
591 static const struct nla_policy hwsim_genl_policy
[MAC802154_HWSIM_ATTR_MAX
+ 1] = {
592 [MAC802154_HWSIM_ATTR_RADIO_ID
] = { .type
= NLA_U32
},
593 [MAC802154_HWSIM_ATTR_RADIO_EDGE
] = { .type
= NLA_NESTED
},
594 [MAC802154_HWSIM_ATTR_RADIO_EDGES
] = { .type
= NLA_NESTED
},
597 /* Generic Netlink operations array */
598 static const struct genl_ops hwsim_nl_ops
[] = {
600 .cmd
= MAC802154_HWSIM_CMD_NEW_RADIO
,
601 .policy
= hwsim_genl_policy
,
602 .doit
= hwsim_new_radio_nl
,
603 .flags
= GENL_UNS_ADMIN_PERM
,
606 .cmd
= MAC802154_HWSIM_CMD_DEL_RADIO
,
607 .policy
= hwsim_genl_policy
,
608 .doit
= hwsim_del_radio_nl
,
609 .flags
= GENL_UNS_ADMIN_PERM
,
612 .cmd
= MAC802154_HWSIM_CMD_GET_RADIO
,
613 .policy
= hwsim_genl_policy
,
614 .doit
= hwsim_get_radio_nl
,
615 .dumpit
= hwsim_dump_radio_nl
,
618 .cmd
= MAC802154_HWSIM_CMD_NEW_EDGE
,
619 .policy
= hwsim_genl_policy
,
620 .doit
= hwsim_new_edge_nl
,
621 .flags
= GENL_UNS_ADMIN_PERM
,
624 .cmd
= MAC802154_HWSIM_CMD_DEL_EDGE
,
625 .policy
= hwsim_genl_policy
,
626 .doit
= hwsim_del_edge_nl
,
627 .flags
= GENL_UNS_ADMIN_PERM
,
630 .cmd
= MAC802154_HWSIM_CMD_SET_EDGE
,
631 .policy
= hwsim_genl_policy
,
632 .doit
= hwsim_set_edge_lqi
,
633 .flags
= GENL_UNS_ADMIN_PERM
,
637 static struct genl_family hwsim_genl_family __ro_after_init
= {
638 .name
= "MAC802154_HWSIM",
640 .maxattr
= MAC802154_HWSIM_ATTR_MAX
,
641 .module
= THIS_MODULE
,
643 .n_ops
= ARRAY_SIZE(hwsim_nl_ops
),
644 .mcgrps
= hwsim_mcgrps
,
645 .n_mcgrps
= ARRAY_SIZE(hwsim_mcgrps
),
648 static void hwsim_mcast_config_msg(struct sk_buff
*mcast_skb
,
649 struct genl_info
*info
)
652 genl_notify(&hwsim_genl_family
, mcast_skb
, info
,
653 HWSIM_MCGRP_CONFIG
, GFP_KERNEL
);
655 genlmsg_multicast(&hwsim_genl_family
, mcast_skb
, 0,
656 HWSIM_MCGRP_CONFIG
, GFP_KERNEL
);
659 static void hwsim_mcast_new_radio(struct genl_info
*info
, struct hwsim_phy
*phy
)
661 struct sk_buff
*mcast_skb
;
664 mcast_skb
= genlmsg_new(GENLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
668 data
= genlmsg_put(mcast_skb
, 0, 0, &hwsim_genl_family
, 0,
669 MAC802154_HWSIM_CMD_NEW_RADIO
);
673 if (append_radio_msg(mcast_skb
, phy
) < 0)
676 genlmsg_end(mcast_skb
, data
);
678 hwsim_mcast_config_msg(mcast_skb
, info
);
682 genlmsg_cancel(mcast_skb
, data
);
683 nlmsg_free(mcast_skb
);
686 static void hwsim_edge_unsubscribe_me(struct hwsim_phy
*phy
)
688 struct hwsim_phy
*tmp
;
689 struct hwsim_edge
*e
;
692 /* going to all phy edges and remove phy from it */
693 list_for_each_entry(tmp
, &hwsim_phys
, list
) {
694 list_for_each_entry_rcu(e
, &tmp
->edges
, list
) {
695 if (e
->endpoint
->idx
== phy
->idx
) {
696 list_del_rcu(&e
->list
);
706 static int hwsim_subscribe_all_others(struct hwsim_phy
*phy
)
708 struct hwsim_phy
*sub
;
709 struct hwsim_edge
*e
;
711 list_for_each_entry(sub
, &hwsim_phys
, list
) {
712 e
= hwsim_alloc_edge(sub
, 0xff);
716 list_add_rcu(&e
->list
, &phy
->edges
);
719 list_for_each_entry(sub
, &hwsim_phys
, list
) {
720 e
= hwsim_alloc_edge(phy
, 0xff);
724 list_add_rcu(&e
->list
, &sub
->edges
);
731 list_for_each_entry_rcu(e
, &phy
->edges
, list
) {
732 list_del_rcu(&e
->list
);
737 hwsim_edge_unsubscribe_me(phy
);
741 static int hwsim_add_one(struct genl_info
*info
, struct device
*dev
,
744 struct ieee802154_hw
*hw
;
745 struct hwsim_phy
*phy
;
746 struct hwsim_pib
*pib
;
750 idx
= hwsim_radio_idx
++;
752 hw
= ieee802154_alloc_hw(sizeof(*phy
), &hwsim_ops
);
759 /* 868 MHz BPSK 802.15.4-2003 */
760 hw
->phy
->supported
.channels
[0] |= 1;
761 /* 915 MHz BPSK 802.15.4-2003 */
762 hw
->phy
->supported
.channels
[0] |= 0x7fe;
763 /* 2.4 GHz O-QPSK 802.15.4-2003 */
764 hw
->phy
->supported
.channels
[0] |= 0x7FFF800;
765 /* 868 MHz ASK 802.15.4-2006 */
766 hw
->phy
->supported
.channels
[1] |= 1;
767 /* 915 MHz ASK 802.15.4-2006 */
768 hw
->phy
->supported
.channels
[1] |= 0x7fe;
769 /* 868 MHz O-QPSK 802.15.4-2006 */
770 hw
->phy
->supported
.channels
[2] |= 1;
771 /* 915 MHz O-QPSK 802.15.4-2006 */
772 hw
->phy
->supported
.channels
[2] |= 0x7fe;
773 /* 2.4 GHz CSS 802.15.4a-2007 */
774 hw
->phy
->supported
.channels
[3] |= 0x3fff;
775 /* UWB Sub-gigahertz 802.15.4a-2007 */
776 hw
->phy
->supported
.channels
[4] |= 1;
777 /* UWB Low band 802.15.4a-2007 */
778 hw
->phy
->supported
.channels
[4] |= 0x1e;
779 /* UWB High band 802.15.4a-2007 */
780 hw
->phy
->supported
.channels
[4] |= 0xffe0;
781 /* 750 MHz O-QPSK 802.15.4c-2009 */
782 hw
->phy
->supported
.channels
[5] |= 0xf;
783 /* 750 MHz MPSK 802.15.4c-2009 */
784 hw
->phy
->supported
.channels
[5] |= 0xf0;
785 /* 950 MHz BPSK 802.15.4d-2009 */
786 hw
->phy
->supported
.channels
[6] |= 0x3ff;
787 /* 950 MHz GFSK 802.15.4d-2009 */
788 hw
->phy
->supported
.channels
[6] |= 0x3ffc00;
790 ieee802154_random_extended_addr(&hw
->phy
->perm_extended_addr
);
792 /* hwsim phy channel 13 as default */
793 hw
->phy
->current_channel
= 13;
794 pib
= kzalloc(sizeof(*pib
), GFP_KERNEL
);
800 rcu_assign_pointer(phy
->pib
, pib
);
802 INIT_LIST_HEAD(&phy
->edges
);
804 hw
->flags
= IEEE802154_HW_PROMISCUOUS
;
807 err
= ieee802154_register_hw(hw
);
811 mutex_lock(&hwsim_phys_lock
);
813 err
= hwsim_subscribe_all_others(phy
);
815 mutex_unlock(&hwsim_phys_lock
);
819 list_add_tail(&phy
->list
, &hwsim_phys
);
820 mutex_unlock(&hwsim_phys_lock
);
822 hwsim_mcast_new_radio(info
, phy
);
829 ieee802154_free_hw(phy
->hw
);
833 static void hwsim_del(struct hwsim_phy
*phy
)
835 struct hwsim_pib
*pib
;
837 hwsim_edge_unsubscribe_me(phy
);
839 list_del(&phy
->list
);
842 pib
= rcu_dereference(phy
->pib
);
847 ieee802154_unregister_hw(phy
->hw
);
848 ieee802154_free_hw(phy
->hw
);
851 static int hwsim_probe(struct platform_device
*pdev
)
853 struct hwsim_phy
*phy
, *tmp
;
856 for (i
= 0; i
< 2; i
++) {
857 err
= hwsim_add_one(NULL
, &pdev
->dev
, true);
862 dev_info(&pdev
->dev
, "Added 2 mac802154 hwsim hardware radios\n");
866 mutex_lock(&hwsim_phys_lock
);
867 list_for_each_entry_safe(phy
, tmp
, &hwsim_phys
, list
)
869 mutex_unlock(&hwsim_phys_lock
);
873 static int hwsim_remove(struct platform_device
*pdev
)
875 struct hwsim_phy
*phy
, *tmp
;
877 mutex_lock(&hwsim_phys_lock
);
878 list_for_each_entry_safe(phy
, tmp
, &hwsim_phys
, list
)
880 mutex_unlock(&hwsim_phys_lock
);
885 static struct platform_driver mac802154hwsim_driver
= {
886 .probe
= hwsim_probe
,
887 .remove
= hwsim_remove
,
889 .name
= "mac802154_hwsim",
893 static __init
int hwsim_init_module(void)
897 rc
= genl_register_family(&hwsim_genl_family
);
901 mac802154hwsim_dev
= platform_device_register_simple("mac802154_hwsim",
903 if (IS_ERR(mac802154hwsim_dev
)) {
904 rc
= PTR_ERR(mac802154hwsim_dev
);
908 rc
= platform_driver_register(&mac802154hwsim_driver
);
915 genl_unregister_family(&hwsim_genl_family
);
917 platform_device_unregister(mac802154hwsim_dev
);
921 static __exit
void hwsim_remove_module(void)
923 genl_unregister_family(&hwsim_genl_family
);
924 platform_driver_unregister(&mac802154hwsim_driver
);
925 platform_device_unregister(mac802154hwsim_dev
);
928 module_init(hwsim_init_module
);
929 module_exit(hwsim_remove_module
);