diff options
author | Johannes Berg <johannes.berg@intel.com> | 2010-08-12 09:38:38 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-08-24 16:27:56 -0400 |
commit | 2e161f78e5f63a7f9fd25a766bb7f816a01eb14a (patch) | |
tree | befd44feeb1f47da1f41e6fc310a223ad67030ff /net/wireless | |
parent | ac4c977d16d843f12901595c91773dddb65768a9 (diff) |
cfg80211/mac80211: extensible frame processing
Allow userspace to register for more than just
action frames by giving the frame subtype, and
make it possible to use this in various modes
as well.
With some tweaks and some added functionality
this will, in the future, also be usable in AP
mode and be able to replace the cooked monitor
interface currently used in that case.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/core.c | 8 | ||||
-rw-r--r-- | net/wireless/core.h | 21 | ||||
-rw-r--r-- | net/wireless/mlme.c | 144 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 108 | ||||
-rw-r--r-- | net/wireless/nl80211.h | 14 | ||||
-rw-r--r-- | net/wireless/util.c | 2 |
6 files changed, 197 insertions, 100 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index c70909c3eae4..d52630bbab04 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -433,7 +433,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
433 | 433 | ||
434 | /* sanity check ifmodes */ | 434 | /* sanity check ifmodes */ |
435 | WARN_ON(!ifmodes); | 435 | WARN_ON(!ifmodes); |
436 | ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1; | 436 | ifmodes &= ((1 << NUM_NL80211_IFTYPES) - 1) & ~1; |
437 | if (WARN_ON(ifmodes != wiphy->interface_modes)) | 437 | if (WARN_ON(ifmodes != wiphy->interface_modes)) |
438 | wiphy->interface_modes = ifmodes; | 438 | wiphy->interface_modes = ifmodes; |
439 | 439 | ||
@@ -685,8 +685,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
685 | INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); | 685 | INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); |
686 | INIT_LIST_HEAD(&wdev->event_list); | 686 | INIT_LIST_HEAD(&wdev->event_list); |
687 | spin_lock_init(&wdev->event_lock); | 687 | spin_lock_init(&wdev->event_lock); |
688 | INIT_LIST_HEAD(&wdev->action_registrations); | 688 | INIT_LIST_HEAD(&wdev->mgmt_registrations); |
689 | spin_lock_init(&wdev->action_registrations_lock); | 689 | spin_lock_init(&wdev->mgmt_registrations_lock); |
690 | 690 | ||
691 | mutex_lock(&rdev->devlist_mtx); | 691 | mutex_lock(&rdev->devlist_mtx); |
692 | list_add_rcu(&wdev->list, &rdev->netdev_list); | 692 | list_add_rcu(&wdev->list, &rdev->netdev_list); |
@@ -806,7 +806,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
806 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); | 806 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); |
807 | list_del_rcu(&wdev->list); | 807 | list_del_rcu(&wdev->list); |
808 | rdev->devlist_generation++; | 808 | rdev->devlist_generation++; |
809 | cfg80211_mlme_purge_actions(wdev); | 809 | cfg80211_mlme_purge_registrations(wdev); |
810 | #ifdef CONFIG_CFG80211_WEXT | 810 | #ifdef CONFIG_CFG80211_WEXT |
811 | kfree(wdev->wext.keys); | 811 | kfree(wdev->wext.keys); |
812 | #endif | 812 | #endif |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 63d57ae399c3..58ab2c791d28 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -331,16 +331,17 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | |||
331 | const u8 *resp_ie, size_t resp_ie_len, | 331 | const u8 *resp_ie, size_t resp_ie_len, |
332 | u16 status, bool wextev, | 332 | u16 status, bool wextev, |
333 | struct cfg80211_bss *bss); | 333 | struct cfg80211_bss *bss); |
334 | int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, | 334 | int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, |
335 | const u8 *match_data, int match_len); | 335 | u16 frame_type, const u8 *match_data, |
336 | void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid); | 336 | int match_len); |
337 | void cfg80211_mlme_purge_actions(struct wireless_dev *wdev); | 337 | void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid); |
338 | int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, | 338 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); |
339 | struct net_device *dev, | 339 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
340 | struct ieee80211_channel *chan, | 340 | struct net_device *dev, |
341 | enum nl80211_channel_type channel_type, | 341 | struct ieee80211_channel *chan, |
342 | bool channel_type_valid, | 342 | enum nl80211_channel_type channel_type, |
343 | const u8 *buf, size_t len, u64 *cookie); | 343 | bool channel_type_valid, |
344 | const u8 *buf, size_t len, u64 *cookie); | ||
344 | 345 | ||
345 | /* SME */ | 346 | /* SME */ |
346 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 347 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index ee0af32ed59e..8515b1e5c578 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c | |||
@@ -748,31 +748,51 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, | |||
748 | } | 748 | } |
749 | EXPORT_SYMBOL(cfg80211_new_sta); | 749 | EXPORT_SYMBOL(cfg80211_new_sta); |
750 | 750 | ||
751 | struct cfg80211_action_registration { | 751 | struct cfg80211_mgmt_registration { |
752 | struct list_head list; | 752 | struct list_head list; |
753 | 753 | ||
754 | u32 nlpid; | 754 | u32 nlpid; |
755 | 755 | ||
756 | int match_len; | 756 | int match_len; |
757 | 757 | ||
758 | __le16 frame_type; | ||
759 | |||
758 | u8 match[]; | 760 | u8 match[]; |
759 | }; | 761 | }; |
760 | 762 | ||
761 | int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, | 763 | int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, |
762 | const u8 *match_data, int match_len) | 764 | u16 frame_type, const u8 *match_data, |
765 | int match_len) | ||
763 | { | 766 | { |
764 | struct cfg80211_action_registration *reg, *nreg; | 767 | struct cfg80211_mgmt_registration *reg, *nreg; |
765 | int err = 0; | 768 | int err = 0; |
769 | u16 mgmt_type; | ||
770 | |||
771 | if (!wdev->wiphy->mgmt_stypes) | ||
772 | return -EOPNOTSUPP; | ||
773 | |||
774 | if ((frame_type & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT) | ||
775 | return -EINVAL; | ||
776 | |||
777 | if (frame_type & ~(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) | ||
778 | return -EINVAL; | ||
779 | |||
780 | mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4; | ||
781 | if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].rx & BIT(mgmt_type))) | ||
782 | return -EINVAL; | ||
766 | 783 | ||
767 | nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL); | 784 | nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL); |
768 | if (!nreg) | 785 | if (!nreg) |
769 | return -ENOMEM; | 786 | return -ENOMEM; |
770 | 787 | ||
771 | spin_lock_bh(&wdev->action_registrations_lock); | 788 | spin_lock_bh(&wdev->mgmt_registrations_lock); |
772 | 789 | ||
773 | list_for_each_entry(reg, &wdev->action_registrations, list) { | 790 | list_for_each_entry(reg, &wdev->mgmt_registrations, list) { |
774 | int mlen = min(match_len, reg->match_len); | 791 | int mlen = min(match_len, reg->match_len); |
775 | 792 | ||
793 | if (frame_type != le16_to_cpu(reg->frame_type)) | ||
794 | continue; | ||
795 | |||
776 | if (memcmp(reg->match, match_data, mlen) == 0) { | 796 | if (memcmp(reg->match, match_data, mlen) == 0) { |
777 | err = -EALREADY; | 797 | err = -EALREADY; |
778 | break; | 798 | break; |
@@ -787,62 +807,75 @@ int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, | |||
787 | memcpy(nreg->match, match_data, match_len); | 807 | memcpy(nreg->match, match_data, match_len); |
788 | nreg->match_len = match_len; | 808 | nreg->match_len = match_len; |
789 | nreg->nlpid = snd_pid; | 809 | nreg->nlpid = snd_pid; |
790 | list_add(&nreg->list, &wdev->action_registrations); | 810 | nreg->frame_type = cpu_to_le16(frame_type); |
811 | list_add(&nreg->list, &wdev->mgmt_registrations); | ||
791 | 812 | ||
792 | out: | 813 | out: |
793 | spin_unlock_bh(&wdev->action_registrations_lock); | 814 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
794 | return err; | 815 | return err; |
795 | } | 816 | } |
796 | 817 | ||
797 | void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid) | 818 | void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid) |
798 | { | 819 | { |
799 | struct cfg80211_action_registration *reg, *tmp; | 820 | struct cfg80211_mgmt_registration *reg, *tmp; |
800 | 821 | ||
801 | spin_lock_bh(&wdev->action_registrations_lock); | 822 | spin_lock_bh(&wdev->mgmt_registrations_lock); |
802 | 823 | ||
803 | list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) { | 824 | list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { |
804 | if (reg->nlpid == nlpid) { | 825 | if (reg->nlpid == nlpid) { |
805 | list_del(®->list); | 826 | list_del(®->list); |
806 | kfree(reg); | 827 | kfree(reg); |
807 | } | 828 | } |
808 | } | 829 | } |
809 | 830 | ||
810 | spin_unlock_bh(&wdev->action_registrations_lock); | 831 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
811 | } | 832 | } |
812 | 833 | ||
813 | void cfg80211_mlme_purge_actions(struct wireless_dev *wdev) | 834 | void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) |
814 | { | 835 | { |
815 | struct cfg80211_action_registration *reg, *tmp; | 836 | struct cfg80211_mgmt_registration *reg, *tmp; |
816 | 837 | ||
817 | spin_lock_bh(&wdev->action_registrations_lock); | 838 | spin_lock_bh(&wdev->mgmt_registrations_lock); |
818 | 839 | ||
819 | list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) { | 840 | list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { |
820 | list_del(®->list); | 841 | list_del(®->list); |
821 | kfree(reg); | 842 | kfree(reg); |
822 | } | 843 | } |
823 | 844 | ||
824 | spin_unlock_bh(&wdev->action_registrations_lock); | 845 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
825 | } | 846 | } |
826 | 847 | ||
827 | int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, | 848 | int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, |
828 | struct net_device *dev, | 849 | struct net_device *dev, |
829 | struct ieee80211_channel *chan, | 850 | struct ieee80211_channel *chan, |
830 | enum nl80211_channel_type channel_type, | 851 | enum nl80211_channel_type channel_type, |
831 | bool channel_type_valid, | 852 | bool channel_type_valid, |
832 | const u8 *buf, size_t len, u64 *cookie) | 853 | const u8 *buf, size_t len, u64 *cookie) |
833 | { | 854 | { |
834 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 855 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
835 | const struct ieee80211_mgmt *mgmt; | 856 | const struct ieee80211_mgmt *mgmt; |
857 | u16 stype; | ||
858 | |||
859 | if (!wdev->wiphy->mgmt_stypes) | ||
860 | return -EOPNOTSUPP; | ||
836 | 861 | ||
837 | if (rdev->ops->action == NULL) | 862 | if (!rdev->ops->mgmt_tx) |
838 | return -EOPNOTSUPP; | 863 | return -EOPNOTSUPP; |
864 | |||
839 | if (len < 24 + 1) | 865 | if (len < 24 + 1) |
840 | return -EINVAL; | 866 | return -EINVAL; |
841 | 867 | ||
842 | mgmt = (const struct ieee80211_mgmt *) buf; | 868 | mgmt = (const struct ieee80211_mgmt *) buf; |
843 | if (!ieee80211_is_action(mgmt->frame_control)) | 869 | |
870 | if (!ieee80211_is_mgmt(mgmt->frame_control)) | ||
844 | return -EINVAL; | 871 | return -EINVAL; |
845 | if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) { | 872 | |
873 | stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; | ||
874 | if (!(wdev->wiphy->mgmt_stypes[wdev->iftype].tx & BIT(stype >> 4))) | ||
875 | return -EINVAL; | ||
876 | |||
877 | if (ieee80211_is_action(mgmt->frame_control) && | ||
878 | mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) { | ||
846 | /* Verify that we are associated with the destination AP */ | 879 | /* Verify that we are associated with the destination AP */ |
847 | wdev_lock(wdev); | 880 | wdev_lock(wdev); |
848 | 881 | ||
@@ -863,64 +896,75 @@ int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, | |||
863 | return -EINVAL; | 896 | return -EINVAL; |
864 | 897 | ||
865 | /* Transmit the Action frame as requested by user space */ | 898 | /* Transmit the Action frame as requested by user space */ |
866 | return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type, | 899 | return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, channel_type, |
867 | channel_type_valid, buf, len, cookie); | 900 | channel_type_valid, buf, len, cookie); |
868 | } | 901 | } |
869 | 902 | ||
870 | bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf, | 903 | bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf, |
871 | size_t len, gfp_t gfp) | 904 | size_t len, gfp_t gfp) |
872 | { | 905 | { |
873 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 906 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
874 | struct wiphy *wiphy = wdev->wiphy; | 907 | struct wiphy *wiphy = wdev->wiphy; |
875 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 908 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
876 | struct cfg80211_action_registration *reg; | 909 | struct cfg80211_mgmt_registration *reg; |
877 | const u8 *action_data; | 910 | const struct ieee80211_txrx_stypes *stypes = |
878 | int action_data_len; | 911 | &wiphy->mgmt_stypes[wdev->iftype]; |
912 | struct ieee80211_mgmt *mgmt = (void *)buf; | ||
913 | const u8 *data; | ||
914 | int data_len; | ||
879 | bool result = false; | 915 | bool result = false; |
916 | __le16 ftype = mgmt->frame_control & | ||
917 | cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE); | ||
918 | u16 stype; | ||
880 | 919 | ||
881 | /* frame length - min size excluding category */ | 920 | stype = (le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE) >> 4; |
882 | action_data_len = len - (IEEE80211_MIN_ACTION_SIZE - 1); | ||
883 | 921 | ||
884 | /* action data starts with category */ | 922 | if (!(stypes->rx & BIT(stype))) |
885 | action_data = buf + IEEE80211_MIN_ACTION_SIZE - 1; | 923 | return false; |
886 | 924 | ||
887 | spin_lock_bh(&wdev->action_registrations_lock); | 925 | data = buf + ieee80211_hdrlen(mgmt->frame_control); |
926 | data_len = len - ieee80211_hdrlen(mgmt->frame_control); | ||
927 | |||
928 | spin_lock_bh(&wdev->mgmt_registrations_lock); | ||
929 | |||
930 | list_for_each_entry(reg, &wdev->mgmt_registrations, list) { | ||
931 | if (reg->frame_type != ftype) | ||
932 | continue; | ||
888 | 933 | ||
889 | list_for_each_entry(reg, &wdev->action_registrations, list) { | 934 | if (reg->match_len > data_len) |
890 | if (reg->match_len > action_data_len) | ||
891 | continue; | 935 | continue; |
892 | 936 | ||
893 | if (memcmp(reg->match, action_data, reg->match_len)) | 937 | if (memcmp(reg->match, data, reg->match_len)) |
894 | continue; | 938 | continue; |
895 | 939 | ||
896 | /* found match! */ | 940 | /* found match! */ |
897 | 941 | ||
898 | /* Indicate the received Action frame to user space */ | 942 | /* Indicate the received Action frame to user space */ |
899 | if (nl80211_send_action(rdev, dev, reg->nlpid, freq, | 943 | if (nl80211_send_mgmt(rdev, dev, reg->nlpid, freq, |
900 | buf, len, gfp)) | 944 | buf, len, gfp)) |
901 | continue; | 945 | continue; |
902 | 946 | ||
903 | result = true; | 947 | result = true; |
904 | break; | 948 | break; |
905 | } | 949 | } |
906 | 950 | ||
907 | spin_unlock_bh(&wdev->action_registrations_lock); | 951 | spin_unlock_bh(&wdev->mgmt_registrations_lock); |
908 | 952 | ||
909 | return result; | 953 | return result; |
910 | } | 954 | } |
911 | EXPORT_SYMBOL(cfg80211_rx_action); | 955 | EXPORT_SYMBOL(cfg80211_rx_mgmt); |
912 | 956 | ||
913 | void cfg80211_action_tx_status(struct net_device *dev, u64 cookie, | 957 | void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie, |
914 | const u8 *buf, size_t len, bool ack, gfp_t gfp) | 958 | const u8 *buf, size_t len, bool ack, gfp_t gfp) |
915 | { | 959 | { |
916 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 960 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
917 | struct wiphy *wiphy = wdev->wiphy; | 961 | struct wiphy *wiphy = wdev->wiphy; |
918 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 962 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
919 | 963 | ||
920 | /* Indicate TX status of the Action frame to user space */ | 964 | /* Indicate TX status of the Action frame to user space */ |
921 | nl80211_send_action_tx_status(rdev, dev, cookie, buf, len, ack, gfp); | 965 | nl80211_send_mgmt_tx_status(rdev, dev, cookie, buf, len, ack, gfp); |
922 | } | 966 | } |
923 | EXPORT_SYMBOL(cfg80211_action_tx_status); | 967 | EXPORT_SYMBOL(cfg80211_mgmt_tx_status); |
924 | 968 | ||
925 | void cfg80211_cqm_rssi_notify(struct net_device *dev, | 969 | void cfg80211_cqm_rssi_notify(struct net_device *dev, |
926 | enum nl80211_cqm_rssi_threshold_event rssi_event, | 970 | enum nl80211_cqm_rssi_threshold_event rssi_event, |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index bb5b78eebeb2..927ffbd2aebc 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -156,6 +156,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { | |||
156 | 156 | ||
157 | [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 }, | 157 | [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 }, |
158 | [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 }, | 158 | [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 }, |
159 | [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 }, | ||
159 | }; | 160 | }; |
160 | 161 | ||
161 | /* policy for the attributes */ | 162 | /* policy for the attributes */ |
@@ -437,6 +438,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
437 | struct ieee80211_rate *rate; | 438 | struct ieee80211_rate *rate; |
438 | int i; | 439 | int i; |
439 | u16 ifmodes = dev->wiphy.interface_modes; | 440 | u16 ifmodes = dev->wiphy.interface_modes; |
441 | const struct ieee80211_txrx_stypes *mgmt_stypes = | ||
442 | dev->wiphy.mgmt_stypes; | ||
440 | 443 | ||
441 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); | 444 | hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); |
442 | if (!hdr) | 445 | if (!hdr) |
@@ -587,7 +590,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
587 | CMD(flush_pmksa, FLUSH_PMKSA); | 590 | CMD(flush_pmksa, FLUSH_PMKSA); |
588 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); | 591 | CMD(remain_on_channel, REMAIN_ON_CHANNEL); |
589 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); | 592 | CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); |
590 | CMD(action, ACTION); | 593 | CMD(mgmt_tx, FRAME); |
591 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { | 594 | if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { |
592 | i++; | 595 | i++; |
593 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); | 596 | NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); |
@@ -608,6 +611,53 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
608 | 611 | ||
609 | nla_nest_end(msg, nl_cmds); | 612 | nla_nest_end(msg, nl_cmds); |
610 | 613 | ||
614 | if (mgmt_stypes) { | ||
615 | u16 stypes; | ||
616 | struct nlattr *nl_ftypes, *nl_ifs; | ||
617 | enum nl80211_iftype ift; | ||
618 | |||
619 | nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES); | ||
620 | if (!nl_ifs) | ||
621 | goto nla_put_failure; | ||
622 | |||
623 | for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { | ||
624 | nl_ftypes = nla_nest_start(msg, ift); | ||
625 | if (!nl_ftypes) | ||
626 | goto nla_put_failure; | ||
627 | i = 0; | ||
628 | stypes = mgmt_stypes[ift].tx; | ||
629 | while (stypes) { | ||
630 | if (stypes & 1) | ||
631 | NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, | ||
632 | (i << 4) | IEEE80211_FTYPE_MGMT); | ||
633 | stypes >>= 1; | ||
634 | i++; | ||
635 | } | ||
636 | nla_nest_end(msg, nl_ftypes); | ||
637 | } | ||
638 | |||
639 | nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES); | ||
640 | if (!nl_ifs) | ||
641 | goto nla_put_failure; | ||
642 | |||
643 | for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) { | ||
644 | nl_ftypes = nla_nest_start(msg, ift); | ||
645 | if (!nl_ftypes) | ||
646 | goto nla_put_failure; | ||
647 | i = 0; | ||
648 | stypes = mgmt_stypes[ift].rx; | ||
649 | while (stypes) { | ||
650 | if (stypes & 1) | ||
651 | NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, | ||
652 | (i << 4) | IEEE80211_FTYPE_MGMT); | ||
653 | stypes >>= 1; | ||
654 | i++; | ||
655 | } | ||
656 | nla_nest_end(msg, nl_ftypes); | ||
657 | } | ||
658 | nla_nest_end(msg, nl_ifs); | ||
659 | } | ||
660 | |||
611 | return genlmsg_end(msg, hdr); | 661 | return genlmsg_end(msg, hdr); |
612 | 662 | ||
613 | nla_put_failure: | 663 | nla_put_failure: |
@@ -4732,17 +4782,18 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, | |||
4732 | return err; | 4782 | return err; |
4733 | } | 4783 | } |
4734 | 4784 | ||
4735 | static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info) | 4785 | static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) |
4736 | { | 4786 | { |
4737 | struct cfg80211_registered_device *rdev; | 4787 | struct cfg80211_registered_device *rdev; |
4738 | struct net_device *dev; | 4788 | struct net_device *dev; |
4789 | u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; | ||
4739 | int err; | 4790 | int err; |
4740 | 4791 | ||
4741 | if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) | 4792 | if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) |
4742 | return -EINVAL; | 4793 | return -EINVAL; |
4743 | 4794 | ||
4744 | if (nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]) < 1) | 4795 | if (info->attrs[NL80211_ATTR_FRAME_TYPE]) |
4745 | return -EINVAL; | 4796 | frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); |
4746 | 4797 | ||
4747 | rtnl_lock(); | 4798 | rtnl_lock(); |
4748 | 4799 | ||
@@ -4757,12 +4808,13 @@ static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info) | |||
4757 | } | 4808 | } |
4758 | 4809 | ||
4759 | /* not much point in registering if we can't reply */ | 4810 | /* not much point in registering if we can't reply */ |
4760 | if (!rdev->ops->action) { | 4811 | if (!rdev->ops->mgmt_tx) { |
4761 | err = -EOPNOTSUPP; | 4812 | err = -EOPNOTSUPP; |
4762 | goto out; | 4813 | goto out; |
4763 | } | 4814 | } |
4764 | 4815 | ||
4765 | err = cfg80211_mlme_register_action(dev->ieee80211_ptr, info->snd_pid, | 4816 | err = cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, |
4817 | frame_type, | ||
4766 | nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), | 4818 | nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), |
4767 | nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); | 4819 | nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); |
4768 | out: | 4820 | out: |
@@ -4773,7 +4825,7 @@ static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info) | |||
4773 | return err; | 4825 | return err; |
4774 | } | 4826 | } |
4775 | 4827 | ||
4776 | static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | 4828 | static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) |
4777 | { | 4829 | { |
4778 | struct cfg80211_registered_device *rdev; | 4830 | struct cfg80211_registered_device *rdev; |
4779 | struct net_device *dev; | 4831 | struct net_device *dev; |
@@ -4796,7 +4848,7 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | |||
4796 | if (err) | 4848 | if (err) |
4797 | goto unlock_rtnl; | 4849 | goto unlock_rtnl; |
4798 | 4850 | ||
4799 | if (!rdev->ops->action) { | 4851 | if (!rdev->ops->mgmt_tx) { |
4800 | err = -EOPNOTSUPP; | 4852 | err = -EOPNOTSUPP; |
4801 | goto out; | 4853 | goto out; |
4802 | } | 4854 | } |
@@ -4839,17 +4891,17 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | |||
4839 | } | 4891 | } |
4840 | 4892 | ||
4841 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | 4893 | hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, |
4842 | NL80211_CMD_ACTION); | 4894 | NL80211_CMD_FRAME); |
4843 | 4895 | ||
4844 | if (IS_ERR(hdr)) { | 4896 | if (IS_ERR(hdr)) { |
4845 | err = PTR_ERR(hdr); | 4897 | err = PTR_ERR(hdr); |
4846 | goto free_msg; | 4898 | goto free_msg; |
4847 | } | 4899 | } |
4848 | err = cfg80211_mlme_action(rdev, dev, chan, channel_type, | 4900 | err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, channel_type, |
4849 | channel_type_valid, | 4901 | channel_type_valid, |
4850 | nla_data(info->attrs[NL80211_ATTR_FRAME]), | 4902 | nla_data(info->attrs[NL80211_ATTR_FRAME]), |
4851 | nla_len(info->attrs[NL80211_ATTR_FRAME]), | 4903 | nla_len(info->attrs[NL80211_ATTR_FRAME]), |
4852 | &cookie); | 4904 | &cookie); |
4853 | if (err) | 4905 | if (err) |
4854 | goto free_msg; | 4906 | goto free_msg; |
4855 | 4907 | ||
@@ -5348,14 +5400,14 @@ static struct genl_ops nl80211_ops[] = { | |||
5348 | .flags = GENL_ADMIN_PERM, | 5400 | .flags = GENL_ADMIN_PERM, |
5349 | }, | 5401 | }, |
5350 | { | 5402 | { |
5351 | .cmd = NL80211_CMD_REGISTER_ACTION, | 5403 | .cmd = NL80211_CMD_REGISTER_FRAME, |
5352 | .doit = nl80211_register_action, | 5404 | .doit = nl80211_register_mgmt, |
5353 | .policy = nl80211_policy, | 5405 | .policy = nl80211_policy, |
5354 | .flags = GENL_ADMIN_PERM, | 5406 | .flags = GENL_ADMIN_PERM, |
5355 | }, | 5407 | }, |
5356 | { | 5408 | { |
5357 | .cmd = NL80211_CMD_ACTION, | 5409 | .cmd = NL80211_CMD_FRAME, |
5358 | .doit = nl80211_action, | 5410 | .doit = nl80211_tx_mgmt, |
5359 | .policy = nl80211_policy, | 5411 | .policy = nl80211_policy, |
5360 | .flags = GENL_ADMIN_PERM, | 5412 | .flags = GENL_ADMIN_PERM, |
5361 | }, | 5413 | }, |
@@ -6055,9 +6107,9 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | |||
6055 | nl80211_mlme_mcgrp.id, gfp); | 6107 | nl80211_mlme_mcgrp.id, gfp); |
6056 | } | 6108 | } |
6057 | 6109 | ||
6058 | int nl80211_send_action(struct cfg80211_registered_device *rdev, | 6110 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
6059 | struct net_device *netdev, u32 nlpid, | 6111 | struct net_device *netdev, u32 nlpid, |
6060 | int freq, const u8 *buf, size_t len, gfp_t gfp) | 6112 | int freq, const u8 *buf, size_t len, gfp_t gfp) |
6061 | { | 6113 | { |
6062 | struct sk_buff *msg; | 6114 | struct sk_buff *msg; |
6063 | void *hdr; | 6115 | void *hdr; |
@@ -6067,7 +6119,7 @@ int nl80211_send_action(struct cfg80211_registered_device *rdev, | |||
6067 | if (!msg) | 6119 | if (!msg) |
6068 | return -ENOMEM; | 6120 | return -ENOMEM; |
6069 | 6121 | ||
6070 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION); | 6122 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME); |
6071 | if (!hdr) { | 6123 | if (!hdr) { |
6072 | nlmsg_free(msg); | 6124 | nlmsg_free(msg); |
6073 | return -ENOMEM; | 6125 | return -ENOMEM; |
@@ -6095,10 +6147,10 @@ int nl80211_send_action(struct cfg80211_registered_device *rdev, | |||
6095 | return -ENOBUFS; | 6147 | return -ENOBUFS; |
6096 | } | 6148 | } |
6097 | 6149 | ||
6098 | void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, | 6150 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, |
6099 | struct net_device *netdev, u64 cookie, | 6151 | struct net_device *netdev, u64 cookie, |
6100 | const u8 *buf, size_t len, bool ack, | 6152 | const u8 *buf, size_t len, bool ack, |
6101 | gfp_t gfp) | 6153 | gfp_t gfp) |
6102 | { | 6154 | { |
6103 | struct sk_buff *msg; | 6155 | struct sk_buff *msg; |
6104 | void *hdr; | 6156 | void *hdr; |
@@ -6107,7 +6159,7 @@ void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, | |||
6107 | if (!msg) | 6159 | if (!msg) |
6108 | return; | 6160 | return; |
6109 | 6161 | ||
6110 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION_TX_STATUS); | 6162 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS); |
6111 | if (!hdr) { | 6163 | if (!hdr) { |
6112 | nlmsg_free(msg); | 6164 | nlmsg_free(msg); |
6113 | return; | 6165 | return; |
@@ -6194,7 +6246,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb, | |||
6194 | 6246 | ||
6195 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) | 6247 | list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) |
6196 | list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) | 6248 | list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) |
6197 | cfg80211_mlme_unregister_actions(wdev, notify->pid); | 6249 | cfg80211_mlme_unregister_socket(wdev, notify->pid); |
6198 | 6250 | ||
6199 | rcu_read_unlock(); | 6251 | rcu_read_unlock(); |
6200 | 6252 | ||
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 2ad7fbc7d9f1..30d2f939150d 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -74,13 +74,13 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | |||
74 | struct net_device *dev, const u8 *mac_addr, | 74 | struct net_device *dev, const u8 *mac_addr, |
75 | struct station_info *sinfo, gfp_t gfp); | 75 | struct station_info *sinfo, gfp_t gfp); |
76 | 76 | ||
77 | int nl80211_send_action(struct cfg80211_registered_device *rdev, | 77 | int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, |
78 | struct net_device *netdev, u32 nlpid, int freq, | 78 | struct net_device *netdev, u32 nlpid, int freq, |
79 | const u8 *buf, size_t len, gfp_t gfp); | 79 | const u8 *buf, size_t len, gfp_t gfp); |
80 | void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, | 80 | void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, |
81 | struct net_device *netdev, u64 cookie, | 81 | struct net_device *netdev, u64 cookie, |
82 | const u8 *buf, size_t len, bool ack, | 82 | const u8 *buf, size_t len, bool ack, |
83 | gfp_t gfp); | 83 | gfp_t gfp); |
84 | 84 | ||
85 | void | 85 | void |
86 | nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, | 86 | nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, |
diff --git a/net/wireless/util.c b/net/wireless/util.c index 1eb24162be61..8d961cc4ae98 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -823,7 +823,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
823 | /* monitor can't bridge anyway */ | 823 | /* monitor can't bridge anyway */ |
824 | break; | 824 | break; |
825 | case NL80211_IFTYPE_UNSPECIFIED: | 825 | case NL80211_IFTYPE_UNSPECIFIED: |
826 | case __NL80211_IFTYPE_AFTER_LAST: | 826 | case NUM_NL80211_IFTYPES: |
827 | /* not happening */ | 827 | /* not happening */ |
828 | break; | 828 | break; |
829 | } | 829 | } |