summaryrefslogtreecommitdiffstats
path: root/net/mac80211/rx.c
diff options
context:
space:
mode:
authorJouni Malinen <jouni.malinen@atheros.com>2010-02-15 12:53:10 +0200
committerJohn W. Linville <linville@tuxdriver.com>2010-02-15 16:14:15 -0500
commit026331c4d9b526561ea96f95fac4bfc52b69e316 (patch)
treea82b0a92a7f03a1d151a9db123320689c73d98c7 /net/mac80211/rx.c
parent8404080568613d93ad7cf0a16dfb68459b42a264 (diff)
downloadblackbird-op-linux-026331c4d9b526561ea96f95fac4bfc52b69e316.tar.gz
blackbird-op-linux-026331c4d9b526561ea96f95fac4bfc52b69e316.zip
cfg80211/mac80211: allow registering for and sending action frames
This implements a new command to register for action frames that userspace wants to handle instead of the in-kernel rejection. It is then responsible for rejecting ones that it decided not to handle. There is no unregistration, but the socket can be closed for that. Frames that are not registered for will not be forwarded to userspace and will be rejected by the kernel, the cfg80211 API helps implementing that. Additionally, this patch adds a new command that allows doing action frame transmission from userspace. It can be used either to exchange action frames on the current operational channel (e.g., with the AP with which we are currently associated) or to exchange off-channel Public Action frames with the remain-on-channel command. Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com> Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r--net/mac80211/rx.c42
1 files changed, 31 insertions, 11 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index a177472adc13..a6080d8d72bb 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1856,28 +1856,25 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
struct ieee80211_sub_if_data *sdata = rx->sdata;
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
struct sk_buff *nskb;
+ struct ieee80211_rx_status *status;
int len = rx->skb->len;
if (!ieee80211_is_action(mgmt->frame_control))
return RX_CONTINUE;
- if (!rx->sta)
+ /* drop too small frames */
+ if (len < IEEE80211_MIN_ACTION_SIZE)
return RX_DROP_UNUSABLE;
- if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+ if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC)
return RX_DROP_UNUSABLE;
- if (ieee80211_drop_unencrypted(rx, mgmt->frame_control))
+ if (!(rx->flags & IEEE80211_RX_RA_MATCH))
return RX_DROP_UNUSABLE;
- /* drop too small frames */
- if (len < IEEE80211_MIN_ACTION_SIZE)
+ if (ieee80211_drop_unencrypted(rx, mgmt->frame_control))
return RX_DROP_UNUSABLE;
- /* return action frames that have *only* category */
- if (len < IEEE80211_MIN_ACTION_SIZE + 1)
- goto return_frame;
-
switch (mgmt->u.action.category) {
case WLAN_CATEGORY_BACK:
/*
@@ -1891,6 +1888,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
sdata->vif.type != NL80211_IFTYPE_AP)
break;
+ /* verify action_code is present */
+ if (len < IEEE80211_MIN_ACTION_SIZE + 1)
+ break;
+
switch (mgmt->u.action.u.addba_req.action_code) {
case WLAN_ACTION_ADDBA_REQ:
if (len < (IEEE80211_MIN_ACTION_SIZE +
@@ -1919,6 +1920,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
if (sdata->vif.type != NL80211_IFTYPE_STATION)
break;
+ /* verify action_code is present */
+ if (len < IEEE80211_MIN_ACTION_SIZE + 1)
+ break;
+
switch (mgmt->u.action.u.measurement.action_code) {
case WLAN_ACTION_SPCT_MSR_REQ:
if (len < (IEEE80211_MIN_ACTION_SIZE +
@@ -1954,7 +1959,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
}
break;
}
- return_frame:
+
/*
* For AP mode, hostapd is responsible for handling any action
* frames that we didn't handle, including returning unknown
@@ -1966,6 +1971,20 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
return RX_DROP_MONITOR;
+ /*
+ * Getting here means the kernel doesn't know how to handle
+ * it, but maybe userspace does ... include returned frames
+ * so userspace can register for those to know whether ones
+ * it transmitted were processed or returned.
+ */
+ status = IEEE80211_SKB_RXCB(rx->skb);
+
+ if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+ cfg80211_rx_action(rx->sdata->dev, status->freq,
+ rx->skb->data, rx->skb->len,
+ GFP_ATOMIC))
+ goto handled;
+
/* do not return rejected action frames */
if (mgmt->u.action.category & 0x80)
return RX_DROP_UNUSABLE;
@@ -1985,7 +2004,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
}
handled:
- rx->sta->rx_packets++;
+ if (rx->sta)
+ rx->sta->rx_packets++;
dev_kfree_skb(rx->skb);
return RX_QUEUED;
}
OpenPOWER on IntegriCloud