]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - net/ieee802154/nl802154.c
Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[karo-tx-linux.git] / net / ieee802154 / nl802154.c
1 /* This program is free software; you can redistribute it and/or modify
2  * it under the terms of the GNU General Public License version 2
3  * as published by the Free Software Foundation.
4  *
5  * This program is distributed in the hope that it will be useful,
6  * but WITHOUT ANY WARRANTY; without even the implied warranty of
7  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
8  * GNU General Public License for more details.
9  *
10  * Authors:
11  * Alexander Aring <aar@pengutronix.de>
12  *
13  * Based on: net/wireless/nl80211.c
14  */
15
16 #include <linux/rtnetlink.h>
17
18 #include <net/cfg802154.h>
19 #include <net/genetlink.h>
20 #include <net/mac802154.h>
21 #include <net/netlink.h>
22 #include <net/nl802154.h>
23 #include <net/sock.h>
24
25 #include "nl802154.h"
26 #include "rdev-ops.h"
27 #include "core.h"
28
29 static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
30                              struct genl_info *info);
31
32 static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
33                                struct genl_info *info);
34
35 /* the netlink family */
36 static struct genl_family nl802154_fam = {
37         .id = GENL_ID_GENERATE,         /* don't bother with a hardcoded ID */
38         .name = NL802154_GENL_NAME,     /* have users key off the name instead */
39         .hdrsize = 0,                   /* no private header */
40         .version = 1,                   /* no particular meaning now */
41         .maxattr = NL802154_ATTR_MAX,
42         .netnsok = true,
43         .pre_doit = nl802154_pre_doit,
44         .post_doit = nl802154_post_doit,
45 };
46
47 /* multicast groups */
48 enum nl802154_multicast_groups {
49         NL802154_MCGRP_CONFIG,
50 };
51
52 static const struct genl_multicast_group nl802154_mcgrps[] = {
53         [NL802154_MCGRP_CONFIG] = { .name = "config", },
54 };
55
56 /* returns ERR_PTR values */
57 static struct wpan_dev *
58 __cfg802154_wpan_dev_from_attrs(struct net *netns, struct nlattr **attrs)
59 {
60         struct cfg802154_registered_device *rdev;
61         struct wpan_dev *result = NULL;
62         bool have_ifidx = attrs[NL802154_ATTR_IFINDEX];
63         bool have_wpan_dev_id = attrs[NL802154_ATTR_WPAN_DEV];
64         u64 wpan_dev_id;
65         int wpan_phy_idx = -1;
66         int ifidx = -1;
67
68         ASSERT_RTNL();
69
70         if (!have_ifidx && !have_wpan_dev_id)
71                 return ERR_PTR(-EINVAL);
72
73         if (have_ifidx)
74                 ifidx = nla_get_u32(attrs[NL802154_ATTR_IFINDEX]);
75         if (have_wpan_dev_id) {
76                 wpan_dev_id = nla_get_u64(attrs[NL802154_ATTR_WPAN_DEV]);
77                 wpan_phy_idx = wpan_dev_id >> 32;
78         }
79
80         list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
81                 struct wpan_dev *wpan_dev;
82
83                 /* TODO netns compare */
84
85                 if (have_wpan_dev_id && rdev->wpan_phy_idx != wpan_phy_idx)
86                         continue;
87
88                 list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) {
89                         if (have_ifidx && wpan_dev->netdev &&
90                             wpan_dev->netdev->ifindex == ifidx) {
91                                 result = wpan_dev;
92                                 break;
93                         }
94                         if (have_wpan_dev_id &&
95                             wpan_dev->identifier == (u32)wpan_dev_id) {
96                                 result = wpan_dev;
97                                 break;
98                         }
99                 }
100
101                 if (result)
102                         break;
103         }
104
105         if (result)
106                 return result;
107
108         return ERR_PTR(-ENODEV);
109 }
110
111 static struct cfg802154_registered_device *
112 __cfg802154_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
113 {
114         struct cfg802154_registered_device *rdev = NULL, *tmp;
115         struct net_device *netdev;
116
117         ASSERT_RTNL();
118
119         if (!attrs[NL802154_ATTR_WPAN_PHY] &&
120             !attrs[NL802154_ATTR_IFINDEX] &&
121             !attrs[NL802154_ATTR_WPAN_DEV])
122                 return ERR_PTR(-EINVAL);
123
124         if (attrs[NL802154_ATTR_WPAN_PHY])
125                 rdev = cfg802154_rdev_by_wpan_phy_idx(
126                                 nla_get_u32(attrs[NL802154_ATTR_WPAN_PHY]));
127
128         if (attrs[NL802154_ATTR_WPAN_DEV]) {
129                 u64 wpan_dev_id = nla_get_u64(attrs[NL802154_ATTR_WPAN_DEV]);
130                 struct wpan_dev *wpan_dev;
131                 bool found = false;
132
133                 tmp = cfg802154_rdev_by_wpan_phy_idx(wpan_dev_id >> 32);
134                 if (tmp) {
135                         /* make sure wpan_dev exists */
136                         list_for_each_entry(wpan_dev, &tmp->wpan_dev_list, list) {
137                                 if (wpan_dev->identifier != (u32)wpan_dev_id)
138                                         continue;
139                                 found = true;
140                                 break;
141                         }
142
143                         if (!found)
144                                 tmp = NULL;
145
146                         if (rdev && tmp != rdev)
147                                 return ERR_PTR(-EINVAL);
148                         rdev = tmp;
149                 }
150         }
151
152         if (attrs[NL802154_ATTR_IFINDEX]) {
153                 int ifindex = nla_get_u32(attrs[NL802154_ATTR_IFINDEX]);
154
155                 netdev = __dev_get_by_index(netns, ifindex);
156                 if (netdev) {
157                         if (netdev->ieee802154_ptr)
158                                 tmp = wpan_phy_to_rdev(
159                                                 netdev->ieee802154_ptr->wpan_phy);
160                         else
161                                 tmp = NULL;
162
163                         /* not wireless device -- return error */
164                         if (!tmp)
165                                 return ERR_PTR(-EINVAL);
166
167                         /* mismatch -- return error */
168                         if (rdev && tmp != rdev)
169                                 return ERR_PTR(-EINVAL);
170
171                         rdev = tmp;
172                 }
173         }
174
175         if (!rdev)
176                 return ERR_PTR(-ENODEV);
177
178         /* TODO netns compare */
179
180         return rdev;
181 }
182
183 /* This function returns a pointer to the driver
184  * that the genl_info item that is passed refers to.
185  *
186  * The result of this can be a PTR_ERR and hence must
187  * be checked with IS_ERR() for errors.
188  */
189 static struct cfg802154_registered_device *
190 cfg802154_get_dev_from_info(struct net *netns, struct genl_info *info)
191 {
192         return __cfg802154_rdev_from_attrs(netns, info->attrs);
193 }
194
195 /* policy for the attributes */
196 static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = {
197         [NL802154_ATTR_WPAN_PHY] = { .type = NLA_U32 },
198         [NL802154_ATTR_WPAN_PHY_NAME] = { .type = NLA_NUL_STRING,
199                                           .len = 20-1 },
200
201         [NL802154_ATTR_IFINDEX] = { .type = NLA_U32 },
202         [NL802154_ATTR_IFTYPE] = { .type = NLA_U32 },
203         [NL802154_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
204
205         [NL802154_ATTR_WPAN_DEV] = { .type = NLA_U64 },
206
207         [NL802154_ATTR_PAGE] = { .type = NLA_U8, },
208         [NL802154_ATTR_CHANNEL] = { .type = NLA_U8, },
209
210         [NL802154_ATTR_TX_POWER] = { .type = NLA_S32, },
211
212         [NL802154_ATTR_CCA_MODE] = { .type = NLA_U32, },
213         [NL802154_ATTR_CCA_OPT] = { .type = NLA_U32, },
214         [NL802154_ATTR_CCA_ED_LEVEL] = { .type = NLA_S32, },
215
216         [NL802154_ATTR_SUPPORTED_CHANNEL] = { .type = NLA_U32, },
217
218         [NL802154_ATTR_PAN_ID] = { .type = NLA_U16, },
219         [NL802154_ATTR_EXTENDED_ADDR] = { .type = NLA_U64 },
220         [NL802154_ATTR_SHORT_ADDR] = { .type = NLA_U16, },
221
222         [NL802154_ATTR_MIN_BE] = { .type = NLA_U8, },
223         [NL802154_ATTR_MAX_BE] = { .type = NLA_U8, },
224         [NL802154_ATTR_MAX_CSMA_BACKOFFS] = { .type = NLA_U8, },
225
226         [NL802154_ATTR_MAX_FRAME_RETRIES] = { .type = NLA_S8, },
227
228         [NL802154_ATTR_LBT_MODE] = { .type = NLA_U8, },
229
230         [NL802154_ATTR_WPAN_PHY_CAPS] = { .type = NLA_NESTED },
231
232         [NL802154_ATTR_SUPPORTED_COMMANDS] = { .type = NLA_NESTED },
233 };
234
235 /* message building helper */
236 static inline void *nl802154hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
237                                     int flags, u8 cmd)
238 {
239         /* since there is no private header just add the generic one */
240         return genlmsg_put(skb, portid, seq, &nl802154_fam, flags, cmd);
241 }
242
243 static int
244 nl802154_put_flags(struct sk_buff *msg, int attr, u32 mask)
245 {
246         struct nlattr *nl_flags = nla_nest_start(msg, attr);
247         int i;
248
249         if (!nl_flags)
250                 return -ENOBUFS;
251
252         i = 0;
253         while (mask) {
254                 if ((mask & 1) && nla_put_flag(msg, i))
255                         return -ENOBUFS;
256
257                 mask >>= 1;
258                 i++;
259         }
260
261         nla_nest_end(msg, nl_flags);
262         return 0;
263 }
264
265 static int
266 nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev,
267                                 struct sk_buff *msg)
268 {
269         struct nlattr *nl_page;
270         unsigned long page;
271
272         nl_page = nla_nest_start(msg, NL802154_ATTR_CHANNELS_SUPPORTED);
273         if (!nl_page)
274                 return -ENOBUFS;
275
276         for (page = 0; page <= IEEE802154_MAX_PAGE; page++) {
277                 if (nla_put_u32(msg, NL802154_ATTR_SUPPORTED_CHANNEL,
278                                 rdev->wpan_phy.supported.channels[page]))
279                         return -ENOBUFS;
280         }
281         nla_nest_end(msg, nl_page);
282
283         return 0;
284 }
285
286 static int
287 nl802154_put_capabilities(struct sk_buff *msg,
288                           struct cfg802154_registered_device *rdev)
289 {
290         const struct wpan_phy_supported *caps = &rdev->wpan_phy.supported;
291         struct nlattr *nl_caps, *nl_channels;
292         int i;
293
294         nl_caps = nla_nest_start(msg, NL802154_ATTR_WPAN_PHY_CAPS);
295         if (!nl_caps)
296                 return -ENOBUFS;
297
298         nl_channels = nla_nest_start(msg, NL802154_CAP_ATTR_CHANNELS);
299         if (!nl_channels)
300                 return -ENOBUFS;
301
302         for (i = 0; i <= IEEE802154_MAX_PAGE; i++) {
303                 if (caps->channels[i]) {
304                         if (nl802154_put_flags(msg, i, caps->channels[i]))
305                                 return -ENOBUFS;
306                 }
307         }
308
309         nla_nest_end(msg, nl_channels);
310
311         if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) {
312                 struct nlattr *nl_ed_lvls;
313
314                 nl_ed_lvls = nla_nest_start(msg,
315                                             NL802154_CAP_ATTR_CCA_ED_LEVELS);
316                 if (!nl_ed_lvls)
317                         return -ENOBUFS;
318
319                 for (i = 0; i < caps->cca_ed_levels_size; i++) {
320                         if (nla_put_s32(msg, i, caps->cca_ed_levels[i]))
321                                 return -ENOBUFS;
322                 }
323
324                 nla_nest_end(msg, nl_ed_lvls);
325         }
326
327         if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) {
328                 struct nlattr *nl_tx_pwrs;
329
330                 nl_tx_pwrs = nla_nest_start(msg, NL802154_CAP_ATTR_TX_POWERS);
331                 if (!nl_tx_pwrs)
332                         return -ENOBUFS;
333
334                 for (i = 0; i < caps->tx_powers_size; i++) {
335                         if (nla_put_s32(msg, i, caps->tx_powers[i]))
336                                 return -ENOBUFS;
337                 }
338
339                 nla_nest_end(msg, nl_tx_pwrs);
340         }
341
342         if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) {
343                 if (nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_MODES,
344                                        caps->cca_modes) ||
345                     nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_OPTS,
346                                        caps->cca_opts))
347                         return -ENOBUFS;
348         }
349
350         if (nla_put_u8(msg, NL802154_CAP_ATTR_MIN_MINBE, caps->min_minbe) ||
351             nla_put_u8(msg, NL802154_CAP_ATTR_MAX_MINBE, caps->max_minbe) ||
352             nla_put_u8(msg, NL802154_CAP_ATTR_MIN_MAXBE, caps->min_maxbe) ||
353             nla_put_u8(msg, NL802154_CAP_ATTR_MAX_MAXBE, caps->max_maxbe) ||
354             nla_put_u8(msg, NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS,
355                        caps->min_csma_backoffs) ||
356             nla_put_u8(msg, NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS,
357                        caps->max_csma_backoffs) ||
358             nla_put_s8(msg, NL802154_CAP_ATTR_MIN_FRAME_RETRIES,
359                        caps->min_frame_retries) ||
360             nla_put_s8(msg, NL802154_CAP_ATTR_MAX_FRAME_RETRIES,
361                        caps->max_frame_retries) ||
362             nl802154_put_flags(msg, NL802154_CAP_ATTR_IFTYPES,
363                                caps->iftypes) ||
364             nla_put_u32(msg, NL802154_CAP_ATTR_LBT, caps->lbt))
365                 return -ENOBUFS;
366
367         nla_nest_end(msg, nl_caps);
368
369         return 0;
370 }
371
372 static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev,
373                                   enum nl802154_commands cmd,
374                                   struct sk_buff *msg, u32 portid, u32 seq,
375                                   int flags)
376 {
377         struct nlattr *nl_cmds;
378         void *hdr;
379         int i;
380
381         hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
382         if (!hdr)
383                 return -ENOBUFS;
384
385         if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) ||
386             nla_put_string(msg, NL802154_ATTR_WPAN_PHY_NAME,
387                            wpan_phy_name(&rdev->wpan_phy)) ||
388             nla_put_u32(msg, NL802154_ATTR_GENERATION,
389                         cfg802154_rdev_list_generation))
390                 goto nla_put_failure;
391
392         if (cmd != NL802154_CMD_NEW_WPAN_PHY)
393                 goto finish;
394
395         /* DUMP PHY PIB */
396
397         /* current channel settings */
398         if (nla_put_u8(msg, NL802154_ATTR_PAGE,
399                        rdev->wpan_phy.current_page) ||
400             nla_put_u8(msg, NL802154_ATTR_CHANNEL,
401                        rdev->wpan_phy.current_channel))
402                 goto nla_put_failure;
403
404         /* TODO remove this behaviour, we still keep support it for a while
405          * so users can change the behaviour to the new one.
406          */
407         if (nl802154_send_wpan_phy_channels(rdev, msg))
408                 goto nla_put_failure;
409
410         /* cca mode */
411         if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) {
412                 if (nla_put_u32(msg, NL802154_ATTR_CCA_MODE,
413                                 rdev->wpan_phy.cca.mode))
414                         goto nla_put_failure;
415
416                 if (rdev->wpan_phy.cca.mode == NL802154_CCA_ENERGY_CARRIER) {
417                         if (nla_put_u32(msg, NL802154_ATTR_CCA_OPT,
418                                         rdev->wpan_phy.cca.opt))
419                                 goto nla_put_failure;
420                 }
421         }
422
423         if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) {
424                 if (nla_put_s32(msg, NL802154_ATTR_TX_POWER,
425                                 rdev->wpan_phy.transmit_power))
426                         goto nla_put_failure;
427         }
428
429         if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) {
430                 if (nla_put_s32(msg, NL802154_ATTR_CCA_ED_LEVEL,
431                                 rdev->wpan_phy.cca_ed_level))
432                         goto nla_put_failure;
433         }
434
435         if (nl802154_put_capabilities(msg, rdev))
436                 goto nla_put_failure;
437
438         nl_cmds = nla_nest_start(msg, NL802154_ATTR_SUPPORTED_COMMANDS);
439         if (!nl_cmds)
440                 goto nla_put_failure;
441
442         i = 0;
443 #define CMD(op, n)                                                      \
444         do {                                                            \
445                 if (rdev->ops->op) {                                    \
446                         i++;                                            \
447                         if (nla_put_u32(msg, i, NL802154_CMD_ ## n))    \
448                                 goto nla_put_failure;                   \
449                 }                                                       \
450         } while (0)
451
452         CMD(add_virtual_intf, NEW_INTERFACE);
453         CMD(del_virtual_intf, DEL_INTERFACE);
454         CMD(set_channel, SET_CHANNEL);
455         CMD(set_pan_id, SET_PAN_ID);
456         CMD(set_short_addr, SET_SHORT_ADDR);
457         CMD(set_backoff_exponent, SET_BACKOFF_EXPONENT);
458         CMD(set_max_csma_backoffs, SET_MAX_CSMA_BACKOFFS);
459         CMD(set_max_frame_retries, SET_MAX_FRAME_RETRIES);
460         CMD(set_lbt_mode, SET_LBT_MODE);
461
462         if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER)
463                 CMD(set_tx_power, SET_TX_POWER);
464
465         if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL)
466                 CMD(set_cca_ed_level, SET_CCA_ED_LEVEL);
467
468         if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE)
469                 CMD(set_cca_mode, SET_CCA_MODE);
470
471 #undef CMD
472         nla_nest_end(msg, nl_cmds);
473
474 finish:
475         genlmsg_end(msg, hdr);
476         return 0;
477
478 nla_put_failure:
479         genlmsg_cancel(msg, hdr);
480         return -EMSGSIZE;
481 }
482
483 struct nl802154_dump_wpan_phy_state {
484         s64 filter_wpan_phy;
485         long start;
486
487 };
488
489 static int nl802154_dump_wpan_phy_parse(struct sk_buff *skb,
490                                         struct netlink_callback *cb,
491                                         struct nl802154_dump_wpan_phy_state *state)
492 {
493         struct nlattr **tb = nl802154_fam.attrbuf;
494         int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl802154_fam.hdrsize,
495                               tb, nl802154_fam.maxattr, nl802154_policy);
496
497         /* TODO check if we can handle error here,
498          * we have no backward compatibility
499          */
500         if (ret)
501                 return 0;
502
503         if (tb[NL802154_ATTR_WPAN_PHY])
504                 state->filter_wpan_phy = nla_get_u32(tb[NL802154_ATTR_WPAN_PHY]);
505         if (tb[NL802154_ATTR_WPAN_DEV])
506                 state->filter_wpan_phy = nla_get_u64(tb[NL802154_ATTR_WPAN_DEV]) >> 32;
507         if (tb[NL802154_ATTR_IFINDEX]) {
508                 struct net_device *netdev;
509                 struct cfg802154_registered_device *rdev;
510                 int ifidx = nla_get_u32(tb[NL802154_ATTR_IFINDEX]);
511
512                 /* TODO netns */
513                 netdev = __dev_get_by_index(&init_net, ifidx);
514                 if (!netdev)
515                         return -ENODEV;
516                 if (netdev->ieee802154_ptr) {
517                         rdev = wpan_phy_to_rdev(
518                                         netdev->ieee802154_ptr->wpan_phy);
519                         state->filter_wpan_phy = rdev->wpan_phy_idx;
520                 }
521         }
522
523         return 0;
524 }
525
526 static int
527 nl802154_dump_wpan_phy(struct sk_buff *skb, struct netlink_callback *cb)
528 {
529         int idx = 0, ret;
530         struct nl802154_dump_wpan_phy_state *state = (void *)cb->args[0];
531         struct cfg802154_registered_device *rdev;
532
533         rtnl_lock();
534         if (!state) {
535                 state = kzalloc(sizeof(*state), GFP_KERNEL);
536                 if (!state) {
537                         rtnl_unlock();
538                         return -ENOMEM;
539                 }
540                 state->filter_wpan_phy = -1;
541                 ret = nl802154_dump_wpan_phy_parse(skb, cb, state);
542                 if (ret) {
543                         kfree(state);
544                         rtnl_unlock();
545                         return ret;
546                 }
547                 cb->args[0] = (long)state;
548         }
549
550         list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
551                 /* TODO net ns compare */
552                 if (++idx <= state->start)
553                         continue;
554                 if (state->filter_wpan_phy != -1 &&
555                     state->filter_wpan_phy != rdev->wpan_phy_idx)
556                         continue;
557                 /* attempt to fit multiple wpan_phy data chunks into the skb */
558                 ret = nl802154_send_wpan_phy(rdev,
559                                              NL802154_CMD_NEW_WPAN_PHY,
560                                              skb,
561                                              NETLINK_CB(cb->skb).portid,
562                                              cb->nlh->nlmsg_seq, NLM_F_MULTI);
563                 if (ret < 0) {
564                         if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
565                             !skb->len && cb->min_dump_alloc < 4096) {
566                                 cb->min_dump_alloc = 4096;
567                                 rtnl_unlock();
568                                 return 1;
569                         }
570                         idx--;
571                         break;
572                 }
573                 break;
574         }
575         rtnl_unlock();
576
577         state->start = idx;
578
579         return skb->len;
580 }
581
582 static int nl802154_dump_wpan_phy_done(struct netlink_callback *cb)
583 {
584         kfree((void *)cb->args[0]);
585         return 0;
586 }
587
588 static int nl802154_get_wpan_phy(struct sk_buff *skb, struct genl_info *info)
589 {
590         struct sk_buff *msg;
591         struct cfg802154_registered_device *rdev = info->user_ptr[0];
592
593         msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
594         if (!msg)
595                 return -ENOMEM;
596
597         if (nl802154_send_wpan_phy(rdev, NL802154_CMD_NEW_WPAN_PHY, msg,
598                                    info->snd_portid, info->snd_seq, 0) < 0) {
599                 nlmsg_free(msg);
600                 return -ENOBUFS;
601         }
602
603         return genlmsg_reply(msg, info);
604 }
605
606 static inline u64 wpan_dev_id(struct wpan_dev *wpan_dev)
607 {
608         return (u64)wpan_dev->identifier |
609                ((u64)wpan_phy_to_rdev(wpan_dev->wpan_phy)->wpan_phy_idx << 32);
610 }
611
612 static int
613 nl802154_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
614                     struct cfg802154_registered_device *rdev,
615                     struct wpan_dev *wpan_dev)
616 {
617         struct net_device *dev = wpan_dev->netdev;
618         void *hdr;
619
620         hdr = nl802154hdr_put(msg, portid, seq, flags,
621                               NL802154_CMD_NEW_INTERFACE);
622         if (!hdr)
623                 return -1;
624
625         if (dev &&
626             (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex) ||
627              nla_put_string(msg, NL802154_ATTR_IFNAME, dev->name)))
628                 goto nla_put_failure;
629
630         if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) ||
631             nla_put_u32(msg, NL802154_ATTR_IFTYPE, wpan_dev->iftype) ||
632             nla_put_u64(msg, NL802154_ATTR_WPAN_DEV, wpan_dev_id(wpan_dev)) ||
633             nla_put_u32(msg, NL802154_ATTR_GENERATION,
634                         rdev->devlist_generation ^
635                         (cfg802154_rdev_list_generation << 2)))
636                 goto nla_put_failure;
637
638         /* address settings */
639         if (nla_put_le64(msg, NL802154_ATTR_EXTENDED_ADDR,
640                          wpan_dev->extended_addr) ||
641             nla_put_le16(msg, NL802154_ATTR_SHORT_ADDR,
642                          wpan_dev->short_addr) ||
643             nla_put_le16(msg, NL802154_ATTR_PAN_ID, wpan_dev->pan_id))
644                 goto nla_put_failure;
645
646         /* ARET handling */
647         if (nla_put_s8(msg, NL802154_ATTR_MAX_FRAME_RETRIES,
648                        wpan_dev->frame_retries) ||
649             nla_put_u8(msg, NL802154_ATTR_MAX_BE, wpan_dev->max_be) ||
650             nla_put_u8(msg, NL802154_ATTR_MAX_CSMA_BACKOFFS,
651                        wpan_dev->csma_retries) ||
652             nla_put_u8(msg, NL802154_ATTR_MIN_BE, wpan_dev->min_be))
653                 goto nla_put_failure;
654
655         /* listen before transmit */
656         if (nla_put_u8(msg, NL802154_ATTR_LBT_MODE, wpan_dev->lbt))
657                 goto nla_put_failure;
658
659         genlmsg_end(msg, hdr);
660         return 0;
661
662 nla_put_failure:
663         genlmsg_cancel(msg, hdr);
664         return -EMSGSIZE;
665 }
666
667 static int
668 nl802154_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
669 {
670         int wp_idx = 0;
671         int if_idx = 0;
672         int wp_start = cb->args[0];
673         int if_start = cb->args[1];
674         struct cfg802154_registered_device *rdev;
675         struct wpan_dev *wpan_dev;
676
677         rtnl_lock();
678         list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
679                 /* TODO netns compare */
680                 if (wp_idx < wp_start) {
681                         wp_idx++;
682                         continue;
683                 }
684                 if_idx = 0;
685
686                 list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) {
687                         if (if_idx < if_start) {
688                                 if_idx++;
689                                 continue;
690                         }
691                         if (nl802154_send_iface(skb, NETLINK_CB(cb->skb).portid,
692                                                 cb->nlh->nlmsg_seq, NLM_F_MULTI,
693                                                 rdev, wpan_dev) < 0) {
694                                 goto out;
695                         }
696                         if_idx++;
697                 }
698
699                 wp_idx++;
700         }
701 out:
702         rtnl_unlock();
703
704         cb->args[0] = wp_idx;
705         cb->args[1] = if_idx;
706
707         return skb->len;
708 }
709
710 static int nl802154_get_interface(struct sk_buff *skb, struct genl_info *info)
711 {
712         struct sk_buff *msg;
713         struct cfg802154_registered_device *rdev = info->user_ptr[0];
714         struct wpan_dev *wdev = info->user_ptr[1];
715
716         msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
717         if (!msg)
718                 return -ENOMEM;
719
720         if (nl802154_send_iface(msg, info->snd_portid, info->snd_seq, 0,
721                                 rdev, wdev) < 0) {
722                 nlmsg_free(msg);
723                 return -ENOBUFS;
724         }
725
726         return genlmsg_reply(msg, info);
727 }
728
729 static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info)
730 {
731         struct cfg802154_registered_device *rdev = info->user_ptr[0];
732         enum nl802154_iftype type = NL802154_IFTYPE_UNSPEC;
733         __le64 extended_addr = cpu_to_le64(0x0000000000000000ULL);
734
735         /* TODO avoid failing a new interface
736          * creation due to pending removal?
737          */
738
739         if (!info->attrs[NL802154_ATTR_IFNAME])
740                 return -EINVAL;
741
742         if (info->attrs[NL802154_ATTR_IFTYPE]) {
743                 type = nla_get_u32(info->attrs[NL802154_ATTR_IFTYPE]);
744                 if (type > NL802154_IFTYPE_MAX ||
745                     !(rdev->wpan_phy.supported.iftypes & BIT(type)))
746                         return -EINVAL;
747         }
748
749         /* TODO add nla_get_le64 to netlink */
750         if (info->attrs[NL802154_ATTR_EXTENDED_ADDR])
751                 extended_addr = (__force __le64)nla_get_u64(
752                                 info->attrs[NL802154_ATTR_EXTENDED_ADDR]);
753
754         if (!rdev->ops->add_virtual_intf)
755                 return -EOPNOTSUPP;
756
757         return rdev_add_virtual_intf(rdev,
758                                      nla_data(info->attrs[NL802154_ATTR_IFNAME]),
759                                      NET_NAME_USER, type, extended_addr);
760 }
761
762 static int nl802154_del_interface(struct sk_buff *skb, struct genl_info *info)
763 {
764         struct cfg802154_registered_device *rdev = info->user_ptr[0];
765         struct wpan_dev *wpan_dev = info->user_ptr[1];
766
767         if (!rdev->ops->del_virtual_intf)
768                 return -EOPNOTSUPP;
769
770         /* If we remove a wpan device without a netdev then clear
771          * user_ptr[1] so that nl802154_post_doit won't dereference it
772          * to check if it needs to do dev_put(). Otherwise it crashes
773          * since the wpan_dev has been freed, unlike with a netdev where
774          * we need the dev_put() for the netdev to really be freed.
775          */
776         if (!wpan_dev->netdev)
777                 info->user_ptr[1] = NULL;
778
779         return rdev_del_virtual_intf(rdev, wpan_dev);
780 }
781
782 static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info)
783 {
784         struct cfg802154_registered_device *rdev = info->user_ptr[0];
785         u8 channel, page;
786
787         if (!info->attrs[NL802154_ATTR_PAGE] ||
788             !info->attrs[NL802154_ATTR_CHANNEL])
789                 return -EINVAL;
790
791         page = nla_get_u8(info->attrs[NL802154_ATTR_PAGE]);
792         channel = nla_get_u8(info->attrs[NL802154_ATTR_CHANNEL]);
793
794         /* check 802.15.4 constraints */
795         if (page > IEEE802154_MAX_PAGE || channel > IEEE802154_MAX_CHANNEL ||
796             !(rdev->wpan_phy.supported.channels[page] & BIT(channel)))
797                 return -EINVAL;
798
799         return rdev_set_channel(rdev, page, channel);
800 }
801
802 static int nl802154_set_cca_mode(struct sk_buff *skb, struct genl_info *info)
803 {
804         struct cfg802154_registered_device *rdev = info->user_ptr[0];
805         struct wpan_phy_cca cca;
806
807         if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE))
808                 return -EOPNOTSUPP;
809
810         if (!info->attrs[NL802154_ATTR_CCA_MODE])
811                 return -EINVAL;
812
813         cca.mode = nla_get_u32(info->attrs[NL802154_ATTR_CCA_MODE]);
814         /* checking 802.15.4 constraints */
815         if (cca.mode < NL802154_CCA_ENERGY ||
816             cca.mode > NL802154_CCA_ATTR_MAX ||
817             !(rdev->wpan_phy.supported.cca_modes & BIT(cca.mode)))
818                 return -EINVAL;
819
820         if (cca.mode == NL802154_CCA_ENERGY_CARRIER) {
821                 if (!info->attrs[NL802154_ATTR_CCA_OPT])
822                         return -EINVAL;
823
824                 cca.opt = nla_get_u32(info->attrs[NL802154_ATTR_CCA_OPT]);
825                 if (cca.opt > NL802154_CCA_OPT_ATTR_MAX ||
826                     !(rdev->wpan_phy.supported.cca_opts & BIT(cca.opt)))
827                         return -EINVAL;
828         }
829
830         return rdev_set_cca_mode(rdev, &cca);
831 }
832
833 static int nl802154_set_cca_ed_level(struct sk_buff *skb, struct genl_info *info)
834 {
835         struct cfg802154_registered_device *rdev = info->user_ptr[0];
836         s32 ed_level;
837         int i;
838
839         if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL))
840                 return -EOPNOTSUPP;
841
842         if (!info->attrs[NL802154_ATTR_CCA_ED_LEVEL])
843                 return -EINVAL;
844
845         ed_level = nla_get_s32(info->attrs[NL802154_ATTR_CCA_ED_LEVEL]);
846
847         for (i = 0; i < rdev->wpan_phy.supported.cca_ed_levels_size; i++) {
848                 if (ed_level == rdev->wpan_phy.supported.cca_ed_levels[i])
849                         return rdev_set_cca_ed_level(rdev, ed_level);
850         }
851
852         return -EINVAL;
853 }
854
855 static int nl802154_set_tx_power(struct sk_buff *skb, struct genl_info *info)
856 {
857         struct cfg802154_registered_device *rdev = info->user_ptr[0];
858         s32 power;
859         int i;
860
861         if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER))
862                 return -EOPNOTSUPP;
863
864         if (!info->attrs[NL802154_ATTR_TX_POWER])
865                 return -EINVAL;
866
867         power = nla_get_s32(info->attrs[NL802154_ATTR_TX_POWER]);
868
869         for (i = 0; i < rdev->wpan_phy.supported.tx_powers_size; i++) {
870                 if (power == rdev->wpan_phy.supported.tx_powers[i])
871                         return rdev_set_tx_power(rdev, power);
872         }
873
874         return -EINVAL;
875 }
876
877 static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info)
878 {
879         struct cfg802154_registered_device *rdev = info->user_ptr[0];
880         struct net_device *dev = info->user_ptr[1];
881         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
882         __le16 pan_id;
883
884         /* conflict here while tx/rx calls */
885         if (netif_running(dev))
886                 return -EBUSY;
887
888         /* don't change address fields on monitor */
889         if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
890             !info->attrs[NL802154_ATTR_PAN_ID])
891                 return -EINVAL;
892
893         pan_id = nla_get_le16(info->attrs[NL802154_ATTR_PAN_ID]);
894
895         /* TODO
896          * I am not sure about to check here on broadcast pan_id.
897          * Broadcast is a valid setting, comment from 802.15.4:
898          * If this value is 0xffff, the device is not associated.
899          *
900          * This could useful to simple deassociate an device.
901          */
902         if (pan_id == cpu_to_le16(IEEE802154_PAN_ID_BROADCAST))
903                 return -EINVAL;
904
905         return rdev_set_pan_id(rdev, wpan_dev, pan_id);
906 }
907
908 static int nl802154_set_short_addr(struct sk_buff *skb, struct genl_info *info)
909 {
910         struct cfg802154_registered_device *rdev = info->user_ptr[0];
911         struct net_device *dev = info->user_ptr[1];
912         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
913         __le16 short_addr;
914
915         /* conflict here while tx/rx calls */
916         if (netif_running(dev))
917                 return -EBUSY;
918
919         /* don't change address fields on monitor */
920         if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
921             !info->attrs[NL802154_ATTR_SHORT_ADDR])
922                 return -EINVAL;
923
924         short_addr = nla_get_le16(info->attrs[NL802154_ATTR_SHORT_ADDR]);
925
926         /* TODO
927          * I am not sure about to check here on broadcast short_addr.
928          * Broadcast is a valid setting, comment from 802.15.4:
929          * A value of 0xfffe indicates that the device has
930          * associated but has not been allocated an address. A
931          * value of 0xffff indicates that the device does not
932          * have a short address.
933          *
934          * I think we should allow to set these settings but
935          * don't allow to allow socket communication with it.
936          */
937         if (short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC) ||
938             short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST))
939                 return -EINVAL;
940
941         return rdev_set_short_addr(rdev, wpan_dev, short_addr);
942 }
943
944 static int
945 nl802154_set_backoff_exponent(struct sk_buff *skb, struct genl_info *info)
946 {
947         struct cfg802154_registered_device *rdev = info->user_ptr[0];
948         struct net_device *dev = info->user_ptr[1];
949         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
950         u8 min_be, max_be;
951
952         /* should be set on netif open inside phy settings */
953         if (netif_running(dev))
954                 return -EBUSY;
955
956         if (!info->attrs[NL802154_ATTR_MIN_BE] ||
957             !info->attrs[NL802154_ATTR_MAX_BE])
958                 return -EINVAL;
959
960         min_be = nla_get_u8(info->attrs[NL802154_ATTR_MIN_BE]);
961         max_be = nla_get_u8(info->attrs[NL802154_ATTR_MAX_BE]);
962
963         /* check 802.15.4 constraints */
964         if (min_be < rdev->wpan_phy.supported.min_minbe ||
965             min_be > rdev->wpan_phy.supported.max_minbe ||
966             max_be < rdev->wpan_phy.supported.min_maxbe ||
967             max_be > rdev->wpan_phy.supported.max_maxbe ||
968             min_be > max_be)
969                 return -EINVAL;
970
971         return rdev_set_backoff_exponent(rdev, wpan_dev, min_be, max_be);
972 }
973
974 static int
975 nl802154_set_max_csma_backoffs(struct sk_buff *skb, struct genl_info *info)
976 {
977         struct cfg802154_registered_device *rdev = info->user_ptr[0];
978         struct net_device *dev = info->user_ptr[1];
979         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
980         u8 max_csma_backoffs;
981
982         /* conflict here while other running iface settings */
983         if (netif_running(dev))
984                 return -EBUSY;
985
986         if (!info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS])
987                 return -EINVAL;
988
989         max_csma_backoffs = nla_get_u8(
990                         info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS]);
991
992         /* check 802.15.4 constraints */
993         if (max_csma_backoffs < rdev->wpan_phy.supported.min_csma_backoffs ||
994             max_csma_backoffs > rdev->wpan_phy.supported.max_csma_backoffs)
995                 return -EINVAL;
996
997         return rdev_set_max_csma_backoffs(rdev, wpan_dev, max_csma_backoffs);
998 }
999
1000 static int
1001 nl802154_set_max_frame_retries(struct sk_buff *skb, struct genl_info *info)
1002 {
1003         struct cfg802154_registered_device *rdev = info->user_ptr[0];
1004         struct net_device *dev = info->user_ptr[1];
1005         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1006         s8 max_frame_retries;
1007
1008         if (netif_running(dev))
1009                 return -EBUSY;
1010
1011         if (!info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES])
1012                 return -EINVAL;
1013
1014         max_frame_retries = nla_get_s8(
1015                         info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES]);
1016
1017         /* check 802.15.4 constraints */
1018         if (max_frame_retries < rdev->wpan_phy.supported.min_frame_retries ||
1019             max_frame_retries > rdev->wpan_phy.supported.max_frame_retries)
1020                 return -EINVAL;
1021
1022         return rdev_set_max_frame_retries(rdev, wpan_dev, max_frame_retries);
1023 }
1024
1025 static int nl802154_set_lbt_mode(struct sk_buff *skb, struct genl_info *info)
1026 {
1027         struct cfg802154_registered_device *rdev = info->user_ptr[0];
1028         struct net_device *dev = info->user_ptr[1];
1029         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1030         bool mode;
1031
1032         if (netif_running(dev))
1033                 return -EBUSY;
1034
1035         if (!info->attrs[NL802154_ATTR_LBT_MODE])
1036                 return -EINVAL;
1037
1038         mode = !!nla_get_u8(info->attrs[NL802154_ATTR_LBT_MODE]);
1039         if (!wpan_phy_supported_bool(mode, rdev->wpan_phy.supported.lbt))
1040                 return -EINVAL;
1041
1042         return rdev_set_lbt_mode(rdev, wpan_dev, mode);
1043 }
1044
1045 #define NL802154_FLAG_NEED_WPAN_PHY     0x01
1046 #define NL802154_FLAG_NEED_NETDEV       0x02
1047 #define NL802154_FLAG_NEED_RTNL         0x04
1048 #define NL802154_FLAG_CHECK_NETDEV_UP   0x08
1049 #define NL802154_FLAG_NEED_NETDEV_UP    (NL802154_FLAG_NEED_NETDEV |\
1050                                          NL802154_FLAG_CHECK_NETDEV_UP)
1051 #define NL802154_FLAG_NEED_WPAN_DEV     0x10
1052 #define NL802154_FLAG_NEED_WPAN_DEV_UP  (NL802154_FLAG_NEED_WPAN_DEV |\
1053                                          NL802154_FLAG_CHECK_NETDEV_UP)
1054
1055 static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
1056                              struct genl_info *info)
1057 {
1058         struct cfg802154_registered_device *rdev;
1059         struct wpan_dev *wpan_dev;
1060         struct net_device *dev;
1061         bool rtnl = ops->internal_flags & NL802154_FLAG_NEED_RTNL;
1062
1063         if (rtnl)
1064                 rtnl_lock();
1065
1066         if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_PHY) {
1067                 rdev = cfg802154_get_dev_from_info(genl_info_net(info), info);
1068                 if (IS_ERR(rdev)) {
1069                         if (rtnl)
1070                                 rtnl_unlock();
1071                         return PTR_ERR(rdev);
1072                 }
1073                 info->user_ptr[0] = rdev;
1074         } else if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV ||
1075                    ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
1076                 ASSERT_RTNL();
1077                 wpan_dev = __cfg802154_wpan_dev_from_attrs(genl_info_net(info),
1078                                                            info->attrs);
1079                 if (IS_ERR(wpan_dev)) {
1080                         if (rtnl)
1081                                 rtnl_unlock();
1082                         return PTR_ERR(wpan_dev);
1083                 }
1084
1085                 dev = wpan_dev->netdev;
1086                 rdev = wpan_phy_to_rdev(wpan_dev->wpan_phy);
1087
1088                 if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV) {
1089                         if (!dev) {
1090                                 if (rtnl)
1091                                         rtnl_unlock();
1092                                 return -EINVAL;
1093                         }
1094
1095                         info->user_ptr[1] = dev;
1096                 } else {
1097                         info->user_ptr[1] = wpan_dev;
1098                 }
1099
1100                 if (dev) {
1101                         if (ops->internal_flags & NL802154_FLAG_CHECK_NETDEV_UP &&
1102                             !netif_running(dev)) {
1103                                 if (rtnl)
1104                                         rtnl_unlock();
1105                                 return -ENETDOWN;
1106                         }
1107
1108                         dev_hold(dev);
1109                 }
1110
1111                 info->user_ptr[0] = rdev;
1112         }
1113
1114         return 0;
1115 }
1116
1117 static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
1118                                struct genl_info *info)
1119 {
1120         if (info->user_ptr[1]) {
1121                 if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
1122                         struct wpan_dev *wpan_dev = info->user_ptr[1];
1123
1124                         if (wpan_dev->netdev)
1125                                 dev_put(wpan_dev->netdev);
1126                 } else {
1127                         dev_put(info->user_ptr[1]);
1128                 }
1129         }
1130
1131         if (ops->internal_flags & NL802154_FLAG_NEED_RTNL)
1132                 rtnl_unlock();
1133 }
1134
1135 static const struct genl_ops nl802154_ops[] = {
1136         {
1137                 .cmd = NL802154_CMD_GET_WPAN_PHY,
1138                 .doit = nl802154_get_wpan_phy,
1139                 .dumpit = nl802154_dump_wpan_phy,
1140                 .done = nl802154_dump_wpan_phy_done,
1141                 .policy = nl802154_policy,
1142                 /* can be retrieved by unprivileged users */
1143                 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1144                                   NL802154_FLAG_NEED_RTNL,
1145         },
1146         {
1147                 .cmd = NL802154_CMD_GET_INTERFACE,
1148                 .doit = nl802154_get_interface,
1149                 .dumpit = nl802154_dump_interface,
1150                 .policy = nl802154_policy,
1151                 /* can be retrieved by unprivileged users */
1152                 .internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
1153                                   NL802154_FLAG_NEED_RTNL,
1154         },
1155         {
1156                 .cmd = NL802154_CMD_NEW_INTERFACE,
1157                 .doit = nl802154_new_interface,
1158                 .policy = nl802154_policy,
1159                 .flags = GENL_ADMIN_PERM,
1160                 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1161                                   NL802154_FLAG_NEED_RTNL,
1162         },
1163         {
1164                 .cmd = NL802154_CMD_DEL_INTERFACE,
1165                 .doit = nl802154_del_interface,
1166                 .policy = nl802154_policy,
1167                 .flags = GENL_ADMIN_PERM,
1168                 .internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
1169                                   NL802154_FLAG_NEED_RTNL,
1170         },
1171         {
1172                 .cmd = NL802154_CMD_SET_CHANNEL,
1173                 .doit = nl802154_set_channel,
1174                 .policy = nl802154_policy,
1175                 .flags = GENL_ADMIN_PERM,
1176                 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1177                                   NL802154_FLAG_NEED_RTNL,
1178         },
1179         {
1180                 .cmd = NL802154_CMD_SET_CCA_MODE,
1181                 .doit = nl802154_set_cca_mode,
1182                 .policy = nl802154_policy,
1183                 .flags = GENL_ADMIN_PERM,
1184                 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1185                                   NL802154_FLAG_NEED_RTNL,
1186         },
1187         {
1188                 .cmd = NL802154_CMD_SET_CCA_ED_LEVEL,
1189                 .doit = nl802154_set_cca_ed_level,
1190                 .policy = nl802154_policy,
1191                 .flags = GENL_ADMIN_PERM,
1192                 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1193                                   NL802154_FLAG_NEED_RTNL,
1194         },
1195         {
1196                 .cmd = NL802154_CMD_SET_TX_POWER,
1197                 .doit = nl802154_set_tx_power,
1198                 .policy = nl802154_policy,
1199                 .flags = GENL_ADMIN_PERM,
1200                 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1201                                   NL802154_FLAG_NEED_RTNL,
1202         },
1203         {
1204                 .cmd = NL802154_CMD_SET_PAN_ID,
1205                 .doit = nl802154_set_pan_id,
1206                 .policy = nl802154_policy,
1207                 .flags = GENL_ADMIN_PERM,
1208                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
1209                                   NL802154_FLAG_NEED_RTNL,
1210         },
1211         {
1212                 .cmd = NL802154_CMD_SET_SHORT_ADDR,
1213                 .doit = nl802154_set_short_addr,
1214                 .policy = nl802154_policy,
1215                 .flags = GENL_ADMIN_PERM,
1216                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
1217                                   NL802154_FLAG_NEED_RTNL,
1218         },
1219         {
1220                 .cmd = NL802154_CMD_SET_BACKOFF_EXPONENT,
1221                 .doit = nl802154_set_backoff_exponent,
1222                 .policy = nl802154_policy,
1223                 .flags = GENL_ADMIN_PERM,
1224                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
1225                                   NL802154_FLAG_NEED_RTNL,
1226         },
1227         {
1228                 .cmd = NL802154_CMD_SET_MAX_CSMA_BACKOFFS,
1229                 .doit = nl802154_set_max_csma_backoffs,
1230                 .policy = nl802154_policy,
1231                 .flags = GENL_ADMIN_PERM,
1232                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
1233                                   NL802154_FLAG_NEED_RTNL,
1234         },
1235         {
1236                 .cmd = NL802154_CMD_SET_MAX_FRAME_RETRIES,
1237                 .doit = nl802154_set_max_frame_retries,
1238                 .policy = nl802154_policy,
1239                 .flags = GENL_ADMIN_PERM,
1240                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
1241                                   NL802154_FLAG_NEED_RTNL,
1242         },
1243         {
1244                 .cmd = NL802154_CMD_SET_LBT_MODE,
1245                 .doit = nl802154_set_lbt_mode,
1246                 .policy = nl802154_policy,
1247                 .flags = GENL_ADMIN_PERM,
1248                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
1249                                   NL802154_FLAG_NEED_RTNL,
1250         },
1251 };
1252
1253 /* initialisation/exit functions */
1254 int nl802154_init(void)
1255 {
1256         return genl_register_family_with_ops_groups(&nl802154_fam, nl802154_ops,
1257                                                     nl802154_mcgrps);
1258 }
1259
1260 void nl802154_exit(void)
1261 {
1262         genl_unregister_family(&nl802154_fam);
1263 }