diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 923 |
1 files changed, 742 insertions, 181 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 2456e4ee445e..24168560ebae 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) | 524 | goto bad_res; |
450 | sec_freq = freq + 20; | 525 | else if (channel_type == NL80211_CHAN_HT40PLUS && |
451 | else | 526 | (chan->flags & IEEE80211_CHAN_NO_HT40PLUS)) |
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; | 527 | goto bad_res; |
460 | 528 | ||
461 | if (sec_freq) { | 529 | /* |
462 | struct ieee80211_channel *schan; | 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 | */ | ||
463 | 534 | ||
464 | /* no 40 MHz capabilities */ | 535 | ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; |
536 | |||
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,44 +1124,8 @@ 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; | ||
963 | |||
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; | 1128 | return -EINVAL; |
998 | } | ||
999 | 1129 | ||
1000 | rtnl_lock(); | 1130 | rtnl_lock(); |
1001 | 1131 | ||
@@ -1003,6 +1133,14 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
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]) |
@@ -1516,6 +1687,12 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
1516 | if (err) | 1687 | if (err) |
1517 | goto out_rtnl; | 1688 | goto out_rtnl; |
1518 | 1689 | ||
1690 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
1691 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) { | ||
1692 | err = -EINVAL; | ||
1693 | goto out; | ||
1694 | } | ||
1695 | |||
1519 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); | 1696 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); |
1520 | if (err) | 1697 | if (err) |
1521 | goto out; | 1698 | goto out; |
@@ -1567,13 +1744,16 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
1567 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); | 1744 | nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); |
1568 | params.listen_interval = | 1745 | params.listen_interval = |
1569 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); | 1746 | nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); |
1747 | |||
1570 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); | 1748 | params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); |
1749 | if (!params.aid || params.aid > IEEE80211_MAX_AID) | ||
1750 | return -EINVAL; | ||
1751 | |||
1571 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) | 1752 | if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) |
1572 | params.ht_capa = | 1753 | params.ht_capa = |
1573 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); | 1754 | nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]); |
1574 | 1755 | ||
1575 | if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], | 1756 | if (parse_station_flags(info, ¶ms)) |
1576 | ¶ms.station_flags)) | ||
1577 | return -EINVAL; | 1757 | return -EINVAL; |
1578 | 1758 | ||
1579 | rtnl_lock(); | 1759 | rtnl_lock(); |
@@ -1582,6 +1762,12 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
1582 | if (err) | 1762 | if (err) |
1583 | goto out_rtnl; | 1763 | goto out_rtnl; |
1584 | 1764 | ||
1765 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
1766 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) { | ||
1767 | err = -EINVAL; | ||
1768 | goto out; | ||
1769 | } | ||
1770 | |||
1585 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); | 1771 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); |
1586 | if (err) | 1772 | if (err) |
1587 | goto out; | 1773 | goto out; |
@@ -1625,6 +1811,12 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | |||
1625 | if (err) | 1811 | if (err) |
1626 | goto out_rtnl; | 1812 | goto out_rtnl; |
1627 | 1813 | ||
1814 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && | ||
1815 | dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) { | ||
1816 | err = -EINVAL; | ||
1817 | goto out; | ||
1818 | } | ||
1819 | |||
1628 | if (!drv->ops->del_station) { | 1820 | if (!drv->ops->del_station) { |
1629 | err = -EOPNOTSUPP; | 1821 | err = -EOPNOTSUPP; |
1630 | goto out; | 1822 | goto out; |
@@ -1808,7 +2000,7 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | |||
1808 | if (err) | 2000 | if (err) |
1809 | goto out; | 2001 | goto out; |
1810 | 2002 | ||
1811 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 2003 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
1812 | if (!msg) | 2004 | if (!msg) |
1813 | goto out; | 2005 | goto out; |
1814 | 2006 | ||
@@ -2124,7 +2316,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2124 | goto out; | 2316 | goto out; |
2125 | 2317 | ||
2126 | /* Draw up a netlink message to send back */ | 2318 | /* Draw up a netlink message to send back */ |
2127 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 2319 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
2128 | if (!msg) { | 2320 | if (!msg) { |
2129 | err = -ENOBUFS; | 2321 | err = -ENOBUFS; |
2130 | goto out; | 2322 | goto out; |
@@ -2302,7 +2494,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
2302 | if (!cfg80211_regdomain) | 2494 | if (!cfg80211_regdomain) |
2303 | goto out; | 2495 | goto out; |
2304 | 2496 | ||
2305 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 2497 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
2306 | if (!msg) { | 2498 | if (!msg) { |
2307 | err = -ENOBUFS; | 2499 | err = -ENOBUFS; |
2308 | goto out; | 2500 | goto out; |
@@ -2385,18 +2577,24 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2385 | rem_reg_rules) { | 2577 | rem_reg_rules) { |
2386 | num_rules++; | 2578 | num_rules++; |
2387 | if (num_rules > NL80211_MAX_SUPP_REG_RULES) | 2579 | if (num_rules > NL80211_MAX_SUPP_REG_RULES) |
2388 | goto bad_reg; | 2580 | return -EINVAL; |
2389 | } | 2581 | } |
2390 | 2582 | ||
2391 | if (!reg_is_valid_request(alpha2)) | 2583 | mutex_lock(&cfg80211_mutex); |
2392 | return -EINVAL; | 2584 | |
2585 | if (!reg_is_valid_request(alpha2)) { | ||
2586 | r = -EINVAL; | ||
2587 | goto bad_reg; | ||
2588 | } | ||
2393 | 2589 | ||
2394 | size_of_regd = sizeof(struct ieee80211_regdomain) + | 2590 | size_of_regd = sizeof(struct ieee80211_regdomain) + |
2395 | (num_rules * sizeof(struct ieee80211_reg_rule)); | 2591 | (num_rules * sizeof(struct ieee80211_reg_rule)); |
2396 | 2592 | ||
2397 | rd = kzalloc(size_of_regd, GFP_KERNEL); | 2593 | rd = kzalloc(size_of_regd, GFP_KERNEL); |
2398 | if (!rd) | 2594 | if (!rd) { |
2399 | return -ENOMEM; | 2595 | r = -ENOMEM; |
2596 | goto bad_reg; | ||
2597 | } | ||
2400 | 2598 | ||
2401 | rd->n_reg_rules = num_rules; | 2599 | rd->n_reg_rules = num_rules; |
2402 | rd->alpha2[0] = alpha2[0]; | 2600 | rd->alpha2[0] = alpha2[0]; |
@@ -2413,20 +2611,24 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2413 | 2611 | ||
2414 | rule_idx++; | 2612 | rule_idx++; |
2415 | 2613 | ||
2416 | if (rule_idx > NL80211_MAX_SUPP_REG_RULES) | 2614 | if (rule_idx > NL80211_MAX_SUPP_REG_RULES) { |
2615 | r = -EINVAL; | ||
2417 | goto bad_reg; | 2616 | goto bad_reg; |
2617 | } | ||
2418 | } | 2618 | } |
2419 | 2619 | ||
2420 | BUG_ON(rule_idx != num_rules); | 2620 | BUG_ON(rule_idx != num_rules); |
2421 | 2621 | ||
2422 | mutex_lock(&cfg80211_mutex); | ||
2423 | r = set_regdom(rd); | 2622 | r = set_regdom(rd); |
2623 | |||
2424 | mutex_unlock(&cfg80211_mutex); | 2624 | mutex_unlock(&cfg80211_mutex); |
2625 | |||
2425 | return r; | 2626 | return r; |
2426 | 2627 | ||
2427 | bad_reg: | 2628 | bad_reg: |
2629 | mutex_unlock(&cfg80211_mutex); | ||
2428 | kfree(rd); | 2630 | kfree(rd); |
2429 | return -EINVAL; | 2631 | return r; |
2430 | } | 2632 | } |
2431 | 2633 | ||
2432 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | 2634 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) |
@@ -2442,6 +2644,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2442 | enum ieee80211_band band; | 2644 | enum ieee80211_band band; |
2443 | size_t ie_len; | 2645 | size_t ie_len; |
2444 | 2646 | ||
2647 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
2648 | return -EINVAL; | ||
2649 | |||
2445 | rtnl_lock(); | 2650 | rtnl_lock(); |
2446 | 2651 | ||
2447 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 2652 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
@@ -2492,6 +2697,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2492 | else | 2697 | else |
2493 | ie_len = 0; | 2698 | ie_len = 0; |
2494 | 2699 | ||
2700 | if (ie_len > wiphy->max_scan_ie_len) { | ||
2701 | err = -EINVAL; | ||
2702 | goto out; | ||
2703 | } | ||
2704 | |||
2495 | request = kzalloc(sizeof(*request) | 2705 | request = kzalloc(sizeof(*request) |
2496 | + sizeof(*ssid) * n_ssids | 2706 | + sizeof(*ssid) * n_ssids |
2497 | + sizeof(channel) * n_channels | 2707 | + sizeof(channel) * n_channels |
@@ -2554,7 +2764,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2554 | 2764 | ||
2555 | if (info->attrs[NL80211_ATTR_IE]) { | 2765 | if (info->attrs[NL80211_ATTR_IE]) { |
2556 | request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 2766 | request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
2557 | memcpy(request->ie, nla_data(info->attrs[NL80211_ATTR_IE]), | 2767 | memcpy((void *)request->ie, |
2768 | nla_data(info->attrs[NL80211_ATTR_IE]), | ||
2558 | request->ie_len); | 2769 | request->ie_len); |
2559 | } | 2770 | } |
2560 | 2771 | ||
@@ -2710,6 +2921,15 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
2710 | struct wiphy *wiphy; | 2921 | struct wiphy *wiphy; |
2711 | int err; | 2922 | int err; |
2712 | 2923 | ||
2924 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
2925 | return -EINVAL; | ||
2926 | |||
2927 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
2928 | return -EINVAL; | ||
2929 | |||
2930 | if (!info->attrs[NL80211_ATTR_AUTH_TYPE]) | ||
2931 | return -EINVAL; | ||
2932 | |||
2713 | rtnl_lock(); | 2933 | rtnl_lock(); |
2714 | 2934 | ||
2715 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 2935 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
@@ -2731,11 +2951,6 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
2731 | goto out; | 2951 | goto out; |
2732 | } | 2952 | } |
2733 | 2953 | ||
2734 | if (!info->attrs[NL80211_ATTR_MAC]) { | ||
2735 | err = -EINVAL; | ||
2736 | goto out; | ||
2737 | } | ||
2738 | |||
2739 | wiphy = &drv->wiphy; | 2954 | wiphy = &drv->wiphy; |
2740 | memset(&req, 0, sizeof(req)); | 2955 | memset(&req, 0, sizeof(req)); |
2741 | 2956 | ||
@@ -2761,13 +2976,10 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
2761 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 2976 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
2762 | } | 2977 | } |
2763 | 2978 | ||
2764 | if (info->attrs[NL80211_ATTR_AUTH_TYPE]) { | 2979 | req.auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); |
2765 | req.auth_type = | 2980 | if (!nl80211_valid_auth_type(req.auth_type)) { |
2766 | nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); | 2981 | err = -EINVAL; |
2767 | if (!nl80211_valid_auth_type(req.auth_type)) { | 2982 | goto out; |
2768 | err = -EINVAL; | ||
2769 | goto out; | ||
2770 | } | ||
2771 | } | 2983 | } |
2772 | 2984 | ||
2773 | err = drv->ops->auth(&drv->wiphy, dev, &req); | 2985 | err = drv->ops->auth(&drv->wiphy, dev, &req); |
@@ -2788,6 +3000,13 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
2788 | struct wiphy *wiphy; | 3000 | struct wiphy *wiphy; |
2789 | int err; | 3001 | int err; |
2790 | 3002 | ||
3003 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
3004 | return -EINVAL; | ||
3005 | |||
3006 | if (!info->attrs[NL80211_ATTR_MAC] || | ||
3007 | !info->attrs[NL80211_ATTR_SSID]) | ||
3008 | return -EINVAL; | ||
3009 | |||
2791 | rtnl_lock(); | 3010 | rtnl_lock(); |
2792 | 3011 | ||
2793 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 3012 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
@@ -2809,12 +3028,6 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
2809 | goto out; | 3028 | goto out; |
2810 | } | 3029 | } |
2811 | 3030 | ||
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; | 3031 | wiphy = &drv->wiphy; |
2819 | memset(&req, 0, sizeof(req)); | 3032 | memset(&req, 0, sizeof(req)); |
2820 | 3033 | ||
@@ -2838,6 +3051,19 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
2838 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 3051 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
2839 | } | 3052 | } |
2840 | 3053 | ||
3054 | if (info->attrs[NL80211_ATTR_USE_MFP]) { | ||
3055 | enum nl80211_mfp use_mfp = | ||
3056 | nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); | ||
3057 | if (use_mfp == NL80211_MFP_REQUIRED) | ||
3058 | req.use_mfp = true; | ||
3059 | else if (use_mfp != NL80211_MFP_NO) { | ||
3060 | err = -EINVAL; | ||
3061 | goto out; | ||
3062 | } | ||
3063 | } | ||
3064 | |||
3065 | req.control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; | ||
3066 | |||
2841 | err = drv->ops->assoc(&drv->wiphy, dev, &req); | 3067 | err = drv->ops->assoc(&drv->wiphy, dev, &req); |
2842 | 3068 | ||
2843 | out: | 3069 | out: |
@@ -2856,6 +3082,15 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
2856 | struct wiphy *wiphy; | 3082 | struct wiphy *wiphy; |
2857 | int err; | 3083 | int err; |
2858 | 3084 | ||
3085 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
3086 | return -EINVAL; | ||
3087 | |||
3088 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
3089 | return -EINVAL; | ||
3090 | |||
3091 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | ||
3092 | return -EINVAL; | ||
3093 | |||
2859 | rtnl_lock(); | 3094 | rtnl_lock(); |
2860 | 3095 | ||
2861 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 3096 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
@@ -2877,24 +3112,16 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
2877 | goto out; | 3112 | goto out; |
2878 | } | 3113 | } |
2879 | 3114 | ||
2880 | if (!info->attrs[NL80211_ATTR_MAC]) { | ||
2881 | err = -EINVAL; | ||
2882 | goto out; | ||
2883 | } | ||
2884 | |||
2885 | wiphy = &drv->wiphy; | 3115 | wiphy = &drv->wiphy; |
2886 | memset(&req, 0, sizeof(req)); | 3116 | memset(&req, 0, sizeof(req)); |
2887 | 3117 | ||
2888 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3118 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2889 | 3119 | ||
2890 | if (info->attrs[NL80211_ATTR_REASON_CODE]) { | 3120 | req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); |
2891 | req.reason_code = | 3121 | if (req.reason_code == 0) { |
2892 | nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | 3122 | /* Reason Code 0 is reserved */ |
2893 | if (req.reason_code == 0) { | 3123 | err = -EINVAL; |
2894 | /* Reason Code 0 is reserved */ | 3124 | goto out; |
2895 | err = -EINVAL; | ||
2896 | goto out; | ||
2897 | } | ||
2898 | } | 3125 | } |
2899 | 3126 | ||
2900 | if (info->attrs[NL80211_ATTR_IE]) { | 3127 | if (info->attrs[NL80211_ATTR_IE]) { |
@@ -2920,6 +3147,15 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
2920 | struct wiphy *wiphy; | 3147 | struct wiphy *wiphy; |
2921 | int err; | 3148 | int err; |
2922 | 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 | |||
2923 | rtnl_lock(); | 3159 | rtnl_lock(); |
2924 | 3160 | ||
2925 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 3161 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
@@ -2941,24 +3177,16 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
2941 | goto out; | 3177 | goto out; |
2942 | } | 3178 | } |
2943 | 3179 | ||
2944 | if (!info->attrs[NL80211_ATTR_MAC]) { | ||
2945 | err = -EINVAL; | ||
2946 | goto out; | ||
2947 | } | ||
2948 | |||
2949 | wiphy = &drv->wiphy; | 3180 | wiphy = &drv->wiphy; |
2950 | memset(&req, 0, sizeof(req)); | 3181 | memset(&req, 0, sizeof(req)); |
2951 | 3182 | ||
2952 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3183 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2953 | 3184 | ||
2954 | if (info->attrs[NL80211_ATTR_REASON_CODE]) { | 3185 | req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); |
2955 | req.reason_code = | 3186 | if (req.reason_code == 0) { |
2956 | nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | 3187 | /* Reason Code 0 is reserved */ |
2957 | if (req.reason_code == 0) { | 3188 | err = -EINVAL; |
2958 | /* Reason Code 0 is reserved */ | 3189 | goto out; |
2959 | err = -EINVAL; | ||
2960 | goto out; | ||
2961 | } | ||
2962 | } | 3190 | } |
2963 | 3191 | ||
2964 | if (info->attrs[NL80211_ATTR_IE]) { | 3192 | if (info->attrs[NL80211_ATTR_IE]) { |
@@ -2976,6 +3204,124 @@ unlock_rtnl: | |||
2976 | return err; | 3204 | return err; |
2977 | } | 3205 | } |
2978 | 3206 | ||
3207 | static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | ||
3208 | { | ||
3209 | struct cfg80211_registered_device *drv; | ||
3210 | struct net_device *dev; | ||
3211 | struct cfg80211_ibss_params ibss; | ||
3212 | struct wiphy *wiphy; | ||
3213 | int err; | ||
3214 | |||
3215 | memset(&ibss, 0, sizeof(ibss)); | ||
3216 | |||
3217 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
3218 | return -EINVAL; | ||
3219 | |||
3220 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || | ||
3221 | !info->attrs[NL80211_ATTR_SSID] || | ||
3222 | !nla_len(info->attrs[NL80211_ATTR_SSID])) | ||
3223 | return -EINVAL; | ||
3224 | |||
3225 | ibss.beacon_interval = 100; | ||
3226 | |||
3227 | if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) { | ||
3228 | ibss.beacon_interval = | ||
3229 | nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); | ||
3230 | if (ibss.beacon_interval < 1 || ibss.beacon_interval > 10000) | ||
3231 | return -EINVAL; | ||
3232 | } | ||
3233 | |||
3234 | rtnl_lock(); | ||
3235 | |||
3236 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
3237 | if (err) | ||
3238 | goto unlock_rtnl; | ||
3239 | |||
3240 | if (!drv->ops->join_ibss) { | ||
3241 | err = -EOPNOTSUPP; | ||
3242 | goto out; | ||
3243 | } | ||
3244 | |||
3245 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | ||
3246 | err = -EOPNOTSUPP; | ||
3247 | goto out; | ||
3248 | } | ||
3249 | |||
3250 | if (!netif_running(dev)) { | ||
3251 | err = -ENETDOWN; | ||
3252 | goto out; | ||
3253 | } | ||
3254 | |||
3255 | wiphy = &drv->wiphy; | ||
3256 | |||
3257 | if (info->attrs[NL80211_ATTR_MAC]) | ||
3258 | ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
3259 | ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | ||
3260 | ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | ||
3261 | |||
3262 | if (info->attrs[NL80211_ATTR_IE]) { | ||
3263 | ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
3264 | ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
3265 | } | ||
3266 | |||
3267 | ibss.channel = ieee80211_get_channel(wiphy, | ||
3268 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | ||
3269 | if (!ibss.channel || | ||
3270 | ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || | ||
3271 | ibss.channel->flags & IEEE80211_CHAN_DISABLED) { | ||
3272 | err = -EINVAL; | ||
3273 | goto out; | ||
3274 | } | ||
3275 | |||
3276 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; | ||
3277 | |||
3278 | err = cfg80211_join_ibss(drv, dev, &ibss); | ||
3279 | |||
3280 | out: | ||
3281 | cfg80211_put_dev(drv); | ||
3282 | dev_put(dev); | ||
3283 | unlock_rtnl: | ||
3284 | rtnl_unlock(); | ||
3285 | return err; | ||
3286 | } | ||
3287 | |||
3288 | static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) | ||
3289 | { | ||
3290 | struct cfg80211_registered_device *drv; | ||
3291 | struct net_device *dev; | ||
3292 | int err; | ||
3293 | |||
3294 | rtnl_lock(); | ||
3295 | |||
3296 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
3297 | if (err) | ||
3298 | goto unlock_rtnl; | ||
3299 | |||
3300 | if (!drv->ops->leave_ibss) { | ||
3301 | err = -EOPNOTSUPP; | ||
3302 | goto out; | ||
3303 | } | ||
3304 | |||
3305 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | ||
3306 | err = -EOPNOTSUPP; | ||
3307 | goto out; | ||
3308 | } | ||
3309 | |||
3310 | if (!netif_running(dev)) { | ||
3311 | err = -ENETDOWN; | ||
3312 | goto out; | ||
3313 | } | ||
3314 | |||
3315 | err = cfg80211_leave_ibss(drv, dev, false); | ||
3316 | |||
3317 | out: | ||
3318 | cfg80211_put_dev(drv); | ||
3319 | dev_put(dev); | ||
3320 | unlock_rtnl: | ||
3321 | rtnl_unlock(); | ||
3322 | return err; | ||
3323 | } | ||
3324 | |||
2979 | static struct genl_ops nl80211_ops[] = { | 3325 | static struct genl_ops nl80211_ops[] = { |
2980 | { | 3326 | { |
2981 | .cmd = NL80211_CMD_GET_WIPHY, | 3327 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -3177,6 +3523,18 @@ static struct genl_ops nl80211_ops[] = { | |||
3177 | .policy = nl80211_policy, | 3523 | .policy = nl80211_policy, |
3178 | .flags = GENL_ADMIN_PERM, | 3524 | .flags = GENL_ADMIN_PERM, |
3179 | }, | 3525 | }, |
3526 | { | ||
3527 | .cmd = NL80211_CMD_JOIN_IBSS, | ||
3528 | .doit = nl80211_join_ibss, | ||
3529 | .policy = nl80211_policy, | ||
3530 | .flags = GENL_ADMIN_PERM, | ||
3531 | }, | ||
3532 | { | ||
3533 | .cmd = NL80211_CMD_LEAVE_IBSS, | ||
3534 | .doit = nl80211_leave_ibss, | ||
3535 | .policy = nl80211_policy, | ||
3536 | .flags = GENL_ADMIN_PERM, | ||
3537 | }, | ||
3180 | }; | 3538 | }; |
3181 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 3539 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
3182 | .name = "mlme", | 3540 | .name = "mlme", |
@@ -3199,7 +3557,7 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) | |||
3199 | { | 3557 | { |
3200 | struct sk_buff *msg; | 3558 | struct sk_buff *msg; |
3201 | 3559 | ||
3202 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 3560 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
3203 | if (!msg) | 3561 | if (!msg) |
3204 | return; | 3562 | return; |
3205 | 3563 | ||
@@ -3211,11 +3569,43 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev) | |||
3211 | genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); | 3569 | genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL); |
3212 | } | 3570 | } |
3213 | 3571 | ||
3572 | static int nl80211_add_scan_req(struct sk_buff *msg, | ||
3573 | struct cfg80211_registered_device *rdev) | ||
3574 | { | ||
3575 | struct cfg80211_scan_request *req = rdev->scan_req; | ||
3576 | struct nlattr *nest; | ||
3577 | int i; | ||
3578 | |||
3579 | if (WARN_ON(!req)) | ||
3580 | return 0; | ||
3581 | |||
3582 | nest = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS); | ||
3583 | if (!nest) | ||
3584 | goto nla_put_failure; | ||
3585 | for (i = 0; i < req->n_ssids; i++) | ||
3586 | NLA_PUT(msg, i, req->ssids[i].ssid_len, req->ssids[i].ssid); | ||
3587 | nla_nest_end(msg, nest); | ||
3588 | |||
3589 | nest = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES); | ||
3590 | if (!nest) | ||
3591 | goto nla_put_failure; | ||
3592 | for (i = 0; i < req->n_channels; i++) | ||
3593 | NLA_PUT_U32(msg, i, req->channels[i]->center_freq); | ||
3594 | nla_nest_end(msg, nest); | ||
3595 | |||
3596 | if (req->ie) | ||
3597 | NLA_PUT(msg, NL80211_ATTR_IE, req->ie_len, req->ie); | ||
3598 | |||
3599 | return 0; | ||
3600 | nla_put_failure: | ||
3601 | return -ENOBUFS; | ||
3602 | } | ||
3603 | |||
3214 | static int nl80211_send_scan_donemsg(struct sk_buff *msg, | 3604 | static int nl80211_send_scan_donemsg(struct sk_buff *msg, |
3215 | struct cfg80211_registered_device *rdev, | 3605 | struct cfg80211_registered_device *rdev, |
3216 | struct net_device *netdev, | 3606 | struct net_device *netdev, |
3217 | u32 pid, u32 seq, int flags, | 3607 | u32 pid, u32 seq, int flags, |
3218 | u32 cmd) | 3608 | u32 cmd) |
3219 | { | 3609 | { |
3220 | void *hdr; | 3610 | void *hdr; |
3221 | 3611 | ||
@@ -3226,7 +3616,8 @@ static int nl80211_send_scan_donemsg(struct sk_buff *msg, | |||
3226 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | 3616 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); |
3227 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | 3617 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); |
3228 | 3618 | ||
3229 | /* XXX: we should probably bounce back the request? */ | 3619 | /* ignore errors and send incomplete event anyway */ |
3620 | nl80211_add_scan_req(msg, rdev); | ||
3230 | 3621 | ||
3231 | return genlmsg_end(msg, hdr); | 3622 | return genlmsg_end(msg, hdr); |
3232 | 3623 | ||
@@ -3240,7 +3631,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | |||
3240 | { | 3631 | { |
3241 | struct sk_buff *msg; | 3632 | struct sk_buff *msg; |
3242 | 3633 | ||
3243 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 3634 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
3244 | if (!msg) | 3635 | if (!msg) |
3245 | return; | 3636 | return; |
3246 | 3637 | ||
@@ -3258,7 +3649,7 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | |||
3258 | { | 3649 | { |
3259 | struct sk_buff *msg; | 3650 | struct sk_buff *msg; |
3260 | 3651 | ||
3261 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 3652 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
3262 | if (!msg) | 3653 | if (!msg) |
3263 | return; | 3654 | return; |
3264 | 3655 | ||
@@ -3280,7 +3671,7 @@ void nl80211_send_reg_change_event(struct regulatory_request *request) | |||
3280 | struct sk_buff *msg; | 3671 | struct sk_buff *msg; |
3281 | void *hdr; | 3672 | void *hdr; |
3282 | 3673 | ||
3283 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 3674 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
3284 | if (!msg) | 3675 | if (!msg) |
3285 | return; | 3676 | return; |
3286 | 3677 | ||
@@ -3334,7 +3725,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, | |||
3334 | struct sk_buff *msg; | 3725 | struct sk_buff *msg; |
3335 | void *hdr; | 3726 | void *hdr; |
3336 | 3727 | ||
3337 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); | 3728 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); |
3338 | if (!msg) | 3729 | if (!msg) |
3339 | return; | 3730 | return; |
3340 | 3731 | ||
@@ -3375,38 +3766,208 @@ void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, | |||
3375 | nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_ASSOCIATE); | 3766 | nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_ASSOCIATE); |
3376 | } | 3767 | } |
3377 | 3768 | ||
3378 | void nl80211_send_rx_deauth(struct cfg80211_registered_device *rdev, | 3769 | void nl80211_send_deauth(struct cfg80211_registered_device *rdev, |
3379 | struct net_device *netdev, const u8 *buf, | 3770 | struct net_device *netdev, const u8 *buf, size_t len) |
3380 | size_t len) | ||
3381 | { | 3771 | { |
3382 | nl80211_send_mlme_event(rdev, netdev, buf, len, | 3772 | nl80211_send_mlme_event(rdev, netdev, buf, len, |
3383 | NL80211_CMD_DEAUTHENTICATE); | 3773 | NL80211_CMD_DEAUTHENTICATE); |
3384 | } | 3774 | } |
3385 | 3775 | ||
3386 | void nl80211_send_rx_disassoc(struct cfg80211_registered_device *rdev, | 3776 | void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, |
3387 | struct net_device *netdev, const u8 *buf, | 3777 | struct net_device *netdev, const u8 *buf, |
3388 | size_t len) | 3778 | size_t len) |
3389 | { | 3779 | { |
3390 | nl80211_send_mlme_event(rdev, netdev, buf, len, | 3780 | nl80211_send_mlme_event(rdev, netdev, buf, len, |
3391 | NL80211_CMD_DISASSOCIATE); | 3781 | NL80211_CMD_DISASSOCIATE); |
3392 | } | 3782 | } |
3393 | 3783 | ||
3784 | static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, | ||
3785 | struct net_device *netdev, int cmd, | ||
3786 | const u8 *addr) | ||
3787 | { | ||
3788 | struct sk_buff *msg; | ||
3789 | void *hdr; | ||
3790 | |||
3791 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); | ||
3792 | if (!msg) | ||
3793 | return; | ||
3794 | |||
3795 | hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); | ||
3796 | if (!hdr) { | ||
3797 | nlmsg_free(msg); | ||
3798 | return; | ||
3799 | } | ||
3800 | |||
3801 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
3802 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
3803 | NLA_PUT_FLAG(msg, NL80211_ATTR_TIMED_OUT); | ||
3804 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); | ||
3805 | |||
3806 | if (genlmsg_end(msg, hdr) < 0) { | ||
3807 | nlmsg_free(msg); | ||
3808 | return; | ||
3809 | } | ||
3810 | |||
3811 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC); | ||
3812 | return; | ||
3813 | |||
3814 | nla_put_failure: | ||
3815 | genlmsg_cancel(msg, hdr); | ||
3816 | nlmsg_free(msg); | ||
3817 | } | ||
3818 | |||
3819 | void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, | ||
3820 | struct net_device *netdev, const u8 *addr) | ||
3821 | { | ||
3822 | nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE, | ||
3823 | addr); | ||
3824 | } | ||
3825 | |||
3826 | void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, | ||
3827 | struct net_device *netdev, const u8 *addr) | ||
3828 | { | ||
3829 | nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE, addr); | ||
3830 | } | ||
3831 | |||
3832 | void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, | ||
3833 | struct net_device *netdev, const u8 *bssid, | ||
3834 | gfp_t gfp) | ||
3835 | { | ||
3836 | struct sk_buff *msg; | ||
3837 | void *hdr; | ||
3838 | |||
3839 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | ||
3840 | if (!msg) | ||
3841 | return; | ||
3842 | |||
3843 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS); | ||
3844 | if (!hdr) { | ||
3845 | nlmsg_free(msg); | ||
3846 | return; | ||
3847 | } | ||
3848 | |||
3849 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
3850 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
3851 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); | ||
3852 | |||
3853 | if (genlmsg_end(msg, hdr) < 0) { | ||
3854 | nlmsg_free(msg); | ||
3855 | return; | ||
3856 | } | ||
3857 | |||
3858 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); | ||
3859 | return; | ||
3860 | |||
3861 | nla_put_failure: | ||
3862 | genlmsg_cancel(msg, hdr); | ||
3863 | nlmsg_free(msg); | ||
3864 | } | ||
3865 | |||
3866 | void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, | ||
3867 | struct net_device *netdev, const u8 *addr, | ||
3868 | enum nl80211_key_type key_type, int key_id, | ||
3869 | const u8 *tsc) | ||
3870 | { | ||
3871 | struct sk_buff *msg; | ||
3872 | void *hdr; | ||
3873 | |||
3874 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); | ||
3875 | if (!msg) | ||
3876 | return; | ||
3877 | |||
3878 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE); | ||
3879 | if (!hdr) { | ||
3880 | nlmsg_free(msg); | ||
3881 | return; | ||
3882 | } | ||
3883 | |||
3884 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
3885 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
3886 | if (addr) | ||
3887 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); | ||
3888 | NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, key_type); | ||
3889 | NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id); | ||
3890 | if (tsc) | ||
3891 | NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc); | ||
3892 | |||
3893 | if (genlmsg_end(msg, hdr) < 0) { | ||
3894 | nlmsg_free(msg); | ||
3895 | return; | ||
3896 | } | ||
3897 | |||
3898 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC); | ||
3899 | return; | ||
3900 | |||
3901 | nla_put_failure: | ||
3902 | genlmsg_cancel(msg, hdr); | ||
3903 | nlmsg_free(msg); | ||
3904 | } | ||
3905 | |||
3906 | void nl80211_send_beacon_hint_event(struct wiphy *wiphy, | ||
3907 | struct ieee80211_channel *channel_before, | ||
3908 | struct ieee80211_channel *channel_after) | ||
3909 | { | ||
3910 | struct sk_buff *msg; | ||
3911 | void *hdr; | ||
3912 | struct nlattr *nl_freq; | ||
3913 | |||
3914 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); | ||
3915 | if (!msg) | ||
3916 | return; | ||
3917 | |||
3918 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_BEACON_HINT); | ||
3919 | if (!hdr) { | ||
3920 | nlmsg_free(msg); | ||
3921 | return; | ||
3922 | } | ||
3923 | |||
3924 | /* | ||
3925 | * Since we are applying the beacon hint to a wiphy we know its | ||
3926 | * wiphy_idx is valid | ||
3927 | */ | ||
3928 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)); | ||
3929 | |||
3930 | /* Before */ | ||
3931 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE); | ||
3932 | if (!nl_freq) | ||
3933 | goto nla_put_failure; | ||
3934 | if (nl80211_msg_put_channel(msg, channel_before)) | ||
3935 | goto nla_put_failure; | ||
3936 | nla_nest_end(msg, nl_freq); | ||
3937 | |||
3938 | /* After */ | ||
3939 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER); | ||
3940 | if (!nl_freq) | ||
3941 | goto nla_put_failure; | ||
3942 | if (nl80211_msg_put_channel(msg, channel_after)) | ||
3943 | goto nla_put_failure; | ||
3944 | nla_nest_end(msg, nl_freq); | ||
3945 | |||
3946 | if (genlmsg_end(msg, hdr) < 0) { | ||
3947 | nlmsg_free(msg); | ||
3948 | return; | ||
3949 | } | ||
3950 | |||
3951 | genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_ATOMIC); | ||
3952 | |||
3953 | return; | ||
3954 | |||
3955 | nla_put_failure: | ||
3956 | genlmsg_cancel(msg, hdr); | ||
3957 | nlmsg_free(msg); | ||
3958 | } | ||
3959 | |||
3394 | /* initialisation/exit functions */ | 3960 | /* initialisation/exit functions */ |
3395 | 3961 | ||
3396 | int nl80211_init(void) | 3962 | int nl80211_init(void) |
3397 | { | 3963 | { |
3398 | int err, i; | 3964 | int err; |
3399 | 3965 | ||
3400 | err = genl_register_family(&nl80211_fam); | 3966 | err = genl_register_family_with_ops(&nl80211_fam, |
3967 | nl80211_ops, ARRAY_SIZE(nl80211_ops)); | ||
3401 | if (err) | 3968 | if (err) |
3402 | return err; | 3969 | return err; |
3403 | 3970 | ||
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); | 3971 | err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp); |
3411 | if (err) | 3972 | if (err) |
3412 | goto err_out; | 3973 | goto err_out; |