diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ieee80211/ieee80211_rx.c | 38 |
1 files changed, 28 insertions, 10 deletions
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index f73fc164b9ef..d60358d702d7 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c | |||
@@ -779,33 +779,44 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, | |||
779 | return 0; | 779 | return 0; |
780 | } | 780 | } |
781 | 781 | ||
782 | /* Filter out unrelated packets, call ieee80211_rx[_mgt] */ | 782 | /* Filter out unrelated packets, call ieee80211_rx[_mgt] |
783 | int ieee80211_rx_any(struct ieee80211_device *ieee, | 783 | * This function takes over the skb, it should not be used again after calling |
784 | * this function. */ | ||
785 | void ieee80211_rx_any(struct ieee80211_device *ieee, | ||
784 | struct sk_buff *skb, struct ieee80211_rx_stats *stats) | 786 | struct sk_buff *skb, struct ieee80211_rx_stats *stats) |
785 | { | 787 | { |
786 | struct ieee80211_hdr_4addr *hdr; | 788 | struct ieee80211_hdr_4addr *hdr; |
787 | int is_packet_for_us; | 789 | int is_packet_for_us; |
788 | u16 fc; | 790 | u16 fc; |
789 | 791 | ||
790 | if (ieee->iw_mode == IW_MODE_MONITOR) | 792 | if (ieee->iw_mode == IW_MODE_MONITOR) { |
791 | return ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL; | 793 | if (!ieee80211_rx(ieee, skb, stats)) |
794 | dev_kfree_skb_irq(skb); | ||
795 | return; | ||
796 | } | ||
797 | |||
798 | if (skb->len < sizeof(struct ieee80211_hdr)) | ||
799 | goto drop_free; | ||
792 | 800 | ||
793 | hdr = (struct ieee80211_hdr_4addr *)skb->data; | 801 | hdr = (struct ieee80211_hdr_4addr *)skb->data; |
794 | fc = le16_to_cpu(hdr->frame_ctl); | 802 | fc = le16_to_cpu(hdr->frame_ctl); |
795 | 803 | ||
796 | if ((fc & IEEE80211_FCTL_VERS) != 0) | 804 | if ((fc & IEEE80211_FCTL_VERS) != 0) |
797 | return -EINVAL; | 805 | goto drop_free; |
798 | 806 | ||
799 | switch (fc & IEEE80211_FCTL_FTYPE) { | 807 | switch (fc & IEEE80211_FCTL_FTYPE) { |
800 | case IEEE80211_FTYPE_MGMT: | 808 | case IEEE80211_FTYPE_MGMT: |
809 | if (skb->len < sizeof(struct ieee80211_hdr_3addr)) | ||
810 | goto drop_free; | ||
801 | ieee80211_rx_mgt(ieee, hdr, stats); | 811 | ieee80211_rx_mgt(ieee, hdr, stats); |
802 | return 0; | 812 | dev_kfree_skb_irq(skb); |
813 | return; | ||
803 | case IEEE80211_FTYPE_DATA: | 814 | case IEEE80211_FTYPE_DATA: |
804 | break; | 815 | break; |
805 | case IEEE80211_FTYPE_CTL: | 816 | case IEEE80211_FTYPE_CTL: |
806 | return 0; | 817 | return; |
807 | default: | 818 | default: |
808 | return -EINVAL; | 819 | return; |
809 | } | 820 | } |
810 | 821 | ||
811 | is_packet_for_us = 0; | 822 | is_packet_for_us = 0; |
@@ -849,8 +860,14 @@ int ieee80211_rx_any(struct ieee80211_device *ieee, | |||
849 | } | 860 | } |
850 | 861 | ||
851 | if (is_packet_for_us) | 862 | if (is_packet_for_us) |
852 | return (ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL); | 863 | if (!ieee80211_rx(ieee, skb, stats)) |
853 | return 0; | 864 | dev_kfree_skb_irq(skb); |
865 | return; | ||
866 | |||
867 | drop_free: | ||
868 | dev_kfree_skb_irq(skb); | ||
869 | ieee->stats.rx_dropped++; | ||
870 | return; | ||
854 | } | 871 | } |
855 | 872 | ||
856 | #define MGMT_FRAME_FIXED_PART_LENGTH 0x24 | 873 | #define MGMT_FRAME_FIXED_PART_LENGTH 0x24 |
@@ -1730,5 +1747,6 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee, | |||
1730 | } | 1747 | } |
1731 | } | 1748 | } |
1732 | 1749 | ||
1750 | EXPORT_SYMBOL_GPL(ieee80211_rx_any); | ||
1733 | EXPORT_SYMBOL(ieee80211_rx_mgt); | 1751 | EXPORT_SYMBOL(ieee80211_rx_mgt); |
1734 | EXPORT_SYMBOL(ieee80211_rx); | 1752 | EXPORT_SYMBOL(ieee80211_rx); |