aboutsummaryrefslogtreecommitdiffstats
path: root/package/hostapd/patches/006-use-nl80211-for-sta.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/hostapd/patches/006-use-nl80211-for-sta.patch')
-rw-r--r--package/hostapd/patches/006-use-nl80211-for-sta.patch411
1 files changed, 411 insertions, 0 deletions
diff --git a/package/hostapd/patches/006-use-nl80211-for-sta.patch b/package/hostapd/patches/006-use-nl80211-for-sta.patch
new file mode 100644
index 0000000000..f94ba42886
--- /dev/null
+++ b/package/hostapd/patches/006-use-nl80211-for-sta.patch
@@ -0,0 +1,411 @@
+---
+ hostapd/driver_devicescape.c | 330 ++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 249 insertions(+), 81 deletions(-)
+
+--- hostap.orig/hostapd/driver_devicescape.c 2007-11-09 13:41:15.000000000 +0100
++++ hostap/hostapd/driver_devicescape.c 2007-11-09 13:41:16.000000000 +0100
+@@ -75,8 +75,14 @@ struct i802_driver_data {
+
+ #define HAPD_DECL struct hostapd_data *hapd = iface->bss[0]
+
+-static int i802_sta_set_flags(void *priv, const u8 *addr,
+- int total_flags, int flags_or, int flags_and);
++/* helper for netlink get routines */
++static int ack_wait_handler(struct nl_msg *msg, void *arg)
++{
++ int *finished = arg;
++
++ *finished = 1;
++ return NL_STOP;
++}
+
+
+ static int hostapd_set_iface_flags(struct i802_driver_data *drv, int dev_up)
+@@ -255,14 +261,6 @@ static int get_key_handler(struct nl_msg
+ return NL_SKIP;
+ }
+
+-static int ack_wait_handler(struct nl_msg *msg, void *arg)
+-{
+- int *finished = arg;
+-
+- *finished = 1;
+- return NL_STOP;
+-}
+-
+ static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
+ int idx, u8 *seq)
+ {
+@@ -629,43 +627,126 @@ static int i802_get_retry(void *priv, in
+ static int i802_flush(void *priv)
+ {
+ struct i802_driver_data *drv = priv;
+- struct prism2_hostapd_param param;
++ struct nl_msg *msg;
++ int ret = -1;
+
+- memset(&param, 0, sizeof(param));
+- param.cmd = PRISM2_HOSTAPD_FLUSH;
+- return hostapd_ioctl(drv, &param, sizeof(param));
++ msg = nlmsg_alloc();
++ if (!msg)
++ goto out;
++
++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
++ 0, NL80211_CMD_NEW_STATION, 0);
++
++ /*
++ * XXX: FIX! this needs to flush all VLANs too
++ */
++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
++ if_nametoindex(drv->iface));
++
++ ret = 0;
++
++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
++ nl_wait_for_ack(drv->nl_handle) < 0) {
++ ret = -1;
++ }
++
++ nla_put_failure:
++ nlmsg_free(msg);
++
++ out:
++ return ret;
+ }
+
+
++static int get_sta_handler(struct nl_msg *msg, void *arg)
++{
++ struct nlattr *tb[NL80211_ATTR_MAX + 1];
++ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
++ struct hostap_sta_driver_data *data = arg;
++ struct nlattr *stats[NL80211_STA_STAT_MAX + 1];
++ static struct nla_policy stats_policy[NL80211_STA_STAT_MAX + 1] = {
++ [NL80211_STA_STAT_INACTIVE_TIME] = { .type = NLA_U32 },
++ [NL80211_STA_STAT_RX_BYTES] = { .type = NLA_U32 },
++ [NL80211_STA_STAT_TX_BYTES] = { .type = NLA_U32 },
++ };
++
++ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
++ genlmsg_attrlen(gnlh, 0), NULL);
++
++ /*
++ * TODO: validate the interface and mac address!
++ * Otherwise, there's a race condition as soon as
++ * the kernel starts sending station notifications.
++ */
++
++ if (!tb[NL80211_ATTR_STA_STATS]) {
++ printf("sta stats missing!\n");
++ return NL_SKIP;
++ }
++ if (nla_parse_nested(stats, NL80211_STA_STAT_MAX,
++ tb[NL80211_ATTR_STA_STATS],
++ stats_policy)) {
++ printf("failed to parse nested attributes!\n");
++ return NL_SKIP;
++ }
++
++ if (stats[NL80211_STA_STAT_INACTIVE_TIME])
++ data->inactive_msec =
++ nla_get_u32(stats[NL80211_STA_STAT_INACTIVE_TIME]);
++ if (stats[NL80211_STA_STAT_RX_BYTES])
++ data->rx_bytes = nla_get_u32(stats[NL80211_STA_STAT_RX_BYTES]);
++ if (stats[NL80211_STA_STAT_TX_BYTES])
++ data->rx_bytes = nla_get_u32(stats[NL80211_STA_STAT_TX_BYTES]);
++
++ return NL_SKIP;
++}
++
+ static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
+ const u8 *addr)
+ {
+ struct i802_driver_data *drv = priv;
+- struct prism2_hostapd_param param;
++ struct nl_msg *msg;
++ struct nl_cb *cb = NULL;
++ int ret = -1;
++ int err = 0;
++ int finished = 0;
+
+- memset(data, 0, sizeof(*data));
++ msg = nlmsg_alloc();
++ if (!msg)
++ goto out;
+
+- memset(&param, 0, sizeof(param));
+- param.cmd = PRISM2_HOSTAPD_GET_INFO_STA;
+- memcpy(param.sta_addr, addr, ETH_ALEN);
+- if (hostapd_ioctl(drv, &param, sizeof(param))) {
+- printf(" Could not get station info from kernel driver.\n");
+- return -1;
+- }
++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
++ 0, NL80211_CMD_GET_STATION, 0);
++
++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));
++
++ cb = nl_cb_alloc(NL_CB_CUSTOM);
++ if (!cb)
++ goto out;
++
++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0)
++ goto out;
++
++ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_sta_handler, data);
++ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished);
++
++ err = nl_recvmsgs(drv->nl_handle, cb);
++
++ if (!finished)
++ err = nl_wait_for_ack(drv->nl_handle);
++
++ if (err < 0)
++ goto out;
++
++ ret = 0;
++
++ out:
++ nl_cb_put(cb);
++ nla_put_failure:
++ nlmsg_free(msg);
++ return ret;
+
+- data->inactive_msec = param.u.get_info_sta.inactive_msec;
+- data->rx_packets = param.u.get_info_sta.rx_packets;
+- data->tx_packets = param.u.get_info_sta.tx_packets;
+- data->rx_bytes = param.u.get_info_sta.rx_bytes;
+- data->tx_bytes = param.u.get_info_sta.tx_bytes;
+- data->current_tx_rate = param.u.get_info_sta.current_tx_rate;
+- data->flags = param.u.get_info_sta.flags;
+- data->num_ps_buf_frames = param.u.get_info_sta.num_ps_buf_frames;
+- data->tx_retry_failed = param.u.get_info_sta.tx_retry_failed;
+- data->tx_retry_count = param.u.get_info_sta.tx_retry_count;
+- data->last_rssi = param.u.get_info_sta.last_rssi;
+- data->last_ack_rssi = param.u.get_info_sta.last_ack_rssi;
+- return 0;
+ }
+
+
+@@ -744,35 +825,68 @@ static int i802_sta_add(const char *ifna
+ size_t supp_rates_len, int flags)
+ {
+ struct i802_driver_data *drv = priv;
+- struct prism2_hostapd_param param;
+- size_t len;
++ struct nl_msg *msg;
++ int ret = -1;
+
+- memset(&param, 0, sizeof(param));
+- param.cmd = PRISM2_HOSTAPD_ADD_STA;
+- memcpy(param.sta_addr, addr, ETH_ALEN);
+- param.u.add_sta.aid = aid;
+- param.u.add_sta.capability = capability;
+- len = supp_rates_len;
+- if (len > sizeof(param.u.add_sta.supp_rates))
+- len = sizeof(param.u.add_sta.supp_rates);
+- memcpy(param.u.add_sta.supp_rates, supp_rates, len);
+- return hostapd_ioctl_iface(ifname, drv, &param, sizeof(param));
++ msg = nlmsg_alloc();
++ if (!msg)
++ goto out;
++
++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
++ 0, NL80211_CMD_NEW_STATION, 0);
++
++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
++ if_nametoindex(drv->iface));
++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
++ NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, aid);
++ NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, supp_rates_len,
++ supp_rates);
++ NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, 0);
++
++ ret = 0;
++
++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
++ nl_wait_for_ack(drv->nl_handle) < 0) {
++ ret = -1;
++ }
++
++ nla_put_failure:
++ nlmsg_free(msg);
++
++ out:
++ return ret;
+ }
+
+
+ static int i802_sta_remove(void *priv, const u8 *addr)
+ {
+ struct i802_driver_data *drv = priv;
+- struct prism2_hostapd_param param;
++ struct nl_msg *msg;
++ int ret = -1;
+
+- i802_sta_set_flags(drv, addr, 0, 0, ~WLAN_STA_AUTHORIZED);
++ msg = nlmsg_alloc();
++ if (!msg)
++ goto out;
+
+- memset(&param, 0, sizeof(param));
+- param.cmd = PRISM2_HOSTAPD_REMOVE_STA;
+- memcpy(param.sta_addr, addr, ETH_ALEN);
+- if (hostapd_ioctl(drv, &param, sizeof(param)))
+- return -1;
+- return 0;
++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
++ 0, NL80211_CMD_DEL_STATION, 0);
++
++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
++ if_nametoindex(drv->iface));
++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
++
++ ret = 0;
++
++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
++ nl_wait_for_ack(drv->nl_handle) < 0) {
++ ret = -1;
++ }
++
++ nla_put_failure:
++ nlmsg_free(msg);
++
++ out:
++ return ret;
+ }
+
+
+@@ -780,14 +894,51 @@ static int i802_sta_set_flags(void *priv
+ int total_flags, int flags_or, int flags_and)
+ {
+ struct i802_driver_data *drv = priv;
+- struct prism2_hostapd_param param;
++ struct nl_msg *msg, *flags = NULL;
++ int ret = -1;
+
+- memset(&param, 0, sizeof(param));
+- param.cmd = PRISM2_HOSTAPD_SET_FLAGS_STA;
+- memcpy(param.sta_addr, addr, ETH_ALEN);
+- param.u.set_flags_sta.flags_or = flags_or;
+- param.u.set_flags_sta.flags_and = flags_and;
+- return hostapd_ioctl(drv, &param, sizeof(param));
++ msg = nlmsg_alloc();
++ if (!msg)
++ goto out;
++
++ flags = nlmsg_alloc();
++ if (!flags)
++ goto free_msg;
++
++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
++ 0, NL80211_CMD_SET_STATION, 0);
++
++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
++ if_nametoindex(drv->iface));
++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
++
++ if (total_flags & WLAN_STA_AUTHORIZED)
++ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
++
++ if (total_flags & WLAN_STA_WME)
++ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
++
++ if (total_flags & WLAN_STA_SHORT_PREAMBLE)
++ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
++
++ if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
++ goto nla_put_failure;
++
++ ret = 0;
++
++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
++ nl_wait_for_ack(drv->nl_handle) < 0) {
++ ret = -1;
++ }
++
++ nla_put_failure:
++ nlmsg_free(flags);
++
++ free_msg:
++ nlmsg_free(msg);
++
++ out:
++ return ret;
+ }
+
+
+@@ -1257,18 +1408,38 @@ static struct hostapd_hw_modes * i802_ge
+ }
+
+
+-static int i802_set_sta_vlan(void *priv, const u8 *addr, const char *ifname,
+- int vlan_id)
++static int i802_set_sta_vlan(void *priv, const u8 *addr,
++ const char *ifname, int vlan_id)
+ {
+ struct i802_driver_data *drv = priv;
+- struct prism2_hostapd_param param;
++ struct nl_msg *msg;
++ int ret = -1;
+
+- memset(&param, 0, sizeof(param));
+- param.cmd = PRISM2_HOSTAPD_SET_STA_VLAN;
+- memcpy(param.sta_addr, addr, ETH_ALEN);
+- os_strlcpy(param.u.set_sta_vlan.vlan_name, ifname, IFNAMSIZ);
+- param.u.set_sta_vlan.vlan_id = vlan_id;
+- return hostapd_ioctl(drv, &param, sizeof(param));
++ msg = nlmsg_alloc();
++ if (!msg)
++ goto out;
++
++ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
++ 0, NL80211_CMD_SET_STATION, 0);
++
++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
++ if_nametoindex(drv->iface));
++ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
++ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
++ if_nametoindex(ifname));
++
++ ret = 0;
++
++ if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
++ nl_wait_for_ack(drv->nl_handle) < 0) {
++ ret = -1;
++ }
++
++ nla_put_failure:
++ nlmsg_free(msg);
++
++ out:
++ return ret;
+ }
+
+
+@@ -1750,17 +1921,14 @@ static int i802_init_sockets(struct i802
+
+ static int i802_get_inact_sec(void *priv, const u8 *addr)
+ {
+- struct i802_driver_data *drv = priv;
+- struct prism2_hostapd_param param;
++ struct hostap_sta_driver_data data;
++ int ret;
+
+- memset(&param, 0, sizeof(param));
+- param.cmd = PRISM2_HOSTAPD_GET_INFO_STA;
+- memcpy(param.sta_addr, addr, ETH_ALEN);
+- if (hostapd_ioctl(drv, &param, sizeof(param))) {
++ data.inactive_msec = -1;
++ ret = i802_read_sta_data(priv, &data, addr);
++ if (ret || data.inactive_msec == -1)
+ return -1;
+- }
+-
+- return param.u.get_info_sta.inactive_msec / 1000;
++ return data.inactive_msec / 1000;
+ }
+
+