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