diff options
Diffstat (limited to 'net/ieee80211/ieee80211_rx.c')
| -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); | 
