New: mac80211 stack from the wireless-dev tree
[librecmc/librecmc.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 }