aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-08-12 09:38:38 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-08-24 16:27:56 -0400
commit2e161f78e5f63a7f9fd25a766bb7f816a01eb14a (patch)
treebefd44feeb1f47da1f41e6fc310a223ad67030ff /net/wireless
parentac4c977d16d843f12901595c91773dddb65768a9 (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.c8
-rw-r--r--net/wireless/core.h21
-rw-r--r--net/wireless/mlme.c144
-rw-r--r--net/wireless/nl80211.c108
-rw-r--r--net/wireless/nl80211.h14
-rw-r--r--net/wireless/util.c2
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);
334int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, 334int 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,
336void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid); 336 int match_len);
337void cfg80211_mlme_purge_actions(struct wireless_dev *wdev); 337void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid);
338int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, 338void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev);
339 struct net_device *dev, 339int 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 */
346int __cfg80211_connect(struct cfg80211_registered_device *rdev, 347int __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}
749EXPORT_SYMBOL(cfg80211_new_sta); 749EXPORT_SYMBOL(cfg80211_new_sta);
750 750
751struct cfg80211_action_registration { 751struct 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
761int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid, 763int 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
797void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid) 818void 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(&reg->list); 826 list_del(&reg->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
813void cfg80211_mlme_purge_actions(struct wireless_dev *wdev) 834void 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(&reg->list); 841 list_del(&reg->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
827int cfg80211_mlme_action(struct cfg80211_registered_device *rdev, 848int 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
870bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf, 903bool 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}
911EXPORT_SYMBOL(cfg80211_rx_action); 955EXPORT_SYMBOL(cfg80211_rx_mgmt);
912 956
913void cfg80211_action_tx_status(struct net_device *dev, u64 cookie, 957void 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}
923EXPORT_SYMBOL(cfg80211_action_tx_status); 967EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
924 968
925void cfg80211_cqm_rssi_notify(struct net_device *dev, 969void 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
4735static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info) 4785static 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
4776static int nl80211_action(struct sk_buff *skb, struct genl_info *info) 4828static 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
6058int nl80211_send_action(struct cfg80211_registered_device *rdev, 6110int 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
6098void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, 6150void 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
77int nl80211_send_action(struct cfg80211_registered_device *rdev, 77int 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);
80void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, 80void 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
85void 85void
86nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev, 86nl80211_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 }