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.c328
1 files changed, 295 insertions, 33 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index d5230ecc784d..9919892575f4 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -20,6 +20,7 @@
20#include <linux/etherdevice.h> 20#include <linux/etherdevice.h>
21#include <linux/if_arp.h> 21#include <linux/if_arp.h>
22#include <linux/bitmap.h> 22#include <linux/bitmap.h>
23#include <linux/crc32.h>
23#include <net/net_namespace.h> 24#include <net/net_namespace.h>
24#include <net/cfg80211.h> 25#include <net/cfg80211.h>
25#include <net/rtnetlink.h> 26#include <net/rtnetlink.h>
@@ -96,13 +97,13 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
96 97
97void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) 98void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx)
98{ 99{
99 struct sk_buff *skb = tx->skb; 100 struct sk_buff *skb;
100 struct ieee80211_hdr *hdr; 101 struct ieee80211_hdr *hdr;
101 102
102 do { 103 skb_queue_walk(&tx->skbs, skb) {
103 hdr = (struct ieee80211_hdr *) skb->data; 104 hdr = (struct ieee80211_hdr *) skb->data;
104 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); 105 hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
105 } while ((skb = skb->next)); 106 }
106} 107}
107 108
108int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, 109int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
@@ -564,6 +565,172 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
564} 565}
565EXPORT_SYMBOL(ieee80211_queue_delayed_work); 566EXPORT_SYMBOL(ieee80211_queue_delayed_work);
566 567
568u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
569 struct ieee802_11_elems *elems,
570 u64 filter, u32 crc)
571{
572 size_t left = len;
573 u8 *pos = start;
574 bool calc_crc = filter != 0;
575
576 memset(elems, 0, sizeof(*elems));
577 elems->ie_start = start;
578 elems->total_len = len;
579
580 while (left >= 2) {
581 u8 id, elen;
582
583 id = *pos++;
584 elen = *pos++;
585 left -= 2;
586
587 if (elen > left)
588 break;
589
590 if (calc_crc && id < 64 && (filter & (1ULL << id)))
591 crc = crc32_be(crc, pos - 2, elen + 2);
592
593 switch (id) {
594 case WLAN_EID_SSID:
595 elems->ssid = pos;
596 elems->ssid_len = elen;
597 break;
598 case WLAN_EID_SUPP_RATES:
599 elems->supp_rates = pos;
600 elems->supp_rates_len = elen;
601 break;
602 case WLAN_EID_FH_PARAMS:
603 elems->fh_params = pos;
604 elems->fh_params_len = elen;
605 break;
606 case WLAN_EID_DS_PARAMS:
607 elems->ds_params = pos;
608 elems->ds_params_len = elen;
609 break;
610 case WLAN_EID_CF_PARAMS:
611 elems->cf_params = pos;
612 elems->cf_params_len = elen;
613 break;
614 case WLAN_EID_TIM:
615 if (elen >= sizeof(struct ieee80211_tim_ie)) {
616 elems->tim = (void *)pos;
617 elems->tim_len = elen;
618 }
619 break;
620 case WLAN_EID_IBSS_PARAMS:
621 elems->ibss_params = pos;
622 elems->ibss_params_len = elen;
623 break;
624 case WLAN_EID_CHALLENGE:
625 elems->challenge = pos;
626 elems->challenge_len = elen;
627 break;
628 case WLAN_EID_VENDOR_SPECIFIC:
629 if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
630 pos[2] == 0xf2) {
631 /* Microsoft OUI (00:50:F2) */
632
633 if (calc_crc)
634 crc = crc32_be(crc, pos - 2, elen + 2);
635
636 if (pos[3] == 1) {
637 /* OUI Type 1 - WPA IE */
638 elems->wpa = pos;
639 elems->wpa_len = elen;
640 } else if (elen >= 5 && pos[3] == 2) {
641 /* OUI Type 2 - WMM IE */
642 if (pos[4] == 0) {
643 elems->wmm_info = pos;
644 elems->wmm_info_len = elen;
645 } else if (pos[4] == 1) {
646 elems->wmm_param = pos;
647 elems->wmm_param_len = elen;
648 }
649 }
650 }
651 break;
652 case WLAN_EID_RSN:
653 elems->rsn = pos;
654 elems->rsn_len = elen;
655 break;
656 case WLAN_EID_ERP_INFO:
657 elems->erp_info = pos;
658 elems->erp_info_len = elen;
659 break;
660 case WLAN_EID_EXT_SUPP_RATES:
661 elems->ext_supp_rates = pos;
662 elems->ext_supp_rates_len = elen;
663 break;
664 case WLAN_EID_HT_CAPABILITY:
665 if (elen >= sizeof(struct ieee80211_ht_cap))
666 elems->ht_cap_elem = (void *)pos;
667 break;
668 case WLAN_EID_HT_INFORMATION:
669 if (elen >= sizeof(struct ieee80211_ht_info))
670 elems->ht_info_elem = (void *)pos;
671 break;
672 case WLAN_EID_MESH_ID:
673 elems->mesh_id = pos;
674 elems->mesh_id_len = elen;
675 break;
676 case WLAN_EID_MESH_CONFIG:
677 if (elen >= sizeof(struct ieee80211_meshconf_ie))
678 elems->mesh_config = (void *)pos;
679 break;
680 case WLAN_EID_PEER_MGMT:
681 elems->peering = pos;
682 elems->peering_len = elen;
683 break;
684 case WLAN_EID_PREQ:
685 elems->preq = pos;
686 elems->preq_len = elen;
687 break;
688 case WLAN_EID_PREP:
689 elems->prep = pos;
690 elems->prep_len = elen;
691 break;
692 case WLAN_EID_PERR:
693 elems->perr = pos;
694 elems->perr_len = elen;
695 break;
696 case WLAN_EID_RANN:
697 if (elen >= sizeof(struct ieee80211_rann_ie))
698 elems->rann = (void *)pos;
699 break;
700 case WLAN_EID_CHANNEL_SWITCH:
701 elems->ch_switch_elem = pos;
702 elems->ch_switch_elem_len = elen;
703 break;
704 case WLAN_EID_QUIET:
705 if (!elems->quiet_elem) {
706 elems->quiet_elem = pos;
707 elems->quiet_elem_len = elen;
708 }
709 elems->num_of_quiet_elem++;
710 break;
711 case WLAN_EID_COUNTRY:
712 elems->country_elem = pos;
713 elems->country_elem_len = elen;
714 break;
715 case WLAN_EID_PWR_CONSTRAINT:
716 elems->pwr_constr_elem = pos;
717 elems->pwr_constr_elem_len = elen;
718 break;
719 case WLAN_EID_TIMEOUT_INTERVAL:
720 elems->timeout_int = pos;
721 elems->timeout_int_len = elen;
722 break;
723 default:
724 break;
725 }
726
727 left -= elen;
728 pos += elen;
729 }
730
731 return crc;
732}
733
567void ieee802_11_parse_elems(u8 *start, size_t len, 734void ieee802_11_parse_elems(u8 *start, size_t len,
568 struct ieee802_11_elems *elems) 735 struct ieee802_11_elems *elems)
569{ 736{
@@ -812,23 +979,9 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
812 offset = noffset; 979 offset = noffset;
813 } 980 }
814 981
815 if (sband->ht_cap.ht_supported) { 982 if (sband->ht_cap.ht_supported)
816 u16 cap = sband->ht_cap.cap; 983 pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap,
817 __le16 tmp; 984 sband->ht_cap.cap);
818
819 *pos++ = WLAN_EID_HT_CAPABILITY;
820 *pos++ = sizeof(struct ieee80211_ht_cap);
821 memset(pos, 0, sizeof(struct ieee80211_ht_cap));
822 tmp = cpu_to_le16(cap);
823 memcpy(pos, &tmp, sizeof(u16));
824 pos += sizeof(u16);
825 *pos++ = sband->ht_cap.ampdu_factor |
826 (sband->ht_cap.ampdu_density <<
827 IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
828 memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
829 pos += sizeof(sband->ht_cap.mcs);
830 pos += 2 + 4 + 1; /* ext info, BF cap, antsel */
831 }
832 985
833 /* 986 /*
834 * If adding more here, adjust code in main.c 987 * If adding more here, adjust code in main.c
@@ -989,16 +1142,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
989 */ 1142 */
990 } 1143 }
991#endif 1144#endif
992
993 /* setup fragmentation threshold */
994 drv_set_frag_threshold(local, hw->wiphy->frag_threshold);
995
996 /* setup RTS threshold */
997 drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
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 */ 1145 /* everything else happens only if HW was up & running */
1003 if (!local->open_count) 1146 if (!local->open_count)
1004 goto wake_up; 1147 goto wake_up;
@@ -1017,6 +1160,15 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1017 return res; 1160 return res;
1018 } 1161 }
1019 1162
1163 /* setup fragmentation threshold */
1164 drv_set_frag_threshold(local, hw->wiphy->frag_threshold);
1165
1166 /* setup RTS threshold */
1167 drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
1168
1169 /* reset coverage class */
1170 drv_set_coverage_class(local, hw->wiphy->coverage_class);
1171
1020 ieee80211_led_radio(local, true); 1172 ieee80211_led_radio(local, true);
1021 ieee80211_mod_tpt_led_trig(local, 1173 ieee80211_mod_tpt_led_trig(local,
1022 IEEE80211_TPT_LEDTRIG_FL_RADIO, 0); 1174 IEEE80211_TPT_LEDTRIG_FL_RADIO, 0);
@@ -1026,7 +1178,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1026 if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && 1178 if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
1027 sdata->vif.type != NL80211_IFTYPE_MONITOR && 1179 sdata->vif.type != NL80211_IFTYPE_MONITOR &&
1028 ieee80211_sdata_running(sdata)) 1180 ieee80211_sdata_running(sdata))
1029 res = drv_add_interface(local, &sdata->vif); 1181 res = drv_add_interface(local, sdata);
1030 } 1182 }
1031 1183
1032 /* add STAs back */ 1184 /* add STAs back */
@@ -1076,11 +1228,13 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1076 BSS_CHANGED_BEACON_INT | 1228 BSS_CHANGED_BEACON_INT |
1077 BSS_CHANGED_BSSID | 1229 BSS_CHANGED_BSSID |
1078 BSS_CHANGED_CQM | 1230 BSS_CHANGED_CQM |
1079 BSS_CHANGED_QOS; 1231 BSS_CHANGED_QOS |
1232 BSS_CHANGED_IDLE;
1080 1233
1081 switch (sdata->vif.type) { 1234 switch (sdata->vif.type) {
1082 case NL80211_IFTYPE_STATION: 1235 case NL80211_IFTYPE_STATION:
1083 changed |= BSS_CHANGED_ASSOC; 1236 changed |= BSS_CHANGED_ASSOC |
1237 BSS_CHANGED_ARP_FILTER;
1084 mutex_lock(&sdata->u.mgd.mtx); 1238 mutex_lock(&sdata->u.mgd.mtx);
1085 ieee80211_bss_info_change_notify(sdata, changed); 1239 ieee80211_bss_info_change_notify(sdata, changed);
1086 mutex_unlock(&sdata->u.mgd.mtx); 1240 mutex_unlock(&sdata->u.mgd.mtx);
@@ -1090,6 +1244,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1090 /* fall through */ 1244 /* fall through */
1091 case NL80211_IFTYPE_AP: 1245 case NL80211_IFTYPE_AP:
1092 changed |= BSS_CHANGED_SSID; 1246 changed |= BSS_CHANGED_SSID;
1247
1248 if (sdata->vif.type == NL80211_IFTYPE_AP)
1249 changed |= BSS_CHANGED_AP_PROBE_RESP;
1250
1093 /* fall through */ 1251 /* fall through */
1094 case NL80211_IFTYPE_MESH_POINT: 1252 case NL80211_IFTYPE_MESH_POINT:
1095 changed |= BSS_CHANGED_BEACON | 1253 changed |= BSS_CHANGED_BEACON |
@@ -1111,6 +1269,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1111 } 1269 }
1112 } 1270 }
1113 1271
1272 ieee80211_recalc_ps(local, -1);
1273
1114 /* 1274 /*
1115 * Clear the WLAN_STA_BLOCK_BA flag so new aggregation 1275 * Clear the WLAN_STA_BLOCK_BA flag so new aggregation
1116 * sessions can be established after a resume. 1276 * sessions can be established after a resume.
@@ -1366,6 +1526,108 @@ void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif)
1366} 1526}
1367EXPORT_SYMBOL(ieee80211_disable_rssi_reports); 1527EXPORT_SYMBOL(ieee80211_disable_rssi_reports);
1368 1528
1529u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
1530 u16 cap)
1531{
1532 __le16 tmp;
1533
1534 *pos++ = WLAN_EID_HT_CAPABILITY;
1535 *pos++ = sizeof(struct ieee80211_ht_cap);
1536 memset(pos, 0, sizeof(struct ieee80211_ht_cap));
1537
1538 /* capability flags */
1539 tmp = cpu_to_le16(cap);
1540 memcpy(pos, &tmp, sizeof(u16));
1541 pos += sizeof(u16);
1542
1543 /* AMPDU parameters */
1544 *pos++ = ht_cap->ampdu_factor |
1545 (ht_cap->ampdu_density <<
1546 IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
1547
1548 /* MCS set */
1549 memcpy(pos, &ht_cap->mcs, sizeof(ht_cap->mcs));
1550 pos += sizeof(ht_cap->mcs);
1551
1552 /* extended capabilities */
1553 pos += sizeof(__le16);
1554
1555 /* BF capabilities */
1556 pos += sizeof(__le32);
1557
1558 /* antenna selection */
1559 pos += sizeof(u8);
1560
1561 return pos;
1562}
1563
1564u8 *ieee80211_ie_build_ht_info(u8 *pos,
1565 struct ieee80211_sta_ht_cap *ht_cap,
1566 struct ieee80211_channel *channel,
1567 enum nl80211_channel_type channel_type)
1568{
1569 struct ieee80211_ht_info *ht_info;
1570 /* Build HT Information */
1571 *pos++ = WLAN_EID_HT_INFORMATION;
1572 *pos++ = sizeof(struct ieee80211_ht_info);
1573 ht_info = (struct ieee80211_ht_info *)pos;
1574 ht_info->control_chan =
1575 ieee80211_frequency_to_channel(channel->center_freq);
1576 switch (channel_type) {
1577 case NL80211_CHAN_HT40MINUS:
1578 ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
1579 break;
1580 case NL80211_CHAN_HT40PLUS:
1581 ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
1582 break;
1583 case NL80211_CHAN_HT20:
1584 default:
1585 ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
1586 break;
1587 }
1588 if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
1589 ht_info->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
1590
1591 /*
1592 * Note: According to 802.11n-2009 9.13.3.1, HT Protection field and
1593 * RIFS Mode are reserved in IBSS mode, therefore keep them at 0
1594 */
1595 ht_info->operation_mode = 0x0000;
1596 ht_info->stbc_param = 0x0000;
1597
1598 /* It seems that Basic MCS set and Supported MCS set
1599 are identical for the first 10 bytes */
1600 memset(&ht_info->basic_set, 0, 16);
1601 memcpy(&ht_info->basic_set, &ht_cap->mcs, 10);
1602
1603 return pos + sizeof(struct ieee80211_ht_info);
1604}
1605
1606enum nl80211_channel_type
1607ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info)
1608{
1609 enum nl80211_channel_type channel_type;
1610
1611 if (!ht_info)
1612 return NL80211_CHAN_NO_HT;
1613
1614 switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
1615 case IEEE80211_HT_PARAM_CHA_SEC_NONE:
1616 channel_type = NL80211_CHAN_HT20;
1617 break;
1618 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
1619 channel_type = NL80211_CHAN_HT40PLUS;
1620 break;
1621 case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
1622 channel_type = NL80211_CHAN_HT40MINUS;
1623 break;
1624 default:
1625 channel_type = NL80211_CHAN_NO_HT;
1626 }
1627
1628 return channel_type;
1629}
1630
1369int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb) 1631int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
1370{ 1632{
1371 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); 1633 struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);