initial round of hostapd support patches
Subsystems (2)
Johannes Berg
maintainercover initial round of hostapd support patches
Now that 2.6.24-rc1 is released I guess I can throw more new patches at you :)
This is a first piece of hostapd support patches, these introduce new nl80211 API.
I do not think these patches will apply since I left out some, but comments would nonetheless be greatly appreciated.
johannes
Johannes Berg
maintainerPATCH 1/9 cfg80211/nl80211: introduce key handling
This introduces key handling to cfg80211/nl80211. Default and group keys can be added, changed and removed; sequence counters for each key can be retrieved.
--- include/linux/nl80211.h | 34 +++++ include/net/cfg80211.h | 44 +++++++ net/wireless/core.c | 3 net/wireless/nl80211.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 370 insertions(+)
include/linux/nl80211.h +34 -0
@@ -37,6 +37,16 @@* userspace to request deletion of a virtual interface, then requires * attribute %NL80211_ATTR_IFINDEX. * +* @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified +* by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. +* @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT or +* %NL80211_ATTR_KEY_THRESHOLD. +* @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA, +* %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER +* attributes. +* @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX +* or %NL80211_ATTR_MAC. +* * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */
@@ -54,6 +64,11 @@ enum nl80211_commands {NL80211_CMD_NEW_INTERFACE ,NL80211_CMD_DEL_INTERFACE , +NL80211_CMD_GET_KEY , +NL80211_CMD_SET_KEY , +NL80211_CMD_NEW_KEY , +NL80211_CMD_DEL_KEY , +/* add commands here */ /* used to define NL80211_CMD_MAX below */
@@ -75,6 +90,17 @@ enum nl80211_commands {* @NL80211_ATTR_IFNAME: network interface name * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype * +* @NL80211_ATTR_MAC: MAC address (various uses) +* +* @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of +* 16 bytes encryption key followed by 8 bytes each for TX and RX MIC +* keys +* @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3) +* @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11 +* section 7.3.2.25.1, e.g. 0x000FAC04) +* @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and +* CCMP keys, each six bytes in little endian +* * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */
@@ -89,6 +115,14 @@ enum nl80211_attrs {NL80211_ATTR_IFNAME ,NL80211_ATTR_IFTYPE , +NL80211_ATTR_MAC , + +NL80211_ATTR_KEY_DATA , +NL80211_ATTR_KEY_IDX , +NL80211_ATTR_KEY_CIPHER , +NL80211_ATTR_KEY_SEQ , +NL80211_ATTR_KEY_DEFAULT , +/* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST,
net/wireless/nl80211.c +289 -0
307 lines not on this page · raw message
net/wireless/core.c +3 -0
@@ -184,6 +184,9 @@ struct wiphy *wiphy_new(struct cfg80211_struct cfg80211_registered_device *drv;int alloc_size; +WARN_ON (!ops->add_key && ops->del_key); +WARN_ON (ops->add_key && !ops->del_key); + alloc_size =sizeof (*drv) + sizeof_priv; drv =kzalloc (alloc_size,GFP_KERNEL );
include/net/cfg80211.h +44 -0
62 lines not on this page · raw message
Johannes Berg
maintainerPATCH 2/9 mac80211: support adding/removing keys via cfg80211
In reply to Johannes BergThis adds the necessary hooks to mac80211 to allow userspace to edit keys with cfg80211 (through nl80211.)
--- net/mac80211/cfg.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+)
net/mac80211/cfg.c +91 -0
@@ -6,6 +6,7 @@* This file is GPLv2 as found in COPYING. */ +#include <linux/ieee80211.h> #include <linux/nl80211.h> #include <linux/rtnetlink.h> #include <net/net_namespace.h>
@@ -99,8 +100,98 @@ static int ieee80211_change_iface(structreturn 0 ; } +static int ieee80211_add_key (struct wiphy *wiphy,struct net_device *dev, +u8 key_idx,u8 *mac_addr, +struct key_params *params) +{ +struct ieee80211_sub_if_data *sdata; +struct sta_info *sta =NULL ; +enum ieee80211_key_alg alg; +int ret; + + sdata =IEEE80211_DEV_TO_SUB_IF (dev); + +switch (params->cipher) { +case WLAN_CIPHER_SUITE_WEP40 : +case WLAN_CIPHER_SUITE_WEP104 : + alg =ALG_WEP ; +break ; +case WLAN_CIPHER_SUITE_TKIP : + alg =ALG_TKIP ; +break ; +case WLAN_CIPHER_SUITE_CCMP : + alg =ALG_CCMP ; +break ; +default : +return -EINVAL ; + } + +if (mac_addr) { + sta =sta_info_get (sdata->local, mac_addr); +if (!sta) +return -ENOENT ; + } + + ret =0 ; +if (!ieee80211_key_alloc (sdata, sta, alg, key_idx, + params->key_len, params->key)) + ret = -ENOMEM ; + +if (sta) +sta_info_put (sta); + +return ret; +} + +static int ieee80211_del_key (struct wiphy *wiphy,struct net_device *dev, +u8 key_idx,u8 *mac_addr) +{ +struct ieee80211_sub_if_data *sdata; +struct sta_info *sta; +int ret; + + sdata =IEEE80211_DEV_TO_SUB_IF (dev); + +if (mac_addr) { + sta =sta_info_get (sdata->local, mac_addr); +if (!sta) +return -ENOENT ; + + ret =0 ; +if (sta->key) +ieee80211_key_free (sta->key); +else + ret = -ENOENT ; + +sta_info_put (sta); +return ret; + } + +if (!sdata->keys[key_idx]) +return -ENOENT ; + +ieee80211_key_free (sdata->keys[key_idx]); + +return 0 ; +} + +static int ieee80211_config_default_key (struct wiphy *wiphy, +struct net_device *dev, +u8 key_idx) +{ +struct ieee80211_sub_if_data *sdata; + + sdata =IEEE80211_DEV_TO_SUB_IF (dev); +ieee80211_set_default_key (sdata, key_idx); + +return 0 ; +} +struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, .change_virtual_intf = ieee80211_change_iface, + .add_key = ieee80211_add_key, + .del_key = ieee80211_del_key, + .set_default_key = ieee80211_config_default_key, };
Johannes Berg
maintainerPATCH 3/9 mac80211: support getting key sequence counters via cfg80211
In reply to Johannes BergThis implements cfg80211's get_key() to allow retrieving the sequence counter for a TKIP or CCMP key from userspace. It also cleans up and documents the associated low-level driver interface.
--- include/net/mac80211.h | 14 ++------ net/mac80211/cfg.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 10 deletions(-)
net/mac80211/cfg.c +84 -1
@@ -1,7 +1,7 @@/* * mac80211 configuration hooks for cfg80211 * -* Copyright 2006 Johannes Berg <[email protected]> +* Copyright 2006, 2007 Johannes Berg <[email protected]> * * This file is GPLv2 as found in COPYING. */
@@ -175,6 +175,88 @@ static int ieee80211_del_key(struct wiphreturn 0 ; } +static int ieee80211_get_key (struct wiphy *wiphy,struct net_device *dev, +u8 key_idx,u8 *mac_addr,void *cookie, +void (*callback)(void *cookie, +struct key_params *params)) +{ +struct ieee80211_sub_if_data *sdata =IEEE80211_DEV_TO_SUB_IF (dev); +struct sta_info *sta =NULL ; +u8 seq[6 ] = {0 }; +struct key_params params; +struct ieee80211_key *key; +u32 iv32; +u16 iv16; +int err = -ENOENT ; + +if (mac_addr) { + sta =sta_info_get (sdata->local, mac_addr); +if (!sta) + goto out; + + key = sta->key; + }else + key = sdata->keys[key_idx]; + +if (!key) + goto out; + +memset (¶ms,0 ,sizeof (params)); + +switch (key->conf.alg) { +case ALG_TKIP : + params.cipher =WLAN_CIPHER_SUITE_TKIP ; + + iv32 = key->u.tkip.iv32; + iv16 = key->u.tkip.iv16; + +if (key->flags &KEY_FLAG_UPLOADED_TO_HARDWARE && + sdata->local->ops->get_tkip_seq) + sdata->local->ops->get_tkip_seq ( +local_to_hw (sdata->local), + key->conf.hw_key_idx, + &iv32, &iv16); + + seq[0 ] = iv16 &0xff ; + seq[1 ] = (iv16 >>8 ) &0xff ; + seq[2 ] = iv32 &0xff ; + seq[3 ] = (iv32 >>8 ) &0xff ; + seq[4 ] = (iv32 >>16 ) &0xff ; + seq[5 ] = (iv32 >>24 ) &0xff ; + params.seq = seq; + params.seq_len =6 ; +break ; +case ALG_CCMP : + params.cipher =WLAN_CIPHER_SUITE_CCMP ; + seq[0 ] = key->u.ccmp.tx_pn[5 ]; + seq[1 ] = key->u.ccmp.tx_pn[4 ]; + seq[2 ] = key->u.ccmp.tx_pn[3 ]; + seq[3 ] = key->u.ccmp.tx_pn[2 ]; + seq[4 ] = key->u.ccmp.tx_pn[1 ]; + seq[5 ] = key->u.ccmp.tx_pn[0 ]; + params.seq = seq; + params.seq_len =6 ; +break ; +case ALG_WEP : +if (key->conf.keylen ==5 ) + params.cipher =WLAN_CIPHER_SUITE_WEP40 ; +else + params.cipher =WLAN_CIPHER_SUITE_WEP104 ; +break ; + } + + params.key = key->conf.key; + params.key_len = key->conf.keylen; + +callback (cookie, ¶ms); + err =0 ; + + out: +if (sta) +sta_info_put (sta); +return err; +} +static int ieee80211_config_default_key (struct wiphy *wiphy,struct net_device *dev,u8 key_idx)
@@ -193,5 +275,6 @@ struct cfg80211_ops mac80211_config_ops .change_virtual_intf = ieee80211_change_iface, .add_key = ieee80211_add_key, .del_key = ieee80211_del_key, + .get_key = ieee80211_get_key, .set_default_key = ieee80211_config_default_key, };
include/net/mac80211.h +5 -9
@@ -597,9 +597,6 @@ struct ieee80211_key_conf {u8 key[0 ]; }; -#define IEEE80211_SEQ_COUNTER_RX 0 -#define IEEE80211_SEQ_COUNTER_TX 1 -/** * enum set_key_cmd - key command *
@@ -957,9 +954,9 @@ enum ieee80211_erp_change_flags {* response or association responses this updates the state of privacy_invoked * returns 0 for success or an error number. * -* @get_sequence_counter: For devices that have internal sequence counters this -* callback allows mac80211 to access the current value of a counter. -* This callback seems not well-defined, tell us if you need it. +* @get_tkip_seq: If your device implements TKIP encryption in hardware this +* callback should be provided to read the TKIP transmit IVs (both IV32 +* and IV16) for the given key from hardware. * * @set_rts_threshold: Configuration of RTS threshold (if device needs it) *
@@ -1037,9 +1034,8 @@ struct ieee80211_ops { struct ieee80211_low_level_stats *stats);int (*set_privacy_invoked)(struct ieee80211_hw *hw,int privacy_invoked); -int (*get_sequence_counter)(struct ieee80211_hw *hw, -u8 * addr,u8 keyidx,u8 txrx, -u32 * iv32,u16 * iv16); +void (*get_tkip_seq)(struct ieee80211_hw *hw,u8 hw_key_idx, +u32 *iv32,u16 *iv16);int (*set_rts_threshold)(struct ieee80211_hw *hw,u32 value);int (*set_frag_threshold)(struct ieee80211_hw *hw,u32 value); int (*set_retry_limit)(struct ieee80211_hw *hw,
Johannes Berg
maintainerPATCH 4/9 cfg80211/nl80211: add beacon settings
In reply to Johannes BergThis adds the necessary API to nl80211/cfg80211 to allow changing beaconing settings.
--- include/linux/nl80211.h | 19 ++++++++ include/net/cfg80211.h | 27 +++++++++++ net/wireless/nl80211.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+)
include/net/cfg80211.h +27 -0
@@ -69,6 +69,26 @@ struct key_params {u32 cipher; }; +/** +* struct beacon_parameters - beacon parameters +* +* Used to configure the beacon for an interface. +* +* @head: head portion of beacon (before TIM IE) +* or %NULL if not changed +* @tail: tail portion of beacon (after TIM IE) +* or %NULL if not changed +* @interval: beacon interval or zero if not changed +* @dtim_period: DTIM period or zero if not changed +* @head_len: length of @head +* @tail_len: length of @tail +*/ +struct beacon_parameters { +u8 *head, *tail; +int interval, dtim_period; +int head_len, tail_len; +}; +/* from net/wireless.h */ struct wiphy ;
@@ -103,6 +123,10 @@ struct wiphy;* and @key_index * * @set_default_key: set the default key on an interface +* +* @set_beacon: Set the beacon parameters for an access point mode +* interface. The @info parameter can be %NULL when the beacon is +* removed. */ struct cfg80211_ops { int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
@@ -122,6 +146,9 @@ struct cfg80211_ops {int (*set_default_key)(struct wiphy *wiphy,struct net_device *netdev,u8 key_index); + +int (*set_beacon)(struct wiphy *wiphy,struct net_device *dev, + struct beacon_parameters *info); };#endif /* __NET_CFG80211_H */
include/linux/nl80211.h +19 -0
@@ -47,6 +47,10 @@* @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX * or %NL80211_ATTR_MAC. * +* @NL80211_CMD_SET_BEACON: set the beacon on an access point device using +* the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD, +* %NL80211_BEACON_HEAD and %NL80211_BEACON_TAIL attributes. +* * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */
@@ -69,6 +73,11 @@ enum nl80211_commands {NL80211_CMD_NEW_KEY ,NL80211_CMD_DEL_KEY , +NL80211_CMD_GET_BEACON ,/* ? */ +NL80211_CMD_SET_BEACON , +NL80211_CMD_NEW_BEACON ,/* ? */ +NL80211_CMD_DEL_BEACON ,/* ? */ +/* add commands here */ /* used to define NL80211_CMD_MAX below */
@@ -101,6 +110,11 @@ enum nl80211_commands {* @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and * CCMP keys, each six bytes in little endian * +* @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU +* @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing +* @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE +* @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE +* * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */
@@ -123,6 +137,11 @@ enum nl80211_attrs {NL80211_ATTR_KEY_SEQ ,NL80211_ATTR_KEY_DEFAULT , +NL80211_ATTR_BEACON_INTERVAL , +NL80211_ATTR_DTIM_PERIOD , +NL80211_ATTR_BEACON_HEAD , +NL80211_ATTR_BEACON_TAIL , +/* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST,
net/wireless/nl80211.c +111 -0
129 lines not on this page · raw message
Johannes Berg
maintainerRe: [patch 4/9] cfg80211/nl80211: add beacon settings
include/linux/nl80211.h enum nl80211_commands { · line 79
Quoted 5 lines · Johannes Berg
include/linux/nl80211.h +4
-0+NL80211_CMD_GET_BEACON ,/* ? */ +NL80211_CMD_SET_BEACON , +NL80211_CMD_NEW_BEACON ,/* ? */ + NL80211_CMD_DEL_BEACON, /* ? */
As you can see, I currently only support SET_BEACON. DEL_BEACON might make sense as well, and NEW_BEACON could be used when no beacon is configured (SET_BEACON would fail in that case). Right now you can stop beaconing by removing the beacon head which admittedly is kinda nasty. If I did del_beacon/add_beacon then set_beacon would fail with no beacon head, is that better? Further thoughts?
johannes
Johannes Berg
maintainerPATCH 5/9 mac80211: add beacon configuration via cfg80211
In reply to Johannes BergThis patch implements the cfg80211 hooks for configuring beaconing on an access point interface in mac80211. While doing so, it fixes a number of races that could badly crash the machine when the beacon is changed while being requested by the driver.
---
The dtim_count field should possibly also be part of the beacon structure, but the possible race there doesn't really matter, worst thing is that one beacon will be sent with a wrong dtim count if (and only if) userspace changes the dtim period during operation.
net/mac80211/cfg.c | 108 +++++++++++++++++++++++++++++++++++++++++ net/mac80211/debugfs_netdev.c | 27 ---------- net/mac80211/ieee80211_i.h | 14 +++-- net/mac80211/ieee80211_iface.c | 4 - net/mac80211/tx.c | 63 ++++++++++++++--------- 5 files changed, 156 insertions(+), 60 deletions(-)
net/mac80211/cfg.c +108 -0
@@ -10,6 +10,7 @@#include <linux/nl80211.h> #include <linux/rtnetlink.h> #include <net/net_namespace.h> +#include <linux/rcupdate.h> #include <net/cfg80211.h> #include "ieee80211_i.h" #include "cfg.h"
@@ -269,6 +270,112 @@ static int ieee80211_config_default_key(return 0 ; } +static int ieee80211_set_beacon (struct wiphy *wiphy,struct net_device *dev, +struct beacon_parameters *beacon) +{ +struct ieee80211_sub_if_data *sdata =IEEE80211_DEV_TO_SUB_IF (dev); +struct beacon_data *new, *old; +int new_head_len, new_tail_len; +int size; +int err = -EINVAL ; + +if (sdata->type !=IEEE80211_IF_TYPE_AP ) +return -EINVAL ; + + old = sdata->u.ap.beacon; + +/* catch disabling beacons early */ +if (!beacon) { + new =NULL ; + goto done; + } + +/* head must be set */ +if (beacon->head && !beacon->head_len) +return -EINVAL ; + +/* +* This is a kludge. beacon interval should really be part +* of the beacon information. +*/ +if (beacon->interval) { + sdata->local->hw.conf.beacon_int = beacon->interval; +if (ieee80211_hw_config (sdata->local)) +return -EINVAL ; +/* +* We updated some parameter so if below bails out +* it's not an error. +*/ + err =0 ; + } + +/* Need to have a beacon head if we don't have one yet */ +if (!beacon->head && !old) +return err; + +/* sorry, no way to start beaconing without dtim period */ +if (!beacon->dtim_period && !old) +return err; + +/* new or old head? */ +if (beacon->head) + new_head_len = beacon->head_len; +else + new_head_len = old->head_len; + +/* new or old tail? */ +if (beacon->tail || !old) +/* beacon->tail_len will be zero for !beacon->tail */ + new_tail_len = beacon->tail_len; +else + new_tail_len = old->tail_len; + + size =sizeof (*new) + new_head_len + new_tail_len; + + new =kzalloc (size,GFP_KERNEL ); +if (!new) +return -ENOMEM ; + +/* start filling the new info now */ + +/* new or old dtim period? */ +if (beacon->dtim_period) + new->dtim_period = beacon->dtim_period; +else + new->dtim_period = old->dtim_period; + +/* +* pointers go into the block we allocated, +* memory is | beacon_data | head | tail | +*/ + new->head = ((u8 *) new) +sizeof (*new); + new->tail = new->head + new_head_len; + new->head_len = new_head_len; + new->tail_len = new_tail_len; + +/* copy in head */ +if (beacon->head) +memcpy (new->head, beacon->head, new_head_len); +else +memcpy (new->head, old->head, new_head_len); + +/* copy in optional tail */ +if (beacon->tail) +memcpy (new->tail, beacon->tail, new_tail_len); +else +if (old) +memcpy (new->tail, old->tail, new_tail_len); + + done: +rcu_assign_pointer (sdata->u.ap.beacon, new); + +synchronize_rcu (); + +kfree (old); + +return ieee80211_if_config_beacon (dev); +} +struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface,
@@ -277,4 +384,5 @@ struct cfg80211_ops mac80211_config_ops .del_key = ieee80211_del_key, .get_key = ieee80211_get_key, .set_default_key = ieee80211_config_default_key, + .set_beacon = ieee80211_set_beacon, };
net/mac80211/debugfs_netdev.c +0 -27
@@ -125,7 +125,6 @@ __IEEE80211_IF_FILE(flags);/* AP attributes */ IEEE80211_IF_FILE (num_sta_ps, u.ap.num_sta_ps,ATOMIC ); -IEEE80211_IF_FILE (dtim_period, u.ap.dtim_period,DEC );IEEE80211_IF_FILE (dtim_count, u.ap.dtim_count,DEC );IEEE80211_IF_FILE (num_beacons, u.ap.num_beacons,DEC );IEEE80211_IF_FILE (force_unicast_rateidx, u.ap.force_unicast_rateidx,DEC );
@@ -139,26 +138,6 @@ static ssize_t ieee80211_if_fmt_num_buff }__IEEE80211_IF_FILE (num_buffered_multicast); -static ssize_t ieee80211_if_fmt_beacon_head_len ( -const struct ieee80211_sub_if_data *sdata,char *buf,int buflen) -{ -if (sdata->u.ap.beacon_head) -return scnprintf (buf, buflen,"%d\n" , - sdata->u.ap.beacon_head_len); -return scnprintf (buf, buflen,"\n" ); -} -__IEEE80211_IF_FILE (beacon_head_len); - -static ssize_t ieee80211_if_fmt_beacon_tail_len ( -const struct ieee80211_sub_if_data *sdata,char *buf,int buflen) -{ -if (sdata->u.ap.beacon_tail) -return scnprintf (buf, buflen,"%d\n" , - sdata->u.ap.beacon_tail_len); -return scnprintf (buf, buflen,"\n" ); -} -__IEEE80211_IF_FILE (beacon_tail_len); -/* WDS attributes */ IEEE80211_IF_FILE (peer, u.wds.remote_addr,MAC );
@@ -195,14 +174,11 @@ static void add_ap_files(struct ieee8021DEBUGFS_ADD (eapol, ap);DEBUGFS_ADD (ieee8021_x, ap);DEBUGFS_ADD (num_sta_ps, ap); -DEBUGFS_ADD (dtim_period, ap);DEBUGFS_ADD (dtim_count, ap);DEBUGFS_ADD (num_beacons, ap);DEBUGFS_ADD (force_unicast_rateidx, ap);DEBUGFS_ADD (max_ratectrl_rateidx, ap);DEBUGFS_ADD (num_buffered_multicast, ap); -DEBUGFS_ADD (beacon_head_len, ap); -DEBUGFS_ADD (beacon_tail_len, ap); }static void add_wds_files (struct ieee80211_sub_if_data *sdata)
@@ -288,14 +264,11 @@ static void del_ap_files(struct ieee8021DEBUGFS_DEL (eapol, ap);DEBUGFS_DEL (ieee8021_x, ap);DEBUGFS_DEL (num_sta_ps, ap); -DEBUGFS_DEL (dtim_period, ap);DEBUGFS_DEL (dtim_count, ap);DEBUGFS_DEL (num_beacons, ap);DEBUGFS_DEL (force_unicast_rateidx, ap);DEBUGFS_DEL (max_ratectrl_rateidx, ap);DEBUGFS_DEL (num_buffered_multicast, ap); -DEBUGFS_DEL (beacon_head_len, ap); -DEBUGFS_DEL (beacon_tail_len, ap); }static void del_wds_files (struct ieee80211_sub_if_data *sdata)
net/mac80211/ieee80211_i.h +8 -6
@@ -186,9 +186,14 @@ typedef ieee80211_txrx_result (*ieee8021typedef ieee80211_txrx_result (*ieee80211_rx_handler ) (struct ieee80211_txrx_data *rx); +struct beacon_data { +u8 *head, *tail; +int head_len, tail_len; +int dtim_period; +}; +struct ieee80211_if_ap { -u8 *beacon_head, *beacon_tail; -int beacon_head_len, beacon_tail_len; +struct beacon_data *beacon;struct list_head vlans;
@@ -201,7 +206,7 @@ struct ieee80211_if_ap {u8 tim[sizeof (unsigned long ) *BITS_TO_LONGS (IEEE80211_MAX_AID +1 )];atomic_t num_sta_ps;/* number of stations in PS mode */ struct sk_buff_head ps_bc_buf; -int dtim_period, dtim_count; +int dtim_count;int force_unicast_rateidx;/* forced TX rateidx for unicast frames */ int max_ratectrl_rateidx;/* max TX rateidx for rate control */ int num_beacons;/* number of TXed beacon frames for this BSS */
@@ -357,14 +362,11 @@ struct ieee80211_sub_if_data {struct dentry *eapol;struct dentry *ieee8021_x;struct dentry *num_sta_ps; -struct dentry *dtim_period;struct dentry *dtim_count;struct dentry *num_beacons;struct dentry *force_unicast_rateidx;struct dentry *max_ratectrl_rateidx;struct dentry *num_buffered_multicast; -struct dentry *beacon_head_len; -struct dentry *beacon_tail_len; } ap;struct {struct dentry *channel_use;
net/mac80211/ieee80211_iface.c +1 -3
@@ -127,7 +127,6 @@ void ieee80211_if_set_type(struct net_de sdata->u.vlan.ap =NULL ;break ;case IEEE80211_IF_TYPE_AP : - sdata->u.ap.dtim_period =2 ; sdata->u.ap.force_unicast_rateidx =-1 ; sdata->u.ap.max_ratectrl_rateidx =-1 ;skb_queue_head_init (&sdata->u.ap.ps_bc_buf);
@@ -208,8 +207,7 @@ void ieee80211_if_reinit(struct net_devi } } -kfree (sdata->u.ap.beacon_head); -kfree (sdata->u.ap.beacon_tail); +kfree (sdata->u.ap.beacon);while ((skb =skb_dequeue (&sdata->u.ap.ps_bc_buf))) { local->total_ps_buffered--;
net/mac80211/tx.c +39 -24
133 lines not on this page · raw message
Re: [patch 5/9] mac80211: add beacon configuration via cfg80211
Quoted 32 lines · Johannes Berg
This patch implements the cfg80211 hooks for configuring beaconing on an access point interface in mac80211. While doing so, it fixes a number of races that could badly crash the machine when the beacon is changed while being requested by the driver.
Signed-off-by Johannes Berg <[email protected]>---
Thedtim_countfield should possibly also be part of the beacon structure, but the possible race there doesn't really matter, worst thing is that one beacon will be sent with a wrong dtim count if (and only if) userspace changes the dtim period during operation.net/mac80211/cfg.c | 108 +++++++++++++++++++++++++++++++++++++++++ net/mac80211/debugfs_netdev.c | 27 ---------- net/mac80211/ieee80211_i.h | 14 +++-- net/mac80211/ieee80211_iface.c | 4 - net/mac80211/tx.c | 63 ++++++++++++++--------- 5 files changed, 156 insertions(+), 60 deletions(-)net/mac80211/cfg.c 2007-10-25 10:46:56.070256998 +0200 renamed from net/mac80211/cfg.c 2007-10-24 11:35:49.722690568 +0200 +1
-0@@ -10,6 +10,7 @@ #include <linux/nl80211.h> #include <linux/rtnetlink.h> #include <net/net_namespace.h> +#include <linux/rcupdate.h> #include <net/cfg80211.h> #include "ieee80211_i.h" #include "cfg.h"
net/mac80211/cfg.c 2007-10-25 10:46:56.070256998 +0200 static int ieee80211_config_default_key( · line 274
Quoted 5 lines
net/mac80211/cfg.c 2007-10-25 10:46:56.070256998 +0200 renamed from net/mac80211/cfg.c 2007-10-24 11:35:49.722690568 +0200 +2
-0@@ -269,6 +270,112 @@ static int ieee80211_config_default_key( return 0; } +static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *beacon)
To be consistent how about s/beacon/params here for beacon_parameters.
Luis
Johannes Berg
maintainerRe: [patch 5/9] mac80211: add beacon configuration via cfg80211
Quoted 6 lines
net/mac80211/cfg.c static int ieee80211_config_default_key( · line 274
Quoted 4 lines
net/mac80211/cfg.c +2
-0+static int ieee80211_set_beacon (struct wiphy *wiphy,struct net_device *dev, +struct beacon_parameters *beacon)To be consistent how about s/beacon/params here for
beacon_parameters.
Heh, I guess I can do that.
johannes
Johannes Berg
maintainerPATCH 6/9 nl80211/cfg80211: station handling
In reply to Johannes BergThis patch adds station handling to cfg80211/nl80211.
--- include/linux/nl80211.h | 68 +++++++++++++ include/net/cfg80211.h | 54 ++++++++++ net/wireless/nl80211.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 358 insertions(+)
include/linux/nl80211.h +68 -0
@@ -7,6 +7,18 @@*/ /** +* DOC: Station handling +* +* Stations are added per interface, but a special case exists with VLAN +* interfaces. When a station is bound to an AP interface, it may be moved +* into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN). +* The station is still assumed to belong to the AP interface it was added +* to. +* +* TODO: need more info? +*/ + +/** * enum nl80211_commands - supported nl80211 commands * * @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -51,6 +63,16 @@* the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD, * %NL80211_BEACON_HEAD and %NL80211_BEACON_TAIL attributes. * +* @NL80211_CMD_GET_STATION: Get station attributes for station identified by +* %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. +* @NL80211_CMD_SET_STATION: Set station attributes for station identified by +* %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. +* @NL80211_CMD_NEW_STATION: Add a station with given attributes to the +* the interface identified by %NL80211_ATTR_IFINDEX. +* @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC +* or, if no MAC address given, all stations, on the interface identified +* by %NL80211_ATTR_IFINDEX. +* * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */
@@ -78,6 +100,11 @@ enum nl80211_commands {NL80211_CMD_NEW_BEACON ,/* ? */ NL80211_CMD_DEL_BEACON ,/* ? */ +NL80211_CMD_GET_STATION , +NL80211_CMD_SET_STATION , +NL80211_CMD_NEW_STATION , +NL80211_CMD_DEL_STATION , +/* add commands here */ /* used to define NL80211_CMD_MAX below */
@@ -115,6 +142,17 @@ enum nl80211_commands {* @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE * +* @NL80211_ATTR_STA_AID: Association ID for the station (u16) +* @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of +* &enum nl80211_sta_flags. +* @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by +* IEEE 802.11 7.3.1.6 (u16). +* @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported +* rates as defined by IEEE 802.11 7.3.2.2 but without the length +* restriction (at most %NL80211_MAX_SUPP_RATES). +* @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station +* to, or the AP interface the station was originally added to to. +* * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */
@@ -142,12 +180,20 @@ enum nl80211_attrs {NL80211_ATTR_BEACON_HEAD ,NL80211_ATTR_BEACON_TAIL , +NL80211_ATTR_STA_AID , +NL80211_ATTR_STA_FLAGS , +NL80211_ATTR_STA_LISTEN_INTERVAL , +NL80211_ATTR_STA_SUPPORTED_RATES , +NL80211_ATTR_STA_VLAN , +/* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST,NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST -1 }; +#define NL80211_MAX_SUPP_RATES 32 +/** * enum nl80211_iftype - (virtual) interface types *
@@ -179,4 +225,26 @@ enum nl80211_iftype {NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST -1 }; +/** +* enum nl80211_sta_flags - station flags +* +* Station flags. When a station is added to an AP interface, it is +* assumed to be already associated (and hence authenticated.) +* +* @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X) +* @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames +* with short barker preamble +* @NL80211_STA_FLAG_WME: station is WME/QoS capable +*/ +enum nl80211_sta_flags { + __NL80211_STA_FLAG_INVALID, +NL80211_STA_FLAG_AUTHORIZED , +NL80211_STA_FLAG_SHORT_PREAMBLE , +NL80211_STA_FLAG_WME , + +/* keep last */ + __NL80211_STA_FLAG_AFTER_LAST, +NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST -1 +}; +#endif /* __LINUX_NL80211_H */
include/net/cfg80211.h +54 -0
72 lines not on this page · raw message
net/wireless/nl80211.c +236 -0
254 lines not on this page · raw message
Re: [patch 6/9] nl80211/cfg80211: station handling
Quoted 62 lines · Johannes Berg
This patch adds station handling to cfg80211/nl80211.
Signed-off-by Johannes Berg <[email protected]>--- include/linux/nl80211.h | 68 +++++++++++++ include/net/cfg80211.h | 54 ++++++++++ net/wireless/nl80211.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 358 insertions(+)include/linux/nl80211.h 2007-10-24 16:57:06.090256076 +0200 renamed from include/linux/nl80211.h 2007-10-24 16:50:00.170256240 +0200 +27
-0@@ -7,6 +7,18 @@ */ /** + * DOC: Station handling + * + * Stations are added per interface, but a special case exists with VLAN + * interfaces. When a station is bound to an AP interface, it may be moved + * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN). + * The station is still assumed to belong to the AP interface it was added + * to. + * + * TODO: need more info? + */ + +/** * enum nl80211_commands - supported nl80211 commands * * @NL80211_CMD_UNSPEC: unspecified command to catch errors@@ -51,6 +63,16 @@ * the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD, * %NL80211_BEACON_HEAD and %NL80211_BEACON_TAIL attributes. * + * @NL80211_CMD_GET_STATION: Get station attributes for station identified by + * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_SET_STATION: Set station attributes for station identified by + * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the + * the interface identified by %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC + * or, if no MAC address given, all stations, on the interface identified + * by %NL80211_ATTR_IFINDEX. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */@@ -78,6 +100,11 @@ enum nl80211_commands { NL80211_CMD_NEW_BEACON, /* ? */ NL80211_CMD_DEL_BEACON, /* ? */ + NL80211_CMD_GET_STATION, + NL80211_CMD_SET_STATION, + NL80211_CMD_NEW_STATION, + NL80211_CMD_DEL_STATION, + /* add commands here */ /* used to define NL80211_CMD_MAX below */@@ -115,6 +142,17 @@ enum nl80211_commands { * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
include/linux/nl80211.h 2007-10-24 16:57:06.090256076 +0200 enum nl80211_commands { · line 152
Quoted 10 lines
include/linux/nl80211.h 2007-10-24 16:57:06.090256076 +0200 renamed from include/linux/nl80211.h 2007-10-24 16:50:00.170256240 +0200 +8
-0* @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE * + * @NL80211_ATTR_STA_AID: Association ID for the station (u16) + * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of + * &enum nl80211_sta_flags. + * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by + * IEEE 802.11 7.3.1.6 (u16). + * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported + * rates as defined by IEEE 802.11 7.3.2.2 but without the length + * restriction (at most %NL80211_MAX_SUPP_RATES).
Is this necessary? Shouldn't we just embrace the supported rates of the hardware? If cfg80211 is extended to have devices register their hardware capabilities then we can take it from there perhaps ?
Quoted 190 lines
include/linux/nl80211.h 2007-10-24 16:57:06.090256076 +0200 renamed from include/linux/nl80211.h 2007-10-24 16:50:00.170256240 +0200 +33
-0+ * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station + * to, or the AP interface the station was originally added to to. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */@@ -142,12 +180,20 @@ enum nl80211_attrs { NL80211_ATTR_BEACON_HEAD, NL80211_ATTR_BEACON_TAIL, + NL80211_ATTR_STA_AID, + NL80211_ATTR_STA_FLAGS, + NL80211_ATTR_STA_LISTEN_INTERVAL, + NL80211_ATTR_STA_SUPPORTED_RATES, + NL80211_ATTR_STA_VLAN, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 }; +#define NL80211_MAX_SUPP_RATES 32 + /** * enum nl80211_iftype - (virtual) interface types *@@ -179,4 +225,26 @@ enum nl80211_iftype { NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1 }; +/** + * enum nl80211_sta_flags - station flags + * + * Station flags. When a station is added to an AP interface, it is + * assumed to be already associated (and hence authenticated.) + * + * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X) + * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames + * with short barker preamble + * @NL80211_STA_FLAG_WME: station is WME/QoS capable + */ +enum nl80211_sta_flags { + __NL80211_STA_FLAG_INVALID, + NL80211_STA_FLAG_AUTHORIZED, + NL80211_STA_FLAG_SHORT_PREAMBLE, + NL80211_STA_FLAG_WME, + + /* keep last */ + __NL80211_STA_FLAG_AFTER_LAST, + NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1 +}; + #endif /* __LINUX_NL80211_H */include/net/cfg80211.h 2007-10-24 16:56:35.020252386 +0200 renamed from include/net/cfg80211.h 2007-10-24 16:50:00.200259495 +0200 +54
-0@@ -89,6 +89,47 @@ struct beacon_parameters { int head_len, tail_len; }; +/** + * enum station_flags - station flags + * + * Station capability flags. Note that these must be the bits + * according to the nl80211 flags. + * + * @STATION_FLAG_CHANGED: station flags were changed + * @STATION_FLAG_AUTHORIZED: station is authorized to send frames (802.1X) + * @STATION_FLAG_SHORT_PREAMBLE: station is capable of receiving frames + * with short preambles + * @STATION_FLAG_WME: station is WME/QoS capable + */ +enum station_flags { + STATION_FLAG_CHANGED = 1<<0, + STATION_FLAG_AUTHORIZED = 1<<NL80211_STA_FLAG_AUTHORIZED, + STATION_FLAG_SHORT_PREAMBLE = 1<<NL80211_STA_FLAG_SHORT_PREAMBLE, + STATION_FLAG_WME = 1<<NL80211_STA_FLAG_WME, +}; + +/** + * struct station_parameters - station parameters + * + * Used to change and create a new station. + * + * @vlan: vlan interface station should belong to + * @supported_rates: supported rates in IEEE 802.11 format + * (or NULL for no change) + * @supported_rates_len: number of supported rates + * @station_flags: station flags (see &enum station_flags) + * @listen_interval: listen interval or -1 for no change + * @aid: AID or zero for no change + */ +struct station_parameters { + u8 *supported_rates; + struct net_device *vlan; + u32 station_flags; + int listen_interval; + u16 aid; + u8 supported_rates_len; +}; + /* from net/wireless.h */ struct wiphy;@@ -127,6 +168,12 @@ struct wiphy; * @set_beacon: Set the beacon parameters for an access point mode * interface. The @info parameter can be %NULL when the beacon is * removed. + * + * @add_station: Add a new station. + * + * @del_station: Remove a station; @mac may be NULL to remove all stations. + * + * @change_station: Modify a given station. */ struct cfg80211_ops { int (*add_virtual_intf)(struct wiphy *wiphy, char *name,@@ -149,6 +196,13 @@ struct cfg80211_ops { int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev, struct beacon_parameters *info); + + int (*add_station)(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_parameters *params); + int (*del_station)(struct wiphy *wiphy, struct net_device *dev, + u8 *mac); + int (*change_station)(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_parameters *params); }; #endif /* __NET_CFG80211_H */net/wireless/nl80211.c 2007-10-24 16:57:23.710253471 +0200 renamed from net/wireless/nl80211.c 2007-10-24 16:50:00.230261882 +0200 +46
-0@@ -76,6 +76,12 @@ static struct nla_policy nl80211_policy[ .len = IEEE80211_MAX_DATA_LEN }, [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY, .len = IEEE80211_MAX_DATA_LEN }, + [NL80211_ATTR_STA_AID] = { .type = NLA_U16 }, + [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED }, + [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 }, + [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, + .len = NL80211_MAX_SUPP_RATES }, + [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, }; /* message building helper */@@ -692,6 +698,211 @@ static int nl80211_del_beacon(struct sk_ return err; } +static +struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] __read_mostly = { + [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG }, + [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG }, + [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG }, +}; + +static int parse_station_flags(struct nlattr *nla, u32 *staflags) +{ + struct nlattr *flags[NL80211_STA_FLAG_MAX + 1]; + int flag; + + *staflags = 0; + + if (!nla) + return 0; + + if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX, + nla, sta_flags_policy)) + return -EINVAL; + + *staflags = STATION_FLAG_CHANGED; + + for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) + if (flags[flag]) + *staflags |= (1<<flag); + + return 0; +} + +static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) +{ + return -EOPNOTSUPP; +} + +/* + * Get vlan interface making sure it is on the right wiphy. + */ +static int get_vlan(struct nlattr *vlanattr, + struct cfg80211_registered_device *rdev,
net/wireless/nl80211.c 2007-10-24 16:57:23.710253471 +0200 static int nl80211_del_beacon(struct sk_ · line 750
Quoted 10 lines
net/wireless/nl80211.c 2007-10-24 16:57:23.710253471 +0200 renamed from net/wireless/nl80211.c 2007-10-24 16:50:00.230261882 +0200 +8
-0+ struct net_device **vlan) +{ + if (vlanattr) { + *vlan = dev_get_by_index(&init_net, nla_get_u32(vlanattr)); + if (!*vlan) + return -ENODEV; + if (!(*vlan)->ieee80211_ptr) + return -EINVAL;
Check #1 for (!(*vlan)->ieee80211_ptr)
net/wireless/nl80211.c 2007-10-24 16:57:23.710253471 +0200 static int nl80211_del_beacon(struct sk_ · line 752
Quoted 2 lines
net/wireless/nl80211.c 2007-10-24 16:57:23.710253471 +0200 renamed from net/wireless/nl80211.c 2007-10-24 16:50:00.230261882 +0200 +2
-0+ if (!(*vlan)->ieee80211_ptr) + return -EINVAL;
Check #2 for (!(*vlan)->ieee80211_ptr). Double check.
Quoted 38 lines
net/wireless/nl80211.c 2007-10-24 16:57:23.710253471 +0200 renamed from net/wireless/nl80211.c 2007-10-24 16:50:00.230261882 +0200 +38
-0+ if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy) + return -EINVAL; + } + return 0; +} + +static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + int err; + struct net_device *dev; + struct station_parameters params; + u8 *mac_addr = NULL; + + memset(¶ms, 0, sizeof(params)); + + params.listen_interval = -1; + + if (info->attrs[NL80211_ATTR_STA_AID]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + + if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) { + params.supported_rates = + nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); + params.supported_rates_len = + nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); + } + + if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) + params.listen_interval = + nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); + + if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
net/wireless/nl80211.c 2007-10-24 16:57:23.710253471 +0200 static int nl80211_del_beacon(struct sk_ · line 800
Quoted 10 lines
net/wireless/nl80211.c 2007-10-24 16:57:23.710253471 +0200 renamed from net/wireless/nl80211.c 2007-10-24 16:50:00.230261882 +0200 +10
-0+ ¶ms.station_flags)) + return -EINVAL; + + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); + if (err) + return err; + + err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); + if (err) + goto out;
This is minor, but how about doing the check of info->attrs[NL80211_ATTR_STA_VLAN] outside of get_vlan to make it clear here we're setting it to 0 if not found?
Quoted 150 lines
net/wireless/nl80211.c 2007-10-24 16:57:23.710253471 +0200 renamed from net/wireless/nl80211.c 2007-10-24 16:50:00.230261882 +0200 +107
-0+ + if (!drv->ops->change_station) { + err = -EOPNOTSUPP; + goto out; + } + + rtnl_lock(); + err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, ¶ms); + rtnl_unlock(); + + out: + if (params.vlan) + dev_put(params.vlan); + cfg80211_put_dev(drv); + dev_put(dev); + return err; +} + +static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + int err; + struct net_device *dev; + struct station_parameters params; + u8 *mac_addr = NULL; + + memset(¶ms, 0, sizeof(params)); + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_STA_AID]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) + return -EINVAL; + + mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + params.supported_rates = + nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); + params.supported_rates_len = + nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); + params.listen_interval = + nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); + params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); + + if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS], + ¶ms.station_flags)) + return -EINVAL; + + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); + if (err) + return err; + + err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); + if (err) + goto out; + + if (!drv->ops->add_station) { + err = -EOPNOTSUPP; + goto out; + } + + rtnl_lock(); + err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, ¶ms); + rtnl_unlock(); + + out: + if (params.vlan) + dev_put(params.vlan); + cfg80211_put_dev(drv); + dev_put(dev); + return err; +} + +static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + int err; + struct net_device *dev; + u8 *mac_addr = NULL; + + if (info->attrs[NL80211_ATTR_MAC]) + mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); + + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); + if (err) + return err; + + if (!drv->ops->del_station) { + err = -EOPNOTSUPP; + goto out; + } + + rtnl_lock(); + err = drv->ops->del_station(&drv->wiphy, dev, mac_addr); + rtnl_unlock(); + + out: + cfg80211_put_dev(drv); + dev_put(dev); + return err; +} + static struct genl_ops nl80211_ops[] = {{ .cmd = NL80211_CMD_GET_WIPHY,net/wireless/nl80211.c 2007-10-24 16:57:23.710253471 +0200 renamed from net/wireless/nl80211.c 2007-10-24 16:50:00.230261882 +0200 +25
-2@@ -774,6 +985,31 @@ static struct genl_ops nl80211_ops[] = { .flags = GENL_ADMIN_PERM, .doit = nl80211_del_beacon, }, + { + .cmd = NL80211_CMD_GET_STATION, + .doit = nl80211_get_station, + /* TODO: implement dumpit */ + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_SET_STATION, + .doit = nl80211_set_station, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_NEW_STATION, + .doit = nl80211_new_station, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_DEL_STATION, + .doit = nl80211_del_station, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, }; /* multicast groups */ -- -To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [patch 6/9] nl80211/cfg80211: station handling
Quoted 8 lines · On Thursday 25 October 2007 11:46:03 you wrote:
Quoted 3 lines
+ * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of
supported + * rates as defined by IEEE 802.11 7.3.2.2 but without the
length + * restriction (at most %NL80211_MAX_SUPP_RATES).Is this necessary? Shouldn't we just embrace the supported rates of the hardware? If cfg80211 is extended to have devices register their hardware capabilities then we can take it from there perhaps ?
This is for the supported rates of the sta we want to TX to. Rate control needs to know what rates are valid for a particular sta.
-Michael Wu
Johannes Berg
maintainerRe: [patch 6/9] nl80211/cfg80211: station handling
In reply to Luis R. RodriguezQuoted 15 lines
Quoted 4 lines
net/wireless/nl80211.c +2
-0+static int get_vlan(struct nlattr *vlanattr, + struct cfg80211_registered_device *rdev,net/wireless/nl80211.c static int nl80211_del_beacon(struct sk_ · line 748
Quoted 10 lines
net/wireless/nl80211.c +8
-0+ struct net_device **vlan) +{ +if (vlanattr) { + *vlan =dev_get_by_index (&init_net,nla_get_u32 (vlanattr)); +if (!*vlan) +return -ENODEV ; +if (!(*vlan)->ieee80211_ptr) +return -EINVAL ;
Quoted 6 lines
Check #1 for (!(*vlan)->ieee80211_ptr)
Review
Quoted 2 lines
(quoted diff) +2
-0+ if (!(*vlan)->ieee80211_ptr) + return -EINVAL;Check #2 for (!(*vlan)->ieee80211_ptr). Double check.
Hah. I think the latter was meant to be ->wiphy but that shouldn't be necessary.
Quoted 7 lines
net/wireless/nl80211.c static int nl80211_del_beacon(struct sk_ · line 798
Quoted 3 lines
net/wireless/nl80211.c +3
-0+ err =get_vlan (info->attrs[NL80211_ATTR_STA_VLAN ], drv, ¶ms.vlan); +if (err) + goto out;This is minor, but how about doing the check of info->attrs[NL80211_ATTR_STA_VLAN] outside of
get_vlanto make it clear here we're setting it to 0 if not found?
Dunno. That makes the error path more complicated, no? I guess that then I'd rather do an *vlan = NULL assignment in get_vlan() to make it crystal clear.
johannes
Johannes Berg
maintainerPATCH 7/9 mac80211: implement cfg80211s station handling
In reply to Johannes BergThis implements station handling from userspace via cfg80211 in mac80211.
--- net/mac80211/cfg.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+)
net/mac80211/cfg.c +192 -0
@@ -14,6 +14,7 @@#include <net/cfg80211.h> #include "ieee80211_i.h" #include "cfg.h" +#include "ieee80211_rate.h" static enum ieee80211_if_types nl80211_type_to_mac80211_type (enum nl80211_iftype type)
@@ -382,6 +383,194 @@ static int ieee80211_set_beacon(struct wreturn ieee80211_if_config_beacon (dev); } +/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ +struct iapp_layer2_update { +u8 da[ETH_ALEN ];/* broadcast */ +u8 sa[ETH_ALEN ];/* STA addr */ +__be16 len;/* 6 */ +u8 dsap;/* 0 */ +u8 ssap;/* 0 */ +u8 control; +u8 xid_info[3 ]; +} __attribute__ ((packed)); + +static void ieee80211_send_layer2_update (struct sta_info *sta) +{ +struct iapp_layer2_update *msg; +struct sk_buff *skb; + +/* Send Level 2 Update Frame to update forwarding tables in layer 2 +* bridge devices */ + + skb =dev_alloc_skb (sizeof (*msg)); +if (!skb) +return ; + msg = (struct iapp_layer2_update *)skb_put (skb,sizeof (*msg)); + +/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID) +* Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */ + +memset (msg->da,0xff ,ETH_ALEN ); +memcpy (msg->sa, sta->addr,ETH_ALEN ); + msg->len =htons (6 ); + msg->dsap =0 ; + msg->ssap =0x01 ;/* NULL LSAP, CR Bit: Response */ + msg->control =0xaf ;/* XID response lsb.1111F101. +* F=0 (no poll command; unsolicited frame) */ + msg->xid_info[0 ] =0x81 ;/* XID format identifier */ + msg->xid_info[1 ] =1 ;/* LLC types/classes: Type 1 LLC */ + msg->xid_info[2 ] =0 ;/* XID sender's receive window size (RW) */ + + skb->dev = sta->dev; + skb->protocol =eth_type_trans (skb, sta->dev); +memset (skb->cb,0 ,sizeof (skb->cb)); +netif_rx (skb); +} + +static void sta_apply_parameters (struct ieee80211_local *local, +struct sta_info *sta, +struct station_parameters *params) +{ +u32 rates; +int i, j; +struct ieee80211_hw_mode *mode; + +if (params->station_flags &STATION_FLAG_CHANGED ) { + sta->flags &= ~WLAN_STA_AUTHORIZED ; +if (params->station_flags &STATION_FLAG_AUTHORIZED ) + sta->flags |=WLAN_STA_AUTHORIZED ; + + sta->flags &= ~WLAN_STA_SHORT_PREAMBLE ; +if (params->station_flags &STATION_FLAG_SHORT_PREAMBLE ) + sta->flags |=WLAN_STA_SHORT_PREAMBLE ; + + sta->flags &= ~WLAN_STA_WME ; +if (params->station_flags &STATION_FLAG_WME ) + sta->flags |=WLAN_STA_WME ; + } + +if (params->aid) { + sta->aid = params->aid; +if (sta->aid >IEEE80211_MAX_AID ) + sta->aid =0 ;/* XXX: should this be an error? */ + } + +if (params->listen_interval >=0 ) + sta->listen_interval = params->listen_interval; + +if (params->supported_rates) { + rates =0 ; + mode = local->oper_hw_mode; +for (i =0 ; i < params->supported_rates_len; i++) { +int rate = (params->supported_rates[i] &0x7f ) *5 ; +for (j =0 ; j < mode->num_rates; j++) { +if (mode->rates[j].rate == rate) + rates |=BIT (j); + } + } + sta->supp_rates = rates; + } +} + +static int ieee80211_add_station (struct wiphy *wiphy,struct net_device *dev, +u8 *mac,struct station_parameters *params) +{ +struct ieee80211_local *local =wdev_priv (dev->ieee80211_ptr); +struct sta_info *sta; +struct ieee80211_sub_if_data *sdata; + +/* Prevent a race with changing the rate control algorithm */ +if (!netif_running (dev)) +return -ENETDOWN ; + +/* XXX: get sta belonging to dev */ + sta =sta_info_get (local, mac); +if (sta) { +sta_info_put (sta); +return -EEXIST ; + } + +if (params->vlan) { + sdata =IEEE80211_DEV_TO_SUB_IF (params->vlan); + +if (sdata->type !=IEEE80211_IF_TYPE_VLAN || + sdata->type !=IEEE80211_IF_TYPE_AP ) +return -EINVAL ; + }else + sdata =IEEE80211_DEV_TO_SUB_IF (dev); + + sta =sta_info_add (local, dev, mac,GFP_KERNEL ); +if (!sta) +return -ENOMEM ; + + sta->dev = sdata->dev; +if (sdata->type ==IEEE80211_IF_TYPE_VLAN || + sdata->type ==IEEE80211_IF_TYPE_AP ) +ieee80211_send_layer2_update (sta); + + sta->flags =WLAN_STA_AUTH |WLAN_STA_ASSOC ; + +sta_apply_parameters (local, sta, params); + +rate_control_rate_init (sta, local); + +sta_info_put (sta); + +return 0 ; +} + +static int ieee80211_del_station (struct wiphy *wiphy,struct net_device *dev, +u8 *mac) +{ +struct ieee80211_local *local =wdev_priv (dev->ieee80211_ptr); +struct sta_info *sta; + +if (mac) { +/* XXX: get sta belonging to dev */ + sta =sta_info_get (local, mac); +if (!sta) +return -ENOENT ; + +sta_info_free (sta); +sta_info_put (sta); + }else +sta_info_flush (local, dev); + +return 0 ; +} + +static int ieee80211_change_station (struct wiphy *wiphy, +struct net_device *dev, +u8 *mac, +struct station_parameters *params) +{ +struct ieee80211_local *local =wdev_priv (dev->ieee80211_ptr); +struct sta_info *sta; +struct ieee80211_sub_if_data *vlansdata; + +/* XXX: get sta belonging to dev */ + sta =sta_info_get (local, mac); +if (!sta) +return -ENOENT ; + +if (params->vlan && params->vlan != sta->dev) { + vlansdata =IEEE80211_DEV_TO_SUB_IF (params->vlan); + +if (vlansdata->type !=IEEE80211_IF_TYPE_VLAN || + vlansdata->type !=IEEE80211_IF_TYPE_AP ) +return -EINVAL ; + + sta->dev = params->vlan; +ieee80211_send_layer2_update (sta); + } + +sta_apply_parameters (local, sta, params); + +sta_info_put (sta); + +return 0 ; +} +struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface,
@@ -391,4 +580,7 @@ struct cfg80211_ops mac80211_config_ops .get_key = ieee80211_get_key, .set_default_key = ieee80211_config_default_key, .set_beacon = ieee80211_set_beacon, + .add_station = ieee80211_add_station, + .del_station = ieee80211_del_station, + .change_station = ieee80211_change_station, };
Johannes Berg
maintainerPATCH 8/9 cfg80211/nl80211: implement station attribute retrieval
In reply to Johannes BergAfter a station is added to the kernel's structures, userspace has to be able to retrieve statistics about that station, especially whether the station was idle and how much bytes were transferred to and from it. This adds the necessary code to nl80211.
--- include/linux/nl80211.h | 28 ++++++++++++++++ include/net/cfg80211.h | 35 ++++++++++++++++++++ net/wireless/nl80211.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 144 insertions(+), 1 deletion(-)
include/linux/nl80211.h +28 -0
@@ -152,6 +152,9 @@ enum nl80211_commands {* restriction (at most %NL80211_MAX_SUPP_RATES). * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station * to, or the AP interface the station was originally added to to. +* @NL80211_ATTR_STA_STATS: statistics for a station, part of station info +* given for %NL80211_CMD_GET_STATION, nested attribute containing +* info as possible, see &enum nl80211_sta_stats. * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -185,6 +188,7 @@ enum nl80211_attrs {NL80211_ATTR_STA_LISTEN_INTERVAL ,NL80211_ATTR_STA_SUPPORTED_RATES ,NL80211_ATTR_STA_VLAN , + NL80211_ATTR_STA_STATS,/* add attributes here, update the policy in nl80211.c */
@@ -247,4 +251,28 @@ enum nl80211_sta_flags {NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST -1 }; +/** +* enum nl80211_sta_stats - station statistics +* +* These attribute types are used with %NL80211_ATTR_STA_STATS +* when getting information about a station. +* +* @__NL80211_STA_STAT_INVALID: attribute number 0 is reserved +* @NL80211_STA_STAT_INACTIVE_TIME: time since last activity (u32, msecs) +* @NL80211_STA_STAT_RX_BYTES: total received bytes (u32, from this station) +* @NL80211_STA_STAT_TX_BYTES: total transmitted bytes (u32, to this station) +* @__NL80211_STA_STAT_AFTER_LAST: internal +* @NL80211_STA_STAT_MAX: highest possible station stats attribute +*/ +enum nl80211_sta_stats { + __NL80211_STA_STAT_INVALID, +NL80211_STA_STAT_INACTIVE_TIME , +NL80211_STA_STAT_RX_BYTES , +NL80211_STA_STAT_TX_BYTES , + +/* keep last */ + __NL80211_STA_STAT_AFTER_LAST, +NL80211_STA_STAT_MAX = __NL80211_STA_STAT_AFTER_LAST -1 +}; +#endif /* __LINUX_NL80211_H */
include/net/cfg80211.h +35 -0
@@ -130,6 +130,39 @@ struct station_parameters {u8 supported_rates_len; }; +/** +* enum station_stats_flags - station statistics flags +* +* Used by the driver to indicate which info in &struct station_stats +* it has filled in during get_station(). +* +* @STATION_STAT_INACTIVE_TIME: @inactive_time filled +* @STATION_STAT_RX_BYTES: @rx_bytes filled +* @STATION_STAT_TX_BYTES: @tx_bytes filled +*/ +enum station_stats_flags { +STATION_STAT_INACTIVE_TIME =1 <<0 , +STATION_STAT_RX_BYTES =1 <<1 , +STATION_STAT_TX_BYTES =1 <<2 , +}; + +/** +* struct station_stats - station statistics +* +* Station information filled by driver for get_station(). +* +* @filled: bitflag of flags from &enum station_stats_flags +* @inactive_time: time since last station activity (tx/rx) in milliseconds +* @rx_bytes: bytes received from this station +* @tx_bytes: bytes transmitted to this station +*/ +struct station_stats { +u32 filled; +u32 inactive_time; +u32 rx_bytes; +u32 tx_bytes; +}; +/* from net/wireless.h */ struct wiphy ;
@@ -203,6 +236,8 @@ struct cfg80211_ops { u8 *mac);int (*change_station)(struct wiphy *wiphy,struct net_device *dev,u8 *mac,struct station_parameters *params); +int (*get_station)(struct wiphy *wiphy,struct net_device *dev, + u8 *mac, struct station_stats *stats); };#endif /* __NET_CFG80211_H */
net/wireless/nl80211.c +81 -1
90 lines not on this page · raw message
Johannes Berg
maintainerPATCH 9/9 mac80211: implement station stats retrieval
In reply to Johannes BergThis implements the required cfg80211 callback in mac80211 to allow userspace to get station statistics.
--- net/mac80211/cfg.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
net/mac80211/cfg.c +26 -0
@@ -571,6 +571,31 @@ static int ieee80211_change_station(strureturn 0 ; } +static int ieee80211_get_station (struct wiphy *wiphy,struct net_device *dev, +u8 *mac,struct station_stats *stats) +{ +struct ieee80211_local *local =wdev_priv (dev->ieee80211_ptr); +struct sta_info *sta; + + sta =sta_info_get (local, mac); +if (!sta) +return -ENOENT ; + +/* XXX: verify sta->dev == dev */ + + stats->filled =STATION_STAT_INACTIVE_TIME | +STATION_STAT_RX_BYTES | +STATION_STAT_TX_BYTES ; + + stats->inactive_time =jiffies_to_msecs (jiffies - sta->last_rx); + stats->rx_bytes = sta->rx_bytes; + stats->tx_bytes = sta->tx_bytes; + +sta_info_put (sta); + +return 0 ; +} +struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface,
@@ -583,4 +608,5 @@ struct cfg80211_ops mac80211_config_ops .add_station = ieee80211_add_station, .del_station = ieee80211_del_station, .change_station = ieee80211_change_station, + .get_station = ieee80211_get_station, };