Branch data Line data Source code
1 : : /*
2 : : * Control interface for shared AP commands
3 : : * Copyright (c) 2004-2013, Jouni Malinen <j@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 "eapol_auth/eapol_auth_sm.h"
14 : : #include "hostapd.h"
15 : : #include "ieee802_1x.h"
16 : : #include "wpa_auth.h"
17 : : #include "ieee802_11.h"
18 : : #include "sta_info.h"
19 : : #include "wps_hostapd.h"
20 : : #include "p2p_hostapd.h"
21 : : #include "ctrl_iface_ap.h"
22 : : #include "ap_drv_ops.h"
23 : :
24 : :
25 : 19 : static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd,
26 : : struct sta_info *sta,
27 : : char *buf, size_t buflen)
28 : : {
29 : : struct hostap_sta_driver_data data;
30 : : int ret;
31 : :
32 [ - + ]: 19 : if (hostapd_drv_read_sta_data(hapd, &data, sta->addr) < 0)
33 : 0 : return 0;
34 : :
35 : 19 : ret = os_snprintf(buf, buflen, "rx_packets=%lu\ntx_packets=%lu\n"
36 : : "rx_bytes=%lu\ntx_bytes=%lu\n",
37 : : data.rx_packets, data.tx_packets,
38 : : data.rx_bytes, data.tx_bytes);
39 [ + - ][ - + ]: 19 : if (ret < 0 || (size_t) ret >= buflen)
40 : 0 : return 0;
41 : 19 : return ret;
42 : : }
43 : :
44 : :
45 : 19 : static int hostapd_get_sta_conn_time(struct sta_info *sta,
46 : : char *buf, size_t buflen)
47 : : {
48 : : struct os_reltime age;
49 : : int ret;
50 : :
51 [ - + ]: 19 : if (!sta->connected_time.sec)
52 : 0 : return 0;
53 : :
54 : 19 : os_reltime_age(&sta->connected_time, &age);
55 : :
56 : 19 : ret = os_snprintf(buf, buflen, "connected_time=%u\n",
57 : 19 : (unsigned int) age.sec);
58 [ - + ][ + - ]: 19 : if (ret < 0 || (size_t) ret >= buflen)
59 : 0 : return 0;
60 : 19 : return ret;
61 : : }
62 : :
63 : :
64 : 19 : static const char * timeout_next_str(int val)
65 : : {
66 [ + - - - : 19 : switch (val) {
- - ]
67 : : case STA_NULLFUNC:
68 : 19 : return "NULLFUNC POLL";
69 : : case STA_DISASSOC:
70 : 0 : return "DISASSOC";
71 : : case STA_DEAUTH:
72 : 0 : return "DEAUTH";
73 : : case STA_REMOVE:
74 : 0 : return "REMOVE";
75 : : case STA_DISASSOC_FROM_CLI:
76 : 0 : return "DISASSOC_FROM_CLI";
77 : : }
78 : :
79 : 19 : return "?";
80 : : }
81 : :
82 : :
83 : 19 : static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
84 : : struct sta_info *sta,
85 : : char *buf, size_t buflen)
86 : : {
87 : : int len, res, ret, i;
88 : :
89 [ - + ]: 19 : if (!sta)
90 : 0 : return 0;
91 : :
92 : 19 : len = 0;
93 : 114 : ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=",
94 : 114 : MAC2STR(sta->addr));
95 [ + - ][ - + ]: 19 : if (ret < 0 || (size_t) ret >= buflen - len)
96 : 0 : return len;
97 : 19 : len += ret;
98 : :
99 : 19 : ret = ap_sta_flags_txt(sta->flags, buf + len, buflen - len);
100 [ - + ]: 19 : if (ret < 0)
101 : 0 : return len;
102 : 19 : len += ret;
103 : :
104 : 57 : ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n"
105 : : "listen_interval=%d\nsupported_rates=",
106 : 57 : sta->aid, sta->capability, sta->listen_interval);
107 [ + - ][ - + ]: 19 : if (ret < 0 || (size_t) ret >= buflen - len)
108 : 0 : return len;
109 : 19 : len += ret;
110 : :
111 [ + + ]: 247 : for (i = 0; i < sta->supported_rates_len; i++) {
112 [ + + ]: 228 : ret = os_snprintf(buf + len, buflen - len, "%02x%s",
113 : 228 : sta->supported_rates[i],
114 : 228 : i + 1 < sta->supported_rates_len ? " " : "");
115 [ + - ][ - + ]: 228 : if (ret < 0 || (size_t) ret >= buflen - len)
116 : 0 : return len;
117 : 228 : len += ret;
118 : : }
119 : :
120 : 19 : ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n",
121 : 19 : timeout_next_str(sta->timeout_next));
122 [ - + ][ + - ]: 19 : if (ret < 0 || (size_t) ret >= buflen - len)
123 : 0 : return len;
124 : 19 : len += ret;
125 : :
126 : 19 : res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
127 [ + - ]: 19 : if (res >= 0)
128 : 19 : len += res;
129 : 19 : res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
130 [ + - ]: 19 : if (res >= 0)
131 : 19 : len += res;
132 : 19 : res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
133 [ + - ]: 19 : if (res >= 0)
134 : 19 : len += res;
135 : 19 : res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
136 : : buflen - len);
137 [ + - ]: 19 : if (res >= 0)
138 : 19 : len += res;
139 : 19 : res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
140 [ + - ]: 19 : if (res >= 0)
141 : 19 : len += res;
142 : :
143 : 19 : len += hostapd_get_sta_tx_rx(hapd, sta, buf + len, buflen - len);
144 : 19 : len += hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
145 : :
146 : 19 : return len;
147 : : }
148 : :
149 : :
150 : 2 : int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
151 : : char *buf, size_t buflen)
152 : : {
153 : 2 : return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
154 : : }
155 : :
156 : :
157 : 17 : int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
158 : : char *buf, size_t buflen)
159 : : {
160 : : u8 addr[ETH_ALEN];
161 : : int ret;
162 : : const char *pos;
163 : : struct sta_info *sta;
164 : :
165 [ - + ]: 17 : if (hwaddr_aton(txtaddr, addr)) {
166 : 0 : ret = os_snprintf(buf, buflen, "FAIL\n");
167 [ # # ][ # # ]: 0 : if (ret < 0 || (size_t) ret >= buflen)
168 : 0 : return 0;
169 : 0 : return ret;
170 : : }
171 : :
172 : 17 : sta = ap_get_sta(hapd, addr);
173 [ - + ]: 17 : if (sta == NULL)
174 : 0 : return -1;
175 : :
176 : 17 : pos = os_strchr(txtaddr, ' ');
177 [ + + ]: 17 : if (pos) {
178 : 2 : pos++;
179 : :
180 : : #ifdef HOSTAPD_DUMP_STATE
181 [ + - ]: 2 : if (os_strcmp(pos, "eapol") == 0) {
182 [ - + ]: 2 : if (sta->eapol_sm == NULL)
183 : 0 : return -1;
184 : 2 : return eapol_auth_dump_state(sta->eapol_sm, buf,
185 : : buflen);
186 : : }
187 : : #endif /* HOSTAPD_DUMP_STATE */
188 : :
189 : 0 : return -1;
190 : : }
191 : :
192 : 17 : return hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
193 : : }
194 : :
195 : :
196 : 4 : int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
197 : : char *buf, size_t buflen)
198 : : {
199 : : u8 addr[ETH_ALEN];
200 : : struct sta_info *sta;
201 : : int ret;
202 : :
203 [ + - ][ - + ]: 4 : if (hwaddr_aton(txtaddr, addr) ||
204 : : (sta = ap_get_sta(hapd, addr)) == NULL) {
205 : 0 : ret = os_snprintf(buf, buflen, "FAIL\n");
206 [ # # ][ # # ]: 0 : if (ret < 0 || (size_t) ret >= buflen)
207 : 0 : return 0;
208 : 0 : return ret;
209 : : }
210 : :
211 [ + + ]: 4 : if (!sta->next)
212 : 2 : return 0;
213 : :
214 : 4 : return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
215 : : }
216 : :
217 : :
218 : : #ifdef CONFIG_P2P_MANAGER
219 : 0 : static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
220 : : u8 minor_reason_code, const u8 *addr)
221 : : {
222 : : struct ieee80211_mgmt *mgmt;
223 : : int ret;
224 : : u8 *pos;
225 : :
226 [ # # ]: 0 : if (hapd->driver->send_frame == NULL)
227 : 0 : return -1;
228 : :
229 : 0 : mgmt = os_zalloc(sizeof(*mgmt) + 100);
230 [ # # ]: 0 : if (mgmt == NULL)
231 : 0 : return -1;
232 : :
233 : 0 : wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
234 : : " with minor reason code %u (stype=%u)",
235 : : MAC2STR(addr), minor_reason_code, stype);
236 : :
237 : 0 : mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
238 : 0 : os_memcpy(mgmt->da, addr, ETH_ALEN);
239 : 0 : os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
240 : 0 : os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
241 [ # # ]: 0 : if (stype == WLAN_FC_STYPE_DEAUTH) {
242 : 0 : mgmt->u.deauth.reason_code =
243 : : host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
244 : 0 : pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
245 : : } else {
246 : 0 : mgmt->u.disassoc.reason_code =
247 : : host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
248 : 0 : pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
249 : : }
250 : :
251 : 0 : *pos++ = WLAN_EID_VENDOR_SPECIFIC;
252 : 0 : *pos++ = 4 + 3 + 1;
253 : 0 : WPA_PUT_BE24(pos, OUI_WFA);
254 : 0 : pos += 3;
255 : 0 : *pos++ = P2P_OUI_TYPE;
256 : :
257 : 0 : *pos++ = P2P_ATTR_MINOR_REASON_CODE;
258 : 0 : WPA_PUT_LE16(pos, 1);
259 : 0 : pos += 2;
260 : 0 : *pos++ = minor_reason_code;
261 : :
262 : 0 : ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
263 : 0 : pos - (u8 *) mgmt, 1);
264 : 0 : os_free(mgmt);
265 : :
266 [ # # ]: 0 : return ret < 0 ? -1 : 0;
267 : : }
268 : : #endif /* CONFIG_P2P_MANAGER */
269 : :
270 : :
271 : 3 : int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
272 : : const char *txtaddr)
273 : : {
274 : : u8 addr[ETH_ALEN];
275 : : struct sta_info *sta;
276 : : const char *pos;
277 : 3 : u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
278 : :
279 : 3 : wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
280 : : txtaddr);
281 : :
282 [ - + ]: 3 : if (hwaddr_aton(txtaddr, addr))
283 : 0 : return -1;
284 : :
285 : 3 : pos = os_strstr(txtaddr, " test=");
286 [ - + ]: 3 : if (pos) {
287 : : struct ieee80211_mgmt mgmt;
288 : : int encrypt;
289 [ # # ]: 0 : if (hapd->driver->send_frame == NULL)
290 : 0 : return -1;
291 : 0 : pos += 6;
292 : 0 : encrypt = atoi(pos);
293 : 0 : os_memset(&mgmt, 0, sizeof(mgmt));
294 : 0 : mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
295 : : WLAN_FC_STYPE_DEAUTH);
296 : 0 : os_memcpy(mgmt.da, addr, ETH_ALEN);
297 : 0 : os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
298 : 0 : os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
299 : 0 : mgmt.u.deauth.reason_code =
300 : : host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
301 [ # # ]: 0 : if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
302 : : IEEE80211_HDRLEN +
303 : : sizeof(mgmt.u.deauth),
304 : : encrypt) < 0)
305 : 0 : return -1;
306 : 0 : return 0;
307 : : }
308 : :
309 : : #ifdef CONFIG_P2P_MANAGER
310 : 2 : pos = os_strstr(txtaddr, " p2p=");
311 [ - + ]: 2 : if (pos) {
312 : 0 : return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
313 : 0 : atoi(pos + 5), addr);
314 : : }
315 : : #endif /* CONFIG_P2P_MANAGER */
316 : :
317 : 3 : pos = os_strstr(txtaddr, " reason=");
318 [ + + ]: 3 : if (pos)
319 : 1 : reason = atoi(pos + 8);
320 : :
321 : 3 : hostapd_drv_sta_deauth(hapd, addr, reason);
322 : 3 : sta = ap_get_sta(hapd, addr);
323 [ + - ]: 3 : if (sta)
324 : 3 : ap_sta_deauthenticate(hapd, sta, reason);
325 [ # # ]: 0 : else if (addr[0] == 0xff)
326 : 0 : hostapd_free_stas(hapd);
327 : :
328 : 3 : return 0;
329 : : }
330 : :
331 : :
332 : 1 : int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
333 : : const char *txtaddr)
334 : : {
335 : : u8 addr[ETH_ALEN];
336 : : struct sta_info *sta;
337 : : const char *pos;
338 : 1 : u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
339 : :
340 : 1 : wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
341 : : txtaddr);
342 : :
343 [ - + ]: 1 : if (hwaddr_aton(txtaddr, addr))
344 : 0 : return -1;
345 : :
346 : 1 : pos = os_strstr(txtaddr, " test=");
347 [ - + ]: 1 : if (pos) {
348 : : struct ieee80211_mgmt mgmt;
349 : : int encrypt;
350 [ # # ]: 0 : if (hapd->driver->send_frame == NULL)
351 : 0 : return -1;
352 : 0 : pos += 6;
353 : 0 : encrypt = atoi(pos);
354 : 0 : os_memset(&mgmt, 0, sizeof(mgmt));
355 : 0 : mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
356 : : WLAN_FC_STYPE_DISASSOC);
357 : 0 : os_memcpy(mgmt.da, addr, ETH_ALEN);
358 : 0 : os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
359 : 0 : os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
360 : 0 : mgmt.u.disassoc.reason_code =
361 : : host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
362 [ # # ]: 0 : if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
363 : : IEEE80211_HDRLEN +
364 : : sizeof(mgmt.u.deauth),
365 : : encrypt) < 0)
366 : 0 : return -1;
367 : 0 : return 0;
368 : : }
369 : :
370 : : #ifdef CONFIG_P2P_MANAGER
371 : 0 : pos = os_strstr(txtaddr, " p2p=");
372 [ # # ]: 0 : if (pos) {
373 : 0 : return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
374 : 0 : atoi(pos + 5), addr);
375 : : }
376 : : #endif /* CONFIG_P2P_MANAGER */
377 : :
378 : 1 : pos = os_strstr(txtaddr, " reason=");
379 [ - + ]: 1 : if (pos)
380 : 0 : reason = atoi(pos + 8);
381 : :
382 : 1 : hostapd_drv_sta_disassoc(hapd, addr, reason);
383 : 1 : sta = ap_get_sta(hapd, addr);
384 [ + - ]: 1 : if (sta)
385 : 1 : ap_sta_disassociate(hapd, sta, reason);
386 [ # # ]: 0 : else if (addr[0] == 0xff)
387 : 0 : hostapd_free_stas(hapd);
388 : :
389 : 1 : return 0;
390 : : }
391 : :
392 : :
393 : 13 : int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
394 : : size_t buflen)
395 : : {
396 : 13 : struct hostapd_iface *iface = hapd->iface;
397 : 13 : int len = 0, ret;
398 : : size_t i;
399 : :
400 : 13 : ret = os_snprintf(buf + len, buflen - len,
401 : : "state=%s\n"
402 : : "phy=%s\n"
403 : : "freq=%d\n"
404 : : "num_sta_non_erp=%d\n"
405 : : "num_sta_no_short_slot_time=%d\n"
406 : : "num_sta_no_short_preamble=%d\n"
407 : : "olbc=%d\n"
408 : : "num_sta_ht_no_gf=%d\n"
409 : : "num_sta_no_ht=%d\n"
410 : : "num_sta_ht_20_mhz=%d\n"
411 : : "olbc_ht=%d\n"
412 : : "ht_op_mode=0x%x\n",
413 : : hostapd_state_text(iface->state),
414 : 13 : iface->phy,
415 : : iface->freq,
416 : : iface->num_sta_non_erp,
417 : : iface->num_sta_no_short_slot_time,
418 : : iface->num_sta_no_short_preamble,
419 : : iface->olbc,
420 : : iface->num_sta_ht_no_gf,
421 : : iface->num_sta_no_ht,
422 : : iface->num_sta_ht_20mhz,
423 : : iface->olbc_ht,
424 : 13 : iface->ht_op_mode);
425 [ - + ][ + - ]: 13 : if (ret < 0 || (size_t) ret >= buflen - len)
426 : 0 : return len;
427 : 13 : len += ret;
428 : :
429 : 91 : ret = os_snprintf(buf + len, buflen - len,
430 : : "channel=%u\n"
431 : : "secondary_channel=%d\n"
432 : : "ieee80211n=%d\n"
433 : : "ieee80211ac=%d\n"
434 : : "vht_oper_chwidth=%d\n"
435 : : "vht_oper_centr_freq_seg0_idx=%d\n"
436 : : "vht_oper_centr_freq_seg1_idx=%d\n",
437 : 13 : iface->conf->channel,
438 : 13 : iface->conf->secondary_channel,
439 : 13 : iface->conf->ieee80211n,
440 : 13 : iface->conf->ieee80211ac,
441 : 13 : iface->conf->vht_oper_chwidth,
442 : 13 : iface->conf->vht_oper_centr_freq_seg0_idx,
443 : 13 : iface->conf->vht_oper_centr_freq_seg1_idx);
444 [ + - ][ - + ]: 13 : if (ret < 0 || (size_t) ret >= buflen - len)
445 : 0 : return len;
446 : 13 : len += ret;
447 : :
448 [ + + ]: 32 : for (i = 0; i < iface->num_bss; i++) {
449 : 19 : struct hostapd_data *bss = iface->bss[i];
450 : 19 : ret = os_snprintf(buf + len, buflen - len,
451 : : "bss[%d]=%s\n"
452 : : "bssid[%d]=" MACSTR "\n"
453 : : "ssid[%d]=%s\n"
454 : : "num_sta[%d]=%d\n",
455 : 19 : (int) i, bss->conf->iface,
456 : 114 : (int) i, MAC2STR(bss->own_addr),
457 : : (int) i,
458 : 19 : wpa_ssid_txt(bss->conf->ssid.ssid,
459 : 19 : bss->conf->ssid.ssid_len),
460 : : (int) i, bss->num_sta);
461 [ - + ][ + - ]: 19 : if (ret < 0 || (size_t) ret >= buflen - len)
462 : 0 : return len;
463 : 19 : len += ret;
464 : : }
465 : :
466 : 13 : return len;
467 : : }
468 : :
469 : :
470 : 1 : int hostapd_parse_csa_settings(const char *pos,
471 : : struct csa_settings *settings)
472 : : {
473 : : char *end;
474 : :
475 [ - + ]: 1 : if (!settings)
476 : 0 : return -1;
477 : :
478 : 1 : os_memset(settings, 0, sizeof(*settings));
479 : 1 : settings->cs_count = strtol(pos, &end, 10);
480 [ - + ]: 1 : if (pos == end) {
481 : 0 : wpa_printf(MSG_ERROR, "chanswitch: invalid cs_count provided");
482 : 0 : return -1;
483 : : }
484 : :
485 : 1 : settings->freq_params.freq = atoi(end);
486 [ - + ]: 1 : if (settings->freq_params.freq == 0) {
487 : 0 : wpa_printf(MSG_ERROR, "chanswitch: invalid freq provided");
488 : 0 : return -1;
489 : : }
490 : :
491 : : #define SET_CSA_SETTING(str) \
492 : : do { \
493 : : const char *pos2 = os_strstr(pos, " " #str "="); \
494 : : if (pos2) { \
495 : : pos2 += sizeof(" " #str "=") - 1; \
496 : : settings->freq_params.str = atoi(pos2); \
497 : : } \
498 : : } while (0)
499 : :
500 [ - + ]: 1 : SET_CSA_SETTING(center_freq1);
501 [ - + ]: 1 : SET_CSA_SETTING(center_freq2);
502 [ - + ]: 1 : SET_CSA_SETTING(bandwidth);
503 [ - + ]: 1 : SET_CSA_SETTING(sec_channel_offset);
504 : 1 : settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
505 : 1 : settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
506 : 1 : settings->block_tx = !!os_strstr(pos, " blocktx");
507 : : #undef SET_CSA_SETTING
508 : :
509 : 1 : return 0;
510 : : }
|