xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/wificonfig/wificonfig.c (revision 6834:15dacdddd911)
1995Shx147065 /*
2995Shx147065  * CDDL HEADER START
3995Shx147065  *
4995Shx147065  * The contents of this file are subject to the terms of the
5*6834Sff224033  * Common Development and Distribution License (the "License").
6*6834Sff224033  * You may not use this file except in compliance with the License.
7995Shx147065  *
8995Shx147065  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9995Shx147065  * or http://www.opensolaris.org/os/licensing.
10995Shx147065  * See the License for the specific language governing permissions
11995Shx147065  * and limitations under the License.
12995Shx147065  *
13995Shx147065  * When distributing Covered Code, include this CDDL HEADER in each
14995Shx147065  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15995Shx147065  * If applicable, add the following below this CDDL HEADER, with the
16995Shx147065  * fields enclosed by brackets "[]" replaced with your own identifying
17995Shx147065  * information: Portions Copyright [yyyy] [name of copyright owner]
18995Shx147065  *
19995Shx147065  * CDDL HEADER END
20995Shx147065  */
21995Shx147065 /*
22*6834Sff224033  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23995Shx147065  * Use is subject to license terms.
24995Shx147065  */
25995Shx147065 
26995Shx147065 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27995Shx147065 
28995Shx147065 #include <stdio.h>
29995Shx147065 #include <stdlib.h>
30995Shx147065 #include <stddef.h>
31995Shx147065 #include <errno.h>
32995Shx147065 #include <ctype.h>
33995Shx147065 #include <stdarg.h>
34995Shx147065 #include <fcntl.h>
35995Shx147065 #include <unistd.h>
36995Shx147065 #include <net/if.h>
37995Shx147065 #include <sys/types.h>
38995Shx147065 #include <sys/stat.h>
39995Shx147065 #include <sys/wait.h>
40995Shx147065 #include <sys/ipc.h>
41995Shx147065 #include <sys/ddi.h>
42995Shx147065 #include <stropts.h>
43995Shx147065 #include <assert.h>
44995Shx147065 #include <termios.h>
45995Shx147065 #include <time.h>
46995Shx147065 #include <string.h>
47995Shx147065 #include <strings.h>
48995Shx147065 #include <auth_attr.h>
49995Shx147065 #include <auth_list.h>
50995Shx147065 #include <libdevinfo.h>
51995Shx147065 #include <secdb.h>
52995Shx147065 #include <priv.h>
53995Shx147065 #include <pwd.h>
54995Shx147065 #include <umem.h>
55995Shx147065 #include <locale.h>
56995Shx147065 #include <libintl.h>
57995Shx147065 #include <dirent.h>
58995Shx147065 #include <inet/wifi_ioctl.h>
59995Shx147065 
60995Shx147065 /*
61995Shx147065  * Debug information
62995Shx147065  */
63995Shx147065 #ifdef	DEBUG
64995Shx147065 int wifi_debug = 0;
65995Shx147065 void wifi_dbgprintf(char *fmt, ...);
66995Shx147065 #define	PRTDBG(msg) if (wifi_debug > 1) wifi_dbgprintf msg
67995Shx147065 #else /* DEBUG */
68995Shx147065 #define	PRTDBG(msg)
69995Shx147065 #endif /* DEBUG */
70995Shx147065 
71995Shx147065 #define	MAX_HISTORY_NUM			10
72995Shx147065 #define	MAX_PREFERENCE_NUM		10
73995Shx147065 #define	MAX_SCANBUF_LEN			256
74995Shx147065 #define	MAX_CONFIG_FILE_LENGTH		256
75995Shx147065 #define	MAX_LOADPF_LENGTH		256
76995Shx147065 #define	LOADPROFILE_TIMEOUT		10
77995Shx147065 #define	RECORD_ADD		0
78995Shx147065 #define	RECORD_DEL		1
79995Shx147065 /*
80995Shx147065  * Wificonfig exit status
81995Shx147065  */
82995Shx147065 #define	WIFI_EXIT_DEF		0
83995Shx147065 #define	WIFI_FATAL_ERR		1
84995Shx147065 #define	WIFI_IMPROPER_USE	2
85995Shx147065 #define	WIFI_MINOR_ERR		3
86995Shx147065 
87995Shx147065 #define	WIFI_LOCKF "/var/run/lockf_wifi"
88995Shx147065 
89995Shx147065 typedef enum {
90995Shx147065 	PREFERENCE,
91995Shx147065 	HISTORY,
92995Shx147065 	ACTIVEP,
93995Shx147065 	PROFILE,
94995Shx147065 	OTHER
95995Shx147065 } list_type_t;
96995Shx147065 
97995Shx147065 #define	WIFI_PREFER	"{preference}"
98995Shx147065 #define	WIFI_HISTORY	"{history}"
99995Shx147065 #define	WIFI_ACTIVEP	"{active_profile}"
100995Shx147065 
101995Shx147065 typedef enum {
102995Shx147065 	LINKSTATUS = 0,
103995Shx147065 	BSSID,
104995Shx147065 	ESSID,
105995Shx147065 	BSSTYPE,
106995Shx147065 	CREATEIBSS,
107995Shx147065 	CHANNEL,
108995Shx147065 	RATES,
109995Shx147065 	POWERMODE,
110995Shx147065 	AUTHMODE,
111995Shx147065 	ENCRYPTION,
112995Shx147065 	WEPKEYID,
113995Shx147065 	WEPKEY,
114995Shx147065 	SIGNAL,
115995Shx147065 	RADIOON,
116995Shx147065 	WLANLIST,
117995Shx147065 	CONFIG_ITEM_END /* 15 */
118995Shx147065 } config_item_t;
119995Shx147065 typedef struct ae {
120995Shx147065 	struct ae *ae_next;
121995Shx147065 	char *ae_arg;
122995Shx147065 }ae_t;
123995Shx147065 typedef struct aelist {
124995Shx147065 	int ael_argc;
125995Shx147065 	ae_t *ael_head, *ael_tail;
126995Shx147065 	list_type_t type;
127995Shx147065 }aelist_t;
128995Shx147065 typedef struct section {
129995Shx147065 	struct section *section_next;
130995Shx147065 	aelist_t *list;
131995Shx147065 	char *section_id;
132995Shx147065 }section_t;
133995Shx147065 
134995Shx147065 /*
135995Shx147065  * config_file_t is an abstract of configration file,
136995Shx147065  * either/etc/inet/wifi/wifi.<interface> or /etc/inet/secret/
137995Shx147065  * wifi/wifiwepkey.<interface>
138995Shx147065  */
139995Shx147065 typedef struct config_file {
140995Shx147065 	int section_argc;
141995Shx147065 	section_t *section_head, *section_tail;
142995Shx147065 }config_file_t;
143995Shx147065 
144995Shx147065 static config_file_t *gp_config_file = NULL;
145995Shx147065 static config_file_t *gp_wepkey_file = NULL;
146995Shx147065 static char *p_file_wifi = "/etc/inet/wifi";
147995Shx147065 static char *p_file_wifiwepkey = "/etc/inet/secret/wifiwepkey";
148995Shx147065 
149995Shx147065 typedef enum {
150995Shx147065 	AUTH_WEP = 0,
151995Shx147065 	AUTH_OTHER = 1
152995Shx147065 } wifi_auth_t;
153995Shx147065 
154995Shx147065 static char *p_auth_string[] = {
155995Shx147065 	WIFI_WEP_AUTH,
156995Shx147065 	WIFI_CONFIG_AUTH
157995Shx147065 };
158995Shx147065 
159995Shx147065 /*
160995Shx147065  * gbuf: is a global buf, which is used to communicate between the user and
161995Shx147065  * the driver
162995Shx147065  */
163995Shx147065 static wldp_t *gbuf = NULL;
164995Shx147065 static char *gExecName = NULL;
165995Shx147065 
166995Shx147065 static void print_error(uint32_t);
167995Shx147065 static void *safe_malloc(size_t);
168995Shx147065 static void *safe_calloc(size_t, size_t);
169995Shx147065 static char *safe_strdup(const char *s1);
170995Shx147065 static void safe_snprintf(char *s, size_t n,
171995Shx147065     const char *format, ...);
172995Shx147065 static void safe_fclose(FILE *stream);
173995Shx147065 static void new_ae(aelist_t *ael, const char *arg);
174995Shx147065 static aelist_t *new_ael(list_type_t type);
175995Shx147065 static config_file_t *new_config_file();
176995Shx147065 static void new_section(config_file_t *p_config_file, aelist_t *p_list,
177995Shx147065 	const char *section_id);
178995Shx147065 static void destroy_config(config_file_t *p_config_file);
179995Shx147065 static config_file_t *parse_file(const char *pfile);
180995Shx147065 static char **aeltoargv(aelist_t *ael, int *ael_num);
181995Shx147065 static boolean_t fprint_config_file(config_file_t *p_config_file,
182995Shx147065 	const char *file_name);
183995Shx147065 static char *append_pa(const char *arg);
184995Shx147065 static section_t *find_section(config_file_t *p_config_file,
185995Shx147065 	const char *section_id);
186995Shx147065 static ae_t *find_ae(aelist_t *plist, const char *arg);
187995Shx147065 static void update_aelist(aelist_t *plist, const char *arg);
188995Shx147065 static const char *get_value(const char *arg);
189995Shx147065 static char *find_active_profile(int);
190995Shx147065 static const char *essid_of_profile(const char *profile);
191995Shx147065 static boolean_t search_interface(char *interface);
192995Shx147065 static int open_dev(char *devname);
193995Shx147065 static boolean_t call_ioctl(int, int, uint32_t, uint32_t);
194995Shx147065 static boolean_t del_prefer(config_file_t *p_config_file, const char *prefer,
195995Shx147065     boolean_t rflag);
196995Shx147065 static boolean_t del_section(config_file_t *p_config_file, char *section_id);
197995Shx147065 static boolean_t set_prefer(config_file_t *p_config_file, const char *prefer,
198995Shx147065 	int rank);
199995Shx147065 static void add_to_history(config_file_t *p_config_file,
200995Shx147065     int argc, char **argv);
201995Shx147065 static boolean_t check_authority(wifi_auth_t type);
202995Shx147065 static void heuristic_load(int fd, uint32_t ess_num, wl_ess_conf_t **);
203995Shx147065 static char *select_profile(int fd, int readonly, int timeout);
204995Shx147065 static char *construct_format(uint32_t nt);
205995Shx147065 static void print_gbuf(config_item_t index);
206995Shx147065 static boolean_t items_in_profile(aelist_t *, aelist_t *, int, char **);
207995Shx147065 static char *get_commit_key(int, int, char **);
208995Shx147065 static void print_wepkey_info(const char *id, const char *wepkeyn);
209995Shx147065 static void  do_print_usage();
210995Shx147065 static boolean_t do_print_support_params(int fd);
211995Shx147065 static boolean_t do_autoconf(int fd, int argc, char **argv);
212995Shx147065 static boolean_t do_startconf(int fd, int argc, char **argv);
213995Shx147065 static boolean_t do_loadpf(int fd, int argc, char **argv);
214995Shx147065 static boolean_t do_disconnect(int fd, int argc, char **argv);
215995Shx147065 static boolean_t do_printpf(int fd, int argc, char **argv);
216995Shx147065 static boolean_t do_restoredef(int fd, int argc, char **argv);
217995Shx147065 static boolean_t do_history(int fd, int argc, char **argv);
218995Shx147065 static boolean_t do_deletepf(int fd, int argc, char **argv);
219995Shx147065 static boolean_t do_wepkey(int fd, int argc, char **argv);
220995Shx147065 static boolean_t do_setprefer(int fd, int argc, char **arg);
221995Shx147065 static boolean_t do_rmprefer(int fd, int argc, char **argv);
222995Shx147065 static boolean_t do_lsprefer(int fd, int argc, char **argv);
223995Shx147065 static boolean_t do_wlanlist(int fd, int argc, char **argv);
224995Shx147065 static boolean_t do_showstatus(int fd, int argc, char **argv);
225995Shx147065 static boolean_t do_getprofparam(int fd, int argc, char **argv);
226995Shx147065 static boolean_t do_setprofparam(int fd, int argc, char **argv);
227995Shx147065 static boolean_t do_setprofwepkey(int fd, int argc, char **argv);
228995Shx147065 static boolean_t is_rates_support(int fd, int num, uint8_t *rates);
229995Shx147065 static boolean_t do_set_bsstype(int fd, const char *arg);
230995Shx147065 static boolean_t do_set_essid(int fd, const char *arg);
231995Shx147065 static boolean_t do_set_powermode(int fd, const char *arg);
232995Shx147065 static boolean_t do_set_rates(int fd, const char *arg);
233995Shx147065 static boolean_t do_set_channel(int fd, const char *arg);
234995Shx147065 static boolean_t do_set_createibss(int fd, const char *arg);
235995Shx147065 static boolean_t do_set_radioon(int fd, const char *arg);
236995Shx147065 static boolean_t do_set_wepkeyid(int fd, const char *arg);
237995Shx147065 static boolean_t do_set_encryption(int fd, const char *arg);
238995Shx147065 static boolean_t do_set_authmode(int fd, const char *arg);
239995Shx147065 static boolean_t do_set_wepkey(int fd, const char *pbuf);
240995Shx147065 static boolean_t do_get_createibss(int fd);
241995Shx147065 static boolean_t do_get_bsstype(int fd);
242995Shx147065 static boolean_t do_get_essid(int fd);
243995Shx147065 static boolean_t do_get_bssid(int fd);
244995Shx147065 static boolean_t do_get_radioon(int fd);
245995Shx147065 static boolean_t do_get_signal(int fd);
246995Shx147065 static boolean_t do_get_wepkeyid(int fd);
247995Shx147065 static boolean_t do_get_encryption(int fd);
248995Shx147065 static boolean_t do_get_authmode(int fd);
249995Shx147065 static boolean_t do_get_powermode(int fd);
250995Shx147065 static boolean_t do_get_rates(int fd);
251995Shx147065 static boolean_t do_get_wlanlist(int fd);
252995Shx147065 static boolean_t do_get_linkstatus(int fd);
253995Shx147065 static boolean_t do_get_channel(int fd);
254995Shx147065 static boolean_t do_get(int fd, int argc, char **argv);
255995Shx147065 static boolean_t do_set(int fd, int argc, char **argv);
256995Shx147065 static boolean_t do_createprofile(int fd, int argc, char **argv);
257995Shx147065 static boolean_t value_is_valid(config_item_t item, const char *value);
258995Shx147065 
259995Shx147065 typedef struct cmd_ops {
260995Shx147065 	char cmd[32];
261995Shx147065 	boolean_t (*p_do_func)(int fd, int argc, char **argv);
262995Shx147065 	boolean_t b_auth;
263995Shx147065 	boolean_t b_fileonly; /* operation only on the config file */
264995Shx147065 	boolean_t b_readonly; /* only read from the card or config file */
265995Shx147065 } cmd_ops_t;
266995Shx147065 static cmd_ops_t do_func[] = {
267995Shx147065 	{
268995Shx147065 		"autoconf",
269995Shx147065 		do_autoconf,
270995Shx147065 		B_TRUE,
271995Shx147065 		B_FALSE,
272995Shx147065 		B_FALSE
273995Shx147065 	},
274995Shx147065 	{
275995Shx147065 		"startconf",
276995Shx147065 		do_startconf,
277995Shx147065 		B_TRUE,
278995Shx147065 		B_FALSE,
279995Shx147065 		B_TRUE
280995Shx147065 	},
281995Shx147065 	{
282995Shx147065 		"connect",
283995Shx147065 		do_loadpf,
284995Shx147065 		B_TRUE,
285995Shx147065 		B_FALSE,
286995Shx147065 		B_FALSE
287995Shx147065 	},
288995Shx147065 	{
289995Shx147065 		"disconnect",
290995Shx147065 		do_disconnect,
291995Shx147065 		B_TRUE,
292995Shx147065 		B_FALSE,
293995Shx147065 		B_FALSE
294995Shx147065 	},
295995Shx147065 	{
296995Shx147065 		"showprofile",
297995Shx147065 		do_printpf,
298995Shx147065 		B_FALSE,
299995Shx147065 		B_TRUE,
300995Shx147065 		B_TRUE
301995Shx147065 	},
302995Shx147065 	{
303995Shx147065 		"deleteprofile",
304995Shx147065 		do_deletepf,
305995Shx147065 		B_TRUE,
306995Shx147065 		B_TRUE,
307995Shx147065 		B_FALSE
308995Shx147065 	},
309995Shx147065 	{
310995Shx147065 		"history",
311995Shx147065 		do_history,
312995Shx147065 		B_FALSE,
313995Shx147065 		B_TRUE,
314995Shx147065 		B_TRUE
315995Shx147065 	},
316995Shx147065 	{
317995Shx147065 		"listprefer",
318995Shx147065 		do_lsprefer,
319995Shx147065 		B_FALSE,
320995Shx147065 		B_TRUE,
321995Shx147065 		B_TRUE
322995Shx147065 	},
323995Shx147065 	{
324995Shx147065 		"removeprefer",
325995Shx147065 		do_rmprefer,
326995Shx147065 		B_TRUE,
327995Shx147065 		B_TRUE,
328995Shx147065 		B_FALSE
329995Shx147065 	},
330995Shx147065 	{
331995Shx147065 		"setprefer",
332995Shx147065 		do_setprefer,
333995Shx147065 		B_TRUE,
334995Shx147065 		B_TRUE,
335995Shx147065 		B_FALSE
336995Shx147065 	},
337995Shx147065 	{
338995Shx147065 		"setwepkey",
339995Shx147065 		do_wepkey,
340995Shx147065 		B_TRUE,
341995Shx147065 		B_FALSE,
342995Shx147065 		B_FALSE
343995Shx147065 	},
344995Shx147065 	{
345995Shx147065 		"restoredef",
346995Shx147065 		do_restoredef,
347995Shx147065 		B_TRUE,
348995Shx147065 		B_FALSE,
349995Shx147065 		B_FALSE
350995Shx147065 	},
351995Shx147065 	{
352995Shx147065 		"getparam",
353995Shx147065 		do_get,
354995Shx147065 		B_FALSE,
355995Shx147065 		B_FALSE,
356995Shx147065 		B_TRUE
357995Shx147065 	},
358995Shx147065 	{
359995Shx147065 		"setparam",
360995Shx147065 		do_set,
361995Shx147065 		B_TRUE,
362995Shx147065 		B_FALSE,
363995Shx147065 		B_FALSE
364995Shx147065 	},
365995Shx147065 	{
366995Shx147065 		"createprofile",
367995Shx147065 		do_createprofile,
368995Shx147065 		B_TRUE,
369995Shx147065 		B_TRUE,
370995Shx147065 		B_FALSE
371995Shx147065 	},
372995Shx147065 	{
373995Shx147065 		"scan",
374995Shx147065 		do_wlanlist,
375995Shx147065 		B_FALSE,
376995Shx147065 		B_FALSE,
377995Shx147065 		B_FALSE
378995Shx147065 	},
379995Shx147065 	{
380995Shx147065 		"showstatus",
381995Shx147065 		do_showstatus,
382995Shx147065 		B_FALSE,
383995Shx147065 		B_FALSE,
384995Shx147065 		B_TRUE
385995Shx147065 	},
386995Shx147065 	{
387995Shx147065 		"setprofileparam",
388995Shx147065 		do_setprofparam,
389995Shx147065 		B_TRUE,
390995Shx147065 		B_TRUE,
391995Shx147065 		B_FALSE
392995Shx147065 	},
393995Shx147065 	{
394995Shx147065 		"getprofileparam",
395995Shx147065 		do_getprofparam,
396995Shx147065 		B_FALSE,
397995Shx147065 		B_TRUE,
398995Shx147065 		B_TRUE
399995Shx147065 	},
400995Shx147065 	{
401995Shx147065 		"setprofilewepkey",
402995Shx147065 		do_setprofwepkey,
403995Shx147065 		B_TRUE,
404995Shx147065 		B_TRUE,
405995Shx147065 		B_FALSE
406995Shx147065 	}
407995Shx147065 };
408995Shx147065 
409995Shx147065 
410995Shx147065 typedef enum {RW, RO, WO} rw_property_t;
411995Shx147065 typedef struct gs_ops {
412995Shx147065 	config_item_t index;
413995Shx147065 	char cmd[32];
414995Shx147065 	boolean_t (*p_do_get_func)(int fd);
415995Shx147065 	boolean_t (*p_do_set_func)(int fd, const char *arg);
416995Shx147065 	rw_property_t rw;
417995Shx147065 } gs_ops_t;
418995Shx147065 static gs_ops_t do_gs_func[] = {
419995Shx147065 	{LINKSTATUS, "linkstatus", NULL, NULL, RO},
420995Shx147065 	{BSSID, "bssid", do_get_bssid, NULL, RO},
421995Shx147065 	{ESSID, "essid", do_get_essid, do_set_essid, RW},
422995Shx147065 	{BSSTYPE, "bsstype", do_get_bsstype, do_set_bsstype, RW},
423995Shx147065 	{CREATEIBSS, "createibss", do_get_createibss, do_set_createibss, RW},
424995Shx147065 	{CHANNEL, "channel", do_get_channel, do_set_channel, RW},
425995Shx147065 	{RATES, "rates", do_get_rates, do_set_rates, RW},
426995Shx147065 	{POWERMODE, "powermode", do_get_powermode, do_set_powermode, RW},
427995Shx147065 	{AUTHMODE, "authmode", do_get_authmode, do_set_authmode, RW},
428995Shx147065 	{ENCRYPTION, "encryption", do_get_encryption, do_set_encryption, RW},
429995Shx147065 	{WEPKEYID, "wepkeyindex", do_get_wepkeyid, do_set_wepkeyid, RW},
430995Shx147065 	{WEPKEY, "wepkey|1-4", NULL, do_set_wepkey, WO},
431995Shx147065 	{SIGNAL, "signal", do_get_signal, NULL, RO},
432995Shx147065 	{RADIOON, "radio",	do_get_radioon, do_set_radioon, RW},
433995Shx147065 };
434995Shx147065 
435995Shx147065 #define	N_FUNC		sizeof (do_func) / sizeof (cmd_ops_t)
436995Shx147065 #define	N_GS_FUNC 	sizeof (do_gs_func) / sizeof (gs_ops_t)
437995Shx147065 
438995Shx147065 /*
439995Shx147065  * valid rate value
440995Shx147065  */
441995Shx147065 typedef	struct wifi_rates_tab {
442995Shx147065 	char *rates_s;
443995Shx147065 	uint8_t rates_i;
444995Shx147065 	uint8_t rates_reserve0;
445995Shx147065 	uint8_t rates_reserve1;
446995Shx147065 	uint8_t rates_reserve2;
447995Shx147065 } wifi_rates_tab_t;
448995Shx147065 
449995Shx147065 /*
450995Shx147065  * the rates value is in increments of 500kb/s.
451995Shx147065  * according to the 802.11 a/b/g specs(IEEE):
452995Shx147065  * 802.11b(IEEE Std 802.11b-1999) page35, rates should be:
453995Shx147065  *	X02, X04, X0b, X16
454995Shx147065  * 802.11a(IEEE Std 802.11a-1999) page47, rates should be:
455995Shx147065  *	6,9,12,18,24,36,48,54 Mb/s
456995Shx147065  * 802.11g(IEEE Std 802.11g-2003) page44, rates should be:
457995Shx147065  *	1,2,5.5,11,6,9,12,18,22,24,33,36,48,54 Mb/s
458995Shx147065  */
459995Shx147065 #define	WIFI_RATES_NUM	14
460995Shx147065 static wifi_rates_tab_t wifi_rates_s[WIFI_RATES_NUM] = {
461995Shx147065 	{"1",	WL_RATE_1M,	0,	0,	0},
462995Shx147065 	{"2",	WL_RATE_2M,	0,	0,	0},
463995Shx147065 	{"5.5",	WL_RATE_5_5M,	0,	0,	0},
464995Shx147065 	{"6",	WL_RATE_6M,	0,	0,	0},
465995Shx147065 	{"9",	WL_RATE_9M,	0,	0,	0},
466995Shx147065 	{"11",	WL_RATE_11M,	0,	0,	0},
467995Shx147065 	{"12",	WL_RATE_12M,	0,	0,	0},
468995Shx147065 	{"18",	WL_RATE_18M,	0,	0,	0},
469995Shx147065 	{"22",	WL_RATE_22M,	0,	0,	0},
470995Shx147065 	{"24",	WL_RATE_24M,	0,	0,	0},
471995Shx147065 	{"33",	WL_RATE_33M,	0,	0,	0},
472995Shx147065 	{"36",	WL_RATE_36M,	0,	0,	0},
473995Shx147065 	{"48",	WL_RATE_48M,	0,	0,	0},
474995Shx147065 	{"54",	WL_RATE_54M,	0,	0,	0}
475995Shx147065 };
476995Shx147065 /* print the error message on why set or get ioctl command failed. */
477995Shx147065 static void
print_error(uint32_t errorno)478995Shx147065 print_error(uint32_t errorno)
479995Shx147065 {
480995Shx147065 	char *buf;
481995Shx147065 
482995Shx147065 	switch (errorno) {
483995Shx147065 	case WL_SUCCESS:
484995Shx147065 		buf = gettext("command succeeded");
485995Shx147065 		break;
486995Shx147065 	case WL_NOTSUPPORTED:
487995Shx147065 	case WL_LACK_FEATURE:
488995Shx147065 	case WL_HW_ERROR:
489995Shx147065 	case WL_ACCESS_DENIED:
490995Shx147065 		buf = strerror(errorno);
491995Shx147065 		break;
492995Shx147065 	case WL_READONLY:
493995Shx147065 		buf = gettext("parameter read-only");
494995Shx147065 		break;
495995Shx147065 	case WL_WRITEONLY:
496995Shx147065 		buf = gettext("parameter write-only");
497995Shx147065 		break;
498995Shx147065 	case WL_NOAP:
499995Shx147065 		buf = gettext("no access point available");
500995Shx147065 		break;
501995Shx147065 	default:
502995Shx147065 		buf = gettext("unknown error");
503995Shx147065 		break;
504995Shx147065 	}
505995Shx147065 	(void) fprintf(stderr, "%s\n", buf);
506995Shx147065 }
507995Shx147065 
508995Shx147065 static void *
safe_malloc(size_t size)509995Shx147065 safe_malloc(size_t size)
510995Shx147065 {
511995Shx147065 	void *buf;
512995Shx147065 
513995Shx147065 	buf = malloc(size);
514995Shx147065 	if (buf == NULL) {
515995Shx147065 		(void) fprintf(stderr, gettext("%s: malloc: %s\n"),
516995Shx147065 		    gExecName, strerror(errno));
517995Shx147065 		exit(WIFI_FATAL_ERR);
518995Shx147065 	}
519995Shx147065 	return (buf);
520995Shx147065 }
521995Shx147065 
522995Shx147065 static void *
safe_calloc(size_t nelem,size_t elsize)523995Shx147065 safe_calloc(size_t nelem, size_t elsize)
524995Shx147065 {
525995Shx147065 	void *buf;
526995Shx147065 
527995Shx147065 	buf = calloc(nelem, elsize);
528995Shx147065 	if (buf == NULL) {
529995Shx147065 		(void) fprintf(stderr, gettext("%s: calloc: %s\n"),
530995Shx147065 		    gExecName, strerror(errno));
531995Shx147065 		exit(WIFI_FATAL_ERR);
532995Shx147065 	}
533995Shx147065 	return (buf);
534995Shx147065 }
535995Shx147065 
536995Shx147065 static char *
safe_strdup(const char * s1)537995Shx147065 safe_strdup(const char *s1)
538995Shx147065 {
539995Shx147065 	char *p;
540995Shx147065 
541995Shx147065 	p = strdup(s1);
542995Shx147065 	if (p == NULL) {
543995Shx147065 		(void) fprintf(stderr, gettext("%s: strdup: %s\n"),
544995Shx147065 		    gExecName, strerror(errno));
545995Shx147065 		exit(WIFI_FATAL_ERR);
546995Shx147065 	}
547995Shx147065 	return (p);
548995Shx147065 }
549995Shx147065 
550995Shx147065 static void
safe_snprintf(char * s,size_t n,const char * format,...)551995Shx147065 safe_snprintf(char *s, size_t n,  const  char  *format, ...)
552995Shx147065 {
553995Shx147065 	int len;
554995Shx147065 	va_list ap;
555995Shx147065 	va_start(ap, format);
556995Shx147065 
557995Shx147065 	len = vsnprintf(s, n, format, ap);
558995Shx147065 	if ((len <= 0) || (len > n - 1)) {
559995Shx147065 		(void) fprintf(stderr,
560995Shx147065 		    gettext("%s: snprintf: %s\n"),
561995Shx147065 		    gExecName, strerror(errno));
562995Shx147065 		exit(WIFI_FATAL_ERR);
563995Shx147065 	}
564995Shx147065 	va_end(ap);
565995Shx147065 }
566995Shx147065 
567995Shx147065 static void
safe_fclose(FILE * stream)568995Shx147065 safe_fclose(FILE *stream)
569995Shx147065 {
570995Shx147065 	int err;
571995Shx147065 
572995Shx147065 	err = fclose(stream);
573995Shx147065 	if (err == EOF) {
574995Shx147065 		(void) fprintf(stderr, gettext("%s: fclose: %s\n"),
575995Shx147065 		    gExecName, strerror(errno));
576995Shx147065 		exit(WIFI_FATAL_ERR);
577995Shx147065 	}
578995Shx147065 }
579995Shx147065 /*
580995Shx147065  * new_ae: Add an element with content pointed by arg to the list *ael.
581995Shx147065  */
582995Shx147065 static void
new_ae(aelist_t * ael,const char * arg)583995Shx147065 new_ae(aelist_t *ael, const char *arg)
584995Shx147065 {
585995Shx147065 	ae_t *pae = NULL;
586995Shx147065 
587995Shx147065 	PRTDBG(("new_ae(0x%x, \"%s\")\n", ael, arg));
588995Shx147065 	assert((ael != NULL) && (arg != NULL));
589995Shx147065 
590995Shx147065 	pae = safe_calloc(sizeof (*pae), 1);
591995Shx147065 	pae->ae_arg = safe_strdup(arg);
592995Shx147065 	pae->ae_next = NULL;
593995Shx147065 
594995Shx147065 	if (ael->ael_tail == NULL) {
595995Shx147065 		ael->ael_head = pae;
596995Shx147065 	} else {
597995Shx147065 		ael->ael_tail->ae_next = pae;
598995Shx147065 	}
599995Shx147065 	ael->ael_tail = pae;
600995Shx147065 	ael->ael_argc++;
601995Shx147065 }
602995Shx147065 /*
603995Shx147065  * new_ael:  Create a new aelist with list_type "type"
604995Shx147065  * and return the list pointer.
605995Shx147065  */
606995Shx147065 static aelist_t *
new_ael(list_type_t type)607995Shx147065 new_ael(list_type_t type)
608995Shx147065 {
609995Shx147065 	aelist_t *plist;
610995Shx147065 
611995Shx147065 	plist = safe_calloc(sizeof (*plist), 1);
612995Shx147065 	plist->type = type;
613995Shx147065 	plist->ael_argc = 0;
614995Shx147065 	plist->ael_head = plist->ael_tail = NULL;
615995Shx147065 
616995Shx147065 	PRTDBG(("new_ael(%d) = 0x%x\n", type, plist));
617995Shx147065 	return (plist);
618995Shx147065 }
619995Shx147065 
620995Shx147065 /*
621995Shx147065  * new_config_file: Creates a new config_file_t struct which is counterpart of
622995Shx147065  * of the configration file, and return the pointer.
623995Shx147065  */
624995Shx147065 static config_file_t *
new_config_file()625995Shx147065 new_config_file()
626995Shx147065 {
627995Shx147065 	config_file_t *p_config_file;
628995Shx147065 
629995Shx147065 	p_config_file = safe_calloc(sizeof (config_file_t), 1);
630995Shx147065 	p_config_file->section_argc = 0;
631995Shx147065 	p_config_file->section_head = p_config_file->section_tail = NULL;
632995Shx147065 
633995Shx147065 	PRTDBG(("new_config_file() = 0x%x\n", p_config_file));
634995Shx147065 	return (p_config_file);
635995Shx147065 }
636995Shx147065 
637995Shx147065 /*
638995Shx147065  * new_section: Add a list pointed by "p_list", with identity "section_id" to
639995Shx147065  * the config_file_t struct pointed by "p_config_file"
640995Shx147065  */
641995Shx147065 static void
new_section(config_file_t * p_config_file,aelist_t * p_list,const char * section_id)642995Shx147065 new_section(config_file_t *p_config_file, aelist_t *p_list,
643995Shx147065     const char *section_id)
644995Shx147065 {
645995Shx147065 	section_t *p_section = NULL;
646995Shx147065 
647995Shx147065 	PRTDBG(("new_section(0x%x, 0x%x, \"%s\")\n", p_config_file, p_list,
648995Shx147065 	    section_id));
649995Shx147065 	assert((p_config_file != NULL) && (p_list != NULL) &&
650995Shx147065 	    (section_id != NULL));
651995Shx147065 
652995Shx147065 	p_section = safe_calloc(sizeof (*p_section), 1);
653995Shx147065 	p_section->list = p_list;
654995Shx147065 	p_section->section_next = NULL;
655995Shx147065 	p_section->section_id = safe_strdup(section_id);
656995Shx147065 
657995Shx147065 	if (p_config_file->section_tail == NULL) {
658995Shx147065 		p_config_file->section_head = p_section;
659995Shx147065 	} else {
660995Shx147065 		p_config_file->section_tail->section_next = p_section;
661995Shx147065 	}
662995Shx147065 	p_config_file->section_tail = p_section;
663995Shx147065 	p_config_file->section_argc++;
664995Shx147065 }
665995Shx147065 
666995Shx147065 /*
667995Shx147065  * destroy_config:Destroy the config_file struct
668995Shx147065  */
669995Shx147065 static void
destroy_config(config_file_t * p_config_file)670995Shx147065 destroy_config(config_file_t *p_config_file)
671995Shx147065 {
672995Shx147065 	section_t *p_section = NULL;
673995Shx147065 	aelist_t *p_list = NULL;
674995Shx147065 	ae_t *pae = NULL;
675995Shx147065 
676995Shx147065 	PRTDBG(("destory_config(0x%x)\n", p_config_file));
677995Shx147065 	assert(p_config_file != NULL);
678995Shx147065 
679995Shx147065 	p_section = p_config_file->section_head;
680995Shx147065 	while (p_section != NULL) {
681995Shx147065 		p_list = p_section->list;
682995Shx147065 		if (p_list != NULL) {
683995Shx147065 			pae = p_list->ael_head;
684995Shx147065 			while (pae != NULL) {
685995Shx147065 				if (pae->ae_arg != NULL)
686995Shx147065 					free(pae->ae_arg);
687995Shx147065 				pae->ae_arg = NULL;
688995Shx147065 				pae = pae->ae_next;
689995Shx147065 				free(p_list->ael_head);
690995Shx147065 				p_list->ael_head = pae;
691995Shx147065 			}
692995Shx147065 			free(p_list);
693995Shx147065 			p_list = NULL;
694995Shx147065 		}
695995Shx147065 		if (p_section->section_id != NULL)
696995Shx147065 			free(p_section->section_id);
697995Shx147065 		p_section->section_id = NULL;
698995Shx147065 		p_section = p_section->section_next;
699995Shx147065 		free(p_config_file->section_head);
700995Shx147065 		p_config_file->section_head = p_section;
701995Shx147065 	}
702995Shx147065 	free(p_config_file);
703995Shx147065 	p_config_file = NULL;
704995Shx147065 }
705995Shx147065 
706995Shx147065 /*
707995Shx147065  * parse_file: Parse each section of the configration file
708995Shx147065  * and construct the config_file_t structure.
709995Shx147065  * Example:
710995Shx147065  * A config file has contents below:
711995Shx147065  *
712995Shx147065  * {preferrence}
713995Shx147065  * essid=ap7-3
714995Shx147065  * essid=linksys
715995Shx147065  *
716995Shx147065  * {history}
717995Shx147065  * essid=ap7-3
718995Shx147065  * essid=ap7-2
719995Shx147065  *
720995Shx147065  * [ap7-3]
721995Shx147065  * essid=ap7-3
722995Shx147065  * wepkeyid=3
723995Shx147065  * channel=11
724995Shx147065  * rates=1,2
725995Shx147065  *
726995Shx147065  * [linksys]
727995Shx147065  * essid=linksys
728995Shx147065  * createibss=BSS
729995Shx147065  * authmode=OPENSYSTEM
730995Shx147065  * wepkeyid=1
731995Shx147065  *
732995Shx147065  * then its config_file_t structure will be:
733995Shx147065  *
734995Shx147065  *                        config_file_t
735995Shx147065  *                       |~~~~~~~~~~~~~~~~~~~~~~~~~~|
736995Shx147065  *                       |      section_argc=5      |
737995Shx147065  *                       |~~~~~~~~~~~~T~~~~~~~~~~~~~|
738995Shx147065  *                      /|   *head    |    *tail    |\
739995Shx147065  *                     / ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \
740995Shx147065  *                    /                                \
741995Shx147065  *                   /	                                \
742995Shx147065  *                  /                                    \
743995Shx147065  *                 /                                      \
744995Shx147065  *                /                                        \
745995Shx147065  *  section_t    V           section_t                      V section_t
746995Shx147065  * |~~~~~~~~~~~~~~~|~~|     |~~~~~~~~~~~~~~~|~~|      |~~~~~~~~~~~~~~|~~|
747995Shx147065  * |"{preferrence}"|  |     |  "{history}"  |  |      | "[linksys]"  |  |
748995Shx147065  * |~~~~~~~~~~~~~~~| -+---->|~~~~~~~~~~~~~~~| -+->..->|~~~~~~~~~~~~~~| -+->NULL
749995Shx147065  * |    *list      |  |     |    *list      |  |      |    *list     |  |
750995Shx147065  * ~~T~~~~~~~~~~~~~~~~~     ~~~T~~~~~~~~~~~~~~~~      ~~~T~~~~~~~~~~~~~~~
751995Shx147065  *   |                         |                         |
752995Shx147065  *   |                         |                         |
753995Shx147065  *   V aelist_t                V aelist_t                V aelist_t
754995Shx147065  * |~~~~~~~~~~~~~|          |~~~~~~~~~~~~~|           |~~~~~~~~~~~~~|
755995Shx147065  * |  argc=2     |          |  argc=3     |           |  argc=4     |
756995Shx147065  * |~~~~~~~~~~~~~|          |~~~~~~~~~~~~~|           |~~~~~~~~~~~~~|
757995Shx147065  * |PREFFERRENCE |          |   HISTORY   |           |   PROFILE   |
758995Shx147065  * |~~~~~~T~~~~~~|          |~~~~~~T~~~~~~|           |~~~~~~T~~~~~~|
759995Shx147065  * |*head |*tail |\         |*head |*tail |\          |*head |*tail |
760995Shx147065  * ~~T~~~~~~~~~~~~ \        ~~T~~~~~~~~~~~~ \        /~~~~~~~~~~~~~~~\
761995Shx147065  *   |              \         V              V      /                 \
762995Shx147065  *   |               \        ...            ...   /                   \
763995Shx147065  *   V ae_t           V  ae_t             ae_t    V           ae_t      V
764995Shx147065  * |~~~~~~~~~T~~|  |~~~~~~~~~T~~|       |~~~~~~~~~T~~|      |~~~~~~~~~T~~|
765995Shx147065  * |"essid=  | -+->|"essid=  | -+->NULL |"essid=  | -+->..->|"wepkeyid| -+->NULL
766995Shx147065  * | ap7-3"  |  |  | linksys"|  |       | linksys"|  |      | =1"     |  |
767995Shx147065  * ~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~       ~~~~~~~~~~~~~~      ~~~~~~~~~~~~~~
768995Shx147065  *
769995Shx147065  */
770995Shx147065 
771995Shx147065 static config_file_t *
parse_file(const char * pfile)772995Shx147065 parse_file(const char *pfile)
773995Shx147065 {
774995Shx147065 	FILE *file = NULL;
775995Shx147065 	int fd = 0;
776995Shx147065 	char buf_line[256];
777995Shx147065 	config_file_t *p_config_file;
778995Shx147065 	list_type_t cur_list = OTHER;
779995Shx147065 	aelist_t *prefer_list = NULL;
780995Shx147065 	aelist_t *history_list = NULL;
781995Shx147065 	aelist_t *profile_list = NULL;
782995Shx147065 	aelist_t *activep_list = NULL;
783995Shx147065 
784995Shx147065 	assert(pfile != NULL);
785995Shx147065 	/*
786995Shx147065 	 * The files /etc/inet/wifi and /etc/inet/secret/wifiwepkey should
787995Shx147065 	 * be opened with "r" attribute. If these two files do not exist,
788995Shx147065 	 * create them here.
789995Shx147065 	 */
790995Shx147065 	file = fopen(pfile, "r");
791995Shx147065 
792995Shx147065 	if (file == NULL) {
793995Shx147065 		fd = open(pfile, O_CREAT|O_EXCL|O_RDWR, 0600);
794995Shx147065 		if (fd < 0) {
795995Shx147065 			(void) fprintf(stderr, gettext("%s: failed to open %s"
796995Shx147065 			    "\n"), gExecName, pfile);
797995Shx147065 			goto error1;
798995Shx147065 		}
799995Shx147065 		file = fdopen(fd, "w");
800995Shx147065 		(void) chmod(pfile, S_IRUSR);
801995Shx147065 	}
802995Shx147065 
803995Shx147065 	p_config_file = new_config_file();
804995Shx147065 
805995Shx147065 	while (fgets(buf_line, sizeof (buf_line), file) != NULL) {
806995Shx147065 		if ((buf_line[0] == '\n') || (buf_line[0] == ' '))
807995Shx147065 			continue;
808995Shx147065 		/* replace the old '\n' to '\0' */
809995Shx147065 		buf_line[strlen(buf_line) - 1] = '\0';
810995Shx147065 		if (strstr(buf_line, WIFI_PREFER) == buf_line) {
811995Shx147065 			if (prefer_list == NULL) {
812995Shx147065 				cur_list = PREFERENCE;
813995Shx147065 				prefer_list = new_ael(PREFERENCE);
814995Shx147065 				new_section(p_config_file, prefer_list,
815995Shx147065 				    WIFI_PREFER);
816995Shx147065 			} else {
817995Shx147065 				(void) fprintf(stderr, gettext("%s: "
818995Shx147065 				    "%s : duplicated %s section\n"),
819995Shx147065 				    gExecName, pfile, WIFI_PREFER);
820995Shx147065 				goto error;
821995Shx147065 			}
822995Shx147065 		} else if (strstr(buf_line, WIFI_HISTORY) == buf_line) {
823995Shx147065 			if (history_list == NULL) {
824995Shx147065 				cur_list = HISTORY;
825995Shx147065 				history_list = new_ael(HISTORY);
826995Shx147065 				new_section(p_config_file, history_list,
827995Shx147065 				    WIFI_HISTORY);
828995Shx147065 			} else {
829995Shx147065 				(void) fprintf(stderr, gettext("%s: "
830995Shx147065 				    "%s : duplicated %s section\n"),
831995Shx147065 				    gExecName, pfile, WIFI_HISTORY);
832995Shx147065 				goto error;
833995Shx147065 			}
834995Shx147065 		} else if (strstr(buf_line, WIFI_ACTIVEP) == buf_line) {
835995Shx147065 			if (activep_list == NULL) {
836995Shx147065 				cur_list = ACTIVEP;
837995Shx147065 				activep_list = new_ael(ACTIVEP);
838995Shx147065 				new_section(p_config_file, activep_list,
839995Shx147065 				    WIFI_ACTIVEP);
840995Shx147065 			} else {
841995Shx147065 				(void) fprintf(stderr, gettext("%s: "
842995Shx147065 				    "%s : duplicated %s section\n"),
843995Shx147065 				    gExecName, pfile, WIFI_ACTIVEP);
844995Shx147065 				goto error;
845995Shx147065 			}
846995Shx147065 		} else if ((strchr(buf_line, '[') == buf_line) &&
847995Shx147065 		    (buf_line[strlen(buf_line) - 1] == ']')) {
848995Shx147065 			cur_list = PROFILE;
849995Shx147065 			profile_list = new_ael(PROFILE);
850995Shx147065 			new_section(p_config_file, profile_list,
851995Shx147065 			    buf_line);
852995Shx147065 		} else {
853995Shx147065 			switch (cur_list) {
854995Shx147065 			case PREFERENCE:
855995Shx147065 				if (prefer_list->ael_argc <=
856995Shx147065 				    MAX_PREFERENCE_NUM)
857995Shx147065 					new_ae(prefer_list, buf_line);
858995Shx147065 				break;
859995Shx147065 			case HISTORY:
860995Shx147065 				if (history_list->ael_argc <=
861995Shx147065 				    MAX_HISTORY_NUM)
862995Shx147065 					new_ae(history_list, buf_line);
863995Shx147065 				break;
864995Shx147065 			case ACTIVEP:
865995Shx147065 				if ((activep_list->ael_argc <= 1) &&
866995Shx147065 				    (strpbrk(buf_line, "=") != NULL))
867995Shx147065 					new_ae(activep_list, buf_line);
868995Shx147065 				break;
869995Shx147065 			case PROFILE:
870995Shx147065 				if (strpbrk(buf_line, "=") != NULL)
871995Shx147065 					new_ae(profile_list, buf_line);
872995Shx147065 				break;
873995Shx147065 			default:
874995Shx147065 				(void) fprintf(stderr,
875995Shx147065 				    gettext("%s: %s: file format error\n"),
876995Shx147065 				    gExecName, pfile);
877995Shx147065 				goto error;
878995Shx147065 			}
879995Shx147065 		}
880995Shx147065 	}
881995Shx147065 	PRTDBG(("parse_file(\"%s\")=0x%x\n", pfile, p_config_file));
882995Shx147065 	(void) fclose(file);
883995Shx147065 	return (p_config_file);
884995Shx147065 error:
885995Shx147065 	destroy_config(p_config_file);
886995Shx147065 	(void) fclose(file);
887995Shx147065 error1:
888995Shx147065 	return (NULL);
889995Shx147065 }
890995Shx147065 /*
891995Shx147065  * construct an argument vector from an aelist
892995Shx147065  */
893995Shx147065 static char **
aeltoargv(aelist_t * ael,int * ael_num)894995Shx147065 aeltoargv(aelist_t *ael, int *ael_num)
895995Shx147065 {
896995Shx147065 	ae_t *ae = NULL;
897995Shx147065 	char **argv = NULL;
898995Shx147065 	int argc = 0;
899995Shx147065 
900995Shx147065 	PRTDBG(("aeltoargv(%x)\n", ael));
901995Shx147065 	assert(ael != NULL);
902995Shx147065 
903995Shx147065 	argv = safe_calloc(sizeof (*argv), ael->ael_argc);
904995Shx147065 
905995Shx147065 	for (argc = 0, ae = ael->ael_head; ae; ae = ae->ae_next) {
906995Shx147065 		/* skip bssid since it can not be set */
907995Shx147065 		if (strncmp(ae->ae_arg, "bssid=", strlen("bssid=")) == 0)
908995Shx147065 			continue;
909995Shx147065 		argv[argc] = safe_strdup(ae->ae_arg);
910995Shx147065 		argc++;
911995Shx147065 		if (ae == ael->ael_tail)
912995Shx147065 			break;
913995Shx147065 	}
914995Shx147065 
915995Shx147065 	PRTDBG(("aeltoargv(0x%x) = 0x%x\n\n", ael, argv));
916995Shx147065 	*ael_num = argc;
917995Shx147065 	return (argv);
918995Shx147065 }
919995Shx147065 
920995Shx147065 /*
921995Shx147065  * archived contents into a file
922995Shx147065  */
923995Shx147065 static boolean_t
fprint_config_file(config_file_t * p_config_file,const char * file_name)924995Shx147065 fprint_config_file(config_file_t *p_config_file, const char *file_name)
925995Shx147065 {
926995Shx147065 	FILE *file = NULL;
927995Shx147065 	int fd = 0;
928995Shx147065 	int len;
929995Shx147065 	section_t *p_section = NULL;
930995Shx147065 	aelist_t *p_list = NULL;
931995Shx147065 	ae_t *pae = NULL;
932995Shx147065 	char temp_file[256];
933995Shx147065 	struct stat buf;
934995Shx147065 
935995Shx147065 	PRTDBG(("fprint_config_file(0x%x, \"%s\")\n", p_config_file,
936*6834Sff224033 	    file_name));
937995Shx147065 	assert((p_config_file != NULL)&&(strcmp(file_name, "") != 0));
938995Shx147065 
939995Shx147065 	safe_snprintf(temp_file, sizeof (temp_file),
940995Shx147065 	    "%s.tmp", file_name);
941995Shx147065 	fd = open(temp_file, O_CREAT|O_WRONLY|O_TRUNC, 0600);
942995Shx147065 	if (fd < 0) {
943995Shx147065 		(void) fprintf(stderr, gettext("%s: failed to open %s\n"),
944995Shx147065 		    gExecName, temp_file);
945995Shx147065 		return (B_FALSE);
946995Shx147065 	}
947995Shx147065 	file = fdopen(fd, "w");
948995Shx147065 
949995Shx147065 	p_section = p_config_file->section_head;
950995Shx147065 	while (p_section != NULL) {
951995Shx147065 		p_list = p_section->list;
952995Shx147065 		if (p_list != NULL) {
953995Shx147065 			PRTDBG(("fprint_config_file: section_id=%s\n",
954995Shx147065 			    p_section->section_id));
955995Shx147065 			len = fprintf(file, "\n%s\n", p_section->section_id);
956995Shx147065 			if (len < 0) {
957995Shx147065 				(void) fprintf(stderr, gettext("%s: "
958995Shx147065 				    "failed to update %s: %s\n"),
959995Shx147065 				    gExecName, file_name, strerror(errno));
960995Shx147065 				safe_fclose(file);
961995Shx147065 				return (B_FALSE);
962995Shx147065 			}
963995Shx147065 			pae = p_list->ael_head;
964995Shx147065 			while (pae != NULL) {
965995Shx147065 				if (pae->ae_arg != NULL) {
966995Shx147065 					len = fprintf(file, "%s\n",
967995Shx147065 					    pae->ae_arg);
968995Shx147065 					if (len < 0) {
969995Shx147065 						(void) fprintf(stderr,
970995Shx147065 						    gettext("%s: failed to "
971995Shx147065 						    "update %s: %s\n"),
972995Shx147065 						    gExecName, file_name,
973995Shx147065 						    strerror(errno));
974995Shx147065 						safe_fclose(file);
975995Shx147065 						return (B_FALSE);
976995Shx147065 					}
977995Shx147065 				}
978995Shx147065 				pae = pae->ae_next;
979995Shx147065 			}
980995Shx147065 		}
981995Shx147065 		p_section = p_section->section_next;
982995Shx147065 	}
983995Shx147065 	safe_fclose(file);
984995Shx147065 	/*
985995Shx147065 	 * The attribute of the file /etc/inet/wifi and
986995Shx147065 	 * /etc/inet/security/wifiwepkey should be retained.
987995Shx147065 	 * if those file do not exist, set default file mode.
988995Shx147065 	 */
989995Shx147065 	if (stat(file_name, &buf) != 0) {
990995Shx147065 		if (errno == ENOENT) {
991995Shx147065 			buf.st_mode = 0600;
992995Shx147065 		} else {
993995Shx147065 			(void) fprintf(stderr, gettext("%s: failed to get "
994995Shx147065 			    "file %s stat: %s\n"),
995995Shx147065 			    gExecName, file_name, strerror(errno));
996995Shx147065 			return (B_FALSE);
997995Shx147065 		}
998995Shx147065 	}
999995Shx147065 	if (rename(temp_file, file_name) != 0) {
1000995Shx147065 		(void) fprintf(stderr, gettext("%s: failed to update %s: %s"
1001995Shx147065 		    "\n"), gExecName, file_name, strerror(errno));
1002995Shx147065 		return (B_FALSE);
1003995Shx147065 	}
1004995Shx147065 	(void) chmod(file_name, buf.st_mode);
1005995Shx147065 	return (B_TRUE);
1006995Shx147065 }
1007995Shx147065 /*
1008995Shx147065  * append_pa: Each section holds a section_id which identifies a section
1009995Shx147065  * a profile uses its essid appending "[]" to denote its section_id.
1010995Shx147065  * note: new memory is allocated, remember to free.
1011995Shx147065  */
1012995Shx147065 static char *
append_pa(const char * arg)1013995Shx147065 append_pa(const char *arg)
1014995Shx147065 {
1015995Shx147065 	char *pbuf = NULL;
1016995Shx147065 	int len;
1017995Shx147065 
1018995Shx147065 	assert(arg != NULL);
1019995Shx147065 
1020995Shx147065 	len = strlen(arg) + 3;
1021995Shx147065 	pbuf = safe_malloc(len);
1022995Shx147065 	safe_snprintf(pbuf, len, "[%s]", arg);
1023995Shx147065 	PRTDBG(("append_pa(\"%s\") = \"%s\"\n", arg, pbuf));
1024995Shx147065 	return (pbuf);
1025995Shx147065 }
1026995Shx147065 /*
1027995Shx147065  * find a section by section_id from p_config_file,
1028995Shx147065  * return the section pointer.
1029995Shx147065  */
1030995Shx147065 static section_t *
find_section(config_file_t * p_config_file,const char * section_id)1031995Shx147065 find_section(config_file_t *p_config_file, const char *section_id)
1032995Shx147065 {
1033995Shx147065 	section_t *p_section = NULL;
1034995Shx147065 
1035995Shx147065 	PRTDBG(("find_section(0x%x, \"%s\")\n", p_config_file, section_id));
1036995Shx147065 	assert((section_id != NULL)&&(p_config_file != NULL));
1037995Shx147065 
1038995Shx147065 	p_section = p_config_file->section_head;
1039995Shx147065 
1040995Shx147065 	while (p_section != NULL) {
1041995Shx147065 		if ((p_section->section_id != NULL) &&
1042995Shx147065 		    (strcmp(p_section->section_id, section_id) == 0))
1043995Shx147065 			return (p_section);
1044995Shx147065 		p_section = p_section->section_next;
1045995Shx147065 	}
1046995Shx147065 	return (NULL);
1047995Shx147065 }
1048995Shx147065 
1049995Shx147065 /*
1050995Shx147065  * get_value: Get rid of "parameter=" from a "parameter=value", for example:
1051995Shx147065  * when we read an line from file, we gets "essid=ap7-2", this function
1052995Shx147065  * returns the pointer to string "ap7-2";
1053995Shx147065  */
1054995Shx147065 
1055995Shx147065 static const char *
get_value(const char * arg)1056995Shx147065 get_value(const char *arg)
1057995Shx147065 {
1058995Shx147065 	char *p;
1059995Shx147065 	assert(arg != NULL);
1060995Shx147065 
1061995Shx147065 	p = strchr(arg, '=');
1062995Shx147065 	PRTDBG(("get_value(\"%s\") = \"%s\"\n", arg, p + 1));
1063995Shx147065 	if (p != NULL)
1064995Shx147065 		return (p + 1);
1065995Shx147065 	else
1066995Shx147065 		return (NULL);
1067995Shx147065 }
1068995Shx147065 
1069995Shx147065 /*
1070995Shx147065  * search /dev/wifi to see which interface is available
1071995Shx147065  */
1072995Shx147065 static boolean_t
search_interface(char * interface)1073995Shx147065 search_interface(char *interface)
1074995Shx147065 {
1075995Shx147065 	DIR *dirp;
1076995Shx147065 	struct dirent *dp;
1077995Shx147065 	char buf[256];
1078995Shx147065 	int fd;
1079995Shx147065 
1080995Shx147065 	PRTDBG(("search interface\n"));
1081995Shx147065 	assert(interface != NULL);
1082995Shx147065 
1083995Shx147065 	/*
1084995Shx147065 	 * Try to return the first found wifi interface.
1085995Shx147065 	 * If no wifi interface is available, return B_FALSE
1086995Shx147065 	 */
1087995Shx147065 
1088995Shx147065 	if ((dirp = opendir("/dev/wifi")) == NULL) {
1089995Shx147065 		PRTDBG(("failed to open '/dev/wifi'\n"));
1090995Shx147065 		return (B_FALSE);
1091995Shx147065 	}
1092995Shx147065 	while ((dp = readdir(dirp)) != NULL) {
1093995Shx147065 		if (strcmp(dp->d_name, ".") == 0 ||
1094995Shx147065 		    strcmp(dp->d_name, "..") == 0)
1095995Shx147065 			continue;
1096995Shx147065 		if (dp->d_name[strlen(dp->d_name) - 1] < '0' ||
1097995Shx147065 		    dp->d_name[strlen(dp->d_name) - 1] > '9')
1098995Shx147065 			continue;
1099995Shx147065 		safe_snprintf(buf, sizeof (buf), "%s%s",
1100995Shx147065 		    "/dev/wifi/", dp->d_name);
1101995Shx147065 		fd = open(buf, O_RDWR);
1102995Shx147065 		if (fd == -1) {
1103995Shx147065 			PRTDBG(("interface %s doesn't exist\n", dp->d_name));
1104995Shx147065 			continue;
1105995Shx147065 		} else {
1106995Shx147065 			PRTDBG(("interface %s is the first found interface\n",
1107995Shx147065 			    dp->d_name));
1108995Shx147065 			(void) strlcpy(interface, buf, LIFNAMSIZ);
1109995Shx147065 			(void) close(fd);
1110995Shx147065 			(void) closedir(dirp);
1111995Shx147065 			return (B_TRUE);
1112995Shx147065 		}
1113995Shx147065 	}
1114995Shx147065 
1115995Shx147065 	PRTDBG(("failed to find available wireless interface\n"));
1116995Shx147065 	(void) closedir(dirp);
1117995Shx147065 	return (B_FALSE);
1118995Shx147065 
1119995Shx147065 }
1120995Shx147065 /*
1121995Shx147065  * open_dev: Open the driver.
1122995Shx147065  * if the 'devname' has format like 'ath0', we should add the path to that
1123995Shx147065  * device(/dev/ath0) and open it; if the 'devname' has format like
1124995Shx147065  * '/dev/wifi/ath0', we open it directly.
1125995Shx147065  */
1126995Shx147065 static int
open_dev(char * devname)1127995Shx147065 open_dev(char *devname)
1128995Shx147065 {
1129995Shx147065 	int fd;
1130995Shx147065 	int len;
1131995Shx147065 	char *pbuf = NULL;
1132995Shx147065 
1133995Shx147065 	PRTDBG(("open_dev(\"%s\")\n", devname));
1134995Shx147065 	assert(devname != NULL);
1135995Shx147065 	/*
1136995Shx147065 	 * If the devname is got from the user input, we
1137995Shx147065 	 * add '/dev/' to that relative devname. If it
1138995Shx147065 	 * is got from the 'search interface', it is an
1139995Shx147065 	 * absolute path.
1140995Shx147065 	 */
1141995Shx147065 	if (strncmp(devname, "/dev/wifi/", strlen("/dev/wifi/")) == 0) {
1142995Shx147065 		pbuf = safe_strdup(devname);
1143995Shx147065 	} else {
1144995Shx147065 		len = strlen(devname) + strlen("/dev/") + 1;
1145995Shx147065 		pbuf = safe_malloc(len);
1146995Shx147065 		safe_snprintf(pbuf, len, "/dev/%s", devname);
1147995Shx147065 	}
1148995Shx147065 	fd = open(pbuf, O_RDWR);
1149995Shx147065 	free(pbuf);
1150995Shx147065 
1151995Shx147065 	if (fd == -1) {
1152995Shx147065 		(void) fprintf(stderr, gettext("%s: failed to open '%s': %s"
1153995Shx147065 		    "\n"), gExecName, devname, strerror(errno));
1154995Shx147065 		return (-1);
1155995Shx147065 	}
1156995Shx147065 	if (!isastream(fd)) {
1157995Shx147065 		(void) fprintf(stderr, gettext("%s: %s is "
1158995Shx147065 		    "not a stream device\n"),
1159995Shx147065 		    gExecName, devname);
1160995Shx147065 		(void) close(fd);
1161995Shx147065 		return (-1);
1162995Shx147065 	}
1163995Shx147065 	return (fd);
1164995Shx147065 }
1165995Shx147065 /*
1166995Shx147065  * call_ioctl: Fill strioctl structure and issue an ioctl system call
1167995Shx147065  */
1168995Shx147065 static boolean_t
call_ioctl(int fd,int cmd,uint32_t params,uint32_t buf_len)1169995Shx147065 call_ioctl(int fd, int cmd, uint32_t params, uint32_t buf_len)
1170995Shx147065 {
1171995Shx147065 	struct strioctl stri;
1172995Shx147065 
1173995Shx147065 	PRTDBG(("call_ioctl_gs(%d, 0x%x, 0x%x, 0x%x)\n",
1174995Shx147065 	    fd, cmd, params, buf_len));
1175995Shx147065 
1176995Shx147065 	switch (cmd) {
1177995Shx147065 	case WLAN_GET_PARAM:
1178995Shx147065 		(void) memset(gbuf, 0, MAX_BUF_LEN);
1179995Shx147065 		stri.ic_len = MAX_BUF_LEN;
1180995Shx147065 		break;
1181995Shx147065 	case WLAN_SET_PARAM:
1182995Shx147065 		gbuf->wldp_length = buf_len + WIFI_BUF_OFFSET;
1183995Shx147065 		stri.ic_len = gbuf->wldp_length;
1184995Shx147065 		break;
1185995Shx147065 	case WLAN_COMMAND:
1186995Shx147065 		gbuf->wldp_length = sizeof (wldp_t);
1187995Shx147065 		stri.ic_len = gbuf->wldp_length;
1188995Shx147065 		break;
1189995Shx147065 	default:
1190995Shx147065 		(void) fprintf(stderr, gettext("%s: ioctl : "
1191995Shx147065 		    "unsupported ioctl command\n"), gExecName);
1192995Shx147065 		return (B_FALSE);
1193995Shx147065 	}
1194995Shx147065 	gbuf->wldp_type = NET_802_11;
1195995Shx147065 	gbuf->wldp_id = params;
1196995Shx147065 
1197995Shx147065 	stri.ic_cmd = cmd;
1198995Shx147065 	stri.ic_timout = 0;
1199995Shx147065 	stri.ic_dp = (char *)gbuf;
1200995Shx147065 
1201995Shx147065 	if (ioctl(fd, I_STR, &stri) == -1) {
1202995Shx147065 		gbuf->wldp_result = 0xffff;
1203995Shx147065 		return (B_FALSE);
1204995Shx147065 	}
1205995Shx147065 	if (cmd == WLAN_COMMAND) {
1206995Shx147065 		return (B_TRUE);
1207995Shx147065 	} else {
1208995Shx147065 		return (gbuf->wldp_result != WL_SUCCESS ?
1209*6834Sff224033 		    B_FALSE:B_TRUE);
1210995Shx147065 	}
1211995Shx147065 }
1212995Shx147065 
1213995Shx147065 /*
1214995Shx147065  * del_prefer: Delete an item from the {preferrence} list, the idea is
1215995Shx147065  * simply free the ae_t element, and set ae_arg to NULL, then when archive
1216995Shx147065  * the config_file_t struct to the file, it will be delete.
1217995Shx147065  * The last flag is used to identify whether this function is invoked due to
1218995Shx147065  * the 'removeprefer' subcommand or due to 'deleteprofile' subcommand.
1219995Shx147065  */
1220995Shx147065 static boolean_t
del_prefer(config_file_t * p_config_file,const char * prefer,boolean_t rflag)1221995Shx147065 del_prefer(config_file_t *p_config_file, const char *prefer, boolean_t rflag)
1222995Shx147065 {
1223995Shx147065 	section_t *p_section = NULL;
1224995Shx147065 	aelist_t *plist = NULL;
1225995Shx147065 	ae_t *pae = NULL;
1226995Shx147065 	int i = 0, position = 0;
1227995Shx147065 	int number;
1228995Shx147065 	ae_t *prm_ae = NULL;
1229995Shx147065 
1230995Shx147065 	PRTDBG(("del_prefer(0x%x, \"%s\")\n", p_config_file, prefer));
1231995Shx147065 	assert((prefer != NULL)&&(p_config_file != NULL));
1232995Shx147065 
1233995Shx147065 	p_section = find_section(p_config_file, WIFI_PREFER);
1234995Shx147065 	if (p_section != NULL)
1235995Shx147065 		plist = p_section->list;
1236995Shx147065 
1237995Shx147065 	if ((p_section == NULL) || (plist == NULL))
1238995Shx147065 		return (B_FALSE);
1239995Shx147065 
1240995Shx147065 	number = plist->ael_argc;
1241995Shx147065 	pae = plist->ael_head;
1242995Shx147065 	prm_ae = plist->ael_head;
1243995Shx147065 	while (pae != NULL) {
1244995Shx147065 		if (strcmp(prefer, pae->ae_arg) == 0) {
1245995Shx147065 			free(pae->ae_arg);
1246995Shx147065 			pae->ae_arg = NULL; /* mark */
1247995Shx147065 			if (!position) {
1248995Shx147065 				plist->ael_head = pae->ae_next;
1249995Shx147065 				if (pae->ae_next == NULL)
1250995Shx147065 					plist->ael_tail = NULL;
1251995Shx147065 			} else {
1252995Shx147065 				for (i = 0; i < position - 1; i++)
1253995Shx147065 					prm_ae = prm_ae->ae_next;
1254995Shx147065 				prm_ae->ae_next = pae->ae_next;
1255995Shx147065 				if (pae->ae_next == NULL)
1256995Shx147065 					plist->ael_tail = prm_ae;
1257995Shx147065 			}
1258995Shx147065 			free(pae);
1259995Shx147065 			pae = NULL;
1260995Shx147065 			plist->ael_argc--;
1261995Shx147065 			break;
1262995Shx147065 		}
1263995Shx147065 		position++;
1264995Shx147065 		pae = pae->ae_next;
1265995Shx147065 	}
1266995Shx147065 	if ((number == plist->ael_argc) && (rflag == B_TRUE)) {
1267995Shx147065 		(void) fprintf(stderr, gettext("%s: removeprefer : "
1268995Shx147065 		    "no such profile: '%s' in the preference list\n"),
1269995Shx147065 		    gExecName, prefer);
1270995Shx147065 		return (B_FALSE);
1271995Shx147065 	}
1272995Shx147065 	return (B_TRUE);
1273995Shx147065 }
1274995Shx147065 
1275995Shx147065 /*
1276995Shx147065  * del_section: Delete an section from p_config_file, the idea is
1277995Shx147065  * simply free the aelist_t struct and set it to NULL, when archiving
1278995Shx147065  * config_file_t struct to the file, we will find section list is NULL,
1279995Shx147065  * and will not write it to file, so it will be deleted.
1280995Shx147065  */
1281995Shx147065 static boolean_t
del_section(config_file_t * p_config_file,char * section_id)1282995Shx147065 del_section(config_file_t *p_config_file, char *section_id)
1283995Shx147065 {
1284995Shx147065 	section_t *p_section = NULL;
1285995Shx147065 	section_t *prm_section = NULL;
1286995Shx147065 	aelist_t *plist = NULL;
1287995Shx147065 	ae_t *pae = NULL;
1288995Shx147065 	int i = 0, position = 0;
1289995Shx147065 
1290995Shx147065 	PRTDBG(("del_section(0x%x, \"%s\")\n", p_config_file, section_id));
1291995Shx147065 	PRTDBG(("del_section: %d section(s) in config file\n",
1292995Shx147065 	    p_config_file->section_argc));
1293995Shx147065 	assert((section_id != NULL)&&(p_config_file != NULL));
1294995Shx147065 
1295995Shx147065 	if (find_section(p_config_file, section_id) == NULL) {
1296995Shx147065 		return (B_FALSE);
1297995Shx147065 	}
1298995Shx147065 	p_section = p_config_file->section_head;
1299995Shx147065 	prm_section = p_config_file->section_head;
1300995Shx147065 	while (p_section != NULL) {
1301995Shx147065 		if (p_section->section_id != NULL) {
1302995Shx147065 			if (strcmp(p_section->section_id, section_id) == 0) {
1303995Shx147065 				plist = p_section->list;
1304995Shx147065 				pae = plist->ael_head;
1305995Shx147065 				while (pae != NULL) {
1306995Shx147065 					free(pae->ae_arg);
1307995Shx147065 					pae->ae_arg = NULL;
1308995Shx147065 					pae = pae->ae_next;
1309995Shx147065 					free(plist->ael_head);
1310995Shx147065 					plist->ael_head = pae;
1311995Shx147065 				}
1312995Shx147065 				free(plist);
1313995Shx147065 				p_section->list = NULL;
1314995Shx147065 				free(p_section->section_id);
1315995Shx147065 				p_section->section_id = NULL;
1316995Shx147065 
1317995Shx147065 				if (!position) {
1318995Shx147065 					p_config_file->section_head =
1319995Shx147065 					    p_section->section_next;
1320995Shx147065 					if (p_section->section_next == NULL)
1321995Shx147065 						p_config_file->section_tail =
1322995Shx147065 						    NULL;
1323995Shx147065 				} else {
1324995Shx147065 					for (i = 0; i < position - 1; i++) {
1325995Shx147065 						prm_section =
1326995Shx147065 						    prm_section->section_next;
1327995Shx147065 					}
1328995Shx147065 					prm_section->section_next =
1329995Shx147065 					    p_section->section_next;
1330995Shx147065 					if (p_section->section_next == NULL)
1331995Shx147065 						p_config_file->section_tail =
1332995Shx147065 						    prm_section;
1333995Shx147065 				}
1334995Shx147065 				free(p_section);
1335995Shx147065 				p_config_file->section_argc--;
1336995Shx147065 				break;
1337995Shx147065 			}
1338995Shx147065 			position++;
1339995Shx147065 		}
1340995Shx147065 		p_section = p_section->section_next;
1341995Shx147065 	}
1342995Shx147065 	return (B_TRUE);
1343995Shx147065 }
1344995Shx147065 
1345995Shx147065 /*
1346995Shx147065  * set_prefer: Reorder the preferrence list.
1347995Shx147065  */
1348995Shx147065 static boolean_t
set_prefer(config_file_t * p_config_file,const char * prefer,int rank)1349995Shx147065 set_prefer(config_file_t *p_config_file, const char *prefer, int rank)
1350995Shx147065 {
1351995Shx147065 	char *pbuf = NULL;
1352995Shx147065 	aelist_t *plist = NULL;
1353995Shx147065 	section_t *p_section = NULL;
1354995Shx147065 	ae_t *pae = NULL;
1355995Shx147065 	int i = 0, position = 0;
1356995Shx147065 	ae_t *pae_move = NULL;
1357995Shx147065 
1358995Shx147065 	assert(prefer != NULL);
1359995Shx147065 	PRTDBG(("set_prefer(0x%x, \"%s\", %d)\n", p_config_file, prefer, rank));
1360995Shx147065 
1361995Shx147065 	pbuf = append_pa(prefer);
1362995Shx147065 	if (find_section(p_config_file, pbuf) == NULL) {
1363995Shx147065 		(void) fprintf(stderr, gettext("%s: setprefer: "
1364995Shx147065 		    "no such profile: '%s'\n"),
1365995Shx147065 		    gExecName, prefer);
1366995Shx147065 		free(pbuf);
1367995Shx147065 		return (B_FALSE);
1368995Shx147065 	}
1369995Shx147065 	free(pbuf);
1370995Shx147065 
1371995Shx147065 	p_section = find_section(p_config_file, WIFI_PREFER);
1372995Shx147065 
1373995Shx147065 	if (p_section == NULL) {
1374995Shx147065 		plist = new_ael(PREFERENCE);
1375995Shx147065 		new_section(p_config_file, plist, WIFI_PREFER);
1376995Shx147065 		new_ae(plist, prefer);
1377995Shx147065 		return (B_TRUE);
1378995Shx147065 	} else {
1379995Shx147065 		plist = p_section->list;
1380995Shx147065 	}
1381995Shx147065 
1382995Shx147065 	pae = plist->ael_head;
1383995Shx147065 	pae_move = plist->ael_head;
1384995Shx147065 	while (pae != NULL) {
1385995Shx147065 		if (strcmp(prefer, pae->ae_arg) == 0) {
1386995Shx147065 			free(pae->ae_arg);
1387995Shx147065 			pae->ae_arg = NULL;
1388995Shx147065 			if (!position) {
1389995Shx147065 				plist->ael_head = pae->ae_next;
1390995Shx147065 				if (pae->ae_next == NULL)
1391995Shx147065 					plist->ael_tail = NULL;
1392995Shx147065 			} else {
1393995Shx147065 				for (i = 0; i < position - 1; i++)
1394995Shx147065 					pae_move = pae_move->ae_next;
1395995Shx147065 				pae_move->ae_next = pae->ae_next;
1396995Shx147065 				if (pae->ae_next == NULL)
1397995Shx147065 					plist->ael_tail = pae_move;
1398995Shx147065 			}
1399995Shx147065 			free(pae);
1400995Shx147065 			plist->ael_argc--;
1401995Shx147065 			break;
1402995Shx147065 		}
1403995Shx147065 		position++;
1404995Shx147065 		pae = pae->ae_next;
1405995Shx147065 	}
1406995Shx147065 	PRTDBG(("set_prefer: %d Profiles in prefer list\n", plist->ael_argc));
1407995Shx147065 	if (rank > plist->ael_argc) {
1408995Shx147065 		new_ae(plist, prefer);
1409995Shx147065 	} else if (rank <= 1) {
1410995Shx147065 		pae = safe_calloc(sizeof (ae_t), 1);
1411995Shx147065 		pae->ae_arg = safe_strdup(prefer);
1412995Shx147065 		pae->ae_next = plist->ael_head;
1413995Shx147065 		plist->ael_head = pae;
1414995Shx147065 		plist->ael_argc++;
1415995Shx147065 	} else {
1416995Shx147065 		pae_move = plist->ael_head;
1417995Shx147065 		for (i = 1; i < rank-1; i++) {
1418995Shx147065 			pae_move = pae_move->ae_next;
1419995Shx147065 		}
1420995Shx147065 		pae = safe_calloc(sizeof (ae_t), 1);
1421995Shx147065 		pae->ae_arg = safe_strdup(prefer);
1422995Shx147065 		pae->ae_next = pae_move->ae_next;
1423995Shx147065 		pae_move->ae_next = pae;
1424995Shx147065 		plist->ael_argc++;
1425995Shx147065 	}
1426995Shx147065 	/*
1427995Shx147065 	 * If number of prefer list items is larger than the MAX_PREFERENCE_NUM
1428995Shx147065 	 * delete those items whose No is larger than MAX_PREFERENCE_NUM.
1429995Shx147065 	 */
1430995Shx147065 	if (plist->ael_argc > MAX_PREFERENCE_NUM) {
1431995Shx147065 		pae = plist->ael_head;
1432995Shx147065 		while (pae->ae_next != plist->ael_tail)
1433995Shx147065 			pae = pae->ae_next;
1434995Shx147065 		free(plist->ael_tail->ae_arg);
1435995Shx147065 		plist->ael_tail->ae_arg = NULL;
1436995Shx147065 		free(plist->ael_tail);
1437995Shx147065 		plist->ael_tail = pae;
1438995Shx147065 		plist->ael_tail->ae_next = NULL;
1439995Shx147065 		plist->ael_argc--;
1440995Shx147065 	}
1441995Shx147065 	PRTDBG(("set_prefer: %d Profiles in prefer list\n", plist->ael_argc));
1442995Shx147065 	return (B_TRUE);
1443995Shx147065 }
1444995Shx147065 /*
1445995Shx147065  * add_to_history: Save the scanlist argv into history section
1446995Shx147065  */
1447995Shx147065 static void
add_to_history(config_file_t * p_config_file,int argc,char ** argv)1448995Shx147065 add_to_history(config_file_t *p_config_file, int argc, char **argv)
1449995Shx147065 {
1450995Shx147065 	int i = 0, j = 0, pos = 0;
1451995Shx147065 	aelist_t *plist = NULL;
1452995Shx147065 	section_t *p_section = NULL;
1453995Shx147065 	ae_t *pae = NULL;
1454995Shx147065 	ae_t *pae_m = NULL;
1455995Shx147065 	char item[256];
1456995Shx147065 	time_t cltime;
1457995Shx147065 
1458995Shx147065 	PRTDBG(("add_to_history(0x%x, %d, 0x%x)\n", p_config_file, argc, argv));
1459995Shx147065 	assert(p_config_file != NULL);
1460995Shx147065 
1461995Shx147065 	p_section = find_section(p_config_file, WIFI_HISTORY);
1462995Shx147065 
1463995Shx147065 	if (p_section == NULL) {
1464995Shx147065 		plist = new_ael(HISTORY);
1465995Shx147065 		new_section(p_config_file, plist, WIFI_HISTORY);
1466995Shx147065 	} else {
1467995Shx147065 		plist = p_section->list;
1468995Shx147065 	}
1469995Shx147065 
1470995Shx147065 	if (plist != NULL) {
1471995Shx147065 		for (i = 0; i < argc; i++) {
1472995Shx147065 			if (!strlen(argv[i]))
1473995Shx147065 				continue;
1474995Shx147065 			pos = 0;
1475995Shx147065 			pae = plist->ael_head;
1476995Shx147065 			pae_m = plist->ael_head;
1477995Shx147065 			/*
1478995Shx147065 			 * add time stamp to the history record
1479995Shx147065 			 */
1480995Shx147065 			cltime = time(&cltime);
1481995Shx147065 			(void) snprintf(item, sizeof (item), "%s%c%ld",
1482995Shx147065 			    argv[i], ',', cltime);
1483995Shx147065 			while (pae != NULL) {
1484995Shx147065 				if (strncmp(item, pae->ae_arg,
1485995Shx147065 				    strlen(argv[i])) == 0) {
1486995Shx147065 					free(pae->ae_arg);
1487995Shx147065 					pae->ae_arg = NULL;
1488995Shx147065 					if (!pos) {
1489995Shx147065 						plist->ael_head = pae->ae_next;
1490995Shx147065 						if (pae->ae_next == NULL)
1491995Shx147065 							plist->ael_tail = NULL;
1492995Shx147065 					} else {
1493995Shx147065 						for (j = 0; j < pos - 1; j++)
1494995Shx147065 							pae_m = pae_m->ae_next;
1495995Shx147065 						pae_m->ae_next = pae->ae_next;
1496995Shx147065 						if (pae->ae_next == NULL)
1497995Shx147065 							plist->ael_tail = pae_m;
1498995Shx147065 					}
1499995Shx147065 					free(pae);
1500995Shx147065 					plist->ael_argc--;
1501995Shx147065 					break;
1502995Shx147065 				}
1503995Shx147065 				pos++;
1504995Shx147065 				pae = pae->ae_next;
1505995Shx147065 			}
1506995Shx147065 			new_ae(plist, item);
1507995Shx147065 		}
1508995Shx147065 
1509995Shx147065 		if (plist->ael_argc > MAX_HISTORY_NUM) {
1510995Shx147065 			for (i = 0; i < plist->ael_argc - MAX_HISTORY_NUM;
1511995Shx147065 			    i++) {
1512995Shx147065 				pae = plist->ael_head;
1513995Shx147065 				free(pae->ae_arg);
1514995Shx147065 				plist->ael_head = pae->ae_next;
1515995Shx147065 				free(pae);
1516995Shx147065 			}
1517995Shx147065 			plist->ael_argc = MAX_HISTORY_NUM;
1518995Shx147065 		}
1519995Shx147065 	}
1520995Shx147065 }
1521995Shx147065 
1522995Shx147065 static void
do_print_usage()1523995Shx147065 do_print_usage()
1524995Shx147065 {
1525995Shx147065 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1526995Shx147065 	    " autoconf [wait={n|forever}]\n"), gExecName);
1527995Shx147065 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1528995Shx147065 	    " connect profile [wait={n|forever}]\n"), gExecName);
1529995Shx147065 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1530995Shx147065 	    " connect essid [wait={n|forever}]\n"), gExecName);
1531995Shx147065 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1532995Shx147065 	    " disconnect\n"), gExecName);
1533995Shx147065 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1534995Shx147065 	    " getparam [parameter [...]]\n"), gExecName);
1535995Shx147065 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1536995Shx147065 	    " setparam [parameter=value [...]]\n"), gExecName);
1537995Shx147065 	(void) fprintf(stderr, gettext(
1538*6834Sff224033 	    "\tparameters:\n"
1539*6834Sff224033 	    "\t\tbssid\t\t - read only: 6 byte mac address of "
1540*6834Sff224033 	    "base station\n"
1541*6834Sff224033 	    "\t\tessid\t\t - name of the network, a string of up "
1542*6834Sff224033 	    "to 32 chars\n"
1543*6834Sff224033 	    "\t\tbsstype\t\t - bss(ap, infrastructure), ibss(ad-hoc)"
1544*6834Sff224033 	    " or auto\n"
1545*6834Sff224033 	    "\t\tcreateibss\t - flag to identify whether a ibss is to be\n"
1546*6834Sff224033 	    "\t\t\t\t   created when the network to connect is\n"
1547*6834Sff224033 	    "\t\t\t\t   not available, yes or no\n"
1548*6834Sff224033 	    "\t\tchannel\t\t - channel(used only when creating an ibss)\n"
1549*6834Sff224033 	    "\t\t\t\t   valid value:\n"
1550*6834Sff224033 	    "\t\t\t\t\t 802.11a: 0-99\n"
1551*6834Sff224033 	    "\t\t\t\t\t 802.11b: 1-14\n"
1552*6834Sff224033 	    "\t\t\t\t\t 802.11g: 1-14\n"
1553*6834Sff224033 	    "\t\trates\t\t - set of rates, seperated by ',' valid rates:\n"
1554*6834Sff224033 	    "\t\t\t\t   1,2,5.5,6,9,11,12,18,22,24,33,36,48 and 54\n"
1555*6834Sff224033 	    "\t\tpowermode\t - off, mps or fast\n"
1556*6834Sff224033 	    "\t\tauthmode\t - opensystem or shared_key\n"
1557*6834Sff224033 	    "\t\tencryption\t - none or wep\n"
1558*6834Sff224033 	    "\t\twepkey|1-4\t - write only:\n"
1559*6834Sff224033 	    "\t\t\t\t   5 chars or 10 hex digits for 40bit wepkey;\n"
1560*6834Sff224033 	    "\t\t\t\t   13 chars or 26 hex digits for 128bit wepkey\n"
1561*6834Sff224033 	    "\t\twepkeyindex\t - an integer within the range 1-4\n"
1562*6834Sff224033 	    "\t\tsignal\t\t - read only: signal strength from 0 to 15\n"
1563*6834Sff224033 	    "\t\tradio\t\t - on or off\n"));
1564995Shx147065 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1565995Shx147065 	    " restoredef\n"), gExecName);
1566995Shx147065 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1567995Shx147065 	    " scan\n"), gExecName);
1568995Shx147065 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1569995Shx147065 	    " showstatus\n"), gExecName);
1570995Shx147065 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1571995Shx147065 	    " setwepkey 1|2|3|4\n"), gExecName);
1572995Shx147065 
1573995Shx147065 	(void) fprintf(stderr, "\n");
1574995Shx147065 
1575995Shx147065 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1576995Shx147065 	    " createprofile profile parameter=value [...]\n"), gExecName);
1577995Shx147065 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1578995Shx147065 	    " deleteprofile profile1 [profile2 [...]]\n"), gExecName);
1579995Shx147065 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1580995Shx147065 	    " showprofile profile1 [profile2 [...]]\n"), gExecName);
1581995Shx147065 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1582995Shx147065 	    " setprofilewepkey profile 1|2|3|4\n"), gExecName);
1583995Shx147065 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1584995Shx147065 	    " getprofileparam profile [parameter [...]]\n"), gExecName);
1585995Shx147065 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1586995Shx147065 	    " setprofileparam profile [parameter=value [...]]\n"), gExecName);
1587995Shx147065 
1588995Shx147065 	(void) fprintf(stderr, "\n");
1589995Shx147065 
1590995Shx147065 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1591995Shx147065 	    " history\n"), gExecName);
1592995Shx147065 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1593995Shx147065 	    " listprefer\n"), gExecName);
1594995Shx147065 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1595995Shx147065 	    " removeprefer profile\n"), gExecName);
1596995Shx147065 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1597995Shx147065 	    " setprefer profile [n]\n"), gExecName);
1598995Shx147065 }
1599995Shx147065 
1600995Shx147065 /*
1601995Shx147065  * do_print_support_params: Query interface which cmd is supported
1602995Shx147065  */
1603995Shx147065 static boolean_t
do_print_support_params(int fd)1604995Shx147065 do_print_support_params(int fd)
1605995Shx147065 {
1606995Shx147065 	int i = 0, n = 0;
1607995Shx147065 
1608995Shx147065 	PRTDBG(("do_print_support_params(\"%d\")\n", fd));
1609995Shx147065 	assert(fd != -1);
1610995Shx147065 
1611995Shx147065 	(void) printf(gettext("\t  parameter\tproperty\n"));
1612995Shx147065 	for (i = 0; i < N_GS_FUNC; i++) {
1613995Shx147065 		gbuf->wldp_result = WL_LACK_FEATURE;
1614995Shx147065 		if ((do_gs_func[i].p_do_get_func != NULL) &&
1615995Shx147065 		    (do_gs_func[i].p_do_get_func(fd) != B_TRUE)) {
1616995Shx147065 				continue;
1617995Shx147065 		}
1618995Shx147065 		if (gbuf->wldp_result == WL_SUCCESS) {
1619995Shx147065 			(void) printf("\t%11s", do_gs_func[i].cmd);
1620995Shx147065 			if (do_gs_func[i].rw == RO)
1621995Shx147065 				(void) printf(gettext("\tread only\n"));
1622995Shx147065 			else
1623995Shx147065 				(void) printf(gettext("\tread/write\n"));
1624995Shx147065 			n++;
1625995Shx147065 		}
1626995Shx147065 	}
1627995Shx147065 
1628995Shx147065 	return (n ? B_TRUE : B_FALSE);
1629995Shx147065 }
1630995Shx147065 
1631995Shx147065 /*
1632995Shx147065  * check_authority: Check if command is permitted.
1633995Shx147065  */
1634995Shx147065 static boolean_t
check_authority(wifi_auth_t type)1635995Shx147065 check_authority(wifi_auth_t type)
1636995Shx147065 {
1637995Shx147065 	struct passwd *pw = NULL;
1638995Shx147065 
1639995Shx147065 	PRTDBG(("check_authority()\n"));
1640995Shx147065 
1641995Shx147065 	pw = getpwuid(getuid());
1642995Shx147065 	if (pw == NULL)
1643995Shx147065 		return (B_FALSE);
1644995Shx147065 	if (chkauthattr(p_auth_string[type], pw->pw_name) == 0) {
1645995Shx147065 		if (type == AUTH_WEP)
1646995Shx147065 			(void) fprintf(stderr, gettext("%s: "
1647995Shx147065 			    "privilege '%s' is required for setting "
1648995Shx147065 			    "wepkey.\n"), gExecName, WIFI_WEP_AUTH);
1649995Shx147065 		else
1650995Shx147065 			(void) fprintf(stderr, gettext("%s: "
1651995Shx147065 			    "privilege '%s' is required.\n"),
1652995Shx147065 			    gExecName, WIFI_CONFIG_AUTH);
1653995Shx147065 		return (B_FALSE);
1654995Shx147065 	} else {
1655995Shx147065 		return (B_TRUE);
1656995Shx147065 	}
1657995Shx147065 }
1658995Shx147065 
1659995Shx147065 /*
1660995Shx147065  * construct the 'history' and 'scan' output format
1661995Shx147065  * memory allocated. need to free after the function is invoked.
1662995Shx147065  */
1663995Shx147065 static char *
construct_format(uint32_t nt)1664995Shx147065 construct_format(uint32_t nt)
1665995Shx147065 {
1666995Shx147065 	char *format;
1667995Shx147065 	int len = 0, i;
1668995Shx147065 
1669995Shx147065 #define	FORMAT_LEN 256
1670995Shx147065 	assert((nt >= 1) && (nt <= 4));
1671995Shx147065 	format = safe_malloc(FORMAT_LEN);
1672995Shx147065 
1673995Shx147065 	for (i = 0; i < nt; i++)
1674995Shx147065 		len += snprintf(format + len, FORMAT_LEN - len, "\t");
1675995Shx147065 	if ((len <= 0) || (len > FORMAT_LEN - 1)) {
1676995Shx147065 		return ("\t\t\t\t");
1677995Shx147065 	}
1678995Shx147065 	return (format);
1679995Shx147065 }
1680995Shx147065 
1681995Shx147065 /*
1682995Shx147065  * find the essid of the named profile.
1683995Shx147065  * gp_config_file is golable, so the return is gloable too.
1684995Shx147065  */
1685995Shx147065 static const char *
essid_of_profile(const char * profile)1686995Shx147065 essid_of_profile(const char *profile)
1687995Shx147065 {
1688995Shx147065 	section_t *p_section = NULL;
1689995Shx147065 	aelist_t *plist = NULL;
1690995Shx147065 	ae_t *pae = NULL;
1691995Shx147065 	char *pbuf;
1692995Shx147065 
1693995Shx147065 	PRTDBG(("essid_of_profile: profile = %s\n", profile));
1694995Shx147065 	pbuf = append_pa(profile);
1695995Shx147065 	p_section = find_section(gp_config_file, pbuf);
1696995Shx147065 	free(pbuf);
1697995Shx147065 
1698995Shx147065 	if (p_section == NULL) {
1699995Shx147065 		return (NULL);
1700995Shx147065 	} else {
1701995Shx147065 		plist = p_section->list;
1702995Shx147065 	}
1703995Shx147065 	pae = plist->ael_head;
1704995Shx147065 	while (pae != NULL) {
1705995Shx147065 		if (strncmp(pae->ae_arg, "essid=", strlen("essid=")) == 0) {
1706995Shx147065 			PRTDBG(("essid_of_profile: essid = %s\n",
1707995Shx147065 			    pae->ae_arg));
1708995Shx147065 			return (get_value(pae->ae_arg));
1709995Shx147065 		}
1710995Shx147065 		pae = pae->ae_next;
1711995Shx147065 	}
1712995Shx147065 	return (NULL);
1713995Shx147065 }
1714995Shx147065 
1715995Shx147065 /*
1716995Shx147065  * If we don't know which profile is our favorate in 'autoconf',
1717995Shx147065  * we select the wifi network based on the following heuristic
1718995Shx147065  * 1. the network without wep.
1719995Shx147065  * 2. the network with the strongst signal.
1720995Shx147065  * 3. the network with the faster speed(not implemented since signal affects
1721995Shx147065  * the speed in some degree).
1722995Shx147065  */
1723995Shx147065 static void
heuristic_load(int fd,uint32_t ess_num,wl_ess_conf_t ** p_ess_conf)1724995Shx147065 heuristic_load(int fd, uint32_t ess_num, wl_ess_conf_t **p_ess_conf)
1725995Shx147065 {
1726995Shx147065 	int i = 0;
1727995Shx147065 	char *flag = NULL;
1728995Shx147065 	int have_nowep_wlan = 0;
1729995Shx147065 	wl_rssi_t maxsignal = 0;
1730995Shx147065 	char essid[34];
1731995Shx147065 	int timeout = LOADPROFILE_TIMEOUT;
1732995Shx147065 
1733995Shx147065 	PRTDBG(("heuristic_load: enter\n"));
1734995Shx147065 	(void) call_ioctl(fd, WLAN_COMMAND, WL_LOAD_DEFAULTS, 0);
1735995Shx147065 	flag = calloc(sizeof (char), ess_num);
1736995Shx147065 	for (i = 0; i < ess_num; i++) { /* extract none-wep network */
1737995Shx147065 		if (p_ess_conf[i]->wl_ess_conf_wepenabled == B_FALSE) {
1738995Shx147065 			flag[i] = 1;
1739995Shx147065 			have_nowep_wlan = 1;
1740995Shx147065 		}
1741995Shx147065 	}
1742995Shx147065 	/*
1743995Shx147065 	 * if all the wlans are weped, we select the one with strongest signal
1744995Shx147065 	 * in all of them, otherwise we just select in the none weped ones.
1745995Shx147065 	 */
1746995Shx147065 	if (!have_nowep_wlan)
1747995Shx147065 		(void) memset(flag, 1, ess_num);
1748995Shx147065 	for (i = 0; i < ess_num; i++) { /* extract the strongest signal ones */
1749995Shx147065 		if (flag[i] == 1) {
1750995Shx147065 			if (p_ess_conf[i]->wl_ess_conf_sl > maxsignal) {
1751995Shx147065 				maxsignal = p_ess_conf[i]->wl_ess_conf_sl;
1752995Shx147065 				(void) memset(flag, 0, i);
1753995Shx147065 			} else if (p_ess_conf[i]->wl_ess_conf_sl == maxsignal)
1754995Shx147065 				continue;
1755995Shx147065 			else
1756995Shx147065 				flag[i] = 0;
1757995Shx147065 		}
1758995Shx147065 	}
1759995Shx147065 	for (i = 0; i < ess_num; i++) {
1760995Shx147065 		if (flag[i] == 1)
1761995Shx147065 			break;
1762995Shx147065 	}
1763995Shx147065 	free(flag);
1764995Shx147065 	PRTDBG(("heuristic_load: %s is selected\n",
1765995Shx147065 	    p_ess_conf[i]->wl_ess_conf_essid.wl_essid_essid));
1766995Shx147065 	/* select one in all the networks which meet the preceding stardands */
1767995Shx147065 	if (i == ess_num)
1768995Shx147065 		(void) do_set_essid(fd, "");
1769995Shx147065 	else
1770995Shx147065 		(void) do_set_essid(fd,
1771995Shx147065 		    p_ess_conf[i]->wl_ess_conf_essid.wl_essid_essid);
1772995Shx147065 
1773995Shx147065 	if ((ess_num == 0) || (do_get_essid(fd) == B_FALSE)) {
1774995Shx147065 		(void) fprintf(stderr, gettext("%s: autoconf:"
1775995Shx147065 		    " failed to connect to any essid\n"),
1776995Shx147065 		    gExecName);
1777995Shx147065 		exit(WIFI_MINOR_ERR);
1778995Shx147065 	}
1779995Shx147065 	(void) strlcpy(essid, ((wl_essid_t *)(gbuf->wldp_buf))->wl_essid_essid,
1780995Shx147065 	    sizeof (essid));
1781995Shx147065 	(void) printf(gettext("%s: autoconf: essid '%s' is selected%s\n"),
1782995Shx147065 	    gExecName, essid,
1783995Shx147065 	    have_nowep_wlan ? "" : ": this is a WEPed "
1784995Shx147065 	    "access point");
1785995Shx147065 
1786995Shx147065 	if (!have_nowep_wlan)
1787995Shx147065 		exit(WIFI_FATAL_ERR);
1788995Shx147065 
1789995Shx147065 	while (timeout > 0) {
1790995Shx147065 		if ((do_get_linkstatus(fd) == B_TRUE) &&
1791995Shx147065 		    (*(wl_linkstatus_t *)(gbuf->wldp_buf) == WL_CONNECTED)) {
1792995Shx147065 			(void) printf(gettext("%s: connecting to "
1793995Shx147065 			    "essid '%s'\n"), gExecName, essid);
1794995Shx147065 			return;
1795995Shx147065 		}
1796995Shx147065 		(void) sleep(1);
1797995Shx147065 		timeout--;
1798995Shx147065 	}
1799995Shx147065 	(void) fprintf(stderr, gettext("%s: failed to connect to "
1800995Shx147065 	    "essid '%s'\n"), gExecName, essid);
1801995Shx147065 	exit(WIFI_FATAL_ERR);
1802995Shx147065 }
1803995Shx147065 
1804995Shx147065 /*
1805995Shx147065  * Called in autoconf and startconf to find which 'profile' is selected.
1806995Shx147065  * The process is: check profile names in the prefer list item by item,
1807995Shx147065  * if the essid of the profile is in the scan list, then it is the wanted.
1808995Shx147065  * readonly: 1 for startconf
1809995Shx147065  *           0 for autoconf
1810995Shx147065  * for autoconf, the scan result will be recorded in the history list.
1811995Shx147065  */
1812995Shx147065 static char *
select_profile(int fd,int readonly,int timeout)1813995Shx147065 select_profile(int fd, int readonly, int timeout)
1814995Shx147065 {
1815995Shx147065 	uint32_t ess_num = 0;
1816995Shx147065 	int nprefer = 1;
1817995Shx147065 	char **ess_argv;
1818995Shx147065 	char **hisess_argv;
1819995Shx147065 	wl_ess_conf_t **p_ess_conf;
1820995Shx147065 	section_t *p_section = NULL;
1821995Shx147065 	aelist_t *plist = NULL;
1822995Shx147065 	ae_t *pae = NULL;
1823995Shx147065 	int i;
1824995Shx147065 	const char *parg;
1825995Shx147065 	char *selected = NULL;
1826995Shx147065 	boolean_t flag = B_FALSE;
1827995Shx147065 
1828995Shx147065 	if ((call_ioctl(fd, WLAN_COMMAND, WL_SCAN, 0) == B_FALSE) ||
1829995Shx147065 	    (do_get_wlanlist(fd) == B_FALSE)) {
1830995Shx147065 		(void) fprintf(stderr, gettext("%s: "
1831995Shx147065 		    "autoconf : failed to scan\n"), gExecName);
1832995Shx147065 		exit(WIFI_FATAL_ERR);
1833995Shx147065 	}
1834995Shx147065 	ess_num = ((wl_ess_list_t *)(gbuf->wldp_buf))->wl_ess_list_num;
1835995Shx147065 	ess_argv = safe_calloc(sizeof (char *), ess_num);
1836995Shx147065 	hisess_argv = safe_calloc(sizeof (char *), ess_num);
1837995Shx147065 	p_ess_conf = safe_calloc(sizeof (wl_ess_list_t *), ess_num);
1838995Shx147065 	for (i = 0; i < ess_num; i++) {
1839995Shx147065 		p_ess_conf[i] = ((wl_ess_list_t *)gbuf->wldp_buf)
1840995Shx147065 		    ->wl_ess_list_ess + i;
1841995Shx147065 		ess_argv[i] = safe_malloc(MAX_SCANBUF_LEN);
1842995Shx147065 		if (readonly == 0) {
1843995Shx147065 			hisess_argv[i] = safe_malloc(MAX_SCANBUF_LEN);
1844995Shx147065 			(void) snprintf(hisess_argv[i], MAX_SCANBUF_LEN,
1845995Shx147065 			    "%s%c%02x:%02x:%02x:%02x:%02x:%02x%c%s",
1846995Shx147065 			    p_ess_conf[i]->wl_ess_conf_essid.wl_essid_essid,
1847995Shx147065 			    ',',
1848995Shx147065 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[0]),
1849995Shx147065 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[1]),
1850995Shx147065 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[2]),
1851995Shx147065 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[3]),
1852995Shx147065 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[4]),
1853995Shx147065 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[5]), ',',
1854995Shx147065 			    (p_ess_conf[i]->wl_ess_conf_wepenabled == B_TRUE
1855995Shx147065 			    ?  "wep":"none"));
1856995Shx147065 		}
1857995Shx147065 		(void) snprintf(ess_argv[i], MAX_SCANBUF_LEN, "%s",
1858995Shx147065 		    p_ess_conf[i]->wl_ess_conf_essid.wl_essid_essid);
1859995Shx147065 	}
1860995Shx147065 	if (readonly == 0) {
1861995Shx147065 		add_to_history(gp_config_file, ess_num, hisess_argv);
1862995Shx147065 		for (i = 0; i < ess_num; i++) {
1863995Shx147065 			free(hisess_argv[i]);
1864995Shx147065 		}
1865995Shx147065 		free(hisess_argv);
1866995Shx147065 	}
1867995Shx147065 
1868995Shx147065 	p_section = find_section(gp_config_file, WIFI_PREFER);
1869995Shx147065 	if (p_section == NULL) {
1870995Shx147065 		if (ess_num > 0) {
1871995Shx147065 			heuristic_load(fd, ess_num, p_ess_conf);
1872995Shx147065 			exit(WIFI_EXIT_DEF);
1873995Shx147065 		}
1874995Shx147065 		goto done;
1875995Shx147065 	}
1876995Shx147065 	plist = p_section->list;
1877995Shx147065 	assert(plist != NULL);
1878995Shx147065 	if (plist != NULL) {
1879995Shx147065 		nprefer = plist->ael_argc;
1880995Shx147065 		if (nprefer == 0) {
1881995Shx147065 			if (ess_num > 0) {
1882995Shx147065 				heuristic_load(fd, ess_num, p_ess_conf);
1883995Shx147065 				exit(WIFI_EXIT_DEF);
1884995Shx147065 			}
1885995Shx147065 			goto done;
1886995Shx147065 		}
1887995Shx147065 	}
1888995Shx147065 	pae = plist->ael_head;
1889995Shx147065 	while ((pae != NULL) && (flag != B_TRUE)) {
1890995Shx147065 		parg = essid_of_profile(pae->ae_arg);
1891995Shx147065 		if (parg != NULL) {
1892995Shx147065 			for (i = 0; i < ess_num; i++) {
1893995Shx147065 				if (strcmp(parg, ess_argv[i]) == 0) {
1894995Shx147065 					selected = pae->ae_arg;
1895995Shx147065 					flag = B_TRUE;
1896995Shx147065 					break;
1897995Shx147065 				}
1898995Shx147065 			}
1899995Shx147065 		}
1900995Shx147065 		pae = pae->ae_next;
1901995Shx147065 	}
1902995Shx147065 done:
1903995Shx147065 	if ((selected == NULL) && (timeout == 0)) {
1904995Shx147065 		heuristic_load(fd, ess_num, p_ess_conf);
1905995Shx147065 	}
1906995Shx147065 	for (i = 0; i < ess_num; i++) {
1907995Shx147065 		free(ess_argv[i]);
1908995Shx147065 	}
1909995Shx147065 	free(ess_argv);
1910995Shx147065 	free(p_ess_conf);
1911995Shx147065 	return (selected);
1912995Shx147065 }
1913995Shx147065 
1914995Shx147065 static boolean_t
is_waittime_valid(char * pbuf)1915995Shx147065 is_waittime_valid(char *pbuf)
1916995Shx147065 {
1917995Shx147065 	int i;
1918995Shx147065 
1919995Shx147065 	i = atoi(pbuf);
1920995Shx147065 	if (i == -1)
1921995Shx147065 		return (B_TRUE);
1922995Shx147065 	for (i = 0; i < strlen(pbuf); i++) {
1923995Shx147065 		if (isdigit(pbuf[i]) == 0) {
1924995Shx147065 			return (B_FALSE);
1925995Shx147065 		}
1926995Shx147065 	}
1927995Shx147065 	return (B_TRUE);
1928995Shx147065 }
1929995Shx147065 /*
1930995Shx147065  * do_autoconf: First scan the wlanlist, and select one essid from scan result
1931995Shx147065  * by the order in {preferrence} list. If no match, then heuristic_load;
1932995Shx147065  */
1933995Shx147065 /*ARGSUSED*/
1934995Shx147065 static boolean_t
do_autoconf(int fd,int argc,char ** argv)1935995Shx147065 do_autoconf(int fd, int argc, char **argv)
1936995Shx147065 {
1937995Shx147065 	const char *selected = NULL;
1938995Shx147065 	int timeout = LOADPROFILE_TIMEOUT, forever = 0, len = 0;
1939995Shx147065 	char *pequal, *param;
1940995Shx147065 	char **ld_argv = NULL;
1941995Shx147065 	boolean_t ret = B_TRUE;
1942995Shx147065 
1943995Shx147065 	PRTDBG(("do_autoconf(%d, 0x%x)\n", argc, argv));
1944995Shx147065 	assert(fd > 0);
1945995Shx147065 	if (argc > 0) {
1946995Shx147065 		param = safe_strdup(argv[0]);
1947995Shx147065 		pequal = strchr(param, '=');
1948995Shx147065 		if (pequal != NULL) {
1949995Shx147065 			*pequal++ = '\0';
1950995Shx147065 		} else {
1951995Shx147065 			do_print_usage();
1952995Shx147065 			exit(WIFI_IMPROPER_USE);
1953995Shx147065 		}
1954995Shx147065 		if (strcmp(param, "wait") != 0) {
1955995Shx147065 			do_print_usage();
1956995Shx147065 			exit(WIFI_IMPROPER_USE);
1957995Shx147065 		} else {
1958995Shx147065 			if (strcmp(pequal, "forever") == 0) {
1959995Shx147065 				forever = 1;
1960995Shx147065 			} else {
1961995Shx147065 				if (is_waittime_valid(pequal) == B_FALSE) {
1962995Shx147065 					(void) fprintf(stderr, gettext("%s: "
1963995Shx147065 					    "invalid value %s for 'wait'\n"),
1964995Shx147065 					    gExecName, pequal);
1965995Shx147065 					exit(WIFI_FATAL_ERR);
1966995Shx147065 				}
1967995Shx147065 				if (sscanf(pequal, "%d", &timeout) != 1) {
1968995Shx147065 					do_print_usage();
1969995Shx147065 					exit(WIFI_IMPROPER_USE);
1970995Shx147065 				}
1971995Shx147065 				if (timeout == -1) {
1972995Shx147065 					forever = 1;
1973995Shx147065 				}
1974995Shx147065 			}
1975995Shx147065 		}
1976995Shx147065 		free(param);
1977995Shx147065 		if (argc > 1) {
1978995Shx147065 			(void) fprintf(stderr, gettext("%s: trailing "
1979995Shx147065 			    "useless tokens after '%s'\n"),
1980995Shx147065 			    gExecName, argv[0]);
1981995Shx147065 		}
1982995Shx147065 	}
1983995Shx147065 
1984995Shx147065 	while ((forever == 1) || (timeout > 0)) {
1985995Shx147065 		timeout--;
1986995Shx147065 		selected = select_profile(fd, 0, max(timeout, forever));
1987995Shx147065 		if (selected != NULL)
1988995Shx147065 			break;
1989995Shx147065 		(void) sleep(1);
1990995Shx147065 	}
1991995Shx147065 	if (selected == NULL) {
1992995Shx147065 		return (B_TRUE);
1993995Shx147065 	}
1994995Shx147065 	(void) printf(gettext("%s: autoconf: profile [%s]"
1995995Shx147065 	    " is selected\n"), gExecName, selected);
1996995Shx147065 	ld_argv = safe_calloc(sizeof (char *), argc+1);
1997995Shx147065 	ld_argv[0] = safe_strdup(selected);
1998995Shx147065 	if (argc > 0) {
1999995Shx147065 		len = max(strlen(argv[0]), strlen("wait=forever"));
2000995Shx147065 		ld_argv[1] = safe_malloc(len);
2001995Shx147065 		safe_snprintf(ld_argv[1], len + 1, forever == 1 ?
2002995Shx147065 		    "wait=forever" : "wait=%d", timeout);
2003995Shx147065 	}
2004995Shx147065 	ret = do_loadpf(fd, argc+1, ld_argv);
2005995Shx147065 	free(ld_argv[0]);
2006995Shx147065 	if (argc > 0) {
2007995Shx147065 		free(ld_argv[1]);
2008995Shx147065 	}
2009995Shx147065 	free(ld_argv);
2010995Shx147065 	return (ret);
2011995Shx147065 }
2012995Shx147065 
2013995Shx147065 /*
2014995Shx147065  * do_startconf: almost the same as the do_autoconf, except that doesn't
2015995Shx147065  * write file.
2016995Shx147065  */
2017995Shx147065 /*ARGSUSED*/
2018995Shx147065 static boolean_t
do_startconf(int fd,int argc,char ** argv)2019995Shx147065 do_startconf(int fd, int argc, char **argv)
2020995Shx147065 {
2021995Shx147065 	int i = 0, ael_num = 0;
2022995Shx147065 	section_t *p_section = NULL;
2023995Shx147065 	section_t *p_wep_section = NULL;
2024995Shx147065 	aelist_t *plist = NULL;
2025995Shx147065 	const char *selected = NULL;
2026995Shx147065 	ae_t *pae = NULL;
2027995Shx147065 	char *pbuf = NULL;
2028995Shx147065 	char **argvnew = NULL;
2029995Shx147065 
2030995Shx147065 	PRTDBG(("do_startconf(%d, 0x%x)\n", argc, argv));
2031995Shx147065 	assert(fd > 0);
2032995Shx147065 
2033995Shx147065 	selected = select_profile(fd, 1, 0);
2034995Shx147065 	if (selected == NULL) {
2035995Shx147065 		return (B_TRUE);
2036995Shx147065 	}
2037995Shx147065 
2038995Shx147065 	(void) call_ioctl(fd, WLAN_COMMAND, WL_LOAD_DEFAULTS, 0);
2039995Shx147065 
2040995Shx147065 	pbuf = append_pa(selected);
2041995Shx147065 	p_wep_section = find_section(gp_wepkey_file, pbuf);
2042995Shx147065 	p_section = find_section(gp_config_file, pbuf);
2043995Shx147065 	free(pbuf);
2044995Shx147065 
2045995Shx147065 	if (p_wep_section != NULL) {
2046995Shx147065 		plist = p_wep_section->list;
2047995Shx147065 		pae = plist->ael_head;
2048995Shx147065 		while (pae != NULL) {
2049995Shx147065 			if (pae->ae_arg != NULL)
2050995Shx147065 				(void) do_set_wepkey(fd, pae->ae_arg);
2051995Shx147065 			pae = pae->ae_next;
2052995Shx147065 		}
2053995Shx147065 	}
2054995Shx147065 
2055995Shx147065 	if (p_section != NULL) {
2056995Shx147065 		plist = p_section->list;
2057995Shx147065 		if (plist->ael_argc == 0) {
2058995Shx147065 			return (B_TRUE);
2059995Shx147065 		}
2060995Shx147065 		argvnew = aeltoargv(plist, &ael_num);
2061995Shx147065 		(void) do_set(fd, ael_num, argvnew);
2062995Shx147065 
2063995Shx147065 		for (i = 0; i < ael_num; i++)
2064995Shx147065 			free(argvnew[i]);
2065995Shx147065 		free(argvnew);
2066995Shx147065 	}
2067995Shx147065 	return (B_TRUE);
2068995Shx147065 }
2069995Shx147065 
2070995Shx147065 static char *
find_active_profile(int fd)2071995Shx147065 find_active_profile(int fd)
2072995Shx147065 {
2073995Shx147065 	section_t *p_section = NULL, *activep_section = NULL;
2074995Shx147065 	aelist_t *plist = NULL;
2075995Shx147065 	ae_t *pae = NULL;
2076995Shx147065 	const char *pessid = NULL, *pbssid = NULL;
2077995Shx147065 	char essid[34], bssid[32];
2078995Shx147065 	const char *activeprofile = NULL;
2079995Shx147065 
2080995Shx147065 	PRTDBG(("find_active_profile: %d\n", fd));
2081995Shx147065 	if (do_get_essid(fd) == B_FALSE) {
2082995Shx147065 		return (NULL);
2083995Shx147065 	}
2084995Shx147065 	(void) strlcpy(essid, ((wl_essid_t *)(gbuf->wldp_buf))->wl_essid_essid,
2085995Shx147065 	    sizeof (essid));
2086995Shx147065 	if (do_get_bssid(fd) == B_FALSE) {
2087995Shx147065 		return (NULL);
2088995Shx147065 	}
2089995Shx147065 	safe_snprintf(bssid, sizeof (bssid), "%02x:%02x:%02x:%02x:%02x:%02x",
2090995Shx147065 	    ((uint8_t *)gbuf->wldp_buf)[0],
2091995Shx147065 	    ((uint8_t *)gbuf->wldp_buf)[1],
2092995Shx147065 	    ((uint8_t *)gbuf->wldp_buf)[2],
2093995Shx147065 	    ((uint8_t *)gbuf->wldp_buf)[3],
2094995Shx147065 	    ((uint8_t *)gbuf->wldp_buf)[4],
2095995Shx147065 	    ((uint8_t *)gbuf->wldp_buf)[5]);
2096995Shx147065 	activep_section = find_section(gp_config_file, WIFI_ACTIVEP);
2097995Shx147065 	if (activep_section == NULL)
2098995Shx147065 		return (NULL);
2099995Shx147065 	activeprofile = get_value(activep_section->list->
2100995Shx147065 	    ael_head->ae_arg);
2101995Shx147065 	if (activeprofile == NULL)
2102995Shx147065 		return (NULL);
2103995Shx147065 	p_section = gp_config_file->section_head;
2104995Shx147065 	while (p_section != NULL) {
2105995Shx147065 		if (((plist = p_section->list) != NULL) &&
2106995Shx147065 		    (plist->type == PROFILE) &&
2107995Shx147065 		    (strcmp(p_section->section_id, activeprofile) == 0)) {
2108995Shx147065 			pae = plist->ael_head;
2109995Shx147065 			while (pae != NULL) {
2110995Shx147065 				if (strncmp(pae->ae_arg, "essid=",
2111995Shx147065 				    strlen("essid=")) == 0) {
2112995Shx147065 					pessid = get_value(pae->ae_arg);
2113995Shx147065 				}
2114995Shx147065 				if (strncmp(pae->ae_arg, "bssid=",
2115995Shx147065 				    strlen("bssid=")) == 0) {
2116995Shx147065 					pbssid = get_value(pae->ae_arg);
2117995Shx147065 				}
2118995Shx147065 				pae = pae->ae_next;
2119995Shx147065 			}
2120995Shx147065 			if (pessid && pbssid &&
2121995Shx147065 			    (strcmp(essid, pessid) == 0) &&
2122995Shx147065 			    (strcmp(bssid, pbssid) == 0)) {
2123995Shx147065 				return (p_section->section_id);
2124995Shx147065 			}
2125995Shx147065 		}
2126995Shx147065 		p_section = p_section->section_next;
2127995Shx147065 	}
2128995Shx147065 	return (NULL);
2129995Shx147065 }
2130995Shx147065 
2131995Shx147065 static void
record_active_profile(char * pname,int action)2132995Shx147065 record_active_profile(char *pname, int action)
2133995Shx147065 {
2134995Shx147065 	section_t *p_section = NULL;
2135995Shx147065 	aelist_t *plist = NULL;
2136995Shx147065 	char pbuf[256];
2137995Shx147065 
2138995Shx147065 	p_section = find_section(gp_config_file, WIFI_ACTIVEP);
2139995Shx147065 	if (p_section == NULL) {
2140995Shx147065 		plist = new_ael(ACTIVEP);
2141995Shx147065 		new_section(gp_config_file, plist, WIFI_ACTIVEP);
2142995Shx147065 	} else {
2143995Shx147065 		plist = p_section->list;
2144995Shx147065 	}
2145995Shx147065 
2146995Shx147065 	if (action == RECORD_ADD) {
2147995Shx147065 		assert(pname != NULL);
2148995Shx147065 		safe_snprintf(pbuf, sizeof (pbuf), "activep=%s", pname);
2149995Shx147065 		update_aelist(plist, pbuf);
2150995Shx147065 	} else if (action == RECORD_DEL) {
2151995Shx147065 		assert(pname == NULL);
2152995Shx147065 		update_aelist(plist, "activep= ");
2153995Shx147065 	}
2154995Shx147065 }
2155995Shx147065 
2156995Shx147065 /*
2157995Shx147065  * do_loadpf: load a profile, set related parameters both in wifi
2158995Shx147065  * and in wifiwepkey, if network name is not exist in the
2159995Shx147065  * configration files, then we clean all parameters and set essid only
2160995Shx147065  */
2161995Shx147065 static boolean_t
do_loadpf(int fd,int argc,char ** argv)2162995Shx147065 do_loadpf(int fd, int argc, char ** argv)
2163995Shx147065 {
2164995Shx147065 	int i = 0, ael_num = 0;
2165995Shx147065 	int timeout = LOADPROFILE_TIMEOUT, forever = 0;
2166995Shx147065 	section_t *p_section = NULL;
2167995Shx147065 	section_t *p_wep_section = NULL;
2168995Shx147065 	aelist_t *plist = NULL;
2169995Shx147065 	ae_t *pae = NULL;
2170995Shx147065 	char *pbuf = NULL;
2171995Shx147065 	char **argvnew = NULL;
2172995Shx147065 	char *connect;
2173995Shx147065 	char *pequal, *param;
2174995Shx147065 
2175995Shx147065 	PRTDBG(("do_loadpf(%d, %x)\n", argc, argv));
2176995Shx147065 	assert(fd > 0);
2177995Shx147065 	if (argc == 0) {
2178995Shx147065 		(void) fprintf(stderr, gettext("%s: connect: "
2179995Shx147065 		    "profile name missing\n"), gExecName);
2180995Shx147065 		return (B_FALSE);
2181995Shx147065 	}
2182995Shx147065 	if (argc > 1) {
2183995Shx147065 		param = safe_strdup(argv[1]);
2184995Shx147065 		pequal = strchr(param, '=');
2185995Shx147065 		if (pequal != NULL) {
2186995Shx147065 			*pequal++ = '\0';
2187995Shx147065 		} else {
2188995Shx147065 			do_print_usage();
2189995Shx147065 			exit(WIFI_IMPROPER_USE);
2190995Shx147065 		}
2191995Shx147065 		if (strcmp(param, "wait") != 0) {
2192995Shx147065 			do_print_usage();
2193995Shx147065 			exit(WIFI_IMPROPER_USE);
2194995Shx147065 		} else {
2195995Shx147065 			if (strcmp(pequal, "forever") == 0) {
2196995Shx147065 				forever = 1;
2197995Shx147065 			} else {
2198995Shx147065 				if (is_waittime_valid(pequal) == B_FALSE) {
2199995Shx147065 					(void) fprintf(stderr, gettext("%s: "
2200995Shx147065 					    "invalid value %s for 'wait'\n"),
2201995Shx147065 					    gExecName, pequal);
2202995Shx147065 					exit(WIFI_FATAL_ERR);
2203995Shx147065 				}
2204995Shx147065 				if (sscanf(pequal, "%d", &timeout) != 1) {
2205995Shx147065 					do_print_usage();
2206995Shx147065 					exit(WIFI_IMPROPER_USE);
2207995Shx147065 				}
2208995Shx147065 				if (timeout == -1) {
2209995Shx147065 					forever = 1;
2210995Shx147065 				}
2211995Shx147065 			}
2212995Shx147065 		}
2213995Shx147065 		free(param);
2214995Shx147065 		if (argc > 2) {
2215995Shx147065 			(void) fprintf(stderr, gettext("%s: trailing "
2216995Shx147065 			    "useless tokens after '%s'\n"),
2217995Shx147065 			    gExecName, argv[1]);
2218995Shx147065 		}
2219995Shx147065 	}
2220995Shx147065 	(void) call_ioctl(fd, WLAN_COMMAND, WL_LOAD_DEFAULTS, 0);
2221995Shx147065 
2222995Shx147065 	pbuf = append_pa(argv[0]);
2223995Shx147065 	p_wep_section = find_section(gp_wepkey_file, pbuf);
2224995Shx147065 	p_section = find_section(gp_config_file, pbuf);
2225995Shx147065 
2226995Shx147065 	if (p_wep_section != NULL) {
2227995Shx147065 		(void) set_prefer(gp_config_file, argv[0], 1);
2228995Shx147065 		plist = p_wep_section->list;
2229995Shx147065 		pae = plist->ael_head;
2230995Shx147065 		while (pae != NULL) {
2231995Shx147065 			if (pae->ae_arg != NULL) {
2232995Shx147065 				(void) do_set_wepkey(fd, pae->ae_arg);
2233995Shx147065 			}
2234995Shx147065 			pae = pae->ae_next;
2235995Shx147065 		}
2236995Shx147065 	}
2237995Shx147065 
2238995Shx147065 	if (p_section != NULL) {
2239995Shx147065 		connect = "profile";
2240995Shx147065 
2241995Shx147065 		(void) set_prefer(gp_config_file, argv[0], 1);
2242995Shx147065 		plist = p_section->list;
2243995Shx147065 		if (plist->ael_argc == 0) {
2244995Shx147065 			free(pbuf);
2245995Shx147065 			return (B_TRUE);
2246995Shx147065 		}
2247995Shx147065 		argvnew = aeltoargv(plist, &ael_num);
2248995Shx147065 		/*
2249995Shx147065 		 * if there is no 'essid' item in argvnew, the profile
2250995Shx147065 		 * name(argv[0]) is treated as essid.
2251995Shx147065 		 */
2252995Shx147065 		for (i = 0; i < ael_num; i++) {
2253995Shx147065 			if (strncmp(argvnew[i], "essid=", strlen("essid="))
2254995Shx147065 			    == 0)
2255995Shx147065 				break;
2256995Shx147065 		}
2257995Shx147065 		if (i == ael_num)
2258995Shx147065 			(void) do_set_essid(fd, argv[0]);
2259995Shx147065 
2260995Shx147065 		(void) do_set(fd, ael_num, argvnew);
2261995Shx147065 
2262995Shx147065 		for (i = 0; i < ael_num; i++)
2263995Shx147065 			free(argvnew[i]);
2264995Shx147065 		free(argvnew);
2265995Shx147065 
2266995Shx147065 		/*
2267995Shx147065 		 * set flag in {active_profile} so that showprofile knows
2268995Shx147065 		 * which profile is active when more than one profiles are
2269995Shx147065 		 * created for the same WLAN.
2270995Shx147065 		 */
2271995Shx147065 		record_active_profile(pbuf, RECORD_ADD);
2272995Shx147065 	} else {
2273995Shx147065 		(void) do_set_essid(fd, argv[0]);
2274995Shx147065 		connect = "essid";
2275995Shx147065 	}
2276995Shx147065 
2277995Shx147065 	while ((forever == 1) || (timeout > 0)) {
2278995Shx147065 		if ((do_get_linkstatus(fd) == B_TRUE) &&
2279995Shx147065 		    (*(wl_linkstatus_t *)(gbuf->wldp_buf) == WL_CONNECTED)) {
2280995Shx147065 			section_t *p_section = NULL;
2281995Shx147065 			aelist_t *plist = NULL;
2282995Shx147065 			char bssid[32];
2283995Shx147065 			/* record bssid in the profile */
2284995Shx147065 			if (do_get_bssid(fd) == B_FALSE) {
2285995Shx147065 				free(pbuf);
2286995Shx147065 				return (B_TRUE);
2287995Shx147065 			}
2288995Shx147065 			safe_snprintf(bssid, sizeof (bssid),
2289995Shx147065 			    "bssid=%02x:%02x:%02x:%02x:%02x:%02x",
2290995Shx147065 			    ((uint8_t *)gbuf->wldp_buf)[0],
2291995Shx147065 			    ((uint8_t *)gbuf->wldp_buf)[1],
2292995Shx147065 			    ((uint8_t *)gbuf->wldp_buf)[2],
2293995Shx147065 			    ((uint8_t *)gbuf->wldp_buf)[3],
2294995Shx147065 			    ((uint8_t *)gbuf->wldp_buf)[4],
2295995Shx147065 			    ((uint8_t *)gbuf->wldp_buf)[5]);
2296995Shx147065 
2297995Shx147065 			p_section = find_section(gp_config_file, pbuf);
2298995Shx147065 			if (p_section != NULL) {
2299995Shx147065 				plist = p_section->list;
2300995Shx147065 				update_aelist(plist, bssid);
2301995Shx147065 			}
2302995Shx147065 			free(pbuf);
2303995Shx147065 			(void) printf(gettext("%s: connecting to "
2304995Shx147065 			    "%s '%s'\n"), gExecName, connect, argv[0]);
2305995Shx147065 			return (B_TRUE);
2306995Shx147065 		}
2307995Shx147065 		(void) sleep(1);
2308995Shx147065 		timeout--;
2309995Shx147065 		PRTDBG(("connect counting:......%d\n", timeout));
2310995Shx147065 	}
2311995Shx147065 	(void) fprintf(stderr, gettext("%s: failed to connect to "
2312995Shx147065 	    "%s '%s'\n"), gExecName, connect, argv[0]);
2313995Shx147065 	free(pbuf);
2314995Shx147065 	return (B_FALSE);
2315995Shx147065 }
2316995Shx147065 
2317995Shx147065 /*
2318995Shx147065  * if wepkey is set in the profile, display wepkey|n=*****
2319995Shx147065  * when showprofile and getprofilewepkey.
2320995Shx147065  * if wepkeyn is NULL, all the wepkeys will be display,
2321995Shx147065  * otherwise, just display the matching one.
2322995Shx147065  */
2323995Shx147065 static void
print_wepkey_info(const char * id,const char * wepkeyn)2324995Shx147065 print_wepkey_info(const char *id, const char *wepkeyn)
2325995Shx147065 {
2326995Shx147065 	char *pequal, *param;
2327995Shx147065 	section_t *p_section = NULL;
2328995Shx147065 	aelist_t *plist = NULL;
2329995Shx147065 	ae_t *pae = NULL;
2330995Shx147065 
2331995Shx147065 	p_section = find_section(gp_wepkey_file, id);
2332995Shx147065 	if (p_section != NULL) {
2333995Shx147065 		plist = p_section->list;
2334995Shx147065 		pae = plist->ael_head;
2335995Shx147065 		while (pae != NULL) {
2336995Shx147065 			if (pae->ae_arg != NULL) {
2337995Shx147065 				param = safe_strdup(pae->ae_arg);
2338995Shx147065 				pequal = strchr(param, '=');
2339995Shx147065 				if (pequal == NULL)
2340995Shx147065 					return;
2341995Shx147065 				*pequal = '\0';
2342995Shx147065 				if (wepkeyn != NULL) {
2343995Shx147065 					if (strcmp(wepkeyn, param) == 0)
2344995Shx147065 						(void) printf("\t%s=*****\n",
2345995Shx147065 						    param);
2346995Shx147065 					free(param);
2347995Shx147065 					return;
2348995Shx147065 				} else {
2349995Shx147065 					(void) printf("\t%s=*****\n", param);
2350995Shx147065 					free(param);
2351995Shx147065 				}
2352995Shx147065 			}
2353995Shx147065 			pae = pae->ae_next;
2354995Shx147065 		}
2355995Shx147065 	}
2356995Shx147065 }
2357995Shx147065 
2358995Shx147065 /*
2359995Shx147065  * do_printpf: print each parameters of the profile, if no network name
2360995Shx147065  * assigned, then print all profile saved in configration file.
2361995Shx147065  */
2362995Shx147065 /*ARGSUSED*/
2363995Shx147065 static boolean_t
do_printpf(int fd,int argc,char ** argv)2364995Shx147065 do_printpf(int fd, int argc, char ** argv)
2365995Shx147065 {
2366995Shx147065 	section_t *p_section = NULL;
2367995Shx147065 	aelist_t *plist = NULL;
2368995Shx147065 	ae_t *pae = NULL;
2369995Shx147065 	char *pbuf = NULL;
2370995Shx147065 	int i;
2371995Shx147065 
2372995Shx147065 	PRTDBG(("do_printpf(%d, %x)\n", argc, argv));
2373995Shx147065 
2374995Shx147065 	/*
2375995Shx147065 	 * if no profile name is inputted, all the profiles will be displayed.
2376995Shx147065 	 */
2377995Shx147065 	if (argc == 0) {
2378995Shx147065 		p_section = gp_config_file->section_head;
2379995Shx147065 		while (p_section != NULL) {
2380995Shx147065 			plist = p_section->list;
2381995Shx147065 			if (plist->type == PROFILE) {
2382995Shx147065 				(void) printf("%s\n", p_section->section_id);
2383995Shx147065 				pae = plist->ael_head;
2384995Shx147065 				while (pae != NULL) {
2385995Shx147065 					if (pae->ae_arg != NULL) {
2386995Shx147065 						(void) printf("\t%s\n",
2387995Shx147065 						    pae->ae_arg);
2388995Shx147065 					}
2389995Shx147065 					pae = pae->ae_next;
2390995Shx147065 				}
2391995Shx147065 				/*
2392995Shx147065 				 * identify whether wepkey is set
2393995Shx147065 				 * in the profile
2394995Shx147065 				 */
2395995Shx147065 				print_wepkey_info(p_section->section_id, NULL);
2396995Shx147065 			}
2397995Shx147065 			p_section = p_section->section_next;
2398995Shx147065 		}
2399995Shx147065 		return (B_TRUE);
2400995Shx147065 	}
2401995Shx147065 
2402995Shx147065 	for (i = 0; i < argc; i++) {
2403995Shx147065 		pbuf =	append_pa(argv[i]);
2404995Shx147065 		p_section = find_section(gp_config_file, pbuf);
2405995Shx147065 		free(pbuf);
2406995Shx147065 		if (p_section != NULL)	{
2407995Shx147065 			(void) printf("%s\n", p_section->section_id);
2408995Shx147065 			plist = p_section->list;
2409995Shx147065 			if (plist != NULL) {
2410995Shx147065 				pae = plist->ael_head;
2411995Shx147065 				while (pae != NULL) {
2412995Shx147065 					if (pae->ae_arg != NULL) {
2413995Shx147065 						(void) printf("\t%s\n",
2414995Shx147065 						    pae->ae_arg);
2415995Shx147065 					}
2416995Shx147065 					pae = pae->ae_next;
2417995Shx147065 				}
2418995Shx147065 				/*
2419995Shx147065 				 * identify whether wepkey is set
2420995Shx147065 				 * in the profile
2421995Shx147065 				 */
2422995Shx147065 				print_wepkey_info(p_section->section_id, NULL);
2423995Shx147065 			}
2424995Shx147065 		} else {
2425995Shx147065 			(void) fprintf(stderr,
2426*6834Sff224033 			    gettext("%s: showprofile : "
2427*6834Sff224033 			    "no such profile: '%s'\n"),
2428*6834Sff224033 			    gExecName, argv[i]);
2429995Shx147065 			return (B_FALSE);
2430995Shx147065 		}
2431995Shx147065 	}
2432995Shx147065 	return (B_TRUE);
2433995Shx147065 }
2434995Shx147065 /*
2435995Shx147065  * find_ae: Find an ae by its contents, return its pointer.
2436995Shx147065  */
2437995Shx147065 static ae_t *
find_ae(aelist_t * plist,const char * arg)2438995Shx147065 find_ae(aelist_t *plist, const char *arg)
2439995Shx147065 {
2440995Shx147065 	char *param = NULL;
2441995Shx147065 	char *pnext = NULL;
2442995Shx147065 	ae_t *pae = NULL;
2443995Shx147065 
2444995Shx147065 	if ((arg == NULL) || (plist == NULL)) {
2445995Shx147065 		PRTDBG(("find_ae: arg= NULL or plist=NULL\n"));
2446995Shx147065 		return (NULL);
2447995Shx147065 	}
2448995Shx147065 	PRTDBG(("find_ae(0x%x, \"%s\")\n", plist, arg));
2449995Shx147065 	param = safe_strdup(arg);
2450995Shx147065 	pnext = strchr(param, '=');
2451995Shx147065 	if (pnext != NULL) {
2452995Shx147065 		*pnext = '\0';
2453995Shx147065 	} else {
2454995Shx147065 		PRTDBG(("find_ae: param = \"%s\"\n", param));
2455995Shx147065 		free(param);
2456995Shx147065 		return (NULL);
2457995Shx147065 	}
2458995Shx147065 
2459995Shx147065 	pae = plist->ael_head;
2460995Shx147065 	while (pae != NULL) {
2461995Shx147065 		if ((pae->ae_arg != NULL) &&
2462995Shx147065 		    (strncmp(pae->ae_arg, param, strlen(param)) == 0)) {
2463995Shx147065 			PRTDBG(("find_ae: param = \"%s\"\n", param));
2464995Shx147065 			free(param);
2465995Shx147065 			return (pae);
2466995Shx147065 		}
2467995Shx147065 		pae = pae->ae_next;
2468995Shx147065 	}
2469995Shx147065 	free(param);
2470995Shx147065 	return (NULL);
2471995Shx147065 }
2472995Shx147065 
2473995Shx147065 /*
2474995Shx147065  * update_aelist: Update an aelist by arg, for example:
2475995Shx147065  * there are an item with content"essid=ap7-2",
2476995Shx147065  * update_aelist(0x..., "essid=myssid2") will update it as "essid=myssid2"
2477995Shx147065  */
2478995Shx147065 static void
update_aelist(aelist_t * plist,const char * arg)2479995Shx147065 update_aelist(aelist_t *plist, const char *arg)
2480995Shx147065 {
2481995Shx147065 	ae_t *pae = NULL;
2482995Shx147065 
2483995Shx147065 	assert((arg != NULL)&&(plist != NULL));
2484995Shx147065 	PRTDBG(("update_aelist(0x%x, \"%s\")\n", plist, arg));
2485995Shx147065 	pae = find_ae(plist, arg);
2486995Shx147065 	if (pae == NULL) {
2487995Shx147065 		new_ae(plist, arg);
2488995Shx147065 	} else {
2489995Shx147065 		free(pae->ae_arg);
2490995Shx147065 		pae->ae_arg = safe_strdup(arg);
2491995Shx147065 	}
2492995Shx147065 }
2493995Shx147065 
2494995Shx147065 /*
2495995Shx147065  * do_deletepf: delete a profile in configration files.
2496995Shx147065  */
2497995Shx147065 /*ARGSUSED*/
2498995Shx147065 static boolean_t
do_deletepf(int fd,int argc,char ** argv)2499995Shx147065 do_deletepf(int fd, int argc, char **argv)
2500995Shx147065 {
2501995Shx147065 	int i = 0;
2502995Shx147065 	char *section_id;
2503995Shx147065 	char *prefer;
2504995Shx147065 	section_t *p_section = NULL, *p_sectionbak = NULL;
2505995Shx147065 	aelist_t *plist = NULL;
2506995Shx147065 
2507995Shx147065 	PRTDBG(("do_deletepf(%d, \"%s\")\n", argc, argv));
2508995Shx147065 	if (argc <= 0) {
2509995Shx147065 		do_print_usage();
2510995Shx147065 		exit(WIFI_IMPROPER_USE);
2511995Shx147065 	}
2512995Shx147065 
2513995Shx147065 	/*
2514995Shx147065 	 * if a "all" is inputted, all the profiles will be deleted.
2515995Shx147065 	 */
2516995Shx147065 	if (strcasecmp(argv[0], "all") == 0) {
2517995Shx147065 		p_section = gp_config_file->section_head;
2518995Shx147065 		while ((p_section != NULL) &&
2519995Shx147065 		    ((plist = p_section->list) != NULL)) {
2520995Shx147065 			if (plist->type == PROFILE) {
2521995Shx147065 				p_sectionbak = p_section->section_next;
2522995Shx147065 				section_id = safe_strdup(p_section->section_id);
2523995Shx147065 				(void) del_section(gp_config_file, section_id);
2524995Shx147065 				(void) del_section(gp_wepkey_file, section_id);
2525995Shx147065 				/*
2526995Shx147065 				 * remove the '[]' of the [section_id]
2527995Shx147065 				 */
2528995Shx147065 				prefer = section_id + 1;
2529995Shx147065 				*(prefer + strlen(section_id) - 2) = '\0';
2530995Shx147065 				(void) del_prefer(gp_config_file, prefer,
2531995Shx147065 				    B_FALSE);
2532995Shx147065 				free(section_id);
2533995Shx147065 				p_section = p_sectionbak;
2534995Shx147065 					continue;
2535995Shx147065 			}
2536995Shx147065 			p_section = p_section->section_next;
2537995Shx147065 		}
2538995Shx147065 		return (B_TRUE);
2539995Shx147065 	}
2540995Shx147065 	if (gp_config_file != NULL) {
2541995Shx147065 		for (i = 0; i < argc; i++) {
2542995Shx147065 			section_id = append_pa(argv[i]);
2543995Shx147065 			if (del_section(gp_config_file, section_id)
2544995Shx147065 			    == B_FALSE) {
2545995Shx147065 				if (del_section(gp_wepkey_file, section_id)
2546995Shx147065 				    == B_TRUE) {
2547995Shx147065 					(void) del_prefer(gp_config_file,
2548995Shx147065 					    argv[i], B_FALSE);
2549995Shx147065 					free(section_id);
2550995Shx147065 					return (B_TRUE);
2551995Shx147065 				} else {
2552995Shx147065 					(void) fprintf(stderr,
2553995Shx147065 					    gettext("%s: deleteprofile"
2554995Shx147065 					    ": no such profile: '%s'\n"),
2555995Shx147065 					    gExecName, argv[i]);
2556995Shx147065 					free(section_id);
2557995Shx147065 					return (B_FALSE);
2558995Shx147065 				}
2559995Shx147065 			}
2560995Shx147065 			(void) del_prefer(gp_config_file, argv[i], B_FALSE);
2561995Shx147065 			(void) del_section(gp_wepkey_file, section_id);
2562995Shx147065 			free(section_id);
2563995Shx147065 		}
2564995Shx147065 	}
2565995Shx147065 	return (B_TRUE);
2566995Shx147065 }
2567995Shx147065 
2568995Shx147065 /*
2569995Shx147065  * do_history: Print the list in {history} section.
2570995Shx147065  */
2571995Shx147065 /*ARGSUSED*/
2572995Shx147065 static boolean_t
do_history(int fd,int argc,char ** argv)2573995Shx147065 do_history(int fd, int argc, char **argv)
2574995Shx147065 {
2575995Shx147065 	section_t *p_section = NULL;
2576995Shx147065 	aelist_t *plist = NULL;
2577995Shx147065 	ae_t *pae = NULL;
2578995Shx147065 	char *param, *param_bak, *pcomma;
2579995Shx147065 	uint32_t maxessidlen = 0, ulen;
2580995Shx147065 	char format[256], *ntstr;
2581995Shx147065 	uint32_t nt = 0, cnt = 0;
2582995Shx147065 	int len;
2583995Shx147065 	time_t cltime;
2584995Shx147065 
2585995Shx147065 	PRTDBG(("do_history(%d, 0x%x)\n", argc, argv));
2586995Shx147065 	if (argc > 0) {
2587995Shx147065 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
2588995Shx147065 		    "after 'history'\n"), gExecName);
2589995Shx147065 	}
2590995Shx147065 	p_section = find_section(gp_config_file, WIFI_HISTORY);
2591995Shx147065 	if (p_section == NULL) {
2592995Shx147065 		PRTDBG(("no history section\n"));
2593995Shx147065 		return (B_FALSE);
2594995Shx147065 	}
2595995Shx147065 	plist = p_section->list;
2596995Shx147065 
2597995Shx147065 	/*
2598995Shx147065 	 * If history section is empty, directly return.
2599995Shx147065 	 */
2600995Shx147065 	if (plist == NULL)
2601995Shx147065 		return (B_TRUE);
2602995Shx147065 	/*
2603995Shx147065 	 * construct the output format in terms of the
2604995Shx147065 	 * maxmium essid length
2605995Shx147065 	 */
2606995Shx147065 	pae = NULL;
2607995Shx147065 	pae = plist->ael_head;
2608995Shx147065 	while (pae != NULL) {
2609995Shx147065 		if (pae->ae_arg != NULL) {
2610995Shx147065 			param = safe_strdup(pae->ae_arg);
2611995Shx147065 			pcomma = strchr(param, ',');
2612995Shx147065 			if (pcomma == NULL) {
2613995Shx147065 				(void) fprintf(stderr,
2614995Shx147065 				    gettext("%s: history : "
2615995Shx147065 				    "data format error\n"),
2616995Shx147065 				    gExecName);
2617995Shx147065 				free(param);
2618995Shx147065 				return (B_FALSE);
2619995Shx147065 			}
2620995Shx147065 			*pcomma = '\0';
2621995Shx147065 			ulen = strlen(param);
2622995Shx147065 			maxessidlen = (maxessidlen > ulen
2623995Shx147065 			    ? maxessidlen:ulen);
2624995Shx147065 			free(param);
2625995Shx147065 		}
2626995Shx147065 		pae = pae->ae_next;
2627995Shx147065 	}
2628995Shx147065 	if ((nt = (maxessidlen / 8 + 1)) > 4)
2629995Shx147065 		nt = 4;
2630995Shx147065 	len = snprintf(format, sizeof (format), gettext("essid"));
2631995Shx147065 	ntstr = construct_format(nt);
2632995Shx147065 	assert((ntstr != NULL) && (strlen(ntstr) <= 4));
2633995Shx147065 	len += snprintf(format + len, sizeof (format) - len, "%s", ntstr);
2634995Shx147065 	len += snprintf(format + len, sizeof (format) - len,
2635995Shx147065 	    gettext("bssid\t\t  encryption\tlast seen\n"));
2636995Shx147065 
2637995Shx147065 	if ((len <= 0) || (len > sizeof (format) - 1)) {
2638995Shx147065 		(void) printf(gettext("essid\t\t\t\tbssid\t\t  encryption"
2639995Shx147065 		    "\tlast seen\n"));
2640995Shx147065 	} else {
2641995Shx147065 		(void) printf("%s", format);
2642995Shx147065 	}
2643995Shx147065 	/*
2644995Shx147065 	 * output the contents of the history section.
2645995Shx147065 	 */
2646995Shx147065 	pae = plist->ael_head;
2647995Shx147065 	while (pae != NULL) {
2648995Shx147065 		if (pae->ae_arg != NULL) {
2649995Shx147065 			param = safe_strdup(pae->ae_arg);
2650995Shx147065 			param_bak = param;
2651995Shx147065 			if ((pcomma = strchr(param, ',')) != NULL) {
2652995Shx147065 				*pcomma = '\0';
2653995Shx147065 				cnt = nt - (min((strlen(param)/8 + 1), 4) - 1);
2654995Shx147065 				ntstr = construct_format(cnt);
2655995Shx147065 				assert(ntstr != NULL);
2656995Shx147065 				/* display essid */
2657995Shx147065 				(void) printf("%s%s", param, ntstr);
2658995Shx147065 				free(ntstr);
2659995Shx147065 			}
2660995Shx147065 			param = pcomma + 1;
2661995Shx147065 			if ((pcomma = strchr(param, ',')) != NULL) {
2662995Shx147065 				*pcomma = '\0';
2663995Shx147065 				/* display bssid */
2664995Shx147065 				(void) printf("%s ", param);
2665995Shx147065 			}
2666995Shx147065 			param = pcomma + 1;
2667995Shx147065 			if ((pcomma = strchr(param, ',')) != NULL) {
2668995Shx147065 				*pcomma = '\0';
2669995Shx147065 				/* display wep */
2670995Shx147065 				(void) printf("%s\t\t", param);
2671995Shx147065 			}
2672995Shx147065 			param = pcomma + 1;
2673995Shx147065 			/* display time stamp */
2674995Shx147065 			cltime = (time_t)atol(param);
2675995Shx147065 			(void) printf("%s", ctime(&cltime));
2676995Shx147065 			free(param_bak);
2677995Shx147065 		}
2678995Shx147065 		pae = pae->ae_next;
2679995Shx147065 	}
2680995Shx147065 
2681995Shx147065 	return (B_TRUE);
2682995Shx147065 }
2683995Shx147065 
2684995Shx147065 /*
2685995Shx147065  * do_lsprefer: Print the list in {preferrence} section
2686995Shx147065  */
2687995Shx147065 /*ARGSUSED*/
2688995Shx147065 static boolean_t
do_lsprefer(int fd,int argc,char ** argv)2689995Shx147065 do_lsprefer(int fd, int argc, char **argv)
2690995Shx147065 {
2691995Shx147065 	int i = 0;
2692995Shx147065 	section_t *p_section = NULL;
2693995Shx147065 	aelist_t *plist = NULL;
2694995Shx147065 	ae_t *pae = NULL;
2695995Shx147065 	char *pbuf;
2696995Shx147065 
2697995Shx147065 	PRTDBG(("do_lsprefer(%d, 0x%x)\n", argc, argv));
2698995Shx147065 	if (argc > 0) {
2699995Shx147065 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
2700995Shx147065 		    "after 'listprefer'\n"), gExecName);
2701995Shx147065 	}
2702995Shx147065 	p_section = find_section(gp_config_file, WIFI_PREFER);
2703995Shx147065 	if (p_section != NULL) {
2704995Shx147065 		plist = p_section->list;
2705995Shx147065 		if (plist != NULL) {
2706995Shx147065 			pae = NULL;
2707995Shx147065 			pae = plist->ael_head;
2708995Shx147065 			while (pae != NULL) {
2709995Shx147065 				if (pae->ae_arg != NULL) {
2710995Shx147065 					pbuf = append_pa(pae->ae_arg);
2711995Shx147065 					(void) printf("%d\t%s\n", ++i, pbuf);
2712995Shx147065 				}
2713995Shx147065 				pae = pae->ae_next;
2714995Shx147065 			}
2715995Shx147065 		}
2716995Shx147065 		return (B_TRUE);
2717995Shx147065 	} else {
2718995Shx147065 		PRTDBG(("no preference section\n"));
2719995Shx147065 		return (B_FALSE);
2720995Shx147065 	}
2721995Shx147065 }
2722995Shx147065 
2723995Shx147065 /*
2724995Shx147065  * do_rmprefer: Remove an item in {preferrence} list
2725995Shx147065  */
2726995Shx147065 /*ARGSUSED*/
2727995Shx147065 static boolean_t
do_rmprefer(int fd,int argc,char ** argv)2728995Shx147065 do_rmprefer(int fd, int argc, char **argv)
2729995Shx147065 {
2730995Shx147065 	int i = 0;
2731995Shx147065 	section_t *p_section = NULL;
2732995Shx147065 	aelist_t *plist = NULL;
2733995Shx147065 	ae_t *pae = NULL;
2734995Shx147065 
2735995Shx147065 	PRTDBG(("do_rmprefer(%d, 0x%x)\n", argc, argv));
2736995Shx147065 	if (argc <= 0) {
2737995Shx147065 		do_print_usage();
2738995Shx147065 		exit(WIFI_IMPROPER_USE);
2739995Shx147065 	}
2740995Shx147065 
2741995Shx147065 	/*
2742995Shx147065 	 * if a "all" is inputted, all the items in the preference
2743995Shx147065 	 * list will be deleted.
2744995Shx147065 	 */
2745995Shx147065 	if (strcasecmp(argv[0], "all") == 0) {
2746995Shx147065 		p_section = find_section(gp_config_file, WIFI_PREFER);
2747995Shx147065 		if (p_section != NULL)
2748995Shx147065 			plist = p_section->list;
2749995Shx147065 
2750995Shx147065 		if ((p_section == NULL) || (plist == NULL))
2751995Shx147065 			return (B_FALSE);
2752995Shx147065 		pae = plist->ael_head;
2753995Shx147065 		while (pae != NULL) {
2754995Shx147065 			free(pae);
2755995Shx147065 			pae = pae->ae_next;
2756995Shx147065 		}
2757995Shx147065 		plist->ael_head = plist->ael_tail = NULL;
2758995Shx147065 		plist->ael_argc = 0;
2759995Shx147065 	} else if (gp_config_file != NULL) {
2760995Shx147065 		for (i = 0; i < argc; i++) {
2761995Shx147065 			if (del_prefer(gp_config_file, argv[i], B_TRUE)
2762995Shx147065 			    == B_FALSE) {
2763995Shx147065 				return (B_FALSE);
2764995Shx147065 			}
2765995Shx147065 		}
2766995Shx147065 	}
2767995Shx147065 	return (B_TRUE);
2768995Shx147065 }
2769995Shx147065 
2770995Shx147065 static boolean_t
is_prefer_rank_valid(const char * pbuf)2771995Shx147065 is_prefer_rank_valid(const char *pbuf)
2772995Shx147065 {
2773995Shx147065 	int i;
2774995Shx147065 	boolean_t ret = B_FALSE;
2775995Shx147065 
2776995Shx147065 	for (i = 0; i < strlen(pbuf); i++) {
2777995Shx147065 		if (isdigit(pbuf[i]) == 0) {
2778995Shx147065 			ret = B_FALSE;
2779995Shx147065 			goto exit0;
2780995Shx147065 		}
2781995Shx147065 	}
2782995Shx147065 	i = atoi(pbuf);
2783995Shx147065 	if ((i >= 1) && (i <= MAX_PREFERENCE_NUM))
2784995Shx147065 		ret = B_TRUE;
2785995Shx147065 exit0:
2786995Shx147065 	return (ret);
2787995Shx147065 }
2788995Shx147065 
2789995Shx147065 /*
2790995Shx147065  * do_setprefer: Set network preferrence
2791995Shx147065  */
2792995Shx147065 /*ARGSUSED*/
2793995Shx147065 static boolean_t
do_setprefer(int fd,int argc,char ** argv)2794995Shx147065 do_setprefer(int fd, int argc, char **argv)
2795995Shx147065 {
2796995Shx147065 	int rank = 0;
2797995Shx147065 
2798995Shx147065 	PRTDBG(("do_setprefer(%d, 0x%x)\n", argc, argv));
2799995Shx147065 	if (argc <= 0) {
2800995Shx147065 		do_print_usage();
2801995Shx147065 		exit(WIFI_IMPROPER_USE);
2802995Shx147065 	}
2803995Shx147065 	if (argc == 1) {
2804995Shx147065 		rank = 1;
2805995Shx147065 	} else {
2806995Shx147065 		if (is_prefer_rank_valid(argv[1]) == B_FALSE) {
2807995Shx147065 			(void) fprintf(stderr, gettext("%s: preference rank "
2808995Shx147065 			    "should be an integer within 1-10\n"), gExecName);
2809995Shx147065 			return (B_FALSE);
2810995Shx147065 		}
2811995Shx147065 		rank = atoi(argv[1]);
2812995Shx147065 	}
2813995Shx147065 	return (set_prefer(gp_config_file, argv[0], rank));
2814995Shx147065 }
2815995Shx147065 
2816995Shx147065 static boolean_t
is_wepkeyindex_valid(const char * pbuf)2817995Shx147065 is_wepkeyindex_valid(const char *pbuf)
2818995Shx147065 {
2819995Shx147065 	int i;
2820995Shx147065 	boolean_t ret = B_FALSE;
2821995Shx147065 
2822995Shx147065 	for (i = 0; i < strlen(pbuf); i++) {
2823995Shx147065 		if (isdigit(pbuf[i]) == 0) {
2824995Shx147065 			ret = B_FALSE;
2825995Shx147065 			goto exit0;
2826995Shx147065 		}
2827995Shx147065 	}
2828995Shx147065 	i = atoi(pbuf);
2829995Shx147065 	if ((i >= 1) && (i <= MAX_NWEPKEYS))
2830995Shx147065 		ret = B_TRUE;
2831995Shx147065 exit0:
2832995Shx147065 	return (ret);
2833995Shx147065 }
2834995Shx147065 
2835995Shx147065 static boolean_t
is_channel_valid(const char * pbuf)2836995Shx147065 is_channel_valid(const char *pbuf)
2837995Shx147065 {
2838995Shx147065 	int i;
2839995Shx147065 	boolean_t ret = B_FALSE;
2840995Shx147065 
2841995Shx147065 	for (i = 0; i < strlen(pbuf); i++) {
2842995Shx147065 		if (isdigit(pbuf[i]) == 0) {
2843995Shx147065 			ret = B_FALSE;
2844995Shx147065 			goto exit0;
2845995Shx147065 		}
2846995Shx147065 	}
2847995Shx147065 	i = atoi(pbuf);
2848995Shx147065 	if ((i >= 0) && (i <= MAX_CHANNEL_NUM))
2849995Shx147065 		ret = B_TRUE;
2850995Shx147065 exit0:
2851995Shx147065 	return (ret);
2852995Shx147065 }
2853995Shx147065 
2854995Shx147065 static boolean_t
is_wepkey_valid(const char * pbuf,uint32_t length)2855995Shx147065 is_wepkey_valid(const char *pbuf, uint32_t length)
2856995Shx147065 {
2857995Shx147065 	int i;
2858995Shx147065 	boolean_t ret = B_FALSE;
2859995Shx147065 
2860995Shx147065 	switch (length) {
2861995Shx147065 	case 10:
2862995Shx147065 	case 26:
2863995Shx147065 		for (i = 0; i < length; i++) {
2864995Shx147065 			if (isxdigit(pbuf[i]) == 0) {
2865995Shx147065 				ret = B_FALSE;
2866995Shx147065 				goto exit0;
2867995Shx147065 			}
2868995Shx147065 		}
2869995Shx147065 		ret = B_TRUE;
2870995Shx147065 		break;
2871995Shx147065 	case 5:
2872995Shx147065 	case 13:
2873995Shx147065 		ret = B_TRUE;
2874995Shx147065 		break;
2875995Shx147065 	default:
2876995Shx147065 		ret = B_FALSE;
2877995Shx147065 		break;
2878995Shx147065 	}
2879995Shx147065 exit0:
2880995Shx147065 	if (ret == B_FALSE) {
2881995Shx147065 		(void) fprintf(stderr, gettext("%s: "
2882995Shx147065 		    "wepkey should be:\n"
2883995Shx147065 		    "\t 40bits: 5 char or 10 hex digits.\n"
2884995Shx147065 		    "\t 128bits: 13 char or 26 hex digits.\n"),
2885995Shx147065 		    gExecName);
2886995Shx147065 	}
2887995Shx147065 	return (ret);
2888995Shx147065 }
2889995Shx147065 
2890995Shx147065 /*
2891995Shx147065  * get_valid_wepkey: get an valid wepkey from stdin
2892995Shx147065  */
2893995Shx147065 static char *
get_valid_wepkey()2894995Shx147065 get_valid_wepkey()
2895995Shx147065 {
2896995Shx147065 	int i = 0;
2897995Shx147065 	char *buf = NULL;
2898995Shx147065 	uint8_t length = 0;
2899995Shx147065 	struct termios stored_settings;
2900995Shx147065 	struct termios new_settings;
2901995Shx147065 
2902995Shx147065 	PRTDBG(("get_valid_wepkey()\n"));
2903995Shx147065 	buf = safe_calloc(sizeof (char), MAX_KEY_LENGTH + 2);
2904995Shx147065 	/*
2905995Shx147065 	 * Because we need to get single char from terminal, so we need to
2906995Shx147065 	 * disable canonical mode and set buffer size to 1 tyte. And because
2907995Shx147065 	 * wepkey should not be see by others, so we disable echo too.
2908995Shx147065 	 */
2909995Shx147065 	(void) fflush(stdin);
2910995Shx147065 	(void) tcgetattr(0, &stored_settings);
2911995Shx147065 	new_settings = stored_settings;
2912995Shx147065 	new_settings.c_lflag &= (~ICANON);
2913995Shx147065 	new_settings.c_lflag &= (~ECHO);
2914995Shx147065 	new_settings.c_cc[VTIME] = 0;
2915995Shx147065 	new_settings.c_cc[VMIN] = 1;
2916995Shx147065 	/* Set new terminal attributes */
2917995Shx147065 	(void) tcsetattr(0, TCSANOW, &new_settings);
2918995Shx147065 	while (((buf[i++] = getchar()) != '\n') && (i < MAX_KEY_LENGTH + 1)) {
2919995Shx147065 		(void) putchar('*');
2920995Shx147065 	}
2921995Shx147065 	(void) putchar('\n');
2922995Shx147065 	/* Restore terminal attributes */
2923995Shx147065 	(void) tcsetattr(0, TCSANOW, &stored_settings);
2924995Shx147065 	(void) fflush(stdin);
2925995Shx147065 
2926995Shx147065 	if (buf[--i] != '\n') {
2927995Shx147065 		(void) fprintf(stderr, gettext("%s: wepkey length "
2928995Shx147065 		    "exceeds 26 hex digits\n"), gExecName);
2929995Shx147065 		free(buf);
2930995Shx147065 		return (NULL);
2931995Shx147065 	}
2932995Shx147065 	/* Replace last char '\n' with '\0' */
2933995Shx147065 	buf[i] = '\0';
2934995Shx147065 	length = (uint8_t)i;
2935995Shx147065 	return ((is_wepkey_valid(buf, length) == B_TRUE)?
2936995Shx147065 	    buf : NULL);
2937995Shx147065 }
2938995Shx147065 
2939995Shx147065 /*
2940995Shx147065  * do_set_wepkey: Set parameters in wepkey, and call ioctl
2941995Shx147065  */
2942995Shx147065 static boolean_t
do_set_wepkey(int fd,const char * pbuf)2943995Shx147065 do_set_wepkey(int fd, const char *pbuf)
2944995Shx147065 {
2945995Shx147065 	int id = 0;
2946995Shx147065 	char i = 0;
2947995Shx147065 	uint8_t len = 0;
2948995Shx147065 	uint8_t length;
2949995Shx147065 	const char *wepkey = NULL;
2950995Shx147065 	char key[MAX_KEY_LENGTH] = {0};
2951995Shx147065 	unsigned int keytmp;
2952995Shx147065 	wl_wep_key_tab_t wepkey_tab;
2953995Shx147065 
2954995Shx147065 	PRTDBG(("do_set_wepkey(%d, \"%s\")\n", fd, pbuf));
2955995Shx147065 	if (!check_authority(AUTH_WEP)) {
2956995Shx147065 		exit(WIFI_FATAL_ERR);
2957995Shx147065 	}
2958995Shx147065 	id = pbuf[strlen("wepkeyn") - 1] - '0';
2959995Shx147065 	wepkey = get_value(pbuf);
2960995Shx147065 	length = strlen(wepkey);
2961995Shx147065 	switch (length) {
2962995Shx147065 	case 10:
2963995Shx147065 	case 26:
2964995Shx147065 		for (i = 0; i < length / 2; i++) {
2965995Shx147065 			(void) sscanf(wepkey + i * 2, "%2x", &keytmp);
2966995Shx147065 			key[i] = (char)keytmp;
2967995Shx147065 		}
2968995Shx147065 		len = length / 2;
2969995Shx147065 		break;
2970995Shx147065 	case 5:
2971995Shx147065 	case 13:
2972995Shx147065 		(void) strlcpy(key, wepkey, MAX_KEY_LENGTH);
2973995Shx147065 		len = length;
2974995Shx147065 		break;
2975995Shx147065 	default:
2976995Shx147065 		PRTDBG(("do_set_wepkey: error pbuf size\n"));
2977995Shx147065 		(void) fprintf(stderr, gettext("%s: "
2978995Shx147065 		    "wepkey should be:\n"
2979995Shx147065 		    "\t 40bits: 5 char or 10 hex digits.\n"
2980995Shx147065 		    "\t 128bits: 13 char or 26 hex digits.\n"),
2981995Shx147065 		    gExecName);
2982995Shx147065 		exit(WIFI_FATAL_ERR);
2983995Shx147065 	}
2984995Shx147065 
2985995Shx147065 	(void) memset(wepkey_tab, 0, sizeof (wepkey_tab));
2986995Shx147065 	for (i = 0; i < MAX_NWEPKEYS; i++) {
2987995Shx147065 		wepkey_tab[i].wl_wep_operation = WL_NUL;
2988995Shx147065 	}
2989995Shx147065 
2990995Shx147065 	if (id > 0 && id <= MAX_NWEPKEYS) {
2991995Shx147065 		wepkey_tab[id-1].wl_wep_operation = WL_ADD;
2992995Shx147065 		wepkey_tab[id-1].wl_wep_length = len;
2993995Shx147065 		(void) memcpy(wepkey_tab[id-1].wl_wep_key, key, len);
2994995Shx147065 	} else {
2995995Shx147065 		(void) fprintf(stderr, gettext("%s: wepkeyindex "
2996995Shx147065 		    "should be an integer within the range 1-4\n"), gExecName);
2997995Shx147065 		exit(WIFI_FATAL_ERR);
2998995Shx147065 	}
2999995Shx147065 	(void) memmove(gbuf->wldp_buf, &wepkey_tab, sizeof (wl_wep_key_tab_t));
3000995Shx147065 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_WEP_KEY_TAB,
3001995Shx147065 	    sizeof (wl_wep_key_tab_t)));
3002995Shx147065 }
3003995Shx147065 
3004995Shx147065 /*
3005995Shx147065  * get the committed wepkey. the return form is like wepkey1=*****;
3006995Shx147065  */
3007995Shx147065 /*ARGSUSED*/
3008995Shx147065 static char *
get_commit_key(int fd,int argc,char ** argv)3009995Shx147065 get_commit_key(int fd, int argc, char **argv)
3010995Shx147065 {
3011995Shx147065 	int key;
3012995Shx147065 	int len;
3013995Shx147065 	char *wepkey = NULL;
3014995Shx147065 	char *wepkey_confirm = NULL;
3015995Shx147065 	char *pbuf = NULL;
3016995Shx147065 
3017995Shx147065 	key = atoi(argv[0]);
3018995Shx147065 	if (key <= 0 || key > MAX_NWEPKEYS) {
3019995Shx147065 		(void) fprintf(stderr, gettext("%s: wepkeyindex "
3020995Shx147065 		    "should be an integer within the range 1-4\n"), gExecName);
3021995Shx147065 		goto exit0;
3022995Shx147065 	}
3023995Shx147065 	(void) printf(gettext("input wepkey%d:"), key);
3024995Shx147065 	wepkey = get_valid_wepkey();
3025995Shx147065 	if (wepkey == NULL) {
3026995Shx147065 		goto exit0;
3027995Shx147065 	}
3028995Shx147065 	(void) printf(gettext("confirm wepkey%d:"), key);
3029995Shx147065 	wepkey_confirm = get_valid_wepkey();
3030995Shx147065 	if (wepkey_confirm == NULL) {
3031995Shx147065 		free(wepkey);
3032995Shx147065 		goto exit0;
3033995Shx147065 	}
3034995Shx147065 	if (strcmp(wepkey, wepkey_confirm) != 0) {
3035995Shx147065 		free(wepkey);
3036995Shx147065 		free(wepkey_confirm);
3037995Shx147065 		(void) fprintf(stderr,
3038995Shx147065 		    gettext("%s: wepkey: "
3039995Shx147065 		    "two inputs are not identical\n"), gExecName);
3040995Shx147065 		goto exit0;
3041995Shx147065 	}
3042995Shx147065 	free(wepkey_confirm); /* wepkey_confirm is no longer used */
3043995Shx147065 
3044995Shx147065 	len = MAX_KEY_LENGTH + strlen("wepkey1=\n") + 1;
3045995Shx147065 	pbuf = safe_malloc(len);
3046995Shx147065 	safe_snprintf(pbuf, len, "%s%d=%s", "wepkey", key, wepkey);
3047995Shx147065 
3048995Shx147065 	free(wepkey); /* wepkey is no longer used */
3049995Shx147065 	return (pbuf);
3050995Shx147065 exit0:
3051995Shx147065 	return (NULL);
3052995Shx147065 }
3053995Shx147065 
3054995Shx147065 /*
3055995Shx147065  * do_wepkey: Get input from user, call do_set_wepkey
3056995Shx147065  */
3057995Shx147065 /*ARGSUSED*/
3058995Shx147065 static boolean_t
do_wepkey(int fd,int argc,char ** argv)3059995Shx147065 do_wepkey(int fd, int argc, char **argv)
3060995Shx147065 {
3061995Shx147065 	char *pbuf;
3062995Shx147065 
3063995Shx147065 	PRTDBG(("do_wepkey(%d, 0x%x)\n", argc, argv));
3064995Shx147065 	assert(fd > 0);
3065995Shx147065 	if (argc <= 0) {
3066995Shx147065 		do_print_usage();
3067995Shx147065 		exit(WIFI_IMPROPER_USE);
3068995Shx147065 	}
3069995Shx147065 	if (argc > 1) {
3070995Shx147065 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
3071995Shx147065 		    "after 'setwepkey'\n"), gExecName);
3072995Shx147065 	}
3073995Shx147065 	pbuf = get_commit_key(fd, argc, argv);
3074995Shx147065 	if ((pbuf != NULL) && (do_set_wepkey(fd, pbuf) == B_TRUE)) {
3075995Shx147065 		free(pbuf);
3076995Shx147065 		return (B_TRUE);
3077995Shx147065 	}
3078995Shx147065 	free(pbuf);
3079995Shx147065 	return (B_FALSE);
3080995Shx147065 }
3081995Shx147065 
3082995Shx147065 /*ARGSUSED*/
3083995Shx147065 static boolean_t
do_setprofwepkey(int fd,int argc,char ** argv)3084995Shx147065 do_setprofwepkey(int fd, int argc, char **argv)
3085995Shx147065 {
3086995Shx147065 	char *pbuf;
3087995Shx147065 	char *section_id = NULL;
3088995Shx147065 	section_t *p_section = NULL;
3089995Shx147065 	aelist_t *plist = NULL;
3090995Shx147065 
3091995Shx147065 	PRTDBG(("do_setprofwepkey(%d, 0x%x)\n", argc, argv));
3092995Shx147065 	if (argc < 2) {
3093995Shx147065 		do_print_usage();
3094995Shx147065 		exit(WIFI_IMPROPER_USE);
3095995Shx147065 	}
3096995Shx147065 	if (argc > 2) {
3097995Shx147065 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
3098995Shx147065 		    "after 'setprofwepkey'\n"), gExecName);
3099995Shx147065 	}
3100995Shx147065 
3101995Shx147065 	section_id = append_pa(argv[0]);
3102995Shx147065 	p_section = find_section(gp_wepkey_file, section_id);
3103995Shx147065 	free(section_id);
3104995Shx147065 	if (p_section == NULL) {
3105995Shx147065 		(void) fprintf(stderr, gettext("%s: "
3106995Shx147065 		    "no such profile: '%s'\n"),
3107995Shx147065 		    gExecName, argv[0]);
3108995Shx147065 		return (B_FALSE);
3109995Shx147065 	}
3110995Shx147065 
3111995Shx147065 	argc--;
3112995Shx147065 	argv++;
3113995Shx147065 	pbuf = get_commit_key(fd, argc, argv);
3114995Shx147065 	if (pbuf == NULL)
3115995Shx147065 		return (B_FALSE);
3116995Shx147065 	plist = p_section->list;
3117995Shx147065 	update_aelist(plist, pbuf);
3118995Shx147065 
3119995Shx147065 	return (B_TRUE);
3120995Shx147065 }
3121995Shx147065 
3122995Shx147065 /*
3123995Shx147065  * do_wlanlist: Scan for wlanlist
3124995Shx147065  */
3125995Shx147065 /*ARGSUSED*/
3126995Shx147065 static boolean_t
do_wlanlist(int fd,int argc,char ** argv)3127995Shx147065 do_wlanlist(int fd, int argc, char **argv)
3128995Shx147065 {
3129995Shx147065 	PRTDBG(("do_wlanlist(%d, 0x%x)\n", argc, argv));
3130995Shx147065 	assert(fd > 0);
3131995Shx147065 	if (argc > 0) {
3132995Shx147065 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
3133995Shx147065 		    "after 'scan'\n"), gExecName);
3134995Shx147065 	}
3135995Shx147065 	if (call_ioctl(fd, WLAN_COMMAND, WL_SCAN, 0) == B_FALSE) {
3136995Shx147065 		(void) fprintf(stderr, gettext("%s: failed to scan\n"),
3137995Shx147065 		    gExecName);
3138995Shx147065 		return (B_FALSE);
3139995Shx147065 	}
3140995Shx147065 	if (do_get_wlanlist(fd) == B_TRUE) {
3141995Shx147065 		print_gbuf(WLANLIST);
3142995Shx147065 	}
3143995Shx147065 	return (B_TRUE);
3144995Shx147065 }
3145995Shx147065 
3146995Shx147065 /*
3147995Shx147065  * do_showstatus: show the basic status of the interface, including
3148995Shx147065  * linkstauts, essid, encryption and signal strength.
3149995Shx147065  */
3150995Shx147065 /*ARGSUSED*/
3151995Shx147065 static boolean_t
do_showstatus(int fd,int argc,char ** argv)3152995Shx147065 do_showstatus(int fd, int argc, char **argv)
3153995Shx147065 {
3154995Shx147065 	wl_rssi_t signal;
3155995Shx147065 	char *active_profile = NULL;
3156995Shx147065 
3157995Shx147065 	PRTDBG(("do_showstatus(%d, 0x%x)\n", argc, argv));
3158995Shx147065 	assert(fd > 0);
3159995Shx147065 
3160995Shx147065 	if (argc > 0) {
3161995Shx147065 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
3162995Shx147065 		    "after 'showstatus'\n"), gExecName);
3163995Shx147065 	}
3164995Shx147065 	if (do_get_linkstatus(fd) == B_TRUE) {
3165995Shx147065 		print_gbuf(LINKSTATUS);
3166995Shx147065 		if (*(wl_linkstatus_t *)(gbuf->wldp_buf) == WL_NOTCONNECTED) {
3167995Shx147065 			return (B_TRUE);
3168995Shx147065 		}
3169995Shx147065 	}
3170995Shx147065 	active_profile = find_active_profile(fd);
3171995Shx147065 	(void) printf("\tactive profile: %s\n",
3172995Shx147065 	    active_profile ? active_profile : "none");
3173995Shx147065 	if (do_get_essid(fd) == B_TRUE) {
3174995Shx147065 		print_gbuf(ESSID);
3175995Shx147065 	}
3176995Shx147065 	if (do_get_bssid(fd) == B_TRUE) {
3177995Shx147065 		print_gbuf(BSSID);
3178995Shx147065 	}
3179995Shx147065 	if (do_get_encryption(fd) == B_TRUE) {
3180995Shx147065 		print_gbuf(ENCRYPTION);
3181995Shx147065 	}
3182995Shx147065 	if (do_get_signal(fd) == B_TRUE) {
3183995Shx147065 		signal = *(wl_rssi_t *)(gbuf->wldp_buf);
3184995Shx147065 		if (signal < 4) {
3185995Shx147065 			(void) printf("\tsignal strength: weak(%d)\n",
3186995Shx147065 			    signal);
3187995Shx147065 		} else if ((signal >= 4) && (signal <= 11)) {
3188995Shx147065 			(void) printf("\tsignal strength: medium(%d)\n",
3189995Shx147065 			    signal);
3190995Shx147065 		} else {
3191995Shx147065 			(void) printf("\tsignal strength: strong(%d)\n",
3192995Shx147065 			    signal);
3193995Shx147065 		}
3194995Shx147065 	}
3195995Shx147065 
3196995Shx147065 	return (B_TRUE);
3197995Shx147065 }
3198995Shx147065 
3199995Shx147065 
3200995Shx147065 /*
3201995Shx147065  * do_restoredef: Ask driver for loading default parameters
3202995Shx147065  */
3203995Shx147065 /*ARGSUSED*/
3204995Shx147065 static boolean_t
do_restoredef(int fd,int argc,char ** argv)3205995Shx147065 do_restoredef(int fd, int argc, char **argv)
3206995Shx147065 {
3207995Shx147065 	PRTDBG(("do_restoredef(%d, 0x%x)\n", argc, argv));
3208995Shx147065 	assert(fd > 0);
3209995Shx147065 
3210995Shx147065 	if (argc > 0) {
3211995Shx147065 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
3212995Shx147065 		    "after 'restoredef'\n"), gExecName);
3213995Shx147065 	}
3214995Shx147065 	record_active_profile(NULL, RECORD_DEL);
3215995Shx147065 	if (call_ioctl(fd, WLAN_COMMAND, WL_LOAD_DEFAULTS, 0) == B_FALSE) {
3216995Shx147065 		return (B_FALSE);
3217995Shx147065 	} else {
3218995Shx147065 		return (B_TRUE);
3219995Shx147065 	}
3220995Shx147065 }
3221995Shx147065 
3222995Shx147065 /*
3223995Shx147065  * do_disconnect: disconnect from the current connectted network
3224995Shx147065  */
3225995Shx147065 /*ARGSUSED*/
3226995Shx147065 static boolean_t
do_disconnect(int fd,int argc,char ** argv)3227995Shx147065 do_disconnect(int fd, int argc, char **argv)
3228995Shx147065 {
3229995Shx147065 	PRTDBG(("do_disconnect(%d, 0x%x)\n", argc, argv));
3230995Shx147065 	assert(fd > 0);
3231995Shx147065 
3232995Shx147065 	if (argc > 0) {
3233995Shx147065 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
3234995Shx147065 		    "after 'disconnect'\n"), gExecName);
3235995Shx147065 	}
3236995Shx147065 	record_active_profile(NULL, RECORD_DEL);
3237995Shx147065 	if (call_ioctl(fd, WLAN_COMMAND, WL_DISASSOCIATE, 0) == B_FALSE) {
3238995Shx147065 		return (B_FALSE);
3239995Shx147065 	} else {
3240995Shx147065 		return (B_TRUE);
3241995Shx147065 	}
3242995Shx147065 }
3243995Shx147065 
3244995Shx147065 static boolean_t
do_set_essid(int fd,const char * arg)3245995Shx147065 do_set_essid(int fd, const char *arg)
3246995Shx147065 {
3247995Shx147065 	wl_essid_t essid;
3248995Shx147065 
3249995Shx147065 	PRTDBG(("do_set_essid(%d, \"%s\")\n", fd, arg));
3250995Shx147065 
3251995Shx147065 	/*
3252995Shx147065 	 * a trick here: clean the active_profile flag
3253995Shx147065 	 * in section{active_profile}
3254995Shx147065 	 */
3255995Shx147065 	record_active_profile(NULL, RECORD_DEL);
3256995Shx147065 
3257995Shx147065 	(void) memset(&essid, 0x0, sizeof (essid));
3258995Shx147065 
3259995Shx147065 	if (arg == NULL || strcmp(arg, "") == 0) {
3260995Shx147065 		essid.wl_essid_length = 0;
3261995Shx147065 		essid.wl_essid_essid[0] = '\0';
3262995Shx147065 	} else {
3263995Shx147065 		essid.wl_essid_length = strlen(arg);
3264*6834Sff224033 		if (essid.wl_essid_length > MAX_ESSID_LENGTH - 1) {
3265995Shx147065 			(void) fprintf(stderr, gettext("%s: "
3266995Shx147065 			    "essid exceeds 32 bytes\n"), gExecName);
3267995Shx147065 			exit(WIFI_FATAL_ERR);
3268995Shx147065 		}
3269995Shx147065 		(void) strcpy(essid.wl_essid_essid, arg);
3270995Shx147065 	}
3271995Shx147065 	(void) memmove(gbuf->wldp_buf, &essid, sizeof (wl_essid_t));
3272995Shx147065 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_ESSID, sizeof (wl_essid_t)));
3273995Shx147065 }
3274995Shx147065 
3275995Shx147065 static boolean_t
do_set_bsstype(int fd,const char * arg)3276995Shx147065 do_set_bsstype(int fd, const char *arg)
3277995Shx147065 {
3278995Shx147065 	wl_bss_type_t bsstype;
3279995Shx147065 
3280995Shx147065 	assert(arg != NULL);
3281995Shx147065 
3282995Shx147065 	PRTDBG(("do_set_bsstype(%d, \"%s\")\n", fd, arg));
3283995Shx147065 
3284995Shx147065 	(void) memset(&bsstype, 0xff, sizeof (bsstype));
3285995Shx147065 
3286995Shx147065 	if ((strcasecmp(arg, "BSS") == 0) ||
3287995Shx147065 	    (strcasecmp(arg, "AP") == 0) ||
3288995Shx147065 	    (strcasecmp(arg, "INFRASTRUCTURE") == 0)) {
3289995Shx147065 		bsstype = WL_BSS_BSS;
3290995Shx147065 	} else if ((strcasecmp(arg, "IBSS") == 0) ||
3291995Shx147065 	    (strcasecmp(arg, "AD-HOC") == 0)) {
3292995Shx147065 		bsstype = WL_BSS_IBSS;
3293995Shx147065 	} else if (strcasecmp(arg, "AUTO") == 0) {
3294995Shx147065 		bsstype = WL_BSS_ANY;
3295995Shx147065 	} else {
3296995Shx147065 		(void) fprintf(stderr, gettext("%s: bsstype: "
3297995Shx147065 		    "bss(ap,infrastructure) ibss(ad-hoc) or auto\n"),
3298995Shx147065 		    gExecName);
3299995Shx147065 		exit(WIFI_FATAL_ERR);
3300995Shx147065 	}
3301995Shx147065 
3302995Shx147065 	(void) memmove(gbuf->wldp_buf, &bsstype, sizeof (wl_bss_type_t));
3303995Shx147065 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_BSS_TYPE,
3304995Shx147065 	    sizeof (wl_bss_type_t)));
3305995Shx147065 }
3306995Shx147065 
3307995Shx147065 static boolean_t
do_set_createibss(int fd,const char * arg)3308995Shx147065 do_set_createibss(int fd, const char *arg)
3309995Shx147065 {
3310995Shx147065 	wl_create_ibss_t create_ibss;
3311995Shx147065 
3312995Shx147065 	assert(arg != NULL);
3313995Shx147065 
3314995Shx147065 	PRTDBG(("do_set_createibss(%d, \"%s\")\n", fd, arg));
3315995Shx147065 
3316995Shx147065 	(void) memset(&create_ibss, 0x0, sizeof (create_ibss));
3317995Shx147065 
3318995Shx147065 	if (strcasecmp(arg, "YES") == 0) {
3319995Shx147065 		create_ibss = B_TRUE;
3320995Shx147065 	} else if (strcasecmp(arg, "NO") == 0) {
3321995Shx147065 		create_ibss = B_FALSE;
3322995Shx147065 	} else {
3323995Shx147065 		(void) fprintf(stderr, gettext("%s: "
3324995Shx147065 		    "createibss: yes or no\n"), gExecName);
3325995Shx147065 		exit(WIFI_FATAL_ERR);
3326995Shx147065 	}
3327995Shx147065 
3328995Shx147065 	(void) memmove(gbuf->wldp_buf, &create_ibss,
3329995Shx147065 	    sizeof (wl_create_ibss_t));
3330995Shx147065 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_CREATE_IBSS,
3331995Shx147065 	    sizeof (wl_create_ibss_t)));
3332995Shx147065 }
3333995Shx147065 
3334995Shx147065 static boolean_t
do_set_channel(int fd,const char * arg)3335995Shx147065 do_set_channel(int fd, const char *arg)
3336995Shx147065 {
3337995Shx147065 	wl_phy_conf_t phy_conf;
3338995Shx147065 
3339995Shx147065 	assert(arg != NULL);
3340995Shx147065 	PRTDBG(("do_set_channel(%d, \"%s\")\n", fd, arg));
3341995Shx147065 
3342995Shx147065 	(void) memset(&phy_conf, 0xff, sizeof (phy_conf));
3343995Shx147065 
3344995Shx147065 	if (is_channel_valid(arg) == B_FALSE) {
3345995Shx147065 		(void) fprintf(stderr, gettext("%s: channel No. "
3346995Shx147065 		    "should be:\n"
3347995Shx147065 		    "\t802.11a: 0-99\n"
3348995Shx147065 		    "\t802.11b: 1-14\n"
3349995Shx147065 		    "\t802.11g: 1-14\n"), gExecName);
3350995Shx147065 		exit(WIFI_FATAL_ERR);
3351995Shx147065 	}
3352995Shx147065 	phy_conf.wl_phy_dsss_conf.wl_dsss_channel = atoi(arg);
3353995Shx147065 	PRTDBG(("channel=%d\n", phy_conf.wl_phy_dsss_conf.wl_dsss_channel));
3354995Shx147065 
3355995Shx147065 	(void) memmove(gbuf->wldp_buf, &phy_conf, sizeof (wl_phy_conf_t));
3356995Shx147065 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_PHY_CONFIG,
3357995Shx147065 	    sizeof (wl_phy_conf_t)));
3358995Shx147065 }
3359995Shx147065 /*
3360995Shx147065  * is_rates_support: Querying driver about supported rates.
3361995Shx147065  */
3362995Shx147065 static boolean_t
is_rates_support(int fd,int num,uint8_t * rates)3363995Shx147065 is_rates_support(int fd, int num, uint8_t *rates)
3364995Shx147065 {
3365995Shx147065 	int rates_num = 0;
3366995Shx147065 	int i = 0, j = 0;
3367995Shx147065 	uint8_t value = 0;
3368995Shx147065 
3369995Shx147065 	assert((rates != NULL)&&(num != 0));
3370995Shx147065 	PRTDBG(("is_rates_support(%d, %d, 0x%x)\n", fd, num, rates));
3371995Shx147065 
3372995Shx147065 	if (call_ioctl(fd, WLAN_GET_PARAM, WL_SUPPORTED_RATES, 0)
3373995Shx147065 	    == B_TRUE) {
3374995Shx147065 		rates_num = ((wl_rates_t *)(gbuf->wldp_buf))->wl_rates_num;
3375995Shx147065 
3376995Shx147065 		for (i = 0; i < num; i++) {
3377995Shx147065 			PRTDBG(("rates[%d] = %d\n", i, rates[i]));
3378995Shx147065 			for (j = 0; j < rates_num; j++) {
3379995Shx147065 				value = ((wl_rates_t *)gbuf->wldp_buf)
3380995Shx147065 				    ->wl_rates_rates[j];
3381995Shx147065 				PRTDBG(("supported rates[%d]=%d\n", j, value));
3382995Shx147065 				if (value == rates[i]) {
3383995Shx147065 					break;
3384995Shx147065 				}
3385995Shx147065 			}
3386995Shx147065 			if (j == rates_num) {
3387995Shx147065 				if (rates[i] == 11) {
3388995Shx147065 					(void) fprintf(stderr,
3389995Shx147065 					    gettext("%s: "
3390995Shx147065 					    "rate 5.5M is not supported\n"),
3391995Shx147065 					    gExecName);
3392995Shx147065 				} else {
3393995Shx147065 					(void) fprintf(stderr,
3394995Shx147065 					    gettext("%s: "
3395995Shx147065 					    "rate %dM is not supported\n"),
3396995Shx147065 					    gExecName, rates[i]/2);
3397995Shx147065 				}
3398995Shx147065 				return (B_FALSE);
3399995Shx147065 			}
3400995Shx147065 		}
3401995Shx147065 		return (B_TRUE);
3402995Shx147065 	}
3403995Shx147065 	return (B_FALSE);
3404995Shx147065 }
3405995Shx147065 
3406995Shx147065 /*
3407995Shx147065  *
3408995Shx147065  */
3409995Shx147065 static uint8_t
rates_convert(const char * rates)3410995Shx147065 rates_convert(const char *rates)
3411995Shx147065 {
3412995Shx147065 	int i;
3413995Shx147065 	uint8_t ret;
3414995Shx147065 
3415995Shx147065 	for (i = 0; i < WIFI_RATES_NUM; i++) {
3416995Shx147065 		if (strcmp(rates, wifi_rates_s[i].rates_s) == 0) {
3417995Shx147065 			ret = wifi_rates_s[i].rates_i;
3418995Shx147065 			break;
3419995Shx147065 		}
3420995Shx147065 	}
3421995Shx147065 	if (i == WIFI_RATES_NUM) {
3422995Shx147065 		(void) fprintf(stderr, gettext("%s: "
3423995Shx147065 		    "invalid rates '%s'\n"), gExecName, rates);
3424995Shx147065 		exit(WIFI_FATAL_ERR);
3425995Shx147065 	}
3426995Shx147065 	return (ret);
3427995Shx147065 }
3428995Shx147065 
3429995Shx147065 /*
3430995Shx147065  * get_rates: convert string value arg into uint8_t array,
3431995Shx147065  * array length will be save into *len[i].
3432995Shx147065  * for example:
3433995Shx147065  * arg = "1,2,5.5,11"
3434995Shx147065  * then after call, rates[] = {2,4,11,22} will be returned.
3435995Shx147065  * and *len will equal to 4
3436995Shx147065  */
3437995Shx147065 static uint8_t *
get_rates(const char * arg,uint32_t * len)3438995Shx147065 get_rates(const char *arg, uint32_t *len)
3439995Shx147065 {
3440995Shx147065 	int i = 1, j = 0;
3441995Shx147065 	uint8_t *rates = NULL;
3442995Shx147065 	char *pnext = NULL;
3443995Shx147065 	char *token;
3444995Shx147065 	char *pstart;
3445995Shx147065 	char *pstart_bak;
3446995Shx147065 
3447995Shx147065 	assert(arg != NULL);
3448995Shx147065 
3449995Shx147065 	if (strlen(arg) == 0) {
3450995Shx147065 		PRTDBG(("get_rates: empty rates string\n"));
3451995Shx147065 		return (NULL);
3452995Shx147065 	}
3453995Shx147065 	PRTDBG(("get_rates(\"%s\", 0x%x)\n", arg, len));
3454995Shx147065 	pstart = safe_strdup(arg);
3455995Shx147065 	pstart_bak = pstart;
3456995Shx147065 	while ((pnext = strchr(pstart, ',')) != NULL) {
3457995Shx147065 		pstart = pnext + 1;
3458995Shx147065 		i++;
3459995Shx147065 	}
3460995Shx147065 	*len = i;
3461995Shx147065 	rates = safe_calloc(sizeof (uint8_t), i);
3462995Shx147065 
3463995Shx147065 	pstart = pstart_bak;
3464995Shx147065 	if ((token = strtok(pstart, ",")) != NULL) {
3465995Shx147065 		PRTDBG(("rates[0]: %s\n", token));
3466995Shx147065 		rates[0] = rates_convert(token);
3467995Shx147065 		i = 1;
3468995Shx147065 		while ((token = strtok(NULL, ",")) != NULL) {
3469995Shx147065 			PRTDBG(("rates[%d]: %s\n", i, token));
3470995Shx147065 			rates[i++] = rates_convert(token);
3471995Shx147065 		}
3472995Shx147065 	}
3473995Shx147065 	free(pstart_bak);
3474995Shx147065 	for (i = 0; i < *len; i++) {
3475995Shx147065 		for (j = 0; j < i; j++)
3476995Shx147065 			if (rates[j] == rates[i]) {
3477995Shx147065 				(void) fprintf(stderr,
3478995Shx147065 				    gettext("%s: rates duplicated\n"),
3479995Shx147065 				    gExecName);
3480995Shx147065 				free(rates);
3481995Shx147065 				return (NULL);
3482995Shx147065 			}
3483995Shx147065 	}
3484995Shx147065 
3485995Shx147065 	return (rates);
3486995Shx147065 }
3487995Shx147065 
3488995Shx147065 static boolean_t
do_set_rates(int fd,const char * arg)3489995Shx147065 do_set_rates(int fd, const char *arg)
3490995Shx147065 {
3491995Shx147065 	int i = 0;
3492995Shx147065 	uint32_t num = 0;
3493995Shx147065 	uint8_t *rates;
3494995Shx147065 
3495995Shx147065 	assert(arg != NULL);
3496995Shx147065 
3497995Shx147065 	PRTDBG(("do_set_rates(%d, \"%s\")\n", fd, arg));
3498995Shx147065 
3499995Shx147065 	rates = get_rates(arg, &num);
3500995Shx147065 	if ((rates == NULL) ||
3501995Shx147065 	    is_rates_support(fd, num, rates) == B_FALSE) {
3502995Shx147065 		exit(WIFI_FATAL_ERR);
3503995Shx147065 	}
3504995Shx147065 
3505995Shx147065 	((wl_rates_t *)(gbuf->wldp_buf))->wl_rates_num = num;
3506995Shx147065 	for (i = 0; i < num; i++) {
3507995Shx147065 		((wl_rates_t *)gbuf->wldp_buf)->wl_rates_rates[i]
3508995Shx147065 		    = rates[i];
3509995Shx147065 	}
3510995Shx147065 	free(rates);
3511995Shx147065 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_DESIRED_RATES,
3512995Shx147065 	    offsetof(wl_rates_t, wl_rates_rates) +
3513995Shx147065 	    num*sizeof (char)));
3514995Shx147065 }
3515995Shx147065 
3516995Shx147065 static boolean_t
do_set_powermode(int fd,const char * arg)3517995Shx147065 do_set_powermode(int fd, const char *arg)
3518995Shx147065 {
3519995Shx147065 	wl_ps_mode_t ps_mode;
3520995Shx147065 
3521995Shx147065 	assert(arg != NULL);
3522995Shx147065 
3523995Shx147065 	PRTDBG(("do_set_powermode(%d, \"%s\")\n", fd, arg));
3524995Shx147065 
3525995Shx147065 	(void) memset(&ps_mode, 0xff, sizeof (ps_mode));
3526995Shx147065 
3527995Shx147065 	if ((strcasecmp(arg, "OFF") == 0) ||
3528995Shx147065 	    (strcasecmp(arg, "MPS") == 0) ||
3529995Shx147065 	    (strcasecmp(arg, "FAST") == 0)) {
3530995Shx147065 		switch (arg[0]) {
3531995Shx147065 		case 'O':
3532995Shx147065 		case 'o':
3533995Shx147065 			ps_mode.wl_ps_mode = WL_PM_AM;
3534995Shx147065 			break;
3535995Shx147065 		case 'M':
3536995Shx147065 		case 'm':
3537995Shx147065 			ps_mode.wl_ps_mode = WL_PM_MPS;
3538995Shx147065 			break;
3539995Shx147065 		case 'F':
3540995Shx147065 		case 'f':
3541995Shx147065 			ps_mode.wl_ps_mode = WL_PM_FAST;
3542995Shx147065 			break;
3543995Shx147065 		default:
3544995Shx147065 			break;
3545995Shx147065 		}
3546995Shx147065 	} else {
3547995Shx147065 		(void) fprintf(stderr,
3548995Shx147065 		    gettext("%s: powermode: off mps or fast\n"), gExecName);
3549995Shx147065 		exit(WIFI_FATAL_ERR);
3550995Shx147065 	}
3551995Shx147065 
3552995Shx147065 	(void) memmove(gbuf->wldp_buf, &ps_mode, sizeof (wl_ps_mode_t));
3553995Shx147065 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_POWER_MODE,
3554995Shx147065 	    sizeof (wl_ps_mode_t)));
3555995Shx147065 }
3556995Shx147065 
3557995Shx147065 static boolean_t
do_set_authmode(int fd,const char * arg)3558995Shx147065 do_set_authmode(int fd, const char *arg)
3559995Shx147065 {
3560995Shx147065 	wl_authmode_t auth_mode;
3561995Shx147065 
3562995Shx147065 	assert(arg != NULL);
3563995Shx147065 	PRTDBG(("do_set_authmode(%d, \"%s\")\n", fd, arg));
3564995Shx147065 
3565995Shx147065 	(void) memset(&auth_mode, 0xff, sizeof (auth_mode));
3566995Shx147065 	/* Mark */
3567995Shx147065 	if (strcasecmp(arg, "OPENSYSTEM") == 0) {
3568995Shx147065 		auth_mode = WL_OPENSYSTEM;
3569995Shx147065 	} else if (strcasecmp(arg, "SHARED_KEY") == 0) {
3570995Shx147065 		auth_mode = WL_SHAREDKEY;
3571995Shx147065 	} else {
3572995Shx147065 		(void) fprintf(stderr,
3573995Shx147065 		    gettext("%s: authmode: "
3574995Shx147065 		    "opensystem or shared_key\n"), gExecName);
3575995Shx147065 		exit(WIFI_FATAL_ERR);
3576995Shx147065 	}
3577995Shx147065 
3578995Shx147065 	(void) memmove(gbuf->wldp_buf, &auth_mode, sizeof (wl_authmode_t));
3579995Shx147065 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_AUTH_MODE,
3580995Shx147065 	    sizeof (wl_authmode_t)));
3581995Shx147065 }
3582995Shx147065 
3583995Shx147065 static boolean_t
do_set_encryption(int fd,const char * arg)3584995Shx147065 do_set_encryption(int fd, const char *arg)
3585995Shx147065 {
3586995Shx147065 	wl_encryption_t encryption;
3587995Shx147065 
3588995Shx147065 	assert(arg != NULL);
3589995Shx147065 	PRTDBG(("do_set_encryption(%d, \"%s\")\n", fd, arg));
3590995Shx147065 
3591995Shx147065 	(void) memset(&encryption, 0xff, sizeof (encryption));
3592995Shx147065 
3593995Shx147065 	if (strcasecmp(arg, "NONE") == 0) {
3594995Shx147065 		encryption = WL_NOENCRYPTION;
3595995Shx147065 	} else if (strcasecmp(arg, "WEP") == 0) {
3596995Shx147065 		encryption = WL_ENC_WEP;
3597995Shx147065 	} else {
3598995Shx147065 		(void) fprintf(stderr, gettext("%s: encryption: "
3599995Shx147065 		    "none or wep\n"), gExecName);
3600995Shx147065 		exit(WIFI_FATAL_ERR);
3601995Shx147065 	}
3602995Shx147065 
3603995Shx147065 	(void) memmove(gbuf->wldp_buf, &encryption, sizeof (wl_encryption_t));
3604995Shx147065 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_ENCRYPTION,
3605995Shx147065 	    sizeof (wl_encryption_t)));
3606995Shx147065 }
3607995Shx147065 
3608995Shx147065 static boolean_t
do_set_wepkeyid(int fd,const char * arg)3609995Shx147065 do_set_wepkeyid(int fd, const char *arg)
3610995Shx147065 {
3611995Shx147065 	wl_wep_key_id_t wep_key_id;
3612995Shx147065 
3613995Shx147065 	assert(arg != NULL);
3614995Shx147065 	PRTDBG(("do_set_wepkeyid(%d, \"%s\")\n", fd, arg));
3615995Shx147065 
3616995Shx147065 	(void) memset(&wep_key_id, 0xff, sizeof (wep_key_id));
3617995Shx147065 	if (is_wepkeyindex_valid(arg) == B_FALSE) {
3618995Shx147065 		(void) fprintf(stderr, gettext("%s: wepkeyindex "
3619995Shx147065 		    "should be an integer within the range 1-4\n"), gExecName);
3620995Shx147065 		exit(WIFI_FATAL_ERR);
3621995Shx147065 	}
3622995Shx147065 	wep_key_id = atoi(arg) - 1;
3623995Shx147065 
3624995Shx147065 	(void) memmove(gbuf->wldp_buf, &wep_key_id, sizeof (wl_wep_key_id_t));
3625995Shx147065 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_WEP_KEY_ID,
3626995Shx147065 	    sizeof (wl_wep_key_id_t)));
3627995Shx147065 }
3628995Shx147065 
3629995Shx147065 static boolean_t
do_set_radioon(int fd,const char * arg)3630995Shx147065 do_set_radioon(int fd, const char *arg)
3631995Shx147065 {
3632995Shx147065 	wl_radio_t radio;
3633995Shx147065 
3634995Shx147065 	assert(arg != NULL);
3635995Shx147065 	PRTDBG(("do_set_radioon(%d, \"%s\")\n", fd, arg));
3636995Shx147065 
3637995Shx147065 	(void) memset(&radio, 0xff, sizeof (radio));
3638995Shx147065 
3639995Shx147065 	if (strcasecmp(arg, "ON") == 0) {
3640995Shx147065 		radio = B_TRUE;
3641995Shx147065 	} else if (strcasecmp(arg, "OFF") == 0) {
3642995Shx147065 		radio = B_FALSE;
3643995Shx147065 	} else {
3644995Shx147065 		(void) fprintf(stderr,
3645995Shx147065 		    gettext("%s: radio : on or off\n"), gExecName);
3646995Shx147065 		exit(WIFI_FATAL_ERR);
3647995Shx147065 	}
3648995Shx147065 
3649995Shx147065 	(void) memmove(gbuf->wldp_buf, &radio, sizeof (wl_radio_t));
3650995Shx147065 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_RADIO, sizeof (wl_radio_t)));
3651995Shx147065 }
3652995Shx147065 /*
3653995Shx147065  * print_gbuf: After each ioctl system call, gbuf will contain result, gbuf
3654995Shx147065  * contents's format varies from each kind of ioctl system call.
3655995Shx147065  */
3656995Shx147065 static void
print_gbuf(config_item_t index)3657995Shx147065 print_gbuf(config_item_t index)
3658995Shx147065 {
3659995Shx147065 	int i = 0, j = 0;
3660995Shx147065 	uint32_t ess_num;
3661995Shx147065 	char **ess_argv;
3662995Shx147065 	uint32_t rates_num;
3663995Shx147065 	uint32_t subtype;
3664995Shx147065 	wl_bss_type_t bsstype;
3665995Shx147065 	wl_create_ibss_t createibss;
3666995Shx147065 	wl_ps_mode_t *ps_mode;
3667995Shx147065 	wl_authmode_t authmode;
3668995Shx147065 	wl_encryption_t encryption;
3669995Shx147065 	wl_wep_key_id_t wepkeyid;
3670995Shx147065 	wl_rssi_t signal;
3671995Shx147065 	wl_radio_t radioon;
3672995Shx147065 	wl_ess_conf_t **p_ess_conf;
3673995Shx147065 	wl_linkstatus_t linkstatus;
3674995Shx147065 	char format[256], *ntstr;
3675995Shx147065 	uint32_t maxessidlen = 0, nt = 0, cnt = 0;
3676995Shx147065 	int len;
3677995Shx147065 	uint8_t bssid[6];
3678995Shx147065 
3679995Shx147065 	PRTDBG(("print_gbuf(%d)\n", index));
3680995Shx147065 	assert(gbuf->wldp_length < MAX_BUF_LEN);
3681995Shx147065 
3682995Shx147065 	switch (index) {
3683995Shx147065 	case BSSID:
3684995Shx147065 		(void) printf("\tbssid: ");
3685995Shx147065 		(void) memset(bssid, 0, sizeof (bssid));
3686995Shx147065 		if (memcmp((uint8_t *)gbuf->wldp_buf, bssid, sizeof (bssid))
3687995Shx147065 		    == 0) {
3688995Shx147065 			(void) printf("none\n");
3689995Shx147065 			break;
3690995Shx147065 		}
3691995Shx147065 		(void) memset(bssid, 0xff, sizeof (bssid));
3692995Shx147065 		if (memcmp((uint8_t *)gbuf->wldp_buf, bssid, sizeof (bssid))
3693995Shx147065 		    == 0) {
3694995Shx147065 			(void) printf("none\n");
3695995Shx147065 			break;
3696995Shx147065 		}
3697995Shx147065 		for (i = 0; i < 5; i++)
3698995Shx147065 			(void) printf("%02x:", ((uint8_t *)gbuf->wldp_buf)[i]);
3699995Shx147065 		(void) printf("%02x\n", ((uint8_t *)gbuf->wldp_buf)[i]);
3700995Shx147065 		break;
3701995Shx147065 	case ESSID:
3702995Shx147065 		(void) printf("\tessid: %s\n", ((wl_essid_t *)(gbuf->wldp_buf))
3703995Shx147065 		    ->wl_essid_essid);
3704995Shx147065 		break;
3705995Shx147065 	case BSSTYPE:
3706995Shx147065 		bsstype = *(wl_bss_type_t *)(gbuf->wldp_buf);
3707995Shx147065 		switch (bsstype) {
3708995Shx147065 		case WL_BSS_BSS:
3709995Shx147065 			(void) printf("\tbsstype: bss(ap, infrastructure)\n");
3710995Shx147065 			break;
3711995Shx147065 		case WL_BSS_IBSS:
3712995Shx147065 			(void) printf("\tbsstype: ibss(ad-hoc)\n");
3713995Shx147065 			break;
3714995Shx147065 		case WL_BSS_ANY:
3715995Shx147065 			(void) printf("\tbsstype: auto\n");
3716995Shx147065 			break;
3717995Shx147065 		default:
3718995Shx147065 			(void) fprintf(stderr,
3719995Shx147065 			    gettext("%s: "
3720995Shx147065 			    "invalid bsstype value\n"), gExecName);
3721995Shx147065 		}
3722995Shx147065 		break;
3723995Shx147065 	case CREATEIBSS:
3724995Shx147065 		createibss = *(wl_create_ibss_t *)(gbuf->wldp_buf);
3725995Shx147065 		switch (createibss) {
3726995Shx147065 		case B_TRUE:
3727995Shx147065 			(void) printf("\tcreateibss: yes\n");
3728995Shx147065 			break;
3729995Shx147065 		case B_FALSE:
3730995Shx147065 			(void) printf("\tcreateibss: no\n");
3731995Shx147065 			break;
3732995Shx147065 		default:
3733995Shx147065 			(void) fprintf(stderr,
3734995Shx147065 			    gettext("%s: "
3735995Shx147065 			    "invalid createibss value\n"), gExecName);
3736995Shx147065 		}
3737995Shx147065 		break;
3738995Shx147065 	case CHANNEL:
3739995Shx147065 		subtype = ((wl_fhss_t *)(gbuf->wldp_buf))->wl_fhss_subtype;
3740995Shx147065 		switch (subtype) {
3741995Shx147065 		case WL_FHSS:
3742995Shx147065 		case WL_DSSS:
3743995Shx147065 		case WL_IRBASE:
3744995Shx147065 		case WL_HRDS:
3745995Shx147065 		case WL_ERP:
3746995Shx147065 			(void) printf("\tchannel: %d\n", ((wl_fhss_t *)
3747995Shx147065 			    (gbuf->wldp_buf))->wl_fhss_channel);
3748995Shx147065 			break;
3749995Shx147065 		case WL_OFDM:
3750995Shx147065 			(void) printf("\tchannel: %d\n", ((wl_ofdm_t *)
3751995Shx147065 			    (gbuf->wldp_buf))
3752995Shx147065 			    ->wl_ofdm_frequency);
3753995Shx147065 			break;
3754995Shx147065 		default:
3755995Shx147065 			(void) fprintf(stderr, gettext("%s: "
3756995Shx147065 			    "invalid subtype\n"), gExecName);
3757995Shx147065 			break;
3758995Shx147065 		}
3759995Shx147065 		break;
3760995Shx147065 	case RATES:
3761995Shx147065 		rates_num = ((wl_rates_t *)(gbuf->wldp_buf))->wl_rates_num;
3762995Shx147065 		(void) printf("\trates: ");
3763995Shx147065 		for (i = 0; i < rates_num; i++) {
3764995Shx147065 			char rate;
3765995Shx147065 			rate = ((wl_rates_t *)gbuf->wldp_buf)
3766995Shx147065 			    ->wl_rates_rates[i];
3767995Shx147065 			if (rate == WL_RATE_5_5M)
3768995Shx147065 				(void) printf("5.5");
3769995Shx147065 			else
3770995Shx147065 				(void) printf("%d", (uint8_t)(rate / 2));
3771995Shx147065 
3772995Shx147065 			if (i == (rates_num - 1))
3773995Shx147065 				(void) printf("\n");
3774995Shx147065 			else
3775995Shx147065 				(void) printf(",");
3776995Shx147065 		}
3777995Shx147065 		break;
3778995Shx147065 	case POWERMODE:
3779995Shx147065 		ps_mode = (wl_ps_mode_t *)(gbuf->wldp_buf);
3780995Shx147065 		switch (ps_mode->wl_ps_mode) {
3781995Shx147065 		case WL_PM_AM:
3782995Shx147065 			(void) printf("\tpowermode: off\n");
3783995Shx147065 			break;
3784995Shx147065 		case WL_PM_MPS:
3785995Shx147065 			(void) printf("\tpowermode: mps\n");
3786995Shx147065 			break;
3787995Shx147065 		case WL_PM_FAST:
3788995Shx147065 			(void) printf("\tpowermode: fast\n");
3789995Shx147065 			break;
3790995Shx147065 		default:
3791995Shx147065 			(void) fprintf(stderr,
3792995Shx147065 			    gettext("%s: "
3793995Shx147065 			    "invalid powermode value\n"), gExecName);
3794995Shx147065 			break;
3795995Shx147065 		}
3796995Shx147065 		break;
3797995Shx147065 	case AUTHMODE:
3798995Shx147065 		authmode = *(wl_authmode_t *)(gbuf->wldp_buf);
3799995Shx147065 		switch (authmode) {
3800995Shx147065 		case WL_OPENSYSTEM:
3801995Shx147065 			(void) printf("\tauthmode: opensystem\n");
3802995Shx147065 			break;
3803995Shx147065 		case WL_SHAREDKEY:
3804995Shx147065 			(void) printf("\tauthmode: shared_key\n");
3805995Shx147065 			break;
3806995Shx147065 		default:
3807995Shx147065 			(void) fprintf(stderr,
3808995Shx147065 			    gettext("%s: "
3809995Shx147065 			    "invalid authmode value\n"), gExecName);
3810995Shx147065 			break;
3811995Shx147065 		}
3812995Shx147065 		break;
3813995Shx147065 	case ENCRYPTION:
3814995Shx147065 		encryption = *(wl_encryption_t *)(gbuf->wldp_buf);
3815995Shx147065 		switch (encryption) {
3816995Shx147065 		case WL_NOENCRYPTION:
3817995Shx147065 			(void) printf("\tencryption: none\n");
3818995Shx147065 			break;
3819995Shx147065 		case WL_ENC_WEP:
3820995Shx147065 			(void) printf("\tencryption: wep\n");
3821995Shx147065 			break;
3822995Shx147065 		default:
3823995Shx147065 			(void) fprintf(stderr,
3824995Shx147065 			    gettext("%s: "
3825995Shx147065 			    "invalid encryption value\n"), gExecName);
3826995Shx147065 			break;
3827995Shx147065 		}
3828995Shx147065 		break;
3829995Shx147065 	case WEPKEYID:
3830995Shx147065 		wepkeyid = *(wl_wep_key_id_t *)(gbuf->wldp_buf);
3831995Shx147065 		(void) printf("\twepkeyindex: %d\n", wepkeyid + 1);
3832995Shx147065 		break;
3833995Shx147065 	case SIGNAL:
3834995Shx147065 		signal = *(wl_rssi_t *)(gbuf->wldp_buf);
3835995Shx147065 		(void) printf("\tsignal: %d\n", signal);
3836995Shx147065 		break;
3837995Shx147065 	case RADIOON:
3838995Shx147065 		radioon = *(wl_radio_t *)(gbuf->wldp_buf);
3839995Shx147065 		switch (radioon) {
3840995Shx147065 		case B_TRUE:
3841995Shx147065 			(void) printf("\tradio: on\n");
3842995Shx147065 			break;
3843995Shx147065 		case B_FALSE:
3844995Shx147065 			(void) printf("\tradio: off\n");
3845995Shx147065 			break;
3846995Shx147065 		default: /* Mark */
3847995Shx147065 			(void) fprintf(stderr,
3848995Shx147065 			    gettext("%s: "
3849995Shx147065 			    "invalid radioon value\n"), gExecName);
3850995Shx147065 		}
3851995Shx147065 		break;
3852995Shx147065 	case LINKSTATUS:
3853995Shx147065 		linkstatus = *(wl_linkstatus_t *)(gbuf->wldp_buf);
3854995Shx147065 		switch (linkstatus) {
3855995Shx147065 		case WL_CONNECTED:
3856995Shx147065 			(void) printf("\tlinkstatus: connected\n");
3857995Shx147065 			break;
3858995Shx147065 		case WL_NOTCONNECTED:
3859995Shx147065 			(void) printf("\tlinkstatus: not connected\n");
3860995Shx147065 			break;
3861995Shx147065 		default: /* Mark */
3862995Shx147065 			(void) fprintf(stderr,
3863995Shx147065 			    gettext("%s: "
3864995Shx147065 			    "invalid linkstatus value\n"), gExecName);
3865995Shx147065 		}
3866995Shx147065 		break;
3867995Shx147065 	case WLANLIST:
3868995Shx147065 		ess_num = ((wl_ess_list_t *)(gbuf->wldp_buf))->wl_ess_list_num;
3869995Shx147065 		ess_argv = safe_calloc(sizeof (char *), ess_num);
3870995Shx147065 		p_ess_conf = safe_calloc(sizeof (wl_ess_conf_t *), ess_num);
3871995Shx147065 		for (i = 0; i < ess_num; i++) {
3872995Shx147065 			p_ess_conf[i] = ((wl_ess_list_t *)gbuf->wldp_buf)
3873995Shx147065 			    ->wl_ess_list_ess + i;
3874995Shx147065 			maxessidlen = (maxessidlen >
3875995Shx147065 			    strlen(p_ess_conf[i]
3876995Shx147065 			    ->wl_ess_conf_essid.wl_essid_essid) ?
3877995Shx147065 			    maxessidlen :
3878995Shx147065 			    strlen(p_ess_conf[i]
3879995Shx147065 			    ->wl_ess_conf_essid.wl_essid_essid));
3880995Shx147065 		}
3881995Shx147065 		/*
3882995Shx147065 		 * construct the output format.
3883995Shx147065 		 */
3884995Shx147065 		if ((nt = (maxessidlen / 8 + 1)) > 4)
3885995Shx147065 			nt = 4;
3886995Shx147065 		len = snprintf(format, sizeof (format), gettext("essid"));
3887995Shx147065 		ntstr = construct_format(nt);
3888995Shx147065 		assert(ntstr != NULL);
3889995Shx147065 		len += snprintf(format + len, sizeof (format) - len, "%s",
3890995Shx147065 		    ntstr);
3891995Shx147065 		len += snprintf(format + len, sizeof (format) - len,
3892995Shx147065 		    gettext("bssid\t\t  type\t\tencryption\tsignallevel\n"));
3893995Shx147065 
3894995Shx147065 		if ((len <= 0) || (len > sizeof (format) - 1)) {
3895995Shx147065 			(void) printf("essid\t\t\t\tbssid\t\t  type\t\t"
3896995Shx147065 			    "encryption\tsignallevel\n");
3897995Shx147065 		} else {
3898995Shx147065 			(void) printf("%s", format);
3899995Shx147065 		}
3900995Shx147065 
3901995Shx147065 		for (i = 0; i < ess_num; i++) {
3902995Shx147065 			ess_argv[i] = safe_malloc(MAX_SCANBUF_LEN);
3903995Shx147065 			safe_snprintf(ess_argv[i], MAX_SCANBUF_LEN,
3904995Shx147065 			    "%s%c%02x:%02x:%02x:%02x:%02x:%02x%c%s",
3905995Shx147065 			    p_ess_conf[i]->wl_ess_conf_essid.wl_essid_essid,
3906995Shx147065 			    ',',
3907995Shx147065 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[0]),
3908995Shx147065 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[1]),
3909995Shx147065 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[2]),
3910995Shx147065 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[3]),
3911995Shx147065 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[4]),
3912995Shx147065 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[5]), ',',
3913995Shx147065 			    (p_ess_conf[i]->wl_ess_conf_wepenabled ==
3914995Shx147065 			    B_TRUE ? "wep":"none"));
3915995Shx147065 			len = strlen(p_ess_conf[i]->wl_ess_conf_essid.
3916995Shx147065 			    wl_essid_essid);
3917995Shx147065 			cnt = nt - (min(len /8 + 1, 4) - 1);
3918995Shx147065 			ntstr = construct_format(cnt);
3919995Shx147065 			assert(ntstr != NULL);
3920995Shx147065 			(void) printf("%s%s", p_ess_conf[i]->wl_ess_conf_essid.
3921995Shx147065 			    wl_essid_essid, ntstr);
3922995Shx147065 			free(ntstr);
3923995Shx147065 			for (j = 0; j < 5; j++) {
3924995Shx147065 				(void) printf("%02x:", (uint8_t)(p_ess_conf[i]
3925995Shx147065 				    ->wl_ess_conf_bssid[j]));
3926995Shx147065 			}
3927995Shx147065 			(void) printf("%02x ", (uint8_t)(p_ess_conf[i]
3928995Shx147065 			    ->wl_ess_conf_bssid[j]));
3929995Shx147065 
3930995Shx147065 			if (p_ess_conf[i]->wl_ess_conf_bsstype ==
3931995Shx147065 			    WL_BSS_BSS)
3932995Shx147065 				(void) printf("access point");
3933995Shx147065 			else
3934995Shx147065 				(void) printf("ad-hoc");
3935995Shx147065 			if (p_ess_conf[i]->wl_ess_conf_wepenabled ==
3936995Shx147065 			    WL_ENC_WEP)
3937995Shx147065 				(void) printf("\twep\t");
3938995Shx147065 			else
3939995Shx147065 				(void) printf("\tnone\t");
3940995Shx147065 			(void) printf("\t%d\n", p_ess_conf[i]->wl_ess_conf_sl);
3941995Shx147065 		}
3942995Shx147065 		add_to_history(gp_config_file, ess_num, ess_argv);
3943995Shx147065 		free(p_ess_conf);
3944995Shx147065 		for (i = 0; i < ess_num; i++) {
3945995Shx147065 			free(ess_argv[i]);
3946995Shx147065 		}
3947995Shx147065 		free(ess_argv);
3948995Shx147065 		break;
3949995Shx147065 	default:
3950995Shx147065 		(void) fprintf(stderr, gettext("%s: "
3951995Shx147065 		    "invalid parameter type\n"), gExecName);
3952995Shx147065 		break;
3953995Shx147065 	}
3954995Shx147065 }
3955995Shx147065 /*
3956995Shx147065  * do_get_xxx: will send ioctl to driver, then the driver will fill gbuf
3957995Shx147065  * with related value. gbuf has a format of wldp_t structure.
3958995Shx147065  */
3959995Shx147065 static boolean_t
do_get_bssid(int fd)3960995Shx147065 do_get_bssid(int fd)
3961995Shx147065 {
3962995Shx147065 	PRTDBG(("do_get_bssid(%d)\n", fd));
3963995Shx147065 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_BSSID, 0));
3964995Shx147065 }
3965995Shx147065 
3966995Shx147065 static boolean_t
do_get_essid(int fd)3967995Shx147065 do_get_essid(int fd)
3968995Shx147065 {
3969995Shx147065 	PRTDBG(("do_get_essid(%d)\n", fd));
3970995Shx147065 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_ESSID, 0));
3971995Shx147065 }
3972995Shx147065 
3973995Shx147065 static boolean_t
do_get_bsstype(int fd)3974995Shx147065 do_get_bsstype(int fd)
3975995Shx147065 {
3976995Shx147065 	PRTDBG(("do_get_bsstype(%d)\n", fd));
3977995Shx147065 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_BSS_TYPE, 0));
3978995Shx147065 }
3979995Shx147065 
3980995Shx147065 static boolean_t
do_get_createibss(int fd)3981995Shx147065 do_get_createibss(int fd)
3982995Shx147065 {
3983995Shx147065 	PRTDBG(("do_get_createibss(%d)\n", fd));
3984995Shx147065 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_CREATE_IBSS, 0));
3985995Shx147065 }
3986995Shx147065 
3987995Shx147065 static boolean_t
do_get_channel(int fd)3988995Shx147065 do_get_channel(int fd)
3989995Shx147065 {
3990995Shx147065 	PRTDBG(("do_get_channel(%d)\n", fd));
3991995Shx147065 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_PHY_CONFIG, 0));
3992995Shx147065 }
3993995Shx147065 
3994995Shx147065 static boolean_t
do_get_wlanlist(int fd)3995995Shx147065 do_get_wlanlist(int fd)
3996995Shx147065 {
3997995Shx147065 	PRTDBG(("do_get_wlanlist(%d)\n", fd));
3998995Shx147065 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_ESS_LIST, 0));
3999995Shx147065 }
4000995Shx147065 
4001995Shx147065 static boolean_t
do_get_linkstatus(int fd)4002995Shx147065 do_get_linkstatus(int fd)
4003995Shx147065 {
4004995Shx147065 	PRTDBG(("do_get_linkstauts(%d)\n", fd));
4005995Shx147065 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_LINKSTATUS, 0));
4006995Shx147065 }
4007995Shx147065 
4008995Shx147065 static boolean_t
do_get_rates(int fd)4009995Shx147065 do_get_rates(int fd)
4010995Shx147065 {
4011995Shx147065 	PRTDBG(("do_get_rates(%d)\n", fd));
4012995Shx147065 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_DESIRED_RATES, 0));
4013995Shx147065 }
4014995Shx147065 
4015995Shx147065 static boolean_t
do_get_powermode(int fd)4016995Shx147065 do_get_powermode(int fd)
4017995Shx147065 {
4018995Shx147065 	PRTDBG(("do_get_powermode(%d)\n", fd));
4019995Shx147065 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_POWER_MODE, 0));
4020995Shx147065 }
4021995Shx147065 
4022995Shx147065 static boolean_t
do_get_authmode(int fd)4023995Shx147065 do_get_authmode(int fd)
4024995Shx147065 {
4025995Shx147065 	PRTDBG(("do_get_authmode(%d)\n", fd));
4026995Shx147065 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_AUTH_MODE, 0));
4027995Shx147065 }
4028995Shx147065 
4029995Shx147065 static boolean_t
do_get_encryption(int fd)4030995Shx147065 do_get_encryption(int fd)
4031995Shx147065 {
4032995Shx147065 	PRTDBG(("do_get_encryption(%d)\n", fd));
4033995Shx147065 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_ENCRYPTION, 0));
4034995Shx147065 }
4035995Shx147065 
4036995Shx147065 static boolean_t
do_get_wepkeyid(int fd)4037995Shx147065 do_get_wepkeyid(int fd)
4038995Shx147065 {
4039995Shx147065 	PRTDBG(("do_get_wepkeyid(%d)\n", fd));
4040995Shx147065 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_WEP_KEY_ID, 0));
4041995Shx147065 }
4042995Shx147065 static boolean_t
do_get_signal(int fd)4043995Shx147065 do_get_signal(int fd)
4044995Shx147065 {
4045995Shx147065 	PRTDBG(("do_get_signal(%d)\n", fd));
4046995Shx147065 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_RSSI, 0));
4047995Shx147065 }
4048995Shx147065 
4049995Shx147065 static boolean_t
do_get_radioon(int fd)4050995Shx147065 do_get_radioon(int fd)
4051995Shx147065 {
4052995Shx147065 	PRTDBG(("do_get_radioon(%d)\n", fd));
4053995Shx147065 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_RADIO, 0));
4054995Shx147065 }
4055995Shx147065 
4056995Shx147065 /*
4057995Shx147065  * param has two kinds of forms:
4058995Shx147065  * 'wepkeyn=*****' (when equalflag == B_TRUE),
4059995Shx147065  * 'wepkeyn' (when equalflag == B_FALSE)
4060995Shx147065  */
4061995Shx147065 static boolean_t
param_is_wepkey(char * param,boolean_t equalflag)4062995Shx147065 param_is_wepkey(char *param, boolean_t equalflag)
4063995Shx147065 {
4064995Shx147065 	if ((equalflag == B_FALSE) &&
4065995Shx147065 	    (strcmp(param, "wepkey1") == 0) ||
4066995Shx147065 	    (strcmp(param, "wepkey2") == 0) ||
4067995Shx147065 	    (strcmp(param, "wepkey3") == 0) ||
4068995Shx147065 	    (strcmp(param, "wepkey4") == 0))
4069995Shx147065 		return (B_TRUE);
4070995Shx147065 	else if ((equalflag == B_TRUE) &&
4071995Shx147065 	    (strncmp(param, "wepkey1=", strlen("wepkey1="))) == 0 ||
4072995Shx147065 	    (strncmp(param, "wepkey2=", strlen("wepkey2="))) == 0 ||
4073995Shx147065 	    (strncmp(param, "wepkey3=", strlen("wepkey3="))) == 0 ||
4074995Shx147065 	    (strncmp(param, "wepkey4=", strlen("wepkey4="))) == 0)
4075995Shx147065 		return (B_TRUE);
4076995Shx147065 	else
4077995Shx147065 		return (B_FALSE);
4078995Shx147065 }
4079995Shx147065 
4080995Shx147065 /*
4081995Shx147065  * update/add items in the profile
4082995Shx147065  */
4083995Shx147065 static boolean_t
items_in_profile(aelist_t * cplist,aelist_t * wplist,int argc,char ** argv)4084995Shx147065 items_in_profile(aelist_t *cplist, aelist_t *wplist, int argc, char **argv)
4085995Shx147065 {
4086995Shx147065 	int i = 0, j = 0;
4087995Shx147065 	char *param;
4088995Shx147065 	char *pequal;
4089995Shx147065 	const char *wepkey;
4090995Shx147065 
4091995Shx147065 	for (i = 0; i < argc; i++) {
4092995Shx147065 		if (param_is_wepkey(argv[i], B_TRUE) == B_TRUE) {
4093995Shx147065 			wepkey = get_value(argv[i]);
4094995Shx147065 			if (value_is_valid(WEPKEY, wepkey) == B_FALSE) {
4095995Shx147065 				(void) fprintf(stderr, gettext("%s: "
4096995Shx147065 				    "invalid value '%s' for parameter "
4097995Shx147065 				    "'wepkey'\n"), gExecName, wepkey);
4098995Shx147065 				return (B_FALSE);
4099995Shx147065 			}
4100995Shx147065 			update_aelist(wplist, argv[i]);
4101995Shx147065 			continue;
4102995Shx147065 		}
4103995Shx147065 		param = safe_strdup(argv[i]);
4104995Shx147065 		pequal = strchr(param, '=');
4105995Shx147065 		if (pequal == NULL) {
4106995Shx147065 			(void) fprintf(stderr, gettext("%s: "
4107995Shx147065 			    "invalid argument '%s', use "
4108995Shx147065 			    "parameter=value'\n"),
4109995Shx147065 			    gExecName, argv[i]);
4110995Shx147065 			free(param);
4111995Shx147065 			return (B_FALSE);
4112995Shx147065 		}
4113995Shx147065 
4114995Shx147065 		*pequal++ = '\0';
4115995Shx147065 		for (j = 0; j < N_GS_FUNC; j++) {
4116995Shx147065 			if (strcmp(param, do_gs_func[j].cmd) == 0) {
4117995Shx147065 				break;
4118995Shx147065 			}
4119995Shx147065 		}
4120995Shx147065 		if (j == N_GS_FUNC) {
4121995Shx147065 			(void) fprintf(stderr, gettext("%s: "
4122995Shx147065 			    "unrecognized parameter '%s'\n"),
4123995Shx147065 			    gExecName, param);
4124995Shx147065 			free(param);
4125995Shx147065 			return (B_FALSE);
4126995Shx147065 		}
4127995Shx147065 		if (value_is_valid(do_gs_func[j].index, pequal) ==
4128995Shx147065 		    B_FALSE) {
4129995Shx147065 			(void) fprintf(stderr, gettext("%s: "
4130995Shx147065 			    "invalid value '%s' for parameter '%s'\n"),
4131995Shx147065 			    gExecName, pequal, param);
4132995Shx147065 			return (B_FALSE);
4133995Shx147065 		}
4134995Shx147065 		free(param);
4135995Shx147065 		update_aelist(cplist, argv[i]);
4136995Shx147065 	}
4137995Shx147065 	return (B_TRUE);
4138995Shx147065 }
4139995Shx147065 
4140995Shx147065 /*
4141995Shx147065  * do_createprofile: Called when create a profile off-line.
4142995Shx147065  */
4143995Shx147065 /*ARGSUSED*/
4144995Shx147065 static boolean_t
do_createprofile(int fd,int argc,char ** argv)4145995Shx147065 do_createprofile(int fd, int argc, char **argv)
4146995Shx147065 {
4147995Shx147065 	int i = 0;
4148995Shx147065 	char *pbuf = NULL;
4149995Shx147065 	char *pfbuf = NULL;
4150995Shx147065 	const char *profilename;
4151995Shx147065 	aelist_t *plist_config = NULL, *plist_wepkey = NULL;
4152995Shx147065 
4153995Shx147065 	PRTDBG(("do_createprofile(%d, 0x%x)\n", argc, argv));
4154995Shx147065 	if (argc <= 0) {
4155995Shx147065 		do_print_usage();
4156995Shx147065 		exit(WIFI_IMPROPER_USE);
4157995Shx147065 	}
4158995Shx147065 	/*
4159995Shx147065 	 * When creating a profile, if the profile name is not specified,
4160995Shx147065 	 * the essid is selected as the profile name. the paramters are
4161995Shx147065 	 * saved into the section.
4162995Shx147065 	 */
4163995Shx147065 	if (strchr(argv[0], '=') == NULL) {
4164995Shx147065 		pfbuf = safe_strdup(argv[0]);
4165995Shx147065 		argc--;
4166995Shx147065 		argv++;
4167995Shx147065 	}
4168995Shx147065 	for (i = 0; i < argc; i++) {
4169995Shx147065 		if (strncmp(argv[i], "essid=", strlen("essid=")) == 0) {
4170995Shx147065 			break;
4171995Shx147065 		}
4172995Shx147065 	}
4173995Shx147065 	if (i == argc) {
4174995Shx147065 		(void) fprintf(stderr,
4175995Shx147065 		    gettext("%s: "
4176995Shx147065 		    "essid required when creating profile\n"),
4177995Shx147065 		    gExecName);
4178995Shx147065 		goto exit0;
4179995Shx147065 	}
4180995Shx147065 	profilename = (pfbuf ? pfbuf : get_value(argv[i]));
4181995Shx147065 	if (strlen(profilename) == 0) {
4182995Shx147065 		(void) fprintf(stderr,
4183995Shx147065 		    gettext("%s: "
4184995Shx147065 		    "non-empty essid required\n"),
4185995Shx147065 		    gExecName);
4186995Shx147065 		goto exit0;
4187995Shx147065 	}
4188995Shx147065 	/*
4189995Shx147065 	 * 'all', '{preference}', '{history}', '{active_profile}'
4190995Shx147065 	 * and any string with '[' as start and ']' as end should
4191995Shx147065 	 * not be a profile name
4192995Shx147065 	 */
4193995Shx147065 	if ((strcasecmp(profilename, "all") == 0) ||
4194995Shx147065 	    (strcmp(profilename, WIFI_HISTORY) == 0) ||
4195995Shx147065 	    (strcmp(profilename, WIFI_PREFER) == 0) ||
4196995Shx147065 	    (strcmp(profilename, WIFI_ACTIVEP) == 0) ||
4197995Shx147065 	    ((profilename[0] == '[') &&
4198995Shx147065 	    (profilename[strlen(profilename) - 1] == ']'))) {
4199995Shx147065 		(void) fprintf(stderr, gettext("%s: "
4200995Shx147065 		    "'%s' is an invalid profile name\n"),
4201995Shx147065 		    gExecName, profilename);
4202995Shx147065 		goto exit0;
4203995Shx147065 	}
4204995Shx147065 	pbuf = append_pa(profilename);
4205995Shx147065 
4206995Shx147065 	PRTDBG(("do_createprofile: profile_name = %s\n", pbuf));
4207995Shx147065 	if ((find_section(gp_config_file, pbuf) != NULL) ||
4208995Shx147065 	    find_section(gp_wepkey_file, pbuf) != NULL) {
4209995Shx147065 		(void) fprintf(stderr,
4210995Shx147065 		    gettext("%s: "
4211995Shx147065 		    "profile '%s' already exists\n"),
4212995Shx147065 		    gExecName, profilename);
4213995Shx147065 		goto exit1;
4214995Shx147065 	}
4215995Shx147065 	/*
4216995Shx147065 	 * Save each parameters in the profile.
4217995Shx147065 	 */
4218995Shx147065 	plist_config = new_ael(PROFILE);
4219995Shx147065 	new_section(gp_config_file, plist_config, pbuf);
4220995Shx147065 	plist_wepkey = new_ael(PROFILE);
4221995Shx147065 	new_section(gp_wepkey_file, plist_wepkey, pbuf);
4222995Shx147065 	free(pfbuf);
4223995Shx147065 	free(pbuf);
4224995Shx147065 	return (items_in_profile(plist_config, plist_wepkey,
4225995Shx147065 	    argc, argv));
4226995Shx147065 exit1:
4227995Shx147065 	free(pbuf);
4228995Shx147065 exit0:
4229995Shx147065 	free(pfbuf);
4230995Shx147065 	return (B_FALSE);
4231995Shx147065 }
4232995Shx147065 
4233995Shx147065 /*ARGSUSED*/
4234995Shx147065 static boolean_t
do_setprofparam(int fd,int argc,char ** argv)4235995Shx147065 do_setprofparam(int fd, int argc, char **argv)
4236995Shx147065 {
4237995Shx147065 	char *pbuf = NULL;
4238995Shx147065 	section_t *psection_config = NULL, *psection_wep = NULL;
4239995Shx147065 	aelist_t *plist_config = NULL, *plist_wepkey = NULL;
4240995Shx147065 
4241995Shx147065 	PRTDBG(("do_setprofparam(%d, 0x%x)\n", argc, argv));
4242995Shx147065 	if (argc < 1) {
4243995Shx147065 		do_print_usage();
4244995Shx147065 		exit(WIFI_IMPROPER_USE);
4245995Shx147065 	}
4246995Shx147065 	pbuf = append_pa(argv[0]);
4247995Shx147065 
4248995Shx147065 	psection_config = find_section(gp_config_file, pbuf);
4249995Shx147065 	psection_wep = find_section(gp_wepkey_file, pbuf);
4250995Shx147065 	if ((psection_config == NULL) || (psection_wep == NULL)) {
4251995Shx147065 		(void) fprintf(stderr, gettext("%s: "
4252995Shx147065 		    "profile '%s' doesn't exist\n"),
4253995Shx147065 		    gExecName, argv[0]);
4254995Shx147065 		free(pbuf);
4255995Shx147065 		return (B_FALSE);
4256995Shx147065 	}
4257995Shx147065 	free(pbuf);
4258995Shx147065 	/*
4259995Shx147065 	 * modify each parameters in the profile.
4260995Shx147065 	 */
4261995Shx147065 	plist_config = psection_config->list;
4262995Shx147065 	plist_wepkey = psection_wep->list;
4263995Shx147065 	argc--;
4264995Shx147065 	argv++;
4265995Shx147065 	return (items_in_profile(plist_config, plist_wepkey,
4266995Shx147065 	    argc, argv));
4267995Shx147065 }
4268995Shx147065 
4269995Shx147065 /*ARGSUSED*/
4270995Shx147065 static boolean_t
do_getprofparam(int fd,int argc,char ** argv)4271995Shx147065 do_getprofparam(int fd, int argc, char **argv)
4272995Shx147065 {
4273995Shx147065 	int i = 0, j = 0;
4274995Shx147065 	int flag;
4275995Shx147065 	boolean_t ret = B_TRUE;
4276995Shx147065 	section_t *p_section = NULL;
4277995Shx147065 	aelist_t *plist = NULL;
4278995Shx147065 	ae_t *pae = NULL;
4279995Shx147065 	char *pbuf = NULL;
4280995Shx147065 
4281995Shx147065 	PRTDBG(("do_getprofparam(%d, 0x%x)\n", argc, argv));
4282995Shx147065 	if (argc < 1) {
4283995Shx147065 		do_print_usage();
4284995Shx147065 		exit(WIFI_IMPROPER_USE);
4285995Shx147065 	}
4286995Shx147065 	pbuf = append_pa(argv[0]);
4287995Shx147065 	p_section = find_section(gp_config_file, pbuf);
4288995Shx147065 	if (p_section == NULL) {
4289995Shx147065 		(void) fprintf(stderr, gettext("%s: "
4290995Shx147065 		    "profile '%s' doesn't exist\n"),
4291995Shx147065 		    gExecName, argv[0]);
4292995Shx147065 		ret = B_FALSE;
4293995Shx147065 		goto exit0;
4294995Shx147065 	}
4295995Shx147065 	argc--;
4296995Shx147065 	argv++;
4297995Shx147065 
4298995Shx147065 	plist = p_section->list;
4299995Shx147065 	assert(plist != NULL);
4300995Shx147065 	/*
4301995Shx147065 	 * If no specific parameter typed, we print out all parameters
4302995Shx147065 	 */
4303995Shx147065 	if (argc == 0) {
4304995Shx147065 		pae = plist->ael_head;
4305995Shx147065 		while (pae != NULL) {
4306995Shx147065 			if (pae->ae_arg != NULL) {
4307995Shx147065 				(void) printf("\t%s\n", pae->ae_arg);
4308995Shx147065 			}
4309995Shx147065 			pae = pae->ae_next;
4310995Shx147065 		}
4311995Shx147065 		print_wepkey_info(p_section->section_id, NULL);
4312995Shx147065 		ret = B_TRUE;
4313995Shx147065 		goto exit0;
4314995Shx147065 	}
4315995Shx147065 
4316995Shx147065 	/*
4317995Shx147065 	 * Match function with do_gs_func[] table, and print its result
4318995Shx147065 	 */
4319995Shx147065 	for (i = 0; i < argc; i++) {
4320995Shx147065 		flag = 0;
4321995Shx147065 		for (j = 0; j < N_GS_FUNC; j++) {
4322995Shx147065 			if (strcmp(argv[i], do_gs_func[j].cmd) == 0) {
4323995Shx147065 				break;
4324995Shx147065 			}
4325995Shx147065 			if (param_is_wepkey(argv[i], B_FALSE) == B_TRUE) {
4326995Shx147065 				j = WEPKEY;
4327995Shx147065 				print_wepkey_info(p_section->section_id,
4328995Shx147065 				    argv[i]);
4329995Shx147065 				flag++;
4330995Shx147065 				break;
4331995Shx147065 			}
4332995Shx147065 		}
4333995Shx147065 		if (j == N_GS_FUNC) {
4334995Shx147065 			(void) fprintf(stderr,
4335995Shx147065 			    gettext("wificonifg: unrecognized parameter: "
4336995Shx147065 			    "%s\n"), argv[i]);
4337995Shx147065 			ret = B_FALSE;
4338995Shx147065 			goto exit0;
4339995Shx147065 		}
4340995Shx147065 
4341995Shx147065 		pae = plist->ael_head;
4342995Shx147065 		while ((pae != NULL) && (!flag)) {
4343995Shx147065 			if ((pae->ae_arg != NULL) &&
4344995Shx147065 			    (strncmp(pae->ae_arg, argv[i],
4345995Shx147065 			    strlen(argv[i])) == 0)) {
4346995Shx147065 				(void) printf("\t%s\n", pae->ae_arg);
4347995Shx147065 				flag++;
4348995Shx147065 			}
4349995Shx147065 			pae = pae->ae_next;
4350995Shx147065 		}
4351995Shx147065 		if (!flag) {
4352995Shx147065 			(void) fprintf(stderr, gettext("%s: "
4353995Shx147065 			    "parameter '%s' has not been set in profile %s\n"),
4354995Shx147065 			    gExecName, argv[i], pbuf);
4355995Shx147065 			ret = B_FALSE;
4356995Shx147065 			goto exit0;
4357995Shx147065 		}
4358995Shx147065 	}
4359995Shx147065 exit0:
4360995Shx147065 	free(pbuf);
4361995Shx147065 	return (ret);
4362995Shx147065 }
4363995Shx147065 
4364995Shx147065 /*
4365995Shx147065  * Verify whether the value in the parameter=value pair is valid or not.
4366995Shx147065  * For the channel, since we donot know what kind of wifi card(a,b,or g)
4367995Shx147065  * is in the system, so we just leave to verify the validity of the value
4368995Shx147065  * when the value is set to the card.
4369995Shx147065  * The same goes for the rates.
4370995Shx147065  */
4371995Shx147065 static boolean_t
value_is_valid(config_item_t item,const char * value)4372995Shx147065 value_is_valid(config_item_t item, const char *value)
4373995Shx147065 {
4374995Shx147065 	uint32_t num = 0;
4375995Shx147065 	uint8_t *rates;
4376995Shx147065 	boolean_t ret;
4377995Shx147065 
4378995Shx147065 	assert(value != NULL);
4379995Shx147065 	switch (item) {
4380995Shx147065 	case ESSID:
4381995Shx147065 		if (strlen(value) > 32)
4382995Shx147065 			ret = B_FALSE;
4383995Shx147065 		else
4384995Shx147065 			ret = B_TRUE;
4385995Shx147065 		break;
4386995Shx147065 	case BSSTYPE:
4387995Shx147065 		if ((strcasecmp(value, "bss") == 0) ||
4388995Shx147065 		    (strcasecmp(value, "ap") == 0) ||
4389995Shx147065 		    (strcasecmp(value, "infrastructure") == 0) ||
4390995Shx147065 		    (strcasecmp(value, "ibss") == 0) ||
4391995Shx147065 		    (strcasecmp(value, "ad-hoc") == 0) ||
4392995Shx147065 		    (strcasecmp(value, "auto") == 0))
4393995Shx147065 			ret = B_TRUE;
4394995Shx147065 		else
4395995Shx147065 			ret = B_FALSE;
4396995Shx147065 		break;
4397995Shx147065 	case CREATEIBSS:
4398995Shx147065 		if ((strcasecmp(value, "yes") == 0) ||
4399995Shx147065 		    (strcasecmp(value, "no") == 0))
4400995Shx147065 			ret = B_TRUE;
4401995Shx147065 		else
4402995Shx147065 			ret = B_FALSE;
4403995Shx147065 		break;
4404995Shx147065 	case AUTHMODE:
4405995Shx147065 		if ((strcasecmp(value, "opensystem") == 0) ||
4406995Shx147065 		    (strcasecmp(value, "shared_key") == 0))
4407995Shx147065 			ret = B_TRUE;
4408995Shx147065 		else
4409995Shx147065 			ret = B_FALSE;
4410995Shx147065 		break;
4411995Shx147065 	case POWERMODE:
4412995Shx147065 		if ((strcasecmp(value, "off") == 0) ||
4413995Shx147065 		    (strcasecmp(value, "mps") == 0) ||
4414995Shx147065 		    (strcasecmp(value, "fast") == 0))
4415995Shx147065 			ret = B_TRUE;
4416995Shx147065 		else
4417995Shx147065 			ret = B_FALSE;
4418995Shx147065 		break;
4419995Shx147065 	case ENCRYPTION:
4420995Shx147065 		if ((strcasecmp(value, "wep") == 0) ||
4421995Shx147065 		    (strcasecmp(value, "none") == 0))
4422995Shx147065 			ret = B_TRUE;
4423995Shx147065 		else
4424995Shx147065 			ret = B_FALSE;
4425995Shx147065 		break;
4426995Shx147065 	case RADIOON:
4427995Shx147065 		if ((strcasecmp(value, "on") == 0) ||
4428995Shx147065 		    (strcasecmp(value, "off") == 0))
4429995Shx147065 			ret = B_TRUE;
4430995Shx147065 		else
4431995Shx147065 			ret = B_FALSE;
4432995Shx147065 		break;
4433995Shx147065 	case WEPKEYID:
4434995Shx147065 		ret = is_wepkeyindex_valid(value);
4435995Shx147065 		break;
4436995Shx147065 	case WEPKEY:
4437995Shx147065 		ret = is_wepkey_valid(value, strlen(value));
4438995Shx147065 		break;
4439995Shx147065 	case CHANNEL:
4440995Shx147065 		ret = is_channel_valid(value);
4441995Shx147065 		break;
4442995Shx147065 	case RATES:
4443995Shx147065 		rates = get_rates(value, &num);
4444995Shx147065 		if (rates == NULL) {
4445995Shx147065 			ret = B_FALSE;
4446995Shx147065 		} else {
4447995Shx147065 			free(rates);
4448995Shx147065 			ret = B_TRUE;
4449995Shx147065 		}
4450995Shx147065 		break;
4451995Shx147065 	default:
4452995Shx147065 		ret = B_FALSE;
4453995Shx147065 		break;
4454995Shx147065 	}
4455995Shx147065 
4456995Shx147065 	return (ret);
4457995Shx147065 }
4458995Shx147065 
4459995Shx147065 /*
4460995Shx147065  * do_set: Called when set a parameter, the format should be
4461995Shx147065  * parameter=value.
4462995Shx147065  */
4463995Shx147065 static boolean_t
do_set(int fd,int argc,char ** argv)4464995Shx147065 do_set(int fd, int argc, char **argv)
4465995Shx147065 {
4466995Shx147065 	int i = 0, j = 0;
4467995Shx147065 	char *param;
4468995Shx147065 	char *pequal;
4469995Shx147065 	char *value;
4470995Shx147065 	boolean_t ret;
4471995Shx147065 
4472995Shx147065 	PRTDBG(("do_set(%d, 0x%x)\n", argc, argv));
4473995Shx147065 	assert(fd > 0);
4474995Shx147065 	if (argc <= 0) {
4475995Shx147065 		(void) do_print_support_params(fd);
4476995Shx147065 		ret = B_FALSE;
4477995Shx147065 		goto exit0;
4478995Shx147065 	}
4479995Shx147065 	/*
4480995Shx147065 	 * Set each parameters, if one failed, others behind it will
4481995Shx147065 	 * not be set
4482995Shx147065 	 */
4483995Shx147065 	for (i = 0; i < argc; i++) {
4484995Shx147065 		/*
4485995Shx147065 		 * Separate param and its value, if the user types "param=",
4486995Shx147065 		 * then value will be set to "";if the user types "param",
4487995Shx147065 		 * it is an error.
4488995Shx147065 		 */
4489995Shx147065 		param = safe_strdup(argv[i]);
4490995Shx147065 		pequal = strchr(param, '=');
4491995Shx147065 		value = NULL;
4492995Shx147065 		if (pequal != NULL) {
4493995Shx147065 			*pequal = '\0';
4494995Shx147065 			value = pequal + 1;
4495995Shx147065 		} else {
4496995Shx147065 			(void) fprintf(stderr,
4497995Shx147065 			    gettext("%s: invalid setparam argument "
4498995Shx147065 			    "'%s', use 'parameter=value'\n"),
4499995Shx147065 			    gExecName, argv[i]);
4500995Shx147065 			free(param);
4501995Shx147065 			ret = B_FALSE;
4502995Shx147065 			goto exit0;
4503995Shx147065 		}
4504995Shx147065 		PRTDBG(("do_set: param = \"%s\", value = \"%s\"\n",
4505995Shx147065 		    param, value));
4506995Shx147065 		for (j = 0; j < N_GS_FUNC; j++) {
4507995Shx147065 			/*
4508995Shx147065 			 * Match each parameters with do_gs_func table,
4509995Shx147065 			 */
4510995Shx147065 			if (strcmp(param, do_gs_func[j].cmd) == 0)
4511995Shx147065 				break;
4512995Shx147065 			if (param_is_wepkey(param, B_FALSE) == B_TRUE) {
4513995Shx147065 				value = argv[i];
4514995Shx147065 				j = WEPKEY;
4515995Shx147065 				break;
4516995Shx147065 			}
4517995Shx147065 		}
4518995Shx147065 		if (j == N_GS_FUNC) {
4519995Shx147065 			(void) fprintf(stderr,
4520995Shx147065 			    gettext("%s: unrecognized parameter: "
4521995Shx147065 			    "%s\n"), gExecName, param);
4522995Shx147065 			free(param);
4523995Shx147065 			ret  = B_FALSE;
4524995Shx147065 			goto exit0;
4525995Shx147065 		}
4526995Shx147065 
4527995Shx147065 		if (do_gs_func[j].p_do_set_func == NULL) {
4528995Shx147065 			(void) fprintf(stderr,
4529995Shx147065 			    gettext("%s: parameter '%s' is read-only\n"),
4530995Shx147065 			    gExecName, do_gs_func[j].cmd);
4531995Shx147065 			free(param);
4532995Shx147065 			ret = B_FALSE;
4533995Shx147065 			goto exit0;
4534995Shx147065 		}
4535995Shx147065 		if (do_gs_func[j].p_do_set_func(fd, value)
4536*6834Sff224033 		    == B_TRUE) {
4537995Shx147065 			ret = B_TRUE;
4538995Shx147065 		} else {
4539995Shx147065 			if (gbuf->wldp_result != WL_SUCCESS) {
4540995Shx147065 				(void) fprintf(stderr,
4541995Shx147065 				    gettext("%s: "
4542995Shx147065 				    "failed to set '%s' for "),
4543995Shx147065 				    gExecName, param);
4544995Shx147065 				print_error(gbuf->wldp_result);
4545995Shx147065 			}
4546995Shx147065 			free(param);
4547995Shx147065 			ret = B_FALSE;
4548995Shx147065 			goto exit0;
4549995Shx147065 		}
4550995Shx147065 		free(param);
4551995Shx147065 	}
4552995Shx147065 exit0:
4553995Shx147065 	return (ret);
4554995Shx147065 }
4555995Shx147065 
4556995Shx147065 static boolean_t
do_get(int fd,int argc,char ** argv)4557995Shx147065 do_get(int fd, int argc, char **argv)
4558995Shx147065 {
4559995Shx147065 	int i = 0, j = 0, n = 0;
4560995Shx147065 	boolean_t ret = B_TRUE;
4561995Shx147065 
4562995Shx147065 	PRTDBG(("do_get(%d, 0x%x)\n", argc, argv));
4563995Shx147065 	assert(fd > 0);
4564995Shx147065 	/*
4565995Shx147065 	 * If no specific parameter typed, we print out all parameters
4566995Shx147065 	 */
4567995Shx147065 	if (argc <= 0) {
4568995Shx147065 		for (i = 0; i < N_GS_FUNC; i++) {
4569995Shx147065 			if ((do_gs_func[i].p_do_get_func != NULL) &&
4570995Shx147065 			    (do_gs_func[i].p_do_get_func(fd)
4571995Shx147065 			    == B_TRUE)) {
4572995Shx147065 				print_gbuf(do_gs_func[i].index);
4573995Shx147065 				n++;
4574995Shx147065 			}
4575995Shx147065 		}
4576995Shx147065 		ret = n ? B_TRUE:B_FALSE;
4577995Shx147065 		goto exit0;
4578995Shx147065 	}
4579995Shx147065 	/*
4580995Shx147065 	 * Match function with do_gs_func[] table, and print its result
4581995Shx147065 	 */
4582995Shx147065 	for (i = 0; i < argc; i++) {
4583995Shx147065 		for (j = 0; j < N_GS_FUNC; j++) {
4584995Shx147065 			if (strcmp(argv[i], do_gs_func[j].cmd) == 0) {
4585995Shx147065 				break;
4586995Shx147065 			}
4587995Shx147065 			if (param_is_wepkey(argv[i], B_FALSE) == B_TRUE) {
4588995Shx147065 				j = WEPKEY;
4589995Shx147065 				break;
4590995Shx147065 			}
4591995Shx147065 		}
4592995Shx147065 		if (j == N_GS_FUNC) {
4593995Shx147065 			(void) fprintf(stderr,
4594995Shx147065 			    gettext("wificonifg: unrecognized parameter: "
4595995Shx147065 			    "%s\n"), argv[i]);
4596995Shx147065 			ret = B_FALSE;
4597995Shx147065 			goto exit0;
4598995Shx147065 		}
4599995Shx147065 		if (do_gs_func[j].p_do_get_func == NULL) {
4600995Shx147065 			(void) fprintf(stderr,
4601995Shx147065 			    gettext("%s: parameter '%s' is write-only\n"),
4602995Shx147065 			    gExecName, do_gs_func[j].cmd);
4603995Shx147065 			ret = B_FALSE;
4604995Shx147065 			goto exit0;
4605995Shx147065 		}
4606995Shx147065 		if (do_gs_func[j].p_do_get_func(fd) == B_TRUE) {
4607995Shx147065 			print_gbuf(do_gs_func[j].index);
4608995Shx147065 			ret = B_TRUE;
4609995Shx147065 		} else {
4610995Shx147065 			(void) fprintf(stderr,
4611995Shx147065 			    gettext("%s: "
4612995Shx147065 			    "failed to read parameter '%s' : "),
4613995Shx147065 			    gExecName, argv[i]);
4614995Shx147065 			print_error(gbuf->wldp_result);
4615995Shx147065 			ret = B_FALSE;
4616995Shx147065 		}
4617995Shx147065 	}
4618995Shx147065 exit0:
4619995Shx147065 	return (ret);
4620995Shx147065 }
4621995Shx147065 
4622995Shx147065 /*
4623995Shx147065  * Only one wificonfig is running at one time.
4624995Shx147065  * The following wificonfig which tries to be run will return error,
4625995Shx147065  * and the pid of the process will own the filelock will be printed out.
4626995Shx147065  */
4627995Shx147065 static pid_t
enter_wifi_lock(int * fd)4628995Shx147065 enter_wifi_lock(int *fd)
4629995Shx147065 {
4630995Shx147065 	int fd0 = -1;
4631995Shx147065 	struct flock lock;
4632995Shx147065 
4633995Shx147065 	fd0 = open(WIFI_LOCKF, O_CREAT|O_WRONLY, 0600);
4634995Shx147065 	if (fd0 < 0) {
4635995Shx147065 		(void) fprintf(stderr, gettext("%s: failed to open lockfile"
4636995Shx147065 		    " '"WIFI_LOCKF"': %s\n"), gExecName, strerror(errno));
4637995Shx147065 		exit(WIFI_FATAL_ERR);
4638995Shx147065 	}
4639995Shx147065 
4640995Shx147065 	*fd = fd0;
4641995Shx147065 	lock.l_type = F_WRLCK;
4642995Shx147065 	lock.l_whence = SEEK_SET;
4643995Shx147065 	lock.l_start = 0;
4644995Shx147065 	lock.l_len = 0;
4645995Shx147065 
4646995Shx147065 	if ((fcntl(fd0, F_SETLK, &lock) == -1) &&
4647995Shx147065 	    (errno == EAGAIN || errno == EDEADLK)) {
4648995Shx147065 		if (fcntl(fd0, F_GETLK, &lock) == -1) {
4649995Shx147065 			(void) fprintf(stderr,
4650995Shx147065 			    gettext("%s: enter_filelock"));
4651995Shx147065 			exit(WIFI_FATAL_ERR);
4652995Shx147065 		}
4653995Shx147065 		(void) fprintf(stderr, gettext("%s:"
4654995Shx147065 		    "enter_filelock:filelock is owned "
4655995Shx147065 		    "by 'process %d'\n"), gExecName, lock.l_pid);
4656995Shx147065 		return (lock.l_pid);
4657995Shx147065 	}
4658995Shx147065 
4659995Shx147065 	return (getpid());
4660995Shx147065 }
4661995Shx147065 
4662995Shx147065 static void
exit_wifi_lock(int fd)4663995Shx147065 exit_wifi_lock(int fd)
4664995Shx147065 {
4665995Shx147065 	struct flock lock;
4666995Shx147065 
4667995Shx147065 	lock.l_type = F_UNLCK;
4668995Shx147065 	lock.l_whence = SEEK_SET;
4669995Shx147065 	lock.l_start = 0;
4670995Shx147065 	lock.l_len = 0;
4671995Shx147065 	if (fcntl(fd, F_SETLK, &lock) == -1) {
4672995Shx147065 		(void) fprintf(stderr, gettext("%s: failed to"
4673995Shx147065 		    " exit_filelock: %s\n"),
4674995Shx147065 		    gExecName, strerror(errno));
4675995Shx147065 	}
4676995Shx147065 	(void) close(fd);
4677995Shx147065 }
4678995Shx147065 
4679995Shx147065 int
main(int argc,char ** argv)4680995Shx147065 main(int argc, char **argv)
4681995Shx147065 {
4682995Shx147065 	int i, ret;
4683995Shx147065 	int fddev = -1;
4684995Shx147065 	int c, iflag = 0, rflag = 0, fileonly = 0, readonly = 0;
4685995Shx147065 	int fd;
4686995Shx147065 	char *iname = NULL;
4687995Shx147065 	char *path = NULL;
4688995Shx147065 	extern char *optarg;
4689995Shx147065 	extern int optind;
4690995Shx147065 	char interface[LIFNAMSIZ];
4691995Shx147065 	char file_wifi[MAX_CONFIG_FILE_LENGTH];
4692995Shx147065 	char file_wifiwepkey[MAX_CONFIG_FILE_LENGTH];
4693995Shx147065 	priv_set_t *ppriv;
4694995Shx147065 	wifi_auth_t autht;
4695995Shx147065 
4696995Shx147065 	PRTDBG(("main(%d, 0x%x)\n", argc, argv));
4697995Shx147065 	PRTDBG(("uid=%d\n", getuid()));
4698995Shx147065 	PRTDBG(("euid=%d\n", geteuid()));
4699995Shx147065 
4700995Shx147065 #ifdef DEBUG
4701995Shx147065 	if (wifi_debug == 1) { /* for debuf purpose only */
4702995Shx147065 		(void) printf("Press RETURN to continue...\n");
4703995Shx147065 		(void) getchar();
4704995Shx147065 	}
4705995Shx147065 #endif
4706995Shx147065 	ret = WIFI_EXIT_DEF;
4707995Shx147065 
4708995Shx147065 	(void) setlocale(LC_ALL, "");
4709995Shx147065 	(void) textdomain(TEXT_DOMAIN);
4710995Shx147065 
4711995Shx147065 	gExecName = argv[0];
4712995Shx147065 
4713995Shx147065 	gbuf = safe_malloc(MAX_BUF_LEN);
4714995Shx147065 
4715995Shx147065 	if ((ppriv = priv_str_to_set("basic", ",", NULL)) == NULL) {
4716995Shx147065 		PRTDBG(("main: priviledge init error\n"));
4717995Shx147065 		(void) fprintf(stderr, gettext("%s: "
4718995Shx147065 		    "set priviledge to 'basic' error\n"),
4719995Shx147065 		    gExecName);
4720995Shx147065 		ret = WIFI_FATAL_ERR;
4721995Shx147065 		goto exit0;
4722995Shx147065 	}
4723995Shx147065 	(void) priv_addset(ppriv, PRIV_NET_RAWACCESS);
4724995Shx147065 	(void) priv_addset(ppriv, PRIV_SYS_NET_CONFIG);
4725995Shx147065 	if (setppriv(PRIV_SET, PRIV_PERMITTED, ppriv) == -1) {
4726995Shx147065 		(void) fprintf(stderr, gettext("%s: "
4727995Shx147065 		    "set permitted priviledge: %s\n"),
4728995Shx147065 		    gExecName, strerror(errno));
4729995Shx147065 		ret = WIFI_FATAL_ERR;
4730995Shx147065 		goto exit0;
4731995Shx147065 	}
4732995Shx147065 	if (setppriv(PRIV_SET, PRIV_LIMIT, ppriv) == -1) {
4733995Shx147065 		(void) fprintf(stderr, gettext("%s: "
4734995Shx147065 		    "set limit priviledge: %s\n"),
4735995Shx147065 		    gExecName, strerror(errno));
4736995Shx147065 		ret = WIFI_FATAL_ERR;
4737995Shx147065 		goto exit0;
4738995Shx147065 	}
4739995Shx147065 	if (setppriv(PRIV_SET, PRIV_INHERITABLE, ppriv) == -1) {
4740995Shx147065 		(void) fprintf(stderr, gettext("%s: "
4741995Shx147065 		    "set inherit priviledge: %s\n"),
4742995Shx147065 		    gExecName, strerror(errno));
4743995Shx147065 		ret = WIFI_FATAL_ERR;
4744995Shx147065 		goto exit0;
4745995Shx147065 	}
4746995Shx147065 	if (setppriv(PRIV_SET, PRIV_EFFECTIVE, ppriv) == -1) {
4747995Shx147065 		(void) fprintf(stderr, gettext("%s: "
4748995Shx147065 		    "set effective priviledge: %s\n"),
4749995Shx147065 		    gExecName, strerror(errno));
4750995Shx147065 		ret = WIFI_FATAL_ERR;
4751995Shx147065 		goto exit0;
4752995Shx147065 	}
4753995Shx147065 	priv_freeset(ppriv);
4754995Shx147065 
4755995Shx147065 	for (i = 0; i < argc; i++) {
4756995Shx147065 		PRTDBG(("%d\t\t\"%s\"\n", i, argv[i]));
4757995Shx147065 	}
4758995Shx147065 
4759995Shx147065 	while ((c = getopt(argc, argv, "i:R:")) != EOF) {
4760995Shx147065 		switch (c) {
4761995Shx147065 		case 'i':
4762995Shx147065 			if (iflag) {
4763995Shx147065 				do_print_usage();
4764995Shx147065 				ret = WIFI_IMPROPER_USE;
4765995Shx147065 				goto exit0;
4766995Shx147065 			}
4767995Shx147065 			iflag = 1;
4768995Shx147065 			iname = optarg;
4769995Shx147065 			break;
4770995Shx147065 		case 'R':
4771995Shx147065 			if (rflag) {
4772995Shx147065 				do_print_usage();
4773995Shx147065 				ret = WIFI_IMPROPER_USE;
4774995Shx147065 				goto exit0;
4775995Shx147065 			}
4776995Shx147065 			rflag = 1;
4777995Shx147065 			path = optarg;
4778995Shx147065 			break;
4779995Shx147065 		case '?':
4780995Shx147065 		default:
4781995Shx147065 			do_print_usage();
4782995Shx147065 			ret = WIFI_IMPROPER_USE;
4783995Shx147065 			goto exit0;
4784995Shx147065 		}
4785995Shx147065 	}
4786995Shx147065 	argc -= optind;
4787995Shx147065 	argv +=	optind;
4788995Shx147065 
4789995Shx147065 	if (argc <= 0) {
4790995Shx147065 		if (iname) {
4791995Shx147065 			if ((fddev = open_dev(iname)) == -1) {
4792995Shx147065 				ret = WIFI_FATAL_ERR;
4793995Shx147065 				goto exit0;
4794995Shx147065 			}
4795995Shx147065 			if (do_print_support_params(fddev) ==
4796995Shx147065 			    B_TRUE)
4797995Shx147065 				ret = WIFI_EXIT_DEF;
4798995Shx147065 			else
4799995Shx147065 				ret = WIFI_FATAL_ERR;
4800995Shx147065 			goto exit1;
4801995Shx147065 		} else {
4802995Shx147065 			do_print_usage();
4803995Shx147065 			ret = WIFI_IMPROPER_USE;
4804995Shx147065 			goto exit0;
4805995Shx147065 		}
4806995Shx147065 	}
4807995Shx147065 
4808995Shx147065 	for (i = 0; i < N_FUNC; i++) {
4809995Shx147065 		if (strcmp(argv[0], do_func[i].cmd) == 0) {
4810995Shx147065 			autht = ((strcmp(argv[0], "setwepkey") == 0) ||
4811995Shx147065 			    (strcmp(argv[0], "setprofwepkey") == 0)) ?
4812995Shx147065 			    AUTH_WEP:AUTH_OTHER;
4813995Shx147065 			if (do_func[i].b_auth &&
4814995Shx147065 			    !check_authority(autht)) {
4815995Shx147065 				ret = WIFI_FATAL_ERR;
4816995Shx147065 				goto exit0;
4817995Shx147065 			}
4818995Shx147065 			if (do_func[i].b_fileonly)
4819995Shx147065 				fileonly++;
4820995Shx147065 			if (do_func[i].b_readonly)
4821995Shx147065 				readonly++;
4822995Shx147065 			break;
4823995Shx147065 		}
4824995Shx147065 	}
4825995Shx147065 	if (i == N_FUNC) {
4826995Shx147065 		(void) fprintf(stderr, gettext("%s: unrecognized "
4827995Shx147065 		    "subcommand: %s\n"), gExecName, argv[0]);
4828995Shx147065 		do_print_usage();
4829995Shx147065 		ret = WIFI_IMPROPER_USE;
4830995Shx147065 		goto exit0;
4831995Shx147065 	}
4832995Shx147065 	if ((fileonly) && (iname)) {
4833995Shx147065 		do_print_usage();
4834995Shx147065 		ret = WIFI_IMPROPER_USE;
4835995Shx147065 		goto exit0;
4836995Shx147065 	}
4837995Shx147065 	if ((!fileonly) && (!iname)) {
4838995Shx147065 		if (search_interface(interface) != B_TRUE) {
4839995Shx147065 			(void) fprintf(stderr, gettext("%s: "
4840995Shx147065 			    "failed to find the default wifi interface;"
4841995Shx147065 			    " -i option should be used to specify the "
4842995Shx147065 			    "wifi interface\n"), gExecName);
4843995Shx147065 			ret = WIFI_FATAL_ERR;
4844995Shx147065 			goto exit0;
4845995Shx147065 		}
4846995Shx147065 		iname = interface;
4847995Shx147065 	}
4848995Shx147065 	if (iname) {
4849995Shx147065 		if ((fddev = open_dev(iname)) == -1) {
4850995Shx147065 			ret = WIFI_FATAL_ERR;
4851995Shx147065 			goto exit0;
4852995Shx147065 		}
4853995Shx147065 	}
4854995Shx147065 	if (rflag) {
4855995Shx147065 		safe_snprintf(file_wifi, sizeof (file_wifi),
4856995Shx147065 		    "%s%s", path, p_file_wifi);
4857995Shx147065 		safe_snprintf(file_wifiwepkey, sizeof (file_wifiwepkey),
4858995Shx147065 		    "%s%s", path, p_file_wifiwepkey);
4859995Shx147065 	} else {
4860995Shx147065 		safe_snprintf(file_wifi, sizeof (file_wifi),
4861995Shx147065 		    "%s", p_file_wifi);
4862995Shx147065 		safe_snprintf(file_wifiwepkey, sizeof (file_wifiwepkey),
4863995Shx147065 		    "%s", p_file_wifiwepkey);
4864995Shx147065 	}
4865995Shx147065 	/*
4866995Shx147065 	 * There is an occasion when more than one wificonfig processes
4867995Shx147065 	 * which attempt to write the <wifi> and <wifiwepkey> files are
4868995Shx147065 	 * running. We must be able to avoid this.
4869995Shx147065 	 * We use file lock here to implement this.
4870995Shx147065 	 */
4871995Shx147065 	if ((!readonly) && (enter_wifi_lock(&fd) != getpid())) {
4872995Shx147065 		ret = WIFI_FATAL_ERR;
4873995Shx147065 		goto exit1;
4874995Shx147065 	}
4875995Shx147065 	gp_config_file = parse_file(file_wifi);
4876995Shx147065 	if (gp_config_file == NULL) {
4877995Shx147065 		ret = WIFI_FATAL_ERR;
4878995Shx147065 		goto exit2;
4879995Shx147065 	}
4880995Shx147065 
4881995Shx147065 	gp_wepkey_file = parse_file(file_wifiwepkey);
4882995Shx147065 	if (gp_wepkey_file == NULL) {
4883995Shx147065 		destroy_config(gp_config_file);
4884995Shx147065 		ret = WIFI_FATAL_ERR;
4885995Shx147065 		goto exit2;
4886995Shx147065 	}
4887995Shx147065 	if (do_func[i].p_do_func(fddev, argc-1, argv+1)
4888995Shx147065 	    == B_TRUE) {
4889995Shx147065 		/*
4890995Shx147065 		 * can not write file when startconfing
4891995Shx147065 		 * during boot
4892995Shx147065 		 */
4893995Shx147065 		if (do_func[i].b_readonly)
4894995Shx147065 			ret = WIFI_EXIT_DEF;
4895995Shx147065 		else if ((fprint_config_file(gp_config_file,
4896995Shx147065 		    file_wifi) != B_TRUE) ||
4897995Shx147065 		    (fprint_config_file(gp_wepkey_file,
4898995Shx147065 		    file_wifiwepkey) != B_TRUE))
4899995Shx147065 			ret = WIFI_FATAL_ERR;
4900995Shx147065 		else
4901995Shx147065 			ret = WIFI_EXIT_DEF;
4902995Shx147065 	} else {
4903995Shx147065 		PRTDBG(("Command %s failed\n", argv[0]));
4904995Shx147065 		ret = WIFI_FATAL_ERR;
4905995Shx147065 	}
4906995Shx147065 	destroy_config(gp_wepkey_file);
4907995Shx147065 	destroy_config(gp_config_file);
4908995Shx147065 exit2:
4909995Shx147065 	if (!readonly)
4910995Shx147065 		exit_wifi_lock(fd);
4911995Shx147065 exit1:
4912995Shx147065 	if (iname)
4913995Shx147065 		(void) close(fddev);
4914995Shx147065 exit0:
4915995Shx147065 	free(gbuf);
4916995Shx147065 	return (ret);
4917995Shx147065 }
4918995Shx147065 
4919995Shx147065 #ifdef DEBUG
4920995Shx147065 static void
wifi_dbgprintf(char * fmt,...)4921995Shx147065 wifi_dbgprintf(char *fmt, ...)
4922995Shx147065 {
4923995Shx147065 	va_list ap;
4924995Shx147065 	va_start(ap, fmt);
4925995Shx147065 	(void) vfprintf(stdout, fmt, ap);
4926995Shx147065 	va_end(ap);
4927995Shx147065 }
4928995Shx147065 #endif
4929