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