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:
Jouni Malinen 2009-03-12 21:55:42 +02:00 committed by Jouni Malinen
parent 86f4deb635
commit 816bce98e1

View File

@ -54,6 +54,13 @@ enum ieee80211_msg_type {
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;
@ -74,8 +81,8 @@ struct i802_driver_data {
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;
@ -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 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;
@ -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)
{
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)
return -1;
if (hostapd_set_iface_flags(priv, ifname, 1)) {
nl80211_remove_iface(priv, ifidx);
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;
}
@ -1123,12 +1162,19 @@ static int i802_set_beacon(const char *iface, void *priv,
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,
@ -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_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;
@ -1212,13 +1258,15 @@ static int i802_set_beacon_int(void *priv, int value)
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));
@ -1235,21 +1283,33 @@ static int i802_set_dtim_period(const char *iface, void *priv, int value)
{
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;
}
@ -2961,6 +3021,7 @@ static void *i802_init_bssid(struct hostapd_data *hapd, const u8 *bssid)
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;
@ -2987,6 +3048,7 @@ static void *i802_init(struct hostapd_data *hapd)
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 */
@ -3023,6 +3085,14 @@ static void i802_deinit(void *priv)
free(drv->if_indices);
os_free(drv->neighbors);
bss = drv->bss.next;
while (bss) {
prev = bss;
bss = bss->next;
os_free(bss);
}
free(drv);
}