1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
8  * Sun elects to license this software under the BSD license.
9  * See README for more details.
10  */
11 
12 #pragma ident	"%Z%%M%	%I%	%E% SMI"
13 
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <stdarg.h>
17 #include <unistd.h>
18 #include <string.h>
19 #include <syslog.h>
20 #include <sys/stat.h>
21 #include <errno.h>
22 #include <signal.h>
23 #include <fcntl.h>
24 #include <door.h>
25 #include <libscf.h>
26 #include <libdladm.h>
27 #include <libdllink.h>
28 #include <sys/ethernet.h>
29 
30 #include "wpa_impl.h"
31 #include "wpa_enc.h"
32 #include "driver.h"
33 #include "eloop.h"
34 #include "l2_packet.h"
35 
36 extern struct wpa_driver_ops wpa_driver_wifi_ops;
37 int wpa_debug_level = MSG_ERROR;
38 
39 /*
40  * wpa_printf - conditional printf
41  * @level: priority level (MSG_*) of the message
42  * @fmt: printf format string, followed by optional arguments
43  *
44  * This function is used to print conditional debugging and error messages. The
45  * output may be directed to stdout, stderr, and/or syslog based on
46  * configuration.
47  */
48 void
49 wpa_printf(int level, char *fmt, ...)
50 {
51 	va_list ap;
52 	char buffer[MAX_LOGBUF];
53 
54 	if (level < wpa_debug_level)
55 		return;
56 
57 	va_start(ap, fmt);
58 
59 	/* LINTED E_SEC_PRINTF_VAR_FMT */
60 	(void) vsnprintf(buffer, sizeof (buffer), fmt, ap);
61 
62 	va_end(ap);
63 
64 	syslog(LOG_NOTICE | LOG_DAEMON, "%s", buffer);
65 }
66 
67 /*
68  * wpa_hexdump - conditional hex dump
69  * @level: priority level (MSG_*) of the message
70  * @title: title of for the message
71  * @buf: data buffer to be dumped
72  * @len: length of the @buf
73  *
74  * This function is used to print conditional debugging and error messages. The
75  * output may be directed to stdout, stderr, and/or syslog based on
76  * configuration. The contents of @buf is printed out has hex dump.
77  */
78 void
79 wpa_hexdump(int level, const char *title, const uint8_t *buf, size_t len)
80 {
81 	size_t i;
82 	char buffer[MAX_LOGBUF], tmp[4];
83 	int n;
84 
85 	if (level < wpa_debug_level)
86 		return;
87 
88 	(void) snprintf(buffer, sizeof (buffer), "%s - hexdump(len=%d):",
89 	    title, len);
90 	n = strlen(buffer);
91 
92 	for (i = 0; i < len; i++) {
93 		(void) sprintf(tmp, " %02x", buf[i]);
94 
95 		n += strlen(tmp);
96 		if (n >= MAX_LOGBUF) break;
97 
98 		(void) strlcat(buffer, tmp, sizeof (buffer));
99 	}
100 
101 	syslog(LOG_NOTICE | LOG_DAEMON, "%s", buffer);
102 }
103 
104 static const char *
105 wpa_ssid_txt(char *ssid, size_t ssid_len)
106 {
107 	static char ssid_txt[MAX_ESSID_LENGTH + 1];
108 	char *pos;
109 
110 	if (ssid_len > MAX_ESSID_LENGTH)
111 		ssid_len = MAX_ESSID_LENGTH;
112 	(void) memcpy(ssid_txt, ssid, ssid_len);
113 	ssid_txt[ssid_len] = '\0';
114 	for (pos = ssid_txt; *pos != '\0'; pos ++) {
115 		if ((uint8_t)*pos < 32 || (uint8_t)*pos >= 127)
116 			*pos = '_';
117 	}
118 	return (ssid_txt);
119 }
120 
121 /* ARGSUSED */
122 void
123 wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
124 {
125 	struct wpa_supplicant *wpa_s = eloop_ctx;
126 	struct wpa_ssid *ssid;
127 
128 	if (wpa_s->conf == NULL)
129 		return;
130 
131 	if (wpa_s->wpa_state == WPA_DISCONNECTED)
132 		wpa_s->wpa_state = WPA_SCANNING;
133 
134 	ssid = wpa_s->conf->ssid;
135 	wpa_printf(MSG_DEBUG, "Starting AP scan (%s SSID)",
136 	    ssid ? "specific": "broadcast");
137 
138 	if (ssid) {
139 		wpa_printf(MSG_DEBUG, "Scan SSID: %s", ssid->ssid);
140 	}
141 
142 	if (wpa_s->driver->scan(wpa_s->linkid)) {
143 		wpa_printf(MSG_WARNING, "Failed to initiate AP scan.");
144 	}
145 }
146 
147 void
148 wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
149 {
150 	wpa_printf(MSG_DEBUG, "Setting scan request: %d sec %d usec",
151 	    sec, usec);
152 	(void) eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
153 	(void) eloop_register_timeout(sec, usec, wpa_supplicant_scan,
154 	    wpa_s, NULL);
155 }
156 
157 void
158 wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s)
159 {
160 	wpa_printf(MSG_DEBUG, "Cancelling scan request");
161 	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
162 }
163 
164 /* ARGSUSED */
165 static void
166 wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
167 {
168 	struct wpa_supplicant *wpa_s = eloop_ctx;
169 
170 	wpa_printf(MSG_INFO, "Authentication with " MACSTR " timed out.",
171 	    MAC2STR(wpa_s->bssid));
172 
173 	wpa_s->reassociate = 1;
174 	wpa_supplicant_req_scan(wpa_s, 0, 0);
175 }
176 
177 void
178 wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
179 				int sec, int usec)
180 {
181 	wpa_printf(MSG_DEBUG, "Setting authentication timeout: %d sec "
182 	    "%d usec", sec, usec);
183 	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
184 	(void) eloop_register_timeout(sec, usec, wpa_supplicant_timeout,
185 	    wpa_s, NULL);
186 }
187 
188 void
189 wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
190 {
191 	wpa_printf(MSG_DEBUG, "Cancelling authentication timeout");
192 	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
193 }
194 
195 static void
196 wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
197 {
198 	l2_packet_deinit(wpa_s->l2);
199 	wpa_s->l2 = NULL;
200 
201 	if (wpa_s->conf != NULL) {
202 		wpa_config_free(wpa_s->conf);
203 		wpa_s->conf = NULL;
204 	}
205 
206 	free(wpa_s->ap_wpa_ie);
207 	pmksa_candidate_free(wpa_s);
208 	pmksa_cache_free(wpa_s);
209 }
210 
211 static void
212 wpa_clear_keys(struct wpa_supplicant *wpa_s, uint8_t *addr)
213 {
214 	wpa_s->driver->set_key(wpa_s->linkid, WPA_ALG_NONE,
215 	    (uint8_t *)"\xff\xff\xff\xff\xff\xff", 0, 0, NULL, 0, NULL, 0);
216 	wpa_s->driver->set_key(wpa_s->linkid, WPA_ALG_NONE,
217 	    (uint8_t *)"\xff\xff\xff\xff\xff\xff", 1, 0, NULL, 0, NULL, 0);
218 	wpa_s->driver->set_key(wpa_s->linkid, WPA_ALG_NONE,
219 	    (uint8_t *)"\xff\xff\xff\xff\xff\xff", 2, 0, NULL, 0, NULL, 0);
220 	wpa_s->driver->set_key(wpa_s->linkid, WPA_ALG_NONE,
221 	    (uint8_t *)"\xff\xff\xff\xff\xff\xff", 3, 0, NULL, 0, NULL, 0);
222 	if (addr) {
223 		wpa_s->driver->set_key(wpa_s->linkid, WPA_ALG_NONE, addr,
224 		    0, 0, NULL, 0, NULL, 0);
225 	}
226 }
227 
228 static void
229 wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
230 {
231 	wpa_s->wpa_state = WPA_DISCONNECTED;
232 	(void) memset(wpa_s->bssid, 0, IEEE80211_ADDR_LEN);
233 }
234 
235 static int
236 wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
237     dladm_wlan_ess_t *bss, struct wpa_ssid *ssid,
238     uint8_t *wpa_ie, int *wpa_ie_len)
239 {
240 	struct wpa_ie_data ie;
241 	int sel, proto;
242 	uint8_t *ap_ie;
243 	size_t ap_ie_len;
244 
245 	/* RSN or WPA */
246 	if (bss->we_wpa_ie_len && bss->we_wpa_ie[0] == RSN_INFO_ELEM &&
247 	    (ssid->proto & WPA_PROTO_RSN)) {
248 		wpa_printf(MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
249 		proto = WPA_PROTO_RSN;
250 	} else {
251 		wpa_printf(MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
252 		proto = WPA_PROTO_WPA;
253 	}
254 
255 	ap_ie = bss->we_wpa_ie;
256 	ap_ie_len = bss->we_wpa_ie_len;
257 
258 	if (wpa_parse_wpa_ie(wpa_s, ap_ie, ap_ie_len, &ie)) {
259 		wpa_printf(MSG_WARNING, "WPA: Failed to parse WPA IE for "
260 		    "the selected BSS.");
261 		return (-1);
262 	}
263 
264 	wpa_s->proto = proto;
265 	free(wpa_s->ap_wpa_ie);
266 	wpa_s->ap_wpa_ie = malloc(ap_ie_len);
267 	(void) memcpy(wpa_s->ap_wpa_ie, ap_ie, ap_ie_len);
268 	wpa_s->ap_wpa_ie_len = ap_ie_len;
269 
270 	sel = ie.group_cipher & ssid->group_cipher;
271 	if (sel & WPA_CIPHER_CCMP) {
272 		wpa_s->group_cipher = WPA_CIPHER_CCMP;
273 	} else if (sel & WPA_CIPHER_TKIP) {
274 		wpa_s->group_cipher = WPA_CIPHER_TKIP;
275 	} else if (sel & WPA_CIPHER_WEP104) {
276 		wpa_s->group_cipher = WPA_CIPHER_WEP104;
277 	} else if (sel & WPA_CIPHER_WEP40) {
278 		wpa_s->group_cipher = WPA_CIPHER_WEP40;
279 	} else {
280 		wpa_printf(MSG_WARNING, "WPA: Failed to select group cipher.");
281 		return (-1);
282 	}
283 
284 	sel = ie.pairwise_cipher & ssid->pairwise_cipher;
285 	if (sel & WPA_CIPHER_CCMP) {
286 		wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
287 	} else if (sel & WPA_CIPHER_TKIP) {
288 		wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
289 	} else if (sel & WPA_CIPHER_NONE) {
290 		wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
291 	} else {
292 		wpa_printf(MSG_WARNING, "WPA: Failed to select pairwise "
293 		    "cipher.");
294 		return (-1);
295 	}
296 
297 	sel = ie.key_mgmt & ssid->key_mgmt;
298 	if (sel & WPA_KEY_MGMT_IEEE8021X) {
299 		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
300 	} else if (sel & WPA_KEY_MGMT_PSK) {
301 		wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
302 	} else {
303 		wpa_printf(MSG_WARNING, "WPA: Failed to select authenticated "
304 		    "key management type.");
305 		return (-1);
306 	}
307 
308 	*wpa_ie_len = wpa_gen_wpa_ie(wpa_s, wpa_ie);
309 	if (*wpa_ie_len < 0) {
310 		wpa_printf(MSG_WARNING, "WPA: Failed to generate WPA IE.");
311 		return (-1);
312 	}
313 	wpa_hexdump(MSG_DEBUG, "WPA: Own WPA IE", wpa_ie, *wpa_ie_len);
314 
315 	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
316 		(void) memcpy(wpa_s->pmk, ssid->psk, PMK_LEN);
317 	else if (wpa_s->cur_pmksa)
318 		(void) memcpy(wpa_s->pmk, wpa_s->cur_pmksa->pmk, PMK_LEN);
319 	else {
320 		(void) memset(wpa_s->pmk, 0, PMK_LEN);
321 	}
322 
323 	return (0);
324 }
325 
326 static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
327     dladm_wlan_ess_t *bss, struct wpa_ssid *ssid)
328 {
329 	uint8_t wpa_ie[IEEE80211_MAX_OPT_IE];
330 	int wpa_ie_len;
331 
332 	wpa_s->reassociate = 0;
333 	wpa_printf(MSG_DEBUG, "Trying to associate with " MACSTR
334 	    " (SSID='%s' freq=%d MHz)", MAC2STR(bss->we_bssid.wb_bytes),
335 	    wpa_ssid_txt((char *)ssid->ssid, ssid->ssid_len), bss->we_freq);
336 	wpa_supplicant_cancel_scan(wpa_s);
337 
338 	if (bss->we_wpa_ie_len &&
339 	    (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK))) {
340 		wpa_s->cur_pmksa = pmksa_cache_get(wpa_s,
341 		    bss->we_bssid.wb_bytes, NULL);
342 		if (wpa_s->cur_pmksa) {
343 			wpa_hexdump(MSG_DEBUG, "RSN: PMKID",
344 			    wpa_s->cur_pmksa->pmkid, PMKID_LEN);
345 		}
346 		if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
347 		    wpa_ie, &wpa_ie_len)) {
348 			wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key "
349 			    "management and encryption suites");
350 			return;
351 		}
352 	} else {
353 		wpa_ie_len = 0;
354 	}
355 
356 	wpa_clear_keys(wpa_s, bss->we_bssid.wb_bytes);
357 	wpa_s->wpa_state = WPA_ASSOCIATING;
358 	wpa_s->driver->associate(wpa_s->linkid,
359 	    (const char *)bss->we_bssid.wb_bytes, wpa_ie, wpa_ie_len);
360 
361 	/* Timeout for IEEE 802.11 authentication and association */
362 	wpa_supplicant_req_auth_timeout(wpa_s, 15, 0);
363 }
364 
365 void
366 wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s, int reason_code)
367 {
368 	uint8_t *addr = NULL;
369 	wpa_s->wpa_state = WPA_DISCONNECTED;
370 	if (memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00",
371 	    IEEE80211_ADDR_LEN) != 0) {
372 		wpa_s->driver->disassociate(wpa_s->linkid, reason_code);
373 		addr = wpa_s->bssid;
374 	}
375 	wpa_clear_keys(wpa_s, addr);
376 }
377 
378 static dladm_wlan_ess_t *
379 wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group,
380     dladm_wlan_ess_t *results, int num, struct wpa_ssid **selected_ssid)
381 {
382 	struct wpa_ssid *ssid;
383 	dladm_wlan_ess_t *bss, *selected = NULL;
384 	int i;
385 
386 	struct wpa_ie_data ie;
387 
388 	wpa_printf(MSG_DEBUG, "Selecting BSS from scan results (%d)", num);
389 
390 	bss = NULL;
391 	ssid = NULL;
392 
393 	/* try to find matched AP */
394 	for (i = 0; i < num && !selected; i++) {
395 		bss = &results[i];
396 		wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
397 		    "wpa_ie_len=%d",
398 		    i, MAC2STR(bss->we_bssid.wb_bytes),
399 		    wpa_ssid_txt(bss->we_ssid.we_bytes, bss->we_ssid_len),
400 		    bss->we_wpa_ie_len);
401 		if (bss->we_wpa_ie_len == 0) {
402 			wpa_printf(MSG_DEBUG, "   skip - no WPA/RSN IE");
403 		}
404 
405 		ssid = group;
406 		if (bss->we_ssid_len != ssid->ssid_len ||
407 		    memcmp(bss->we_ssid.we_bytes, ssid->ssid,
408 		    bss->we_ssid_len) != 0) {
409 			wpa_printf(MSG_DEBUG, "   skip - SSID mismatch");
410 			continue;
411 		}
412 		if (!((ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_WPA)) &&
413 		    wpa_parse_wpa_ie(wpa_s, bss->we_wpa_ie,
414 		    bss->we_wpa_ie_len, &ie) == 0)) {
415 			wpa_printf(MSG_DEBUG, "   skip - "
416 			    "could not parse WPA/RSN IE");
417 			continue;
418 		}
419 		if (!(ie.proto & ssid->proto)) {
420 			wpa_printf(MSG_DEBUG, "   skip - proto mismatch");
421 			continue;
422 		}
423 		if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
424 			wpa_printf(MSG_DEBUG, "   skip - PTK cipher mismatch");
425 			continue;
426 		}
427 		if (!(ie.group_cipher & ssid->group_cipher)) {
428 			wpa_printf(MSG_DEBUG, "   skip - GTK cipher mismatch");
429 			continue;
430 		}
431 		if (!(ie.key_mgmt & ssid->key_mgmt)) {
432 			wpa_printf(MSG_DEBUG, "   skip - key mgmt mismatch");
433 			continue;
434 		}
435 
436 		selected = bss;
437 		*selected_ssid = ssid;
438 		wpa_printf(MSG_DEBUG, "   selected");
439 	}
440 
441 	return (selected);
442 }
443 
444 
445 static void
446 wpa_supplicant_scan_results(struct wpa_supplicant *wpa_s)
447 {
448 	dladm_wlan_ess_t results[MAX_SCANRESULTS];
449 	int num;
450 	dladm_wlan_ess_t *selected = NULL;
451 	struct wpa_ssid *ssid;
452 
453 	(void) memset(results, 0, sizeof (dladm_wlan_ess_t) * MAX_SCANRESULTS);
454 	num = wpa_s->driver->get_scan_results(wpa_s->linkid, results,
455 	    MAX_SCANRESULTS);
456 	wpa_printf(MSG_DEBUG, "Scan results: %d", num);
457 	if (num < 0)
458 		return;
459 	if (num > MAX_SCANRESULTS) {
460 		wpa_printf(MSG_INFO, "Not enough room for all APs (%d < %d)",
461 		    num, MAX_SCANRESULTS);
462 		num = MAX_SCANRESULTS;
463 	}
464 
465 	selected = wpa_supplicant_select_bss(wpa_s,
466 	    wpa_s->conf->ssid, results, num, &ssid);
467 
468 	if (selected) {
469 		if (wpa_s->reassociate ||
470 		    memcmp(selected->we_bssid.wb_bytes, wpa_s->bssid,
471 		    IEEE80211_ADDR_LEN) != 0) {
472 			wpa_supplicant_associate(wpa_s, selected, ssid);
473 		} else {
474 			wpa_printf(MSG_DEBUG, "Already associated with the "
475 			    "selected AP.");
476 		}
477 	} else {
478 		wpa_printf(MSG_DEBUG, "No suitable AP found.");
479 		wpa_supplicant_req_scan(wpa_s, 5, 0);	/* wait 5 seconds */
480 	}
481 }
482 
483 /*
484  * wpa_event_handler - report a driver event for wpa_supplicant
485  * @wpa_s: pointer to wpa_supplicant data; this is the @ctx variable registered
486  *	with wpa_driver_events_init()
487  * @event: event type (defined above)
488  *
489  * Driver wrapper code should call this function whenever an event is received
490  * from the driver.
491  */
492 void
493 wpa_event_handler(void *cookie, wpa_event_type event)
494 {
495 	struct wpa_supplicant *wpa_s = cookie;
496 	uint8_t bssid[IEEE80211_ADDR_LEN];
497 
498 	switch (event) {
499 	case EVENT_ASSOC:
500 		wpa_s->wpa_state = WPA_ASSOCIATED;
501 		wpa_printf(MSG_DEBUG, "\nAssociation event - clear replay "
502 		    "counter\n");
503 		(void) memset(wpa_s->rx_replay_counter, 0,
504 		    WPA_REPLAY_COUNTER_LEN);
505 		wpa_s->rx_replay_counter_set = 0;
506 		wpa_s->renew_snonce = 1;
507 		if (wpa_s->driver->get_bssid(wpa_s->linkid,
508 		    (char *)bssid) >= 0 &&
509 		    memcmp(bssid, wpa_s->bssid, IEEE80211_ADDR_LEN) != 0) {
510 			wpa_printf(MSG_DEBUG, "Associated to a new BSS: "
511 			    "BSSID=" MACSTR, MAC2STR(bssid));
512 			(void) memcpy(wpa_s->bssid, bssid, IEEE80211_ADDR_LEN);
513 			if (wpa_s->key_mgmt != WPA_KEY_MGMT_NONE)
514 				wpa_clear_keys(wpa_s, bssid);
515 		}
516 
517 		wpa_s->eapol_received = 0;
518 		if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
519 			wpa_supplicant_cancel_auth_timeout(wpa_s);
520 		} else {
521 			/* Timeout for receiving the first EAPOL packet */
522 			wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);
523 		}
524 		break;
525 	case EVENT_DISASSOC:
526 		if (wpa_s->wpa_state >= WPA_ASSOCIATED)
527 			wpa_supplicant_req_scan(wpa_s, 0, 100000);
528 		wpa_supplicant_mark_disassoc(wpa_s);
529 		wpa_printf(MSG_DEBUG, "Disconnect event - remove keys");
530 		if (wpa_s->key_mgmt != WPA_KEY_MGMT_NONE)
531 			wpa_clear_keys(wpa_s, wpa_s->bssid);
532 		break;
533 	case EVENT_SCAN_RESULTS:
534 		wpa_supplicant_scan_results(wpa_s);
535 		break;
536 	default:
537 		wpa_printf(MSG_INFO, "Unknown event %d", event);
538 		break;
539 	}
540 }
541 
542 /* ARGSUSED */
543 static void
544 wpa_supplicant_terminate(int sig, void *eloop_ctx, void *signal_ctx)
545 {
546 	wpa_printf(MSG_INFO, "Signal %d received - terminating", sig);
547 	eloop_terminate();
548 }
549 
550 static int
551 wpa_supplicant_driver_init(const char *link, struct wpa_supplicant *wpa_s)
552 {
553 	wpa_s->l2 = l2_packet_init(link, ETHERTYPE_EAPOL,
554 	    wpa_supplicant_rx_eapol, wpa_s);
555 	if (wpa_s->l2 == NULL)
556 		return (-1);
557 
558 	if (l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
559 		(void) fprintf(stderr, "Failed to get own L2 address\n");
560 		return (-1);
561 	}
562 
563 	if (wpa_s->driver->set_wpa(wpa_s->linkid, 1) < 0) {
564 		wpa_printf(MSG_ERROR, "Failed to enable WPA in the driver.");
565 		return (-1);
566 	}
567 
568 	wpa_clear_keys(wpa_s, NULL);
569 	wpa_supplicant_req_scan(wpa_s, 0, 100000);
570 
571 	return (0);
572 }
573 
574 static int door_id = -1;
575 
576 /* ARGSUSED */
577 static void
578 event_handler(void *cookie, char *argp, size_t asize,
579     door_desc_t *dp, uint_t n_desc)
580 {
581 	wpa_event_type event;
582 
583 	event = ((wl_events_t *)argp)->event;
584 	wpa_event_handler(cookie, event);
585 
586 	(void) door_return(NULL, 0, NULL, 0);
587 }
588 
589 /*
590  * Create the driver to wpad door
591  */
592 int
593 wpa_supplicant_door_setup(void *cookie, char *doorname)
594 {
595 	struct stat stbuf;
596 	int error = 0;
597 
598 	wpa_printf(MSG_DEBUG, "wpa_supplicant_door_setup(%s)", doorname);
599 	/*
600 	 * Create the door
601 	 */
602 	door_id = door_create(event_handler, cookie,
603 	    DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
604 
605 	if (door_id < 0) {
606 		error = -1;
607 		goto out;
608 	}
609 
610 	if (stat(doorname, &stbuf) < 0) {
611 		int newfd;
612 		if ((newfd = creat(doorname, 0666)) < 0) {
613 			(void) door_revoke(door_id);
614 			door_id = -1;
615 			error = -1;
616 
617 			goto out;
618 		}
619 		(void) close(newfd);
620 	}
621 
622 	if (fattach(door_id, doorname) < 0) {
623 		if ((errno != EBUSY) || (fdetach(doorname) < 0) ||
624 		    (fattach(door_id, doorname) < 0)) {
625 			(void) door_revoke(door_id);
626 			door_id = -1;
627 			error = -1;
628 
629 			goto out;
630 		}
631 	}
632 
633 out:
634 	return (error);
635 }
636 
637 void
638 wpa_supplicant_door_destroy(char *doorname)
639 {
640 	wpa_printf(MSG_DEBUG, "wpa_supplicant_door_destroy(%s)\n", doorname);
641 
642 	if (door_id == -1)
643 		return;
644 
645 	if (door_revoke(door_id) == -1) {
646 		wpa_printf(MSG_ERROR, "failed to door_revoke(%d) %s, exiting.",
647 		    door_id, strerror(errno));
648 	}
649 
650 	if (fdetach(doorname) == -1) {
651 		wpa_printf(MSG_ERROR, "failed to fdetach %s: %s, exiting.",
652 		    doorname, strerror(errno));
653 	}
654 
655 	(void) close(door_id);
656 }
657 
658 static int
659 wpa_config_parse_ssid(struct wpa_ssid *ssid, int line, const char *value)
660 {
661 	free(ssid->ssid);
662 
663 	ssid->ssid = (uint8_t *)strdup(value);
664 	ssid->ssid_len = strlen(value);
665 
666 	if (ssid->ssid == NULL) {
667 		wpa_printf(MSG_ERROR, "Invalid SSID '%s'.", line, value);
668 		return (-1);
669 	}
670 	if (ssid->ssid_len > MAX_ESSID_LENGTH) {
671 		free(ssid->ssid);
672 		wpa_printf(MSG_ERROR, "Too long SSID '%s'.", line, value);
673 		return (-1);
674 	}
675 	wpa_printf(MSG_MSGDUMP, "SSID: %s", ssid->ssid);
676 	return (0);
677 }
678 
679 static struct wpa_ssid *
680 wpa_config_read_network(struct wpa_supplicant *wpa_s)
681 {
682 	struct wpa_ssid *ssid;
683 	char buf[MAX_ESSID_LENGTH + 1];
684 	dladm_secobj_class_t cl;
685 	uint8_t psk[MAX_PSK_LENGTH + 1];
686 	uint_t key_len;
687 
688 	wpa_printf(MSG_MSGDUMP, "Start of a new network configration");
689 
690 	ssid = (struct wpa_ssid *)malloc(sizeof (*ssid));
691 	if (ssid == NULL)
692 		return (NULL);
693 	(void) memset(ssid, 0, sizeof (*ssid));
694 
695 	/*
696 	 * Set default supported values
697 	 */
698 	ssid->proto = WPA_PROTO_WPA | WPA_PROTO_RSN;
699 	ssid->pairwise_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP;
700 	ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP |
701 	    WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40;
702 	ssid->key_mgmt = WPA_KEY_MGMT_PSK; /* | WPA_KEY_MGMT_IEEE8021X; */
703 
704 	(void) memset(buf, 0, MAX_ESSID_LENGTH + 1);
705 	wpa_s->driver->get_ssid(wpa_s->linkid, (char *)buf);
706 
707 	(void) wpa_config_parse_ssid(ssid, 0, buf);
708 
709 	key_len = sizeof (psk);
710 	(void) dladm_get_secobj((const char *)wpa_s->kname, &cl, psk, &key_len,
711 	    DLADM_OPT_ACTIVE);
712 	psk[key_len] = '\0';
713 	ssid->passphrase = strdup((const char *)psk);
714 
715 	if (ssid->passphrase) {
716 		pbkdf2_sha1(ssid->passphrase, (char *)ssid->ssid,
717 		    ssid->ssid_len, 4096, ssid->psk, PMK_LEN);
718 		wpa_hexdump(MSG_MSGDUMP, "PSK (from passphrase)",
719 		    ssid->psk, PMK_LEN);
720 		ssid->psk_set = 1;
721 	}
722 
723 	if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) {
724 		wpa_printf(MSG_ERROR, "WPA-PSK accepted for key "
725 		    "management, but no PSK configured.");
726 		free(ssid);
727 		ssid = NULL;
728 	}
729 
730 	return (ssid);
731 }
732 
733 struct wpa_config *
734 wpa_config_read(void *arg)
735 {
736 	struct wpa_ssid *ssid;
737 	struct wpa_config *config;
738 	struct wpa_supplicant *wpa_s = arg;
739 
740 	config = malloc(sizeof (*config));
741 	if (config == NULL)
742 		return (NULL);
743 	(void) memset(config, 0, sizeof (*config));
744 	config->eapol_version = 1;	/* fixed value */
745 
746 	wpa_printf(MSG_DEBUG, "Reading configuration parameters from driver\n");
747 
748 	ssid = wpa_config_read_network(wpa_s);
749 	if (ssid == NULL) {
750 		wpa_config_free(config);
751 		config = NULL;
752 	} else {
753 		config->ssid = ssid;
754 	}
755 
756 	return (config);
757 }
758 
759 void
760 wpa_config_free(struct wpa_config *config)
761 {
762 	struct wpa_ssid *ssid = config->ssid;
763 
764 	if (ssid != NULL) {
765 		free(ssid->ssid);
766 		free(ssid->passphrase);
767 		free(ssid);
768 	}
769 	free(config);
770 }
771 
772 static int
773 daemon(boolean_t nochdir, boolean_t noclose)
774 {
775 	int retv;
776 
777 	if ((retv = fork()) == -1)
778 		return (-1);
779 	if (retv != 0)
780 		_exit(EXIT_SUCCESS);
781 	if (setsid() == -1)
782 		return (-1);
783 
784 	if (!nochdir && chdir("/") == -1)
785 		return (-1);
786 
787 	if (!noclose) {
788 		(void) close(0);
789 		(void) close(1);
790 		(void) close(2);
791 		if ((retv = open("/dev/null", O_RDWR)) != -1) {
792 			(void) dup2(retv, 1);
793 			(void) dup2(retv, 2);
794 		}
795 	}
796 
797 	return (0);
798 }
799 
800 /*
801  * make sure wpad is running under SMF context.
802  */
803 static boolean_t
804 is_smf_context(void)
805 {
806 	char *fmri;
807 
808 	return (((fmri = getenv("SMF_FMRI")) != NULL) &&
809 	    (strstr(fmri, SERVICE_NAME) != NULL));
810 }
811 
812 int
813 main(int argc, char *argv[])
814 {
815 	struct wpa_supplicant wpa_s;
816 	char *link = NULL;
817 	char *key = NULL;
818 	dlpi_handle_t dh = NULL;
819 	datalink_id_t linkid;
820 	dladm_phys_attr_t dpa;
821 	int c;
822 	int exitcode;
823 	char door_file[MAXPATHLEN];
824 
825 	if (!is_smf_context()) {
826 		(void) fprintf(stderr,
827 		    "wpad is an smf(5) managed service and cannot be run from "
828 		    "the command line; please use dladm(1M).\n");
829 		return (SMF_EXIT_ERR_NOSMF);
830 	}
831 
832 	for (;;) {
833 		c = getopt(argc, argv, "i:k:");
834 		if (c < 0)
835 			break;
836 		switch (c) {
837 		case 'i':
838 			link = optarg;
839 			break;
840 		case 'k':
841 			key = optarg;
842 			break;
843 		default:
844 			return (SMF_EXIT_ERR_CONFIG);
845 		}
846 	}
847 
848 	/*
849 	 * key name is required to retrieve PSK value through libwdladm APIs.
850 	 * key is saved by dladm command by keyname
851 	 * see dladm.
852 	 */
853 	if ((link == NULL) || (key == NULL)) {
854 		wpa_printf(MSG_ERROR, "\nLink & key is required.");
855 		return (-1);
856 	}
857 
858 	if ((strlen(key) >= sizeof (wpa_s.kname)))  {
859 		wpa_printf(MSG_ERROR, "Too long key name '%s'.", key);
860 		return (-1);
861 	}
862 
863 	if (daemon(0, 0))
864 		return (-1);
865 
866 	/*
867 	 * Hold this link open to prevent a link renaming operation.
868 	 */
869 	if (dlpi_open(link, &dh, 0) != DLPI_SUCCESS) {
870 		wpa_printf(MSG_ERROR, "Failed to open link '%s'.", link);
871 		return (-1);
872 	}
873 
874 	if (dladm_name2info(link, &linkid, NULL, NULL, NULL) !=
875 	    DLADM_STATUS_OK) {
876 		wpa_printf(MSG_ERROR, "Invalid link name '%s'.", link);
877 		dlpi_close(dh);
878 		return (-1);
879 	}
880 
881 	/*
882 	 * Get the device name of the link, which will be used as the door
883 	 * file name used to communicate with the driver. Note that different
884 	 * links use different doors.
885 	 */
886 	if (dladm_phys_info(linkid, &dpa, DLADM_OPT_ACTIVE) !=
887 	    DLADM_STATUS_OK) {
888 		wpa_printf(MSG_ERROR,
889 		    "Failed to get device name of link '%s'.", link);
890 		dlpi_close(dh);
891 		return (-1);
892 	}
893 	(void) snprintf(door_file, MAXPATHLEN, "%s_%s", WPA_DOOR, dpa.dp_dev);
894 
895 	(void) memset(&wpa_s, 0, sizeof (wpa_s));
896 	wpa_s.driver = &wpa_driver_wifi_ops;
897 	wpa_s.linkid = linkid;
898 	(void) strlcpy(wpa_s.kname, key, sizeof (wpa_s.kname));
899 	eloop_init(&wpa_s);
900 
901 	/*
902 	 * Setup default WPA/WPA2 configuration
903 	 * get ESSID and PSK value
904 	 */
905 	wpa_s.conf = wpa_config_read(&wpa_s);
906 	if (wpa_s.conf == NULL || wpa_s.conf->ssid == NULL) {
907 		wpa_printf(MSG_ERROR, "\nNo networks (SSID) configured.\n");
908 		exitcode = -1;
909 		goto cleanup;
910 	}
911 
912 	exitcode = 0;
913 
914 	/*
915 	 * Setup door file to communicate with driver
916 	 */
917 	if (wpa_supplicant_door_setup(&wpa_s, door_file) != 0) {
918 		wpa_printf(MSG_ERROR, "Failed to setup door(%s)", door_file);
919 		exitcode = -1;
920 		goto cleanup;
921 	}
922 
923 	wpa_s.renew_snonce = 1;
924 	if (wpa_supplicant_driver_init(link, &wpa_s) < 0) {
925 		exitcode = -1;
926 		goto cleanup;
927 	}
928 
929 	/*
930 	 * This link is hold again in wpa_supplicant_driver_init(), so that
931 	 * we release the first reference.
932 	 */
933 	dlpi_close(dh);
934 	dh = NULL;
935 
936 	wpa_printf(MSG_DEBUG, "=> eloop_run");
937 
938 	(void) eloop_register_signal(SIGINT, wpa_supplicant_terminate, NULL);
939 	(void) eloop_register_signal(SIGTERM, wpa_supplicant_terminate, NULL);
940 	(void) eloop_register_signal(SIGKILL, wpa_supplicant_terminate, NULL);
941 
942 	eloop_run();
943 
944 	wpa_printf(MSG_DEBUG, "<= eloop_run()");
945 	wpa_supplicant_disassociate(&wpa_s, REASON_DEAUTH_LEAVING);
946 
947 	if (wpa_s.driver->set_wpa(wpa_s.linkid, 0) < 0) {
948 		wpa_printf(MSG_ERROR, "Failed to disable WPA in the driver.\n");
949 	}
950 
951 cleanup:
952 	wpa_supplicant_door_destroy(door_file);
953 	wpa_supplicant_cleanup(&wpa_s);
954 	eloop_destroy();
955 
956 	if (dh != NULL)
957 		dlpi_close(dh);
958 
959 	return (exitcode);
960 }
961