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