a3281b8bfd5bf1fa24bd05a351b476031776797f
[cascardo/linux.git] / net / ieee802154 / nl-mac.c
1 /*
2  * Netlink inteface for IEEE 802.15.4 stack
3  *
4  * Copyright 2007, 2008 Siemens AG
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Written by:
20  * Sergey Lapin <slapin@ossfans.org>
21  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
22  * Maxim Osipov <maxim.osipov@siemens.com>
23  */
24
25 #include <linux/gfp.h>
26 #include <linux/kernel.h>
27 #include <linux/if_arp.h>
28 #include <linux/netdevice.h>
29 #include <net/netlink.h>
30 #include <net/genetlink.h>
31 #include <net/sock.h>
32 #include <linux/nl802154.h>
33 #include <linux/export.h>
34 #include <net/af_ieee802154.h>
35 #include <net/nl802154.h>
36 #include <net/ieee802154.h>
37 #include <net/ieee802154_netdev.h>
38 #include <net/wpan-phy.h>
39
40 #include "ieee802154.h"
41
42 static int nla_put_hwaddr(struct sk_buff *msg, int type, __le64 hwaddr)
43 {
44         return nla_put_u64(msg, type, swab64((__force u64)hwaddr));
45 }
46
47 static __le64 nla_get_hwaddr(const struct nlattr *nla)
48 {
49         return ieee802154_devaddr_from_raw(nla_data(nla));
50 }
51
52 static int nla_put_shortaddr(struct sk_buff *msg, int type, __le16 addr)
53 {
54         return nla_put_u16(msg, type, le16_to_cpu(addr));
55 }
56
57 static __le16 nla_get_shortaddr(const struct nlattr *nla)
58 {
59         return cpu_to_le16(nla_get_u16(nla));
60 }
61
62 int ieee802154_nl_assoc_indic(struct net_device *dev,
63                 struct ieee802154_addr *addr, u8 cap)
64 {
65         struct sk_buff *msg;
66
67         pr_debug("%s\n", __func__);
68
69         if (addr->mode != IEEE802154_ADDR_LONG) {
70                 pr_err("%s: received non-long source address!\n", __func__);
71                 return -EINVAL;
72         }
73
74         msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC);
75         if (!msg)
76                 return -ENOBUFS;
77
78         if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
79             nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
80             nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
81                     dev->dev_addr) ||
82             nla_put_hwaddr(msg, IEEE802154_ATTR_SRC_HW_ADDR,
83                            addr->extended_addr) ||
84             nla_put_u8(msg, IEEE802154_ATTR_CAPABILITY, cap))
85                 goto nla_put_failure;
86
87         return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
88
89 nla_put_failure:
90         nlmsg_free(msg);
91         return -ENOBUFS;
92 }
93 EXPORT_SYMBOL(ieee802154_nl_assoc_indic);
94
95 int ieee802154_nl_assoc_confirm(struct net_device *dev, __le16 short_addr,
96                 u8 status)
97 {
98         struct sk_buff *msg;
99
100         pr_debug("%s\n", __func__);
101
102         msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF);
103         if (!msg)
104                 return -ENOBUFS;
105
106         if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
107             nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
108             nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
109                     dev->dev_addr) ||
110             nla_put_shortaddr(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) ||
111             nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
112                 goto nla_put_failure;
113         return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
114
115 nla_put_failure:
116         nlmsg_free(msg);
117         return -ENOBUFS;
118 }
119 EXPORT_SYMBOL(ieee802154_nl_assoc_confirm);
120
121 int ieee802154_nl_disassoc_indic(struct net_device *dev,
122                 struct ieee802154_addr *addr, u8 reason)
123 {
124         struct sk_buff *msg;
125
126         pr_debug("%s\n", __func__);
127
128         msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC);
129         if (!msg)
130                 return -ENOBUFS;
131
132         if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
133             nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
134             nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
135                     dev->dev_addr))
136                 goto nla_put_failure;
137         if (addr->mode == IEEE802154_ADDR_LONG) {
138                 if (nla_put_hwaddr(msg, IEEE802154_ATTR_SRC_HW_ADDR,
139                                    addr->extended_addr))
140                         goto nla_put_failure;
141         } else {
142                 if (nla_put_shortaddr(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
143                                       addr->short_addr))
144                         goto nla_put_failure;
145         }
146         if (nla_put_u8(msg, IEEE802154_ATTR_REASON, reason))
147                 goto nla_put_failure;
148         return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
149
150 nla_put_failure:
151         nlmsg_free(msg);
152         return -ENOBUFS;
153 }
154 EXPORT_SYMBOL(ieee802154_nl_disassoc_indic);
155
156 int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status)
157 {
158         struct sk_buff *msg;
159
160         pr_debug("%s\n", __func__);
161
162         msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF);
163         if (!msg)
164                 return -ENOBUFS;
165
166         if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
167             nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
168             nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
169                     dev->dev_addr) ||
170             nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
171                 goto nla_put_failure;
172         return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
173
174 nla_put_failure:
175         nlmsg_free(msg);
176         return -ENOBUFS;
177 }
178 EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm);
179
180 int ieee802154_nl_beacon_indic(struct net_device *dev, __le16 panid,
181                                __le16 coord_addr)
182 {
183         struct sk_buff *msg;
184
185         pr_debug("%s\n", __func__);
186
187         msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC);
188         if (!msg)
189                 return -ENOBUFS;
190
191         if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
192             nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
193             nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
194                     dev->dev_addr) ||
195             nla_put_shortaddr(msg, IEEE802154_ATTR_COORD_SHORT_ADDR,
196                               coord_addr) ||
197             nla_put_shortaddr(msg, IEEE802154_ATTR_COORD_PAN_ID, panid))
198                 goto nla_put_failure;
199         return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
200
201 nla_put_failure:
202         nlmsg_free(msg);
203         return -ENOBUFS;
204 }
205 EXPORT_SYMBOL(ieee802154_nl_beacon_indic);
206
207 int ieee802154_nl_scan_confirm(struct net_device *dev,
208                 u8 status, u8 scan_type, u32 unscanned, u8 page,
209                 u8 *edl/* , struct list_head *pan_desc_list */)
210 {
211         struct sk_buff *msg;
212
213         pr_debug("%s\n", __func__);
214
215         msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF);
216         if (!msg)
217                 return -ENOBUFS;
218
219         if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
220             nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
221             nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
222                     dev->dev_addr) ||
223             nla_put_u8(msg, IEEE802154_ATTR_STATUS, status) ||
224             nla_put_u8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type) ||
225             nla_put_u32(msg, IEEE802154_ATTR_CHANNELS, unscanned) ||
226             nla_put_u8(msg, IEEE802154_ATTR_PAGE, page) ||
227             (edl &&
228              nla_put(msg, IEEE802154_ATTR_ED_LIST, 27, edl)))
229                 goto nla_put_failure;
230         return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
231
232 nla_put_failure:
233         nlmsg_free(msg);
234         return -ENOBUFS;
235 }
236 EXPORT_SYMBOL(ieee802154_nl_scan_confirm);
237
238 int ieee802154_nl_start_confirm(struct net_device *dev, u8 status)
239 {
240         struct sk_buff *msg;
241
242         pr_debug("%s\n", __func__);
243
244         msg = ieee802154_nl_create(0, IEEE802154_START_CONF);
245         if (!msg)
246                 return -ENOBUFS;
247
248         if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
249             nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
250             nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
251                     dev->dev_addr) ||
252             nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
253                 goto nla_put_failure;
254         return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
255
256 nla_put_failure:
257         nlmsg_free(msg);
258         return -ENOBUFS;
259 }
260 EXPORT_SYMBOL(ieee802154_nl_start_confirm);
261
262 static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid,
263         u32 seq, int flags, struct net_device *dev)
264 {
265         void *hdr;
266         struct wpan_phy *phy;
267         struct ieee802154_mlme_ops *ops;
268         __le16 short_addr, pan_id;
269
270         pr_debug("%s\n", __func__);
271
272         hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags,
273                 IEEE802154_LIST_IFACE);
274         if (!hdr)
275                 goto out;
276
277         ops = ieee802154_mlme_ops(dev);
278         phy = ops->get_phy(dev);
279         BUG_ON(!phy);
280
281         short_addr = ops->get_short_addr(dev);
282         pan_id = ops->get_pan_id(dev);
283
284         if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
285             nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
286             nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
287             nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
288                     dev->dev_addr) ||
289             nla_put_shortaddr(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) ||
290             nla_put_shortaddr(msg, IEEE802154_ATTR_PAN_ID, pan_id))
291                 goto nla_put_failure;
292
293         if (ops->get_mac_params) {
294                 struct ieee802154_mac_params params;
295
296                 ops->get_mac_params(dev, &params);
297
298                 if (nla_put_s8(msg, IEEE802154_ATTR_TXPOWER,
299                                params.transmit_power) ||
300                     nla_put_u8(msg, IEEE802154_ATTR_LBT_ENABLED, params.lbt) ||
301                     nla_put_u8(msg, IEEE802154_ATTR_CCA_MODE,
302                                params.cca_mode) ||
303                     nla_put_s32(msg, IEEE802154_ATTR_CCA_ED_LEVEL,
304                                 params.cca_ed_level) ||
305                     nla_put_u8(msg, IEEE802154_ATTR_CSMA_RETRIES,
306                                params.csma_retries) ||
307                     nla_put_u8(msg, IEEE802154_ATTR_CSMA_MIN_BE,
308                                params.min_be) ||
309                     nla_put_u8(msg, IEEE802154_ATTR_CSMA_MAX_BE,
310                                params.max_be) ||
311                     nla_put_s8(msg, IEEE802154_ATTR_FRAME_RETRIES,
312                                params.frame_retries))
313                         goto nla_put_failure;
314         }
315
316         wpan_phy_put(phy);
317         return genlmsg_end(msg, hdr);
318
319 nla_put_failure:
320         wpan_phy_put(phy);
321         genlmsg_cancel(msg, hdr);
322 out:
323         return -EMSGSIZE;
324 }
325
326 /* Requests from userspace */
327 static struct net_device *ieee802154_nl_get_dev(struct genl_info *info)
328 {
329         struct net_device *dev;
330
331         if (info->attrs[IEEE802154_ATTR_DEV_NAME]) {
332                 char name[IFNAMSIZ + 1];
333                 nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME],
334                                 sizeof(name));
335                 dev = dev_get_by_name(&init_net, name);
336         } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX])
337                 dev = dev_get_by_index(&init_net,
338                         nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX]));
339         else
340                 return NULL;
341
342         if (!dev)
343                 return NULL;
344
345         if (dev->type != ARPHRD_IEEE802154) {
346                 dev_put(dev);
347                 return NULL;
348         }
349
350         return dev;
351 }
352
353 int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info)
354 {
355         struct net_device *dev;
356         struct ieee802154_addr addr;
357         u8 page;
358         int ret = -EOPNOTSUPP;
359
360         if (!info->attrs[IEEE802154_ATTR_CHANNEL] ||
361             !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
362             (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] &&
363                 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) ||
364             !info->attrs[IEEE802154_ATTR_CAPABILITY])
365                 return -EINVAL;
366
367         dev = ieee802154_nl_get_dev(info);
368         if (!dev)
369                 return -ENODEV;
370         if (!ieee802154_mlme_ops(dev)->assoc_req)
371                 goto out;
372
373         if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) {
374                 addr.mode = IEEE802154_ADDR_LONG;
375                 addr.extended_addr = nla_get_hwaddr(
376                                 info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]);
377         } else {
378                 addr.mode = IEEE802154_ADDR_SHORT;
379                 addr.short_addr = nla_get_shortaddr(
380                                 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
381         }
382         addr.pan_id = nla_get_shortaddr(
383                         info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
384
385         if (info->attrs[IEEE802154_ATTR_PAGE])
386                 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
387         else
388                 page = 0;
389
390         ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr,
391                         nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]),
392                         page,
393                         nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY]));
394
395 out:
396         dev_put(dev);
397         return ret;
398 }
399
400 int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info)
401 {
402         struct net_device *dev;
403         struct ieee802154_addr addr;
404         int ret = -EOPNOTSUPP;
405
406         if (!info->attrs[IEEE802154_ATTR_STATUS] ||
407             !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] ||
408             !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR])
409                 return -EINVAL;
410
411         dev = ieee802154_nl_get_dev(info);
412         if (!dev)
413                 return -ENODEV;
414         if (!ieee802154_mlme_ops(dev)->assoc_resp)
415                 goto out;
416
417         addr.mode = IEEE802154_ADDR_LONG;
418         addr.extended_addr = nla_get_hwaddr(
419                         info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]);
420         addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
421
422         ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr,
423                 nla_get_shortaddr(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
424                 nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS]));
425
426 out:
427         dev_put(dev);
428         return ret;
429 }
430
431 int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info)
432 {
433         struct net_device *dev;
434         struct ieee802154_addr addr;
435         int ret = -EOPNOTSUPP;
436
437         if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] &&
438                 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) ||
439             !info->attrs[IEEE802154_ATTR_REASON])
440                 return -EINVAL;
441
442         dev = ieee802154_nl_get_dev(info);
443         if (!dev)
444                 return -ENODEV;
445         if (!ieee802154_mlme_ops(dev)->disassoc_req)
446                 goto out;
447
448         if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) {
449                 addr.mode = IEEE802154_ADDR_LONG;
450                 addr.extended_addr = nla_get_hwaddr(
451                                 info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]);
452         } else {
453                 addr.mode = IEEE802154_ADDR_SHORT;
454                 addr.short_addr = nla_get_shortaddr(
455                                 info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]);
456         }
457         addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
458
459         ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr,
460                         nla_get_u8(info->attrs[IEEE802154_ATTR_REASON]));
461
462 out:
463         dev_put(dev);
464         return ret;
465 }
466
467 /*
468  * PANid, channel, beacon_order = 15, superframe_order = 15,
469  * PAN_coordinator, battery_life_extension = 0,
470  * coord_realignment = 0, security_enable = 0
471 */
472 int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
473 {
474         struct net_device *dev;
475         struct ieee802154_addr addr;
476
477         u8 channel, bcn_ord, sf_ord;
478         u8 page;
479         int pan_coord, blx, coord_realign;
480         int ret = -EOPNOTSUPP;
481
482         if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
483             !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] ||
484             !info->attrs[IEEE802154_ATTR_CHANNEL] ||
485             !info->attrs[IEEE802154_ATTR_BCN_ORD] ||
486             !info->attrs[IEEE802154_ATTR_SF_ORD] ||
487             !info->attrs[IEEE802154_ATTR_PAN_COORD] ||
488             !info->attrs[IEEE802154_ATTR_BAT_EXT] ||
489             !info->attrs[IEEE802154_ATTR_COORD_REALIGN]
490          )
491                 return -EINVAL;
492
493         dev = ieee802154_nl_get_dev(info);
494         if (!dev)
495                 return -ENODEV;
496         if (!ieee802154_mlme_ops(dev)->start_req)
497                 goto out;
498
499         addr.mode = IEEE802154_ADDR_SHORT;
500         addr.short_addr = nla_get_shortaddr(
501                         info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
502         addr.pan_id = nla_get_shortaddr(
503                         info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
504
505         channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]);
506         bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]);
507         sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]);
508         pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]);
509         blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]);
510         coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]);
511
512         if (info->attrs[IEEE802154_ATTR_PAGE])
513                 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
514         else
515                 page = 0;
516
517
518         if (addr.short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST)) {
519                 ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS);
520                 dev_put(dev);
521                 return -EINVAL;
522         }
523
524         ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page,
525                 bcn_ord, sf_ord, pan_coord, blx, coord_realign);
526
527 out:
528         dev_put(dev);
529         return ret;
530 }
531
532 int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
533 {
534         struct net_device *dev;
535         int ret = -EOPNOTSUPP;
536         u8 type;
537         u32 channels;
538         u8 duration;
539         u8 page;
540
541         if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] ||
542             !info->attrs[IEEE802154_ATTR_CHANNELS] ||
543             !info->attrs[IEEE802154_ATTR_DURATION])
544                 return -EINVAL;
545
546         dev = ieee802154_nl_get_dev(info);
547         if (!dev)
548                 return -ENODEV;
549         if (!ieee802154_mlme_ops(dev)->scan_req)
550                 goto out;
551
552         type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]);
553         channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]);
554         duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]);
555
556         if (info->attrs[IEEE802154_ATTR_PAGE])
557                 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
558         else
559                 page = 0;
560
561
562         ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page,
563                         duration);
564
565 out:
566         dev_put(dev);
567         return ret;
568 }
569
570 int ieee802154_list_iface(struct sk_buff *skb, struct genl_info *info)
571 {
572         /* Request for interface name, index, type, IEEE address,
573            PAN Id, short address */
574         struct sk_buff *msg;
575         struct net_device *dev = NULL;
576         int rc = -ENOBUFS;
577
578         pr_debug("%s\n", __func__);
579
580         dev = ieee802154_nl_get_dev(info);
581         if (!dev)
582                 return -ENODEV;
583
584         msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
585         if (!msg)
586                 goto out_dev;
587
588         rc = ieee802154_nl_fill_iface(msg, info->snd_portid, info->snd_seq,
589                         0, dev);
590         if (rc < 0)
591                 goto out_free;
592
593         dev_put(dev);
594
595         return genlmsg_reply(msg, info);
596 out_free:
597         nlmsg_free(msg);
598 out_dev:
599         dev_put(dev);
600         return rc;
601
602 }
603
604 int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb)
605 {
606         struct net *net = sock_net(skb->sk);
607         struct net_device *dev;
608         int idx;
609         int s_idx = cb->args[0];
610
611         pr_debug("%s\n", __func__);
612
613         idx = 0;
614         for_each_netdev(net, dev) {
615                 if (idx < s_idx || (dev->type != ARPHRD_IEEE802154))
616                         goto cont;
617
618                 if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).portid,
619                         cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0)
620                         break;
621 cont:
622                 idx++;
623         }
624         cb->args[0] = idx;
625
626         return skb->len;
627 }
628
629 int ieee802154_set_macparams(struct sk_buff *skb, struct genl_info *info)
630 {
631         struct net_device *dev = NULL;
632         struct ieee802154_mlme_ops *ops;
633         struct ieee802154_mac_params params;
634         struct wpan_phy *phy;
635         int rc = -EINVAL;
636
637         pr_debug("%s\n", __func__);
638
639         dev = ieee802154_nl_get_dev(info);
640         if (!dev)
641                 return -ENODEV;
642
643         ops = ieee802154_mlme_ops(dev);
644
645         if (!ops->get_mac_params || !ops->set_mac_params) {
646                 rc = -EOPNOTSUPP;
647                 goto out;
648         }
649
650         if (netif_running(dev)) {
651                 rc = -EBUSY;
652                 goto out;
653         }
654
655         if (!info->attrs[IEEE802154_ATTR_LBT_ENABLED] &&
656             !info->attrs[IEEE802154_ATTR_CCA_MODE] &&
657             !info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL] &&
658             !info->attrs[IEEE802154_ATTR_CSMA_RETRIES] &&
659             !info->attrs[IEEE802154_ATTR_CSMA_MIN_BE] &&
660             !info->attrs[IEEE802154_ATTR_CSMA_MAX_BE] &&
661             !info->attrs[IEEE802154_ATTR_FRAME_RETRIES])
662                 goto out;
663
664         phy = ops->get_phy(dev);
665
666         if ((!phy->set_lbt && info->attrs[IEEE802154_ATTR_LBT_ENABLED]) ||
667             (!phy->set_cca_mode && info->attrs[IEEE802154_ATTR_CCA_MODE]) ||
668             (!phy->set_cca_ed_level &&
669              info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]) ||
670             (!phy->set_csma_params &&
671              (info->attrs[IEEE802154_ATTR_CSMA_RETRIES] ||
672               info->attrs[IEEE802154_ATTR_CSMA_MIN_BE] ||
673               info->attrs[IEEE802154_ATTR_CSMA_MAX_BE])) ||
674             (!phy->set_frame_retries &&
675              info->attrs[IEEE802154_ATTR_FRAME_RETRIES])) {
676                 rc = -EOPNOTSUPP;
677                 goto out_phy;
678         }
679
680         ops->get_mac_params(dev, &params);
681
682         if (info->attrs[IEEE802154_ATTR_TXPOWER])
683                 params.transmit_power = nla_get_s8(info->attrs[IEEE802154_ATTR_TXPOWER]);
684
685         if (info->attrs[IEEE802154_ATTR_LBT_ENABLED])
686                 params.lbt = nla_get_u8(info->attrs[IEEE802154_ATTR_LBT_ENABLED]);
687
688         if (info->attrs[IEEE802154_ATTR_CCA_MODE])
689                 params.cca_mode = nla_get_u8(info->attrs[IEEE802154_ATTR_CCA_MODE]);
690
691         if (info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL])
692                 params.cca_ed_level = nla_get_s32(info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]);
693
694         if (info->attrs[IEEE802154_ATTR_CSMA_RETRIES])
695                 params.csma_retries = nla_get_u8(info->attrs[IEEE802154_ATTR_CSMA_RETRIES]);
696
697         if (info->attrs[IEEE802154_ATTR_CSMA_MIN_BE])
698                 params.min_be = nla_get_u8(info->attrs[IEEE802154_ATTR_CSMA_MIN_BE]);
699
700         if (info->attrs[IEEE802154_ATTR_CSMA_MAX_BE])
701                 params.max_be = nla_get_u8(info->attrs[IEEE802154_ATTR_CSMA_MAX_BE]);
702
703         if (info->attrs[IEEE802154_ATTR_FRAME_RETRIES])
704                 params.frame_retries = nla_get_s8(info->attrs[IEEE802154_ATTR_FRAME_RETRIES]);
705
706         rc = ops->set_mac_params(dev, &params);
707
708         wpan_phy_put(phy);
709         dev_put(dev);
710         return rc;
711
712 out_phy:
713         wpan_phy_put(phy);
714 out:
715         dev_put(dev);
716         return rc;
717 }
718
719
720
721 static int
722 ieee802154_llsec_parse_key_id(struct genl_info *info,
723                               struct ieee802154_llsec_key_id *desc)
724 {
725         memset(desc, 0, sizeof(*desc));
726
727         if (!info->attrs[IEEE802154_ATTR_LLSEC_KEY_MODE])
728                 return -EINVAL;
729
730         desc->mode = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_KEY_MODE]);
731
732         if (desc->mode == IEEE802154_SCF_KEY_IMPLICIT) {
733                 if (!info->attrs[IEEE802154_ATTR_PAN_ID] &&
734                     !(info->attrs[IEEE802154_ATTR_SHORT_ADDR] ||
735                       info->attrs[IEEE802154_ATTR_HW_ADDR]))
736                         return -EINVAL;
737
738                 desc->device_addr.pan_id = nla_get_shortaddr(info->attrs[IEEE802154_ATTR_PAN_ID]);
739
740                 if (info->attrs[IEEE802154_ATTR_SHORT_ADDR]) {
741                         desc->device_addr.mode = IEEE802154_ADDR_SHORT;
742                         desc->device_addr.short_addr = nla_get_shortaddr(info->attrs[IEEE802154_ATTR_SHORT_ADDR]);
743                 } else {
744                         desc->device_addr.mode = IEEE802154_ADDR_LONG;
745                         desc->device_addr.extended_addr = nla_get_hwaddr(info->attrs[IEEE802154_ATTR_HW_ADDR]);
746                 }
747         }
748
749         if (desc->mode != IEEE802154_SCF_KEY_IMPLICIT &&
750             !info->attrs[IEEE802154_ATTR_LLSEC_KEY_ID])
751                 return -EINVAL;
752
753         if (desc->mode == IEEE802154_SCF_KEY_SHORT_INDEX &&
754             !info->attrs[IEEE802154_ATTR_LLSEC_KEY_SOURCE_SHORT])
755                 return -EINVAL;
756
757         if (desc->mode == IEEE802154_SCF_KEY_HW_INDEX &&
758             !info->attrs[IEEE802154_ATTR_LLSEC_KEY_SOURCE_EXTENDED])
759                 return -EINVAL;
760
761         if (desc->mode != IEEE802154_SCF_KEY_IMPLICIT)
762                 desc->id = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_KEY_ID]);
763
764         switch (desc->mode) {
765         case IEEE802154_SCF_KEY_SHORT_INDEX:
766         {
767                 u32 source = nla_get_u32(info->attrs[IEEE802154_ATTR_LLSEC_KEY_SOURCE_SHORT]);
768                 desc->short_source = cpu_to_le32(source);
769                 break;
770         }
771         case IEEE802154_SCF_KEY_HW_INDEX:
772                 desc->extended_source = nla_get_hwaddr(info->attrs[IEEE802154_ATTR_LLSEC_KEY_SOURCE_EXTENDED]);
773                 break;
774         }
775
776         return 0;
777 }
778
779 static int
780 ieee802154_llsec_fill_key_id(struct sk_buff *msg,
781                              const struct ieee802154_llsec_key_id *desc)
782 {
783         if (nla_put_u8(msg, IEEE802154_ATTR_LLSEC_KEY_MODE, desc->mode))
784                 return -EMSGSIZE;
785
786         if (desc->mode == IEEE802154_SCF_KEY_IMPLICIT) {
787                 if (nla_put_shortaddr(msg, IEEE802154_ATTR_PAN_ID,
788                                       desc->device_addr.pan_id))
789                         return -EMSGSIZE;
790
791                 if (desc->device_addr.mode == IEEE802154_ADDR_SHORT &&
792                     nla_put_shortaddr(msg, IEEE802154_ATTR_SHORT_ADDR,
793                                       desc->device_addr.short_addr))
794                         return -EMSGSIZE;
795
796                 if (desc->device_addr.mode == IEEE802154_ADDR_LONG &&
797                     nla_put_hwaddr(msg, IEEE802154_ATTR_HW_ADDR,
798                                    desc->device_addr.extended_addr))
799                         return -EMSGSIZE;
800         }
801
802         if (desc->mode != IEEE802154_SCF_KEY_IMPLICIT &&
803             nla_put_u8(msg, IEEE802154_ATTR_LLSEC_KEY_ID, desc->id))
804                 return -EMSGSIZE;
805
806         if (desc->mode == IEEE802154_SCF_KEY_SHORT_INDEX &&
807             nla_put_u32(msg, IEEE802154_ATTR_LLSEC_KEY_SOURCE_SHORT,
808                         le32_to_cpu(desc->short_source)))
809                 return -EMSGSIZE;
810
811         if (desc->mode == IEEE802154_SCF_KEY_HW_INDEX &&
812             nla_put_hwaddr(msg, IEEE802154_ATTR_LLSEC_KEY_SOURCE_EXTENDED,
813                            desc->extended_source))
814                 return -EMSGSIZE;
815
816         return 0;
817 }
818
819 int ieee802154_llsec_getparams(struct sk_buff *skb, struct genl_info *info)
820 {
821         struct sk_buff *msg;
822         struct net_device *dev = NULL;
823         int rc = -ENOBUFS;
824         struct ieee802154_mlme_ops *ops;
825         void *hdr;
826         struct ieee802154_llsec_params params;
827
828         pr_debug("%s\n", __func__);
829
830         dev = ieee802154_nl_get_dev(info);
831         if (!dev)
832                 return -ENODEV;
833
834         ops = ieee802154_mlme_ops(dev);
835         if (!ops->llsec) {
836                 rc = -EOPNOTSUPP;
837                 goto out_dev;
838         }
839
840         msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
841         if (!msg)
842                 goto out_dev;
843
844         hdr = genlmsg_put(msg, 0, info->snd_seq, &nl802154_family, 0,
845                 IEEE802154_LLSEC_GETPARAMS);
846         if (!hdr)
847                 goto out_free;
848
849         rc = ops->llsec->get_params(dev, &params);
850         if (rc < 0)
851                 goto out_free;
852
853         if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
854             nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
855             nla_put_u8(msg, IEEE802154_ATTR_LLSEC_ENABLED, params.enabled) ||
856             nla_put_u8(msg, IEEE802154_ATTR_LLSEC_SECLEVEL, params.out_level) ||
857             nla_put_u32(msg, IEEE802154_ATTR_LLSEC_FRAME_COUNTER,
858                         be32_to_cpu(params.frame_counter)) ||
859             ieee802154_llsec_fill_key_id(msg, &params.out_key))
860                 goto out_free;
861
862         dev_put(dev);
863
864         return ieee802154_nl_reply(msg, info);
865 out_free:
866         nlmsg_free(msg);
867 out_dev:
868         dev_put(dev);
869         return rc;
870 }
871
872 int ieee802154_llsec_setparams(struct sk_buff *skb, struct genl_info *info)
873 {
874         struct net_device *dev = NULL;
875         int rc = -EINVAL;
876         struct ieee802154_mlme_ops *ops;
877         struct ieee802154_llsec_params params;
878         int changed = 0;
879
880         pr_debug("%s\n", __func__);
881
882         dev = ieee802154_nl_get_dev(info);
883         if (!dev)
884                 return -ENODEV;
885
886         if (!info->attrs[IEEE802154_ATTR_LLSEC_ENABLED] &&
887             !info->attrs[IEEE802154_ATTR_LLSEC_KEY_MODE] &&
888             !info->attrs[IEEE802154_ATTR_LLSEC_SECLEVEL])
889                 goto out;
890
891         ops = ieee802154_mlme_ops(dev);
892         if (!ops->llsec) {
893                 rc = -EOPNOTSUPP;
894                 goto out;
895         }
896
897         if (info->attrs[IEEE802154_ATTR_LLSEC_SECLEVEL] &&
898             nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_SECLEVEL]) > 7)
899                 goto out;
900
901         if (info->attrs[IEEE802154_ATTR_LLSEC_ENABLED]) {
902                 params.enabled = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_ENABLED]);
903                 changed |= IEEE802154_LLSEC_PARAM_ENABLED;
904         }
905
906         if (info->attrs[IEEE802154_ATTR_LLSEC_KEY_MODE]) {
907                 if (ieee802154_llsec_parse_key_id(info, &params.out_key))
908                         goto out;
909
910                 changed |= IEEE802154_LLSEC_PARAM_OUT_KEY;
911         }
912
913         if (info->attrs[IEEE802154_ATTR_LLSEC_SECLEVEL]) {
914                 params.out_level = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_SECLEVEL]);
915                 changed |= IEEE802154_LLSEC_PARAM_OUT_LEVEL;
916         }
917
918         if (info->attrs[IEEE802154_ATTR_LLSEC_FRAME_COUNTER]) {
919                 u32 fc = nla_get_u32(info->attrs[IEEE802154_ATTR_LLSEC_FRAME_COUNTER]);
920
921                 params.frame_counter = cpu_to_be32(fc);
922                 changed |= IEEE802154_LLSEC_PARAM_FRAME_COUNTER;
923         }
924
925         rc = ops->llsec->set_params(dev, &params, changed);
926
927         dev_put(dev);
928
929         return rc;
930 out:
931         dev_put(dev);
932         return rc;
933 }
934
935
936
937 struct llsec_dump_data {
938         struct sk_buff *skb;
939         int s_idx, s_idx2;
940         int portid;
941         int nlmsg_seq;
942         struct net_device *dev;
943         struct ieee802154_mlme_ops *ops;
944         struct ieee802154_llsec_table *table;
945 };
946
947 static int
948 ieee802154_llsec_dump_table(struct sk_buff *skb, struct netlink_callback *cb,
949                             int (*step)(struct llsec_dump_data*))
950 {
951         struct net *net = sock_net(skb->sk);
952         struct net_device *dev;
953         struct llsec_dump_data data;
954         int idx = 0;
955         int first_dev = cb->args[0];
956         int rc;
957
958         for_each_netdev(net, dev) {
959                 if (idx < first_dev || dev->type != ARPHRD_IEEE802154)
960                         goto skip;
961
962                 data.ops = ieee802154_mlme_ops(dev);
963                 if (!data.ops->llsec)
964                         goto skip;
965
966                 data.skb = skb;
967                 data.s_idx = cb->args[1];
968                 data.s_idx2 = cb->args[2];
969                 data.dev = dev;
970                 data.portid = NETLINK_CB(cb->skb).portid;
971                 data.nlmsg_seq = cb->nlh->nlmsg_seq;
972
973                 data.ops->llsec->lock_table(dev);
974                 data.ops->llsec->get_table(data.dev, &data.table);
975                 rc = step(&data);
976                 data.ops->llsec->unlock_table(dev);
977
978                 if (rc < 0)
979                         break;
980
981 skip:
982                 idx++;
983         }
984         cb->args[0] = idx;
985
986         return skb->len;
987 }
988
989 static int
990 ieee802154_nl_llsec_change(struct sk_buff *skb, struct genl_info *info,
991                            int (*fn)(struct net_device*, struct genl_info*))
992 {
993         struct net_device *dev = NULL;
994         int rc = -EINVAL;
995
996         dev = ieee802154_nl_get_dev(info);
997         if (!dev)
998                 return -ENODEV;
999
1000         if (!ieee802154_mlme_ops(dev)->llsec)
1001                 rc = -EOPNOTSUPP;
1002         else
1003                 rc = fn(dev, info);
1004
1005         dev_put(dev);
1006         return rc;
1007 }
1008
1009
1010
1011 static int
1012 ieee802154_llsec_parse_key(struct genl_info *info,
1013                            struct ieee802154_llsec_key *key)
1014 {
1015         u8 frames;
1016         u32 commands[256 / 32];
1017
1018         memset(key, 0, sizeof(*key));
1019
1020         if (!info->attrs[IEEE802154_ATTR_LLSEC_KEY_USAGE_FRAME_TYPES] ||
1021             !info->attrs[IEEE802154_ATTR_LLSEC_KEY_BYTES])
1022                 return -EINVAL;
1023
1024         frames = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_KEY_USAGE_FRAME_TYPES]);
1025         if ((frames & BIT(IEEE802154_FC_TYPE_MAC_CMD)) &&
1026             !info->attrs[IEEE802154_ATTR_LLSEC_KEY_USAGE_COMMANDS])
1027                 return -EINVAL;
1028
1029         if (info->attrs[IEEE802154_ATTR_LLSEC_KEY_USAGE_COMMANDS]) {
1030                 nla_memcpy(commands,
1031                            info->attrs[IEEE802154_ATTR_LLSEC_KEY_USAGE_COMMANDS],
1032                            256 / 8);
1033
1034                 if (commands[0] || commands[1] || commands[2] || commands[3] ||
1035                     commands[4] || commands[5] || commands[6] ||
1036                     commands[7] >= BIT(IEEE802154_CMD_GTS_REQ + 1))
1037                         return -EINVAL;
1038
1039                 key->cmd_frame_ids = commands[7];
1040         }
1041
1042         key->frame_types = frames;
1043
1044         nla_memcpy(key->key, info->attrs[IEEE802154_ATTR_LLSEC_KEY_BYTES],
1045                    IEEE802154_LLSEC_KEY_SIZE);
1046
1047         return 0;
1048 }
1049
1050 static int llsec_add_key(struct net_device *dev, struct genl_info *info)
1051 {
1052         struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
1053         struct ieee802154_llsec_key key;
1054         struct ieee802154_llsec_key_id id;
1055
1056         if (ieee802154_llsec_parse_key(info, &key) ||
1057             ieee802154_llsec_parse_key_id(info, &id))
1058                 return -EINVAL;
1059
1060         return ops->llsec->add_key(dev, &id, &key);
1061 }
1062
1063 int ieee802154_llsec_add_key(struct sk_buff *skb, struct genl_info *info)
1064 {
1065         if ((info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL)) !=
1066             (NLM_F_CREATE | NLM_F_EXCL))
1067                 return -EINVAL;
1068
1069         return ieee802154_nl_llsec_change(skb, info, llsec_add_key);
1070 }
1071
1072 static int llsec_remove_key(struct net_device *dev, struct genl_info *info)
1073 {
1074         struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
1075         struct ieee802154_llsec_key_id id;
1076
1077         if (ieee802154_llsec_parse_key_id(info, &id))
1078                 return -EINVAL;
1079
1080         return ops->llsec->del_key(dev, &id);
1081 }
1082
1083 int ieee802154_llsec_del_key(struct sk_buff *skb, struct genl_info *info)
1084 {
1085         return ieee802154_nl_llsec_change(skb, info, llsec_remove_key);
1086 }
1087
1088 static int
1089 ieee802154_nl_fill_key(struct sk_buff *msg, u32 portid, u32 seq,
1090                        const struct ieee802154_llsec_key_entry *key,
1091                        const struct net_device *dev)
1092 {
1093         void *hdr;
1094         u32 commands[256 / 32];
1095
1096         hdr = genlmsg_put(msg, 0, seq, &nl802154_family, NLM_F_MULTI,
1097                           IEEE802154_LLSEC_LIST_KEY);
1098         if (!hdr)
1099                 goto out;
1100
1101         if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
1102             nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
1103             ieee802154_llsec_fill_key_id(msg, &key->id) ||
1104             nla_put_u8(msg, IEEE802154_ATTR_LLSEC_KEY_USAGE_FRAME_TYPES,
1105                        key->key->frame_types))
1106                 goto nla_put_failure;
1107
1108         if (key->key->frame_types & BIT(IEEE802154_FC_TYPE_MAC_CMD)) {
1109                 memset(commands, 0, sizeof(commands));
1110                 commands[7] = key->key->cmd_frame_ids;
1111                 if (nla_put(msg, IEEE802154_ATTR_LLSEC_KEY_USAGE_COMMANDS,
1112                             sizeof(commands), commands))
1113                         goto nla_put_failure;
1114         }
1115
1116         if (nla_put(msg, IEEE802154_ATTR_LLSEC_KEY_BYTES,
1117                     IEEE802154_LLSEC_KEY_SIZE, key->key->key))
1118                 goto nla_put_failure;
1119
1120         genlmsg_end(msg, hdr);
1121         return 0;
1122
1123 nla_put_failure:
1124         genlmsg_cancel(msg, hdr);
1125 out:
1126         return -EMSGSIZE;
1127 }
1128
1129 static int llsec_iter_keys(struct llsec_dump_data *data)
1130 {
1131         struct ieee802154_llsec_key_entry *pos;
1132         int rc = 0, idx = 0;
1133
1134         list_for_each_entry(pos, &data->table->keys, list) {
1135                 if (idx++ < data->s_idx)
1136                         continue;
1137
1138                 if (ieee802154_nl_fill_key(data->skb, data->portid,
1139                                            data->nlmsg_seq, pos, data->dev)) {
1140                         rc = -EMSGSIZE;
1141                         break;
1142                 }
1143
1144                 data->s_idx++;
1145         }
1146
1147         return rc;
1148 }
1149
1150 int ieee802154_llsec_dump_keys(struct sk_buff *skb, struct netlink_callback *cb)
1151 {
1152         return ieee802154_llsec_dump_table(skb, cb, llsec_iter_keys);
1153 }
1154
1155
1156
1157 static int
1158 llsec_parse_dev(struct genl_info *info,
1159                 struct ieee802154_llsec_device *dev)
1160 {
1161         memset(dev, 0, sizeof(*dev));
1162
1163         if (!info->attrs[IEEE802154_ATTR_LLSEC_FRAME_COUNTER] ||
1164             !info->attrs[IEEE802154_ATTR_HW_ADDR] ||
1165             !info->attrs[IEEE802154_ATTR_LLSEC_DEV_OVERRIDE] ||
1166             !info->attrs[IEEE802154_ATTR_LLSEC_DEV_KEY_MODE] ||
1167             (!!info->attrs[IEEE802154_ATTR_PAN_ID] !=
1168              !!info->attrs[IEEE802154_ATTR_SHORT_ADDR]))
1169                 return -EINVAL;
1170
1171         if (info->attrs[IEEE802154_ATTR_PAN_ID]) {
1172                 dev->pan_id = nla_get_shortaddr(info->attrs[IEEE802154_ATTR_PAN_ID]);
1173                 dev->short_addr = nla_get_shortaddr(info->attrs[IEEE802154_ATTR_SHORT_ADDR]);
1174         } else {
1175                 dev->short_addr = cpu_to_le16(IEEE802154_ADDR_UNDEF);
1176         }
1177
1178         dev->hwaddr = nla_get_hwaddr(info->attrs[IEEE802154_ATTR_HW_ADDR]);
1179         dev->frame_counter = nla_get_u32(info->attrs[IEEE802154_ATTR_LLSEC_FRAME_COUNTER]);
1180         dev->seclevel_exempt = !!nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_DEV_OVERRIDE]);
1181         dev->key_mode = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_DEV_KEY_MODE]);
1182
1183         if (dev->key_mode >= __IEEE802154_LLSEC_DEVKEY_MAX)
1184                 return -EINVAL;
1185
1186         return 0;
1187 }
1188
1189 static int llsec_add_dev(struct net_device *dev, struct genl_info *info)
1190 {
1191         struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
1192         struct ieee802154_llsec_device desc;
1193
1194         if (llsec_parse_dev(info, &desc))
1195                 return -EINVAL;
1196
1197         return ops->llsec->add_dev(dev, &desc);
1198 }
1199
1200 int ieee802154_llsec_add_dev(struct sk_buff *skb, struct genl_info *info)
1201 {
1202         if ((info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL)) !=
1203             (NLM_F_CREATE | NLM_F_EXCL))
1204                 return -EINVAL;
1205
1206         return ieee802154_nl_llsec_change(skb, info, llsec_add_dev);
1207 }
1208
1209 static int llsec_del_dev(struct net_device *dev, struct genl_info *info)
1210 {
1211         struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
1212         __le64 devaddr;
1213
1214         if (!info->attrs[IEEE802154_ATTR_HW_ADDR])
1215                 return -EINVAL;
1216
1217         devaddr = nla_get_hwaddr(info->attrs[IEEE802154_ATTR_HW_ADDR]);
1218
1219         return ops->llsec->del_dev(dev, devaddr);
1220 }
1221
1222 int ieee802154_llsec_del_dev(struct sk_buff *skb, struct genl_info *info)
1223 {
1224         return ieee802154_nl_llsec_change(skb, info, llsec_del_dev);
1225 }
1226
1227 static int
1228 ieee802154_nl_fill_dev(struct sk_buff *msg, u32 portid, u32 seq,
1229                        const struct ieee802154_llsec_device *desc,
1230                        const struct net_device *dev)
1231 {
1232         void *hdr;
1233
1234         hdr = genlmsg_put(msg, 0, seq, &nl802154_family, NLM_F_MULTI,
1235                           IEEE802154_LLSEC_LIST_DEV);
1236         if (!hdr)
1237                 goto out;
1238
1239         if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
1240             nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
1241             nla_put_shortaddr(msg, IEEE802154_ATTR_PAN_ID, desc->pan_id) ||
1242             nla_put_shortaddr(msg, IEEE802154_ATTR_SHORT_ADDR,
1243                               desc->short_addr) ||
1244             nla_put_hwaddr(msg, IEEE802154_ATTR_HW_ADDR, desc->hwaddr) ||
1245             nla_put_u32(msg, IEEE802154_ATTR_LLSEC_FRAME_COUNTER,
1246                         desc->frame_counter) ||
1247             nla_put_u8(msg, IEEE802154_ATTR_LLSEC_DEV_OVERRIDE,
1248                        desc->seclevel_exempt) ||
1249             nla_put_u8(msg, IEEE802154_ATTR_LLSEC_DEV_KEY_MODE, desc->key_mode))
1250                 goto nla_put_failure;
1251
1252         genlmsg_end(msg, hdr);
1253         return 0;
1254
1255 nla_put_failure:
1256         genlmsg_cancel(msg, hdr);
1257 out:
1258         return -EMSGSIZE;
1259 }
1260
1261 static int llsec_iter_devs(struct llsec_dump_data *data)
1262 {
1263         struct ieee802154_llsec_device *pos;
1264         int rc = 0, idx = 0;
1265
1266         list_for_each_entry(pos, &data->table->devices, list) {
1267                 if (idx++ < data->s_idx)
1268                         continue;
1269
1270                 if (ieee802154_nl_fill_dev(data->skb, data->portid,
1271                                            data->nlmsg_seq, pos, data->dev)) {
1272                         rc = -EMSGSIZE;
1273                         break;
1274                 }
1275
1276                 data->s_idx++;
1277         }
1278
1279         return rc;
1280 }
1281
1282 int ieee802154_llsec_dump_devs(struct sk_buff *skb, struct netlink_callback *cb)
1283 {
1284         return ieee802154_llsec_dump_table(skb, cb, llsec_iter_devs);
1285 }
1286
1287
1288
1289 static int llsec_add_devkey(struct net_device *dev, struct genl_info *info)
1290 {
1291         struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
1292         struct ieee802154_llsec_device_key key;
1293         __le64 devaddr;
1294
1295         if (!info->attrs[IEEE802154_ATTR_LLSEC_FRAME_COUNTER] ||
1296             !info->attrs[IEEE802154_ATTR_HW_ADDR] ||
1297             ieee802154_llsec_parse_key_id(info, &key.key_id))
1298                 return -EINVAL;
1299
1300         devaddr = nla_get_hwaddr(info->attrs[IEEE802154_ATTR_HW_ADDR]);
1301         key.frame_counter = nla_get_u32(info->attrs[IEEE802154_ATTR_LLSEC_FRAME_COUNTER]);
1302
1303         return ops->llsec->add_devkey(dev, devaddr, &key);
1304 }
1305
1306 int ieee802154_llsec_add_devkey(struct sk_buff *skb, struct genl_info *info)
1307 {
1308         if ((info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL)) !=
1309             (NLM_F_CREATE | NLM_F_EXCL))
1310                 return -EINVAL;
1311
1312         return ieee802154_nl_llsec_change(skb, info, llsec_add_devkey);
1313 }
1314
1315 static int llsec_del_devkey(struct net_device *dev, struct genl_info *info)
1316 {
1317         struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
1318         struct ieee802154_llsec_device_key key;
1319         __le64 devaddr;
1320
1321         if (!info->attrs[IEEE802154_ATTR_HW_ADDR] ||
1322             ieee802154_llsec_parse_key_id(info, &key.key_id))
1323                 return -EINVAL;
1324
1325         devaddr = nla_get_hwaddr(info->attrs[IEEE802154_ATTR_HW_ADDR]);
1326
1327         return ops->llsec->del_devkey(dev, devaddr, &key);
1328 }
1329
1330 int ieee802154_llsec_del_devkey(struct sk_buff *skb, struct genl_info *info)
1331 {
1332         return ieee802154_nl_llsec_change(skb, info, llsec_del_devkey);
1333 }
1334
1335 static int
1336 ieee802154_nl_fill_devkey(struct sk_buff *msg, u32 portid, u32 seq,
1337                           __le64 devaddr,
1338                           const struct ieee802154_llsec_device_key *devkey,
1339                           const struct net_device *dev)
1340 {
1341         void *hdr;
1342
1343         hdr = genlmsg_put(msg, 0, seq, &nl802154_family, NLM_F_MULTI,
1344                           IEEE802154_LLSEC_LIST_DEVKEY);
1345         if (!hdr)
1346                 goto out;
1347
1348         if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
1349             nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
1350             nla_put_hwaddr(msg, IEEE802154_ATTR_HW_ADDR, devaddr) ||
1351             nla_put_u32(msg, IEEE802154_ATTR_LLSEC_FRAME_COUNTER,
1352                         devkey->frame_counter) ||
1353             ieee802154_llsec_fill_key_id(msg, &devkey->key_id))
1354                 goto nla_put_failure;
1355
1356         genlmsg_end(msg, hdr);
1357         return 0;
1358
1359 nla_put_failure:
1360         genlmsg_cancel(msg, hdr);
1361 out:
1362         return -EMSGSIZE;
1363 }
1364
1365 static int llsec_iter_devkeys(struct llsec_dump_data *data)
1366 {
1367         struct ieee802154_llsec_device *dpos;
1368         struct ieee802154_llsec_device_key *kpos;
1369         int rc = 0, idx = 0, idx2;
1370
1371         list_for_each_entry(dpos, &data->table->devices, list) {
1372                 if (idx++ < data->s_idx)
1373                         continue;
1374
1375                 idx2 = 0;
1376
1377                 list_for_each_entry(kpos, &dpos->keys, list) {
1378                         if (idx2++ < data->s_idx2)
1379                                 continue;
1380
1381                         if (ieee802154_nl_fill_devkey(data->skb, data->portid,
1382                                                       data->nlmsg_seq,
1383                                                       dpos->hwaddr, kpos,
1384                                                       data->dev)) {
1385                                 return rc = -EMSGSIZE;
1386                         }
1387
1388                         data->s_idx2++;
1389                 }
1390
1391                 data->s_idx++;
1392         }
1393
1394         return rc;
1395 }
1396
1397 int ieee802154_llsec_dump_devkeys(struct sk_buff *skb,
1398                                   struct netlink_callback *cb)
1399 {
1400         return ieee802154_llsec_dump_table(skb, cb, llsec_iter_devkeys);
1401 }
1402
1403
1404
1405 static int
1406 llsec_parse_seclevel(struct genl_info *info,
1407                      struct ieee802154_llsec_seclevel *sl)
1408 {
1409         memset(sl, 0, sizeof(*sl));
1410
1411         if (!info->attrs[IEEE802154_ATTR_LLSEC_FRAME_TYPE] ||
1412             !info->attrs[IEEE802154_ATTR_LLSEC_SECLEVELS] ||
1413             !info->attrs[IEEE802154_ATTR_LLSEC_DEV_OVERRIDE])
1414                 return -EINVAL;
1415
1416         sl->frame_type = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_FRAME_TYPE]);
1417         if (sl->frame_type == IEEE802154_FC_TYPE_MAC_CMD) {
1418                 if (!info->attrs[IEEE802154_ATTR_LLSEC_CMD_FRAME_ID])
1419                         return -EINVAL;
1420
1421                 sl->cmd_frame_id = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_CMD_FRAME_ID]);
1422         }
1423
1424         sl->sec_levels = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_SECLEVELS]);
1425         sl->device_override = nla_get_u8(info->attrs[IEEE802154_ATTR_LLSEC_DEV_OVERRIDE]);
1426
1427         return 0;
1428 }
1429
1430 static int llsec_add_seclevel(struct net_device *dev, struct genl_info *info)
1431 {
1432         struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
1433         struct ieee802154_llsec_seclevel sl;
1434
1435         if (llsec_parse_seclevel(info, &sl))
1436                 return -EINVAL;
1437
1438         return ops->llsec->add_seclevel(dev, &sl);
1439 }
1440
1441 int ieee802154_llsec_add_seclevel(struct sk_buff *skb, struct genl_info *info)
1442 {
1443         if ((info->nlhdr->nlmsg_flags & (NLM_F_CREATE | NLM_F_EXCL)) !=
1444             (NLM_F_CREATE | NLM_F_EXCL))
1445                 return -EINVAL;
1446
1447         return ieee802154_nl_llsec_change(skb, info, llsec_add_seclevel);
1448 }
1449
1450 static int llsec_del_seclevel(struct net_device *dev, struct genl_info *info)
1451 {
1452         struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
1453         struct ieee802154_llsec_seclevel sl;
1454
1455         if (llsec_parse_seclevel(info, &sl))
1456                 return -EINVAL;
1457
1458         return ops->llsec->del_seclevel(dev, &sl);
1459 }
1460
1461 int ieee802154_llsec_del_seclevel(struct sk_buff *skb, struct genl_info *info)
1462 {
1463         return ieee802154_nl_llsec_change(skb, info, llsec_del_seclevel);
1464 }
1465
1466 static int
1467 ieee802154_nl_fill_seclevel(struct sk_buff *msg, u32 portid, u32 seq,
1468                             const struct ieee802154_llsec_seclevel *sl,
1469                             const struct net_device *dev)
1470 {
1471         void *hdr;
1472
1473         hdr = genlmsg_put(msg, 0, seq, &nl802154_family, NLM_F_MULTI,
1474                           IEEE802154_LLSEC_LIST_SECLEVEL);
1475         if (!hdr)
1476                 goto out;
1477
1478         if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
1479             nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
1480             nla_put_u8(msg, IEEE802154_ATTR_LLSEC_FRAME_TYPE, sl->frame_type) ||
1481             nla_put_u8(msg, IEEE802154_ATTR_LLSEC_SECLEVELS, sl->sec_levels) ||
1482             nla_put_u8(msg, IEEE802154_ATTR_LLSEC_DEV_OVERRIDE,
1483                        sl->device_override))
1484                 goto nla_put_failure;
1485
1486         if (sl->frame_type == IEEE802154_FC_TYPE_MAC_CMD &&
1487             nla_put_u8(msg, IEEE802154_ATTR_LLSEC_CMD_FRAME_ID,
1488                        sl->cmd_frame_id))
1489                 goto nla_put_failure;
1490
1491         genlmsg_end(msg, hdr);
1492         return 0;
1493
1494 nla_put_failure:
1495         genlmsg_cancel(msg, hdr);
1496 out:
1497         return -EMSGSIZE;
1498 }
1499
1500 static int llsec_iter_seclevels(struct llsec_dump_data *data)
1501 {
1502         struct ieee802154_llsec_seclevel *pos;
1503         int rc = 0, idx = 0;
1504
1505         list_for_each_entry(pos, &data->table->security_levels, list) {
1506                 if (idx++ < data->s_idx)
1507                         continue;
1508
1509                 if (ieee802154_nl_fill_seclevel(data->skb, data->portid,
1510                                                 data->nlmsg_seq, pos,
1511                                                 data->dev)) {
1512                         rc = -EMSGSIZE;
1513                         break;
1514                 }
1515
1516                 data->s_idx++;
1517         }
1518
1519         return rc;
1520 }
1521
1522 int ieee802154_llsec_dump_seclevels(struct sk_buff *skb,
1523                                     struct netlink_callback *cb)
1524 {
1525         return ieee802154_llsec_dump_table(skb, cb, llsec_iter_seclevels);
1526 }