Home | History | Annotate | Download | only in ap
      1 /*
      2  * Control interface for shared AP commands
      3  * Copyright (c) 2004-2009, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This software may be distributed under the terms of the BSD license.
      6  * See README for more details.
      7  */
      8 
      9 #include "utils/includes.h"
     10 
     11 #include "utils/common.h"
     12 #include "common/ieee802_11_defs.h"
     13 #include "hostapd.h"
     14 #include "ieee802_1x.h"
     15 #include "wpa_auth.h"
     16 #include "ieee802_11.h"
     17 #include "sta_info.h"
     18 #include "wps_hostapd.h"
     19 #include "p2p_hostapd.h"
     20 #include "ctrl_iface_ap.h"
     21 #include "ap_drv_ops.h"
     22 
     23 
     24 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
     25 				      struct sta_info *sta,
     26 				      char *buf, size_t buflen)
     27 {
     28 	int len, res, ret;
     29 
     30 	if (sta == NULL) {
     31 		ret = os_snprintf(buf, buflen, "FAIL\n");
     32 		if (ret < 0 || (size_t) ret >= buflen)
     33 			return 0;
     34 		return ret;
     35 	}
     36 
     37 	len = 0;
     38 	ret = os_snprintf(buf + len, buflen - len, MACSTR "\n",
     39 			  MAC2STR(sta->addr));
     40 	if (ret < 0 || (size_t) ret >= buflen - len)
     41 		return len;
     42 	len += ret;
     43 
     44 	res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
     45 	if (res >= 0)
     46 		len += res;
     47 	res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
     48 	if (res >= 0)
     49 		len += res;
     50 	res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
     51 	if (res >= 0)
     52 		len += res;
     53 	res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
     54 				      buflen - len);
     55 	if (res >= 0)
     56 		len += res;
     57 	res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
     58 	if (res >= 0)
     59 		len += res;
     60 
     61 	return len;
     62 }
     63 
     64 
     65 int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
     66 				 char *buf, size_t buflen)
     67 {
     68 	return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
     69 }
     70 
     71 
     72 int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
     73 			   char *buf, size_t buflen)
     74 {
     75 	u8 addr[ETH_ALEN];
     76 	int ret;
     77 
     78 	if (hwaddr_aton(txtaddr, addr)) {
     79 		ret = os_snprintf(buf, buflen, "FAIL\n");
     80 		if (ret < 0 || (size_t) ret >= buflen)
     81 			return 0;
     82 		return ret;
     83 	}
     84 	return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
     85 					  buf, buflen);
     86 }
     87 
     88 
     89 int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
     90 				char *buf, size_t buflen)
     91 {
     92 	u8 addr[ETH_ALEN];
     93 	struct sta_info *sta;
     94 	int ret;
     95 
     96 	if (hwaddr_aton(txtaddr, addr) ||
     97 	    (sta = ap_get_sta(hapd, addr)) == NULL) {
     98 		ret = os_snprintf(buf, buflen, "FAIL\n");
     99 		if (ret < 0 || (size_t) ret >= buflen)
    100 			return 0;
    101 		return ret;
    102 	}
    103 	return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
    104 }
    105 
    106 
    107 #ifdef CONFIG_P2P_MANAGER
    108 static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
    109 				  u8 minor_reason_code, const u8 *addr)
    110 {
    111 	struct ieee80211_mgmt *mgmt;
    112 	int ret;
    113 	u8 *pos;
    114 
    115 	if (hapd->driver->send_frame == NULL)
    116 		return -1;
    117 
    118 	mgmt = os_zalloc(sizeof(*mgmt) + 100);
    119 	if (mgmt == NULL)
    120 		return -1;
    121 
    122 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
    123 		" with minor reason code %u (stype=%u)",
    124 		MAC2STR(addr), minor_reason_code, stype);
    125 
    126 	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
    127 	os_memcpy(mgmt->da, addr, ETH_ALEN);
    128 	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
    129 	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
    130 	if (stype == WLAN_FC_STYPE_DEAUTH) {
    131 		mgmt->u.deauth.reason_code =
    132 			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
    133 		pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
    134 	} else {
    135 		mgmt->u.disassoc.reason_code =
    136 			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
    137 		pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
    138 	}
    139 
    140 	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
    141 	*pos++ = 4 + 3 + 1;
    142 	WPA_PUT_BE24(pos, OUI_WFA);
    143 	pos += 3;
    144 	*pos++ = P2P_OUI_TYPE;
    145 
    146 	*pos++ = P2P_ATTR_MINOR_REASON_CODE;
    147 	WPA_PUT_LE16(pos, 1);
    148 	pos += 2;
    149 	*pos++ = minor_reason_code;
    150 
    151 	ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
    152 				       pos - (u8 *) mgmt, 1);
    153 	os_free(mgmt);
    154 
    155 	return ret < 0 ? -1 : 0;
    156 }
    157 #endif /* CONFIG_P2P_MANAGER */
    158 
    159 
    160 int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
    161 				      const char *txtaddr)
    162 {
    163 	u8 addr[ETH_ALEN];
    164 	struct sta_info *sta;
    165 	const char *pos;
    166 
    167 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
    168 		txtaddr);
    169 
    170 	if (hwaddr_aton(txtaddr, addr))
    171 		return -1;
    172 
    173 	pos = os_strstr(txtaddr, " test=");
    174 	if (pos) {
    175 		struct ieee80211_mgmt mgmt;
    176 		int encrypt;
    177 		if (hapd->driver->send_frame == NULL)
    178 			return -1;
    179 		pos += 6;
    180 		encrypt = atoi(pos);
    181 		os_memset(&mgmt, 0, sizeof(mgmt));
    182 		mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
    183 						  WLAN_FC_STYPE_DEAUTH);
    184 		os_memcpy(mgmt.da, addr, ETH_ALEN);
    185 		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
    186 		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
    187 		mgmt.u.deauth.reason_code =
    188 			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
    189 		if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
    190 					     IEEE80211_HDRLEN +
    191 					     sizeof(mgmt.u.deauth),
    192 					     encrypt) < 0)
    193 			return -1;
    194 		return 0;
    195 	}
    196 
    197 #ifdef CONFIG_P2P_MANAGER
    198 	pos = os_strstr(txtaddr, " p2p=");
    199 	if (pos) {
    200 		return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
    201 					      atoi(pos + 5), addr);
    202 	}
    203 #endif /* CONFIG_P2P_MANAGER */
    204 
    205 	hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
    206 	sta = ap_get_sta(hapd, addr);
    207 	if (sta)
    208 		ap_sta_deauthenticate(hapd, sta,
    209 				      WLAN_REASON_PREV_AUTH_NOT_VALID);
    210 	else if (addr[0] == 0xff)
    211 		hostapd_free_stas(hapd);
    212 
    213 	return 0;
    214 }
    215 
    216 
    217 int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
    218 				    const char *txtaddr)
    219 {
    220 	u8 addr[ETH_ALEN];
    221 	struct sta_info *sta;
    222 	const char *pos;
    223 
    224 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
    225 		txtaddr);
    226 
    227 	if (hwaddr_aton(txtaddr, addr))
    228 		return -1;
    229 
    230 	pos = os_strstr(txtaddr, " test=");
    231 	if (pos) {
    232 		struct ieee80211_mgmt mgmt;
    233 		int encrypt;
    234 		if (hapd->driver->send_frame == NULL)
    235 			return -1;
    236 		pos += 6;
    237 		encrypt = atoi(pos);
    238 		os_memset(&mgmt, 0, sizeof(mgmt));
    239 		mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
    240 						  WLAN_FC_STYPE_DISASSOC);
    241 		os_memcpy(mgmt.da, addr, ETH_ALEN);
    242 		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
    243 		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
    244 		mgmt.u.disassoc.reason_code =
    245 			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
    246 		if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
    247 					     IEEE80211_HDRLEN +
    248 					     sizeof(mgmt.u.deauth),
    249 					     encrypt) < 0)
    250 			return -1;
    251 		return 0;
    252 	}
    253 
    254 #ifdef CONFIG_P2P_MANAGER
    255 	pos = os_strstr(txtaddr, " p2p=");
    256 	if (pos) {
    257 		return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
    258 					      atoi(pos + 5), addr);
    259 	}
    260 #endif /* CONFIG_P2P_MANAGER */
    261 
    262 	hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
    263 	sta = ap_get_sta(hapd, addr);
    264 	if (sta)
    265 		ap_sta_disassociate(hapd, sta,
    266 				    WLAN_REASON_PREV_AUTH_NOT_VALID);
    267 	else if (addr[0] == 0xff)
    268 		hostapd_free_stas(hapd);
    269 
    270 	return 0;
    271 }
    272