aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/mac80211.h5
-rw-r--r--net/mac80211/rx.c36
-rw-r--r--net/wireless/util.c24
3 files changed, 54 insertions, 11 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 1a8f50af49a..ecaae10426f 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1822,7 +1822,10 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw);
1822 * ieee80211_rx - receive frame 1822 * ieee80211_rx - receive frame
1823 * 1823 *
1824 * Use this function to hand received frames to mac80211. The receive 1824 * Use this function to hand received frames to mac80211. The receive
1825 * buffer in @skb must start with an IEEE 802.11 header. 1825 * buffer in @skb must start with an IEEE 802.11 header. In case of a
1826 * paged @skb is used, the driver is recommended to put the ieee80211
1827 * header of the frame on the linear part of the @skb to avoid memory
1828 * allocation and/or memcpy by the stack.
1826 * 1829 *
1827 * This function may not be called in IRQ context. Calls to this function 1830 * This function may not be called in IRQ context. Calls to this function
1828 * for a single hardware must be synchronized against each other. Calls to 1831 * for a single hardware must be synchronized against each other. Calls to
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 1da57c8e849..11ed5aa90f8 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -38,7 +38,7 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
38{ 38{
39 if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) { 39 if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) {
40 if (likely(skb->len > FCS_LEN)) 40 if (likely(skb->len > FCS_LEN))
41 skb_trim(skb, skb->len - FCS_LEN); 41 __pskb_trim(skb, skb->len - FCS_LEN);
42 else { 42 else {
43 /* driver bug */ 43 /* driver bug */
44 WARN_ON(1); 44 WARN_ON(1);
@@ -227,6 +227,12 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
227 if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) 227 if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
228 present_fcs_len = FCS_LEN; 228 present_fcs_len = FCS_LEN;
229 229
230 /* make sure hdr->frame_control is on the linear part */
231 if (!pskb_may_pull(origskb, 2)) {
232 dev_kfree_skb(origskb);
233 return NULL;
234 }
235
230 if (!local->monitors) { 236 if (!local->monitors) {
231 if (should_drop_frame(origskb, present_fcs_len)) { 237 if (should_drop_frame(origskb, present_fcs_len)) {
232 dev_kfree_skb(origskb); 238 dev_kfree_skb(origskb);
@@ -931,6 +937,9 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
931 return RX_DROP_MONITOR; 937 return RX_DROP_MONITOR;
932 } 938 }
933 939
940 if (skb_linearize(rx->skb))
941 return RX_DROP_UNUSABLE;
942
934 /* Check for weak IVs if possible */ 943 /* Check for weak IVs if possible */
935 if (rx->sta && rx->key->conf.alg == ALG_WEP && 944 if (rx->sta && rx->key->conf.alg == ALG_WEP &&
936 ieee80211_is_data(hdr->frame_control) && 945 ieee80211_is_data(hdr->frame_control) &&
@@ -1231,6 +1240,9 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
1231 } 1240 }
1232 I802_DEBUG_INC(rx->local->rx_handlers_fragments); 1241 I802_DEBUG_INC(rx->local->rx_handlers_fragments);
1233 1242
1243 if (skb_linearize(rx->skb))
1244 return RX_DROP_UNUSABLE;
1245
1234 seq = (sc & IEEE80211_SCTL_SEQ) >> 4; 1246 seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
1235 1247
1236 if (frag == 0) { 1248 if (frag == 0) {
@@ -1588,6 +1600,9 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
1588 skb->dev = dev; 1600 skb->dev = dev;
1589 __skb_queue_head_init(&frame_list); 1601 __skb_queue_head_init(&frame_list);
1590 1602
1603 if (skb_linearize(skb))
1604 return RX_DROP_UNUSABLE;
1605
1591 ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, 1606 ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
1592 rx->sdata->vif.type, 1607 rx->sdata->vif.type,
1593 rx->local->hw.extra_tx_headroom); 1608 rx->local->hw.extra_tx_headroom);
@@ -2357,29 +2372,42 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
2357 struct ieee80211_local *local = hw_to_local(hw); 2372 struct ieee80211_local *local = hw_to_local(hw);
2358 struct ieee80211_sub_if_data *sdata; 2373 struct ieee80211_sub_if_data *sdata;
2359 struct ieee80211_hdr *hdr; 2374 struct ieee80211_hdr *hdr;
2375 __le16 fc;
2360 struct ieee80211_rx_data rx; 2376 struct ieee80211_rx_data rx;
2361 int prepares; 2377 int prepares;
2362 struct ieee80211_sub_if_data *prev = NULL; 2378 struct ieee80211_sub_if_data *prev = NULL;
2363 struct sk_buff *skb_new; 2379 struct sk_buff *skb_new;
2364 struct sta_info *sta, *tmp; 2380 struct sta_info *sta, *tmp;
2365 bool found_sta = false; 2381 bool found_sta = false;
2382 int err = 0;
2366 2383
2367 hdr = (struct ieee80211_hdr *)skb->data; 2384 fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
2368 memset(&rx, 0, sizeof(rx)); 2385 memset(&rx, 0, sizeof(rx));
2369 rx.skb = skb; 2386 rx.skb = skb;
2370 rx.local = local; 2387 rx.local = local;
2371 2388
2372 if (ieee80211_is_data(hdr->frame_control) || ieee80211_is_mgmt(hdr->frame_control)) 2389 if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc))
2373 local->dot11ReceivedFragmentCount++; 2390 local->dot11ReceivedFragmentCount++;
2374 2391
2375 if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) || 2392 if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
2376 test_bit(SCAN_OFF_CHANNEL, &local->scanning))) 2393 test_bit(SCAN_OFF_CHANNEL, &local->scanning)))
2377 rx.flags |= IEEE80211_RX_IN_SCAN; 2394 rx.flags |= IEEE80211_RX_IN_SCAN;
2378 2395
2396 if (ieee80211_is_mgmt(fc))
2397 err = skb_linearize(skb);
2398 else
2399 err = !pskb_may_pull(skb, ieee80211_hdrlen(fc));
2400
2401 if (err) {
2402 dev_kfree_skb(skb);
2403 return;
2404 }
2405
2406 hdr = (struct ieee80211_hdr *)skb->data;
2379 ieee80211_parse_qos(&rx); 2407 ieee80211_parse_qos(&rx);
2380 ieee80211_verify_alignment(&rx); 2408 ieee80211_verify_alignment(&rx);
2381 2409
2382 if (ieee80211_is_data(hdr->frame_control)) { 2410 if (ieee80211_is_data(fc)) {
2383 for_each_sta_info(local, hdr->addr2, sta, tmp) { 2411 for_each_sta_info(local, hdr->addr2, sta, tmp) {
2384 rx.sta = sta; 2412 rx.sta = sta;
2385 found_sta = true; 2413 found_sta = true;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index be2ab8c59e3..7acb81b9675 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -330,11 +330,18 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
330 if (iftype == NL80211_IFTYPE_MESH_POINT) { 330 if (iftype == NL80211_IFTYPE_MESH_POINT) {
331 struct ieee80211s_hdr *meshdr = 331 struct ieee80211s_hdr *meshdr =
332 (struct ieee80211s_hdr *) (skb->data + hdrlen); 332 (struct ieee80211s_hdr *) (skb->data + hdrlen);
333 hdrlen += ieee80211_get_mesh_hdrlen(meshdr); 333 /* make sure meshdr->flags is on the linear part */
334 if (!pskb_may_pull(skb, hdrlen + 1))
335 return -1;
334 if (meshdr->flags & MESH_FLAGS_AE_A5_A6) { 336 if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {
335 memcpy(dst, meshdr->eaddr1, ETH_ALEN); 337 skb_copy_bits(skb, hdrlen +
336 memcpy(src, meshdr->eaddr2, ETH_ALEN); 338 offsetof(struct ieee80211s_hdr, eaddr1),
339 dst, ETH_ALEN);
340 skb_copy_bits(skb, hdrlen +
341 offsetof(struct ieee80211s_hdr, eaddr2),
342 src, ETH_ALEN);
337 } 343 }
344 hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
338 } 345 }
339 break; 346 break;
340 case cpu_to_le16(IEEE80211_FCTL_FROMDS): 347 case cpu_to_le16(IEEE80211_FCTL_FROMDS):
@@ -346,9 +353,14 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
346 if (iftype == NL80211_IFTYPE_MESH_POINT) { 353 if (iftype == NL80211_IFTYPE_MESH_POINT) {
347 struct ieee80211s_hdr *meshdr = 354 struct ieee80211s_hdr *meshdr =
348 (struct ieee80211s_hdr *) (skb->data + hdrlen); 355 (struct ieee80211s_hdr *) (skb->data + hdrlen);
349 hdrlen += ieee80211_get_mesh_hdrlen(meshdr); 356 /* make sure meshdr->flags is on the linear part */
357 if (!pskb_may_pull(skb, hdrlen + 1))
358 return -1;
350 if (meshdr->flags & MESH_FLAGS_AE_A4) 359 if (meshdr->flags & MESH_FLAGS_AE_A4)
351 memcpy(src, meshdr->eaddr1, ETH_ALEN); 360 skb_copy_bits(skb, hdrlen +
361 offsetof(struct ieee80211s_hdr, eaddr1),
362 src, ETH_ALEN);
363 hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
352 } 364 }
353 break; 365 break;
354 case cpu_to_le16(0): 366 case cpu_to_le16(0):
@@ -357,7 +369,7 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
357 break; 369 break;
358 } 370 }
359 371
360 if (unlikely(skb->len - hdrlen < 8)) 372 if (!pskb_may_pull(skb, hdrlen + 8))
361 return -1; 373 return -1;
362 374
363 payload = skb->data + hdrlen; 375 payload = skb->data + hdrlen;