Branch data Line data Source code
1 : : /*
2 : : * hostapd / WPS integration
3 : : * Copyright (c) 2008-2012, 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 "utils/eloop.h"
13 : : #include "utils/uuid.h"
14 : : #include "common/wpa_ctrl.h"
15 : : #include "common/ieee802_11_defs.h"
16 : : #include "common/ieee802_11_common.h"
17 : : #include "eapol_auth/eapol_auth_sm.h"
18 : : #include "eapol_auth/eapol_auth_sm_i.h"
19 : : #include "wps/wps.h"
20 : : #include "wps/wps_defs.h"
21 : : #include "wps/wps_dev_attr.h"
22 : : #include "wps/wps_attr_parse.h"
23 : : #include "hostapd.h"
24 : : #include "ap_config.h"
25 : : #include "ap_drv_ops.h"
26 : : #include "beacon.h"
27 : : #include "sta_info.h"
28 : : #include "wps_hostapd.h"
29 : :
30 : :
31 : : #ifdef CONFIG_WPS_UPNP
32 : : #include "wps/wps_upnp.h"
33 : : static int hostapd_wps_upnp_init(struct hostapd_data *hapd,
34 : : struct wps_context *wps);
35 : : static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd);
36 : : #endif /* CONFIG_WPS_UPNP */
37 : :
38 : : static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
39 : : const u8 *bssid,
40 : : const u8 *ie, size_t ie_len,
41 : : int ssi_signal);
42 : : static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
43 : :
44 : :
45 : : struct wps_for_each_data {
46 : : int (*func)(struct hostapd_data *h, void *ctx);
47 : : void *ctx;
48 : : struct hostapd_data *calling_hapd;
49 : : };
50 : :
51 : :
52 : 104 : static int wps_for_each(struct hostapd_iface *iface, void *ctx)
53 : : {
54 : 104 : struct wps_for_each_data *data = ctx;
55 : : size_t j;
56 : :
57 [ - + ]: 104 : if (iface == NULL)
58 : 0 : return 0;
59 [ + + ]: 208 : for (j = 0; j < iface->num_bss; j++) {
60 : 104 : struct hostapd_data *hapd = iface->bss[j];
61 : : int ret;
62 : :
63 [ - + ][ # # ]: 104 : if (hapd != data->calling_hapd &&
64 [ # # ]: 0 : (hapd->conf->wps_independent ||
65 : 0 : data->calling_hapd->conf->wps_independent))
66 : 0 : continue;
67 : :
68 : 104 : ret = data->func(hapd, data->ctx);
69 [ - + ]: 104 : if (ret)
70 : 0 : return ret;
71 : : }
72 : :
73 : 104 : return 0;
74 : : }
75 : :
76 : :
77 : 104 : static int hostapd_wps_for_each(struct hostapd_data *hapd,
78 : : int (*func)(struct hostapd_data *h, void *ctx),
79 : : void *ctx)
80 : : {
81 : 104 : struct hostapd_iface *iface = hapd->iface;
82 : : struct wps_for_each_data data;
83 : 104 : data.func = func;
84 : 104 : data.ctx = ctx;
85 : 104 : data.calling_hapd = hapd;
86 [ - + ][ # # ]: 104 : if (iface->interfaces == NULL ||
87 : 0 : iface->interfaces->for_each_interface == NULL)
88 : 104 : return wps_for_each(iface, &data);
89 : 104 : return iface->interfaces->for_each_interface(iface->interfaces,
90 : : wps_for_each, &data);
91 : : }
92 : :
93 : :
94 : 8 : static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr,
95 : : const u8 *p2p_dev_addr, const u8 *psk,
96 : : size_t psk_len)
97 : : {
98 : 8 : struct hostapd_data *hapd = ctx;
99 : : struct hostapd_wpa_psk *p;
100 : 8 : struct hostapd_ssid *ssid = &hapd->conf->ssid;
101 : :
102 [ + + ]: 8 : if (is_zero_ether_addr(p2p_dev_addr)) {
103 : 1 : wpa_printf(MSG_DEBUG,
104 : : "Received new WPA/WPA2-PSK from WPS for STA " MACSTR,
105 : 6 : MAC2STR(mac_addr));
106 : : } else {
107 : 7 : wpa_printf(MSG_DEBUG,
108 : : "Received new WPA/WPA2-PSK from WPS for STA " MACSTR
109 : : " P2P Device Addr " MACSTR,
110 : 84 : MAC2STR(mac_addr), MAC2STR(p2p_dev_addr));
111 : : }
112 : 8 : wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
113 : :
114 [ - + ]: 8 : if (psk_len != PMK_LEN) {
115 : 0 : wpa_printf(MSG_DEBUG, "Unexpected PSK length %lu",
116 : : (unsigned long) psk_len);
117 : 0 : return -1;
118 : : }
119 : :
120 : : /* Add the new PSK to runtime PSK list */
121 : 8 : p = os_zalloc(sizeof(*p));
122 [ - + ]: 8 : if (p == NULL)
123 : 0 : return -1;
124 : 8 : os_memcpy(p->addr, mac_addr, ETH_ALEN);
125 : 8 : os_memcpy(p->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
126 : 8 : os_memcpy(p->psk, psk, PMK_LEN);
127 : :
128 [ + - ]: 8 : if (hapd->new_psk_cb) {
129 : 8 : hapd->new_psk_cb(hapd->new_psk_cb_ctx, mac_addr, p2p_dev_addr,
130 : : psk, psk_len);
131 : : }
132 : :
133 : 8 : p->next = ssid->wpa_psk;
134 : 8 : ssid->wpa_psk = p;
135 : :
136 [ - + ]: 8 : if (ssid->wpa_psk_file) {
137 : : FILE *f;
138 : : char hex[PMK_LEN * 2 + 1];
139 : : /* Add the new PSK to PSK list file */
140 : 0 : f = fopen(ssid->wpa_psk_file, "a");
141 [ # # ]: 0 : if (f == NULL) {
142 : 0 : wpa_printf(MSG_DEBUG, "Failed to add the PSK to "
143 : : "'%s'", ssid->wpa_psk_file);
144 : 0 : return -1;
145 : : }
146 : :
147 : 0 : wpa_snprintf_hex(hex, sizeof(hex), psk, psk_len);
148 : 0 : fprintf(f, MACSTR " %s\n", MAC2STR(mac_addr), hex);
149 : 0 : fclose(f);
150 : : }
151 : :
152 : 8 : return 0;
153 : : }
154 : :
155 : :
156 : 207 : static int hostapd_wps_set_ie_cb(void *ctx, struct wpabuf *beacon_ie,
157 : : struct wpabuf *probe_resp_ie)
158 : : {
159 : 207 : struct hostapd_data *hapd = ctx;
160 : 207 : wpabuf_free(hapd->wps_beacon_ie);
161 : 207 : hapd->wps_beacon_ie = beacon_ie;
162 : 207 : wpabuf_free(hapd->wps_probe_resp_ie);
163 : 207 : hapd->wps_probe_resp_ie = probe_resp_ie;
164 [ + + ]: 207 : if (hapd->beacon_set_done)
165 : 152 : ieee802_11_set_beacon(hapd);
166 : 207 : return hostapd_set_ap_wps_ie(hapd);
167 : : }
168 : :
169 : :
170 : 0 : static void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
171 : : const struct wps_device_data *dev)
172 : : {
173 : 0 : struct hostapd_data *hapd = ctx;
174 : : char uuid[40], txt[400];
175 : : int len;
176 : : char devtype[WPS_DEV_TYPE_BUFSIZE];
177 [ # # ]: 0 : if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
178 : 0 : return;
179 : 0 : wpa_printf(MSG_DEBUG, "WPS: PIN needed for E-UUID %s", uuid);
180 : 0 : len = os_snprintf(txt, sizeof(txt), WPS_EVENT_PIN_NEEDED
181 : : "%s " MACSTR " [%s|%s|%s|%s|%s|%s]",
182 : 0 : uuid, MAC2STR(dev->mac_addr), dev->device_name,
183 : : dev->manufacturer, dev->model_name,
184 : : dev->model_number, dev->serial_number,
185 : 0 : wps_dev_type_bin2str(dev->pri_dev_type, devtype,
186 : : sizeof(devtype)));
187 [ # # ][ # # ]: 0 : if (len > 0 && len < (int) sizeof(txt))
188 : 0 : wpa_msg(hapd->msg_ctx, MSG_INFO, "%s", txt);
189 : :
190 [ # # ]: 0 : if (hapd->conf->wps_pin_requests) {
191 : : FILE *f;
192 : : struct os_time t;
193 : 0 : f = fopen(hapd->conf->wps_pin_requests, "a");
194 [ # # ]: 0 : if (f == NULL)
195 : 0 : return;
196 : 0 : os_get_time(&t);
197 : 0 : fprintf(f, "%ld\t%s\t" MACSTR "\t%s\t%s\t%s\t%s\t%s"
198 : : "\t%s\n",
199 : 0 : t.sec, uuid, MAC2STR(dev->mac_addr), dev->device_name,
200 : : dev->manufacturer, dev->model_name, dev->model_number,
201 : : dev->serial_number,
202 : 0 : wps_dev_type_bin2str(dev->pri_dev_type, devtype,
203 : : sizeof(devtype)));
204 : 0 : fclose(f);
205 : : }
206 : : }
207 : :
208 : :
209 : : struct wps_stop_reg_data {
210 : : struct hostapd_data *current_hapd;
211 : : const u8 *uuid_e;
212 : : const u8 *dev_pw;
213 : : size_t dev_pw_len;
214 : : };
215 : :
216 : 52 : static int wps_stop_registrar(struct hostapd_data *hapd, void *ctx)
217 : : {
218 : 52 : struct wps_stop_reg_data *data = ctx;
219 [ - + ][ # # ]: 52 : if (hapd != data->current_hapd && hapd->wps != NULL)
220 : 0 : wps_registrar_complete(hapd->wps->registrar, data->uuid_e,
221 : : data->dev_pw, data->dev_pw_len);
222 : 52 : return 0;
223 : : }
224 : :
225 : :
226 : 52 : static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
227 : : const u8 *uuid_e, const u8 *dev_pw,
228 : : size_t dev_pw_len)
229 : : {
230 : 52 : struct hostapd_data *hapd = ctx;
231 : : char uuid[40];
232 : : struct wps_stop_reg_data data;
233 [ - + ]: 52 : if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
234 : 52 : return;
235 : 52 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s",
236 : 312 : MAC2STR(mac_addr), uuid);
237 [ + - ]: 52 : if (hapd->wps_reg_success_cb)
238 : 52 : hapd->wps_reg_success_cb(hapd->wps_reg_success_cb_ctx,
239 : : mac_addr, uuid_e);
240 : 52 : data.current_hapd = hapd;
241 : 52 : data.uuid_e = uuid_e;
242 : 52 : data.dev_pw = dev_pw;
243 : 52 : data.dev_pw_len = dev_pw_len;
244 : 52 : hostapd_wps_for_each(hapd, wps_stop_registrar, &data);
245 : : }
246 : :
247 : :
248 : 60 : static void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr,
249 : : const u8 *uuid_e,
250 : : const u8 *pri_dev_type,
251 : : u16 config_methods,
252 : : u16 dev_password_id, u8 request_type,
253 : : const char *dev_name)
254 : : {
255 : 60 : struct hostapd_data *hapd = ctx;
256 : : char uuid[40];
257 : : char devtype[WPS_DEV_TYPE_BUFSIZE];
258 [ - + ]: 60 : if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
259 : 60 : return;
260 [ - + ]: 60 : if (dev_name == NULL)
261 : 0 : dev_name = "";
262 : 60 : wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ENROLLEE_SEEN MACSTR
263 : : " %s %s 0x%x %u %u [%s]",
264 : 360 : MAC2STR(addr), uuid,
265 : : wps_dev_type_bin2str(pri_dev_type, devtype,
266 : : sizeof(devtype)),
267 : : config_methods, dev_password_id, request_type, dev_name);
268 : : }
269 : :
270 : :
271 : 0 : static int str_starts(const char *str, const char *start)
272 : : {
273 : 0 : return os_strncmp(str, start, os_strlen(start)) == 0;
274 : : }
275 : :
276 : :
277 : 0 : static void wps_reload_config(void *eloop_data, void *user_ctx)
278 : : {
279 : 0 : struct hostapd_iface *iface = eloop_data;
280 : :
281 : 0 : wpa_printf(MSG_DEBUG, "WPS: Reload configuration data");
282 [ # # # # ]: 0 : if (iface->interfaces == NULL ||
283 : 0 : iface->interfaces->reload_config(iface) < 0) {
284 : 0 : wpa_printf(MSG_WARNING, "WPS: Failed to reload the updated "
285 : : "configuration");
286 : : }
287 : 0 : }
288 : :
289 : :
290 : 52 : void hostapd_wps_eap_completed(struct hostapd_data *hapd)
291 : : {
292 : : /*
293 : : * Reduce race condition of the station trying to reconnect immediately
294 : : * after AP reconfiguration through WPS by rescheduling the reload
295 : : * timeout to happen after EAP completion rather than the originally
296 : : * scheduled 100 ms after new configuration became known.
297 : : */
298 [ - + ]: 52 : if (eloop_deplete_timeout(0, 0, wps_reload_config, hapd->iface, NULL))
299 : 0 : wpa_printf(MSG_DEBUG, "WPS: Reschedule immediate configuration reload");
300 : 52 : }
301 : :
302 : :
303 : 0 : static void hapd_new_ap_event(struct hostapd_data *hapd, const u8 *attr,
304 : : size_t attr_len)
305 : : {
306 : 0 : size_t blen = attr_len * 2 + 1;
307 : 0 : char *buf = os_malloc(blen);
308 [ # # ]: 0 : if (buf) {
309 : 0 : wpa_snprintf_hex(buf, blen, attr, attr_len);
310 : 0 : wpa_msg(hapd->msg_ctx, MSG_INFO,
311 : : WPS_EVENT_NEW_AP_SETTINGS "%s", buf);
312 : 0 : os_free(buf);
313 : : }
314 : 0 : }
315 : :
316 : :
317 : 0 : static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
318 : : const struct wps_credential *cred)
319 : : {
320 : 0 : struct hostapd_bss_config *bss = hapd->conf;
321 : :
322 : 0 : wpa_printf(MSG_DEBUG, "WPS: Updating in-memory configuration");
323 : :
324 : 0 : bss->wps_state = 2;
325 [ # # ]: 0 : if (cred->ssid_len <= HOSTAPD_MAX_SSID_LEN) {
326 : 0 : os_memcpy(bss->ssid.ssid, cred->ssid, cred->ssid_len);
327 : 0 : bss->ssid.ssid_len = cred->ssid_len;
328 : 0 : bss->ssid.ssid_set = 1;
329 : : }
330 : :
331 [ # # ][ # # ]: 0 : if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
332 : 0 : (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
333 : 0 : bss->wpa = 3;
334 [ # # ]: 0 : else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK))
335 : 0 : bss->wpa = 2;
336 [ # # ]: 0 : else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
337 : 0 : bss->wpa = 1;
338 : : else
339 : 0 : bss->wpa = 0;
340 : :
341 [ # # ]: 0 : if (bss->wpa) {
342 [ # # ]: 0 : if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA))
343 : 0 : bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
344 [ # # ]: 0 : if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
345 : 0 : bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
346 : :
347 : 0 : bss->wpa_pairwise = 0;
348 [ # # ]: 0 : if (cred->encr_type & WPS_ENCR_AES)
349 : 0 : bss->wpa_pairwise |= WPA_CIPHER_CCMP;
350 [ # # ]: 0 : if (cred->encr_type & WPS_ENCR_TKIP)
351 : 0 : bss->wpa_pairwise |= WPA_CIPHER_TKIP;
352 : 0 : bss->rsn_pairwise = bss->wpa_pairwise;
353 : 0 : bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa,
354 : : bss->wpa_pairwise,
355 : : bss->rsn_pairwise);
356 : :
357 [ # # ][ # # ]: 0 : if (cred->key_len >= 8 && cred->key_len < 64) {
358 : 0 : os_free(bss->ssid.wpa_passphrase);
359 : 0 : bss->ssid.wpa_passphrase = os_zalloc(cred->key_len + 1);
360 [ # # ]: 0 : if (bss->ssid.wpa_passphrase)
361 : 0 : os_memcpy(bss->ssid.wpa_passphrase, cred->key,
362 : : cred->key_len);
363 : 0 : os_free(bss->ssid.wpa_psk);
364 : 0 : bss->ssid.wpa_psk = NULL;
365 [ # # ]: 0 : } else if (cred->key_len == 64) {
366 : 0 : os_free(bss->ssid.wpa_psk);
367 : 0 : bss->ssid.wpa_psk =
368 : 0 : os_zalloc(sizeof(struct hostapd_wpa_psk));
369 [ # # # # ]: 0 : if (bss->ssid.wpa_psk &&
370 : 0 : hexstr2bin((const char *) cred->key,
371 : 0 : bss->ssid.wpa_psk->psk, PMK_LEN) == 0) {
372 : 0 : bss->ssid.wpa_psk->group = 1;
373 : 0 : os_free(bss->ssid.wpa_passphrase);
374 : 0 : bss->ssid.wpa_passphrase = NULL;
375 : : }
376 : : }
377 : 0 : bss->auth_algs = 1;
378 : : } else {
379 [ # # ][ # # ]: 0 : if ((cred->auth_type & WPS_AUTH_OPEN) &&
380 : 0 : (cred->auth_type & WPS_AUTH_SHARED))
381 : 0 : bss->auth_algs = 3;
382 [ # # ]: 0 : else if (cred->auth_type & WPS_AUTH_SHARED)
383 : 0 : bss->auth_algs = 2;
384 : : else
385 : 0 : bss->auth_algs = 1;
386 [ # # ][ # # ]: 0 : if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx > 0 &&
[ # # ]
387 : 0 : cred->key_idx <= 4) {
388 : 0 : struct hostapd_wep_keys *wep = &bss->ssid.wep;
389 : 0 : int idx = cred->key_idx;
390 [ # # ]: 0 : if (idx)
391 : 0 : idx--;
392 : 0 : wep->idx = idx;
393 [ # # ][ # # ]: 0 : if (cred->key_len == 10 || cred->key_len == 26) {
394 : 0 : os_free(wep->key[idx]);
395 : 0 : wep->key[idx] = os_malloc(cred->key_len / 2);
396 [ # # # # ]: 0 : if (wep->key[idx] == NULL ||
397 : 0 : hexstr2bin((const char *) cred->key,
398 : : wep->key[idx],
399 : 0 : cred->key_len / 2))
400 : 0 : return -1;
401 : 0 : wep->len[idx] = cred->key_len / 2;
402 : : } else {
403 : 0 : os_free(wep->key[idx]);
404 : 0 : wep->key[idx] = os_malloc(cred->key_len);
405 [ # # ]: 0 : if (wep->key[idx] == NULL)
406 : 0 : return -1;
407 : 0 : os_memcpy(wep->key[idx], cred->key,
408 : : cred->key_len);
409 : 0 : wep->len[idx] = cred->key_len;
410 : : }
411 : 0 : wep->keys_set = 1;
412 : : }
413 : : }
414 : :
415 : : /* Schedule configuration reload after short period of time to allow
416 : : * EAP-WSC to be finished.
417 : : */
418 : 0 : eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface,
419 : : NULL);
420 : :
421 : 0 : return 0;
422 : : }
423 : :
424 : :
425 : 0 : static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
426 : : {
427 : 0 : const struct wps_credential *cred = ctx;
428 : : FILE *oconf, *nconf;
429 : : size_t len, i;
430 : : char *tmp_fname;
431 : : char buf[1024];
432 : : int multi_bss;
433 : : int wpa;
434 : :
435 [ # # ]: 0 : if (hapd->wps == NULL)
436 : 0 : return 0;
437 : :
438 : 0 : wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
439 : 0 : cred->cred_attr, cred->cred_attr_len);
440 : :
441 : 0 : wpa_printf(MSG_DEBUG, "WPS: Received new AP Settings");
442 : 0 : wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len);
443 : 0 : wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x",
444 : 0 : cred->auth_type);
445 : 0 : wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type);
446 : 0 : wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx);
447 : 0 : wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
448 : 0 : cred->key, cred->key_len);
449 : 0 : wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR,
450 : 0 : MAC2STR(cred->mac_addr));
451 : :
452 [ # # ][ # # ]: 0 : if ((hapd->conf->wps_cred_processing == 1 ||
453 [ # # ]: 0 : hapd->conf->wps_cred_processing == 2) && cred->cred_attr) {
454 : 0 : hapd_new_ap_event(hapd, cred->cred_attr, cred->cred_attr_len);
455 [ # # ][ # # ]: 0 : } else if (hapd->conf->wps_cred_processing == 1 ||
456 : 0 : hapd->conf->wps_cred_processing == 2) {
457 : : struct wpabuf *attr;
458 : 0 : attr = wpabuf_alloc(200);
459 [ # # ][ # # ]: 0 : if (attr && wps_build_credential_wrap(attr, cred) == 0)
460 : 0 : hapd_new_ap_event(hapd, wpabuf_head_u8(attr),
461 : : wpabuf_len(attr));
462 : 0 : wpabuf_free(attr);
463 : : } else
464 : 0 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS);
465 : :
466 [ # # ]: 0 : if (hapd->conf->wps_cred_processing == 1)
467 : 0 : return 0;
468 : :
469 : 0 : os_memcpy(hapd->wps->ssid, cred->ssid, cred->ssid_len);
470 : 0 : hapd->wps->ssid_len = cred->ssid_len;
471 : 0 : hapd->wps->encr_types = cred->encr_type;
472 : 0 : hapd->wps->auth_types = cred->auth_type;
473 [ # # ]: 0 : if (cred->key_len == 0) {
474 : 0 : os_free(hapd->wps->network_key);
475 : 0 : hapd->wps->network_key = NULL;
476 : 0 : hapd->wps->network_key_len = 0;
477 : : } else {
478 [ # # ][ # # ]: 0 : if (hapd->wps->network_key == NULL ||
479 : 0 : hapd->wps->network_key_len < cred->key_len) {
480 : 0 : hapd->wps->network_key_len = 0;
481 : 0 : os_free(hapd->wps->network_key);
482 : 0 : hapd->wps->network_key = os_malloc(cred->key_len);
483 [ # # ]: 0 : if (hapd->wps->network_key == NULL)
484 : 0 : return -1;
485 : : }
486 : 0 : hapd->wps->network_key_len = cred->key_len;
487 : 0 : os_memcpy(hapd->wps->network_key, cred->key, cred->key_len);
488 : : }
489 : 0 : hapd->wps->wps_state = WPS_STATE_CONFIGURED;
490 : :
491 [ # # ]: 0 : if (hapd->iface->config_fname == NULL)
492 : 0 : return hapd_wps_reconfig_in_memory(hapd, cred);
493 : 0 : len = os_strlen(hapd->iface->config_fname) + 5;
494 : 0 : tmp_fname = os_malloc(len);
495 [ # # ]: 0 : if (tmp_fname == NULL)
496 : 0 : return -1;
497 : 0 : os_snprintf(tmp_fname, len, "%s-new", hapd->iface->config_fname);
498 : :
499 : 0 : oconf = fopen(hapd->iface->config_fname, "r");
500 [ # # ]: 0 : if (oconf == NULL) {
501 : 0 : wpa_printf(MSG_WARNING, "WPS: Could not open current "
502 : : "configuration file");
503 : 0 : os_free(tmp_fname);
504 : 0 : return -1;
505 : : }
506 : :
507 : 0 : nconf = fopen(tmp_fname, "w");
508 [ # # ]: 0 : if (nconf == NULL) {
509 : 0 : wpa_printf(MSG_WARNING, "WPS: Could not write updated "
510 : : "configuration file");
511 : 0 : os_free(tmp_fname);
512 : 0 : fclose(oconf);
513 : 0 : return -1;
514 : : }
515 : :
516 : 0 : fprintf(nconf, "# WPS configuration - START\n");
517 : :
518 : 0 : fprintf(nconf, "wps_state=2\n");
519 : :
520 [ # # ]: 0 : if (is_hex(cred->ssid, cred->ssid_len)) {
521 : 0 : fprintf(nconf, "ssid2=");
522 [ # # ]: 0 : for (i = 0; i < cred->ssid_len; i++)
523 : 0 : fprintf(nconf, "%02x", cred->ssid[i]);
524 : 0 : fprintf(nconf, "\n");
525 : : } else {
526 : 0 : fprintf(nconf, "ssid=");
527 [ # # ]: 0 : for (i = 0; i < cred->ssid_len; i++)
528 : 0 : fputc(cred->ssid[i], nconf);
529 : 0 : fprintf(nconf, "\n");
530 : : }
531 : :
532 [ # # ][ # # ]: 0 : if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
533 : 0 : (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
534 : 0 : wpa = 3;
535 [ # # ]: 0 : else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK))
536 : 0 : wpa = 2;
537 [ # # ]: 0 : else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
538 : 0 : wpa = 1;
539 : : else
540 : 0 : wpa = 0;
541 : :
542 [ # # ]: 0 : if (wpa) {
543 : : char *prefix;
544 : 0 : fprintf(nconf, "wpa=%d\n", wpa);
545 : :
546 : 0 : fprintf(nconf, "wpa_key_mgmt=");
547 : 0 : prefix = "";
548 [ # # ]: 0 : if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA)) {
549 : 0 : fprintf(nconf, "WPA-EAP");
550 : 0 : prefix = " ";
551 : : }
552 [ # # ]: 0 : if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
553 : 0 : fprintf(nconf, "%sWPA-PSK", prefix);
554 : 0 : fprintf(nconf, "\n");
555 : :
556 : 0 : fprintf(nconf, "wpa_pairwise=");
557 : 0 : prefix = "";
558 [ # # ]: 0 : if (cred->encr_type & WPS_ENCR_AES) {
559 : 0 : fprintf(nconf, "CCMP");
560 : 0 : prefix = " ";
561 : : }
562 [ # # ]: 0 : if (cred->encr_type & WPS_ENCR_TKIP) {
563 : 0 : fprintf(nconf, "%sTKIP", prefix);
564 : : }
565 : 0 : fprintf(nconf, "\n");
566 : :
567 [ # # ][ # # ]: 0 : if (cred->key_len >= 8 && cred->key_len < 64) {
568 : 0 : fprintf(nconf, "wpa_passphrase=");
569 [ # # ]: 0 : for (i = 0; i < cred->key_len; i++)
570 : 0 : fputc(cred->key[i], nconf);
571 : 0 : fprintf(nconf, "\n");
572 [ # # ]: 0 : } else if (cred->key_len == 64) {
573 : 0 : fprintf(nconf, "wpa_psk=");
574 [ # # ]: 0 : for (i = 0; i < cred->key_len; i++)
575 : 0 : fputc(cred->key[i], nconf);
576 : 0 : fprintf(nconf, "\n");
577 : : } else {
578 : 0 : wpa_printf(MSG_WARNING, "WPS: Invalid key length %lu "
579 : : "for WPA/WPA2",
580 : : (unsigned long) cred->key_len);
581 : : }
582 : :
583 : 0 : fprintf(nconf, "auth_algs=1\n");
584 : : } else {
585 [ # # ][ # # ]: 0 : if ((cred->auth_type & WPS_AUTH_OPEN) &&
586 : 0 : (cred->auth_type & WPS_AUTH_SHARED))
587 : 0 : fprintf(nconf, "auth_algs=3\n");
588 [ # # ]: 0 : else if (cred->auth_type & WPS_AUTH_SHARED)
589 : 0 : fprintf(nconf, "auth_algs=2\n");
590 : : else
591 : 0 : fprintf(nconf, "auth_algs=1\n");
592 : :
593 [ # # ][ # # ]: 0 : if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx <= 4) {
594 : 0 : int key_idx = cred->key_idx;
595 [ # # ]: 0 : if (key_idx)
596 : 0 : key_idx--;
597 : 0 : fprintf(nconf, "wep_default_key=%d\n", key_idx);
598 : 0 : fprintf(nconf, "wep_key%d=", key_idx);
599 [ # # ][ # # ]: 0 : if (cred->key_len == 10 || cred->key_len == 26) {
600 : : /* WEP key as a hex string */
601 [ # # ]: 0 : for (i = 0; i < cred->key_len; i++)
602 : 0 : fputc(cred->key[i], nconf);
603 : : } else {
604 : : /* Raw WEP key; convert to hex */
605 [ # # ]: 0 : for (i = 0; i < cred->key_len; i++)
606 : 0 : fprintf(nconf, "%02x", cred->key[i]);
607 : : }
608 : 0 : fprintf(nconf, "\n");
609 : : }
610 : : }
611 : :
612 : 0 : fprintf(nconf, "# WPS configuration - END\n");
613 : :
614 : 0 : multi_bss = 0;
615 [ # # ]: 0 : while (fgets(buf, sizeof(buf), oconf)) {
616 [ # # ]: 0 : if (os_strncmp(buf, "bss=", 4) == 0)
617 : 0 : multi_bss = 1;
618 [ # # # # ]: 0 : if (!multi_bss &&
619 [ # # ]: 0 : (str_starts(buf, "ssid=") ||
620 [ # # ]: 0 : str_starts(buf, "ssid2=") ||
621 [ # # ]: 0 : str_starts(buf, "auth_algs=") ||
622 [ # # ]: 0 : str_starts(buf, "wep_default_key=") ||
623 [ # # ]: 0 : str_starts(buf, "wep_key") ||
624 [ # # ]: 0 : str_starts(buf, "wps_state=") ||
625 [ # # ]: 0 : str_starts(buf, "wpa=") ||
626 [ # # ]: 0 : str_starts(buf, "wpa_psk=") ||
627 [ # # ]: 0 : str_starts(buf, "wpa_pairwise=") ||
628 [ # # ]: 0 : str_starts(buf, "rsn_pairwise=") ||
629 [ # # ]: 0 : str_starts(buf, "wpa_key_mgmt=") ||
630 : 0 : str_starts(buf, "wpa_passphrase="))) {
631 : 0 : fprintf(nconf, "#WPS# %s", buf);
632 : : } else
633 : 0 : fprintf(nconf, "%s", buf);
634 : : }
635 : :
636 : 0 : fclose(nconf);
637 : 0 : fclose(oconf);
638 : :
639 [ # # ]: 0 : if (rename(tmp_fname, hapd->iface->config_fname) < 0) {
640 : 0 : wpa_printf(MSG_WARNING, "WPS: Failed to rename the updated "
641 : 0 : "configuration file: %s", strerror(errno));
642 : 0 : os_free(tmp_fname);
643 : 0 : return -1;
644 : : }
645 : :
646 : 0 : os_free(tmp_fname);
647 : :
648 : : /* Schedule configuration reload after short period of time to allow
649 : : * EAP-WSC to be finished.
650 : : */
651 : 0 : eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface,
652 : : NULL);
653 : :
654 : 0 : wpa_printf(MSG_DEBUG, "WPS: AP configuration updated");
655 : :
656 : 0 : return 0;
657 : : }
658 : :
659 : :
660 : 0 : static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
661 : : {
662 : 0 : struct hostapd_data *hapd = ctx;
663 : 0 : return hostapd_wps_for_each(hapd, hapd_wps_cred_cb, (void *) cred);
664 : : }
665 : :
666 : :
667 : 0 : static void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx)
668 : : {
669 : 0 : struct hostapd_data *hapd = eloop_data;
670 : :
671 [ # # ]: 0 : if (hapd->conf->ap_setup_locked)
672 : 0 : return;
673 [ # # ]: 0 : if (hapd->ap_pin_failures_consecutive >= 10)
674 : 0 : return;
675 : :
676 : 0 : wpa_printf(MSG_DEBUG, "WPS: Re-enable AP PIN");
677 : 0 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED);
678 : 0 : hapd->wps->ap_setup_locked = 0;
679 : 0 : wps_registrar_update_ie(hapd->wps->registrar);
680 : : }
681 : :
682 : :
683 : 0 : static int wps_pwd_auth_fail(struct hostapd_data *hapd, void *ctx)
684 : : {
685 : 0 : struct wps_event_pwd_auth_fail *data = ctx;
686 : :
687 [ # # ][ # # ]: 0 : if (!data->enrollee || hapd->conf->ap_pin == NULL || hapd->wps == NULL)
[ # # ]
688 : 0 : return 0;
689 : :
690 : : /*
691 : : * Registrar failed to prove its knowledge of the AP PIN. Lock AP setup
692 : : * for some time if this happens multiple times to slow down brute
693 : : * force attacks.
694 : : */
695 : 0 : hapd->ap_pin_failures++;
696 : 0 : hapd->ap_pin_failures_consecutive++;
697 : 0 : wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u "
698 : : "(%u consecutive)",
699 : : hapd->ap_pin_failures, hapd->ap_pin_failures_consecutive);
700 [ # # ]: 0 : if (hapd->ap_pin_failures < 3)
701 : 0 : return 0;
702 : :
703 : 0 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED);
704 : 0 : hapd->wps->ap_setup_locked = 1;
705 : :
706 : 0 : wps_registrar_update_ie(hapd->wps->registrar);
707 : :
708 [ # # ][ # # ]: 0 : if (!hapd->conf->ap_setup_locked &&
709 : 0 : hapd->ap_pin_failures_consecutive >= 10) {
710 : : /*
711 : : * In indefinite lockdown - disable automatic AP PIN
712 : : * reenablement.
713 : : */
714 : 0 : eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
715 : 0 : wpa_printf(MSG_DEBUG, "WPS: AP PIN disabled indefinitely");
716 [ # # ]: 0 : } else if (!hapd->conf->ap_setup_locked) {
717 [ # # ]: 0 : if (hapd->ap_pin_lockout_time == 0)
718 : 0 : hapd->ap_pin_lockout_time = 60;
719 [ # # ][ # # ]: 0 : else if (hapd->ap_pin_lockout_time < 365 * 24 * 60 * 60 &&
720 : 0 : (hapd->ap_pin_failures % 3) == 0)
721 : 0 : hapd->ap_pin_lockout_time *= 2;
722 : :
723 : 0 : wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN for %u seconds",
724 : : hapd->ap_pin_lockout_time);
725 : 0 : eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
726 : 0 : eloop_register_timeout(hapd->ap_pin_lockout_time, 0,
727 : : hostapd_wps_reenable_ap_pin, hapd,
728 : : NULL);
729 : : }
730 : :
731 : 0 : return 0;
732 : : }
733 : :
734 : :
735 : 0 : static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
736 : : struct wps_event_pwd_auth_fail *data)
737 : : {
738 : : /* Update WPS Status - Authentication Failure */
739 : 0 : wpa_printf(MSG_DEBUG, "WPS: Authentication failure update");
740 : 0 : hapd->wps_stats.status = WPS_STATUS_FAILURE;
741 : 0 : hapd->wps_stats.failure_reason = WPS_EI_AUTH_FAILURE;
742 : 0 : os_memcpy(hapd->wps_stats.peer_addr, data->peer_macaddr, ETH_ALEN);
743 : :
744 : 0 : hostapd_wps_for_each(hapd, wps_pwd_auth_fail, data);
745 : 0 : }
746 : :
747 : :
748 : 0 : static int wps_ap_pin_success(struct hostapd_data *hapd, void *ctx)
749 : : {
750 [ # # ][ # # ]: 0 : if (hapd->conf->ap_pin == NULL || hapd->wps == NULL)
751 : 0 : return 0;
752 : :
753 [ # # ]: 0 : if (hapd->ap_pin_failures_consecutive == 0)
754 : 0 : return 0;
755 : :
756 : 0 : wpa_printf(MSG_DEBUG, "WPS: Clear consecutive AP PIN failure counter "
757 : : "- total validation failures %u (%u consecutive)",
758 : : hapd->ap_pin_failures, hapd->ap_pin_failures_consecutive);
759 : 0 : hapd->ap_pin_failures_consecutive = 0;
760 : :
761 : 0 : return 0;
762 : : }
763 : :
764 : :
765 : 0 : static void hostapd_wps_ap_pin_success(struct hostapd_data *hapd)
766 : : {
767 : 0 : hostapd_wps_for_each(hapd, wps_ap_pin_success, NULL);
768 : 0 : }
769 : :
770 : :
771 : 0 : static void hostapd_wps_event_pbc_overlap(struct hostapd_data *hapd)
772 : : {
773 : : /* Update WPS Status - PBC Overlap */
774 : 0 : hapd->wps_stats.pbc_status = WPS_PBC_STATUS_OVERLAP;
775 : 0 : }
776 : :
777 : :
778 : 0 : static void hostapd_wps_event_pbc_timeout(struct hostapd_data *hapd)
779 : : {
780 : : /* Update WPS PBC Status:PBC Timeout */
781 : 0 : hapd->wps_stats.pbc_status = WPS_PBC_STATUS_TIMEOUT;
782 : 0 : }
783 : :
784 : :
785 : 4 : static void hostapd_wps_event_pbc_active(struct hostapd_data *hapd)
786 : : {
787 : : /* Update WPS PBC status - Active */
788 : 4 : hapd->wps_stats.pbc_status = WPS_PBC_STATUS_ACTIVE;
789 : 4 : }
790 : :
791 : :
792 : 4 : static void hostapd_wps_event_pbc_disable(struct hostapd_data *hapd)
793 : : {
794 : : /* Update WPS PBC status - Active */
795 : 4 : hapd->wps_stats.pbc_status = WPS_PBC_STATUS_DISABLE;
796 : 4 : }
797 : :
798 : :
799 : 52 : static void hostapd_wps_event_success(struct hostapd_data *hapd,
800 : : struct wps_event_success *success)
801 : : {
802 : : /* Update WPS status - Success */
803 : 52 : hapd->wps_stats.pbc_status = WPS_PBC_STATUS_DISABLE;
804 : 52 : hapd->wps_stats.status = WPS_STATUS_SUCCESS;
805 : 52 : os_memcpy(hapd->wps_stats.peer_addr, success->peer_macaddr, ETH_ALEN);
806 : 52 : }
807 : :
808 : :
809 : 0 : static void hostapd_wps_event_fail(struct hostapd_data *hapd,
810 : : struct wps_event_fail *fail)
811 : : {
812 : : /* Update WPS status - Failure */
813 : 0 : hapd->wps_stats.status = WPS_STATUS_FAILURE;
814 : 0 : os_memcpy(hapd->wps_stats.peer_addr, fail->peer_macaddr, ETH_ALEN);
815 : :
816 : 0 : hapd->wps_stats.failure_reason = fail->error_indication;
817 : :
818 [ # # ][ # # ]: 0 : if (fail->error_indication > 0 &&
819 : 0 : fail->error_indication < NUM_WPS_EI_VALUES) {
820 : 0 : wpa_msg(hapd->msg_ctx, MSG_INFO,
821 : : WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)",
822 : 0 : fail->msg, fail->config_error, fail->error_indication,
823 : 0 : wps_ei_str(fail->error_indication));
824 : : } else {
825 : 0 : wpa_msg(hapd->msg_ctx, MSG_INFO,
826 : : WPS_EVENT_FAIL "msg=%d config_error=%d",
827 : 0 : fail->msg, fail->config_error);
828 : : }
829 : 0 : }
830 : :
831 : :
832 : 60 : static void hostapd_wps_event_cb(void *ctx, enum wps_event event,
833 : : union wps_event_data *data)
834 : : {
835 : 60 : struct hostapd_data *hapd = ctx;
836 : :
837 [ - - + - : 60 : switch (event) {
- - + + -
- - - - -
- - ]
838 : : case WPS_EV_M2D:
839 : 0 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_M2D);
840 : 0 : break;
841 : : case WPS_EV_FAIL:
842 : 0 : hostapd_wps_event_fail(hapd, &data->fail);
843 : 0 : break;
844 : : case WPS_EV_SUCCESS:
845 : 52 : hostapd_wps_event_success(hapd, &data->success);
846 : 52 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_SUCCESS);
847 : 52 : break;
848 : : case WPS_EV_PWD_AUTH_FAIL:
849 : 0 : hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail);
850 : 0 : break;
851 : : case WPS_EV_PBC_OVERLAP:
852 : 0 : hostapd_wps_event_pbc_overlap(hapd);
853 : 0 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_OVERLAP);
854 : 0 : break;
855 : : case WPS_EV_PBC_TIMEOUT:
856 : 0 : hostapd_wps_event_pbc_timeout(hapd);
857 : 0 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_TIMEOUT);
858 : 0 : break;
859 : : case WPS_EV_PBC_ACTIVE:
860 : 4 : hostapd_wps_event_pbc_active(hapd);
861 : 4 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ACTIVE);
862 : 4 : break;
863 : : case WPS_EV_PBC_DISABLE:
864 : 4 : hostapd_wps_event_pbc_disable(hapd);
865 : 4 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_DISABLE);
866 : 4 : break;
867 : : case WPS_EV_ER_AP_ADD:
868 : 0 : break;
869 : : case WPS_EV_ER_AP_REMOVE:
870 : 0 : break;
871 : : case WPS_EV_ER_ENROLLEE_ADD:
872 : 0 : break;
873 : : case WPS_EV_ER_ENROLLEE_REMOVE:
874 : 0 : break;
875 : : case WPS_EV_ER_AP_SETTINGS:
876 : 0 : break;
877 : : case WPS_EV_ER_SET_SELECTED_REGISTRAR:
878 : 0 : break;
879 : : case WPS_EV_AP_PIN_SUCCESS:
880 : 0 : hostapd_wps_ap_pin_success(hapd);
881 : 0 : break;
882 : : }
883 [ + - ]: 60 : if (hapd->wps_event_cb)
884 : 60 : hapd->wps_event_cb(hapd->wps_event_cb_ctx, event, data);
885 : 60 : }
886 : :
887 : :
888 : 52 : static int hostapd_wps_rf_band_cb(void *ctx)
889 : : {
890 : 52 : struct hostapd_data *hapd = ctx;
891 : :
892 : 52 : return hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
893 [ - + ]: 52 : WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
894 : : }
895 : :
896 : :
897 : 55 : static void hostapd_wps_clear_ies(struct hostapd_data *hapd)
898 : : {
899 : 55 : wpabuf_free(hapd->wps_beacon_ie);
900 : 55 : hapd->wps_beacon_ie = NULL;
901 : :
902 : 55 : wpabuf_free(hapd->wps_probe_resp_ie);
903 : 55 : hapd->wps_probe_resp_ie = NULL;
904 : :
905 : 55 : hostapd_set_ap_wps_ie(hapd);
906 : 55 : }
907 : :
908 : :
909 : 0 : static int get_uuid_cb(struct hostapd_iface *iface, void *ctx)
910 : : {
911 : 0 : const u8 **uuid = ctx;
912 : : size_t j;
913 : :
914 [ # # ]: 0 : if (iface == NULL)
915 : 0 : return 0;
916 [ # # ]: 0 : for (j = 0; j < iface->num_bss; j++) {
917 : 0 : struct hostapd_data *hapd = iface->bss[j];
918 [ # # ]: 0 : if (hapd->wps && !hapd->conf->wps_independent &&
[ # # # # ]
919 : 0 : !is_nil_uuid(hapd->wps->uuid)) {
920 : 0 : *uuid = hapd->wps->uuid;
921 : 0 : return 1;
922 : : }
923 : : }
924 : :
925 : 0 : return 0;
926 : : }
927 : :
928 : :
929 : 0 : static const u8 * get_own_uuid(struct hostapd_iface *iface)
930 : : {
931 : : const u8 *uuid;
932 [ # # ][ # # ]: 0 : if (iface->interfaces == NULL ||
933 : 0 : iface->interfaces->for_each_interface == NULL)
934 : 0 : return NULL;
935 : 0 : uuid = NULL;
936 : 0 : iface->interfaces->for_each_interface(iface->interfaces, get_uuid_cb,
937 : : &uuid);
938 : 0 : return uuid;
939 : : }
940 : :
941 : :
942 : 0 : static int count_interface_cb(struct hostapd_iface *iface, void *ctx)
943 : : {
944 : 0 : int *count= ctx;
945 : 0 : (*count)++;
946 : 0 : return 0;
947 : : }
948 : :
949 : :
950 : 55 : static int interface_count(struct hostapd_iface *iface)
951 : : {
952 : 55 : int count = 0;
953 [ - + ][ # # ]: 55 : if (iface->interfaces == NULL ||
954 : 0 : iface->interfaces->for_each_interface == NULL)
955 : 55 : return 0;
956 : 0 : iface->interfaces->for_each_interface(iface->interfaces,
957 : : count_interface_cb, &count);
958 : 55 : return count;
959 : : }
960 : :
961 : :
962 : 55 : static int hostapd_wps_set_vendor_ext(struct hostapd_data *hapd,
963 : : struct wps_context *wps)
964 : : {
965 : : int i;
966 : :
967 [ + + ]: 605 : for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
968 : 550 : wpabuf_free(wps->dev.vendor_ext[i]);
969 : 550 : wps->dev.vendor_ext[i] = NULL;
970 : :
971 [ + - ]: 550 : if (hapd->conf->wps_vendor_ext[i] == NULL)
972 : 550 : continue;
973 : :
974 : 0 : wps->dev.vendor_ext[i] =
975 : 0 : wpabuf_dup(hapd->conf->wps_vendor_ext[i]);
976 [ # # ]: 0 : if (wps->dev.vendor_ext[i] == NULL) {
977 [ # # ]: 0 : while (--i >= 0)
978 : 0 : wpabuf_free(wps->dev.vendor_ext[i]);
979 : 0 : return -1;
980 : : }
981 : : }
982 : :
983 : 55 : return 0;
984 : : }
985 : :
986 : :
987 : 55 : int hostapd_init_wps(struct hostapd_data *hapd,
988 : : struct hostapd_bss_config *conf)
989 : : {
990 : : struct wps_context *wps;
991 : : struct wps_registrar_config cfg;
992 : :
993 [ - + ]: 55 : if (conf->wps_state == 0) {
994 : 0 : hostapd_wps_clear_ies(hapd);
995 : 0 : return 0;
996 : : }
997 : :
998 : 55 : wps = os_zalloc(sizeof(*wps));
999 [ - + ]: 55 : if (wps == NULL)
1000 : 0 : return -1;
1001 : :
1002 : 55 : wps->cred_cb = hostapd_wps_cred_cb;
1003 : 55 : wps->event_cb = hostapd_wps_event_cb;
1004 : 55 : wps->rf_band_cb = hostapd_wps_rf_band_cb;
1005 : 55 : wps->cb_ctx = hapd;
1006 : :
1007 : 55 : os_memset(&cfg, 0, sizeof(cfg));
1008 : 55 : wps->wps_state = hapd->conf->wps_state;
1009 : 55 : wps->ap_setup_locked = hapd->conf->ap_setup_locked;
1010 [ - + ]: 55 : if (is_nil_uuid(hapd->conf->uuid)) {
1011 : : const u8 *uuid;
1012 : 0 : uuid = get_own_uuid(hapd->iface);
1013 [ # # ][ # # ]: 0 : if (uuid && !conf->wps_independent) {
1014 : 0 : os_memcpy(wps->uuid, uuid, UUID_LEN);
1015 : 0 : wpa_hexdump(MSG_DEBUG, "WPS: Clone UUID from another "
1016 : 0 : "interface", wps->uuid, UUID_LEN);
1017 : : } else {
1018 : 0 : uuid_gen_mac_addr(hapd->own_addr, wps->uuid);
1019 : 0 : wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC "
1020 : 0 : "address", wps->uuid, UUID_LEN);
1021 : : }
1022 : : } else {
1023 : 55 : os_memcpy(wps->uuid, hapd->conf->uuid, UUID_LEN);
1024 : 55 : wpa_hexdump(MSG_DEBUG, "WPS: Use configured UUID",
1025 : 55 : wps->uuid, UUID_LEN);
1026 : : }
1027 : 55 : wps->ssid_len = hapd->conf->ssid.ssid_len;
1028 : 55 : os_memcpy(wps->ssid, hapd->conf->ssid.ssid, wps->ssid_len);
1029 : 55 : wps->ap = 1;
1030 : 55 : os_memcpy(wps->dev.mac_addr, hapd->own_addr, ETH_ALEN);
1031 : 110 : wps->dev.device_name = hapd->conf->device_name ?
1032 [ + - ]: 55 : os_strdup(hapd->conf->device_name) : NULL;
1033 : 110 : wps->dev.manufacturer = hapd->conf->manufacturer ?
1034 [ - + ]: 55 : os_strdup(hapd->conf->manufacturer) : NULL;
1035 : 110 : wps->dev.model_name = hapd->conf->model_name ?
1036 [ - + ]: 55 : os_strdup(hapd->conf->model_name) : NULL;
1037 : 110 : wps->dev.model_number = hapd->conf->model_number ?
1038 [ - + ]: 55 : os_strdup(hapd->conf->model_number) : NULL;
1039 : 110 : wps->dev.serial_number = hapd->conf->serial_number ?
1040 [ - + ]: 55 : os_strdup(hapd->conf->serial_number) : NULL;
1041 : 55 : wps->config_methods =
1042 : 55 : wps_config_methods_str2bin(hapd->conf->config_methods);
1043 : : #ifdef CONFIG_WPS2
1044 [ - + ]: 55 : if ((wps->config_methods &
1045 : : (WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY |
1046 : : WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) {
1047 : 0 : wpa_printf(MSG_INFO, "WPS: Converting display to "
1048 : : "virtual_display for WPS 2.0 compliance");
1049 : 0 : wps->config_methods |= WPS_CONFIG_VIRT_DISPLAY;
1050 : : }
1051 [ - + ]: 55 : if ((wps->config_methods &
1052 : : (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON |
1053 : : WPS_CONFIG_PHY_PUSHBUTTON)) == WPS_CONFIG_PUSHBUTTON) {
1054 : 0 : wpa_printf(MSG_INFO, "WPS: Converting push_button to "
1055 : : "virtual_push_button for WPS 2.0 compliance");
1056 : 0 : wps->config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
1057 : : }
1058 : : #endif /* CONFIG_WPS2 */
1059 : 55 : os_memcpy(wps->dev.pri_dev_type, hapd->conf->device_type,
1060 : : WPS_DEV_TYPE_LEN);
1061 : :
1062 [ - + ]: 55 : if (hostapd_wps_set_vendor_ext(hapd, wps) < 0) {
1063 : 0 : os_free(wps);
1064 : 0 : return -1;
1065 : : }
1066 : :
1067 : 55 : wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
1068 : :
1069 [ - + ]: 55 : if (conf->wps_rf_bands) {
1070 : 0 : wps->dev.rf_bands = conf->wps_rf_bands;
1071 : : } else {
1072 [ - + ]: 55 : wps->dev.rf_bands =
1073 : 55 : hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
1074 : : WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
1075 : : }
1076 : :
1077 [ + - ]: 55 : if (conf->wpa & WPA_PROTO_RSN) {
1078 [ + - ]: 55 : if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
1079 : 55 : wps->auth_types |= WPS_AUTH_WPA2PSK;
1080 [ - + ]: 55 : if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
1081 : 0 : wps->auth_types |= WPS_AUTH_WPA2;
1082 : :
1083 [ + - ]: 55 : if (conf->rsn_pairwise & WPA_CIPHER_CCMP)
1084 : 55 : wps->encr_types |= WPS_ENCR_AES;
1085 [ - + ]: 55 : if (conf->rsn_pairwise & WPA_CIPHER_TKIP)
1086 : 0 : wps->encr_types |= WPS_ENCR_TKIP;
1087 : : }
1088 : :
1089 [ - + ]: 55 : if (conf->wpa & WPA_PROTO_WPA) {
1090 [ # # ]: 0 : if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
1091 : 0 : wps->auth_types |= WPS_AUTH_WPAPSK;
1092 [ # # ]: 0 : if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
1093 : 0 : wps->auth_types |= WPS_AUTH_WPA;
1094 : :
1095 [ # # ]: 0 : if (conf->wpa_pairwise & WPA_CIPHER_CCMP)
1096 : 0 : wps->encr_types |= WPS_ENCR_AES;
1097 [ # # ]: 0 : if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
1098 : 0 : wps->encr_types |= WPS_ENCR_TKIP;
1099 : : }
1100 : :
1101 [ - + ]: 55 : if (conf->ssid.security_policy == SECURITY_PLAINTEXT) {
1102 : 0 : wps->encr_types |= WPS_ENCR_NONE;
1103 : 0 : wps->auth_types |= WPS_AUTH_OPEN;
1104 [ - + ]: 55 : } else if (conf->ssid.security_policy == SECURITY_STATIC_WEP) {
1105 : 0 : wps->encr_types |= WPS_ENCR_WEP;
1106 [ # # ]: 0 : if (conf->auth_algs & WPA_AUTH_ALG_OPEN)
1107 : 0 : wps->auth_types |= WPS_AUTH_OPEN;
1108 [ # # ]: 0 : if (conf->auth_algs & WPA_AUTH_ALG_SHARED)
1109 : 0 : wps->auth_types |= WPS_AUTH_SHARED;
1110 [ - + ]: 55 : } else if (conf->ssid.security_policy == SECURITY_IEEE_802_1X) {
1111 : 0 : wps->auth_types |= WPS_AUTH_OPEN;
1112 [ # # ]: 0 : if (conf->default_wep_key_len)
1113 : 0 : wps->encr_types |= WPS_ENCR_WEP;
1114 : : else
1115 : 0 : wps->encr_types |= WPS_ENCR_NONE;
1116 : : }
1117 : :
1118 [ + - ]: 55 : if (conf->ssid.wpa_psk_file) {
1119 : : /* Use per-device PSKs */
1120 [ - + ]: 55 : } else if (conf->ssid.wpa_passphrase) {
1121 : 0 : wps->network_key = (u8 *) os_strdup(conf->ssid.wpa_passphrase);
1122 : 0 : wps->network_key_len = os_strlen(conf->ssid.wpa_passphrase);
1123 [ + - ]: 55 : } else if (conf->ssid.wpa_psk) {
1124 : 55 : wps->network_key = os_malloc(2 * PMK_LEN + 1);
1125 [ - + ]: 55 : if (wps->network_key == NULL) {
1126 : 0 : os_free(wps);
1127 : 0 : return -1;
1128 : : }
1129 : 55 : wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
1130 : 55 : conf->ssid.wpa_psk->psk, PMK_LEN);
1131 : 55 : wps->network_key_len = 2 * PMK_LEN;
1132 [ # # ][ # # ]: 0 : } else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
1133 : 0 : wps->network_key = os_malloc(conf->ssid.wep.len[0]);
1134 [ # # ]: 0 : if (wps->network_key == NULL) {
1135 : 0 : os_free(wps);
1136 : 0 : return -1;
1137 : : }
1138 : 0 : os_memcpy(wps->network_key, conf->ssid.wep.key[0],
1139 : : conf->ssid.wep.len[0]);
1140 : 0 : wps->network_key_len = conf->ssid.wep.len[0];
1141 : : }
1142 : :
1143 [ + - ]: 55 : if (conf->ssid.wpa_psk) {
1144 : 55 : os_memcpy(wps->psk, conf->ssid.wpa_psk->psk, PMK_LEN);
1145 : 55 : wps->psk_set = 1;
1146 : : }
1147 : :
1148 [ - + ]: 55 : if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) {
1149 : : /* Override parameters to enable security by default */
1150 : 0 : wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
1151 : 0 : wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
1152 : : }
1153 : :
1154 : 55 : wps->ap_settings = conf->ap_settings;
1155 : 55 : wps->ap_settings_len = conf->ap_settings_len;
1156 : :
1157 : 55 : cfg.new_psk_cb = hostapd_wps_new_psk_cb;
1158 : 55 : cfg.set_ie_cb = hostapd_wps_set_ie_cb;
1159 : 55 : cfg.pin_needed_cb = hostapd_wps_pin_needed_cb;
1160 : 55 : cfg.reg_success_cb = hostapd_wps_reg_success_cb;
1161 : 55 : cfg.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb;
1162 : 55 : cfg.cb_ctx = hapd;
1163 : 55 : cfg.skip_cred_build = conf->skip_cred_build;
1164 : 55 : cfg.extra_cred = conf->extra_cred;
1165 : 55 : cfg.extra_cred_len = conf->extra_cred_len;
1166 [ - + ][ # # ]: 55 : cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) &&
1167 : 0 : conf->skip_cred_build;
1168 [ - + ]: 55 : if (conf->ssid.security_policy == SECURITY_STATIC_WEP)
1169 : 0 : cfg.static_wep_only = 1;
1170 : 55 : cfg.dualband = interface_count(hapd->iface) > 1;
1171 [ - + ]: 55 : if ((wps->dev.rf_bands & (WPS_RF_50GHZ | WPS_RF_24GHZ)) ==
1172 : : (WPS_RF_50GHZ | WPS_RF_24GHZ))
1173 : 0 : cfg.dualband = 1;
1174 [ - + ]: 55 : if (cfg.dualband)
1175 : 0 : wpa_printf(MSG_DEBUG, "WPS: Dualband AP");
1176 : 55 : cfg.force_per_enrollee_psk = conf->force_per_enrollee_psk;
1177 : :
1178 : 55 : wps->registrar = wps_registrar_init(wps, &cfg);
1179 [ - + ]: 55 : if (wps->registrar == NULL) {
1180 : 0 : wpa_printf(MSG_ERROR, "Failed to initialize WPS Registrar");
1181 : 0 : os_free(wps->network_key);
1182 : 0 : os_free(wps);
1183 : 0 : return -1;
1184 : : }
1185 : :
1186 : : #ifdef CONFIG_WPS_UPNP
1187 : 55 : wps->friendly_name = hapd->conf->friendly_name;
1188 : 55 : wps->manufacturer_url = hapd->conf->manufacturer_url;
1189 : 55 : wps->model_description = hapd->conf->model_description;
1190 : 55 : wps->model_url = hapd->conf->model_url;
1191 : 55 : wps->upc = hapd->conf->upc;
1192 : : #endif /* CONFIG_WPS_UPNP */
1193 : :
1194 : 55 : hostapd_register_probereq_cb(hapd, hostapd_wps_probe_req_rx, hapd);
1195 : :
1196 : 55 : hapd->wps = wps;
1197 : :
1198 : 55 : return 0;
1199 : : }
1200 : :
1201 : :
1202 : 55 : int hostapd_init_wps_complete(struct hostapd_data *hapd)
1203 : : {
1204 : 55 : struct wps_context *wps = hapd->wps;
1205 : :
1206 [ - + ]: 55 : if (wps == NULL)
1207 : 0 : return 0;
1208 : :
1209 : : #ifdef CONFIG_WPS_UPNP
1210 [ - + ]: 55 : if (hostapd_wps_upnp_init(hapd, wps) < 0) {
1211 : 0 : wpa_printf(MSG_ERROR, "Failed to initialize WPS UPnP");
1212 : 0 : wps_registrar_deinit(wps->registrar);
1213 : 0 : os_free(wps->network_key);
1214 : 0 : os_free(wps);
1215 : 0 : hapd->wps = NULL;
1216 : 0 : return -1;
1217 : : }
1218 : : #endif /* CONFIG_WPS_UPNP */
1219 : :
1220 : 55 : return 0;
1221 : : }
1222 : :
1223 : :
1224 : 55 : static void hostapd_wps_nfc_clear(struct wps_context *wps)
1225 : : {
1226 : : #ifdef CONFIG_WPS_NFC
1227 : 55 : wpa_printf(MSG_DEBUG, "WPS: Clear NFC Tag context %p", wps);
1228 : 55 : wps->ap_nfc_dev_pw_id = 0;
1229 : 55 : wpabuf_free(wps->ap_nfc_dh_pubkey);
1230 : 55 : wps->ap_nfc_dh_pubkey = NULL;
1231 : 55 : wpabuf_free(wps->ap_nfc_dh_privkey);
1232 : 55 : wps->ap_nfc_dh_privkey = NULL;
1233 : 55 : wpabuf_free(wps->ap_nfc_dev_pw);
1234 : 55 : wps->ap_nfc_dev_pw = NULL;
1235 : : #endif /* CONFIG_WPS_NFC */
1236 : 55 : }
1237 : :
1238 : :
1239 : 55 : void hostapd_deinit_wps(struct hostapd_data *hapd)
1240 : : {
1241 : 55 : eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
1242 : 55 : eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
1243 [ - + ]: 55 : if (hapd->wps == NULL)
1244 : 55 : return;
1245 : : #ifdef CONFIG_WPS_UPNP
1246 : 55 : hostapd_wps_upnp_deinit(hapd);
1247 : : #endif /* CONFIG_WPS_UPNP */
1248 : 55 : wps_registrar_deinit(hapd->wps->registrar);
1249 : 55 : os_free(hapd->wps->network_key);
1250 : 55 : wps_device_data_free(&hapd->wps->dev);
1251 : 55 : wpabuf_free(hapd->wps->dh_pubkey);
1252 : 55 : wpabuf_free(hapd->wps->dh_privkey);
1253 : 55 : wps_free_pending_msgs(hapd->wps->upnp_msgs);
1254 : 55 : hostapd_wps_nfc_clear(hapd->wps);
1255 : 55 : os_free(hapd->wps);
1256 : 55 : hapd->wps = NULL;
1257 : 55 : hostapd_wps_clear_ies(hapd);
1258 : : }
1259 : :
1260 : :
1261 : 0 : void hostapd_update_wps(struct hostapd_data *hapd)
1262 : : {
1263 [ # # ]: 0 : if (hapd->wps == NULL)
1264 : 0 : return;
1265 : :
1266 : : #ifdef CONFIG_WPS_UPNP
1267 : 0 : hapd->wps->friendly_name = hapd->conf->friendly_name;
1268 : 0 : hapd->wps->manufacturer_url = hapd->conf->manufacturer_url;
1269 : 0 : hapd->wps->model_description = hapd->conf->model_description;
1270 : 0 : hapd->wps->model_url = hapd->conf->model_url;
1271 : 0 : hapd->wps->upc = hapd->conf->upc;
1272 : : #endif /* CONFIG_WPS_UPNP */
1273 : :
1274 : 0 : hostapd_wps_set_vendor_ext(hapd, hapd->wps);
1275 : :
1276 [ # # ]: 0 : if (hapd->conf->wps_state)
1277 : 0 : wps_registrar_update_ie(hapd->wps->registrar);
1278 : : else
1279 : 0 : hostapd_deinit_wps(hapd);
1280 : : }
1281 : :
1282 : :
1283 : : struct wps_add_pin_data {
1284 : : const u8 *addr;
1285 : : const u8 *uuid;
1286 : : const u8 *pin;
1287 : : size_t pin_len;
1288 : : int timeout;
1289 : : int added;
1290 : : };
1291 : :
1292 : :
1293 : 48 : static int wps_add_pin(struct hostapd_data *hapd, void *ctx)
1294 : : {
1295 : 48 : struct wps_add_pin_data *data = ctx;
1296 : : int ret;
1297 : :
1298 [ - + ]: 48 : if (hapd->wps == NULL)
1299 : 0 : return 0;
1300 : 48 : ret = wps_registrar_add_pin(hapd->wps->registrar, data->addr,
1301 : : data->uuid, data->pin, data->pin_len,
1302 : : data->timeout);
1303 [ + - ]: 48 : if (ret == 0)
1304 : 48 : data->added++;
1305 : 48 : return ret;
1306 : : }
1307 : :
1308 : :
1309 : 48 : int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
1310 : : const char *uuid, const char *pin, int timeout)
1311 : : {
1312 : : u8 u[UUID_LEN];
1313 : : struct wps_add_pin_data data;
1314 : :
1315 : 48 : data.addr = addr;
1316 : 48 : data.uuid = u;
1317 : 48 : data.pin = (const u8 *) pin;
1318 : 48 : data.pin_len = os_strlen(pin);
1319 : 48 : data.timeout = timeout;
1320 : 48 : data.added = 0;
1321 : :
1322 [ + - ]: 48 : if (os_strcmp(uuid, "any") == 0)
1323 : 48 : data.uuid = NULL;
1324 : : else {
1325 [ # # ]: 0 : if (uuid_str2bin(uuid, u))
1326 : 0 : return -1;
1327 : 0 : data.uuid = u;
1328 : : }
1329 [ - + ]: 48 : if (hostapd_wps_for_each(hapd, wps_add_pin, &data) < 0)
1330 : 0 : return -1;
1331 [ + - ]: 48 : return data.added ? 0 : -1;
1332 : : }
1333 : :
1334 : :
1335 : 4 : static int wps_button_pushed(struct hostapd_data *hapd, void *ctx)
1336 : : {
1337 : 4 : const u8 *p2p_dev_addr = ctx;
1338 [ - + ]: 4 : if (hapd->wps == NULL)
1339 : 0 : return 0;
1340 : 4 : return wps_registrar_button_pushed(hapd->wps->registrar, p2p_dev_addr);
1341 : : }
1342 : :
1343 : :
1344 : 4 : int hostapd_wps_button_pushed(struct hostapd_data *hapd,
1345 : : const u8 *p2p_dev_addr)
1346 : : {
1347 : 4 : return hostapd_wps_for_each(hapd, wps_button_pushed,
1348 : : (void *) p2p_dev_addr);
1349 : : }
1350 : :
1351 : :
1352 : 0 : static int wps_cancel(struct hostapd_data *hapd, void *ctx)
1353 : : {
1354 [ # # ]: 0 : if (hapd->wps == NULL)
1355 : 0 : return 0;
1356 : :
1357 : 0 : wps_registrar_wps_cancel(hapd->wps->registrar);
1358 : 0 : ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
1359 : :
1360 : 0 : return 0;
1361 : : }
1362 : :
1363 : :
1364 : 0 : int hostapd_wps_cancel(struct hostapd_data *hapd)
1365 : : {
1366 : 0 : return hostapd_wps_for_each(hapd, wps_cancel, NULL);
1367 : : }
1368 : :
1369 : :
1370 : 100 : static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
1371 : : const u8 *bssid,
1372 : : const u8 *ie, size_t ie_len,
1373 : : int ssi_signal)
1374 : : {
1375 : 100 : struct hostapd_data *hapd = ctx;
1376 : : struct wpabuf *wps_ie;
1377 : : struct ieee802_11_elems elems;
1378 : :
1379 [ - + ]: 100 : if (hapd->wps == NULL)
1380 : 0 : return 0;
1381 : :
1382 [ - + ]: 100 : if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) {
1383 : 0 : wpa_printf(MSG_DEBUG, "WPS: Could not parse ProbeReq from "
1384 : 0 : MACSTR, MAC2STR(addr));
1385 : 0 : return 0;
1386 : : }
1387 : :
1388 [ + - ][ + + ]: 100 : if (elems.ssid && elems.ssid_len > 0 &&
[ + + ]
1389 [ - + ]: 52 : (elems.ssid_len != hapd->conf->ssid.ssid_len ||
1390 : 52 : os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) !=
1391 : : 0))
1392 : 37 : return 0; /* Not for us */
1393 : :
1394 : 63 : wps_ie = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
1395 [ + + ]: 63 : if (wps_ie == NULL)
1396 : 3 : return 0;
1397 [ - + ]: 60 : if (wps_validate_probe_req(wps_ie, addr) < 0) {
1398 : 0 : wpabuf_free(wps_ie);
1399 : 0 : return 0;
1400 : : }
1401 : :
1402 [ + - ]: 60 : if (wpabuf_len(wps_ie) > 0) {
1403 : 60 : int p2p_wildcard = 0;
1404 : : #ifdef CONFIG_P2P
1405 [ + - ][ - + ]: 60 : if (elems.ssid && elems.ssid_len == P2P_WILDCARD_SSID_LEN &&
[ # # ]
1406 : 0 : os_memcmp(elems.ssid, P2P_WILDCARD_SSID,
1407 : : P2P_WILDCARD_SSID_LEN) == 0)
1408 : 0 : p2p_wildcard = 1;
1409 : : #endif /* CONFIG_P2P */
1410 : 60 : wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie,
1411 : : p2p_wildcard);
1412 : : #ifdef CONFIG_WPS_UPNP
1413 : : /* FIX: what exactly should be included in the WLANEvent?
1414 : : * WPS attributes? Full ProbeReq frame? */
1415 [ + - ]: 60 : if (!p2p_wildcard)
1416 : 60 : upnp_wps_device_send_wlan_event(
1417 : : hapd->wps_upnp, addr,
1418 : : UPNP_WPS_WLANEVENT_TYPE_PROBE, wps_ie);
1419 : : #endif /* CONFIG_WPS_UPNP */
1420 : : }
1421 : :
1422 : 60 : wpabuf_free(wps_ie);
1423 : :
1424 : 100 : return 0;
1425 : : }
1426 : :
1427 : :
1428 : : #ifdef CONFIG_WPS_UPNP
1429 : :
1430 : 0 : static int hostapd_rx_req_put_wlan_response(
1431 : : void *priv, enum upnp_wps_wlanevent_type ev_type,
1432 : : const u8 *mac_addr, const struct wpabuf *msg,
1433 : : enum wps_msg_type msg_type)
1434 : : {
1435 : 0 : struct hostapd_data *hapd = priv;
1436 : : struct sta_info *sta;
1437 : : struct upnp_pending_message *p;
1438 : :
1439 : 0 : wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse ev_type=%d mac_addr="
1440 : 0 : MACSTR, ev_type, MAC2STR(mac_addr));
1441 : 0 : wpa_hexdump(MSG_MSGDUMP, "WPS UPnP: PutWLANResponse NewMessage",
1442 : : wpabuf_head(msg), wpabuf_len(msg));
1443 [ # # ]: 0 : if (ev_type != UPNP_WPS_WLANEVENT_TYPE_EAP) {
1444 : 0 : wpa_printf(MSG_DEBUG, "WPS UPnP: Ignored unexpected "
1445 : : "PutWLANResponse WLANEventType %d", ev_type);
1446 : 0 : return -1;
1447 : : }
1448 : :
1449 : : /*
1450 : : * EAP response to ongoing to WPS Registration. Send it to EAP-WSC
1451 : : * server implementation for delivery to the peer.
1452 : : */
1453 : :
1454 : 0 : sta = ap_get_sta(hapd, mac_addr);
1455 : : #ifndef CONFIG_WPS_STRICT
1456 : : if (!sta) {
1457 : : /*
1458 : : * Workaround - Intel wsccmd uses bogus NewWLANEventMAC:
1459 : : * Pick STA that is in an ongoing WPS registration without
1460 : : * checking the MAC address.
1461 : : */
1462 : : wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found based "
1463 : : "on NewWLANEventMAC; try wildcard match");
1464 : : for (sta = hapd->sta_list; sta; sta = sta->next) {
1465 : : if (sta->eapol_sm && (sta->flags & WLAN_STA_WPS))
1466 : : break;
1467 : : }
1468 : : }
1469 : : #endif /* CONFIG_WPS_STRICT */
1470 : :
1471 [ # # ][ # # ]: 0 : if (!sta || !(sta->flags & WLAN_STA_WPS)) {
1472 : 0 : wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found");
1473 : 0 : return 0;
1474 : : }
1475 : :
1476 : 0 : p = os_zalloc(sizeof(*p));
1477 [ # # ]: 0 : if (p == NULL)
1478 : 0 : return -1;
1479 : 0 : os_memcpy(p->addr, sta->addr, ETH_ALEN);
1480 : 0 : p->msg = wpabuf_dup(msg);
1481 : 0 : p->type = msg_type;
1482 : 0 : p->next = hapd->wps->upnp_msgs;
1483 : 0 : hapd->wps->upnp_msgs = p;
1484 : :
1485 : 0 : return eapol_auth_eap_pending_cb(sta->eapol_sm, sta->eapol_sm->eap);
1486 : : }
1487 : :
1488 : :
1489 : 55 : static int hostapd_wps_upnp_init(struct hostapd_data *hapd,
1490 : : struct wps_context *wps)
1491 : : {
1492 : : struct upnp_wps_device_ctx *ctx;
1493 : :
1494 [ + - ]: 55 : if (!hapd->conf->upnp_iface)
1495 : 55 : return 0;
1496 : 0 : ctx = os_zalloc(sizeof(*ctx));
1497 [ # # ]: 0 : if (ctx == NULL)
1498 : 0 : return -1;
1499 : :
1500 : 0 : ctx->rx_req_put_wlan_response = hostapd_rx_req_put_wlan_response;
1501 [ # # ]: 0 : if (hapd->conf->ap_pin)
1502 : 0 : ctx->ap_pin = os_strdup(hapd->conf->ap_pin);
1503 : :
1504 : 0 : hapd->wps_upnp = upnp_wps_device_init(ctx, wps, hapd,
1505 : 0 : hapd->conf->upnp_iface);
1506 [ # # ]: 0 : if (hapd->wps_upnp == NULL)
1507 : 0 : return -1;
1508 : 0 : wps->wps_upnp = hapd->wps_upnp;
1509 : :
1510 : 55 : return 0;
1511 : : }
1512 : :
1513 : :
1514 : 55 : static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd)
1515 : : {
1516 : 55 : upnp_wps_device_deinit(hapd->wps_upnp, hapd);
1517 : 55 : }
1518 : :
1519 : : #endif /* CONFIG_WPS_UPNP */
1520 : :
1521 : :
1522 : 0 : int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
1523 : : char *buf, size_t buflen)
1524 : : {
1525 [ # # ]: 0 : if (hapd->wps == NULL)
1526 : 0 : return 0;
1527 : 0 : return wps_registrar_get_info(hapd->wps->registrar, addr, buf, buflen);
1528 : : }
1529 : :
1530 : :
1531 : 0 : static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx)
1532 : : {
1533 : 0 : struct hostapd_data *hapd = eloop_data;
1534 : 0 : wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out");
1535 : 0 : hostapd_wps_ap_pin_disable(hapd);
1536 : 0 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_PIN_DISABLED);
1537 : 0 : }
1538 : :
1539 : :
1540 : 0 : static void hostapd_wps_ap_pin_enable(struct hostapd_data *hapd, int timeout)
1541 : : {
1542 : 0 : wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout);
1543 : 0 : hapd->ap_pin_failures = 0;
1544 : 0 : hapd->ap_pin_failures_consecutive = 0;
1545 : 0 : hapd->conf->ap_setup_locked = 0;
1546 [ # # ]: 0 : if (hapd->wps->ap_setup_locked) {
1547 : 0 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED);
1548 : 0 : hapd->wps->ap_setup_locked = 0;
1549 : 0 : wps_registrar_update_ie(hapd->wps->registrar);
1550 : : }
1551 : 0 : eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
1552 [ # # ]: 0 : if (timeout > 0)
1553 : 0 : eloop_register_timeout(timeout, 0,
1554 : : hostapd_wps_ap_pin_timeout, hapd, NULL);
1555 : 0 : }
1556 : :
1557 : :
1558 : 0 : static int wps_ap_pin_disable(struct hostapd_data *hapd, void *ctx)
1559 : : {
1560 : 0 : os_free(hapd->conf->ap_pin);
1561 : 0 : hapd->conf->ap_pin = NULL;
1562 : : #ifdef CONFIG_WPS_UPNP
1563 : 0 : upnp_wps_set_ap_pin(hapd->wps_upnp, NULL);
1564 : : #endif /* CONFIG_WPS_UPNP */
1565 : 0 : eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
1566 : 0 : return 0;
1567 : : }
1568 : :
1569 : :
1570 : 0 : void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd)
1571 : : {
1572 : 0 : wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN");
1573 : 0 : hostapd_wps_for_each(hapd, wps_ap_pin_disable, NULL);
1574 : 0 : }
1575 : :
1576 : :
1577 : : struct wps_ap_pin_data {
1578 : : char pin_txt[9];
1579 : : int timeout;
1580 : : };
1581 : :
1582 : :
1583 : 0 : static int wps_ap_pin_set(struct hostapd_data *hapd, void *ctx)
1584 : : {
1585 : 0 : struct wps_ap_pin_data *data = ctx;
1586 : 0 : os_free(hapd->conf->ap_pin);
1587 : 0 : hapd->conf->ap_pin = os_strdup(data->pin_txt);
1588 : : #ifdef CONFIG_WPS_UPNP
1589 : 0 : upnp_wps_set_ap_pin(hapd->wps_upnp, data->pin_txt);
1590 : : #endif /* CONFIG_WPS_UPNP */
1591 : 0 : hostapd_wps_ap_pin_enable(hapd, data->timeout);
1592 : 0 : return 0;
1593 : : }
1594 : :
1595 : :
1596 : 0 : const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout)
1597 : : {
1598 : : unsigned int pin;
1599 : : struct wps_ap_pin_data data;
1600 : :
1601 : 0 : pin = wps_generate_pin();
1602 : 0 : os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%08u", pin);
1603 : 0 : data.timeout = timeout;
1604 : 0 : hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
1605 : 0 : return hapd->conf->ap_pin;
1606 : : }
1607 : :
1608 : :
1609 : 0 : const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd)
1610 : : {
1611 : 0 : return hapd->conf->ap_pin;
1612 : : }
1613 : :
1614 : :
1615 : 0 : int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
1616 : : int timeout)
1617 : : {
1618 : : struct wps_ap_pin_data data;
1619 : : int ret;
1620 : :
1621 : 0 : ret = os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%s", pin);
1622 [ # # ][ # # ]: 0 : if (ret < 0 || ret >= (int) sizeof(data.pin_txt))
1623 : 0 : return -1;
1624 : 0 : data.timeout = timeout;
1625 : 0 : return hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
1626 : : }
1627 : :
1628 : :
1629 : 0 : static int wps_update_ie(struct hostapd_data *hapd, void *ctx)
1630 : : {
1631 [ # # ]: 0 : if (hapd->wps)
1632 : 0 : wps_registrar_update_ie(hapd->wps->registrar);
1633 : 0 : return 0;
1634 : : }
1635 : :
1636 : :
1637 : 0 : void hostapd_wps_update_ie(struct hostapd_data *hapd)
1638 : : {
1639 : 0 : hostapd_wps_for_each(hapd, wps_update_ie, NULL);
1640 : 0 : }
1641 : :
1642 : :
1643 : 0 : int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
1644 : : const char *auth, const char *encr, const char *key)
1645 : : {
1646 : : struct wps_credential cred;
1647 : : size_t len;
1648 : :
1649 : 0 : os_memset(&cred, 0, sizeof(cred));
1650 : :
1651 : 0 : len = os_strlen(ssid);
1652 [ # # ]: 0 : if ((len & 1) || len > 2 * sizeof(cred.ssid) ||
[ # # # # ]
1653 : 0 : hexstr2bin(ssid, cred.ssid, len / 2))
1654 : 0 : return -1;
1655 : 0 : cred.ssid_len = len / 2;
1656 : :
1657 [ # # ]: 0 : if (os_strncmp(auth, "OPEN", 4) == 0)
1658 : 0 : cred.auth_type = WPS_AUTH_OPEN;
1659 [ # # ]: 0 : else if (os_strncmp(auth, "WPAPSK", 6) == 0)
1660 : 0 : cred.auth_type = WPS_AUTH_WPAPSK;
1661 [ # # ]: 0 : else if (os_strncmp(auth, "WPA2PSK", 7) == 0)
1662 : 0 : cred.auth_type = WPS_AUTH_WPA2PSK;
1663 : : else
1664 : 0 : return -1;
1665 : :
1666 [ # # ]: 0 : if (encr) {
1667 [ # # ]: 0 : if (os_strncmp(encr, "NONE", 4) == 0)
1668 : 0 : cred.encr_type = WPS_ENCR_NONE;
1669 [ # # ]: 0 : else if (os_strncmp(encr, "WEP", 3) == 0)
1670 : 0 : cred.encr_type = WPS_ENCR_WEP;
1671 [ # # ]: 0 : else if (os_strncmp(encr, "TKIP", 4) == 0)
1672 : 0 : cred.encr_type = WPS_ENCR_TKIP;
1673 [ # # ]: 0 : else if (os_strncmp(encr, "CCMP", 4) == 0)
1674 : 0 : cred.encr_type = WPS_ENCR_AES;
1675 : : else
1676 : 0 : return -1;
1677 : : } else
1678 : 0 : cred.encr_type = WPS_ENCR_NONE;
1679 : :
1680 [ # # ]: 0 : if (key) {
1681 : 0 : len = os_strlen(key);
1682 [ # # ]: 0 : if ((len & 1) || len > 2 * sizeof(cred.key) ||
[ # # # # ]
1683 : 0 : hexstr2bin(key, cred.key, len / 2))
1684 : 0 : return -1;
1685 : 0 : cred.key_len = len / 2;
1686 : : }
1687 : :
1688 : 0 : return wps_registrar_config_ap(hapd->wps->registrar, &cred);
1689 : : }
1690 : :
1691 : :
1692 : : #ifdef CONFIG_WPS_NFC
1693 : :
1694 : : struct wps_nfc_password_token_data {
1695 : : const u8 *oob_dev_pw;
1696 : : size_t oob_dev_pw_len;
1697 : : int added;
1698 : : };
1699 : :
1700 : :
1701 : 0 : static int wps_add_nfc_password_token(struct hostapd_data *hapd, void *ctx)
1702 : : {
1703 : 0 : struct wps_nfc_password_token_data *data = ctx;
1704 : : int ret;
1705 : :
1706 [ # # ]: 0 : if (hapd->wps == NULL)
1707 : 0 : return 0;
1708 : 0 : ret = wps_registrar_add_nfc_password_token(hapd->wps->registrar,
1709 : : data->oob_dev_pw,
1710 : : data->oob_dev_pw_len);
1711 [ # # ]: 0 : if (ret == 0)
1712 : 0 : data->added++;
1713 : 0 : return ret;
1714 : : }
1715 : :
1716 : :
1717 : 0 : static int hostapd_wps_add_nfc_password_token(struct hostapd_data *hapd,
1718 : : struct wps_parse_attr *attr)
1719 : : {
1720 : : struct wps_nfc_password_token_data data;
1721 : :
1722 : 0 : data.oob_dev_pw = attr->oob_dev_password;
1723 : 0 : data.oob_dev_pw_len = attr->oob_dev_password_len;
1724 : 0 : data.added = 0;
1725 [ # # ]: 0 : if (hostapd_wps_for_each(hapd, wps_add_nfc_password_token, &data) < 0)
1726 : 0 : return -1;
1727 [ # # ]: 0 : return data.added ? 0 : -1;
1728 : : }
1729 : :
1730 : :
1731 : 0 : static int hostapd_wps_nfc_tag_process(struct hostapd_data *hapd,
1732 : : const struct wpabuf *wps)
1733 : : {
1734 : : struct wps_parse_attr attr;
1735 : :
1736 : 0 : wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps);
1737 : :
1738 [ # # ]: 0 : if (wps_parse_msg(wps, &attr)) {
1739 : 0 : wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag");
1740 : 0 : return -1;
1741 : : }
1742 : :
1743 [ # # ]: 0 : if (attr.oob_dev_password)
1744 : 0 : return hostapd_wps_add_nfc_password_token(hapd, &attr);
1745 : :
1746 : 0 : wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag");
1747 : 0 : return -1;
1748 : : }
1749 : :
1750 : :
1751 : 0 : int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd,
1752 : : const struct wpabuf *data)
1753 : : {
1754 : 0 : const struct wpabuf *wps = data;
1755 : 0 : struct wpabuf *tmp = NULL;
1756 : : int ret;
1757 : :
1758 [ # # ]: 0 : if (wpabuf_len(data) < 4)
1759 : 0 : return -1;
1760 : :
1761 [ # # ]: 0 : if (*wpabuf_head_u8(data) != 0x10) {
1762 : : /* Assume this contains full NDEF record */
1763 : 0 : tmp = ndef_parse_wifi(data);
1764 [ # # ]: 0 : if (tmp == NULL) {
1765 : 0 : wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF");
1766 : 0 : return -1;
1767 : : }
1768 : 0 : wps = tmp;
1769 : : }
1770 : :
1771 : 0 : ret = hostapd_wps_nfc_tag_process(hapd, wps);
1772 : 0 : wpabuf_free(tmp);
1773 : 0 : return ret;
1774 : : }
1775 : :
1776 : :
1777 : 0 : struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
1778 : : int ndef)
1779 : : {
1780 : : struct wpabuf *ret;
1781 : :
1782 [ # # ]: 0 : if (hapd->wps == NULL)
1783 : 0 : return NULL;
1784 : :
1785 : 0 : ret = wps_get_oob_cred(hapd->wps);
1786 [ # # ][ # # ]: 0 : if (ndef && ret) {
1787 : : struct wpabuf *tmp;
1788 : 0 : tmp = ndef_build_wifi(ret);
1789 : 0 : wpabuf_free(ret);
1790 [ # # ]: 0 : if (tmp == NULL)
1791 : 0 : return NULL;
1792 : 0 : ret = tmp;
1793 : : }
1794 : :
1795 : 0 : return ret;
1796 : : }
1797 : :
1798 : :
1799 : 0 : struct wpabuf * hostapd_wps_nfc_hs_cr(struct hostapd_data *hapd, int ndef)
1800 : : {
1801 : : /*
1802 : : * Handover Select carrier record for WPS uses the same format as
1803 : : * configuration token.
1804 : : */
1805 : 0 : return hostapd_wps_nfc_config_token(hapd, ndef);
1806 : : }
1807 : :
1808 : :
1809 : 0 : struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef)
1810 : : {
1811 [ # # ]: 0 : if (hapd->conf->wps_nfc_pw_from_config) {
1812 : 0 : return wps_nfc_token_build(ndef,
1813 : 0 : hapd->conf->wps_nfc_dev_pw_id,
1814 : 0 : hapd->conf->wps_nfc_dh_pubkey,
1815 : 0 : hapd->conf->wps_nfc_dev_pw);
1816 : : }
1817 : :
1818 : 0 : return wps_nfc_token_gen(ndef, &hapd->conf->wps_nfc_dev_pw_id,
1819 : 0 : &hapd->conf->wps_nfc_dh_pubkey,
1820 : 0 : &hapd->conf->wps_nfc_dh_privkey,
1821 : 0 : &hapd->conf->wps_nfc_dev_pw);
1822 : : }
1823 : :
1824 : :
1825 : 0 : int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd)
1826 : : {
1827 : 0 : struct wps_context *wps = hapd->wps;
1828 : : struct wpabuf *pw;
1829 : :
1830 [ # # ]: 0 : if (wps == NULL)
1831 : 0 : return -1;
1832 : :
1833 [ # # ][ # # ]: 0 : if (!hapd->conf->wps_nfc_dh_pubkey ||
1834 [ # # ]: 0 : !hapd->conf->wps_nfc_dh_privkey ||
1835 [ # # ]: 0 : !hapd->conf->wps_nfc_dev_pw ||
1836 : 0 : !hapd->conf->wps_nfc_dev_pw_id)
1837 : 0 : return -1;
1838 : :
1839 : 0 : hostapd_wps_nfc_clear(wps);
1840 : 0 : wpa_printf(MSG_DEBUG,
1841 : : "WPS: Enable NFC Tag (Dev Pw Id %u) for AP interface %s (context %p)",
1842 : 0 : hapd->conf->wps_nfc_dev_pw_id, hapd->conf->iface, wps);
1843 : 0 : wps->ap_nfc_dev_pw_id = hapd->conf->wps_nfc_dev_pw_id;
1844 : 0 : wps->ap_nfc_dh_pubkey = wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey);
1845 : 0 : wps->ap_nfc_dh_privkey = wpabuf_dup(hapd->conf->wps_nfc_dh_privkey);
1846 : 0 : pw = hapd->conf->wps_nfc_dev_pw;
1847 : 0 : wps->ap_nfc_dev_pw = wpabuf_alloc(
1848 : 0 : wpabuf_len(pw) * 2 + 1);
1849 [ # # ]: 0 : if (wps->ap_nfc_dev_pw) {
1850 : 0 : wpa_snprintf_hex_uppercase(
1851 : 0 : (char *) wpabuf_put(wps->ap_nfc_dev_pw,
1852 : 0 : wpabuf_len(pw) * 2),
1853 : 0 : wpabuf_len(pw) * 2 + 1,
1854 : 0 : wpabuf_head(pw), wpabuf_len(pw));
1855 : : }
1856 : :
1857 [ # # ][ # # ]: 0 : if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey ||
[ # # ]
1858 : 0 : !wps->ap_nfc_dev_pw) {
1859 : 0 : hostapd_wps_nfc_clear(wps);
1860 : 0 : return -1;
1861 : : }
1862 : :
1863 : 0 : return 0;
1864 : : }
1865 : :
1866 : :
1867 : 0 : void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd)
1868 : : {
1869 : 0 : wpa_printf(MSG_DEBUG, "WPS: Disable NFC token for AP interface %s",
1870 : 0 : hapd->conf->iface);
1871 : 0 : hostapd_wps_nfc_clear(hapd->wps);
1872 : 0 : }
1873 : :
1874 : : #endif /* CONFIG_WPS_NFC */
|