diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-12-06 14:58:41 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-12-06 14:58:41 -0500 |
commit | 403e16731ffddc097eae89f53f9a7b0f0c9769c4 (patch) | |
tree | 228d17985ad8ea22a7763457bf9641eb44781568 /net/mac80211/util.c | |
parent | 55cb0797fa779e36f62876a8aa44cbf3984e8d59 (diff) | |
parent | da29d2a5780d80857773d7776b7603a449b0b6e0 (diff) |
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
Conflicts:
drivers/net/wireless/mwifiex/sta_ioctl.c
net/mac80211/scan.c
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r-- | net/mac80211/util.c | 58 |
1 files changed, 35 insertions, 23 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 08132ff98155..f11e8c540db4 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1107,12 +1107,12 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1107 | } | 1107 | } |
1108 | 1108 | ||
1109 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | 1109 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, |
1110 | const u8 *ie, size_t ie_len, | 1110 | size_t buffer_len, const u8 *ie, size_t ie_len, |
1111 | enum ieee80211_band band, u32 rate_mask, | 1111 | enum ieee80211_band band, u32 rate_mask, |
1112 | u8 channel) | 1112 | u8 channel) |
1113 | { | 1113 | { |
1114 | struct ieee80211_supported_band *sband; | 1114 | struct ieee80211_supported_band *sband; |
1115 | u8 *pos; | 1115 | u8 *pos = buffer, *end = buffer + buffer_len; |
1116 | size_t offset = 0, noffset; | 1116 | size_t offset = 0, noffset; |
1117 | int supp_rates_len, i; | 1117 | int supp_rates_len, i; |
1118 | u8 rates[32]; | 1118 | u8 rates[32]; |
@@ -1123,8 +1123,6 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1123 | if (WARN_ON_ONCE(!sband)) | 1123 | if (WARN_ON_ONCE(!sband)) |
1124 | return 0; | 1124 | return 0; |
1125 | 1125 | ||
1126 | pos = buffer; | ||
1127 | |||
1128 | num_rates = 0; | 1126 | num_rates = 0; |
1129 | for (i = 0; i < sband->n_bitrates; i++) { | 1127 | for (i = 0; i < sband->n_bitrates; i++) { |
1130 | if ((BIT(i) & rate_mask) == 0) | 1128 | if ((BIT(i) & rate_mask) == 0) |
@@ -1134,6 +1132,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1134 | 1132 | ||
1135 | supp_rates_len = min_t(int, num_rates, 8); | 1133 | supp_rates_len = min_t(int, num_rates, 8); |
1136 | 1134 | ||
1135 | if (end - pos < 2 + supp_rates_len) | ||
1136 | goto out_err; | ||
1137 | *pos++ = WLAN_EID_SUPP_RATES; | 1137 | *pos++ = WLAN_EID_SUPP_RATES; |
1138 | *pos++ = supp_rates_len; | 1138 | *pos++ = supp_rates_len; |
1139 | memcpy(pos, rates, supp_rates_len); | 1139 | memcpy(pos, rates, supp_rates_len); |
@@ -1150,6 +1150,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1150 | before_extrates, | 1150 | before_extrates, |
1151 | ARRAY_SIZE(before_extrates), | 1151 | ARRAY_SIZE(before_extrates), |
1152 | offset); | 1152 | offset); |
1153 | if (end - pos < noffset - offset) | ||
1154 | goto out_err; | ||
1153 | memcpy(pos, ie + offset, noffset - offset); | 1155 | memcpy(pos, ie + offset, noffset - offset); |
1154 | pos += noffset - offset; | 1156 | pos += noffset - offset; |
1155 | offset = noffset; | 1157 | offset = noffset; |
@@ -1157,6 +1159,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1157 | 1159 | ||
1158 | ext_rates_len = num_rates - supp_rates_len; | 1160 | ext_rates_len = num_rates - supp_rates_len; |
1159 | if (ext_rates_len > 0) { | 1161 | if (ext_rates_len > 0) { |
1162 | if (end - pos < 2 + ext_rates_len) | ||
1163 | goto out_err; | ||
1160 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | 1164 | *pos++ = WLAN_EID_EXT_SUPP_RATES; |
1161 | *pos++ = ext_rates_len; | 1165 | *pos++ = ext_rates_len; |
1162 | memcpy(pos, rates + supp_rates_len, ext_rates_len); | 1166 | memcpy(pos, rates + supp_rates_len, ext_rates_len); |
@@ -1164,6 +1168,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1164 | } | 1168 | } |
1165 | 1169 | ||
1166 | if (channel && sband->band == IEEE80211_BAND_2GHZ) { | 1170 | if (channel && sband->band == IEEE80211_BAND_2GHZ) { |
1171 | if (end - pos < 3) | ||
1172 | goto out_err; | ||
1167 | *pos++ = WLAN_EID_DS_PARAMS; | 1173 | *pos++ = WLAN_EID_DS_PARAMS; |
1168 | *pos++ = 1; | 1174 | *pos++ = 1; |
1169 | *pos++ = channel; | 1175 | *pos++ = channel; |
@@ -1182,14 +1188,19 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1182 | noffset = ieee80211_ie_split(ie, ie_len, | 1188 | noffset = ieee80211_ie_split(ie, ie_len, |
1183 | before_ht, ARRAY_SIZE(before_ht), | 1189 | before_ht, ARRAY_SIZE(before_ht), |
1184 | offset); | 1190 | offset); |
1191 | if (end - pos < noffset - offset) | ||
1192 | goto out_err; | ||
1185 | memcpy(pos, ie + offset, noffset - offset); | 1193 | memcpy(pos, ie + offset, noffset - offset); |
1186 | pos += noffset - offset; | 1194 | pos += noffset - offset; |
1187 | offset = noffset; | 1195 | offset = noffset; |
1188 | } | 1196 | } |
1189 | 1197 | ||
1190 | if (sband->ht_cap.ht_supported) | 1198 | if (sband->ht_cap.ht_supported) { |
1199 | if (end - pos < 2 + sizeof(struct ieee80211_ht_cap)) | ||
1200 | goto out_err; | ||
1191 | pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, | 1201 | pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, |
1192 | sband->ht_cap.cap); | 1202 | sband->ht_cap.cap); |
1203 | } | ||
1193 | 1204 | ||
1194 | /* | 1205 | /* |
1195 | * If adding more here, adjust code in main.c | 1206 | * If adding more here, adjust code in main.c |
@@ -1199,15 +1210,23 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | |||
1199 | /* add any remaining custom IEs */ | 1210 | /* add any remaining custom IEs */ |
1200 | if (ie && ie_len) { | 1211 | if (ie && ie_len) { |
1201 | noffset = ie_len; | 1212 | noffset = ie_len; |
1213 | if (end - pos < noffset - offset) | ||
1214 | goto out_err; | ||
1202 | memcpy(pos, ie + offset, noffset - offset); | 1215 | memcpy(pos, ie + offset, noffset - offset); |
1203 | pos += noffset - offset; | 1216 | pos += noffset - offset; |
1204 | } | 1217 | } |
1205 | 1218 | ||
1206 | if (sband->vht_cap.vht_supported) | 1219 | if (sband->vht_cap.vht_supported) { |
1220 | if (end - pos < 2 + sizeof(struct ieee80211_vht_cap)) | ||
1221 | goto out_err; | ||
1207 | pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, | 1222 | pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, |
1208 | sband->vht_cap.cap); | 1223 | sband->vht_cap.cap); |
1224 | } | ||
1209 | 1225 | ||
1210 | return pos - buffer; | 1226 | return pos - buffer; |
1227 | out_err: | ||
1228 | WARN_ONCE(1, "not enough space for preq IEs\n"); | ||
1229 | return pos - buffer; | ||
1211 | } | 1230 | } |
1212 | 1231 | ||
1213 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | 1232 | struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, |
@@ -1220,14 +1239,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1220 | struct ieee80211_local *local = sdata->local; | 1239 | struct ieee80211_local *local = sdata->local; |
1221 | struct sk_buff *skb; | 1240 | struct sk_buff *skb; |
1222 | struct ieee80211_mgmt *mgmt; | 1241 | struct ieee80211_mgmt *mgmt; |
1223 | size_t buf_len; | ||
1224 | u8 *buf; | ||
1225 | u8 chan_no; | 1242 | u8 chan_no; |
1226 | 1243 | int ies_len; | |
1227 | /* FIXME: come up with a proper value */ | ||
1228 | buf = kmalloc(200 + ie_len, GFP_KERNEL); | ||
1229 | if (!buf) | ||
1230 | return NULL; | ||
1231 | 1244 | ||
1232 | /* | 1245 | /* |
1233 | * Do not send DS Channel parameter for directed probe requests | 1246 | * Do not send DS Channel parameter for directed probe requests |
@@ -1239,14 +1252,16 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1239 | else | 1252 | else |
1240 | chan_no = ieee80211_frequency_to_channel(chan->center_freq); | 1253 | chan_no = ieee80211_frequency_to_channel(chan->center_freq); |
1241 | 1254 | ||
1242 | buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len, chan->band, | ||
1243 | ratemask, chan_no); | ||
1244 | |||
1245 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, | 1255 | skb = ieee80211_probereq_get(&local->hw, &sdata->vif, |
1246 | ssid, ssid_len, | 1256 | ssid, ssid_len, 100 + ie_len); |
1247 | buf, buf_len); | ||
1248 | if (!skb) | 1257 | if (!skb) |
1249 | goto out; | 1258 | return NULL; |
1259 | |||
1260 | ies_len = ieee80211_build_preq_ies(local, skb_tail_pointer(skb), | ||
1261 | skb_tailroom(skb), | ||
1262 | ie, ie_len, chan->band, | ||
1263 | ratemask, chan_no); | ||
1264 | skb_put(skb, ies_len); | ||
1250 | 1265 | ||
1251 | if (dst) { | 1266 | if (dst) { |
1252 | mgmt = (struct ieee80211_mgmt *) skb->data; | 1267 | mgmt = (struct ieee80211_mgmt *) skb->data; |
@@ -1256,9 +1271,6 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, | |||
1256 | 1271 | ||
1257 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 1272 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; |
1258 | 1273 | ||
1259 | out: | ||
1260 | kfree(buf); | ||
1261 | |||
1262 | return skb; | 1274 | return skb; |
1263 | } | 1275 | } |
1264 | 1276 | ||
@@ -1527,7 +1539,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1527 | changed |= BSS_CHANGED_IBSS; | 1539 | changed |= BSS_CHANGED_IBSS; |
1528 | /* fall through */ | 1540 | /* fall through */ |
1529 | case NL80211_IFTYPE_AP: | 1541 | case NL80211_IFTYPE_AP: |
1530 | changed |= BSS_CHANGED_SSID; | 1542 | changed |= BSS_CHANGED_SSID | BSS_CHANGED_P2P_PS; |
1531 | 1543 | ||
1532 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 1544 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
1533 | changed |= BSS_CHANGED_AP_PROBE_RESP; | 1545 | changed |= BSS_CHANGED_AP_PROBE_RESP; |