Merge SSB driver from tree at bu3sch.de, pulled 24/6
[openwrt.git] / package / mac80211 / src / wireless / nl80211.c
1 /*
2 * This is the new netlink-based wireless configuration interface.
3 *
4 * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
5 */
6
7 #include <linux/if.h>
8 #include <linux/module.h>
9 #include <linux/err.h>
10 #include <linux/mutex.h>
11 #include <linux/list.h>
12 #include <linux/if_ether.h>
13 #include <linux/ieee80211.h>
14 #include <linux/nl80211.h>
15 #include <linux/rtnetlink.h>
16 #include <net/genetlink.h>
17 #include <net/cfg80211.h>
18 #include "core.h"
19 #include "nl80211.h"
20
21 /* the netlink family */
22 static struct genl_family nl80211_fam = {
23 .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */
24 .name = "nl80211", /* have users key off the name instead */
25 .hdrsize = 0, /* no private header */
26 .version = 1, /* no particular meaning now */
27 .maxattr = NL80211_ATTR_MAX,
28 };
29
30 /* internal helper: validate an information element attribute */
31 static int check_information_element(struct nlattr *nla)
32 {
33 int len = nla_len(nla);
34 u8 *data = nla_data(nla);
35 int elementlen;
36
37 while (len >= 2) {
38 /* 1 byte ID, 1 byte len, `len' bytes data */
39 elementlen = *(data+1) + 2;
40 data += elementlen;
41 len -= elementlen;
42 }
43 return len ? -EINVAL : 0;
44 }
45
46 /* internal helper: get drv and dev */
47 static int get_drv_dev_by_info_ifindex(struct genl_info *info,
48 struct cfg80211_registered_device **drv,
49 struct net_device **dev)
50 {
51 int ifindex;
52
53 if (!info->attrs[NL80211_ATTR_IFINDEX])
54 return -EINVAL;
55
56 ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
57 *dev = dev_get_by_index(ifindex);
58 if (!dev)
59 return -ENODEV;
60
61 *drv = cfg80211_get_dev_from_ifindex(ifindex);
62 if (IS_ERR(*drv)) {
63 dev_put(*dev);
64 return PTR_ERR(*drv);
65 }
66
67 return 0;
68 }
69
70 /* policy for the attributes */
71 static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
72 [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
73 [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
74 [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
75 [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
76 .len = BUS_ID_SIZE-1 },
77 [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
78 [NL80211_ATTR_BSSID] = { .len = ETH_ALEN },
79 [NL80211_ATTR_SSID] = { .type = NLA_BINARY,
80 .len = IEEE80211_MAX_SSID_LEN },
81 [NL80211_ATTR_CHANNEL] = { .type = NLA_U32 },
82 [NL80211_ATTR_PHYMODE] = { .type = NLA_U32 },
83 [NL80211_ATTR_CHANNEL_LIST] = { .type = NLA_NESTED },
84 [NL80211_ATTR_BSS_LIST] = { .type = NLA_NESTED },
85 [NL80211_ATTR_BSSTYPE] = { .type = NLA_U32 },
86 [NL80211_ATTR_BEACON_PERIOD] = { .type = NLA_U32 },
87 [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
88 [NL80211_ATTR_TIMESTAMP] = { .type = NLA_U64 },
89 [NL80211_ATTR_IE] = { .type = NLA_BINARY, .len = NL80211_MAX_IE_LEN },
90 [NL80211_ATTR_AUTH_ALGORITHM] = { .type = NLA_U32 },
91 [NL80211_ATTR_TIMEOUT_TU] = { .type = NLA_U32 },
92 [NL80211_ATTR_REASON_CODE] = { .type = NLA_U32 },
93 [NL80211_ATTR_ASSOCIATION_ID] = { .type = NLA_U16 },
94 [NL80211_ATTR_DEAUTHENTICATED] = { .type = NLA_FLAG },
95 [NL80211_ATTR_RX_SENSITIVITY] = { .type = NLA_U32 },
96 [NL80211_ATTR_TRANSMIT_POWER] = { .type = NLA_U32 },
97 [NL80211_ATTR_FRAG_THRESHOLD] = { .type = NLA_U32 },
98 [NL80211_ATTR_FLAG_SCAN_ACTIVE] = { .type = NLA_FLAG },
99 [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY },
100 [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY },
101 [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
102 .len = WLAN_MAX_KEY_LEN },
103 [NL80211_ATTR_KEY_ID] = { .type = NLA_U32 },
104 [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 },
105 [NL80211_ATTR_MAC] = { .len = ETH_ALEN },
106 [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
107 };
108
109 /* netlink command implementations */
110
111 #define CHECK_CMD(ptr, cmd) \
112 if (drv->ops->ptr) \
113 NLA_PUT_FLAG(msg, NL80211_CMD_##cmd);
114
115 static int nl80211_get_cmdlist(struct sk_buff *skb, struct genl_info *info)
116 {
117 struct cfg80211_registered_device *drv;
118 struct sk_buff *msg;
119 void *hdr;
120 int err;
121 struct nlattr *start;
122
123 drv = cfg80211_get_dev_from_info(info);
124 if (IS_ERR(drv))
125 return PTR_ERR(drv);
126
127 hdr = nl80211msg_new(&msg, info->snd_pid, info->snd_seq, 0,
128 NL80211_CMD_NEW_CMDLIST);
129 if (IS_ERR(hdr)) {
130 err = PTR_ERR(hdr);
131 goto put_drv;
132 }
133
134 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, drv->idx);
135
136 start = nla_nest_start(msg, NL80211_ATTR_CMDS);
137 if (!start)
138 goto nla_put_failure;
139
140 /* unconditionally allow some common commands we handle centrally
141 * or where we require the implementation */
142 NLA_PUT_FLAG(msg, NL80211_CMD_GET_CMDLIST);
143 NLA_PUT_FLAG(msg, NL80211_CMD_GET_WIPHYS);
144 NLA_PUT_FLAG(msg, NL80211_CMD_GET_INTERFACES);
145 NLA_PUT_FLAG(msg, NL80211_CMD_RENAME_WIPHY);
146
147 CHECK_CMD(add_virtual_intf, ADD_VIRTUAL_INTERFACE);
148 CHECK_CMD(del_virtual_intf, DEL_VIRTUAL_INTERFACE);
149 CHECK_CMD(associate, ASSOCIATE);
150 CHECK_CMD(disassociate, DISASSOCIATE);
151 CHECK_CMD(deauth, DEAUTH);
152 CHECK_CMD(initiate_scan, INITIATE_SCAN);
153 CHECK_CMD(get_association, GET_ASSOCIATION);
154 CHECK_CMD(get_auth_list, GET_AUTH_LIST);
155 CHECK_CMD(add_key, ADD_KEY);
156 CHECK_CMD(del_key, DEL_KEY);
157
158 nla_nest_end(msg, start);
159
160 genlmsg_end(msg, hdr);
161
162 err = genlmsg_unicast(msg, info->snd_pid);
163 goto put_drv;
164
165 nla_put_failure:
166 err = -ENOBUFS;
167 nlmsg_free(msg);
168 put_drv:
169 cfg80211_put_dev(drv);
170 return err;
171 }
172 #undef CHECK_CMD
173
174 static int nl80211_get_wiphys(struct sk_buff *skb, struct genl_info *info)
175 {
176 struct sk_buff *msg;
177 void *hdr;
178 struct nlattr *start, *indexstart;
179 struct cfg80211_registered_device *drv;
180 int idx = 1;
181
182 hdr = nl80211msg_new(&msg, info->snd_pid, info->snd_seq, 0,
183 NL80211_CMD_NEW_WIPHYS);
184 if (IS_ERR(hdr))
185 return PTR_ERR(hdr);
186
187 start = nla_nest_start(msg, NL80211_ATTR_WIPHY_LIST);
188 if (!start)
189 goto nla_outer_nest_failure;
190
191 mutex_lock(&cfg80211_drv_mutex);
192 list_for_each_entry(drv, &cfg80211_drv_list, list) {
193 indexstart = nla_nest_start(msg, idx++);
194 if (!indexstart)
195 goto nla_put_failure;
196 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, drv->idx);
197 nla_nest_end(msg, indexstart);
198 }
199 mutex_unlock(&cfg80211_drv_mutex);
200
201 nla_nest_end(msg, start);
202
203 genlmsg_end(msg, hdr);
204
205 return genlmsg_unicast(msg, info->snd_pid);
206
207 nla_put_failure:
208 mutex_unlock(&cfg80211_drv_mutex);
209 nla_outer_nest_failure:
210 nlmsg_free(msg);
211 return -ENOBUFS;
212 }
213
214 static int addifidx(struct net_device *dev, struct sk_buff *skb, int *idx)
215 {
216 int err = -ENOBUFS;
217 struct nlattr *start;
218
219 dev_hold(dev);
220
221 start = nla_nest_start(skb, *idx++);
222 if (!start)
223 goto nla_put_failure;
224
225 NLA_PUT_U32(skb, NL80211_ATTR_IFINDEX, dev->ifindex);
226 NLA_PUT_STRING(skb, NL80211_ATTR_IFNAME, dev->name);
227
228 nla_nest_end(skb, start);
229 err = 0;
230
231 nla_put_failure:
232 dev_put(dev);
233 return err;
234 }
235
236 static int nl80211_get_intfs(struct sk_buff *skb, struct genl_info *info)
237 {
238 struct cfg80211_registered_device *drv;
239 struct sk_buff *msg;
240 void *hdr;
241 int err, array_idx;
242 struct nlattr *start;
243 struct wireless_dev *wdev;
244
245 drv = cfg80211_get_dev_from_info(info);
246 if (IS_ERR(drv))
247 return PTR_ERR(drv);
248
249 hdr = nl80211msg_new(&msg, info->snd_pid, info->snd_seq, 0,
250 NL80211_CMD_NEW_INTERFACES);
251 if (IS_ERR(hdr)) {
252 err = PTR_ERR(hdr);
253 goto put_drv;
254 }
255
256 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, drv->idx);
257
258 start = nla_nest_start(msg, NL80211_ATTR_INTERFACE_LIST);
259 if (!start) {
260 err = -ENOBUFS;
261 goto msg_free;
262 }
263
264 array_idx = 1;
265 err = 0;
266 mutex_lock(&drv->devlist_mtx);
267 list_for_each_entry(wdev, &drv->netdev_list, list) {
268 err = addifidx(wdev->netdev, msg, &array_idx);
269 if (err)
270 break;
271 }
272 mutex_unlock(&drv->devlist_mtx);
273 if (err)
274 goto msg_free;
275
276 nla_nest_end(msg, start);
277
278 genlmsg_end(msg, hdr);
279
280 err = genlmsg_unicast(msg, info->snd_pid);
281 goto put_drv;
282
283 nla_put_failure:
284 err = -ENOBUFS;
285 msg_free:
286 nlmsg_free(msg);
287 put_drv:
288 cfg80211_put_dev(drv);
289 return err;
290 }
291
292 static int nl80211_add_virt_intf(struct sk_buff *skb, struct genl_info *info)
293 {
294 struct cfg80211_registered_device *drv;
295 int err;
296 unsigned int type = NL80211_IFTYPE_UNSPECIFIED;
297
298 if (!info->attrs[NL80211_ATTR_IFNAME])
299 return -EINVAL;
300
301 if (info->attrs[NL80211_ATTR_IFTYPE]) {
302 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
303 if (type > NL80211_IFTYPE_MAX)
304 return -EINVAL;
305 }
306
307 drv = cfg80211_get_dev_from_info(info);
308 if (IS_ERR(drv))
309 return PTR_ERR(drv);
310
311 if (!drv->ops->add_virtual_intf) {
312 err = -EOPNOTSUPP;
313 goto unlock;
314 }
315
316 rtnl_lock();
317 err = drv->ops->add_virtual_intf(&drv->wiphy,
318 nla_data(info->attrs[NL80211_ATTR_IFNAME]), type);
319 rtnl_unlock();
320
321 unlock:
322 cfg80211_put_dev(drv);
323 return err;
324 }
325
326 static int nl80211_del_virt_intf(struct sk_buff *skb, struct genl_info *info)
327 {
328 struct cfg80211_registered_device *drv;
329 int ifindex, err;
330 struct net_device *dev;
331
332 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
333 if (err)
334 return err;
335 ifindex = dev->ifindex;
336 dev_put(dev);
337
338 if (!drv->ops->del_virtual_intf) {
339 err = -EOPNOTSUPP;
340 goto out;
341 }
342
343 rtnl_lock();
344 err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex);
345 rtnl_unlock();
346
347 out:
348 cfg80211_put_dev(drv);
349 return err;
350 }
351
352 static int nl80211_change_virt_intf(struct sk_buff *skb, struct genl_info *info)
353 {
354 struct cfg80211_registered_device *drv;
355 int err, ifindex;
356 unsigned int type;
357 struct net_device *dev;
358
359 if (info->attrs[NL80211_ATTR_IFTYPE]) {
360 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
361 if (type > NL80211_IFTYPE_MAX)
362 return -EINVAL;
363 } else
364 return -EINVAL;
365
366 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
367 if (err)
368 return err;
369 ifindex = dev->ifindex;
370 dev_put(dev);
371
372 if (!drv->ops->change_virtual_intf) {
373 err = -EOPNOTSUPP;
374 goto unlock;
375 }
376
377 rtnl_lock();
378 err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, type);
379 rtnl_unlock();
380
381 unlock:
382 cfg80211_put_dev(drv);
383 return err;
384 }
385
386 static int nl80211_get_association(struct sk_buff *skb, struct genl_info *info)
387 {
388 struct cfg80211_registered_device *drv;
389 int err;
390 struct net_device *dev;
391 struct sk_buff *msg;
392 void *hdr;
393 u8 bssid[ETH_ALEN];
394
395 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
396 if (err)
397 return err;
398
399 if (!drv->ops->get_association) {
400 err = -EOPNOTSUPP;
401 goto out_put_drv;
402 }
403
404 rtnl_lock();
405 err = drv->ops->get_association(&drv->wiphy, dev, bssid);
406 rtnl_unlock();
407 if (err < 0)
408 goto out_put_drv;
409
410 hdr = nl80211msg_new(&msg, info->snd_pid, info->snd_seq, 0,
411 NL80211_CMD_ASSOCIATION_CHANGED);
412
413 if (IS_ERR(hdr)) {
414 err = PTR_ERR(hdr);
415 goto out_put_drv;
416 }
417
418 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
419 if (err == 1)
420 NLA_PUT(msg, NL80211_ATTR_BSSID, ETH_ALEN, bssid);
421
422 genlmsg_end(msg, hdr);
423 err = genlmsg_unicast(msg, info->snd_pid);
424 goto out_put_drv;
425
426 nla_put_failure:
427 err = -ENOBUFS;
428 nlmsg_free(msg);
429 out_put_drv:
430 cfg80211_put_dev(drv);
431 dev_put(dev);
432 return err;
433 }
434
435 static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
436 {
437 struct cfg80211_registered_device *drv;
438 int err;
439 struct net_device *dev;
440 struct association_params assoc_params;
441
442 memset(&assoc_params, 0, sizeof(assoc_params));
443
444 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
445 if (err)
446 return err;
447
448 if (!drv->ops->associate) {
449 err = -EOPNOTSUPP;
450 goto out;
451 }
452
453 if (!info->attrs[NL80211_ATTR_SSID])
454 return -EINVAL;
455
456 assoc_params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
457 assoc_params.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
458
459 if (info->attrs[NL80211_ATTR_BSSID])
460 assoc_params.bssid = nla_data(info->attrs[NL80211_ATTR_BSSID]);
461
462 if (info->attrs[NL80211_ATTR_IE]) {
463 err = check_information_element(info->attrs[NL80211_ATTR_IE]);
464 if (err)
465 goto out;
466 assoc_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
467 assoc_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
468 }
469
470 if (info->attrs[NL80211_ATTR_TIMEOUT_TU]) {
471 assoc_params.timeout =
472 nla_get_u32(info->attrs[NL80211_ATTR_TIMEOUT_TU]);
473 assoc_params.valid |= ASSOC_PARAMS_TIMEOUT;
474 }
475
476 rtnl_lock();
477 err = drv->ops->associate(&drv->wiphy, dev, &assoc_params);
478 rtnl_unlock();
479
480 out:
481 cfg80211_put_dev(drv);
482 dev_put(dev);
483 return err;
484 }
485
486 static int nl80211_disassoc_deauth(struct sk_buff *skb, struct genl_info *info)
487 {
488 struct cfg80211_registered_device *drv;
489 int err;
490 struct net_device *dev;
491 int (*act)(struct wiphy *wiphy, struct net_device *dev);
492
493 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
494 if (err)
495 return err;
496
497 switch (info->genlhdr->cmd) {
498 case NL80211_CMD_DISASSOCIATE:
499 act = drv->ops->disassociate;
500 break;
501 case NL80211_CMD_DEAUTH:
502 act = drv->ops->deauth;
503 break;
504 default:
505 act = NULL;
506 }
507
508 if (!act) {
509 err = -EOPNOTSUPP;
510 goto out;
511 }
512
513 rtnl_lock();
514 err = act(&drv->wiphy, dev);
515 rtnl_unlock();
516 out:
517 cfg80211_put_dev(drv);
518 dev_put(dev);
519 return err;
520 }
521
522 struct add_cb_data {
523 int idx;
524 struct sk_buff *skb;
525 };
526
527 static int add_bssid(void *data, u8 *bssid)
528 {
529 struct add_cb_data *cb = data;
530 int err = -ENOBUFS;
531 struct nlattr *start;
532
533 start = nla_nest_start(cb->skb, cb->idx++);
534 if (!start)
535 goto nla_put_failure;
536
537 NLA_PUT(cb->skb, NL80211_ATTR_BSSID, ETH_ALEN, bssid);
538
539 nla_nest_end(cb->skb, start);
540 err = 0;
541
542 nla_put_failure:
543 return err;
544 }
545
546 static int nl80211_get_auth_list(struct sk_buff *skb, struct genl_info *info)
547 {
548 struct cfg80211_registered_device *drv;
549 struct net_device *dev;
550 struct sk_buff *msg;
551 void *hdr;
552 int err;
553 struct nlattr *start;
554 struct add_cb_data cb;
555
556 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
557 if (err)
558 return err;
559
560 if (!drv->ops->get_auth_list) {
561 err = -EOPNOTSUPP;
562 goto put_drv;
563 }
564
565 hdr = nl80211msg_new(&msg, info->snd_pid, info->snd_seq, 0,
566 NL80211_CMD_NEW_AUTH_LIST);
567 if (IS_ERR(hdr)) {
568 err = PTR_ERR(hdr);
569 goto put_drv;
570 }
571
572 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
573
574 start = nla_nest_start(msg, NL80211_ATTR_BSS_LIST);
575 if (!start) {
576 err = -ENOBUFS;
577 goto msg_free;
578 }
579
580 cb.skb = msg;
581 cb.idx = 1;
582 rtnl_lock();
583 err = drv->ops->get_auth_list(&drv->wiphy, dev, &cb, add_bssid);
584 rtnl_unlock();
585 if (err)
586 goto msg_free;
587
588 nla_nest_end(msg, start);
589
590 genlmsg_end(msg, hdr);
591
592 err = genlmsg_unicast(msg, info->snd_pid);
593 goto put_drv;
594
595 nla_put_failure:
596 err = -ENOBUFS;
597 msg_free:
598 nlmsg_free(msg);
599 put_drv:
600 cfg80211_put_dev(drv);
601 dev_put(dev);
602 return err;
603 }
604
605 static int nl80211_initiate_scan(struct sk_buff *skb, struct genl_info *info)
606 {
607 struct cfg80211_registered_device *drv;
608 int err;
609 struct net_device *dev;
610 struct scan_params params;
611 struct scan_channel *channels = NULL;
612 int count = -1;
613
614 if (info->attrs[NL80211_ATTR_PHYMODE])
615 params.phymode = nla_get_u32(info->attrs[NL80211_ATTR_PHYMODE]);
616
617 if (params.phymode > NL80211_PHYMODE_MAX)
618 return -EINVAL;
619
620 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
621 if (err)
622 return err;
623
624 if (!drv->ops->initiate_scan) {
625 err = -EOPNOTSUPP;
626 goto out;
627 }
628
629 params.active = nla_get_flag(info->attrs[NL80211_ATTR_FLAG_SCAN_ACTIVE]);
630
631 if (info->attrs[NL80211_ATTR_CHANNEL_LIST]) {
632 struct nlattr *attr = info->attrs[NL80211_ATTR_CHANNEL_LIST];
633 struct nlattr *nla;
634 int rem;
635 struct nlattr **tb;
636
637 /* let's count first */
638 count = 0;
639 nla_for_each_attr(nla, nla_data(attr), nla_len(attr), rem)
640 count++;
641
642 if (count == 0) {
643 /* assume we should actually scan all channels,
644 * scanning no channels make no sense */
645 count = -1;
646 goto done_channels;
647 }
648
649 if (count > NL80211_MAX_CHANNEL_LIST_ITEM) {
650 err = -EINVAL;
651 goto out;
652 }
653
654 channels = kmalloc(count * sizeof(struct scan_channel),
655 GFP_KERNEL);
656 tb = kmalloc((NL80211_ATTR_MAX+1) * sizeof(struct nlattr),
657 GFP_KERNEL);
658
659 count = 0;
660 nla_for_each_attr(nla, nla_data(attr), nla_len(attr), rem) {
661 err = nla_parse(tb, NL80211_ATTR_MAX, nla_data(nla),
662 nla_len(nla), nl80211_policy);
663
664 if (err || !tb[NL80211_ATTR_CHANNEL]) {
665 err = -EINVAL;
666 kfree(tb);
667 kfree(channels);
668 goto out;
669 }
670
671 channels[count].phymode = params.phymode;
672
673 if (tb[NL80211_ATTR_PHYMODE])
674 channels[count].phymode =
675 nla_get_u32(tb[NL80211_ATTR_PHYMODE]);
676
677 if (channels[count].phymode > NL80211_PHYMODE_MAX) {
678 err = -EINVAL;
679 kfree(tb);
680 kfree(channels);
681 goto out;
682 }
683
684 channels[count].channel =
685 nla_get_u32(tb[NL80211_ATTR_CHANNEL]);
686
687 channels[count].active =
688 nla_get_flag(tb[NL80211_ATTR_FLAG_SCAN_ACTIVE]);
689 count++;
690 }
691 kfree(tb);
692 }
693
694 done_channels:
695 params.channels = channels;
696 params.n_channels = count;
697
698 rtnl_lock();
699 err = drv->ops->initiate_scan(&drv->wiphy, dev, &params);
700 rtnl_unlock();
701
702 kfree(channels);
703 out:
704 cfg80211_put_dev(drv);
705 dev_put(dev);
706 return err;
707 }
708
709 static int nl80211_rename_wiphy(struct sk_buff *skb, struct genl_info *info)
710 {
711 struct cfg80211_registered_device *rdev;
712 int result;
713
714 if (!info->attrs[NL80211_ATTR_WIPHY_NAME])
715 return -EINVAL;
716
717 rdev = cfg80211_get_dev_from_info(info);
718 if (IS_ERR(rdev))
719 return PTR_ERR(rdev);
720
721 result = cfg80211_dev_rename(rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
722
723 cfg80211_put_dev(rdev);
724 return result;
725 }
726
727 static int nl80211_key_cmd(struct sk_buff *skb, struct genl_info *info)
728 {
729 struct cfg80211_registered_device *drv;
730 int err, del;
731 struct net_device *dev;
732 struct key_params params;
733 int (*act)(struct wiphy *wiphy, struct net_device *dev,
734 struct key_params *params);
735
736 memset(&params, 0, sizeof(params));
737
738 if (!info->attrs[NL80211_ATTR_KEY_TYPE])
739 return -EINVAL;
740
741 if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
742 return -EINVAL;
743
744 params.key_type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
745 if (params.key_type > NL80211_KEYTYPE_MAX)
746 return -EINVAL;
747
748 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
749 if (err)
750 return err;
751
752 switch (info->genlhdr->cmd) {
753 case NL80211_CMD_ADD_KEY:
754 act = drv->ops->add_key;
755 del = 0;
756 break;
757 case NL80211_CMD_DEL_KEY:
758 act = drv->ops->del_key;
759 del = 1;
760 break;
761 default:
762 act = NULL;
763 }
764
765 if (!act) {
766 err = -EOPNOTSUPP;
767 goto out;
768 }
769
770 if (info->attrs[NL80211_ATTR_KEY_DATA]) {
771 params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
772 params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
773 }
774
775 if (info->attrs[NL80211_ATTR_KEY_ID]) {
776 params.key_id = nla_get_u32(info->attrs[NL80211_ATTR_KEY_ID]);
777 } else {
778 params.key_id = -1;
779 }
780
781 params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
782
783 if (info->attrs[NL80211_ATTR_MAC]) {
784 params.macaddress = nla_data(info->attrs[NL80211_ATTR_MAC]);
785 } else {
786 params.macaddress = NULL;
787 }
788
789 rtnl_lock();
790 err = act(&drv->wiphy, dev, &params);
791 rtnl_unlock();
792
793 out:
794 cfg80211_put_dev(drv);
795 dev_put(dev);
796 return err;
797 }
798
799 static struct genl_ops nl80211_ops[] = {
800 {
801 .cmd = NL80211_CMD_RENAME_WIPHY,
802 .doit = nl80211_rename_wiphy,
803 .policy = nl80211_policy,
804 .flags = GENL_ADMIN_PERM,
805 },
806 {
807 .cmd = NL80211_CMD_GET_CMDLIST,
808 .doit = nl80211_get_cmdlist,
809 .policy = nl80211_policy,
810 /* can be retrieved by unprivileged users */
811 },
812 {
813 .cmd = NL80211_CMD_ADD_VIRTUAL_INTERFACE,
814 .doit = nl80211_add_virt_intf,
815 .policy = nl80211_policy,
816 .flags = GENL_ADMIN_PERM,
817 },
818 {
819 .cmd = NL80211_CMD_DEL_VIRTUAL_INTERFACE,
820 .doit = nl80211_del_virt_intf,
821 .policy = nl80211_policy,
822 .flags = GENL_ADMIN_PERM,
823 },
824 {
825 .cmd = NL80211_CMD_CHANGE_VIRTUAL_INTERFACE,
826 .doit = nl80211_change_virt_intf,
827 .policy = nl80211_policy,
828 .flags = GENL_ADMIN_PERM,
829 },
830 {
831 .cmd = NL80211_CMD_GET_WIPHYS,
832 .doit = nl80211_get_wiphys,
833 .policy = nl80211_policy,
834 /* can be retrieved by unprivileged users */
835 },
836 {
837 .cmd = NL80211_CMD_GET_INTERFACES,
838 .doit = nl80211_get_intfs,
839 .policy = nl80211_policy,
840 /* can be retrieved by unprivileged users */
841 },
842 {
843 .cmd = NL80211_CMD_INITIATE_SCAN,
844 .doit = nl80211_initiate_scan,
845 .policy = nl80211_policy,
846 .flags = GENL_ADMIN_PERM,
847 },
848 {
849 .cmd = NL80211_CMD_GET_ASSOCIATION,
850 .doit = nl80211_get_association,
851 .policy = nl80211_policy,
852 /* can be retrieved by unprivileged users */
853 },
854 {
855 .cmd = NL80211_CMD_ASSOCIATE,
856 .doit = nl80211_associate,
857 .policy = nl80211_policy,
858 .flags = GENL_ADMIN_PERM,
859 },
860 {
861 .cmd = NL80211_CMD_DISASSOCIATE,
862 .doit = nl80211_disassoc_deauth,
863 .policy = nl80211_policy,
864 .flags = GENL_ADMIN_PERM,
865 },
866 {
867 .cmd = NL80211_CMD_DEAUTH,
868 .doit = nl80211_disassoc_deauth,
869 .policy = nl80211_policy,
870 .flags = GENL_ADMIN_PERM,
871 },
872 {
873 .cmd = NL80211_CMD_GET_AUTH_LIST,
874 .doit = nl80211_get_auth_list,
875 .policy = nl80211_policy,
876 /* can be retrieved by unprivileged users */
877 },
878 /*
879 {
880 .cmd = NL80211_CMD_AP_SET_BEACON,
881 .policy = nl80211_policy,
882 .flags = GENL_ADMIN_PERM,
883 },
884 {
885 .cmd = NL80211_CMD_AP_ADD_STA,
886 .policy = nl80211_policy,
887 .flags = GENL_ADMIN_PERM,
888 },
889 {
890 .cmd = NL80211_CMD_AP_UPDATE_STA,
891 .policy = nl80211_policy,
892 .flags = GENL_ADMIN_PERM,
893 },
894 {
895 .cmd = NL80211_CMD_AP_GET_STA_INFO,
896 .policy = nl80211_policy,
897 .flags = GENL_ADMIN_PERM,
898 },
899 {
900 .cmd = NL80211_CMD_AP_SET_RATESETS,
901 .policy = nl80211_policy,
902 .flags = GENL_ADMIN_PERM,
903 },
904 */
905 {
906 .cmd = NL80211_CMD_ADD_KEY,
907 .doit = nl80211_key_cmd,
908 .policy = nl80211_policy,
909 .flags = GENL_ADMIN_PERM,
910 },
911 {
912 .cmd = NL80211_CMD_DEL_KEY,
913 .doit = nl80211_key_cmd,
914 .policy = nl80211_policy,
915 .flags = GENL_ADMIN_PERM,
916 },
917 };
918
919
920 /* exported functions */
921
922 void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, int flags, u8 cmd)
923 {
924 /* since there is no private header just add the generic one */
925 return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd);
926 }
927 EXPORT_SYMBOL_GPL(nl80211hdr_put);
928
929 void *nl80211msg_new(struct sk_buff **skb, u32 pid, u32 seq, int flags, u8 cmd)
930 {
931 void *hdr;
932
933 *skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
934 if (!*skb)
935 return ERR_PTR(-ENOBUFS);
936
937 hdr = nl80211hdr_put(*skb, pid, seq, flags, cmd);
938 if (!hdr) {
939 nlmsg_free(*skb);
940 return ERR_PTR(-ENOBUFS);
941 }
942
943 return hdr;
944 }
945 EXPORT_SYMBOL_GPL(nl80211msg_new);
946
947 /* notification functions */
948
949 void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
950 {
951 struct sk_buff *msg;
952 void *hdr;
953
954 hdr = nl80211msg_new(&msg, 0, 0, 0, NL80211_CMD_WIPHY_NEWNAME);
955 if (IS_ERR(hdr))
956 return;
957
958 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->idx);
959 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&rdev->wiphy));
960
961 genlmsg_end(msg, hdr);
962 genlmsg_multicast(msg, 0, NL80211_GROUP_CONFIG, GFP_KERNEL);
963
964 return;
965
966 nla_put_failure:
967 nlmsg_free(msg);
968 }
969
970 /* initialisation/exit functions */
971
972 int nl80211_init(void)
973 {
974 int err, i;
975
976 err = genl_register_family(&nl80211_fam);
977 if (err)
978 return err;
979
980 for (i = 0; i < ARRAY_SIZE(nl80211_ops); i++) {
981 err = genl_register_ops(&nl80211_fam, &nl80211_ops[i]);
982 if (err)
983 goto err_out;
984 }
985 return 0;
986 err_out:
987 genl_unregister_family(&nl80211_fam);
988 return err;
989 }
990
991 void nl80211_exit(void)
992 {
993 genl_unregister_family(&nl80211_fam);
994 }
This page took 0.093238 seconds and 5 git commands to generate.