16ba597c5SAnurag S. Maskey /*
26ba597c5SAnurag S. Maskey  * CDDL HEADER START
36ba597c5SAnurag S. Maskey  *
46ba597c5SAnurag S. Maskey  * The contents of this file are subject to the terms of the
56ba597c5SAnurag S. Maskey  * Common Development and Distribution License (the "License").
66ba597c5SAnurag S. Maskey  * You may not use this file except in compliance with the License.
76ba597c5SAnurag S. Maskey  *
86ba597c5SAnurag S. Maskey  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96ba597c5SAnurag S. Maskey  * or http://www.opensolaris.org/os/licensing.
106ba597c5SAnurag S. Maskey  * See the License for the specific language governing permissions
116ba597c5SAnurag S. Maskey  * and limitations under the License.
126ba597c5SAnurag S. Maskey  *
136ba597c5SAnurag S. Maskey  * When distributing Covered Code, include this CDDL HEADER in each
146ba597c5SAnurag S. Maskey  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156ba597c5SAnurag S. Maskey  * If applicable, add the following below this CDDL HEADER, with the
166ba597c5SAnurag S. Maskey  * fields enclosed by brackets "[]" replaced with your own identifying
176ba597c5SAnurag S. Maskey  * information: Portions Copyright [yyyy] [name of copyright owner]
186ba597c5SAnurag S. Maskey  *
196ba597c5SAnurag S. Maskey  * CDDL HEADER END
206ba597c5SAnurag S. Maskey  */
216ba597c5SAnurag S. Maskey 
226ba597c5SAnurag S. Maskey /*
23*f6da83d4SAnurag S. Maskey  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
246ba597c5SAnurag S. Maskey  */
256ba597c5SAnurag S. Maskey 
266ba597c5SAnurag S. Maskey #include <ctype.h>
276ba597c5SAnurag S. Maskey #include <errno.h>
286ba597c5SAnurag S. Maskey #include <limits.h>
296ba597c5SAnurag S. Maskey #include <stdio.h>
306ba597c5SAnurag S. Maskey #include <stdlib.h>
316ba597c5SAnurag S. Maskey #include <string.h>
326ba597c5SAnurag S. Maskey #include <libdladm.h>
336ba597c5SAnurag S. Maskey #include <libdllink.h>
346ba597c5SAnurag S. Maskey #include <libdlwlan.h>
356ba597c5SAnurag S. Maskey #include <libgen.h>
366ba597c5SAnurag S. Maskey #include <libnwam.h>
376ba597c5SAnurag S. Maskey 
386ba597c5SAnurag S. Maskey #include "events.h"
396ba597c5SAnurag S. Maskey #include "known_wlans.h"
406ba597c5SAnurag S. Maskey #include "ncu.h"
416ba597c5SAnurag S. Maskey #include "objects.h"
426ba597c5SAnurag S. Maskey #include "util.h"
436ba597c5SAnurag S. Maskey 
446ba597c5SAnurag S. Maskey /*
456ba597c5SAnurag S. Maskey  * known_wlans.c - contains routines which handle the known WLAN abstraction.
466ba597c5SAnurag S. Maskey  */
476ba597c5SAnurag S. Maskey 
486ba597c5SAnurag S. Maskey #define	KNOWN_WIFI_NETS_FILE		"/etc/nwam/known_wifi_nets"
496ba597c5SAnurag S. Maskey 
506ba597c5SAnurag S. Maskey /* enum for parsing each line of /etc/nwam/known_wifi_nets */
516ba597c5SAnurag S. Maskey typedef enum {
526ba597c5SAnurag S. Maskey 	ESSID = 0,
536ba597c5SAnurag S. Maskey 	BSSID,
546ba597c5SAnurag S. Maskey 	MAX_FIELDS
556ba597c5SAnurag S. Maskey } known_wifi_nets_fields_t;
566ba597c5SAnurag S. Maskey 
576ba597c5SAnurag S. Maskey /* Structure for one BSSID */
586ba597c5SAnurag S. Maskey typedef struct bssid {
596ba597c5SAnurag S. Maskey 	struct qelem	bssid_links;
606ba597c5SAnurag S. Maskey 	char		*bssid;
616ba597c5SAnurag S. Maskey } bssid_t;
626ba597c5SAnurag S. Maskey 
636ba597c5SAnurag S. Maskey /* Structure for an ESSID and its BSSIDs */
646ba597c5SAnurag S. Maskey typedef struct kw {
656ba597c5SAnurag S. Maskey 	struct qelem	kw_links;
666ba597c5SAnurag S. Maskey 	char		kw_essid[NWAM_MAX_NAME_LEN];
676ba597c5SAnurag S. Maskey 	uint32_t	kw_num_bssids;
686ba597c5SAnurag S. Maskey 	struct qelem	kw_bssids;
696ba597c5SAnurag S. Maskey } kw_t;
706ba597c5SAnurag S. Maskey 
716ba597c5SAnurag S. Maskey /* Holds the linked-list of ESSIDs to make Known WLANs out of */
726ba597c5SAnurag S. Maskey static struct qelem kw_list;
736ba597c5SAnurag S. Maskey 
746ba597c5SAnurag S. Maskey /* Used in walking secobjs looking for an ESSID prefix match. */
756ba597c5SAnurag S. Maskey struct nwamd_secobj_arg {
766ba597c5SAnurag S. Maskey 	char nsa_essid_prefix[DLADM_WLAN_MAX_KEYNAME_LEN];
776ba597c5SAnurag S. Maskey 	char nsa_keyname[DLADM_WLAN_MAX_KEYNAME_LEN];
786ba597c5SAnurag S. Maskey 	dladm_wlan_key_t *nsa_key;
796ba597c5SAnurag S. Maskey 	uint64_t nsa_secmode;
806ba597c5SAnurag S. Maskey };
816ba597c5SAnurag S. Maskey 
826ba597c5SAnurag S. Maskey static void
kw_list_init(void)836ba597c5SAnurag S. Maskey kw_list_init(void)
846ba597c5SAnurag S. Maskey {
856ba597c5SAnurag S. Maskey 	kw_list.q_forw = kw_list.q_back = &kw_list;
866ba597c5SAnurag S. Maskey }
876ba597c5SAnurag S. Maskey 
886ba597c5SAnurag S. Maskey static void
kw_list_free(void)896ba597c5SAnurag S. Maskey kw_list_free(void)
906ba597c5SAnurag S. Maskey {
916ba597c5SAnurag S. Maskey 	kw_t *kw;
926ba597c5SAnurag S. Maskey 	bssid_t *b;
936ba597c5SAnurag S. Maskey 
946ba597c5SAnurag S. Maskey 	while (kw_list.q_forw != &kw_list) {
956ba597c5SAnurag S. Maskey 		kw = (kw_t *)kw_list.q_forw;
966ba597c5SAnurag S. Maskey 
976ba597c5SAnurag S. Maskey 		/* free kw_bssids */
986ba597c5SAnurag S. Maskey 		while (kw->kw_bssids.q_forw != &kw->kw_bssids) {
996ba597c5SAnurag S. Maskey 			b = (bssid_t *)kw->kw_bssids.q_forw;
1006ba597c5SAnurag S. Maskey 			remque(&b->bssid_links);
1016ba597c5SAnurag S. Maskey 			free(b->bssid);
1026ba597c5SAnurag S. Maskey 			free(b);
1036ba597c5SAnurag S. Maskey 		}
1046ba597c5SAnurag S. Maskey 		remque(&kw->kw_links);
1056ba597c5SAnurag S. Maskey 		free(kw);
1066ba597c5SAnurag S. Maskey 	}
1076ba597c5SAnurag S. Maskey }
1086ba597c5SAnurag S. Maskey 
1096ba597c5SAnurag S. Maskey /* Returns the entry in kw_list for the given ESSID.  NULL if non-existent */
1106ba597c5SAnurag S. Maskey static kw_t *
kw_lookup(const char * essid)1116ba597c5SAnurag S. Maskey kw_lookup(const char *essid)
1126ba597c5SAnurag S. Maskey {
1136ba597c5SAnurag S. Maskey 	kw_t *kw;
1146ba597c5SAnurag S. Maskey 
1156ba597c5SAnurag S. Maskey 	if (essid == NULL)
1166ba597c5SAnurag S. Maskey 		return (NULL);
1176ba597c5SAnurag S. Maskey 
1186ba597c5SAnurag S. Maskey 	for (kw = (kw_t *)kw_list.q_forw;
1196ba597c5SAnurag S. Maskey 	    kw != (kw_t *)&kw_list;
1206ba597c5SAnurag S. Maskey 	    kw = (kw_t *)kw->kw_links.q_forw) {
1216ba597c5SAnurag S. Maskey 		if (strcmp(essid, kw->kw_essid) == 0)
1226ba597c5SAnurag S. Maskey 			return (kw);
1236ba597c5SAnurag S. Maskey 	}
1246ba597c5SAnurag S. Maskey 	return (NULL);
1256ba597c5SAnurag S. Maskey }
1266ba597c5SAnurag S. Maskey 
1276ba597c5SAnurag S. Maskey /* Adds an ESSID/BSSID combination to kw_list.  Returns B_TRUE on success. */
1286ba597c5SAnurag S. Maskey static boolean_t
kw_add(const char * essid,const char * bssid)1296ba597c5SAnurag S. Maskey kw_add(const char *essid, const char *bssid)
1306ba597c5SAnurag S. Maskey {
1316ba597c5SAnurag S. Maskey 	kw_t *kw;
1326ba597c5SAnurag S. Maskey 	bssid_t *b;
1336ba597c5SAnurag S. Maskey 
1346ba597c5SAnurag S. Maskey 	if ((b = calloc(1, sizeof (bssid_t))) == NULL) {
1356ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "kw_add: cannot allocate for bssid_t: %m");
1366ba597c5SAnurag S. Maskey 		return (B_FALSE);
1376ba597c5SAnurag S. Maskey 	}
1386ba597c5SAnurag S. Maskey 	if ((kw = calloc(1, sizeof (kw_t))) == NULL) {
1396ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "kw_add: cannot allocate for kw_t: %m");
1406ba597c5SAnurag S. Maskey 		free(b);
1416ba597c5SAnurag S. Maskey 		return (B_FALSE);
1426ba597c5SAnurag S. Maskey 	}
1436ba597c5SAnurag S. Maskey 	kw->kw_bssids.q_forw = kw->kw_bssids.q_back = &kw->kw_bssids;
1446ba597c5SAnurag S. Maskey 
1456ba597c5SAnurag S. Maskey 	b->bssid = strdup(bssid);
1466ba597c5SAnurag S. Maskey 	(void) strlcpy(kw->kw_essid, essid, sizeof (kw->kw_essid));
1476ba597c5SAnurag S. Maskey 	kw->kw_num_bssids = 1;
1486ba597c5SAnurag S. Maskey 
1496ba597c5SAnurag S. Maskey 	insque(&b->bssid_links, kw->kw_bssids.q_back);
1506ba597c5SAnurag S. Maskey 	insque(&kw->kw_links, kw_list.q_back);
1516ba597c5SAnurag S. Maskey 
1526ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "kw_add: added Known WLAN %s, BSSID %s", essid, bssid);
1536ba597c5SAnurag S. Maskey 	return (B_TRUE);
1546ba597c5SAnurag S. Maskey }
1556ba597c5SAnurag S. Maskey 
1566ba597c5SAnurag S. Maskey /*
1576ba597c5SAnurag S. Maskey  * Add the BSSID to the given kw.  Since /etc/nwam/known_wifi_nets is
1586ba597c5SAnurag S. Maskey  * populated such that the wifi networks visited later are towards the end
1596ba597c5SAnurag S. Maskey  * of the file, remove the give kw from its current position and append it
1606ba597c5SAnurag S. Maskey  * to the end of kw_list.  This ensures that kw_list is in the reverse
1616ba597c5SAnurag S. Maskey  * order of visited wifi networks.  Returns B_TRUE on success.
1626ba597c5SAnurag S. Maskey  */
1636ba597c5SAnurag S. Maskey static boolean_t
kw_update(kw_t * kw,const char * bssid)1646ba597c5SAnurag S. Maskey kw_update(kw_t *kw, const char *bssid)
1656ba597c5SAnurag S. Maskey {
1666ba597c5SAnurag S. Maskey 	bssid_t *b;
1676ba597c5SAnurag S. Maskey 
1686ba597c5SAnurag S. Maskey 	if ((b = calloc(1, sizeof (bssid_t))) == NULL) {
1696ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "kw_update: cannot allocate for bssid_t: %m");
1706ba597c5SAnurag S. Maskey 		return (B_FALSE);
1716ba597c5SAnurag S. Maskey 	}
1726ba597c5SAnurag S. Maskey 
1736ba597c5SAnurag S. Maskey 	b->bssid = strdup(bssid);
1746ba597c5SAnurag S. Maskey 	insque(&b->bssid_links, kw->kw_bssids.q_back);
1756ba597c5SAnurag S. Maskey 	kw->kw_num_bssids++;
1766ba597c5SAnurag S. Maskey 
1776ba597c5SAnurag S. Maskey 	/* remove kw from current position */
1786ba597c5SAnurag S. Maskey 	remque(&kw->kw_links);
1796ba597c5SAnurag S. Maskey 	/* and insert at end */
1806ba597c5SAnurag S. Maskey 	insque(&kw->kw_links, kw_list.q_back);
1816ba597c5SAnurag S. Maskey 
1826ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "kw_update: appended BSSID %s to Known WLAN %s",
1836ba597c5SAnurag S. Maskey 	    bssid, kw->kw_essid);
1846ba597c5SAnurag S. Maskey 	return (B_TRUE);
1856ba597c5SAnurag S. Maskey }
1866ba597c5SAnurag S. Maskey 
1876ba597c5SAnurag S. Maskey /*
1886ba597c5SAnurag S. Maskey  * Parses /etc/nwam/known_wifi_nets and populates kw_list, with the oldest
1896ba597c5SAnurag S. Maskey  * wifi networks first in the list.  Returns the number of unique entries
1906ba597c5SAnurag S. Maskey  * in kw_list (to use for priority values).
1916ba597c5SAnurag S. Maskey  */
1926ba597c5SAnurag S. Maskey static int
parse_known_wifi_nets(void)1936ba597c5SAnurag S. Maskey parse_known_wifi_nets(void)
1946ba597c5SAnurag S. Maskey {
1956ba597c5SAnurag S. Maskey 	FILE *fp;
1966ba597c5SAnurag S. Maskey 	char line[LINE_MAX];
1976ba597c5SAnurag S. Maskey 	char *cp, *tok[MAX_FIELDS];
1986ba597c5SAnurag S. Maskey 	int lnum, num_kw = 0;
1996ba597c5SAnurag S. Maskey 	kw_t *kw;
2006ba597c5SAnurag S. Maskey 
2016ba597c5SAnurag S. Maskey 	kw_list_init();
2026ba597c5SAnurag S. Maskey 
2036ba597c5SAnurag S. Maskey 	/*
2046ba597c5SAnurag S. Maskey 	 * The file format is:
2056ba597c5SAnurag S. Maskey 	 * essid\tbssid (essid followed by tab followed by bssid)
2066ba597c5SAnurag S. Maskey 	 */
2076ba597c5SAnurag S. Maskey 	fp = fopen(KNOWN_WIFI_NETS_FILE, "r");
2086ba597c5SAnurag S. Maskey 	if (fp == NULL)
2096ba597c5SAnurag S. Maskey 		return (0);
2106ba597c5SAnurag S. Maskey 	for (lnum = 1; fgets(line, sizeof (line), fp) != NULL; lnum++) {
2116ba597c5SAnurag S. Maskey 
2126ba597c5SAnurag S. Maskey 		cp = line;
2136ba597c5SAnurag S. Maskey 		while (isspace(*cp))
2146ba597c5SAnurag S. Maskey 			cp++;
2156ba597c5SAnurag S. Maskey 		if (*cp == '#' || *cp == '\0')
2166ba597c5SAnurag S. Maskey 			continue;
2176ba597c5SAnurag S. Maskey 
2186ba597c5SAnurag S. Maskey 		if (bufsplit(cp, MAX_FIELDS, tok) != MAX_FIELDS) {
2196ba597c5SAnurag S. Maskey 			syslog(LOG_ERR, "%s:%d: wrong number of tokens; "
2206ba597c5SAnurag S. Maskey 			    "ignoring entry", KNOWN_WIFI_NETS_FILE, lnum);
2216ba597c5SAnurag S. Maskey 			continue;
2226ba597c5SAnurag S. Maskey 		}
2236ba597c5SAnurag S. Maskey 
2246ba597c5SAnurag S. Maskey 		if ((kw = kw_lookup(tok[ESSID])) == NULL) {
2256ba597c5SAnurag S. Maskey 			if (!kw_add(tok[ESSID], tok[BSSID])) {
2266ba597c5SAnurag S. Maskey 				nlog(LOG_ERR,
2276ba597c5SAnurag S. Maskey 				    "%s:%d: cannot add entry (%s,%s) to list",
2286ba597c5SAnurag S. Maskey 				    KNOWN_WIFI_NETS_FILE, lnum,
2296ba597c5SAnurag S. Maskey 				    tok[ESSID], tok[BSSID]);
2306ba597c5SAnurag S. Maskey 			} else {
2316ba597c5SAnurag S. Maskey 				num_kw++;
2326ba597c5SAnurag S. Maskey 			}
2336ba597c5SAnurag S. Maskey 		} else {
2346ba597c5SAnurag S. Maskey 			if (!kw_update(kw, tok[BSSID])) {
2356ba597c5SAnurag S. Maskey 				nlog(LOG_ERR,
2366ba597c5SAnurag S. Maskey 				    "%s:%d:cannot update entry (%s,%s) to list",
2376ba597c5SAnurag S. Maskey 				    KNOWN_WIFI_NETS_FILE, lnum,
2386ba597c5SAnurag S. Maskey 				    tok[ESSID], tok[BSSID]);
2396ba597c5SAnurag S. Maskey 			}
2406ba597c5SAnurag S. Maskey 		}
2416ba597c5SAnurag S. Maskey 		/* next line ... */
2426ba597c5SAnurag S. Maskey 	}
2436ba597c5SAnurag S. Maskey 
2446ba597c5SAnurag S. Maskey 	(void) fclose(fp);
2456ba597c5SAnurag S. Maskey 	return (num_kw);
2466ba597c5SAnurag S. Maskey }
2476ba597c5SAnurag S. Maskey 
2486ba597c5SAnurag S. Maskey /*
2496ba597c5SAnurag S. Maskey  * Walk security objects looking for one that matches the essid prefix.
2506ba597c5SAnurag S. Maskey  * Store the key and keyname if a match is found - we use the last match
2516ba597c5SAnurag S. Maskey  * as the key for the known WLAN, since it is the most recently updated.
2526ba597c5SAnurag S. Maskey  */
2536ba597c5SAnurag S. Maskey /* ARGSUSED0 */
2546ba597c5SAnurag S. Maskey static boolean_t
find_secobj_matching_prefix(dladm_handle_t dh,void * arg,const char * secobjname)2556ba597c5SAnurag S. Maskey find_secobj_matching_prefix(dladm_handle_t dh, void *arg,
2566ba597c5SAnurag S. Maskey     const char *secobjname)
2576ba597c5SAnurag S. Maskey {
2586ba597c5SAnurag S. Maskey 	struct nwamd_secobj_arg *nsa = arg;
2596ba597c5SAnurag S. Maskey 
2606ba597c5SAnurag S. Maskey 	if (strncmp(nsa->nsa_essid_prefix, secobjname,
2616ba597c5SAnurag S. Maskey 	    strlen(nsa->nsa_essid_prefix)) == 0) {
2626ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "find_secobj_matching_prefix: "
2636ba597c5SAnurag S. Maskey 		    "found secobj with prefix %s : %s\n",
2646ba597c5SAnurag S. Maskey 		    nsa->nsa_essid_prefix, secobjname);
2656ba597c5SAnurag S. Maskey 		/* Free last key found (if any) */
2666ba597c5SAnurag S. Maskey 		if (nsa->nsa_key != NULL)
2676ba597c5SAnurag S. Maskey 			free(nsa->nsa_key);
2686ba597c5SAnurag S. Maskey 		/* Retrive key so we can get security mode */
2696ba597c5SAnurag S. Maskey 		nsa->nsa_key = nwamd_wlan_get_key_named(secobjname, 0);
2706ba597c5SAnurag S. Maskey 		(void) strlcpy(nsa->nsa_keyname, secobjname,
2716ba597c5SAnurag S. Maskey 		    sizeof (nsa->nsa_keyname));
2726ba597c5SAnurag S. Maskey 		switch (nsa->nsa_key->wk_class) {
2736ba597c5SAnurag S. Maskey 		case DLADM_SECOBJ_CLASS_WEP:
2746ba597c5SAnurag S. Maskey 			nsa->nsa_secmode = DLADM_WLAN_SECMODE_WEP;
2756ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "find_secobj_matching_prefix: "
2766ba597c5SAnurag S. Maskey 			    "got WEP key %s", nsa->nsa_keyname);
2776ba597c5SAnurag S. Maskey 			break;
2786ba597c5SAnurag S. Maskey 		case DLADM_SECOBJ_CLASS_WPA:
2796ba597c5SAnurag S. Maskey 			nsa->nsa_secmode = DLADM_WLAN_SECMODE_WPA;
2806ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "find_secobj_matching_prefix: "
2816ba597c5SAnurag S. Maskey 			    "got WPA key %s", nsa->nsa_keyname);
2826ba597c5SAnurag S. Maskey 			break;
2836ba597c5SAnurag S. Maskey 		default:
2846ba597c5SAnurag S. Maskey 			/* shouldn't happen */
2856ba597c5SAnurag S. Maskey 			nsa->nsa_secmode = DLADM_WLAN_SECMODE_NONE;
2866ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "find_secobj_matching_prefix: "
2876ba597c5SAnurag S. Maskey 			    "key class for key %s was invalid",
2886ba597c5SAnurag S. Maskey 			    nsa->nsa_keyname);
2896ba597c5SAnurag S. Maskey 			break;
2906ba597c5SAnurag S. Maskey 		}
2916ba597c5SAnurag S. Maskey 	}
2926ba597c5SAnurag S. Maskey 	return (B_TRUE);
2936ba597c5SAnurag S. Maskey }
2946ba597c5SAnurag S. Maskey 
2956ba597c5SAnurag S. Maskey 
2966ba597c5SAnurag S. Maskey /* Upgrade /etc/nwam/known_wifi_nets file to new libnwam-based config model */
2976ba597c5SAnurag S. Maskey void
upgrade_known_wifi_nets_config(void)2986ba597c5SAnurag S. Maskey upgrade_known_wifi_nets_config(void)
2996ba597c5SAnurag S. Maskey {
3006ba597c5SAnurag S. Maskey 	kw_t *kw;
3016ba597c5SAnurag S. Maskey 	bssid_t *b;
3026ba597c5SAnurag S. Maskey 	nwam_known_wlan_handle_t kwh;
3036ba597c5SAnurag S. Maskey 	char **bssids;
3046ba597c5SAnurag S. Maskey 	nwam_error_t err;
3056ba597c5SAnurag S. Maskey 	uint64_t priority;
3066ba597c5SAnurag S. Maskey 	int i, num_kw;
3076ba597c5SAnurag S. Maskey 	struct nwamd_secobj_arg nsa;
3086ba597c5SAnurag S. Maskey 
3096ba597c5SAnurag S. Maskey 	nlog(LOG_INFO, "Upgrading %s to Known WLANs", KNOWN_WIFI_NETS_FILE);
3106ba597c5SAnurag S. Maskey 
3116ba597c5SAnurag S. Maskey 	/* Parse /etc/nwam/known_wifi_nets */
3126ba597c5SAnurag S. Maskey 	num_kw = parse_known_wifi_nets();
3136ba597c5SAnurag S. Maskey 
3146ba597c5SAnurag S. Maskey 	/* Create Known WLANs for each unique ESSID */
3156ba597c5SAnurag S. Maskey 	for (kw = (kw_t *)kw_list.q_forw, priority = num_kw-1;
3166ba597c5SAnurag S. Maskey 	    kw != (kw_t *)&kw_list;
3176ba597c5SAnurag S. Maskey 	    kw = (kw_t *)kw->kw_links.q_forw, priority--) {
3186ba597c5SAnurag S. Maskey 		nwam_value_t priorityval = NULL;
3196ba597c5SAnurag S. Maskey 		nwam_value_t bssidsval = NULL;
3206ba597c5SAnurag S. Maskey 		nwam_value_t secmodeval = NULL;
3216ba597c5SAnurag S. Maskey 		nwam_value_t keynameval = NULL;
3226ba597c5SAnurag S. Maskey 
3236ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "Creating Known WLAN %s", kw->kw_essid);
3246ba597c5SAnurag S. Maskey 
3256ba597c5SAnurag S. Maskey 		if ((err = nwam_known_wlan_create(kw->kw_essid, &kwh))
3266ba597c5SAnurag S. Maskey 		    != NWAM_SUCCESS) {
3276ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "upgrade wlan %s: "
3286ba597c5SAnurag S. Maskey 			    "could not create known wlan: %s", kw->kw_essid,
3296ba597c5SAnurag S. Maskey 			    nwam_strerror(err));
3306ba597c5SAnurag S. Maskey 			continue;
3316ba597c5SAnurag S. Maskey 		}
3326ba597c5SAnurag S. Maskey 
3336ba597c5SAnurag S. Maskey 		/* priority of this ESSID */
3346ba597c5SAnurag S. Maskey 		if ((err = nwam_value_create_uint64(priority, &priorityval))
3356ba597c5SAnurag S. Maskey 		    != NWAM_SUCCESS) {
3366ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "upgrade wlan %s: "
3376ba597c5SAnurag S. Maskey 			    "could not create priority value: %s", kw->kw_essid,
3386ba597c5SAnurag S. Maskey 			    nwam_strerror(err));
3396ba597c5SAnurag S. Maskey 			nwam_known_wlan_free(kwh);
3406ba597c5SAnurag S. Maskey 			continue;
3416ba597c5SAnurag S. Maskey 		}
3426ba597c5SAnurag S. Maskey 		err = nwam_known_wlan_set_prop_value(kwh,
3436ba597c5SAnurag S. Maskey 		    NWAM_KNOWN_WLAN_PROP_PRIORITY, priorityval);
3446ba597c5SAnurag S. Maskey 		nwam_value_free(priorityval);
3456ba597c5SAnurag S. Maskey 		if (err != NWAM_SUCCESS) {
3466ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "upgrade wlan %s: "
3476ba597c5SAnurag S. Maskey 			    "could not set priority value: %s", kw->kw_essid,
3486ba597c5SAnurag S. Maskey 			    nwam_strerror(err));
3496ba597c5SAnurag S. Maskey 			nwam_known_wlan_free(kwh);
3506ba597c5SAnurag S. Maskey 			continue;
3516ba597c5SAnurag S. Maskey 		}
3526ba597c5SAnurag S. Maskey 
3536ba597c5SAnurag S. Maskey 		/* loop through kw->kw_bssids and create an array of bssids */
3546ba597c5SAnurag S. Maskey 		bssids = calloc(kw->kw_num_bssids, sizeof (char *));
3556ba597c5SAnurag S. Maskey 		if (bssids == NULL) {
3566ba597c5SAnurag S. Maskey 			nwam_known_wlan_free(kwh);
3576ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "upgrade wlan %s: "
3586ba597c5SAnurag S. Maskey 			    "could not calloc for bssids: %m", kw->kw_essid);
3596ba597c5SAnurag S. Maskey 			continue;
3606ba597c5SAnurag S. Maskey 		}
3616ba597c5SAnurag S. Maskey 		for (b = (bssid_t *)kw->kw_bssids.q_forw, i = 0;
3626ba597c5SAnurag S. Maskey 		    b != (bssid_t *)&kw->kw_bssids;
3636ba597c5SAnurag S. Maskey 		    b = (bssid_t *)b->bssid_links.q_forw, i++) {
3646ba597c5SAnurag S. Maskey 			bssids[i] = strdup(b->bssid);
3656ba597c5SAnurag S. Maskey 		}
3666ba597c5SAnurag S. Maskey 
3676ba597c5SAnurag S. Maskey 		/* BSSIDs for this ESSID */
3686ba597c5SAnurag S. Maskey 		if ((err = nwam_value_create_string_array(bssids,
3696ba597c5SAnurag S. Maskey 		    kw->kw_num_bssids, &bssidsval)) != NWAM_SUCCESS) {
3706ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "upgrade wlan %s: "
3716ba597c5SAnurag S. Maskey 			    "could not create bssids value: %s", kw->kw_essid,
3726ba597c5SAnurag S. Maskey 			    nwam_strerror(err));
3736ba597c5SAnurag S. Maskey 			for (i = 0; i < kw->kw_num_bssids; i++)
3746ba597c5SAnurag S. Maskey 				free(bssids[i]);
3756ba597c5SAnurag S. Maskey 			free(bssids);
3766ba597c5SAnurag S. Maskey 			nwam_known_wlan_free(kwh);
3776ba597c5SAnurag S. Maskey 			continue;
3786ba597c5SAnurag S. Maskey 		}
3796ba597c5SAnurag S. Maskey 		err = nwam_known_wlan_set_prop_value(kwh,
3806ba597c5SAnurag S. Maskey 		    NWAM_KNOWN_WLAN_PROP_BSSIDS, bssidsval);
3816ba597c5SAnurag S. Maskey 		nwam_value_free(bssidsval);
3826ba597c5SAnurag S. Maskey 		for (i = 0; i < kw->kw_num_bssids; i++)
3836ba597c5SAnurag S. Maskey 			free(bssids[i]);
3846ba597c5SAnurag S. Maskey 		free(bssids);
3856ba597c5SAnurag S. Maskey 		if (err != NWAM_SUCCESS) {
3866ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "upgrade wlan %s: "
3876ba597c5SAnurag S. Maskey 			    "could not set bssids: %s", kw->kw_essid,
3886ba597c5SAnurag S. Maskey 			    nwam_strerror(err));
3896ba597c5SAnurag S. Maskey 			nwam_known_wlan_free(kwh);
3906ba597c5SAnurag S. Maskey 			continue;
3916ba597c5SAnurag S. Maskey 		}
3926ba597c5SAnurag S. Maskey 
3936ba597c5SAnurag S. Maskey 		/*
3946ba597c5SAnurag S. Maskey 		 * Retrieve last key matching ESSID prefix if any, and set
3956ba597c5SAnurag S. Maskey 		 * the retrieved key name and security mode.
3966ba597c5SAnurag S. Maskey 		 */
3976ba597c5SAnurag S. Maskey 		nwamd_set_key_name(kw->kw_essid, NULL, nsa.nsa_essid_prefix,
3986ba597c5SAnurag S. Maskey 		    sizeof (nsa.nsa_essid_prefix));
3996ba597c5SAnurag S. Maskey 		nsa.nsa_key = NULL;
4006ba597c5SAnurag S. Maskey 		nsa.nsa_secmode = DLADM_WLAN_SECMODE_NONE;
4016ba597c5SAnurag S. Maskey 		(void) dladm_walk_secobj(dld_handle, &nsa,
4026ba597c5SAnurag S. Maskey 		    find_secobj_matching_prefix, DLADM_OPT_PERSIST);
4036ba597c5SAnurag S. Maskey 		if (nsa.nsa_key != NULL) {
4046ba597c5SAnurag S. Maskey 			if ((err = nwam_value_create_string(nsa.nsa_keyname,
4056ba597c5SAnurag S. Maskey 			    &keynameval)) == NWAM_SUCCESS) {
4066ba597c5SAnurag S. Maskey 				(void) nwam_known_wlan_set_prop_value(kwh,
4076ba597c5SAnurag S. Maskey 				    NWAM_KNOWN_WLAN_PROP_KEYNAME, keynameval);
4086ba597c5SAnurag S. Maskey 			}
4096ba597c5SAnurag S. Maskey 			free(nsa.nsa_key);
4106ba597c5SAnurag S. Maskey 			nwam_value_free(keynameval);
4116ba597c5SAnurag S. Maskey 		}
4126ba597c5SAnurag S. Maskey 
4136ba597c5SAnurag S. Maskey 		if ((err = nwam_value_create_uint64(nsa.nsa_secmode,
4146ba597c5SAnurag S. Maskey 		    &secmodeval)) != NWAM_SUCCESS ||
4156ba597c5SAnurag S. Maskey 		    (err = nwam_known_wlan_set_prop_value(kwh,
4166ba597c5SAnurag S. Maskey 		    NWAM_KNOWN_WLAN_PROP_SECURITY_MODE, secmodeval))
4176ba597c5SAnurag S. Maskey 		    != NWAM_SUCCESS) {
4186ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "upgrade wlan %s: "
4196ba597c5SAnurag S. Maskey 			    "could not set security mode: %s",
4206ba597c5SAnurag S. Maskey 			    kw->kw_essid, nwam_strerror(err));
4216ba597c5SAnurag S. Maskey 			nwam_value_free(secmodeval);
4226ba597c5SAnurag S. Maskey 			nwam_known_wlan_free(kwh);
4236ba597c5SAnurag S. Maskey 			continue;
4246ba597c5SAnurag S. Maskey 		}
4256ba597c5SAnurag S. Maskey 
4266ba597c5SAnurag S. Maskey 		/* commit, no collision checking by libnwam */
4276ba597c5SAnurag S. Maskey 		err = nwam_known_wlan_commit(kwh,
4286ba597c5SAnurag S. Maskey 		    NWAM_FLAG_KNOWN_WLAN_NO_COLLISION_CHECK);
4296ba597c5SAnurag S. Maskey 		nwam_known_wlan_free(kwh);
4306ba597c5SAnurag S. Maskey 		if (err != NWAM_SUCCESS) {
4316ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "upgrade wlan %s: "
4326ba597c5SAnurag S. Maskey 			    "could not commit wlan: %s", kw->kw_essid,
4336ba597c5SAnurag S. Maskey 			    nwam_strerror(err));
4346ba597c5SAnurag S. Maskey 		}
4356ba597c5SAnurag S. Maskey 		/* next ... */
4366ba597c5SAnurag S. Maskey 	}
4376ba597c5SAnurag S. Maskey 
4386ba597c5SAnurag S. Maskey 	kw_list_free();
4396ba597c5SAnurag S. Maskey }
4406ba597c5SAnurag S. Maskey 
4416ba597c5SAnurag S. Maskey nwam_error_t
known_wlan_get_keyname(const char * essid,char * name)4426ba597c5SAnurag S. Maskey known_wlan_get_keyname(const char *essid, char *name)
4436ba597c5SAnurag S. Maskey {
4446ba597c5SAnurag S. Maskey 	nwam_known_wlan_handle_t kwh = NULL;
4456ba597c5SAnurag S. Maskey 	nwam_value_t keynameval = NULL;
4466ba597c5SAnurag S. Maskey 	char *keyname;
4476ba597c5SAnurag S. Maskey 	nwam_error_t err;
4486ba597c5SAnurag S. Maskey 
4496ba597c5SAnurag S. Maskey 	if ((err = nwam_known_wlan_read(essid, 0, &kwh)) != NWAM_SUCCESS)
4506ba597c5SAnurag S. Maskey 		return (err);
4516ba597c5SAnurag S. Maskey 	if ((err = nwam_known_wlan_get_prop_value(kwh,
4526ba597c5SAnurag S. Maskey 	    NWAM_KNOWN_WLAN_PROP_KEYNAME, &keynameval)) == NWAM_SUCCESS &&
4536ba597c5SAnurag S. Maskey 	    (err = nwam_value_get_string(keynameval, &keyname))
4546ba597c5SAnurag S. Maskey 	    == NWAM_SUCCESS) {
4556ba597c5SAnurag S. Maskey 		(void) strlcpy(name, keyname, NWAM_MAX_VALUE_LEN);
4566ba597c5SAnurag S. Maskey 	}
4576ba597c5SAnurag S. Maskey 	if (keynameval != NULL)
4586ba597c5SAnurag S. Maskey 		nwam_value_free(keynameval);
4596ba597c5SAnurag S. Maskey 
4606ba597c5SAnurag S. Maskey 	if (kwh != NULL)
4616ba597c5SAnurag S. Maskey 		nwam_known_wlan_free(kwh);
4626ba597c5SAnurag S. Maskey 
4636ba597c5SAnurag S. Maskey 	return (err);
4646ba597c5SAnurag S. Maskey }
4656ba597c5SAnurag S. Maskey 
4666ba597c5SAnurag S. Maskey /* Performs a scan on a wifi link NCU */
4676ba597c5SAnurag S. Maskey /* ARGSUSED */
4686ba597c5SAnurag S. Maskey static int
nwamd_ncu_known_wlan_committed(nwamd_object_t object,void * data)4696ba597c5SAnurag S. Maskey nwamd_ncu_known_wlan_committed(nwamd_object_t object, void *data)
4706ba597c5SAnurag S. Maskey {
4716ba597c5SAnurag S. Maskey 	nwamd_ncu_t *ncu_data = object->nwamd_object_data;
4726ba597c5SAnurag S. Maskey 
4736ba597c5SAnurag S. Maskey 	if (ncu_data->ncu_type != NWAM_NCU_TYPE_LINK)
4746ba597c5SAnurag S. Maskey 		return (0);
4756ba597c5SAnurag S. Maskey 
4766ba597c5SAnurag S. Maskey 	/* network selection will be done only if possible */
477*f6da83d4SAnurag S. Maskey 	if (ncu_data->ncu_link.nwamd_link_media == DL_WIFI)
4786ba597c5SAnurag S. Maskey 		(void) nwamd_wlan_scan(ncu_data->ncu_name);
4796ba597c5SAnurag S. Maskey 	return (0);
4806ba597c5SAnurag S. Maskey }
4816ba597c5SAnurag S. Maskey 
4826ba597c5SAnurag S. Maskey /* Handle known WLAN initialization/refresh event */
4836ba597c5SAnurag S. Maskey /* ARGSUSED */
4846ba597c5SAnurag S. Maskey void
nwamd_known_wlan_handle_init_event(nwamd_event_t known_wlan_event)4856ba597c5SAnurag S. Maskey nwamd_known_wlan_handle_init_event(nwamd_event_t known_wlan_event)
4866ba597c5SAnurag S. Maskey {
4876ba597c5SAnurag S. Maskey 	/*
4886ba597c5SAnurag S. Maskey 	 * Since the Known WLAN list has changed, do a rescan so that the
4896ba597c5SAnurag S. Maskey 	 * best network is selected.
4906ba597c5SAnurag S. Maskey 	 */
4916ba597c5SAnurag S. Maskey 	(void) nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU,
4926ba597c5SAnurag S. Maskey 	    nwamd_ncu_known_wlan_committed, NULL);
4936ba597c5SAnurag S. Maskey }
4946ba597c5SAnurag S. Maskey 
4956ba597c5SAnurag S. Maskey void
nwamd_known_wlan_handle_action_event(nwamd_event_t known_wlan_event)4966ba597c5SAnurag S. Maskey nwamd_known_wlan_handle_action_event(nwamd_event_t known_wlan_event)
4976ba597c5SAnurag S. Maskey {
4986ba597c5SAnurag S. Maskey 	switch (known_wlan_event->event_msg->nwe_data.nwe_object_action.
4996ba597c5SAnurag S. Maskey 	    nwe_action) {
5006ba597c5SAnurag S. Maskey 	case NWAM_ACTION_ADD:
5016ba597c5SAnurag S. Maskey 	case NWAM_ACTION_REFRESH:
5026ba597c5SAnurag S. Maskey 		nwamd_known_wlan_handle_init_event(known_wlan_event);
5036ba597c5SAnurag S. Maskey 		break;
5046ba597c5SAnurag S. Maskey 	case NWAM_ACTION_DESTROY:
5056ba597c5SAnurag S. Maskey 		/* Nothing needs to be done for destroy */
5066ba597c5SAnurag S. Maskey 		break;
5076ba597c5SAnurag S. Maskey 	/* all other events are invalid for known WLANs */
5086ba597c5SAnurag S. Maskey 	case NWAM_ACTION_ENABLE:
5096ba597c5SAnurag S. Maskey 	case NWAM_ACTION_DISABLE:
5106ba597c5SAnurag S. Maskey 	default:
5116ba597c5SAnurag S. Maskey 		nlog(LOG_INFO, "nwam_known_wlan_handle_action_event: "
5126ba597c5SAnurag S. Maskey 		    "unexpected action");
5136ba597c5SAnurag S. Maskey 		break;
5146ba597c5SAnurag S. Maskey 	}
5156ba597c5SAnurag S. Maskey }
5166ba597c5SAnurag S. Maskey 
5176ba597c5SAnurag S. Maskey int
nwamd_known_wlan_action(const char * known_wlan,nwam_action_t action)5186ba597c5SAnurag S. Maskey nwamd_known_wlan_action(const char *known_wlan, nwam_action_t action)
5196ba597c5SAnurag S. Maskey {
5206ba597c5SAnurag S. Maskey 	nwamd_event_t known_wlan_event = nwamd_event_init_object_action
5216ba597c5SAnurag S. Maskey 	    (NWAM_OBJECT_TYPE_KNOWN_WLAN, known_wlan, NULL, action);
5226ba597c5SAnurag S. Maskey 	if (known_wlan_event == NULL)
5236ba597c5SAnurag S. Maskey 		return (1);
5246ba597c5SAnurag S. Maskey 	nwamd_event_enqueue(known_wlan_event);
5256ba597c5SAnurag S. Maskey 	return (0);
5266ba597c5SAnurag S. Maskey }
527