Cumulative patch from commit d2ba3d6bd9336ef8fd761a0cc7999824d4c4da41

d2ba3d6 VLAN: Simplify no-WEP with VLAN check
d66dcb0 WEP: Remove VLAN support from hostapd
646f12a bsd: Add a commit routine
32dc6a3 bsd: Mark define sta_set_flags() only for hostapd
70a867c bsd: Mark the interface down before opening the routing socket
89f4690 bsd: Compute the RSSI level
5dd82c6 bsd: Set IEEE80211_KEY_NOREPLAY in IBSS/AHDEMO mode
cb76af8 bsd: Skip SIOCSIFFFLAGS ioctl when there is no change.
7239ea7 nl80211: Add stop AP mode event API

Change-Id: Ib1c41f2ed18299451f05d0adf808b8b560522c86
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index fbc1ee0..54a2e75 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -451,19 +451,6 @@
 	os_free(conf->radius);
 	os_free(conf->radius_das_shared_secret);
 	hostapd_config_free_vlan(conf);
-	if (conf->ssid.dyn_vlan_keys) {
-		struct hostapd_ssid *ssid = &conf->ssid;
-		size_t i;
-		for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) {
-			if (ssid->dyn_vlan_keys[i] == NULL)
-				continue;
-			hostapd_config_free_wep(ssid->dyn_vlan_keys[i]);
-			os_free(ssid->dyn_vlan_keys[i]);
-		}
-		os_free(ssid->dyn_vlan_keys);
-		ssid->dyn_vlan_keys = NULL;
-	}
-
 	os_free(conf->time_zone);
 
 #ifdef CONFIG_IEEE80211R
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index b340c1e..9b87686 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -74,8 +74,6 @@
 #ifdef CONFIG_FULL_DYNAMIC_VLAN
 	char *vlan_tagged_interface;
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
-	struct hostapd_wep_keys **dyn_vlan_keys;
-	size_t max_dyn_vlan_keys;
 };
 
 
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index ac67001..7925a3e 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -221,30 +221,6 @@
 		errors++;
 	}
 
-	if (ssid->dyn_vlan_keys) {
-		size_t i;
-		for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) {
-			const char *ifname;
-			struct hostapd_wep_keys *key = ssid->dyn_vlan_keys[i];
-			if (key == NULL)
-				continue;
-			ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan,
-							    i);
-			if (ifname == NULL)
-				continue;
-
-			idx = key->idx;
-			if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_WEP,
-						broadcast_ether_addr, idx, 1,
-						NULL, 0, key->key[idx],
-						key->len[idx])) {
-				wpa_printf(MSG_WARNING, "Could not set "
-					   "dynamic VLAN WEP encryption.");
-				errors++;
-			}
-		}
-	}
-
 	return errors;
 }
 
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 3554e8b..9867581 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -186,114 +186,10 @@
 }
 
 
-#ifndef CONFIG_NO_VLAN
-static struct hostapd_wep_keys *
-ieee802_1x_group_alloc(struct hostapd_data *hapd, const char *ifname)
-{
-	struct hostapd_wep_keys *key;
-
-	key = os_zalloc(sizeof(*key));
-	if (key == NULL)
-		return NULL;
-
-	key->default_len = hapd->conf->default_wep_key_len;
-
-	if (key->idx >= hapd->conf->broadcast_key_idx_max ||
-	    key->idx < hapd->conf->broadcast_key_idx_min)
-		key->idx = hapd->conf->broadcast_key_idx_min;
-	else
-		key->idx++;
-
-	if (!key->key[key->idx])
-		key->key[key->idx] = os_malloc(key->default_len);
-	if (key->key[key->idx] == NULL ||
-	    random_get_bytes(key->key[key->idx], key->default_len)) {
-		printf("Could not generate random WEP key (dynamic VLAN).\n");
-		os_free(key->key[key->idx]);
-		key->key[key->idx] = NULL;
-		os_free(key);
-		return NULL;
-	}
-	key->len[key->idx] = key->default_len;
-
-	wpa_printf(MSG_DEBUG, "%s: Default WEP idx %d for dynamic VLAN\n",
-		   ifname, key->idx);
-	wpa_hexdump_key(MSG_DEBUG, "Default WEP key (dynamic VLAN)",
-			key->key[key->idx], key->len[key->idx]);
-
-	if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_WEP,
-				broadcast_ether_addr, key->idx, 1,
-				NULL, 0, key->key[key->idx],
-				key->len[key->idx]))
-		printf("Could not set dynamic VLAN WEP encryption key.\n");
-
-	hostapd_set_drv_ieee8021x(hapd, ifname, 1);
-
-	return key;
-}
-
-
-static struct hostapd_wep_keys *
-ieee802_1x_get_group(struct hostapd_data *hapd, struct hostapd_ssid *ssid,
-		     size_t vlan_id)
-{
-	const char *ifname;
-
-	if (vlan_id == 0)
-		return &ssid->wep;
-
-	if (vlan_id <= ssid->max_dyn_vlan_keys && ssid->dyn_vlan_keys &&
-	    ssid->dyn_vlan_keys[vlan_id])
-		return ssid->dyn_vlan_keys[vlan_id];
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Creating new group "
-		   "state machine for VLAN ID %lu",
-		   (unsigned long) vlan_id);
-
-	ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
-	if (ifname == NULL) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Unknown VLAN ID %lu - "
-			   "cannot create group key state machine",
-			   (unsigned long) vlan_id);
-		return NULL;
-	}
-
-	if (ssid->dyn_vlan_keys == NULL) {
-		int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]);
-		ssid->dyn_vlan_keys = os_zalloc(size);
-		if (ssid->dyn_vlan_keys == NULL)
-			return NULL;
-		ssid->max_dyn_vlan_keys = vlan_id;
-	}
-
-	if (ssid->max_dyn_vlan_keys < vlan_id) {
-		struct hostapd_wep_keys **na;
-		int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]);
-		na = os_realloc(ssid->dyn_vlan_keys, size);
-		if (na == NULL)
-			return NULL;
-		ssid->dyn_vlan_keys = na;
-		os_memset(&ssid->dyn_vlan_keys[ssid->max_dyn_vlan_keys + 1], 0,
-			  (vlan_id - ssid->max_dyn_vlan_keys) *
-			  sizeof(ssid->dyn_vlan_keys[0]));
-		ssid->max_dyn_vlan_keys = vlan_id;
-	}
-
-	ssid->dyn_vlan_keys[vlan_id] = ieee802_1x_group_alloc(hapd, ifname);
-
-	return ssid->dyn_vlan_keys[vlan_id];
-}
-#endif /* CONFIG_NO_VLAN */
-
-
 void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
 {
 	struct eapol_authenticator *eapol = hapd->eapol_auth;
 	struct eapol_state_machine *sm = sta->eapol_sm;
-#ifndef CONFIG_NO_VLAN
-	struct hostapd_wep_keys *key = NULL;
-	int vlan_id;
-#endif /* CONFIG_NO_VLAN */
 
 	if (sm == NULL || !sm->eap_if->eapKeyData)
 		return;
@@ -302,18 +198,12 @@
 		   MAC2STR(sta->addr));
 
 #ifndef CONFIG_NO_VLAN
-	vlan_id = sta->vlan_id;
-	if (vlan_id < 0 || vlan_id > MAX_VLAN_ID)
-		vlan_id = 0;
-
-	if (vlan_id) {
-		key = ieee802_1x_get_group(hapd, sta->ssid, vlan_id);
-		if (key && key->key[key->idx])
-			ieee802_1x_tx_key_one(hapd, sta, key->idx, 1,
-					      key->key[key->idx],
-					      key->len[key->idx]);
-	} else
+	if (sta->vlan_id > 0 && sta->vlan_id <= MAX_VLAN_ID) {
+		wpa_printf(MSG_ERROR, "Using WEP with vlans is not supported.");
+		return;
+	}
 #endif /* CONFIG_NO_VLAN */
+
 	if (eapol->default_wep_key) {
 		ieee802_1x_tx_key_one(hapd, sta, eapol->default_wep_key_idx, 1,
 				      eapol->default_wep_key,
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 9d869b1..4acb12b 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -61,10 +61,37 @@
 	int	prev_roaming;	/* roaming state to restore on deinit */
 	int	prev_privacy;	/* privacy state to restore on deinit */
 	int	prev_wpa;	/* wpa state to restore on deinit */
+	enum ieee80211_opmode opmode;	/* operation mode */
 };
 
 /* Generic functions for hostapd and wpa_supplicant */
 
+static enum ieee80211_opmode
+get80211opmode(struct bsd_driver_data *drv)
+{
+	struct ifmediareq ifmr;
+
+	(void) memset(&ifmr, 0, sizeof(ifmr));
+	(void) strncpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
+
+	if (ioctl(drv->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
+		if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) {
+			if (ifmr.ifm_current & IFM_FLAG0)
+				return IEEE80211_M_AHDEMO;
+			else
+				return IEEE80211_M_IBSS;
+		}
+		if (ifmr.ifm_current & IFM_IEEE80211_HOSTAP)
+			return IEEE80211_M_HOSTAP;
+		if (ifmr.ifm_current & IFM_IEEE80211_MONITOR)
+			return IEEE80211_M_MONITOR;
+		if (ifmr.ifm_current & IFM_IEEE80211_MBSS)
+			return IEEE80211_M_MBSS;
+	}
+	return IEEE80211_M_STA;
+}
+
+
 static int
 bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len)
 {
@@ -265,10 +292,15 @@
 		return -1;
 	}
 
-	if (enable)
+	if (enable) {
+		if (ifr.ifr_flags & IFF_UP)
+			return 0;
 		ifr.ifr_flags |= IFF_UP;
-	else
+	} else {
+		if (!(ifr.ifr_flags & IFF_UP))
+			return 0;
 		ifr.ifr_flags &= ~IFF_UP;
+	}
 
 	if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) {
 		perror("ioctl[SIOCSIFFLAGS]");
@@ -278,12 +310,21 @@
 	return 0;
 }
 
+#ifdef HOSTAPD
+static int
+bsd_commit(void *priv)
+{
+	return bsd_ctrl_iface(priv, 1);
+}
+#endif /* HOSTAPD */
+
 static int
 bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
 	    const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
 	    size_t seq_len, const u8 *key, size_t key_len)
 {
 	struct ieee80211req_key wk;
+	struct bsd_driver_data *drv = priv;
 
 	wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
 		   "seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx,
@@ -338,6 +379,14 @@
 	}
 	if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
 		wk.ik_flags |= IEEE80211_KEY_DEFAULT;
+#ifndef HOSTAPD
+	/*
+	 * Ignore replay failures in IBSS and AHDEMO mode.
+	 */
+	if (drv->opmode == IEEE80211_M_IBSS ||
+	    drv->opmode == IEEE80211_M_AHDEMO)
+		wk.ik_flags |= IEEE80211_KEY_NOREPLAY;
+#endif /* HOSTAPD */
 	wk.ik_keylen = key_len;
 	if (seq) {
 #ifdef WORDS_BIGENDIAN
@@ -473,6 +522,7 @@
 	return bsd_ctrl_iface(priv, 1);
 }
 
+#ifdef HOSTAPD
 static int
 bsd_set_sta_authorized(void *priv, const u8 *addr,
 		       int total_flags, int flags_or, int flags_and)
@@ -492,6 +542,7 @@
 				   IEEE80211_MLME_AUTHORIZE :
 				   IEEE80211_MLME_UNAUTHORIZE, 0, addr);
 }
+#endif /* HOSTAPD */
 
 static void
 bsd_new_sta(void *priv, void *ctx, u8 addr[IEEE80211_ADDR_LEN])
@@ -1295,6 +1346,11 @@
 	result->caps = sr->isr_capinfo;
 	result->qual = sr->isr_rssi;
 	result->noise = sr->isr_noise;
+	/*
+	 * the rssi value reported by the kernel is in 0.5dB steps relative to
+	 * the reported noise floor. see ieee80211_node.h for details.
+	 */
+	result->level = sr->isr_rssi / 2 + sr->isr_noise;
 
 	pos = (u8 *)(result + 1);
 
@@ -1461,6 +1517,12 @@
 	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
 	if (drv->sock < 0)
 		goto fail1;
+
+	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+	/* Down interface during setup. */
+	if (bsd_ctrl_iface(drv, 0) < 0)
+		goto fail;
+
 	drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
 	if (drv->route < 0)
 		goto fail;
@@ -1468,11 +1530,6 @@
 		wpa_driver_bsd_event_receive, ctx, drv);
 
 	drv->ctx = ctx;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-
-	/* Down interface during setup. */
-	if (bsd_ctrl_iface(drv, 0) < 0)
-		goto fail;
 
 	if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
 		wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
@@ -1493,6 +1550,8 @@
 	if (wpa_driver_bsd_capa(drv))
 		goto fail;
 
+	drv->opmode = get80211opmode(drv);
+
 	return drv;
 fail:
 	close(drv->sock);
@@ -1548,6 +1607,8 @@
 	.read_sta_data		= bsd_read_sta_driver_data,
 	.sta_disassoc		= bsd_sta_disassoc,
 	.sta_deauth		= bsd_sta_deauth,
+	.sta_set_flags		= bsd_set_sta_authorized,
+	.commit			= bsd_commit,
 #else /* HOSTAPD */
 	.init			= wpa_driver_bsd_init,
 	.deinit			= wpa_driver_bsd_deinit,
@@ -1566,6 +1627,5 @@
 	.hapd_set_ssid		= bsd_set_ssid,
 	.hapd_get_ssid		= bsd_get_ssid,
 	.hapd_send_eapol	= bsd_send_eapol,
-	.sta_set_flags		= bsd_set_sta_authorized,
 	.set_generic_elem	= bsd_set_opt_ie,
 };
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 9b0e6d7..2b364c1 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -2455,6 +2455,13 @@
 }
 
 
+static void nl80211_stop_ap(struct wpa_driver_nl80211_data *drv,
+			    struct nlattr **tb)
+{
+	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_UNAVAILABLE, NULL);
+}
+
+
 static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv,
 					 struct nlattr **tb)
 {
@@ -2679,6 +2686,9 @@
 	case NL80211_CMD_RADAR_DETECT:
 		nl80211_radar_event(drv, tb);
 		break;
+	case NL80211_CMD_STOP_AP:
+		nl80211_stop_ap(drv, tb);
+		break;
 	default:
 		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
 			"(cmd=%d)", cmd);