aboutsummaryrefslogtreecommitdiffstats
path: root/net
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
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')
-rw-r--r--net/mac80211/cfg.c12
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/iface.c6
-rw-r--r--net/mac80211/main.c37
-rw-r--r--net/mac80211/rx.c137
-rw-r--r--net/mac80211/status.c2
-rw-r--r--net/mac80211/util.c6
-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
13 files changed, 344 insertions, 154 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index f9a317766136..94787d21282c 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1521,11 +1521,11 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
1521 return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); 1521 return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
1522} 1522}
1523 1523
1524static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev, 1524static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
1525 struct ieee80211_channel *chan, 1525 struct ieee80211_channel *chan,
1526 enum nl80211_channel_type channel_type, 1526 enum nl80211_channel_type channel_type,
1527 bool channel_type_valid, 1527 bool channel_type_valid,
1528 const u8 *buf, size_t len, u64 *cookie) 1528 const u8 *buf, size_t len, u64 *cookie)
1529{ 1529{
1530 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 1530 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1531 struct ieee80211_local *local = sdata->local; 1531 struct ieee80211_local *local = sdata->local;
@@ -1625,6 +1625,6 @@ struct cfg80211_ops mac80211_config_ops = {
1625 .set_bitrate_mask = ieee80211_set_bitrate_mask, 1625 .set_bitrate_mask = ieee80211_set_bitrate_mask,
1626 .remain_on_channel = ieee80211_remain_on_channel, 1626 .remain_on_channel = ieee80211_remain_on_channel,
1627 .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, 1627 .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
1628 .action = ieee80211_action, 1628 .mgmt_tx = ieee80211_mgmt_tx,
1629 .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config, 1629 .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
1630}; 1630};
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 1bf05bfd149d..e73ae51dc036 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -170,6 +170,7 @@ typedef unsigned __bitwise__ ieee80211_rx_result;
170#define IEEE80211_RX_RA_MATCH BIT(1) 170#define IEEE80211_RX_RA_MATCH BIT(1)
171#define IEEE80211_RX_AMSDU BIT(2) 171#define IEEE80211_RX_AMSDU BIT(2)
172#define IEEE80211_RX_FRAGMENTED BIT(3) 172#define IEEE80211_RX_FRAGMENTED BIT(3)
173#define IEEE80211_MALFORMED_ACTION_FRM BIT(4)
173/* only add flags here that do not change with subframes of an aMPDU */ 174/* only add flags here that do not change with subframes of an aMPDU */
174 175
175struct ieee80211_rx_data { 176struct ieee80211_rx_data {
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 9459aeee0ddc..86f434f234ae 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -177,7 +177,7 @@ static int ieee80211_open(struct net_device *dev)
177 /* no special treatment */ 177 /* no special treatment */
178 break; 178 break;
179 case NL80211_IFTYPE_UNSPECIFIED: 179 case NL80211_IFTYPE_UNSPECIFIED:
180 case __NL80211_IFTYPE_AFTER_LAST: 180 case NUM_NL80211_IFTYPES:
181 /* cannot happen */ 181 /* cannot happen */
182 WARN_ON(1); 182 WARN_ON(1);
183 break; 183 break;
@@ -634,7 +634,7 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
634 case NL80211_IFTYPE_MONITOR: 634 case NL80211_IFTYPE_MONITOR:
635 break; 635 break;
636 case NL80211_IFTYPE_UNSPECIFIED: 636 case NL80211_IFTYPE_UNSPECIFIED:
637 case __NL80211_IFTYPE_AFTER_LAST: 637 case NUM_NL80211_IFTYPES:
638 BUG(); 638 BUG();
639 break; 639 break;
640 } 640 }
@@ -886,7 +886,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
886 case NL80211_IFTYPE_AP_VLAN: 886 case NL80211_IFTYPE_AP_VLAN:
887 break; 887 break;
888 case NL80211_IFTYPE_UNSPECIFIED: 888 case NL80211_IFTYPE_UNSPECIFIED:
889 case __NL80211_IFTYPE_AFTER_LAST: 889 case NUM_NL80211_IFTYPES:
890 BUG(); 890 BUG();
891 break; 891 break;
892 } 892 }
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 0afccda42a24..a53feac4618c 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -417,6 +417,41 @@ void ieee80211_napi_complete(struct ieee80211_hw *hw)
417} 417}
418EXPORT_SYMBOL(ieee80211_napi_complete); 418EXPORT_SYMBOL(ieee80211_napi_complete);
419 419
420/* There isn't a lot of sense in it, but you can transmit anything you like */
421static const struct ieee80211_txrx_stypes
422ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
423 [NL80211_IFTYPE_ADHOC] = {
424 .tx = 0xffff,
425 .rx = BIT(IEEE80211_STYPE_ACTION >> 4),
426 },
427 [NL80211_IFTYPE_STATION] = {
428 .tx = 0xffff,
429 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
430 BIT(IEEE80211_STYPE_PROBE_REQ >> 4),
431 },
432 [NL80211_IFTYPE_AP] = {
433 .tx = 0xffff,
434 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
435 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
436 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
437 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
438 BIT(IEEE80211_STYPE_AUTH >> 4) |
439 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
440 BIT(IEEE80211_STYPE_ACTION >> 4),
441 },
442 [NL80211_IFTYPE_AP_VLAN] = {
443 /* copy AP */
444 .tx = 0xffff,
445 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
446 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
447 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
448 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
449 BIT(IEEE80211_STYPE_AUTH >> 4) |
450 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
451 BIT(IEEE80211_STYPE_ACTION >> 4),
452 },
453};
454
420struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, 455struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
421 const struct ieee80211_ops *ops) 456 const struct ieee80211_ops *ops)
422{ 457{
@@ -446,6 +481,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
446 if (!wiphy) 481 if (!wiphy)
447 return NULL; 482 return NULL;
448 483
484 wiphy->mgmt_stypes = ieee80211_default_mgmt_stypes;
485
449 wiphy->flags |= WIPHY_FLAG_NETNS_OK | 486 wiphy->flags |= WIPHY_FLAG_NETNS_OK |
450 WIPHY_FLAG_4ADDR_AP | 487 WIPHY_FLAG_4ADDR_AP |
451 WIPHY_FLAG_4ADDR_STATION; 488 WIPHY_FLAG_4ADDR_STATION;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 4fdbed58ca2f..aa41e382bbb3 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1940,13 +1940,36 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
1940} 1940}
1941 1941
1942static ieee80211_rx_result debug_noinline 1942static ieee80211_rx_result debug_noinline
1943ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
1944{
1945 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
1946
1947 /*
1948 * From here on, look only at management frames.
1949 * Data and control frames are already handled,
1950 * and unknown (reserved) frames are useless.
1951 */
1952 if (rx->skb->len < 24)
1953 return RX_DROP_MONITOR;
1954
1955 if (!ieee80211_is_mgmt(mgmt->frame_control))
1956 return RX_DROP_MONITOR;
1957
1958 if (!(rx->flags & IEEE80211_RX_RA_MATCH))
1959 return RX_DROP_MONITOR;
1960
1961 if (ieee80211_drop_unencrypted_mgmt(rx))
1962 return RX_DROP_UNUSABLE;
1963
1964 return RX_CONTINUE;
1965}
1966
1967static ieee80211_rx_result debug_noinline
1943ieee80211_rx_h_action(struct ieee80211_rx_data *rx) 1968ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
1944{ 1969{
1945 struct ieee80211_local *local = rx->local; 1970 struct ieee80211_local *local = rx->local;
1946 struct ieee80211_sub_if_data *sdata = rx->sdata; 1971 struct ieee80211_sub_if_data *sdata = rx->sdata;
1947 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; 1972 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
1948 struct sk_buff *nskb;
1949 struct ieee80211_rx_status *status;
1950 int len = rx->skb->len; 1973 int len = rx->skb->len;
1951 1974
1952 if (!ieee80211_is_action(mgmt->frame_control)) 1975 if (!ieee80211_is_action(mgmt->frame_control))
@@ -1962,9 +1985,6 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
1962 if (!(rx->flags & IEEE80211_RX_RA_MATCH)) 1985 if (!(rx->flags & IEEE80211_RX_RA_MATCH))
1963 return RX_DROP_UNUSABLE; 1986 return RX_DROP_UNUSABLE;
1964 1987
1965 if (ieee80211_drop_unencrypted_mgmt(rx))
1966 return RX_DROP_UNUSABLE;
1967
1968 switch (mgmt->u.action.category) { 1988 switch (mgmt->u.action.category) {
1969 case WLAN_CATEGORY_BACK: 1989 case WLAN_CATEGORY_BACK:
1970 /* 1990 /*
@@ -2055,17 +2075,36 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
2055 goto queue; 2075 goto queue;
2056 } 2076 }
2057 2077
2078 return RX_CONTINUE;
2079
2058 invalid: 2080 invalid:
2059 /* 2081 rx->flags |= IEEE80211_MALFORMED_ACTION_FRM;
2060 * For AP mode, hostapd is responsible for handling any action 2082 /* will return in the next handlers */
2061 * frames that we didn't handle, including returning unknown 2083 return RX_CONTINUE;
2062 * ones. For all other modes we will return them to the sender, 2084
2063 * setting the 0x80 bit in the action category, as required by 2085 handled:
2064 * 802.11-2007 7.3.1.11. 2086 if (rx->sta)
2065 */ 2087 rx->sta->rx_packets++;
2066 if (sdata->vif.type == NL80211_IFTYPE_AP || 2088 dev_kfree_skb(rx->skb);
2067 sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 2089 return RX_QUEUED;
2068 return RX_DROP_MONITOR; 2090
2091 queue:
2092 rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
2093 skb_queue_tail(&sdata->skb_queue, rx->skb);
2094 ieee80211_queue_work(&local->hw, &sdata->work);
2095 if (rx->sta)
2096 rx->sta->rx_packets++;
2097 return RX_QUEUED;
2098}
2099
2100static ieee80211_rx_result debug_noinline
2101ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
2102{
2103 struct ieee80211_rx_status *status;
2104
2105 /* skip known-bad action frames and return them in the next handler */
2106 if (rx->flags & IEEE80211_MALFORMED_ACTION_FRM)
2107 return RX_CONTINUE;
2069 2108
2070 /* 2109 /*
2071 * Getting here means the kernel doesn't know how to handle 2110 * Getting here means the kernel doesn't know how to handle
@@ -2075,10 +2114,44 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
2075 */ 2114 */
2076 status = IEEE80211_SKB_RXCB(rx->skb); 2115 status = IEEE80211_SKB_RXCB(rx->skb);
2077 2116
2078 if (cfg80211_rx_action(rx->sdata->dev, status->freq, 2117 if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq,
2079 rx->skb->data, rx->skb->len, 2118 rx->skb->data, rx->skb->len,
2080 GFP_ATOMIC)) 2119 GFP_ATOMIC)) {
2081 goto handled; 2120 if (rx->sta)
2121 rx->sta->rx_packets++;
2122 dev_kfree_skb(rx->skb);
2123 return RX_QUEUED;
2124 }
2125
2126
2127 return RX_CONTINUE;
2128}
2129
2130static ieee80211_rx_result debug_noinline
2131ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
2132{
2133 struct ieee80211_local *local = rx->local;
2134 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
2135 struct sk_buff *nskb;
2136 struct ieee80211_sub_if_data *sdata = rx->sdata;
2137
2138 if (!ieee80211_is_action(mgmt->frame_control))
2139 return RX_CONTINUE;
2140
2141 /*
2142 * For AP mode, hostapd is responsible for handling any action
2143 * frames that we didn't handle, including returning unknown
2144 * ones. For all other modes we will return them to the sender,
2145 * setting the 0x80 bit in the action category, as required by
2146 * 802.11-2007 7.3.1.11.
2147 * Newer versions of hostapd shall also use the management frame
2148 * registration mechanisms, but older ones still use cooked
2149 * monitor interfaces so push all frames there.
2150 */
2151 if (!(rx->flags & IEEE80211_MALFORMED_ACTION_FRM) &&
2152 (sdata->vif.type == NL80211_IFTYPE_AP ||
2153 sdata->vif.type == NL80211_IFTYPE_AP_VLAN))
2154 return RX_DROP_MONITOR;
2082 2155
2083 /* do not return rejected action frames */ 2156 /* do not return rejected action frames */
2084 if (mgmt->u.action.category & 0x80) 2157 if (mgmt->u.action.category & 0x80)
@@ -2097,20 +2170,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
2097 2170
2098 ieee80211_tx_skb(rx->sdata, nskb); 2171 ieee80211_tx_skb(rx->sdata, nskb);
2099 } 2172 }
2100
2101 handled:
2102 if (rx->sta)
2103 rx->sta->rx_packets++;
2104 dev_kfree_skb(rx->skb); 2173 dev_kfree_skb(rx->skb);
2105 return RX_QUEUED; 2174 return RX_QUEUED;
2106
2107 queue:
2108 rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TYPE_FRAME;
2109 skb_queue_tail(&sdata->skb_queue, rx->skb);
2110 ieee80211_queue_work(&local->hw, &sdata->work);
2111 if (rx->sta)
2112 rx->sta->rx_packets++;
2113 return RX_QUEUED;
2114} 2175}
2115 2176
2116static ieee80211_rx_result debug_noinline 2177static ieee80211_rx_result debug_noinline
@@ -2121,15 +2182,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
2121 struct ieee80211_mgmt *mgmt = (void *)rx->skb->data; 2182 struct ieee80211_mgmt *mgmt = (void *)rx->skb->data;
2122 __le16 stype; 2183 __le16 stype;
2123 2184
2124 if (!(rx->flags & IEEE80211_RX_RA_MATCH))
2125 return RX_DROP_MONITOR;
2126
2127 if (rx->skb->len < 24)
2128 return RX_DROP_MONITOR;
2129
2130 if (ieee80211_drop_unencrypted_mgmt(rx))
2131 return RX_DROP_UNUSABLE;
2132
2133 rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb); 2185 rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb);
2134 if (rxs != RX_CONTINUE) 2186 if (rxs != RX_CONTINUE)
2135 return rxs; 2187 return rxs;
@@ -2374,7 +2426,10 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx,
2374 if (res != RX_CONTINUE) 2426 if (res != RX_CONTINUE)
2375 goto rxh_next; 2427 goto rxh_next;
2376 2428
2429 CALL_RXH(ieee80211_rx_h_mgmt_check)
2377 CALL_RXH(ieee80211_rx_h_action) 2430 CALL_RXH(ieee80211_rx_h_action)
2431 CALL_RXH(ieee80211_rx_h_userspace_mgmt)
2432 CALL_RXH(ieee80211_rx_h_action_return)
2378 CALL_RXH(ieee80211_rx_h_mgmt) 2433 CALL_RXH(ieee80211_rx_h_mgmt)
2379 2434
2380 rxh_next: 2435 rxh_next:
@@ -2527,7 +2582,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
2527 break; 2582 break;
2528 case NL80211_IFTYPE_MONITOR: 2583 case NL80211_IFTYPE_MONITOR:
2529 case NL80211_IFTYPE_UNSPECIFIED: 2584 case NL80211_IFTYPE_UNSPECIFIED:
2530 case __NL80211_IFTYPE_AFTER_LAST: 2585 case NUM_NL80211_IFTYPES:
2531 /* should never get here */ 2586 /* should never get here */
2532 WARN_ON(1); 2587 WARN_ON(1);
2533 break; 2588 break;
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 10caec5ea8fa..67a35841bef0 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -296,7 +296,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
296 } 296 }
297 297
298 if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) 298 if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX)
299 cfg80211_action_tx_status( 299 cfg80211_mgmt_tx_status(
300 skb->dev, (unsigned long) skb, skb->data, skb->len, 300 skb->dev, (unsigned long) skb, skb->data, skb->len,
301 !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC); 301 !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC);
302 302
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 748387d45bc0..cd2b485fed4f 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -471,7 +471,7 @@ void ieee80211_iterate_active_interfaces(
471 471
472 list_for_each_entry(sdata, &local->interfaces, list) { 472 list_for_each_entry(sdata, &local->interfaces, list) {
473 switch (sdata->vif.type) { 473 switch (sdata->vif.type) {
474 case __NL80211_IFTYPE_AFTER_LAST: 474 case NUM_NL80211_IFTYPES:
475 case NL80211_IFTYPE_UNSPECIFIED: 475 case NL80211_IFTYPE_UNSPECIFIED:
476 case NL80211_IFTYPE_MONITOR: 476 case NL80211_IFTYPE_MONITOR:
477 case NL80211_IFTYPE_AP_VLAN: 477 case NL80211_IFTYPE_AP_VLAN:
@@ -505,7 +505,7 @@ void ieee80211_iterate_active_interfaces_atomic(
505 505
506 list_for_each_entry_rcu(sdata, &local->interfaces, list) { 506 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
507 switch (sdata->vif.type) { 507 switch (sdata->vif.type) {
508 case __NL80211_IFTYPE_AFTER_LAST: 508 case NUM_NL80211_IFTYPES:
509 case NL80211_IFTYPE_UNSPECIFIED: 509 case NL80211_IFTYPE_UNSPECIFIED:
510 case NL80211_IFTYPE_MONITOR: 510 case NL80211_IFTYPE_MONITOR:
511 case NL80211_IFTYPE_AP_VLAN: 511 case NL80211_IFTYPE_AP_VLAN:
@@ -1189,7 +1189,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1189 /* ignore virtual */ 1189 /* ignore virtual */
1190 break; 1190 break;
1191 case NL80211_IFTYPE_UNSPECIFIED: 1191 case NL80211_IFTYPE_UNSPECIFIED:
1192 case __NL80211_IFTYPE_AFTER_LAST: 1192 case NUM_NL80211_IFTYPES:
1193 WARN_ON(1); 1193 WARN_ON(1);
1194 break; 1194 break;
1195 } 1195 }
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 }