diff options
author | John W. Linville <linville@tuxdriver.com> | 2012-10-29 16:05:51 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-10-29 16:05:51 -0400 |
commit | ab3d59d265e772e734c36fe738809cb1a910f566 (patch) | |
tree | b6d29908d3d45b078d025341b1cc272ba4c0a6d0 /net/mac80211/rx.c | |
parent | 42d36074e53eadfd79e6db518b5caf8fba914f8b (diff) | |
parent | 8c6e30936a7893a85f6222084f0f26aceb81137a (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless
Conflicts:
drivers/net/wireless/mwifiex/cfg80211.c
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r-- | net/mac80211/rx.c | 74 |
1 files changed, 56 insertions, 18 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index d07216ab5f72..8c1f1527d671 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -531,6 +531,11 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) | |||
531 | 531 | ||
532 | if (ieee80211_is_action(hdr->frame_control)) { | 532 | if (ieee80211_is_action(hdr->frame_control)) { |
533 | u8 category; | 533 | u8 category; |
534 | |||
535 | /* make sure category field is present */ | ||
536 | if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE) | ||
537 | return RX_DROP_MONITOR; | ||
538 | |||
534 | mgmt = (struct ieee80211_mgmt *)hdr; | 539 | mgmt = (struct ieee80211_mgmt *)hdr; |
535 | category = mgmt->u.action.category; | 540 | category = mgmt->u.action.category; |
536 | if (category != WLAN_CATEGORY_MESH_ACTION && | 541 | if (category != WLAN_CATEGORY_MESH_ACTION && |
@@ -883,14 +888,16 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
883 | */ | 888 | */ |
884 | if (rx->sta && rx->sdata->vif.type == NL80211_IFTYPE_STATION && | 889 | if (rx->sta && rx->sdata->vif.type == NL80211_IFTYPE_STATION && |
885 | ieee80211_is_data_present(hdr->frame_control)) { | 890 | ieee80211_is_data_present(hdr->frame_control)) { |
886 | u16 ethertype; | 891 | unsigned int hdrlen; |
887 | u8 *payload; | 892 | __be16 ethertype; |
888 | 893 | ||
889 | payload = rx->skb->data + | 894 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
890 | ieee80211_hdrlen(hdr->frame_control); | 895 | |
891 | ethertype = (payload[6] << 8) | payload[7]; | 896 | if (rx->skb->len < hdrlen + 8) |
892 | if (cpu_to_be16(ethertype) == | 897 | return RX_DROP_MONITOR; |
893 | rx->sdata->control_port_protocol) | 898 | |
899 | skb_copy_bits(rx->skb, hdrlen + 6, ðertype, 2); | ||
900 | if (ethertype == rx->sdata->control_port_protocol) | ||
894 | return RX_CONTINUE; | 901 | return RX_CONTINUE; |
895 | } | 902 | } |
896 | 903 | ||
@@ -1467,11 +1474,14 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
1467 | 1474 | ||
1468 | hdr = (struct ieee80211_hdr *)rx->skb->data; | 1475 | hdr = (struct ieee80211_hdr *)rx->skb->data; |
1469 | fc = hdr->frame_control; | 1476 | fc = hdr->frame_control; |
1477 | |||
1478 | if (ieee80211_is_ctl(fc)) | ||
1479 | return RX_CONTINUE; | ||
1480 | |||
1470 | sc = le16_to_cpu(hdr->seq_ctrl); | 1481 | sc = le16_to_cpu(hdr->seq_ctrl); |
1471 | frag = sc & IEEE80211_SCTL_FRAG; | 1482 | frag = sc & IEEE80211_SCTL_FRAG; |
1472 | 1483 | ||
1473 | if (likely((!ieee80211_has_morefrags(fc) && frag == 0) || | 1484 | if (likely((!ieee80211_has_morefrags(fc) && frag == 0) || |
1474 | (rx->skb)->len < 24 || | ||
1475 | is_multicast_ether_addr(hdr->addr1))) { | 1485 | is_multicast_ether_addr(hdr->addr1))) { |
1476 | /* not fragmented */ | 1486 | /* not fragmented */ |
1477 | goto out; | 1487 | goto out; |
@@ -1894,6 +1904,20 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1894 | 1904 | ||
1895 | hdr = (struct ieee80211_hdr *) skb->data; | 1905 | hdr = (struct ieee80211_hdr *) skb->data; |
1896 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 1906 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
1907 | |||
1908 | /* make sure fixed part of mesh header is there, also checks skb len */ | ||
1909 | if (!pskb_may_pull(rx->skb, hdrlen + 6)) | ||
1910 | return RX_DROP_MONITOR; | ||
1911 | |||
1912 | mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); | ||
1913 | |||
1914 | /* make sure full mesh header is there, also checks skb len */ | ||
1915 | if (!pskb_may_pull(rx->skb, | ||
1916 | hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr))) | ||
1917 | return RX_DROP_MONITOR; | ||
1918 | |||
1919 | /* reload pointers */ | ||
1920 | hdr = (struct ieee80211_hdr *) skb->data; | ||
1897 | mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); | 1921 | mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen); |
1898 | 1922 | ||
1899 | /* frame is in RMC, don't forward */ | 1923 | /* frame is in RMC, don't forward */ |
@@ -1902,7 +1926,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1902 | mesh_rmc_check(hdr->addr3, mesh_hdr, rx->sdata)) | 1926 | mesh_rmc_check(hdr->addr3, mesh_hdr, rx->sdata)) |
1903 | return RX_DROP_MONITOR; | 1927 | return RX_DROP_MONITOR; |
1904 | 1928 | ||
1905 | if (!ieee80211_is_data(hdr->frame_control)) | 1929 | if (!ieee80211_is_data(hdr->frame_control) || |
1930 | !(status->rx_flags & IEEE80211_RX_RA_MATCH)) | ||
1906 | return RX_CONTINUE; | 1931 | return RX_CONTINUE; |
1907 | 1932 | ||
1908 | if (!mesh_hdr->ttl) | 1933 | if (!mesh_hdr->ttl) |
@@ -1916,9 +1941,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1916 | if (is_multicast_ether_addr(hdr->addr1)) { | 1941 | if (is_multicast_ether_addr(hdr->addr1)) { |
1917 | mpp_addr = hdr->addr3; | 1942 | mpp_addr = hdr->addr3; |
1918 | proxied_addr = mesh_hdr->eaddr1; | 1943 | proxied_addr = mesh_hdr->eaddr1; |
1919 | } else { | 1944 | } else if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6) { |
1945 | /* has_a4 already checked in ieee80211_rx_mesh_check */ | ||
1920 | mpp_addr = hdr->addr4; | 1946 | mpp_addr = hdr->addr4; |
1921 | proxied_addr = mesh_hdr->eaddr2; | 1947 | proxied_addr = mesh_hdr->eaddr2; |
1948 | } else { | ||
1949 | return RX_DROP_MONITOR; | ||
1922 | } | 1950 | } |
1923 | 1951 | ||
1924 | rcu_read_lock(); | 1952 | rcu_read_lock(); |
@@ -1946,12 +1974,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) | |||
1946 | } | 1974 | } |
1947 | skb_set_queue_mapping(skb, q); | 1975 | skb_set_queue_mapping(skb, q); |
1948 | 1976 | ||
1949 | if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) | ||
1950 | goto out; | ||
1951 | |||
1952 | if (!--mesh_hdr->ttl) { | 1977 | if (!--mesh_hdr->ttl) { |
1953 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl); | 1978 | IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl); |
1954 | return RX_DROP_MONITOR; | 1979 | goto out; |
1955 | } | 1980 | } |
1956 | 1981 | ||
1957 | if (!ifmsh->mshcfg.dot11MeshForwarding) | 1982 | if (!ifmsh->mshcfg.dot11MeshForwarding) |
@@ -2358,6 +2383,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2358 | } | 2383 | } |
2359 | break; | 2384 | break; |
2360 | case WLAN_CATEGORY_SELF_PROTECTED: | 2385 | case WLAN_CATEGORY_SELF_PROTECTED: |
2386 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
2387 | sizeof(mgmt->u.action.u.self_prot.action_code))) | ||
2388 | break; | ||
2389 | |||
2361 | switch (mgmt->u.action.u.self_prot.action_code) { | 2390 | switch (mgmt->u.action.u.self_prot.action_code) { |
2362 | case WLAN_SP_MESH_PEERING_OPEN: | 2391 | case WLAN_SP_MESH_PEERING_OPEN: |
2363 | case WLAN_SP_MESH_PEERING_CLOSE: | 2392 | case WLAN_SP_MESH_PEERING_CLOSE: |
@@ -2376,6 +2405,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
2376 | } | 2405 | } |
2377 | break; | 2406 | break; |
2378 | case WLAN_CATEGORY_MESH_ACTION: | 2407 | case WLAN_CATEGORY_MESH_ACTION: |
2408 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
2409 | sizeof(mgmt->u.action.u.mesh_action.action_code))) | ||
2410 | break; | ||
2411 | |||
2379 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | 2412 | if (!ieee80211_vif_is_mesh(&sdata->vif)) |
2380 | break; | 2413 | break; |
2381 | if (mesh_action_is_path_sel(mgmt) && | 2414 | if (mesh_action_is_path_sel(mgmt) && |
@@ -2918,10 +2951,15 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
2918 | if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc)) | 2951 | if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc)) |
2919 | local->dot11ReceivedFragmentCount++; | 2952 | local->dot11ReceivedFragmentCount++; |
2920 | 2953 | ||
2921 | if (ieee80211_is_mgmt(fc)) | 2954 | if (ieee80211_is_mgmt(fc)) { |
2922 | err = skb_linearize(skb); | 2955 | /* drop frame if too short for header */ |
2923 | else | 2956 | if (skb->len < ieee80211_hdrlen(fc)) |
2957 | err = -ENOBUFS; | ||
2958 | else | ||
2959 | err = skb_linearize(skb); | ||
2960 | } else { | ||
2924 | err = !pskb_may_pull(skb, ieee80211_hdrlen(fc)); | 2961 | err = !pskb_may_pull(skb, ieee80211_hdrlen(fc)); |
2962 | } | ||
2925 | 2963 | ||
2926 | if (err) { | 2964 | if (err) { |
2927 | dev_kfree_skb(skb); | 2965 | dev_kfree_skb(skb); |