~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to net/ieee802154/nl-mac.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 struct genl_multicast_group ieee802154_coord_mcgrp = {
 
43
        .name           = IEEE802154_MCAST_COORD_NAME,
 
44
};
 
45
 
 
46
static struct genl_multicast_group ieee802154_beacon_mcgrp = {
 
47
        .name           = IEEE802154_MCAST_BEACON_NAME,
 
48
};
 
49
 
 
50
int ieee802154_nl_assoc_indic(struct net_device *dev,
 
51
                struct ieee802154_addr *addr, u8 cap)
 
52
{
 
53
        struct sk_buff *msg;
 
54
 
 
55
        pr_debug("%s\n", __func__);
 
56
 
 
57
        if (addr->addr_type != IEEE802154_ADDR_LONG) {
 
58
                pr_err("%s: received non-long source address!\n", __func__);
 
59
                return -EINVAL;
 
60
        }
 
61
 
 
62
        msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC);
 
63
        if (!msg)
 
64
                return -ENOBUFS;
 
65
 
 
66
        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
 
 
71
        NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
 
72
                        addr->hwaddr);
 
73
 
 
74
        NLA_PUT_U8(msg, IEEE802154_ATTR_CAPABILITY, cap);
 
75
 
 
76
        return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
 
77
 
 
78
nla_put_failure:
 
79
        nlmsg_free(msg);
 
80
        return -ENOBUFS;
 
81
}
 
82
EXPORT_SYMBOL(ieee802154_nl_assoc_indic);
 
83
 
 
84
int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr,
 
85
                u8 status)
 
86
{
 
87
        struct sk_buff *msg;
 
88
 
 
89
        pr_debug("%s\n", __func__);
 
90
 
 
91
        msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF);
 
92
        if (!msg)
 
93
                return -ENOBUFS;
 
94
 
 
95
        NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
 
96
        NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
 
97
        NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
 
98
                        dev->dev_addr);
 
99
 
 
100
        NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr);
 
101
        NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
 
102
 
 
103
        return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
 
104
 
 
105
nla_put_failure:
 
106
        nlmsg_free(msg);
 
107
        return -ENOBUFS;
 
108
}
 
109
EXPORT_SYMBOL(ieee802154_nl_assoc_confirm);
 
110
 
 
111
int ieee802154_nl_disassoc_indic(struct net_device *dev,
 
112
                struct ieee802154_addr *addr, u8 reason)
 
113
{
 
114
        struct sk_buff *msg;
 
115
 
 
116
        pr_debug("%s\n", __func__);
 
117
 
 
118
        msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC);
 
119
        if (!msg)
 
120
                return -ENOBUFS;
 
121
 
 
122
        NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
 
123
        NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
 
124
        NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
 
125
                        dev->dev_addr);
 
126
 
 
127
        if (addr->addr_type == IEEE802154_ADDR_LONG)
 
128
                NLA_PUT(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
 
129
                                addr->hwaddr);
 
130
        else
 
131
                NLA_PUT_U16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
 
132
                                addr->short_addr);
 
133
 
 
134
        NLA_PUT_U8(msg, IEEE802154_ATTR_REASON, reason);
 
135
 
 
136
        return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
 
137
 
 
138
nla_put_failure:
 
139
        nlmsg_free(msg);
 
140
        return -ENOBUFS;
 
141
}
 
142
EXPORT_SYMBOL(ieee802154_nl_disassoc_indic);
 
143
 
 
144
int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status)
 
145
{
 
146
        struct sk_buff *msg;
 
147
 
 
148
        pr_debug("%s\n", __func__);
 
149
 
 
150
        msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF);
 
151
        if (!msg)
 
152
                return -ENOBUFS;
 
153
 
 
154
        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
 
 
159
        NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
 
160
 
 
161
        return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
 
162
 
 
163
nla_put_failure:
 
164
        nlmsg_free(msg);
 
165
        return -ENOBUFS;
 
166
}
 
167
EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm);
 
168
 
 
169
int ieee802154_nl_beacon_indic(struct net_device *dev,
 
170
                u16 panid, u16 coord_addr)
 
171
{
 
172
        struct sk_buff *msg;
 
173
 
 
174
        pr_debug("%s\n", __func__);
 
175
 
 
176
        msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC);
 
177
        if (!msg)
 
178
                return -ENOBUFS;
 
179
 
 
180
        NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
 
181
        NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
 
182
        NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
 
183
                        dev->dev_addr);
 
184
        NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr);
 
185
        NLA_PUT_U16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid);
 
186
 
 
187
        return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
 
188
 
 
189
nla_put_failure:
 
190
        nlmsg_free(msg);
 
191
        return -ENOBUFS;
 
192
}
 
193
EXPORT_SYMBOL(ieee802154_nl_beacon_indic);
 
194
 
 
195
int ieee802154_nl_scan_confirm(struct net_device *dev,
 
196
                u8 status, u8 scan_type, u32 unscanned, u8 page,
 
197
                u8 *edl/* , struct list_head *pan_desc_list */)
 
198
{
 
199
        struct sk_buff *msg;
 
200
 
 
201
        pr_debug("%s\n", __func__);
 
202
 
 
203
        msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF);
 
204
        if (!msg)
 
205
                return -ENOBUFS;
 
206
 
 
207
        NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
 
208
        NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
 
209
        NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
 
210
                        dev->dev_addr);
 
211
 
 
212
        NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
 
213
        NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type);
 
214
        NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned);
 
215
        NLA_PUT_U8(msg, IEEE802154_ATTR_PAGE, page);
 
216
 
 
217
        if (edl)
 
218
                NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl);
 
219
 
 
220
        return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
 
221
 
 
222
nla_put_failure:
 
223
        nlmsg_free(msg);
 
224
        return -ENOBUFS;
 
225
}
 
226
EXPORT_SYMBOL(ieee802154_nl_scan_confirm);
 
227
 
 
228
int ieee802154_nl_start_confirm(struct net_device *dev, u8 status)
 
229
{
 
230
        struct sk_buff *msg;
 
231
 
 
232
        pr_debug("%s\n", __func__);
 
233
 
 
234
        msg = ieee802154_nl_create(0, IEEE802154_START_CONF);
 
235
        if (!msg)
 
236
                return -ENOBUFS;
 
237
 
 
238
        NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
 
239
        NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
 
240
        NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
 
241
                        dev->dev_addr);
 
242
 
 
243
        NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
 
244
 
 
245
        return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
 
246
 
 
247
nla_put_failure:
 
248
        nlmsg_free(msg);
 
249
        return -ENOBUFS;
 
250
}
 
251
EXPORT_SYMBOL(ieee802154_nl_start_confirm);
 
252
 
 
253
static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 pid,
 
254
        u32 seq, int flags, struct net_device *dev)
 
255
{
 
256
        void *hdr;
 
257
        struct wpan_phy *phy;
 
258
 
 
259
        pr_debug("%s\n", __func__);
 
260
 
 
261
        hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags,
 
262
                IEEE802154_LIST_IFACE);
 
263
        if (!hdr)
 
264
                goto out;
 
265
 
 
266
        phy = ieee802154_mlme_ops(dev)->get_phy(dev);
 
267
        BUG_ON(!phy);
 
268
 
 
269
        NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name);
 
270
        NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy));
 
271
        NLA_PUT_U32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex);
 
272
 
 
273
        NLA_PUT(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
 
274
                dev->dev_addr);
 
275
        NLA_PUT_U16(msg, IEEE802154_ATTR_SHORT_ADDR,
 
276
                ieee802154_mlme_ops(dev)->get_short_addr(dev));
 
277
        NLA_PUT_U16(msg, IEEE802154_ATTR_PAN_ID,
 
278
                ieee802154_mlme_ops(dev)->get_pan_id(dev));
 
279
        wpan_phy_put(phy);
 
280
        return genlmsg_end(msg, hdr);
 
281
 
 
282
nla_put_failure:
 
283
        wpan_phy_put(phy);
 
284
        genlmsg_cancel(msg, hdr);
 
285
out:
 
286
        return -EMSGSIZE;
 
287
}
 
288
 
 
289
/* Requests from userspace */
 
290
static struct net_device *ieee802154_nl_get_dev(struct genl_info *info)
 
291
{
 
292
        struct net_device *dev;
 
293
 
 
294
        if (info->attrs[IEEE802154_ATTR_DEV_NAME]) {
 
295
                char name[IFNAMSIZ + 1];
 
296
                nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME],
 
297
                                sizeof(name));
 
298
                dev = dev_get_by_name(&init_net, name);
 
299
        } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX])
 
300
                dev = dev_get_by_index(&init_net,
 
301
                        nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX]));
 
302
        else
 
303
                return NULL;
 
304
 
 
305
        if (!dev)
 
306
                return NULL;
 
307
 
 
308
        if (dev->type != ARPHRD_IEEE802154) {
 
309
                dev_put(dev);
 
310
                return NULL;
 
311
        }
 
312
 
 
313
        return dev;
 
314
}
 
315
 
 
316
static int ieee802154_associate_req(struct sk_buff *skb,
 
317
                struct genl_info *info)
 
318
{
 
319
        struct net_device *dev;
 
320
        struct ieee802154_addr addr;
 
321
        u8 page;
 
322
        int ret = -EINVAL;
 
323
 
 
324
        if (!info->attrs[IEEE802154_ATTR_CHANNEL] ||
 
325
            !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
 
326
            (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] &&
 
327
                !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) ||
 
328
            !info->attrs[IEEE802154_ATTR_CAPABILITY])
 
329
                return -EINVAL;
 
330
 
 
331
        dev = ieee802154_nl_get_dev(info);
 
332
        if (!dev)
 
333
                return -ENODEV;
 
334
 
 
335
        if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) {
 
336
                addr.addr_type = IEEE802154_ADDR_LONG;
 
337
                nla_memcpy(addr.hwaddr,
 
338
                                info->attrs[IEEE802154_ATTR_COORD_HW_ADDR],
 
339
                                IEEE802154_ADDR_LEN);
 
340
        } else {
 
341
                addr.addr_type = IEEE802154_ADDR_SHORT;
 
342
                addr.short_addr = nla_get_u16(
 
343
                                info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
 
344
        }
 
345
        addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
 
346
 
 
347
        if (info->attrs[IEEE802154_ATTR_PAGE])
 
348
                page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
 
349
        else
 
350
                page = 0;
 
351
 
 
352
        ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr,
 
353
                        nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]),
 
354
                        page,
 
355
                        nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY]));
 
356
 
 
357
        dev_put(dev);
 
358
        return ret;
 
359
}
 
360
 
 
361
static int ieee802154_associate_resp(struct sk_buff *skb,
 
362
                struct genl_info *info)
 
363
{
 
364
        struct net_device *dev;
 
365
        struct ieee802154_addr addr;
 
366
        int ret = -EINVAL;
 
367
 
 
368
        if (!info->attrs[IEEE802154_ATTR_STATUS] ||
 
369
            !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] ||
 
370
            !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR])
 
371
                return -EINVAL;
 
372
 
 
373
        dev = ieee802154_nl_get_dev(info);
 
374
        if (!dev)
 
375
                return -ENODEV;
 
376
 
 
377
        addr.addr_type = IEEE802154_ADDR_LONG;
 
378
        nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
 
379
                        IEEE802154_ADDR_LEN);
 
380
        addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
 
381
 
 
382
 
 
383
        ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr,
 
384
                nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
 
385
                nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS]));
 
386
 
 
387
        dev_put(dev);
 
388
        return ret;
 
389
}
 
390
 
 
391
static int ieee802154_disassociate_req(struct sk_buff *skb,
 
392
                struct genl_info *info)
 
393
{
 
394
        struct net_device *dev;
 
395
        struct ieee802154_addr addr;
 
396
        int ret = -EINVAL;
 
397
 
 
398
        if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] &&
 
399
                !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) ||
 
400
            !info->attrs[IEEE802154_ATTR_REASON])
 
401
                return -EINVAL;
 
402
 
 
403
        dev = ieee802154_nl_get_dev(info);
 
404
        if (!dev)
 
405
                return -ENODEV;
 
406
 
 
407
        if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) {
 
408
                addr.addr_type = IEEE802154_ADDR_LONG;
 
409
                nla_memcpy(addr.hwaddr,
 
410
                                info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
 
411
                                IEEE802154_ADDR_LEN);
 
412
        } else {
 
413
                addr.addr_type = IEEE802154_ADDR_SHORT;
 
414
                addr.short_addr = nla_get_u16(
 
415
                                info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]);
 
416
        }
 
417
        addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
 
418
 
 
419
        ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr,
 
420
                        nla_get_u8(info->attrs[IEEE802154_ATTR_REASON]));
 
421
 
 
422
        dev_put(dev);
 
423
        return ret;
 
424
}
 
425
 
 
426
/*
 
427
 * PANid, channel, beacon_order = 15, superframe_order = 15,
 
428
 * PAN_coordinator, battery_life_extension = 0,
 
429
 * coord_realignment = 0, security_enable = 0
 
430
*/
 
431
static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
 
432
{
 
433
        struct net_device *dev;
 
434
        struct ieee802154_addr addr;
 
435
 
 
436
        u8 channel, bcn_ord, sf_ord;
 
437
        u8 page;
 
438
        int pan_coord, blx, coord_realign;
 
439
        int ret;
 
440
 
 
441
        if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
 
442
            !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] ||
 
443
            !info->attrs[IEEE802154_ATTR_CHANNEL] ||
 
444
            !info->attrs[IEEE802154_ATTR_BCN_ORD] ||
 
445
            !info->attrs[IEEE802154_ATTR_SF_ORD] ||
 
446
            !info->attrs[IEEE802154_ATTR_PAN_COORD] ||
 
447
            !info->attrs[IEEE802154_ATTR_BAT_EXT] ||
 
448
            !info->attrs[IEEE802154_ATTR_COORD_REALIGN]
 
449
         )
 
450
                return -EINVAL;
 
451
 
 
452
        dev = ieee802154_nl_get_dev(info);
 
453
        if (!dev)
 
454
                return -ENODEV;
 
455
 
 
456
        addr.addr_type = IEEE802154_ADDR_SHORT;
 
457
        addr.short_addr = nla_get_u16(
 
458
                        info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
 
459
        addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
 
460
 
 
461
        channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]);
 
462
        bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]);
 
463
        sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]);
 
464
        pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]);
 
465
        blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]);
 
466
        coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]);
 
467
 
 
468
        if (info->attrs[IEEE802154_ATTR_PAGE])
 
469
                page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
 
470
        else
 
471
                page = 0;
 
472
 
 
473
 
 
474
        if (addr.short_addr == IEEE802154_ADDR_BROADCAST) {
 
475
                ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS);
 
476
                dev_put(dev);
 
477
                return -EINVAL;
 
478
        }
 
479
 
 
480
        ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page,
 
481
                bcn_ord, sf_ord, pan_coord, blx, coord_realign);
 
482
 
 
483
        dev_put(dev);
 
484
        return ret;
 
485
}
 
486
 
 
487
static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
 
488
{
 
489
        struct net_device *dev;
 
490
        int ret;
 
491
        u8 type;
 
492
        u32 channels;
 
493
        u8 duration;
 
494
        u8 page;
 
495
 
 
496
        if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] ||
 
497
            !info->attrs[IEEE802154_ATTR_CHANNELS] ||
 
498
            !info->attrs[IEEE802154_ATTR_DURATION])
 
499
                return -EINVAL;
 
500
 
 
501
        dev = ieee802154_nl_get_dev(info);
 
502
        if (!dev)
 
503
                return -ENODEV;
 
504
 
 
505
        type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]);
 
506
        channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]);
 
507
        duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]);
 
508
 
 
509
        if (info->attrs[IEEE802154_ATTR_PAGE])
 
510
                page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
 
511
        else
 
512
                page = 0;
 
513
 
 
514
 
 
515
        ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page,
 
516
                        duration);
 
517
 
 
518
        dev_put(dev);
 
519
        return ret;
 
520
}
 
521
 
 
522
static int ieee802154_list_iface(struct sk_buff *skb,
 
523
        struct genl_info *info)
 
524
{
 
525
        /* Request for interface name, index, type, IEEE address,
 
526
           PAN Id, short address */
 
527
        struct sk_buff *msg;
 
528
        struct net_device *dev = NULL;
 
529
        int rc = -ENOBUFS;
 
530
 
 
531
        pr_debug("%s\n", __func__);
 
532
 
 
533
        dev = ieee802154_nl_get_dev(info);
 
534
        if (!dev)
 
535
                return -ENODEV;
 
536
 
 
537
        msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
 
538
        if (!msg)
 
539
                goto out_dev;
 
540
 
 
541
        rc = ieee802154_nl_fill_iface(msg, info->snd_pid, info->snd_seq,
 
542
                        0, dev);
 
543
        if (rc < 0)
 
544
                goto out_free;
 
545
 
 
546
        dev_put(dev);
 
547
 
 
548
        return genlmsg_reply(msg, info);
 
549
out_free:
 
550
        nlmsg_free(msg);
 
551
out_dev:
 
552
        dev_put(dev);
 
553
        return rc;
 
554
 
 
555
}
 
556
 
 
557
static int ieee802154_dump_iface(struct sk_buff *skb,
 
558
        struct netlink_callback *cb)
 
559
{
 
560
        struct net *net = sock_net(skb->sk);
 
561
        struct net_device *dev;
 
562
        int idx;
 
563
        int s_idx = cb->args[0];
 
564
 
 
565
        pr_debug("%s\n", __func__);
 
566
 
 
567
        idx = 0;
 
568
        for_each_netdev(net, dev) {
 
569
                if (idx < s_idx || (dev->type != ARPHRD_IEEE802154))
 
570
                        goto cont;
 
571
 
 
572
                if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).pid,
 
573
                        cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0)
 
574
                        break;
 
575
cont:
 
576
                idx++;
 
577
        }
 
578
        cb->args[0] = idx;
 
579
 
 
580
        return skb->len;
 
581
}
 
582
 
 
583
static struct genl_ops ieee802154_coordinator_ops[] = {
 
584
        IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req),
 
585
        IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp),
 
586
        IEEE802154_OP(IEEE802154_DISASSOCIATE_REQ, ieee802154_disassociate_req),
 
587
        IEEE802154_OP(IEEE802154_SCAN_REQ, ieee802154_scan_req),
 
588
        IEEE802154_OP(IEEE802154_START_REQ, ieee802154_start_req),
 
589
        IEEE802154_DUMP(IEEE802154_LIST_IFACE, ieee802154_list_iface,
 
590
                                                        ieee802154_dump_iface),
 
591
};
 
592
 
 
593
/*
 
594
 * No need to unregister as family unregistration will do it.
 
595
 */
 
596
int nl802154_mac_register(void)
 
597
{
 
598
        int i;
 
599
        int rc;
 
600
 
 
601
        rc = genl_register_mc_group(&nl802154_family,
 
602
                        &ieee802154_coord_mcgrp);
 
603
        if (rc)
 
604
                return rc;
 
605
 
 
606
        rc = genl_register_mc_group(&nl802154_family,
 
607
                        &ieee802154_beacon_mcgrp);
 
608
        if (rc)
 
609
                return rc;
 
610
 
 
611
        for (i = 0; i < ARRAY_SIZE(ieee802154_coordinator_ops); i++) {
 
612
                rc = genl_register_ops(&nl802154_family,
 
613
                                &ieee802154_coordinator_ops[i]);
 
614
                if (rc)
 
615
                        return rc;
 
616
        }
 
617
 
 
618
        return 0;
 
619
}