diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 639 |
1 files changed, 560 insertions, 79 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 2456e4ee445e..b1fc98225fd1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -61,6 +61,10 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
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 }, |
@@ -116,8 +120,40 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
116 | .len = IEEE80211_MAX_SSID_LEN }, | 120 | .len = IEEE80211_MAX_SSID_LEN }, |
117 | [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 }, | 121 | [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 }, |
118 | [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 }, | 122 | [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 }, |
123 | [NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG }, | ||
124 | [NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG }, | ||
119 | }; | 125 | }; |
120 | 126 | ||
127 | /* IE validation */ | ||
128 | static bool is_valid_ie_attr(const struct nlattr *attr) | ||
129 | { | ||
130 | const u8 *pos; | ||
131 | int len; | ||
132 | |||
133 | if (!attr) | ||
134 | return true; | ||
135 | |||
136 | pos = nla_data(attr); | ||
137 | len = nla_len(attr); | ||
138 | |||
139 | while (len) { | ||
140 | u8 elemlen; | ||
141 | |||
142 | if (len < 2) | ||
143 | return false; | ||
144 | len -= 2; | ||
145 | |||
146 | elemlen = pos[1]; | ||
147 | if (elemlen > len) | ||
148 | return false; | ||
149 | |||
150 | len -= elemlen; | ||
151 | pos += 2 + elemlen; | ||
152 | } | ||
153 | |||
154 | return true; | ||
155 | } | ||
156 | |||
121 | /* message building helper */ | 157 | /* message building helper */ |
122 | static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, | 158 | static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, |
123 | int flags, u8 cmd) | 159 | int flags, u8 cmd) |
@@ -126,6 +162,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); | 162 | return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd); |
127 | } | 163 | } |
128 | 164 | ||
165 | static int nl80211_msg_put_channel(struct sk_buff *msg, | ||
166 | struct ieee80211_channel *chan) | ||
167 | { | ||
168 | NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ, | ||
169 | chan->center_freq); | ||
170 | |||
171 | if (chan->flags & IEEE80211_CHAN_DISABLED) | ||
172 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED); | ||
173 | if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) | ||
174 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN); | ||
175 | if (chan->flags & IEEE80211_CHAN_NO_IBSS) | ||
176 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS); | ||
177 | if (chan->flags & IEEE80211_CHAN_RADAR) | ||
178 | NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR); | ||
179 | |||
180 | NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, | ||
181 | DBM_TO_MBM(chan->max_power)); | ||
182 | |||
183 | return 0; | ||
184 | |||
185 | nla_put_failure: | ||
186 | return -ENOBUFS; | ||
187 | } | ||
188 | |||
129 | /* netlink command implementations */ | 189 | /* netlink command implementations */ |
130 | 190 | ||
131 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 191 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, |
@@ -149,8 +209,24 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
149 | 209 | ||
150 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); | 210 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); |
151 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); | 211 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); |
212 | |||
213 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, | ||
214 | dev->wiphy.retry_short); | ||
215 | NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, | ||
216 | dev->wiphy.retry_long); | ||
217 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, | ||
218 | dev->wiphy.frag_threshold); | ||
219 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, | ||
220 | dev->wiphy.rts_threshold); | ||
221 | |||
152 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, | 222 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, |
153 | dev->wiphy.max_scan_ssids); | 223 | dev->wiphy.max_scan_ssids); |
224 | NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN, | ||
225 | dev->wiphy.max_scan_ie_len); | ||
226 | |||
227 | NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES, | ||
228 | sizeof(u32) * dev->wiphy.n_cipher_suites, | ||
229 | dev->wiphy.cipher_suites); | ||
154 | 230 | ||
155 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); | 231 | nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES); |
156 | if (!nl_modes) | 232 | if (!nl_modes) |
@@ -202,20 +278,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
202 | goto nla_put_failure; | 278 | goto nla_put_failure; |
203 | 279 | ||
204 | chan = &dev->wiphy.bands[band]->channels[i]; | 280 | 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 | 281 | ||
217 | NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, | 282 | if (nl80211_msg_put_channel(msg, chan)) |
218 | DBM_TO_MBM(chan->max_power)); | 283 | goto nla_put_failure; |
219 | 284 | ||
220 | nla_nest_end(msg, nl_freq); | 285 | nla_nest_end(msg, nl_freq); |
221 | } | 286 | } |
@@ -273,6 +338,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
273 | CMD(assoc, ASSOCIATE); | 338 | CMD(assoc, ASSOCIATE); |
274 | CMD(deauth, DEAUTHENTICATE); | 339 | CMD(deauth, DEAUTHENTICATE); |
275 | CMD(disassoc, DISASSOCIATE); | 340 | CMD(disassoc, DISASSOCIATE); |
341 | CMD(join_ibss, JOIN_IBSS); | ||
276 | 342 | ||
277 | #undef CMD | 343 | #undef CMD |
278 | nla_nest_end(msg, nl_cmds); | 344 | nla_nest_end(msg, nl_cmds); |
@@ -365,6 +431,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
365 | struct cfg80211_registered_device *rdev; | 431 | struct cfg80211_registered_device *rdev; |
366 | int result = 0, rem_txq_params = 0; | 432 | int result = 0, rem_txq_params = 0; |
367 | struct nlattr *nl_txq_params; | 433 | struct nlattr *nl_txq_params; |
434 | u32 changed; | ||
435 | u8 retry_short = 0, retry_long = 0; | ||
436 | u32 frag_threshold = 0, rts_threshold = 0; | ||
368 | 437 | ||
369 | rtnl_lock(); | 438 | rtnl_lock(); |
370 | 439 | ||
@@ -479,6 +548,84 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
479 | goto bad_res; | 548 | goto bad_res; |
480 | } | 549 | } |
481 | 550 | ||
551 | changed = 0; | ||
552 | |||
553 | if (info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]) { | ||
554 | retry_short = nla_get_u8( | ||
555 | info->attrs[NL80211_ATTR_WIPHY_RETRY_SHORT]); | ||
556 | if (retry_short == 0) { | ||
557 | result = -EINVAL; | ||
558 | goto bad_res; | ||
559 | } | ||
560 | changed |= WIPHY_PARAM_RETRY_SHORT; | ||
561 | } | ||
562 | |||
563 | if (info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]) { | ||
564 | retry_long = nla_get_u8( | ||
565 | info->attrs[NL80211_ATTR_WIPHY_RETRY_LONG]); | ||
566 | if (retry_long == 0) { | ||
567 | result = -EINVAL; | ||
568 | goto bad_res; | ||
569 | } | ||
570 | changed |= WIPHY_PARAM_RETRY_LONG; | ||
571 | } | ||
572 | |||
573 | if (info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]) { | ||
574 | frag_threshold = nla_get_u32( | ||
575 | info->attrs[NL80211_ATTR_WIPHY_FRAG_THRESHOLD]); | ||
576 | if (frag_threshold < 256) { | ||
577 | result = -EINVAL; | ||
578 | goto bad_res; | ||
579 | } | ||
580 | if (frag_threshold != (u32) -1) { | ||
581 | /* | ||
582 | * Fragments (apart from the last one) are required to | ||
583 | * have even length. Make the fragmentation code | ||
584 | * simpler by stripping LSB should someone try to use | ||
585 | * odd threshold value. | ||
586 | */ | ||
587 | frag_threshold &= ~0x1; | ||
588 | } | ||
589 | changed |= WIPHY_PARAM_FRAG_THRESHOLD; | ||
590 | } | ||
591 | |||
592 | if (info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]) { | ||
593 | rts_threshold = nla_get_u32( | ||
594 | info->attrs[NL80211_ATTR_WIPHY_RTS_THRESHOLD]); | ||
595 | changed |= WIPHY_PARAM_RTS_THRESHOLD; | ||
596 | } | ||
597 | |||
598 | if (changed) { | ||
599 | u8 old_retry_short, old_retry_long; | ||
600 | u32 old_frag_threshold, old_rts_threshold; | ||
601 | |||
602 | if (!rdev->ops->set_wiphy_params) { | ||
603 | result = -EOPNOTSUPP; | ||
604 | goto bad_res; | ||
605 | } | ||
606 | |||
607 | old_retry_short = rdev->wiphy.retry_short; | ||
608 | old_retry_long = rdev->wiphy.retry_long; | ||
609 | old_frag_threshold = rdev->wiphy.frag_threshold; | ||
610 | old_rts_threshold = rdev->wiphy.rts_threshold; | ||
611 | |||
612 | if (changed & WIPHY_PARAM_RETRY_SHORT) | ||
613 | rdev->wiphy.retry_short = retry_short; | ||
614 | if (changed & WIPHY_PARAM_RETRY_LONG) | ||
615 | rdev->wiphy.retry_long = retry_long; | ||
616 | if (changed & WIPHY_PARAM_FRAG_THRESHOLD) | ||
617 | rdev->wiphy.frag_threshold = frag_threshold; | ||
618 | if (changed & WIPHY_PARAM_RTS_THRESHOLD) | ||
619 | rdev->wiphy.rts_threshold = rts_threshold; | ||
620 | |||
621 | result = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); | ||
622 | if (result) { | ||
623 | rdev->wiphy.retry_short = old_retry_short; | ||
624 | rdev->wiphy.retry_long = old_retry_long; | ||
625 | rdev->wiphy.frag_threshold = old_frag_threshold; | ||
626 | rdev->wiphy.rts_threshold = old_rts_threshold; | ||
627 | } | ||
628 | } | ||
482 | 629 | ||
483 | bad_res: | 630 | bad_res: |
484 | mutex_unlock(&rdev->mtx); | 631 | mutex_unlock(&rdev->mtx); |
@@ -489,6 +636,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
489 | 636 | ||
490 | 637 | ||
491 | static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 638 | static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, |
639 | struct cfg80211_registered_device *rdev, | ||
492 | struct net_device *dev) | 640 | struct net_device *dev) |
493 | { | 641 | { |
494 | void *hdr; | 642 | void *hdr; |
@@ -498,6 +646,7 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
498 | return -1; | 646 | return -1; |
499 | 647 | ||
500 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 648 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
649 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
501 | NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); | 650 | NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name); |
502 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); | 651 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, dev->ieee80211_ptr->iftype); |
503 | return genlmsg_end(msg, hdr); | 652 | return genlmsg_end(msg, hdr); |
@@ -532,7 +681,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
532 | } | 681 | } |
533 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, | 682 | if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, |
534 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 683 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
535 | wdev->netdev) < 0) { | 684 | dev, wdev->netdev) < 0) { |
536 | mutex_unlock(&dev->devlist_mtx); | 685 | mutex_unlock(&dev->devlist_mtx); |
537 | goto out; | 686 | goto out; |
538 | } | 687 | } |
@@ -566,7 +715,8 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) | |||
566 | if (!msg) | 715 | if (!msg) |
567 | goto out_err; | 716 | goto out_err; |
568 | 717 | ||
569 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, netdev) < 0) | 718 | if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, |
719 | dev, netdev) < 0) | ||
570 | goto out_free; | 720 | goto out_free; |
571 | 721 | ||
572 | dev_put(netdev); | 722 | dev_put(netdev); |
@@ -616,7 +766,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
616 | struct cfg80211_registered_device *drv; | 766 | struct cfg80211_registered_device *drv; |
617 | struct vif_params params; | 767 | struct vif_params params; |
618 | int err, ifindex; | 768 | int err, ifindex; |
619 | enum nl80211_iftype type; | 769 | enum nl80211_iftype otype, ntype; |
620 | struct net_device *dev; | 770 | struct net_device *dev; |
621 | u32 _flags, *flags = NULL; | 771 | u32 _flags, *flags = NULL; |
622 | bool change = false; | 772 | bool change = false; |
@@ -630,30 +780,27 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
630 | goto unlock_rtnl; | 780 | goto unlock_rtnl; |
631 | 781 | ||
632 | ifindex = dev->ifindex; | 782 | ifindex = dev->ifindex; |
633 | type = dev->ieee80211_ptr->iftype; | 783 | otype = ntype = dev->ieee80211_ptr->iftype; |
634 | dev_put(dev); | 784 | dev_put(dev); |
635 | 785 | ||
636 | if (info->attrs[NL80211_ATTR_IFTYPE]) { | 786 | if (info->attrs[NL80211_ATTR_IFTYPE]) { |
637 | enum nl80211_iftype ntype; | ||
638 | |||
639 | ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); | 787 | ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); |
640 | if (type != ntype) | 788 | if (otype != ntype) |
641 | change = true; | 789 | change = true; |
642 | type = ntype; | 790 | if (ntype > NL80211_IFTYPE_MAX) { |
643 | if (type > NL80211_IFTYPE_MAX) { | ||
644 | err = -EINVAL; | 791 | err = -EINVAL; |
645 | goto unlock; | 792 | goto unlock; |
646 | } | 793 | } |
647 | } | 794 | } |
648 | 795 | ||
649 | if (!drv->ops->change_virtual_intf || | 796 | if (!drv->ops->change_virtual_intf || |
650 | !(drv->wiphy.interface_modes & (1 << type))) { | 797 | !(drv->wiphy.interface_modes & (1 << ntype))) { |
651 | err = -EOPNOTSUPP; | 798 | err = -EOPNOTSUPP; |
652 | goto unlock; | 799 | goto unlock; |
653 | } | 800 | } |
654 | 801 | ||
655 | if (info->attrs[NL80211_ATTR_MESH_ID]) { | 802 | if (info->attrs[NL80211_ATTR_MESH_ID]) { |
656 | if (type != NL80211_IFTYPE_MESH_POINT) { | 803 | if (ntype != NL80211_IFTYPE_MESH_POINT) { |
657 | err = -EINVAL; | 804 | err = -EINVAL; |
658 | goto unlock; | 805 | goto unlock; |
659 | } | 806 | } |
@@ -663,7 +810,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
663 | } | 810 | } |
664 | 811 | ||
665 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { | 812 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { |
666 | if (type != NL80211_IFTYPE_MONITOR) { | 813 | if (ntype != NL80211_IFTYPE_MONITOR) { |
667 | err = -EINVAL; | 814 | err = -EINVAL; |
668 | goto unlock; | 815 | goto unlock; |
669 | } | 816 | } |
@@ -678,12 +825,17 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
678 | 825 | ||
679 | if (change) | 826 | if (change) |
680 | err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, | 827 | err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, |
681 | type, flags, ¶ms); | 828 | ntype, flags, ¶ms); |
682 | else | 829 | else |
683 | err = 0; | 830 | err = 0; |
684 | 831 | ||
685 | dev = __dev_get_by_index(&init_net, ifindex); | 832 | dev = __dev_get_by_index(&init_net, ifindex); |
686 | WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type)); | 833 | WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != ntype)); |
834 | |||
835 | if (dev && !err && (ntype != otype)) { | ||
836 | if (otype == NL80211_IFTYPE_ADHOC) | ||
837 | cfg80211_clear_ibss(dev, false); | ||
838 | } | ||
687 | 839 | ||
688 | unlock: | 840 | unlock: |
689 | cfg80211_put_dev(drv); | 841 | cfg80211_put_dev(drv); |
@@ -934,7 +1086,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) | 1086 | static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) |
935 | { | 1087 | { |
936 | struct cfg80211_registered_device *drv; | 1088 | struct cfg80211_registered_device *drv; |
937 | int err; | 1089 | int err, i; |
938 | struct net_device *dev; | 1090 | struct net_device *dev; |
939 | struct key_params params; | 1091 | struct key_params params; |
940 | u8 key_idx = 0; | 1092 | u8 key_idx = 0; |
@@ -1003,6 +1155,14 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
1003 | if (err) | 1155 | if (err) |
1004 | goto unlock_rtnl; | 1156 | goto unlock_rtnl; |
1005 | 1157 | ||
1158 | for (i = 0; i < drv->wiphy.n_cipher_suites; i++) | ||
1159 | if (params.cipher == drv->wiphy.cipher_suites[i]) | ||
1160 | break; | ||
1161 | if (i == drv->wiphy.n_cipher_suites) { | ||
1162 | err = -EINVAL; | ||
1163 | goto out; | ||
1164 | } | ||
1165 | |||
1006 | if (!drv->ops->add_key) { | 1166 | if (!drv->ops->add_key) { |
1007 | err = -EOPNOTSUPP; | 1167 | err = -EOPNOTSUPP; |
1008 | goto out; | 1168 | goto out; |
@@ -1069,6 +1229,9 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1069 | struct beacon_parameters params; | 1229 | struct beacon_parameters params; |
1070 | int haveinfo = 0; | 1230 | int haveinfo = 0; |
1071 | 1231 | ||
1232 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL])) | ||
1233 | return -EINVAL; | ||
1234 | |||
1072 | rtnl_lock(); | 1235 | rtnl_lock(); |
1073 | 1236 | ||
1074 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1237 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
@@ -2442,6 +2605,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2442 | enum ieee80211_band band; | 2605 | enum ieee80211_band band; |
2443 | size_t ie_len; | 2606 | size_t ie_len; |
2444 | 2607 | ||
2608 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
2609 | return -EINVAL; | ||
2610 | |||
2445 | rtnl_lock(); | 2611 | rtnl_lock(); |
2446 | 2612 | ||
2447 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 2613 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
@@ -2492,6 +2658,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2492 | else | 2658 | else |
2493 | ie_len = 0; | 2659 | ie_len = 0; |
2494 | 2660 | ||
2661 | if (ie_len > wiphy->max_scan_ie_len) { | ||
2662 | err = -EINVAL; | ||
2663 | goto out; | ||
2664 | } | ||
2665 | |||
2495 | request = kzalloc(sizeof(*request) | 2666 | request = kzalloc(sizeof(*request) |
2496 | + sizeof(*ssid) * n_ssids | 2667 | + sizeof(*ssid) * n_ssids |
2497 | + sizeof(channel) * n_channels | 2668 | + sizeof(channel) * n_channels |
@@ -2554,7 +2725,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2554 | 2725 | ||
2555 | if (info->attrs[NL80211_ATTR_IE]) { | 2726 | if (info->attrs[NL80211_ATTR_IE]) { |
2556 | request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 2727 | request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
2557 | memcpy(request->ie, nla_data(info->attrs[NL80211_ATTR_IE]), | 2728 | memcpy((void *)request->ie, |
2729 | nla_data(info->attrs[NL80211_ATTR_IE]), | ||
2558 | request->ie_len); | 2730 | request->ie_len); |
2559 | } | 2731 | } |
2560 | 2732 | ||
@@ -2710,6 +2882,15 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
2710 | struct wiphy *wiphy; | 2882 | struct wiphy *wiphy; |
2711 | int err; | 2883 | int err; |
2712 | 2884 | ||
2885 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
2886 | return -EINVAL; | ||
2887 | |||
2888 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
2889 | return -EINVAL; | ||
2890 | |||
2891 | if (!info->attrs[NL80211_ATTR_AUTH_TYPE]) | ||
2892 | return -EINVAL; | ||
2893 | |||
2713 | rtnl_lock(); | 2894 | rtnl_lock(); |
2714 | 2895 | ||
2715 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 2896 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
@@ -2731,11 +2912,6 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
2731 | goto out; | 2912 | goto out; |
2732 | } | 2913 | } |
2733 | 2914 | ||
2734 | if (!info->attrs[NL80211_ATTR_MAC]) { | ||
2735 | err = -EINVAL; | ||
2736 | goto out; | ||
2737 | } | ||
2738 | |||
2739 | wiphy = &drv->wiphy; | 2915 | wiphy = &drv->wiphy; |
2740 | memset(&req, 0, sizeof(req)); | 2916 | memset(&req, 0, sizeof(req)); |
2741 | 2917 | ||
@@ -2761,13 +2937,10 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | |||
2761 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | 2937 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); |
2762 | } | 2938 | } |
2763 | 2939 | ||
2764 | if (info->attrs[NL80211_ATTR_AUTH_TYPE]) { | 2940 | req.auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); |
2765 | req.auth_type = | 2941 | if (!nl80211_valid_auth_type(req.auth_type)) { |
2766 | nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); | 2942 | err = -EINVAL; |
2767 | if (!nl80211_valid_auth_type(req.auth_type)) { | 2943 | goto out; |
2768 | err = -EINVAL; | ||
2769 | goto out; | ||
2770 | } | ||
2771 | } | 2944 | } |
2772 | 2945 | ||
2773 | err = drv->ops->auth(&drv->wiphy, dev, &req); | 2946 | err = drv->ops->auth(&drv->wiphy, dev, &req); |
@@ -2788,6 +2961,13 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
2788 | struct wiphy *wiphy; | 2961 | struct wiphy *wiphy; |
2789 | int err; | 2962 | int err; |
2790 | 2963 | ||
2964 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
2965 | return -EINVAL; | ||
2966 | |||
2967 | if (!info->attrs[NL80211_ATTR_MAC] || | ||
2968 | !info->attrs[NL80211_ATTR_SSID]) | ||
2969 | return -EINVAL; | ||
2970 | |||
2791 | rtnl_lock(); | 2971 | rtnl_lock(); |
2792 | 2972 | ||
2793 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 2973 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
@@ -2809,12 +2989,6 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
2809 | goto out; | 2989 | goto out; |
2810 | } | 2990 | } |
2811 | 2991 | ||
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; | 2992 | wiphy = &drv->wiphy; |
2819 | memset(&req, 0, sizeof(req)); | 2993 | memset(&req, 0, sizeof(req)); |
2820 | 2994 | ||
@@ -2856,6 +3030,15 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
2856 | struct wiphy *wiphy; | 3030 | struct wiphy *wiphy; |
2857 | int err; | 3031 | int err; |
2858 | 3032 | ||
3033 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
3034 | return -EINVAL; | ||
3035 | |||
3036 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
3037 | return -EINVAL; | ||
3038 | |||
3039 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | ||
3040 | return -EINVAL; | ||
3041 | |||
2859 | rtnl_lock(); | 3042 | rtnl_lock(); |
2860 | 3043 | ||
2861 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 3044 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
@@ -2877,24 +3060,16 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | |||
2877 | goto out; | 3060 | goto out; |
2878 | } | 3061 | } |
2879 | 3062 | ||
2880 | if (!info->attrs[NL80211_ATTR_MAC]) { | ||
2881 | err = -EINVAL; | ||
2882 | goto out; | ||
2883 | } | ||
2884 | |||
2885 | wiphy = &drv->wiphy; | 3063 | wiphy = &drv->wiphy; |
2886 | memset(&req, 0, sizeof(req)); | 3064 | memset(&req, 0, sizeof(req)); |
2887 | 3065 | ||
2888 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3066 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2889 | 3067 | ||
2890 | if (info->attrs[NL80211_ATTR_REASON_CODE]) { | 3068 | req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); |
2891 | req.reason_code = | 3069 | if (req.reason_code == 0) { |
2892 | nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | 3070 | /* Reason Code 0 is reserved */ |
2893 | if (req.reason_code == 0) { | 3071 | err = -EINVAL; |
2894 | /* Reason Code 0 is reserved */ | 3072 | goto out; |
2895 | err = -EINVAL; | ||
2896 | goto out; | ||
2897 | } | ||
2898 | } | 3073 | } |
2899 | 3074 | ||
2900 | if (info->attrs[NL80211_ATTR_IE]) { | 3075 | if (info->attrs[NL80211_ATTR_IE]) { |
@@ -2920,6 +3095,15 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
2920 | struct wiphy *wiphy; | 3095 | struct wiphy *wiphy; |
2921 | int err; | 3096 | int err; |
2922 | 3097 | ||
3098 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
3099 | return -EINVAL; | ||
3100 | |||
3101 | if (!info->attrs[NL80211_ATTR_MAC]) | ||
3102 | return -EINVAL; | ||
3103 | |||
3104 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | ||
3105 | return -EINVAL; | ||
3106 | |||
2923 | rtnl_lock(); | 3107 | rtnl_lock(); |
2924 | 3108 | ||
2925 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 3109 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
@@ -2941,24 +3125,16 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | |||
2941 | goto out; | 3125 | goto out; |
2942 | } | 3126 | } |
2943 | 3127 | ||
2944 | if (!info->attrs[NL80211_ATTR_MAC]) { | ||
2945 | err = -EINVAL; | ||
2946 | goto out; | ||
2947 | } | ||
2948 | |||
2949 | wiphy = &drv->wiphy; | 3128 | wiphy = &drv->wiphy; |
2950 | memset(&req, 0, sizeof(req)); | 3129 | memset(&req, 0, sizeof(req)); |
2951 | 3130 | ||
2952 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 3131 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
2953 | 3132 | ||
2954 | if (info->attrs[NL80211_ATTR_REASON_CODE]) { | 3133 | req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); |
2955 | req.reason_code = | 3134 | if (req.reason_code == 0) { |
2956 | nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | 3135 | /* Reason Code 0 is reserved */ |
2957 | if (req.reason_code == 0) { | 3136 | err = -EINVAL; |
2958 | /* Reason Code 0 is reserved */ | 3137 | goto out; |
2959 | err = -EINVAL; | ||
2960 | goto out; | ||
2961 | } | ||
2962 | } | 3138 | } |
2963 | 3139 | ||
2964 | if (info->attrs[NL80211_ATTR_IE]) { | 3140 | if (info->attrs[NL80211_ATTR_IE]) { |
@@ -2976,6 +3152,124 @@ unlock_rtnl: | |||
2976 | return err; | 3152 | return err; |
2977 | } | 3153 | } |
2978 | 3154 | ||
3155 | static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) | ||
3156 | { | ||
3157 | struct cfg80211_registered_device *drv; | ||
3158 | struct net_device *dev; | ||
3159 | struct cfg80211_ibss_params ibss; | ||
3160 | struct wiphy *wiphy; | ||
3161 | int err; | ||
3162 | |||
3163 | memset(&ibss, 0, sizeof(ibss)); | ||
3164 | |||
3165 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
3166 | return -EINVAL; | ||
3167 | |||
3168 | if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || | ||
3169 | !info->attrs[NL80211_ATTR_SSID] || | ||
3170 | !nla_len(info->attrs[NL80211_ATTR_SSID])) | ||
3171 | return -EINVAL; | ||
3172 | |||
3173 | ibss.beacon_interval = 100; | ||
3174 | |||
3175 | if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) { | ||
3176 | ibss.beacon_interval = | ||
3177 | nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]); | ||
3178 | if (ibss.beacon_interval < 1 || ibss.beacon_interval > 10000) | ||
3179 | return -EINVAL; | ||
3180 | } | ||
3181 | |||
3182 | rtnl_lock(); | ||
3183 | |||
3184 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
3185 | if (err) | ||
3186 | goto unlock_rtnl; | ||
3187 | |||
3188 | if (!drv->ops->join_ibss) { | ||
3189 | err = -EOPNOTSUPP; | ||
3190 | goto out; | ||
3191 | } | ||
3192 | |||
3193 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | ||
3194 | err = -EOPNOTSUPP; | ||
3195 | goto out; | ||
3196 | } | ||
3197 | |||
3198 | if (!netif_running(dev)) { | ||
3199 | err = -ENETDOWN; | ||
3200 | goto out; | ||
3201 | } | ||
3202 | |||
3203 | wiphy = &drv->wiphy; | ||
3204 | |||
3205 | if (info->attrs[NL80211_ATTR_MAC]) | ||
3206 | ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
3207 | ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | ||
3208 | ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | ||
3209 | |||
3210 | if (info->attrs[NL80211_ATTR_IE]) { | ||
3211 | ibss.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
3212 | ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
3213 | } | ||
3214 | |||
3215 | ibss.channel = ieee80211_get_channel(wiphy, | ||
3216 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | ||
3217 | if (!ibss.channel || | ||
3218 | ibss.channel->flags & IEEE80211_CHAN_NO_IBSS || | ||
3219 | ibss.channel->flags & IEEE80211_CHAN_DISABLED) { | ||
3220 | err = -EINVAL; | ||
3221 | goto out; | ||
3222 | } | ||
3223 | |||
3224 | ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; | ||
3225 | |||
3226 | err = cfg80211_join_ibss(drv, dev, &ibss); | ||
3227 | |||
3228 | out: | ||
3229 | cfg80211_put_dev(drv); | ||
3230 | dev_put(dev); | ||
3231 | unlock_rtnl: | ||
3232 | rtnl_unlock(); | ||
3233 | return err; | ||
3234 | } | ||
3235 | |||
3236 | static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info) | ||
3237 | { | ||
3238 | struct cfg80211_registered_device *drv; | ||
3239 | struct net_device *dev; | ||
3240 | int err; | ||
3241 | |||
3242 | rtnl_lock(); | ||
3243 | |||
3244 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
3245 | if (err) | ||
3246 | goto unlock_rtnl; | ||
3247 | |||
3248 | if (!drv->ops->leave_ibss) { | ||
3249 | err = -EOPNOTSUPP; | ||
3250 | goto out; | ||
3251 | } | ||
3252 | |||
3253 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) { | ||
3254 | err = -EOPNOTSUPP; | ||
3255 | goto out; | ||
3256 | } | ||
3257 | |||
3258 | if (!netif_running(dev)) { | ||
3259 | err = -ENETDOWN; | ||
3260 | goto out; | ||
3261 | } | ||
3262 | |||
3263 | err = cfg80211_leave_ibss(drv, dev, false); | ||
3264 | |||
3265 | out: | ||
3266 | cfg80211_put_dev(drv); | ||
3267 | dev_put(dev); | ||
3268 | unlock_rtnl: | ||
3269 | rtnl_unlock(); | ||
3270 | return err; | ||
3271 | } | ||
3272 | |||
2979 | static struct genl_ops nl80211_ops[] = { | 3273 | static struct genl_ops nl80211_ops[] = { |
2980 | { | 3274 | { |
2981 | .cmd = NL80211_CMD_GET_WIPHY, | 3275 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -3177,6 +3471,18 @@ static struct genl_ops nl80211_ops[] = { | |||
3177 | .policy = nl80211_policy, | 3471 | .policy = nl80211_policy, |
3178 | .flags = GENL_ADMIN_PERM, | 3472 | .flags = GENL_ADMIN_PERM, |
3179 | }, | 3473 | }, |
3474 | { | ||
3475 | .cmd = NL80211_CMD_JOIN_IBSS, | ||
3476 | .doit = nl80211_join_ibss, | ||
3477 | .policy = nl80211_policy, | ||
3478 | .flags = GENL_ADMIN_PERM, | ||
3479 | }, | ||
3480 | { | ||
3481 | .cmd = NL80211_CMD_LEAVE_IBSS, | ||
3482 | .doit = nl80211_leave_ibss, | ||
3483 | .policy = nl80211_policy, | ||
3484 | .flags = GENL_ADMIN_PERM, | ||
3485 | }, | ||
3180 | }; | 3486 | }; |
3181 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 3487 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
3182 | .name = "mlme", | 3488 | .name = "mlme", |
@@ -3375,22 +3681,197 @@ void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, | |||
3375 | nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_ASSOCIATE); | 3681 | nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_ASSOCIATE); |
3376 | } | 3682 | } |
3377 | 3683 | ||
3378 | void nl80211_send_rx_deauth(struct cfg80211_registered_device *rdev, | 3684 | void nl80211_send_deauth(struct cfg80211_registered_device *rdev, |
3379 | struct net_device *netdev, const u8 *buf, | 3685 | struct net_device *netdev, const u8 *buf, size_t len) |
3380 | size_t len) | ||
3381 | { | 3686 | { |
3382 | nl80211_send_mlme_event(rdev, netdev, buf, len, | 3687 | nl80211_send_mlme_event(rdev, netdev, buf, len, |
3383 | NL80211_CMD_DEAUTHENTICATE); | 3688 | NL80211_CMD_DEAUTHENTICATE); |
3384 | } | 3689 | } |
3385 | 3690 | ||
3386 | void nl80211_send_rx_disassoc(struct cfg80211_registered_device *rdev, | 3691 | void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, |
3387 | struct net_device *netdev, const u8 *buf, | 3692 | struct net_device *netdev, const u8 *buf, |
3388 | size_t len) | 3693 | size_t len) |
3389 | { | 3694 | { |
3390 | nl80211_send_mlme_event(rdev, netdev, buf, len, | 3695 | nl80211_send_mlme_event(rdev, netdev, buf, len, |
3391 | NL80211_CMD_DISASSOCIATE); | 3696 | NL80211_CMD_DISASSOCIATE); |
3392 | } | 3697 | } |
3393 | 3698 | ||
3699 | void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev, | ||
3700 | struct net_device *netdev, int cmd, | ||
3701 | const u8 *addr) | ||
3702 | { | ||
3703 | struct sk_buff *msg; | ||
3704 | void *hdr; | ||
3705 | |||
3706 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); | ||
3707 | if (!msg) | ||
3708 | return; | ||
3709 | |||
3710 | hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); | ||
3711 | if (!hdr) { | ||
3712 | nlmsg_free(msg); | ||
3713 | return; | ||
3714 | } | ||
3715 | |||
3716 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
3717 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
3718 | NLA_PUT_FLAG(msg, NL80211_ATTR_TIMED_OUT); | ||
3719 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); | ||
3720 | |||
3721 | if (genlmsg_end(msg, hdr) < 0) { | ||
3722 | nlmsg_free(msg); | ||
3723 | return; | ||
3724 | } | ||
3725 | |||
3726 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC); | ||
3727 | return; | ||
3728 | |||
3729 | nla_put_failure: | ||
3730 | genlmsg_cancel(msg, hdr); | ||
3731 | nlmsg_free(msg); | ||
3732 | } | ||
3733 | |||
3734 | void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, | ||
3735 | struct net_device *netdev, const u8 *addr) | ||
3736 | { | ||
3737 | nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_AUTHENTICATE, | ||
3738 | addr); | ||
3739 | } | ||
3740 | |||
3741 | void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, | ||
3742 | struct net_device *netdev, const u8 *addr) | ||
3743 | { | ||
3744 | nl80211_send_mlme_timeout(rdev, netdev, NL80211_CMD_ASSOCIATE, addr); | ||
3745 | } | ||
3746 | |||
3747 | void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, | ||
3748 | struct net_device *netdev, const u8 *bssid, | ||
3749 | gfp_t gfp) | ||
3750 | { | ||
3751 | struct sk_buff *msg; | ||
3752 | void *hdr; | ||
3753 | |||
3754 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | ||
3755 | if (!msg) | ||
3756 | return; | ||
3757 | |||
3758 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_JOIN_IBSS); | ||
3759 | if (!hdr) { | ||
3760 | nlmsg_free(msg); | ||
3761 | return; | ||
3762 | } | ||
3763 | |||
3764 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
3765 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
3766 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); | ||
3767 | |||
3768 | if (genlmsg_end(msg, hdr) < 0) { | ||
3769 | nlmsg_free(msg); | ||
3770 | return; | ||
3771 | } | ||
3772 | |||
3773 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); | ||
3774 | return; | ||
3775 | |||
3776 | nla_put_failure: | ||
3777 | genlmsg_cancel(msg, hdr); | ||
3778 | nlmsg_free(msg); | ||
3779 | } | ||
3780 | |||
3781 | void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, | ||
3782 | struct net_device *netdev, const u8 *addr, | ||
3783 | enum nl80211_key_type key_type, int key_id, | ||
3784 | const u8 *tsc) | ||
3785 | { | ||
3786 | struct sk_buff *msg; | ||
3787 | void *hdr; | ||
3788 | |||
3789 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
3790 | if (!msg) | ||
3791 | return; | ||
3792 | |||
3793 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE); | ||
3794 | if (!hdr) { | ||
3795 | nlmsg_free(msg); | ||
3796 | return; | ||
3797 | } | ||
3798 | |||
3799 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
3800 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
3801 | if (addr) | ||
3802 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr); | ||
3803 | NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, key_type); | ||
3804 | NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id); | ||
3805 | if (tsc) | ||
3806 | NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc); | ||
3807 | |||
3808 | if (genlmsg_end(msg, hdr) < 0) { | ||
3809 | nlmsg_free(msg); | ||
3810 | return; | ||
3811 | } | ||
3812 | |||
3813 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL); | ||
3814 | return; | ||
3815 | |||
3816 | nla_put_failure: | ||
3817 | genlmsg_cancel(msg, hdr); | ||
3818 | nlmsg_free(msg); | ||
3819 | } | ||
3820 | |||
3821 | void nl80211_send_beacon_hint_event(struct wiphy *wiphy, | ||
3822 | struct ieee80211_channel *channel_before, | ||
3823 | struct ieee80211_channel *channel_after) | ||
3824 | { | ||
3825 | struct sk_buff *msg; | ||
3826 | void *hdr; | ||
3827 | struct nlattr *nl_freq; | ||
3828 | |||
3829 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); | ||
3830 | if (!msg) | ||
3831 | return; | ||
3832 | |||
3833 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_BEACON_HINT); | ||
3834 | if (!hdr) { | ||
3835 | nlmsg_free(msg); | ||
3836 | return; | ||
3837 | } | ||
3838 | |||
3839 | /* | ||
3840 | * Since we are applying the beacon hint to a wiphy we know its | ||
3841 | * wiphy_idx is valid | ||
3842 | */ | ||
3843 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)); | ||
3844 | |||
3845 | /* Before */ | ||
3846 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE); | ||
3847 | if (!nl_freq) | ||
3848 | goto nla_put_failure; | ||
3849 | if (nl80211_msg_put_channel(msg, channel_before)) | ||
3850 | goto nla_put_failure; | ||
3851 | nla_nest_end(msg, nl_freq); | ||
3852 | |||
3853 | /* After */ | ||
3854 | nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER); | ||
3855 | if (!nl_freq) | ||
3856 | goto nla_put_failure; | ||
3857 | if (nl80211_msg_put_channel(msg, channel_after)) | ||
3858 | goto nla_put_failure; | ||
3859 | nla_nest_end(msg, nl_freq); | ||
3860 | |||
3861 | if (genlmsg_end(msg, hdr) < 0) { | ||
3862 | nlmsg_free(msg); | ||
3863 | return; | ||
3864 | } | ||
3865 | |||
3866 | genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_ATOMIC); | ||
3867 | |||
3868 | return; | ||
3869 | |||
3870 | nla_put_failure: | ||
3871 | genlmsg_cancel(msg, hdr); | ||
3872 | nlmsg_free(msg); | ||
3873 | } | ||
3874 | |||
3394 | /* initialisation/exit functions */ | 3875 | /* initialisation/exit functions */ |
3395 | 3876 | ||
3396 | int nl80211_init(void) | 3877 | int nl80211_init(void) |