aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r--net/mac80211/util.c346
1 files changed, 126 insertions, 220 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 5bfb80cba634..eca0fad09709 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -13,13 +13,13 @@
13 13
14#include <net/mac80211.h> 14#include <net/mac80211.h>
15#include <linux/netdevice.h> 15#include <linux/netdevice.h>
16#include <linux/export.h>
16#include <linux/types.h> 17#include <linux/types.h>
17#include <linux/slab.h> 18#include <linux/slab.h>
18#include <linux/skbuff.h> 19#include <linux/skbuff.h>
19#include <linux/etherdevice.h> 20#include <linux/etherdevice.h>
20#include <linux/if_arp.h> 21#include <linux/if_arp.h>
21#include <linux/bitmap.h> 22#include <linux/bitmap.h>
22#include <linux/crc32.h>
23#include <net/net_namespace.h> 23#include <net/net_namespace.h>
24#include <net/cfg80211.h> 24#include <net/cfg80211.h>
25#include <net/rtnetlink.h> 25#include <net/rtnetlink.h>
@@ -368,14 +368,14 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
368 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 368 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
369} 369}
370 370
371int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, 371void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
372 struct sk_buff_head *skbs, 372 struct sk_buff_head *skbs,
373 void (*fn)(void *data), void *data) 373 void (*fn)(void *data), void *data)
374{ 374{
375 struct ieee80211_hw *hw = &local->hw; 375 struct ieee80211_hw *hw = &local->hw;
376 struct sk_buff *skb; 376 struct sk_buff *skb;
377 unsigned long flags; 377 unsigned long flags;
378 int queue, ret = 0, i; 378 int queue, i;
379 379
380 spin_lock_irqsave(&local->queue_stop_reason_lock, flags); 380 spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
381 for (i = 0; i < hw->queues; i++) 381 for (i = 0; i < hw->queues; i++)
@@ -390,7 +390,6 @@ int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
390 continue; 390 continue;
391 } 391 }
392 392
393 ret++;
394 queue = skb_get_queue_mapping(skb); 393 queue = skb_get_queue_mapping(skb);
395 __skb_queue_tail(&local->pending[queue], skb); 394 __skb_queue_tail(&local->pending[queue], skb);
396 } 395 }
@@ -402,14 +401,12 @@ int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
402 __ieee80211_wake_queue(hw, i, 401 __ieee80211_wake_queue(hw, i,
403 IEEE80211_QUEUE_STOP_REASON_SKB_ADD); 402 IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
404 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 403 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
405
406 return ret;
407} 404}
408 405
409int ieee80211_add_pending_skbs(struct ieee80211_local *local, 406void ieee80211_add_pending_skbs(struct ieee80211_local *local,
410 struct sk_buff_head *skbs) 407 struct sk_buff_head *skbs)
411{ 408{
412 return ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL); 409 ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
413} 410}
414 411
415void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, 412void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
@@ -573,172 +570,6 @@ void ieee802_11_parse_elems(u8 *start, size_t len,
573 ieee802_11_parse_elems_crc(start, len, elems, 0, 0); 570 ieee802_11_parse_elems_crc(start, len, elems, 0, 0);
574} 571}
575 572
576u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
577 struct ieee802_11_elems *elems,
578 u64 filter, u32 crc)
579{
580 size_t left = len;
581 u8 *pos = start;
582 bool calc_crc = filter != 0;
583
584 memset(elems, 0, sizeof(*elems));
585 elems->ie_start = start;
586 elems->total_len = len;
587
588 while (left >= 2) {
589 u8 id, elen;
590
591 id = *pos++;
592 elen = *pos++;
593 left -= 2;
594
595 if (elen > left)
596 break;
597
598 if (calc_crc && id < 64 && (filter & (1ULL << id)))
599 crc = crc32_be(crc, pos - 2, elen + 2);
600
601 switch (id) {
602 case WLAN_EID_SSID:
603 elems->ssid = pos;
604 elems->ssid_len = elen;
605 break;
606 case WLAN_EID_SUPP_RATES:
607 elems->supp_rates = pos;
608 elems->supp_rates_len = elen;
609 break;
610 case WLAN_EID_FH_PARAMS:
611 elems->fh_params = pos;
612 elems->fh_params_len = elen;
613 break;
614 case WLAN_EID_DS_PARAMS:
615 elems->ds_params = pos;
616 elems->ds_params_len = elen;
617 break;
618 case WLAN_EID_CF_PARAMS:
619 elems->cf_params = pos;
620 elems->cf_params_len = elen;
621 break;
622 case WLAN_EID_TIM:
623 if (elen >= sizeof(struct ieee80211_tim_ie)) {
624 elems->tim = (void *)pos;
625 elems->tim_len = elen;
626 }
627 break;
628 case WLAN_EID_IBSS_PARAMS:
629 elems->ibss_params = pos;
630 elems->ibss_params_len = elen;
631 break;
632 case WLAN_EID_CHALLENGE:
633 elems->challenge = pos;
634 elems->challenge_len = elen;
635 break;
636 case WLAN_EID_VENDOR_SPECIFIC:
637 if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
638 pos[2] == 0xf2) {
639 /* Microsoft OUI (00:50:F2) */
640
641 if (calc_crc)
642 crc = crc32_be(crc, pos - 2, elen + 2);
643
644 if (pos[3] == 1) {
645 /* OUI Type 1 - WPA IE */
646 elems->wpa = pos;
647 elems->wpa_len = elen;
648 } else if (elen >= 5 && pos[3] == 2) {
649 /* OUI Type 2 - WMM IE */
650 if (pos[4] == 0) {
651 elems->wmm_info = pos;
652 elems->wmm_info_len = elen;
653 } else if (pos[4] == 1) {
654 elems->wmm_param = pos;
655 elems->wmm_param_len = elen;
656 }
657 }
658 }
659 break;
660 case WLAN_EID_RSN:
661 elems->rsn = pos;
662 elems->rsn_len = elen;
663 break;
664 case WLAN_EID_ERP_INFO:
665 elems->erp_info = pos;
666 elems->erp_info_len = elen;
667 break;
668 case WLAN_EID_EXT_SUPP_RATES:
669 elems->ext_supp_rates = pos;
670 elems->ext_supp_rates_len = elen;
671 break;
672 case WLAN_EID_HT_CAPABILITY:
673 if (elen >= sizeof(struct ieee80211_ht_cap))
674 elems->ht_cap_elem = (void *)pos;
675 break;
676 case WLAN_EID_HT_INFORMATION:
677 if (elen >= sizeof(struct ieee80211_ht_info))
678 elems->ht_info_elem = (void *)pos;
679 break;
680 case WLAN_EID_MESH_ID:
681 elems->mesh_id = pos;
682 elems->mesh_id_len = elen;
683 break;
684 case WLAN_EID_MESH_CONFIG:
685 if (elen >= sizeof(struct ieee80211_meshconf_ie))
686 elems->mesh_config = (void *)pos;
687 break;
688 case WLAN_EID_PEER_LINK:
689 elems->peer_link = pos;
690 elems->peer_link_len = elen;
691 break;
692 case WLAN_EID_PREQ:
693 elems->preq = pos;
694 elems->preq_len = elen;
695 break;
696 case WLAN_EID_PREP:
697 elems->prep = pos;
698 elems->prep_len = elen;
699 break;
700 case WLAN_EID_PERR:
701 elems->perr = pos;
702 elems->perr_len = elen;
703 break;
704 case WLAN_EID_RANN:
705 if (elen >= sizeof(struct ieee80211_rann_ie))
706 elems->rann = (void *)pos;
707 break;
708 case WLAN_EID_CHANNEL_SWITCH:
709 elems->ch_switch_elem = pos;
710 elems->ch_switch_elem_len = elen;
711 break;
712 case WLAN_EID_QUIET:
713 if (!elems->quiet_elem) {
714 elems->quiet_elem = pos;
715 elems->quiet_elem_len = elen;
716 }
717 elems->num_of_quiet_elem++;
718 break;
719 case WLAN_EID_COUNTRY:
720 elems->country_elem = pos;
721 elems->country_elem_len = elen;
722 break;
723 case WLAN_EID_PWR_CONSTRAINT:
724 elems->pwr_constr_elem = pos;
725 elems->pwr_constr_elem_len = elen;
726 break;
727 case WLAN_EID_TIMEOUT_INTERVAL:
728 elems->timeout_int = pos;
729 elems->timeout_int_len = elen;
730 break;
731 default:
732 break;
733 }
734
735 left -= elen;
736 pos += elen;
737 }
738
739 return crc;
740}
741
742void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) 573void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
743{ 574{
744 struct ieee80211_local *local = sdata->local; 575 struct ieee80211_local *local = sdata->local;
@@ -799,7 +630,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
799 630
800 qparam.uapsd = false; 631 qparam.uapsd = false;
801 632
802 drv_conf_tx(local, queue, &qparam); 633 sdata->tx_conf[queue] = qparam;
634 drv_conf_tx(local, sdata, queue, &qparam);
803 } 635 }
804 636
805 /* after reinitialize QoS TX queues setting to default, 637 /* after reinitialize QoS TX queues setting to default,
@@ -873,11 +705,9 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
873 705
874 skb = dev_alloc_skb(local->hw.extra_tx_headroom + 706 skb = dev_alloc_skb(local->hw.extra_tx_headroom +
875 sizeof(*mgmt) + 6 + extra_len); 707 sizeof(*mgmt) + 6 + extra_len);
876 if (!skb) { 708 if (!skb)
877 printk(KERN_DEBUG "%s: failed to allocate buffer for auth "
878 "frame\n", sdata->name);
879 return; 709 return;
880 } 710
881 skb_reserve(skb, local->hw.extra_tx_headroom); 711 skb_reserve(skb, local->hw.extra_tx_headroom);
882 712
883 mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); 713 mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);
@@ -1016,7 +846,7 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1016} 846}
1017 847
1018struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, 848struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
1019 u8 *dst, 849 u8 *dst, u32 ratemask,
1020 const u8 *ssid, size_t ssid_len, 850 const u8 *ssid, size_t ssid_len,
1021 const u8 *ie, size_t ie_len, 851 const u8 *ie, size_t ie_len,
1022 bool directed) 852 bool directed)
@@ -1030,11 +860,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
1030 860
1031 /* FIXME: come up with a proper value */ 861 /* FIXME: come up with a proper value */
1032 buf = kmalloc(200 + ie_len, GFP_KERNEL); 862 buf = kmalloc(200 + ie_len, GFP_KERNEL);
1033 if (!buf) { 863 if (!buf)
1034 printk(KERN_DEBUG "%s: failed to allocate temporary IE "
1035 "buffer\n", sdata->name);
1036 return NULL; 864 return NULL;
1037 }
1038 865
1039 /* 866 /*
1040 * Do not send DS Channel parameter for directed probe requests 867 * Do not send DS Channel parameter for directed probe requests
@@ -1049,13 +876,13 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
1049 876
1050 buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, 877 buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len,
1051 local->hw.conf.channel->band, 878 local->hw.conf.channel->band,
1052 sdata->rc_rateidx_mask 879 ratemask, chan);
1053 [local->hw.conf.channel->band],
1054 chan);
1055 880
1056 skb = ieee80211_probereq_get(&local->hw, &sdata->vif, 881 skb = ieee80211_probereq_get(&local->hw, &sdata->vif,
1057 ssid, ssid_len, 882 ssid, ssid_len,
1058 buf, buf_len); 883 buf, buf_len);
884 if (!skb)
885 goto out;
1059 886
1060 if (dst) { 887 if (dst) {
1061 mgmt = (struct ieee80211_mgmt *) skb->data; 888 mgmt = (struct ieee80211_mgmt *) skb->data;
@@ -1064,6 +891,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
1064 } 891 }
1065 892
1066 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; 893 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
894
895 out:
1067 kfree(buf); 896 kfree(buf);
1068 897
1069 return skb; 898 return skb;
@@ -1072,14 +901,18 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
1072void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, 901void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
1073 const u8 *ssid, size_t ssid_len, 902 const u8 *ssid, size_t ssid_len,
1074 const u8 *ie, size_t ie_len, 903 const u8 *ie, size_t ie_len,
1075 bool directed) 904 u32 ratemask, bool directed, bool no_cck)
1076{ 905{
1077 struct sk_buff *skb; 906 struct sk_buff *skb;
1078 907
1079 skb = ieee80211_build_probe_req(sdata, dst, ssid, ssid_len, ie, ie_len, 908 skb = ieee80211_build_probe_req(sdata, dst, ratemask, ssid, ssid_len,
1080 directed); 909 ie, ie_len, directed);
1081 if (skb) 910 if (skb) {
911 if (no_cck)
912 IEEE80211_SKB_CB(skb)->flags |=
913 IEEE80211_TX_CTL_NO_CCK_RATE;
1082 ieee80211_tx_skb(sdata, skb); 914 ieee80211_tx_skb(sdata, skb);
915 }
1083} 916}
1084 917
1085u32 ieee80211_sta_get_rates(struct ieee80211_local *local, 918u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
@@ -1134,7 +967,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1134 struct ieee80211_hw *hw = &local->hw; 967 struct ieee80211_hw *hw = &local->hw;
1135 struct ieee80211_sub_if_data *sdata; 968 struct ieee80211_sub_if_data *sdata;
1136 struct sta_info *sta; 969 struct sta_info *sta;
1137 int res; 970 int res, i;
1138 971
1139#ifdef CONFIG_PM 972#ifdef CONFIG_PM
1140 if (local->suspended) 973 if (local->suspended)
@@ -1157,27 +990,37 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1157 } 990 }
1158#endif 991#endif
1159 992
1160 /* restart hardware */ 993 /* setup fragmentation threshold */
1161 if (local->open_count) { 994 drv_set_frag_threshold(local, hw->wiphy->frag_threshold);
1162 /*
1163 * Upon resume hardware can sometimes be goofy due to
1164 * various platform / driver / bus issues, so restarting
1165 * the device may at times not work immediately. Propagate
1166 * the error.
1167 */
1168 res = drv_start(local);
1169 if (res) {
1170 WARN(local->suspended, "Hardware became unavailable "
1171 "upon resume. This could be a software issue "
1172 "prior to suspend or a hardware issue.\n");
1173 return res;
1174 }
1175 995
1176 ieee80211_led_radio(local, true); 996 /* setup RTS threshold */
1177 ieee80211_mod_tpt_led_trig(local, 997 drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
1178 IEEE80211_TPT_LEDTRIG_FL_RADIO, 0); 998
999 /* reset coverage class */
1000 drv_set_coverage_class(local, hw->wiphy->coverage_class);
1001
1002 /* everything else happens only if HW was up & running */
1003 if (!local->open_count)
1004 goto wake_up;
1005
1006 /*
1007 * Upon resume hardware can sometimes be goofy due to
1008 * various platform / driver / bus issues, so restarting
1009 * the device may at times not work immediately. Propagate
1010 * the error.
1011 */
1012 res = drv_start(local);
1013 if (res) {
1014 WARN(local->suspended, "Hardware became unavailable "
1015 "upon resume. This could be a software issue "
1016 "prior to suspend or a hardware issue.\n");
1017 return res;
1179 } 1018 }
1180 1019
1020 ieee80211_led_radio(local, true);
1021 ieee80211_mod_tpt_led_trig(local,
1022 IEEE80211_TPT_LEDTRIG_FL_RADIO, 0);
1023
1181 /* add interfaces */ 1024 /* add interfaces */
1182 list_for_each_entry(sdata, &local->interfaces, list) { 1025 list_for_each_entry(sdata, &local->interfaces, list) {
1183 if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && 1026 if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
@@ -1196,16 +1039,22 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1196 struct ieee80211_sub_if_data, 1039 struct ieee80211_sub_if_data,
1197 u.ap); 1040 u.ap);
1198 1041
1042 memset(&sta->sta.drv_priv, 0, hw->sta_data_size);
1199 WARN_ON(drv_sta_add(local, sdata, &sta->sta)); 1043 WARN_ON(drv_sta_add(local, sdata, &sta->sta));
1200 } 1044 }
1201 } 1045 }
1202 mutex_unlock(&local->sta_mtx); 1046 mutex_unlock(&local->sta_mtx);
1203 1047
1204 /* setup fragmentation threshold */ 1048 /* reconfigure tx conf */
1205 drv_set_frag_threshold(local, hw->wiphy->frag_threshold); 1049 list_for_each_entry(sdata, &local->interfaces, list) {
1050 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
1051 sdata->vif.type == NL80211_IFTYPE_MONITOR ||
1052 !ieee80211_sdata_running(sdata))
1053 continue;
1206 1054
1207 /* setup RTS threshold */ 1055 for (i = 0; i < hw->queues; i++)
1208 drv_set_rts_threshold(local, hw->wiphy->rts_threshold); 1056 drv_conf_tx(local, sdata, i, &sdata->tx_conf[i]);
1057 }
1209 1058
1210 /* reconfigure hardware */ 1059 /* reconfigure hardware */
1211 ieee80211_hw_config(local, ~0); 1060 ieee80211_hw_config(local, ~0);
@@ -1241,6 +1090,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1241 changed |= BSS_CHANGED_IBSS; 1090 changed |= BSS_CHANGED_IBSS;
1242 /* fall through */ 1091 /* fall through */
1243 case NL80211_IFTYPE_AP: 1092 case NL80211_IFTYPE_AP:
1093 changed |= BSS_CHANGED_SSID;
1094 /* fall through */
1244 case NL80211_IFTYPE_MESH_POINT: 1095 case NL80211_IFTYPE_MESH_POINT:
1245 changed |= BSS_CHANGED_BEACON | 1096 changed |= BSS_CHANGED_BEACON |
1246 BSS_CHANGED_BEACON_ENABLED; 1097 BSS_CHANGED_BEACON_ENABLED;
@@ -1276,7 +1127,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1276 1127
1277 list_for_each_entry(sta, &local->sta_list, list) { 1128 list_for_each_entry(sta, &local->sta_list, list) {
1278 ieee80211_sta_tear_down_BA_sessions(sta, true); 1129 ieee80211_sta_tear_down_BA_sessions(sta, true);
1279 clear_sta_flags(sta, WLAN_STA_BLOCK_BA); 1130 clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
1280 } 1131 }
1281 1132
1282 mutex_unlock(&local->sta_mtx); 1133 mutex_unlock(&local->sta_mtx);
@@ -1287,9 +1138,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1287 if (ieee80211_sdata_running(sdata)) 1138 if (ieee80211_sdata_running(sdata))
1288 ieee80211_enable_keys(sdata); 1139 ieee80211_enable_keys(sdata);
1289 1140
1290#ifdef CONFIG_PM
1291 wake_up: 1141 wake_up:
1292#endif
1293 ieee80211_wake_queues_by_reason(hw, 1142 ieee80211_wake_queues_by_reason(hw,
1294 IEEE80211_QUEUE_STOP_REASON_SUSPEND); 1143 IEEE80211_QUEUE_STOP_REASON_SUSPEND);
1295 1144
@@ -1517,3 +1366,60 @@ void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif)
1517 _ieee80211_enable_rssi_reports(sdata, 0, 0); 1366 _ieee80211_enable_rssi_reports(sdata, 0, 0);
1518} 1367}
1519EXPORT_SYMBOL(ieee80211_disable_rssi_reports); 1368EXPORT_SYMBOL(ieee80211_disable_rssi_reports);
1369
1370int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
1371{
1372 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
1373 struct ieee80211_local *local = sdata->local;
1374 struct ieee80211_supported_band *sband;
1375 int rate;
1376 u8 i, rates, *pos;
1377
1378 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
1379 rates = sband->n_bitrates;
1380 if (rates > 8)
1381 rates = 8;
1382
1383 if (skb_tailroom(skb) < rates + 2)
1384 return -ENOMEM;
1385
1386 pos = skb_put(skb, rates + 2);
1387 *pos++ = WLAN_EID_SUPP_RATES;
1388 *pos++ = rates;
1389 for (i = 0; i < rates; i++) {
1390 rate = sband->bitrates[i].bitrate;
1391 *pos++ = (u8) (rate / 5);
1392 }
1393
1394 return 0;
1395}
1396
1397int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
1398{
1399 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
1400 struct ieee80211_local *local = sdata->local;
1401 struct ieee80211_supported_band *sband;
1402 int rate;
1403 u8 i, exrates, *pos;
1404
1405 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
1406 exrates = sband->n_bitrates;
1407 if (exrates > 8)
1408 exrates -= 8;
1409 else
1410 exrates = 0;
1411
1412 if (skb_tailroom(skb) < exrates + 2)
1413 return -ENOMEM;
1414
1415 if (exrates) {
1416 pos = skb_put(skb, exrates + 2);
1417 *pos++ = WLAN_EID_EXT_SUPP_RATES;
1418 *pos++ = exrates;
1419 for (i = 8; i < sband->n_bitrates; i++) {
1420 rate = sband->bitrates[i].bitrate;
1421 *pos++ = (u8) (rate / 5);
1422 }
1423 }
1424 return 0;
1425}