Skip to content

Commit 026331c

Browse files
Jouni Malinenlinvjw
authored andcommitted
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>
1 parent 8404080 commit 026331c

File tree

13 files changed

+625
-18
lines changed

13 files changed

+625
-18
lines changed

include/linux/nl80211.h

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/*
44
* 802.11 netlink interface public header
55
*
6-
* Copyright 2006, 2007, 2008 Johannes Berg <johannes@sipsolutions.net>
6+
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
77
* Copyright 2008 Michael Wu <flamingice@sourmilk.net>
88
* Copyright 2008 Luis Carlos Cobo <luisca@cozybit.com>
99
* Copyright 2008 Michael Buesch <mb@bu3sch.de>
@@ -299,6 +299,31 @@
299299
* rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface
300300
* and @NL80211_ATTR_TX_RATES the set of allowed rates.
301301
*
302+
* @NL80211_CMD_REGISTER_ACTION: Register for receiving certain action frames
303+
* (via @NL80211_CMD_ACTION) for processing in userspace. This command
304+
* requires an interface index and a match attribute containing the first
305+
* few bytes of the frame that should match, e.g. a single byte for only
306+
* a category match or four bytes for vendor frames including the OUI.
307+
* The registration cannot be dropped, but is removed automatically
308+
* when the netlink socket is closed. Multiple registrations can be made.
309+
* @NL80211_CMD_ACTION: Action frame TX request and RX notification. This
310+
* command is used both as a request to transmit an Action frame and as an
311+
* event indicating reception of an Action frame that was not processed in
312+
* kernel code, but is for us (i.e., which may need to be processed in a
313+
* user space application). %NL80211_ATTR_FRAME is used to specify the
314+
* frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and
315+
* optionally %NL80211_ATTR_WIPHY_CHANNEL_TYPE) is used to indicate on
316+
* which channel the frame is to be transmitted or was received. This
317+
* channel has to be the current channel (remain-on-channel or the
318+
* operational channel). When called, this operation returns a cookie
319+
* (%NL80211_ATTR_COOKIE) that will be included with the TX status event
320+
* pertaining to the TX request.
321+
* @NL80211_CMD_ACTION_TX_STATUS: Report TX status of an Action frame
322+
* transmitted with %NL80211_CMD_ACTION. %NL80211_ATTR_COOKIE identifies
323+
* the TX command and %NL80211_ATTR_FRAME includes the contents of the
324+
* frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged
325+
* the frame.
326+
*
302327
* @NL80211_CMD_MAX: highest used command number
303328
* @__NL80211_CMD_AFTER_LAST: internal use
304329
*/
@@ -387,6 +412,10 @@ enum nl80211_commands {
387412

388413
NL80211_CMD_SET_TX_BITRATE_MASK,
389414

415+
NL80211_CMD_REGISTER_ACTION,
416+
NL80211_CMD_ACTION,
417+
NL80211_CMD_ACTION_TX_STATUS,
418+
390419
/* add new commands above here */
391420

392421
/* used to define NL80211_CMD_MAX below */
@@ -653,6 +682,12 @@ enum nl80211_commands {
653682
* rates based on negotiated supported rates information. This attribute
654683
* is used with %NL80211_CMD_SET_TX_BITRATE_MASK.
655684
*
685+
* @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain
686+
* at least one byte, currently used with @NL80211_CMD_REGISTER_ACTION.
687+
*
688+
* @NL80211_ATTR_ACK: Flag attribute indicating that the frame was
689+
* acknowledged by the recipient.
690+
*
656691
* @NL80211_ATTR_MAX: highest attribute number currently defined
657692
* @__NL80211_ATTR_AFTER_LAST: internal use
658693
*/
@@ -798,6 +833,10 @@ enum nl80211_attrs {
798833

799834
NL80211_ATTR_TX_RATES,
800835

836+
NL80211_ATTR_FRAME_MATCH,
837+
838+
NL80211_ATTR_ACK,
839+
801840
/* add attributes here, update the policy in nl80211.c */
802841

803842
__NL80211_ATTR_AFTER_LAST,

include/net/cfg80211.h

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/*
44
* 802.11 device and configuration interface
55
*
6-
* Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net>
6+
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
77
*
88
* This program is free software; you can redistribute it and/or modify
99
* it under the terms of the GNU General Public License version 2 as
@@ -998,6 +998,7 @@ struct cfg80211_pmksa {
998998
* @cancel_remain_on_channel: Cancel an on-going remain-on-channel operation.
999999
* This allows the operation to be terminated prior to timeout based on
10001000
* the duration value.
1001+
* @action: Transmit an action frame
10011002
*
10021003
* @testmode_cmd: run a test mode command
10031004
*
@@ -1144,6 +1145,11 @@ struct cfg80211_ops {
11441145
struct net_device *dev,
11451146
u64 cookie);
11461147

1148+
int (*action)(struct wiphy *wiphy, struct net_device *dev,
1149+
struct ieee80211_channel *chan,
1150+
enum nl80211_channel_type channel_type,
1151+
const u8 *buf, size_t len, u64 *cookie);
1152+
11471153
/* some temporary stuff to finish wext */
11481154
int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
11491155
bool enabled, int timeout);
@@ -1445,6 +1451,8 @@ struct cfg80211_cached_keys;
14451451
* set by driver (if supported) on add_interface BEFORE registering the
14461452
* netdev and may otherwise be used by driver read-only, will be update
14471453
* by cfg80211 on change_interface
1454+
* @action_registrations: list of registrations for action frames
1455+
* @action_registrations_lock: lock for the list
14481456
*/
14491457
struct wireless_dev {
14501458
struct wiphy *wiphy;
@@ -1454,6 +1462,9 @@ struct wireless_dev {
14541462
struct list_head list;
14551463
struct net_device *netdev;
14561464

1465+
struct list_head action_registrations;
1466+
spinlock_t action_registrations_lock;
1467+
14571468
struct mutex mtx;
14581469

14591470
struct work_struct cleanup_work;
@@ -2291,4 +2302,38 @@ void cfg80211_remain_on_channel_expired(struct net_device *dev,
22912302
void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
22922303
struct station_info *sinfo, gfp_t gfp);
22932304

2305+
/**
2306+
* cfg80211_rx_action - notification of received, unprocessed Action frame
2307+
* @dev: network device
2308+
* @freq: Frequency on which the frame was received in MHz
2309+
* @buf: Action frame (header + body)
2310+
* @len: length of the frame data
2311+
* @gfp: context flags
2312+
* Returns %true if a user space application is responsible for rejecting the
2313+
* unrecognized Action frame; %false if no such application is registered
2314+
* (i.e., the driver is responsible for rejecting the unrecognized Action
2315+
* frame)
2316+
*
2317+
* This function is called whenever an Action frame is received for a station
2318+
* mode interface, but is not processed in kernel.
2319+
*/
2320+
bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf,
2321+
size_t len, gfp_t gfp);
2322+
2323+
/**
2324+
* cfg80211_action_tx_status - notification of TX status for Action frame
2325+
* @dev: network device
2326+
* @cookie: Cookie returned by cfg80211_ops::action()
2327+
* @buf: Action frame (header + body)
2328+
* @len: length of the frame data
2329+
* @ack: Whether frame was acknowledged
2330+
* @gfp: context flags
2331+
*
2332+
* This function is called whenever an Action frame was requested to be
2333+
* transmitted with cfg80211_ops::action() to report the TX status of the
2334+
* transmission attempt.
2335+
*/
2336+
void cfg80211_action_tx_status(struct net_device *dev, u64 cookie,
2337+
const u8 *buf, size_t len, bool ack, gfp_t gfp);
2338+
22942339
#endif /* __NET_CFG80211_H */

include/net/mac80211.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright 2002-2005, Devicescape Software, Inc.
55
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
6-
* Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net>
6+
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
77
*
88
* This program is free software; you can redistribute it and/or modify
99
* it under the terms of the GNU General Public License version 2 as
@@ -264,6 +264,9 @@ struct ieee80211_bss_conf {
264264
* be modified again (no seqno assignment, crypto, etc.)
265265
* @IEEE80211_TX_INTFL_HAS_RADIOTAP: This frame was injected and still
266266
* has a radiotap header at skb->data.
267+
* @IEEE80211_TX_INTFL_NL80211_FRAME_TX: Frame was requested through nl80211
268+
* MLME command (internal to mac80211 to figure out whether to send TX
269+
* status to user space)
267270
*/
268271
enum mac80211_tx_control_flags {
269272
IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0),
@@ -286,6 +289,7 @@ enum mac80211_tx_control_flags {
286289
IEEE80211_TX_CTL_MORE_FRAMES = BIT(18),
287290
IEEE80211_TX_INTFL_RETRANSMISSION = BIT(19),
288291
IEEE80211_TX_INTFL_HAS_RADIOTAP = BIT(20),
292+
IEEE80211_TX_INTFL_NL80211_FRAME_TX = BIT(21),
289293
};
290294

291295
/**

net/mac80211/cfg.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* mac80211 configuration hooks for cfg80211
33
*
4-
* Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
4+
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
55
*
66
* This file is GPLv2 as found in COPYING.
77
*/
@@ -1448,6 +1448,15 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
14481448
return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
14491449
}
14501450

1451+
static 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+
14511460
struct cfg80211_ops mac80211_config_ops = {
14521461
.add_virtual_intf = ieee80211_add_iface,
14531462
.del_virtual_intf = ieee80211_del_iface,
@@ -1496,4 +1505,5 @@ struct cfg80211_ops mac80211_config_ops = {
14961505
.set_bitrate_mask = ieee80211_set_bitrate_mask,
14971506
.remain_on_channel = ieee80211_remain_on_channel,
14981507
.cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
1508+
.action = ieee80211_action,
14991509
};

net/mac80211/ieee80211_i.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Copyright 2002-2005, Instant802 Networks, Inc.
33
* Copyright 2005, Devicescape Software, Inc.
44
* 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>
66
*
77
* This program is free software; you can redistribute it and/or modify
88
* 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,
966966
int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
967967
struct cfg80211_disassoc_request *req,
968968
void *cookie);
969+
int 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);
969973
ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
970974
struct sk_buff *skb);
971975
void ieee80211_send_pspoll(struct ieee80211_local *local,

net/mac80211/mlme.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2084,3 +2084,38 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
20842084

20852085
return 0;
20862086
}
2087+
2088+
int 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+
}

net/mac80211/rx.c

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1856,28 +1856,25 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
18561856
struct ieee80211_sub_if_data *sdata = rx->sdata;
18571857
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
18581858
struct sk_buff *nskb;
1859+
struct ieee80211_rx_status *status;
18591860
int len = rx->skb->len;
18601861

18611862
if (!ieee80211_is_action(mgmt->frame_control))
18621863
return RX_CONTINUE;
18631864

1864-
if (!rx->sta)
1865+
/* drop too small frames */
1866+
if (len < IEEE80211_MIN_ACTION_SIZE)
18651867
return RX_DROP_UNUSABLE;
18661868

1867-
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
1869+
if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC)
18681870
return RX_DROP_UNUSABLE;
18691871

1870-
if (ieee80211_drop_unencrypted(rx, mgmt->frame_control))
1872+
if (!(rx->flags & IEEE80211_RX_RA_MATCH))
18711873
return RX_DROP_UNUSABLE;
18721874

1873-
/* drop too small frames */
1874-
if (len < IEEE80211_MIN_ACTION_SIZE)
1875+
if (ieee80211_drop_unencrypted(rx, mgmt->frame_control))
18751876
return RX_DROP_UNUSABLE;
18761877

1877-
/* return action frames that have *only* category */
1878-
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
1879-
goto return_frame;
1880-
18811878
switch (mgmt->u.action.category) {
18821879
case WLAN_CATEGORY_BACK:
18831880
/*
@@ -1891,6 +1888,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
18911888
sdata->vif.type != NL80211_IFTYPE_AP)
18921889
break;
18931890

1891+
/* verify action_code is present */
1892+
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
1893+
break;
1894+
18941895
switch (mgmt->u.action.u.addba_req.action_code) {
18951896
case WLAN_ACTION_ADDBA_REQ:
18961897
if (len < (IEEE80211_MIN_ACTION_SIZE +
@@ -1919,6 +1920,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
19191920
if (sdata->vif.type != NL80211_IFTYPE_STATION)
19201921
break;
19211922

1923+
/* verify action_code is present */
1924+
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
1925+
break;
1926+
19221927
switch (mgmt->u.action.u.measurement.action_code) {
19231928
case WLAN_ACTION_SPCT_MSR_REQ:
19241929
if (len < (IEEE80211_MIN_ACTION_SIZE +
@@ -1954,7 +1959,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
19541959
}
19551960
break;
19561961
}
1957-
return_frame:
1962+
19581963
/*
19591964
* For AP mode, hostapd is responsible for handling any action
19601965
* frames that we didn't handle, including returning unknown
@@ -1966,6 +1971,20 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
19661971
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
19671972
return RX_DROP_MONITOR;
19681973

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+
19691988
/* do not return rejected action frames */
19701989
if (mgmt->u.action.category & 0x80)
19711990
return RX_DROP_UNUSABLE;
@@ -1985,7 +2004,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
19852004
}
19862005

19872006
handled:
1988-
rx->sta->rx_packets++;
2007+
if (rx->sta)
2008+
rx->sta->rx_packets++;
19892009
dev_kfree_skb(rx->skb);
19902010
return RX_QUEUED;
19912011
}

net/mac80211/status.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Copyright 2002-2005, Instant802 Networks, Inc.
33
* Copyright 2005-2006, Devicescape Software, Inc.
44
* 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>
66
*
77
* This program is free software; you can redistribute it and/or modify
88
* 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)
288288
msecs_to_jiffies(10));
289289
}
290290

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+
291296
/* this was a transmitted frame, but now we want to reuse it */
292297
skb_orphan(skb);
293298

0 commit comments

Comments
 (0)