diff options
Diffstat (limited to 'package/mac80211/patches/022-nl80211-sta.patch')
-rw-r--r-- | package/mac80211/patches/022-nl80211-sta.patch | 464 |
1 files changed, 464 insertions, 0 deletions
diff --git a/package/mac80211/patches/022-nl80211-sta.patch b/package/mac80211/patches/022-nl80211-sta.patch new file mode 100644 index 0000000..4d08721 --- /dev/null +++ b/package/mac80211/patches/022-nl80211-sta.patch @@ -0,0 +1,464 @@ +Subject: cfg80211/nl80211: station handling + +This patch adds station handling to cfg80211/nl80211. + +Signed-off-by: Johannes Berg <johannes@sipsolutions.net> + +--- + include/linux/nl80211.h | 68 +++++++++++++ + include/net/cfg80211.h | 54 ++++++++++ + net/wireless/nl80211.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 358 insertions(+) + +--- everything.orig/include/linux/nl80211.h 2007-11-08 16:56:32.431522732 +0100 ++++ everything/include/linux/nl80211.h 2007-11-08 17:15:15.961529840 +0100 +@@ -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 +@@ -56,6 +68,16 @@ + * parameters are like for %NL80211_CMD_SET_BEACON. + * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it + * ++ * @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 + */ +@@ -83,6 +105,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 */ +@@ -120,6 +147,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 + */ +@@ -147,12 +185,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 + * +@@ -184,4 +230,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 */ +--- everything.orig/include/net/cfg80211.h 2007-11-08 16:50:38.421522842 +0100 ++++ everything/include/net/cfg80211.h 2007-11-08 17:15:15.971532444 +0100 +@@ -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; + +@@ -130,6 +171,12 @@ struct wiphy; + * interface. This should reject the call when no beacon has been + * configured. + * @del_beacon: Remove beacon configuration and stop sending the beacon. ++ * ++ * @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, +@@ -155,6 +202,13 @@ struct cfg80211_ops { + int (*set_beacon)(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info); + int (*del_beacon)(struct wiphy *wiphy, struct net_device *dev); ++ ++ 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 */ +--- everything.orig/net/wireless/nl80211.c 2007-11-08 16:58:36.711524524 +0100 ++++ everything/net/wireless/nl80211.c 2007-11-08 17:15:15.981533909 +0100 +@@ -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 */ +@@ -715,6 +721,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, ++ struct net_device **vlan) ++{ ++ *vlan = NULL; ++ ++ if (vlanattr) { ++ *vlan = dev_get_by_index(nla_get_u32(vlanattr)); ++ if (!*vlan) ++ return -ENODEV; ++ if (!(*vlan)->ieee80211_ptr) ++ return -EINVAL; ++ 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], ++ ¶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->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, +@@ -796,6 +1007,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 */ |