aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/ibss.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-03-07 14:54:29 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-03-25 09:42:41 -0400
commitc3ffeab4345830aadfc78444933754330f1339e7 (patch)
treea7939d86dfd0e4fb4519fa6b15b7f6a6325becb3 /net/mac80211/ibss.c
parent1852d40eaba36fe1e97e0e497ffce291c99f5886 (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.c131
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)
1023int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, 1036int 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
1105int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) 1102int 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