xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa_supplicant.c (revision 10547:1a61a72b11d5)
14126Szf162725 /*
2*10547SVladimir.Kotal@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
34126Szf162725  * Use is subject to license terms.
44126Szf162725  */
54126Szf162725 
64126Szf162725 /*
74126Szf162725  * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
84126Szf162725  * Sun elects to license this software under the BSD license.
94126Szf162725  * See README for more details.
104126Szf162725  */
114126Szf162725 
124126Szf162725 #include <stdio.h>
134126Szf162725 #include <stdlib.h>
144126Szf162725 #include <stdarg.h>
154126Szf162725 #include <unistd.h>
164126Szf162725 #include <string.h>
174126Szf162725 #include <syslog.h>
184126Szf162725 #include <sys/stat.h>
194126Szf162725 #include <errno.h>
204126Szf162725 #include <signal.h>
214126Szf162725 #include <fcntl.h>
224126Szf162725 #include <door.h>
236411Szf162725 #include <libscf.h>
244126Szf162725 #include <libdladm.h>
254126Szf162725 #include <libdllink.h>
264126Szf162725 #include <sys/ethernet.h>
274126Szf162725 
284126Szf162725 #include "wpa_impl.h"
294126Szf162725 #include "wpa_enc.h"
304126Szf162725 #include "driver.h"
314126Szf162725 #include "eloop.h"
324126Szf162725 #include "l2_packet.h"
334126Szf162725 
344126Szf162725 extern struct wpa_driver_ops wpa_driver_wifi_ops;
354126Szf162725 int wpa_debug_level = MSG_ERROR;
364126Szf162725 
374126Szf162725 /*
384126Szf162725  * wpa_printf - conditional printf
394126Szf162725  * @level: priority level (MSG_*) of the message
404126Szf162725  * @fmt: printf format string, followed by optional arguments
414126Szf162725  *
424126Szf162725  * This function is used to print conditional debugging and error messages. The
434126Szf162725  * output may be directed to stdout, stderr, and/or syslog based on
444126Szf162725  * configuration.
454126Szf162725  */
464126Szf162725 void
wpa_printf(int level,char * fmt,...)474126Szf162725 wpa_printf(int level, char *fmt, ...)
484126Szf162725 {
494126Szf162725 	va_list ap;
504126Szf162725 	char buffer[MAX_LOGBUF];
514126Szf162725 
524126Szf162725 	if (level < wpa_debug_level)
534126Szf162725 		return;
544126Szf162725 
554126Szf162725 	va_start(ap, fmt);
564126Szf162725 
574126Szf162725 	/* LINTED E_SEC_PRINTF_VAR_FMT */
584126Szf162725 	(void) vsnprintf(buffer, sizeof (buffer), fmt, ap);
594126Szf162725 
604126Szf162725 	va_end(ap);
614126Szf162725 
624126Szf162725 	syslog(LOG_NOTICE | LOG_DAEMON, "%s", buffer);
634126Szf162725 }
644126Szf162725 
654126Szf162725 /*
664126Szf162725  * wpa_hexdump - conditional hex dump
674126Szf162725  * @level: priority level (MSG_*) of the message
684126Szf162725  * @title: title of for the message
694126Szf162725  * @buf: data buffer to be dumped
704126Szf162725  * @len: length of the @buf
714126Szf162725  *
724126Szf162725  * This function is used to print conditional debugging and error messages. The
734126Szf162725  * output may be directed to stdout, stderr, and/or syslog based on
744126Szf162725  * configuration. The contents of @buf is printed out has hex dump.
754126Szf162725  */
764126Szf162725 void
wpa_hexdump(int level,const char * title,const uint8_t * buf,size_t len)774126Szf162725 wpa_hexdump(int level, const char *title, const uint8_t *buf, size_t len)
784126Szf162725 {
794126Szf162725 	size_t i;
804126Szf162725 	char buffer[MAX_LOGBUF], tmp[4];
814126Szf162725 	int n;
824126Szf162725 
834126Szf162725 	if (level < wpa_debug_level)
844126Szf162725 		return;
854126Szf162725 
864126Szf162725 	(void) snprintf(buffer, sizeof (buffer), "%s - hexdump(len=%d):",
874126Szf162725 	    title, len);
884126Szf162725 	n = strlen(buffer);
894126Szf162725 
904126Szf162725 	for (i = 0; i < len; i++) {
914126Szf162725 		(void) sprintf(tmp, " %02x", buf[i]);
924126Szf162725 
934126Szf162725 		n += strlen(tmp);
944126Szf162725 		if (n >= MAX_LOGBUF) break;
954126Szf162725 
964126Szf162725 		(void) strlcat(buffer, tmp, sizeof (buffer));
974126Szf162725 	}
984126Szf162725 
994126Szf162725 	syslog(LOG_NOTICE | LOG_DAEMON, "%s", buffer);
1004126Szf162725 }
1014126Szf162725 
1024126Szf162725 static const char *
wpa_ssid_txt(char * ssid,size_t ssid_len)1034126Szf162725 wpa_ssid_txt(char *ssid, size_t ssid_len)
1044126Szf162725 {
1054126Szf162725 	static char ssid_txt[MAX_ESSID_LENGTH + 1];
1064126Szf162725 	char *pos;
1074126Szf162725 
1084126Szf162725 	if (ssid_len > MAX_ESSID_LENGTH)
1094126Szf162725 		ssid_len = MAX_ESSID_LENGTH;
1104126Szf162725 	(void) memcpy(ssid_txt, ssid, ssid_len);
1114126Szf162725 	ssid_txt[ssid_len] = '\0';
1124126Szf162725 	for (pos = ssid_txt; *pos != '\0'; pos ++) {
1134126Szf162725 		if ((uint8_t)*pos < 32 || (uint8_t)*pos >= 127)
1144126Szf162725 			*pos = '_';
1154126Szf162725 	}
1164126Szf162725 	return (ssid_txt);
1174126Szf162725 }
1184126Szf162725 
1194126Szf162725 /* ARGSUSED */
1204126Szf162725 void
wpa_supplicant_scan(void * eloop_ctx,void * timeout_ctx)1214126Szf162725 wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
1224126Szf162725 {
1234126Szf162725 	struct wpa_supplicant *wpa_s = eloop_ctx;
1244126Szf162725 	struct wpa_ssid *ssid;
1254126Szf162725 
1264126Szf162725 	if (wpa_s->conf == NULL)
1274126Szf162725 		return;
1284126Szf162725 
1294126Szf162725 	if (wpa_s->wpa_state == WPA_DISCONNECTED)
1304126Szf162725 		wpa_s->wpa_state = WPA_SCANNING;
1314126Szf162725 
1324126Szf162725 	ssid = wpa_s->conf->ssid;
1334126Szf162725 	wpa_printf(MSG_DEBUG, "Starting AP scan (%s SSID)",
1344126Szf162725 	    ssid ? "specific": "broadcast");
1354126Szf162725 
1364126Szf162725 	if (ssid) {
1374126Szf162725 		wpa_printf(MSG_DEBUG, "Scan SSID: %s", ssid->ssid);
1384126Szf162725 	}
1394126Szf162725 
1408453SAnurag.Maskey@Sun.COM 	if (wpa_s->driver->scan(wpa_s->handle, wpa_s->linkid)) {
1414126Szf162725 		wpa_printf(MSG_WARNING, "Failed to initiate AP scan.");
1424126Szf162725 	}
1434126Szf162725 }
1444126Szf162725 
1454126Szf162725 void
wpa_supplicant_req_scan(struct wpa_supplicant * wpa_s,int sec,int usec)1464126Szf162725 wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
1474126Szf162725 {
1484126Szf162725 	wpa_printf(MSG_DEBUG, "Setting scan request: %d sec %d usec",
1494126Szf162725 	    sec, usec);
1504126Szf162725 	(void) eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
1514126Szf162725 	(void) eloop_register_timeout(sec, usec, wpa_supplicant_scan,
1524126Szf162725 	    wpa_s, NULL);
1534126Szf162725 }
1544126Szf162725 
1554126Szf162725 void
wpa_supplicant_cancel_scan(struct wpa_supplicant * wpa_s)1564126Szf162725 wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s)
1574126Szf162725 {
1584126Szf162725 	wpa_printf(MSG_DEBUG, "Cancelling scan request");
1594126Szf162725 	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
1604126Szf162725 }
1614126Szf162725 
1624126Szf162725 /* ARGSUSED */
1634126Szf162725 static void
wpa_supplicant_timeout(void * eloop_ctx,void * timeout_ctx)1644126Szf162725 wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
1654126Szf162725 {
1664126Szf162725 	struct wpa_supplicant *wpa_s = eloop_ctx;
1674126Szf162725 
1684126Szf162725 	wpa_printf(MSG_INFO, "Authentication with " MACSTR " timed out.",
1694126Szf162725 	    MAC2STR(wpa_s->bssid));
1704126Szf162725 
1714126Szf162725 	wpa_s->reassociate = 1;
1724126Szf162725 	wpa_supplicant_req_scan(wpa_s, 0, 0);
1734126Szf162725 }
1744126Szf162725 
1754126Szf162725 void
wpa_supplicant_req_auth_timeout(struct wpa_supplicant * wpa_s,int sec,int usec)1764126Szf162725 wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
1774126Szf162725 				int sec, int usec)
1784126Szf162725 {
1794126Szf162725 	wpa_printf(MSG_DEBUG, "Setting authentication timeout: %d sec "
1804126Szf162725 	    "%d usec", sec, usec);
1814126Szf162725 	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
1824126Szf162725 	(void) eloop_register_timeout(sec, usec, wpa_supplicant_timeout,
1834126Szf162725 	    wpa_s, NULL);
1844126Szf162725 }
1854126Szf162725 
1864126Szf162725 void
wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant * wpa_s)1874126Szf162725 wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
1884126Szf162725 {
1894126Szf162725 	wpa_printf(MSG_DEBUG, "Cancelling authentication timeout");
1904126Szf162725 	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
1914126Szf162725 }
1924126Szf162725 
1934126Szf162725 static void
wpa_supplicant_cleanup(struct wpa_supplicant * wpa_s)1944126Szf162725 wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
1954126Szf162725 {
1964126Szf162725 	l2_packet_deinit(wpa_s->l2);
1974126Szf162725 	wpa_s->l2 = NULL;
1984126Szf162725 
1994126Szf162725 	if (wpa_s->conf != NULL) {
2004126Szf162725 		wpa_config_free(wpa_s->conf);
2014126Szf162725 		wpa_s->conf = NULL;
2024126Szf162725 	}
2034126Szf162725 
2048453SAnurag.Maskey@Sun.COM 	dladm_close(wpa_s->handle);
2054126Szf162725 	free(wpa_s->ap_wpa_ie);
2064126Szf162725 	pmksa_candidate_free(wpa_s);
2074126Szf162725 	pmksa_cache_free(wpa_s);
2084126Szf162725 }
2094126Szf162725 
2104126Szf162725 static void
wpa_clear_keys(struct wpa_supplicant * wpa_s,uint8_t * addr)2114126Szf162725 wpa_clear_keys(struct wpa_supplicant *wpa_s, uint8_t *addr)
2124126Szf162725 {
2138453SAnurag.Maskey@Sun.COM 	wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, WPA_ALG_NONE,
2144126Szf162725 	    (uint8_t *)"\xff\xff\xff\xff\xff\xff", 0, 0, NULL, 0, NULL, 0);
2158453SAnurag.Maskey@Sun.COM 	wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, WPA_ALG_NONE,
2164126Szf162725 	    (uint8_t *)"\xff\xff\xff\xff\xff\xff", 1, 0, NULL, 0, NULL, 0);
2178453SAnurag.Maskey@Sun.COM 	wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, WPA_ALG_NONE,
2184126Szf162725 	    (uint8_t *)"\xff\xff\xff\xff\xff\xff", 2, 0, NULL, 0, NULL, 0);
2198453SAnurag.Maskey@Sun.COM 	wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, WPA_ALG_NONE,
2204126Szf162725 	    (uint8_t *)"\xff\xff\xff\xff\xff\xff", 3, 0, NULL, 0, NULL, 0);
2214126Szf162725 	if (addr) {
2228453SAnurag.Maskey@Sun.COM 		wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid,
2238453SAnurag.Maskey@Sun.COM 		    WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL, 0);
2244126Szf162725 	}
2254126Szf162725 }
2264126Szf162725 
2274126Szf162725 static void
wpa_supplicant_mark_disassoc(struct wpa_supplicant * wpa_s)2284126Szf162725 wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
2294126Szf162725 {
2304126Szf162725 	wpa_s->wpa_state = WPA_DISCONNECTED;
2314126Szf162725 	(void) memset(wpa_s->bssid, 0, IEEE80211_ADDR_LEN);
2324126Szf162725 }
2334126Szf162725 
2344126Szf162725 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)2354126Szf162725 wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
2364126Szf162725     dladm_wlan_ess_t *bss, struct wpa_ssid *ssid,
2374126Szf162725     uint8_t *wpa_ie, int *wpa_ie_len)
2384126Szf162725 {
2394126Szf162725 	struct wpa_ie_data ie;
2404126Szf162725 	int sel, proto;
2414126Szf162725 	uint8_t *ap_ie;
2424126Szf162725 	size_t ap_ie_len;
2434126Szf162725 
2444126Szf162725 	/* RSN or WPA */
2454126Szf162725 	if (bss->we_wpa_ie_len && bss->we_wpa_ie[0] == RSN_INFO_ELEM &&
2464126Szf162725 	    (ssid->proto & WPA_PROTO_RSN)) {
2474126Szf162725 		wpa_printf(MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
2484126Szf162725 		proto = WPA_PROTO_RSN;
2494126Szf162725 	} else {
2504126Szf162725 		wpa_printf(MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
2514126Szf162725 		proto = WPA_PROTO_WPA;
2524126Szf162725 	}
2534126Szf162725 
2544126Szf162725 	ap_ie = bss->we_wpa_ie;
2554126Szf162725 	ap_ie_len = bss->we_wpa_ie_len;
2564126Szf162725 
2574126Szf162725 	if (wpa_parse_wpa_ie(wpa_s, ap_ie, ap_ie_len, &ie)) {
2584126Szf162725 		wpa_printf(MSG_WARNING, "WPA: Failed to parse WPA IE for "
2594126Szf162725 		    "the selected BSS.");
2604126Szf162725 		return (-1);
2614126Szf162725 	}
2624126Szf162725 
2634126Szf162725 	wpa_s->proto = proto;
2644126Szf162725 	free(wpa_s->ap_wpa_ie);
2654126Szf162725 	wpa_s->ap_wpa_ie = malloc(ap_ie_len);
2664126Szf162725 	(void) memcpy(wpa_s->ap_wpa_ie, ap_ie, ap_ie_len);
2674126Szf162725 	wpa_s->ap_wpa_ie_len = ap_ie_len;
2684126Szf162725 
2694126Szf162725 	sel = ie.group_cipher & ssid->group_cipher;
2704126Szf162725 	if (sel & WPA_CIPHER_CCMP) {
2714126Szf162725 		wpa_s->group_cipher = WPA_CIPHER_CCMP;
2724126Szf162725 	} else if (sel & WPA_CIPHER_TKIP) {
2734126Szf162725 		wpa_s->group_cipher = WPA_CIPHER_TKIP;
2744126Szf162725 	} else if (sel & WPA_CIPHER_WEP104) {
2754126Szf162725 		wpa_s->group_cipher = WPA_CIPHER_WEP104;
2764126Szf162725 	} else if (sel & WPA_CIPHER_WEP40) {
2774126Szf162725 		wpa_s->group_cipher = WPA_CIPHER_WEP40;
2784126Szf162725 	} else {
2794126Szf162725 		wpa_printf(MSG_WARNING, "WPA: Failed to select group cipher.");
2804126Szf162725 		return (-1);
2814126Szf162725 	}
2824126Szf162725 
2834126Szf162725 	sel = ie.pairwise_cipher & ssid->pairwise_cipher;
2844126Szf162725 	if (sel & WPA_CIPHER_CCMP) {
2854126Szf162725 		wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
2864126Szf162725 	} else if (sel & WPA_CIPHER_TKIP) {
2874126Szf162725 		wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
2884126Szf162725 	} else if (sel & WPA_CIPHER_NONE) {
2894126Szf162725 		wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
2904126Szf162725 	} else {
2914126Szf162725 		wpa_printf(MSG_WARNING, "WPA: Failed to select pairwise "
2924126Szf162725 		    "cipher.");
2934126Szf162725 		return (-1);
2944126Szf162725 	}
2954126Szf162725 
2964126Szf162725 	sel = ie.key_mgmt & ssid->key_mgmt;
2974126Szf162725 	if (sel & WPA_KEY_MGMT_IEEE8021X) {
2984126Szf162725 		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
2994126Szf162725 	} else if (sel & WPA_KEY_MGMT_PSK) {
3004126Szf162725 		wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
3014126Szf162725 	} else {
3024126Szf162725 		wpa_printf(MSG_WARNING, "WPA: Failed to select authenticated "
3034126Szf162725 		    "key management type.");
3044126Szf162725 		return (-1);
3054126Szf162725 	}
3064126Szf162725 
3074126Szf162725 	*wpa_ie_len = wpa_gen_wpa_ie(wpa_s, wpa_ie);
3084126Szf162725 	if (*wpa_ie_len < 0) {
3094126Szf162725 		wpa_printf(MSG_WARNING, "WPA: Failed to generate WPA IE.");
3104126Szf162725 		return (-1);
3114126Szf162725 	}
3124126Szf162725 	wpa_hexdump(MSG_DEBUG, "WPA: Own WPA IE", wpa_ie, *wpa_ie_len);
3134126Szf162725 
3144126Szf162725 	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
3154126Szf162725 		(void) memcpy(wpa_s->pmk, ssid->psk, PMK_LEN);
3164126Szf162725 	else if (wpa_s->cur_pmksa)
3174126Szf162725 		(void) memcpy(wpa_s->pmk, wpa_s->cur_pmksa->pmk, PMK_LEN);
3184126Szf162725 	else {
3194126Szf162725 		(void) memset(wpa_s->pmk, 0, PMK_LEN);
3204126Szf162725 	}
3214126Szf162725 
3224126Szf162725 	return (0);
3234126Szf162725 }
3244126Szf162725 
wpa_supplicant_associate(struct wpa_supplicant * wpa_s,dladm_wlan_ess_t * bss,struct wpa_ssid * ssid)3254126Szf162725 static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
3264126Szf162725     dladm_wlan_ess_t *bss, struct wpa_ssid *ssid)
3274126Szf162725 {
3284126Szf162725 	uint8_t wpa_ie[IEEE80211_MAX_OPT_IE];
3294126Szf162725 	int wpa_ie_len;
3304126Szf162725 
3314126Szf162725 	wpa_s->reassociate = 0;
3324126Szf162725 	wpa_printf(MSG_DEBUG, "Trying to associate with " MACSTR
3334126Szf162725 	    " (SSID='%s' freq=%d MHz)", MAC2STR(bss->we_bssid.wb_bytes),
3344126Szf162725 	    wpa_ssid_txt((char *)ssid->ssid, ssid->ssid_len), bss->we_freq);
3354126Szf162725 	wpa_supplicant_cancel_scan(wpa_s);
3364126Szf162725 
3374126Szf162725 	if (bss->we_wpa_ie_len &&
3384126Szf162725 	    (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK))) {
3394126Szf162725 		wpa_s->cur_pmksa = pmksa_cache_get(wpa_s,
3404126Szf162725 		    bss->we_bssid.wb_bytes, NULL);
3414126Szf162725 		if (wpa_s->cur_pmksa) {
3424126Szf162725 			wpa_hexdump(MSG_DEBUG, "RSN: PMKID",
3434126Szf162725 			    wpa_s->cur_pmksa->pmkid, PMKID_LEN);
3444126Szf162725 		}
3454126Szf162725 		if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
3464126Szf162725 		    wpa_ie, &wpa_ie_len)) {
3474126Szf162725 			wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key "
3484126Szf162725 			    "management and encryption suites");
3494126Szf162725 			return;
3504126Szf162725 		}
3514126Szf162725 	} else {
3524126Szf162725 		wpa_ie_len = 0;
3534126Szf162725 	}
3544126Szf162725 
3554126Szf162725 	wpa_clear_keys(wpa_s, bss->we_bssid.wb_bytes);
3564126Szf162725 	wpa_s->wpa_state = WPA_ASSOCIATING;
3578453SAnurag.Maskey@Sun.COM 	wpa_s->driver->associate(wpa_s->handle, wpa_s->linkid,
3584126Szf162725 	    (const char *)bss->we_bssid.wb_bytes, wpa_ie, wpa_ie_len);
3594126Szf162725 
3604126Szf162725 	/* Timeout for IEEE 802.11 authentication and association */
3614126Szf162725 	wpa_supplicant_req_auth_timeout(wpa_s, 15, 0);
3624126Szf162725 }
3634126Szf162725 
3644126Szf162725 void
wpa_supplicant_disassociate(struct wpa_supplicant * wpa_s,int reason_code)3654126Szf162725 wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s, int reason_code)
3664126Szf162725 {
3674126Szf162725 	uint8_t *addr = NULL;
3684126Szf162725 	wpa_s->wpa_state = WPA_DISCONNECTED;
3694126Szf162725 	if (memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00",
3704126Szf162725 	    IEEE80211_ADDR_LEN) != 0) {
3718453SAnurag.Maskey@Sun.COM 		wpa_s->driver->disassociate(wpa_s->handle, wpa_s->linkid,
3728453SAnurag.Maskey@Sun.COM 		    reason_code);
3734126Szf162725 		addr = wpa_s->bssid;
3744126Szf162725 	}
3754126Szf162725 	wpa_clear_keys(wpa_s, addr);
3764126Szf162725 }
3774126Szf162725 
3784126Szf162725 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)3794126Szf162725 wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group,
3804126Szf162725     dladm_wlan_ess_t *results, int num, struct wpa_ssid **selected_ssid)
3814126Szf162725 {
3824126Szf162725 	struct wpa_ssid *ssid;
3834126Szf162725 	dladm_wlan_ess_t *bss, *selected = NULL;
3844126Szf162725 	int i;
3854126Szf162725 
3864126Szf162725 	struct wpa_ie_data ie;
3874126Szf162725 
3884126Szf162725 	wpa_printf(MSG_DEBUG, "Selecting BSS from scan results (%d)", num);
3894126Szf162725 
3904126Szf162725 	bss = NULL;
3914126Szf162725 	ssid = NULL;
3924126Szf162725 
3934126Szf162725 	/* try to find matched AP */
3944126Szf162725 	for (i = 0; i < num && !selected; i++) {
3954126Szf162725 		bss = &results[i];
3964126Szf162725 		wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
3974126Szf162725 		    "wpa_ie_len=%d",
3984126Szf162725 		    i, MAC2STR(bss->we_bssid.wb_bytes),
3994126Szf162725 		    wpa_ssid_txt(bss->we_ssid.we_bytes, bss->we_ssid_len),
4004126Szf162725 		    bss->we_wpa_ie_len);
4014126Szf162725 		if (bss->we_wpa_ie_len == 0) {
4024126Szf162725 			wpa_printf(MSG_DEBUG, "   skip - no WPA/RSN IE");
4034126Szf162725 		}
4044126Szf162725 
4054126Szf162725 		ssid = group;
4064126Szf162725 		if (bss->we_ssid_len != ssid->ssid_len ||
4074126Szf162725 		    memcmp(bss->we_ssid.we_bytes, ssid->ssid,
4084126Szf162725 		    bss->we_ssid_len) != 0) {
4094126Szf162725 			wpa_printf(MSG_DEBUG, "   skip - SSID mismatch");
4104126Szf162725 			continue;
4114126Szf162725 		}
4124126Szf162725 		if (!((ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_WPA)) &&
4134126Szf162725 		    wpa_parse_wpa_ie(wpa_s, bss->we_wpa_ie,
4144126Szf162725 		    bss->we_wpa_ie_len, &ie) == 0)) {
4154126Szf162725 			wpa_printf(MSG_DEBUG, "   skip - "
4164126Szf162725 			    "could not parse WPA/RSN IE");
4174126Szf162725 			continue;
4184126Szf162725 		}
4194126Szf162725 		if (!(ie.proto & ssid->proto)) {
4204126Szf162725 			wpa_printf(MSG_DEBUG, "   skip - proto mismatch");
4214126Szf162725 			continue;
4224126Szf162725 		}
4234126Szf162725 		if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
4244126Szf162725 			wpa_printf(MSG_DEBUG, "   skip - PTK cipher mismatch");
4254126Szf162725 			continue;
4264126Szf162725 		}
4274126Szf162725 		if (!(ie.group_cipher & ssid->group_cipher)) {
4284126Szf162725 			wpa_printf(MSG_DEBUG, "   skip - GTK cipher mismatch");
4294126Szf162725 			continue;
4304126Szf162725 		}
4314126Szf162725 		if (!(ie.key_mgmt & ssid->key_mgmt)) {
4324126Szf162725 			wpa_printf(MSG_DEBUG, "   skip - key mgmt mismatch");
4334126Szf162725 			continue;
4344126Szf162725 		}
4354126Szf162725 
4364126Szf162725 		selected = bss;
4374126Szf162725 		*selected_ssid = ssid;
4384126Szf162725 		wpa_printf(MSG_DEBUG, "   selected");
4394126Szf162725 	}
4404126Szf162725 
4414126Szf162725 	return (selected);
4424126Szf162725 }
4434126Szf162725 
4444126Szf162725 
4454126Szf162725 static void
wpa_supplicant_scan_results(struct wpa_supplicant * wpa_s)4464126Szf162725 wpa_supplicant_scan_results(struct wpa_supplicant *wpa_s)
4474126Szf162725 {
4484126Szf162725 	dladm_wlan_ess_t results[MAX_SCANRESULTS];
4494126Szf162725 	int num;
4504126Szf162725 	dladm_wlan_ess_t *selected = NULL;
4514126Szf162725 	struct wpa_ssid *ssid;
4524126Szf162725 
4534126Szf162725 	(void) memset(results, 0, sizeof (dladm_wlan_ess_t) * MAX_SCANRESULTS);
4548453SAnurag.Maskey@Sun.COM 	num = wpa_s->driver->get_scan_results(wpa_s->handle, wpa_s->linkid,
4558453SAnurag.Maskey@Sun.COM 	    results, MAX_SCANRESULTS);
4564126Szf162725 	wpa_printf(MSG_DEBUG, "Scan results: %d", num);
4574126Szf162725 	if (num < 0)
4584126Szf162725 		return;
4594126Szf162725 	if (num > MAX_SCANRESULTS) {
4604126Szf162725 		wpa_printf(MSG_INFO, "Not enough room for all APs (%d < %d)",
4614126Szf162725 		    num, MAX_SCANRESULTS);
4624126Szf162725 		num = MAX_SCANRESULTS;
4634126Szf162725 	}
4644126Szf162725 
4654126Szf162725 	selected = wpa_supplicant_select_bss(wpa_s,
4664126Szf162725 	    wpa_s->conf->ssid, results, num, &ssid);
4674126Szf162725 
4684126Szf162725 	if (selected) {
4694126Szf162725 		if (wpa_s->reassociate ||
4704126Szf162725 		    memcmp(selected->we_bssid.wb_bytes, wpa_s->bssid,
4714126Szf162725 		    IEEE80211_ADDR_LEN) != 0) {
4724126Szf162725 			wpa_supplicant_associate(wpa_s, selected, ssid);
4734126Szf162725 		} else {
4744126Szf162725 			wpa_printf(MSG_DEBUG, "Already associated with the "
4754126Szf162725 			    "selected AP.");
4764126Szf162725 		}
4774126Szf162725 	} else {
4784126Szf162725 		wpa_printf(MSG_DEBUG, "No suitable AP found.");
4794126Szf162725 		wpa_supplicant_req_scan(wpa_s, 5, 0);	/* wait 5 seconds */
4804126Szf162725 	}
4814126Szf162725 }
4824126Szf162725 
4834126Szf162725 /*
4844126Szf162725  * wpa_event_handler - report a driver event for wpa_supplicant
4854126Szf162725  * @wpa_s: pointer to wpa_supplicant data; this is the @ctx variable registered
4864126Szf162725  *	with wpa_driver_events_init()
4874126Szf162725  * @event: event type (defined above)
4884126Szf162725  *
4894126Szf162725  * Driver wrapper code should call this function whenever an event is received
4904126Szf162725  * from the driver.
4914126Szf162725  */
4924126Szf162725 void
wpa_event_handler(void * cookie,wpa_event_type event)4934126Szf162725 wpa_event_handler(void *cookie, wpa_event_type event)
4944126Szf162725 {
4954126Szf162725 	struct wpa_supplicant *wpa_s = cookie;
4964126Szf162725 
4974126Szf162725 	switch (event) {
4984126Szf162725 	case EVENT_ASSOC:
4998230SQuaker.Fang@Sun.COM 		wpa_printf(MSG_DEBUG, "\nAssociation event\n");
5008230SQuaker.Fang@Sun.COM 		/* async event */
5018230SQuaker.Fang@Sun.COM 		if (wpa_s->wpa_state < WPA_ASSOCIATED) {
5028230SQuaker.Fang@Sun.COM 			wpa_s->wpa_state = WPA_ASSOCIATED;
5038230SQuaker.Fang@Sun.COM 			if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
5048230SQuaker.Fang@Sun.COM 				wpa_supplicant_cancel_auth_timeout(wpa_s);
5058230SQuaker.Fang@Sun.COM 			} else {
5068230SQuaker.Fang@Sun.COM 				/* Timeout for receiving first EAPOL packet */
5078230SQuaker.Fang@Sun.COM 				wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);
5088230SQuaker.Fang@Sun.COM 			}
5094126Szf162725 		}
5104126Szf162725 		break;
5114126Szf162725 	case EVENT_DISASSOC:
5124126Szf162725 		if (wpa_s->wpa_state >= WPA_ASSOCIATED)
5134126Szf162725 			wpa_supplicant_req_scan(wpa_s, 0, 100000);
5144126Szf162725 		wpa_supplicant_mark_disassoc(wpa_s);
5154126Szf162725 		wpa_printf(MSG_DEBUG, "Disconnect event - remove keys");
5164126Szf162725 		if (wpa_s->key_mgmt != WPA_KEY_MGMT_NONE)
5174126Szf162725 			wpa_clear_keys(wpa_s, wpa_s->bssid);
5184126Szf162725 		break;
5194126Szf162725 	case EVENT_SCAN_RESULTS:
5204126Szf162725 		wpa_supplicant_scan_results(wpa_s);
5218230SQuaker.Fang@Sun.COM 		/* reset vars */
5228230SQuaker.Fang@Sun.COM 		(void) memset(wpa_s->rx_replay_counter, 0,
5238230SQuaker.Fang@Sun.COM 		    WPA_REPLAY_COUNTER_LEN);
5248230SQuaker.Fang@Sun.COM 		wpa_s->rx_replay_counter_set = 0;
5258230SQuaker.Fang@Sun.COM 		wpa_s->renew_snonce = 1;
5268230SQuaker.Fang@Sun.COM 		wpa_s->eapol_received = 0;
5274126Szf162725 		break;
5284126Szf162725 	default:
5294126Szf162725 		wpa_printf(MSG_INFO, "Unknown event %d", event);
5304126Szf162725 		break;
5314126Szf162725 	}
5324126Szf162725 }
5334126Szf162725 
5344126Szf162725 /* ARGSUSED */
5354126Szf162725 static void
wpa_supplicant_terminate(int sig,void * eloop_ctx,void * signal_ctx)5364126Szf162725 wpa_supplicant_terminate(int sig, void *eloop_ctx, void *signal_ctx)
5374126Szf162725 {
5384126Szf162725 	wpa_printf(MSG_INFO, "Signal %d received - terminating", sig);
5394126Szf162725 	eloop_terminate();
5404126Szf162725 }
5414126Szf162725 
5424126Szf162725 static int
wpa_supplicant_driver_init(const char * link,struct wpa_supplicant * wpa_s)5435895Syz147064 wpa_supplicant_driver_init(const char *link, struct wpa_supplicant *wpa_s)
5444126Szf162725 {
5455895Syz147064 	wpa_s->l2 = l2_packet_init(link, ETHERTYPE_EAPOL,
5464126Szf162725 	    wpa_supplicant_rx_eapol, wpa_s);
5474126Szf162725 	if (wpa_s->l2 == NULL)
5484126Szf162725 		return (-1);
5494126Szf162725 
5504126Szf162725 	if (l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
5514126Szf162725 		(void) fprintf(stderr, "Failed to get own L2 address\n");
5524126Szf162725 		return (-1);
5534126Szf162725 	}
5544126Szf162725 
5558453SAnurag.Maskey@Sun.COM 	if (wpa_s->driver->set_wpa(wpa_s->handle, wpa_s->linkid, 1) < 0) {
5564126Szf162725 		wpa_printf(MSG_ERROR, "Failed to enable WPA in the driver.");
5574126Szf162725 		return (-1);
5584126Szf162725 	}
5594126Szf162725 
5604126Szf162725 	wpa_clear_keys(wpa_s, NULL);
5614126Szf162725 	wpa_supplicant_req_scan(wpa_s, 0, 100000);
5624126Szf162725 
5634126Szf162725 	return (0);
5644126Szf162725 }
5654126Szf162725 
5664126Szf162725 static int door_id = -1;
5674126Szf162725 
5684126Szf162725 /* ARGSUSED */
5694126Szf162725 static void
event_handler(void * cookie,char * argp,size_t asize,door_desc_t * dp,uint_t n_desc)5704126Szf162725 event_handler(void *cookie, char *argp, size_t asize,
5714126Szf162725     door_desc_t *dp, uint_t n_desc)
5724126Szf162725 {
5734126Szf162725 	wpa_event_type event;
5744126Szf162725 
5757249Sff224033 	/* LINTED E_BAD_PTR_CAST_ALIGN */
5764126Szf162725 	event = ((wl_events_t *)argp)->event;
5774126Szf162725 	wpa_event_handler(cookie, event);
5784126Szf162725 
5794126Szf162725 	(void) door_return(NULL, 0, NULL, 0);
5804126Szf162725 }
5814126Szf162725 
5824126Szf162725 /*
5834126Szf162725  * Create the driver to wpad door
5844126Szf162725  */
5854126Szf162725 int
wpa_supplicant_door_setup(void * cookie,char * doorname)5864126Szf162725 wpa_supplicant_door_setup(void *cookie, char *doorname)
5874126Szf162725 {
5884126Szf162725 	struct stat stbuf;
5894126Szf162725 	int error = 0;
5904126Szf162725 
5914126Szf162725 	wpa_printf(MSG_DEBUG, "wpa_supplicant_door_setup(%s)", doorname);
5924126Szf162725 	/*
5934126Szf162725 	 * Create the door
5944126Szf162725 	 */
5954126Szf162725 	door_id = door_create(event_handler, cookie,
5964126Szf162725 	    DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
5974126Szf162725 
5984126Szf162725 	if (door_id < 0) {
5994126Szf162725 		error = -1;
6004126Szf162725 		goto out;
6014126Szf162725 	}
6024126Szf162725 
6034126Szf162725 	if (stat(doorname, &stbuf) < 0) {
6044126Szf162725 		int newfd;
6054126Szf162725 		if ((newfd = creat(doorname, 0666)) < 0) {
6064126Szf162725 			(void) door_revoke(door_id);
6074126Szf162725 			door_id = -1;
6084126Szf162725 			error = -1;
6094126Szf162725 
6104126Szf162725 			goto out;
6114126Szf162725 		}
6124126Szf162725 		(void) close(newfd);
6134126Szf162725 	}
6144126Szf162725 
6154126Szf162725 	if (fattach(door_id, doorname) < 0) {
6164126Szf162725 		if ((errno != EBUSY) || (fdetach(doorname) < 0) ||
6174126Szf162725 		    (fattach(door_id, doorname) < 0)) {
6184126Szf162725 			(void) door_revoke(door_id);
6194126Szf162725 			door_id = -1;
6204126Szf162725 			error = -1;
6214126Szf162725 
6224126Szf162725 			goto out;
6234126Szf162725 		}
6244126Szf162725 	}
6254126Szf162725 
6264126Szf162725 out:
6274126Szf162725 	return (error);
6284126Szf162725 }
6294126Szf162725 
6304126Szf162725 void
wpa_supplicant_door_destroy(char * doorname)6314126Szf162725 wpa_supplicant_door_destroy(char *doorname)
6324126Szf162725 {
6334126Szf162725 	wpa_printf(MSG_DEBUG, "wpa_supplicant_door_destroy(%s)\n", doorname);
6344126Szf162725 
6355895Syz147064 	if (door_id == -1)
6365895Syz147064 		return;
6375895Syz147064 
6384126Szf162725 	if (door_revoke(door_id) == -1) {
6394126Szf162725 		wpa_printf(MSG_ERROR, "failed to door_revoke(%d) %s, exiting.",
6404126Szf162725 		    door_id, strerror(errno));
6414126Szf162725 	}
6424126Szf162725 
6434126Szf162725 	if (fdetach(doorname) == -1) {
6444126Szf162725 		wpa_printf(MSG_ERROR, "failed to fdetach %s: %s, exiting.",
6454126Szf162725 		    doorname, strerror(errno));
6464126Szf162725 	}
6474126Szf162725 
6484126Szf162725 	(void) close(door_id);
6494126Szf162725 }
6504126Szf162725 
6514126Szf162725 static int
wpa_config_parse_ssid(struct wpa_ssid * ssid,int line,const char * value)6524126Szf162725 wpa_config_parse_ssid(struct wpa_ssid *ssid, int line, const char *value)
6534126Szf162725 {
6544126Szf162725 	free(ssid->ssid);
6554126Szf162725 
6564126Szf162725 	ssid->ssid = (uint8_t *)strdup(value);
6574126Szf162725 	ssid->ssid_len = strlen(value);
6584126Szf162725 
6594126Szf162725 	if (ssid->ssid == NULL) {
6604126Szf162725 		wpa_printf(MSG_ERROR, "Invalid SSID '%s'.", line, value);
6614126Szf162725 		return (-1);
6624126Szf162725 	}
6634126Szf162725 	if (ssid->ssid_len > MAX_ESSID_LENGTH) {
6644126Szf162725 		free(ssid->ssid);
6654126Szf162725 		wpa_printf(MSG_ERROR, "Too long SSID '%s'.", line, value);
6664126Szf162725 		return (-1);
6674126Szf162725 	}
6684126Szf162725 	wpa_printf(MSG_MSGDUMP, "SSID: %s", ssid->ssid);
6694126Szf162725 	return (0);
6704126Szf162725 }
6714126Szf162725 
6724126Szf162725 static struct wpa_ssid *
wpa_config_read_network(struct wpa_supplicant * wpa_s)6734126Szf162725 wpa_config_read_network(struct wpa_supplicant *wpa_s)
6744126Szf162725 {
6754126Szf162725 	struct wpa_ssid *ssid;
6764126Szf162725 	char buf[MAX_ESSID_LENGTH + 1];
6774126Szf162725 	dladm_secobj_class_t cl;
6784126Szf162725 	uint8_t psk[MAX_PSK_LENGTH + 1];
6794126Szf162725 	uint_t key_len;
6804126Szf162725 
6814126Szf162725 	wpa_printf(MSG_MSGDUMP, "Start of a new network configration");
6824126Szf162725 
6834126Szf162725 	ssid = (struct wpa_ssid *)malloc(sizeof (*ssid));
6844126Szf162725 	if (ssid == NULL)
6854126Szf162725 		return (NULL);
6864126Szf162725 	(void) memset(ssid, 0, sizeof (*ssid));
6874126Szf162725 
6884126Szf162725 	/*
6894126Szf162725 	 * Set default supported values
6904126Szf162725 	 */
6914126Szf162725 	ssid->proto = WPA_PROTO_WPA | WPA_PROTO_RSN;
6924126Szf162725 	ssid->pairwise_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP;
6934126Szf162725 	ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP |
6944126Szf162725 	    WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40;
6954126Szf162725 	ssid->key_mgmt = WPA_KEY_MGMT_PSK; /* | WPA_KEY_MGMT_IEEE8021X; */
6964126Szf162725 
6974126Szf162725 	(void) memset(buf, 0, MAX_ESSID_LENGTH + 1);
6988453SAnurag.Maskey@Sun.COM 	wpa_s->driver->get_ssid(wpa_s->handle, wpa_s->linkid, (char *)buf);
6994126Szf162725 
7004126Szf162725 	(void) wpa_config_parse_ssid(ssid, 0, buf);
7014126Szf162725 
7024126Szf162725 	key_len = sizeof (psk);
7038453SAnurag.Maskey@Sun.COM 	(void) dladm_get_secobj(wpa_s->handle, (const char *)wpa_s->kname, &cl,
7048453SAnurag.Maskey@Sun.COM 	    psk, &key_len, DLADM_OPT_ACTIVE);
7054126Szf162725 	psk[key_len] = '\0';
7064126Szf162725 	ssid->passphrase = strdup((const char *)psk);
7074126Szf162725 
7084126Szf162725 	if (ssid->passphrase) {
7094126Szf162725 		pbkdf2_sha1(ssid->passphrase, (char *)ssid->ssid,
7104126Szf162725 		    ssid->ssid_len, 4096, ssid->psk, PMK_LEN);
7114126Szf162725 		wpa_hexdump(MSG_MSGDUMP, "PSK (from passphrase)",
7124126Szf162725 		    ssid->psk, PMK_LEN);
7134126Szf162725 		ssid->psk_set = 1;
7144126Szf162725 	}
7154126Szf162725 
7164126Szf162725 	if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) {
7174126Szf162725 		wpa_printf(MSG_ERROR, "WPA-PSK accepted for key "
7184126Szf162725 		    "management, but no PSK configured.");
7194126Szf162725 		free(ssid);
7204126Szf162725 		ssid = NULL;
7214126Szf162725 	}
7224126Szf162725 
7234126Szf162725 	return (ssid);
7244126Szf162725 }
7254126Szf162725 
7264126Szf162725 struct wpa_config *
wpa_config_read(void * arg)7274126Szf162725 wpa_config_read(void *arg)
7284126Szf162725 {
7294126Szf162725 	struct wpa_ssid *ssid;
7304126Szf162725 	struct wpa_config *config;
7314126Szf162725 	struct wpa_supplicant *wpa_s = arg;
7324126Szf162725 
7334126Szf162725 	config = malloc(sizeof (*config));
7344126Szf162725 	if (config == NULL)
7354126Szf162725 		return (NULL);
7364126Szf162725 	(void) memset(config, 0, sizeof (*config));
7374126Szf162725 	config->eapol_version = 1;	/* fixed value */
7384126Szf162725 
7394126Szf162725 	wpa_printf(MSG_DEBUG, "Reading configuration parameters from driver\n");
7404126Szf162725 
7414126Szf162725 	ssid = wpa_config_read_network(wpa_s);
7424126Szf162725 	if (ssid == NULL) {
7434126Szf162725 		wpa_config_free(config);
7444126Szf162725 		config = NULL;
7454126Szf162725 	} else {
7464126Szf162725 		config->ssid = ssid;
7474126Szf162725 	}
7484126Szf162725 
7494126Szf162725 	return (config);
7504126Szf162725 }
7514126Szf162725 
7524126Szf162725 void
wpa_config_free(struct wpa_config * config)7534126Szf162725 wpa_config_free(struct wpa_config *config)
7544126Szf162725 {
7554126Szf162725 	struct wpa_ssid *ssid = config->ssid;
7564126Szf162725 
7575895Syz147064 	if (ssid != NULL) {
7585895Syz147064 		free(ssid->ssid);
7595895Syz147064 		free(ssid->passphrase);
7605895Syz147064 		free(ssid);
7615895Syz147064 	}
7624126Szf162725 	free(config);
7634126Szf162725 }
7644126Szf162725 
7656411Szf162725 /*
7666411Szf162725  * make sure wpad is running under SMF context.
7676411Szf162725  */
7686411Szf162725 static boolean_t
is_smf_context(void)7696411Szf162725 is_smf_context(void)
7704126Szf162725 {
7716411Szf162725 	char *fmri;
7726411Szf162725 
7736411Szf162725 	return (((fmri = getenv("SMF_FMRI")) != NULL) &&
7746411Szf162725 	    (strstr(fmri, SERVICE_NAME) != NULL));
7754126Szf162725 }
7764126Szf162725 
7774126Szf162725 int
main(int argc,char * argv[])7784126Szf162725 main(int argc, char *argv[])
7794126Szf162725 {
7804126Szf162725 	struct wpa_supplicant wpa_s;
7814126Szf162725 	char *link = NULL;
7824126Szf162725 	char *key = NULL;
7835895Syz147064 	dlpi_handle_t dh = NULL;
7845895Syz147064 	datalink_id_t linkid;
7855895Syz147064 	dladm_phys_attr_t dpa;
7864126Szf162725 	int c;
7874126Szf162725 	int exitcode;
7886411Szf162725 	char door_file[MAXPATHLEN];
7898453SAnurag.Maskey@Sun.COM 	dladm_handle_t handle;
7906411Szf162725 
7916411Szf162725 	if (!is_smf_context()) {
7926411Szf162725 		(void) fprintf(stderr,
7936411Szf162725 		    "wpad is an smf(5) managed service and cannot be run from "
7946411Szf162725 		    "the command line; please use dladm(1M).\n");
7956411Szf162725 		return (SMF_EXIT_ERR_NOSMF);
7966411Szf162725 	}
7974126Szf162725 
7984126Szf162725 	for (;;) {
7996411Szf162725 		c = getopt(argc, argv, "i:k:");
8004126Szf162725 		if (c < 0)
8014126Szf162725 			break;
8024126Szf162725 		switch (c) {
8034126Szf162725 		case 'i':
8044126Szf162725 			link = optarg;
8054126Szf162725 			break;
8064126Szf162725 		case 'k':
8074126Szf162725 			key = optarg;
8084126Szf162725 			break;
8094126Szf162725 		default:
8106411Szf162725 			return (SMF_EXIT_ERR_CONFIG);
8114126Szf162725 		}
8124126Szf162725 	}
8134126Szf162725 
8144126Szf162725 	/*
8154126Szf162725 	 * key name is required to retrieve PSK value through libwdladm APIs.
8164126Szf162725 	 * key is saved by dladm command by keyname
8174126Szf162725 	 * see dladm.
8184126Szf162725 	 */
8194126Szf162725 	if ((link == NULL) || (key == NULL)) {
8204126Szf162725 		wpa_printf(MSG_ERROR, "\nLink & key is required.");
8214126Szf162725 		return (-1);
8224126Szf162725 	}
8234126Szf162725 
8245895Syz147064 	if ((strlen(key) >= sizeof (wpa_s.kname)))  {
8255895Syz147064 		wpa_printf(MSG_ERROR, "Too long key name '%s'.", key);
8265895Syz147064 		return (-1);
8275895Syz147064 	}
8285895Syz147064 
8295895Syz147064 	if (daemon(0, 0))
8305895Syz147064 		return (-1);
8315895Syz147064 
8325895Syz147064 	/*
8335895Syz147064 	 * Hold this link open to prevent a link renaming operation.
8345895Syz147064 	 */
8355895Syz147064 	if (dlpi_open(link, &dh, 0) != DLPI_SUCCESS) {
8365895Syz147064 		wpa_printf(MSG_ERROR, "Failed to open link '%s'.", link);
8374126Szf162725 		return (-1);
8384126Szf162725 	}
8394126Szf162725 
8408453SAnurag.Maskey@Sun.COM 	/* This handle is stored in wpa_s when that struct is filled. */
8418453SAnurag.Maskey@Sun.COM 	if (dladm_open(&handle) != DLADM_STATUS_OK) {
8428453SAnurag.Maskey@Sun.COM 		wpa_printf(MSG_ERROR, "Failed to open dladm handle");
8438453SAnurag.Maskey@Sun.COM 		dlpi_close(dh);
8448453SAnurag.Maskey@Sun.COM 		return (-1);
8458453SAnurag.Maskey@Sun.COM 	}
8468453SAnurag.Maskey@Sun.COM 
8478453SAnurag.Maskey@Sun.COM 	if (dladm_name2info(handle, link, &linkid, NULL, NULL, NULL) !=
8485895Syz147064 	    DLADM_STATUS_OK) {
8495895Syz147064 		wpa_printf(MSG_ERROR, "Invalid link name '%s'.", link);
8508453SAnurag.Maskey@Sun.COM 		dladm_close(handle);
8515895Syz147064 		dlpi_close(dh);
8525895Syz147064 		return (-1);
8535895Syz147064 	}
8544126Szf162725 
8554126Szf162725 	/*
8565895Syz147064 	 * Get the device name of the link, which will be used as the door
8575895Syz147064 	 * file name used to communicate with the driver. Note that different
8585895Syz147064 	 * links use different doors.
8594126Szf162725 	 */
8608453SAnurag.Maskey@Sun.COM 	if (dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_ACTIVE) !=
8615895Syz147064 	    DLADM_STATUS_OK) {
8625895Syz147064 		wpa_printf(MSG_ERROR,
8635895Syz147064 		    "Failed to get device name of link '%s'.", link);
8648453SAnurag.Maskey@Sun.COM 		dladm_close(handle);
8655895Syz147064 		dlpi_close(dh);
8665895Syz147064 		return (-1);
8675895Syz147064 	}
8686411Szf162725 	(void) snprintf(door_file, MAXPATHLEN, "%s_%s", WPA_DOOR, dpa.dp_dev);
8695895Syz147064 
8705895Syz147064 	(void) memset(&wpa_s, 0, sizeof (wpa_s));
8715895Syz147064 	wpa_s.driver = &wpa_driver_wifi_ops;
8728453SAnurag.Maskey@Sun.COM 	wpa_s.handle = handle;
8735895Syz147064 	wpa_s.linkid = linkid;
8745895Syz147064 	(void) strlcpy(wpa_s.kname, key, sizeof (wpa_s.kname));
8755895Syz147064 	eloop_init(&wpa_s);
8764126Szf162725 
8774126Szf162725 	/*
8784126Szf162725 	 * Setup default WPA/WPA2 configuration
8794126Szf162725 	 * get ESSID and PSK value
8804126Szf162725 	 */
8814126Szf162725 	wpa_s.conf = wpa_config_read(&wpa_s);
8824126Szf162725 	if (wpa_s.conf == NULL || wpa_s.conf->ssid == NULL) {
8834126Szf162725 		wpa_printf(MSG_ERROR, "\nNo networks (SSID) configured.\n");
8845895Syz147064 		exitcode = -1;
8855895Syz147064 		goto cleanup;
8864126Szf162725 	}
8874126Szf162725 
8884126Szf162725 	exitcode = 0;
8894126Szf162725 
8905895Syz147064 	/*
8915895Syz147064 	 * Setup door file to communicate with driver
8925895Syz147064 	 */
8934126Szf162725 	if (wpa_supplicant_door_setup(&wpa_s, door_file) != 0) {
8944126Szf162725 		wpa_printf(MSG_ERROR, "Failed to setup door(%s)", door_file);
8954126Szf162725 		exitcode = -1;
8964126Szf162725 		goto cleanup;
8974126Szf162725 	}
8984126Szf162725 
8994126Szf162725 	wpa_s.renew_snonce = 1;
9005895Syz147064 	if (wpa_supplicant_driver_init(link, &wpa_s) < 0) {
9014126Szf162725 		exitcode = -1;
9024126Szf162725 		goto cleanup;
9034126Szf162725 	}
9044126Szf162725 
9055895Syz147064 	/*
9065895Syz147064 	 * This link is hold again in wpa_supplicant_driver_init(), so that
9075895Syz147064 	 * we release the first reference.
9085895Syz147064 	 */
9095895Syz147064 	dlpi_close(dh);
9105895Syz147064 	dh = NULL;
9115895Syz147064 
9124126Szf162725 	wpa_printf(MSG_DEBUG, "=> eloop_run");
9134126Szf162725 
9144126Szf162725 	(void) eloop_register_signal(SIGINT, wpa_supplicant_terminate, NULL);
9154126Szf162725 	(void) eloop_register_signal(SIGTERM, wpa_supplicant_terminate, NULL);
9164126Szf162725 	(void) eloop_register_signal(SIGKILL, wpa_supplicant_terminate, NULL);
9174126Szf162725 
9184126Szf162725 	eloop_run();
9194126Szf162725 
9204126Szf162725 	wpa_printf(MSG_DEBUG, "<= eloop_run()");
9214126Szf162725 	wpa_supplicant_disassociate(&wpa_s, REASON_DEAUTH_LEAVING);
9224126Szf162725 
9238453SAnurag.Maskey@Sun.COM 	if (wpa_s.driver->set_wpa(wpa_s.handle, wpa_s.linkid, 0) < 0) {
9244126Szf162725 		wpa_printf(MSG_ERROR, "Failed to disable WPA in the driver.\n");
9254126Szf162725 	}
9264126Szf162725 
9275895Syz147064 cleanup:
9284126Szf162725 	wpa_supplicant_door_destroy(door_file);
9298453SAnurag.Maskey@Sun.COM 	/* The libdladm handle is closed in the following method */
9304126Szf162725 	wpa_supplicant_cleanup(&wpa_s);
9314126Szf162725 	eloop_destroy();
9324126Szf162725 
9335895Syz147064 	if (dh != NULL)
9345895Syz147064 		dlpi_close(dh);
9355895Syz147064 
9364126Szf162725 	return (exitcode);
9374126Szf162725 }
938