--- hostapd/driver_devicescape.c | 332 ++++++++++++++++++++++++++++++++----------- 1 file changed, 251 insertions(+), 81 deletions(-) --- hostap.orig/hostapd/driver_devicescape.c 2007-11-14 17:31:15.000000000 +0100 +++ hostap/hostapd/driver_devicescape.c 2007-11-14 17:31: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(¶m, 0, sizeof(param)); - param.cmd = PRISM2_HOSTAPD_FLUSH; - return hostapd_ioctl(drv, ¶m, 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; + + msg = nlmsg_alloc(); + if (!msg) + goto out; - memset(data, 0, sizeof(*data)); + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, + 0, NL80211_CMD_GET_STATION, 0); - memset(¶m, 0, sizeof(param)); - param.cmd = PRISM2_HOSTAPD_GET_INFO_STA; - memcpy(param.sta_addr, addr, ETH_ALEN); - if (hostapd_ioctl(drv, ¶m, sizeof(param))) { - printf(" Could not get station info from kernel driver.\n"); - return -1; - } + 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,70 @@ 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(¶m, 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, ¶m, 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 = nl_send_auto_complete(drv->nl_handle, msg); + if (ret < 0) + goto nla_put_failure; + + ret = nl_wait_for_ack(drv->nl_handle); + /* ignore EEXIST, this happens if a STA associates while associated */ + if (ret == -EEXIST || ret >= 0) + ret = 0; + + 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(¶m, 0, sizeof(param)); - param.cmd = PRISM2_HOSTAPD_REMOVE_STA; - memcpy(param.sta_addr, addr, ETH_ALEN); - if (hostapd_ioctl(drv, ¶m, 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 +896,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(¶m, 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, ¶m, 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 +1410,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(¶m, 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, ¶m, 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; } @@ -1752,17 +1925,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(¶m, 0, sizeof(param)); - param.cmd = PRISM2_HOSTAPD_GET_INFO_STA; - memcpy(param.sta_addr, addr, ETH_ALEN); - if (hostapd_ioctl(drv, ¶m, 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; }