~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/ieee802154/nl802154.c

Version: ~ [ linux-5.16-rc3 ] ~ [ linux-5.15.5 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.82 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.162 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.218 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.256 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.291 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.293 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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         [NL802154_ATTR_ACKREQ_DEFAULT] = { .type = NLA_U8 },
235 
236 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
237         [NL802154_ATTR_SEC_ENABLED] = { .type = NLA_U8, },
238         [NL802154_ATTR_SEC_OUT_LEVEL] = { .type = NLA_U32, },
239         [NL802154_ATTR_SEC_OUT_KEY_ID] = { .type = NLA_NESTED, },
240         [NL802154_ATTR_SEC_FRAME_COUNTER] = { .type = NLA_U32 },
241 
242         [NL802154_ATTR_SEC_LEVEL] = { .type = NLA_NESTED },
243         [NL802154_ATTR_SEC_DEVICE] = { .type = NLA_NESTED },
244         [NL802154_ATTR_SEC_DEVKEY] = { .type = NLA_NESTED },
245         [NL802154_ATTR_SEC_KEY] = { .type = NLA_NESTED },
246 #endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
247 };
248 
249 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
250 static int
251 nl802154_prepare_wpan_dev_dump(struct sk_buff *skb,
252                                struct netlink_callback *cb,
253                                struct cfg802154_registered_device **rdev,
254                                struct wpan_dev **wpan_dev)
255 {
256         int err;
257 
258         rtnl_lock();
259 
260         if (!cb->args[0]) {
261                 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl802154_fam.hdrsize,
262                                   nl802154_fam.attrbuf, nl802154_fam.maxattr,
263                                   nl802154_policy);
264                 if (err)
265                         goto out_unlock;
266 
267                 *wpan_dev = __cfg802154_wpan_dev_from_attrs(sock_net(skb->sk),
268                                                             nl802154_fam.attrbuf);
269                 if (IS_ERR(*wpan_dev)) {
270                         err = PTR_ERR(*wpan_dev);
271                         goto out_unlock;
272                 }
273                 *rdev = wpan_phy_to_rdev((*wpan_dev)->wpan_phy);
274                 /* 0 is the first index - add 1 to parse only once */
275                 cb->args[0] = (*rdev)->wpan_phy_idx + 1;
276                 cb->args[1] = (*wpan_dev)->identifier;
277         } else {
278                 /* subtract the 1 again here */
279                 struct wpan_phy *wpan_phy = wpan_phy_idx_to_wpan_phy(cb->args[0] - 1);
280                 struct wpan_dev *tmp;
281 
282                 if (!wpan_phy) {
283                         err = -ENODEV;
284                         goto out_unlock;
285                 }
286                 *rdev = wpan_phy_to_rdev(wpan_phy);
287                 *wpan_dev = NULL;
288 
289                 list_for_each_entry(tmp, &(*rdev)->wpan_dev_list, list) {
290                         if (tmp->identifier == cb->args[1]) {
291                                 *wpan_dev = tmp;
292                                 break;
293                         }
294                 }
295 
296                 if (!*wpan_dev) {
297                         err = -ENODEV;
298                         goto out_unlock;
299                 }
300         }
301 
302         return 0;
303  out_unlock:
304         rtnl_unlock();
305         return err;
306 }
307 
308 static void
309 nl802154_finish_wpan_dev_dump(struct cfg802154_registered_device *rdev)
310 {
311         rtnl_unlock();
312 }
313 #endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
314 
315 /* message building helper */
316 static inline void *nl802154hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
317                                     int flags, u8 cmd)
318 {
319         /* since there is no private header just add the generic one */
320         return genlmsg_put(skb, portid, seq, &nl802154_fam, flags, cmd);
321 }
322 
323 static int
324 nl802154_put_flags(struct sk_buff *msg, int attr, u32 mask)
325 {
326         struct nlattr *nl_flags = nla_nest_start(msg, attr);
327         int i;
328 
329         if (!nl_flags)
330                 return -ENOBUFS;
331 
332         i = 0;
333         while (mask) {
334                 if ((mask & 1) && nla_put_flag(msg, i))
335                         return -ENOBUFS;
336 
337                 mask >>= 1;
338                 i++;
339         }
340 
341         nla_nest_end(msg, nl_flags);
342         return 0;
343 }
344 
345 static int
346 nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev,
347                                 struct sk_buff *msg)
348 {
349         struct nlattr *nl_page;
350         unsigned long page;
351 
352         nl_page = nla_nest_start(msg, NL802154_ATTR_CHANNELS_SUPPORTED);
353         if (!nl_page)
354                 return -ENOBUFS;
355 
356         for (page = 0; page <= IEEE802154_MAX_PAGE; page++) {
357                 if (nla_put_u32(msg, NL802154_ATTR_SUPPORTED_CHANNEL,
358                                 rdev->wpan_phy.supported.channels[page]))
359                         return -ENOBUFS;
360         }
361         nla_nest_end(msg, nl_page);
362 
363         return 0;
364 }
365 
366 static int
367 nl802154_put_capabilities(struct sk_buff *msg,
368                           struct cfg802154_registered_device *rdev)
369 {
370         const struct wpan_phy_supported *caps = &rdev->wpan_phy.supported;
371         struct nlattr *nl_caps, *nl_channels;
372         int i;
373 
374         nl_caps = nla_nest_start(msg, NL802154_ATTR_WPAN_PHY_CAPS);
375         if (!nl_caps)
376                 return -ENOBUFS;
377 
378         nl_channels = nla_nest_start(msg, NL802154_CAP_ATTR_CHANNELS);
379         if (!nl_channels)
380                 return -ENOBUFS;
381 
382         for (i = 0; i <= IEEE802154_MAX_PAGE; i++) {
383                 if (caps->channels[i]) {
384                         if (nl802154_put_flags(msg, i, caps->channels[i]))
385                                 return -ENOBUFS;
386                 }
387         }
388 
389         nla_nest_end(msg, nl_channels);
390 
391         if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) {
392                 struct nlattr *nl_ed_lvls;
393 
394                 nl_ed_lvls = nla_nest_start(msg,
395                                             NL802154_CAP_ATTR_CCA_ED_LEVELS);
396                 if (!nl_ed_lvls)
397                         return -ENOBUFS;
398 
399                 for (i = 0; i < caps->cca_ed_levels_size; i++) {
400                         if (nla_put_s32(msg, i, caps->cca_ed_levels[i]))
401                                 return -ENOBUFS;
402                 }
403 
404                 nla_nest_end(msg, nl_ed_lvls);
405         }
406 
407         if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) {
408                 struct nlattr *nl_tx_pwrs;
409 
410                 nl_tx_pwrs = nla_nest_start(msg, NL802154_CAP_ATTR_TX_POWERS);
411                 if (!nl_tx_pwrs)
412                         return -ENOBUFS;
413 
414                 for (i = 0; i < caps->tx_powers_size; i++) {
415                         if (nla_put_s32(msg, i, caps->tx_powers[i]))
416                                 return -ENOBUFS;
417                 }
418 
419                 nla_nest_end(msg, nl_tx_pwrs);
420         }
421 
422         if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) {
423                 if (nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_MODES,
424                                        caps->cca_modes) ||
425                     nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_OPTS,
426                                        caps->cca_opts))
427                         return -ENOBUFS;
428         }
429 
430         if (nla_put_u8(msg, NL802154_CAP_ATTR_MIN_MINBE, caps->min_minbe) ||
431             nla_put_u8(msg, NL802154_CAP_ATTR_MAX_MINBE, caps->max_minbe) ||
432             nla_put_u8(msg, NL802154_CAP_ATTR_MIN_MAXBE, caps->min_maxbe) ||
433             nla_put_u8(msg, NL802154_CAP_ATTR_MAX_MAXBE, caps->max_maxbe) ||
434             nla_put_u8(msg, NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS,
435                        caps->min_csma_backoffs) ||
436             nla_put_u8(msg, NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS,
437                        caps->max_csma_backoffs) ||
438             nla_put_s8(msg, NL802154_CAP_ATTR_MIN_FRAME_RETRIES,
439                        caps->min_frame_retries) ||
440             nla_put_s8(msg, NL802154_CAP_ATTR_MAX_FRAME_RETRIES,
441                        caps->max_frame_retries) ||
442             nl802154_put_flags(msg, NL802154_CAP_ATTR_IFTYPES,
443                                caps->iftypes) ||
444             nla_put_u32(msg, NL802154_CAP_ATTR_LBT, caps->lbt))
445                 return -ENOBUFS;
446 
447         nla_nest_end(msg, nl_caps);
448 
449         return 0;
450 }
451 
452 static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev,
453                                   enum nl802154_commands cmd,
454                                   struct sk_buff *msg, u32 portid, u32 seq,
455                                   int flags)
456 {
457         struct nlattr *nl_cmds;
458         void *hdr;
459         int i;
460 
461         hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
462         if (!hdr)
463                 return -ENOBUFS;
464 
465         if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) ||
466             nla_put_string(msg, NL802154_ATTR_WPAN_PHY_NAME,
467                            wpan_phy_name(&rdev->wpan_phy)) ||
468             nla_put_u32(msg, NL802154_ATTR_GENERATION,
469                         cfg802154_rdev_list_generation))
470                 goto nla_put_failure;
471 
472         if (cmd != NL802154_CMD_NEW_WPAN_PHY)
473                 goto finish;
474 
475         /* DUMP PHY PIB */
476 
477         /* current channel settings */
478         if (nla_put_u8(msg, NL802154_ATTR_PAGE,
479                        rdev->wpan_phy.current_page) ||
480             nla_put_u8(msg, NL802154_ATTR_CHANNEL,
481                        rdev->wpan_phy.current_channel))
482                 goto nla_put_failure;
483 
484         /* TODO remove this behaviour, we still keep support it for a while
485          * so users can change the behaviour to the new one.
486          */
487         if (nl802154_send_wpan_phy_channels(rdev, msg))
488                 goto nla_put_failure;
489 
490         /* cca mode */
491         if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) {
492                 if (nla_put_u32(msg, NL802154_ATTR_CCA_MODE,
493                                 rdev->wpan_phy.cca.mode))
494                         goto nla_put_failure;
495 
496                 if (rdev->wpan_phy.cca.mode == NL802154_CCA_ENERGY_CARRIER) {
497                         if (nla_put_u32(msg, NL802154_ATTR_CCA_OPT,
498                                         rdev->wpan_phy.cca.opt))
499                                 goto nla_put_failure;
500                 }
501         }
502 
503         if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) {
504                 if (nla_put_s32(msg, NL802154_ATTR_TX_POWER,
505                                 rdev->wpan_phy.transmit_power))
506                         goto nla_put_failure;
507         }
508 
509         if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) {
510                 if (nla_put_s32(msg, NL802154_ATTR_CCA_ED_LEVEL,
511                                 rdev->wpan_phy.cca_ed_level))
512                         goto nla_put_failure;
513         }
514 
515         if (nl802154_put_capabilities(msg, rdev))
516                 goto nla_put_failure;
517 
518         nl_cmds = nla_nest_start(msg, NL802154_ATTR_SUPPORTED_COMMANDS);
519         if (!nl_cmds)
520                 goto nla_put_failure;
521 
522         i = 0;
523 #define CMD(op, n)                                                      \
524         do {                                                            \
525                 if (rdev->ops->op) {                                    \
526                         i++;                                            \
527                         if (nla_put_u32(msg, i, NL802154_CMD_ ## n))    \
528                                 goto nla_put_failure;                   \
529                 }                                                       \
530         } while (0)
531 
532         CMD(add_virtual_intf, NEW_INTERFACE);
533         CMD(del_virtual_intf, DEL_INTERFACE);
534         CMD(set_channel, SET_CHANNEL);
535         CMD(set_pan_id, SET_PAN_ID);
536         CMD(set_short_addr, SET_SHORT_ADDR);
537         CMD(set_backoff_exponent, SET_BACKOFF_EXPONENT);
538         CMD(set_max_csma_backoffs, SET_MAX_CSMA_BACKOFFS);
539         CMD(set_max_frame_retries, SET_MAX_FRAME_RETRIES);
540         CMD(set_lbt_mode, SET_LBT_MODE);
541         CMD(set_ackreq_default, SET_ACKREQ_DEFAULT);
542 
543         if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER)
544                 CMD(set_tx_power, SET_TX_POWER);
545 
546         if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL)
547                 CMD(set_cca_ed_level, SET_CCA_ED_LEVEL);
548 
549         if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE)
550                 CMD(set_cca_mode, SET_CCA_MODE);
551 
552 #undef CMD
553         nla_nest_end(msg, nl_cmds);
554 
555 finish:
556         genlmsg_end(msg, hdr);
557         return 0;
558 
559 nla_put_failure:
560         genlmsg_cancel(msg, hdr);
561         return -EMSGSIZE;
562 }
563 
564 struct nl802154_dump_wpan_phy_state {
565         s64 filter_wpan_phy;
566         long start;
567 
568 };
569 
570 static int nl802154_dump_wpan_phy_parse(struct sk_buff *skb,
571                                         struct netlink_callback *cb,
572                                         struct nl802154_dump_wpan_phy_state *state)
573 {
574         struct nlattr **tb = nl802154_fam.attrbuf;
575         int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl802154_fam.hdrsize,
576                               tb, nl802154_fam.maxattr, nl802154_policy);
577 
578         /* TODO check if we can handle error here,
579          * we have no backward compatibility
580          */
581         if (ret)
582                 return 0;
583 
584         if (tb[NL802154_ATTR_WPAN_PHY])
585                 state->filter_wpan_phy = nla_get_u32(tb[NL802154_ATTR_WPAN_PHY]);
586         if (tb[NL802154_ATTR_WPAN_DEV])
587                 state->filter_wpan_phy = nla_get_u64(tb[NL802154_ATTR_WPAN_DEV]) >> 32;
588         if (tb[NL802154_ATTR_IFINDEX]) {
589                 struct net_device *netdev;
590                 struct cfg802154_registered_device *rdev;
591                 int ifidx = nla_get_u32(tb[NL802154_ATTR_IFINDEX]);
592 
593                 /* TODO netns */
594                 netdev = __dev_get_by_index(&init_net, ifidx);
595                 if (!netdev)
596                         return -ENODEV;
597                 if (netdev->ieee802154_ptr) {
598                         rdev = wpan_phy_to_rdev(
599                                         netdev->ieee802154_ptr->wpan_phy);
600                         state->filter_wpan_phy = rdev->wpan_phy_idx;
601                 }
602         }
603 
604         return 0;
605 }
606 
607 static int
608 nl802154_dump_wpan_phy(struct sk_buff *skb, struct netlink_callback *cb)
609 {
610         int idx = 0, ret;
611         struct nl802154_dump_wpan_phy_state *state = (void *)cb->args[0];
612         struct cfg802154_registered_device *rdev;
613 
614         rtnl_lock();
615         if (!state) {
616                 state = kzalloc(sizeof(*state), GFP_KERNEL);
617                 if (!state) {
618                         rtnl_unlock();
619                         return -ENOMEM;
620                 }
621                 state->filter_wpan_phy = -1;
622                 ret = nl802154_dump_wpan_phy_parse(skb, cb, state);
623                 if (ret) {
624                         kfree(state);
625                         rtnl_unlock();
626                         return ret;
627                 }
628                 cb->args[0] = (long)state;
629         }
630 
631         list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
632                 /* TODO net ns compare */
633                 if (++idx <= state->start)
634                         continue;
635                 if (state->filter_wpan_phy != -1 &&
636                     state->filter_wpan_phy != rdev->wpan_phy_idx)
637                         continue;
638                 /* attempt to fit multiple wpan_phy data chunks into the skb */
639                 ret = nl802154_send_wpan_phy(rdev,
640                                              NL802154_CMD_NEW_WPAN_PHY,
641                                              skb,
642                                              NETLINK_CB(cb->skb).portid,
643                                              cb->nlh->nlmsg_seq, NLM_F_MULTI);
644                 if (ret < 0) {
645                         if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
646                             !skb->len && cb->min_dump_alloc < 4096) {
647                                 cb->min_dump_alloc = 4096;
648                                 rtnl_unlock();
649                                 return 1;
650                         }
651                         idx--;
652                         break;
653                 }
654                 break;
655         }
656         rtnl_unlock();
657 
658         state->start = idx;
659 
660         return skb->len;
661 }
662 
663 static int nl802154_dump_wpan_phy_done(struct netlink_callback *cb)
664 {
665         kfree((void *)cb->args[0]);
666         return 0;
667 }
668 
669 static int nl802154_get_wpan_phy(struct sk_buff *skb, struct genl_info *info)
670 {
671         struct sk_buff *msg;
672         struct cfg802154_registered_device *rdev = info->user_ptr[0];
673 
674         msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
675         if (!msg)
676                 return -ENOMEM;
677 
678         if (nl802154_send_wpan_phy(rdev, NL802154_CMD_NEW_WPAN_PHY, msg,
679                                    info->snd_portid, info->snd_seq, 0) < 0) {
680                 nlmsg_free(msg);
681                 return -ENOBUFS;
682         }
683 
684         return genlmsg_reply(msg, info);
685 }
686 
687 static inline u64 wpan_dev_id(struct wpan_dev *wpan_dev)
688 {
689         return (u64)wpan_dev->identifier |
690                ((u64)wpan_phy_to_rdev(wpan_dev->wpan_phy)->wpan_phy_idx << 32);
691 }
692 
693 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
694 #include <net/ieee802154_netdev.h>
695 
696 static int
697 ieee802154_llsec_send_key_id(struct sk_buff *msg,
698                              const struct ieee802154_llsec_key_id *desc)
699 {
700         struct nlattr *nl_dev_addr;
701 
702         if (nla_put_u32(msg, NL802154_KEY_ID_ATTR_MODE, desc->mode))
703                 return -ENOBUFS;
704 
705         switch (desc->mode) {
706         case NL802154_KEY_ID_MODE_IMPLICIT:
707                 nl_dev_addr = nla_nest_start(msg, NL802154_KEY_ID_ATTR_IMPLICIT);
708                 if (!nl_dev_addr)
709                         return -ENOBUFS;
710 
711                 if (nla_put_le16(msg, NL802154_DEV_ADDR_ATTR_PAN_ID,
712                                  desc->device_addr.pan_id) ||
713                     nla_put_u32(msg,  NL802154_DEV_ADDR_ATTR_MODE,
714                                 desc->device_addr.mode))
715                         return -ENOBUFS;
716 
717                 switch (desc->device_addr.mode) {
718                 case NL802154_DEV_ADDR_SHORT:
719                         if (nla_put_le16(msg, NL802154_DEV_ADDR_ATTR_SHORT,
720                                          desc->device_addr.short_addr))
721                                 return -ENOBUFS;
722                         break;
723                 case NL802154_DEV_ADDR_EXTENDED:
724                         if (nla_put_le64(msg, NL802154_DEV_ADDR_ATTR_EXTENDED,
725                                          desc->device_addr.extended_addr,
726                                          NL802154_DEV_ADDR_ATTR_PAD))
727                                 return -ENOBUFS;
728                         break;
729                 default:
730                         /* userspace should handle unknown */
731                         break;
732                 }
733 
734                 nla_nest_end(msg, nl_dev_addr);
735                 break;
736         case NL802154_KEY_ID_MODE_INDEX:
737                 break;
738         case NL802154_KEY_ID_MODE_INDEX_SHORT:
739                 /* TODO renmae short_source? */
740                 if (nla_put_le32(msg, NL802154_KEY_ID_ATTR_SOURCE_SHORT,
741                                  desc->short_source))
742                         return -ENOBUFS;
743                 break;
744         case NL802154_KEY_ID_MODE_INDEX_EXTENDED:
745                 if (nla_put_le64(msg, NL802154_KEY_ID_ATTR_SOURCE_EXTENDED,
746                                  desc->extended_source,
747                                  NL802154_KEY_ID_ATTR_PAD))
748                         return -ENOBUFS;
749                 break;
750         default:
751                 /* userspace should handle unknown */
752                 break;
753         }
754 
755         /* TODO key_id to key_idx ? Check naming */
756         if (desc->mode != NL802154_KEY_ID_MODE_IMPLICIT) {
757                 if (nla_put_u8(msg, NL802154_KEY_ID_ATTR_INDEX, desc->id))
758                         return -ENOBUFS;
759         }
760 
761         return 0;
762 }
763 
764 static int nl802154_get_llsec_params(struct sk_buff *msg,
765                                      struct cfg802154_registered_device *rdev,
766                                      struct wpan_dev *wpan_dev)
767 {
768         struct nlattr *nl_key_id;
769         struct ieee802154_llsec_params params;
770         int ret;
771 
772         ret = rdev_get_llsec_params(rdev, wpan_dev, &params);
773         if (ret < 0)
774                 return ret;
775 
776         if (nla_put_u8(msg, NL802154_ATTR_SEC_ENABLED, params.enabled) ||
777             nla_put_u32(msg, NL802154_ATTR_SEC_OUT_LEVEL, params.out_level) ||
778             nla_put_be32(msg, NL802154_ATTR_SEC_FRAME_COUNTER,
779                          params.frame_counter))
780                 return -ENOBUFS;
781 
782         nl_key_id = nla_nest_start(msg, NL802154_ATTR_SEC_OUT_KEY_ID);
783         if (!nl_key_id)
784                 return -ENOBUFS;
785 
786         ret = ieee802154_llsec_send_key_id(msg, &params.out_key);
787         if (ret < 0)
788                 return ret;
789 
790         nla_nest_end(msg, nl_key_id);
791 
792         return 0;
793 }
794 #endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
795 
796 static int
797 nl802154_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
798                     struct cfg802154_registered_device *rdev,
799                     struct wpan_dev *wpan_dev)
800 {
801         struct net_device *dev = wpan_dev->netdev;
802         void *hdr;
803 
804         hdr = nl802154hdr_put(msg, portid, seq, flags,
805                               NL802154_CMD_NEW_INTERFACE);
806         if (!hdr)
807                 return -1;
808 
809         if (dev &&
810             (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex) ||
811              nla_put_string(msg, NL802154_ATTR_IFNAME, dev->name)))
812                 goto nla_put_failure;
813 
814         if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) ||
815             nla_put_u32(msg, NL802154_ATTR_IFTYPE, wpan_dev->iftype) ||
816             nla_put_u64_64bit(msg, NL802154_ATTR_WPAN_DEV,
817                               wpan_dev_id(wpan_dev), NL802154_ATTR_PAD) ||
818             nla_put_u32(msg, NL802154_ATTR_GENERATION,
819                         rdev->devlist_generation ^
820                         (cfg802154_rdev_list_generation << 2)))
821                 goto nla_put_failure;
822 
823         /* address settings */
824         if (nla_put_le64(msg, NL802154_ATTR_EXTENDED_ADDR,
825                          wpan_dev->extended_addr,
826                          NL802154_ATTR_PAD) ||
827             nla_put_le16(msg, NL802154_ATTR_SHORT_ADDR,
828                          wpan_dev->short_addr) ||
829             nla_put_le16(msg, NL802154_ATTR_PAN_ID, wpan_dev->pan_id))
830                 goto nla_put_failure;
831 
832         /* ARET handling */
833         if (nla_put_s8(msg, NL802154_ATTR_MAX_FRAME_RETRIES,
834                        wpan_dev->frame_retries) ||
835             nla_put_u8(msg, NL802154_ATTR_MAX_BE, wpan_dev->max_be) ||
836             nla_put_u8(msg, NL802154_ATTR_MAX_CSMA_BACKOFFS,
837                        wpan_dev->csma_retries) ||
838             nla_put_u8(msg, NL802154_ATTR_MIN_BE, wpan_dev->min_be))
839                 goto nla_put_failure;
840 
841         /* listen before transmit */
842         if (nla_put_u8(msg, NL802154_ATTR_LBT_MODE, wpan_dev->lbt))
843                 goto nla_put_failure;
844 
845         /* ackreq default behaviour */
846         if (nla_put_u8(msg, NL802154_ATTR_ACKREQ_DEFAULT, wpan_dev->ackreq))
847                 goto nla_put_failure;
848 
849 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
850         if (nl802154_get_llsec_params(msg, rdev, wpan_dev) < 0)
851                 goto nla_put_failure;
852 #endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
853 
854         genlmsg_end(msg, hdr);
855         return 0;
856 
857 nla_put_failure:
858         genlmsg_cancel(msg, hdr);
859         return -EMSGSIZE;
860 }
861 
862 static int
863 nl802154_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
864 {
865         int wp_idx = 0;
866         int if_idx = 0;
867         int wp_start = cb->args[0];
868         int if_start = cb->args[1];
869         struct cfg802154_registered_device *rdev;
870         struct wpan_dev *wpan_dev;
871 
872         rtnl_lock();
873         list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
874                 /* TODO netns compare */
875                 if (wp_idx < wp_start) {
876                         wp_idx++;
877                         continue;
878                 }
879                 if_idx = 0;
880 
881                 list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) {
882                         if (if_idx < if_start) {
883                                 if_idx++;
884                                 continue;
885                         }
886                         if (nl802154_send_iface(skb, NETLINK_CB(cb->skb).portid,
887                                                 cb->nlh->nlmsg_seq, NLM_F_MULTI,
888                                                 rdev, wpan_dev) < 0) {
889                                 goto out;
890                         }
891                         if_idx++;
892                 }
893 
894                 wp_idx++;
895         }
896 out:
897         rtnl_unlock();
898 
899         cb->args[0] = wp_idx;
900         cb->args[1] = if_idx;
901 
902         return skb->len;
903 }
904 
905 static int nl802154_get_interface(struct sk_buff *skb, struct genl_info *info)
906 {
907         struct sk_buff *msg;
908         struct cfg802154_registered_device *rdev = info->user_ptr[0];
909         struct wpan_dev *wdev = info->user_ptr[1];
910 
911         msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
912         if (!msg)
913                 return -ENOMEM;
914 
915         if (nl802154_send_iface(msg, info->snd_portid, info->snd_seq, 0,
916                                 rdev, wdev) < 0) {
917                 nlmsg_free(msg);
918                 return -ENOBUFS;
919         }
920 
921         return genlmsg_reply(msg, info);
922 }
923 
924 static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info)
925 {
926         struct cfg802154_registered_device *rdev = info->user_ptr[0];
927         enum nl802154_iftype type = NL802154_IFTYPE_UNSPEC;
928         __le64 extended_addr = cpu_to_le64(0x0000000000000000ULL);
929 
930         /* TODO avoid failing a new interface
931          * creation due to pending removal?
932          */
933 
934         if (!info->attrs[NL802154_ATTR_IFNAME])
935                 return -EINVAL;
936 
937         if (info->attrs[NL802154_ATTR_IFTYPE]) {
938                 type = nla_get_u32(info->attrs[NL802154_ATTR_IFTYPE]);
939                 if (type > NL802154_IFTYPE_MAX ||
940                     !(rdev->wpan_phy.supported.iftypes & BIT(type)))
941                         return -EINVAL;
942         }
943 
944         if (info->attrs[NL802154_ATTR_EXTENDED_ADDR])
945                 extended_addr = nla_get_le64(info->attrs[NL802154_ATTR_EXTENDED_ADDR]);
946 
947         if (!rdev->ops->add_virtual_intf)
948                 return -EOPNOTSUPP;
949 
950         return rdev_add_virtual_intf(rdev,
951                                      nla_data(info->attrs[NL802154_ATTR_IFNAME]),
952                                      NET_NAME_USER, type, extended_addr);
953 }
954 
955 static int nl802154_del_interface(struct sk_buff *skb, struct genl_info *info)
956 {
957         struct cfg802154_registered_device *rdev = info->user_ptr[0];
958         struct wpan_dev *wpan_dev = info->user_ptr[1];
959 
960         if (!rdev->ops->del_virtual_intf)
961                 return -EOPNOTSUPP;
962 
963         /* If we remove a wpan device without a netdev then clear
964          * user_ptr[1] so that nl802154_post_doit won't dereference it
965          * to check if it needs to do dev_put(). Otherwise it crashes
966          * since the wpan_dev has been freed, unlike with a netdev where
967          * we need the dev_put() for the netdev to really be freed.
968          */
969         if (!wpan_dev->netdev)
970                 info->user_ptr[1] = NULL;
971 
972         return rdev_del_virtual_intf(rdev, wpan_dev);
973 }
974 
975 static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info)
976 {
977         struct cfg802154_registered_device *rdev = info->user_ptr[0];
978         u8 channel, page;
979 
980         if (!info->attrs[NL802154_ATTR_PAGE] ||
981             !info->attrs[NL802154_ATTR_CHANNEL])
982                 return -EINVAL;
983 
984         page = nla_get_u8(info->attrs[NL802154_ATTR_PAGE]);
985         channel = nla_get_u8(info->attrs[NL802154_ATTR_CHANNEL]);
986 
987         /* check 802.15.4 constraints */
988         if (page > IEEE802154_MAX_PAGE || channel > IEEE802154_MAX_CHANNEL ||
989             !(rdev->wpan_phy.supported.channels[page] & BIT(channel)))
990                 return -EINVAL;
991 
992         return rdev_set_channel(rdev, page, channel);
993 }
994 
995 static int nl802154_set_cca_mode(struct sk_buff *skb, struct genl_info *info)
996 {
997         struct cfg802154_registered_device *rdev = info->user_ptr[0];
998         struct wpan_phy_cca cca;
999 
1000         if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE))
1001                 return -EOPNOTSUPP;
1002 
1003         if (!info->attrs[NL802154_ATTR_CCA_MODE])
1004                 return -EINVAL;
1005 
1006         cca.mode = nla_get_u32(info->attrs[NL802154_ATTR_CCA_MODE]);
1007         /* checking 802.15.4 constraints */
1008         if (cca.mode < NL802154_CCA_ENERGY ||
1009             cca.mode > NL802154_CCA_ATTR_MAX ||
1010             !(rdev->wpan_phy.supported.cca_modes & BIT(cca.mode)))
1011                 return -EINVAL;
1012 
1013         if (cca.mode == NL802154_CCA_ENERGY_CARRIER) {
1014                 if (!info->attrs[NL802154_ATTR_CCA_OPT])
1015                         return -EINVAL;
1016 
1017                 cca.opt = nla_get_u32(info->attrs[NL802154_ATTR_CCA_OPT]);
1018                 if (cca.opt > NL802154_CCA_OPT_ATTR_MAX ||
1019                     !(rdev->wpan_phy.supported.cca_opts & BIT(cca.opt)))
1020                         return -EINVAL;
1021         }
1022 
1023         return rdev_set_cca_mode(rdev, &cca);
1024 }
1025 
1026 static int nl802154_set_cca_ed_level(struct sk_buff *skb, struct genl_info *info)
1027 {
1028         struct cfg802154_registered_device *rdev = info->user_ptr[0];
1029         s32 ed_level;
1030         int i;
1031 
1032         if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL))
1033                 return -EOPNOTSUPP;
1034 
1035         if (!info->attrs[NL802154_ATTR_CCA_ED_LEVEL])
1036                 return -EINVAL;
1037 
1038         ed_level = nla_get_s32(info->attrs[NL802154_ATTR_CCA_ED_LEVEL]);
1039 
1040         for (i = 0; i < rdev->wpan_phy.supported.cca_ed_levels_size; i++) {
1041                 if (ed_level == rdev->wpan_phy.supported.cca_ed_levels[i])
1042                         return rdev_set_cca_ed_level(rdev, ed_level);
1043         }
1044 
1045         return -EINVAL;
1046 }
1047 
1048 static int nl802154_set_tx_power(struct sk_buff *skb, struct genl_info *info)
1049 {
1050         struct cfg802154_registered_device *rdev = info->user_ptr[0];
1051         s32 power;
1052         int i;
1053 
1054         if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER))
1055                 return -EOPNOTSUPP;
1056 
1057         if (!info->attrs[NL802154_ATTR_TX_POWER])
1058                 return -EINVAL;
1059 
1060         power = nla_get_s32(info->attrs[NL802154_ATTR_TX_POWER]);
1061 
1062         for (i = 0; i < rdev->wpan_phy.supported.tx_powers_size; i++) {
1063                 if (power == rdev->wpan_phy.supported.tx_powers[i])
1064                         return rdev_set_tx_power(rdev, power);
1065         }
1066 
1067         return -EINVAL;
1068 }
1069 
1070 static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info)
1071 {
1072         struct cfg802154_registered_device *rdev = info->user_ptr[0];
1073         struct net_device *dev = info->user_ptr[1];
1074         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1075         __le16 pan_id;
1076 
1077         /* conflict here while tx/rx calls */
1078         if (netif_running(dev))
1079                 return -EBUSY;
1080 
1081         if (wpan_dev->lowpan_dev) {
1082                 if (netif_running(wpan_dev->lowpan_dev))
1083                         return -EBUSY;
1084         }
1085 
1086         /* don't change address fields on monitor */
1087         if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
1088             !info->attrs[NL802154_ATTR_PAN_ID])
1089                 return -EINVAL;
1090 
1091         pan_id = nla_get_le16(info->attrs[NL802154_ATTR_PAN_ID]);
1092 
1093         /* TODO
1094          * I am not sure about to check here on broadcast pan_id.
1095          * Broadcast is a valid setting, comment from 802.15.4:
1096          * If this value is 0xffff, the device is not associated.
1097          *
1098          * This could useful to simple deassociate an device.
1099          */
1100         if (pan_id == cpu_to_le16(IEEE802154_PAN_ID_BROADCAST))
1101                 return -EINVAL;
1102 
1103         return rdev_set_pan_id(rdev, wpan_dev, pan_id);
1104 }
1105 
1106 static int nl802154_set_short_addr(struct sk_buff *skb, struct genl_info *info)
1107 {
1108         struct cfg802154_registered_device *rdev = info->user_ptr[0];
1109         struct net_device *dev = info->user_ptr[1];
1110         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1111         __le16 short_addr;
1112 
1113         /* conflict here while tx/rx calls */
1114         if (netif_running(dev))
1115                 return -EBUSY;
1116 
1117         if (wpan_dev->lowpan_dev) {
1118                 if (netif_running(wpan_dev->lowpan_dev))
1119                         return -EBUSY;
1120         }
1121 
1122         /* don't change address fields on monitor */
1123         if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
1124             !info->attrs[NL802154_ATTR_SHORT_ADDR])
1125                 return -EINVAL;
1126 
1127         short_addr = nla_get_le16(info->attrs[NL802154_ATTR_SHORT_ADDR]);
1128 
1129         /* TODO
1130          * I am not sure about to check here on broadcast short_addr.
1131          * Broadcast is a valid setting, comment from 802.15.4:
1132          * A value of 0xfffe indicates that the device has
1133          * associated but has not been allocated an address. A
1134          * value of 0xffff indicates that the device does not
1135          * have a short address.
1136          *
1137          * I think we should allow to set these settings but
1138          * don't allow to allow socket communication with it.
1139          */
1140         if (short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC) ||
1141             short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST))
1142                 return -EINVAL;
1143 
1144         return rdev_set_short_addr(rdev, wpan_dev, short_addr);
1145 }
1146 
1147 static int
1148 nl802154_set_backoff_exponent(struct sk_buff *skb, struct genl_info *info)
1149 {
1150         struct cfg802154_registered_device *rdev = info->user_ptr[0];
1151         struct net_device *dev = info->user_ptr[1];
1152         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1153         u8 min_be, max_be;
1154 
1155         /* should be set on netif open inside phy settings */
1156         if (netif_running(dev))
1157                 return -EBUSY;
1158 
1159         if (!info->attrs[NL802154_ATTR_MIN_BE] ||
1160             !info->attrs[NL802154_ATTR_MAX_BE])
1161                 return -EINVAL;
1162 
1163         min_be = nla_get_u8(info->attrs[NL802154_ATTR_MIN_BE]);
1164         max_be = nla_get_u8(info->attrs[NL802154_ATTR_MAX_BE]);
1165 
1166         /* check 802.15.4 constraints */
1167         if (min_be < rdev->wpan_phy.supported.min_minbe ||
1168             min_be > rdev->wpan_phy.supported.max_minbe ||
1169             max_be < rdev->wpan_phy.supported.min_maxbe ||
1170             max_be > rdev->wpan_phy.supported.max_maxbe ||
1171             min_be > max_be)
1172                 return -EINVAL;
1173 
1174         return rdev_set_backoff_exponent(rdev, wpan_dev, min_be, max_be);
1175 }
1176 
1177 static int
1178 nl802154_set_max_csma_backoffs(struct sk_buff *skb, struct genl_info *info)
1179 {
1180         struct cfg802154_registered_device *rdev = info->user_ptr[0];
1181         struct net_device *dev = info->user_ptr[1];
1182         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1183         u8 max_csma_backoffs;
1184 
1185         /* conflict here while other running iface settings */
1186         if (netif_running(dev))
1187                 return -EBUSY;
1188 
1189         if (!info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS])
1190                 return -EINVAL;
1191 
1192         max_csma_backoffs = nla_get_u8(
1193                         info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS]);
1194 
1195         /* check 802.15.4 constraints */
1196         if (max_csma_backoffs < rdev->wpan_phy.supported.min_csma_backoffs ||
1197             max_csma_backoffs > rdev->wpan_phy.supported.max_csma_backoffs)
1198                 return -EINVAL;
1199 
1200         return rdev_set_max_csma_backoffs(rdev, wpan_dev, max_csma_backoffs);
1201 }
1202 
1203 static int
1204 nl802154_set_max_frame_retries(struct sk_buff *skb, struct genl_info *info)
1205 {
1206         struct cfg802154_registered_device *rdev = info->user_ptr[0];
1207         struct net_device *dev = info->user_ptr[1];
1208         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1209         s8 max_frame_retries;
1210 
1211         if (netif_running(dev))
1212                 return -EBUSY;
1213 
1214         if (!info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES])
1215                 return -EINVAL;
1216 
1217         max_frame_retries = nla_get_s8(
1218                         info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES]);
1219 
1220         /* check 802.15.4 constraints */
1221         if (max_frame_retries < rdev->wpan_phy.supported.min_frame_retries ||
1222             max_frame_retries > rdev->wpan_phy.supported.max_frame_retries)
1223                 return -EINVAL;
1224 
1225         return rdev_set_max_frame_retries(rdev, wpan_dev, max_frame_retries);
1226 }
1227 
1228 static int nl802154_set_lbt_mode(struct sk_buff *skb, struct genl_info *info)
1229 {
1230         struct cfg802154_registered_device *rdev = info->user_ptr[0];
1231         struct net_device *dev = info->user_ptr[1];
1232         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1233         int mode;
1234 
1235         if (netif_running(dev))
1236                 return -EBUSY;
1237 
1238         if (!info->attrs[NL802154_ATTR_LBT_MODE])
1239                 return -EINVAL;
1240 
1241         mode = nla_get_u8(info->attrs[NL802154_ATTR_LBT_MODE]);
1242 
1243         if (mode != 0 && mode != 1)
1244                 return -EINVAL;
1245 
1246         if (!wpan_phy_supported_bool(mode, rdev->wpan_phy.supported.lbt))
1247                 return -EINVAL;
1248 
1249         return rdev_set_lbt_mode(rdev, wpan_dev, mode);
1250 }
1251 
1252 static int
1253 nl802154_set_ackreq_default(struct sk_buff *skb, struct genl_info *info)
1254 {
1255         struct cfg802154_registered_device *rdev = info->user_ptr[0];
1256         struct net_device *dev = info->user_ptr[1];
1257         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1258         int ackreq;
1259 
1260         if (netif_running(dev))
1261                 return -EBUSY;
1262 
1263         if (!info->attrs[NL802154_ATTR_ACKREQ_DEFAULT])
1264                 return -EINVAL;
1265 
1266         ackreq = nla_get_u8(info->attrs[NL802154_ATTR_ACKREQ_DEFAULT]);
1267 
1268         if (ackreq != 0 && ackreq != 1)
1269                 return -EINVAL;
1270 
1271         return rdev_set_ackreq_default(rdev, wpan_dev, ackreq);
1272 }
1273 
1274 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
1275 static const struct nla_policy nl802154_dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = {
1276         [NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 },
1277         [NL802154_DEV_ADDR_ATTR_MODE] = { .type = NLA_U32 },
1278         [NL802154_DEV_ADDR_ATTR_SHORT] = { .type = NLA_U16 },
1279         [NL802154_DEV_ADDR_ATTR_EXTENDED] = { .type = NLA_U64 },
1280 };
1281 
1282 static int
1283 ieee802154_llsec_parse_dev_addr(struct nlattr *nla,
1284                                 struct ieee802154_addr *addr)
1285 {
1286         struct nlattr *attrs[NL802154_DEV_ADDR_ATTR_MAX + 1];
1287 
1288         if (!nla || nla_parse_nested(attrs, NL802154_DEV_ADDR_ATTR_MAX, nla,
1289                                      nl802154_dev_addr_policy))
1290                 return -EINVAL;
1291 
1292         if (!attrs[NL802154_DEV_ADDR_ATTR_PAN_ID] ||
1293             !attrs[NL802154_DEV_ADDR_ATTR_MODE] ||
1294             !(attrs[NL802154_DEV_ADDR_ATTR_SHORT] ||
1295               attrs[NL802154_DEV_ADDR_ATTR_EXTENDED]))
1296                 return -EINVAL;
1297 
1298         addr->pan_id = nla_get_le16(attrs[NL802154_DEV_ADDR_ATTR_PAN_ID]);
1299         addr->mode = nla_get_u32(attrs[NL802154_DEV_ADDR_ATTR_MODE]);
1300         switch (addr->mode) {
1301         case NL802154_DEV_ADDR_SHORT:
1302                 addr->short_addr = nla_get_le16(attrs[NL802154_DEV_ADDR_ATTR_SHORT]);
1303                 break;
1304         case NL802154_DEV_ADDR_EXTENDED:
1305                 addr->extended_addr = nla_get_le64(attrs[NL802154_DEV_ADDR_ATTR_EXTENDED]);
1306                 break;
1307         default:
1308                 return -EINVAL;
1309         }
1310 
1311         return 0;
1312 }
1313 
1314 static const struct nla_policy nl802154_key_id_policy[NL802154_KEY_ID_ATTR_MAX + 1] = {
1315         [NL802154_KEY_ID_ATTR_MODE] = { .type = NLA_U32 },
1316         [NL802154_KEY_ID_ATTR_INDEX] = { .type = NLA_U8 },
1317         [NL802154_KEY_ID_ATTR_IMPLICIT] = { .type = NLA_NESTED },
1318         [NL802154_KEY_ID_ATTR_SOURCE_SHORT] = { .type = NLA_U32 },
1319         [NL802154_KEY_ID_ATTR_SOURCE_EXTENDED] = { .type = NLA_U64 },
1320 };
1321 
1322 static int
1323 ieee802154_llsec_parse_key_id(struct nlattr *nla,
1324                               struct ieee802154_llsec_key_id *desc)
1325 {
1326         struct nlattr *attrs[NL802154_KEY_ID_ATTR_MAX + 1];
1327 
1328         if (!nla || nla_parse_nested(attrs, NL802154_KEY_ID_ATTR_MAX, nla,
1329                                      nl802154_key_id_policy))
1330                 return -EINVAL;
1331 
1332         if (!attrs[NL802154_KEY_ID_ATTR_MODE])
1333                 return -EINVAL;
1334 
1335         desc->mode = nla_get_u32(attrs[NL802154_KEY_ID_ATTR_MODE]);
1336         switch (desc->mode) {
1337         case NL802154_KEY_ID_MODE_IMPLICIT:
1338                 if (!attrs[NL802154_KEY_ID_ATTR_IMPLICIT])
1339                         return -EINVAL;
1340 
1341                 if (ieee802154_llsec_parse_dev_addr(attrs[NL802154_KEY_ID_ATTR_IMPLICIT],
1342                                                     &desc->device_addr) < 0)
1343                         return -EINVAL;
1344                 break;
1345         case NL802154_KEY_ID_MODE_INDEX:
1346                 break;
1347         case NL802154_KEY_ID_MODE_INDEX_SHORT:
1348                 if (!attrs[NL802154_KEY_ID_ATTR_SOURCE_SHORT])
1349                         return -EINVAL;
1350 
1351                 desc->short_source = nla_get_le32(attrs[NL802154_KEY_ID_ATTR_SOURCE_SHORT]);
1352                 break;
1353         case NL802154_KEY_ID_MODE_INDEX_EXTENDED:
1354                 if (!attrs[NL802154_KEY_ID_ATTR_SOURCE_EXTENDED])
1355                         return -EINVAL;
1356 
1357                 desc->extended_source = nla_get_le64(attrs[NL802154_KEY_ID_ATTR_SOURCE_EXTENDED]);
1358                 break;
1359         default:
1360                 return -EINVAL;
1361         }
1362 
1363         if (desc->mode != NL802154_KEY_ID_MODE_IMPLICIT) {
1364                 if (!attrs[NL802154_KEY_ID_ATTR_INDEX])
1365                         return -EINVAL;
1366 
1367                 /* TODO change id to idx */
1368                 desc->id = nla_get_u8(attrs[NL802154_KEY_ID_ATTR_INDEX]);
1369         }
1370 
1371         return 0;
1372 }
1373 
1374 static int nl802154_set_llsec_params(struct sk_buff *skb,
1375                                      struct genl_info *info)
1376 {
1377         struct cfg802154_registered_device *rdev = info->user_ptr[0];
1378         struct net_device *dev = info->user_ptr[1];
1379         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1380         struct ieee802154_llsec_params params;
1381         u32 changed = 0;
1382         int ret;
1383 
1384         if (info->attrs[NL802154_ATTR_SEC_ENABLED]) {
1385                 u8 enabled;
1386 
1387                 enabled = nla_get_u8(info->attrs[NL802154_ATTR_SEC_ENABLED]);
1388                 if (enabled != 0 && enabled != 1)
1389                         return -EINVAL;
1390 
1391                 params.enabled = nla_get_u8(info->attrs[NL802154_ATTR_SEC_ENABLED]);
1392                 changed |= IEEE802154_LLSEC_PARAM_ENABLED;
1393         }
1394 
1395         if (info->attrs[NL802154_ATTR_SEC_OUT_KEY_ID]) {
1396                 ret = ieee802154_llsec_parse_key_id(info->attrs[NL802154_ATTR_SEC_OUT_KEY_ID],
1397                                                     &params.out_key);
1398                 if (ret < 0)
1399                         return ret;
1400 
1401                 changed |= IEEE802154_LLSEC_PARAM_OUT_KEY;
1402         }
1403 
1404         if (info->attrs[NL802154_ATTR_SEC_OUT_LEVEL]) {
1405                 params.out_level = nla_get_u32(info->attrs[NL802154_ATTR_SEC_OUT_LEVEL]);
1406                 if (params.out_level > NL802154_SECLEVEL_MAX)
1407                         return -EINVAL;
1408 
1409                 changed |= IEEE802154_LLSEC_PARAM_OUT_LEVEL;
1410         }
1411 
1412         if (info->attrs[NL802154_ATTR_SEC_FRAME_COUNTER]) {
1413                 params.frame_counter = nla_get_be32(info->attrs[NL802154_ATTR_SEC_FRAME_COUNTER]);
1414                 changed |= IEEE802154_LLSEC_PARAM_FRAME_COUNTER;
1415         }
1416 
1417         return rdev_set_llsec_params(rdev, wpan_dev, &params, changed);
1418 }
1419 
1420 static int nl802154_send_key(struct sk_buff *msg, u32 cmd, u32 portid,
1421                              u32 seq, int flags,
1422                              struct cfg802154_registered_device *rdev,
1423                              struct net_device *dev,
1424                              const struct ieee802154_llsec_key_entry *key)
1425 {
1426         void *hdr;
1427         u32 commands[NL802154_CMD_FRAME_NR_IDS / 32];
1428         struct nlattr *nl_key, *nl_key_id;
1429 
1430         hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
1431         if (!hdr)
1432                 return -1;
1433 
1434         if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
1435                 goto nla_put_failure;
1436 
1437         nl_key = nla_nest_start(msg, NL802154_ATTR_SEC_KEY);
1438         if (!nl_key)
1439                 goto nla_put_failure;
1440 
1441         nl_key_id = nla_nest_start(msg, NL802154_KEY_ATTR_ID);
1442         if (!nl_key_id)
1443                 goto nla_put_failure;
1444 
1445         if (ieee802154_llsec_send_key_id(msg, &key->id) < 0)
1446                 goto nla_put_failure;
1447 
1448         nla_nest_end(msg, nl_key_id);
1449 
1450         if (nla_put_u8(msg, NL802154_KEY_ATTR_USAGE_FRAMES,
1451                        key->key->frame_types))
1452                 goto nla_put_failure;
1453 
1454         if (key->key->frame_types & BIT(NL802154_FRAME_CMD)) {
1455                 /* TODO for each nested */
1456                 memset(commands, 0, sizeof(commands));
1457                 commands[7] = key->key->cmd_frame_ids;
1458                 if (nla_put(msg, NL802154_KEY_ATTR_USAGE_CMDS,
1459                             sizeof(commands), commands))
1460                         goto nla_put_failure;
1461         }
1462 
1463         if (nla_put(msg, NL802154_KEY_ATTR_BYTES, NL802154_KEY_SIZE,
1464                     key->key->key))
1465                 goto nla_put_failure;
1466 
1467         nla_nest_end(msg, nl_key);
1468         genlmsg_end(msg, hdr);
1469 
1470         return 0;
1471 
1472 nla_put_failure:
1473         genlmsg_cancel(msg, hdr);
1474         return -EMSGSIZE;
1475 }
1476 
1477 static int
1478 nl802154_dump_llsec_key(struct sk_buff *skb, struct netlink_callback *cb)
1479 {
1480         struct cfg802154_registered_device *rdev = NULL;
1481         struct ieee802154_llsec_key_entry *key;
1482         struct ieee802154_llsec_table *table;
1483         struct wpan_dev *wpan_dev;
1484         int err;
1485 
1486         err = nl802154_prepare_wpan_dev_dump(skb, cb, &rdev, &wpan_dev);
1487         if (err)
1488                 return err;
1489 
1490         if (!wpan_dev->netdev) {
1491                 err = -EINVAL;
1492                 goto out_err;
1493         }
1494 
1495         rdev_lock_llsec_table(rdev, wpan_dev);
1496         rdev_get_llsec_table(rdev, wpan_dev, &table);
1497 
1498         /* TODO make it like station dump */
1499         if (cb->args[2])
1500                 goto out;
1501 
1502         list_for_each_entry(key, &table->keys, list) {
1503                 if (nl802154_send_key(skb, NL802154_CMD_NEW_SEC_KEY,
1504                                       NETLINK_CB(cb->skb).portid,
1505                                       cb->nlh->nlmsg_seq, NLM_F_MULTI,
1506                                       rdev, wpan_dev->netdev, key) < 0) {
1507                         /* TODO */
1508                         err = -EIO;
1509                         rdev_unlock_llsec_table(rdev, wpan_dev);
1510                         goto out_err;
1511                 }
1512         }
1513 
1514         cb->args[2] = 1;
1515 
1516 out:
1517         rdev_unlock_llsec_table(rdev, wpan_dev);
1518         err = skb->len;
1519 out_err:
1520         nl802154_finish_wpan_dev_dump(rdev);
1521 
1522         return err;
1523 }
1524 
1525 static const struct nla_policy nl802154_key_policy[NL802154_KEY_ATTR_MAX + 1] = {
1526         [NL802154_KEY_ATTR_ID] = { NLA_NESTED },
1527         /* TODO handle it as for_each_nested and NLA_FLAG? */
1528         [NL802154_KEY_ATTR_USAGE_FRAMES] = { NLA_U8 },
1529         /* TODO handle it as for_each_nested, not static array? */
1530         [NL802154_KEY_ATTR_USAGE_CMDS] = { .len = NL802154_CMD_FRAME_NR_IDS / 8 },
1531         [NL802154_KEY_ATTR_BYTES] = { .len = NL802154_KEY_SIZE },
1532 };
1533 
1534 static int nl802154_add_llsec_key(struct sk_buff *skb, struct genl_info *info)
1535 {
1536         struct cfg802154_registered_device *rdev = info->user_ptr[0];
1537         struct net_device *dev = info->user_ptr[1];
1538         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1539         struct nlattr *attrs[NL802154_KEY_ATTR_MAX + 1];
1540         struct ieee802154_llsec_key key = { };
1541         struct ieee802154_llsec_key_id id = { };
1542         u32 commands[NL802154_CMD_FRAME_NR_IDS / 32] = { };
1543 
1544         if (nla_parse_nested(attrs, NL802154_KEY_ATTR_MAX,
1545                              info->attrs[NL802154_ATTR_SEC_KEY],
1546                              nl802154_key_policy))
1547                 return -EINVAL;
1548 
1549         if (!attrs[NL802154_KEY_ATTR_USAGE_FRAMES] ||
1550             !attrs[NL802154_KEY_ATTR_BYTES])
1551                 return -EINVAL;
1552 
1553         if (ieee802154_llsec_parse_key_id(attrs[NL802154_KEY_ATTR_ID], &id) < 0)
1554                 return -ENOBUFS;
1555 
1556         key.frame_types = nla_get_u8(attrs[NL802154_KEY_ATTR_USAGE_FRAMES]);
1557         if (key.frame_types > BIT(NL802154_FRAME_MAX) ||
1558             ((key.frame_types & BIT(NL802154_FRAME_CMD)) &&
1559              !attrs[NL802154_KEY_ATTR_USAGE_CMDS]))
1560                 return -EINVAL;
1561 
1562         if (attrs[NL802154_KEY_ATTR_USAGE_CMDS]) {
1563                 /* TODO for each nested */
1564                 nla_memcpy(commands, attrs[NL802154_KEY_ATTR_USAGE_CMDS],
1565                            NL802154_CMD_FRAME_NR_IDS / 8);
1566 
1567                 /* TODO understand the -EINVAL logic here? last condition */
1568                 if (commands[0] || commands[1] || commands[2] || commands[3] ||
1569                     commands[4] || commands[5] || commands[6] ||
1570                     commands[7] > BIT(NL802154_CMD_FRAME_MAX))
1571                         return -EINVAL;
1572 
1573                 key.cmd_frame_ids = commands[7];
1574         } else {
1575                 key.cmd_frame_ids = 0;
1576         }
1577 
1578         nla_memcpy(key.key, attrs[NL802154_KEY_ATTR_BYTES], NL802154_KEY_SIZE);
1579 
1580         if (ieee802154_llsec_parse_key_id(attrs[NL802154_KEY_ATTR_ID], &id) < 0)
1581                 return -ENOBUFS;
1582 
1583         return rdev_add_llsec_key(rdev, wpan_dev, &id, &key);
1584 }
1585 
1586 static int nl802154_del_llsec_key(struct sk_buff *skb, struct genl_info *info)
1587 {
1588         struct cfg802154_registered_device *rdev = info->user_ptr[0];
1589         struct net_device *dev = info->user_ptr[1];
1590         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1591         struct nlattr *attrs[NL802154_KEY_ATTR_MAX + 1];
1592         struct ieee802154_llsec_key_id id;
1593 
1594         if (nla_parse_nested(attrs, NL802154_KEY_ATTR_MAX,
1595                              info->attrs[NL802154_ATTR_SEC_KEY],
1596                              nl802154_key_policy))
1597                 return -EINVAL;
1598 
1599         if (ieee802154_llsec_parse_key_id(attrs[NL802154_KEY_ATTR_ID], &id) < 0)
1600                 return -ENOBUFS;
1601 
1602         return rdev_del_llsec_key(rdev, wpan_dev, &id);
1603 }
1604 
1605 static int nl802154_send_device(struct sk_buff *msg, u32 cmd, u32 portid,
1606                                 u32 seq, int flags,
1607                                 struct cfg802154_registered_device *rdev,
1608                                 struct net_device *dev,
1609                                 const struct ieee802154_llsec_device *dev_desc)
1610 {
1611         void *hdr;
1612         struct nlattr *nl_device;
1613 
1614         hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
1615         if (!hdr)
1616                 return -1;
1617 
1618         if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
1619                 goto nla_put_failure;
1620 
1621         nl_device = nla_nest_start(msg, NL802154_ATTR_SEC_DEVICE);
1622         if (!nl_device)
1623                 goto nla_put_failure;
1624 
1625         if (nla_put_u32(msg, NL802154_DEV_ATTR_FRAME_COUNTER,
1626                         dev_desc->frame_counter) ||
1627             nla_put_le16(msg, NL802154_DEV_ATTR_PAN_ID, dev_desc->pan_id) ||
1628             nla_put_le16(msg, NL802154_DEV_ATTR_SHORT_ADDR,
1629                          dev_desc->short_addr) ||
1630             nla_put_le64(msg, NL802154_DEV_ATTR_EXTENDED_ADDR,
1631                          dev_desc->hwaddr, NL802154_DEV_ATTR_PAD) ||
1632             nla_put_u8(msg, NL802154_DEV_ATTR_SECLEVEL_EXEMPT,
1633                        dev_desc->seclevel_exempt) ||
1634             nla_put_u32(msg, NL802154_DEV_ATTR_KEY_MODE, dev_desc->key_mode))
1635                 goto nla_put_failure;
1636 
1637         nla_nest_end(msg, nl_device);
1638         genlmsg_end(msg, hdr);
1639 
1640         return 0;
1641 
1642 nla_put_failure:
1643         genlmsg_cancel(msg, hdr);
1644         return -EMSGSIZE;
1645 }
1646 
1647 static int
1648 nl802154_dump_llsec_dev(struct sk_buff *skb, struct netlink_callback *cb)
1649 {
1650         struct cfg802154_registered_device *rdev = NULL;
1651         struct ieee802154_llsec_device *dev;
1652         struct ieee802154_llsec_table *table;
1653         struct wpan_dev *wpan_dev;
1654         int err;
1655 
1656         err = nl802154_prepare_wpan_dev_dump(skb, cb, &rdev, &wpan_dev);
1657         if (err)
1658                 return err;
1659 
1660         if (!wpan_dev->netdev) {
1661                 err = -EINVAL;
1662                 goto out_err;
1663         }
1664 
1665         rdev_lock_llsec_table(rdev, wpan_dev);
1666         rdev_get_llsec_table(rdev, wpan_dev, &table);
1667 
1668         /* TODO make it like station dump */
1669         if (cb->args[2])
1670                 goto out;
1671 
1672         list_for_each_entry(dev, &table->devices, list) {
1673                 if (nl802154_send_device(skb, NL802154_CMD_NEW_SEC_LEVEL,
1674                                          NETLINK_CB(cb->skb).portid,
1675                                          cb->nlh->nlmsg_seq, NLM_F_MULTI,
1676                                          rdev, wpan_dev->netdev, dev) < 0) {
1677                         /* TODO */
1678                         err = -EIO;
1679                         rdev_unlock_llsec_table(rdev, wpan_dev);
1680                         goto out_err;
1681                 }
1682         }
1683 
1684         cb->args[2] = 1;
1685 
1686 out:
1687         rdev_unlock_llsec_table(rdev, wpan_dev);
1688         err = skb->len;
1689 out_err:
1690         nl802154_finish_wpan_dev_dump(rdev);
1691 
1692         return err;
1693 }
1694 
1695 static const struct nla_policy nl802154_dev_policy[NL802154_DEV_ATTR_MAX + 1] = {
1696         [NL802154_DEV_ATTR_FRAME_COUNTER] = { NLA_U32 },
1697         [NL802154_DEV_ATTR_PAN_ID] = { .type = NLA_U16 },
1698         [NL802154_DEV_ATTR_SHORT_ADDR] = { .type = NLA_U16 },
1699         [NL802154_DEV_ATTR_EXTENDED_ADDR] = { .type = NLA_U64 },
1700         [NL802154_DEV_ATTR_SECLEVEL_EXEMPT] = { NLA_U8 },
1701         [NL802154_DEV_ATTR_KEY_MODE] = { NLA_U32 },
1702 };
1703 
1704 static int
1705 ieee802154_llsec_parse_device(struct nlattr *nla,
1706                               struct ieee802154_llsec_device *dev)
1707 {
1708         struct nlattr *attrs[NL802154_DEV_ATTR_MAX + 1];
1709 
1710         if (!nla || nla_parse_nested(attrs, NL802154_DEV_ATTR_MAX, nla,
1711                                      nl802154_dev_policy))
1712                 return -EINVAL;
1713 
1714         memset(dev, 0, sizeof(*dev));
1715 
1716         if (!attrs[NL802154_DEV_ATTR_FRAME_COUNTER] ||
1717             !attrs[NL802154_DEV_ATTR_PAN_ID] ||
1718             !attrs[NL802154_DEV_ATTR_SHORT_ADDR] ||
1719             !attrs[NL802154_DEV_ATTR_EXTENDED_ADDR] ||
1720             !attrs[NL802154_DEV_ATTR_SECLEVEL_EXEMPT] ||
1721             !attrs[NL802154_DEV_ATTR_KEY_MODE])
1722                 return -EINVAL;
1723 
1724         /* TODO be32 */
1725         dev->frame_counter = nla_get_u32(attrs[NL802154_DEV_ATTR_FRAME_COUNTER]);
1726         dev->pan_id = nla_get_le16(attrs[NL802154_DEV_ATTR_PAN_ID]);
1727         dev->short_addr = nla_get_le16(attrs[NL802154_DEV_ATTR_SHORT_ADDR]);
1728         /* TODO rename hwaddr to extended_addr */
1729         dev->hwaddr = nla_get_le64(attrs[NL802154_DEV_ATTR_EXTENDED_ADDR]);
1730         dev->seclevel_exempt = nla_get_u8(attrs[NL802154_DEV_ATTR_SECLEVEL_EXEMPT]);
1731         dev->key_mode = nla_get_u32(attrs[NL802154_DEV_ATTR_KEY_MODE]);
1732 
1733         if (dev->key_mode > NL802154_DEVKEY_MAX ||
1734             (dev->seclevel_exempt != 0 && dev->seclevel_exempt != 1))
1735                 return -EINVAL;
1736 
1737         return 0;
1738 }
1739 
1740 static int nl802154_add_llsec_dev(struct sk_buff *skb, struct genl_info *info)
1741 {
1742         struct cfg802154_registered_device *rdev = info->user_ptr[0];
1743         struct net_device *dev = info->user_ptr[1];
1744         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1745         struct ieee802154_llsec_device dev_desc;
1746 
1747         if (ieee802154_llsec_parse_device(info->attrs[NL802154_ATTR_SEC_DEVICE],
1748                                           &dev_desc) < 0)
1749                 return -EINVAL;
1750 
1751         return rdev_add_device(rdev, wpan_dev, &dev_desc);
1752 }
1753 
1754 static int nl802154_del_llsec_dev(struct sk_buff *skb, struct genl_info *info)
1755 {
1756         struct cfg802154_registered_device *rdev = info->user_ptr[0];
1757         struct net_device *dev = info->user_ptr[1];
1758         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1759         struct nlattr *attrs[NL802154_DEV_ATTR_MAX + 1];
1760         __le64 extended_addr;
1761 
1762         if (nla_parse_nested(attrs, NL802154_DEV_ATTR_MAX,
1763                              info->attrs[NL802154_ATTR_SEC_DEVICE],
1764                              nl802154_dev_policy))
1765                 return -EINVAL;
1766 
1767         if (!attrs[NL802154_DEV_ATTR_EXTENDED_ADDR])
1768                 return -EINVAL;
1769 
1770         extended_addr = nla_get_le64(attrs[NL802154_DEV_ATTR_EXTENDED_ADDR]);
1771         return rdev_del_device(rdev, wpan_dev, extended_addr);
1772 }
1773 
1774 static int nl802154_send_devkey(struct sk_buff *msg, u32 cmd, u32 portid,
1775                                 u32 seq, int flags,
1776                                 struct cfg802154_registered_device *rdev,
1777                                 struct net_device *dev, __le64 extended_addr,
1778                                 const struct ieee802154_llsec_device_key *devkey)
1779 {
1780         void *hdr;
1781         struct nlattr *nl_devkey, *nl_key_id;
1782 
1783         hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
1784         if (!hdr)
1785                 return -1;
1786 
1787         if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
1788                 goto nla_put_failure;
1789 
1790         nl_devkey = nla_nest_start(msg, NL802154_ATTR_SEC_DEVKEY);
1791         if (!nl_devkey)
1792                 goto nla_put_failure;
1793 
1794         if (nla_put_le64(msg, NL802154_DEVKEY_ATTR_EXTENDED_ADDR,
1795                          extended_addr, NL802154_DEVKEY_ATTR_PAD) ||
1796             nla_put_u32(msg, NL802154_DEVKEY_ATTR_FRAME_COUNTER,
1797                         devkey->frame_counter))
1798                 goto nla_put_failure;
1799 
1800         nl_key_id = nla_nest_start(msg, NL802154_DEVKEY_ATTR_ID);
1801         if (!nl_key_id)
1802                 goto nla_put_failure;
1803 
1804         if (ieee802154_llsec_send_key_id(msg, &devkey->key_id) < 0)
1805                 goto nla_put_failure;
1806 
1807         nla_nest_end(msg, nl_key_id);
1808         nla_nest_end(msg, nl_devkey);
1809         genlmsg_end(msg, hdr);
1810 
1811         return 0;
1812 
1813 nla_put_failure:
1814         genlmsg_cancel(msg, hdr);
1815         return -EMSGSIZE;
1816 }
1817 
1818 static int
1819 nl802154_dump_llsec_devkey(struct sk_buff *skb, struct netlink_callback *cb)
1820 {
1821         struct cfg802154_registered_device *rdev = NULL;
1822         struct ieee802154_llsec_device_key *kpos;
1823         struct ieee802154_llsec_device *dpos;
1824         struct ieee802154_llsec_table *table;
1825         struct wpan_dev *wpan_dev;
1826         int err;
1827 
1828         err = nl802154_prepare_wpan_dev_dump(skb, cb, &rdev, &wpan_dev);
1829         if (err)
1830                 return err;
1831 
1832         if (!wpan_dev->netdev) {
1833                 err = -EINVAL;
1834                 goto out_err;
1835         }
1836 
1837         rdev_lock_llsec_table(rdev, wpan_dev);
1838         rdev_get_llsec_table(rdev, wpan_dev, &table);
1839 
1840         /* TODO make it like station dump */
1841         if (cb->args[2])
1842                 goto out;
1843 
1844         /* TODO look if remove devkey and do some nested attribute */
1845         list_for_each_entry(dpos, &table->devices, list) {
1846                 list_for_each_entry(kpos, &dpos->keys, list) {
1847                         if (nl802154_send_devkey(skb,
1848                                                  NL802154_CMD_NEW_SEC_LEVEL,
1849                                                  NETLINK_CB(cb->skb).portid,
1850                                                  cb->nlh->nlmsg_seq,
1851                                                  NLM_F_MULTI, rdev,
1852                                                  wpan_dev->netdev,
1853                                                  dpos->hwaddr,
1854                                                  kpos) < 0) {
1855                                 /* TODO */
1856                                 err = -EIO;
1857                                 rdev_unlock_llsec_table(rdev, wpan_dev);
1858                                 goto out_err;
1859                         }
1860                 }
1861         }
1862 
1863         cb->args[2] = 1;
1864 
1865 out:
1866         rdev_unlock_llsec_table(rdev, wpan_dev);
1867         err = skb->len;
1868 out_err:
1869         nl802154_finish_wpan_dev_dump(rdev);
1870 
1871         return err;
1872 }
1873 
1874 static const struct nla_policy nl802154_devkey_policy[NL802154_DEVKEY_ATTR_MAX + 1] = {
1875         [NL802154_DEVKEY_ATTR_FRAME_COUNTER] = { NLA_U32 },
1876         [NL802154_DEVKEY_ATTR_EXTENDED_ADDR] = { NLA_U64 },
1877         [NL802154_DEVKEY_ATTR_ID] = { NLA_NESTED },
1878 };
1879 
1880 static int nl802154_add_llsec_devkey(struct sk_buff *skb, struct genl_info *info)
1881 {
1882         struct cfg802154_registered_device *rdev = info->user_ptr[0];
1883         struct net_device *dev = info->user_ptr[1];
1884         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1885         struct nlattr *attrs[NL802154_DEVKEY_ATTR_MAX + 1];
1886         struct ieee802154_llsec_device_key key;
1887         __le64 extended_addr;
1888 
1889         if (!info->attrs[NL802154_ATTR_SEC_DEVKEY] ||
1890             nla_parse_nested(attrs, NL802154_DEVKEY_ATTR_MAX,
1891                              info->attrs[NL802154_ATTR_SEC_DEVKEY],
1892                              nl802154_devkey_policy) < 0)
1893                 return -EINVAL;
1894 
1895         if (!attrs[NL802154_DEVKEY_ATTR_FRAME_COUNTER] ||
1896             !attrs[NL802154_DEVKEY_ATTR_EXTENDED_ADDR])
1897                 return -EINVAL;
1898 
1899         /* TODO change key.id ? */
1900         if (ieee802154_llsec_parse_key_id(attrs[NL802154_DEVKEY_ATTR_ID],
1901                                           &key.key_id) < 0)
1902                 return -ENOBUFS;
1903 
1904         /* TODO be32 */
1905         key.frame_counter = nla_get_u32(attrs[NL802154_DEVKEY_ATTR_FRAME_COUNTER]);
1906         /* TODO change naming hwaddr -> extended_addr
1907          * check unique identifier short+pan OR extended_addr
1908          */
1909         extended_addr = nla_get_le64(attrs[NL802154_DEVKEY_ATTR_EXTENDED_ADDR]);
1910         return rdev_add_devkey(rdev, wpan_dev, extended_addr, &key);
1911 }
1912 
1913 static int nl802154_del_llsec_devkey(struct sk_buff *skb, struct genl_info *info)
1914 {
1915         struct cfg802154_registered_device *rdev = info->user_ptr[0];
1916         struct net_device *dev = info->user_ptr[1];
1917         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1918         struct nlattr *attrs[NL802154_DEVKEY_ATTR_MAX + 1];
1919         struct ieee802154_llsec_device_key key;
1920         __le64 extended_addr;
1921 
1922         if (nla_parse_nested(attrs, NL802154_DEVKEY_ATTR_MAX,
1923                              info->attrs[NL802154_ATTR_SEC_DEVKEY],
1924                              nl802154_devkey_policy))
1925                 return -EINVAL;
1926 
1927         if (!attrs[NL802154_DEVKEY_ATTR_EXTENDED_ADDR])
1928                 return -EINVAL;
1929 
1930         /* TODO change key.id ? */
1931         if (ieee802154_llsec_parse_key_id(attrs[NL802154_DEVKEY_ATTR_ID],
1932                                           &key.key_id) < 0)
1933                 return -ENOBUFS;
1934 
1935         /* TODO change naming hwaddr -> extended_addr
1936          * check unique identifier short+pan OR extended_addr
1937          */
1938         extended_addr = nla_get_le64(attrs[NL802154_DEVKEY_ATTR_EXTENDED_ADDR]);
1939         return rdev_del_devkey(rdev, wpan_dev, extended_addr, &key);
1940 }
1941 
1942 static int nl802154_send_seclevel(struct sk_buff *msg, u32 cmd, u32 portid,
1943                                   u32 seq, int flags,
1944                                   struct cfg802154_registered_device *rdev,
1945                                   struct net_device *dev,
1946                                   const struct ieee802154_llsec_seclevel *sl)
1947 {
1948         void *hdr;
1949         struct nlattr *nl_seclevel;
1950 
1951         hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
1952         if (!hdr)
1953                 return -1;
1954 
1955         if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
1956                 goto nla_put_failure;
1957 
1958         nl_seclevel = nla_nest_start(msg, NL802154_ATTR_SEC_LEVEL);
1959         if (!nl_seclevel)
1960                 goto nla_put_failure;
1961 
1962         if (nla_put_u32(msg, NL802154_SECLEVEL_ATTR_FRAME, sl->frame_type) ||
1963             nla_put_u32(msg, NL802154_SECLEVEL_ATTR_LEVELS, sl->sec_levels) ||
1964             nla_put_u8(msg, NL802154_SECLEVEL_ATTR_DEV_OVERRIDE,
1965                        sl->device_override))
1966                 goto nla_put_failure;
1967 
1968         if (sl->frame_type == NL802154_FRAME_CMD) {
1969                 if (nla_put_u32(msg, NL802154_SECLEVEL_ATTR_CMD_FRAME,
1970                                 sl->cmd_frame_id))
1971                         goto nla_put_failure;
1972         }
1973 
1974         nla_nest_end(msg, nl_seclevel);
1975         genlmsg_end(msg, hdr);
1976 
1977         return 0;
1978 
1979 nla_put_failure:
1980         genlmsg_cancel(msg, hdr);
1981         return -EMSGSIZE;
1982 }
1983 
1984 static int
1985 nl802154_dump_llsec_seclevel(struct sk_buff *skb, struct netlink_callback *cb)
1986 {
1987         struct cfg802154_registered_device *rdev = NULL;
1988         struct ieee802154_llsec_seclevel *sl;
1989         struct ieee802154_llsec_table *table;
1990         struct wpan_dev *wpan_dev;
1991         int err;
1992 
1993         err = nl802154_prepare_wpan_dev_dump(skb, cb, &rdev, &wpan_dev);
1994         if (err)
1995                 return err;
1996 
1997         if (!wpan_dev->netdev) {
1998                 err = -EINVAL;
1999                 goto out_err;
2000         }
2001 
2002         rdev_lock_llsec_table(rdev, wpan_dev);
2003         rdev_get_llsec_table(rdev, wpan_dev, &table);
2004 
2005         /* TODO make it like station dump */
2006         if (cb->args[2])
2007                 goto out;
2008 
2009         list_for_each_entry(sl, &table->security_levels, list) {
2010                 if (nl802154_send_seclevel(skb, NL802154_CMD_NEW_SEC_LEVEL,
2011                                            NETLINK_CB(cb->skb).portid,
2012                                            cb->nlh->nlmsg_seq, NLM_F_MULTI,
2013                                            rdev, wpan_dev->netdev, sl) < 0) {
2014                         /* TODO */
2015                         err = -EIO;
2016                         rdev_unlock_llsec_table(rdev, wpan_dev);
2017                         goto out_err;
2018                 }
2019         }
2020 
2021         cb->args[2] = 1;
2022 
2023 out:
2024         rdev_unlock_llsec_table(rdev, wpan_dev);
2025         err = skb->len;
2026 out_err:
2027         nl802154_finish_wpan_dev_dump(rdev);
2028 
2029         return err;
2030 }
2031 
2032 static const struct nla_policy nl802154_seclevel_policy[NL802154_SECLEVEL_ATTR_MAX + 1] = {
2033         [NL802154_SECLEVEL_ATTR_LEVELS] = { .type = NLA_U8 },
2034         [NL802154_SECLEVEL_ATTR_FRAME] = { .type = NLA_U32 },
2035         [NL802154_SECLEVEL_ATTR_CMD_FRAME] = { .type = NLA_U32 },
2036         [NL802154_SECLEVEL_ATTR_DEV_OVERRIDE] = { .type = NLA_U8 },
2037 };
2038 
2039 static int
2040 llsec_parse_seclevel(struct nlattr *nla, struct ieee802154_llsec_seclevel *sl)
2041 {
2042         struct nlattr *attrs[NL802154_SECLEVEL_ATTR_MAX + 1];
2043 
2044         if (!nla || nla_parse_nested(attrs, NL802154_SECLEVEL_ATTR_MAX, nla,
2045                                      nl802154_seclevel_policy))
2046                 return -EINVAL;
2047 
2048         memset(sl, 0, sizeof(*sl));
2049 
2050         if (!attrs[NL802154_SECLEVEL_ATTR_LEVELS] ||
2051             !attrs[NL802154_SECLEVEL_ATTR_FRAME] ||
2052             !attrs[NL802154_SECLEVEL_ATTR_DEV_OVERRIDE])
2053                 return -EINVAL;
2054 
2055         sl->sec_levels = nla_get_u8(attrs[NL802154_SECLEVEL_ATTR_LEVELS]);
2056         sl->frame_type = nla_get_u32(attrs[NL802154_SECLEVEL_ATTR_FRAME]);
2057         sl->device_override = nla_get_u8(attrs[NL802154_SECLEVEL_ATTR_DEV_OVERRIDE]);
2058         if (sl->frame_type > NL802154_FRAME_MAX ||
2059             (sl->device_override != 0 && sl->device_override != 1))
2060                 return -EINVAL;
2061 
2062         if (sl->frame_type == NL802154_FRAME_CMD) {
2063                 if (!attrs[NL802154_SECLEVEL_ATTR_CMD_FRAME])
2064                         return -EINVAL;
2065 
2066                 sl->cmd_frame_id = nla_get_u32(attrs[NL802154_SECLEVEL_ATTR_CMD_FRAME]);
2067                 if (sl->cmd_frame_id > NL802154_CMD_FRAME_MAX)
2068                         return -EINVAL;
2069         }
2070 
2071         return 0;
2072 }
2073 
2074 static int nl802154_add_llsec_seclevel(struct sk_buff *skb,
2075                                        struct genl_info *info)
2076 {
2077         struct cfg802154_registered_device *rdev = info->user_ptr[0];
2078         struct net_device *dev = info->user_ptr[1];
2079         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
2080         struct ieee802154_llsec_seclevel sl;
2081 
2082         if (llsec_parse_seclevel(info->attrs[NL802154_ATTR_SEC_LEVEL],
2083                                  &sl) < 0)
2084                 return -EINVAL;
2085 
2086         return rdev_add_seclevel(rdev, wpan_dev, &sl);
2087 }
2088 
2089 static int nl802154_del_llsec_seclevel(struct sk_buff *skb,
2090                                        struct genl_info *info)
2091 {
2092         struct cfg802154_registered_device *rdev = info->user_ptr[0];
2093         struct net_device *dev = info->user_ptr[1];
2094         struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
2095         struct ieee802154_llsec_seclevel sl;
2096 
2097         if (!info->attrs[NL802154_ATTR_SEC_LEVEL] ||
2098             llsec_parse_seclevel(info->attrs[NL802154_ATTR_SEC_LEVEL],
2099                                  &sl) < 0)
2100                 return -EINVAL;
2101 
2102         return rdev_del_seclevel(rdev, wpan_dev, &sl);
2103 }
2104 #endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
2105 
2106 #define NL802154_FLAG_NEED_WPAN_PHY     0x01
2107 #define NL802154_FLAG_NEED_NETDEV       0x02
2108 #define NL802154_FLAG_NEED_RTNL         0x04
2109 #define NL802154_FLAG_CHECK_NETDEV_UP   0x08
2110 #define NL802154_FLAG_NEED_NETDEV_UP    (NL802154_FLAG_NEED_NETDEV |\
2111                                          NL802154_FLAG_CHECK_NETDEV_UP)
2112 #define NL802154_FLAG_NEED_WPAN_DEV     0x10
2113 #define NL802154_FLAG_NEED_WPAN_DEV_UP  (NL802154_FLAG_NEED_WPAN_DEV |\
2114                                          NL802154_FLAG_CHECK_NETDEV_UP)
2115 
2116 static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
2117                              struct genl_info *info)
2118 {
2119         struct cfg802154_registered_device *rdev;
2120         struct wpan_dev *wpan_dev;
2121         struct net_device *dev;
2122         bool rtnl = ops->internal_flags & NL802154_FLAG_NEED_RTNL;
2123 
2124         if (rtnl)
2125                 rtnl_lock();
2126 
2127         if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_PHY) {
2128                 rdev = cfg802154_get_dev_from_info(genl_info_net(info), info);
2129                 if (IS_ERR(rdev)) {
2130                         if (rtnl)
2131                                 rtnl_unlock();
2132                         return PTR_ERR(rdev);
2133                 }
2134                 info->user_ptr[0] = rdev;
2135         } else if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV ||
2136                    ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
2137                 ASSERT_RTNL();
2138                 wpan_dev = __cfg802154_wpan_dev_from_attrs(genl_info_net(info),
2139                                                            info->attrs);
2140                 if (IS_ERR(wpan_dev)) {
2141                         if (rtnl)
2142                                 rtnl_unlock();
2143                         return PTR_ERR(wpan_dev);
2144                 }
2145 
2146                 dev = wpan_dev->netdev;
2147                 rdev = wpan_phy_to_rdev(wpan_dev->wpan_phy);
2148 
2149                 if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV) {
2150                         if (!dev) {
2151                                 if (rtnl)
2152                                         rtnl_unlock();
2153                                 return -EINVAL;
2154                         }
2155 
2156                         info->user_ptr[1] = dev;
2157                 } else {
2158                         info->user_ptr[1] = wpan_dev;
2159                 }
2160 
2161                 if (dev) {
2162                         if (ops->internal_flags & NL802154_FLAG_CHECK_NETDEV_UP &&
2163                             !netif_running(dev)) {
2164                                 if (rtnl)
2165                                         rtnl_unlock();
2166                                 return -ENETDOWN;
2167                         }
2168 
2169                         dev_hold(dev);
2170                 }
2171 
2172                 info->user_ptr[0] = rdev;
2173         }
2174 
2175         return 0;
2176 }
2177 
2178 static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
2179                                struct genl_info *info)
2180 {
2181         if (info->user_ptr[1]) {
2182                 if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
2183                         struct wpan_dev *wpan_dev = info->user_ptr[1];
2184 
2185                         if (wpan_dev->netdev)
2186                                 dev_put(wpan_dev->netdev);
2187                 } else {
2188                         dev_put(info->user_ptr[1]);
2189                 }
2190         }
2191 
2192         if (ops->internal_flags & NL802154_FLAG_NEED_RTNL)
2193                 rtnl_unlock();
2194 }
2195 
2196 static const struct genl_ops nl802154_ops[] = {
2197         {
2198                 .cmd = NL802154_CMD_GET_WPAN_PHY,
2199                 .doit = nl802154_get_wpan_phy,
2200                 .dumpit = nl802154_dump_wpan_phy,
2201                 .done = nl802154_dump_wpan_phy_done,
2202                 .policy = nl802154_policy,
2203                 /* can be retrieved by unprivileged users */
2204                 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
2205                                   NL802154_FLAG_NEED_RTNL,
2206         },
2207         {
2208                 .cmd = NL802154_CMD_GET_INTERFACE,
2209                 .doit = nl802154_get_interface,
2210                 .dumpit = nl802154_dump_interface,
2211                 .policy = nl802154_policy,
2212                 /* can be retrieved by unprivileged users */
2213                 .internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
2214                                   NL802154_FLAG_NEED_RTNL,
2215         },
2216         {
2217                 .cmd = NL802154_CMD_NEW_INTERFACE,
2218                 .doit = nl802154_new_interface,
2219                 .policy = nl802154_policy,
2220                 .flags = GENL_ADMIN_PERM,
2221                 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
2222                                   NL802154_FLAG_NEED_RTNL,
2223         },
2224         {
2225                 .cmd = NL802154_CMD_DEL_INTERFACE,
2226                 .doit = nl802154_del_interface,
2227                 .policy = nl802154_policy,
2228                 .flags = GENL_ADMIN_PERM,
2229                 .internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
2230                                   NL802154_FLAG_NEED_RTNL,
2231         },
2232         {
2233                 .cmd = NL802154_CMD_SET_CHANNEL,
2234                 .doit = nl802154_set_channel,
2235                 .policy = nl802154_policy,
2236                 .flags = GENL_ADMIN_PERM,
2237                 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
2238                                   NL802154_FLAG_NEED_RTNL,
2239         },
2240         {
2241                 .cmd = NL802154_CMD_SET_CCA_MODE,
2242                 .doit = nl802154_set_cca_mode,
2243                 .policy = nl802154_policy,
2244                 .flags = GENL_ADMIN_PERM,
2245                 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
2246                                   NL802154_FLAG_NEED_RTNL,
2247         },
2248         {
2249                 .cmd = NL802154_CMD_SET_CCA_ED_LEVEL,
2250                 .doit = nl802154_set_cca_ed_level,
2251                 .policy = nl802154_policy,
2252                 .flags = GENL_ADMIN_PERM,
2253                 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
2254                                   NL802154_FLAG_NEED_RTNL,
2255         },
2256         {
2257                 .cmd = NL802154_CMD_SET_TX_POWER,
2258                 .doit = nl802154_set_tx_power,
2259                 .policy = nl802154_policy,
2260                 .flags = GENL_ADMIN_PERM,
2261                 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
2262                                   NL802154_FLAG_NEED_RTNL,
2263         },
2264         {
2265                 .cmd = NL802154_CMD_SET_PAN_ID,
2266                 .doit = nl802154_set_pan_id,
2267                 .policy = nl802154_policy,
2268                 .flags = GENL_ADMIN_PERM,
2269                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
2270                                   NL802154_FLAG_NEED_RTNL,
2271         },
2272         {
2273                 .cmd = NL802154_CMD_SET_SHORT_ADDR,
2274                 .doit = nl802154_set_short_addr,
2275                 .policy = nl802154_policy,
2276                 .flags = GENL_ADMIN_PERM,
2277                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
2278                                   NL802154_FLAG_NEED_RTNL,
2279         },
2280         {
2281                 .cmd = NL802154_CMD_SET_BACKOFF_EXPONENT,
2282                 .doit = nl802154_set_backoff_exponent,
2283                 .policy = nl802154_policy,
2284                 .flags = GENL_ADMIN_PERM,
2285                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
2286                                   NL802154_FLAG_NEED_RTNL,
2287         },
2288         {
2289                 .cmd = NL802154_CMD_SET_MAX_CSMA_BACKOFFS,
2290                 .doit = nl802154_set_max_csma_backoffs,
2291                 .policy = nl802154_policy,
2292                 .flags = GENL_ADMIN_PERM,
2293                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
2294                                   NL802154_FLAG_NEED_RTNL,
2295         },
2296         {
2297                 .cmd = NL802154_CMD_SET_MAX_FRAME_RETRIES,
2298                 .doit = nl802154_set_max_frame_retries,
2299                 .policy = nl802154_policy,
2300                 .flags = GENL_ADMIN_PERM,
2301                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
2302                                   NL802154_FLAG_NEED_RTNL,
2303         },
2304         {
2305                 .cmd = NL802154_CMD_SET_LBT_MODE,
2306                 .doit = nl802154_set_lbt_mode,
2307                 .policy = nl802154_policy,
2308                 .flags = GENL_ADMIN_PERM,
2309                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
2310                                   NL802154_FLAG_NEED_RTNL,
2311         },
2312         {
2313                 .cmd = NL802154_CMD_SET_ACKREQ_DEFAULT,
2314                 .doit = nl802154_set_ackreq_default,
2315                 .policy = nl802154_policy,
2316                 .flags = GENL_ADMIN_PERM,
2317                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
2318                                   NL802154_FLAG_NEED_RTNL,
2319         },
2320 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
2321         {
2322                 .cmd = NL802154_CMD_SET_SEC_PARAMS,
2323                 .doit = nl802154_set_llsec_params,
2324                 .policy = nl802154_policy,
2325                 .flags = GENL_ADMIN_PERM,
2326                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
2327                                   NL802154_FLAG_NEED_RTNL,
2328         },
2329         {
2330                 .cmd = NL802154_CMD_GET_SEC_KEY,
2331                 /* TODO .doit by matching key id? */
2332                 .dumpit = nl802154_dump_llsec_key,
2333                 .policy = nl802154_policy,
2334                 .flags = GENL_ADMIN_PERM,
2335                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
2336                                   NL802154_FLAG_NEED_RTNL,
2337         },
2338         {
2339                 .cmd = NL802154_CMD_NEW_SEC_KEY,
2340                 .doit = nl802154_add_llsec_key,
2341                 .policy = nl802154_policy,
2342                 .flags = GENL_ADMIN_PERM,
2343                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
2344                                   NL802154_FLAG_NEED_RTNL,
2345         },
2346         {
2347                 .cmd = NL802154_CMD_DEL_SEC_KEY,
2348                 .doit = nl802154_del_llsec_key,
2349                 .policy = nl802154_policy,
2350                 .flags = GENL_ADMIN_PERM,
2351                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
2352                                   NL802154_FLAG_NEED_RTNL,
2353         },
2354         /* TODO unique identifier must short+pan OR extended_addr */
2355         {
2356                 .cmd = NL802154_CMD_GET_SEC_DEV,
2357                 /* TODO .doit by matching extended_addr? */
2358                 .dumpit = nl802154_dump_llsec_dev,
2359                 .policy = nl802154_policy,
2360                 .flags = GENL_ADMIN_PERM,
2361                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
2362                                   NL802154_FLAG_NEED_RTNL,
2363         },
2364         {
2365                 .cmd = NL802154_CMD_NEW_SEC_DEV,
2366                 .doit = nl802154_add_llsec_dev,
2367                 .policy = nl802154_policy,
2368                 .flags = GENL_ADMIN_PERM,
2369                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
2370                                   NL802154_FLAG_NEED_RTNL,
2371         },
2372         {
2373                 .cmd = NL802154_CMD_DEL_SEC_DEV,
2374                 .doit = nl802154_del_llsec_dev,
2375                 .policy = nl802154_policy,
2376                 .flags = GENL_ADMIN_PERM,
2377                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
2378                                   NL802154_FLAG_NEED_RTNL,
2379         },
2380         /* TODO remove complete devkey, put it as nested? */
2381         {
2382                 .cmd = NL802154_CMD_GET_SEC_DEVKEY,
2383                 /* TODO doit by matching ??? */
2384                 .dumpit = nl802154_dump_llsec_devkey,
2385                 .policy = nl802154_policy,
2386                 .flags = GENL_ADMIN_PERM,
2387                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
2388                                   NL802154_FLAG_NEED_RTNL,
2389         },
2390         {
2391                 .cmd = NL802154_CMD_NEW_SEC_DEVKEY,
2392                 .doit = nl802154_add_llsec_devkey,
2393                 .policy = nl802154_policy,
2394                 .flags = GENL_ADMIN_PERM,
2395                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
2396                                   NL802154_FLAG_NEED_RTNL,
2397         },
2398         {
2399                 .cmd = NL802154_CMD_DEL_SEC_DEVKEY,
2400                 .doit = nl802154_del_llsec_devkey,
2401                 .policy = nl802154_policy,
2402                 .flags = GENL_ADMIN_PERM,
2403                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
2404                                   NL802154_FLAG_NEED_RTNL,
2405         },
2406         {
2407                 .cmd = NL802154_CMD_GET_SEC_LEVEL,
2408                 /* TODO .doit by matching frame_type? */
2409                 .dumpit = nl802154_dump_llsec_seclevel,
2410                 .policy = nl802154_policy,
2411                 .flags = GENL_ADMIN_PERM,
2412                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
2413                                   NL802154_FLAG_NEED_RTNL,
2414         },
2415         {
2416                 .cmd = NL802154_CMD_NEW_SEC_LEVEL,
2417                 .doit = nl802154_add_llsec_seclevel,
2418                 .policy = nl802154_policy,
2419                 .flags = GENL_ADMIN_PERM,
2420                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
2421                                   NL802154_FLAG_NEED_RTNL,
2422         },
2423         {
2424                 .cmd = NL802154_CMD_DEL_SEC_LEVEL,
2425                 /* TODO match frame_type only? */
2426                 .doit = nl802154_del_llsec_seclevel,
2427                 .policy = nl802154_policy,
2428                 .flags = GENL_ADMIN_PERM,
2429                 .internal_flags = NL802154_FLAG_NEED_NETDEV |
2430                                   NL802154_FLAG_NEED_RTNL,
2431         },
2432 #endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
2433 };
2434 
2435 /* initialisation/exit functions */
2436 int nl802154_init(void)
2437 {
2438         return genl_register_family_with_ops_groups(&nl802154_fam, nl802154_ops,
2439                                                     nl802154_mcgrps);
2440 }
2441 
2442 void nl802154_exit(void)
2443 {
2444         genl_unregister_family(&nl802154_fam);
2445 }
2446 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp