]> Pileus Git - ~andy/linux/blob - net/wireless/nl80211.c
mac80211/cfg80211: Add BSS configuration options for AP mode
[~andy/linux] / net / wireless / nl80211.c
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 */
23 static 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 */
32 static int get_drv_dev_by_info_ifindex(struct nlattr **attrs,
33                                        struct cfg80211_registered_device **drv,
34                                        struct net_device **dev)
35 {
36         int ifindex;
37
38         if (!attrs[NL80211_ATTR_IFINDEX])
39                 return -EINVAL;
40
41         ifindex = nla_get_u32(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 */
56 static 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 },
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 },
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 },
79         [NL80211_ATTR_STA_AID] = { .type = NLA_U16 },
80         [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED },
81         [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
82         [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
83                                                .len = NL80211_MAX_SUPP_RATES },
84         [NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 },
85         [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
86         [NL80211_ATTR_MNTR_FLAGS] = { .type = NLA_NESTED },
87         [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
88                                 .len = IEEE80211_MAX_MESH_ID_LEN },
89         [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 },
90
91         [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 },
92         [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 },
93         [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 },
94 };
95
96 /* message building helper */
97 static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq,
98                                    int flags, u8 cmd)
99 {
100         /* since there is no private header just add the generic one */
101         return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd);
102 }
103
104 /* netlink command implementations */
105
106 static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
107                               struct cfg80211_registered_device *dev)
108 {
109         void *hdr;
110         struct nlattr *nl_bands, *nl_band;
111         struct nlattr *nl_freqs, *nl_freq;
112         struct nlattr *nl_rates, *nl_rate;
113         enum ieee80211_band band;
114         struct ieee80211_channel *chan;
115         struct ieee80211_rate *rate;
116         int i;
117
118         hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
119         if (!hdr)
120                 return -1;
121
122         NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
123         NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
124
125         nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
126         if (!nl_bands)
127                 goto nla_put_failure;
128
129         for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
130                 if (!dev->wiphy.bands[band])
131                         continue;
132
133                 nl_band = nla_nest_start(msg, band);
134                 if (!nl_band)
135                         goto nla_put_failure;
136
137                 /* add frequencies */
138                 nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS);
139                 if (!nl_freqs)
140                         goto nla_put_failure;
141
142                 for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) {
143                         nl_freq = nla_nest_start(msg, i);
144                         if (!nl_freq)
145                                 goto nla_put_failure;
146
147                         chan = &dev->wiphy.bands[band]->channels[i];
148                         NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ,
149                                     chan->center_freq);
150
151                         if (chan->flags & IEEE80211_CHAN_DISABLED)
152                                 NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED);
153                         if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
154                                 NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN);
155                         if (chan->flags & IEEE80211_CHAN_NO_IBSS)
156                                 NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS);
157                         if (chan->flags & IEEE80211_CHAN_RADAR)
158                                 NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR);
159
160                         nla_nest_end(msg, nl_freq);
161                 }
162
163                 nla_nest_end(msg, nl_freqs);
164
165                 /* add bitrates */
166                 nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
167                 if (!nl_rates)
168                         goto nla_put_failure;
169
170                 for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) {
171                         nl_rate = nla_nest_start(msg, i);
172                         if (!nl_rate)
173                                 goto nla_put_failure;
174
175                         rate = &dev->wiphy.bands[band]->bitrates[i];
176                         NLA_PUT_U32(msg, NL80211_BITRATE_ATTR_RATE,
177                                     rate->bitrate);
178                         if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
179                                 NLA_PUT_FLAG(msg,
180                                         NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE);
181
182                         nla_nest_end(msg, nl_rate);
183                 }
184
185                 nla_nest_end(msg, nl_rates);
186
187                 nla_nest_end(msg, nl_band);
188         }
189         nla_nest_end(msg, nl_bands);
190
191         return genlmsg_end(msg, hdr);
192
193  nla_put_failure:
194         genlmsg_cancel(msg, hdr);
195         return -EMSGSIZE;
196 }
197
198 static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
199 {
200         int idx = 0;
201         int start = cb->args[0];
202         struct cfg80211_registered_device *dev;
203
204         mutex_lock(&cfg80211_drv_mutex);
205         list_for_each_entry(dev, &cfg80211_drv_list, list) {
206                 if (++idx <= start)
207                         continue;
208                 if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid,
209                                        cb->nlh->nlmsg_seq, NLM_F_MULTI,
210                                        dev) < 0) {
211                         idx--;
212                         break;
213                 }
214         }
215         mutex_unlock(&cfg80211_drv_mutex);
216
217         cb->args[0] = idx;
218
219         return skb->len;
220 }
221
222 static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
223 {
224         struct sk_buff *msg;
225         struct cfg80211_registered_device *dev;
226
227         dev = cfg80211_get_dev_from_info(info);
228         if (IS_ERR(dev))
229                 return PTR_ERR(dev);
230
231         msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
232         if (!msg)
233                 goto out_err;
234
235         if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0)
236                 goto out_free;
237
238         cfg80211_put_dev(dev);
239
240         return genlmsg_unicast(msg, info->snd_pid);
241
242  out_free:
243         nlmsg_free(msg);
244  out_err:
245         cfg80211_put_dev(dev);
246         return -ENOBUFS;
247 }
248
249 static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
250 {
251         struct cfg80211_registered_device *rdev;
252         int result;
253
254         if (!info->attrs[NL80211_ATTR_WIPHY_NAME])
255                 return -EINVAL;
256
257         rdev = cfg80211_get_dev_from_info(info);
258         if (IS_ERR(rdev))
259                 return PTR_ERR(rdev);
260
261         result = cfg80211_dev_rename(rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
262
263         cfg80211_put_dev(rdev);
264         return result;
265 }
266
267
268 static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
269                               struct net_device *dev)
270 {
271         void *hdr;
272
273         hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE);
274         if (!hdr)
275                 return -1;
276
277         NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
278         NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name);
279         /* TODO: interface type */
280         return genlmsg_end(msg, hdr);
281
282  nla_put_failure:
283         genlmsg_cancel(msg, hdr);
284         return -EMSGSIZE;
285 }
286
287 static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
288 {
289         int wp_idx = 0;
290         int if_idx = 0;
291         int wp_start = cb->args[0];
292         int if_start = cb->args[1];
293         struct cfg80211_registered_device *dev;
294         struct wireless_dev *wdev;
295
296         mutex_lock(&cfg80211_drv_mutex);
297         list_for_each_entry(dev, &cfg80211_drv_list, list) {
298                 if (wp_idx < wp_start) {
299                         wp_idx++;
300                         continue;
301                 }
302                 if_idx = 0;
303
304                 mutex_lock(&dev->devlist_mtx);
305                 list_for_each_entry(wdev, &dev->netdev_list, list) {
306                         if (if_idx < if_start) {
307                                 if_idx++;
308                                 continue;
309                         }
310                         if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid,
311                                                cb->nlh->nlmsg_seq, NLM_F_MULTI,
312                                                wdev->netdev) < 0) {
313                                 mutex_unlock(&dev->devlist_mtx);
314                                 goto out;
315                         }
316                         if_idx++;
317                 }
318                 mutex_unlock(&dev->devlist_mtx);
319
320                 wp_idx++;
321         }
322  out:
323         mutex_unlock(&cfg80211_drv_mutex);
324
325         cb->args[0] = wp_idx;
326         cb->args[1] = if_idx;
327
328         return skb->len;
329 }
330
331 static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
332 {
333         struct sk_buff *msg;
334         struct cfg80211_registered_device *dev;
335         struct net_device *netdev;
336         int err;
337
338         err = get_drv_dev_by_info_ifindex(info->attrs, &dev, &netdev);
339         if (err)
340                 return err;
341
342         msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
343         if (!msg)
344                 goto out_err;
345
346         if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, netdev) < 0)
347                 goto out_free;
348
349         dev_put(netdev);
350         cfg80211_put_dev(dev);
351
352         return genlmsg_unicast(msg, info->snd_pid);
353
354  out_free:
355         nlmsg_free(msg);
356  out_err:
357         dev_put(netdev);
358         cfg80211_put_dev(dev);
359         return -ENOBUFS;
360 }
361
362 static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
363         [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG },
364         [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG },
365         [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
366         [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
367         [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
368 };
369
370 static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
371 {
372         struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1];
373         int flag;
374
375         *mntrflags = 0;
376
377         if (!nla)
378                 return -EINVAL;
379
380         if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX,
381                              nla, mntr_flags_policy))
382                 return -EINVAL;
383
384         for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++)
385                 if (flags[flag])
386                         *mntrflags |= (1<<flag);
387
388         return 0;
389 }
390
391 static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
392 {
393         struct cfg80211_registered_device *drv;
394         struct vif_params params;
395         int err, ifindex;
396         enum nl80211_iftype type;
397         struct net_device *dev;
398         u32 flags;
399
400         memset(&params, 0, sizeof(params));
401
402         if (info->attrs[NL80211_ATTR_IFTYPE]) {
403                 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
404                 if (type > NL80211_IFTYPE_MAX)
405                         return -EINVAL;
406         } else
407                 return -EINVAL;
408
409         err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
410         if (err)
411                 return err;
412         ifindex = dev->ifindex;
413         dev_put(dev);
414
415         if (!drv->ops->change_virtual_intf) {
416                 err = -EOPNOTSUPP;
417                 goto unlock;
418         }
419
420         if (type == NL80211_IFTYPE_MESH_POINT &&
421             info->attrs[NL80211_ATTR_MESH_ID]) {
422                 params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
423                 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
424         }
425
426         rtnl_lock();
427         err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
428                                   info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
429                                   &flags);
430         err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
431                                             type, err ? NULL : &flags, &params);
432         rtnl_unlock();
433
434  unlock:
435         cfg80211_put_dev(drv);
436         return err;
437 }
438
439 static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
440 {
441         struct cfg80211_registered_device *drv;
442         struct vif_params params;
443         int err;
444         enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
445         u32 flags;
446
447         memset(&params, 0, sizeof(params));
448
449         if (!info->attrs[NL80211_ATTR_IFNAME])
450                 return -EINVAL;
451
452         if (info->attrs[NL80211_ATTR_IFTYPE]) {
453                 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
454                 if (type > NL80211_IFTYPE_MAX)
455                         return -EINVAL;
456         }
457
458         drv = cfg80211_get_dev_from_info(info);
459         if (IS_ERR(drv))
460                 return PTR_ERR(drv);
461
462         if (!drv->ops->add_virtual_intf) {
463                 err = -EOPNOTSUPP;
464                 goto unlock;
465         }
466
467         if (type == NL80211_IFTYPE_MESH_POINT &&
468             info->attrs[NL80211_ATTR_MESH_ID]) {
469                 params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
470                 params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
471         }
472
473         rtnl_lock();
474         err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
475                                   info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
476                                   &flags);
477         err = drv->ops->add_virtual_intf(&drv->wiphy,
478                 nla_data(info->attrs[NL80211_ATTR_IFNAME]),
479                 type, err ? NULL : &flags, &params);
480         rtnl_unlock();
481
482
483  unlock:
484         cfg80211_put_dev(drv);
485         return err;
486 }
487
488 static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
489 {
490         struct cfg80211_registered_device *drv;
491         int ifindex, err;
492         struct net_device *dev;
493
494         err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
495         if (err)
496                 return err;
497         ifindex = dev->ifindex;
498         dev_put(dev);
499
500         if (!drv->ops->del_virtual_intf) {
501                 err = -EOPNOTSUPP;
502                 goto out;
503         }
504
505         rtnl_lock();
506         err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex);
507         rtnl_unlock();
508
509  out:
510         cfg80211_put_dev(drv);
511         return err;
512 }
513
514 struct get_key_cookie {
515         struct sk_buff *msg;
516         int error;
517 };
518
519 static void get_key_callback(void *c, struct key_params *params)
520 {
521         struct get_key_cookie *cookie = c;
522
523         if (params->key)
524                 NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA,
525                         params->key_len, params->key);
526
527         if (params->seq)
528                 NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ,
529                         params->seq_len, params->seq);
530
531         if (params->cipher)
532                 NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
533                             params->cipher);
534
535         return;
536  nla_put_failure:
537         cookie->error = 1;
538 }
539
540 static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
541 {
542         struct cfg80211_registered_device *drv;
543         int err;
544         struct net_device *dev;
545         u8 key_idx = 0;
546         u8 *mac_addr = NULL;
547         struct get_key_cookie cookie = {
548                 .error = 0,
549         };
550         void *hdr;
551         struct sk_buff *msg;
552
553         if (info->attrs[NL80211_ATTR_KEY_IDX])
554                 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
555
556         if (key_idx > 3)
557                 return -EINVAL;
558
559         if (info->attrs[NL80211_ATTR_MAC])
560                 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
561
562         err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
563         if (err)
564                 return err;
565
566         if (!drv->ops->get_key) {
567                 err = -EOPNOTSUPP;
568                 goto out;
569         }
570
571         msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
572         if (!msg) {
573                 err = -ENOMEM;
574                 goto out;
575         }
576
577         hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
578                              NL80211_CMD_NEW_KEY);
579
580         if (IS_ERR(hdr)) {
581                 err = PTR_ERR(hdr);
582                 goto out;
583         }
584
585         cookie.msg = msg;
586
587         NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
588         NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
589         if (mac_addr)
590                 NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
591
592         rtnl_lock();
593         err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr,
594                                 &cookie, get_key_callback);
595         rtnl_unlock();
596
597         if (err)
598                 goto out;
599
600         if (cookie.error)
601                 goto nla_put_failure;
602
603         genlmsg_end(msg, hdr);
604         err = genlmsg_unicast(msg, info->snd_pid);
605         goto out;
606
607  nla_put_failure:
608         err = -ENOBUFS;
609         nlmsg_free(msg);
610  out:
611         cfg80211_put_dev(drv);
612         dev_put(dev);
613         return err;
614 }
615
616 static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
617 {
618         struct cfg80211_registered_device *drv;
619         int err;
620         struct net_device *dev;
621         u8 key_idx;
622
623         if (!info->attrs[NL80211_ATTR_KEY_IDX])
624                 return -EINVAL;
625
626         key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
627
628         if (key_idx > 3)
629                 return -EINVAL;
630
631         /* currently only support setting default key */
632         if (!info->attrs[NL80211_ATTR_KEY_DEFAULT])
633                 return -EINVAL;
634
635         err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
636         if (err)
637                 return err;
638
639         if (!drv->ops->set_default_key) {
640                 err = -EOPNOTSUPP;
641                 goto out;
642         }
643
644         rtnl_lock();
645         err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx);
646         rtnl_unlock();
647
648  out:
649         cfg80211_put_dev(drv);
650         dev_put(dev);
651         return err;
652 }
653
654 static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
655 {
656         struct cfg80211_registered_device *drv;
657         int err;
658         struct net_device *dev;
659         struct key_params params;
660         u8 key_idx = 0;
661         u8 *mac_addr = NULL;
662
663         memset(&params, 0, sizeof(params));
664
665         if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
666                 return -EINVAL;
667
668         if (info->attrs[NL80211_ATTR_KEY_DATA]) {
669                 params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
670                 params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
671         }
672
673         if (info->attrs[NL80211_ATTR_KEY_IDX])
674                 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
675
676         params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
677
678         if (info->attrs[NL80211_ATTR_MAC])
679                 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
680
681         if (key_idx > 3)
682                 return -EINVAL;
683
684         /*
685          * Disallow pairwise keys with non-zero index unless it's WEP
686          * (because current deployments use pairwise WEP keys with
687          * non-zero indizes but 802.11i clearly specifies to use zero)
688          */
689         if (mac_addr && key_idx &&
690             params.cipher != WLAN_CIPHER_SUITE_WEP40 &&
691             params.cipher != WLAN_CIPHER_SUITE_WEP104)
692                 return -EINVAL;
693
694         /* TODO: add definitions for the lengths to linux/ieee80211.h */
695         switch (params.cipher) {
696         case WLAN_CIPHER_SUITE_WEP40:
697                 if (params.key_len != 5)
698                         return -EINVAL;
699                 break;
700         case WLAN_CIPHER_SUITE_TKIP:
701                 if (params.key_len != 32)
702                         return -EINVAL;
703                 break;
704         case WLAN_CIPHER_SUITE_CCMP:
705                 if (params.key_len != 16)
706                         return -EINVAL;
707                 break;
708         case WLAN_CIPHER_SUITE_WEP104:
709                 if (params.key_len != 13)
710                         return -EINVAL;
711                 break;
712         default:
713                 return -EINVAL;
714         }
715
716         err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
717         if (err)
718                 return err;
719
720         if (!drv->ops->add_key) {
721                 err = -EOPNOTSUPP;
722                 goto out;
723         }
724
725         rtnl_lock();
726         err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, &params);
727         rtnl_unlock();
728
729  out:
730         cfg80211_put_dev(drv);
731         dev_put(dev);
732         return err;
733 }
734
735 static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
736 {
737         struct cfg80211_registered_device *drv;
738         int err;
739         struct net_device *dev;
740         u8 key_idx = 0;
741         u8 *mac_addr = NULL;
742
743         if (info->attrs[NL80211_ATTR_KEY_IDX])
744                 key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
745
746         if (key_idx > 3)
747                 return -EINVAL;
748
749         if (info->attrs[NL80211_ATTR_MAC])
750                 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
751
752         err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
753         if (err)
754                 return err;
755
756         if (!drv->ops->del_key) {
757                 err = -EOPNOTSUPP;
758                 goto out;
759         }
760
761         rtnl_lock();
762         err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
763         rtnl_unlock();
764
765  out:
766         cfg80211_put_dev(drv);
767         dev_put(dev);
768         return err;
769 }
770
771 static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
772 {
773         int (*call)(struct wiphy *wiphy, struct net_device *dev,
774                     struct beacon_parameters *info);
775         struct cfg80211_registered_device *drv;
776         int err;
777         struct net_device *dev;
778         struct beacon_parameters params;
779         int haveinfo = 0;
780
781         err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
782         if (err)
783                 return err;
784
785         switch (info->genlhdr->cmd) {
786         case NL80211_CMD_NEW_BEACON:
787                 /* these are required for NEW_BEACON */
788                 if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
789                     !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
790                     !info->attrs[NL80211_ATTR_BEACON_HEAD]) {
791                         err = -EINVAL;
792                         goto out;
793                 }
794
795                 call = drv->ops->add_beacon;
796                 break;
797         case NL80211_CMD_SET_BEACON:
798                 call = drv->ops->set_beacon;
799                 break;
800         default:
801                 WARN_ON(1);
802                 err = -EOPNOTSUPP;
803                 goto out;
804         }
805
806         if (!call) {
807                 err = -EOPNOTSUPP;
808                 goto out;
809         }
810
811         memset(&params, 0, sizeof(params));
812
813         if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
814                 params.interval =
815                     nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
816                 haveinfo = 1;
817         }
818
819         if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
820                 params.dtim_period =
821                     nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
822                 haveinfo = 1;
823         }
824
825         if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
826                 params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
827                 params.head_len =
828                     nla_len(info->attrs[NL80211_ATTR_BEACON_HEAD]);
829                 haveinfo = 1;
830         }
831
832         if (info->attrs[NL80211_ATTR_BEACON_TAIL]) {
833                 params.tail = nla_data(info->attrs[NL80211_ATTR_BEACON_TAIL]);
834                 params.tail_len =
835                     nla_len(info->attrs[NL80211_ATTR_BEACON_TAIL]);
836                 haveinfo = 1;
837         }
838
839         if (!haveinfo) {
840                 err = -EINVAL;
841                 goto out;
842         }
843
844         rtnl_lock();
845         err = call(&drv->wiphy, dev, &params);
846         rtnl_unlock();
847
848  out:
849         cfg80211_put_dev(drv);
850         dev_put(dev);
851         return err;
852 }
853
854 static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
855 {
856         struct cfg80211_registered_device *drv;
857         int err;
858         struct net_device *dev;
859
860         err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
861         if (err)
862                 return err;
863
864         if (!drv->ops->del_beacon) {
865                 err = -EOPNOTSUPP;
866                 goto out;
867         }
868
869         rtnl_lock();
870         err = drv->ops->del_beacon(&drv->wiphy, dev);
871         rtnl_unlock();
872
873  out:
874         cfg80211_put_dev(drv);
875         dev_put(dev);
876         return err;
877 }
878
879 static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
880         [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
881         [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
882         [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
883 };
884
885 static int parse_station_flags(struct nlattr *nla, u32 *staflags)
886 {
887         struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
888         int flag;
889
890         *staflags = 0;
891
892         if (!nla)
893                 return 0;
894
895         if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX,
896                              nla, sta_flags_policy))
897                 return -EINVAL;
898
899         *staflags = STATION_FLAG_CHANGED;
900
901         for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++)
902                 if (flags[flag])
903                         *staflags |= (1<<flag);
904
905         return 0;
906 }
907
908 static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
909                                 int flags, struct net_device *dev,
910                                 u8 *mac_addr, struct station_info *sinfo)
911 {
912         void *hdr;
913         struct nlattr *sinfoattr;
914
915         hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
916         if (!hdr)
917                 return -1;
918
919         NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
920         NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
921
922         sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO);
923         if (!sinfoattr)
924                 goto nla_put_failure;
925         if (sinfo->filled & STATION_INFO_INACTIVE_TIME)
926                 NLA_PUT_U32(msg, NL80211_STA_INFO_INACTIVE_TIME,
927                             sinfo->inactive_time);
928         if (sinfo->filled & STATION_INFO_RX_BYTES)
929                 NLA_PUT_U32(msg, NL80211_STA_INFO_RX_BYTES,
930                             sinfo->rx_bytes);
931         if (sinfo->filled & STATION_INFO_TX_BYTES)
932                 NLA_PUT_U32(msg, NL80211_STA_INFO_TX_BYTES,
933                             sinfo->tx_bytes);
934         if (sinfo->filled & STATION_INFO_LLID)
935                 NLA_PUT_U16(msg, NL80211_STA_INFO_LLID,
936                             sinfo->llid);
937         if (sinfo->filled & STATION_INFO_PLID)
938                 NLA_PUT_U16(msg, NL80211_STA_INFO_PLID,
939                             sinfo->plid);
940         if (sinfo->filled & STATION_INFO_PLINK_STATE)
941                 NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE,
942                             sinfo->plink_state);
943
944         nla_nest_end(msg, sinfoattr);
945
946         return genlmsg_end(msg, hdr);
947
948  nla_put_failure:
949         genlmsg_cancel(msg, hdr);
950         return -EMSGSIZE;
951 }
952
953 static int nl80211_dump_station(struct sk_buff *skb,
954                                 struct netlink_callback *cb)
955 {
956         struct station_info sinfo;
957         struct cfg80211_registered_device *dev;
958         struct net_device *netdev;
959         u8 mac_addr[ETH_ALEN];
960         int ifidx = cb->args[0];
961         int sta_idx = cb->args[1];
962         int err;
963
964         if (!ifidx) {
965                 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
966                                   nl80211_fam.attrbuf, nl80211_fam.maxattr,
967                                   nl80211_policy);
968                 if (err)
969                         return err;
970
971                 if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
972                         return -EINVAL;
973
974                 ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
975                 if (!ifidx)
976                         return -EINVAL;
977         }
978
979         netdev = dev_get_by_index(&init_net, ifidx);
980         if (!netdev)
981                 return -ENODEV;
982
983         dev = cfg80211_get_dev_from_ifindex(ifidx);
984         if (IS_ERR(dev)) {
985                 err = PTR_ERR(dev);
986                 goto out_put_netdev;
987         }
988
989         if (!dev->ops->dump_station) {
990                 err = -ENOSYS;
991                 goto out_err;
992         }
993
994         rtnl_lock();
995
996         while (1) {
997                 err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx,
998                                              mac_addr, &sinfo);
999                 if (err == -ENOENT)
1000                         break;
1001                 if (err)
1002                         goto out_err_rtnl;
1003
1004                 if (nl80211_send_station(skb,
1005                                 NETLINK_CB(cb->skb).pid,
1006                                 cb->nlh->nlmsg_seq, NLM_F_MULTI,
1007                                 netdev, mac_addr,
1008                                 &sinfo) < 0)
1009                         goto out;
1010
1011                 sta_idx++;
1012         }
1013
1014
1015  out:
1016         cb->args[1] = sta_idx;
1017         err = skb->len;
1018  out_err_rtnl:
1019         rtnl_unlock();
1020  out_err:
1021         cfg80211_put_dev(dev);
1022  out_put_netdev:
1023         dev_put(netdev);
1024
1025         return err;
1026 }
1027
1028 static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
1029 {
1030         struct cfg80211_registered_device *drv;
1031         int err;
1032         struct net_device *dev;
1033         struct station_info sinfo;
1034         struct sk_buff *msg;
1035         u8 *mac_addr = NULL;
1036
1037         memset(&sinfo, 0, sizeof(sinfo));
1038
1039         if (!info->attrs[NL80211_ATTR_MAC])
1040                 return -EINVAL;
1041
1042         mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
1043
1044         err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1045         if (err)
1046                 return err;
1047
1048         if (!drv->ops->get_station) {
1049                 err = -EOPNOTSUPP;
1050                 goto out;
1051         }
1052
1053         rtnl_lock();
1054         err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo);
1055         rtnl_unlock();
1056
1057         if (err)
1058                 goto out;
1059
1060         msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1061         if (!msg)
1062                 goto out;
1063
1064         if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0,
1065                                  dev, mac_addr, &sinfo) < 0)
1066                 goto out_free;
1067
1068         err = genlmsg_unicast(msg, info->snd_pid);
1069         goto out;
1070
1071  out_free:
1072         nlmsg_free(msg);
1073
1074  out:
1075         cfg80211_put_dev(drv);
1076         dev_put(dev);
1077         return err;
1078 }
1079
1080 /*
1081  * Get vlan interface making sure it is on the right wiphy.
1082  */
1083 static int get_vlan(struct nlattr *vlanattr,
1084                     struct cfg80211_registered_device *rdev,
1085                     struct net_device **vlan)
1086 {
1087         *vlan = NULL;
1088
1089         if (vlanattr) {
1090                 *vlan = dev_get_by_index(&init_net, nla_get_u32(vlanattr));
1091                 if (!*vlan)
1092                         return -ENODEV;
1093                 if (!(*vlan)->ieee80211_ptr)
1094                         return -EINVAL;
1095                 if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy)
1096                         return -EINVAL;
1097         }
1098         return 0;
1099 }
1100
1101 static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
1102 {
1103         struct cfg80211_registered_device *drv;
1104         int err;
1105         struct net_device *dev;
1106         struct station_parameters params;
1107         u8 *mac_addr = NULL;
1108
1109         memset(&params, 0, sizeof(params));
1110
1111         params.listen_interval = -1;
1112
1113         if (info->attrs[NL80211_ATTR_STA_AID])
1114                 return -EINVAL;
1115
1116         if (!info->attrs[NL80211_ATTR_MAC])
1117                 return -EINVAL;
1118
1119         mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
1120
1121         if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
1122                 params.supported_rates =
1123                         nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
1124                 params.supported_rates_len =
1125                         nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
1126         }
1127
1128         if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
1129                 params.listen_interval =
1130                     nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
1131
1132         if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
1133                                 &params.station_flags))
1134                 return -EINVAL;
1135
1136         if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
1137                 params.plink_action =
1138                     nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
1139
1140         err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1141         if (err)
1142                 return err;
1143
1144         err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
1145         if (err)
1146                 goto out;
1147
1148         if (!drv->ops->change_station) {
1149                 err = -EOPNOTSUPP;
1150                 goto out;
1151         }
1152
1153         rtnl_lock();
1154         err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, &params);
1155         rtnl_unlock();
1156
1157  out:
1158         if (params.vlan)
1159                 dev_put(params.vlan);
1160         cfg80211_put_dev(drv);
1161         dev_put(dev);
1162         return err;
1163 }
1164
1165 static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
1166 {
1167         struct cfg80211_registered_device *drv;
1168         int err;
1169         struct net_device *dev;
1170         struct station_parameters params;
1171         u8 *mac_addr = NULL;
1172
1173         memset(&params, 0, sizeof(params));
1174
1175         if (!info->attrs[NL80211_ATTR_MAC])
1176                 return -EINVAL;
1177
1178         if (!info->attrs[NL80211_ATTR_STA_AID])
1179                 return -EINVAL;
1180
1181         if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
1182                 return -EINVAL;
1183
1184         if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
1185                 return -EINVAL;
1186
1187         mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
1188         params.supported_rates =
1189                 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
1190         params.supported_rates_len =
1191                 nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
1192         params.listen_interval =
1193                 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
1194         params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
1195
1196         if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
1197                                 &params.station_flags))
1198                 return -EINVAL;
1199
1200         err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1201         if (err)
1202                 return err;
1203
1204         err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
1205         if (err)
1206                 goto out;
1207
1208         if (!drv->ops->add_station) {
1209                 err = -EOPNOTSUPP;
1210                 goto out;
1211         }
1212
1213         rtnl_lock();
1214         err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, &params);
1215         rtnl_unlock();
1216
1217  out:
1218         if (params.vlan)
1219                 dev_put(params.vlan);
1220         cfg80211_put_dev(drv);
1221         dev_put(dev);
1222         return err;
1223 }
1224
1225 static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
1226 {
1227         struct cfg80211_registered_device *drv;
1228         int err;
1229         struct net_device *dev;
1230         u8 *mac_addr = NULL;
1231
1232         if (info->attrs[NL80211_ATTR_MAC])
1233                 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
1234
1235         err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1236         if (err)
1237                 return err;
1238
1239         if (!drv->ops->del_station) {
1240                 err = -EOPNOTSUPP;
1241                 goto out;
1242         }
1243
1244         rtnl_lock();
1245         err = drv->ops->del_station(&drv->wiphy, dev, mac_addr);
1246         rtnl_unlock();
1247
1248  out:
1249         cfg80211_put_dev(drv);
1250         dev_put(dev);
1251         return err;
1252 }
1253
1254 static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq,
1255                                 int flags, struct net_device *dev,
1256                                 u8 *dst, u8 *next_hop,
1257                                 struct mpath_info *pinfo)
1258 {
1259         void *hdr;
1260         struct nlattr *pinfoattr;
1261
1262         hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
1263         if (!hdr)
1264                 return -1;
1265
1266         NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
1267         NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
1268         NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop);
1269
1270         pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO);
1271         if (!pinfoattr)
1272                 goto nla_put_failure;
1273         if (pinfo->filled & MPATH_INFO_FRAME_QLEN)
1274                 NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN,
1275                             pinfo->frame_qlen);
1276         if (pinfo->filled & MPATH_INFO_DSN)
1277                 NLA_PUT_U32(msg, NL80211_MPATH_INFO_DSN,
1278                             pinfo->dsn);
1279         if (pinfo->filled & MPATH_INFO_METRIC)
1280                 NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC,
1281                             pinfo->metric);
1282         if (pinfo->filled & MPATH_INFO_EXPTIME)
1283                 NLA_PUT_U32(msg, NL80211_MPATH_INFO_EXPTIME,
1284                             pinfo->exptime);
1285         if (pinfo->filled & MPATH_INFO_FLAGS)
1286                 NLA_PUT_U8(msg, NL80211_MPATH_INFO_FLAGS,
1287                             pinfo->flags);
1288         if (pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT)
1289                 NLA_PUT_U32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
1290                             pinfo->discovery_timeout);
1291         if (pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES)
1292                 NLA_PUT_U8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES,
1293                             pinfo->discovery_retries);
1294
1295         nla_nest_end(msg, pinfoattr);
1296
1297         return genlmsg_end(msg, hdr);
1298
1299  nla_put_failure:
1300         genlmsg_cancel(msg, hdr);
1301         return -EMSGSIZE;
1302 }
1303
1304 static int nl80211_dump_mpath(struct sk_buff *skb,
1305                               struct netlink_callback *cb)
1306 {
1307         struct mpath_info pinfo;
1308         struct cfg80211_registered_device *dev;
1309         struct net_device *netdev;
1310         u8 dst[ETH_ALEN];
1311         u8 next_hop[ETH_ALEN];
1312         int ifidx = cb->args[0];
1313         int path_idx = cb->args[1];
1314         int err;
1315
1316         if (!ifidx) {
1317                 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
1318                                   nl80211_fam.attrbuf, nl80211_fam.maxattr,
1319                                   nl80211_policy);
1320                 if (err)
1321                         return err;
1322
1323                 if (!nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX])
1324                         return -EINVAL;
1325
1326                 ifidx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_IFINDEX]);
1327                 if (!ifidx)
1328                         return -EINVAL;
1329         }
1330
1331         netdev = dev_get_by_index(&init_net, ifidx);
1332         if (!netdev)
1333                 return -ENODEV;
1334
1335         dev = cfg80211_get_dev_from_ifindex(ifidx);
1336         if (IS_ERR(dev)) {
1337                 err = PTR_ERR(dev);
1338                 goto out_put_netdev;
1339         }
1340
1341         if (!dev->ops->dump_mpath) {
1342                 err = -ENOSYS;
1343                 goto out_err;
1344         }
1345
1346         rtnl_lock();
1347
1348         while (1) {
1349                 err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx,
1350                                            dst, next_hop, &pinfo);
1351                 if (err == -ENOENT)
1352                         break;
1353                 if (err)
1354                         goto out_err_rtnl;
1355
1356                 if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).pid,
1357                                        cb->nlh->nlmsg_seq, NLM_F_MULTI,
1358                                        netdev, dst, next_hop,
1359                                        &pinfo) < 0)
1360                         goto out;
1361
1362                 path_idx++;
1363         }
1364
1365
1366  out:
1367         cb->args[1] = path_idx;
1368         err = skb->len;
1369  out_err_rtnl:
1370         rtnl_unlock();
1371  out_err:
1372         cfg80211_put_dev(dev);
1373  out_put_netdev:
1374         dev_put(netdev);
1375
1376         return err;
1377 }
1378
1379 static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
1380 {
1381         struct cfg80211_registered_device *drv;
1382         int err;
1383         struct net_device *dev;
1384         struct mpath_info pinfo;
1385         struct sk_buff *msg;
1386         u8 *dst = NULL;
1387         u8 next_hop[ETH_ALEN];
1388
1389         memset(&pinfo, 0, sizeof(pinfo));
1390
1391         if (!info->attrs[NL80211_ATTR_MAC])
1392                 return -EINVAL;
1393
1394         dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
1395
1396         err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1397         if (err)
1398                 return err;
1399
1400         if (!drv->ops->get_mpath) {
1401                 err = -EOPNOTSUPP;
1402                 goto out;
1403         }
1404
1405         rtnl_lock();
1406         err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo);
1407         rtnl_unlock();
1408
1409         if (err)
1410                 goto out;
1411
1412         msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1413         if (!msg)
1414                 goto out;
1415
1416         if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0,
1417                                  dev, dst, next_hop, &pinfo) < 0)
1418                 goto out_free;
1419
1420         err = genlmsg_unicast(msg, info->snd_pid);
1421         goto out;
1422
1423  out_free:
1424         nlmsg_free(msg);
1425
1426  out:
1427         cfg80211_put_dev(drv);
1428         dev_put(dev);
1429         return err;
1430 }
1431
1432 static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
1433 {
1434         struct cfg80211_registered_device *drv;
1435         int err;
1436         struct net_device *dev;
1437         u8 *dst = NULL;
1438         u8 *next_hop = NULL;
1439
1440         if (!info->attrs[NL80211_ATTR_MAC])
1441                 return -EINVAL;
1442
1443         if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
1444                 return -EINVAL;
1445
1446         dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
1447         next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
1448
1449         err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1450         if (err)
1451                 return err;
1452
1453         if (!drv->ops->change_mpath) {
1454                 err = -EOPNOTSUPP;
1455                 goto out;
1456         }
1457
1458         rtnl_lock();
1459         err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop);
1460         rtnl_unlock();
1461
1462  out:
1463         cfg80211_put_dev(drv);
1464         dev_put(dev);
1465         return err;
1466 }
1467 static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
1468 {
1469         struct cfg80211_registered_device *drv;
1470         int err;
1471         struct net_device *dev;
1472         u8 *dst = NULL;
1473         u8 *next_hop = NULL;
1474
1475         if (!info->attrs[NL80211_ATTR_MAC])
1476                 return -EINVAL;
1477
1478         if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
1479                 return -EINVAL;
1480
1481         dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
1482         next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
1483
1484         err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1485         if (err)
1486                 return err;
1487
1488         if (!drv->ops->add_mpath) {
1489                 err = -EOPNOTSUPP;
1490                 goto out;
1491         }
1492
1493         rtnl_lock();
1494         err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop);
1495         rtnl_unlock();
1496
1497  out:
1498         cfg80211_put_dev(drv);
1499         dev_put(dev);
1500         return err;
1501 }
1502
1503 static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
1504 {
1505         struct cfg80211_registered_device *drv;
1506         int err;
1507         struct net_device *dev;
1508         u8 *dst = NULL;
1509
1510         if (info->attrs[NL80211_ATTR_MAC])
1511                 dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
1512
1513         err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1514         if (err)
1515                 return err;
1516
1517         if (!drv->ops->del_mpath) {
1518                 err = -EOPNOTSUPP;
1519                 goto out;
1520         }
1521
1522         rtnl_lock();
1523         err = drv->ops->del_mpath(&drv->wiphy, dev, dst);
1524         rtnl_unlock();
1525
1526  out:
1527         cfg80211_put_dev(drv);
1528         dev_put(dev);
1529         return err;
1530 }
1531
1532 static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
1533 {
1534         struct cfg80211_registered_device *drv;
1535         int err;
1536         struct net_device *dev;
1537         struct bss_parameters params;
1538
1539         memset(&params, 0, sizeof(params));
1540         /* default to not changing parameters */
1541         params.use_cts_prot = -1;
1542         params.use_short_preamble = -1;
1543         params.use_short_slot_time = -1;
1544
1545         if (info->attrs[NL80211_ATTR_BSS_CTS_PROT])
1546                 params.use_cts_prot =
1547                     nla_get_u8(info->attrs[NL80211_ATTR_BSS_CTS_PROT]);
1548         if (info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE])
1549                 params.use_short_preamble =
1550                     nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_PREAMBLE]);
1551         if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME])
1552                 params.use_short_slot_time =
1553                     nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]);
1554
1555         err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
1556         if (err)
1557                 return err;
1558
1559         if (!drv->ops->change_bss) {
1560                 err = -EOPNOTSUPP;
1561                 goto out;
1562         }
1563
1564         rtnl_lock();
1565         err = drv->ops->change_bss(&drv->wiphy, dev, &params);
1566         rtnl_unlock();
1567
1568  out:
1569         cfg80211_put_dev(drv);
1570         dev_put(dev);
1571         return err;
1572 }
1573
1574 static struct genl_ops nl80211_ops[] = {
1575         {
1576                 .cmd = NL80211_CMD_GET_WIPHY,
1577                 .doit = nl80211_get_wiphy,
1578                 .dumpit = nl80211_dump_wiphy,
1579                 .policy = nl80211_policy,
1580                 /* can be retrieved by unprivileged users */
1581         },
1582         {
1583                 .cmd = NL80211_CMD_SET_WIPHY,
1584                 .doit = nl80211_set_wiphy,
1585                 .policy = nl80211_policy,
1586                 .flags = GENL_ADMIN_PERM,
1587         },
1588         {
1589                 .cmd = NL80211_CMD_GET_INTERFACE,
1590                 .doit = nl80211_get_interface,
1591                 .dumpit = nl80211_dump_interface,
1592                 .policy = nl80211_policy,
1593                 /* can be retrieved by unprivileged users */
1594         },
1595         {
1596                 .cmd = NL80211_CMD_SET_INTERFACE,
1597                 .doit = nl80211_set_interface,
1598                 .policy = nl80211_policy,
1599                 .flags = GENL_ADMIN_PERM,
1600         },
1601         {
1602                 .cmd = NL80211_CMD_NEW_INTERFACE,
1603                 .doit = nl80211_new_interface,
1604                 .policy = nl80211_policy,
1605                 .flags = GENL_ADMIN_PERM,
1606         },
1607         {
1608                 .cmd = NL80211_CMD_DEL_INTERFACE,
1609                 .doit = nl80211_del_interface,
1610                 .policy = nl80211_policy,
1611                 .flags = GENL_ADMIN_PERM,
1612         },
1613         {
1614                 .cmd = NL80211_CMD_GET_KEY,
1615                 .doit = nl80211_get_key,
1616                 .policy = nl80211_policy,
1617                 .flags = GENL_ADMIN_PERM,
1618         },
1619         {
1620                 .cmd = NL80211_CMD_SET_KEY,
1621                 .doit = nl80211_set_key,
1622                 .policy = nl80211_policy,
1623                 .flags = GENL_ADMIN_PERM,
1624         },
1625         {
1626                 .cmd = NL80211_CMD_NEW_KEY,
1627                 .doit = nl80211_new_key,
1628                 .policy = nl80211_policy,
1629                 .flags = GENL_ADMIN_PERM,
1630         },
1631         {
1632                 .cmd = NL80211_CMD_DEL_KEY,
1633                 .doit = nl80211_del_key,
1634                 .policy = nl80211_policy,
1635                 .flags = GENL_ADMIN_PERM,
1636         },
1637         {
1638                 .cmd = NL80211_CMD_SET_BEACON,
1639                 .policy = nl80211_policy,
1640                 .flags = GENL_ADMIN_PERM,
1641                 .doit = nl80211_addset_beacon,
1642         },
1643         {
1644                 .cmd = NL80211_CMD_NEW_BEACON,
1645                 .policy = nl80211_policy,
1646                 .flags = GENL_ADMIN_PERM,
1647                 .doit = nl80211_addset_beacon,
1648         },
1649         {
1650                 .cmd = NL80211_CMD_DEL_BEACON,
1651                 .policy = nl80211_policy,
1652                 .flags = GENL_ADMIN_PERM,
1653                 .doit = nl80211_del_beacon,
1654         },
1655         {
1656                 .cmd = NL80211_CMD_GET_STATION,
1657                 .doit = nl80211_get_station,
1658                 .dumpit = nl80211_dump_station,
1659                 .policy = nl80211_policy,
1660                 .flags = GENL_ADMIN_PERM,
1661         },
1662         {
1663                 .cmd = NL80211_CMD_SET_STATION,
1664                 .doit = nl80211_set_station,
1665                 .policy = nl80211_policy,
1666                 .flags = GENL_ADMIN_PERM,
1667         },
1668         {
1669                 .cmd = NL80211_CMD_NEW_STATION,
1670                 .doit = nl80211_new_station,
1671                 .policy = nl80211_policy,
1672                 .flags = GENL_ADMIN_PERM,
1673         },
1674         {
1675                 .cmd = NL80211_CMD_DEL_STATION,
1676                 .doit = nl80211_del_station,
1677                 .policy = nl80211_policy,
1678                 .flags = GENL_ADMIN_PERM,
1679         },
1680         {
1681                 .cmd = NL80211_CMD_GET_MPATH,
1682                 .doit = nl80211_get_mpath,
1683                 .dumpit = nl80211_dump_mpath,
1684                 .policy = nl80211_policy,
1685                 .flags = GENL_ADMIN_PERM,
1686         },
1687         {
1688                 .cmd = NL80211_CMD_SET_MPATH,
1689                 .doit = nl80211_set_mpath,
1690                 .policy = nl80211_policy,
1691                 .flags = GENL_ADMIN_PERM,
1692         },
1693         {
1694                 .cmd = NL80211_CMD_NEW_MPATH,
1695                 .doit = nl80211_new_mpath,
1696                 .policy = nl80211_policy,
1697                 .flags = GENL_ADMIN_PERM,
1698         },
1699         {
1700                 .cmd = NL80211_CMD_DEL_MPATH,
1701                 .doit = nl80211_del_mpath,
1702                 .policy = nl80211_policy,
1703                 .flags = GENL_ADMIN_PERM,
1704         },
1705         {
1706                 .cmd = NL80211_CMD_SET_BSS,
1707                 .doit = nl80211_set_bss,
1708                 .policy = nl80211_policy,
1709                 .flags = GENL_ADMIN_PERM,
1710         },
1711 };
1712
1713 /* multicast groups */
1714 static struct genl_multicast_group nl80211_config_mcgrp = {
1715         .name = "config",
1716 };
1717
1718 /* notification functions */
1719
1720 void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
1721 {
1722         struct sk_buff *msg;
1723
1724         msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1725         if (!msg)
1726                 return;
1727
1728         if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) {
1729                 nlmsg_free(msg);
1730                 return;
1731         }
1732
1733         genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL);
1734 }
1735
1736 /* initialisation/exit functions */
1737
1738 int nl80211_init(void)
1739 {
1740         int err, i;
1741
1742         err = genl_register_family(&nl80211_fam);
1743         if (err)
1744                 return err;
1745
1746         for (i = 0; i < ARRAY_SIZE(nl80211_ops); i++) {
1747                 err = genl_register_ops(&nl80211_fam, &nl80211_ops[i]);
1748                 if (err)
1749                         goto err_out;
1750         }
1751
1752         err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp);
1753         if (err)
1754                 goto err_out;
1755
1756         return 0;
1757  err_out:
1758         genl_unregister_family(&nl80211_fam);
1759         return err;
1760 }
1761
1762 void nl80211_exit(void)
1763 {
1764         genl_unregister_family(&nl80211_fam);
1765 }