diff options
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r-- | net/mac80211/util.c | 280 |
1 files changed, 88 insertions, 192 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ddeb1b998383..7439d26bf5f9 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/etherdevice.h> | 19 | #include <linux/etherdevice.h> |
20 | #include <linux/if_arp.h> | 20 | #include <linux/if_arp.h> |
21 | #include <linux/bitmap.h> | 21 | #include <linux/bitmap.h> |
22 | #include <linux/crc32.h> | ||
23 | #include <net/net_namespace.h> | 22 | #include <net/net_namespace.h> |
24 | #include <net/cfg80211.h> | 23 | #include <net/cfg80211.h> |
25 | #include <net/rtnetlink.h> | 24 | #include <net/rtnetlink.h> |
@@ -368,14 +367,14 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, | |||
368 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 367 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
369 | } | 368 | } |
370 | 369 | ||
371 | int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, | 370 | void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, |
372 | struct sk_buff_head *skbs, | 371 | struct sk_buff_head *skbs, |
373 | void (*fn)(void *data), void *data) | 372 | void (*fn)(void *data), void *data) |
374 | { | 373 | { |
375 | struct ieee80211_hw *hw = &local->hw; | 374 | struct ieee80211_hw *hw = &local->hw; |
376 | struct sk_buff *skb; | 375 | struct sk_buff *skb; |
377 | unsigned long flags; | 376 | unsigned long flags; |
378 | int queue, ret = 0, i; | 377 | int queue, i; |
379 | 378 | ||
380 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 379 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
381 | for (i = 0; i < hw->queues; i++) | 380 | for (i = 0; i < hw->queues; i++) |
@@ -390,7 +389,6 @@ int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, | |||
390 | continue; | 389 | continue; |
391 | } | 390 | } |
392 | 391 | ||
393 | ret++; | ||
394 | queue = skb_get_queue_mapping(skb); | 392 | queue = skb_get_queue_mapping(skb); |
395 | __skb_queue_tail(&local->pending[queue], skb); | 393 | __skb_queue_tail(&local->pending[queue], skb); |
396 | } | 394 | } |
@@ -402,14 +400,12 @@ int ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, | |||
402 | __ieee80211_wake_queue(hw, i, | 400 | __ieee80211_wake_queue(hw, i, |
403 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); | 401 | IEEE80211_QUEUE_STOP_REASON_SKB_ADD); |
404 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 402 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
405 | |||
406 | return ret; | ||
407 | } | 403 | } |
408 | 404 | ||
409 | int ieee80211_add_pending_skbs(struct ieee80211_local *local, | 405 | void ieee80211_add_pending_skbs(struct ieee80211_local *local, |
410 | struct sk_buff_head *skbs) | 406 | struct sk_buff_head *skbs) |
411 | { | 407 | { |
412 | return ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL); | 408 | ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL); |
413 | } | 409 | } |
414 | 410 | ||
415 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | 411 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, |
@@ -573,172 +569,6 @@ void ieee802_11_parse_elems(u8 *start, size_t len, | |||
573 | ieee802_11_parse_elems_crc(start, len, elems, 0, 0); | 569 | ieee802_11_parse_elems_crc(start, len, elems, 0, 0); |
574 | } | 570 | } |
575 | 571 | ||
576 | u32 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 | |||
742 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) | 572 | void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) |
743 | { | 573 | { |
744 | struct ieee80211_local *local = sdata->local; | 574 | struct ieee80211_local *local = sdata->local; |
@@ -799,8 +629,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) | |||
799 | 629 | ||
800 | qparam.uapsd = false; | 630 | qparam.uapsd = false; |
801 | 631 | ||
802 | local->tx_conf[queue] = qparam; | 632 | sdata->tx_conf[queue] = qparam; |
803 | drv_conf_tx(local, queue, &qparam); | 633 | drv_conf_tx(local, sdata, queue, &qparam); |
804 | } | 634 | } |
805 | 635 | ||
806 | /* after reinitialize QoS TX queues setting to default, | 636 | /* after reinitialize QoS TX queues setting to default, |
@@ -874,11 +704,9 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
874 | 704 | ||
875 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 705 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
876 | sizeof(*mgmt) + 6 + extra_len); | 706 | sizeof(*mgmt) + 6 + extra_len); |
877 | if (!skb) { | 707 | if (!skb) |
878 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | ||
879 | "frame\n", sdata->name); | ||
880 | return; | 708 | return; |
881 | } | 709 | |
882 | skb_reserve(skb, local->hw.extra_tx_headroom); | 710 | skb_reserve(skb, local->hw.extra_tx_headroom); |
883 | 711 | ||
884 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); | 712 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); |
@@ -1031,11 +859,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1031 | 859 | ||
1032 | /* FIXME: come up with a proper value */ | 860 | /* FIXME: come up with a proper value */ |
1033 | buf = kmalloc(200 + ie_len, GFP_KERNEL); | 861 | buf = kmalloc(200 + ie_len, GFP_KERNEL); |
1034 | if (!buf) { | 862 | if (!buf) |
1035 | printk(KERN_DEBUG "%s: failed to allocate temporary IE " | ||
1036 | "buffer\n", sdata->name); | ||
1037 | return NULL; | 863 | return NULL; |
1038 | } | ||
1039 | 864 | ||
1040 | /* | 865 | /* |
1041 | * Do not send DS Channel parameter for directed probe requests | 866 | * Do not send DS Channel parameter for directed probe requests |
@@ -1071,14 +896,18 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1071 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 896 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, |
1072 | const u8 *ssid, size_t ssid_len, | 897 | const u8 *ssid, size_t ssid_len, |
1073 | const u8 *ie, size_t ie_len, | 898 | const u8 *ie, size_t ie_len, |
1074 | u32 ratemask, bool directed) | 899 | u32 ratemask, bool directed, bool no_cck) |
1075 | { | 900 | { |
1076 | struct sk_buff *skb; | 901 | struct sk_buff *skb; |
1077 | 902 | ||
1078 | skb = ieee80211_build_probe_req(sdata, dst, ratemask, ssid, ssid_len, | 903 | skb = ieee80211_build_probe_req(sdata, dst, ratemask, ssid, ssid_len, |
1079 | ie, ie_len, directed); | 904 | ie, ie_len, directed); |
1080 | if (skb) | 905 | if (skb) { |
906 | if (no_cck) | ||
907 | IEEE80211_SKB_CB(skb)->flags |= | ||
908 | IEEE80211_TX_CTL_NO_CCK_RATE; | ||
1081 | ieee80211_tx_skb(sdata, skb); | 909 | ieee80211_tx_skb(sdata, skb); |
910 | } | ||
1082 | } | 911 | } |
1083 | 912 | ||
1084 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | 913 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, |
@@ -1205,14 +1034,22 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1205 | struct ieee80211_sub_if_data, | 1034 | struct ieee80211_sub_if_data, |
1206 | u.ap); | 1035 | u.ap); |
1207 | 1036 | ||
1037 | memset(&sta->sta.drv_priv, 0, hw->sta_data_size); | ||
1208 | WARN_ON(drv_sta_add(local, sdata, &sta->sta)); | 1038 | WARN_ON(drv_sta_add(local, sdata, &sta->sta)); |
1209 | } | 1039 | } |
1210 | } | 1040 | } |
1211 | mutex_unlock(&local->sta_mtx); | 1041 | mutex_unlock(&local->sta_mtx); |
1212 | 1042 | ||
1213 | /* reconfigure tx conf */ | 1043 | /* reconfigure tx conf */ |
1214 | for (i = 0; i < hw->queues; i++) | 1044 | list_for_each_entry(sdata, &local->interfaces, list) { |
1215 | drv_conf_tx(local, i, &local->tx_conf[i]); | 1045 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN || |
1046 | sdata->vif.type == NL80211_IFTYPE_MONITOR || | ||
1047 | !ieee80211_sdata_running(sdata)) | ||
1048 | continue; | ||
1049 | |||
1050 | for (i = 0; i < hw->queues; i++) | ||
1051 | drv_conf_tx(local, sdata, i, &sdata->tx_conf[i]); | ||
1052 | } | ||
1216 | 1053 | ||
1217 | /* reconfigure hardware */ | 1054 | /* reconfigure hardware */ |
1218 | ieee80211_hw_config(local, ~0); | 1055 | ieee80211_hw_config(local, ~0); |
@@ -1248,6 +1085,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1248 | changed |= BSS_CHANGED_IBSS; | 1085 | changed |= BSS_CHANGED_IBSS; |
1249 | /* fall through */ | 1086 | /* fall through */ |
1250 | case NL80211_IFTYPE_AP: | 1087 | case NL80211_IFTYPE_AP: |
1088 | changed |= BSS_CHANGED_SSID; | ||
1089 | /* fall through */ | ||
1251 | case NL80211_IFTYPE_MESH_POINT: | 1090 | case NL80211_IFTYPE_MESH_POINT: |
1252 | changed |= BSS_CHANGED_BEACON | | 1091 | changed |= BSS_CHANGED_BEACON | |
1253 | BSS_CHANGED_BEACON_ENABLED; | 1092 | BSS_CHANGED_BEACON_ENABLED; |
@@ -1283,7 +1122,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1283 | 1122 | ||
1284 | list_for_each_entry(sta, &local->sta_list, list) { | 1123 | list_for_each_entry(sta, &local->sta_list, list) { |
1285 | ieee80211_sta_tear_down_BA_sessions(sta, true); | 1124 | ieee80211_sta_tear_down_BA_sessions(sta, true); |
1286 | clear_sta_flags(sta, WLAN_STA_BLOCK_BA); | 1125 | clear_sta_flag(sta, WLAN_STA_BLOCK_BA); |
1287 | } | 1126 | } |
1288 | 1127 | ||
1289 | mutex_unlock(&local->sta_mtx); | 1128 | mutex_unlock(&local->sta_mtx); |
@@ -1522,3 +1361,60 @@ void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif) | |||
1522 | _ieee80211_enable_rssi_reports(sdata, 0, 0); | 1361 | _ieee80211_enable_rssi_reports(sdata, 0, 0); |
1523 | } | 1362 | } |
1524 | EXPORT_SYMBOL(ieee80211_disable_rssi_reports); | 1363 | EXPORT_SYMBOL(ieee80211_disable_rssi_reports); |
1364 | |||
1365 | int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb) | ||
1366 | { | ||
1367 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
1368 | struct ieee80211_local *local = sdata->local; | ||
1369 | struct ieee80211_supported_band *sband; | ||
1370 | int rate; | ||
1371 | u8 i, rates, *pos; | ||
1372 | |||
1373 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
1374 | rates = sband->n_bitrates; | ||
1375 | if (rates > 8) | ||
1376 | rates = 8; | ||
1377 | |||
1378 | if (skb_tailroom(skb) < rates + 2) | ||
1379 | return -ENOMEM; | ||
1380 | |||
1381 | pos = skb_put(skb, rates + 2); | ||
1382 | *pos++ = WLAN_EID_SUPP_RATES; | ||
1383 | *pos++ = rates; | ||
1384 | for (i = 0; i < rates; i++) { | ||
1385 | rate = sband->bitrates[i].bitrate; | ||
1386 | *pos++ = (u8) (rate / 5); | ||
1387 | } | ||
1388 | |||
1389 | return 0; | ||
1390 | } | ||
1391 | |||
1392 | int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb) | ||
1393 | { | ||
1394 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
1395 | struct ieee80211_local *local = sdata->local; | ||
1396 | struct ieee80211_supported_band *sband; | ||
1397 | int rate; | ||
1398 | u8 i, exrates, *pos; | ||
1399 | |||
1400 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
1401 | exrates = sband->n_bitrates; | ||
1402 | if (exrates > 8) | ||
1403 | exrates -= 8; | ||
1404 | else | ||
1405 | exrates = 0; | ||
1406 | |||
1407 | if (skb_tailroom(skb) < exrates + 2) | ||
1408 | return -ENOMEM; | ||
1409 | |||
1410 | if (exrates) { | ||
1411 | pos = skb_put(skb, exrates + 2); | ||
1412 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
1413 | *pos++ = exrates; | ||
1414 | for (i = 8; i < sband->n_bitrates; i++) { | ||
1415 | rate = sband->bitrates[i].bitrate; | ||
1416 | *pos++ = (u8) (rate / 5); | ||
1417 | } | ||
1418 | } | ||
1419 | return 0; | ||
1420 | } | ||