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