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