cfg80211/nl80211: add beacon settings
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / net / wireless / nl80211.c
CommitLineData
55682965
JB
1/*
2 * This is the new netlink-based wireless configuration interface.
3 *
4 * Copyright 2006, 2007 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 <linux/netlink.h>
17#include <net/genetlink.h>
18#include <net/cfg80211.h>
19#include "core.h"
20#include "nl80211.h"
21
22/* the netlink family */
23static struct genl_family nl80211_fam = {
24 .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */
25 .name = "nl80211", /* have users key off the name instead */
26 .hdrsize = 0, /* no private header */
27 .version = 1, /* no particular meaning now */
28 .maxattr = NL80211_ATTR_MAX,
29};
30
31/* internal helper: get drv and dev */
32static int get_drv_dev_by_info_ifindex(struct genl_info *info,
33 struct cfg80211_registered_device **drv,
34 struct net_device **dev)
35{
36 int ifindex;
37
38 if (!info->attrs[NL80211_ATTR_IFINDEX])
39 return -EINVAL;
40
41 ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
42 *dev = dev_get_by_index(&init_net, ifindex);
43 if (!*dev)
44 return -ENODEV;
45
46 *drv = cfg80211_get_dev_from_ifindex(ifindex);
47 if (IS_ERR(*drv)) {
48 dev_put(*dev);
49 return PTR_ERR(*drv);
50 }
51
52 return 0;
53}
54
55/* policy for the attributes */
56static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
57 [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
58 [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
59 .len = BUS_ID_SIZE-1 },
60
61 [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
62 [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
63 [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
41ade00f
JB
64
65 [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
66
67 [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
68 .len = WLAN_MAX_KEY_LEN },
69 [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
70 [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
71 [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
ed1b6cc7
JB
72
73 [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
74 [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
75 [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY,
76 .len = IEEE80211_MAX_DATA_LEN },
77 [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
78 .len = IEEE80211_MAX_DATA_LEN },
55682965
JB
79};
80
81/* message building helper */
82static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq,
83 int flags, u8 cmd)
84{
85 /* since there is no private header just add the generic one */
86 return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd);
87}
88
89/* netlink command implementations */
90
91static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
92 struct cfg80211_registered_device *dev)
93{
94 void *hdr;
95
96 hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
97 if (!hdr)
98 return -1;
99
100 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
101 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
102 return genlmsg_end(msg, hdr);
103
104 nla_put_failure:
105 return genlmsg_cancel(msg, hdr);
106}
107
108static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
109{
110 int idx = 0;
111 int start = cb->args[0];
112 struct cfg80211_registered_device *dev;
113
114 mutex_lock(&cfg80211_drv_mutex);
115 list_for_each_entry(dev, &cfg80211_drv_list, list) {
116 if (++idx < start)
117 continue;
118 if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid,
119 cb->nlh->nlmsg_seq, NLM_F_MULTI,
120 dev) < 0)
121 break;
122 }
123 mutex_unlock(&cfg80211_drv_mutex);
124
125 cb->args[0] = idx;
126
127 return skb->len;
128}
129
130static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
131{
132 struct sk_buff *msg;
133 struct cfg80211_registered_device *dev;
134
135 dev = cfg80211_get_dev_from_info(info);
136 if (IS_ERR(dev))
137 return PTR_ERR(dev);
138
139 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
140 if (!msg)
141 goto out_err;
142
143 if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0)
144 goto out_free;
145
146 cfg80211_put_dev(dev);
147
148 return genlmsg_unicast(msg, info->snd_pid);
149
150 out_free:
151 nlmsg_free(msg);
152 out_err:
153 cfg80211_put_dev(dev);
154 return -ENOBUFS;
155}
156
157static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
158{
159 struct cfg80211_registered_device *rdev;
160 int result;
161
162 if (!info->attrs[NL80211_ATTR_WIPHY_NAME])
163 return -EINVAL;
164
165 rdev = cfg80211_get_dev_from_info(info);
166 if (IS_ERR(rdev))
167 return PTR_ERR(rdev);
168
169 result = cfg80211_dev_rename(rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
170
171 cfg80211_put_dev(rdev);
172 return result;
173}
174
175
176static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
177 struct net_device *dev)
178{
179 void *hdr;
180
181 hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE);
182 if (!hdr)
183 return -1;
184
185 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
186 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name);
187 /* TODO: interface type */
188 return genlmsg_end(msg, hdr);
189
190 nla_put_failure:
191 return genlmsg_cancel(msg, hdr);
192}
193
194static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
195{
196 int wp_idx = 0;
197 int if_idx = 0;
198 int wp_start = cb->args[0];
199 int if_start = cb->args[1];
200 struct cfg80211_registered_device *dev;
201 struct wireless_dev *wdev;
202
203 mutex_lock(&cfg80211_drv_mutex);
204 list_for_each_entry(dev, &cfg80211_drv_list, list) {
205 if (++wp_idx < wp_start)
206 continue;
207 if_idx = 0;
208
209 mutex_lock(&dev->devlist_mtx);
210 list_for_each_entry(wdev, &dev->netdev_list, list) {
211 if (++if_idx < if_start)
212 continue;
213 if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid,
214 cb->nlh->nlmsg_seq, NLM_F_MULTI,
215 wdev->netdev) < 0)
216 break;
217 }
218 mutex_unlock(&dev->devlist_mtx);
219 }
220 mutex_unlock(&cfg80211_drv_mutex);
221
222 cb->args[0] = wp_idx;
223 cb->args[1] = if_idx;
224
225 return skb->len;
226}
227
228static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
229{
230 struct sk_buff *msg;
231 struct cfg80211_registered_device *dev;
232 struct net_device *netdev;
233 int err;
234
235 err = get_drv_dev_by_info_ifindex(info, &dev, &netdev);
236 if (err)
237 return err;
238
239 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
240 if (!msg)
241 goto out_err;
242
243 if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, netdev) < 0)
244 goto out_free;
245
246 dev_put(netdev);
247 cfg80211_put_dev(dev);
248
249 return genlmsg_unicast(msg, info->snd_pid);
250
251 out_free:
252 nlmsg_free(msg);
253 out_err:
254 dev_put(netdev);
255 cfg80211_put_dev(dev);
256 return -ENOBUFS;
257}
258
259static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
260{
261 struct cfg80211_registered_device *drv;
262 int err, ifindex;
263 enum nl80211_iftype type;
264 struct net_device *dev;
265
266 if (info->attrs[NL80211_ATTR_IFTYPE]) {
267 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
268 if (type > NL80211_IFTYPE_MAX)
269 return -EINVAL;
270 } else
271 return -EINVAL;
272
273 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
274 if (err)
275 return err;
276 ifindex = dev->ifindex;
277 dev_put(dev);
278
279 if (!drv->ops->change_virtual_intf) {
280 err = -EOPNOTSUPP;
281 goto unlock;
282 }
283
284 rtnl_lock();
285 err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, type);
286 rtnl_unlock();
287
288 unlock:
289 cfg80211_put_dev(drv);
290 return err;
291}
292
293static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
294{
295 struct cfg80211_registered_device *drv;
296 int err;
297 enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
298
299 if (!info->attrs[NL80211_ATTR_IFNAME])
300 return -EINVAL;
301
302 if (info->attrs[NL80211_ATTR_IFTYPE]) {
303 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
304 if (type > NL80211_IFTYPE_MAX)
305 return -EINVAL;
306 }
307
308 drv = cfg80211_get_dev_from_info(info);
309 if (IS_ERR(drv))
310 return PTR_ERR(drv);
311
312 if (!drv->ops->add_virtual_intf) {
313 err = -EOPNOTSUPP;
314 goto unlock;
315 }
316
317 rtnl_lock();
318 err = drv->ops->add_virtual_intf(&drv->wiphy,
319 nla_data(info->attrs[NL80211_ATTR_IFNAME]), type);
320 rtnl_unlock();
321
322 unlock:
323 cfg80211_put_dev(drv);
324 return err;
325}
326
327static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
328{
329 struct cfg80211_registered_device *drv;
330 int ifindex, err;
331 struct net_device *dev;
332
333 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
334 if (err)
335 return err;
336 ifindex = dev->ifindex;
337 dev_put(dev);
338
339 if (!drv->ops->del_virtual_intf) {
340 err = -EOPNOTSUPP;
341 goto out;
342 }
343
344 rtnl_lock();
345 err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex);
346 rtnl_unlock();
347
348 out:
349 cfg80211_put_dev(drv);
350 return err;
351}
352
41ade00f
JB
353struct get_key_cookie {
354 struct sk_buff *msg;
355 int error;
356};
357
358static void get_key_callback(void *c, struct key_params *params)
359{
360 struct get_key_cookie *cookie = c;
361
362 if (params->key)
363 NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA,
364 params->key_len, params->key);
365
366 if (params->seq)
367 NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ,
368 params->seq_len, params->seq);
369
370 if (params->cipher)
371 NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
372 params->cipher);
373
374 return;
375 nla_put_failure:
376 cookie->error = 1;
377}
378
379static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
380{
381 struct cfg80211_registered_device *drv;
382 int err;
383 struct net_device *dev;
384 u8 key_idx = 0;
385 u8 *mac_addr = NULL;
386 struct get_key_cookie cookie = {
387 .error = 0,
388 };
389 void *hdr;
390 struct sk_buff *msg;
391
392 if (info->attrs[NL80211_ATTR_KEY_IDX])
393 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
394
395 if (key_idx > 3)
396 return -EINVAL;
397
398 if (info->attrs[NL80211_ATTR_MAC])
399 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
400
401 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
402 if (err)
403 return err;
404
405 if (!drv->ops->get_key) {
406 err = -EOPNOTSUPP;
407 goto out;
408 }
409
410 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
411 if (!msg) {
412 err = -ENOMEM;
413 goto out;
414 }
415
416 hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
417 NL80211_CMD_NEW_KEY);
418
419 if (IS_ERR(hdr)) {
420 err = PTR_ERR(hdr);
421 goto out;
422 }
423
424 cookie.msg = msg;
425
426 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
427 NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
428 if (mac_addr)
429 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
430
431 rtnl_lock();
432 err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr,
433 &cookie, get_key_callback);
434 rtnl_unlock();
435
436 if (err)
437 goto out;
438
439 if (cookie.error)
440 goto nla_put_failure;
441
442 genlmsg_end(msg, hdr);
443 err = genlmsg_unicast(msg, info->snd_pid);
444 goto out;
445
446 nla_put_failure:
447 err = -ENOBUFS;
448 nlmsg_free(msg);
449 out:
450 cfg80211_put_dev(drv);
451 dev_put(dev);
452 return err;
453}
454
455static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
456{
457 struct cfg80211_registered_device *drv;
458 int err;
459 struct net_device *dev;
460 u8 key_idx;
461
462 if (!info->attrs[NL80211_ATTR_KEY_IDX])
463 return -EINVAL;
464
465 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
466
467 if (key_idx > 3)
468 return -EINVAL;
469
470 /* currently only support setting default key */
471 if (!info->attrs[NL80211_ATTR_KEY_DEFAULT])
472 return -EINVAL;
473
474 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
475 if (err)
476 return err;
477
478 if (!drv->ops->set_default_key) {
479 err = -EOPNOTSUPP;
480 goto out;
481 }
482
483 rtnl_lock();
484 err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx);
485 rtnl_unlock();
486
487 out:
488 cfg80211_put_dev(drv);
489 dev_put(dev);
490 return err;
491}
492
493static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
494{
495 struct cfg80211_registered_device *drv;
496 int err;
497 struct net_device *dev;
498 struct key_params params;
499 u8 key_idx = 0;
500 u8 *mac_addr = NULL;
501
502 memset(&params, 0, sizeof(params));
503
504 if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
505 return -EINVAL;
506
507 if (info->attrs[NL80211_ATTR_KEY_DATA]) {
508 params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
509 params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
510 }
511
512 if (info->attrs[NL80211_ATTR_KEY_IDX])
513 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
514
515 params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
516
517 if (info->attrs[NL80211_ATTR_MAC])
518 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
519
520 if (key_idx > 3)
521 return -EINVAL;
522
523 /*
524 * Disallow pairwise keys with non-zero index unless it's WEP
525 * (because current deployments use pairwise WEP keys with
526 * non-zero indizes but 802.11i clearly specifies to use zero)
527 */
528 if (mac_addr && key_idx &&
529 params.cipher != WLAN_CIPHER_SUITE_WEP40 &&
530 params.cipher != WLAN_CIPHER_SUITE_WEP104)
531 return -EINVAL;
532
533 /* TODO: add definitions for the lengths to linux/ieee80211.h */
534 switch (params.cipher) {
535 case WLAN_CIPHER_SUITE_WEP40:
536 if (params.key_len != 5)
537 return -EINVAL;
538 break;
539 case WLAN_CIPHER_SUITE_TKIP:
540 if (params.key_len != 32)
541 return -EINVAL;
542 break;
543 case WLAN_CIPHER_SUITE_CCMP:
544 if (params.key_len != 16)
545 return -EINVAL;
546 break;
547 case WLAN_CIPHER_SUITE_WEP104:
548 if (params.key_len != 13)
549 return -EINVAL;
550 break;
551 default:
552 return -EINVAL;
553 }
554
555 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
556 if (err)
557 return err;
558
559 if (!drv->ops->add_key) {
560 err = -EOPNOTSUPP;
561 goto out;
562 }
563
564 rtnl_lock();
565 err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, &params);
566 rtnl_unlock();
567
568 out:
569 cfg80211_put_dev(drv);
570 dev_put(dev);
571 return err;
572}
573
574static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
575{
576 struct cfg80211_registered_device *drv;
577 int err;
578 struct net_device *dev;
579 u8 key_idx = 0;
580 u8 *mac_addr = NULL;
581
582 if (info->attrs[NL80211_ATTR_KEY_IDX])
583 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
584
585 if (key_idx > 3)
586 return -EINVAL;
587
588 if (info->attrs[NL80211_ATTR_MAC])
589 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
590
591 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
592 if (err)
593 return err;
594
595 if (!drv->ops->del_key) {
596 err = -EOPNOTSUPP;
597 goto out;
598 }
599
600 rtnl_lock();
601 err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
602 rtnl_unlock();
603
604 out:
605 cfg80211_put_dev(drv);
606 dev_put(dev);
607 return err;
608}
609
ed1b6cc7
JB
610static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
611{
612 int (*call)(struct wiphy *wiphy, struct net_device *dev,
613 struct beacon_parameters *info);
614 struct cfg80211_registered_device *drv;
615 int err;
616 struct net_device *dev;
617 struct beacon_parameters params;
618 int haveinfo = 0;
619
620 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
621 if (err)
622 return err;
623
624 switch (info->genlhdr->cmd) {
625 case NL80211_CMD_NEW_BEACON:
626 /* these are required for NEW_BEACON */
627 if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
628 !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
629 !info->attrs[NL80211_ATTR_BEACON_HEAD]) {
630 err = -EINVAL;
631 goto out;
632 }
633
634 call = drv->ops->add_beacon;
635 break;
636 case NL80211_CMD_SET_BEACON:
637 call = drv->ops->set_beacon;
638 break;
639 default:
640 WARN_ON(1);
641 err = -EOPNOTSUPP;
642 goto out;
643 }
644
645 if (!call) {
646 err = -EOPNOTSUPP;
647 goto out;
648 }
649
650 memset(&params, 0, sizeof(params));
651
652 if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
653 params.interval =
654 nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
655 haveinfo = 1;
656 }
657
658 if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
659 params.dtim_period =
660 nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
661 haveinfo = 1;
662 }
663
664 if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
665 params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
666 params.head_len =
667 nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
668 haveinfo = 1;
669 }
670
671 if (info->attrs[NL80211_ATTR_BEACON_TAIL]) {
672 params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
673 params.tail_len =
674 nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]);
675 haveinfo = 1;
676 }
677
678 if (!haveinfo) {
679 err = -EINVAL;
680 goto out;
681 }
682
683 rtnl_lock();
684 err = call(&drv->wiphy, dev, &params);
685 rtnl_unlock();
686
687 out:
688 cfg80211_put_dev(drv);
689 dev_put(dev);
690 return err;
691}
692
693static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
694{
695 struct cfg80211_registered_device *drv;
696 int err;
697 struct net_device *dev;
698
699 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
700 if (err)
701 return err;
702
703 if (!drv->ops->del_beacon) {
704 err = -EOPNOTSUPP;
705 goto out;
706 }
707
708 rtnl_lock();
709 err = drv->ops->del_beacon(&drv->wiphy, dev);
710 rtnl_unlock();
711
712 out:
713 cfg80211_put_dev(drv);
714 dev_put(dev);
715 return err;
716}
717
55682965
JB
718static struct genl_ops nl80211_ops[] = {
719 {
720 .cmd = NL80211_CMD_GET_WIPHY,
721 .doit = nl80211_get_wiphy,
722 .dumpit = nl80211_dump_wiphy,
723 .policy = nl80211_policy,
724 /* can be retrieved by unprivileged users */
725 },
726 {
727 .cmd = NL80211_CMD_SET_WIPHY,
728 .doit = nl80211_set_wiphy,
729 .policy = nl80211_policy,
730 .flags = GENL_ADMIN_PERM,
731 },
732 {
733 .cmd = NL80211_CMD_GET_INTERFACE,
734 .doit = nl80211_get_interface,
735 .dumpit = nl80211_dump_interface,
736 .policy = nl80211_policy,
737 /* can be retrieved by unprivileged users */
738 },
739 {
740 .cmd = NL80211_CMD_SET_INTERFACE,
741 .doit = nl80211_set_interface,
742 .policy = nl80211_policy,
743 .flags = GENL_ADMIN_PERM,
744 },
745 {
746 .cmd = NL80211_CMD_NEW_INTERFACE,
747 .doit = nl80211_new_interface,
748 .policy = nl80211_policy,
749 .flags = GENL_ADMIN_PERM,
750 },
751 {
752 .cmd = NL80211_CMD_DEL_INTERFACE,
753 .doit = nl80211_del_interface,
754 .policy = nl80211_policy,
41ade00f
JB
755 .flags = GENL_ADMIN_PERM,
756 },
757 {
758 .cmd = NL80211_CMD_GET_KEY,
759 .doit = nl80211_get_key,
760 .policy = nl80211_policy,
761 .flags = GENL_ADMIN_PERM,
762 },
763 {
764 .cmd = NL80211_CMD_SET_KEY,
765 .doit = nl80211_set_key,
766 .policy = nl80211_policy,
767 .flags = GENL_ADMIN_PERM,
768 },
769 {
770 .cmd = NL80211_CMD_NEW_KEY,
771 .doit = nl80211_new_key,
772 .policy = nl80211_policy,
773 .flags = GENL_ADMIN_PERM,
774 },
775 {
776 .cmd = NL80211_CMD_DEL_KEY,
777 .doit = nl80211_del_key,
778 .policy = nl80211_policy,
55682965
JB
779 .flags = GENL_ADMIN_PERM,
780 },
ed1b6cc7
JB
781 {
782 .cmd = NL80211_CMD_SET_BEACON,
783 .policy = nl80211_policy,
784 .flags = GENL_ADMIN_PERM,
785 .doit = nl80211_addset_beacon,
786 },
787 {
788 .cmd = NL80211_CMD_NEW_BEACON,
789 .policy = nl80211_policy,
790 .flags = GENL_ADMIN_PERM,
791 .doit = nl80211_addset_beacon,
792 },
793 {
794 .cmd = NL80211_CMD_DEL_BEACON,
795 .policy = nl80211_policy,
796 .flags = GENL_ADMIN_PERM,
797 .doit = nl80211_del_beacon,
798 },
55682965
JB
799};
800
801/* multicast groups */
802static struct genl_multicast_group nl80211_config_mcgrp = {
803 .name = "config",
804};
805
806/* notification functions */
807
808void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
809{
810 struct sk_buff *msg;
811
812 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
813 if (!msg)
814 return;
815
816 if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) {
817 nlmsg_free(msg);
818 return;
819 }
820
821 genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL);
822}
823
824/* initialisation/exit functions */
825
826int nl80211_init(void)
827{
828 int err, i;
829
830 err = genl_register_family(&nl80211_fam);
831 if (err)
832 return err;
833
834 for (i = 0; i < ARRAY_SIZE(nl80211_ops); i++) {
835 err = genl_register_ops(&nl80211_fam, &nl80211_ops[i]);
836 if (err)
837 goto err_out;
838 }
839
840 err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp);
841 if (err)
842 goto err_out;
843
844 return 0;
845 err_out:
846 genl_unregister_family(&nl80211_fam);
847 return err;
848}
849
850void nl80211_exit(void)
851{
852 genl_unregister_family(&nl80211_fam);
853}