cfg80211/mac80211: extensible frame processing
Subsystems (2)
Johannes Berg
maintainerPATCH 1/1 cfg80211/mac80211: extensible frame processing
From: Johannes Berg <[email protected]>
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 <[email protected]>
--- include/linux/nl80211.h | 93 +++++++++++++++++++++++------ include/net/cfg80211.h | 56 ++++++++++------- net/mac80211/cfg.c | 12 +-- net/mac80211/ieee80211_i.h | 1 net/mac80211/iface.c | 6 - net/mac80211/main.c | 37 +++++++++++ net/mac80211/rx.c | 137 ++++++++++++++++++++++++++++++------------ net/mac80211/status.c | 2 net/mac80211/util.c | 6 - net/wireless/core.c | 8 +- net/wireless/core.h | 21 +++--- net/wireless/mlme.c | 144 +++++++++++++++++++++++++++++---------------- net/wireless/nl80211.c | 108 +++++++++++++++++++++++++-------- net/wireless/nl80211.h | 14 ++-- net/wireless/util.c | 2 15 files changed, 452 insertions(+), 195 deletions(-)
include/linux/nl80211.h +74 -19
@@ -40,6 +40,43 @@*/ /** +* DOC: Frame transmission/registration support +* +* Frame transmission and registration support exists to allow userspace +* management entities such as wpa_supplicant react to management frames +* that are not being handled by the kernel. This includes, for example, +* certain classes of action frames that cannot be handled in the kernel +* for various reasons. +* +* Frame registration is done on a per-interface basis and registrations +* cannot be removed other than by closing the socket. It is possible to +* specify a registration filter to register, for example, only for a +* certain type of action frame. In particular with action frames, those +* that userspace registers for will not be returned as unhandled by the +* driver, so that the registered application has to take responsibility +* for doing that. +* +* The type of frame that can be registered for is also dependent on the +* driver and interface type. The frame types are advertised in wiphy +* attributes so applications know what to expect. +* +* NOTE: When an interface changes type while registrations are active, +* these registrations are ignored until the interface type is +* changed again. This means that changing the interface type can +* lead to a situation that couldn't otherwise be produced, but +* any such registrations will be dormant in the sense that they +* will not be serviced, i.e. they will not receive any frames. +* +* Frame transmission allows userspace to send for example the required +* responses to action frames. It is subject to some sanity checking, +* but many frames can be transmitted. When a frame was transmitted, its +* status is indicated to the sending socket. +* +* For more technical details, see the corresponding command descriptions +* below. +*/ + +/** * enum nl80211_commands - supported nl80211 commands * * @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -301,16 +338,18 @@* rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface * and @NL80211_ATTR_TX_RATES the set of allowed rates. * -* @NL80211_CMD_REGISTER_ACTION: Register for receiving certain action frames -* (via @NL80211_CMD_ACTION) for processing in userspace. This command -* requires an interface index and a match attribute containing the first -* few bytes of the frame that should match, e.g. a single byte for only -* a category match or four bytes for vendor frames including the OUI. -* The registration cannot be dropped, but is removed automatically -* when the netlink socket is closed. Multiple registrations can be made. -* @NL80211_CMD_ACTION: Action frame TX request and RX notification. This -* command is used both as a request to transmit an Action frame and as an -* event indicating reception of an Action frame that was not processed in +* @NL80211_CMD_REGISTER_FRAME: Register for receiving certain mgmt frames +* (via @NL80211_CMD_FRAME) for processing in userspace. This command +* requires an interface index, a frame type attribute (optional for +* backward compatibility reasons, if not given assumes action frames) +* and a match attribute containing the first few bytes of the frame +* that should match, e.g. a single byte for only a category match or +* four bytes for vendor frames including the OUI. The registration +* cannot be dropped, but is removed automatically when the netlink +* socket is closed. Multiple registrations can be made. +* @NL80211_CMD_FRAME: Management frame TX request and RX notification. This +* command is used both as a request to transmit a management frame and +* as an event indicating reception of a frame that was not processed in * kernel code, but is for us (i.e., which may need to be processed in a * user space application). %NL80211_ATTR_FRAME is used to specify the * frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and
@@ -320,8 +359,8 @@* operational channel). When called, this operation returns a cookie * (%NL80211_ATTR_COOKIE) that will be included with the TX status event * pertaining to the TX request. -* @NL80211_CMD_ACTION_TX_STATUS: Report TX status of an Action frame -* transmitted with %NL80211_CMD_ACTION. %NL80211_ATTR_COOKIE identifies +* @NL80211_CMD_FRAME_TX_STATUS: Report TX status of a management frame +* transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies * the TX command and %NL80211_ATTR_FRAME includes the contents of the * frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged * the frame.
@@ -429,9 +468,12 @@ enum nl80211_commands {NL80211_CMD_SET_TX_BITRATE_MASK , -NL80211_CMD_REGISTER_ACTION , -NL80211_CMD_ACTION , -NL80211_CMD_ACTION_TX_STATUS , +NL80211_CMD_REGISTER_FRAME , +NL80211_CMD_REGISTER_ACTION =NL80211_CMD_REGISTER_FRAME , +NL80211_CMD_FRAME , +NL80211_CMD_ACTION =NL80211_CMD_FRAME , +NL80211_CMD_FRAME_TX_STATUS , +NL80211_CMD_ACTION_TX_STATUS =NL80211_CMD_FRAME_TX_STATUS ,NL80211_CMD_SET_POWER_SAVE , NL80211_CMD_GET_POWER_SAVE,
@@ -708,7 +750,16 @@ enum nl80211_commands {* is used with %NL80211_CMD_SET_TX_BITRATE_MASK. * * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain -* at least one byte, currently used with @NL80211_CMD_REGISTER_ACTION. +* at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME. +* @NL80211_ATTR_FRAME_TYPE: A u16 indicating the frame type/subtype for the +* @NL80211_CMD_REGISTER_FRAME command. +* @NL80211_ATTR_TX_FRAME_TYPES: wiphy capability attribute, which is a +* nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing +* information about which frame types can be transmitted with +* %NL80211_CMD_FRAME. +* @NL80211_ATTR_RX_FRAME_TYPES: wiphy capability attribute, which is a +* nested attribute of %NL80211_ATTR_FRAME_TYPE attributes, containing +* information about which frame types can be registered for RX. * * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was * acknowledged by the recipient.
@@ -891,6 +942,10 @@ enum nl80211_attrs {NL80211_ATTR_WIPHY_TX_POWER_SETTING ,NL80211_ATTR_WIPHY_TX_POWER_LEVEL , +NL80211_ATTR_TX_FRAME_TYPES , +NL80211_ATTR_RX_FRAME_TYPES , +NL80211_ATTR_FRAME_TYPE , +/* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST,
@@ -947,7 +1002,7 @@ enum nl80211_attrs {* @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames * @NL80211_IFTYPE_MESH_POINT: mesh point * @NL80211_IFTYPE_MAX: highest interface type number currently defined -* @__NL80211_IFTYPE_AFTER_LAST: internal use +* @NUM_NL80211_IFTYPES: number of defined interface types * * These values are used with the %NL80211_ATTR_IFTYPE * to set the type of an interface.
@@ -964,8 +1019,8 @@ enum nl80211_iftype {NL80211_IFTYPE_MESH_POINT ,/* keep last */ - __NL80211_IFTYPE_AFTER_LAST, - NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1 +NUM_NL80211_IFTYPES , + NL80211_IFTYPE_MAX = NUM_NL80211_IFTYPES - 1 };/**
include/net/cfg80211.h +34 -22
123 lines not on this page · raw message
net/wireless/nl80211.c +80 -28
219 lines not on this page · raw message
net/wireless/core.c +4 -4
@@ -433,7 +433,7 @@ int wiphy_register(struct wiphy *wiphy)/* sanity check ifmodes */ WARN_ON (!ifmodes); - ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) -1 ) & ~1 ; + ifmodes &= ((1 <<NUM_NL80211_IFTYPES ) -1 ) & ~1 ;if (WARN_ON (ifmodes != wiphy->interface_modes)) wiphy->interface_modes = ifmodes;
@@ -685,8 +685,8 @@ static int cfg80211_netdev_notifier_callINIT_WORK (&wdev->cleanup_work, wdev_cleanup_work);INIT_LIST_HEAD (&wdev->event_list);spin_lock_init (&wdev->event_lock); -INIT_LIST_HEAD (&wdev->action_registrations); -spin_lock_init (&wdev->action_registrations_lock); +INIT_LIST_HEAD (&wdev->mgmt_registrations); +spin_lock_init (&wdev->mgmt_registrations_lock);mutex_lock (&rdev->devlist_mtx);list_add_rcu (&wdev->list, &rdev->netdev_list);
@@ -806,7 +806,7 @@ static int cfg80211_netdev_notifier_callsysfs_remove_link (&dev->dev.kobj,"phy80211" );list_del_rcu (&wdev->list); rdev->devlist_generation++; -cfg80211_mlme_purge_actions (wdev); +cfg80211_mlme_purge_registrations (wdev);#ifdef CONFIG_CFG80211_WEXT kfree (wdev->wext.keys);#endif
net/wireless/core.h +11 -10
@@ -331,16 +331,17 @@ void __cfg80211_connect_result(struct ne const u8 *resp_ie, size_t resp_ie_len, u16 status, bool wextev, struct cfg80211_bss *bss); -int cfg80211_mlme_register_action (struct wireless_dev *wdev,u32 snd_pid, -const u8 *match_data,int match_len); -void cfg80211_mlme_unregister_actions (struct wireless_dev *wdev,u32 nlpid); -void cfg80211_mlme_purge_actions (struct wireless_dev *wdev); -int cfg80211_mlme_action (struct cfg80211_registered_device *rdev, -struct net_device *dev, -struct ieee80211_channel *chan, -enum nl80211_channel_type channel_type, -bool channel_type_valid, -const u8 *buf,size_t len,u64 *cookie); +int cfg80211_mlme_register_mgmt (struct wireless_dev *wdev,u32 snd_pid, +u16 frame_type,const u8 *match_data, +int match_len); +void cfg80211_mlme_unregister_socket (struct wireless_dev *wdev,u32 nlpid); +void cfg80211_mlme_purge_registrations (struct wireless_dev *wdev); +int cfg80211_mlme_mgmt_tx (struct cfg80211_registered_device *rdev, +struct net_device *dev, +struct ieee80211_channel *chan, +enum nl80211_channel_type channel_type, +bool channel_type_valid, +const u8 *buf,size_t len,u64 *cookie);/* SME */ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
net/wireless/mlme.c +94 -50
251 lines not on this page · raw message
net/wireless/nl80211.h +7 -7
@@ -74,13 +74,13 @@ void nl80211_send_sta_event(struct cfg80 struct net_device *dev, const u8 *mac_addr, struct station_info *sinfo, gfp_t gfp); -int nl80211_send_action (struct cfg80211_registered_device *rdev, -struct net_device *netdev,u32 nlpid,int freq, -const u8 *buf,size_t len,gfp_t gfp); -void nl80211_send_action_tx_status (struct cfg80211_registered_device *rdev, -struct net_device *netdev,u64 cookie, -const u8 *buf,size_t len,bool ack, -gfp_t gfp); +int nl80211_send_mgmt (struct cfg80211_registered_device *rdev, +struct net_device *netdev,u32 nlpid,int freq, +const u8 *buf,size_t len,gfp_t gfp); +void nl80211_send_mgmt_tx_status (struct cfg80211_registered_device *rdev, +struct net_device *netdev,u64 cookie, +const u8 *buf,size_t len,bool ack, +gfp_t gfp); void nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
net/mac80211/cfg.c +6 -6
@@ -1541,11 +1541,11 @@ static int ieee80211_cancel_remain_on_chreturn ieee80211_wk_cancel_remain_on_channel (sdata, cookie); } -static int ieee80211_action (struct wiphy *wiphy,struct net_device *dev, -struct ieee80211_channel *chan, -enum nl80211_channel_type channel_type, -bool channel_type_valid, -const u8 *buf,size_t len,u64 *cookie) +static int ieee80211_mgmt_tx (struct wiphy *wiphy,struct net_device *dev, +struct ieee80211_channel *chan, +enum nl80211_channel_type channel_type, +bool channel_type_valid, +const u8 *buf,size_t len,u64 *cookie) {struct ieee80211_sub_if_data *sdata =IEEE80211_DEV_TO_SUB_IF (dev);struct ieee80211_local *local = sdata->local;
@@ -1645,6 +1645,6 @@ struct cfg80211_ops mac80211_config_ops .set_bitrate_mask = ieee80211_set_bitrate_mask, .remain_on_channel = ieee80211_remain_on_channel, .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, - .action = ieee80211_action, + .mgmt_tx = ieee80211_mgmt_tx, .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config, };
net/mac80211/rx.c +96 -41
194 lines not on this page · raw message
net/mac80211/status.c +1 -1
@@ -296,7 +296,7 @@ void ieee80211_tx_status(struct ieee8021 }if (info->flags &IEEE80211_TX_INTFL_NL80211_FRAME_TX ) -cfg80211_action_tx_status ( +cfg80211_mgmt_tx_status ( skb->dev, (unsigned long ) skb, skb->data, skb->len, !!(info->flags &IEEE80211_TX_STAT_ACK ),GFP_ATOMIC );
net/mac80211/main.c +37 -0
@@ -390,6 +390,41 @@ static int ieee80211_ifa_changed(struct }#endif +/* There isn't a lot of sense in it, but you can transmit anything you like */ +static const struct ieee80211_txrx_stypes +ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES ] = { + [NL80211_IFTYPE_ADHOC ] = { + .tx =0xffff , + .rx =BIT (IEEE80211_STYPE_ACTION >>4 ), + }, + [NL80211_IFTYPE_STATION ] = { + .tx =0xffff , + .rx =BIT (IEEE80211_STYPE_ACTION >>4 ) | +BIT (IEEE80211_STYPE_PROBE_REQ >>4 ), + }, + [NL80211_IFTYPE_AP ] = { + .tx =0xffff , + .rx =BIT (IEEE80211_STYPE_ASSOC_REQ >>4 ) | +BIT (IEEE80211_STYPE_REASSOC_REQ >>4 ) | +BIT (IEEE80211_STYPE_PROBE_REQ >>4 ) | +BIT (IEEE80211_STYPE_DISASSOC >>4 ) | +BIT (IEEE80211_STYPE_AUTH >>4 ) | +BIT (IEEE80211_STYPE_DEAUTH >>4 ) | +BIT (IEEE80211_STYPE_ACTION >>4 ), + }, + [NL80211_IFTYPE_AP_VLAN ] = { +/* copy AP */ + .tx =0xffff , + .rx =BIT (IEEE80211_STYPE_ASSOC_REQ >>4 ) | +BIT (IEEE80211_STYPE_REASSOC_REQ >>4 ) | +BIT (IEEE80211_STYPE_PROBE_REQ >>4 ) | +BIT (IEEE80211_STYPE_DISASSOC >>4 ) | +BIT (IEEE80211_STYPE_AUTH >>4 ) | +BIT (IEEE80211_STYPE_DEAUTH >>4 ) | +BIT (IEEE80211_STYPE_ACTION >>4 ), + }, +}; +struct ieee80211_hw *ieee80211_alloc_hw (size_t priv_data_len,const struct ieee80211_ops *ops) {
@@ -419,6 +454,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(if (!wiphy)return NULL ; + wiphy->mgmt_stypes = ieee80211_default_mgmt_stypes; + wiphy->flags |=WIPHY_FLAG_NETNS_OK |WIPHY_FLAG_4ADDR_AP |WIPHY_FLAG_4ADDR_STATION ;
net/wireless/util.c +1 -1
@@ -823,7 +823,7 @@ int cfg80211_change_iface(struct cfg8021/* monitor can't bridge anyway */ break ;case NL80211_IFTYPE_UNSPECIFIED : -case __NL80211_IFTYPE_AFTER_LAST: +case NUM_NL80211_IFTYPES :/* not happening */ break ; }
net/mac80211/iface.c +3 -3
@@ -177,7 +177,7 @@ static int ieee80211_open(struct net_dev/* no special treatment */ break ;case NL80211_IFTYPE_UNSPECIFIED : -case __NL80211_IFTYPE_AFTER_LAST: +case NUM_NL80211_IFTYPES :/* cannot happen */ WARN_ON (1 );break ;
@@ -630,7 +630,7 @@ static void ieee80211_teardown_sdata(strcase NL80211_IFTYPE_MONITOR :break ;case NL80211_IFTYPE_UNSPECIFIED : -case __NL80211_IFTYPE_AFTER_LAST: +case NUM_NL80211_IFTYPES :BUG ();break ; }
@@ -882,7 +882,7 @@ static void ieee80211_setup_sdata(structcase NL80211_IFTYPE_AP_VLAN :break ;case NL80211_IFTYPE_UNSPECIFIED : -case __NL80211_IFTYPE_AFTER_LAST: +case NUM_NL80211_IFTYPES :BUG ();break ; }
net/mac80211/util.c +3 -3
@@ -471,7 +471,7 @@ void ieee80211_iterate_active_interfaceslist_for_each_entry (sdata, &local->interfaces, list) {switch (sdata->vif.type) { -case __NL80211_IFTYPE_AFTER_LAST: +case NUM_NL80211_IFTYPES :case NL80211_IFTYPE_UNSPECIFIED :case NL80211_IFTYPE_MONITOR :case NL80211_IFTYPE_AP_VLAN :
@@ -505,7 +505,7 @@ void ieee80211_iterate_active_interfaceslist_for_each_entry_rcu (sdata, &local->interfaces, list) {switch (sdata->vif.type) { -case __NL80211_IFTYPE_AFTER_LAST: +case NUM_NL80211_IFTYPES :case NL80211_IFTYPE_UNSPECIFIED :case NL80211_IFTYPE_MONITOR :case NL80211_IFTYPE_AP_VLAN :
@@ -1189,7 +1189,7 @@ int ieee80211_reconfig(struct ieee80211_/* ignore virtual */ break ;case NL80211_IFTYPE_UNSPECIFIED : -case __NL80211_IFTYPE_AFTER_LAST: +case NUM_NL80211_IFTYPES :WARN_ON (1 );break ; }
net/mac80211/ieee80211_i.h +1 -0
@@ -170,6 +170,7 @@ typedef unsigned __bitwise__ ieee80211_r#define IEEE80211_RX_RA_MATCH BIT(1)#define IEEE80211_RX_AMSDU BIT(2)#define IEEE80211_RX_FRAGMENTED BIT(3) +#define IEEE80211_MALFORMED_ACTION_FRM BIT(4)/* only add flags here that do not change with subframes of an aMPDU */ struct ieee80211_rx_data {