diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 996 |
1 files changed, 811 insertions, 185 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 2456e4ee445e..241bddd0b4f1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * This is the new netlink-based wireless configuration interface. | 2 | * This is the new netlink-based wireless configuration interface. |
3 | * | 3 | * |
4 | * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net> |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/if.h> | 7 | #include <linux/if.h> |
@@ -57,10 +57,14 @@ static int get_drv_dev_by_info_ifindex(struct nlattr **attrs, | |||
57 | static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | 57 | static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { |
58 | [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, | 58 | [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, |
59 | [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, | 59 | [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, |
60 | .len = BUS_ID_SIZE-1 }, | 60 | .len = 20-1 }, |
61 | [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, | 61 | [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, |
62 | [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, | 62 | [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, |
63 | [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 }, | 63 | [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 }, |
64 | [NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 }, | ||
65 | [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 }, | ||
66 | [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, | ||
67 | [NL80211_ATTR_WIPHY_RTS_THRESHOLD] = { .type = NLA_U32 }, | ||
64 | 68 | ||
65 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, | 69 | [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, |
66 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, | 70 | [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, |
@@ -73,6 +77,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
73 | [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, | 77 | [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, |
74 | [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, | 78 | [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 }, |
75 | [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, | 79 | [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG }, |
80 | [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, | ||
76 | 81 | ||
77 | [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, | 82 | [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 }, |
78 | [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, | 83 | [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 }, |
@@ -116,8 +121,45 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
116 | .len = IEEE80211_MAX_SSID_LEN }, | 121 | .len = IEEE80211_MAX_SSID_LEN }, |
117 | [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 }, | 122 | [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 }, |
118 | [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 }, | 123 | [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 }, |
124 | [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG }, | ||
125 | [NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG }, | ||
126 | [NL80211_ATTR_USE_MFP] = { .type = NLA_U32 }, | ||
127 | [NL80211_ATTR_STA_FLAGS2] = { | ||
128 | .len = sizeof(struct nl80211_sta_flag_update), | ||
129 | }, | ||
130 | [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG }, | ||
119 | }; | 131 | }; |
120 | 132 | ||
133 | /* IE validation */ | ||
134 | static bool is_valid_ie_attr(const struct nlattr *attr) | ||
135 | { | ||
136 | const u8 *pos; | ||
137 | int len; | ||
138 | |||
139 | if (!attr) | ||
140 | return true; | ||
141 | |||
142 | pos = nla_data(attr); | ||
143 | len = nla_len(attr); | ||
144 | |||
145 | while (len) { | ||
146 | u8 elemlen; | ||
147 | |||
148 | if (len < 2) | ||
149 | return false; | ||
150 | len -= 2; | ||
151 | |||
152 | elemlen = pos[1]; | ||
153 | if (elemlen > len) | ||
154 | return false; | ||
155 | |||
156 | len -= elemlen; | ||
157 | pos += 2 + elemlen; | ||
158 | } | ||
159 | |||
160 | return true; | ||
161 | } | ||
162 | |||
121 | /* message building helper */ | 163 | /* message building helper */ |
122 | static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, | 164 | static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, |
123 | int flags, u8 cmd) | 165 | int flags, u8 cmd) |
@@ -126,6 +168,30 @@ static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, | |||
126 | return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd); | 168 | return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd); |
127 | } | 169 | } |
128 | 170 | ||
171 | static int nl80211_msg_put_channel(struct sk_buff *msg, | ||
172 | struct ieee80211_channel *chan) | ||
173 | { | ||
174 | NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ, | ||
175 | chan->center_freq); | ||
176 | |||
177 | if (chan->flags & IEEE80211_CHAN_DISABLED) | ||
178 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED); | ||
179 | if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) | ||
180 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN); | ||
181 | if (chan->flags & IEEE80211_CHAN_NO_IBSS) | ||
182 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS); | ||
183 | if (chan->flags & IEEE80211_CHAN_RADAR) | ||
184 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR); | ||
185 | |||
186 | NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, | ||
187 | DBM_TO_MBM(chan->max_power)); | ||
188 | |||
189 | return 0; | ||
190 | |||
191 | nla_put_failure: | ||
192 | return -ENOBUFS; | ||
193 | } | ||
194 | |||
129 | /* netlink command implementations */ | 195 | /* netlink command implementations */ |
130 | 196 | ||
131 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 197 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, |
@@ -149,8 +215,24 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
149 | 215 | ||
150 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); | 216 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); |
151 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); | 217 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); |
218 | |||
219 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, | ||
220 | dev->wiphy.retry_short); | ||
221 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, | ||
222 | dev->wiphy.retry_long); | ||
223 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, | ||
224 | dev->wiphy.frag_threshold); | ||
225 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, | ||
226 | dev->wiphy.rts_threshold); | ||
227 | |||
152 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, | 228 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, |
153 | dev->wiphy.max_scan_ssids); | 229 | dev->wiphy.max_scan_ssids); |
230 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, | ||
231 | dev->wiphy.max_scan_ie_len); | ||
232 | |||
233 | NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, | ||
234 | sizeof(u32) * dev->wiphy.n_cipher_suites, | ||
235 | dev->wiphy.cipher_suites); | ||
154 | 236 | ||
155 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); | 237 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); |
156 | if (!nl_modes) | 238 | if (!nl_modes) |
@@ -202,20 +284,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
202 | goto nla_put_failure; | 284 | goto nla_put_failure; |
203 | 285 | ||
204 | chan = &dev->wiphy.bands[band]->channels[i]; | 286 | chan = &dev->wiphy.bands[band]->channels[i]; |
205 | NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ, | ||
206 | chan->center_freq); | ||
207 | |||
208 | if (chan->flags & IEEE80211_CHAN_DISABLED) | ||
209 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED); | ||
210 | if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) | ||
211 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN); | ||
212 | if (chan->flags & IEEE80211_CHAN_NO_IBSS) | ||
213 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS); | ||
214 | if (chan->flags & IEEE80211_CHAN_RADAR) | ||
215 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR); | ||
216 | 287 | ||
217 | NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, | 288 | if (nl80211_msg_put_channel(msg, chan)) |
218 | DBM_TO_MBM(chan->max_power)); | 289 | goto nla_put_failure; |
219 | 290 | ||
220 | nla_nest_end(msg, nl_freq); | 291 | nla_nest_end(msg, nl_freq); |
221 | } | 292 | } |
@@ -273,6 +344,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
273 | CMD(assoc, ASSOCIATE); | 344 | CMD(assoc, ASSOCIATE); |
274 | CMD(deauth, DEAUTHENTICATE); | 345 | CMD(deauth, DEAUTHENTICATE); |
275 | CMD(disassoc, DISASSOCIATE); | 346 | CMD(disassoc, DISASSOCIATE); |
347 | CMD(join_ibss, JOIN_IBSS); | ||
276 | 348 | ||
277 | #undef CMD | 349 | #undef CMD |
278 | nla_nest_end(msg, nl_cmds); | 350 | nla_nest_end(msg, nl_cmds); |
@@ -317,7 +389,7 @@ static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
317 | if (IS_ERR(dev)) | 389 | if (IS_ERR(dev)) |
318 | return PTR_ERR(dev); | 390 | return PTR_ERR(dev); |
319 | 391 | ||
320 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 392 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
321 | if (!msg) | 393 | if (!msg) |
322 | goto out_err; | 394 | goto out_err; |
323 | 395 | ||
@@ -365,6 +437,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
365 | struct cfg80211_registered_device *rdev; | 437 | struct cfg80211_registered_device *rdev; |
366 | int result = 0, rem_txq_params = 0; | 438 | int result = 0, rem_txq_params = 0; |
367 | struct nlattr *nl_txq_params; | 439 | struct nlattr *nl_txq_params; |
440 | u32 changed; | ||
441 | u8 retry_short = 0, retry_long = 0; | ||
442 | u32 frag_threshold = 0, rts_threshold = 0; | ||
368 | 443 | ||
369 | rtnl_lock(); | 444 | rtnl_lock(); |
370 | 445 | ||
@@ -418,7 +493,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
418 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 493 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
419 | struct ieee80211_channel *chan; | 494 | struct ieee80211_channel *chan; |
420 | struct ieee80211_sta_ht_cap *ht_cap; | 495 | struct ieee80211_sta_ht_cap *ht_cap; |
421 | u32 freq, sec_freq; | 496 | u32 freq; |
422 | 497 | ||
423 | if (!rdev->ops->set_channel) { | 498 | if (!rdev->ops->set_channel) { |
424 | result = -EOPNOTSUPP; | 499 | result = -EOPNOTSUPP; |
@@ -444,33 +519,28 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
444 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) | 519 | if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) |
445 | goto bad_res; | 520 | goto bad_res; |
446 | 521 | ||
447 | if (channel_type == NL80211_CHAN_HT40MINUS) | 522 | if (channel_type == NL80211_CHAN_HT40MINUS && |
448 | sec_freq = freq - 20; | 523 | (chan->flags & IEEE80211_CHAN_NO_HT40MINUS)) |
449 | else if (channel_type == NL80211_CHAN_HT40PLUS) | ||
450 | sec_freq = freq + 20; | ||
451 | else | ||
452 | sec_freq = 0; | ||
453 | |||
454 | ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; | ||
455 | |||
456 | /* no HT capabilities */ | ||
457 | if (channel_type != NL80211_CHAN_NO_HT && | ||
458 | !ht_cap->ht_supported) | ||
459 | goto bad_res; | 524 | goto bad_res; |
525 | else if (channel_type == NL80211_CHAN_HT40PLUS && | ||
526 | (chan->flags & IEEE80211_CHAN_NO_HT40PLUS)) | ||
527 | goto bad_res; | ||
528 | |||
529 | /* | ||
530 | * At this point we know if that if HT40 was requested | ||
531 | * we are allowed to use it and the extension channel | ||
532 | * exists. | ||
533 | */ | ||
460 | 534 | ||
461 | if (sec_freq) { | 535 | ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; |
462 | struct ieee80211_channel *schan; | ||
463 | 536 | ||
464 | /* no 40 MHz capabilities */ | 537 | /* no HT capabilities or intolerant */ |
538 | if (channel_type != NL80211_CHAN_NO_HT) { | ||
539 | if (!ht_cap->ht_supported) | ||
540 | goto bad_res; | ||
465 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || | 541 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || |
466 | (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) | 542 | (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) |
467 | goto bad_res; | 543 | goto bad_res; |
468 | |||
469 | schan = ieee80211_get_channel(&rdev->wiphy, sec_freq); | ||
470 | |||
471 | /* Secondary channel not allowed */ | ||
472 | if (!schan || schan->flags & IEEE80211_CHAN_DISABLED) | ||
473 | goto bad_res; | ||
474 | } | 544 | } |
475 | 545 | ||
476 | result = rdev->ops->set_channel(&rdev->wiphy, chan, | 546 | result = rdev->ops->set_channel(&rdev->wiphy, chan, |
@@ -479,6 +549,84 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
479 | goto bad_res; | 549 | goto bad_res; |
480 | } | 550 | } |
481 | 551 | ||
552 | changed = 0; | ||
553 | |||
554 | if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) { | ||
555 | retry_short = nla_get_u8( | ||
556 | info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]); | ||
557 | if (retry_short == 0) { | ||
558 | result = -EINVAL; | ||
559 | goto bad_res; | ||
560 | } | ||
561 | changed |= WIPHY_PARAM_RETRY_SHORT; | ||
562 | } | ||
563 | |||
564 | if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) { | ||
565 | retry_long = nla_get_u8( | ||
566 | info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]); | ||
567 | if (retry_long == 0) { | ||
568 | result = -EINVAL; | ||
569 | goto bad_res; | ||
570 | } | ||
571 | changed |= WIPHY_PARAM_RETRY_LONG; | ||
572 | } | ||
573 | |||
574 | if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) { | ||
575 | frag_threshold = nla_get_u32( | ||
576 | info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]); | ||
577 | if (frag_threshold < 256) { | ||
578 | result = -EINVAL; | ||
579 | goto bad_res; | ||
580 | } | ||
581 | if (frag_threshold != (u32) -1) { | ||
582 | /* | ||
583 | * Fragments (apart from the last one) are required to | ||
584 | * have even length. Make the fragmentation code | ||
585 | * simpler by stripping LSB should someone try to use | ||
586 | * odd threshold value. | ||
587 | */ | ||
588 | frag_threshold &= ~0x1; | ||
589 | } | ||
590 | changed |= WIPHY_PARAM_FRAG_THRESHOLD; | ||
591 | } | ||
592 | |||
593 | if (info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) { | ||
594 | rts_threshold = nla_get_u32( | ||
595 | info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]); | ||
596 | changed |= WIPHY_PARAM_RTS_THRESHOLD; | ||
597 | } | ||
598 | |||
599 | if (changed) { | ||
600 | u8 old_retry_short, old_retry_long; | ||
601 | u32 old_frag_threshold, old_rts_threshold; | ||
602 | |||
603 | if (!rdev->ops->set_wiphy_params) { | ||
604 | result = -EOPNOTSUPP; | ||
605 | goto bad_res; | ||
606 | } | ||
607 | |||
608 | old_retry_short = rdev->wiphy.retry_short; | ||
609 | old_retry_long = rdev->wiphy.retry_long; | ||
610 | old_frag_threshold = rdev->wiphy.frag_threshold; | ||
611 | old_rts_threshold = rdev->wiphy.rts_threshold; | ||
612 | |||
613 | if (changed & WIPHY_PARAM_RETRY_SHORT) | ||
614 | rdev->wiphy.retry_short = retry_short; | ||
615 | if (changed & WIPHY_PARAM_RETRY_LONG) | ||
616 | rdev->wiphy.retry_long = retry_long; | ||
617 | if (changed & WIPHY_PARAM_FRAG_THRESHOLD) | ||
618 | rdev->wiphy.frag_threshold = frag_threshold; | ||
619 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) | ||
620 | rdev->wiphy.rts_threshold = rts_threshold; | ||
621 | |||
622 | result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); | ||
623 | if (result) { | ||
624 | rdev->wiphy.retry_short = old_retry_short; | ||
625 | rdev->wiphy.retry_long = old_retry_long; | ||
626 | rdev->wiphy.frag_threshold = old_frag_threshold; | ||
627 | rdev->wiphy.rts_threshold = old_rts_threshold; | ||
628 | } | ||
629 | } | ||
482 | 630 | ||
483 | bad_res: | 631 | bad_res: |
484 | mutex_unlock(&rdev->mtx); | 632 | mutex_unlock(&rdev->mtx); |
@@ -489,6 +637,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
489 | 637 | ||
490 | 638 | ||
491 | static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 639 | static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, |
640 | struct cfg80211_registered_device *rdev, | ||
492 | struct net_device *dev) | 641 | struct net_device *dev) |
493 | { | 642 | { |
494 | void *hdr; | 643 | void *hdr; |
@@ -498,6 +647,7 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
498 | return -1; | 647 | return -1; |
499 | 648 | ||
500 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 649 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
650 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
501 | NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); | 651 | NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); |
502 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); | 652 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); |
503 | return genlmsg_end(msg, hdr); | 653 | return genlmsg_end(msg, hdr); |
@@ -532,7 +682,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
532 | } | 682 | } |
533 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, | 683 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, |
534 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 684 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
535 | wdev->netdev) < 0) { | 685 | dev, wdev->netdev) < 0) { |
536 | mutex_unlock(&dev->devlist_mtx); | 686 | mutex_unlock(&dev->devlist_mtx); |
537 | goto out; | 687 | goto out; |
538 | } | 688 | } |
@@ -562,11 +712,12 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) | |||
562 | if (err) | 712 | if (err) |
563 | return err; | 713 | return err; |
564 | 714 | ||
565 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 715 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
566 | if (!msg) | 716 | if (!msg) |
567 | goto out_err; | 717 | goto out_err; |
568 | 718 | ||
569 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, netdev) < 0) | 719 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, |
720 | dev, netdev) < 0) | ||
570 | goto out_free; | 721 | goto out_free; |
571 | 722 | ||
572 | dev_put(netdev); | 723 | dev_put(netdev); |
@@ -616,7 +767,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
616 | struct cfg80211_registered_device *drv; | 767 | struct cfg80211_registered_device *drv; |
617 | struct vif_params params; | 768 | struct vif_params params; |
618 | int err, ifindex; | 769 | int err, ifindex; |
619 | enum nl80211_iftype type; | 770 | enum nl80211_iftype otype, ntype; |
620 | struct net_device *dev; | 771 | struct net_device *dev; |
621 | u32 _flags, *flags = NULL; | 772 | u32 _flags, *flags = NULL; |
622 | bool change = false; | 773 | bool change = false; |
@@ -630,30 +781,27 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
630 | goto unlock_rtnl; | 781 | goto unlock_rtnl; |
631 | 782 | ||
632 | ifindex = dev->ifindex; | 783 | ifindex = dev->ifindex; |
633 | type = dev->ieee80211_ptr->iftype; | 784 | otype = ntype = dev->ieee80211_ptr->iftype; |
634 | dev_put(dev); | 785 | dev_put(dev); |
635 | 786 | ||
636 | if (info->attrs[NL80211_ATTR_IFTYPE]) { | 787 | if (info->attrs[NL80211_ATTR_IFTYPE]) { |
637 | enum nl80211_iftype ntype; | ||
638 | |||
639 | ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); | 788 | ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); |
640 | if (type != ntype) | 789 | if (otype != ntype) |
641 | change = true; | 790 | change = true; |
642 | type = ntype; | 791 | if (ntype > NL80211_IFTYPE_MAX) { |
643 | if (type > NL80211_IFTYPE_MAX) { | ||
644 | err = -EINVAL; | 792 | err = -EINVAL; |
645 | goto unlock; | 793 | goto unlock; |
646 | } | 794 | } |
647 | } | 795 | } |
648 | 796 | ||
649 | if (!drv->ops->change_virtual_intf || | 797 | if (!drv->ops->change_virtual_intf || |
650 | !(drv->wiphy.interface_modes & (1 << type))) { | 798 | !(drv->wiphy.interface_modes & (1 << ntype))) { |
651 | err = -EOPNOTSUPP; | 799 | err = -EOPNOTSUPP; |
652 | goto unlock; | 800 | goto unlock; |
653 | } | 801 | } |
654 | 802 | ||
655 | if (info->attrs[NL80211_ATTR_MESH_ID]) { | 803 | if (info->attrs[NL80211_ATTR_MESH_ID]) { |
656 | if (type != NL80211_IFTYPE_MESH_POINT) { | 804 | if (ntype != NL80211_IFTYPE_MESH_POINT) { |
657 | err = -EINVAL; | 805 | err = -EINVAL; |
658 | goto unlock; | 806 | goto unlock; |
659 | } | 807 | } |
@@ -663,7 +811,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
663 | } | 811 | } |
664 | 812 | ||
665 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { | 813 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { |
666 | if (type != NL80211_IFTYPE_MONITOR) { | 814 | if (ntype != NL80211_IFTYPE_MONITOR) { |
667 | err = -EINVAL; | 815 | err = -EINVAL; |
668 | goto unlock; | 816 | goto unlock; |
669 | } | 817 | } |
@@ -678,12 +826,17 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
678 | 826 | ||
679 | if (change) | 827 | if (change) |
680 | err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, | 828 | err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, |
681 | type, flags, ¶ms); | 829 | ntype, flags, ¶ms); |
682 | else | 830 | else |
683 | err = 0; | 831 | err = 0; |
684 | 832 | ||
685 | dev = __dev_get_by_index(&init_net, ifindex); | 833 | dev = __dev_get_by_index(&init_net, ifindex); |
686 | WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type)); | 834 | WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != ntype)); |
835 | |||
836 | if (dev && !err && (ntype != otype)) { | ||
837 | if (otype == NL80211_IFTYPE_ADHOC) | ||
838 | cfg80211_clear_ibss(dev, false); | ||
839 | } | ||
687 | 840 | ||
688 | unlock: | 841 | unlock: |
689 | cfg80211_put_dev(drv); | 842 | cfg80211_put_dev(drv); |
@@ -832,7 +985,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
832 | goto out; | 985 | goto out; |
833 | } | 986 | } |
834 | 987 | ||
835 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 988 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
836 | if (!msg) { | 989 | if (!msg) { |
837 | err = -ENOMEM; | 990 | err = -ENOMEM; |
838 | goto out; | 991 | goto out; |
@@ -920,6 +1073,14 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
920 | } | 1073 | } |
921 | 1074 | ||
922 | err = func(&drv->wiphy, dev, key_idx); | 1075 | err = func(&drv->wiphy, dev, key_idx); |
1076 | #ifdef CONFIG_WIRELESS_EXT | ||
1077 | if (!err) { | ||
1078 | if (func == drv->ops->set_default_key) | ||
1079 | dev->ieee80211_ptr->wext.default_key = key_idx; | ||
1080 | else | ||
1081 | dev->ieee80211_ptr->wext.default_mgmt_key = key_idx; | ||
1082 | } | ||
1083 | #endif | ||
923 | 1084 | ||
924 | out: | 1085 | out: |
925 | cfg80211_put_dev(drv); | 1086 | cfg80211_put_dev(drv); |
@@ -934,7 +1095,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
934 | static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | 1095 | static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) |
935 | { | 1096 | { |
936 | struct cfg80211_registered_device *drv; | 1097 | struct cfg80211_registered_device *drv; |
937 | int err; | 1098 | int err, i; |
938 | struct net_device *dev; | 1099 | struct net_device *dev; |
939 | struct key_params params; | 1100 | struct key_params params; |
940 | u8 key_idx = 0; | 1101 | u8 key_idx = 0; |
@@ -950,6 +1111,11 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
950 | params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]); | 1111 | params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]); |
951 | } | 1112 | } |
952 | 1113 | ||
1114 | if (info->attrs[NL80211_ATTR_KEY_SEQ]) { | ||
1115 | params.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]); | ||
1116 | params.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]); | ||
1117 | } | ||
1118 | |||
953 | if (info->attrs[NL80211_ATTR_KEY_IDX]) | 1119 | if (info->attrs[NL80211_ATTR_KEY_IDX]) |
954 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | 1120 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); |
955 | 1121 | ||
@@ -958,51 +1124,23 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
958 | if (info->attrs[NL80211_ATTR_MAC]) | 1124 | if (info->attrs[NL80211_ATTR_MAC]) |
959 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1125 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
960 | 1126 | ||
961 | if (key_idx > 5) | 1127 | if (cfg80211_validate_key_settings(¶ms, key_idx, mac_addr)) |
962 | return -EINVAL; | 1128 | return -EINVAL; |
963 | 1129 | ||
964 | /* | ||
965 | * Disallow pairwise keys with non-zero index unless it's WEP | ||
966 | * (because current deployments use pairwise WEP keys with | ||
967 | * non-zero indizes but 802.11i clearly specifies to use zero) | ||
968 | */ | ||
969 | if (mac_addr && key_idx && | ||
970 | params.cipher != WLAN_CIPHER_SUITE_WEP40 && | ||
971 | params.cipher != WLAN_CIPHER_SUITE_WEP104) | ||
972 | return -EINVAL; | ||
973 | |||
974 | /* TODO: add definitions for the lengths to linux/ieee80211.h */ | ||
975 | switch (params.cipher) { | ||
976 | case WLAN_CIPHER_SUITE_WEP40: | ||
977 | if (params.key_len != 5) | ||
978 | return -EINVAL; | ||
979 | break; | ||
980 | case WLAN_CIPHER_SUITE_TKIP: | ||
981 | if (params.key_len != 32) | ||
982 | return -EINVAL; | ||
983 | break; | ||
984 | case WLAN_CIPHER_SUITE_CCMP: | ||
985 | if (params.key_len != 16) | ||
986 | return -EINVAL; | ||
987 | break; | ||
988 | case WLAN_CIPHER_SUITE_WEP104: | ||
989 | if (params.key_len != 13) | ||
990 | return -EINVAL; | ||
991 | break; | ||
992 | case WLAN_CIPHER_SUITE_AES_CMAC: | ||
993 | if (params.key_len != 16) | ||
994 | return -EINVAL; | ||
995 | break; | ||
996 | default: | ||
997 | return -EINVAL; | ||
998 | } | ||
999 | |||
1000 | rtnl_lock(); | 1130 | rtnl_lock(); |
1001 | 1131 | ||
1002 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1132 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1003 | if (err) | 1133 | if (err) |
1004 | goto unlock_rtnl; | 1134 | goto unlock_rtnl; |
1005 | 1135 | ||
1136 | for (i = 0; i < drv->wiphy.n_cipher_suites; i++) | ||
1137 | if (params.cipher == drv->wiphy.cipher_suites[i]) | ||
1138 | break; | ||
1139 | if (i == drv->wiphy.n_cipher_suites) { | ||
1140 | err = -EINVAL; | ||
1141 | goto out; | ||
1142 | } | ||
1143 | |||
1006 | if (!drv->ops->add_key) { | 1144 | if (!drv->ops->add_key) { |
1007 | err = -EOPNOTSUPP; | 1145 | err = -EOPNOTSUPP; |
1008 | goto out; | 1146 | goto out; |
@@ -1049,6 +1187,15 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
1049 | 1187 | ||
1050 | err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr); | 1188 | err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr); |
1051 | 1189 | ||
1190 | #ifdef CONFIG_WIRELESS_EXT | ||
1191 | if (!err) { | ||
1192 | if (key_idx == dev->ieee80211_ptr->wext.default_key) | ||
1193 | dev->ieee80211_ptr->wext.default_key = -1; | ||
1194 | else if (key_idx == dev->ieee80211_ptr->wext.default_mgmt_key) | ||
1195 | dev->ieee80211_ptr->wext.default_mgmt_key = -1; | ||
1196 | } | ||
1197 | #endif | ||
1198 | |||
1052 | out: | 1199 | out: |
1053 | cfg80211_put_dev(drv); | 1200 | cfg80211_put_dev(drv); |
1054 | dev_put(dev); | 1201 | dev_put(dev); |
@@ -1069,6 +1216,9 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1069 | struct beacon_parameters params; | 1216 | struct beacon_parameters params; |
1070 | int haveinfo = 0; | 1217 | int haveinfo = 0; |
1071 | 1218 | ||
1219 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) | ||
1220 | return -EINVAL; | ||
1221 | |||
1072 | rtnl_lock(); | 1222 | rtnl_lock(); |
1073 | 1223 | ||
1074 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1224 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
@@ -1186,15 +1336,36 @@ static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { | |||
1186 | [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG }, | 1336 | [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG }, |
1187 | [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG }, | 1337 | [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG }, |
1188 | [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG }, | 1338 | [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG }, |
1339 | [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG }, | ||
1189 | }; | 1340 | }; |
1190 | 1341 | ||
1191 | static int parse_station_flags(struct nlattr *nla, u32 *staflags) | 1342 | static int parse_station_flags(struct genl_info *info, |
1343 | struct station_parameters *params) | ||
1192 | { | 1344 | { |
1193 | struct nlattr *flags[NL80211_STA_FLAG_MAX + 1]; | 1345 | struct nlattr *flags[NL80211_STA_FLAG_MAX + 1]; |
1346 | struct nlattr *nla; | ||
1194 | int flag; | 1347 | int flag; |
1195 | 1348 | ||
1196 | *staflags = 0; | 1349 | /* |
1350 | * Try parsing the new attribute first so userspace | ||
1351 | * can specify both for older kernels. | ||
1352 | */ | ||
1353 | nla = info->attrs[NL80211_ATTR_STA_FLAGS2]; | ||
1354 | if (nla) { | ||
1355 | struct nl80211_sta_flag_update *sta_flags; | ||
1356 | |||
1357 | sta_flags = nla_data(nla); | ||
1358 | params->sta_flags_mask = sta_flags->mask; | ||
1359 | params->sta_flags_set = sta_flags->set; | ||
1360 | if ((params->sta_flags_mask | | ||
1361 | params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID)) | ||
1362 | return -EINVAL; | ||
1363 | return 0; | ||
1364 | } | ||
1365 | |||
1366 | /* if present, parse the old attribute */ | ||
1197 | 1367 | ||
1368 | nla = info->attrs[NL80211_ATTR_STA_FLAGS]; | ||
1198 | if (!nla) | 1369 | if (!nla) |
1199 | return 0; | 1370 | return 0; |
1200 | 1371 | ||
@@ -1202,11 +1373,12 @@ static int parse_station_flags(struct nlattr *nla, u32 *staflags) | |||
1202 | nla, sta_flags_policy)) | 1373 | nla, sta_flags_policy)) |
1203 | return -EINVAL; | 1374 | return -EINVAL; |
1204 | 1375 | ||
1205 | *staflags = STATION_FLAG_CHANGED; | 1376 | params->sta_flags_mask = (1 << __NL80211_STA_FLAG_AFTER_LAST) - 1; |
1377 | params->sta_flags_mask &= ~1; | ||
1206 | 1378 | ||
1207 | for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) | 1379 | for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) |
1208 | if (flags[flag]) | 1380 | if (flags[flag]) |
1209 | *staflags |= (1<<flag); | 1381 | params->sta_flags_set |= (1<<flag); |
1210 | 1382 | ||
1211 | return 0; | 1383 | return 0; |
1212 | } | 1384 | } |
@@ -1424,7 +1596,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
1424 | if (err) | 1596 | if (err) |
1425 | goto out; | 1597 | goto out; |
1426 | 1598 | ||
1427 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 1599 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1428 | if (!msg) | 1600 | if (!msg) |
1429 | goto out; | 1601 | goto out; |
1430 | 1602 | ||
@@ -1502,8 +1674,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
1502 | params.ht_capa = | 1674 | params.ht_capa = |
1503 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | 1675 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); |
1504 | 1676 | ||
1505 | if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], | 1677 | if (parse_station_flags(info, ¶ms)) |
1506 | ¶ms.station_flags)) | ||
1507 | return -EINVAL; | 1678 | return -EINVAL; |
1508 | 1679 | ||
1509 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) | 1680 | if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) |
@@ -1520,6 +1691,51 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
1520 | if (err) | 1691 | if (err) |
1521 | goto out; | 1692 | goto out; |
1522 | 1693 | ||
1694 | /* validate settings */ | ||
1695 | err = 0; | ||
1696 | |||
1697 | switch (dev->ieee80211_ptr->iftype) { | ||
1698 | case NL80211_IFTYPE_AP: | ||
1699 | case NL80211_IFTYPE_AP_VLAN: | ||
1700 | /* disallow mesh-specific things */ | ||
1701 | if (params.plink_action) | ||
1702 | err = -EINVAL; | ||
1703 | break; | ||
1704 | case NL80211_IFTYPE_STATION: | ||
1705 | /* disallow everything but AUTHORIZED flag */ | ||
1706 | if (params.plink_action) | ||
1707 | err = -EINVAL; | ||
1708 | if (params.vlan) | ||
1709 | err = -EINVAL; | ||
1710 | if (params.supported_rates) | ||
1711 | err = -EINVAL; | ||
1712 | if (params.ht_capa) | ||
1713 | err = -EINVAL; | ||
1714 | if (params.listen_interval >= 0) | ||
1715 | err = -EINVAL; | ||
1716 | if (params.sta_flags_mask & ~BIT(NL80211_STA_FLAG_AUTHORIZED)) | ||
1717 | err = -EINVAL; | ||
1718 | break; | ||
1719 | case NL80211_IFTYPE_MESH_POINT: | ||
1720 | /* disallow things mesh doesn't support */ | ||
1721 | if (params.vlan) | ||
1722 | err = -EINVAL; | ||
1723 | if (params.ht_capa) | ||
1724 | err = -EINVAL; | ||
1725 | if (params.listen_interval >= 0) | ||
1726 | err = -EINVAL; | ||
1727 | if (params.supported_rates) | ||
1728 | err = -EINVAL; | ||
1729 | if (params.sta_flags_mask) | ||
1730 | err = -EINVAL; | ||
1731 | break; | ||
1732 | default: | ||
1733 | err = -EINVAL; | ||
1734 | } | ||
1735 | |||
1736 | if (err) | ||
1737 | goto out; | ||
1738 | |||
1523 | if (!drv->ops->change_station) { | 1739 | if (!drv->ops->change_station) { |
1524 | err = -EOPNOTSUPP; | 1740 | err = -EOPNOTSUPP; |
1525 | goto out; | 1741 | goto out; |
@@ -1551,9 +1767,6 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
1551 | if (!info->attrs[NL80211_ATTR_MAC]) | 1767 | if (!info->attrs[NL80211_ATTR_MAC]) |
1552 | return -EINVAL; | 1768 | return -EINVAL; |
1553 | 1769 | ||
1554 | if (!info->attrs[NL80211_ATTR_STA_AID]) | ||
1555 | return -EINVAL; | ||
1556 | |||
1557 | if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) | 1770 | if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) |
1558 | return -EINVAL; | 1771 | return -EINVAL; |
1559 | 1772 | ||
@@ -1567,13 +1780,18 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
1567 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | 1780 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); |
1568 | params.listen_interval = | 1781 | params.listen_interval = |
1569 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); | 1782 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); |
1570 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); | 1783 | |
1784 | if (info->attrs[NL80211_ATTR_STA_AID]) { | ||
1785 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); | ||
1786 | if (!params.aid || params.aid > IEEE80211_MAX_AID) | ||
1787 | return -EINVAL; | ||
1788 | } | ||
1789 | |||
1571 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | 1790 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) |
1572 | params.ht_capa = | 1791 | params.ht_capa = |
1573 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | 1792 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); |
1574 | 1793 | ||
1575 | if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], | 1794 | if (parse_station_flags(info, ¶ms)) |
1576 | ¶ms.station_flags)) | ||
1577 | return -EINVAL; | 1795 | return -EINVAL; |
1578 | 1796 | ||
1579 | rtnl_lock(); | 1797 | rtnl_lock(); |
@@ -1586,6 +1804,38 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
1586 | if (err) | 1804 | if (err) |
1587 | goto out; | 1805 | goto out; |
1588 | 1806 | ||
1807 | /* validate settings */ | ||
1808 | err = 0; | ||
1809 | |||
1810 | switch (dev->ieee80211_ptr->iftype) { | ||
1811 | case NL80211_IFTYPE_AP: | ||
1812 | case NL80211_IFTYPE_AP_VLAN: | ||
1813 | /* all ok but must have AID */ | ||
1814 | if (!params.aid) | ||
1815 | err = -EINVAL; | ||
1816 | break; | ||
1817 | case NL80211_IFTYPE_MESH_POINT: | ||
1818 | /* disallow things mesh doesn't support */ | ||
1819 | if (params.vlan) | ||
1820 | err = -EINVAL; | ||
1821 | if (params.aid) | ||
1822 | err = -EINVAL; | ||
1823 | if (params.ht_capa) | ||
1824 | err = -EINVAL; | ||
1825 | if (params.listen_interval >= 0) | ||
1826 | err = -EINVAL; | ||
1827 | if (params.supported_rates) | ||
1828 | err = -EINVAL; | ||
1829 | if (params.sta_flags_mask) | ||
1830 | err = -EINVAL; | ||
1831 | break; | ||
1832 | default: | ||
1833 | err = -EINVAL; | ||
1834 | } | ||
1835 | |||
1836 | if (err) | ||
1837 | goto out; | ||
1838 | |||
1589 | if (!drv->ops->add_station) { | 1839 | if (!drv->ops->add_station) { |
1590 | err = -EOPNOTSUPP; | 1840 | err = -EOPNOTSUPP; |
1591 | goto out; | 1841 | goto out; |
@@ -1625,6 +1875,13 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | |||
1625 | if (err) | 1875 | if (err) |
1626 | goto out_rtnl; | 1876 | goto out_rtnl; |
1627 | 1877 | ||
1878 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
1879 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && | ||
1880 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { | ||
1881 | err = -EINVAL; | ||
1882 | goto out; | ||
1883 | } | ||
1884 | |||
1628 | if (!drv->ops->del_station) { | 1885 | if (!drv->ops->del_station) { |
1629 | err = -EOPNOTSUPP; | 1886 | err = -EOPNOTSUPP; |
1630 | goto out; | 1887 | goto out; |
@@ -1808,7 +2065,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | |||
1808 | if (err) | 2065 | if (err) |
1809 | goto out; | 2066 | goto out; |
1810 | 2067 | ||
1811 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 2068 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1812 | if (!msg) | 2069 | if (!msg) |
1813 | goto out; | 2070 | goto out; |
1814 | 2071 | ||
@@ -2124,7 +2381,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2124 | goto out; | 2381 | goto out; |
2125 | 2382 | ||
2126 | /* Draw up a netlink message to send back */ | 2383 | /* Draw up a netlink message to send back */ |
2127 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 2384 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
2128 | if (!msg) { | 2385 | if (!msg) { |
2129 | err = -ENOBUFS; | 2386 | err = -ENOBUFS; |
2130 | goto out; | 2387 | goto out; |
@@ -2302,7 +2559,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
2302 | if (!cfg80211_regdomain) | 2559 | if (!cfg80211_regdomain) |
2303 | goto out; | 2560 | goto out; |
2304 | 2561 | ||
2305 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 2562 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
2306 | if (!msg) { | 2563 | if (!msg) { |
2307 | err = -ENOBUFS; | 2564 | err = -ENOBUFS; |
2308 | goto out; | 2565 | goto out; |
@@ -2385,18 +2642,24 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2385 | rem_reg_rules) { | 2642 | rem_reg_rules) { |
2386 | num_rules++; | 2643 | num_rules++; |
2387 | if (num_rules > NL80211_MAX_SUPP_REG_RULES) | 2644 | if (num_rules > NL80211_MAX_SUPP_REG_RULES) |
2388 | goto bad_reg; | 2645 | return -EINVAL; |
2389 | } | 2646 | } |
2390 | 2647 | ||
2391 | if (!reg_is_valid_request(alpha2)) | 2648 | mutex_lock(&cfg80211_mutex); |
2392 | return -EINVAL; | 2649 | |
2650 | if (!reg_is_valid_request(alpha2)) { | ||
2651 | r = -EINVAL; | ||
2652 | goto bad_reg; | ||
2653 | } | ||
2393 | 2654 | ||
2394 | size_of_regd = sizeof(struct ieee80211_regdomain) + | 2655 | size_of_regd = sizeof(struct ieee80211_regdomain) + |
2395 | (num_rules * sizeof(struct ieee80211_reg_rule)); | 2656 | (num_rules * sizeof(struct ieee80211_reg_rule)); |
2396 | 2657 | ||
2397 | rd = kzalloc(size_of_regd, GFP_KERNEL); | 2658 | rd = kzalloc(size_of_regd, GFP_KERNEL); |
2398 | if (!rd) | 2659 | if (!rd) { |
2399 | return -ENOMEM; | 2660 | r = -ENOMEM; |
2661 | goto bad_reg; | ||
2662 | } | ||
2400 | 2663 | ||
2401 | rd->n_reg_rules = num_rules; | 2664 | rd->n_reg_rules = num_rules; |
2402 | rd->alpha2[0] = alpha2[0]; | 2665 | rd->alpha2[0] = alpha2[0]; |
@@ -2413,20 +2676,24 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2413 | 2676 | ||
2414 | rule_idx++; | 2677 | rule_idx++; |
2415 | 2678 | ||
2416 | if (rule_idx > NL80211_MAX_SUPP_REG_RULES) | 2679 | if (rule_idx > NL80211_MAX_SUPP_REG_RULES) { |
2680 | r = -EINVAL; | ||
2417 | goto bad_reg; | 2681 | goto bad_reg; |
2682 | } | ||
2418 | } | 2683 | } |
2419 | 2684 | ||
2420 | BUG_ON(rule_idx != num_rules); | 2685 | BUG_ON(rule_idx != num_rules); |
2421 | 2686 | ||
2422 | mutex_lock(&cfg80211_mutex); | ||
2423 | r = set_regdom(rd); | 2687 | r = set_regdom(rd); |
2688 | |||
2424 | mutex_unlock(&cfg80211_mutex); | 2689 | mutex_unlock(&cfg80211_mutex); |
2690 | |||
2425 | return r; | 2691 | return r; |
2426 | 2692 | ||
2427 | bad_reg: | 2693 | bad_reg: |
2694 | mutex_unlock(&cfg80211_mutex); | ||
2428 | kfree(rd); | 2695 | kfree(rd); |
2429 | return -EINVAL; | 2696 | return r; |
2430 | } | 2697 | } |
2431 | 2698 | ||
2432 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | 2699 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) |
@@ -2442,6 +2709,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2442 | enum ieee80211_band band; | 2709 | enum ieee80211_band band; |
2443 | size_t ie_len; | 2710 | size_t ie_len; |
2444 | 2711 | ||
2712 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
2713 | return -EINVAL; | ||
2714 | |||
2445 | rtnl_lock(); | 2715 | rtnl_lock(); |
2446 | 2716 | ||
2447 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 2717 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
@@ -2492,6 +2762,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2492 | else | 2762 | else |
2493 | ie_len = 0; | 2763 | ie_len = 0; |
2494 | 2764 | ||
2765 | if (ie_len > wiphy->max_scan_ie_len) { | ||
2766 | err = -EINVAL; | ||
2767 | goto out; | ||
2768 | } | ||
2769 | |||
2495 | request = kzalloc(sizeof(*request) | 2770 | request = kzalloc(sizeof(*request) |
2496 | + sizeof(*ssid) * n_ssids | 2771 | + sizeof(*ssid) * n_ssids |
2497 | + sizeof(channel) * n_channels | 2772 | + sizeof(channel) * n_channels |
@@ -2554,7 +2829,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2554 | 2829 | ||
2555 | if (info->attrs[NL80211_ATTR_IE]) { | 2830 | if (info->attrs[NL80211_ATTR_IE]) { |
2556 | request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 2831 | request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
2557 | memcpy(request->ie, nla_data(info->attrs[NL80211_ATTR_IE]), | 2832 | memcpy((void *)request->ie, |
2833 | nla_data(info->attrs[NL80211_ATTR_IE]), | ||
2558 | request->ie_len); | 2834 | request->ie_len); |
2559 | } | 2835 | } |
2560 | 2836 | ||
@@ -2710,6 +2986,15 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
2710 | struct wiphy *wiphy; | 2986 | struct wiphy *wiphy; |
2711 | int err; | 2987 | int err; |
2712 | 2988 | ||
2989 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
2990 | return -EINVAL; | ||
2991 | |||
2992 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
2993 | return -EINVAL; | ||
2994 | |||
2995 | if (!info->attrs[NL80211_ATTR_AUTH_TYPE]) | ||
2996 | return -EINVAL; | ||
2997 | |||
2713 | rtnl_lock(); | 2998 | rtnl_lock(); |
2714 | 2999 | ||
2715 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 3000 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
@@ -2731,11 +3016,6 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
2731 | goto out; | 3016 | goto out; |
2732 | } | 3017 | } |
2733 | 3018 | ||
2734 | if (!info->attrs[NL80211_ATTR_MAC]) { | ||
2735 | err = -EINVAL; | ||
2736 | goto out; | ||
2737 | } | ||
2738 | |||
2739 | wiphy = &drv->wiphy; | 3019 | wiphy = &drv->wiphy; |
2740 | memset(&req, 0, sizeof(req)); | 3020 | memset(&req, 0, sizeof(req)); |
2741 | 3021 | ||
@@ -2761,13 +3041,10 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
2761 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 3041 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
2762 | } | 3042 | } |
2763 | 3043 | ||
2764 | if (info->attrs[NL80211_ATTR_AUTH_TYPE]) { | 3044 | req.auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); |
2765 | req.auth_type = | 3045 | if (!nl80211_valid_auth_type(req.auth_type)) { |
2766 | nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); | 3046 | err = -EINVAL; |
2767 | if (!nl80211_valid_auth_type(req.auth_type)) { | 3047 | goto out; |
2768 | err = -EINVAL; | ||
2769 | goto out; | ||
2770 | } | ||
2771 | } | 3048 | } |
2772 | 3049 | ||
2773 | err = drv->ops->auth(&drv->wiphy, dev, &req); | 3050 | err = drv->ops->auth(&drv->wiphy, dev, &req); |
@@ -2788,6 +3065,13 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
2788 | struct wiphy *wiphy; | 3065 | struct wiphy *wiphy; |
2789 | int err; | 3066 | int err; |
2790 | 3067 | ||
3068 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
3069 | return -EINVAL; | ||
3070 | |||
3071 | if (!info->attrs[NL80211_ATTR_MAC] || | ||
3072 | !info->attrs[NL80211_ATTR_SSID]) | ||
3073 | return -EINVAL; | ||
3074 | |||
2791 | rtnl_lock(); | 3075 | rtnl_lock(); |
2792 | 3076 | ||
2793 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 3077 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
@@ -2809,12 +3093,6 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
2809 | goto out; | 3093 | goto out; |
2810 | } | 3094 | } |
2811 | 3095 | ||
2812 | if (!info->attrs[NL80211_ATTR_MAC] || | ||
2813 | !info->attrs[NL80211_ATTR_SSID]) { | ||
2814 | err = -EINVAL; | ||
2815 | goto out; | ||
2816 | } | ||
2817 | |||
2818 | wiphy = &drv->wiphy; | 3096 | wiphy = &drv->wiphy; |
2819 | memset(&req, 0, sizeof(req)); | 3097 | memset(&req, 0, sizeof(req)); |
2820 | 3098 | ||
@@ -2838,6 +3116,19 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
2838 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 3116 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
2839 | } | 3117 | } |
2840 | 3118 | ||
3119 | if (info->attrs[NL80211_ATTR_USE_MFP]) { | ||
3120 | enum nl80211_mfp use_mfp = | ||
3121 | nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); | ||
3122 | if (use_mfp == NL80211_MFP_REQUIRED) | ||
3123 | req.use_mfp = true; | ||
3124 | else if (use_mfp != NL80211_MFP_NO) { | ||
3125 | err = -EINVAL; | ||
3126 | goto out; | ||
3127 | } | ||
3128 | } | ||
3129 | |||
3130 | req.control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; | ||
3131 | |||
2841 | err = drv->ops->assoc(&drv->wiphy, dev, &req); | 3132 | err = drv->ops->assoc(&drv->wiphy, dev, &req); |
2842 | 3133 | ||
2843 | out: | 3134 | out: |
@@ -2856,6 +3147,15 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
2856 | struct wiphy *wiphy; | 3147 | struct wiphy *wiphy; |
2857 | int err; | 3148 | int err; |
2858 | 3149 | ||
3150 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
3151 | return -EINVAL; | ||
3152 | |||
3153 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
3154 | return -EINVAL; | ||
3155 | |||
3156 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | ||
3157 | return -EINVAL; | ||
3158 | |||
2859 | rtnl_lock(); | 3159 | rtnl_lock(); |
2860 | 3160 | ||
2861 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 3161 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
@@ -2877,24 +3177,16 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
2877 | goto out; | 3177 | goto out; |
2878 | } | 3178 | } |
2879 | 3179 | ||
2880 | if (!info->attrs[NL80211_ATTR_MAC]) { | ||
2881 | err = -EINVAL; | ||
2882 | goto out; | ||
2883 | } | ||
2884 | |||
2885 | wiphy = &drv->wiphy; | 3180 | wiphy = &drv->wiphy; |
2886 | memset(&req, 0, sizeof(req)); | 3181 | memset(&req, 0, sizeof(req)); |
2887 | 3182 | ||
2888 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3183 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2889 | 3184 | ||
2890 | if (info->attrs[NL80211_ATTR_REASON_CODE]) { | 3185 | req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); |
2891 | req.reason_code = | 3186 | if (req.reason_code == 0) { |
2892 | nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | 3187 | /* Reason Code 0 is reserved */ |
2893 | if (req.reason_code == 0) { | 3188 | err = -EINVAL; |
2894 | /* Reason Code 0 is reserved */ | 3189 | goto out; |
2895 | err = -EINVAL; | ||
2896 | goto out; | ||
2897 | } | ||
2898 | } | 3190 | } |
2899 | 3191 | ||
2900 | if (info->attrs[NL80211_ATTR_IE]) { | 3192 | if (info->attrs[NL80211_ATTR_IE]) { |
@@ -2920,6 +3212,15 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
2920 | struct wiphy *wiphy; | 3212 | struct wiphy *wiphy; |
2921 | int err; | 3213 | int err; |
2922 | 3214 | ||
3215 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
3216 | return -EINVAL; | ||
3217 | |||
3218 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
3219 | return -EINVAL; | ||
3220 | |||
3221 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | ||
3222 | return -EINVAL; | ||
3223 | |||
2923 | rtnl_lock(); | 3224 | rtnl_lock(); |
2924 | 3225 | ||
2925 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 3226 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
@@ -2941,24 +3242,16 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
2941 | goto out; | 3242 | goto out; |
2942 | } | 3243 | } |
2943 | 3244 | ||
2944 | if (!info->attrs[NL80211_ATTR_MAC]) { | ||
2945 | err = -EINVAL; | ||
2946 | goto out; | ||
2947 | } | ||
2948 | |||
2949 | wiphy = &drv->wiphy; | 3245 | wiphy = &drv->wiphy; |
2950 | memset(&req, 0, sizeof(req)); | 3246 | memset(&req, 0, sizeof(req)); |
2951 | 3247 | ||
2952 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3248 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2953 | 3249 | ||
2954 | if (info->attrs[NL80211_ATTR_REASON_CODE]) { | 3250 | req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); |
2955 | req.reason_code = | 3251 | if (req.reason_code == 0) { |
2956 | nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | 3252 | /* Reason Code 0 is reserved */ |
2957 | if (req.reason_code == 0) { | 3253 | err = -EINVAL; |
2958 | /* Reason Code 0 is reserved */ | 3254 | goto out; |
2959 | err = -EINVAL; | ||
2960 | goto out; | ||
2961 | } | ||
2962 | } | 3255 | } |
2963 | 3256 | ||
2964 | if (info->attrs[NL80211_ATTR_IE]) { | 3257 | if (info->attrs[NL80211_ATTR_IE]) { |
@@ -2976,6 +3269,124 @@ unlock_rtnl: | |||
2976 | return err; | 3269 | return err; |
2977 | } | 3270 | } |
2978 | 3271 | ||
3272 | static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | ||
3273 | { | ||
3274 | struct cfg80211_registered_device *drv; | ||
3275 | struct net_device *dev; | ||
3276 | struct cfg80211_ibss_params ibss; | ||
3277 | struct wiphy *wiphy; | ||
3278 | int err; | ||
3279 | |||
3280 | memset(&ibss, 0, sizeof(ibss)); | ||
3281 | |||
3282 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
3283 | return -EINVAL; | ||
3284 | |||
3285 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || | ||
3286 | !info->attrs[NL80211_ATTR_SSID] || | ||
3287 | !nla_len(info->attrs[NL80211_ATTR_SSID])) | ||
3288 | return -EINVAL; | ||
3289 | |||
3290 | ibss.beacon_interval = 100; | ||
3291 | |||
3292 | if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) { | ||
3293 | ibss.beacon_interval = | ||
3294 | nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); | ||
3295 | if (ibss.beacon_interval < 1 || ibss.beacon_interval > 10000) | ||
3296 | return -EINVAL; | ||
3297 | } | ||
3298 | |||
3299 | rtnl_lock(); | ||
3300 | |||
3301 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
3302 | if (err) | ||
3303 | goto unlock_rtnl; | ||
3304 | |||
3305 | if (!drv->ops->join_ibss) { | ||
3306 | err = -EOPNOTSUPP; | ||
3307 | goto out; | ||
3308 | } | ||
3309 | |||
3310 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | ||
3311 | err = -EOPNOTSUPP; | ||
3312 | goto out; | ||
3313 | } | ||
3314 | |||
3315 | if (!netif_running(dev)) { | ||
3316 | err = -ENETDOWN; | ||
3317 | goto out; | ||
3318 | } | ||
3319 | |||
3320 | wiphy = &drv->wiphy; | ||
3321 | |||
3322 | if (info->attrs[NL80211_ATTR_MAC]) | ||
3323 | ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
3324 | ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | ||
3325 | ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | ||
3326 | |||
3327 | if (info->attrs[NL80211_ATTR_IE]) { | ||
3328 | ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
3329 | ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
3330 | } | ||
3331 | |||
3332 | ibss.channel = ieee80211_get_channel(wiphy, | ||
3333 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | ||
3334 | if (!ibss.channel || | ||
3335 | ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || | ||
3336 | ibss.channel->flags & IEEE80211_CHAN_DISABLED) { | ||
3337 | err = -EINVAL; | ||
3338 | goto out; | ||
3339 | } | ||
3340 | |||
3341 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; | ||
3342 | |||
3343 | err = cfg80211_join_ibss(drv, dev, &ibss); | ||
3344 | |||
3345 | out: | ||
3346 | cfg80211_put_dev(drv); | ||
3347 | dev_put(dev); | ||
3348 | unlock_rtnl: | ||
3349 | rtnl_unlock(); | ||
3350 | return err; | ||
3351 | } | ||
3352 | |||
3353 | static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) | ||
3354 | { | ||
3355 | struct cfg80211_registered_device *drv; | ||
3356 | struct net_device *dev; | ||
3357 | int err; | ||
3358 | |||
3359 | rtnl_lock(); | ||
3360 | |||
3361 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
3362 | if (err) | ||
3363 | goto unlock_rtnl; | ||
3364 | |||
3365 | if (!drv->ops->leave_ibss) { | ||
3366 | err = -EOPNOTSUPP; | ||
3367 | goto out; | ||
3368 | } | ||
3369 | |||
3370 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | ||
3371 | err = -EOPNOTSUPP; | ||
3372 | goto out; | ||
3373 | } | ||
3374 | |||
3375 | if (!netif_running(dev)) { | ||
3376 | err = -ENETDOWN; | ||
3377 | goto out; | ||
3378 | } | ||
3379 | |||
3380 | err = cfg80211_leave_ibss(drv, dev, false); | ||
3381 | |||
3382 | out: | ||
3383 | cfg80211_put_dev(drv); | ||
3384 | dev_put(dev); | ||
3385 | unlock_rtnl: | ||
3386 | rtnl_unlock(); | ||
3387 | return err; | ||
3388 | } | ||
3389 | |||
2979 | static struct genl_ops nl80211_ops[] = { | 3390 | static struct genl_ops nl80211_ops[] = { |
2980 | { | 3391 | { |
2981 | .cmd = NL80211_CMD_GET_WIPHY, | 3392 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -3177,6 +3588,18 @@ static struct genl_ops nl80211_ops[] = { | |||
3177 | .policy = nl80211_policy, | 3588 | .policy = nl80211_policy, |
3178 | .flags = GENL_ADMIN_PERM, | 3589 | .flags = GENL_ADMIN_PERM, |
3179 | }, | 3590 | }, |
3591 | { | ||
3592 | .cmd = NL80211_CMD_JOIN_IBSS, | ||
3593 | .doit = nl80211_join_ibss, | ||
3594 | .policy = nl80211_policy, | ||
3595 | .flags = GENL_ADMIN_PERM, | ||
3596 | }, | ||
3597 | { | ||
3598 | .cmd = NL80211_CMD_LEAVE_IBSS, | ||
3599 | .doit = nl80211_leave_ibss, | ||
3600 | .policy = nl80211_policy, | ||
3601 | .flags = GENL_ADMIN_PERM, | ||
3602 | }, | ||
3180 | }; | 3603 | }; |
3181 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 3604 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
3182 | .name = "mlme", | 3605 | .name = "mlme", |
@@ -3199,7 +3622,7 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) | |||
3199 | { | 3622 | { |
3200 | struct sk_buff *msg; | 3623 | struct sk_buff *msg; |
3201 | 3624 | ||
3202 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 3625 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
3203 | if (!msg) | 3626 | if (!msg) |
3204 | return; | 3627 | return; |
3205 | 3628 | ||
@@ -3211,11 +3634,43 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) | |||
3211 | genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); | 3634 | genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); |
3212 | } | 3635 | } |
3213 | 3636 | ||
3637 | static int nl80211_add_scan_req(struct sk_buff *msg, | ||
3638 | struct cfg80211_registered_device *rdev) | ||
3639 | { | ||
3640 | struct cfg80211_scan_request *req = rdev->scan_req; | ||
3641 | struct nlattr *nest; | ||
3642 | int i; | ||
3643 | |||
3644 | if (WARN_ON(!req)) | ||
3645 | return 0; | ||
3646 | |||
3647 | nest = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS); | ||
3648 | if (!nest) | ||
3649 | goto nla_put_failure; | ||
3650 | for (i = 0; i < req->n_ssids; i++) | ||
3651 | NLA_PUT(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid); | ||
3652 | nla_nest_end(msg, nest); | ||
3653 | |||
3654 | nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES); | ||
3655 | if (!nest) | ||
3656 | goto nla_put_failure; | ||
3657 | for (i = 0; i < req->n_channels; i++) | ||
3658 | NLA_PUT_U32(msg, i, req->channels[i]->center_freq); | ||
3659 | nla_nest_end(msg, nest); | ||
3660 | |||
3661 | if (req->ie) | ||
3662 | NLA_PUT(msg, NL80211_ATTR_IE, req->ie_len, req->ie); | ||
3663 | |||
3664 | return 0; | ||
3665 | nla_put_failure: | ||
3666 | return -ENOBUFS; | ||
3667 | } | ||
3668 | |||
3214 | static int nl80211_send_scan_donemsg(struct sk_buff *msg, | 3669 | static int nl80211_send_scan_donemsg(struct sk_buff *msg, |
3215 | struct cfg80211_registered_device *rdev, | 3670 | struct cfg80211_registered_device *rdev, |
3216 | struct net_device *netdev, | 3671 | struct net_device *netdev, |
3217 | u32 pid, u32 seq, int flags, | 3672 | u32 pid, u32 seq, int flags, |
3218 | u32 cmd) | 3673 | u32 cmd) |
3219 | { | 3674 | { |
3220 | void *hdr; | 3675 | void *hdr; |
3221 | 3676 | ||
@@ -3226,7 +3681,8 @@ static int nl80211_send_scan_donemsg(struct sk_buff *msg, | |||
3226 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | 3681 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); |
3227 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | 3682 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); |
3228 | 3683 | ||
3229 | /* XXX: we should probably bounce back the request? */ | 3684 | /* ignore errors and send incomplete event anyway */ |
3685 | nl80211_add_scan_req(msg, rdev); | ||
3230 | 3686 | ||
3231 | return genlmsg_end(msg, hdr); | 3687 | return genlmsg_end(msg, hdr); |
3232 | 3688 | ||
@@ -3240,7 +3696,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | |||
3240 | { | 3696 | { |
3241 | struct sk_buff *msg; | 3697 | struct sk_buff *msg; |
3242 | 3698 | ||
3243 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 3699 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
3244 | if (!msg) | 3700 | if (!msg) |
3245 | return; | 3701 | return; |
3246 | 3702 | ||
@@ -3258,7 +3714,7 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | |||
3258 | { | 3714 | { |
3259 | struct sk_buff *msg; | 3715 | struct sk_buff *msg; |
3260 | 3716 | ||
3261 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 3717 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
3262 | if (!msg) | 3718 | if (!msg) |
3263 | return; | 3719 | return; |
3264 | 3720 | ||
@@ -3280,7 +3736,7 @@ void nl80211_send_reg_change_event(struct regulatory_request *request) | |||
3280 | struct sk_buff *msg; | 3736 | struct sk_buff *msg; |
3281 | void *hdr; | 3737 | void *hdr; |
3282 | 3738 | ||
3283 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 3739 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
3284 | if (!msg) | 3740 | if (!msg) |
3285 | return; | 3741 | return; |
3286 | 3742 | ||
@@ -3334,7 +3790,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, | |||
3334 | struct sk_buff *msg; | 3790 | struct sk_buff *msg; |
3335 | void *hdr; | 3791 | void *hdr; |
3336 | 3792 | ||
3337 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); | 3793 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); |
3338 | if (!msg) | 3794 | if (!msg) |
3339 | return; | 3795 | return; |
3340 | 3796 | ||
@@ -3375,38 +3831,208 @@ void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, | |||
3375 | nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_ASSOCIATE); | 3831 | nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_ASSOCIATE); |
3376 | } | 3832 | } |
3377 | 3833 | ||
3378 | void nl80211_send_rx_deauth(struct cfg80211_registered_device *rdev, | 3834 | void nl80211_send_deauth(struct cfg80211_registered_device *rdev, |
3379 | struct net_device *netdev, const u8 *buf, | 3835 | struct net_device *netdev, const u8 *buf, size_t len) |
3380 | size_t len) | ||
3381 | { | 3836 | { |
3382 | nl80211_send_mlme_event(rdev, netdev, buf, len, | 3837 | nl80211_send_mlme_event(rdev, netdev, buf, len, |
3383 | NL80211_CMD_DEAUTHENTICATE); | 3838 | NL80211_CMD_DEAUTHENTICATE); |
3384 | } | 3839 | } |
3385 | 3840 | ||
3386 | void nl80211_send_rx_disassoc(struct cfg80211_registered_device *rdev, | 3841 | void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, |
3387 | struct net_device *netdev, const u8 *buf, | 3842 | struct net_device *netdev, const u8 *buf, |
3388 | size_t len) | 3843 | size_t len) |
3389 | { | 3844 | { |
3390 | nl80211_send_mlme_event(rdev, netdev, buf, len, | 3845 | nl80211_send_mlme_event(rdev, netdev, buf, len, |
3391 | NL80211_CMD_DISASSOCIATE); | 3846 | NL80211_CMD_DISASSOCIATE); |
3392 | } | 3847 | } |
3393 | 3848 | ||
3849 | static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, | ||
3850 | struct net_device *netdev, int cmd, | ||
3851 | const u8 *addr) | ||
3852 | { | ||
3853 | struct sk_buff *msg; | ||
3854 | void *hdr; | ||
3855 | |||
3856 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); | ||
3857 | if (!msg) | ||
3858 | return; | ||
3859 | |||
3860 | hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); | ||
3861 | if (!hdr) { | ||
3862 | nlmsg_free(msg); | ||
3863 | return; | ||
3864 | } | ||
3865 | |||
3866 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
3867 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
3868 | NLA_PUT_FLAG(msg, NL80211_ATTR_TIMED_OUT); | ||
3869 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); | ||
3870 | |||
3871 | if (genlmsg_end(msg, hdr) < 0) { | ||
3872 | nlmsg_free(msg); | ||
3873 | return; | ||
3874 | } | ||
3875 | |||
3876 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC); | ||
3877 | return; | ||
3878 | |||
3879 | nla_put_failure: | ||
3880 | genlmsg_cancel(msg, hdr); | ||
3881 | nlmsg_free(msg); | ||
3882 | } | ||
3883 | |||
3884 | void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, | ||
3885 | struct net_device *netdev, const u8 *addr) | ||
3886 | { | ||
3887 | nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE, | ||
3888 | addr); | ||
3889 | } | ||
3890 | |||
3891 | void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, | ||
3892 | struct net_device *netdev, const u8 *addr) | ||
3893 | { | ||
3894 | nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE, addr); | ||
3895 | } | ||
3896 | |||
3897 | void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, | ||
3898 | struct net_device *netdev, const u8 *bssid, | ||
3899 | gfp_t gfp) | ||
3900 | { | ||
3901 | struct sk_buff *msg; | ||
3902 | void *hdr; | ||
3903 | |||
3904 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | ||
3905 | if (!msg) | ||
3906 | return; | ||
3907 | |||
3908 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS); | ||
3909 | if (!hdr) { | ||
3910 | nlmsg_free(msg); | ||
3911 | return; | ||
3912 | } | ||
3913 | |||
3914 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
3915 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
3916 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); | ||
3917 | |||
3918 | if (genlmsg_end(msg, hdr) < 0) { | ||
3919 | nlmsg_free(msg); | ||
3920 | return; | ||
3921 | } | ||
3922 | |||
3923 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); | ||
3924 | return; | ||
3925 | |||
3926 | nla_put_failure: | ||
3927 | genlmsg_cancel(msg, hdr); | ||
3928 | nlmsg_free(msg); | ||
3929 | } | ||
3930 | |||
3931 | void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, | ||
3932 | struct net_device *netdev, const u8 *addr, | ||
3933 | enum nl80211_key_type key_type, int key_id, | ||
3934 | const u8 *tsc) | ||
3935 | { | ||
3936 | struct sk_buff *msg; | ||
3937 | void *hdr; | ||
3938 | |||
3939 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); | ||
3940 | if (!msg) | ||
3941 | return; | ||
3942 | |||
3943 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE); | ||
3944 | if (!hdr) { | ||
3945 | nlmsg_free(msg); | ||
3946 | return; | ||
3947 | } | ||
3948 | |||
3949 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
3950 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
3951 | if (addr) | ||
3952 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); | ||
3953 | NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, key_type); | ||
3954 | NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id); | ||
3955 | if (tsc) | ||
3956 | NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc); | ||
3957 | |||
3958 | if (genlmsg_end(msg, hdr) < 0) { | ||
3959 | nlmsg_free(msg); | ||
3960 | return; | ||
3961 | } | ||
3962 | |||
3963 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC); | ||
3964 | return; | ||
3965 | |||
3966 | nla_put_failure: | ||
3967 | genlmsg_cancel(msg, hdr); | ||
3968 | nlmsg_free(msg); | ||
3969 | } | ||
3970 | |||
3971 | void nl80211_send_beacon_hint_event(struct wiphy *wiphy, | ||
3972 | struct ieee80211_channel *channel_before, | ||
3973 | struct ieee80211_channel *channel_after) | ||
3974 | { | ||
3975 | struct sk_buff *msg; | ||
3976 | void *hdr; | ||
3977 | struct nlattr *nl_freq; | ||
3978 | |||
3979 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); | ||
3980 | if (!msg) | ||
3981 | return; | ||
3982 | |||
3983 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_BEACON_HINT); | ||
3984 | if (!hdr) { | ||
3985 | nlmsg_free(msg); | ||
3986 | return; | ||
3987 | } | ||
3988 | |||
3989 | /* | ||
3990 | * Since we are applying the beacon hint to a wiphy we know its | ||
3991 | * wiphy_idx is valid | ||
3992 | */ | ||
3993 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)); | ||
3994 | |||
3995 | /* Before */ | ||
3996 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE); | ||
3997 | if (!nl_freq) | ||
3998 | goto nla_put_failure; | ||
3999 | if (nl80211_msg_put_channel(msg, channel_before)) | ||
4000 | goto nla_put_failure; | ||
4001 | nla_nest_end(msg, nl_freq); | ||
4002 | |||
4003 | /* After */ | ||
4004 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER); | ||
4005 | if (!nl_freq) | ||
4006 | goto nla_put_failure; | ||
4007 | if (nl80211_msg_put_channel(msg, channel_after)) | ||
4008 | goto nla_put_failure; | ||
4009 | nla_nest_end(msg, nl_freq); | ||
4010 | |||
4011 | if (genlmsg_end(msg, hdr) < 0) { | ||
4012 | nlmsg_free(msg); | ||
4013 | return; | ||
4014 | } | ||
4015 | |||
4016 | genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_ATOMIC); | ||
4017 | |||
4018 | return; | ||
4019 | |||
4020 | nla_put_failure: | ||
4021 | genlmsg_cancel(msg, hdr); | ||
4022 | nlmsg_free(msg); | ||
4023 | } | ||
4024 | |||
3394 | /* initialisation/exit functions */ | 4025 | /* initialisation/exit functions */ |
3395 | 4026 | ||
3396 | int nl80211_init(void) | 4027 | int nl80211_init(void) |
3397 | { | 4028 | { |
3398 | int err, i; | 4029 | int err; |
3399 | 4030 | ||
3400 | err = genl_register_family(&nl80211_fam); | 4031 | err = genl_register_family_with_ops(&nl80211_fam, |
4032 | nl80211_ops, ARRAY_SIZE(nl80211_ops)); | ||
3401 | if (err) | 4033 | if (err) |
3402 | return err; | 4034 | return err; |
3403 | 4035 | ||
3404 | for (i = 0; i < ARRAY_SIZE(nl80211_ops); i++) { | ||
3405 | err = genl_register_ops(&nl80211_fam, &nl80211_ops[i]); | ||
3406 | if (err) | ||
3407 | goto err_out; | ||
3408 | } | ||
3409 | |||
3410 | err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp); | 4036 | err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp); |
3411 | if (err) | 4037 | if (err) |
3412 | goto err_out; | 4038 | goto err_out; |