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 : 82 : static int wps_for_each(struct hostapd_iface *iface, void *ctx)
53 : : {
54 : 82 : struct wps_for_each_data *data = ctx;
55 : : size_t j;
56 : :
57 [ - + ]: 82 : if (iface == NULL)
58 : 0 : return 0;
59 [ + + ]: 164 : for (j = 0; j < iface->num_bss; j++) {
60 : 82 : struct hostapd_data *hapd = iface->bss[j];
61 : : int ret;
62 : :
63 [ + + ][ + + ]: 82 : if (hapd != data->calling_hapd &&
64 [ - + ]: 6 : (hapd->conf->wps_independent ||
65 : 6 : data->calling_hapd->conf->wps_independent))
66 : 2 : continue;
67 : :
68 : 80 : ret = data->func(hapd, data->ctx);
69 [ - + ]: 80 : if (ret)
70 : 0 : return ret;
71 : : }
72 : :
73 : 82 : return 0;
74 : : }
75 : :
76 : :
77 : 74 : static int hostapd_wps_for_each(struct hostapd_data *hapd,
78 : : int (*func)(struct hostapd_data *h, void *ctx),
79 : : void *ctx)
80 : : {
81 : 74 : struct hostapd_iface *iface = hapd->iface;
82 : : struct wps_for_each_data data;
83 : 74 : data.func = func;
84 : 74 : data.ctx = ctx;
85 : 74 : data.calling_hapd = hapd;
86 [ + - ][ - + ]: 74 : if (iface->interfaces == NULL ||
87 : 74 : iface->interfaces->for_each_interface == NULL)
88 : 0 : return wps_for_each(iface, &data);
89 : 74 : return iface->interfaces->for_each_interface(iface->interfaces,
90 : : wps_for_each, &data);
91 : : }
92 : :
93 : :
94 : 0 : 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 : 0 : struct hostapd_data *hapd = ctx;
99 : : struct hostapd_wpa_psk *p;
100 : 0 : struct hostapd_ssid *ssid = &hapd->conf->ssid;
101 : :
102 [ # # ]: 0 : if (is_zero_ether_addr(p2p_dev_addr)) {
103 : 0 : wpa_printf(MSG_DEBUG,
104 : : "Received new WPA/WPA2-PSK from WPS for STA " MACSTR,
105 : 0 : MAC2STR(mac_addr));
106 : : } else {
107 : 0 : wpa_printf(MSG_DEBUG,
108 : : "Received new WPA/WPA2-PSK from WPS for STA " MACSTR
109 : : " P2P Device Addr " MACSTR,
110 : 0 : MAC2STR(mac_addr), MAC2STR(p2p_dev_addr));
111 : : }
112 : 0 : wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
113 : :
114 [ # # ]: 0 : 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 : 0 : p = os_zalloc(sizeof(*p));
122 [ # # ]: 0 : if (p == NULL)
123 : 0 : return -1;
124 : 0 : os_memcpy(p->addr, mac_addr, ETH_ALEN);
125 : 0 : os_memcpy(p->p2p_dev_addr, p2p_dev_addr, ETH_ALEN);
126 : 0 : os_memcpy(p->psk, psk, PMK_LEN);
127 : :
128 [ # # ]: 0 : if (hapd->new_psk_cb) {
129 : 0 : hapd->new_psk_cb(hapd->new_psk_cb_ctx, mac_addr, p2p_dev_addr,
130 : : psk, psk_len);
131 : : }
132 : :
133 : 0 : p->next = ssid->wpa_psk;
134 : 0 : ssid->wpa_psk = p;
135 : :
136 [ # # ]: 0 : 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 : 0 : return 0;
153 : : }
154 : :
155 : :
156 : 112 : static int hostapd_wps_set_ie_cb(void *ctx, struct wpabuf *beacon_ie,
157 : : struct wpabuf *probe_resp_ie)
158 : : {
159 : 112 : struct hostapd_data *hapd = ctx;
160 : 112 : wpabuf_free(hapd->wps_beacon_ie);
161 : 112 : hapd->wps_beacon_ie = beacon_ie;
162 : 112 : wpabuf_free(hapd->wps_probe_resp_ie);
163 : 112 : hapd->wps_probe_resp_ie = probe_resp_ie;
164 [ + + ]: 112 : if (hapd->beacon_set_done)
165 : 78 : ieee802_11_set_beacon(hapd);
166 : 112 : return hostapd_set_ap_wps_ie(hapd);
167 : : }
168 : :
169 : :
170 : 2 : static void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
171 : : const struct wps_device_data *dev)
172 : : {
173 : 2 : struct hostapd_data *hapd = ctx;
174 : : char uuid[40], txt[400];
175 : : int len;
176 : : char devtype[WPS_DEV_TYPE_BUFSIZE];
177 [ - + ]: 2 : if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
178 : 0 : return;
179 : 2 : wpa_printf(MSG_DEBUG, "WPS: PIN needed for E-UUID %s", uuid);
180 : 2 : len = os_snprintf(txt, sizeof(txt), WPS_EVENT_PIN_NEEDED
181 : : "%s " MACSTR " [%s|%s|%s|%s|%s|%s]",
182 : 12 : uuid, MAC2STR(dev->mac_addr), dev->device_name,
183 : : dev->manufacturer, dev->model_name,
184 : : dev->model_number, dev->serial_number,
185 : 2 : wps_dev_type_bin2str(dev->pri_dev_type, devtype,
186 : : sizeof(devtype)));
187 [ + - ][ + - ]: 2 : if (len > 0 && len < (int) sizeof(txt))
188 : 2 : wpa_msg(hapd->msg_ctx, MSG_INFO, "%s", txt);
189 : :
190 [ - + ]: 2 : 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 : 2 : 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 : 17 : static int wps_stop_registrar(struct hostapd_data *hapd, void *ctx)
217 : : {
218 : 17 : struct wps_stop_reg_data *data = ctx;
219 [ + + ][ + - ]: 17 : if (hapd != data->current_hapd && hapd->wps != NULL)
220 : 2 : wps_registrar_complete(hapd->wps->registrar, data->uuid_e,
221 : : data->dev_pw, data->dev_pw_len);
222 : 17 : return 0;
223 : : }
224 : :
225 : :
226 : 15 : 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 : 15 : struct hostapd_data *hapd = ctx;
231 : : char uuid[40];
232 : : struct wps_stop_reg_data data;
233 [ - + ]: 15 : if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
234 : 15 : return;
235 : 15 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s",
236 : 90 : MAC2STR(mac_addr), uuid);
237 [ - + ]: 15 : if (hapd->wps_reg_success_cb)
238 : 0 : hapd->wps_reg_success_cb(hapd->wps_reg_success_cb_ctx,
239 : : mac_addr, uuid_e);
240 : 15 : data.current_hapd = hapd;
241 : 15 : data.uuid_e = uuid_e;
242 : 15 : data.dev_pw = dev_pw;
243 : 15 : data.dev_pw_len = dev_pw_len;
244 : 15 : hostapd_wps_for_each(hapd, wps_stop_registrar, &data);
245 : : }
246 : :
247 : :
248 : 92 : 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 : 92 : struct hostapd_data *hapd = ctx;
256 : : char uuid[40];
257 : : char devtype[WPS_DEV_TYPE_BUFSIZE];
258 [ - + ]: 92 : if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
259 : 92 : return;
260 [ - + ]: 92 : if (dev_name == NULL)
261 : 0 : dev_name = "";
262 : 92 : wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ENROLLEE_SEEN MACSTR
263 : : " %s %s 0x%x %u %u [%s]",
264 : 552 : 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 : 13 : static void wps_reload_config(void *eloop_data, void *user_ctx)
278 : : {
279 : 13 : struct hostapd_iface *iface = eloop_data;
280 : :
281 : 13 : wpa_printf(MSG_DEBUG, "WPS: Reload configuration data");
282 [ + - - + ]: 26 : if (iface->interfaces == NULL ||
283 : 13 : iface->interfaces->reload_config(iface) < 0) {
284 : 0 : wpa_printf(MSG_WARNING, "WPS: Failed to reload the updated "
285 : : "configuration");
286 : : }
287 : 13 : }
288 : :
289 : :
290 : 42 : 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 [ + + ]: 42 : if (eloop_deplete_timeout(0, 0, wps_reload_config, hapd->iface, NULL))
299 : 8 : wpa_printf(MSG_DEBUG, "WPS: Reschedule immediate configuration reload");
300 : 42 : }
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 : 13 : static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
318 : : const struct wps_credential *cred)
319 : : {
320 : 13 : struct hostapd_bss_config *bss = hapd->conf;
321 : :
322 : 13 : wpa_printf(MSG_DEBUG, "WPS: Updating in-memory configuration");
323 : :
324 : 13 : bss->wps_state = 2;
325 [ + - ]: 13 : if (cred->ssid_len <= HOSTAPD_MAX_SSID_LEN) {
326 : 13 : os_memcpy(bss->ssid.ssid, cred->ssid, cred->ssid_len);
327 : 13 : bss->ssid.ssid_len = cred->ssid_len;
328 : 13 : bss->ssid.ssid_set = 1;
329 : : }
330 : :
331 [ + - ][ + + ]: 13 : if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
332 : 13 : (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
333 : 8 : bss->wpa = 3;
334 [ + - ]: 5 : else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK))
335 : 5 : 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 [ + - ]: 13 : if (bss->wpa) {
342 [ - + ]: 13 : if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA))
343 : 0 : bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
344 [ + - ]: 13 : if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
345 : 13 : bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
346 : :
347 : 13 : bss->wpa_pairwise = 0;
348 [ + - ]: 13 : if (cred->encr_type & WPS_ENCR_AES)
349 : 13 : bss->wpa_pairwise |= WPA_CIPHER_CCMP;
350 [ + + ]: 13 : if (cred->encr_type & WPS_ENCR_TKIP)
351 : 8 : bss->wpa_pairwise |= WPA_CIPHER_TKIP;
352 : 13 : bss->rsn_pairwise = bss->wpa_pairwise;
353 : 13 : bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa,
354 : : bss->wpa_pairwise,
355 : : bss->rsn_pairwise);
356 : :
357 [ + - ][ + - ]: 13 : if (cred->key_len >= 8 && cred->key_len < 64) {
358 : 13 : os_free(bss->ssid.wpa_passphrase);
359 : 13 : bss->ssid.wpa_passphrase = os_zalloc(cred->key_len + 1);
360 [ + - ]: 13 : if (bss->ssid.wpa_passphrase)
361 : 13 : os_memcpy(bss->ssid.wpa_passphrase, cred->key,
362 : : cred->key_len);
363 : 13 : os_free(bss->ssid.wpa_psk);
364 : 13 : 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 : 13 : 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 : 13 : eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface,
419 : : NULL);
420 : :
421 : 13 : return 0;
422 : : }
423 : :
424 : :
425 : 13 : static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
426 : : {
427 : 13 : 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 [ - + ]: 13 : if (hapd->wps == NULL)
436 : 0 : return 0;
437 : :
438 : 13 : wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
439 : 13 : cred->cred_attr, cred->cred_attr_len);
440 : :
441 : 13 : wpa_printf(MSG_DEBUG, "WPS: Received new AP Settings");
442 : 13 : wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len);
443 : 13 : wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x",
444 : 13 : cred->auth_type);
445 : 13 : wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type);
446 : 13 : wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx);
447 : 13 : wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
448 : 13 : cred->key, cred->key_len);
449 : 13 : wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR,
450 : 78 : MAC2STR(cred->mac_addr));
451 : :
452 [ + - ][ - + ]: 13 : 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 [ + - ][ - + ]: 13 : } 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 : 13 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS);
465 : :
466 [ - + ]: 13 : if (hapd->conf->wps_cred_processing == 1)
467 : 0 : return 0;
468 : :
469 : 13 : os_memcpy(hapd->wps->ssid, cred->ssid, cred->ssid_len);
470 : 13 : hapd->wps->ssid_len = cred->ssid_len;
471 : 13 : hapd->wps->encr_types = cred->encr_type;
472 : 13 : hapd->wps->auth_types = cred->auth_type;
473 [ - + ]: 13 : 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 [ + + ][ + - ]: 13 : if (hapd->wps->network_key == NULL ||
479 : 1 : hapd->wps->network_key_len < cred->key_len) {
480 : 13 : hapd->wps->network_key_len = 0;
481 : 13 : os_free(hapd->wps->network_key);
482 : 13 : hapd->wps->network_key = os_malloc(cred->key_len);
483 [ - + ]: 13 : if (hapd->wps->network_key == NULL)
484 : 0 : return -1;
485 : : }
486 : 13 : hapd->wps->network_key_len = cred->key_len;
487 : 13 : os_memcpy(hapd->wps->network_key, cred->key, cred->key_len);
488 : : }
489 : 13 : hapd->wps->wps_state = WPS_STATE_CONFIGURED;
490 : :
491 [ + - ]: 13 : if (hapd->iface->config_fname == NULL)
492 : 13 : 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 : 13 : return 0;
657 : : }
658 : :
659 : :
660 : 11 : static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
661 : : {
662 : 11 : struct hostapd_data *hapd = ctx;
663 : 11 : 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 : 3 : static int wps_pwd_auth_fail(struct hostapd_data *hapd, void *ctx)
684 : : {
685 : 3 : struct wps_event_pwd_auth_fail *data = ctx;
686 : :
687 [ + - ][ + - ]: 3 : 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 : 3 : hapd->ap_pin_failures++;
696 : 3 : hapd->ap_pin_failures_consecutive++;
697 : 3 : 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 [ + + ]: 3 : if (hapd->ap_pin_failures < 3)
701 : 2 : return 0;
702 : :
703 : 1 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED);
704 : 1 : hapd->wps->ap_setup_locked = 1;
705 : :
706 : 1 : wps_registrar_update_ie(hapd->wps->registrar);
707 : :
708 [ + - ][ - + ]: 1 : if (!hapd->conf->ap_setup_locked &&
709 : 1 : 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 [ + - ]: 1 : } else if (!hapd->conf->ap_setup_locked) {
717 [ + - ]: 1 : if (hapd->ap_pin_lockout_time == 0)
718 : 1 : 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 : 1 : wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN for %u seconds",
724 : : hapd->ap_pin_lockout_time);
725 : 1 : eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
726 : 1 : eloop_register_timeout(hapd->ap_pin_lockout_time, 0,
727 : : hostapd_wps_reenable_ap_pin, hapd,
728 : : NULL);
729 : : }
730 : :
731 : 3 : return 0;
732 : : }
733 : :
734 : :
735 : 3 : 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 : 3 : wpa_printf(MSG_DEBUG, "WPS: Authentication failure update");
740 : 3 : hapd->wps_stats.status = WPS_STATUS_FAILURE;
741 : 3 : hapd->wps_stats.failure_reason = WPS_EI_AUTH_FAILURE;
742 : 3 : os_memcpy(hapd->wps_stats.peer_addr, data->peer_macaddr, ETH_ALEN);
743 : :
744 : 3 : hostapd_wps_for_each(hapd, wps_pwd_auth_fail, data);
745 : 3 : }
746 : :
747 : :
748 : 10 : static int wps_ap_pin_success(struct hostapd_data *hapd, void *ctx)
749 : : {
750 [ + + ][ - + ]: 10 : if (hapd->conf->ap_pin == NULL || hapd->wps == NULL)
751 : 1 : return 0;
752 : :
753 [ + - ]: 9 : if (hapd->ap_pin_failures_consecutive == 0)
754 : 9 : 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 : 10 : return 0;
762 : : }
763 : :
764 : :
765 : 10 : static void hostapd_wps_ap_pin_success(struct hostapd_data *hapd)
766 : : {
767 : 10 : hostapd_wps_for_each(hapd, wps_ap_pin_success, NULL);
768 : 10 : }
769 : :
770 : :
771 : 3 : static void hostapd_wps_event_pbc_overlap(struct hostapd_data *hapd)
772 : : {
773 : : /* Update WPS Status - PBC Overlap */
774 : 3 : hapd->wps_stats.pbc_status = WPS_PBC_STATUS_OVERLAP;
775 : 3 : }
776 : :
777 : :
778 : 1 : static void hostapd_wps_event_pbc_timeout(struct hostapd_data *hapd)
779 : : {
780 : : /* Update WPS PBC Status:PBC Timeout */
781 : 1 : hapd->wps_stats.pbc_status = WPS_PBC_STATUS_TIMEOUT;
782 : 1 : }
783 : :
784 : :
785 : 13 : static void hostapd_wps_event_pbc_active(struct hostapd_data *hapd)
786 : : {
787 : : /* Update WPS PBC status - Active */
788 : 13 : hapd->wps_stats.pbc_status = WPS_PBC_STATUS_ACTIVE;
789 : 13 : }
790 : :
791 : :
792 : 9 : static void hostapd_wps_event_pbc_disable(struct hostapd_data *hapd)
793 : : {
794 : : /* Update WPS PBC status - Active */
795 : 9 : hapd->wps_stats.pbc_status = WPS_PBC_STATUS_DISABLE;
796 : 9 : }
797 : :
798 : :
799 : 19 : static void hostapd_wps_event_success(struct hostapd_data *hapd,
800 : : struct wps_event_success *success)
801 : : {
802 : : /* Update WPS status - Success */
803 : 19 : hapd->wps_stats.pbc_status = WPS_PBC_STATUS_DISABLE;
804 : 19 : hapd->wps_stats.status = WPS_STATUS_SUCCESS;
805 : 19 : os_memcpy(hapd->wps_stats.peer_addr, success->peer_macaddr, ETH_ALEN);
806 : 19 : }
807 : :
808 : :
809 : 12 : static void hostapd_wps_event_fail(struct hostapd_data *hapd,
810 : : struct wps_event_fail *fail)
811 : : {
812 : : /* Update WPS status - Failure */
813 : 12 : hapd->wps_stats.status = WPS_STATUS_FAILURE;
814 : 12 : os_memcpy(hapd->wps_stats.peer_addr, fail->peer_macaddr, ETH_ALEN);
815 : :
816 : 12 : hapd->wps_stats.failure_reason = fail->error_indication;
817 : :
818 [ - + ][ # # ]: 12 : 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 : 12 : wpa_msg(hapd->msg_ctx, MSG_INFO,
826 : : WPS_EVENT_FAIL "msg=%d config_error=%d",
827 : 12 : fail->msg, fail->config_error);
828 : : }
829 : 12 : }
830 : :
831 : :
832 : 70 : static void hostapd_wps_event_cb(void *ctx, enum wps_event event,
833 : : union wps_event_data *data)
834 : : {
835 : 70 : struct hostapd_data *hapd = ctx;
836 : :
837 [ - + + + : 70 : 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 : 12 : hostapd_wps_event_fail(hapd, &data->fail);
843 : 12 : break;
844 : : case WPS_EV_SUCCESS:
845 : 19 : hostapd_wps_event_success(hapd, &data->success);
846 : 19 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_SUCCESS);
847 : 19 : break;
848 : : case WPS_EV_PWD_AUTH_FAIL:
849 : 3 : hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail);
850 : 3 : break;
851 : : case WPS_EV_PBC_OVERLAP:
852 : 3 : hostapd_wps_event_pbc_overlap(hapd);
853 : 3 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_OVERLAP);
854 : 3 : break;
855 : : case WPS_EV_PBC_TIMEOUT:
856 : 1 : hostapd_wps_event_pbc_timeout(hapd);
857 : 1 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_TIMEOUT);
858 : 1 : break;
859 : : case WPS_EV_PBC_ACTIVE:
860 : 13 : hostapd_wps_event_pbc_active(hapd);
861 : 13 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ACTIVE);
862 : 13 : break;
863 : : case WPS_EV_PBC_DISABLE:
864 : 9 : hostapd_wps_event_pbc_disable(hapd);
865 : 9 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_DISABLE);
866 : 9 : 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 : 10 : hostapd_wps_ap_pin_success(hapd);
881 : 10 : break;
882 : : }
883 [ - + ]: 70 : if (hapd->wps_event_cb)
884 : 0 : hapd->wps_event_cb(hapd->wps_event_cb_ctx, event, data);
885 : 70 : }
886 : :
887 : :
888 : 43 : static int hostapd_wps_rf_band_cb(void *ctx)
889 : : {
890 : 43 : struct hostapd_data *hapd = ctx;
891 : :
892 : 43 : return hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
893 [ - + ]: 43 : WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
894 : : }
895 : :
896 : :
897 : 213 : static void hostapd_wps_clear_ies(struct hostapd_data *hapd)
898 : : {
899 : 213 : wpabuf_free(hapd->wps_beacon_ie);
900 : 213 : hapd->wps_beacon_ie = NULL;
901 : :
902 : 213 : wpabuf_free(hapd->wps_probe_resp_ie);
903 : 213 : hapd->wps_probe_resp_ie = NULL;
904 : :
905 : 213 : hostapd_set_ap_wps_ie(hapd);
906 : 213 : }
907 : :
908 : :
909 : 31 : static int get_uuid_cb(struct hostapd_iface *iface, void *ctx)
910 : : {
911 : 31 : const u8 **uuid = ctx;
912 : : size_t j;
913 : :
914 [ - + ]: 31 : if (iface == NULL)
915 : 0 : return 0;
916 [ + + ]: 60 : for (j = 0; j < iface->num_bss; j++) {
917 : 31 : struct hostapd_data *hapd = iface->bss[j];
918 [ + + ]: 33 : if (hapd->wps && !hapd->conf->wps_independent &&
[ + + + - ]
919 : 2 : !is_nil_uuid(hapd->wps->uuid)) {
920 : 2 : *uuid = hapd->wps->uuid;
921 : 2 : return 1;
922 : : }
923 : : }
924 : :
925 : 31 : return 0;
926 : : }
927 : :
928 : :
929 : 30 : static const u8 * get_own_uuid(struct hostapd_iface *iface)
930 : : {
931 : : const u8 *uuid;
932 [ + - ][ - + ]: 30 : if (iface->interfaces == NULL ||
933 : 30 : iface->interfaces->for_each_interface == NULL)
934 : 0 : return NULL;
935 : 30 : uuid = NULL;
936 : 30 : iface->interfaces->for_each_interface(iface->interfaces, get_uuid_cb,
937 : : &uuid);
938 : 30 : return uuid;
939 : : }
940 : :
941 : :
942 : 37 : static int count_interface_cb(struct hostapd_iface *iface, void *ctx)
943 : : {
944 : 37 : int *count= ctx;
945 : 37 : (*count)++;
946 : 37 : return 0;
947 : : }
948 : :
949 : :
950 : 34 : static int interface_count(struct hostapd_iface *iface)
951 : : {
952 : 34 : int count = 0;
953 [ + - ][ - + ]: 34 : if (iface->interfaces == NULL ||
954 : 34 : iface->interfaces->for_each_interface == NULL)
955 : 0 : return 0;
956 : 34 : iface->interfaces->for_each_interface(iface->interfaces,
957 : : count_interface_cb, &count);
958 : 34 : return count;
959 : : }
960 : :
961 : :
962 : 47 : static int hostapd_wps_set_vendor_ext(struct hostapd_data *hapd,
963 : : struct wps_context *wps)
964 : : {
965 : : int i;
966 : :
967 [ + + ]: 517 : for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
968 : 470 : wpabuf_free(wps->dev.vendor_ext[i]);
969 : 470 : wps->dev.vendor_ext[i] = NULL;
970 : :
971 [ + - ]: 470 : if (hapd->conf->wps_vendor_ext[i] == NULL)
972 : 470 : 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 : 47 : return 0;
984 : : }
985 : :
986 : :
987 : 213 : 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 [ + + ]: 213 : if (conf->wps_state == 0) {
994 : 179 : hostapd_wps_clear_ies(hapd);
995 : 179 : return 0;
996 : : }
997 : :
998 : 34 : wps = os_zalloc(sizeof(*wps));
999 [ - + ]: 34 : if (wps == NULL)
1000 : 0 : return -1;
1001 : :
1002 : 34 : wps->cred_cb = hostapd_wps_cred_cb;
1003 : 34 : wps->event_cb = hostapd_wps_event_cb;
1004 : 34 : wps->rf_band_cb = hostapd_wps_rf_band_cb;
1005 : 34 : wps->cb_ctx = hapd;
1006 : :
1007 : 34 : os_memset(&cfg, 0, sizeof(cfg));
1008 : 34 : wps->wps_state = hapd->conf->wps_state;
1009 : 34 : wps->ap_setup_locked = hapd->conf->ap_setup_locked;
1010 [ + + ]: 34 : if (is_nil_uuid(hapd->conf->uuid)) {
1011 : : const u8 *uuid;
1012 : 30 : uuid = get_own_uuid(hapd->iface);
1013 [ + + ][ + - ]: 30 : if (uuid && !conf->wps_independent) {
1014 : 2 : os_memcpy(wps->uuid, uuid, UUID_LEN);
1015 : 2 : wpa_hexdump(MSG_DEBUG, "WPS: Clone UUID from another "
1016 : 2 : "interface", wps->uuid, UUID_LEN);
1017 : : } else {
1018 : 28 : uuid_gen_mac_addr(hapd->own_addr, wps->uuid);
1019 : 30 : wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC "
1020 : 28 : "address", wps->uuid, UUID_LEN);
1021 : : }
1022 : : } else {
1023 : 4 : os_memcpy(wps->uuid, hapd->conf->uuid, UUID_LEN);
1024 : 4 : wpa_hexdump(MSG_DEBUG, "WPS: Use configured UUID",
1025 : 4 : wps->uuid, UUID_LEN);
1026 : : }
1027 : 34 : wps->ssid_len = hapd->conf->ssid.ssid_len;
1028 : 34 : os_memcpy(wps->ssid, hapd->conf->ssid.ssid, wps->ssid_len);
1029 : 34 : wps->ap = 1;
1030 : 34 : os_memcpy(wps->dev.mac_addr, hapd->own_addr, ETH_ALEN);
1031 : 68 : wps->dev.device_name = hapd->conf->device_name ?
1032 [ + + ]: 34 : os_strdup(hapd->conf->device_name) : NULL;
1033 : 68 : wps->dev.manufacturer = hapd->conf->manufacturer ?
1034 [ + + ]: 34 : os_strdup(hapd->conf->manufacturer) : NULL;
1035 : 68 : wps->dev.model_name = hapd->conf->model_name ?
1036 [ + + ]: 34 : os_strdup(hapd->conf->model_name) : NULL;
1037 : 68 : wps->dev.model_number = hapd->conf->model_number ?
1038 [ + + ]: 34 : os_strdup(hapd->conf->model_number) : NULL;
1039 : 68 : wps->dev.serial_number = hapd->conf->serial_number ?
1040 [ + + ]: 34 : os_strdup(hapd->conf->serial_number) : NULL;
1041 : 34 : wps->config_methods =
1042 : 34 : wps_config_methods_str2bin(hapd->conf->config_methods);
1043 : : #ifdef CONFIG_WPS2
1044 [ - + ]: 34 : 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 [ + + ]: 34 : if ((wps->config_methods &
1052 : : (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON |
1053 : : WPS_CONFIG_PHY_PUSHBUTTON)) == WPS_CONFIG_PUSHBUTTON) {
1054 : 4 : wpa_printf(MSG_INFO, "WPS: Converting push_button to "
1055 : : "virtual_push_button for WPS 2.0 compliance");
1056 : 4 : wps->config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
1057 : : }
1058 : : #endif /* CONFIG_WPS2 */
1059 : 34 : os_memcpy(wps->dev.pri_dev_type, hapd->conf->device_type,
1060 : : WPS_DEV_TYPE_LEN);
1061 : :
1062 [ - + ]: 34 : if (hostapd_wps_set_vendor_ext(hapd, wps) < 0) {
1063 : 0 : os_free(wps);
1064 : 0 : return -1;
1065 : : }
1066 : :
1067 : 34 : wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
1068 : :
1069 [ - + ]: 34 : if (conf->wps_rf_bands) {
1070 : 0 : wps->dev.rf_bands = conf->wps_rf_bands;
1071 : : } else {
1072 [ - + ]: 34 : wps->dev.rf_bands =
1073 : 34 : hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
1074 : : WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
1075 : : }
1076 : :
1077 [ + + ]: 34 : if (conf->wpa & WPA_PROTO_RSN) {
1078 [ + - ]: 22 : if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
1079 : 22 : wps->auth_types |= WPS_AUTH_WPA2PSK;
1080 [ - + ]: 22 : if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
1081 : 0 : wps->auth_types |= WPS_AUTH_WPA2;
1082 : :
1083 [ + - ]: 22 : if (conf->rsn_pairwise & WPA_CIPHER_CCMP)
1084 : 22 : wps->encr_types |= WPS_ENCR_AES;
1085 [ - + ]: 22 : if (conf->rsn_pairwise & WPA_CIPHER_TKIP)
1086 : 0 : wps->encr_types |= WPS_ENCR_TKIP;
1087 : : }
1088 : :
1089 [ + + ]: 34 : if (conf->wpa & WPA_PROTO_WPA) {
1090 [ + - ]: 1 : if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
1091 : 1 : wps->auth_types |= WPS_AUTH_WPAPSK;
1092 [ - + ]: 1 : if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
1093 : 0 : wps->auth_types |= WPS_AUTH_WPA;
1094 : :
1095 [ - + ]: 1 : if (conf->wpa_pairwise & WPA_CIPHER_CCMP)
1096 : 0 : wps->encr_types |= WPS_ENCR_AES;
1097 [ + - ]: 1 : if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
1098 : 1 : wps->encr_types |= WPS_ENCR_TKIP;
1099 : : }
1100 : :
1101 [ + + ]: 34 : if (conf->ssid.security_policy == SECURITY_PLAINTEXT) {
1102 : 12 : wps->encr_types |= WPS_ENCR_NONE;
1103 : 12 : wps->auth_types |= WPS_AUTH_OPEN;
1104 [ - + ]: 22 : } 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 [ - + ]: 22 : } 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 [ + - ]: 34 : if (conf->ssid.wpa_psk_file) {
1119 : : /* Use per-device PSKs */
1120 [ + + ]: 34 : } else if (conf->ssid.wpa_passphrase) {
1121 : 22 : wps->network_key = (u8 *) os_strdup(conf->ssid.wpa_passphrase);
1122 : 22 : wps->network_key_len = os_strlen(conf->ssid.wpa_passphrase);
1123 [ - + ]: 12 : } else if (conf->ssid.wpa_psk) {
1124 : 0 : wps->network_key = os_malloc(2 * PMK_LEN + 1);
1125 [ # # ]: 0 : if (wps->network_key == NULL) {
1126 : 0 : os_free(wps);
1127 : 0 : return -1;
1128 : : }
1129 : 0 : wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
1130 : 0 : conf->ssid.wpa_psk->psk, PMK_LEN);
1131 : 0 : wps->network_key_len = 2 * PMK_LEN;
1132 [ - + ][ # # ]: 12 : } 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 [ + + ]: 34 : if (conf->ssid.wpa_psk) {
1144 : 22 : os_memcpy(wps->psk, conf->ssid.wpa_psk->psk, PMK_LEN);
1145 : 22 : wps->psk_set = 1;
1146 : : }
1147 : :
1148 [ + + ]: 34 : if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) {
1149 : : /* Override parameters to enable security by default */
1150 : 11 : wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
1151 : 11 : wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
1152 : : }
1153 : :
1154 : 34 : wps->ap_settings = conf->ap_settings;
1155 : 34 : wps->ap_settings_len = conf->ap_settings_len;
1156 : :
1157 : 34 : cfg.new_psk_cb = hostapd_wps_new_psk_cb;
1158 : 34 : cfg.set_ie_cb = hostapd_wps_set_ie_cb;
1159 : 34 : cfg.pin_needed_cb = hostapd_wps_pin_needed_cb;
1160 : 34 : cfg.reg_success_cb = hostapd_wps_reg_success_cb;
1161 : 34 : cfg.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb;
1162 : 34 : cfg.cb_ctx = hapd;
1163 : 34 : cfg.skip_cred_build = conf->skip_cred_build;
1164 : 34 : cfg.extra_cred = conf->extra_cred;
1165 : 34 : cfg.extra_cred_len = conf->extra_cred_len;
1166 [ - + ][ # # ]: 34 : cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) &&
1167 : 0 : conf->skip_cred_build;
1168 [ - + ]: 34 : if (conf->ssid.security_policy == SECURITY_STATIC_WEP)
1169 : 0 : cfg.static_wep_only = 1;
1170 : 34 : cfg.dualband = interface_count(hapd->iface) > 1;
1171 [ - + ]: 34 : if ((wps->dev.rf_bands & (WPS_RF_50GHZ | WPS_RF_24GHZ)) ==
1172 : : (WPS_RF_50GHZ | WPS_RF_24GHZ))
1173 : 0 : cfg.dualband = 1;
1174 [ + + ]: 34 : if (cfg.dualband)
1175 : 3 : wpa_printf(MSG_DEBUG, "WPS: Dualband AP");
1176 : 34 : cfg.force_per_enrollee_psk = conf->force_per_enrollee_psk;
1177 : :
1178 : 34 : wps->registrar = wps_registrar_init(wps, &cfg);
1179 [ - + ]: 34 : 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 : 34 : wps->friendly_name = hapd->conf->friendly_name;
1188 : 34 : wps->manufacturer_url = hapd->conf->manufacturer_url;
1189 : 34 : wps->model_description = hapd->conf->model_description;
1190 : 34 : wps->model_url = hapd->conf->model_url;
1191 : 34 : wps->upc = hapd->conf->upc;
1192 : : #endif /* CONFIG_WPS_UPNP */
1193 : :
1194 : 34 : hostapd_register_probereq_cb(hapd, hostapd_wps_probe_req_rx, hapd);
1195 : :
1196 : 34 : hapd->wps = wps;
1197 : :
1198 : 213 : return 0;
1199 : : }
1200 : :
1201 : :
1202 : 203 : int hostapd_init_wps_complete(struct hostapd_data *hapd)
1203 : : {
1204 : 203 : struct wps_context *wps = hapd->wps;
1205 : :
1206 [ + + ]: 203 : if (wps == NULL)
1207 : 169 : return 0;
1208 : :
1209 : : #ifdef CONFIG_WPS_UPNP
1210 [ - + ]: 34 : 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 : 203 : return 0;
1221 : : }
1222 : :
1223 : :
1224 : 35 : static void hostapd_wps_nfc_clear(struct wps_context *wps)
1225 : : {
1226 : : #ifdef CONFIG_WPS_NFC
1227 : 35 : wpa_printf(MSG_DEBUG, "WPS: Clear NFC Tag context %p", wps);
1228 : 35 : wps->ap_nfc_dev_pw_id = 0;
1229 : 35 : wpabuf_free(wps->ap_nfc_dh_pubkey);
1230 : 35 : wps->ap_nfc_dh_pubkey = NULL;
1231 : 35 : wpabuf_free(wps->ap_nfc_dh_privkey);
1232 : 35 : wps->ap_nfc_dh_privkey = NULL;
1233 : 35 : wpabuf_free(wps->ap_nfc_dev_pw);
1234 : 35 : wps->ap_nfc_dev_pw = NULL;
1235 : : #endif /* CONFIG_WPS_NFC */
1236 : 35 : }
1237 : :
1238 : :
1239 : 213 : void hostapd_deinit_wps(struct hostapd_data *hapd)
1240 : : {
1241 : 213 : eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
1242 : 213 : eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
1243 : 213 : eloop_cancel_timeout(wps_reload_config, hapd->iface, NULL);
1244 [ + + ]: 213 : if (hapd->wps == NULL)
1245 : 213 : return;
1246 : : #ifdef CONFIG_WPS_UPNP
1247 : 34 : hostapd_wps_upnp_deinit(hapd);
1248 : : #endif /* CONFIG_WPS_UPNP */
1249 : 34 : wps_registrar_deinit(hapd->wps->registrar);
1250 : 34 : os_free(hapd->wps->network_key);
1251 : 34 : wps_device_data_free(&hapd->wps->dev);
1252 : 34 : wpabuf_free(hapd->wps->dh_pubkey);
1253 : 34 : wpabuf_free(hapd->wps->dh_privkey);
1254 : 34 : wps_free_pending_msgs(hapd->wps->upnp_msgs);
1255 : 34 : hostapd_wps_nfc_clear(hapd->wps);
1256 : 34 : os_free(hapd->wps);
1257 : 34 : hapd->wps = NULL;
1258 : 34 : hostapd_wps_clear_ies(hapd);
1259 : : }
1260 : :
1261 : :
1262 : 14 : void hostapd_update_wps(struct hostapd_data *hapd)
1263 : : {
1264 [ + + ]: 14 : if (hapd->wps == NULL)
1265 : 14 : return;
1266 : :
1267 : : #ifdef CONFIG_WPS_UPNP
1268 : 13 : hapd->wps->friendly_name = hapd->conf->friendly_name;
1269 : 13 : hapd->wps->manufacturer_url = hapd->conf->manufacturer_url;
1270 : 13 : hapd->wps->model_description = hapd->conf->model_description;
1271 : 13 : hapd->wps->model_url = hapd->conf->model_url;
1272 : 13 : hapd->wps->upc = hapd->conf->upc;
1273 : : #endif /* CONFIG_WPS_UPNP */
1274 : :
1275 : 13 : hostapd_wps_set_vendor_ext(hapd, hapd->wps);
1276 : :
1277 [ + - ]: 13 : if (hapd->conf->wps_state)
1278 : 13 : wps_registrar_update_ie(hapd->wps->registrar);
1279 : : else
1280 : 0 : hostapd_deinit_wps(hapd);
1281 : : }
1282 : :
1283 : :
1284 : : struct wps_add_pin_data {
1285 : : const u8 *addr;
1286 : : const u8 *uuid;
1287 : : const u8 *pin;
1288 : : size_t pin_len;
1289 : : int timeout;
1290 : : int added;
1291 : : };
1292 : :
1293 : :
1294 : 9 : static int wps_add_pin(struct hostapd_data *hapd, void *ctx)
1295 : : {
1296 : 9 : struct wps_add_pin_data *data = ctx;
1297 : : int ret;
1298 : :
1299 [ - + ]: 9 : if (hapd->wps == NULL)
1300 : 0 : return 0;
1301 : 9 : ret = wps_registrar_add_pin(hapd->wps->registrar, data->addr,
1302 : : data->uuid, data->pin, data->pin_len,
1303 : : data->timeout);
1304 [ + - ]: 9 : if (ret == 0)
1305 : 9 : data->added++;
1306 : 9 : return ret;
1307 : : }
1308 : :
1309 : :
1310 : 8 : int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
1311 : : const char *uuid, const char *pin, int timeout)
1312 : : {
1313 : : u8 u[UUID_LEN];
1314 : : struct wps_add_pin_data data;
1315 : :
1316 : 8 : data.addr = addr;
1317 : 8 : data.uuid = u;
1318 : 8 : data.pin = (const u8 *) pin;
1319 : 8 : data.pin_len = os_strlen(pin);
1320 : 8 : data.timeout = timeout;
1321 : 8 : data.added = 0;
1322 : :
1323 [ + + ]: 8 : if (os_strcmp(uuid, "any") == 0)
1324 : 6 : data.uuid = NULL;
1325 : : else {
1326 [ - + ]: 2 : if (uuid_str2bin(uuid, u))
1327 : 0 : return -1;
1328 : 2 : data.uuid = u;
1329 : : }
1330 [ - + ]: 8 : if (hostapd_wps_for_each(hapd, wps_add_pin, &data) < 0)
1331 : 0 : return -1;
1332 [ + - ]: 8 : return data.added ? 0 : -1;
1333 : : }
1334 : :
1335 : :
1336 : 13 : static int wps_button_pushed(struct hostapd_data *hapd, void *ctx)
1337 : : {
1338 : 13 : const u8 *p2p_dev_addr = ctx;
1339 [ - + ]: 13 : if (hapd->wps == NULL)
1340 : 0 : return 0;
1341 : 13 : return wps_registrar_button_pushed(hapd->wps->registrar, p2p_dev_addr);
1342 : : }
1343 : :
1344 : :
1345 : 12 : int hostapd_wps_button_pushed(struct hostapd_data *hapd,
1346 : : const u8 *p2p_dev_addr)
1347 : : {
1348 : 12 : return hostapd_wps_for_each(hapd, wps_button_pushed,
1349 : : (void *) p2p_dev_addr);
1350 : : }
1351 : :
1352 : :
1353 : 2 : static int wps_cancel(struct hostapd_data *hapd, void *ctx)
1354 : : {
1355 [ - + ]: 2 : if (hapd->wps == NULL)
1356 : 0 : return 0;
1357 : :
1358 : 2 : wps_registrar_wps_cancel(hapd->wps->registrar);
1359 : 2 : ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
1360 : :
1361 : 2 : return 0;
1362 : : }
1363 : :
1364 : :
1365 : 2 : int hostapd_wps_cancel(struct hostapd_data *hapd)
1366 : : {
1367 : 2 : return hostapd_wps_for_each(hapd, wps_cancel, NULL);
1368 : : }
1369 : :
1370 : :
1371 : 92 : static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
1372 : : const u8 *bssid,
1373 : : const u8 *ie, size_t ie_len,
1374 : : int ssi_signal)
1375 : : {
1376 : 92 : struct hostapd_data *hapd = ctx;
1377 : : struct wpabuf *wps_ie;
1378 : : struct ieee802_11_elems elems;
1379 : :
1380 [ - + ]: 92 : if (hapd->wps == NULL)
1381 : 0 : return 0;
1382 : :
1383 [ - + ]: 92 : if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) {
1384 : 0 : wpa_printf(MSG_DEBUG, "WPS: Could not parse ProbeReq from "
1385 : 0 : MACSTR, MAC2STR(addr));
1386 : 0 : return 0;
1387 : : }
1388 : :
1389 [ + - ][ - + ]: 92 : if (elems.ssid && elems.ssid_len > 0 &&
[ # # ]
1390 [ # # ]: 0 : (elems.ssid_len != hapd->conf->ssid.ssid_len ||
1391 : 0 : os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) !=
1392 : : 0))
1393 : 0 : return 0; /* Not for us */
1394 : :
1395 : 92 : wps_ie = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
1396 [ - + ]: 92 : if (wps_ie == NULL)
1397 : 0 : return 0;
1398 [ - + ]: 92 : if (wps_validate_probe_req(wps_ie, addr) < 0) {
1399 : 0 : wpabuf_free(wps_ie);
1400 : 0 : return 0;
1401 : : }
1402 : :
1403 [ + - ]: 92 : if (wpabuf_len(wps_ie) > 0) {
1404 : 92 : int p2p_wildcard = 0;
1405 : : #ifdef CONFIG_P2P
1406 : : if (elems.ssid && elems.ssid_len == P2P_WILDCARD_SSID_LEN &&
1407 : : os_memcmp(elems.ssid, P2P_WILDCARD_SSID,
1408 : : P2P_WILDCARD_SSID_LEN) == 0)
1409 : : p2p_wildcard = 1;
1410 : : #endif /* CONFIG_P2P */
1411 : 92 : wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie,
1412 : : p2p_wildcard);
1413 : : #ifdef CONFIG_WPS_UPNP
1414 : : /* FIX: what exactly should be included in the WLANEvent?
1415 : : * WPS attributes? Full ProbeReq frame? */
1416 [ + - ]: 92 : if (!p2p_wildcard)
1417 : 92 : upnp_wps_device_send_wlan_event(
1418 : : hapd->wps_upnp, addr,
1419 : : UPNP_WPS_WLANEVENT_TYPE_PROBE, wps_ie);
1420 : : #endif /* CONFIG_WPS_UPNP */
1421 : : }
1422 : :
1423 : 92 : wpabuf_free(wps_ie);
1424 : :
1425 : 92 : return 0;
1426 : : }
1427 : :
1428 : :
1429 : : #ifdef CONFIG_WPS_UPNP
1430 : :
1431 : 8 : static int hostapd_rx_req_put_wlan_response(
1432 : : void *priv, enum upnp_wps_wlanevent_type ev_type,
1433 : : const u8 *mac_addr, const struct wpabuf *msg,
1434 : : enum wps_msg_type msg_type)
1435 : : {
1436 : 8 : struct hostapd_data *hapd = priv;
1437 : : struct sta_info *sta;
1438 : : struct upnp_pending_message *p;
1439 : :
1440 : 8 : wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse ev_type=%d mac_addr="
1441 : 48 : MACSTR, ev_type, MAC2STR(mac_addr));
1442 : 8 : wpa_hexdump(MSG_MSGDUMP, "WPS UPnP: PutWLANResponse NewMessage",
1443 : : wpabuf_head(msg), wpabuf_len(msg));
1444 [ - + ]: 8 : if (ev_type != UPNP_WPS_WLANEVENT_TYPE_EAP) {
1445 : 0 : wpa_printf(MSG_DEBUG, "WPS UPnP: Ignored unexpected "
1446 : : "PutWLANResponse WLANEventType %d", ev_type);
1447 : 0 : return -1;
1448 : : }
1449 : :
1450 : : /*
1451 : : * EAP response to ongoing to WPS Registration. Send it to EAP-WSC
1452 : : * server implementation for delivery to the peer.
1453 : : */
1454 : :
1455 : 8 : sta = ap_get_sta(hapd, mac_addr);
1456 : : #ifndef CONFIG_WPS_STRICT
1457 : : if (!sta) {
1458 : : /*
1459 : : * Workaround - Intel wsccmd uses bogus NewWLANEventMAC:
1460 : : * Pick STA that is in an ongoing WPS registration without
1461 : : * checking the MAC address.
1462 : : */
1463 : : wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found based "
1464 : : "on NewWLANEventMAC; try wildcard match");
1465 : : for (sta = hapd->sta_list; sta; sta = sta->next) {
1466 : : if (sta->eapol_sm && (sta->flags & WLAN_STA_WPS))
1467 : : break;
1468 : : }
1469 : : }
1470 : : #endif /* CONFIG_WPS_STRICT */
1471 : :
1472 [ + - ][ - + ]: 8 : if (!sta || !(sta->flags & WLAN_STA_WPS)) {
1473 : 0 : wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found");
1474 : 0 : return 0;
1475 : : }
1476 : :
1477 : 8 : p = os_zalloc(sizeof(*p));
1478 [ - + ]: 8 : if (p == NULL)
1479 : 0 : return -1;
1480 : 8 : os_memcpy(p->addr, sta->addr, ETH_ALEN);
1481 : 8 : p->msg = wpabuf_dup(msg);
1482 : 8 : p->type = msg_type;
1483 : 8 : p->next = hapd->wps->upnp_msgs;
1484 : 8 : hapd->wps->upnp_msgs = p;
1485 : :
1486 : 8 : return eapol_auth_eap_pending_cb(sta->eapol_sm, sta->eapol_sm->eap);
1487 : : }
1488 : :
1489 : :
1490 : 34 : static int hostapd_wps_upnp_init(struct hostapd_data *hapd,
1491 : : struct wps_context *wps)
1492 : : {
1493 : : struct upnp_wps_device_ctx *ctx;
1494 : :
1495 [ + + ]: 34 : if (!hapd->conf->upnp_iface)
1496 : 30 : return 0;
1497 : 4 : ctx = os_zalloc(sizeof(*ctx));
1498 [ - + ]: 4 : if (ctx == NULL)
1499 : 0 : return -1;
1500 : :
1501 : 4 : ctx->rx_req_put_wlan_response = hostapd_rx_req_put_wlan_response;
1502 [ + + ]: 4 : if (hapd->conf->ap_pin)
1503 : 3 : ctx->ap_pin = os_strdup(hapd->conf->ap_pin);
1504 : :
1505 : 4 : hapd->wps_upnp = upnp_wps_device_init(ctx, wps, hapd,
1506 : 4 : hapd->conf->upnp_iface);
1507 [ - + ]: 4 : if (hapd->wps_upnp == NULL)
1508 : 0 : return -1;
1509 : 4 : wps->wps_upnp = hapd->wps_upnp;
1510 : :
1511 : 34 : return 0;
1512 : : }
1513 : :
1514 : :
1515 : 34 : static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd)
1516 : : {
1517 : 34 : upnp_wps_device_deinit(hapd->wps_upnp, hapd);
1518 : 34 : }
1519 : :
1520 : : #endif /* CONFIG_WPS_UPNP */
1521 : :
1522 : :
1523 : 10 : int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
1524 : : char *buf, size_t buflen)
1525 : : {
1526 [ + + ]: 10 : if (hapd->wps == NULL)
1527 : 9 : return 0;
1528 : 10 : return wps_registrar_get_info(hapd->wps->registrar, addr, buf, buflen);
1529 : : }
1530 : :
1531 : :
1532 : 2 : static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx)
1533 : : {
1534 : 2 : struct hostapd_data *hapd = eloop_data;
1535 : 2 : wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out");
1536 : 2 : hostapd_wps_ap_pin_disable(hapd);
1537 : 2 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_PIN_DISABLED);
1538 : 2 : }
1539 : :
1540 : :
1541 : 4 : static void hostapd_wps_ap_pin_enable(struct hostapd_data *hapd, int timeout)
1542 : : {
1543 : 4 : wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout);
1544 : 4 : hapd->ap_pin_failures = 0;
1545 : 4 : hapd->ap_pin_failures_consecutive = 0;
1546 : 4 : hapd->conf->ap_setup_locked = 0;
1547 [ - + ]: 4 : if (hapd->wps->ap_setup_locked) {
1548 : 0 : wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED);
1549 : 0 : hapd->wps->ap_setup_locked = 0;
1550 : 0 : wps_registrar_update_ie(hapd->wps->registrar);
1551 : : }
1552 : 4 : eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
1553 [ + - ]: 4 : if (timeout > 0)
1554 : 4 : eloop_register_timeout(timeout, 0,
1555 : : hostapd_wps_ap_pin_timeout, hapd, NULL);
1556 : 4 : }
1557 : :
1558 : :
1559 : 5 : static int wps_ap_pin_disable(struct hostapd_data *hapd, void *ctx)
1560 : : {
1561 : 5 : os_free(hapd->conf->ap_pin);
1562 : 5 : hapd->conf->ap_pin = NULL;
1563 : : #ifdef CONFIG_WPS_UPNP
1564 : 5 : upnp_wps_set_ap_pin(hapd->wps_upnp, NULL);
1565 : : #endif /* CONFIG_WPS_UPNP */
1566 : 5 : eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
1567 : 5 : return 0;
1568 : : }
1569 : :
1570 : :
1571 : 5 : void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd)
1572 : : {
1573 : 5 : wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN");
1574 : 5 : hostapd_wps_for_each(hapd, wps_ap_pin_disable, NULL);
1575 : 5 : }
1576 : :
1577 : :
1578 : : struct wps_ap_pin_data {
1579 : : char pin_txt[9];
1580 : : int timeout;
1581 : : };
1582 : :
1583 : :
1584 : 4 : static int wps_ap_pin_set(struct hostapd_data *hapd, void *ctx)
1585 : : {
1586 : 4 : struct wps_ap_pin_data *data = ctx;
1587 : 4 : os_free(hapd->conf->ap_pin);
1588 : 4 : hapd->conf->ap_pin = os_strdup(data->pin_txt);
1589 : : #ifdef CONFIG_WPS_UPNP
1590 : 4 : upnp_wps_set_ap_pin(hapd->wps_upnp, data->pin_txt);
1591 : : #endif /* CONFIG_WPS_UPNP */
1592 : 4 : hostapd_wps_ap_pin_enable(hapd, data->timeout);
1593 : 4 : return 0;
1594 : : }
1595 : :
1596 : :
1597 : 2 : const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout)
1598 : : {
1599 : : unsigned int pin;
1600 : : struct wps_ap_pin_data data;
1601 : :
1602 : 2 : pin = wps_generate_pin();
1603 : 2 : os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%08u", pin);
1604 : 2 : data.timeout = timeout;
1605 : 2 : hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
1606 : 2 : return hapd->conf->ap_pin;
1607 : : }
1608 : :
1609 : :
1610 : 3 : const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd)
1611 : : {
1612 : 3 : return hapd->conf->ap_pin;
1613 : : }
1614 : :
1615 : :
1616 : 2 : int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
1617 : : int timeout)
1618 : : {
1619 : : struct wps_ap_pin_data data;
1620 : : int ret;
1621 : :
1622 : 2 : ret = os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%s", pin);
1623 [ + - ][ - + ]: 2 : if (ret < 0 || ret >= (int) sizeof(data.pin_txt))
1624 : 0 : return -1;
1625 : 2 : data.timeout = timeout;
1626 : 2 : return hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
1627 : : }
1628 : :
1629 : :
1630 : 2 : static int wps_update_ie(struct hostapd_data *hapd, void *ctx)
1631 : : {
1632 [ + - ]: 2 : if (hapd->wps)
1633 : 2 : wps_registrar_update_ie(hapd->wps->registrar);
1634 : 2 : return 0;
1635 : : }
1636 : :
1637 : :
1638 : 2 : void hostapd_wps_update_ie(struct hostapd_data *hapd)
1639 : : {
1640 : 2 : hostapd_wps_for_each(hapd, wps_update_ie, NULL);
1641 : 2 : }
1642 : :
1643 : :
1644 : 1 : int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
1645 : : const char *auth, const char *encr, const char *key)
1646 : : {
1647 : : struct wps_credential cred;
1648 : : size_t len;
1649 : :
1650 : 1 : os_memset(&cred, 0, sizeof(cred));
1651 : :
1652 : 1 : len = os_strlen(ssid);
1653 [ + - ]: 2 : if ((len & 1) || len > 2 * sizeof(cred.ssid) ||
[ + - - + ]
1654 : 1 : hexstr2bin(ssid, cred.ssid, len / 2))
1655 : 0 : return -1;
1656 : 1 : cred.ssid_len = len / 2;
1657 : :
1658 [ - + ]: 1 : if (os_strncmp(auth, "OPEN", 4) == 0)
1659 : 0 : cred.auth_type = WPS_AUTH_OPEN;
1660 [ - + ]: 1 : else if (os_strncmp(auth, "WPAPSK", 6) == 0)
1661 : 0 : cred.auth_type = WPS_AUTH_WPAPSK;
1662 [ + - ]: 1 : else if (os_strncmp(auth, "WPA2PSK", 7) == 0)
1663 : 1 : cred.auth_type = WPS_AUTH_WPA2PSK;
1664 : : else
1665 : 0 : return -1;
1666 : :
1667 [ + - ]: 1 : if (encr) {
1668 [ - + ]: 1 : if (os_strncmp(encr, "NONE", 4) == 0)
1669 : 0 : cred.encr_type = WPS_ENCR_NONE;
1670 [ - + ]: 1 : else if (os_strncmp(encr, "WEP", 3) == 0)
1671 : 0 : cred.encr_type = WPS_ENCR_WEP;
1672 [ - + ]: 1 : else if (os_strncmp(encr, "TKIP", 4) == 0)
1673 : 0 : cred.encr_type = WPS_ENCR_TKIP;
1674 [ + - ]: 1 : else if (os_strncmp(encr, "CCMP", 4) == 0)
1675 : 1 : cred.encr_type = WPS_ENCR_AES;
1676 : : else
1677 : 0 : return -1;
1678 : : } else
1679 : 0 : cred.encr_type = WPS_ENCR_NONE;
1680 : :
1681 [ + - ]: 1 : if (key) {
1682 : 1 : len = os_strlen(key);
1683 [ + - ]: 2 : if ((len & 1) || len > 2 * sizeof(cred.key) ||
[ + - - + ]
1684 : 1 : hexstr2bin(key, cred.key, len / 2))
1685 : 0 : return -1;
1686 : 1 : cred.key_len = len / 2;
1687 : : }
1688 : :
1689 : 1 : return wps_registrar_config_ap(hapd->wps->registrar, &cred);
1690 : : }
1691 : :
1692 : :
1693 : : #ifdef CONFIG_WPS_NFC
1694 : :
1695 : : struct wps_nfc_password_token_data {
1696 : : const u8 *oob_dev_pw;
1697 : : size_t oob_dev_pw_len;
1698 : : int added;
1699 : : };
1700 : :
1701 : :
1702 : 2 : static int wps_add_nfc_password_token(struct hostapd_data *hapd, void *ctx)
1703 : : {
1704 : 2 : struct wps_nfc_password_token_data *data = ctx;
1705 : : int ret;
1706 : :
1707 [ - + ]: 2 : if (hapd->wps == NULL)
1708 : 0 : return 0;
1709 : 2 : ret = wps_registrar_add_nfc_password_token(hapd->wps->registrar,
1710 : : data->oob_dev_pw,
1711 : : data->oob_dev_pw_len);
1712 [ + - ]: 2 : if (ret == 0)
1713 : 2 : data->added++;
1714 : 2 : return ret;
1715 : : }
1716 : :
1717 : :
1718 : 2 : static int hostapd_wps_add_nfc_password_token(struct hostapd_data *hapd,
1719 : : struct wps_parse_attr *attr)
1720 : : {
1721 : : struct wps_nfc_password_token_data data;
1722 : :
1723 : 2 : data.oob_dev_pw = attr->oob_dev_password;
1724 : 2 : data.oob_dev_pw_len = attr->oob_dev_password_len;
1725 : 2 : data.added = 0;
1726 [ - + ]: 2 : if (hostapd_wps_for_each(hapd, wps_add_nfc_password_token, &data) < 0)
1727 : 0 : return -1;
1728 [ + - ]: 2 : return data.added ? 0 : -1;
1729 : : }
1730 : :
1731 : :
1732 : 2 : static int hostapd_wps_nfc_tag_process(struct hostapd_data *hapd,
1733 : : const struct wpabuf *wps)
1734 : : {
1735 : : struct wps_parse_attr attr;
1736 : :
1737 : 2 : wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps);
1738 : :
1739 [ - + ]: 2 : if (wps_parse_msg(wps, &attr)) {
1740 : 0 : wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag");
1741 : 0 : return -1;
1742 : : }
1743 : :
1744 [ + - ]: 2 : if (attr.oob_dev_password)
1745 : 2 : return hostapd_wps_add_nfc_password_token(hapd, &attr);
1746 : :
1747 : 0 : wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag");
1748 : 2 : return -1;
1749 : : }
1750 : :
1751 : :
1752 : 2 : int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd,
1753 : : const struct wpabuf *data)
1754 : : {
1755 : 2 : const struct wpabuf *wps = data;
1756 : 2 : struct wpabuf *tmp = NULL;
1757 : : int ret;
1758 : :
1759 [ - + ]: 2 : if (wpabuf_len(data) < 4)
1760 : 0 : return -1;
1761 : :
1762 [ + - ]: 2 : if (*wpabuf_head_u8(data) != 0x10) {
1763 : : /* Assume this contains full NDEF record */
1764 : 2 : tmp = ndef_parse_wifi(data);
1765 [ - + ]: 2 : if (tmp == NULL) {
1766 : 0 : wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF");
1767 : 0 : return -1;
1768 : : }
1769 : 2 : wps = tmp;
1770 : : }
1771 : :
1772 : 2 : ret = hostapd_wps_nfc_tag_process(hapd, wps);
1773 : 2 : wpabuf_free(tmp);
1774 : 2 : return ret;
1775 : : }
1776 : :
1777 : :
1778 : 3 : struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
1779 : : int ndef)
1780 : : {
1781 : : struct wpabuf *ret;
1782 : :
1783 [ - + ]: 3 : if (hapd->wps == NULL)
1784 : 0 : return NULL;
1785 : :
1786 : 3 : ret = wps_get_oob_cred(hapd->wps);
1787 [ + - ][ + - ]: 3 : if (ndef && ret) {
1788 : : struct wpabuf *tmp;
1789 : 3 : tmp = ndef_build_wifi(ret);
1790 : 3 : wpabuf_free(ret);
1791 [ - + ]: 3 : if (tmp == NULL)
1792 : 0 : return NULL;
1793 : 3 : ret = tmp;
1794 : : }
1795 : :
1796 : 3 : return ret;
1797 : : }
1798 : :
1799 : :
1800 : 1 : struct wpabuf * hostapd_wps_nfc_hs_cr(struct hostapd_data *hapd, int ndef)
1801 : : {
1802 : : /*
1803 : : * Handover Select carrier record for WPS uses the same format as
1804 : : * configuration token.
1805 : : */
1806 : 1 : return hostapd_wps_nfc_config_token(hapd, ndef);
1807 : : }
1808 : :
1809 : :
1810 : 1 : struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef)
1811 : : {
1812 [ - + ]: 1 : if (hapd->conf->wps_nfc_pw_from_config) {
1813 : 0 : return wps_nfc_token_build(ndef,
1814 : 0 : hapd->conf->wps_nfc_dev_pw_id,
1815 : 0 : hapd->conf->wps_nfc_dh_pubkey,
1816 : 0 : hapd->conf->wps_nfc_dev_pw);
1817 : : }
1818 : :
1819 : 1 : return wps_nfc_token_gen(ndef, &hapd->conf->wps_nfc_dev_pw_id,
1820 : 1 : &hapd->conf->wps_nfc_dh_pubkey,
1821 : 1 : &hapd->conf->wps_nfc_dh_privkey,
1822 : 1 : &hapd->conf->wps_nfc_dev_pw);
1823 : : }
1824 : :
1825 : :
1826 : 1 : int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd)
1827 : : {
1828 : 1 : struct wps_context *wps = hapd->wps;
1829 : : struct wpabuf *pw;
1830 : :
1831 [ - + ]: 1 : if (wps == NULL)
1832 : 0 : return -1;
1833 : :
1834 [ + - ][ + - ]: 1 : if (!hapd->conf->wps_nfc_dh_pubkey ||
1835 [ + - ]: 1 : !hapd->conf->wps_nfc_dh_privkey ||
1836 [ - + ]: 1 : !hapd->conf->wps_nfc_dev_pw ||
1837 : 1 : !hapd->conf->wps_nfc_dev_pw_id)
1838 : 0 : return -1;
1839 : :
1840 : 1 : hostapd_wps_nfc_clear(wps);
1841 : 1 : wpa_printf(MSG_DEBUG,
1842 : : "WPS: Enable NFC Tag (Dev Pw Id %u) for AP interface %s (context %p)",
1843 : 1 : hapd->conf->wps_nfc_dev_pw_id, hapd->conf->iface, wps);
1844 : 1 : wps->ap_nfc_dev_pw_id = hapd->conf->wps_nfc_dev_pw_id;
1845 : 1 : wps->ap_nfc_dh_pubkey = wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey);
1846 : 1 : wps->ap_nfc_dh_privkey = wpabuf_dup(hapd->conf->wps_nfc_dh_privkey);
1847 : 1 : pw = hapd->conf->wps_nfc_dev_pw;
1848 : 1 : wps->ap_nfc_dev_pw = wpabuf_alloc(
1849 : 1 : wpabuf_len(pw) * 2 + 1);
1850 [ + - ]: 1 : if (wps->ap_nfc_dev_pw) {
1851 : 2 : wpa_snprintf_hex_uppercase(
1852 : 1 : (char *) wpabuf_put(wps->ap_nfc_dev_pw,
1853 : 1 : wpabuf_len(pw) * 2),
1854 : 1 : wpabuf_len(pw) * 2 + 1,
1855 : 1 : wpabuf_head(pw), wpabuf_len(pw));
1856 : : }
1857 : :
1858 [ + - ][ + - ]: 1 : if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey ||
[ - + ]
1859 : 1 : !wps->ap_nfc_dev_pw) {
1860 : 0 : hostapd_wps_nfc_clear(wps);
1861 : 0 : return -1;
1862 : : }
1863 : :
1864 : 1 : return 0;
1865 : : }
1866 : :
1867 : :
1868 : 0 : void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd)
1869 : : {
1870 : 0 : wpa_printf(MSG_DEBUG, "WPS: Disable NFC token for AP interface %s",
1871 : 0 : hapd->conf->iface);
1872 : 0 : hostapd_wps_nfc_clear(hapd->wps);
1873 : 0 : }
1874 : :
1875 : : #endif /* CONFIG_WPS_NFC */
|