blob: f4e92054f7df87ceef6bd5ab97c7fc4c152b2639 [file] [log] [blame]
Alexander Aringf25da512018-07-14 12:33:05 -04001/*
2 * HWSIM IEEE 802.15.4 interface
3 *
4 * (C) 2018 Mojatau, Alexander Aring <aring@mojatau.com>
5 * Copyright 2007-2012 Siemens AG
6 *
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.
10 *
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.
15 *
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>
20 */
21
22#include <linux/module.h>
23#include <linux/timer.h>
24#include <linux/platform_device.h>
25#include <linux/netdevice.h>
26#include <linux/device.h>
27#include <linux/spinlock.h>
28#include <net/mac802154.h>
29#include <net/cfg802154.h>
30#include <net/genetlink.h>
31#include "mac802154_hwsim.h"
32
33MODULE_DESCRIPTION("Software simulator of IEEE 802.15.4 radio(s) for mac802154");
34MODULE_LICENSE("GPL");
35
36static LIST_HEAD(hwsim_phys);
37static DEFINE_MUTEX(hwsim_phys_lock);
38
Alexander Aringc5d99d22018-08-07 10:34:44 -040039static LIST_HEAD(hwsim_ifup_phys);
Alexander Aringf25da512018-07-14 12:33:05 -040040
41static struct platform_device *mac802154hwsim_dev;
42
43/* MAC802154_HWSIM netlink family */
44static struct genl_family hwsim_genl_family;
45
46static int hwsim_radio_idx;
47
48enum hwsim_multicast_groups {
49 HWSIM_MCGRP_CONFIG,
50};
51
52static const struct genl_multicast_group hwsim_mcgrps[] = {
53 [HWSIM_MCGRP_CONFIG] = { .name = "config", },
54};
55
56struct hwsim_pib {
57 u8 page;
58 u8 channel;
59
60 struct rcu_head rcu;
61};
62
63struct hwsim_edge_info {
64 u8 lqi;
65
66 struct rcu_head rcu;
67};
68
69struct hwsim_edge {
70 struct hwsim_phy *endpoint;
Alexander Aringc5d99d22018-08-07 10:34:44 -040071 struct hwsim_edge_info __rcu *info;
Alexander Aringf25da512018-07-14 12:33:05 -040072
73 struct list_head list;
74 struct rcu_head rcu;
75};
76
77struct hwsim_phy {
78 struct ieee802154_hw *hw;
79 u32 idx;
80
81 struct hwsim_pib __rcu *pib;
82
83 bool suspended;
Alexander Aringc5d99d22018-08-07 10:34:44 -040084 struct list_head edges;
Alexander Aringf25da512018-07-14 12:33:05 -040085
86 struct list_head list;
87 struct list_head list_ifup;
88};
89
90static int hwsim_add_one(struct genl_info *info, struct device *dev,
91 bool init);
92static void hwsim_del(struct hwsim_phy *phy);
93
94static int hwsim_hw_ed(struct ieee802154_hw *hw, u8 *level)
95{
96 *level = 0xbe;
97
98 return 0;
99}
100
101static int hwsim_hw_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
102{
103 struct hwsim_phy *phy = hw->priv;
104 struct hwsim_pib *pib, *pib_old;
105
106 pib = kzalloc(sizeof(*pib), GFP_KERNEL);
107 if (!pib)
108 return -ENOMEM;
109
110 pib->page = page;
111 pib->channel = channel;
112
113 pib_old = phy->pib;
114 rcu_assign_pointer(phy->pib, pib);
115 kfree_rcu(pib_old, rcu);
116 return 0;
117}
118
119static int hwsim_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
120{
121 struct hwsim_phy *current_phy = hw->priv;
122 struct hwsim_pib *current_pib, *endpoint_pib;
123 struct hwsim_edge_info *einfo;
124 struct hwsim_edge *e;
125
126 WARN_ON(current_phy->suspended);
127
128 rcu_read_lock();
129 current_pib = rcu_dereference(current_phy->pib);
130 list_for_each_entry_rcu(e, &current_phy->edges, list) {
131 /* Can be changed later in rx_irqsafe, but this is only a
132 * performance tweak. Received radio should drop the frame
133 * in mac802154 stack anyway... so we don't need to be
134 * 100% of locking here to check on suspended
135 */
136 if (e->endpoint->suspended)
137 continue;
138
139 endpoint_pib = rcu_dereference(e->endpoint->pib);
140 if (current_pib->page == endpoint_pib->page &&
141 current_pib->channel == endpoint_pib->channel) {
142 struct sk_buff *newskb = pskb_copy(skb, GFP_ATOMIC);
143
144 einfo = rcu_dereference(e->info);
145 if (newskb)
146 ieee802154_rx_irqsafe(e->endpoint->hw, newskb,
147 einfo->lqi);
148 }
149 }
150 rcu_read_unlock();
151
152 ieee802154_xmit_complete(hw, skb, false);
153 return 0;
154}
155
156static int hwsim_hw_start(struct ieee802154_hw *hw)
157{
158 struct hwsim_phy *phy = hw->priv;
159
160 phy->suspended = false;
161 list_add_rcu(&phy->list_ifup, &hwsim_ifup_phys);
162 synchronize_rcu();
163
164 return 0;
165}
166
167static void hwsim_hw_stop(struct ieee802154_hw *hw)
168{
169 struct hwsim_phy *phy = hw->priv;
170
171 phy->suspended = true;
172 list_del_rcu(&phy->list_ifup);
173 synchronize_rcu();
174}
175
176static int
177hwsim_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
178{
179 return 0;
180}
181
182static const struct ieee802154_ops hwsim_ops = {
183 .owner = THIS_MODULE,
184 .xmit_async = hwsim_hw_xmit,
185 .ed = hwsim_hw_ed,
186 .set_channel = hwsim_hw_channel,
187 .start = hwsim_hw_start,
188 .stop = hwsim_hw_stop,
189 .set_promiscuous_mode = hwsim_set_promiscuous_mode,
190};
191
192static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info)
193{
194 return hwsim_add_one(info, &mac802154hwsim_dev->dev, false);
195}
196
197static int hwsim_del_radio_nl(struct sk_buff *msg, struct genl_info *info)
198{
199 struct hwsim_phy *phy, *tmp;
200 s64 idx = -1;
201
202 if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID])
203 return -EINVAL;
204
205 idx = nla_get_u32(info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID]);
206
207 mutex_lock(&hwsim_phys_lock);
208 list_for_each_entry_safe(phy, tmp, &hwsim_phys, list) {
209 if (idx == phy->idx) {
210 hwsim_del(phy);
211 mutex_unlock(&hwsim_phys_lock);
212 return 0;
213 }
214 }
215 mutex_unlock(&hwsim_phys_lock);
216
217 return -ENODEV;
218}
219
220static int append_radio_msg(struct sk_buff *skb, struct hwsim_phy *phy)
221{
222 struct nlattr *nl_edges, *nl_edge;
223 struct hwsim_edge_info *einfo;
224 struct hwsim_edge *e;
225 int ret;
226
227 ret = nla_put_u32(skb, MAC802154_HWSIM_ATTR_RADIO_ID, phy->idx);
228 if (ret < 0)
229 return ret;
230
231 rcu_read_lock();
232 if (list_empty(&phy->edges)) {
233 rcu_read_unlock();
234 return 0;
235 }
236
237 nl_edges = nla_nest_start(skb, MAC802154_HWSIM_ATTR_RADIO_EDGES);
238 if (!nl_edges) {
239 rcu_read_unlock();
240 return -ENOBUFS;
241 }
242
243 list_for_each_entry_rcu(e, &phy->edges, list) {
244 nl_edge = nla_nest_start(skb, MAC802154_HWSIM_ATTR_RADIO_EDGE);
245 if (!nl_edge) {
246 rcu_read_unlock();
247 nla_nest_cancel(skb, nl_edges);
248 return -ENOBUFS;
249 }
250
251 ret = nla_put_u32(skb, MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID,
252 e->endpoint->idx);
253 if (ret < 0) {
254 rcu_read_unlock();
255 nla_nest_cancel(skb, nl_edge);
256 nla_nest_cancel(skb, nl_edges);
257 return ret;
258 }
259
260 einfo = rcu_dereference(e->info);
261 ret = nla_put_u8(skb, MAC802154_HWSIM_EDGE_ATTR_LQI,
262 einfo->lqi);
263 if (ret < 0) {
264 rcu_read_unlock();
265 nla_nest_cancel(skb, nl_edge);
266 nla_nest_cancel(skb, nl_edges);
267 return ret;
268 }
269
270 nla_nest_end(skb, nl_edge);
271 }
272 rcu_read_unlock();
273
274 nla_nest_end(skb, nl_edges);
275
276 return 0;
277}
278
279static int hwsim_get_radio(struct sk_buff *skb, struct hwsim_phy *phy,
280 u32 portid, u32 seq,
281 struct netlink_callback *cb, int flags)
282{
283 void *hdr;
284 int res = -EMSGSIZE;
285
286 hdr = genlmsg_put(skb, portid, seq, &hwsim_genl_family, flags,
287 MAC802154_HWSIM_CMD_GET_RADIO);
288 if (!hdr)
289 return -EMSGSIZE;
290
291 if (cb)
292 genl_dump_check_consistent(cb, hdr);
293
294 res = append_radio_msg(skb, phy);
295 if (res < 0)
296 goto out_err;
297
298 genlmsg_end(skb, hdr);
299 return 0;
300
301out_err:
302 genlmsg_cancel(skb, hdr);
303 return res;
304}
305
306static int hwsim_get_radio_nl(struct sk_buff *msg, struct genl_info *info)
307{
308 struct hwsim_phy *phy;
309 struct sk_buff *skb;
310 int idx, res = -ENODEV;
311
312 if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID])
313 return -EINVAL;
314 idx = nla_get_u32(info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID]);
315
316 mutex_lock(&hwsim_phys_lock);
317 list_for_each_entry(phy, &hwsim_phys, list) {
318 if (phy->idx != idx)
319 continue;
320
321 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
322 if (!skb) {
323 res = -ENOMEM;
324 goto out_err;
325 }
326
327 res = hwsim_get_radio(skb, phy, info->snd_portid,
328 info->snd_seq, NULL, 0);
329 if (res < 0) {
330 nlmsg_free(skb);
331 goto out_err;
332 }
333
334 genlmsg_reply(skb, info);
335 break;
336 }
337
338out_err:
339 mutex_unlock(&hwsim_phys_lock);
340
341 return res;
342}
343
344static int hwsim_dump_radio_nl(struct sk_buff *skb,
345 struct netlink_callback *cb)
346{
347 int idx = cb->args[0];
348 struct hwsim_phy *phy;
349 int res;
350
351 mutex_lock(&hwsim_phys_lock);
352
353 if (idx == hwsim_radio_idx)
354 goto done;
355
356 list_for_each_entry(phy, &hwsim_phys, list) {
357 if (phy->idx < idx)
358 continue;
359
360 res = hwsim_get_radio(skb, phy, NETLINK_CB(cb->skb).portid,
361 cb->nlh->nlmsg_seq, cb, NLM_F_MULTI);
362 if (res < 0)
363 break;
364
365 idx = phy->idx + 1;
366 }
367
368 cb->args[0] = idx;
369
370done:
371 mutex_unlock(&hwsim_phys_lock);
372 return skb->len;
373}
374
375/* caller need to held hwsim_phys_lock */
376static struct hwsim_phy *hwsim_get_radio_by_id(uint32_t idx)
377{
378 struct hwsim_phy *phy;
379
380 list_for_each_entry(phy, &hwsim_phys, list) {
381 if (phy->idx == idx)
382 return phy;
383 }
384
385 return NULL;
386}
387
388static const struct nla_policy hwsim_edge_policy[MAC802154_HWSIM_EDGE_ATTR_MAX + 1] = {
389 [MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID] = { .type = NLA_U32 },
390 [MAC802154_HWSIM_EDGE_ATTR_LQI] = { .type = NLA_U8 },
391};
392
393static struct hwsim_edge *hwsim_alloc_edge(struct hwsim_phy *endpoint, u8 lqi)
394{
395 struct hwsim_edge_info *einfo;
396 struct hwsim_edge *e;
397
398 e = kzalloc(sizeof(*e), GFP_KERNEL);
399 if (!e)
400 return NULL;
401
402 einfo = kzalloc(sizeof(*einfo), GFP_KERNEL);
403 if (!einfo) {
404 kfree(e);
405 return NULL;
406 }
407
408 einfo->lqi = 0xff;
409 e->info = einfo;
410 e->endpoint = endpoint;
411
412 return e;
413}
414
415static void hwsim_free_edge(struct hwsim_edge *e)
416{
417 kfree_rcu(e->info, rcu);
418 kfree_rcu(e, rcu);
419}
420
421static int hwsim_new_edge_nl(struct sk_buff *msg, struct genl_info *info)
422{
423 struct nlattr *edge_attrs[MAC802154_HWSIM_EDGE_ATTR_MAX + 1];
424 struct hwsim_phy *phy_v0, *phy_v1;
425 struct hwsim_edge *e;
426 u32 v0, v1;
427
428 if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID] &&
429 !info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE])
430 return -EINVAL;
431
432 if (nla_parse_nested(edge_attrs, MAC802154_HWSIM_EDGE_ATTR_MAX,
433 info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE],
434 hwsim_edge_policy, NULL))
435 return -EINVAL;
436
437 if (!edge_attrs[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID])
438 return -EINVAL;
439
440 v0 = nla_get_u32(info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID]);
441 v1 = nla_get_u32(edge_attrs[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID]);
442
443 if (v0 == v1)
444 return -EINVAL;
445
446 mutex_lock(&hwsim_phys_lock);
447 phy_v0 = hwsim_get_radio_by_id(v0);
448 if (!phy_v0) {
449 mutex_unlock(&hwsim_phys_lock);
450 return -ENOENT;
451 }
452
453 phy_v1 = hwsim_get_radio_by_id(v1);
454 if (!phy_v1) {
455 mutex_unlock(&hwsim_phys_lock);
456 return -ENOENT;
457 }
458
459 rcu_read_lock();
460 list_for_each_entry_rcu(e, &phy_v0->edges, list) {
461 if (e->endpoint->idx == v1) {
462 mutex_unlock(&hwsim_phys_lock);
463 rcu_read_unlock();
464 return -EEXIST;
465 }
466 }
467 rcu_read_unlock();
468
469 e = hwsim_alloc_edge(phy_v1, 0xff);
470 if (!e) {
471 mutex_unlock(&hwsim_phys_lock);
472 return -ENOMEM;
473 }
474 list_add_rcu(&e->list, &phy_v0->edges);
475 /* wait until changes are done under hwsim_phys_lock lock
476 * should prevent of calling this function twice while
477 * edges list has not the changes yet.
478 */
479 synchronize_rcu();
480 mutex_unlock(&hwsim_phys_lock);
481
482 return 0;
483}
484
485static int hwsim_del_edge_nl(struct sk_buff *msg, struct genl_info *info)
486{
487 struct nlattr *edge_attrs[MAC802154_HWSIM_EDGE_ATTR_MAX + 1];
488 struct hwsim_phy *phy_v0;
489 struct hwsim_edge *e;
490 u32 v0, v1;
491
492 if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID] &&
493 !info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE])
494 return -EINVAL;
495
496 if (nla_parse_nested(edge_attrs, MAC802154_HWSIM_EDGE_ATTR_MAX + 1,
497 info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE],
498 hwsim_edge_policy, NULL))
499 return -EINVAL;
500
501 if (!edge_attrs[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID])
502 return -EINVAL;
503
504 v0 = nla_get_u32(info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID]);
505 v1 = nla_get_u32(edge_attrs[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID]);
506
507 mutex_lock(&hwsim_phys_lock);
508 phy_v0 = hwsim_get_radio_by_id(v0);
509 if (!phy_v0) {
510 mutex_unlock(&hwsim_phys_lock);
511 return -ENOENT;
512 }
513
514 rcu_read_lock();
515 list_for_each_entry_rcu(e, &phy_v0->edges, list) {
516 if (e->endpoint->idx == v1) {
517 rcu_read_unlock();
518 list_del_rcu(&e->list);
519 hwsim_free_edge(e);
520 /* same again - wait until list changes are done */
521 synchronize_rcu();
522 mutex_unlock(&hwsim_phys_lock);
523 return 0;
524 }
525 }
526 rcu_read_unlock();
527
528 mutex_unlock(&hwsim_phys_lock);
529
530 return -ENOENT;
531}
532
533static int hwsim_set_edge_lqi(struct sk_buff *msg, struct genl_info *info)
534{
535 struct nlattr *edge_attrs[MAC802154_HWSIM_EDGE_ATTR_MAX + 1];
536 struct hwsim_edge_info *einfo;
537 struct hwsim_phy *phy_v0;
538 struct hwsim_edge *e;
539 u32 v0, v1;
540 u8 lqi;
541
542 if (!info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID] &&
543 !info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE])
544 return -EINVAL;
545
546 if (nla_parse_nested(edge_attrs, MAC802154_HWSIM_EDGE_ATTR_MAX + 1,
547 info->attrs[MAC802154_HWSIM_ATTR_RADIO_EDGE],
548 hwsim_edge_policy, NULL))
549 return -EINVAL;
550
551 if (!edge_attrs[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID] &&
552 !edge_attrs[MAC802154_HWSIM_EDGE_ATTR_LQI])
553 return -EINVAL;
554
555 v0 = nla_get_u32(info->attrs[MAC802154_HWSIM_ATTR_RADIO_ID]);
556 v1 = nla_get_u32(edge_attrs[MAC802154_HWSIM_EDGE_ATTR_ENDPOINT_ID]);
557 lqi = nla_get_u8(edge_attrs[MAC802154_HWSIM_EDGE_ATTR_LQI]);
558
559 mutex_lock(&hwsim_phys_lock);
560 phy_v0 = hwsim_get_radio_by_id(v0);
561 if (!phy_v0) {
562 mutex_unlock(&hwsim_phys_lock);
563 return -ENOENT;
564 }
565
566 einfo = kzalloc(sizeof(*einfo), GFP_KERNEL);
567 if (!info) {
568 mutex_unlock(&hwsim_phys_lock);
569 return -ENOMEM;
570 }
571
572 rcu_read_lock();
573 list_for_each_entry_rcu(e, &phy_v0->edges, list) {
574 if (e->endpoint->idx == v1) {
575 einfo->lqi = lqi;
576 rcu_assign_pointer(e->info, einfo);
577 rcu_read_unlock();
578 mutex_unlock(&hwsim_phys_lock);
579 return 0;
580 }
581 }
582 rcu_read_unlock();
583
584 kfree(einfo);
585 mutex_unlock(&hwsim_phys_lock);
586
587 return -ENOENT;
588}
589
590/* MAC802154_HWSIM netlink policy */
591
592static const struct nla_policy hwsim_genl_policy[MAC802154_HWSIM_ATTR_MAX + 1] = {
593 [MAC802154_HWSIM_ATTR_RADIO_ID] = { .type = NLA_U32 },
594 [MAC802154_HWSIM_ATTR_RADIO_EDGE] = { .type = NLA_NESTED },
595 [MAC802154_HWSIM_ATTR_RADIO_EDGES] = { .type = NLA_NESTED },
596};
597
598/* Generic Netlink operations array */
599static const struct genl_ops hwsim_nl_ops[] = {
600 {
601 .cmd = MAC802154_HWSIM_CMD_NEW_RADIO,
602 .policy = hwsim_genl_policy,
603 .doit = hwsim_new_radio_nl,
604 .flags = GENL_UNS_ADMIN_PERM,
605 },
606 {
607 .cmd = MAC802154_HWSIM_CMD_DEL_RADIO,
608 .policy = hwsim_genl_policy,
609 .doit = hwsim_del_radio_nl,
610 .flags = GENL_UNS_ADMIN_PERM,
611 },
612 {
613 .cmd = MAC802154_HWSIM_CMD_GET_RADIO,
614 .policy = hwsim_genl_policy,
615 .doit = hwsim_get_radio_nl,
616 .dumpit = hwsim_dump_radio_nl,
617 },
618 {
619 .cmd = MAC802154_HWSIM_CMD_NEW_EDGE,
620 .policy = hwsim_genl_policy,
621 .doit = hwsim_new_edge_nl,
622 .flags = GENL_UNS_ADMIN_PERM,
623 },
624 {
625 .cmd = MAC802154_HWSIM_CMD_DEL_EDGE,
626 .policy = hwsim_genl_policy,
627 .doit = hwsim_del_edge_nl,
628 .flags = GENL_UNS_ADMIN_PERM,
629 },
630 {
631 .cmd = MAC802154_HWSIM_CMD_SET_EDGE,
632 .policy = hwsim_genl_policy,
633 .doit = hwsim_set_edge_lqi,
634 .flags = GENL_UNS_ADMIN_PERM,
635 },
636};
637
638static struct genl_family hwsim_genl_family __ro_after_init = {
639 .name = "MAC802154_HWSIM",
640 .version = 1,
641 .maxattr = MAC802154_HWSIM_ATTR_MAX,
642 .module = THIS_MODULE,
643 .ops = hwsim_nl_ops,
644 .n_ops = ARRAY_SIZE(hwsim_nl_ops),
645 .mcgrps = hwsim_mcgrps,
646 .n_mcgrps = ARRAY_SIZE(hwsim_mcgrps),
647};
648
649static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb,
650 struct genl_info *info)
651{
652 if (info)
653 genl_notify(&hwsim_genl_family, mcast_skb, info,
654 HWSIM_MCGRP_CONFIG, GFP_KERNEL);
655 else
656 genlmsg_multicast(&hwsim_genl_family, mcast_skb, 0,
657 HWSIM_MCGRP_CONFIG, GFP_KERNEL);
658}
659
660static void hwsim_mcast_new_radio(struct genl_info *info, struct hwsim_phy *phy)
661{
662 struct sk_buff *mcast_skb;
663 void *data;
664
665 mcast_skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
666 if (!mcast_skb)
667 return;
668
669 data = genlmsg_put(mcast_skb, 0, 0, &hwsim_genl_family, 0,
670 MAC802154_HWSIM_CMD_NEW_RADIO);
671 if (!data)
672 goto out_err;
673
674 if (append_radio_msg(mcast_skb, phy) < 0)
675 goto out_err;
676
677 genlmsg_end(mcast_skb, data);
678
679 hwsim_mcast_config_msg(mcast_skb, info);
680 return;
681
682out_err:
683 genlmsg_cancel(mcast_skb, data);
684 nlmsg_free(mcast_skb);
685}
686
687static void hwsim_edge_unsubscribe_me(struct hwsim_phy *phy)
688{
689 struct hwsim_phy *tmp;
690 struct hwsim_edge *e;
691
692 rcu_read_lock();
693 /* going to all phy edges and remove phy from it */
694 list_for_each_entry(tmp, &hwsim_phys, list) {
695 list_for_each_entry_rcu(e, &tmp->edges, list) {
696 if (e->endpoint->idx == phy->idx) {
697 list_del_rcu(&e->list);
698 hwsim_free_edge(e);
699 }
700 }
701 }
702 rcu_read_unlock();
703
704 synchronize_rcu();
705}
706
707static int hwsim_subscribe_all_others(struct hwsim_phy *phy)
708{
709 struct hwsim_phy *sub;
710 struct hwsim_edge *e;
711
712 list_for_each_entry(sub, &hwsim_phys, list) {
713 e = hwsim_alloc_edge(sub, 0xff);
714 if (!e)
715 goto me_fail;
716
717 list_add_rcu(&e->list, &phy->edges);
718 }
719
720 list_for_each_entry(sub, &hwsim_phys, list) {
721 e = hwsim_alloc_edge(phy, 0xff);
722 if (!e)
723 goto sub_fail;
724
725 list_add_rcu(&e->list, &sub->edges);
726 }
727
728 return 0;
729
730me_fail:
731 list_for_each_entry(phy, &hwsim_phys, list) {
732 list_del_rcu(&e->list);
733 hwsim_free_edge(e);
734 }
735sub_fail:
736 hwsim_edge_unsubscribe_me(phy);
737 return -ENOMEM;
738}
739
740static int hwsim_add_one(struct genl_info *info, struct device *dev,
741 bool init)
742{
743 struct ieee802154_hw *hw;
744 struct hwsim_phy *phy;
745 struct hwsim_pib *pib;
746 int idx;
747 int err;
748
749 idx = hwsim_radio_idx++;
750
751 hw = ieee802154_alloc_hw(sizeof(*phy), &hwsim_ops);
752 if (!hw)
753 return -ENOMEM;
754
755 phy = hw->priv;
756 phy->hw = hw;
757
758 /* 868 MHz BPSK 802.15.4-2003 */
759 hw->phy->supported.channels[0] |= 1;
760 /* 915 MHz BPSK 802.15.4-2003 */
761 hw->phy->supported.channels[0] |= 0x7fe;
762 /* 2.4 GHz O-QPSK 802.15.4-2003 */
763 hw->phy->supported.channels[0] |= 0x7FFF800;
764 /* 868 MHz ASK 802.15.4-2006 */
765 hw->phy->supported.channels[1] |= 1;
766 /* 915 MHz ASK 802.15.4-2006 */
767 hw->phy->supported.channels[1] |= 0x7fe;
768 /* 868 MHz O-QPSK 802.15.4-2006 */
769 hw->phy->supported.channels[2] |= 1;
770 /* 915 MHz O-QPSK 802.15.4-2006 */
771 hw->phy->supported.channels[2] |= 0x7fe;
772 /* 2.4 GHz CSS 802.15.4a-2007 */
773 hw->phy->supported.channels[3] |= 0x3fff;
774 /* UWB Sub-gigahertz 802.15.4a-2007 */
775 hw->phy->supported.channels[4] |= 1;
776 /* UWB Low band 802.15.4a-2007 */
777 hw->phy->supported.channels[4] |= 0x1e;
778 /* UWB High band 802.15.4a-2007 */
779 hw->phy->supported.channels[4] |= 0xffe0;
780 /* 750 MHz O-QPSK 802.15.4c-2009 */
781 hw->phy->supported.channels[5] |= 0xf;
782 /* 750 MHz MPSK 802.15.4c-2009 */
783 hw->phy->supported.channels[5] |= 0xf0;
784 /* 950 MHz BPSK 802.15.4d-2009 */
785 hw->phy->supported.channels[6] |= 0x3ff;
786 /* 950 MHz GFSK 802.15.4d-2009 */
787 hw->phy->supported.channels[6] |= 0x3ffc00;
788
789 ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
790
791 /* hwsim phy channel 13 as default */
792 hw->phy->current_channel = 13;
793 pib = kzalloc(sizeof(*pib), GFP_KERNEL);
794 if (!pib) {
795 err = -ENOMEM;
796 goto err_pib;
797 }
798
799 phy->pib = pib;
800 phy->idx = idx;
801 INIT_LIST_HEAD(&phy->edges);
802
803 hw->flags = IEEE802154_HW_PROMISCUOUS;
804 hw->parent = dev;
805
806 err = ieee802154_register_hw(hw);
807 if (err)
808 goto err_reg;
809
810 mutex_lock(&hwsim_phys_lock);
811 if (init) {
812 err = hwsim_subscribe_all_others(phy);
813 if (err < 0)
814 goto err_reg;
815 }
816 list_add_tail(&phy->list, &hwsim_phys);
817 mutex_unlock(&hwsim_phys_lock);
818
819 hwsim_mcast_new_radio(info, phy);
820
821 return idx;
822
823err_reg:
824 kfree(pib);
825err_pib:
826 ieee802154_free_hw(phy->hw);
827 return err;
828}
829
830static void hwsim_del(struct hwsim_phy *phy)
831{
832 hwsim_edge_unsubscribe_me(phy);
833
834 list_del(&phy->list);
835 kfree_rcu(phy->pib, rcu);
836
837 ieee802154_unregister_hw(phy->hw);
838 ieee802154_free_hw(phy->hw);
839}
840
841static int hwsim_probe(struct platform_device *pdev)
842{
843 struct hwsim_phy *phy, *tmp;
844 int err, i;
845
846 for (i = 0; i < 2; i++) {
847 err = hwsim_add_one(NULL, &pdev->dev, true);
848 if (err < 0)
849 goto err_slave;
850 }
851
852 dev_info(&pdev->dev, "Added 2 mac802154 hwsim hardware radios\n");
853 return 0;
854
855err_slave:
856 mutex_lock(&hwsim_phys_lock);
857 list_for_each_entry_safe(phy, tmp, &hwsim_phys, list)
858 hwsim_del(phy);
859 mutex_unlock(&hwsim_phys_lock);
860 return err;
861}
862
863static int hwsim_remove(struct platform_device *pdev)
864{
865 struct hwsim_phy *phy, *tmp;
866
867 mutex_lock(&hwsim_phys_lock);
868 list_for_each_entry_safe(phy, tmp, &hwsim_phys, list)
869 hwsim_del(phy);
870 mutex_unlock(&hwsim_phys_lock);
871
872 return 0;
873}
874
875static struct platform_driver mac802154hwsim_driver = {
876 .probe = hwsim_probe,
877 .remove = hwsim_remove,
878 .driver = {
879 .name = "mac802154_hwsim",
880 },
881};
882
883static __init int hwsim_init_module(void)
884{
885 int rc;
886
887 rc = genl_register_family(&hwsim_genl_family);
888 if (rc)
889 return rc;
890
891 mac802154hwsim_dev = platform_device_register_simple("mac802154_hwsim",
892 -1, NULL, 0);
893 if (IS_ERR(mac802154hwsim_dev)) {
894 rc = PTR_ERR(mac802154hwsim_dev);
895 goto platform_dev;
896 }
897
898 rc = platform_driver_register(&mac802154hwsim_driver);
899 if (rc < 0)
900 goto platform_drv;
901
902 return 0;
903
904platform_drv:
905 genl_unregister_family(&hwsim_genl_family);
906platform_dev:
907 platform_device_unregister(mac802154hwsim_dev);
908 return rc;
909}
910
911static __exit void hwsim_remove_module(void)
912{
913 genl_unregister_family(&hwsim_genl_family);
914 platform_driver_unregister(&mac802154hwsim_driver);
915 platform_device_unregister(mac802154hwsim_dev);
916}
917
918module_init(hwsim_init_module);
919module_exit(hwsim_remove_module);