aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c188
1 files changed, 97 insertions, 91 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index cffef44cec05..1e4054b273dd 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2646,11 +2646,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
2646 struct ieee80211_mgmt *mgmt, 2646 struct ieee80211_mgmt *mgmt,
2647 size_t len, 2647 size_t len,
2648 struct ieee80211_rx_status *rx_status, 2648 struct ieee80211_rx_status *rx_status,
2649 struct ieee802_11_elems *elems,
2649 int beacon) 2650 int beacon)
2650{ 2651{
2651 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); 2652 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
2652 struct ieee802_11_elems elems;
2653 size_t baselen;
2654 int freq, clen; 2653 int freq, clen;
2655 struct ieee80211_sta_bss *bss; 2654 struct ieee80211_sta_bss *bss;
2656 struct sta_info *sta; 2655 struct sta_info *sta;
@@ -2669,29 +2668,24 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
2669 print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da)); 2668 print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da));
2670#endif 2669#endif
2671 2670
2672 baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
2673 if (baselen > len)
2674 return;
2675
2676 beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); 2671 beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
2677 ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
2678 2672
2679 if (ieee80211_vif_is_mesh(&sdata->vif) && elems.mesh_id && 2673 if (ieee80211_vif_is_mesh(&sdata->vif) && elems->mesh_id &&
2680 elems.mesh_config && mesh_matches_local(&elems, dev)) { 2674 elems->mesh_config && mesh_matches_local(elems, dev)) {
2681 u64 rates = ieee80211_sta_get_rates(local, &elems, 2675 u64 rates = ieee80211_sta_get_rates(local, elems,
2682 rx_status->band); 2676 rx_status->band);
2683 2677
2684 mesh_neighbour_update(mgmt->sa, rates, dev, 2678 mesh_neighbour_update(mgmt->sa, rates, dev,
2685 mesh_peer_accepts_plinks(&elems, dev)); 2679 mesh_peer_accepts_plinks(elems, dev));
2686 } 2680 }
2687 2681
2688 rcu_read_lock(); 2682 rcu_read_lock();
2689 2683
2690 if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && 2684 if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems->supp_rates &&
2691 memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && 2685 memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 &&
2692 (sta = sta_info_get(local, mgmt->sa))) { 2686 (sta = sta_info_get(local, mgmt->sa))) {
2693 u64 prev_rates; 2687 u64 prev_rates;
2694 u64 supp_rates = ieee80211_sta_get_rates(local, &elems, 2688 u64 supp_rates = ieee80211_sta_get_rates(local, elems,
2695 rx_status->band); 2689 rx_status->band);
2696 2690
2697 prev_rates = sta->supp_rates[rx_status->band]; 2691 prev_rates = sta->supp_rates[rx_status->band];
@@ -2716,8 +2710,8 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
2716 2710
2717 rcu_read_unlock(); 2711 rcu_read_unlock();
2718 2712
2719 if (elems.ds_params && elems.ds_params_len == 1) 2713 if (elems->ds_params && elems->ds_params_len == 1)
2720 freq = ieee80211_channel_to_frequency(elems.ds_params[0]); 2714 freq = ieee80211_channel_to_frequency(elems->ds_params[0]);
2721 else 2715 else
2722 freq = rx_status->freq; 2716 freq = rx_status->freq;
2723 2717
@@ -2727,23 +2721,23 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
2727 return; 2721 return;
2728 2722
2729#ifdef CONFIG_MAC80211_MESH 2723#ifdef CONFIG_MAC80211_MESH
2730 if (elems.mesh_config) 2724 if (elems->mesh_config)
2731 bss = ieee80211_rx_mesh_bss_get(dev, elems.mesh_id, 2725 bss = ieee80211_rx_mesh_bss_get(dev, elems->mesh_id,
2732 elems.mesh_id_len, elems.mesh_config, freq); 2726 elems->mesh_id_len, elems->mesh_config, freq);
2733 else 2727 else
2734#endif 2728#endif
2735 bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq, 2729 bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq,
2736 elems.ssid, elems.ssid_len); 2730 elems->ssid, elems->ssid_len);
2737 if (!bss) { 2731 if (!bss) {
2738#ifdef CONFIG_MAC80211_MESH 2732#ifdef CONFIG_MAC80211_MESH
2739 if (elems.mesh_config) 2733 if (elems->mesh_config)
2740 bss = ieee80211_rx_mesh_bss_add(dev, elems.mesh_id, 2734 bss = ieee80211_rx_mesh_bss_add(dev, elems->mesh_id,
2741 elems.mesh_id_len, elems.mesh_config, 2735 elems->mesh_id_len, elems->mesh_config,
2742 elems.mesh_config_len, freq); 2736 elems->mesh_config_len, freq);
2743 else 2737 else
2744#endif 2738#endif
2745 bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq, 2739 bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq,
2746 elems.ssid, elems.ssid_len); 2740 elems->ssid, elems->ssid_len);
2747 if (!bss) 2741 if (!bss)
2748 return; 2742 return;
2749 } else { 2743 } else {
@@ -2756,43 +2750,43 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
2756 } 2750 }
2757 2751
2758 /* save the ERP value so that it is available at association time */ 2752 /* save the ERP value so that it is available at association time */
2759 if (elems.erp_info && elems.erp_info_len >= 1) { 2753 if (elems->erp_info && elems->erp_info_len >= 1) {
2760 bss->erp_value = elems.erp_info[0]; 2754 bss->erp_value = elems->erp_info[0];
2761 bss->has_erp_value = 1; 2755 bss->has_erp_value = 1;
2762 } 2756 }
2763 2757
2764 if (elems.ht_cap_elem && 2758 if (elems->ht_cap_elem &&
2765 (!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len || 2759 (!bss->ht_ie || bss->ht_ie_len != elems->ht_cap_elem_len ||
2766 memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) { 2760 memcmp(bss->ht_ie, elems->ht_cap_elem, elems->ht_cap_elem_len))) {
2767 kfree(bss->ht_ie); 2761 kfree(bss->ht_ie);
2768 bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC); 2762 bss->ht_ie = kmalloc(elems->ht_cap_elem_len + 2, GFP_ATOMIC);
2769 if (bss->ht_ie) { 2763 if (bss->ht_ie) {
2770 memcpy(bss->ht_ie, elems.ht_cap_elem - 2, 2764 memcpy(bss->ht_ie, elems->ht_cap_elem - 2,
2771 elems.ht_cap_elem_len + 2); 2765 elems->ht_cap_elem_len + 2);
2772 bss->ht_ie_len = elems.ht_cap_elem_len + 2; 2766 bss->ht_ie_len = elems->ht_cap_elem_len + 2;
2773 } else 2767 } else
2774 bss->ht_ie_len = 0; 2768 bss->ht_ie_len = 0;
2775 } else if (!elems.ht_cap_elem && bss->ht_ie) { 2769 } else if (!elems->ht_cap_elem && bss->ht_ie) {
2776 kfree(bss->ht_ie); 2770 kfree(bss->ht_ie);
2777 bss->ht_ie = NULL; 2771 bss->ht_ie = NULL;
2778 bss->ht_ie_len = 0; 2772 bss->ht_ie_len = 0;
2779 } 2773 }
2780 2774
2781 if (elems.ht_info_elem && 2775 if (elems->ht_info_elem &&
2782 (!bss->ht_add_ie || 2776 (!bss->ht_add_ie ||
2783 bss->ht_add_ie_len != elems.ht_info_elem_len || 2777 bss->ht_add_ie_len != elems->ht_info_elem_len ||
2784 memcmp(bss->ht_add_ie, elems.ht_info_elem, 2778 memcmp(bss->ht_add_ie, elems->ht_info_elem,
2785 elems.ht_info_elem_len))) { 2779 elems->ht_info_elem_len))) {
2786 kfree(bss->ht_add_ie); 2780 kfree(bss->ht_add_ie);
2787 bss->ht_add_ie = 2781 bss->ht_add_ie =
2788 kmalloc(elems.ht_info_elem_len + 2, GFP_ATOMIC); 2782 kmalloc(elems->ht_info_elem_len + 2, GFP_ATOMIC);
2789 if (bss->ht_add_ie) { 2783 if (bss->ht_add_ie) {
2790 memcpy(bss->ht_add_ie, elems.ht_info_elem - 2, 2784 memcpy(bss->ht_add_ie, elems->ht_info_elem - 2,
2791 elems.ht_info_elem_len + 2); 2785 elems->ht_info_elem_len + 2);
2792 bss->ht_add_ie_len = elems.ht_info_elem_len + 2; 2786 bss->ht_add_ie_len = elems->ht_info_elem_len + 2;
2793 } else 2787 } else
2794 bss->ht_add_ie_len = 0; 2788 bss->ht_add_ie_len = 0;
2795 } else if (!elems.ht_info_elem && bss->ht_add_ie) { 2789 } else if (!elems->ht_info_elem && bss->ht_add_ie) {
2796 kfree(bss->ht_add_ie); 2790 kfree(bss->ht_add_ie);
2797 bss->ht_add_ie = NULL; 2791 bss->ht_add_ie = NULL;
2798 bss->ht_add_ie_len = 0; 2792 bss->ht_add_ie_len = 0;
@@ -2802,20 +2796,20 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
2802 bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); 2796 bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
2803 2797
2804 bss->supp_rates_len = 0; 2798 bss->supp_rates_len = 0;
2805 if (elems.supp_rates) { 2799 if (elems->supp_rates) {
2806 clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; 2800 clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
2807 if (clen > elems.supp_rates_len) 2801 if (clen > elems->supp_rates_len)
2808 clen = elems.supp_rates_len; 2802 clen = elems->supp_rates_len;
2809 memcpy(&bss->supp_rates[bss->supp_rates_len], elems.supp_rates, 2803 memcpy(&bss->supp_rates[bss->supp_rates_len], elems->supp_rates,
2810 clen); 2804 clen);
2811 bss->supp_rates_len += clen; 2805 bss->supp_rates_len += clen;
2812 } 2806 }
2813 if (elems.ext_supp_rates) { 2807 if (elems->ext_supp_rates) {
2814 clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; 2808 clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
2815 if (clen > elems.ext_supp_rates_len) 2809 if (clen > elems->ext_supp_rates_len)
2816 clen = elems.ext_supp_rates_len; 2810 clen = elems->ext_supp_rates_len;
2817 memcpy(&bss->supp_rates[bss->supp_rates_len], 2811 memcpy(&bss->supp_rates[bss->supp_rates_len],
2818 elems.ext_supp_rates, clen); 2812 elems->ext_supp_rates, clen);
2819 bss->supp_rates_len += clen; 2813 bss->supp_rates_len += clen;
2820 } 2814 }
2821 2815
@@ -2839,33 +2833,33 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
2839 return; 2833 return;
2840 } 2834 }
2841 2835
2842 if (elems.wpa && 2836 if (elems->wpa &&
2843 (!bss->wpa_ie || bss->wpa_ie_len != elems.wpa_len || 2837 (!bss->wpa_ie || bss->wpa_ie_len != elems->wpa_len ||
2844 memcmp(bss->wpa_ie, elems.wpa, elems.wpa_len))) { 2838 memcmp(bss->wpa_ie, elems->wpa, elems->wpa_len))) {
2845 kfree(bss->wpa_ie); 2839 kfree(bss->wpa_ie);
2846 bss->wpa_ie = kmalloc(elems.wpa_len + 2, GFP_ATOMIC); 2840 bss->wpa_ie = kmalloc(elems->wpa_len + 2, GFP_ATOMIC);
2847 if (bss->wpa_ie) { 2841 if (bss->wpa_ie) {
2848 memcpy(bss->wpa_ie, elems.wpa - 2, elems.wpa_len + 2); 2842 memcpy(bss->wpa_ie, elems->wpa - 2, elems->wpa_len + 2);
2849 bss->wpa_ie_len = elems.wpa_len + 2; 2843 bss->wpa_ie_len = elems->wpa_len + 2;
2850 } else 2844 } else
2851 bss->wpa_ie_len = 0; 2845 bss->wpa_ie_len = 0;
2852 } else if (!elems.wpa && bss->wpa_ie) { 2846 } else if (!elems->wpa && bss->wpa_ie) {
2853 kfree(bss->wpa_ie); 2847 kfree(bss->wpa_ie);
2854 bss->wpa_ie = NULL; 2848 bss->wpa_ie = NULL;
2855 bss->wpa_ie_len = 0; 2849 bss->wpa_ie_len = 0;
2856 } 2850 }
2857 2851
2858 if (elems.rsn && 2852 if (elems->rsn &&
2859 (!bss->rsn_ie || bss->rsn_ie_len != elems.rsn_len || 2853 (!bss->rsn_ie || bss->rsn_ie_len != elems->rsn_len ||
2860 memcmp(bss->rsn_ie, elems.rsn, elems.rsn_len))) { 2854 memcmp(bss->rsn_ie, elems->rsn, elems->rsn_len))) {
2861 kfree(bss->rsn_ie); 2855 kfree(bss->rsn_ie);
2862 bss->rsn_ie = kmalloc(elems.rsn_len + 2, GFP_ATOMIC); 2856 bss->rsn_ie = kmalloc(elems->rsn_len + 2, GFP_ATOMIC);
2863 if (bss->rsn_ie) { 2857 if (bss->rsn_ie) {
2864 memcpy(bss->rsn_ie, elems.rsn - 2, elems.rsn_len + 2); 2858 memcpy(bss->rsn_ie, elems->rsn - 2, elems->rsn_len + 2);
2865 bss->rsn_ie_len = elems.rsn_len + 2; 2859 bss->rsn_ie_len = elems->rsn_len + 2;
2866 } else 2860 } else
2867 bss->rsn_ie_len = 0; 2861 bss->rsn_ie_len = 0;
2868 } else if (!elems.rsn && bss->rsn_ie) { 2862 } else if (!elems->rsn && bss->rsn_ie) {
2869 kfree(bss->rsn_ie); 2863 kfree(bss->rsn_ie);
2870 bss->rsn_ie = NULL; 2864 bss->rsn_ie = NULL;
2871 bss->rsn_ie_len = 0; 2865 bss->rsn_ie_len = 0;
@@ -2885,20 +2879,21 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
2885 * inclusion of the WMM Parameters in beacons, however, is optional. 2879 * inclusion of the WMM Parameters in beacons, however, is optional.
2886 */ 2880 */
2887 2881
2888 if (elems.wmm_param && 2882 if (elems->wmm_param &&
2889 (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_param_len || 2883 (!bss->wmm_ie || bss->wmm_ie_len != elems->wmm_param_len ||
2890 memcmp(bss->wmm_ie, elems.wmm_param, elems.wmm_param_len))) { 2884 memcmp(bss->wmm_ie, elems->wmm_param, elems->wmm_param_len))) {
2891 kfree(bss->wmm_ie); 2885 kfree(bss->wmm_ie);
2892 bss->wmm_ie = kmalloc(elems.wmm_param_len + 2, GFP_ATOMIC); 2886 bss->wmm_ie = kmalloc(elems->wmm_param_len + 2, GFP_ATOMIC);
2893 if (bss->wmm_ie) { 2887 if (bss->wmm_ie) {
2894 memcpy(bss->wmm_ie, elems.wmm_param - 2, 2888 memcpy(bss->wmm_ie, elems->wmm_param - 2,
2895 elems.wmm_param_len + 2); 2889 elems->wmm_param_len + 2);
2896 bss->wmm_ie_len = elems.wmm_param_len + 2; 2890 bss->wmm_ie_len = elems->wmm_param_len + 2;
2897 } else 2891 } else
2898 bss->wmm_ie_len = 0; 2892 bss->wmm_ie_len = 0;
2899 } else if (elems.wmm_info && 2893 } else if (elems->wmm_info &&
2900 (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_info_len || 2894 (!bss->wmm_ie || bss->wmm_ie_len != elems->wmm_info_len ||
2901 memcmp(bss->wmm_ie, elems.wmm_info, elems.wmm_info_len))) { 2895 memcmp(bss->wmm_ie, elems->wmm_info,
2896 elems->wmm_info_len))) {
2902 /* As for certain AP's Fifth bit is not set in WMM IE in 2897 /* As for certain AP's Fifth bit is not set in WMM IE in
2903 * beacon frames.So while parsing the beacon frame the 2898 * beacon frames.So while parsing the beacon frame the
2904 * wmm_info structure is used instead of wmm_param. 2899 * wmm_info structure is used instead of wmm_param.
@@ -2908,14 +2903,14 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
2908 * n-band association. 2903 * n-band association.
2909 */ 2904 */
2910 kfree(bss->wmm_ie); 2905 kfree(bss->wmm_ie);
2911 bss->wmm_ie = kmalloc(elems.wmm_info_len + 2, GFP_ATOMIC); 2906 bss->wmm_ie = kmalloc(elems->wmm_info_len + 2, GFP_ATOMIC);
2912 if (bss->wmm_ie) { 2907 if (bss->wmm_ie) {
2913 memcpy(bss->wmm_ie, elems.wmm_info - 2, 2908 memcpy(bss->wmm_ie, elems->wmm_info - 2,
2914 elems.wmm_info_len + 2); 2909 elems->wmm_info_len + 2);
2915 bss->wmm_ie_len = elems.wmm_info_len + 2; 2910 bss->wmm_ie_len = elems->wmm_info_len + 2;
2916 } else 2911 } else
2917 bss->wmm_ie_len = 0; 2912 bss->wmm_ie_len = 0;
2918 } else if (!elems.wmm_param && !elems.wmm_info && bss->wmm_ie) { 2913 } else if (!elems->wmm_param && !elems->wmm_info && bss->wmm_ie) {
2919 kfree(bss->wmm_ie); 2914 kfree(bss->wmm_ie);
2920 bss->wmm_ie = NULL; 2915 bss->wmm_ie = NULL;
2921 bss->wmm_ie_len = 0; 2916 bss->wmm_ie_len = 0;
@@ -2926,8 +2921,9 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
2926 !local->sta_sw_scanning && !local->sta_hw_scanning && 2921 !local->sta_sw_scanning && !local->sta_hw_scanning &&
2927 bss->capability & WLAN_CAPABILITY_IBSS && 2922 bss->capability & WLAN_CAPABILITY_IBSS &&
2928 bss->freq == local->oper_channel->center_freq && 2923 bss->freq == local->oper_channel->center_freq &&
2929 elems.ssid_len == sdata->u.sta.ssid_len && 2924 elems->ssid_len == sdata->u.sta.ssid_len &&
2930 memcmp(elems.ssid, sdata->u.sta.ssid, sdata->u.sta.ssid_len) == 0) { 2925 memcmp(elems->ssid, sdata->u.sta.ssid,
2926 sdata->u.sta.ssid_len) == 0) {
2931 if (rx_status->flag & RX_FLAG_TSFT) { 2927 if (rx_status->flag & RX_FLAG_TSFT) {
2932 /* in order for correct IBSS merging we need mactime 2928 /* in order for correct IBSS merging we need mactime
2933 * 2929 *
@@ -2986,7 +2982,17 @@ static void ieee80211_rx_mgmt_probe_resp(struct net_device *dev,
2986 size_t len, 2982 size_t len,
2987 struct ieee80211_rx_status *rx_status) 2983 struct ieee80211_rx_status *rx_status)
2988{ 2984{
2989 ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 0); 2985 size_t baselen;
2986 struct ieee802_11_elems elems;
2987
2988 baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
2989 if (baselen > len)
2990 return;
2991
2992 ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
2993 &elems);
2994
2995 ieee80211_rx_bss_info(dev, mgmt, len, rx_status, &elems, 0);
2990} 2996}
2991 2997
2992 2998
@@ -3003,7 +3009,14 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
3003 struct ieee80211_conf *conf = &local->hw.conf; 3009 struct ieee80211_conf *conf = &local->hw.conf;
3004 u32 changed = 0; 3010 u32 changed = 0;
3005 3011
3006 ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 1); 3012 /* Process beacon from the current BSS */
3013 baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
3014 if (baselen > len)
3015 return;
3016
3017 ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
3018
3019 ieee80211_rx_bss_info(dev, mgmt, len, rx_status, &elems, 1);
3007 3020
3008 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 3021 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
3009 if (sdata->vif.type != IEEE80211_IF_TYPE_STA) 3022 if (sdata->vif.type != IEEE80211_IF_TYPE_STA)
@@ -3014,13 +3027,6 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
3014 memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) 3027 memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
3015 return; 3028 return;
3016 3029
3017 /* Process beacon from the current BSS */
3018 baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
3019 if (baselen > len)
3020 return;
3021
3022 ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
3023
3024 ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, 3030 ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
3025 elems.wmm_param_len); 3031 elems.wmm_param_len);
3026 3032