Merge branch 'drm-fixes-3.7' of git://people.freedesktop.org/~agd5f/linux into drm...
[linux-2.6/libata-dev.git] / net / ieee802154 / nl-mac.c
blob96bb08abece29408f0d9d65f453ee7f2c0c55c4e
1 /*
2 * Netlink inteface for IEEE 802.15.4 stack
4 * Copyright 2007, 2008 Siemens AG
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.
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.
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.
19 * Written by:
20 * Sergey Lapin <slapin@ossfans.org>
21 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
22 * Maxim Osipov <maxim.osipov@siemens.com>
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>
40 #include "ieee802154.h"
42 static struct genl_multicast_group ieee802154_coord_mcgrp = {
43 .name = IEEE802154_MCAST_COORD_NAME,
46 static struct genl_multicast_group ieee802154_beacon_mcgrp = {
47 .name = IEEE802154_MCAST_BEACON_NAME,
50 int ieee802154_nl_assoc_indic(struct net_device *dev,
51 struct ieee802154_addr *addr, u8 cap)
53 struct sk_buff *msg;
55 pr_debug("%s\n", __func__);
57 if (addr->addr_type != IEEE802154_ADDR_LONG) {
58 pr_err("%s: received non-long source address!\n", __func__);
59 return -EINVAL;
62 msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC);
63 if (!msg)
64 return -ENOBUFS;
66 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
67 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
68 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
69 dev->dev_addr) ||
70 nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
71 addr->hwaddr) ||
72 nla_put_u8(msg, IEEE802154_ATTR_CAPABILITY, cap))
73 goto nla_put_failure;
75 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
77 nla_put_failure:
78 nlmsg_free(msg);
79 return -ENOBUFS;
81 EXPORT_SYMBOL(ieee802154_nl_assoc_indic);
83 int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr,
84 u8 status)
86 struct sk_buff *msg;
88 pr_debug("%s\n", __func__);
90 msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF);
91 if (!msg)
92 return -ENOBUFS;
94 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
95 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
96 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
97 dev->dev_addr) ||
98 nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) ||
99 nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
100 goto nla_put_failure;
101 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
103 nla_put_failure:
104 nlmsg_free(msg);
105 return -ENOBUFS;
107 EXPORT_SYMBOL(ieee802154_nl_assoc_confirm);
109 int ieee802154_nl_disassoc_indic(struct net_device *dev,
110 struct ieee802154_addr *addr, u8 reason)
112 struct sk_buff *msg;
114 pr_debug("%s\n", __func__);
116 msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC);
117 if (!msg)
118 return -ENOBUFS;
120 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
121 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
122 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
123 dev->dev_addr))
124 goto nla_put_failure;
125 if (addr->addr_type == IEEE802154_ADDR_LONG) {
126 if (nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
127 addr->hwaddr))
128 goto nla_put_failure;
129 } else {
130 if (nla_put_u16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
131 addr->short_addr))
132 goto nla_put_failure;
134 if (nla_put_u8(msg, IEEE802154_ATTR_REASON, reason))
135 goto nla_put_failure;
136 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
138 nla_put_failure:
139 nlmsg_free(msg);
140 return -ENOBUFS;
142 EXPORT_SYMBOL(ieee802154_nl_disassoc_indic);
144 int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status)
146 struct sk_buff *msg;
148 pr_debug("%s\n", __func__);
150 msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF);
151 if (!msg)
152 return -ENOBUFS;
154 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
155 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
156 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
157 dev->dev_addr) ||
158 nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
159 goto nla_put_failure;
160 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
162 nla_put_failure:
163 nlmsg_free(msg);
164 return -ENOBUFS;
166 EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm);
168 int ieee802154_nl_beacon_indic(struct net_device *dev,
169 u16 panid, u16 coord_addr)
171 struct sk_buff *msg;
173 pr_debug("%s\n", __func__);
175 msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC);
176 if (!msg)
177 return -ENOBUFS;
179 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
180 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
181 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
182 dev->dev_addr) ||
183 nla_put_u16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr) ||
184 nla_put_u16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid))
185 goto nla_put_failure;
186 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
188 nla_put_failure:
189 nlmsg_free(msg);
190 return -ENOBUFS;
192 EXPORT_SYMBOL(ieee802154_nl_beacon_indic);
194 int ieee802154_nl_scan_confirm(struct net_device *dev,
195 u8 status, u8 scan_type, u32 unscanned, u8 page,
196 u8 *edl/* , struct list_head *pan_desc_list */)
198 struct sk_buff *msg;
200 pr_debug("%s\n", __func__);
202 msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF);
203 if (!msg)
204 return -ENOBUFS;
206 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
207 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
208 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
209 dev->dev_addr) ||
210 nla_put_u8(msg, IEEE802154_ATTR_STATUS, status) ||
211 nla_put_u8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type) ||
212 nla_put_u32(msg, IEEE802154_ATTR_CHANNELS, unscanned) ||
213 nla_put_u8(msg, IEEE802154_ATTR_PAGE, page) ||
214 (edl &&
215 nla_put(msg, IEEE802154_ATTR_ED_LIST, 27, edl)))
216 goto nla_put_failure;
217 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
219 nla_put_failure:
220 nlmsg_free(msg);
221 return -ENOBUFS;
223 EXPORT_SYMBOL(ieee802154_nl_scan_confirm);
225 int ieee802154_nl_start_confirm(struct net_device *dev, u8 status)
227 struct sk_buff *msg;
229 pr_debug("%s\n", __func__);
231 msg = ieee802154_nl_create(0, IEEE802154_START_CONF);
232 if (!msg)
233 return -ENOBUFS;
235 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
236 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
237 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
238 dev->dev_addr) ||
239 nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
240 goto nla_put_failure;
241 return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
243 nla_put_failure:
244 nlmsg_free(msg);
245 return -ENOBUFS;
247 EXPORT_SYMBOL(ieee802154_nl_start_confirm);
249 static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid,
250 u32 seq, int flags, struct net_device *dev)
252 void *hdr;
253 struct wpan_phy *phy;
255 pr_debug("%s\n", __func__);
257 hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags,
258 IEEE802154_LIST_IFACE);
259 if (!hdr)
260 goto out;
262 phy = ieee802154_mlme_ops(dev)->get_phy(dev);
263 BUG_ON(!phy);
265 if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
266 nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
267 nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
268 nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
269 dev->dev_addr) ||
270 nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR,
271 ieee802154_mlme_ops(dev)->get_short_addr(dev)) ||
272 nla_put_u16(msg, IEEE802154_ATTR_PAN_ID,
273 ieee802154_mlme_ops(dev)->get_pan_id(dev)))
274 goto nla_put_failure;
275 wpan_phy_put(phy);
276 return genlmsg_end(msg, hdr);
278 nla_put_failure:
279 wpan_phy_put(phy);
280 genlmsg_cancel(msg, hdr);
281 out:
282 return -EMSGSIZE;
285 /* Requests from userspace */
286 static struct net_device *ieee802154_nl_get_dev(struct genl_info *info)
288 struct net_device *dev;
290 if (info->attrs[IEEE802154_ATTR_DEV_NAME]) {
291 char name[IFNAMSIZ + 1];
292 nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME],
293 sizeof(name));
294 dev = dev_get_by_name(&init_net, name);
295 } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX])
296 dev = dev_get_by_index(&init_net,
297 nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX]));
298 else
299 return NULL;
301 if (!dev)
302 return NULL;
304 if (dev->type != ARPHRD_IEEE802154) {
305 dev_put(dev);
306 return NULL;
309 return dev;
312 static int ieee802154_associate_req(struct sk_buff *skb,
313 struct genl_info *info)
315 struct net_device *dev;
316 struct ieee802154_addr addr;
317 u8 page;
318 int ret = -EINVAL;
320 if (!info->attrs[IEEE802154_ATTR_CHANNEL] ||
321 !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
322 (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] &&
323 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) ||
324 !info->attrs[IEEE802154_ATTR_CAPABILITY])
325 return -EINVAL;
327 dev = ieee802154_nl_get_dev(info);
328 if (!dev)
329 return -ENODEV;
331 if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) {
332 addr.addr_type = IEEE802154_ADDR_LONG;
333 nla_memcpy(addr.hwaddr,
334 info->attrs[IEEE802154_ATTR_COORD_HW_ADDR],
335 IEEE802154_ADDR_LEN);
336 } else {
337 addr.addr_type = IEEE802154_ADDR_SHORT;
338 addr.short_addr = nla_get_u16(
339 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
341 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
343 if (info->attrs[IEEE802154_ATTR_PAGE])
344 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
345 else
346 page = 0;
348 ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr,
349 nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]),
350 page,
351 nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY]));
353 dev_put(dev);
354 return ret;
357 static int ieee802154_associate_resp(struct sk_buff *skb,
358 struct genl_info *info)
360 struct net_device *dev;
361 struct ieee802154_addr addr;
362 int ret = -EINVAL;
364 if (!info->attrs[IEEE802154_ATTR_STATUS] ||
365 !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] ||
366 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR])
367 return -EINVAL;
369 dev = ieee802154_nl_get_dev(info);
370 if (!dev)
371 return -ENODEV;
373 addr.addr_type = IEEE802154_ADDR_LONG;
374 nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
375 IEEE802154_ADDR_LEN);
376 addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
379 ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr,
380 nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
381 nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS]));
383 dev_put(dev);
384 return ret;
387 static int ieee802154_disassociate_req(struct sk_buff *skb,
388 struct genl_info *info)
390 struct net_device *dev;
391 struct ieee802154_addr addr;
392 int ret = -EINVAL;
394 if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] &&
395 !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) ||
396 !info->attrs[IEEE802154_ATTR_REASON])
397 return -EINVAL;
399 dev = ieee802154_nl_get_dev(info);
400 if (!dev)
401 return -ENODEV;
403 if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) {
404 addr.addr_type = IEEE802154_ADDR_LONG;
405 nla_memcpy(addr.hwaddr,
406 info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
407 IEEE802154_ADDR_LEN);
408 } else {
409 addr.addr_type = IEEE802154_ADDR_SHORT;
410 addr.short_addr = nla_get_u16(
411 info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]);
413 addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
415 ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr,
416 nla_get_u8(info->attrs[IEEE802154_ATTR_REASON]));
418 dev_put(dev);
419 return ret;
423 * PANid, channel, beacon_order = 15, superframe_order = 15,
424 * PAN_coordinator, battery_life_extension = 0,
425 * coord_realignment = 0, security_enable = 0
427 static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
429 struct net_device *dev;
430 struct ieee802154_addr addr;
432 u8 channel, bcn_ord, sf_ord;
433 u8 page;
434 int pan_coord, blx, coord_realign;
435 int ret;
437 if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
438 !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] ||
439 !info->attrs[IEEE802154_ATTR_CHANNEL] ||
440 !info->attrs[IEEE802154_ATTR_BCN_ORD] ||
441 !info->attrs[IEEE802154_ATTR_SF_ORD] ||
442 !info->attrs[IEEE802154_ATTR_PAN_COORD] ||
443 !info->attrs[IEEE802154_ATTR_BAT_EXT] ||
444 !info->attrs[IEEE802154_ATTR_COORD_REALIGN]
446 return -EINVAL;
448 dev = ieee802154_nl_get_dev(info);
449 if (!dev)
450 return -ENODEV;
452 addr.addr_type = IEEE802154_ADDR_SHORT;
453 addr.short_addr = nla_get_u16(
454 info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
455 addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
457 channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]);
458 bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]);
459 sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]);
460 pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]);
461 blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]);
462 coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]);
464 if (info->attrs[IEEE802154_ATTR_PAGE])
465 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
466 else
467 page = 0;
470 if (addr.short_addr == IEEE802154_ADDR_BROADCAST) {
471 ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS);
472 dev_put(dev);
473 return -EINVAL;
476 ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page,
477 bcn_ord, sf_ord, pan_coord, blx, coord_realign);
479 dev_put(dev);
480 return ret;
483 static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
485 struct net_device *dev;
486 int ret;
487 u8 type;
488 u32 channels;
489 u8 duration;
490 u8 page;
492 if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] ||
493 !info->attrs[IEEE802154_ATTR_CHANNELS] ||
494 !info->attrs[IEEE802154_ATTR_DURATION])
495 return -EINVAL;
497 dev = ieee802154_nl_get_dev(info);
498 if (!dev)
499 return -ENODEV;
501 type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]);
502 channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]);
503 duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]);
505 if (info->attrs[IEEE802154_ATTR_PAGE])
506 page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
507 else
508 page = 0;
511 ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page,
512 duration);
514 dev_put(dev);
515 return ret;
518 static int ieee802154_list_iface(struct sk_buff *skb,
519 struct genl_info *info)
521 /* Request for interface name, index, type, IEEE address,
522 PAN Id, short address */
523 struct sk_buff *msg;
524 struct net_device *dev = NULL;
525 int rc = -ENOBUFS;
527 pr_debug("%s\n", __func__);
529 dev = ieee802154_nl_get_dev(info);
530 if (!dev)
531 return -ENODEV;
533 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
534 if (!msg)
535 goto out_dev;
537 rc = ieee802154_nl_fill_iface(msg, info->snd_portid, info->snd_seq,
538 0, dev);
539 if (rc < 0)
540 goto out_free;
542 dev_put(dev);
544 return genlmsg_reply(msg, info);
545 out_free:
546 nlmsg_free(msg);
547 out_dev:
548 dev_put(dev);
549 return rc;
553 static int ieee802154_dump_iface(struct sk_buff *skb,
554 struct netlink_callback *cb)
556 struct net *net = sock_net(skb->sk);
557 struct net_device *dev;
558 int idx;
559 int s_idx = cb->args[0];
561 pr_debug("%s\n", __func__);
563 idx = 0;
564 for_each_netdev(net, dev) {
565 if (idx < s_idx || (dev->type != ARPHRD_IEEE802154))
566 goto cont;
568 if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).portid,
569 cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0)
570 break;
571 cont:
572 idx++;
574 cb->args[0] = idx;
576 return skb->len;
579 static struct genl_ops ieee802154_coordinator_ops[] = {
580 IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req),
581 IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp),
582 IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req),
583 IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req),
584 IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req),
585 IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface,
586 ieee802154_dump_iface),
590 * No need to unregister as family unregistration will do it.
592 int nl802154_mac_register(void)
594 int i;
595 int rc;
597 rc = genl_register_mc_group(&nl802154_family,
598 &ieee802154_coord_mcgrp);
599 if (rc)
600 return rc;
602 rc = genl_register_mc_group(&nl802154_family,
603 &ieee802154_beacon_mcgrp);
604 if (rc)
605 return rc;
607 for (i = 0; i < ARRAY_SIZE(ieee802154_coordinator_ops); i++) {
608 rc = genl_register_ops(&nl802154_family,
609 &ieee802154_coordinator_ops[i]);
610 if (rc)
611 return rc;
614 return 0;