xref: /titanic_52/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa_supplicant.c (revision d92a527c473246e5c750ae6c33ecd2f242a5bf1f)
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 	/* LINTED E_BAD_PTR_CAST_ALIGN */
584 	event = ((wl_events_t *)argp)->event;
585 	wpa_event_handler(cookie, event);
586 
587 	(void) door_return(NULL, 0, NULL, 0);
588 }
589 
590 /*
591  * Create the driver to wpad door
592  */
593 int
594 wpa_supplicant_door_setup(void *cookie, char *doorname)
595 {
596 	struct stat stbuf;
597 	int error = 0;
598 
599 	wpa_printf(MSG_DEBUG, "wpa_supplicant_door_setup(%s)", doorname);
600 	/*
601 	 * Create the door
602 	 */
603 	door_id = door_create(event_handler, cookie,
604 	    DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
605 
606 	if (door_id < 0) {
607 		error = -1;
608 		goto out;
609 	}
610 
611 	if (stat(doorname, &stbuf) < 0) {
612 		int newfd;
613 		if ((newfd = creat(doorname, 0666)) < 0) {
614 			(void) door_revoke(door_id);
615 			door_id = -1;
616 			error = -1;
617 
618 			goto out;
619 		}
620 		(void) close(newfd);
621 	}
622 
623 	if (fattach(door_id, doorname) < 0) {
624 		if ((errno != EBUSY) || (fdetach(doorname) < 0) ||
625 		    (fattach(door_id, doorname) < 0)) {
626 			(void) door_revoke(door_id);
627 			door_id = -1;
628 			error = -1;
629 
630 			goto out;
631 		}
632 	}
633 
634 out:
635 	return (error);
636 }
637 
638 void
639 wpa_supplicant_door_destroy(char *doorname)
640 {
641 	wpa_printf(MSG_DEBUG, "wpa_supplicant_door_destroy(%s)\n", doorname);
642 
643 	if (door_id == -1)
644 		return;
645 
646 	if (door_revoke(door_id) == -1) {
647 		wpa_printf(MSG_ERROR, "failed to door_revoke(%d) %s, exiting.",
648 		    door_id, strerror(errno));
649 	}
650 
651 	if (fdetach(doorname) == -1) {
652 		wpa_printf(MSG_ERROR, "failed to fdetach %s: %s, exiting.",
653 		    doorname, strerror(errno));
654 	}
655 
656 	(void) close(door_id);
657 }
658 
659 static int
660 wpa_config_parse_ssid(struct wpa_ssid *ssid, int line, const char *value)
661 {
662 	free(ssid->ssid);
663 
664 	ssid->ssid = (uint8_t *)strdup(value);
665 	ssid->ssid_len = strlen(value);
666 
667 	if (ssid->ssid == NULL) {
668 		wpa_printf(MSG_ERROR, "Invalid SSID '%s'.", line, value);
669 		return (-1);
670 	}
671 	if (ssid->ssid_len > MAX_ESSID_LENGTH) {
672 		free(ssid->ssid);
673 		wpa_printf(MSG_ERROR, "Too long SSID '%s'.", line, value);
674 		return (-1);
675 	}
676 	wpa_printf(MSG_MSGDUMP, "SSID: %s", ssid->ssid);
677 	return (0);
678 }
679 
680 static struct wpa_ssid *
681 wpa_config_read_network(struct wpa_supplicant *wpa_s)
682 {
683 	struct wpa_ssid *ssid;
684 	char buf[MAX_ESSID_LENGTH + 1];
685 	dladm_secobj_class_t cl;
686 	uint8_t psk[MAX_PSK_LENGTH + 1];
687 	uint_t key_len;
688 
689 	wpa_printf(MSG_MSGDUMP, "Start of a new network configration");
690 
691 	ssid = (struct wpa_ssid *)malloc(sizeof (*ssid));
692 	if (ssid == NULL)
693 		return (NULL);
694 	(void) memset(ssid, 0, sizeof (*ssid));
695 
696 	/*
697 	 * Set default supported values
698 	 */
699 	ssid->proto = WPA_PROTO_WPA | WPA_PROTO_RSN;
700 	ssid->pairwise_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP;
701 	ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP |
702 	    WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40;
703 	ssid->key_mgmt = WPA_KEY_MGMT_PSK; /* | WPA_KEY_MGMT_IEEE8021X; */
704 
705 	(void) memset(buf, 0, MAX_ESSID_LENGTH + 1);
706 	wpa_s->driver->get_ssid(wpa_s->linkid, (char *)buf);
707 
708 	(void) wpa_config_parse_ssid(ssid, 0, buf);
709 
710 	key_len = sizeof (psk);
711 	(void) dladm_get_secobj((const char *)wpa_s->kname, &cl, psk, &key_len,
712 	    DLADM_OPT_ACTIVE);
713 	psk[key_len] = '\0';
714 	ssid->passphrase = strdup((const char *)psk);
715 
716 	if (ssid->passphrase) {
717 		pbkdf2_sha1(ssid->passphrase, (char *)ssid->ssid,
718 		    ssid->ssid_len, 4096, ssid->psk, PMK_LEN);
719 		wpa_hexdump(MSG_MSGDUMP, "PSK (from passphrase)",
720 		    ssid->psk, PMK_LEN);
721 		ssid->psk_set = 1;
722 	}
723 
724 	if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) {
725 		wpa_printf(MSG_ERROR, "WPA-PSK accepted for key "
726 		    "management, but no PSK configured.");
727 		free(ssid);
728 		ssid = NULL;
729 	}
730 
731 	return (ssid);
732 }
733 
734 struct wpa_config *
735 wpa_config_read(void *arg)
736 {
737 	struct wpa_ssid *ssid;
738 	struct wpa_config *config;
739 	struct wpa_supplicant *wpa_s = arg;
740 
741 	config = malloc(sizeof (*config));
742 	if (config == NULL)
743 		return (NULL);
744 	(void) memset(config, 0, sizeof (*config));
745 	config->eapol_version = 1;	/* fixed value */
746 
747 	wpa_printf(MSG_DEBUG, "Reading configuration parameters from driver\n");
748 
749 	ssid = wpa_config_read_network(wpa_s);
750 	if (ssid == NULL) {
751 		wpa_config_free(config);
752 		config = NULL;
753 	} else {
754 		config->ssid = ssid;
755 	}
756 
757 	return (config);
758 }
759 
760 void
761 wpa_config_free(struct wpa_config *config)
762 {
763 	struct wpa_ssid *ssid = config->ssid;
764 
765 	if (ssid != NULL) {
766 		free(ssid->ssid);
767 		free(ssid->passphrase);
768 		free(ssid);
769 	}
770 	free(config);
771 }
772 
773 static int
774 daemon(boolean_t nochdir, boolean_t noclose)
775 {
776 	int retv;
777 
778 	if ((retv = fork()) == -1)
779 		return (-1);
780 	if (retv != 0)
781 		_exit(EXIT_SUCCESS);
782 	if (setsid() == -1)
783 		return (-1);
784 
785 	if (!nochdir && chdir("/") == -1)
786 		return (-1);
787 
788 	if (!noclose) {
789 		(void) close(0);
790 		(void) close(1);
791 		(void) close(2);
792 		if ((retv = open("/dev/null", O_RDWR)) != -1) {
793 			(void) dup2(retv, 1);
794 			(void) dup2(retv, 2);
795 		}
796 	}
797 
798 	return (0);
799 }
800 
801 /*
802  * make sure wpad is running under SMF context.
803  */
804 static boolean_t
805 is_smf_context(void)
806 {
807 	char *fmri;
808 
809 	return (((fmri = getenv("SMF_FMRI")) != NULL) &&
810 	    (strstr(fmri, SERVICE_NAME) != NULL));
811 }
812 
813 int
814 main(int argc, char *argv[])
815 {
816 	struct wpa_supplicant wpa_s;
817 	char *link = NULL;
818 	char *key = NULL;
819 	dlpi_handle_t dh = NULL;
820 	datalink_id_t linkid;
821 	dladm_phys_attr_t dpa;
822 	int c;
823 	int exitcode;
824 	char door_file[MAXPATHLEN];
825 
826 	if (!is_smf_context()) {
827 		(void) fprintf(stderr,
828 		    "wpad is an smf(5) managed service and cannot be run from "
829 		    "the command line; please use dladm(1M).\n");
830 		return (SMF_EXIT_ERR_NOSMF);
831 	}
832 
833 	for (;;) {
834 		c = getopt(argc, argv, "i:k:");
835 		if (c < 0)
836 			break;
837 		switch (c) {
838 		case 'i':
839 			link = optarg;
840 			break;
841 		case 'k':
842 			key = optarg;
843 			break;
844 		default:
845 			return (SMF_EXIT_ERR_CONFIG);
846 		}
847 	}
848 
849 	/*
850 	 * key name is required to retrieve PSK value through libwdladm APIs.
851 	 * key is saved by dladm command by keyname
852 	 * see dladm.
853 	 */
854 	if ((link == NULL) || (key == NULL)) {
855 		wpa_printf(MSG_ERROR, "\nLink & key is required.");
856 		return (-1);
857 	}
858 
859 	if ((strlen(key) >= sizeof (wpa_s.kname)))  {
860 		wpa_printf(MSG_ERROR, "Too long key name '%s'.", key);
861 		return (-1);
862 	}
863 
864 	if (daemon(0, 0))
865 		return (-1);
866 
867 	/*
868 	 * Hold this link open to prevent a link renaming operation.
869 	 */
870 	if (dlpi_open(link, &dh, 0) != DLPI_SUCCESS) {
871 		wpa_printf(MSG_ERROR, "Failed to open link '%s'.", link);
872 		return (-1);
873 	}
874 
875 	if (dladm_name2info(link, &linkid, NULL, NULL, NULL) !=
876 	    DLADM_STATUS_OK) {
877 		wpa_printf(MSG_ERROR, "Invalid link name '%s'.", link);
878 		dlpi_close(dh);
879 		return (-1);
880 	}
881 
882 	/*
883 	 * Get the device name of the link, which will be used as the door
884 	 * file name used to communicate with the driver. Note that different
885 	 * links use different doors.
886 	 */
887 	if (dladm_phys_info(linkid, &dpa, DLADM_OPT_ACTIVE) !=
888 	    DLADM_STATUS_OK) {
889 		wpa_printf(MSG_ERROR,
890 		    "Failed to get device name of link '%s'.", link);
891 		dlpi_close(dh);
892 		return (-1);
893 	}
894 	(void) snprintf(door_file, MAXPATHLEN, "%s_%s", WPA_DOOR, dpa.dp_dev);
895 
896 	(void) memset(&wpa_s, 0, sizeof (wpa_s));
897 	wpa_s.driver = &wpa_driver_wifi_ops;
898 	wpa_s.linkid = linkid;
899 	(void) strlcpy(wpa_s.kname, key, sizeof (wpa_s.kname));
900 	eloop_init(&wpa_s);
901 
902 	/*
903 	 * Setup default WPA/WPA2 configuration
904 	 * get ESSID and PSK value
905 	 */
906 	wpa_s.conf = wpa_config_read(&wpa_s);
907 	if (wpa_s.conf == NULL || wpa_s.conf->ssid == NULL) {
908 		wpa_printf(MSG_ERROR, "\nNo networks (SSID) configured.\n");
909 		exitcode = -1;
910 		goto cleanup;
911 	}
912 
913 	exitcode = 0;
914 
915 	/*
916 	 * Setup door file to communicate with driver
917 	 */
918 	if (wpa_supplicant_door_setup(&wpa_s, door_file) != 0) {
919 		wpa_printf(MSG_ERROR, "Failed to setup door(%s)", door_file);
920 		exitcode = -1;
921 		goto cleanup;
922 	}
923 
924 	wpa_s.renew_snonce = 1;
925 	if (wpa_supplicant_driver_init(link, &wpa_s) < 0) {
926 		exitcode = -1;
927 		goto cleanup;
928 	}
929 
930 	/*
931 	 * This link is hold again in wpa_supplicant_driver_init(), so that
932 	 * we release the first reference.
933 	 */
934 	dlpi_close(dh);
935 	dh = NULL;
936 
937 	wpa_printf(MSG_DEBUG, "=> eloop_run");
938 
939 	(void) eloop_register_signal(SIGINT, wpa_supplicant_terminate, NULL);
940 	(void) eloop_register_signal(SIGTERM, wpa_supplicant_terminate, NULL);
941 	(void) eloop_register_signal(SIGKILL, wpa_supplicant_terminate, NULL);
942 
943 	eloop_run();
944 
945 	wpa_printf(MSG_DEBUG, "<= eloop_run()");
946 	wpa_supplicant_disassociate(&wpa_s, REASON_DEAUTH_LEAVING);
947 
948 	if (wpa_s.driver->set_wpa(wpa_s.linkid, 0) < 0) {
949 		wpa_printf(MSG_ERROR, "Failed to disable WPA in the driver.\n");
950 	}
951 
952 cleanup:
953 	wpa_supplicant_door_destroy(door_file);
954 	wpa_supplicant_cleanup(&wpa_s);
955 	eloop_destroy();
956 
957 	if (dh != NULL)
958 		dlpi_close(dh);
959 
960 	return (exitcode);
961 }
962