aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2010-02-26 02:26:21 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-26 02:26:21 -0500
commit19bc291c99f018bd4f2c38bbf69144086dca903f (patch)
tree9d3cf9bc0c5a78e363dc0547da8bcd1e7c394265 /net
parent04488734806948624dabc4514f96f14cd75b9a50 (diff)
parent4a6967b88af02eebeedfbb91bc09160750225bb5 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Conflicts: drivers/net/wireless/iwlwifi/iwl-core.h drivers/net/wireless/rt2x00/rt2800pci.c
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/cfg.c12
-rw-r--r--net/mac80211/ieee80211_i.h6
-rw-r--r--net/mac80211/iface.c2
-rw-r--r--net/mac80211/mlme.c35
-rw-r--r--net/mac80211/rx.c140
-rw-r--r--net/mac80211/status.c7
-rw-r--r--net/wireless/core.c20
-rw-r--r--net/wireless/core.h9
-rw-r--r--net/wireless/mlme.c166
-rw-r--r--net/wireless/nl80211.c440
-rw-r--r--net/wireless/nl80211.h8
-rw-r--r--net/wireless/wext-compat.c10
12 files changed, 761 insertions, 94 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/iface.c b/net/mac80211/iface.c
index 09fff4662e80..0793d7a8d743 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1031,7 +1031,7 @@ static int netdev_notify(struct notifier_block *nb,
1031 1031
1032 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 1032 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1033 1033
1034 memcpy(sdata->name, sdata->name, IFNAMSIZ); 1034 memcpy(sdata->name, dev->name, IFNAMSIZ);
1035 1035
1036 ieee80211_debugfs_rename_netdev(sdata); 1036 ieee80211_debugfs_rename_netdev(sdata);
1037 return 0; 1037 return 0;
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 c9755f3d986c..b5c48de81d8b 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.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 2007 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
@@ -1397,6 +1397,21 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
1397 ieee80211_is_data(fc) && 1397 ieee80211_is_data(fc) &&
1398 (rx->key || rx->sdata->drop_unencrypted))) 1398 (rx->key || rx->sdata->drop_unencrypted)))
1399 return -EACCES; 1399 return -EACCES;
1400
1401 return 0;
1402}
1403
1404static int
1405ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
1406{
1407 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
1408 __le16 fc = hdr->frame_control;
1409 int res;
1410
1411 res = ieee80211_drop_unencrypted(rx, fc);
1412 if (unlikely(res))
1413 return res;
1414
1400 if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) { 1415 if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) {
1401 if (unlikely(ieee80211_is_unicast_robust_mgmt_frame(rx->skb) && 1416 if (unlikely(ieee80211_is_unicast_robust_mgmt_frame(rx->skb) &&
1402 rx->key)) 1417 rx->key))
@@ -1855,23 +1870,25 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
1855 struct ieee80211_local *local = rx->local; 1870 struct ieee80211_local *local = rx->local;
1856 struct ieee80211_sub_if_data *sdata = rx->sdata; 1871 struct ieee80211_sub_if_data *sdata = rx->sdata;
1857 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; 1872 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
1873 struct sk_buff *nskb;
1874 struct ieee80211_rx_status *status;
1858 int len = rx->skb->len; 1875 int len = rx->skb->len;
1859 1876
1860 if (!ieee80211_is_action(mgmt->frame_control)) 1877 if (!ieee80211_is_action(mgmt->frame_control))
1861 return RX_CONTINUE; 1878 return RX_CONTINUE;
1862 1879
1863 if (!rx->sta) 1880 /* drop too small frames */
1864 return RX_DROP_MONITOR; 1881 if (len < IEEE80211_MIN_ACTION_SIZE)
1882 return RX_DROP_UNUSABLE;
1865 1883
1866 if (!(rx->flags & IEEE80211_RX_RA_MATCH)) 1884 if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC)
1867 return RX_DROP_MONITOR; 1885 return RX_DROP_UNUSABLE;
1868 1886
1869 if (ieee80211_drop_unencrypted(rx, mgmt->frame_control)) 1887 if (!(rx->flags & IEEE80211_RX_RA_MATCH))
1870 return RX_DROP_MONITOR; 1888 return RX_DROP_UNUSABLE;
1871 1889
1872 /* all categories we currently handle have action_code */ 1890 if (ieee80211_drop_unencrypted_mgmt(rx))
1873 if (len < IEEE80211_MIN_ACTION_SIZE + 1) 1891 return RX_DROP_UNUSABLE;
1874 return RX_DROP_MONITOR;
1875 1892
1876 switch (mgmt->u.action.category) { 1893 switch (mgmt->u.action.category) {
1877 case WLAN_CATEGORY_BACK: 1894 case WLAN_CATEGORY_BACK:
@@ -1884,7 +1901,11 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
1884 if (sdata->vif.type != NL80211_IFTYPE_STATION && 1901 if (sdata->vif.type != NL80211_IFTYPE_STATION &&
1885 sdata->vif.type != NL80211_IFTYPE_AP_VLAN && 1902 sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
1886 sdata->vif.type != NL80211_IFTYPE_AP) 1903 sdata->vif.type != NL80211_IFTYPE_AP)
1887 return RX_DROP_MONITOR; 1904 break;
1905
1906 /* verify action_code is present */
1907 if (len < IEEE80211_MIN_ACTION_SIZE + 1)
1908 break;
1888 1909
1889 switch (mgmt->u.action.u.addba_req.action_code) { 1910 switch (mgmt->u.action.u.addba_req.action_code) {
1890 case WLAN_ACTION_ADDBA_REQ: 1911 case WLAN_ACTION_ADDBA_REQ:
@@ -1892,45 +1913,49 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
1892 sizeof(mgmt->u.action.u.addba_req))) 1913 sizeof(mgmt->u.action.u.addba_req)))
1893 return RX_DROP_MONITOR; 1914 return RX_DROP_MONITOR;
1894 ieee80211_process_addba_request(local, rx->sta, mgmt, len); 1915 ieee80211_process_addba_request(local, rx->sta, mgmt, len);
1895 break; 1916 goto handled;
1896 case WLAN_ACTION_ADDBA_RESP: 1917 case WLAN_ACTION_ADDBA_RESP:
1897 if (len < (IEEE80211_MIN_ACTION_SIZE + 1918 if (len < (IEEE80211_MIN_ACTION_SIZE +
1898 sizeof(mgmt->u.action.u.addba_resp))) 1919 sizeof(mgmt->u.action.u.addba_resp)))
1899 return RX_DROP_MONITOR; 1920 break;
1900 ieee80211_process_addba_resp(local, rx->sta, mgmt, len); 1921 ieee80211_process_addba_resp(local, rx->sta, mgmt, len);
1901 break; 1922 goto handled;
1902 case WLAN_ACTION_DELBA: 1923 case WLAN_ACTION_DELBA:
1903 if (len < (IEEE80211_MIN_ACTION_SIZE + 1924 if (len < (IEEE80211_MIN_ACTION_SIZE +
1904 sizeof(mgmt->u.action.u.delba))) 1925 sizeof(mgmt->u.action.u.delba)))
1905 return RX_DROP_MONITOR; 1926 break;
1906 ieee80211_process_delba(sdata, rx->sta, mgmt, len); 1927 ieee80211_process_delba(sdata, rx->sta, mgmt, len);
1907 break; 1928 goto handled;
1908 } 1929 }
1909 break; 1930 break;
1910 case WLAN_CATEGORY_SPECTRUM_MGMT: 1931 case WLAN_CATEGORY_SPECTRUM_MGMT:
1911 if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ) 1932 if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
1912 return RX_DROP_MONITOR; 1933 break;
1913 1934
1914 if (sdata->vif.type != NL80211_IFTYPE_STATION) 1935 if (sdata->vif.type != NL80211_IFTYPE_STATION)
1915 return RX_DROP_MONITOR; 1936 break;
1937
1938 /* verify action_code is present */
1939 if (len < IEEE80211_MIN_ACTION_SIZE + 1)
1940 break;
1916 1941
1917 switch (mgmt->u.action.u.measurement.action_code) { 1942 switch (mgmt->u.action.u.measurement.action_code) {
1918 case WLAN_ACTION_SPCT_MSR_REQ: 1943 case WLAN_ACTION_SPCT_MSR_REQ:
1919 if (len < (IEEE80211_MIN_ACTION_SIZE + 1944 if (len < (IEEE80211_MIN_ACTION_SIZE +
1920 sizeof(mgmt->u.action.u.measurement))) 1945 sizeof(mgmt->u.action.u.measurement)))
1921 return RX_DROP_MONITOR; 1946 break;
1922 ieee80211_process_measurement_req(sdata, mgmt, len); 1947 ieee80211_process_measurement_req(sdata, mgmt, len);
1923 break; 1948 goto handled;
1924 case WLAN_ACTION_SPCT_CHL_SWITCH: 1949 case WLAN_ACTION_SPCT_CHL_SWITCH:
1925 if (len < (IEEE80211_MIN_ACTION_SIZE + 1950 if (len < (IEEE80211_MIN_ACTION_SIZE +
1926 sizeof(mgmt->u.action.u.chan_switch))) 1951 sizeof(mgmt->u.action.u.chan_switch)))
1927 return RX_DROP_MONITOR; 1952 break;
1928 1953
1929 if (sdata->vif.type != NL80211_IFTYPE_STATION) 1954 if (sdata->vif.type != NL80211_IFTYPE_STATION)
1930 return RX_DROP_MONITOR; 1955 break;
1931 1956
1932 if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN)) 1957 if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN))
1933 return RX_DROP_MONITOR; 1958 break;
1934 1959
1935 return ieee80211_sta_rx_mgmt(sdata, rx->skb); 1960 return ieee80211_sta_rx_mgmt(sdata, rx->skb);
1936 } 1961 }
@@ -1938,30 +1963,64 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
1938 case WLAN_CATEGORY_SA_QUERY: 1963 case WLAN_CATEGORY_SA_QUERY:
1939 if (len < (IEEE80211_MIN_ACTION_SIZE + 1964 if (len < (IEEE80211_MIN_ACTION_SIZE +
1940 sizeof(mgmt->u.action.u.sa_query))) 1965 sizeof(mgmt->u.action.u.sa_query)))
1941 return RX_DROP_MONITOR; 1966 break;
1967
1942 switch (mgmt->u.action.u.sa_query.action) { 1968 switch (mgmt->u.action.u.sa_query.action) {
1943 case WLAN_ACTION_SA_QUERY_REQUEST: 1969 case WLAN_ACTION_SA_QUERY_REQUEST:
1944 if (sdata->vif.type != NL80211_IFTYPE_STATION) 1970 if (sdata->vif.type != NL80211_IFTYPE_STATION)
1945 return RX_DROP_MONITOR; 1971 break;
1946 ieee80211_process_sa_query_req(sdata, mgmt, len); 1972 ieee80211_process_sa_query_req(sdata, mgmt, len);
1947 break; 1973 goto handled;
1948 case WLAN_ACTION_SA_QUERY_RESPONSE:
1949 /*
1950 * SA Query response is currently only used in AP mode
1951 * and it is processed in user space.
1952 */
1953 return RX_CONTINUE;
1954 } 1974 }
1955 break; 1975 break;
1956 default: 1976 }
1957 /* do not process rejected action frames */
1958 if (mgmt->u.action.category & 0x80)
1959 return RX_DROP_MONITOR;
1960 1977
1961 return RX_CONTINUE; 1978 /*
1979 * For AP mode, hostapd is responsible for handling any action
1980 * frames that we didn't handle, including returning unknown
1981 * ones. For all other modes we will return them to the sender,
1982 * setting the 0x80 bit in the action category, as required by
1983 * 802.11-2007 7.3.1.11.
1984 */
1985 if (sdata->vif.type == NL80211_IFTYPE_AP ||
1986 sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
1987 return RX_DROP_MONITOR;
1988
1989 /*
1990 * Getting here means the kernel doesn't know how to handle
1991 * it, but maybe userspace does ... include returned frames
1992 * so userspace can register for those to know whether ones
1993 * it transmitted were processed or returned.
1994 */
1995 status = IEEE80211_SKB_RXCB(rx->skb);
1996
1997 if (sdata->vif.type == NL80211_IFTYPE_STATION &&
1998 cfg80211_rx_action(rx->sdata->dev, status->freq,
1999 rx->skb->data, rx->skb->len,
2000 GFP_ATOMIC))
2001 goto handled;
2002
2003 /* do not return rejected action frames */
2004 if (mgmt->u.action.category & 0x80)
2005 return RX_DROP_UNUSABLE;
2006
2007 nskb = skb_copy_expand(rx->skb, local->hw.extra_tx_headroom, 0,
2008 GFP_ATOMIC);
2009 if (nskb) {
2010 struct ieee80211_mgmt *mgmt = (void *)nskb->data;
2011
2012 mgmt->u.action.category |= 0x80;
2013 memcpy(mgmt->da, mgmt->sa, ETH_ALEN);
2014 memcpy(mgmt->sa, rx->sdata->vif.addr, ETH_ALEN);
2015
2016 memset(nskb->cb, 0, sizeof(nskb->cb));
2017
2018 ieee80211_tx_skb(rx->sdata, nskb);
1962 } 2019 }
1963 2020
1964 rx->sta->rx_packets++; 2021 handled:
2022 if (rx->sta)
2023 rx->sta->rx_packets++;
1965 dev_kfree_skb(rx->skb); 2024 dev_kfree_skb(rx->skb);
1966 return RX_QUEUED; 2025 return RX_QUEUED;
1967} 2026}
@@ -1970,14 +2029,13 @@ static ieee80211_rx_result debug_noinline
1970ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) 2029ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
1971{ 2030{
1972 struct ieee80211_sub_if_data *sdata = rx->sdata; 2031 struct ieee80211_sub_if_data *sdata = rx->sdata;
1973 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
1974 ieee80211_rx_result rxs; 2032 ieee80211_rx_result rxs;
1975 2033
1976 if (!(rx->flags & IEEE80211_RX_RA_MATCH)) 2034 if (!(rx->flags & IEEE80211_RX_RA_MATCH))
1977 return RX_DROP_MONITOR; 2035 return RX_DROP_MONITOR;
1978 2036
1979 if (ieee80211_drop_unencrypted(rx, mgmt->frame_control)) 2037 if (ieee80211_drop_unencrypted_mgmt(rx))
1980 return RX_DROP_MONITOR; 2038 return RX_DROP_UNUSABLE;
1981 2039
1982 rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb); 2040 rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb);
1983 if (rxs != RX_CONTINUE) 2041 if (rxs != RX_CONTINUE)
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..7fdb9409ad2a 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++;
@@ -695,19 +698,21 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
695 wdev->wext.default_key = -1; 698 wdev->wext.default_key = -1;
696 wdev->wext.default_mgmt_key = -1; 699 wdev->wext.default_mgmt_key = -1;
697 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; 700 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
701#endif
702
698 if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT) 703 if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT)
699 wdev->wext.ps = true; 704 wdev->ps = true;
700 else 705 else
701 wdev->wext.ps = false; 706 wdev->ps = false;
702 wdev->wext.ps_timeout = 100; 707 wdev->ps_timeout = 100;
703 if (rdev->ops->set_power_mgmt) 708 if (rdev->ops->set_power_mgmt)
704 if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, 709 if (rdev->ops->set_power_mgmt(wdev->wiphy, dev,
705 wdev->wext.ps, 710 wdev->ps,
706 wdev->wext.ps_timeout)) { 711 wdev->ps_timeout)) {
707 /* assume this means it's off */ 712 /* assume this means it's off */
708 wdev->wext.ps = false; 713 wdev->ps = false;
709 } 714 }
710#endif 715
711 if (!dev->ethtool_ops) 716 if (!dev->ethtool_ops)
712 dev->ethtool_ops = &cfg80211_ethtool_ops; 717 dev->ethtool_ops = &cfg80211_ethtool_ops;
713 718
@@ -792,6 +797,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
792 sysfs_remove_link(&dev->dev.kobj, "phy80211"); 797 sysfs_remove_link(&dev->dev.kobj, "phy80211");
793 list_del_rcu(&wdev->list); 798 list_del_rcu(&wdev->list);
794 rdev->devlist_generation++; 799 rdev->devlist_generation++;
800 cfg80211_mlme_purge_actions(wdev);
795#ifdef CONFIG_CFG80211_WEXT 801#ifdef CONFIG_CFG80211_WEXT
796 kfree(wdev->wext.keys); 802 kfree(wdev->wext.keys);
797#endif 803#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 a001ea32cb7d..e447db04cf76 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,10 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
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, },
151 [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 },
148}; 152};
149 153
150/* policy for the attributes */ 154/* policy for the attributes */
@@ -576,6 +580,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
576 CMD(flush_pmksa, FLUSH_PMKSA); 580 CMD(flush_pmksa, FLUSH_PMKSA);
577 CMD(remain_on_channel, REMAIN_ON_CHANNEL); 581 CMD(remain_on_channel, REMAIN_ON_CHANNEL);
578 CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); 582 CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
583 CMD(action, ACTION);
579 if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { 584 if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
580 i++; 585 i++;
581 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); 586 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
@@ -2009,6 +2014,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
2009 if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) 2014 if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
2010 return -EINVAL; 2015 return -EINVAL;
2011 2016
2017 if (!info->attrs[NL80211_ATTR_STA_AID])
2018 return -EINVAL;
2019
2012 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 2020 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
2013 params.supported_rates = 2021 params.supported_rates =
2014 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); 2022 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
@@ -2017,11 +2025,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
2017 params.listen_interval = 2025 params.listen_interval =
2018 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); 2026 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
2019 2027
2020 if (info->attrs[NL80211_ATTR_STA_AID]) { 2028 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
2021 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); 2029 if (!params.aid || params.aid > IEEE80211_MAX_AID)
2022 if (!params.aid || params.aid > IEEE80211_MAX_AID) 2030 return -EINVAL;
2023 return -EINVAL;
2024 }
2025 2031
2026 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) 2032 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
2027 params.ht_capa = 2033 params.ht_capa =
@@ -2036,6 +2042,12 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
2036 if (err) 2042 if (err)
2037 goto out_rtnl; 2043 goto out_rtnl;
2038 2044
2045 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
2046 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) {
2047 err = -EINVAL;
2048 goto out;
2049 }
2050
2039 err = get_vlan(info, rdev, &params.vlan); 2051 err = get_vlan(info, rdev, &params.vlan);
2040 if (err) 2052 if (err)
2041 goto out; 2053 goto out;
@@ -2043,35 +2055,6 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
2043 /* validate settings */ 2055 /* validate settings */
2044 err = 0; 2056 err = 0;
2045 2057
2046 switch (dev->ieee80211_ptr->iftype) {
2047 case NL80211_IFTYPE_AP:
2048 case NL80211_IFTYPE_AP_VLAN:
2049 /* all ok but must have AID */
2050 if (!params.aid)
2051 err = -EINVAL;
2052 break;
2053 case NL80211_IFTYPE_MESH_POINT:
2054 /* disallow things mesh doesn't support */
2055 if (params.vlan)
2056 err = -EINVAL;
2057 if (params.aid)
2058 err = -EINVAL;
2059 if (params.ht_capa)
2060 err = -EINVAL;
2061 if (params.listen_interval >= 0)
2062 err = -EINVAL;
2063 if (params.supported_rates)
2064 err = -EINVAL;
2065 if (params.sta_flags_mask)
2066 err = -EINVAL;
2067 break;
2068 default:
2069 err = -EINVAL;
2070 }
2071
2072 if (err)
2073 goto out;
2074
2075 if (!rdev->ops->add_station) { 2058 if (!rdev->ops->add_station) {
2076 err = -EOPNOTSUPP; 2059 err = -EOPNOTSUPP;
2077 goto out; 2060 goto out;
@@ -2112,8 +2095,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
2112 goto out_rtnl; 2095 goto out_rtnl;
2113 2096
2114 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && 2097 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
2115 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && 2098 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) {
2116 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
2117 err = -EINVAL; 2099 err = -EINVAL;
2118 goto out; 2100 goto out;
2119 } 2101 }
@@ -4545,6 +4527,257 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
4545 return err; 4527 return err;
4546} 4528}
4547 4529
4530static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info)
4531{
4532 struct cfg80211_registered_device *rdev;
4533 struct net_device *dev;
4534 int err;
4535
4536 if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
4537 return -EINVAL;
4538
4539 if (nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]) < 1)
4540 return -EINVAL;
4541
4542 rtnl_lock();
4543
4544 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4545 if (err)
4546 goto unlock_rtnl;
4547
4548 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
4549 err = -EOPNOTSUPP;
4550 goto out;
4551 }
4552
4553 /* not much point in registering if we can't reply */
4554 if (!rdev->ops->action) {
4555 err = -EOPNOTSUPP;
4556 goto out;
4557 }
4558
4559 err = cfg80211_mlme_register_action(dev->ieee80211_ptr, info->snd_pid,
4560 nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
4561 nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
4562 out:
4563 cfg80211_unlock_rdev(rdev);
4564 dev_put(dev);
4565 unlock_rtnl:
4566 rtnl_unlock();
4567 return err;
4568}
4569
4570static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
4571{
4572 struct cfg80211_registered_device *rdev;
4573 struct net_device *dev;
4574 struct ieee80211_channel *chan;
4575 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
4576 u32 freq;
4577 int err;
4578 void *hdr;
4579 u64 cookie;
4580 struct sk_buff *msg;
4581
4582 if (!info->attrs[NL80211_ATTR_FRAME] ||
4583 !info->attrs[NL80211_ATTR_WIPHY_FREQ])
4584 return -EINVAL;
4585
4586 rtnl_lock();
4587
4588 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4589 if (err)
4590 goto unlock_rtnl;
4591
4592 if (!rdev->ops->action) {
4593 err = -EOPNOTSUPP;
4594 goto out;
4595 }
4596
4597 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
4598 err = -EOPNOTSUPP;
4599 goto out;
4600 }
4601
4602 if (!netif_running(dev)) {
4603 err = -ENETDOWN;
4604 goto out;
4605 }
4606
4607 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
4608 channel_type = nla_get_u32(
4609 info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
4610 if (channel_type != NL80211_CHAN_NO_HT &&
4611 channel_type != NL80211_CHAN_HT20 &&
4612 channel_type != NL80211_CHAN_HT40PLUS &&
4613 channel_type != NL80211_CHAN_HT40MINUS)
4614 err = -EINVAL;
4615 goto out;
4616 }
4617
4618 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
4619 chan = rdev_freq_to_chan(rdev, freq, channel_type);
4620 if (chan == NULL) {
4621 err = -EINVAL;
4622 goto out;
4623 }
4624
4625 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4626 if (!msg) {
4627 err = -ENOMEM;
4628 goto out;
4629 }
4630
4631 hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
4632 NL80211_CMD_ACTION);
4633
4634 if (IS_ERR(hdr)) {
4635 err = PTR_ERR(hdr);
4636 goto free_msg;
4637 }
4638 err = cfg80211_mlme_action(rdev, dev, chan, channel_type,
4639 nla_data(info->attrs[NL80211_ATTR_FRAME]),
4640 nla_len(info->attrs[NL80211_ATTR_FRAME]),
4641 &cookie);
4642 if (err)
4643 goto free_msg;
4644
4645 NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
4646
4647 genlmsg_end(msg, hdr);
4648 err = genlmsg_reply(msg, info);
4649 goto out;
4650
4651 nla_put_failure:
4652 err = -ENOBUFS;
4653 free_msg:
4654 nlmsg_free(msg);
4655 out:
4656 cfg80211_unlock_rdev(rdev);
4657 dev_put(dev);
4658unlock_rtnl:
4659 rtnl_unlock();
4660 return err;
4661}
4662
4663static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
4664{
4665 struct cfg80211_registered_device *rdev;
4666 struct wireless_dev *wdev;
4667 struct net_device *dev;
4668 u8 ps_state;
4669 bool state;
4670 int err;
4671
4672 if (!info->attrs[NL80211_ATTR_PS_STATE]) {
4673 err = -EINVAL;
4674 goto out;
4675 }
4676
4677 ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]);
4678
4679 if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) {
4680 err = -EINVAL;
4681 goto out;
4682 }
4683
4684 rtnl_lock();
4685
4686 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4687 if (err)
4688 goto unlock_rdev;
4689
4690 wdev = dev->ieee80211_ptr;
4691
4692 if (!rdev->ops->set_power_mgmt) {
4693 err = -EOPNOTSUPP;
4694 goto unlock_rdev;
4695 }
4696
4697 state = (ps_state == NL80211_PS_ENABLED) ? true : false;
4698
4699 if (state == wdev->ps)
4700 goto unlock_rdev;
4701
4702 wdev->ps = state;
4703
4704 if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, wdev->ps,
4705 wdev->ps_timeout))
4706 /* assume this means it's off */
4707 wdev->ps = false;
4708
4709unlock_rdev:
4710 cfg80211_unlock_rdev(rdev);
4711 dev_put(dev);
4712 rtnl_unlock();
4713
4714out:
4715 return err;
4716}
4717
4718static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
4719{
4720 struct cfg80211_registered_device *rdev;
4721 enum nl80211_ps_state ps_state;
4722 struct wireless_dev *wdev;
4723 struct net_device *dev;
4724 struct sk_buff *msg;
4725 void *hdr;
4726 int err;
4727
4728 rtnl_lock();
4729
4730 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4731 if (err)
4732 goto unlock_rtnl;
4733
4734 wdev = dev->ieee80211_ptr;
4735
4736 if (!rdev->ops->set_power_mgmt) {
4737 err = -EOPNOTSUPP;
4738 goto out;
4739 }
4740
4741 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4742 if (!msg) {
4743 err = -ENOMEM;
4744 goto out;
4745 }
4746
4747 hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
4748 NL80211_CMD_GET_POWER_SAVE);
4749 if (!hdr) {
4750 err = -ENOMEM;
4751 goto free_msg;
4752 }
4753
4754 if (wdev->ps)
4755 ps_state = NL80211_PS_ENABLED;
4756 else
4757 ps_state = NL80211_PS_DISABLED;
4758
4759 NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state);
4760
4761 genlmsg_end(msg, hdr);
4762 err = genlmsg_reply(msg, info);
4763 goto out;
4764
4765nla_put_failure:
4766 err = -ENOBUFS;
4767
4768free_msg:
4769 nlmsg_free(msg);
4770
4771out:
4772 cfg80211_unlock_rdev(rdev);
4773 dev_put(dev);
4774
4775unlock_rtnl:
4776 rtnl_unlock();
4777
4778 return err;
4779}
4780
4548static struct genl_ops nl80211_ops[] = { 4781static struct genl_ops nl80211_ops[] = {
4549 { 4782 {
4550 .cmd = NL80211_CMD_GET_WIPHY, 4783 .cmd = NL80211_CMD_GET_WIPHY,
@@ -4825,6 +5058,30 @@ static struct genl_ops nl80211_ops[] = {
4825 .policy = nl80211_policy, 5058 .policy = nl80211_policy,
4826 .flags = GENL_ADMIN_PERM, 5059 .flags = GENL_ADMIN_PERM,
4827 }, 5060 },
5061 {
5062 .cmd = NL80211_CMD_REGISTER_ACTION,
5063 .doit = nl80211_register_action,
5064 .policy = nl80211_policy,
5065 .flags = GENL_ADMIN_PERM,
5066 },
5067 {
5068 .cmd = NL80211_CMD_ACTION,
5069 .doit = nl80211_action,
5070 .policy = nl80211_policy,
5071 .flags = GENL_ADMIN_PERM,
5072 },
5073 {
5074 .cmd = NL80211_CMD_SET_POWER_SAVE,
5075 .doit = nl80211_set_power_save,
5076 .policy = nl80211_policy,
5077 .flags = GENL_ADMIN_PERM,
5078 },
5079 {
5080 .cmd = NL80211_CMD_GET_POWER_SAVE,
5081 .doit = nl80211_get_power_save,
5082 .policy = nl80211_policy,
5083 /* can be retrieved by unprivileged users */
5084 },
4828}; 5085};
4829 5086
4830static struct genl_multicast_group nl80211_mlme_mcgrp = { 5087static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -5497,6 +5754,110 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
5497 nl80211_mlme_mcgrp.id, gfp); 5754 nl80211_mlme_mcgrp.id, gfp);
5498} 5755}
5499 5756
5757int nl80211_send_action(struct cfg80211_registered_device *rdev,
5758 struct net_device *netdev, u32 nlpid,
5759 int freq, const u8 *buf, size_t len, gfp_t gfp)
5760{
5761 struct sk_buff *msg;
5762 void *hdr;
5763 int err;
5764
5765 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
5766 if (!msg)
5767 return -ENOMEM;
5768
5769 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION);
5770 if (!hdr) {
5771 nlmsg_free(msg);
5772 return -ENOMEM;
5773 }
5774
5775 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
5776 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
5777 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
5778 NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
5779
5780 err = genlmsg_end(msg, hdr);
5781 if (err < 0) {
5782 nlmsg_free(msg);
5783 return err;
5784 }
5785
5786 err = genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
5787 if (err < 0)
5788 return err;
5789 return 0;
5790
5791 nla_put_failure:
5792 genlmsg_cancel(msg, hdr);
5793 nlmsg_free(msg);
5794 return -ENOBUFS;
5795}
5796
5797void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
5798 struct net_device *netdev, u64 cookie,
5799 const u8 *buf, size_t len, bool ack,
5800 gfp_t gfp)
5801{
5802 struct sk_buff *msg;
5803 void *hdr;
5804
5805 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
5806 if (!msg)
5807 return;
5808
5809 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION_TX_STATUS);
5810 if (!hdr) {
5811 nlmsg_free(msg);
5812 return;
5813 }
5814
5815 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
5816 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
5817 NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
5818 NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
5819 if (ack)
5820 NLA_PUT_FLAG(msg, NL80211_ATTR_ACK);
5821
5822 if (genlmsg_end(msg, hdr) < 0) {
5823 nlmsg_free(msg);
5824 return;
5825 }
5826
5827 genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
5828 return;
5829
5830 nla_put_failure:
5831 genlmsg_cancel(msg, hdr);
5832 nlmsg_free(msg);
5833}
5834
5835static int nl80211_netlink_notify(struct notifier_block * nb,
5836 unsigned long state,
5837 void *_notify)
5838{
5839 struct netlink_notify *notify = _notify;
5840 struct cfg80211_registered_device *rdev;
5841 struct wireless_dev *wdev;
5842
5843 if (state != NETLINK_URELEASE)
5844 return NOTIFY_DONE;
5845
5846 rcu_read_lock();
5847
5848 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list)
5849 list_for_each_entry_rcu(wdev, &rdev->netdev_list, list)
5850 cfg80211_mlme_unregister_actions(wdev, notify->pid);
5851
5852 rcu_read_unlock();
5853
5854 return NOTIFY_DONE;
5855}
5856
5857static struct notifier_block nl80211_netlink_notifier = {
5858 .notifier_call = nl80211_netlink_notify,
5859};
5860
5500/* initialisation/exit functions */ 5861/* initialisation/exit functions */
5501 5862
5502int nl80211_init(void) 5863int nl80211_init(void)
@@ -5530,6 +5891,10 @@ int nl80211_init(void)
5530 goto err_out; 5891 goto err_out;
5531#endif 5892#endif
5532 5893
5894 err = netlink_register_notifier(&nl80211_netlink_notifier);
5895 if (err)
5896 goto err_out;
5897
5533 return 0; 5898 return 0;
5534 err_out: 5899 err_out:
5535 genl_unregister_family(&nl80211_fam); 5900 genl_unregister_family(&nl80211_fam);
@@ -5538,5 +5903,6 @@ int nl80211_init(void)
5538 5903
5539void nl80211_exit(void) 5904void nl80211_exit(void)
5540{ 5905{
5906 netlink_unregister_notifier(&nl80211_netlink_notifier);
5541 genl_unregister_family(&nl80211_fam); 5907 genl_unregister_family(&nl80211_fam);
5542} 5908}
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 */
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index b17eeae448d5..9ab51838849e 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -1099,8 +1099,8 @@ int cfg80211_wext_siwpower(struct net_device *dev,
1099{ 1099{
1100 struct wireless_dev *wdev = dev->ieee80211_ptr; 1100 struct wireless_dev *wdev = dev->ieee80211_ptr;
1101 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 1101 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
1102 bool ps = wdev->wext.ps; 1102 bool ps = wdev->ps;
1103 int timeout = wdev->wext.ps_timeout; 1103 int timeout = wdev->ps_timeout;
1104 int err; 1104 int err;
1105 1105
1106 if (wdev->iftype != NL80211_IFTYPE_STATION) 1106 if (wdev->iftype != NL80211_IFTYPE_STATION)
@@ -1133,8 +1133,8 @@ int cfg80211_wext_siwpower(struct net_device *dev,
1133 if (err) 1133 if (err)
1134 return err; 1134 return err;
1135 1135
1136 wdev->wext.ps = ps; 1136 wdev->ps = ps;
1137 wdev->wext.ps_timeout = timeout; 1137 wdev->ps_timeout = timeout;
1138 1138
1139 return 0; 1139 return 0;
1140 1140
@@ -1147,7 +1147,7 @@ int cfg80211_wext_giwpower(struct net_device *dev,
1147{ 1147{
1148 struct wireless_dev *wdev = dev->ieee80211_ptr; 1148 struct wireless_dev *wdev = dev->ieee80211_ptr;
1149 1149
1150 wrq->disabled = !wdev->wext.ps; 1150 wrq->disabled = !wdev->ps;
1151 1151
1152 return 0; 1152 return 0;
1153} 1153}