aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJouni Malinen <jouni.malinen@atheros.com>2010-02-15 05:53:10 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-02-15 16:14:15 -0500
commit026331c4d9b526561ea96f95fac4bfc52b69e316 (patch)
treea82b0a92a7f03a1d151a9db123320689c73d98c7 /net
parent8404080568613d93ad7cf0a16dfb68459b42a264 (diff)
cfg80211/mac80211: allow registering for and sending action frames
This implements a new command to register for action frames that userspace wants to handle instead of the in-kernel rejection. It is then responsible for rejecting ones that it decided not to handle. There is no unregistration, but the socket can be closed for that. Frames that are not registered for will not be forwarded to userspace and will be rejected by the kernel, the cfg80211 API helps implementing that. Additionally, this patch adds a new command that allows doing action frame transmission from userspace. It can be used either to exchange action frames on the current operational channel (e.g., with the AP with which we are currently associated) or to exchange off-channel Public Action frames with the remain-on-channel command. Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com> Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/cfg.c12
-rw-r--r--net/mac80211/ieee80211_i.h6
-rw-r--r--net/mac80211/mlme.c35
-rw-r--r--net/mac80211/rx.c42
-rw-r--r--net/mac80211/status.c7
-rw-r--r--net/wireless/core.c4
-rw-r--r--net/wireless/core.h9
-rw-r--r--net/wireless/mlme.c166
-rw-r--r--net/wireless/nl80211.c260
-rw-r--r--net/wireless/nl80211.h8
10 files changed, 534 insertions, 15 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index e1731b7c2523..b7116ef84a3b 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * mac80211 configuration hooks for cfg80211 2 * mac80211 configuration hooks for cfg80211
3 * 3 *
4 * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> 4 * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
5 * 5 *
6 * This file is GPLv2 as found in COPYING. 6 * This file is GPLv2 as found in COPYING.
7 */ 7 */
@@ -1448,6 +1448,15 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
1448 return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); 1448 return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
1449} 1449}
1450 1450
1451static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev,
1452 struct ieee80211_channel *chan,
1453 enum nl80211_channel_type channel_type,
1454 const u8 *buf, size_t len, u64 *cookie)
1455{
1456 return ieee80211_mgd_action(IEEE80211_DEV_TO_SUB_IF(dev), chan,
1457 channel_type, buf, len, cookie);
1458}
1459
1451struct cfg80211_ops mac80211_config_ops = { 1460struct cfg80211_ops mac80211_config_ops = {
1452 .add_virtual_intf = ieee80211_add_iface, 1461 .add_virtual_intf = ieee80211_add_iface,
1453 .del_virtual_intf = ieee80211_del_iface, 1462 .del_virtual_intf = ieee80211_del_iface,
@@ -1496,4 +1505,5 @@ struct cfg80211_ops mac80211_config_ops = {
1496 .set_bitrate_mask = ieee80211_set_bitrate_mask, 1505 .set_bitrate_mask = ieee80211_set_bitrate_mask,
1497 .remain_on_channel = ieee80211_remain_on_channel, 1506 .remain_on_channel = ieee80211_remain_on_channel,
1498 .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, 1507 .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
1508 .action = ieee80211_action,
1499}; 1509};
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9dd98b674cbc..241533e1bc03 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2,7 +2,7 @@
2 * Copyright 2002-2005, Instant802 Networks, Inc. 2 * Copyright 2002-2005, Instant802 Networks, Inc.
3 * Copyright 2005, Devicescape Software, Inc. 3 * Copyright 2005, Devicescape Software, Inc.
4 * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> 4 * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
5 * Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net> 5 * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as 8 * it under the terms of the GNU General Public License version 2 as
@@ -966,6 +966,10 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
966int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, 966int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
967 struct cfg80211_disassoc_request *req, 967 struct cfg80211_disassoc_request *req,
968 void *cookie); 968 void *cookie);
969int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
970 struct ieee80211_channel *chan,
971 enum nl80211_channel_type channel_type,
972 const u8 *buf, size_t len, u64 *cookie);
969ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, 973ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
970 struct sk_buff *skb); 974 struct sk_buff *skb);
971void ieee80211_send_pspoll(struct ieee80211_local *local, 975void ieee80211_send_pspoll(struct ieee80211_local *local,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index bfc4a5070013..41812a15eea0 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2084,3 +2084,38 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
2084 2084
2085 return 0; 2085 return 0;
2086} 2086}
2087
2088int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
2089 struct ieee80211_channel *chan,
2090 enum nl80211_channel_type channel_type,
2091 const u8 *buf, size_t len, u64 *cookie)
2092{
2093 struct ieee80211_local *local = sdata->local;
2094 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
2095 struct sk_buff *skb;
2096
2097 /* Check that we are on the requested channel for transmission */
2098 if ((chan != local->tmp_channel ||
2099 channel_type != local->tmp_channel_type) &&
2100 (chan != local->oper_channel ||
2101 channel_type != local->oper_channel_type))
2102 return -EBUSY;
2103
2104 skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
2105 if (!skb)
2106 return -ENOMEM;
2107 skb_reserve(skb, local->hw.extra_tx_headroom);
2108
2109 memcpy(skb_put(skb, len), buf, len);
2110
2111 if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED))
2112 IEEE80211_SKB_CB(skb)->flags |=
2113 IEEE80211_TX_INTFL_DONT_ENCRYPT;
2114 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_NL80211_FRAME_TX |
2115 IEEE80211_TX_CTL_REQ_TX_STATUS;
2116 skb->dev = sdata->dev;
2117 ieee80211_tx_skb(sdata, skb);
2118
2119 *cookie = (unsigned long) skb;
2120 return 0;
2121}
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index a177472adc13..a6080d8d72bb 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1856,28 +1856,25 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
1856 struct ieee80211_sub_if_data *sdata = rx->sdata; 1856 struct ieee80211_sub_if_data *sdata = rx->sdata;
1857 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; 1857 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
1858 struct sk_buff *nskb; 1858 struct sk_buff *nskb;
1859 struct ieee80211_rx_status *status;
1859 int len = rx->skb->len; 1860 int len = rx->skb->len;
1860 1861
1861 if (!ieee80211_is_action(mgmt->frame_control)) 1862 if (!ieee80211_is_action(mgmt->frame_control))
1862 return RX_CONTINUE; 1863 return RX_CONTINUE;
1863 1864
1864 if (!rx->sta) 1865 /* drop too small frames */
1866 if (len < IEEE80211_MIN_ACTION_SIZE)
1865 return RX_DROP_UNUSABLE; 1867 return RX_DROP_UNUSABLE;
1866 1868
1867 if (!(rx->flags & IEEE80211_RX_RA_MATCH)) 1869 if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC)
1868 return RX_DROP_UNUSABLE; 1870 return RX_DROP_UNUSABLE;
1869 1871
1870 if (ieee80211_drop_unencrypted(rx, mgmt->frame_control)) 1872 if (!(rx->flags & IEEE80211_RX_RA_MATCH))
1871 return RX_DROP_UNUSABLE; 1873 return RX_DROP_UNUSABLE;
1872 1874
1873 /* drop too small frames */ 1875 if (ieee80211_drop_unencrypted(rx, mgmt->frame_control))
1874 if (len < IEEE80211_MIN_ACTION_SIZE)
1875 return RX_DROP_UNUSABLE; 1876 return RX_DROP_UNUSABLE;
1876 1877
1877 /* return action frames that have *only* category */
1878 if (len < IEEE80211_MIN_ACTION_SIZE + 1)
1879 goto return_frame;
1880
1881 switch (mgmt->u.action.category) { 1878 switch (mgmt->u.action.category) {
1882 case WLAN_CATEGORY_BACK: 1879 case WLAN_CATEGORY_BACK:
1883 /* 1880 /*
@@ -1891,6 +1888,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
1891 sdata->vif.type != NL80211_IFTYPE_AP) 1888 sdata->vif.type != NL80211_IFTYPE_AP)
1892 break; 1889 break;
1893 1890
1891 /* verify action_code is present */
1892 if (len < IEEE80211_MIN_ACTION_SIZE + 1)
1893 break;
1894
1894 switch (mgmt->u.action.u.addba_req.action_code) { 1895 switch (mgmt->u.action.u.addba_req.action_code) {
1895 case WLAN_ACTION_ADDBA_REQ: 1896 case WLAN_ACTION_ADDBA_REQ:
1896 if (len < (IEEE80211_MIN_ACTION_SIZE + 1897 if (len < (IEEE80211_MIN_ACTION_SIZE +
@@ -1919,6 +1920,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
1919 if (sdata->vif.type != NL80211_IFTYPE_STATION) 1920 if (sdata->vif.type != NL80211_IFTYPE_STATION)
1920 break; 1921 break;
1921 1922
1923 /* verify action_code is present */
1924 if (len < IEEE80211_MIN_ACTION_SIZE + 1)
1925 break;
1926
1922 switch (mgmt->u.action.u.measurement.action_code) { 1927 switch (mgmt->u.action.u.measurement.action_code) {
1923 case WLAN_ACTION_SPCT_MSR_REQ: 1928 case WLAN_ACTION_SPCT_MSR_REQ:
1924 if (len < (IEEE80211_MIN_ACTION_SIZE + 1929 if (len < (IEEE80211_MIN_ACTION_SIZE +
@@ -1954,7 +1959,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
1954 } 1959 }
1955 break; 1960 break;
1956 } 1961 }
1957 return_frame: 1962
1958 /* 1963 /*
1959 * For AP mode, hostapd is responsible for handling any action 1964 * For AP mode, hostapd is responsible for handling any action
1960 * frames that we didn't handle, including returning unknown 1965 * frames that we didn't handle, including returning unknown
@@ -1966,6 +1971,20 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
1966 sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 1971 sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
1967 return RX_DROP_MONITOR; 1972 return RX_DROP_MONITOR;
1968 1973
1974 /*
1975 * Getting here means the kernel doesn't know how to handle
1976 * it, but maybe userspace does ... include returned frames
1977 * so userspace can register for those to know whether ones
1978 * it transmitted were processed or returned.
1979 */
1980 status = IEEE80211_SKB_RXCB(rx->skb);
1981
1982 if (sdata->vif.type == NL80211_IFTYPE_STATION &&
1983 cfg80211_rx_action(rx->sdata->dev, status->freq,
1984 rx->skb->data, rx->skb->len,
1985 GFP_ATOMIC))
1986 goto handled;
1987
1969 /* do not return rejected action frames */ 1988 /* do not return rejected action frames */
1970 if (mgmt->u.action.category & 0x80) 1989 if (mgmt->u.action.category & 0x80)
1971 return RX_DROP_UNUSABLE; 1990 return RX_DROP_UNUSABLE;
@@ -1985,7 +2004,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
1985 } 2004 }
1986 2005
1987 handled: 2006 handled:
1988 rx->sta->rx_packets++; 2007 if (rx->sta)
2008 rx->sta->rx_packets++;
1989 dev_kfree_skb(rx->skb); 2009 dev_kfree_skb(rx->skb);
1990 return RX_QUEUED; 2010 return RX_QUEUED;
1991} 2011}
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index ded98730c111..56d5b9a6ec5b 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -2,7 +2,7 @@
2 * Copyright 2002-2005, Instant802 Networks, Inc. 2 * Copyright 2002-2005, Instant802 Networks, Inc.
3 * Copyright 2005-2006, Devicescape Software, Inc. 3 * Copyright 2005-2006, Devicescape Software, Inc.
4 * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> 4 * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
5 * Copyright 2008-2009 Johannes Berg <johannes@sipsolutions.net> 5 * Copyright 2008-2010 Johannes Berg <johannes@sipsolutions.net>
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as 8 * it under the terms of the GNU General Public License version 2 as
@@ -288,6 +288,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
288 msecs_to_jiffies(10)); 288 msecs_to_jiffies(10));
289 } 289 }
290 290
291 if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX)
292 cfg80211_action_tx_status(
293 skb->dev, (unsigned long) skb, skb->data, skb->len,
294 !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC);
295
291 /* this was a transmitted frame, but now we want to reuse it */ 296 /* this was a transmitted frame, but now we want to reuse it */
292 skb_orphan(skb); 297 skb_orphan(skb);
293 298
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 71b6b3a9cf1f..51908dc2ea00 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -677,6 +677,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
677 INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); 677 INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work);
678 INIT_LIST_HEAD(&wdev->event_list); 678 INIT_LIST_HEAD(&wdev->event_list);
679 spin_lock_init(&wdev->event_lock); 679 spin_lock_init(&wdev->event_lock);
680 INIT_LIST_HEAD(&wdev->action_registrations);
681 spin_lock_init(&wdev->action_registrations_lock);
682
680 mutex_lock(&rdev->devlist_mtx); 683 mutex_lock(&rdev->devlist_mtx);
681 list_add_rcu(&wdev->list, &rdev->netdev_list); 684 list_add_rcu(&wdev->list, &rdev->netdev_list);
682 rdev->devlist_generation++; 685 rdev->devlist_generation++;
@@ -792,6 +795,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
792 sysfs_remove_link(&dev->dev.kobj, "phy80211"); 795 sysfs_remove_link(&dev->dev.kobj, "phy80211");
793 list_del_rcu(&wdev->list); 796 list_del_rcu(&wdev->list);
794 rdev->devlist_generation++; 797 rdev->devlist_generation++;
798 cfg80211_mlme_purge_actions(wdev);
795#ifdef CONFIG_CFG80211_WEXT 799#ifdef CONFIG_CFG80211_WEXT
796 kfree(wdev->wext.keys); 800 kfree(wdev->wext.keys);
797#endif 801#endif
diff --git a/net/wireless/core.h b/net/wireless/core.h
index c326a667022a..d52da913145a 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -329,6 +329,15 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
329 const u8 *resp_ie, size_t resp_ie_len, 329 const u8 *resp_ie, size_t resp_ie_len,
330 u16 status, bool wextev, 330 u16 status, bool wextev,
331 struct cfg80211_bss *bss); 331 struct cfg80211_bss *bss);
332int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid,
333 const u8 *match_data, int match_len);
334void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid);
335void cfg80211_mlme_purge_actions(struct wireless_dev *wdev);
336int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
337 struct net_device *dev,
338 struct ieee80211_channel *chan,
339 enum nl80211_channel_type channel_type,
340 const u8 *buf, size_t len, u64 *cookie);
332 341
333/* SME */ 342/* SME */
334int __cfg80211_connect(struct cfg80211_registered_device *rdev, 343int __cfg80211_connect(struct cfg80211_registered_device *rdev,
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 94d151f6f73e..62bc8855e123 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -728,3 +728,169 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
728 nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp); 728 nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp);
729} 729}
730EXPORT_SYMBOL(cfg80211_new_sta); 730EXPORT_SYMBOL(cfg80211_new_sta);
731
732struct cfg80211_action_registration {
733 struct list_head list;
734
735 u32 nlpid;
736
737 int match_len;
738
739 u8 match[];
740};
741
742int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid,
743 const u8 *match_data, int match_len)
744{
745 struct cfg80211_action_registration *reg, *nreg;
746 int err = 0;
747
748 nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL);
749 if (!nreg)
750 return -ENOMEM;
751
752 spin_lock_bh(&wdev->action_registrations_lock);
753
754 list_for_each_entry(reg, &wdev->action_registrations, list) {
755 int mlen = min(match_len, reg->match_len);
756
757 if (memcmp(reg->match, match_data, mlen) == 0) {
758 err = -EALREADY;
759 break;
760 }
761 }
762
763 if (err) {
764 kfree(nreg);
765 goto out;
766 }
767
768 memcpy(nreg->match, match_data, match_len);
769 nreg->match_len = match_len;
770 nreg->nlpid = snd_pid;
771 list_add(&nreg->list, &wdev->action_registrations);
772
773 out:
774 spin_unlock_bh(&wdev->action_registrations_lock);
775 return err;
776}
777
778void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid)
779{
780 struct cfg80211_action_registration *reg, *tmp;
781
782 spin_lock_bh(&wdev->action_registrations_lock);
783
784 list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) {
785 if (reg->nlpid == nlpid) {
786 list_del(&reg->list);
787 kfree(reg);
788 }
789 }
790
791 spin_unlock_bh(&wdev->action_registrations_lock);
792}
793
794void cfg80211_mlme_purge_actions(struct wireless_dev *wdev)
795{
796 struct cfg80211_action_registration *reg, *tmp;
797
798 spin_lock_bh(&wdev->action_registrations_lock);
799
800 list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) {
801 list_del(&reg->list);
802 kfree(reg);
803 }
804
805 spin_unlock_bh(&wdev->action_registrations_lock);
806}
807
808int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
809 struct net_device *dev,
810 struct ieee80211_channel *chan,
811 enum nl80211_channel_type channel_type,
812 const u8 *buf, size_t len, u64 *cookie)
813{
814 struct wireless_dev *wdev = dev->ieee80211_ptr;
815 const struct ieee80211_mgmt *mgmt;
816
817 if (rdev->ops->action == NULL)
818 return -EOPNOTSUPP;
819 if (len < 24 + 1)
820 return -EINVAL;
821
822 mgmt = (const struct ieee80211_mgmt *) buf;
823 if (!ieee80211_is_action(mgmt->frame_control))
824 return -EINVAL;
825 if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) {
826 /* Verify that we are associated with the destination AP */
827 if (!wdev->current_bss ||
828 memcmp(wdev->current_bss->pub.bssid, mgmt->bssid,
829 ETH_ALEN) != 0 ||
830 memcmp(wdev->current_bss->pub.bssid, mgmt->da,
831 ETH_ALEN) != 0)
832 return -ENOTCONN;
833 }
834
835 if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0)
836 return -EINVAL;
837
838 /* Transmit the Action frame as requested by user space */
839 return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type,
840 buf, len, cookie);
841}
842
843bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf,
844 size_t len, gfp_t gfp)
845{
846 struct wireless_dev *wdev = dev->ieee80211_ptr;
847 struct wiphy *wiphy = wdev->wiphy;
848 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
849 struct cfg80211_action_registration *reg;
850 const u8 *action_data;
851 int action_data_len;
852 bool result = false;
853
854 /* frame length - min size excluding category */
855 action_data_len = len - (IEEE80211_MIN_ACTION_SIZE - 1);
856
857 /* action data starts with category */
858 action_data = buf + IEEE80211_MIN_ACTION_SIZE - 1;
859
860 spin_lock_bh(&wdev->action_registrations_lock);
861
862 list_for_each_entry(reg, &wdev->action_registrations, list) {
863 if (reg->match_len > action_data_len)
864 continue;
865
866 if (memcmp(reg->match, action_data, reg->match_len))
867 continue;
868
869 /* found match! */
870
871 /* Indicate the received Action frame to user space */
872 if (nl80211_send_action(rdev, dev, reg->nlpid, freq,
873 buf, len, gfp))
874 continue;
875
876 result = true;
877 break;
878 }
879
880 spin_unlock_bh(&wdev->action_registrations_lock);
881
882 return result;
883}
884EXPORT_SYMBOL(cfg80211_rx_action);
885
886void cfg80211_action_tx_status(struct net_device *dev, u64 cookie,
887 const u8 *buf, size_t len, bool ack, gfp_t gfp)
888{
889 struct wireless_dev *wdev = dev->ieee80211_ptr;
890 struct wiphy *wiphy = wdev->wiphy;
891 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
892
893 /* Indicate TX status of the Action frame to user space */
894 nl80211_send_action_tx_status(rdev, dev, cookie, buf, len, ack, gfp);
895}
896EXPORT_SYMBOL(cfg80211_action_tx_status);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index a95ab9e4c19e..328112081358 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * This is the new netlink-based wireless configuration interface. 2 * This is the new netlink-based wireless configuration interface.
3 * 3 *
4 * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net> 4 * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
5 */ 5 */
6 6
7#include <linux/if.h> 7#include <linux/if.h>
@@ -145,6 +145,9 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
145 [NL80211_ATTR_DURATION] = { .type = NLA_U32 }, 145 [NL80211_ATTR_DURATION] = { .type = NLA_U32 },
146 [NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, 146 [NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
147 [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED }, 147 [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
148 [NL80211_ATTR_FRAME] = { .type = NLA_BINARY,
149 .len = IEEE80211_MAX_DATA_LEN },
150 [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, },
148}; 151};
149 152
150/* policy for the attributes */ 153/* policy for the attributes */
@@ -577,6 +580,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
577 CMD(flush_pmksa, FLUSH_PMKSA); 580 CMD(flush_pmksa, FLUSH_PMKSA);
578 CMD(remain_on_channel, REMAIN_ON_CHANNEL); 581 CMD(remain_on_channel, REMAIN_ON_CHANNEL);
579 CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); 582 CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
583 CMD(action, ACTION);
580 if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { 584 if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
581 i++; 585 i++;
582 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); 586 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
@@ -4526,6 +4530,139 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
4526 return err; 4530 return err;
4527} 4531}
4528 4532
4533static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info)
4534{
4535 struct cfg80211_registered_device *rdev;
4536 struct net_device *dev;
4537 int err;
4538
4539 if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
4540 return -EINVAL;
4541
4542 if (nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]) < 1)
4543 return -EINVAL;
4544
4545 rtnl_lock();
4546
4547 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4548 if (err)
4549 goto unlock_rtnl;
4550
4551 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
4552 err = -EOPNOTSUPP;
4553 goto out;
4554 }
4555
4556 /* not much point in registering if we can't reply */
4557 if (!rdev->ops->action) {
4558 err = -EOPNOTSUPP;
4559 goto out;
4560 }
4561
4562 err = cfg80211_mlme_register_action(dev->ieee80211_ptr, info->snd_pid,
4563 nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
4564 nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
4565 out:
4566 cfg80211_unlock_rdev(rdev);
4567 dev_put(dev);
4568 unlock_rtnl:
4569 rtnl_unlock();
4570 return err;
4571}
4572
4573static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
4574{
4575 struct cfg80211_registered_device *rdev;
4576 struct net_device *dev;
4577 struct ieee80211_channel *chan;
4578 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
4579 u32 freq;
4580 int err;
4581 void *hdr;
4582 u64 cookie;
4583 struct sk_buff *msg;
4584
4585 if (!info->attrs[NL80211_ATTR_FRAME] ||
4586 !info->attrs[NL80211_ATTR_WIPHY_FREQ])
4587 return -EINVAL;
4588
4589 rtnl_lock();
4590
4591 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4592 if (err)
4593 goto unlock_rtnl;
4594
4595 if (!rdev->ops->action) {
4596 err = -EOPNOTSUPP;
4597 goto out;
4598 }
4599
4600 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
4601 err = -EOPNOTSUPP;
4602 goto out;
4603 }
4604
4605 if (!netif_running(dev)) {
4606 err = -ENETDOWN;
4607 goto out;
4608 }
4609
4610 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
4611 channel_type = nla_get_u32(
4612 info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
4613 if (channel_type != NL80211_CHAN_NO_HT &&
4614 channel_type != NL80211_CHAN_HT20 &&
4615 channel_type != NL80211_CHAN_HT40PLUS &&
4616 channel_type != NL80211_CHAN_HT40MINUS)
4617 err = -EINVAL;
4618 goto out;
4619 }
4620
4621 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
4622 chan = rdev_freq_to_chan(rdev, freq, channel_type);
4623 if (chan == NULL) {
4624 err = -EINVAL;
4625 goto out;
4626 }
4627
4628 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4629 if (!msg) {
4630 err = -ENOMEM;
4631 goto out;
4632 }
4633
4634 hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
4635 NL80211_CMD_ACTION);
4636
4637 if (IS_ERR(hdr)) {
4638 err = PTR_ERR(hdr);
4639 goto free_msg;
4640 }
4641 err = cfg80211_mlme_action(rdev, dev, chan, channel_type,
4642 nla_data(info->attrs[NL80211_ATTR_FRAME]),
4643 nla_len(info->attrs[NL80211_ATTR_FRAME]),
4644 &cookie);
4645 if (err)
4646 goto free_msg;
4647
4648 NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
4649
4650 genlmsg_end(msg, hdr);
4651 err = genlmsg_reply(msg, info);
4652 goto out;
4653
4654 nla_put_failure:
4655 err = -ENOBUFS;
4656 free_msg:
4657 nlmsg_free(msg);
4658 out:
4659 cfg80211_unlock_rdev(rdev);
4660 dev_put(dev);
4661unlock_rtnl:
4662 rtnl_unlock();
4663 return err;
4664}
4665
4529static struct genl_ops nl80211_ops[] = { 4666static struct genl_ops nl80211_ops[] = {
4530 { 4667 {
4531 .cmd = NL80211_CMD_GET_WIPHY, 4668 .cmd = NL80211_CMD_GET_WIPHY,
@@ -4806,6 +4943,18 @@ static struct genl_ops nl80211_ops[] = {
4806 .policy = nl80211_policy, 4943 .policy = nl80211_policy,
4807 .flags = GENL_ADMIN_PERM, 4944 .flags = GENL_ADMIN_PERM,
4808 }, 4945 },
4946 {
4947 .cmd = NL80211_CMD_REGISTER_ACTION,
4948 .doit = nl80211_register_action,
4949 .policy = nl80211_policy,
4950 .flags = GENL_ADMIN_PERM,
4951 },
4952 {
4953 .cmd = NL80211_CMD_ACTION,
4954 .doit = nl80211_action,
4955 .policy = nl80211_policy,
4956 .flags = GENL_ADMIN_PERM,
4957 },
4809}; 4958};
4810 4959
4811static struct genl_multicast_group nl80211_mlme_mcgrp = { 4960static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -5478,6 +5627,110 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
5478 nl80211_mlme_mcgrp.id, gfp); 5627 nl80211_mlme_mcgrp.id, gfp);
5479} 5628}
5480 5629
5630int nl80211_send_action(struct cfg80211_registered_device *rdev,
5631 struct net_device *netdev, u32 nlpid,
5632 int freq, const u8 *buf, size_t len, gfp_t gfp)
5633{
5634 struct sk_buff *msg;
5635 void *hdr;
5636 int err;
5637
5638 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
5639 if (!msg)
5640 return -ENOMEM;
5641
5642 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION);
5643 if (!hdr) {
5644 nlmsg_free(msg);
5645 return -ENOMEM;
5646 }
5647
5648 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
5649 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
5650 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
5651 NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
5652
5653 err = genlmsg_end(msg, hdr);
5654 if (err < 0) {
5655 nlmsg_free(msg);
5656 return err;
5657 }
5658
5659 err = genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
5660 if (err < 0)
5661 return err;
5662 return 0;
5663
5664 nla_put_failure:
5665 genlmsg_cancel(msg, hdr);
5666 nlmsg_free(msg);
5667 return -ENOBUFS;
5668}
5669
5670void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
5671 struct net_device *netdev, u64 cookie,
5672 const u8 *buf, size_t len, bool ack,
5673 gfp_t gfp)
5674{
5675 struct sk_buff *msg;
5676 void *hdr;
5677
5678 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
5679 if (!msg)
5680 return;
5681
5682 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION_TX_STATUS);
5683 if (!hdr) {
5684 nlmsg_free(msg);
5685 return;
5686 }
5687
5688 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
5689 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
5690 NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
5691 NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
5692 if (ack)
5693 NLA_PUT_FLAG(msg, NL80211_ATTR_ACK);
5694
5695 if (genlmsg_end(msg, hdr) < 0) {
5696 nlmsg_free(msg);
5697 return;
5698 }
5699
5700 genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
5701 return;
5702
5703 nla_put_failure:
5704 genlmsg_cancel(msg, hdr);
5705 nlmsg_free(msg);
5706}
5707
5708static int nl80211_netlink_notify(struct notifier_block * nb,
5709 unsigned long state,
5710 void *_notify)
5711{
5712 struct netlink_notify *notify = _notify;
5713 struct cfg80211_registered_device *rdev;
5714 struct wireless_dev *wdev;
5715
5716 if (state != NETLINK_URELEASE)
5717 return NOTIFY_DONE;
5718
5719 rcu_read_lock();
5720
5721 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list)
5722 list_for_each_entry_rcu(wdev, &rdev->netdev_list, list)
5723 cfg80211_mlme_unregister_actions(wdev, notify->pid);
5724
5725 rcu_read_unlock();
5726
5727 return NOTIFY_DONE;
5728}
5729
5730static struct notifier_block nl80211_netlink_notifier = {
5731 .notifier_call = nl80211_netlink_notify,
5732};
5733
5481/* initialisation/exit functions */ 5734/* initialisation/exit functions */
5482 5735
5483int nl80211_init(void) 5736int nl80211_init(void)
@@ -5511,6 +5764,10 @@ int nl80211_init(void)
5511 goto err_out; 5764 goto err_out;
5512#endif 5765#endif
5513 5766
5767 err = netlink_register_notifier(&nl80211_netlink_notifier);
5768 if (err)
5769 goto err_out;
5770
5514 return 0; 5771 return 0;
5515 err_out: 5772 err_out:
5516 genl_unregister_family(&nl80211_fam); 5773 genl_unregister_family(&nl80211_fam);
@@ -5519,5 +5776,6 @@ int nl80211_init(void)
5519 5776
5520void nl80211_exit(void) 5777void nl80211_exit(void)
5521{ 5778{
5779 netlink_unregister_notifier(&nl80211_netlink_notifier);
5522 genl_unregister_family(&nl80211_fam); 5780 genl_unregister_family(&nl80211_fam);
5523} 5781}
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 14855b8fb430..4ca511102c6c 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -74,4 +74,12 @@ 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,
78 struct net_device *netdev, u32 nlpid, int freq,
79 const u8 *buf, size_t len, gfp_t gfp);
80void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
81 struct net_device *netdev, u64 cookie,
82 const u8 *buf, size_t len, bool ack,
83 gfp_t gfp);
84
77#endif /* __NET_WIRELESS_NL80211_H */ 85#endif /* __NET_WIRELESS_NL80211_H */