ieee80211_msg_tx_callback_fail = 2,
};
+struct i802_bss {
+ struct i802_bss *next;
+ char iface[IFNAMSIZ + 1];
+ int dtim_period;
+ unsigned int beacon_set:1;
+};
+
struct i802_driver_data {
struct hostapd_data *hapd;
struct nl_cache *nl_cache;
struct nl_cb *nl_cb;
struct genl_family *nl80211;
- int dtim_period, beacon_int;
- unsigned int beacon_set:1;
+ int beacon_int;
+ struct i802_bss bss;
unsigned int ieee802_1x_active:1;
unsigned int ht_40mhz_scan:1;
static int i802_sta_disassoc(void *priv, const u8 *addr, int reason);
+static struct i802_bss * get_bss(struct i802_driver_data *drv,
+ const char *iface)
+{
+ struct i802_bss *bss = &drv->bss;
+ while (bss) {
+ if (os_strncmp(iface, bss->iface, IFNAMSIZ) == 0)
+ return bss;
+ bss = bss->next;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: get_bss(%s) failed", iface);
+ return NULL;
+}
+
+
static void add_ifidx(struct i802_driver_data *drv, int ifidx)
{
int i;
[NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
[NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
[NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
+ [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
+ [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
};
nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
if (stats[NL80211_STA_INFO_RX_BYTES])
data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]);
if (stats[NL80211_STA_INFO_TX_BYTES])
- data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]);
+ data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]);
+ if (stats[NL80211_STA_INFO_RX_PACKETS])
+ data->rx_packets =
+ nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]);
+ if (stats[NL80211_STA_INFO_TX_PACKETS])
+ data->tx_packets =
+ nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
return NL_SKIP;
}
struct i802_driver_data *drv = priv;
struct nl_msg *msg;
+ os_memset(data, 0, sizeof(*data));
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
#endif /* CONFIG_IEEE80211N */
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_NEW_STATION "
+ "result: %d (%s)", ret, strerror(-ret));
if (ret == -EEXIST)
ret = 0;
nla_put_failure:
if (total_flags & WLAN_STA_AUTHORIZED || !drv->ieee802_1x_active)
NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
- if (total_flags & WLAN_STA_WME)
+ if (total_flags & WLAN_STA_WMM)
NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
if (total_flags & WLAN_STA_SHORT_PREAMBLE)
static int i802_bss_add(void *priv, const char *ifname, const u8 *bssid)
{
+ struct i802_driver_data *drv = priv;
int ifidx;
+ struct i802_bss *bss;
- /*
- * The kernel supports that when the low-level driver does,
- * but we currently don't because we need per-BSS data that
- * currently we can't handle easily.
- */
- return -1;
+ bss = os_zalloc(sizeof(*bss));
+ if (bss == NULL)
+ return -1;
+ os_strlcpy(bss->iface, ifname, IFNAMSIZ);
ifidx = nl80211_create_iface(priv, ifname, NL80211_IFTYPE_AP, bssid);
- if (ifidx < 0)
+ if (ifidx < 0) {
+ os_free(bss);
return -1;
+ }
if (hostapd_set_iface_flags(priv, ifname, 1)) {
nl80211_remove_iface(priv, ifidx);
+ os_free(bss);
return -1;
}
+ bss->next = drv->bss.next;
+ drv->bss.next = bss;
return 0;
}
static int i802_bss_remove(void *priv, const char *ifname)
{
+ struct i802_driver_data *drv = priv;
+ struct i802_bss *bss, *prev;
nl80211_remove_iface(priv, if_nametoindex(ifname));
+ prev = &drv->bss;
+ bss = drv->bss.next;
+ while (bss) {
+ if (os_strncmp(ifname, bss->iface, IFNAMSIZ) == 0) {
+ prev->next = bss->next;
+ os_free(bss);
+ break;
+ }
+ prev = bss;
+ bss = bss->next;
+ }
return 0;
}
struct nl_msg *msg;
u8 cmd = NL80211_CMD_NEW_BEACON;
int ret;
+ struct i802_bss *bss;
+
+ bss = get_bss(drv, iface);
+ if (bss == NULL)
+ return -ENOENT;
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
- if (drv->beacon_set)
+ wpa_printf(MSG_DEBUG, "nl80211: Set beacon (iface=%s beacon_set=%d)",
+ iface, bss->beacon_set);
+ if (bss->beacon_set)
cmd = NL80211_CMD_SET_BEACON;
genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, drv->beacon_int);
- if (!drv->dtim_period)
- drv->dtim_period = 2;
- NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period);
+ if (!bss->dtim_period)
+ bss->dtim_period = 2;
+ NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, bss->dtim_period);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (!ret)
- drv->beacon_set = 1;
+ bss->beacon_set = 1;
return ret;
nla_put_failure:
return -ENOBUFS;
drv->beacon_int = value;
- if (!drv->beacon_set)
+ if (!drv->bss.beacon_set)
return 0;
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
+ wpa_printf(MSG_DEBUG, "nl80211: Set beacon interval %d "
+ "(beacon_set=%d)", value, drv->bss.beacon_set);
genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
0, NL80211_CMD_SET_BEACON, 0);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));
{
struct i802_driver_data *drv = priv;
struct nl_msg *msg;
+ int ret = -ENOBUFS;
+ struct i802_bss *bss;
+
+ bss = get_bss(drv, iface);
+ if (bss == NULL)
+ return -ENOENT;
msg = nlmsg_alloc();
if (!msg)
return -ENOMEM;
+ wpa_printf(MSG_DEBUG, "nl80211: Set beacon DTIM period %d (iface=%s "
+ "beacon_set=%d)", value, iface, bss->beacon_set);
genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
0, NL80211_CMD_SET_BEACON, 0);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
- drv->dtim_period = value;
- NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period);
+ bss->dtim_period = value;
+ NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, bss->dtim_period);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_SET_BEACON(%s) "
+ "result: %d (%s)", iface, ret, strerror(-ret));
- return send_and_recv_msgs(drv, msg, NULL, NULL);
nla_put_failure:
- return -ENOBUFS;
+ return ret;
}
drv->hapd = hapd;
memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface));
+ memcpy(drv->bss.iface, hapd->conf->iface, sizeof(drv->iface));
drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
drv->if_indices = drv->default_if_indices;
static void i802_deinit(void *priv)
{
struct i802_driver_data *drv = priv;
+ struct i802_bss *bss, *prev;
if (drv->last_freq_ht) {
/* Clear HT flags from the driver */
free(drv->if_indices);
os_free(drv->neighbors);
+
+ bss = drv->bss.next;
+ while (bss) {
+ prev = bss;
+ bss = bss->next;
+ os_free(bss);
+ }
+
free(drv);
}