Browse Source

Add test commands for sending deauth/disassoc without dropping state

This can be used to test 802.11w by sending a protected or unprotected
deauth/disassoc frame.

hostapd_cli deauth <dst addr> test=<0/1>
hostapd_cli disassoc <dst addr> test=<0/1>

test=0: unprotected
test=1: protected
Jouni Malinen 15 years ago
parent
commit
b91ab76e8c
5 changed files with 88 additions and 5 deletions
  1. 50 0
      hostapd/ctrl_iface.c
  2. 12 4
      hostapd/hostapd_cli.c
  3. 14 0
      src/drivers/driver.h
  4. 2 1
      src/drivers/driver_ndis.c
  5. 10 0
      src/drivers/driver_nl80211.c

+ 50 - 0
hostapd/ctrl_iface.c

@@ -160,12 +160,37 @@ static int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
 {
 	u8 addr[ETH_ALEN];
 	struct sta_info *sta;
+	const char *pos;
 
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s", txtaddr);
 
 	if (hwaddr_aton(txtaddr, addr))
 		return -1;
 
+	pos = os_strstr(txtaddr, " test=");
+	if (pos) {
+		struct ieee80211_mgmt mgmt;
+		int encrypt;
+		if (hapd->driver->send_frame == NULL)
+			return -1;
+		pos += 6;
+		encrypt = atoi(pos);
+		os_memset(&mgmt, 0, sizeof(mgmt));
+		mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+						  WLAN_FC_STYPE_DEAUTH);
+		os_memcpy(mgmt.da, addr, ETH_ALEN);
+		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+		mgmt.u.deauth.reason_code =
+			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+		if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
+					     IEEE80211_HDRLEN +
+					     sizeof(mgmt.u.deauth),
+					     encrypt) < 0)
+			return -1;
+		return 0;
+	}
+
 	hapd->drv.sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
 	sta = ap_get_sta(hapd, addr);
 	if (sta)
@@ -181,12 +206,37 @@ static int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
 {
 	u8 addr[ETH_ALEN];
 	struct sta_info *sta;
+	const char *pos;
 
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s", txtaddr);
 
 	if (hwaddr_aton(txtaddr, addr))
 		return -1;
 
+	pos = os_strstr(txtaddr, " test=");
+	if (pos) {
+		struct ieee80211_mgmt mgmt;
+		int encrypt;
+		if (hapd->driver->send_frame == NULL)
+			return -1;
+		pos += 6;
+		encrypt = atoi(pos);
+		os_memset(&mgmt, 0, sizeof(mgmt));
+		mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+						  WLAN_FC_STYPE_DISASSOC);
+		os_memcpy(mgmt.da, addr, ETH_ALEN);
+		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+		mgmt.u.deauth.reason_code =
+			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+		if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
+					     IEEE80211_HDRLEN +
+					     sizeof(mgmt.u.deauth),
+					     encrypt) < 0)
+			return -1;
+		return 0;
+	}
+
 	hapd->drv.sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
 	sta = ap_get_sta(hapd, addr);
 	if (sta)

+ 12 - 4
hostapd/hostapd_cli.c

@@ -246,12 +246,16 @@ static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
 					  char *argv[])
 {
 	char buf[64];
-	if (argc != 1) {
+	if (argc < 1) {
 		printf("Invalid 'deauthenticate' command - exactly one "
 		       "argument, STA address, is required.\n");
 		return -1;
 	}
-	snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
+	if (argc > 1)
+		os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
+			    argv[0], argv[1]);
+	else
+		os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
 	return wpa_ctrl_command(ctrl, buf);
 }
 
@@ -260,12 +264,16 @@ static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
 					char *argv[])
 {
 	char buf[64];
-	if (argc != 1) {
+	if (argc < 1) {
 		printf("Invalid 'disassociate' command - exactly one "
 		       "argument, STA address, is required.\n");
 		return -1;
 	}
-	snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
+	if (argc > 1)
+		os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
+			    argv[0], argv[1]);
+	else
+		os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
 	return wpa_ctrl_command(ctrl, buf);
 }
 

+ 14 - 0
src/drivers/driver.h

@@ -1774,6 +1774,20 @@ struct wpa_driver_ops {
 	 * least %hysteresis from the previously indicated signal change event.
 	 */
 	int (*signal_monitor)(void *priv, int threshold, int hysteresis);
+
+	/**
+	 * send_frame - Send IEEE 802.11 frame (testing use only)
+	 * @priv: Private driver interface data
+	 * @data: IEEE 802.11 frame with IEEE 802.11 header
+	 * @data_len: Size of the frame
+	 * @encrypt: Whether to encrypt the frame (if keys are set)
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is only used for debugging purposes and is not
+	 * required to be implemented for normal operations.
+	 */
+	int (*send_frame)(void *priv, const u8 *data, size_t data_len,
+			  int encrypt);
 };
 
 

+ 2 - 1
src/drivers/driver_ndis.c

@@ -3275,5 +3275,6 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = {
 	NULL /* deinit_ap */,
 	NULL /* suspend */,
 	NULL /* resume */,
-	NULL /* signal_monitor */
+	NULL /* signal_monitor */,
+	NULL /* send_frame */
 };

+ 10 - 0
src/drivers/driver_nl80211.c

@@ -5237,6 +5237,15 @@ nla_put_failure:
 }
 
 
+static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
+			      int encrypt)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt);
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.name = "nl80211",
 	.desc = "Linux nl80211/cfg80211",
@@ -5297,4 +5306,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.resume = wpa_driver_nl80211_resume,
 	.send_ft_action = nl80211_send_ft_action,
 	.signal_monitor = nl80211_signal_monitor,
+	.send_frame = nl80211_send_frame,
 };