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_get_sta_conn_time(struct sta_info *sta,
     25 				     char *buf, size_t buflen)
     26 {
     27 	struct os_time now, age;
     28 	int len = 0, ret;
     29 
     30 	if (!sta->connected_time.sec)
     31 		return 0;
     32 
     33 	os_get_time(&now);
     34 	os_time_sub(&now, &sta->connected_time, &age);
     35 
     36 	ret = os_snprintf(buf + len, buflen - len, "connected_time=%u\n",
     37 			  (unsigned int) age.sec);
     38 	if (ret < 0 || (size_t) ret >= buflen - len)
     39 		return len;
     40 	len += ret;
     41 
     42 	return len;
     43 }
     44 
     45 
     46 static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
     47 				      struct sta_info *sta,
     48 				      char *buf, size_t buflen)
     49 {
     50 	int len, res, ret;
     51 
     52 	if (sta == NULL) {
     53 		ret = os_snprintf(buf, buflen, "FAIL\n");
     54 		if (ret < 0 || (size_t) ret >= buflen)
     55 			return 0;
     56 		return ret;
     57 	}
     58 
     59 	len = 0;
     60 	ret = os_snprintf(buf + len, buflen - len, MACSTR "\n",
     61 			  MAC2STR(sta->addr));
     62 	if (ret < 0 || (size_t) ret >= buflen - len)
     63 		return len;
     64 	len += ret;
     65 
     66 	res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
     67 	if (res >= 0)
     68 		len += res;
     69 	res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
     70 	if (res >= 0)
     71 		len += res;
     72 	res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
     73 	if (res >= 0)
     74 		len += res;
     75 	res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
     76 				      buflen - len);
     77 	if (res >= 0)
     78 		len += res;
     79 	res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
     80 	if (res >= 0)
     81 		len += res;
     82 
     83 	res = hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
     84 	if (res >= 0)
     85 		len += res;
     86 
     87 	return len;
     88 }
     89 
     90 
     91 int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
     92 				 char *buf, size_t buflen)
     93 {
     94 	return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
     95 }
     96 
     97 
     98 int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
     99 			   char *buf, size_t buflen)
    100 {
    101 	u8 addr[ETH_ALEN];
    102 	int ret;
    103 
    104 	if (hwaddr_aton(txtaddr, addr)) {
    105 		ret = os_snprintf(buf, buflen, "FAIL\n");
    106 		if (ret < 0 || (size_t) ret >= buflen)
    107 			return 0;
    108 		return ret;
    109 	}
    110 	return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
    111 					  buf, buflen);
    112 }
    113 
    114 
    115 int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
    116 				char *buf, size_t buflen)
    117 {
    118 	u8 addr[ETH_ALEN];
    119 	struct sta_info *sta;
    120 	int ret;
    121 
    122 	if (hwaddr_aton(txtaddr, addr) ||
    123 	    (sta = ap_get_sta(hapd, addr)) == NULL) {
    124 		ret = os_snprintf(buf, buflen, "FAIL\n");
    125 		if (ret < 0 || (size_t) ret >= buflen)
    126 			return 0;
    127 		return ret;
    128 	}
    129 	return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
    130 }
    131 
    132 
    133 #ifdef CONFIG_P2P_MANAGER
    134 static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
    135 				  u8 minor_reason_code, const u8 *addr)
    136 {
    137 	struct ieee80211_mgmt *mgmt;
    138 	int ret;
    139 	u8 *pos;
    140 
    141 	if (hapd->driver->send_frame == NULL)
    142 		return -1;
    143 
    144 	mgmt = os_zalloc(sizeof(*mgmt) + 100);
    145 	if (mgmt == NULL)
    146 		return -1;
    147 
    148 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
    149 		" with minor reason code %u (stype=%u)",
    150 		MAC2STR(addr), minor_reason_code, stype);
    151 
    152 	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
    153 	os_memcpy(mgmt->da, addr, ETH_ALEN);
    154 	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
    155 	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
    156 	if (stype == WLAN_FC_STYPE_DEAUTH) {
    157 		mgmt->u.deauth.reason_code =
    158 			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
    159 		pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
    160 	} else {
    161 		mgmt->u.disassoc.reason_code =
    162 			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
    163 		pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
    164 	}
    165 
    166 	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
    167 	*pos++ = 4 + 3 + 1;
    168 	WPA_PUT_BE24(pos, OUI_WFA);
    169 	pos += 3;
    170 	*pos++ = P2P_OUI_TYPE;
    171 
    172 	*pos++ = P2P_ATTR_MINOR_REASON_CODE;
    173 	WPA_PUT_LE16(pos, 1);
    174 	pos += 2;
    175 	*pos++ = minor_reason_code;
    176 
    177 	ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
    178 				       pos - (u8 *) mgmt, 1);
    179 	os_free(mgmt);
    180 
    181 	return ret < 0 ? -1 : 0;
    182 }
    183 #endif /* CONFIG_P2P_MANAGER */
    184 
    185 
    186 int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
    187 				      const char *txtaddr)
    188 {
    189 	u8 addr[ETH_ALEN];
    190 	struct sta_info *sta;
    191 	const char *pos;
    192 	u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
    193 
    194 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
    195 		txtaddr);
    196 
    197 	if (hwaddr_aton(txtaddr, addr))
    198 		return -1;
    199 
    200 	pos = os_strstr(txtaddr, " test=");
    201 	if (pos) {
    202 		struct ieee80211_mgmt mgmt;
    203 		int encrypt;
    204 		if (hapd->driver->send_frame == NULL)
    205 			return -1;
    206 		pos += 6;
    207 		encrypt = atoi(pos);
    208 		os_memset(&mgmt, 0, sizeof(mgmt));
    209 		mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
    210 						  WLAN_FC_STYPE_DEAUTH);
    211 		os_memcpy(mgmt.da, addr, ETH_ALEN);
    212 		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
    213 		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
    214 		mgmt.u.deauth.reason_code =
    215 			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
    216 		if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
    217 					     IEEE80211_HDRLEN +
    218 					     sizeof(mgmt.u.deauth),
    219 					     encrypt) < 0)
    220 			return -1;
    221 		return 0;
    222 	}
    223 
    224 #ifdef CONFIG_P2P_MANAGER
    225 	pos = os_strstr(txtaddr, " p2p=");
    226 	if (pos) {
    227 		return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
    228 					      atoi(pos + 5), addr);
    229 	}
    230 #endif /* CONFIG_P2P_MANAGER */
    231 
    232 	pos = os_strstr(txtaddr, " reason=");
    233 	if (pos)
    234 		reason = atoi(pos + 8);
    235 
    236 	hostapd_drv_sta_deauth(hapd, addr, reason);
    237 	sta = ap_get_sta(hapd, addr);
    238 	if (sta)
    239 		ap_sta_deauthenticate(hapd, sta, reason);
    240 	else if (addr[0] == 0xff)
    241 		hostapd_free_stas(hapd);
    242 
    243 	return 0;
    244 }
    245 
    246 
    247 int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
    248 				    const char *txtaddr)
    249 {
    250 	u8 addr[ETH_ALEN];
    251 	struct sta_info *sta;
    252 	const char *pos;
    253 	u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
    254 
    255 	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
    256 		txtaddr);
    257 
    258 	if (hwaddr_aton(txtaddr, addr))
    259 		return -1;
    260 
    261 	pos = os_strstr(txtaddr, " test=");
    262 	if (pos) {
    263 		struct ieee80211_mgmt mgmt;
    264 		int encrypt;
    265 		if (hapd->driver->send_frame == NULL)
    266 			return -1;
    267 		pos += 6;
    268 		encrypt = atoi(pos);
    269 		os_memset(&mgmt, 0, sizeof(mgmt));
    270 		mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
    271 						  WLAN_FC_STYPE_DISASSOC);
    272 		os_memcpy(mgmt.da, addr, ETH_ALEN);
    273 		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
    274 		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
    275 		mgmt.u.disassoc.reason_code =
    276 			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
    277 		if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
    278 					     IEEE80211_HDRLEN +
    279 					     sizeof(mgmt.u.deauth),
    280 					     encrypt) < 0)
    281 			return -1;
    282 		return 0;
    283 	}
    284 
    285 #ifdef CONFIG_P2P_MANAGER
    286 	pos = os_strstr(txtaddr, " p2p=");
    287 	if (pos) {
    288 		return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
    289 					      atoi(pos + 5), addr);
    290 	}
    291 #endif /* CONFIG_P2P_MANAGER */
    292 
    293 	pos = os_strstr(txtaddr, " reason=");
    294 	if (pos)
    295 		reason = atoi(pos + 8);
    296 
    297 	hostapd_drv_sta_disassoc(hapd, addr, reason);
    298 	sta = ap_get_sta(hapd, addr);
    299 	if (sta)
    300 		ap_sta_disassociate(hapd, sta, reason);
    301 	else if (addr[0] == 0xff)
    302 		hostapd_free_stas(hapd);
    303 
    304 	return 0;
    305 }
    306