diff options
author | Johannes Berg <johannes.berg@intel.com> | 2013-03-07 14:54:29 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2013-03-25 09:42:41 -0400 |
commit | c3ffeab4345830aadfc78444933754330f1339e7 (patch) | |
tree | a7939d86dfd0e4fb4519fa6b15b7f6a6325becb3 /net/mac80211/ibss.c | |
parent | 1852d40eaba36fe1e97e0e497ffce291c99f5886 (diff) |
mac80211: ibss: use beacon_data struct for beacon and probe response
Instead of having an SKB all the time, use a beacon_data struct
with just the information required. This also allows removing a
synchronize_rcu() and using kfree_rcu() instead.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/ibss.c')
-rw-r--r-- | net/mac80211/ibss.c | 131 |
1 files changed, 64 insertions, 67 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index bd02fac188bd..5ab32e2a7b56 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -44,7 +44,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
44 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 44 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
45 | struct ieee80211_local *local = sdata->local; | 45 | struct ieee80211_local *local = sdata->local; |
46 | int rates, i; | 46 | int rates, i; |
47 | struct sk_buff *skb; | ||
48 | struct ieee80211_mgmt *mgmt; | 47 | struct ieee80211_mgmt *mgmt; |
49 | u8 *pos; | 48 | u8 *pos; |
50 | struct ieee80211_supported_band *sband; | 49 | struct ieee80211_supported_band *sband; |
@@ -52,6 +51,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
52 | u32 bss_change; | 51 | u32 bss_change; |
53 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; | 52 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; |
54 | struct cfg80211_chan_def chandef; | 53 | struct cfg80211_chan_def chandef; |
54 | struct beacon_data *presp; | ||
55 | int frame_len; | ||
55 | 56 | ||
56 | lockdep_assert_held(&ifibss->mtx); | 57 | lockdep_assert_held(&ifibss->mtx); |
57 | 58 | ||
@@ -72,13 +73,11 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
72 | BSS_CHANGED_BEACON_ENABLED); | 73 | BSS_CHANGED_BEACON_ENABLED); |
73 | } | 74 | } |
74 | 75 | ||
75 | skb = ifibss->skb; | 76 | presp = rcu_dereference_protected(ifibss->presp, |
76 | RCU_INIT_POINTER(ifibss->presp, NULL); | 77 | lockdep_is_held(&ifibss->mtx)); |
77 | synchronize_rcu(); | 78 | rcu_assign_pointer(ifibss->presp, NULL); |
78 | skb->data = skb->head; | 79 | if (presp) |
79 | skb->len = 0; | 80 | kfree_rcu(presp, rcu_head); |
80 | skb_reset_tail_pointer(skb); | ||
81 | skb_reserve(skb, sdata->local->hw.extra_tx_headroom); | ||
82 | 81 | ||
83 | sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; | 82 | sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; |
84 | 83 | ||
@@ -101,19 +100,24 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
101 | 100 | ||
102 | sband = local->hw.wiphy->bands[chan->band]; | 101 | sband = local->hw.wiphy->bands[chan->band]; |
103 | 102 | ||
104 | /* build supported rates array */ | ||
105 | pos = supp_rates; | ||
106 | for (i = 0; i < sband->n_bitrates; i++) { | ||
107 | int rate = sband->bitrates[i].bitrate; | ||
108 | u8 basic = 0; | ||
109 | if (basic_rates & BIT(i)) | ||
110 | basic = 0x80; | ||
111 | *pos++ = basic | (u8) (rate / 5); | ||
112 | } | ||
113 | |||
114 | /* Build IBSS probe response */ | 103 | /* Build IBSS probe response */ |
115 | mgmt = (void *) skb_put(skb, 24 + sizeof(mgmt->u.beacon)); | 104 | frame_len = sizeof(struct ieee80211_hdr_3addr) + |
116 | memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); | 105 | 12 /* struct ieee80211_mgmt.u.beacon */ + |
106 | 2 + IEEE80211_MAX_SSID_LEN /* max SSID */ + | ||
107 | 2 + 8 /* max Supported Rates */ + | ||
108 | 3 /* max DS params */ + | ||
109 | 4 /* IBSS params */ + | ||
110 | 2 + (IEEE80211_MAX_SUPP_RATES - 8) + | ||
111 | 2 + sizeof(struct ieee80211_ht_cap) + | ||
112 | 2 + sizeof(struct ieee80211_ht_operation) + | ||
113 | ifibss->ie_len; | ||
114 | presp = kzalloc(sizeof(*presp) + frame_len, GFP_KERNEL); | ||
115 | if (!presp) | ||
116 | return; | ||
117 | |||
118 | presp->head = (void *)(presp + 1); | ||
119 | |||
120 | mgmt = (void *) presp->head; | ||
117 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 121 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
118 | IEEE80211_STYPE_PROBE_RESP); | 122 | IEEE80211_STYPE_PROBE_RESP); |
119 | eth_broadcast_addr(mgmt->da); | 123 | eth_broadcast_addr(mgmt->da); |
@@ -123,27 +127,30 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
123 | mgmt->u.beacon.timestamp = cpu_to_le64(tsf); | 127 | mgmt->u.beacon.timestamp = cpu_to_le64(tsf); |
124 | mgmt->u.beacon.capab_info = cpu_to_le16(capability); | 128 | mgmt->u.beacon.capab_info = cpu_to_le16(capability); |
125 | 129 | ||
126 | pos = skb_put(skb, 2 + ifibss->ssid_len); | 130 | pos = (u8 *)mgmt + offsetof(struct ieee80211_mgmt, u.beacon.variable); |
131 | |||
127 | *pos++ = WLAN_EID_SSID; | 132 | *pos++ = WLAN_EID_SSID; |
128 | *pos++ = ifibss->ssid_len; | 133 | *pos++ = ifibss->ssid_len; |
129 | memcpy(pos, ifibss->ssid, ifibss->ssid_len); | 134 | memcpy(pos, ifibss->ssid, ifibss->ssid_len); |
135 | pos += ifibss->ssid_len; | ||
130 | 136 | ||
131 | rates = sband->n_bitrates; | 137 | rates = min_t(int, 8, sband->n_bitrates); |
132 | if (rates > 8) | ||
133 | rates = 8; | ||
134 | pos = skb_put(skb, 2 + rates); | ||
135 | *pos++ = WLAN_EID_SUPP_RATES; | 138 | *pos++ = WLAN_EID_SUPP_RATES; |
136 | *pos++ = rates; | 139 | *pos++ = rates; |
137 | memcpy(pos, supp_rates, rates); | 140 | for (i = 0; i < rates; i++) { |
141 | int rate = sband->bitrates[i].bitrate; | ||
142 | u8 basic = 0; | ||
143 | if (basic_rates & BIT(i)) | ||
144 | basic = 0x80; | ||
145 | *pos++ = basic | (u8) (rate / 5); | ||
146 | } | ||
138 | 147 | ||
139 | if (sband->band == IEEE80211_BAND_2GHZ) { | 148 | if (sband->band == IEEE80211_BAND_2GHZ) { |
140 | pos = skb_put(skb, 2 + 1); | ||
141 | *pos++ = WLAN_EID_DS_PARAMS; | 149 | *pos++ = WLAN_EID_DS_PARAMS; |
142 | *pos++ = 1; | 150 | *pos++ = 1; |
143 | *pos++ = ieee80211_frequency_to_channel(chan->center_freq); | 151 | *pos++ = ieee80211_frequency_to_channel(chan->center_freq); |
144 | } | 152 | } |
145 | 153 | ||
146 | pos = skb_put(skb, 2 + 2); | ||
147 | *pos++ = WLAN_EID_IBSS_PARAMS; | 154 | *pos++ = WLAN_EID_IBSS_PARAMS; |
148 | *pos++ = 2; | 155 | *pos++ = 2; |
149 | /* FIX: set ATIM window based on scan results */ | 156 | /* FIX: set ATIM window based on scan results */ |
@@ -151,23 +158,25 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
151 | *pos++ = 0; | 158 | *pos++ = 0; |
152 | 159 | ||
153 | if (sband->n_bitrates > 8) { | 160 | if (sband->n_bitrates > 8) { |
154 | rates = sband->n_bitrates - 8; | ||
155 | pos = skb_put(skb, 2 + rates); | ||
156 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | 161 | *pos++ = WLAN_EID_EXT_SUPP_RATES; |
157 | *pos++ = rates; | 162 | *pos++ = sband->n_bitrates - 8; |
158 | memcpy(pos, &supp_rates[8], rates); | 163 | for (i = 8; i < sband->n_bitrates; i++) { |
164 | int rate = sband->bitrates[i].bitrate; | ||
165 | u8 basic = 0; | ||
166 | if (basic_rates & BIT(i)) | ||
167 | basic = 0x80; | ||
168 | *pos++ = basic | (u8) (rate / 5); | ||
169 | } | ||
159 | } | 170 | } |
160 | 171 | ||
161 | if (ifibss->ie_len) | 172 | if (ifibss->ie_len) { |
162 | memcpy(skb_put(skb, ifibss->ie_len), | 173 | memcpy(pos, ifibss->ie, ifibss->ie_len); |
163 | ifibss->ie, ifibss->ie_len); | 174 | pos += ifibss->ie_len; |
175 | } | ||
164 | 176 | ||
165 | /* add HT capability and information IEs */ | 177 | /* add HT capability and information IEs */ |
166 | if (chandef.width != NL80211_CHAN_WIDTH_20_NOHT && | 178 | if (chandef.width != NL80211_CHAN_WIDTH_20_NOHT && |
167 | sband->ht_cap.ht_supported) { | 179 | sband->ht_cap.ht_supported) { |
168 | pos = skb_put(skb, 4 + | ||
169 | sizeof(struct ieee80211_ht_cap) + | ||
170 | sizeof(struct ieee80211_ht_operation)); | ||
171 | pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, | 180 | pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, |
172 | sband->ht_cap.cap); | 181 | sband->ht_cap.cap); |
173 | /* | 182 | /* |
@@ -180,7 +189,6 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
180 | } | 189 | } |
181 | 190 | ||
182 | if (local->hw.queues >= IEEE80211_NUM_ACS) { | 191 | if (local->hw.queues >= IEEE80211_NUM_ACS) { |
183 | pos = skb_put(skb, 9); | ||
184 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | 192 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; |
185 | *pos++ = 7; /* len */ | 193 | *pos++ = 7; /* len */ |
186 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ | 194 | *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ |
@@ -192,7 +200,11 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
192 | *pos++ = 0; /* U-APSD no in use */ | 200 | *pos++ = 0; /* U-APSD no in use */ |
193 | } | 201 | } |
194 | 202 | ||
195 | rcu_assign_pointer(ifibss->presp, skb); | 203 | presp->head_len = pos - presp->head; |
204 | if (WARN_ON(presp->head_len > frame_len)) | ||
205 | return; | ||
206 | |||
207 | rcu_assign_pointer(ifibss->presp, presp); | ||
196 | 208 | ||
197 | sdata->vif.bss_conf.enable_beacon = true; | 209 | sdata->vif.bss_conf.enable_beacon = true; |
198 | sdata->vif.bss_conf.beacon_int = beacon_int; | 210 | sdata->vif.bss_conf.beacon_int = beacon_int; |
@@ -230,7 +242,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
230 | round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); | 242 | round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); |
231 | 243 | ||
232 | bss = cfg80211_inform_bss_frame(local->hw.wiphy, chan, | 244 | bss = cfg80211_inform_bss_frame(local->hw.wiphy, chan, |
233 | mgmt, skb->len, 0, GFP_KERNEL); | 245 | mgmt, presp->head_len, 0, GFP_KERNEL); |
234 | cfg80211_put_bss(local->hw.wiphy, bss); | 246 | cfg80211_put_bss(local->hw.wiphy, bss); |
235 | netif_carrier_on(sdata->dev); | 247 | netif_carrier_on(sdata->dev); |
236 | cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL); | 248 | cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL); |
@@ -825,8 +837,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
825 | struct ieee80211_local *local = sdata->local; | 837 | struct ieee80211_local *local = sdata->local; |
826 | int tx_last_beacon, len = req->len; | 838 | int tx_last_beacon, len = req->len; |
827 | struct sk_buff *skb; | 839 | struct sk_buff *skb; |
828 | struct ieee80211_mgmt *resp; | 840 | struct beacon_data *presp; |
829 | struct sk_buff *presp; | ||
830 | u8 *pos, *end; | 841 | u8 *pos, *end; |
831 | 842 | ||
832 | lockdep_assert_held(&ifibss->mtx); | 843 | lockdep_assert_held(&ifibss->mtx); |
@@ -867,13 +878,15 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
867 | } | 878 | } |
868 | 879 | ||
869 | /* Reply with ProbeResp */ | 880 | /* Reply with ProbeResp */ |
870 | skb = skb_copy(presp, GFP_KERNEL); | 881 | skb = dev_alloc_skb(local->tx_headroom + presp->head_len); |
871 | if (!skb) | 882 | if (!skb) |
872 | return; | 883 | return; |
873 | 884 | ||
874 | resp = (struct ieee80211_mgmt *) skb->data; | 885 | skb_reserve(skb, local->tx_headroom); |
875 | memcpy(resp->da, mgmt->sa, ETH_ALEN); | 886 | memcpy(skb_put(skb, presp->head_len), presp->head, presp->head_len); |
876 | ibss_dbg(sdata, "Sending ProbeResp to %pM\n", resp->da); | 887 | |
888 | memcpy(((struct ieee80211_mgmt *) skb->data)->da, mgmt->sa, ETH_ALEN); | ||
889 | ibss_dbg(sdata, "Sending ProbeResp to %pM\n", mgmt->sa); | ||
877 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 890 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
878 | ieee80211_tx_skb(sdata, skb); | 891 | ieee80211_tx_skb(sdata, skb); |
879 | } | 892 | } |
@@ -1023,23 +1036,8 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local) | |||
1023 | int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | 1036 | int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, |
1024 | struct cfg80211_ibss_params *params) | 1037 | struct cfg80211_ibss_params *params) |
1025 | { | 1038 | { |
1026 | struct sk_buff *skb; | ||
1027 | u32 changed = 0; | 1039 | u32 changed = 0; |
1028 | 1040 | ||
1029 | skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom + | ||
1030 | sizeof(struct ieee80211_hdr_3addr) + | ||
1031 | 12 /* struct ieee80211_mgmt.u.beacon */ + | ||
1032 | 2 + IEEE80211_MAX_SSID_LEN /* max SSID */ + | ||
1033 | 2 + 8 /* max Supported Rates */ + | ||
1034 | 3 /* max DS params */ + | ||
1035 | 4 /* IBSS params */ + | ||
1036 | 2 + (IEEE80211_MAX_SUPP_RATES - 8) + | ||
1037 | 2 + sizeof(struct ieee80211_ht_cap) + | ||
1038 | 2 + sizeof(struct ieee80211_ht_operation) + | ||
1039 | params->ie_len); | ||
1040 | if (!skb) | ||
1041 | return -ENOMEM; | ||
1042 | |||
1043 | mutex_lock(&sdata->u.ibss.mtx); | 1041 | mutex_lock(&sdata->u.ibss.mtx); |
1044 | 1042 | ||
1045 | if (params->bssid) { | 1043 | if (params->bssid) { |
@@ -1068,7 +1066,6 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
1068 | sdata->u.ibss.ie_len = params->ie_len; | 1066 | sdata->u.ibss.ie_len = params->ie_len; |
1069 | } | 1067 | } |
1070 | 1068 | ||
1071 | sdata->u.ibss.skb = skb; | ||
1072 | sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH; | 1069 | sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH; |
1073 | sdata->u.ibss.ibss_join_req = jiffies; | 1070 | sdata->u.ibss.ibss_join_req = jiffies; |
1074 | 1071 | ||
@@ -1104,13 +1101,13 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
1104 | 1101 | ||
1105 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | 1102 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) |
1106 | { | 1103 | { |
1107 | struct sk_buff *skb; | ||
1108 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 1104 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
1109 | struct ieee80211_local *local = sdata->local; | 1105 | struct ieee80211_local *local = sdata->local; |
1110 | struct cfg80211_bss *cbss; | 1106 | struct cfg80211_bss *cbss; |
1111 | u16 capability; | 1107 | u16 capability; |
1112 | int active_ibss; | 1108 | int active_ibss; |
1113 | struct sta_info *sta; | 1109 | struct sta_info *sta; |
1110 | struct beacon_data *presp; | ||
1114 | 1111 | ||
1115 | mutex_lock(&sdata->u.ibss.mtx); | 1112 | mutex_lock(&sdata->u.ibss.mtx); |
1116 | 1113 | ||
@@ -1156,8 +1153,8 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
1156 | 1153 | ||
1157 | /* remove beacon */ | 1154 | /* remove beacon */ |
1158 | kfree(sdata->u.ibss.ie); | 1155 | kfree(sdata->u.ibss.ie); |
1159 | skb = rcu_dereference_protected(sdata->u.ibss.presp, | 1156 | presp = rcu_dereference_protected(ifibss->presp, |
1160 | lockdep_is_held(&sdata->u.ibss.mtx)); | 1157 | lockdep_is_held(&sdata->u.ibss.mtx)); |
1161 | RCU_INIT_POINTER(sdata->u.ibss.presp, NULL); | 1158 | RCU_INIT_POINTER(sdata->u.ibss.presp, NULL); |
1162 | sdata->vif.bss_conf.ibss_joined = false; | 1159 | sdata->vif.bss_conf.ibss_joined = false; |
1163 | sdata->vif.bss_conf.ibss_creator = false; | 1160 | sdata->vif.bss_conf.ibss_creator = false; |
@@ -1166,7 +1163,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
1166 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | | 1163 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | |
1167 | BSS_CHANGED_IBSS); | 1164 | BSS_CHANGED_IBSS); |
1168 | synchronize_rcu(); | 1165 | synchronize_rcu(); |
1169 | kfree_skb(skb); | 1166 | kfree(presp); |
1170 | 1167 | ||
1171 | skb_queue_purge(&sdata->skb_queue); | 1168 | skb_queue_purge(&sdata->skb_queue); |
1172 | 1169 | ||