nl80211: Add per-BSS data structure and enable BSS add/remove
This allows mac80211 to be used for multi-BSSID operations.
This commit is contained in:
parent
86f4deb635
commit
816bce98e1
1 changed files with 92 additions and 22 deletions
|
@ -54,6 +54,13 @@ enum ieee80211_msg_type {
|
||||||
ieee80211_msg_tx_callback_fail = 2,
|
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 i802_driver_data {
|
||||||
struct hostapd_data *hapd;
|
struct hostapd_data *hapd;
|
||||||
|
|
||||||
|
@ -74,8 +81,8 @@ struct i802_driver_data {
|
||||||
struct nl_cache *nl_cache;
|
struct nl_cache *nl_cache;
|
||||||
struct nl_cb *nl_cb;
|
struct nl_cb *nl_cb;
|
||||||
struct genl_family *nl80211;
|
struct genl_family *nl80211;
|
||||||
int dtim_period, beacon_int;
|
int beacon_int;
|
||||||
unsigned int beacon_set:1;
|
struct i802_bss bss;
|
||||||
unsigned int ieee802_1x_active:1;
|
unsigned int ieee802_1x_active:1;
|
||||||
unsigned int ht_40mhz_scan:1;
|
unsigned int ht_40mhz_scan:1;
|
||||||
|
|
||||||
|
@ -90,6 +97,20 @@ static int i802_sta_deauth(void *priv, const u8 *addr, int reason);
|
||||||
static int i802_sta_disassoc(void *priv, const u8 *addr, int reason);
|
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)
|
static void add_ifidx(struct i802_driver_data *drv, int ifidx)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -1088,29 +1109,47 @@ static int nl80211_create_iface(struct i802_driver_data *drv,
|
||||||
|
|
||||||
static int i802_bss_add(void *priv, const char *ifname, const u8 *bssid)
|
static int i802_bss_add(void *priv, const char *ifname, const u8 *bssid)
|
||||||
{
|
{
|
||||||
|
struct i802_driver_data *drv = priv;
|
||||||
int ifidx;
|
int ifidx;
|
||||||
|
struct i802_bss *bss;
|
||||||
|
|
||||||
/*
|
bss = os_zalloc(sizeof(*bss));
|
||||||
* The kernel supports that when the low-level driver does,
|
if (bss == NULL)
|
||||||
* but we currently don't because we need per-BSS data that
|
return -1;
|
||||||
* currently we can't handle easily.
|
os_strlcpy(bss->iface, ifname, IFNAMSIZ);
|
||||||
*/
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
ifidx = nl80211_create_iface(priv, ifname, NL80211_IFTYPE_AP, bssid);
|
ifidx = nl80211_create_iface(priv, ifname, NL80211_IFTYPE_AP, bssid);
|
||||||
if (ifidx < 0)
|
if (ifidx < 0) {
|
||||||
return -1;
|
os_free(bss);
|
||||||
if (hostapd_set_iface_flags(priv, ifname, 1)) {
|
|
||||||
nl80211_remove_iface(priv, ifidx);
|
|
||||||
return -1;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int i802_bss_remove(void *priv, const char *ifname)
|
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));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1123,12 +1162,19 @@ static int i802_set_beacon(const char *iface, void *priv,
|
||||||
struct nl_msg *msg;
|
struct nl_msg *msg;
|
||||||
u8 cmd = NL80211_CMD_NEW_BEACON;
|
u8 cmd = NL80211_CMD_NEW_BEACON;
|
||||||
int ret;
|
int ret;
|
||||||
|
struct i802_bss *bss;
|
||||||
|
|
||||||
|
bss = get_bss(drv, iface);
|
||||||
|
if (bss == NULL)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
msg = nlmsg_alloc();
|
msg = nlmsg_alloc();
|
||||||
if (!msg)
|
if (!msg)
|
||||||
return -ENOMEM;
|
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;
|
cmd = NL80211_CMD_SET_BEACON;
|
||||||
|
|
||||||
genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
|
genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
|
||||||
|
@ -1138,13 +1184,13 @@ static int i802_set_beacon(const char *iface, void *priv,
|
||||||
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
|
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
|
||||||
NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, drv->beacon_int);
|
NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, drv->beacon_int);
|
||||||
|
|
||||||
if (!drv->dtim_period)
|
if (!bss->dtim_period)
|
||||||
drv->dtim_period = 2;
|
bss->dtim_period = 2;
|
||||||
NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period);
|
NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, bss->dtim_period);
|
||||||
|
|
||||||
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
|
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
drv->beacon_set = 1;
|
bss->beacon_set = 1;
|
||||||
return ret;
|
return ret;
|
||||||
nla_put_failure:
|
nla_put_failure:
|
||||||
return -ENOBUFS;
|
return -ENOBUFS;
|
||||||
|
@ -1212,13 +1258,15 @@ static int i802_set_beacon_int(void *priv, int value)
|
||||||
|
|
||||||
drv->beacon_int = value;
|
drv->beacon_int = value;
|
||||||
|
|
||||||
if (!drv->beacon_set)
|
if (!drv->bss.beacon_set)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
msg = nlmsg_alloc();
|
msg = nlmsg_alloc();
|
||||||
if (!msg)
|
if (!msg)
|
||||||
return -ENOMEM;
|
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,
|
genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
|
||||||
0, NL80211_CMD_SET_BEACON, 0);
|
0, NL80211_CMD_SET_BEACON, 0);
|
||||||
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));
|
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));
|
||||||
|
@ -1235,21 +1283,33 @@ static int i802_set_dtim_period(const char *iface, void *priv, int value)
|
||||||
{
|
{
|
||||||
struct i802_driver_data *drv = priv;
|
struct i802_driver_data *drv = priv;
|
||||||
struct nl_msg *msg;
|
struct nl_msg *msg;
|
||||||
|
int ret = -ENOBUFS;
|
||||||
|
struct i802_bss *bss;
|
||||||
|
|
||||||
|
bss = get_bss(drv, iface);
|
||||||
|
if (bss == NULL)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
msg = nlmsg_alloc();
|
msg = nlmsg_alloc();
|
||||||
if (!msg)
|
if (!msg)
|
||||||
return -ENOMEM;
|
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,
|
genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
|
||||||
0, NL80211_CMD_SET_BEACON, 0);
|
0, NL80211_CMD_SET_BEACON, 0);
|
||||||
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
|
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
|
||||||
|
|
||||||
drv->dtim_period = value;
|
bss->dtim_period = value;
|
||||||
NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period);
|
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:
|
nla_put_failure:
|
||||||
return -ENOBUFS;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2961,6 +3021,7 @@ static void *i802_init_bssid(struct hostapd_data *hapd, const u8 *bssid)
|
||||||
|
|
||||||
drv->hapd = hapd;
|
drv->hapd = hapd;
|
||||||
memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface));
|
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->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
|
||||||
drv->if_indices = drv->default_if_indices;
|
drv->if_indices = drv->default_if_indices;
|
||||||
|
@ -2987,6 +3048,7 @@ static void *i802_init(struct hostapd_data *hapd)
|
||||||
static void i802_deinit(void *priv)
|
static void i802_deinit(void *priv)
|
||||||
{
|
{
|
||||||
struct i802_driver_data *drv = priv;
|
struct i802_driver_data *drv = priv;
|
||||||
|
struct i802_bss *bss, *prev;
|
||||||
|
|
||||||
if (drv->last_freq_ht) {
|
if (drv->last_freq_ht) {
|
||||||
/* Clear HT flags from the driver */
|
/* Clear HT flags from the driver */
|
||||||
|
@ -3023,6 +3085,14 @@ static void i802_deinit(void *priv)
|
||||||
free(drv->if_indices);
|
free(drv->if_indices);
|
||||||
|
|
||||||
os_free(drv->neighbors);
|
os_free(drv->neighbors);
|
||||||
|
|
||||||
|
bss = drv->bss.next;
|
||||||
|
while (bss) {
|
||||||
|
prev = bss;
|
||||||
|
bss = bss->next;
|
||||||
|
os_free(bss);
|
||||||
|
}
|
||||||
|
|
||||||
free(drv);
|
free(drv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue