aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/mlme.c
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/mlme.c
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/mlme.c')
-rw-r--r--net/wireless/mlme.c144
1 files changed, 94 insertions, 50 deletions
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,