Browse Source

nl80211: Add per-BSS data structure and enable BSS add/remove

This allows mac80211 to be used for multi-BSSID operations.
Jouni Malinen 16 years ago
parent
commit
816bce98e1
1 changed files with 89 additions and 19 deletions
  1. 89 19
      hostapd/driver_nl80211.c

+ 89 - 19
hostapd/driver_nl80211.c

@@ -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)
+	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);
 }