xref: /titanic_41/usr/src/cmd/cmd-inet/usr.sbin/wificonfig/wificonfig.c (revision 82629e3015252bf18319ba3815c773df23e21436)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stddef.h>
31 #include <errno.h>
32 #include <ctype.h>
33 #include <stdarg.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <net/if.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <sys/wait.h>
40 #include <sys/ipc.h>
41 #include <sys/ddi.h>
42 #include <stropts.h>
43 #include <assert.h>
44 #include <termios.h>
45 #include <time.h>
46 #include <string.h>
47 #include <strings.h>
48 #include <auth_attr.h>
49 #include <auth_list.h>
50 #include <libdevinfo.h>
51 #include <secdb.h>
52 #include <priv.h>
53 #include <pwd.h>
54 #include <umem.h>
55 #include <locale.h>
56 #include <libintl.h>
57 #include <dirent.h>
58 #include <inet/wifi_ioctl.h>
59 
60 /*
61  * Debug information
62  */
63 #ifdef	DEBUG
64 int wifi_debug = 0;
65 void wifi_dbgprintf(char *fmt, ...);
66 #define	PRTDBG(msg) if (wifi_debug > 1) wifi_dbgprintf msg
67 #else /* DEBUG */
68 #define	PRTDBG(msg)
69 #endif /* DEBUG */
70 
71 #define	MAX_HISTORY_NUM			10
72 #define	MAX_PREFERENCE_NUM		10
73 #define	MAX_SCANBUF_LEN			256
74 #define	MAX_CONFIG_FILE_LENGTH		256
75 #define	MAX_LOADPF_LENGTH		256
76 #define	LOADPROFILE_TIMEOUT		10
77 #define	RECORD_ADD		0
78 #define	RECORD_DEL		1
79 /*
80  * Wificonfig exit status
81  */
82 #define	WIFI_EXIT_DEF		0
83 #define	WIFI_FATAL_ERR		1
84 #define	WIFI_IMPROPER_USE	2
85 #define	WIFI_MINOR_ERR		3
86 
87 #define	WIFI_LOCKF "/var/run/lockf_wifi"
88 
89 typedef enum {
90 	PREFERENCE,
91 	HISTORY,
92 	ACTIVEP,
93 	PROFILE,
94 	OTHER
95 } list_type_t;
96 
97 #define	WIFI_PREFER	"{preference}"
98 #define	WIFI_HISTORY	"{history}"
99 #define	WIFI_ACTIVEP	"{active_profile}"
100 
101 typedef enum {
102 	LINKSTATUS = 0,
103 	BSSID,
104 	ESSID,
105 	BSSTYPE,
106 	CREATEIBSS,
107 	CHANNEL,
108 	RATES,
109 	POWERMODE,
110 	AUTHMODE,
111 	ENCRYPTION,
112 	WEPKEYID,
113 	WEPKEY,
114 	SIGNAL,
115 	RADIOON,
116 	WLANLIST,
117 	CONFIG_ITEM_END /* 15 */
118 } config_item_t;
119 typedef struct ae {
120 	struct ae *ae_next;
121 	char *ae_arg;
122 }ae_t;
123 typedef struct aelist {
124 	int ael_argc;
125 	ae_t *ael_head, *ael_tail;
126 	list_type_t type;
127 }aelist_t;
128 typedef struct section {
129 	struct section *section_next;
130 	aelist_t *list;
131 	char *section_id;
132 }section_t;
133 
134 /*
135  * config_file_t is an abstract of configration file,
136  * either/etc/inet/wifi/wifi.<interface> or /etc/inet/secret/
137  * wifi/wifiwepkey.<interface>
138  */
139 typedef struct config_file {
140 	int section_argc;
141 	section_t *section_head, *section_tail;
142 }config_file_t;
143 
144 static config_file_t *gp_config_file = NULL;
145 static config_file_t *gp_wepkey_file = NULL;
146 static char *p_file_wifi = "/etc/inet/wifi";
147 static char *p_file_wifiwepkey = "/etc/inet/secret/wifiwepkey";
148 
149 typedef enum {
150 	AUTH_WEP = 0,
151 	AUTH_OTHER = 1
152 } wifi_auth_t;
153 
154 static char *p_auth_string[] = {
155 	WIFI_WEP_AUTH,
156 	WIFI_CONFIG_AUTH
157 };
158 
159 /*
160  * gbuf: is a global buf, which is used to communicate between the user and
161  * the driver
162  */
163 static wldp_t *gbuf = NULL;
164 static char *gExecName = NULL;
165 
166 static void print_error(uint32_t);
167 static void *safe_malloc(size_t);
168 static void *safe_calloc(size_t, size_t);
169 static char *safe_strdup(const char *s1);
170 static void safe_snprintf(char *s, size_t n,
171     const char *format, ...);
172 static void safe_fclose(FILE *stream);
173 static void new_ae(aelist_t *ael, const char *arg);
174 static aelist_t *new_ael(list_type_t type);
175 static config_file_t *new_config_file();
176 static void new_section(config_file_t *p_config_file, aelist_t *p_list,
177 	const char *section_id);
178 static void destroy_config(config_file_t *p_config_file);
179 static config_file_t *parse_file(const char *pfile);
180 static char **aeltoargv(aelist_t *ael, int *ael_num);
181 static boolean_t fprint_config_file(config_file_t *p_config_file,
182 	const char *file_name);
183 static char *append_pa(const char *arg);
184 static section_t *find_section(config_file_t *p_config_file,
185 	const char *section_id);
186 static ae_t *find_ae(aelist_t *plist, const char *arg);
187 static void update_aelist(aelist_t *plist, const char *arg);
188 static const char *get_value(const char *arg);
189 static char *find_active_profile(int);
190 static const char *essid_of_profile(const char *profile);
191 static boolean_t search_interface(char *interface);
192 static int open_dev(char *devname);
193 static boolean_t call_ioctl(int, int, uint32_t, uint32_t);
194 static boolean_t del_prefer(config_file_t *p_config_file, const char *prefer,
195     boolean_t rflag);
196 static boolean_t del_section(config_file_t *p_config_file, char *section_id);
197 static boolean_t set_prefer(config_file_t *p_config_file, const char *prefer,
198 	int rank);
199 static void add_to_history(config_file_t *p_config_file,
200     int argc, char **argv);
201 static boolean_t check_authority(wifi_auth_t type);
202 static void heuristic_load(int fd, uint32_t ess_num, wl_ess_conf_t **);
203 static char *select_profile(int fd, int readonly, int timeout);
204 static char *construct_format(uint32_t nt);
205 static void print_gbuf(config_item_t index);
206 static boolean_t items_in_profile(aelist_t *, aelist_t *, int, char **);
207 static char *get_commit_key(int, int, char **);
208 static void print_wepkey_info(const char *id, const char *wepkeyn);
209 static void  do_print_usage();
210 static boolean_t do_print_support_params(int fd);
211 static boolean_t do_autoconf(int fd, int argc, char **argv);
212 static boolean_t do_startconf(int fd, int argc, char **argv);
213 static boolean_t do_loadpf(int fd, int argc, char **argv);
214 static boolean_t do_disconnect(int fd, int argc, char **argv);
215 static boolean_t do_printpf(int fd, int argc, char **argv);
216 static boolean_t do_restoredef(int fd, int argc, char **argv);
217 static boolean_t do_history(int fd, int argc, char **argv);
218 static boolean_t do_deletepf(int fd, int argc, char **argv);
219 static boolean_t do_wepkey(int fd, int argc, char **argv);
220 static boolean_t do_setprefer(int fd, int argc, char **arg);
221 static boolean_t do_rmprefer(int fd, int argc, char **argv);
222 static boolean_t do_lsprefer(int fd, int argc, char **argv);
223 static boolean_t do_wlanlist(int fd, int argc, char **argv);
224 static boolean_t do_showstatus(int fd, int argc, char **argv);
225 static boolean_t do_getprofparam(int fd, int argc, char **argv);
226 static boolean_t do_setprofparam(int fd, int argc, char **argv);
227 static boolean_t do_setprofwepkey(int fd, int argc, char **argv);
228 static boolean_t is_rates_support(int fd, int num, uint8_t *rates);
229 static boolean_t do_set_bsstype(int fd, const char *arg);
230 static boolean_t do_set_essid(int fd, const char *arg);
231 static boolean_t do_set_powermode(int fd, const char *arg);
232 static boolean_t do_set_rates(int fd, const char *arg);
233 static boolean_t do_set_channel(int fd, const char *arg);
234 static boolean_t do_set_createibss(int fd, const char *arg);
235 static boolean_t do_set_radioon(int fd, const char *arg);
236 static boolean_t do_set_wepkeyid(int fd, const char *arg);
237 static boolean_t do_set_encryption(int fd, const char *arg);
238 static boolean_t do_set_authmode(int fd, const char *arg);
239 static boolean_t do_set_wepkey(int fd, const char *pbuf);
240 static boolean_t do_get_createibss(int fd);
241 static boolean_t do_get_bsstype(int fd);
242 static boolean_t do_get_essid(int fd);
243 static boolean_t do_get_bssid(int fd);
244 static boolean_t do_get_radioon(int fd);
245 static boolean_t do_get_signal(int fd);
246 static boolean_t do_get_wepkeyid(int fd);
247 static boolean_t do_get_encryption(int fd);
248 static boolean_t do_get_authmode(int fd);
249 static boolean_t do_get_powermode(int fd);
250 static boolean_t do_get_rates(int fd);
251 static boolean_t do_get_wlanlist(int fd);
252 static boolean_t do_get_linkstatus(int fd);
253 static boolean_t do_get_channel(int fd);
254 static boolean_t do_get(int fd, int argc, char **argv);
255 static boolean_t do_set(int fd, int argc, char **argv);
256 static boolean_t do_createprofile(int fd, int argc, char **argv);
257 static boolean_t value_is_valid(config_item_t item, const char *value);
258 
259 typedef struct cmd_ops {
260 	char cmd[32];
261 	boolean_t (*p_do_func)(int fd, int argc, char **argv);
262 	boolean_t b_auth;
263 	boolean_t b_fileonly; /* operation only on the config file */
264 	boolean_t b_readonly; /* only read from the card or config file */
265 } cmd_ops_t;
266 static cmd_ops_t do_func[] = {
267 	{
268 		"autoconf",
269 		do_autoconf,
270 		B_TRUE,
271 		B_FALSE,
272 		B_FALSE
273 	},
274 	{
275 		"startconf",
276 		do_startconf,
277 		B_TRUE,
278 		B_FALSE,
279 		B_TRUE
280 	},
281 	{
282 		"connect",
283 		do_loadpf,
284 		B_TRUE,
285 		B_FALSE,
286 		B_FALSE
287 	},
288 	{
289 		"disconnect",
290 		do_disconnect,
291 		B_TRUE,
292 		B_FALSE,
293 		B_FALSE
294 	},
295 	{
296 		"showprofile",
297 		do_printpf,
298 		B_FALSE,
299 		B_TRUE,
300 		B_TRUE
301 	},
302 	{
303 		"deleteprofile",
304 		do_deletepf,
305 		B_TRUE,
306 		B_TRUE,
307 		B_FALSE
308 	},
309 	{
310 		"history",
311 		do_history,
312 		B_FALSE,
313 		B_TRUE,
314 		B_TRUE
315 	},
316 	{
317 		"listprefer",
318 		do_lsprefer,
319 		B_FALSE,
320 		B_TRUE,
321 		B_TRUE
322 	},
323 	{
324 		"removeprefer",
325 		do_rmprefer,
326 		B_TRUE,
327 		B_TRUE,
328 		B_FALSE
329 	},
330 	{
331 		"setprefer",
332 		do_setprefer,
333 		B_TRUE,
334 		B_TRUE,
335 		B_FALSE
336 	},
337 	{
338 		"setwepkey",
339 		do_wepkey,
340 		B_TRUE,
341 		B_FALSE,
342 		B_FALSE
343 	},
344 	{
345 		"restoredef",
346 		do_restoredef,
347 		B_TRUE,
348 		B_FALSE,
349 		B_FALSE
350 	},
351 	{
352 		"getparam",
353 		do_get,
354 		B_FALSE,
355 		B_FALSE,
356 		B_TRUE
357 	},
358 	{
359 		"setparam",
360 		do_set,
361 		B_TRUE,
362 		B_FALSE,
363 		B_FALSE
364 	},
365 	{
366 		"createprofile",
367 		do_createprofile,
368 		B_TRUE,
369 		B_TRUE,
370 		B_FALSE
371 	},
372 	{
373 		"scan",
374 		do_wlanlist,
375 		B_FALSE,
376 		B_FALSE,
377 		B_FALSE
378 	},
379 	{
380 		"showstatus",
381 		do_showstatus,
382 		B_FALSE,
383 		B_FALSE,
384 		B_TRUE
385 	},
386 	{
387 		"setprofileparam",
388 		do_setprofparam,
389 		B_TRUE,
390 		B_TRUE,
391 		B_FALSE
392 	},
393 	{
394 		"getprofileparam",
395 		do_getprofparam,
396 		B_FALSE,
397 		B_TRUE,
398 		B_TRUE
399 	},
400 	{
401 		"setprofilewepkey",
402 		do_setprofwepkey,
403 		B_TRUE,
404 		B_TRUE,
405 		B_FALSE
406 	}
407 };
408 
409 
410 typedef enum {RW, RO, WO} rw_property_t;
411 typedef struct gs_ops {
412 	config_item_t index;
413 	char cmd[32];
414 	boolean_t (*p_do_get_func)(int fd);
415 	boolean_t (*p_do_set_func)(int fd, const char *arg);
416 	rw_property_t rw;
417 } gs_ops_t;
418 static gs_ops_t do_gs_func[] = {
419 	{LINKSTATUS, "linkstatus", NULL, NULL, RO},
420 	{BSSID, "bssid", do_get_bssid, NULL, RO},
421 	{ESSID, "essid", do_get_essid, do_set_essid, RW},
422 	{BSSTYPE, "bsstype", do_get_bsstype, do_set_bsstype, RW},
423 	{CREATEIBSS, "createibss", do_get_createibss, do_set_createibss, RW},
424 	{CHANNEL, "channel", do_get_channel, do_set_channel, RW},
425 	{RATES, "rates", do_get_rates, do_set_rates, RW},
426 	{POWERMODE, "powermode", do_get_powermode, do_set_powermode, RW},
427 	{AUTHMODE, "authmode", do_get_authmode, do_set_authmode, RW},
428 	{ENCRYPTION, "encryption", do_get_encryption, do_set_encryption, RW},
429 	{WEPKEYID, "wepkeyindex", do_get_wepkeyid, do_set_wepkeyid, RW},
430 	{WEPKEY, "wepkey|1-4", NULL, do_set_wepkey, WO},
431 	{SIGNAL, "signal", do_get_signal, NULL, RO},
432 	{RADIOON, "radio",	do_get_radioon, do_set_radioon, RW},
433 };
434 
435 #define	N_FUNC		sizeof (do_func) / sizeof (cmd_ops_t)
436 #define	N_GS_FUNC 	sizeof (do_gs_func) / sizeof (gs_ops_t)
437 
438 /*
439  * valid rate value
440  */
441 typedef	struct wifi_rates_tab {
442 	char *rates_s;
443 	uint8_t rates_i;
444 	uint8_t rates_reserve0;
445 	uint8_t rates_reserve1;
446 	uint8_t rates_reserve2;
447 } wifi_rates_tab_t;
448 
449 /*
450  * the rates value is in increments of 500kb/s.
451  * according to the 802.11 a/b/g specs(IEEE):
452  * 802.11b(IEEE Std 802.11b-1999) page35, rates should be:
453  *	X02, X04, X0b, X16
454  * 802.11a(IEEE Std 802.11a-1999) page47, rates should be:
455  *	6,9,12,18,24,36,48,54 Mb/s
456  * 802.11g(IEEE Std 802.11g-2003) page44, rates should be:
457  *	1,2,5.5,11,6,9,12,18,22,24,33,36,48,54 Mb/s
458  */
459 #define	WIFI_RATES_NUM	14
460 static wifi_rates_tab_t wifi_rates_s[WIFI_RATES_NUM] = {
461 	{"1",	WL_RATE_1M,	0,	0,	0},
462 	{"2",	WL_RATE_2M,	0,	0,	0},
463 	{"5.5",	WL_RATE_5_5M,	0,	0,	0},
464 	{"6",	WL_RATE_6M,	0,	0,	0},
465 	{"9",	WL_RATE_9M,	0,	0,	0},
466 	{"11",	WL_RATE_11M,	0,	0,	0},
467 	{"12",	WL_RATE_12M,	0,	0,	0},
468 	{"18",	WL_RATE_18M,	0,	0,	0},
469 	{"22",	WL_RATE_22M,	0,	0,	0},
470 	{"24",	WL_RATE_24M,	0,	0,	0},
471 	{"33",	WL_RATE_33M,	0,	0,	0},
472 	{"36",	WL_RATE_36M,	0,	0,	0},
473 	{"48",	WL_RATE_48M,	0,	0,	0},
474 	{"54",	WL_RATE_54M,	0,	0,	0}
475 };
476 /* print the error message on why set or get ioctl command failed. */
477 static void
478 print_error(uint32_t errorno)
479 {
480 	char *buf;
481 
482 	switch (errorno) {
483 	case WL_SUCCESS:
484 		buf = gettext("command succeeded");
485 		break;
486 	case WL_NOTSUPPORTED:
487 	case WL_LACK_FEATURE:
488 	case WL_HW_ERROR:
489 	case WL_ACCESS_DENIED:
490 		buf = strerror(errorno);
491 		break;
492 	case WL_READONLY:
493 		buf = gettext("parameter read-only");
494 		break;
495 	case WL_WRITEONLY:
496 		buf = gettext("parameter write-only");
497 		break;
498 	case WL_NOAP:
499 		buf = gettext("no access point available");
500 		break;
501 	default:
502 		buf = gettext("unknown error");
503 		break;
504 	}
505 	(void) fprintf(stderr, "%s\n", buf);
506 }
507 
508 static void *
509 safe_malloc(size_t size)
510 {
511 	void *buf;
512 
513 	buf = malloc(size);
514 	if (buf == NULL) {
515 		(void) fprintf(stderr, gettext("%s: malloc: %s\n"),
516 		    gExecName, strerror(errno));
517 		exit(WIFI_FATAL_ERR);
518 	}
519 	return (buf);
520 }
521 
522 static void *
523 safe_calloc(size_t nelem, size_t elsize)
524 {
525 	void *buf;
526 
527 	buf = calloc(nelem, elsize);
528 	if (buf == NULL) {
529 		(void) fprintf(stderr, gettext("%s: calloc: %s\n"),
530 		    gExecName, strerror(errno));
531 		exit(WIFI_FATAL_ERR);
532 	}
533 	return (buf);
534 }
535 
536 static char *
537 safe_strdup(const char *s1)
538 {
539 	char *p;
540 
541 	p = strdup(s1);
542 	if (p == NULL) {
543 		(void) fprintf(stderr, gettext("%s: strdup: %s\n"),
544 		    gExecName, strerror(errno));
545 		exit(WIFI_FATAL_ERR);
546 	}
547 	return (p);
548 }
549 
550 static void
551 safe_snprintf(char *s, size_t n,  const  char  *format, ...)
552 {
553 	int len;
554 	va_list ap;
555 	va_start(ap, format);
556 
557 	len = vsnprintf(s, n, format, ap);
558 	if ((len <= 0) || (len > n - 1)) {
559 		(void) fprintf(stderr,
560 		    gettext("%s: snprintf: %s\n"),
561 		    gExecName, strerror(errno));
562 		exit(WIFI_FATAL_ERR);
563 	}
564 	va_end(ap);
565 }
566 
567 static void
568 safe_fclose(FILE *stream)
569 {
570 	int err;
571 
572 	err = fclose(stream);
573 	if (err == EOF) {
574 		(void) fprintf(stderr, gettext("%s: fclose: %s\n"),
575 		    gExecName, strerror(errno));
576 		exit(WIFI_FATAL_ERR);
577 	}
578 }
579 /*
580  * new_ae: Add an element with content pointed by arg to the list *ael.
581  */
582 static void
583 new_ae(aelist_t *ael, const char *arg)
584 {
585 	ae_t *pae = NULL;
586 
587 	PRTDBG(("new_ae(0x%x, \"%s\")\n", ael, arg));
588 	assert((ael != NULL) && (arg != NULL));
589 
590 	pae = safe_calloc(sizeof (*pae), 1);
591 	pae->ae_arg = safe_strdup(arg);
592 	pae->ae_next = NULL;
593 
594 	if (ael->ael_tail == NULL) {
595 		ael->ael_head = pae;
596 	} else {
597 		ael->ael_tail->ae_next = pae;
598 	}
599 	ael->ael_tail = pae;
600 	ael->ael_argc++;
601 }
602 /*
603  * new_ael:  Create a new aelist with list_type "type"
604  * and return the list pointer.
605  */
606 static aelist_t *
607 new_ael(list_type_t type)
608 {
609 	aelist_t *plist;
610 
611 	plist = safe_calloc(sizeof (*plist), 1);
612 	plist->type = type;
613 	plist->ael_argc = 0;
614 	plist->ael_head = plist->ael_tail = NULL;
615 
616 	PRTDBG(("new_ael(%d) = 0x%x\n", type, plist));
617 	return (plist);
618 }
619 
620 /*
621  * new_config_file: Creates a new config_file_t struct which is counterpart of
622  * of the configration file, and return the pointer.
623  */
624 static config_file_t *
625 new_config_file()
626 {
627 	config_file_t *p_config_file;
628 
629 	p_config_file = safe_calloc(sizeof (config_file_t), 1);
630 	p_config_file->section_argc = 0;
631 	p_config_file->section_head = p_config_file->section_tail = NULL;
632 
633 	PRTDBG(("new_config_file() = 0x%x\n", p_config_file));
634 	return (p_config_file);
635 }
636 
637 /*
638  * new_section: Add a list pointed by "p_list", with identity "section_id" to
639  * the config_file_t struct pointed by "p_config_file"
640  */
641 static void
642 new_section(config_file_t *p_config_file, aelist_t *p_list,
643     const char *section_id)
644 {
645 	section_t *p_section = NULL;
646 
647 	PRTDBG(("new_section(0x%x, 0x%x, \"%s\")\n", p_config_file, p_list,
648 	    section_id));
649 	assert((p_config_file != NULL) && (p_list != NULL) &&
650 	    (section_id != NULL));
651 
652 	p_section = safe_calloc(sizeof (*p_section), 1);
653 	p_section->list = p_list;
654 	p_section->section_next = NULL;
655 	p_section->section_id = safe_strdup(section_id);
656 
657 	if (p_config_file->section_tail == NULL) {
658 		p_config_file->section_head = p_section;
659 	} else {
660 		p_config_file->section_tail->section_next = p_section;
661 	}
662 	p_config_file->section_tail = p_section;
663 	p_config_file->section_argc++;
664 }
665 
666 /*
667  * destroy_config:Destroy the config_file struct
668  */
669 static void
670 destroy_config(config_file_t *p_config_file)
671 {
672 	section_t *p_section = NULL;
673 	aelist_t *p_list = NULL;
674 	ae_t *pae = NULL;
675 
676 	PRTDBG(("destory_config(0x%x)\n", p_config_file));
677 	assert(p_config_file != NULL);
678 
679 	p_section = p_config_file->section_head;
680 	while (p_section != NULL) {
681 		p_list = p_section->list;
682 		if (p_list != NULL) {
683 			pae = p_list->ael_head;
684 			while (pae != NULL) {
685 				if (pae->ae_arg != NULL)
686 					free(pae->ae_arg);
687 				pae->ae_arg = NULL;
688 				pae = pae->ae_next;
689 				free(p_list->ael_head);
690 				p_list->ael_head = pae;
691 			}
692 			free(p_list);
693 			p_list = NULL;
694 		}
695 		if (p_section->section_id != NULL)
696 			free(p_section->section_id);
697 		p_section->section_id = NULL;
698 		p_section = p_section->section_next;
699 		free(p_config_file->section_head);
700 		p_config_file->section_head = p_section;
701 	}
702 	free(p_config_file);
703 	p_config_file = NULL;
704 }
705 
706 /*
707  * parse_file: Parse each section of the configration file
708  * and construct the config_file_t structure.
709  * Example:
710  * A config file has contents below:
711  *
712  * {preferrence}
713  * essid=ap7-3
714  * essid=linksys
715  *
716  * {history}
717  * essid=ap7-3
718  * essid=ap7-2
719  *
720  * [ap7-3]
721  * essid=ap7-3
722  * wepkeyid=3
723  * channel=11
724  * rates=1,2
725  *
726  * [linksys]
727  * essid=linksys
728  * createibss=BSS
729  * authmode=OPENSYSTEM
730  * wepkeyid=1
731  *
732  * then its config_file_t structure will be:
733  *
734  *                        config_file_t
735  *                       |~~~~~~~~~~~~~~~~~~~~~~~~~~|
736  *                       |      section_argc=5      |
737  *                       |~~~~~~~~~~~~T~~~~~~~~~~~~~|
738  *                      /|   *head    |    *tail    |\
739  *                     / ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \
740  *                    /                                \
741  *                   /	                                \
742  *                  /                                    \
743  *                 /                                      \
744  *                /                                        \
745  *  section_t    V           section_t                      V section_t
746  * |~~~~~~~~~~~~~~~|~~|     |~~~~~~~~~~~~~~~|~~|      |~~~~~~~~~~~~~~|~~|
747  * |"{preferrence}"|  |     |  "{history}"  |  |      | "[linksys]"  |  |
748  * |~~~~~~~~~~~~~~~| -+---->|~~~~~~~~~~~~~~~| -+->..->|~~~~~~~~~~~~~~| -+->NULL
749  * |    *list      |  |     |    *list      |  |      |    *list     |  |
750  * ~~T~~~~~~~~~~~~~~~~~     ~~~T~~~~~~~~~~~~~~~~      ~~~T~~~~~~~~~~~~~~~
751  *   |                         |                         |
752  *   |                         |                         |
753  *   V aelist_t                V aelist_t                V aelist_t
754  * |~~~~~~~~~~~~~|          |~~~~~~~~~~~~~|           |~~~~~~~~~~~~~|
755  * |  argc=2     |          |  argc=3     |           |  argc=4     |
756  * |~~~~~~~~~~~~~|          |~~~~~~~~~~~~~|           |~~~~~~~~~~~~~|
757  * |PREFFERRENCE |          |   HISTORY   |           |   PROFILE   |
758  * |~~~~~~T~~~~~~|          |~~~~~~T~~~~~~|           |~~~~~~T~~~~~~|
759  * |*head |*tail |\         |*head |*tail |\          |*head |*tail |
760  * ~~T~~~~~~~~~~~~ \        ~~T~~~~~~~~~~~~ \        /~~~~~~~~~~~~~~~\
761  *   |              \         V              V      /                 \
762  *   |               \        ...            ...   /                   \
763  *   V ae_t           V  ae_t             ae_t    V           ae_t      V
764  * |~~~~~~~~~T~~|  |~~~~~~~~~T~~|       |~~~~~~~~~T~~|      |~~~~~~~~~T~~|
765  * |"essid=  | -+->|"essid=  | -+->NULL |"essid=  | -+->..->|"wepkeyid| -+->NULL
766  * | ap7-3"  |  |  | linksys"|  |       | linksys"|  |      | =1"     |  |
767  * ~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~       ~~~~~~~~~~~~~~      ~~~~~~~~~~~~~~
768  *
769  */
770 
771 static config_file_t *
772 parse_file(const char *pfile)
773 {
774 	FILE *file = NULL;
775 	int fd = 0;
776 	char buf_line[256];
777 	config_file_t *p_config_file;
778 	list_type_t cur_list = OTHER;
779 	aelist_t *prefer_list = NULL;
780 	aelist_t *history_list = NULL;
781 	aelist_t *profile_list = NULL;
782 	aelist_t *activep_list = NULL;
783 
784 	assert(pfile != NULL);
785 	/*
786 	 * The files /etc/inet/wifi and /etc/inet/secret/wifiwepkey should
787 	 * be opened with "r" attribute. If these two files do not exist,
788 	 * create them here.
789 	 */
790 	file = fopen(pfile, "r");
791 
792 	if (file == NULL) {
793 		fd = open(pfile, O_CREAT|O_EXCL|O_RDWR, 0600);
794 		if (fd < 0) {
795 			(void) fprintf(stderr, gettext("%s: failed to open %s"
796 			    "\n"), gExecName, pfile);
797 			goto error1;
798 		}
799 		file = fdopen(fd, "w");
800 		(void) chmod(pfile, S_IRUSR);
801 	}
802 
803 	p_config_file = new_config_file();
804 
805 	while (fgets(buf_line, sizeof (buf_line), file) != NULL) {
806 		if ((buf_line[0] == '\n') || (buf_line[0] == ' '))
807 			continue;
808 		/* replace the old '\n' to '\0' */
809 		buf_line[strlen(buf_line) - 1] = '\0';
810 		if (strstr(buf_line, WIFI_PREFER) == buf_line) {
811 			if (prefer_list == NULL) {
812 				cur_list = PREFERENCE;
813 				prefer_list = new_ael(PREFERENCE);
814 				new_section(p_config_file, prefer_list,
815 				    WIFI_PREFER);
816 			} else {
817 				(void) fprintf(stderr, gettext("%s: "
818 				    "%s : duplicated %s section\n"),
819 				    gExecName, pfile, WIFI_PREFER);
820 				goto error;
821 			}
822 		} else if (strstr(buf_line, WIFI_HISTORY) == buf_line) {
823 			if (history_list == NULL) {
824 				cur_list = HISTORY;
825 				history_list = new_ael(HISTORY);
826 				new_section(p_config_file, history_list,
827 				    WIFI_HISTORY);
828 			} else {
829 				(void) fprintf(stderr, gettext("%s: "
830 				    "%s : duplicated %s section\n"),
831 				    gExecName, pfile, WIFI_HISTORY);
832 				goto error;
833 			}
834 		} else if (strstr(buf_line, WIFI_ACTIVEP) == buf_line) {
835 			if (activep_list == NULL) {
836 				cur_list = ACTIVEP;
837 				activep_list = new_ael(ACTIVEP);
838 				new_section(p_config_file, activep_list,
839 				    WIFI_ACTIVEP);
840 			} else {
841 				(void) fprintf(stderr, gettext("%s: "
842 				    "%s : duplicated %s section\n"),
843 				    gExecName, pfile, WIFI_ACTIVEP);
844 				goto error;
845 			}
846 		} else if ((strchr(buf_line, '[') == buf_line) &&
847 		    (buf_line[strlen(buf_line) - 1] == ']')) {
848 			cur_list = PROFILE;
849 			profile_list = new_ael(PROFILE);
850 			new_section(p_config_file, profile_list,
851 			    buf_line);
852 		} else {
853 			switch (cur_list) {
854 			case PREFERENCE:
855 				if (prefer_list->ael_argc <=
856 				    MAX_PREFERENCE_NUM)
857 					new_ae(prefer_list, buf_line);
858 				break;
859 			case HISTORY:
860 				if (history_list->ael_argc <=
861 				    MAX_HISTORY_NUM)
862 					new_ae(history_list, buf_line);
863 				break;
864 			case ACTIVEP:
865 				if ((activep_list->ael_argc <= 1) &&
866 				    (strpbrk(buf_line, "=") != NULL))
867 					new_ae(activep_list, buf_line);
868 				break;
869 			case PROFILE:
870 				if (strpbrk(buf_line, "=") != NULL)
871 					new_ae(profile_list, buf_line);
872 				break;
873 			default:
874 				(void) fprintf(stderr,
875 				    gettext("%s: %s: file format error\n"),
876 				    gExecName, pfile);
877 				goto error;
878 			}
879 		}
880 	}
881 	PRTDBG(("parse_file(\"%s\")=0x%x\n", pfile, p_config_file));
882 	(void) fclose(file);
883 	return (p_config_file);
884 error:
885 	destroy_config(p_config_file);
886 	(void) fclose(file);
887 error1:
888 	return (NULL);
889 }
890 /*
891  * construct an argument vector from an aelist
892  */
893 static char **
894 aeltoargv(aelist_t *ael, int *ael_num)
895 {
896 	ae_t *ae = NULL;
897 	char **argv = NULL;
898 	int argc = 0;
899 
900 	PRTDBG(("aeltoargv(%x)\n", ael));
901 	assert(ael != NULL);
902 
903 	argv = safe_calloc(sizeof (*argv), ael->ael_argc);
904 
905 	for (argc = 0, ae = ael->ael_head; ae; ae = ae->ae_next) {
906 		/* skip bssid since it can not be set */
907 		if (strncmp(ae->ae_arg, "bssid=", strlen("bssid=")) == 0)
908 			continue;
909 		argv[argc] = safe_strdup(ae->ae_arg);
910 		argc++;
911 		if (ae == ael->ael_tail)
912 			break;
913 	}
914 
915 	PRTDBG(("aeltoargv(0x%x) = 0x%x\n\n", ael, argv));
916 	*ael_num = argc;
917 	return (argv);
918 }
919 
920 /*
921  * archived contents into a file
922  */
923 static boolean_t
924 fprint_config_file(config_file_t *p_config_file, const char *file_name)
925 {
926 	FILE *file = NULL;
927 	int fd = 0;
928 	int len;
929 	section_t *p_section = NULL;
930 	aelist_t *p_list = NULL;
931 	ae_t *pae = NULL;
932 	char temp_file[256];
933 	struct stat buf;
934 
935 	PRTDBG(("fprint_config_file(0x%x, \"%s\")\n", p_config_file,
936 	    file_name));
937 	assert((p_config_file != NULL)&&(strcmp(file_name, "") != 0));
938 
939 	safe_snprintf(temp_file, sizeof (temp_file),
940 	    "%s.tmp", file_name);
941 	fd = open(temp_file, O_CREAT|O_WRONLY|O_TRUNC, 0600);
942 	if (fd < 0) {
943 		(void) fprintf(stderr, gettext("%s: failed to open %s\n"),
944 		    gExecName, temp_file);
945 		return (B_FALSE);
946 	}
947 	file = fdopen(fd, "w");
948 
949 	p_section = p_config_file->section_head;
950 	while (p_section != NULL) {
951 		p_list = p_section->list;
952 		if (p_list != NULL) {
953 			PRTDBG(("fprint_config_file: section_id=%s\n",
954 			    p_section->section_id));
955 			len = fprintf(file, "\n%s\n", p_section->section_id);
956 			if (len < 0) {
957 				(void) fprintf(stderr, gettext("%s: "
958 				    "failed to update %s: %s\n"),
959 				    gExecName, file_name, strerror(errno));
960 				safe_fclose(file);
961 				return (B_FALSE);
962 			}
963 			pae = p_list->ael_head;
964 			while (pae != NULL) {
965 				if (pae->ae_arg != NULL) {
966 					len = fprintf(file, "%s\n",
967 					    pae->ae_arg);
968 					if (len < 0) {
969 						(void) fprintf(stderr,
970 						    gettext("%s: failed to "
971 						    "update %s: %s\n"),
972 						    gExecName, file_name,
973 						    strerror(errno));
974 						safe_fclose(file);
975 						return (B_FALSE);
976 					}
977 				}
978 				pae = pae->ae_next;
979 			}
980 		}
981 		p_section = p_section->section_next;
982 	}
983 	safe_fclose(file);
984 	/*
985 	 * The attribute of the file /etc/inet/wifi and
986 	 * /etc/inet/security/wifiwepkey should be retained.
987 	 * if those file do not exist, set default file mode.
988 	 */
989 	if (stat(file_name, &buf) != 0) {
990 		if (errno == ENOENT) {
991 			buf.st_mode = 0600;
992 		} else {
993 			(void) fprintf(stderr, gettext("%s: failed to get "
994 			    "file %s stat: %s\n"),
995 			    gExecName, file_name, strerror(errno));
996 			return (B_FALSE);
997 		}
998 	}
999 	if (rename(temp_file, file_name) != 0) {
1000 		(void) fprintf(stderr, gettext("%s: failed to update %s: %s"
1001 		    "\n"), gExecName, file_name, strerror(errno));
1002 		return (B_FALSE);
1003 	}
1004 	(void) chmod(file_name, buf.st_mode);
1005 	return (B_TRUE);
1006 }
1007 /*
1008  * append_pa: Each section holds a section_id which identifies a section
1009  * a profile uses its essid appending "[]" to denote its section_id.
1010  * note: new memory is allocated, remember to free.
1011  */
1012 static char *
1013 append_pa(const char *arg)
1014 {
1015 	char *pbuf = NULL;
1016 	int len;
1017 
1018 	assert(arg != NULL);
1019 
1020 	len = strlen(arg) + 3;
1021 	pbuf = safe_malloc(len);
1022 	safe_snprintf(pbuf, len, "[%s]", arg);
1023 	PRTDBG(("append_pa(\"%s\") = \"%s\"\n", arg, pbuf));
1024 	return (pbuf);
1025 }
1026 /*
1027  * find a section by section_id from p_config_file,
1028  * return the section pointer.
1029  */
1030 static section_t *
1031 find_section(config_file_t *p_config_file, const char *section_id)
1032 {
1033 	section_t *p_section = NULL;
1034 
1035 	PRTDBG(("find_section(0x%x, \"%s\")\n", p_config_file, section_id));
1036 	assert((section_id != NULL)&&(p_config_file != NULL));
1037 
1038 	p_section = p_config_file->section_head;
1039 
1040 	while (p_section != NULL) {
1041 		if ((p_section->section_id != NULL) &&
1042 		    (strcmp(p_section->section_id, section_id) == 0))
1043 			return (p_section);
1044 		p_section = p_section->section_next;
1045 	}
1046 	return (NULL);
1047 }
1048 
1049 /*
1050  * get_value: Get rid of "parameter=" from a "parameter=value", for example:
1051  * when we read an line from file, we gets "essid=ap7-2", this function
1052  * returns the pointer to string "ap7-2";
1053  */
1054 
1055 static const char *
1056 get_value(const char *arg)
1057 {
1058 	char *p;
1059 	assert(arg != NULL);
1060 
1061 	p = strchr(arg, '=');
1062 	PRTDBG(("get_value(\"%s\") = \"%s\"\n", arg, p + 1));
1063 	if (p != NULL)
1064 		return (p + 1);
1065 	else
1066 		return (NULL);
1067 }
1068 
1069 /*
1070  * search /dev/wifi to see which interface is available
1071  */
1072 static boolean_t
1073 search_interface(char *interface)
1074 {
1075 	DIR *dirp;
1076 	struct dirent *dp;
1077 	char buf[256];
1078 	int fd;
1079 
1080 	PRTDBG(("search interface\n"));
1081 	assert(interface != NULL);
1082 
1083 	/*
1084 	 * Try to return the first found wifi interface.
1085 	 * If no wifi interface is available, return B_FALSE
1086 	 */
1087 
1088 	if ((dirp = opendir("/dev/wifi")) == NULL) {
1089 		PRTDBG(("failed to open '/dev/wifi'\n"));
1090 		return (B_FALSE);
1091 	}
1092 	while ((dp = readdir(dirp)) != NULL) {
1093 		if (strcmp(dp->d_name, ".") == 0 ||
1094 		    strcmp(dp->d_name, "..") == 0)
1095 			continue;
1096 		if (dp->d_name[strlen(dp->d_name) - 1] < '0' ||
1097 		    dp->d_name[strlen(dp->d_name) - 1] > '9')
1098 			continue;
1099 		safe_snprintf(buf, sizeof (buf), "%s%s",
1100 		    "/dev/wifi/", dp->d_name);
1101 		fd = open(buf, O_RDWR);
1102 		if (fd == -1) {
1103 			PRTDBG(("interface %s doesn't exist\n", dp->d_name));
1104 			continue;
1105 		} else {
1106 			PRTDBG(("interface %s is the first found interface\n",
1107 			    dp->d_name));
1108 			(void) strlcpy(interface, buf, LIFNAMSIZ);
1109 			(void) close(fd);
1110 			(void) closedir(dirp);
1111 			return (B_TRUE);
1112 		}
1113 	}
1114 
1115 	PRTDBG(("failed to find available wireless interface\n"));
1116 	(void) closedir(dirp);
1117 	return (B_FALSE);
1118 
1119 }
1120 /*
1121  * open_dev: Open the driver.
1122  * if the 'devname' has format like 'ath0', we should add the path to that
1123  * device(/dev/ath0) and open it; if the 'devname' has format like
1124  * '/dev/wifi/ath0', we open it directly.
1125  */
1126 static int
1127 open_dev(char *devname)
1128 {
1129 	int fd;
1130 	int len;
1131 	char *pbuf = NULL;
1132 
1133 	PRTDBG(("open_dev(\"%s\")\n", devname));
1134 	assert(devname != NULL);
1135 	/*
1136 	 * If the devname is got from the user input, we
1137 	 * add '/dev/' to that relative devname. If it
1138 	 * is got from the 'search interface', it is an
1139 	 * absolute path.
1140 	 */
1141 	if (strncmp(devname, "/dev/wifi/", strlen("/dev/wifi/")) == 0) {
1142 		pbuf = safe_strdup(devname);
1143 	} else {
1144 		len = strlen(devname) + strlen("/dev/") + 1;
1145 		pbuf = safe_malloc(len);
1146 		safe_snprintf(pbuf, len, "/dev/%s", devname);
1147 	}
1148 	fd = open(pbuf, O_RDWR);
1149 	free(pbuf);
1150 
1151 	if (fd == -1) {
1152 		(void) fprintf(stderr, gettext("%s: failed to open '%s': %s"
1153 		    "\n"), gExecName, devname, strerror(errno));
1154 		return (-1);
1155 	}
1156 	if (!isastream(fd)) {
1157 		(void) fprintf(stderr, gettext("%s: %s is "
1158 		    "not a stream device\n"),
1159 		    gExecName, devname);
1160 		(void) close(fd);
1161 		return (-1);
1162 	}
1163 	return (fd);
1164 }
1165 /*
1166  * call_ioctl: Fill strioctl structure and issue an ioctl system call
1167  */
1168 static boolean_t
1169 call_ioctl(int fd, int cmd, uint32_t params, uint32_t buf_len)
1170 {
1171 	struct strioctl stri;
1172 
1173 	PRTDBG(("call_ioctl_gs(%d, 0x%x, 0x%x, 0x%x)\n",
1174 	    fd, cmd, params, buf_len));
1175 
1176 	switch (cmd) {
1177 	case WLAN_GET_PARAM:
1178 		(void) memset(gbuf, 0, MAX_BUF_LEN);
1179 		stri.ic_len = MAX_BUF_LEN;
1180 		break;
1181 	case WLAN_SET_PARAM:
1182 		gbuf->wldp_length = buf_len + WIFI_BUF_OFFSET;
1183 		stri.ic_len = gbuf->wldp_length;
1184 		break;
1185 	case WLAN_COMMAND:
1186 		gbuf->wldp_length = sizeof (wldp_t);
1187 		stri.ic_len = gbuf->wldp_length;
1188 		break;
1189 	default:
1190 		(void) fprintf(stderr, gettext("%s: ioctl : "
1191 		    "unsupported ioctl command\n"), gExecName);
1192 		return (B_FALSE);
1193 	}
1194 	gbuf->wldp_type = NET_802_11;
1195 	gbuf->wldp_id = params;
1196 
1197 	stri.ic_cmd = cmd;
1198 	stri.ic_timout = 0;
1199 	stri.ic_dp = (char *)gbuf;
1200 
1201 	if (ioctl(fd, I_STR, &stri) == -1) {
1202 		gbuf->wldp_result = 0xffff;
1203 		return (B_FALSE);
1204 	}
1205 	if (cmd == WLAN_COMMAND) {
1206 		return (B_TRUE);
1207 	} else {
1208 		return (gbuf->wldp_result != WL_SUCCESS ?
1209 		    B_FALSE:B_TRUE);
1210 	}
1211 }
1212 
1213 /*
1214  * del_prefer: Delete an item from the {preferrence} list, the idea is
1215  * simply free the ae_t element, and set ae_arg to NULL, then when archive
1216  * the config_file_t struct to the file, it will be delete.
1217  * The last flag is used to identify whether this function is invoked due to
1218  * the 'removeprefer' subcommand or due to 'deleteprofile' subcommand.
1219  */
1220 static boolean_t
1221 del_prefer(config_file_t *p_config_file, const char *prefer, boolean_t rflag)
1222 {
1223 	section_t *p_section = NULL;
1224 	aelist_t *plist = NULL;
1225 	ae_t *pae = NULL;
1226 	int i = 0, position = 0;
1227 	int number;
1228 	ae_t *prm_ae = NULL;
1229 
1230 	PRTDBG(("del_prefer(0x%x, \"%s\")\n", p_config_file, prefer));
1231 	assert((prefer != NULL)&&(p_config_file != NULL));
1232 
1233 	p_section = find_section(p_config_file, WIFI_PREFER);
1234 	if (p_section != NULL)
1235 		plist = p_section->list;
1236 
1237 	if ((p_section == NULL) || (plist == NULL))
1238 		return (B_FALSE);
1239 
1240 	number = plist->ael_argc;
1241 	pae = plist->ael_head;
1242 	prm_ae = plist->ael_head;
1243 	while (pae != NULL) {
1244 		if (strcmp(prefer, pae->ae_arg) == 0) {
1245 			free(pae->ae_arg);
1246 			pae->ae_arg = NULL; /* mark */
1247 			if (!position) {
1248 				plist->ael_head = pae->ae_next;
1249 				if (pae->ae_next == NULL)
1250 					plist->ael_tail = NULL;
1251 			} else {
1252 				for (i = 0; i < position - 1; i++)
1253 					prm_ae = prm_ae->ae_next;
1254 				prm_ae->ae_next = pae->ae_next;
1255 				if (pae->ae_next == NULL)
1256 					plist->ael_tail = prm_ae;
1257 			}
1258 			free(pae);
1259 			pae = NULL;
1260 			plist->ael_argc--;
1261 			break;
1262 		}
1263 		position++;
1264 		pae = pae->ae_next;
1265 	}
1266 	if ((number == plist->ael_argc) && (rflag == B_TRUE)) {
1267 		(void) fprintf(stderr, gettext("%s: removeprefer : "
1268 		    "no such profile: '%s' in the preference list\n"),
1269 		    gExecName, prefer);
1270 		return (B_FALSE);
1271 	}
1272 	return (B_TRUE);
1273 }
1274 
1275 /*
1276  * del_section: Delete an section from p_config_file, the idea is
1277  * simply free the aelist_t struct and set it to NULL, when archiving
1278  * config_file_t struct to the file, we will find section list is NULL,
1279  * and will not write it to file, so it will be deleted.
1280  */
1281 static boolean_t
1282 del_section(config_file_t *p_config_file, char *section_id)
1283 {
1284 	section_t *p_section = NULL;
1285 	section_t *prm_section = NULL;
1286 	aelist_t *plist = NULL;
1287 	ae_t *pae = NULL;
1288 	int i = 0, position = 0;
1289 
1290 	PRTDBG(("del_section(0x%x, \"%s\")\n", p_config_file, section_id));
1291 	PRTDBG(("del_section: %d section(s) in config file\n",
1292 	    p_config_file->section_argc));
1293 	assert((section_id != NULL)&&(p_config_file != NULL));
1294 
1295 	if (find_section(p_config_file, section_id) == NULL) {
1296 		return (B_FALSE);
1297 	}
1298 	p_section = p_config_file->section_head;
1299 	prm_section = p_config_file->section_head;
1300 	while (p_section != NULL) {
1301 		if (p_section->section_id != NULL) {
1302 			if (strcmp(p_section->section_id, section_id) == 0) {
1303 				plist = p_section->list;
1304 				pae = plist->ael_head;
1305 				while (pae != NULL) {
1306 					free(pae->ae_arg);
1307 					pae->ae_arg = NULL;
1308 					pae = pae->ae_next;
1309 					free(plist->ael_head);
1310 					plist->ael_head = pae;
1311 				}
1312 				free(plist);
1313 				p_section->list = NULL;
1314 				free(p_section->section_id);
1315 				p_section->section_id = NULL;
1316 
1317 				if (!position) {
1318 					p_config_file->section_head =
1319 					    p_section->section_next;
1320 					if (p_section->section_next == NULL)
1321 						p_config_file->section_tail =
1322 						    NULL;
1323 				} else {
1324 					for (i = 0; i < position - 1; i++) {
1325 						prm_section =
1326 						    prm_section->section_next;
1327 					}
1328 					prm_section->section_next =
1329 					    p_section->section_next;
1330 					if (p_section->section_next == NULL)
1331 						p_config_file->section_tail =
1332 						    prm_section;
1333 				}
1334 				free(p_section);
1335 				p_config_file->section_argc--;
1336 				break;
1337 			}
1338 			position++;
1339 		}
1340 		p_section = p_section->section_next;
1341 	}
1342 	return (B_TRUE);
1343 }
1344 
1345 /*
1346  * set_prefer: Reorder the preferrence list.
1347  */
1348 static boolean_t
1349 set_prefer(config_file_t *p_config_file, const char *prefer, int rank)
1350 {
1351 	char *pbuf = NULL;
1352 	aelist_t *plist = NULL;
1353 	section_t *p_section = NULL;
1354 	ae_t *pae = NULL;
1355 	int i = 0, position = 0;
1356 	ae_t *pae_move = NULL;
1357 
1358 	assert(prefer != NULL);
1359 	PRTDBG(("set_prefer(0x%x, \"%s\", %d)\n", p_config_file, prefer, rank));
1360 
1361 	pbuf = append_pa(prefer);
1362 	if (find_section(p_config_file, pbuf) == NULL) {
1363 		(void) fprintf(stderr, gettext("%s: setprefer: "
1364 		    "no such profile: '%s'\n"),
1365 		    gExecName, prefer);
1366 		free(pbuf);
1367 		return (B_FALSE);
1368 	}
1369 	free(pbuf);
1370 
1371 	p_section = find_section(p_config_file, WIFI_PREFER);
1372 
1373 	if (p_section == NULL) {
1374 		plist = new_ael(PREFERENCE);
1375 		new_section(p_config_file, plist, WIFI_PREFER);
1376 		new_ae(plist, prefer);
1377 		return (B_TRUE);
1378 	} else {
1379 		plist = p_section->list;
1380 	}
1381 
1382 	pae = plist->ael_head;
1383 	pae_move = plist->ael_head;
1384 	while (pae != NULL) {
1385 		if (strcmp(prefer, pae->ae_arg) == 0) {
1386 			free(pae->ae_arg);
1387 			pae->ae_arg = NULL;
1388 			if (!position) {
1389 				plist->ael_head = pae->ae_next;
1390 				if (pae->ae_next == NULL)
1391 					plist->ael_tail = NULL;
1392 			} else {
1393 				for (i = 0; i < position - 1; i++)
1394 					pae_move = pae_move->ae_next;
1395 				pae_move->ae_next = pae->ae_next;
1396 				if (pae->ae_next == NULL)
1397 					plist->ael_tail = pae_move;
1398 			}
1399 			free(pae);
1400 			plist->ael_argc--;
1401 			break;
1402 		}
1403 		position++;
1404 		pae = pae->ae_next;
1405 	}
1406 	PRTDBG(("set_prefer: %d Profiles in prefer list\n", plist->ael_argc));
1407 	if (rank > plist->ael_argc) {
1408 		new_ae(plist, prefer);
1409 	} else if (rank <= 1) {
1410 		pae = safe_calloc(sizeof (ae_t), 1);
1411 		pae->ae_arg = safe_strdup(prefer);
1412 		pae->ae_next = plist->ael_head;
1413 		plist->ael_head = pae;
1414 		plist->ael_argc++;
1415 	} else {
1416 		pae_move = plist->ael_head;
1417 		for (i = 1; i < rank-1; i++) {
1418 			pae_move = pae_move->ae_next;
1419 		}
1420 		pae = safe_calloc(sizeof (ae_t), 1);
1421 		pae->ae_arg = safe_strdup(prefer);
1422 		pae->ae_next = pae_move->ae_next;
1423 		pae_move->ae_next = pae;
1424 		plist->ael_argc++;
1425 	}
1426 	/*
1427 	 * If number of prefer list items is larger than the MAX_PREFERENCE_NUM
1428 	 * delete those items whose No is larger than MAX_PREFERENCE_NUM.
1429 	 */
1430 	if (plist->ael_argc > MAX_PREFERENCE_NUM) {
1431 		pae = plist->ael_head;
1432 		while (pae->ae_next != plist->ael_tail)
1433 			pae = pae->ae_next;
1434 		free(plist->ael_tail->ae_arg);
1435 		plist->ael_tail->ae_arg = NULL;
1436 		free(plist->ael_tail);
1437 		plist->ael_tail = pae;
1438 		plist->ael_tail->ae_next = NULL;
1439 		plist->ael_argc--;
1440 	}
1441 	PRTDBG(("set_prefer: %d Profiles in prefer list\n", plist->ael_argc));
1442 	return (B_TRUE);
1443 }
1444 /*
1445  * add_to_history: Save the scanlist argv into history section
1446  */
1447 static void
1448 add_to_history(config_file_t *p_config_file, int argc, char **argv)
1449 {
1450 	int i = 0, j = 0, pos = 0;
1451 	aelist_t *plist = NULL;
1452 	section_t *p_section = NULL;
1453 	ae_t *pae = NULL;
1454 	ae_t *pae_m = NULL;
1455 	char item[256];
1456 	time_t cltime;
1457 
1458 	PRTDBG(("add_to_history(0x%x, %d, 0x%x)\n", p_config_file, argc, argv));
1459 	assert(p_config_file != NULL);
1460 
1461 	p_section = find_section(p_config_file, WIFI_HISTORY);
1462 
1463 	if (p_section == NULL) {
1464 		plist = new_ael(HISTORY);
1465 		new_section(p_config_file, plist, WIFI_HISTORY);
1466 	} else {
1467 		plist = p_section->list;
1468 	}
1469 
1470 	if (plist != NULL) {
1471 		for (i = 0; i < argc; i++) {
1472 			if (!strlen(argv[i]))
1473 				continue;
1474 			pos = 0;
1475 			pae = plist->ael_head;
1476 			pae_m = plist->ael_head;
1477 			/*
1478 			 * add time stamp to the history record
1479 			 */
1480 			cltime = time(&cltime);
1481 			(void) snprintf(item, sizeof (item), "%s%c%ld",
1482 			    argv[i], ',', cltime);
1483 			while (pae != NULL) {
1484 				if (strncmp(item, pae->ae_arg,
1485 				    strlen(argv[i])) == 0) {
1486 					free(pae->ae_arg);
1487 					pae->ae_arg = NULL;
1488 					if (!pos) {
1489 						plist->ael_head = pae->ae_next;
1490 						if (pae->ae_next == NULL)
1491 							plist->ael_tail = NULL;
1492 					} else {
1493 						for (j = 0; j < pos - 1; j++)
1494 							pae_m = pae_m->ae_next;
1495 						pae_m->ae_next = pae->ae_next;
1496 						if (pae->ae_next == NULL)
1497 							plist->ael_tail = pae_m;
1498 					}
1499 					free(pae);
1500 					plist->ael_argc--;
1501 					break;
1502 				}
1503 				pos++;
1504 				pae = pae->ae_next;
1505 			}
1506 			new_ae(plist, item);
1507 		}
1508 
1509 		if (plist->ael_argc > MAX_HISTORY_NUM) {
1510 			for (i = 0; i < plist->ael_argc - MAX_HISTORY_NUM;
1511 			    i++) {
1512 				pae = plist->ael_head;
1513 				free(pae->ae_arg);
1514 				plist->ael_head = pae->ae_next;
1515 				free(pae);
1516 			}
1517 			plist->ael_argc = MAX_HISTORY_NUM;
1518 		}
1519 	}
1520 }
1521 
1522 static void
1523 do_print_usage()
1524 {
1525 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1526 	    " autoconf [wait={n|forever}]\n"), gExecName);
1527 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1528 	    " connect profile [wait={n|forever}]\n"), gExecName);
1529 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1530 	    " connect essid [wait={n|forever}]\n"), gExecName);
1531 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1532 	    " disconnect\n"), gExecName);
1533 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1534 	    " getparam [parameter [...]]\n"), gExecName);
1535 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1536 	    " setparam [parameter=value [...]]\n"), gExecName);
1537 	(void) fprintf(stderr, gettext(
1538 	    "\tparameters:\n"
1539 	    "\t\tbssid\t\t - read only: 6 byte mac address of "
1540 	    "base station\n"
1541 	    "\t\tessid\t\t - name of the network, a string of up "
1542 	    "to 32 chars\n"
1543 	    "\t\tbsstype\t\t - bss(ap, infrastructure), ibss(ad-hoc)"
1544 	    " or auto\n"
1545 	    "\t\tcreateibss\t - flag to identify whether a ibss is to be\n"
1546 	    "\t\t\t\t   created when the network to connect is\n"
1547 	    "\t\t\t\t   not available, yes or no\n"
1548 	    "\t\tchannel\t\t - channel(used only when creating an ibss)\n"
1549 	    "\t\t\t\t   valid value:\n"
1550 	    "\t\t\t\t\t 802.11a: 0-99\n"
1551 	    "\t\t\t\t\t 802.11b: 1-14\n"
1552 	    "\t\t\t\t\t 802.11g: 1-14\n"
1553 	    "\t\trates\t\t - set of rates, seperated by ',' valid rates:\n"
1554 	    "\t\t\t\t   1,2,5.5,6,9,11,12,18,22,24,33,36,48 and 54\n"
1555 	    "\t\tpowermode\t - off, mps or fast\n"
1556 	    "\t\tauthmode\t - opensystem or shared_key\n"
1557 	    "\t\tencryption\t - none or wep\n"
1558 	    "\t\twepkey|1-4\t - write only:\n"
1559 	    "\t\t\t\t   5 chars or 10 hex digits for 40bit wepkey;\n"
1560 	    "\t\t\t\t   13 chars or 26 hex digits for 128bit wepkey\n"
1561 	    "\t\twepkeyindex\t - an integer within the range 1-4\n"
1562 	    "\t\tsignal\t\t - read only: signal strength from 0 to 15\n"
1563 	    "\t\tradio\t\t - on or off\n"));
1564 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1565 	    " restoredef\n"), gExecName);
1566 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1567 	    " scan\n"), gExecName);
1568 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1569 	    " showstatus\n"), gExecName);
1570 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1571 	    " setwepkey 1|2|3|4\n"), gExecName);
1572 
1573 	(void) fprintf(stderr, "\n");
1574 
1575 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1576 	    " createprofile profile parameter=value [...]\n"), gExecName);
1577 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1578 	    " deleteprofile profile1 [profile2 [...]]\n"), gExecName);
1579 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1580 	    " showprofile profile1 [profile2 [...]]\n"), gExecName);
1581 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1582 	    " setprofilewepkey profile 1|2|3|4\n"), gExecName);
1583 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1584 	    " getprofileparam profile [parameter [...]]\n"), gExecName);
1585 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1586 	    " setprofileparam profile [parameter=value [...]]\n"), gExecName);
1587 
1588 	(void) fprintf(stderr, "\n");
1589 
1590 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1591 	    " history\n"), gExecName);
1592 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1593 	    " listprefer\n"), gExecName);
1594 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1595 	    " removeprefer profile\n"), gExecName);
1596 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1597 	    " setprefer profile [n]\n"), gExecName);
1598 }
1599 
1600 /*
1601  * do_print_support_params: Query interface which cmd is supported
1602  */
1603 static boolean_t
1604 do_print_support_params(int fd)
1605 {
1606 	int i = 0, n = 0;
1607 
1608 	PRTDBG(("do_print_support_params(\"%d\")\n", fd));
1609 	assert(fd != -1);
1610 
1611 	(void) printf(gettext("\t  parameter\tproperty\n"));
1612 	for (i = 0; i < N_GS_FUNC; i++) {
1613 		gbuf->wldp_result = WL_LACK_FEATURE;
1614 		if ((do_gs_func[i].p_do_get_func != NULL) &&
1615 		    (do_gs_func[i].p_do_get_func(fd) != B_TRUE)) {
1616 				continue;
1617 		}
1618 		if (gbuf->wldp_result == WL_SUCCESS) {
1619 			(void) printf("\t%11s", do_gs_func[i].cmd);
1620 			if (do_gs_func[i].rw == RO)
1621 				(void) printf(gettext("\tread only\n"));
1622 			else
1623 				(void) printf(gettext("\tread/write\n"));
1624 			n++;
1625 		}
1626 	}
1627 
1628 	return (n ? B_TRUE : B_FALSE);
1629 }
1630 
1631 /*
1632  * check_authority: Check if command is permitted.
1633  */
1634 static boolean_t
1635 check_authority(wifi_auth_t type)
1636 {
1637 	struct passwd *pw = NULL;
1638 
1639 	PRTDBG(("check_authority()\n"));
1640 
1641 	pw = getpwuid(getuid());
1642 	if (pw == NULL)
1643 		return (B_FALSE);
1644 	if (chkauthattr(p_auth_string[type], pw->pw_name) == 0) {
1645 		if (type == AUTH_WEP)
1646 			(void) fprintf(stderr, gettext("%s: "
1647 			    "privilege '%s' is required for setting "
1648 			    "wepkey.\n"), gExecName, WIFI_WEP_AUTH);
1649 		else
1650 			(void) fprintf(stderr, gettext("%s: "
1651 			    "privilege '%s' is required.\n"),
1652 			    gExecName, WIFI_CONFIG_AUTH);
1653 		return (B_FALSE);
1654 	} else {
1655 		return (B_TRUE);
1656 	}
1657 }
1658 
1659 /*
1660  * construct the 'history' and 'scan' output format
1661  * memory allocated. need to free after the function is invoked.
1662  */
1663 static char *
1664 construct_format(uint32_t nt)
1665 {
1666 	char *format;
1667 	int len = 0, i;
1668 
1669 #define	FORMAT_LEN 256
1670 	assert((nt >= 1) && (nt <= 4));
1671 	format = safe_malloc(FORMAT_LEN);
1672 
1673 	for (i = 0; i < nt; i++)
1674 		len += snprintf(format + len, FORMAT_LEN - len, "\t");
1675 	if ((len <= 0) || (len > FORMAT_LEN - 1)) {
1676 		return ("\t\t\t\t");
1677 	}
1678 	return (format);
1679 }
1680 
1681 /*
1682  * find the essid of the named profile.
1683  * gp_config_file is golable, so the return is gloable too.
1684  */
1685 static const char *
1686 essid_of_profile(const char *profile)
1687 {
1688 	section_t *p_section = NULL;
1689 	aelist_t *plist = NULL;
1690 	ae_t *pae = NULL;
1691 	char *pbuf;
1692 
1693 	PRTDBG(("essid_of_profile: profile = %s\n", profile));
1694 	pbuf = append_pa(profile);
1695 	p_section = find_section(gp_config_file, pbuf);
1696 	free(pbuf);
1697 
1698 	if (p_section == NULL) {
1699 		return (NULL);
1700 	} else {
1701 		plist = p_section->list;
1702 	}
1703 	pae = plist->ael_head;
1704 	while (pae != NULL) {
1705 		if (strncmp(pae->ae_arg, "essid=", strlen("essid=")) == 0) {
1706 			PRTDBG(("essid_of_profile: essid = %s\n",
1707 			    pae->ae_arg));
1708 			return (get_value(pae->ae_arg));
1709 		}
1710 		pae = pae->ae_next;
1711 	}
1712 	return (NULL);
1713 }
1714 
1715 /*
1716  * If we don't know which profile is our favorate in 'autoconf',
1717  * we select the wifi network based on the following heuristic
1718  * 1. the network without wep.
1719  * 2. the network with the strongst signal.
1720  * 3. the network with the faster speed(not implemented since signal affects
1721  * the speed in some degree).
1722  */
1723 static void
1724 heuristic_load(int fd, uint32_t ess_num, wl_ess_conf_t **p_ess_conf)
1725 {
1726 	int i = 0;
1727 	char *flag = NULL;
1728 	int have_nowep_wlan = 0;
1729 	wl_rssi_t maxsignal = 0;
1730 	char essid[34];
1731 	int timeout = LOADPROFILE_TIMEOUT;
1732 
1733 	PRTDBG(("heuristic_load: enter\n"));
1734 	(void) call_ioctl(fd, WLAN_COMMAND, WL_LOAD_DEFAULTS, 0);
1735 	flag = calloc(sizeof (char), ess_num);
1736 	for (i = 0; i < ess_num; i++) { /* extract none-wep network */
1737 		if (p_ess_conf[i]->wl_ess_conf_wepenabled == B_FALSE) {
1738 			flag[i] = 1;
1739 			have_nowep_wlan = 1;
1740 		}
1741 	}
1742 	/*
1743 	 * if all the wlans are weped, we select the one with strongest signal
1744 	 * in all of them, otherwise we just select in the none weped ones.
1745 	 */
1746 	if (!have_nowep_wlan)
1747 		(void) memset(flag, 1, ess_num);
1748 	for (i = 0; i < ess_num; i++) { /* extract the strongest signal ones */
1749 		if (flag[i] == 1) {
1750 			if (p_ess_conf[i]->wl_ess_conf_sl > maxsignal) {
1751 				maxsignal = p_ess_conf[i]->wl_ess_conf_sl;
1752 				(void) memset(flag, 0, i);
1753 			} else if (p_ess_conf[i]->wl_ess_conf_sl == maxsignal)
1754 				continue;
1755 			else
1756 				flag[i] = 0;
1757 		}
1758 	}
1759 	for (i = 0; i < ess_num; i++) {
1760 		if (flag[i] == 1)
1761 			break;
1762 	}
1763 	free(flag);
1764 	PRTDBG(("heuristic_load: %s is selected\n",
1765 	    p_ess_conf[i]->wl_ess_conf_essid.wl_essid_essid));
1766 	/* select one in all the networks which meet the preceding stardands */
1767 	if (i == ess_num)
1768 		(void) do_set_essid(fd, "");
1769 	else
1770 		(void) do_set_essid(fd,
1771 		    p_ess_conf[i]->wl_ess_conf_essid.wl_essid_essid);
1772 
1773 	if ((ess_num == 0) || (do_get_essid(fd) == B_FALSE)) {
1774 		(void) fprintf(stderr, gettext("%s: autoconf:"
1775 		    " failed to connect to any essid\n"),
1776 		    gExecName);
1777 		exit(WIFI_MINOR_ERR);
1778 	}
1779 	(void) strlcpy(essid, ((wl_essid_t *)(gbuf->wldp_buf))->wl_essid_essid,
1780 	    sizeof (essid));
1781 	(void) printf(gettext("%s: autoconf: essid '%s' is selected%s\n"),
1782 	    gExecName, essid,
1783 	    have_nowep_wlan ? "" : ": this is a WEPed "
1784 	    "access point");
1785 
1786 	if (!have_nowep_wlan)
1787 		exit(WIFI_FATAL_ERR);
1788 
1789 	while (timeout > 0) {
1790 		if ((do_get_linkstatus(fd) == B_TRUE) &&
1791 		    (*(wl_linkstatus_t *)(gbuf->wldp_buf) == WL_CONNECTED)) {
1792 			(void) printf(gettext("%s: connecting to "
1793 			    "essid '%s'\n"), gExecName, essid);
1794 			return;
1795 		}
1796 		(void) sleep(1);
1797 		timeout--;
1798 	}
1799 	(void) fprintf(stderr, gettext("%s: failed to connect to "
1800 	    "essid '%s'\n"), gExecName, essid);
1801 	exit(WIFI_FATAL_ERR);
1802 }
1803 
1804 /*
1805  * Called in autoconf and startconf to find which 'profile' is selected.
1806  * The process is: check profile names in the prefer list item by item,
1807  * if the essid of the profile is in the scan list, then it is the wanted.
1808  * readonly: 1 for startconf
1809  *           0 for autoconf
1810  * for autoconf, the scan result will be recorded in the history list.
1811  */
1812 static char *
1813 select_profile(int fd, int readonly, int timeout)
1814 {
1815 	uint32_t ess_num = 0;
1816 	int nprefer = 1;
1817 	char **ess_argv;
1818 	char **hisess_argv;
1819 	wl_ess_conf_t **p_ess_conf;
1820 	section_t *p_section = NULL;
1821 	aelist_t *plist = NULL;
1822 	ae_t *pae = NULL;
1823 	int i;
1824 	const char *parg;
1825 	char *selected = NULL;
1826 	boolean_t flag = B_FALSE;
1827 
1828 	if ((call_ioctl(fd, WLAN_COMMAND, WL_SCAN, 0) == B_FALSE) ||
1829 	    (do_get_wlanlist(fd) == B_FALSE)) {
1830 		(void) fprintf(stderr, gettext("%s: "
1831 		    "autoconf : failed to scan\n"), gExecName);
1832 		exit(WIFI_FATAL_ERR);
1833 	}
1834 	ess_num = ((wl_ess_list_t *)(gbuf->wldp_buf))->wl_ess_list_num;
1835 	ess_argv = safe_calloc(sizeof (char *), ess_num);
1836 	hisess_argv = safe_calloc(sizeof (char *), ess_num);
1837 	p_ess_conf = safe_calloc(sizeof (wl_ess_list_t *), ess_num);
1838 	for (i = 0; i < ess_num; i++) {
1839 		p_ess_conf[i] = ((wl_ess_list_t *)gbuf->wldp_buf)
1840 		    ->wl_ess_list_ess + i;
1841 		ess_argv[i] = safe_malloc(MAX_SCANBUF_LEN);
1842 		if (readonly == 0) {
1843 			hisess_argv[i] = safe_malloc(MAX_SCANBUF_LEN);
1844 			(void) snprintf(hisess_argv[i], MAX_SCANBUF_LEN,
1845 			    "%s%c%02x:%02x:%02x:%02x:%02x:%02x%c%s",
1846 			    p_ess_conf[i]->wl_ess_conf_essid.wl_essid_essid,
1847 			    ',',
1848 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[0]),
1849 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[1]),
1850 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[2]),
1851 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[3]),
1852 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[4]),
1853 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[5]), ',',
1854 			    (p_ess_conf[i]->wl_ess_conf_wepenabled == B_TRUE
1855 			    ?  "wep":"none"));
1856 		}
1857 		(void) snprintf(ess_argv[i], MAX_SCANBUF_LEN, "%s",
1858 		    p_ess_conf[i]->wl_ess_conf_essid.wl_essid_essid);
1859 	}
1860 	if (readonly == 0) {
1861 		add_to_history(gp_config_file, ess_num, hisess_argv);
1862 		for (i = 0; i < ess_num; i++) {
1863 			free(hisess_argv[i]);
1864 		}
1865 		free(hisess_argv);
1866 	}
1867 
1868 	p_section = find_section(gp_config_file, WIFI_PREFER);
1869 	if (p_section == NULL) {
1870 		if (ess_num > 0) {
1871 			heuristic_load(fd, ess_num, p_ess_conf);
1872 			exit(WIFI_EXIT_DEF);
1873 		}
1874 		goto done;
1875 	}
1876 	plist = p_section->list;
1877 	assert(plist != NULL);
1878 	if (plist != NULL) {
1879 		nprefer = plist->ael_argc;
1880 		if (nprefer == 0) {
1881 			if (ess_num > 0) {
1882 				heuristic_load(fd, ess_num, p_ess_conf);
1883 				exit(WIFI_EXIT_DEF);
1884 			}
1885 			goto done;
1886 		}
1887 	}
1888 	pae = plist->ael_head;
1889 	while ((pae != NULL) && (flag != B_TRUE)) {
1890 		parg = essid_of_profile(pae->ae_arg);
1891 		if (parg != NULL) {
1892 			for (i = 0; i < ess_num; i++) {
1893 				if (strcmp(parg, ess_argv[i]) == 0) {
1894 					selected = pae->ae_arg;
1895 					flag = B_TRUE;
1896 					break;
1897 				}
1898 			}
1899 		}
1900 		pae = pae->ae_next;
1901 	}
1902 done:
1903 	if ((selected == NULL) && (timeout == 0)) {
1904 		heuristic_load(fd, ess_num, p_ess_conf);
1905 	}
1906 	for (i = 0; i < ess_num; i++) {
1907 		free(ess_argv[i]);
1908 	}
1909 	free(ess_argv);
1910 	free(p_ess_conf);
1911 	return (selected);
1912 }
1913 
1914 static boolean_t
1915 is_waittime_valid(char *pbuf)
1916 {
1917 	int i;
1918 
1919 	i = atoi(pbuf);
1920 	if (i == -1)
1921 		return (B_TRUE);
1922 	for (i = 0; i < strlen(pbuf); i++) {
1923 		if (isdigit(pbuf[i]) == 0) {
1924 			return (B_FALSE);
1925 		}
1926 	}
1927 	return (B_TRUE);
1928 }
1929 /*
1930  * do_autoconf: First scan the wlanlist, and select one essid from scan result
1931  * by the order in {preferrence} list. If no match, then heuristic_load;
1932  */
1933 /*ARGSUSED*/
1934 static boolean_t
1935 do_autoconf(int fd, int argc, char **argv)
1936 {
1937 	const char *selected = NULL;
1938 	int timeout = LOADPROFILE_TIMEOUT, forever = 0, len = 0;
1939 	char *pequal, *param;
1940 	char **ld_argv = NULL;
1941 	boolean_t ret = B_TRUE;
1942 
1943 	PRTDBG(("do_autoconf(%d, 0x%x)\n", argc, argv));
1944 	assert(fd > 0);
1945 	if (argc > 0) {
1946 		param = safe_strdup(argv[0]);
1947 		pequal = strchr(param, '=');
1948 		if (pequal != NULL) {
1949 			*pequal++ = '\0';
1950 		} else {
1951 			do_print_usage();
1952 			exit(WIFI_IMPROPER_USE);
1953 		}
1954 		if (strcmp(param, "wait") != 0) {
1955 			do_print_usage();
1956 			exit(WIFI_IMPROPER_USE);
1957 		} else {
1958 			if (strcmp(pequal, "forever") == 0) {
1959 				forever = 1;
1960 			} else {
1961 				if (is_waittime_valid(pequal) == B_FALSE) {
1962 					(void) fprintf(stderr, gettext("%s: "
1963 					    "invalid value %s for 'wait'\n"),
1964 					    gExecName, pequal);
1965 					exit(WIFI_FATAL_ERR);
1966 				}
1967 				if (sscanf(pequal, "%d", &timeout) != 1) {
1968 					do_print_usage();
1969 					exit(WIFI_IMPROPER_USE);
1970 				}
1971 				if (timeout == -1) {
1972 					forever = 1;
1973 				}
1974 			}
1975 		}
1976 		free(param);
1977 		if (argc > 1) {
1978 			(void) fprintf(stderr, gettext("%s: trailing "
1979 			    "useless tokens after '%s'\n"),
1980 			    gExecName, argv[0]);
1981 		}
1982 	}
1983 
1984 	while ((forever == 1) || (timeout > 0)) {
1985 		timeout--;
1986 		selected = select_profile(fd, 0, max(timeout, forever));
1987 		if (selected != NULL)
1988 			break;
1989 		(void) sleep(1);
1990 	}
1991 	if (selected == NULL) {
1992 		return (B_TRUE);
1993 	}
1994 	(void) printf(gettext("%s: autoconf: profile [%s]"
1995 	    " is selected\n"), gExecName, selected);
1996 	ld_argv = safe_calloc(sizeof (char *), argc+1);
1997 	ld_argv[0] = safe_strdup(selected);
1998 	if (argc > 0) {
1999 		len = max(strlen(argv[0]), strlen("wait=forever"));
2000 		ld_argv[1] = safe_malloc(len);
2001 		safe_snprintf(ld_argv[1], len + 1, forever == 1 ?
2002 		    "wait=forever" : "wait=%d", timeout);
2003 	}
2004 	ret = do_loadpf(fd, argc+1, ld_argv);
2005 	free(ld_argv[0]);
2006 	if (argc > 0) {
2007 		free(ld_argv[1]);
2008 	}
2009 	free(ld_argv);
2010 	return (ret);
2011 }
2012 
2013 /*
2014  * do_startconf: almost the same as the do_autoconf, except that doesn't
2015  * write file.
2016  */
2017 /*ARGSUSED*/
2018 static boolean_t
2019 do_startconf(int fd, int argc, char **argv)
2020 {
2021 	int i = 0, ael_num = 0;
2022 	section_t *p_section = NULL;
2023 	section_t *p_wep_section = NULL;
2024 	aelist_t *plist = NULL;
2025 	const char *selected = NULL;
2026 	ae_t *pae = NULL;
2027 	char *pbuf = NULL;
2028 	char **argvnew = NULL;
2029 
2030 	PRTDBG(("do_startconf(%d, 0x%x)\n", argc, argv));
2031 	assert(fd > 0);
2032 
2033 	selected = select_profile(fd, 1, 0);
2034 	if (selected == NULL) {
2035 		return (B_TRUE);
2036 	}
2037 
2038 	(void) call_ioctl(fd, WLAN_COMMAND, WL_LOAD_DEFAULTS, 0);
2039 
2040 	pbuf = append_pa(selected);
2041 	p_wep_section = find_section(gp_wepkey_file, pbuf);
2042 	p_section = find_section(gp_config_file, pbuf);
2043 	free(pbuf);
2044 
2045 	if (p_wep_section != NULL) {
2046 		plist = p_wep_section->list;
2047 		pae = plist->ael_head;
2048 		while (pae != NULL) {
2049 			if (pae->ae_arg != NULL)
2050 				(void) do_set_wepkey(fd, pae->ae_arg);
2051 			pae = pae->ae_next;
2052 		}
2053 	}
2054 
2055 	if (p_section != NULL) {
2056 		plist = p_section->list;
2057 		if (plist->ael_argc == 0) {
2058 			return (B_TRUE);
2059 		}
2060 		argvnew = aeltoargv(plist, &ael_num);
2061 		(void) do_set(fd, ael_num, argvnew);
2062 
2063 		for (i = 0; i < ael_num; i++)
2064 			free(argvnew[i]);
2065 		free(argvnew);
2066 	}
2067 	return (B_TRUE);
2068 }
2069 
2070 static char *
2071 find_active_profile(int fd)
2072 {
2073 	section_t *p_section = NULL, *activep_section = NULL;
2074 	aelist_t *plist = NULL;
2075 	ae_t *pae = NULL;
2076 	const char *pessid = NULL, *pbssid = NULL;
2077 	char essid[34], bssid[32];
2078 	const char *activeprofile = NULL;
2079 
2080 	PRTDBG(("find_active_profile: %d\n", fd));
2081 	if (do_get_essid(fd) == B_FALSE) {
2082 		return (NULL);
2083 	}
2084 	(void) strlcpy(essid, ((wl_essid_t *)(gbuf->wldp_buf))->wl_essid_essid,
2085 	    sizeof (essid));
2086 	if (do_get_bssid(fd) == B_FALSE) {
2087 		return (NULL);
2088 	}
2089 	safe_snprintf(bssid, sizeof (bssid), "%02x:%02x:%02x:%02x:%02x:%02x",
2090 	    ((uint8_t *)gbuf->wldp_buf)[0],
2091 	    ((uint8_t *)gbuf->wldp_buf)[1],
2092 	    ((uint8_t *)gbuf->wldp_buf)[2],
2093 	    ((uint8_t *)gbuf->wldp_buf)[3],
2094 	    ((uint8_t *)gbuf->wldp_buf)[4],
2095 	    ((uint8_t *)gbuf->wldp_buf)[5]);
2096 	activep_section = find_section(gp_config_file, WIFI_ACTIVEP);
2097 	if (activep_section == NULL)
2098 		return (NULL);
2099 	activeprofile = get_value(activep_section->list->
2100 	    ael_head->ae_arg);
2101 	if (activeprofile == NULL)
2102 		return (NULL);
2103 	p_section = gp_config_file->section_head;
2104 	while (p_section != NULL) {
2105 		if (((plist = p_section->list) != NULL) &&
2106 		    (plist->type == PROFILE) &&
2107 		    (strcmp(p_section->section_id, activeprofile) == 0)) {
2108 			pae = plist->ael_head;
2109 			while (pae != NULL) {
2110 				if (strncmp(pae->ae_arg, "essid=",
2111 				    strlen("essid=")) == 0) {
2112 					pessid = get_value(pae->ae_arg);
2113 				}
2114 				if (strncmp(pae->ae_arg, "bssid=",
2115 				    strlen("bssid=")) == 0) {
2116 					pbssid = get_value(pae->ae_arg);
2117 				}
2118 				pae = pae->ae_next;
2119 			}
2120 			if (pessid && pbssid &&
2121 			    (strcmp(essid, pessid) == 0) &&
2122 			    (strcmp(bssid, pbssid) == 0)) {
2123 				return (p_section->section_id);
2124 			}
2125 		}
2126 		p_section = p_section->section_next;
2127 	}
2128 	return (NULL);
2129 }
2130 
2131 static void
2132 record_active_profile(char *pname, int action)
2133 {
2134 	section_t *p_section = NULL;
2135 	aelist_t *plist = NULL;
2136 	char pbuf[256];
2137 
2138 	p_section = find_section(gp_config_file, WIFI_ACTIVEP);
2139 	if (p_section == NULL) {
2140 		plist = new_ael(ACTIVEP);
2141 		new_section(gp_config_file, plist, WIFI_ACTIVEP);
2142 	} else {
2143 		plist = p_section->list;
2144 	}
2145 
2146 	if (action == RECORD_ADD) {
2147 		assert(pname != NULL);
2148 		safe_snprintf(pbuf, sizeof (pbuf), "activep=%s", pname);
2149 		update_aelist(plist, pbuf);
2150 	} else if (action == RECORD_DEL) {
2151 		assert(pname == NULL);
2152 		update_aelist(plist, "activep= ");
2153 	}
2154 }
2155 
2156 /*
2157  * do_loadpf: load a profile, set related parameters both in wifi
2158  * and in wifiwepkey, if network name is not exist in the
2159  * configration files, then we clean all parameters and set essid only
2160  */
2161 static boolean_t
2162 do_loadpf(int fd, int argc, char ** argv)
2163 {
2164 	int i = 0, ael_num = 0;
2165 	int timeout = LOADPROFILE_TIMEOUT, forever = 0;
2166 	section_t *p_section = NULL;
2167 	section_t *p_wep_section = NULL;
2168 	aelist_t *plist = NULL;
2169 	ae_t *pae = NULL;
2170 	char *pbuf = NULL;
2171 	char **argvnew = NULL;
2172 	char *connect;
2173 	char *pequal, *param;
2174 
2175 	PRTDBG(("do_loadpf(%d, %x)\n", argc, argv));
2176 	assert(fd > 0);
2177 	if (argc == 0) {
2178 		(void) fprintf(stderr, gettext("%s: connect: "
2179 		    "profile name missing\n"), gExecName);
2180 		return (B_FALSE);
2181 	}
2182 	if (argc > 1) {
2183 		param = safe_strdup(argv[1]);
2184 		pequal = strchr(param, '=');
2185 		if (pequal != NULL) {
2186 			*pequal++ = '\0';
2187 		} else {
2188 			do_print_usage();
2189 			exit(WIFI_IMPROPER_USE);
2190 		}
2191 		if (strcmp(param, "wait") != 0) {
2192 			do_print_usage();
2193 			exit(WIFI_IMPROPER_USE);
2194 		} else {
2195 			if (strcmp(pequal, "forever") == 0) {
2196 				forever = 1;
2197 			} else {
2198 				if (is_waittime_valid(pequal) == B_FALSE) {
2199 					(void) fprintf(stderr, gettext("%s: "
2200 					    "invalid value %s for 'wait'\n"),
2201 					    gExecName, pequal);
2202 					exit(WIFI_FATAL_ERR);
2203 				}
2204 				if (sscanf(pequal, "%d", &timeout) != 1) {
2205 					do_print_usage();
2206 					exit(WIFI_IMPROPER_USE);
2207 				}
2208 				if (timeout == -1) {
2209 					forever = 1;
2210 				}
2211 			}
2212 		}
2213 		free(param);
2214 		if (argc > 2) {
2215 			(void) fprintf(stderr, gettext("%s: trailing "
2216 			    "useless tokens after '%s'\n"),
2217 			    gExecName, argv[1]);
2218 		}
2219 	}
2220 	(void) call_ioctl(fd, WLAN_COMMAND, WL_LOAD_DEFAULTS, 0);
2221 
2222 	pbuf = append_pa(argv[0]);
2223 	p_wep_section = find_section(gp_wepkey_file, pbuf);
2224 	p_section = find_section(gp_config_file, pbuf);
2225 
2226 	if (p_wep_section != NULL) {
2227 		(void) set_prefer(gp_config_file, argv[0], 1);
2228 		plist = p_wep_section->list;
2229 		pae = plist->ael_head;
2230 		while (pae != NULL) {
2231 			if (pae->ae_arg != NULL) {
2232 				(void) do_set_wepkey(fd, pae->ae_arg);
2233 			}
2234 			pae = pae->ae_next;
2235 		}
2236 	}
2237 
2238 	if (p_section != NULL) {
2239 		connect = "profile";
2240 
2241 		(void) set_prefer(gp_config_file, argv[0], 1);
2242 		plist = p_section->list;
2243 		if (plist->ael_argc == 0) {
2244 			free(pbuf);
2245 			return (B_TRUE);
2246 		}
2247 		argvnew = aeltoargv(plist, &ael_num);
2248 		/*
2249 		 * if there is no 'essid' item in argvnew, the profile
2250 		 * name(argv[0]) is treated as essid.
2251 		 */
2252 		for (i = 0; i < ael_num; i++) {
2253 			if (strncmp(argvnew[i], "essid=", strlen("essid="))
2254 			    == 0)
2255 				break;
2256 		}
2257 		if (i == ael_num)
2258 			(void) do_set_essid(fd, argv[0]);
2259 
2260 		(void) do_set(fd, ael_num, argvnew);
2261 
2262 		for (i = 0; i < ael_num; i++)
2263 			free(argvnew[i]);
2264 		free(argvnew);
2265 
2266 		/*
2267 		 * set flag in {active_profile} so that showprofile knows
2268 		 * which profile is active when more than one profiles are
2269 		 * created for the same WLAN.
2270 		 */
2271 		record_active_profile(pbuf, RECORD_ADD);
2272 	} else {
2273 		(void) do_set_essid(fd, argv[0]);
2274 		connect = "essid";
2275 	}
2276 
2277 	while ((forever == 1) || (timeout > 0)) {
2278 		if ((do_get_linkstatus(fd) == B_TRUE) &&
2279 		    (*(wl_linkstatus_t *)(gbuf->wldp_buf) == WL_CONNECTED)) {
2280 			section_t *p_section = NULL;
2281 			aelist_t *plist = NULL;
2282 			char bssid[32];
2283 			/* record bssid in the profile */
2284 			if (do_get_bssid(fd) == B_FALSE) {
2285 				free(pbuf);
2286 				return (B_TRUE);
2287 			}
2288 			safe_snprintf(bssid, sizeof (bssid),
2289 			    "bssid=%02x:%02x:%02x:%02x:%02x:%02x",
2290 			    ((uint8_t *)gbuf->wldp_buf)[0],
2291 			    ((uint8_t *)gbuf->wldp_buf)[1],
2292 			    ((uint8_t *)gbuf->wldp_buf)[2],
2293 			    ((uint8_t *)gbuf->wldp_buf)[3],
2294 			    ((uint8_t *)gbuf->wldp_buf)[4],
2295 			    ((uint8_t *)gbuf->wldp_buf)[5]);
2296 
2297 			p_section = find_section(gp_config_file, pbuf);
2298 			if (p_section != NULL) {
2299 				plist = p_section->list;
2300 				update_aelist(plist, bssid);
2301 			}
2302 			free(pbuf);
2303 			(void) printf(gettext("%s: connecting to "
2304 			    "%s '%s'\n"), gExecName, connect, argv[0]);
2305 			return (B_TRUE);
2306 		}
2307 		(void) sleep(1);
2308 		timeout--;
2309 		PRTDBG(("connect counting:......%d\n", timeout));
2310 	}
2311 	(void) fprintf(stderr, gettext("%s: failed to connect to "
2312 	    "%s '%s'\n"), gExecName, connect, argv[0]);
2313 	free(pbuf);
2314 	return (B_FALSE);
2315 }
2316 
2317 /*
2318  * if wepkey is set in the profile, display wepkey|n=*****
2319  * when showprofile and getprofilewepkey.
2320  * if wepkeyn is NULL, all the wepkeys will be display,
2321  * otherwise, just display the matching one.
2322  */
2323 static void
2324 print_wepkey_info(const char *id, const char *wepkeyn)
2325 {
2326 	char *pequal, *param;
2327 	section_t *p_section = NULL;
2328 	aelist_t *plist = NULL;
2329 	ae_t *pae = NULL;
2330 
2331 	p_section = find_section(gp_wepkey_file, id);
2332 	if (p_section != NULL) {
2333 		plist = p_section->list;
2334 		pae = plist->ael_head;
2335 		while (pae != NULL) {
2336 			if (pae->ae_arg != NULL) {
2337 				param = safe_strdup(pae->ae_arg);
2338 				pequal = strchr(param, '=');
2339 				if (pequal == NULL)
2340 					return;
2341 				*pequal = '\0';
2342 				if (wepkeyn != NULL) {
2343 					if (strcmp(wepkeyn, param) == 0)
2344 						(void) printf("\t%s=*****\n",
2345 						    param);
2346 					free(param);
2347 					return;
2348 				} else {
2349 					(void) printf("\t%s=*****\n", param);
2350 					free(param);
2351 				}
2352 			}
2353 			pae = pae->ae_next;
2354 		}
2355 	}
2356 }
2357 
2358 /*
2359  * do_printpf: print each parameters of the profile, if no network name
2360  * assigned, then print all profile saved in configration file.
2361  */
2362 /*ARGSUSED*/
2363 static boolean_t
2364 do_printpf(int fd, int argc, char ** argv)
2365 {
2366 	section_t *p_section = NULL;
2367 	aelist_t *plist = NULL;
2368 	ae_t *pae = NULL;
2369 	char *pbuf = NULL;
2370 	int i;
2371 
2372 	PRTDBG(("do_printpf(%d, %x)\n", argc, argv));
2373 
2374 	/*
2375 	 * if no profile name is inputted, all the profiles will be displayed.
2376 	 */
2377 	if (argc == 0) {
2378 		p_section = gp_config_file->section_head;
2379 		while (p_section != NULL) {
2380 			plist = p_section->list;
2381 			if (plist->type == PROFILE) {
2382 				(void) printf("%s\n", p_section->section_id);
2383 				pae = plist->ael_head;
2384 				while (pae != NULL) {
2385 					if (pae->ae_arg != NULL) {
2386 						(void) printf("\t%s\n",
2387 						    pae->ae_arg);
2388 					}
2389 					pae = pae->ae_next;
2390 				}
2391 				/*
2392 				 * identify whether wepkey is set
2393 				 * in the profile
2394 				 */
2395 				print_wepkey_info(p_section->section_id, NULL);
2396 			}
2397 			p_section = p_section->section_next;
2398 		}
2399 		return (B_TRUE);
2400 	}
2401 
2402 	for (i = 0; i < argc; i++) {
2403 		pbuf =	append_pa(argv[i]);
2404 		p_section = find_section(gp_config_file, pbuf);
2405 		free(pbuf);
2406 		if (p_section != NULL)	{
2407 			(void) printf("%s\n", p_section->section_id);
2408 			plist = p_section->list;
2409 			if (plist != NULL) {
2410 				pae = plist->ael_head;
2411 				while (pae != NULL) {
2412 					if (pae->ae_arg != NULL) {
2413 						(void) printf("\t%s\n",
2414 						    pae->ae_arg);
2415 					}
2416 					pae = pae->ae_next;
2417 				}
2418 				/*
2419 				 * identify whether wepkey is set
2420 				 * in the profile
2421 				 */
2422 				print_wepkey_info(p_section->section_id, NULL);
2423 			}
2424 		} else {
2425 			(void) fprintf(stderr,
2426 			    gettext("%s: showprofile : "
2427 			    "no such profile: '%s'\n"),
2428 			    gExecName, argv[i]);
2429 			return (B_FALSE);
2430 		}
2431 	}
2432 	return (B_TRUE);
2433 }
2434 /*
2435  * find_ae: Find an ae by its contents, return its pointer.
2436  */
2437 static ae_t *
2438 find_ae(aelist_t *plist, const char *arg)
2439 {
2440 	char *param = NULL;
2441 	char *pnext = NULL;
2442 	ae_t *pae = NULL;
2443 
2444 	if ((arg == NULL) || (plist == NULL)) {
2445 		PRTDBG(("find_ae: arg= NULL or plist=NULL\n"));
2446 		return (NULL);
2447 	}
2448 	PRTDBG(("find_ae(0x%x, \"%s\")\n", plist, arg));
2449 	param = safe_strdup(arg);
2450 	pnext = strchr(param, '=');
2451 	if (pnext != NULL) {
2452 		*pnext = '\0';
2453 	} else {
2454 		PRTDBG(("find_ae: param = \"%s\"\n", param));
2455 		free(param);
2456 		return (NULL);
2457 	}
2458 
2459 	pae = plist->ael_head;
2460 	while (pae != NULL) {
2461 		if ((pae->ae_arg != NULL) &&
2462 		    (strncmp(pae->ae_arg, param, strlen(param)) == 0)) {
2463 			PRTDBG(("find_ae: param = \"%s\"\n", param));
2464 			free(param);
2465 			return (pae);
2466 		}
2467 		pae = pae->ae_next;
2468 	}
2469 	free(param);
2470 	return (NULL);
2471 }
2472 
2473 /*
2474  * update_aelist: Update an aelist by arg, for example:
2475  * there are an item with content"essid=ap7-2",
2476  * update_aelist(0x..., "essid=myssid2") will update it as "essid=myssid2"
2477  */
2478 static void
2479 update_aelist(aelist_t *plist, const char *arg)
2480 {
2481 	ae_t *pae = NULL;
2482 
2483 	assert((arg != NULL)&&(plist != NULL));
2484 	PRTDBG(("update_aelist(0x%x, \"%s\")\n", plist, arg));
2485 	pae = find_ae(plist, arg);
2486 	if (pae == NULL) {
2487 		new_ae(plist, arg);
2488 	} else {
2489 		free(pae->ae_arg);
2490 		pae->ae_arg = safe_strdup(arg);
2491 	}
2492 }
2493 
2494 /*
2495  * do_deletepf: delete a profile in configration files.
2496  */
2497 /*ARGSUSED*/
2498 static boolean_t
2499 do_deletepf(int fd, int argc, char **argv)
2500 {
2501 	int i = 0;
2502 	char *section_id;
2503 	char *prefer;
2504 	section_t *p_section = NULL, *p_sectionbak = NULL;
2505 	aelist_t *plist = NULL;
2506 
2507 	PRTDBG(("do_deletepf(%d, \"%s\")\n", argc, argv));
2508 	if (argc <= 0) {
2509 		do_print_usage();
2510 		exit(WIFI_IMPROPER_USE);
2511 	}
2512 
2513 	/*
2514 	 * if a "all" is inputted, all the profiles will be deleted.
2515 	 */
2516 	if (strcasecmp(argv[0], "all") == 0) {
2517 		p_section = gp_config_file->section_head;
2518 		while ((p_section != NULL) &&
2519 		    ((plist = p_section->list) != NULL)) {
2520 			if (plist->type == PROFILE) {
2521 				p_sectionbak = p_section->section_next;
2522 				section_id = safe_strdup(p_section->section_id);
2523 				(void) del_section(gp_config_file, section_id);
2524 				(void) del_section(gp_wepkey_file, section_id);
2525 				/*
2526 				 * remove the '[]' of the [section_id]
2527 				 */
2528 				prefer = section_id + 1;
2529 				*(prefer + strlen(section_id) - 2) = '\0';
2530 				(void) del_prefer(gp_config_file, prefer,
2531 				    B_FALSE);
2532 				free(section_id);
2533 				p_section = p_sectionbak;
2534 					continue;
2535 			}
2536 			p_section = p_section->section_next;
2537 		}
2538 		return (B_TRUE);
2539 	}
2540 	if (gp_config_file != NULL) {
2541 		for (i = 0; i < argc; i++) {
2542 			section_id = append_pa(argv[i]);
2543 			if (del_section(gp_config_file, section_id)
2544 			    == B_FALSE) {
2545 				if (del_section(gp_wepkey_file, section_id)
2546 				    == B_TRUE) {
2547 					(void) del_prefer(gp_config_file,
2548 					    argv[i], B_FALSE);
2549 					free(section_id);
2550 					return (B_TRUE);
2551 				} else {
2552 					(void) fprintf(stderr,
2553 					    gettext("%s: deleteprofile"
2554 					    ": no such profile: '%s'\n"),
2555 					    gExecName, argv[i]);
2556 					free(section_id);
2557 					return (B_FALSE);
2558 				}
2559 			}
2560 			(void) del_prefer(gp_config_file, argv[i], B_FALSE);
2561 			(void) del_section(gp_wepkey_file, section_id);
2562 			free(section_id);
2563 		}
2564 	}
2565 	return (B_TRUE);
2566 }
2567 
2568 /*
2569  * do_history: Print the list in {history} section.
2570  */
2571 /*ARGSUSED*/
2572 static boolean_t
2573 do_history(int fd, int argc, char **argv)
2574 {
2575 	section_t *p_section = NULL;
2576 	aelist_t *plist = NULL;
2577 	ae_t *pae = NULL;
2578 	char *param, *param_bak, *pcomma;
2579 	uint32_t maxessidlen = 0, ulen;
2580 	char format[256], *ntstr;
2581 	uint32_t nt = 0, cnt = 0;
2582 	int len;
2583 	time_t cltime;
2584 
2585 	PRTDBG(("do_history(%d, 0x%x)\n", argc, argv));
2586 	if (argc > 0) {
2587 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
2588 		    "after 'history'\n"), gExecName);
2589 	}
2590 	p_section = find_section(gp_config_file, WIFI_HISTORY);
2591 	if (p_section == NULL) {
2592 		PRTDBG(("no history section\n"));
2593 		return (B_FALSE);
2594 	}
2595 	plist = p_section->list;
2596 
2597 	/*
2598 	 * If history section is empty, directly return.
2599 	 */
2600 	if (plist == NULL)
2601 		return (B_TRUE);
2602 	/*
2603 	 * construct the output format in terms of the
2604 	 * maxmium essid length
2605 	 */
2606 	pae = NULL;
2607 	pae = plist->ael_head;
2608 	while (pae != NULL) {
2609 		if (pae->ae_arg != NULL) {
2610 			param = safe_strdup(pae->ae_arg);
2611 			pcomma = strchr(param, ',');
2612 			if (pcomma == NULL) {
2613 				(void) fprintf(stderr,
2614 				    gettext("%s: history : "
2615 				    "data format error\n"),
2616 				    gExecName);
2617 				free(param);
2618 				return (B_FALSE);
2619 			}
2620 			*pcomma = '\0';
2621 			ulen = strlen(param);
2622 			maxessidlen = (maxessidlen > ulen
2623 			    ? maxessidlen:ulen);
2624 			free(param);
2625 		}
2626 		pae = pae->ae_next;
2627 	}
2628 	if ((nt = (maxessidlen / 8 + 1)) > 4)
2629 		nt = 4;
2630 	len = snprintf(format, sizeof (format), gettext("essid"));
2631 	ntstr = construct_format(nt);
2632 	assert((ntstr != NULL) && (strlen(ntstr) <= 4));
2633 	len += snprintf(format + len, sizeof (format) - len, "%s", ntstr);
2634 	len += snprintf(format + len, sizeof (format) - len,
2635 	    gettext("bssid\t\t  encryption\tlast seen\n"));
2636 
2637 	if ((len <= 0) || (len > sizeof (format) - 1)) {
2638 		(void) printf(gettext("essid\t\t\t\tbssid\t\t  encryption"
2639 		    "\tlast seen\n"));
2640 	} else {
2641 		(void) printf("%s", format);
2642 	}
2643 	/*
2644 	 * output the contents of the history section.
2645 	 */
2646 	pae = plist->ael_head;
2647 	while (pae != NULL) {
2648 		if (pae->ae_arg != NULL) {
2649 			param = safe_strdup(pae->ae_arg);
2650 			param_bak = param;
2651 			if ((pcomma = strchr(param, ',')) != NULL) {
2652 				*pcomma = '\0';
2653 				cnt = nt - (min((strlen(param)/8 + 1), 4) - 1);
2654 				ntstr = construct_format(cnt);
2655 				assert(ntstr != NULL);
2656 				/* display essid */
2657 				(void) printf("%s%s", param, ntstr);
2658 				free(ntstr);
2659 			}
2660 			param = pcomma + 1;
2661 			if ((pcomma = strchr(param, ',')) != NULL) {
2662 				*pcomma = '\0';
2663 				/* display bssid */
2664 				(void) printf("%s ", param);
2665 			}
2666 			param = pcomma + 1;
2667 			if ((pcomma = strchr(param, ',')) != NULL) {
2668 				*pcomma = '\0';
2669 				/* display wep */
2670 				(void) printf("%s\t\t", param);
2671 			}
2672 			param = pcomma + 1;
2673 			/* display time stamp */
2674 			cltime = (time_t)atol(param);
2675 			(void) printf("%s", ctime(&cltime));
2676 			free(param_bak);
2677 		}
2678 		pae = pae->ae_next;
2679 	}
2680 
2681 	return (B_TRUE);
2682 }
2683 
2684 /*
2685  * do_lsprefer: Print the list in {preferrence} section
2686  */
2687 /*ARGSUSED*/
2688 static boolean_t
2689 do_lsprefer(int fd, int argc, char **argv)
2690 {
2691 	int i = 0;
2692 	section_t *p_section = NULL;
2693 	aelist_t *plist = NULL;
2694 	ae_t *pae = NULL;
2695 	char *pbuf;
2696 
2697 	PRTDBG(("do_lsprefer(%d, 0x%x)\n", argc, argv));
2698 	if (argc > 0) {
2699 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
2700 		    "after 'listprefer'\n"), gExecName);
2701 	}
2702 	p_section = find_section(gp_config_file, WIFI_PREFER);
2703 	if (p_section != NULL) {
2704 		plist = p_section->list;
2705 		if (plist != NULL) {
2706 			pae = NULL;
2707 			pae = plist->ael_head;
2708 			while (pae != NULL) {
2709 				if (pae->ae_arg != NULL) {
2710 					pbuf = append_pa(pae->ae_arg);
2711 					(void) printf("%d\t%s\n", ++i, pbuf);
2712 				}
2713 				pae = pae->ae_next;
2714 			}
2715 		}
2716 		return (B_TRUE);
2717 	} else {
2718 		PRTDBG(("no preference section\n"));
2719 		return (B_FALSE);
2720 	}
2721 }
2722 
2723 /*
2724  * do_rmprefer: Remove an item in {preferrence} list
2725  */
2726 /*ARGSUSED*/
2727 static boolean_t
2728 do_rmprefer(int fd, int argc, char **argv)
2729 {
2730 	int i = 0;
2731 	section_t *p_section = NULL;
2732 	aelist_t *plist = NULL;
2733 	ae_t *pae = NULL;
2734 
2735 	PRTDBG(("do_rmprefer(%d, 0x%x)\n", argc, argv));
2736 	if (argc <= 0) {
2737 		do_print_usage();
2738 		exit(WIFI_IMPROPER_USE);
2739 	}
2740 
2741 	/*
2742 	 * if a "all" is inputted, all the items in the preference
2743 	 * list will be deleted.
2744 	 */
2745 	if (strcasecmp(argv[0], "all") == 0) {
2746 		p_section = find_section(gp_config_file, WIFI_PREFER);
2747 		if (p_section != NULL)
2748 			plist = p_section->list;
2749 
2750 		if ((p_section == NULL) || (plist == NULL))
2751 			return (B_FALSE);
2752 		pae = plist->ael_head;
2753 		while (pae != NULL) {
2754 			free(pae);
2755 			pae = pae->ae_next;
2756 		}
2757 		plist->ael_head = plist->ael_tail = NULL;
2758 		plist->ael_argc = 0;
2759 	} else if (gp_config_file != NULL) {
2760 		for (i = 0; i < argc; i++) {
2761 			if (del_prefer(gp_config_file, argv[i], B_TRUE)
2762 			    == B_FALSE) {
2763 				return (B_FALSE);
2764 			}
2765 		}
2766 	}
2767 	return (B_TRUE);
2768 }
2769 
2770 static boolean_t
2771 is_prefer_rank_valid(const char *pbuf)
2772 {
2773 	int i;
2774 	boolean_t ret = B_FALSE;
2775 
2776 	for (i = 0; i < strlen(pbuf); i++) {
2777 		if (isdigit(pbuf[i]) == 0) {
2778 			ret = B_FALSE;
2779 			goto exit0;
2780 		}
2781 	}
2782 	i = atoi(pbuf);
2783 	if ((i >= 1) && (i <= MAX_PREFERENCE_NUM))
2784 		ret = B_TRUE;
2785 exit0:
2786 	return (ret);
2787 }
2788 
2789 /*
2790  * do_setprefer: Set network preferrence
2791  */
2792 /*ARGSUSED*/
2793 static boolean_t
2794 do_setprefer(int fd, int argc, char **argv)
2795 {
2796 	int rank = 0;
2797 
2798 	PRTDBG(("do_setprefer(%d, 0x%x)\n", argc, argv));
2799 	if (argc <= 0) {
2800 		do_print_usage();
2801 		exit(WIFI_IMPROPER_USE);
2802 	}
2803 	if (argc == 1) {
2804 		rank = 1;
2805 	} else {
2806 		if (is_prefer_rank_valid(argv[1]) == B_FALSE) {
2807 			(void) fprintf(stderr, gettext("%s: preference rank "
2808 			    "should be an integer within 1-10\n"), gExecName);
2809 			return (B_FALSE);
2810 		}
2811 		rank = atoi(argv[1]);
2812 	}
2813 	return (set_prefer(gp_config_file, argv[0], rank));
2814 }
2815 
2816 static boolean_t
2817 is_wepkeyindex_valid(const char *pbuf)
2818 {
2819 	int i;
2820 	boolean_t ret = B_FALSE;
2821 
2822 	for (i = 0; i < strlen(pbuf); i++) {
2823 		if (isdigit(pbuf[i]) == 0) {
2824 			ret = B_FALSE;
2825 			goto exit0;
2826 		}
2827 	}
2828 	i = atoi(pbuf);
2829 	if ((i >= 1) && (i <= MAX_NWEPKEYS))
2830 		ret = B_TRUE;
2831 exit0:
2832 	return (ret);
2833 }
2834 
2835 static boolean_t
2836 is_channel_valid(const char *pbuf)
2837 {
2838 	int i;
2839 	boolean_t ret = B_FALSE;
2840 
2841 	for (i = 0; i < strlen(pbuf); i++) {
2842 		if (isdigit(pbuf[i]) == 0) {
2843 			ret = B_FALSE;
2844 			goto exit0;
2845 		}
2846 	}
2847 	i = atoi(pbuf);
2848 	if ((i >= 0) && (i <= MAX_CHANNEL_NUM))
2849 		ret = B_TRUE;
2850 exit0:
2851 	return (ret);
2852 }
2853 
2854 static boolean_t
2855 is_wepkey_valid(const char *pbuf, uint32_t length)
2856 {
2857 	int i;
2858 	boolean_t ret = B_FALSE;
2859 
2860 	switch (length) {
2861 	case 10:
2862 	case 26:
2863 		for (i = 0; i < length; i++) {
2864 			if (isxdigit(pbuf[i]) == 0) {
2865 				ret = B_FALSE;
2866 				goto exit0;
2867 			}
2868 		}
2869 		ret = B_TRUE;
2870 		break;
2871 	case 5:
2872 	case 13:
2873 		ret = B_TRUE;
2874 		break;
2875 	default:
2876 		ret = B_FALSE;
2877 		break;
2878 	}
2879 exit0:
2880 	if (ret == B_FALSE) {
2881 		(void) fprintf(stderr, gettext("%s: "
2882 		    "wepkey should be:\n"
2883 		    "\t 40bits: 5 char or 10 hex digits.\n"
2884 		    "\t 128bits: 13 char or 26 hex digits.\n"),
2885 		    gExecName);
2886 	}
2887 	return (ret);
2888 }
2889 
2890 /*
2891  * get_valid_wepkey: get an valid wepkey from stdin
2892  */
2893 static char *
2894 get_valid_wepkey()
2895 {
2896 	int i = 0;
2897 	char *buf = NULL;
2898 	uint8_t length = 0;
2899 	struct termios stored_settings;
2900 	struct termios new_settings;
2901 
2902 	PRTDBG(("get_valid_wepkey()\n"));
2903 	buf = safe_calloc(sizeof (char), MAX_KEY_LENGTH + 2);
2904 	/*
2905 	 * Because we need to get single char from terminal, so we need to
2906 	 * disable canonical mode and set buffer size to 1 tyte. And because
2907 	 * wepkey should not be see by others, so we disable echo too.
2908 	 */
2909 	(void) fflush(stdin);
2910 	(void) tcgetattr(0, &stored_settings);
2911 	new_settings = stored_settings;
2912 	new_settings.c_lflag &= (~ICANON);
2913 	new_settings.c_lflag &= (~ECHO);
2914 	new_settings.c_cc[VTIME] = 0;
2915 	new_settings.c_cc[VMIN] = 1;
2916 	/* Set new terminal attributes */
2917 	(void) tcsetattr(0, TCSANOW, &new_settings);
2918 	while (((buf[i++] = getchar()) != '\n') && (i < MAX_KEY_LENGTH + 1)) {
2919 		(void) putchar('*');
2920 	}
2921 	(void) putchar('\n');
2922 	/* Restore terminal attributes */
2923 	(void) tcsetattr(0, TCSANOW, &stored_settings);
2924 	(void) fflush(stdin);
2925 
2926 	if (buf[--i] != '\n') {
2927 		(void) fprintf(stderr, gettext("%s: wepkey length "
2928 		    "exceeds 26 hex digits\n"), gExecName);
2929 		free(buf);
2930 		return (NULL);
2931 	}
2932 	/* Replace last char '\n' with '\0' */
2933 	buf[i] = '\0';
2934 	length = (uint8_t)i;
2935 	return ((is_wepkey_valid(buf, length) == B_TRUE)?
2936 	    buf : NULL);
2937 }
2938 
2939 /*
2940  * do_set_wepkey: Set parameters in wepkey, and call ioctl
2941  */
2942 static boolean_t
2943 do_set_wepkey(int fd, const char *pbuf)
2944 {
2945 	int id = 0;
2946 	char i = 0;
2947 	uint8_t len = 0;
2948 	uint8_t length;
2949 	const char *wepkey = NULL;
2950 	char key[MAX_KEY_LENGTH] = {0};
2951 	unsigned int keytmp;
2952 	wl_wep_key_tab_t wepkey_tab;
2953 
2954 	PRTDBG(("do_set_wepkey(%d, \"%s\")\n", fd, pbuf));
2955 	if (!check_authority(AUTH_WEP)) {
2956 		exit(WIFI_FATAL_ERR);
2957 	}
2958 	id = pbuf[strlen("wepkeyn") - 1] - '0';
2959 	wepkey = get_value(pbuf);
2960 	length = strlen(wepkey);
2961 	switch (length) {
2962 	case 10:
2963 	case 26:
2964 		for (i = 0; i < length / 2; i++) {
2965 			(void) sscanf(wepkey + i * 2, "%2x", &keytmp);
2966 			key[i] = (char)keytmp;
2967 		}
2968 		len = length / 2;
2969 		break;
2970 	case 5:
2971 	case 13:
2972 		(void) strlcpy(key, wepkey, MAX_KEY_LENGTH);
2973 		len = length;
2974 		break;
2975 	default:
2976 		PRTDBG(("do_set_wepkey: error pbuf size\n"));
2977 		(void) fprintf(stderr, gettext("%s: "
2978 		    "wepkey should be:\n"
2979 		    "\t 40bits: 5 char or 10 hex digits.\n"
2980 		    "\t 128bits: 13 char or 26 hex digits.\n"),
2981 		    gExecName);
2982 		exit(WIFI_FATAL_ERR);
2983 	}
2984 
2985 	(void) memset(wepkey_tab, 0, sizeof (wepkey_tab));
2986 	for (i = 0; i < MAX_NWEPKEYS; i++) {
2987 		wepkey_tab[i].wl_wep_operation = WL_NUL;
2988 	}
2989 
2990 	if (id > 0 && id <= MAX_NWEPKEYS) {
2991 		wepkey_tab[id-1].wl_wep_operation = WL_ADD;
2992 		wepkey_tab[id-1].wl_wep_length = len;
2993 		(void) memcpy(wepkey_tab[id-1].wl_wep_key, key, len);
2994 	} else {
2995 		(void) fprintf(stderr, gettext("%s: wepkeyindex "
2996 		    "should be an integer within the range 1-4\n"), gExecName);
2997 		exit(WIFI_FATAL_ERR);
2998 	}
2999 	(void) memmove(gbuf->wldp_buf, &wepkey_tab, sizeof (wl_wep_key_tab_t));
3000 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_WEP_KEY_TAB,
3001 	    sizeof (wl_wep_key_tab_t)));
3002 }
3003 
3004 /*
3005  * get the committed wepkey. the return form is like wepkey1=*****;
3006  */
3007 /*ARGSUSED*/
3008 static char *
3009 get_commit_key(int fd, int argc, char **argv)
3010 {
3011 	int key;
3012 	int len;
3013 	char *wepkey = NULL;
3014 	char *wepkey_confirm = NULL;
3015 	char *pbuf = NULL;
3016 
3017 	key = atoi(argv[0]);
3018 	if (key <= 0 || key > MAX_NWEPKEYS) {
3019 		(void) fprintf(stderr, gettext("%s: wepkeyindex "
3020 		    "should be an integer within the range 1-4\n"), gExecName);
3021 		goto exit0;
3022 	}
3023 	(void) printf(gettext("input wepkey%d:"), key);
3024 	wepkey = get_valid_wepkey();
3025 	if (wepkey == NULL) {
3026 		goto exit0;
3027 	}
3028 	(void) printf(gettext("confirm wepkey%d:"), key);
3029 	wepkey_confirm = get_valid_wepkey();
3030 	if (wepkey_confirm == NULL) {
3031 		free(wepkey);
3032 		goto exit0;
3033 	}
3034 	if (strcmp(wepkey, wepkey_confirm) != 0) {
3035 		free(wepkey);
3036 		free(wepkey_confirm);
3037 		(void) fprintf(stderr,
3038 		    gettext("%s: wepkey: "
3039 		    "two inputs are not identical\n"), gExecName);
3040 		goto exit0;
3041 	}
3042 	free(wepkey_confirm); /* wepkey_confirm is no longer used */
3043 
3044 	len = MAX_KEY_LENGTH + strlen("wepkey1=\n") + 1;
3045 	pbuf = safe_malloc(len);
3046 	safe_snprintf(pbuf, len, "%s%d=%s", "wepkey", key, wepkey);
3047 
3048 	free(wepkey); /* wepkey is no longer used */
3049 	return (pbuf);
3050 exit0:
3051 	return (NULL);
3052 }
3053 
3054 /*
3055  * do_wepkey: Get input from user, call do_set_wepkey
3056  */
3057 /*ARGSUSED*/
3058 static boolean_t
3059 do_wepkey(int fd, int argc, char **argv)
3060 {
3061 	char *pbuf;
3062 
3063 	PRTDBG(("do_wepkey(%d, 0x%x)\n", argc, argv));
3064 	assert(fd > 0);
3065 	if (argc <= 0) {
3066 		do_print_usage();
3067 		exit(WIFI_IMPROPER_USE);
3068 	}
3069 	if (argc > 1) {
3070 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
3071 		    "after 'setwepkey'\n"), gExecName);
3072 	}
3073 	pbuf = get_commit_key(fd, argc, argv);
3074 	if ((pbuf != NULL) && (do_set_wepkey(fd, pbuf) == B_TRUE)) {
3075 		free(pbuf);
3076 		return (B_TRUE);
3077 	}
3078 	free(pbuf);
3079 	return (B_FALSE);
3080 }
3081 
3082 /*ARGSUSED*/
3083 static boolean_t
3084 do_setprofwepkey(int fd, int argc, char **argv)
3085 {
3086 	char *pbuf;
3087 	char *section_id = NULL;
3088 	section_t *p_section = NULL;
3089 	aelist_t *plist = NULL;
3090 
3091 	PRTDBG(("do_setprofwepkey(%d, 0x%x)\n", argc, argv));
3092 	if (argc < 2) {
3093 		do_print_usage();
3094 		exit(WIFI_IMPROPER_USE);
3095 	}
3096 	if (argc > 2) {
3097 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
3098 		    "after 'setprofwepkey'\n"), gExecName);
3099 	}
3100 
3101 	section_id = append_pa(argv[0]);
3102 	p_section = find_section(gp_wepkey_file, section_id);
3103 	free(section_id);
3104 	if (p_section == NULL) {
3105 		(void) fprintf(stderr, gettext("%s: "
3106 		    "no such profile: '%s'\n"),
3107 		    gExecName, argv[0]);
3108 		return (B_FALSE);
3109 	}
3110 
3111 	argc--;
3112 	argv++;
3113 	pbuf = get_commit_key(fd, argc, argv);
3114 	if (pbuf == NULL)
3115 		return (B_FALSE);
3116 	plist = p_section->list;
3117 	update_aelist(plist, pbuf);
3118 
3119 	return (B_TRUE);
3120 }
3121 
3122 /*
3123  * do_wlanlist: Scan for wlanlist
3124  */
3125 /*ARGSUSED*/
3126 static boolean_t
3127 do_wlanlist(int fd, int argc, char **argv)
3128 {
3129 	PRTDBG(("do_wlanlist(%d, 0x%x)\n", argc, argv));
3130 	assert(fd > 0);
3131 	if (argc > 0) {
3132 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
3133 		    "after 'scan'\n"), gExecName);
3134 	}
3135 	if (call_ioctl(fd, WLAN_COMMAND, WL_SCAN, 0) == B_FALSE) {
3136 		(void) fprintf(stderr, gettext("%s: failed to scan\n"),
3137 		    gExecName);
3138 		return (B_FALSE);
3139 	}
3140 	if (do_get_wlanlist(fd) == B_TRUE) {
3141 		print_gbuf(WLANLIST);
3142 	}
3143 	return (B_TRUE);
3144 }
3145 
3146 /*
3147  * do_showstatus: show the basic status of the interface, including
3148  * linkstauts, essid, encryption and signal strength.
3149  */
3150 /*ARGSUSED*/
3151 static boolean_t
3152 do_showstatus(int fd, int argc, char **argv)
3153 {
3154 	wl_rssi_t signal;
3155 	char *active_profile = NULL;
3156 
3157 	PRTDBG(("do_showstatus(%d, 0x%x)\n", argc, argv));
3158 	assert(fd > 0);
3159 
3160 	if (argc > 0) {
3161 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
3162 		    "after 'showstatus'\n"), gExecName);
3163 	}
3164 	if (do_get_linkstatus(fd) == B_TRUE) {
3165 		print_gbuf(LINKSTATUS);
3166 		if (*(wl_linkstatus_t *)(gbuf->wldp_buf) == WL_NOTCONNECTED) {
3167 			return (B_TRUE);
3168 		}
3169 	}
3170 	active_profile = find_active_profile(fd);
3171 	(void) printf("\tactive profile: %s\n",
3172 	    active_profile ? active_profile : "none");
3173 	if (do_get_essid(fd) == B_TRUE) {
3174 		print_gbuf(ESSID);
3175 	}
3176 	if (do_get_bssid(fd) == B_TRUE) {
3177 		print_gbuf(BSSID);
3178 	}
3179 	if (do_get_encryption(fd) == B_TRUE) {
3180 		print_gbuf(ENCRYPTION);
3181 	}
3182 	if (do_get_signal(fd) == B_TRUE) {
3183 		signal = *(wl_rssi_t *)(gbuf->wldp_buf);
3184 		if (signal < 4) {
3185 			(void) printf("\tsignal strength: weak(%d)\n",
3186 			    signal);
3187 		} else if ((signal >= 4) && (signal <= 11)) {
3188 			(void) printf("\tsignal strength: medium(%d)\n",
3189 			    signal);
3190 		} else {
3191 			(void) printf("\tsignal strength: strong(%d)\n",
3192 			    signal);
3193 		}
3194 	}
3195 
3196 	return (B_TRUE);
3197 }
3198 
3199 
3200 /*
3201  * do_restoredef: Ask driver for loading default parameters
3202  */
3203 /*ARGSUSED*/
3204 static boolean_t
3205 do_restoredef(int fd, int argc, char **argv)
3206 {
3207 	PRTDBG(("do_restoredef(%d, 0x%x)\n", argc, argv));
3208 	assert(fd > 0);
3209 
3210 	if (argc > 0) {
3211 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
3212 		    "after 'restoredef'\n"), gExecName);
3213 	}
3214 	record_active_profile(NULL, RECORD_DEL);
3215 	if (call_ioctl(fd, WLAN_COMMAND, WL_LOAD_DEFAULTS, 0) == B_FALSE) {
3216 		return (B_FALSE);
3217 	} else {
3218 		return (B_TRUE);
3219 	}
3220 }
3221 
3222 /*
3223  * do_disconnect: disconnect from the current connectted network
3224  */
3225 /*ARGSUSED*/
3226 static boolean_t
3227 do_disconnect(int fd, int argc, char **argv)
3228 {
3229 	PRTDBG(("do_disconnect(%d, 0x%x)\n", argc, argv));
3230 	assert(fd > 0);
3231 
3232 	if (argc > 0) {
3233 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
3234 		    "after 'disconnect'\n"), gExecName);
3235 	}
3236 	record_active_profile(NULL, RECORD_DEL);
3237 	if (call_ioctl(fd, WLAN_COMMAND, WL_DISASSOCIATE, 0) == B_FALSE) {
3238 		return (B_FALSE);
3239 	} else {
3240 		return (B_TRUE);
3241 	}
3242 }
3243 
3244 static boolean_t
3245 do_set_essid(int fd, const char *arg)
3246 {
3247 	wl_essid_t essid;
3248 
3249 	PRTDBG(("do_set_essid(%d, \"%s\")\n", fd, arg));
3250 
3251 	/*
3252 	 * a trick here: clean the active_profile flag
3253 	 * in section{active_profile}
3254 	 */
3255 	record_active_profile(NULL, RECORD_DEL);
3256 
3257 	(void) memset(&essid, 0x0, sizeof (essid));
3258 
3259 	if (arg == NULL || strcmp(arg, "") == 0) {
3260 		essid.wl_essid_length = 0;
3261 		essid.wl_essid_essid[0] = '\0';
3262 	} else {
3263 		essid.wl_essid_length = strlen(arg);
3264 		if (essid.wl_essid_length > MAX_ESSID_LENGTH - 1) {
3265 			(void) fprintf(stderr, gettext("%s: "
3266 			    "essid exceeds 32 bytes\n"), gExecName);
3267 			exit(WIFI_FATAL_ERR);
3268 		}
3269 		(void) strcpy(essid.wl_essid_essid, arg);
3270 	}
3271 	(void) memmove(gbuf->wldp_buf, &essid, sizeof (wl_essid_t));
3272 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_ESSID, sizeof (wl_essid_t)));
3273 }
3274 
3275 static boolean_t
3276 do_set_bsstype(int fd, const char *arg)
3277 {
3278 	wl_bss_type_t bsstype;
3279 
3280 	assert(arg != NULL);
3281 
3282 	PRTDBG(("do_set_bsstype(%d, \"%s\")\n", fd, arg));
3283 
3284 	(void) memset(&bsstype, 0xff, sizeof (bsstype));
3285 
3286 	if ((strcasecmp(arg, "BSS") == 0) ||
3287 	    (strcasecmp(arg, "AP") == 0) ||
3288 	    (strcasecmp(arg, "INFRASTRUCTURE") == 0)) {
3289 		bsstype = WL_BSS_BSS;
3290 	} else if ((strcasecmp(arg, "IBSS") == 0) ||
3291 	    (strcasecmp(arg, "AD-HOC") == 0)) {
3292 		bsstype = WL_BSS_IBSS;
3293 	} else if (strcasecmp(arg, "AUTO") == 0) {
3294 		bsstype = WL_BSS_ANY;
3295 	} else {
3296 		(void) fprintf(stderr, gettext("%s: bsstype: "
3297 		    "bss(ap,infrastructure) ibss(ad-hoc) or auto\n"),
3298 		    gExecName);
3299 		exit(WIFI_FATAL_ERR);
3300 	}
3301 
3302 	(void) memmove(gbuf->wldp_buf, &bsstype, sizeof (wl_bss_type_t));
3303 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_BSS_TYPE,
3304 	    sizeof (wl_bss_type_t)));
3305 }
3306 
3307 static boolean_t
3308 do_set_createibss(int fd, const char *arg)
3309 {
3310 	wl_create_ibss_t create_ibss;
3311 
3312 	assert(arg != NULL);
3313 
3314 	PRTDBG(("do_set_createibss(%d, \"%s\")\n", fd, arg));
3315 
3316 	(void) memset(&create_ibss, 0x0, sizeof (create_ibss));
3317 
3318 	if (strcasecmp(arg, "YES") == 0) {
3319 		create_ibss = B_TRUE;
3320 	} else if (strcasecmp(arg, "NO") == 0) {
3321 		create_ibss = B_FALSE;
3322 	} else {
3323 		(void) fprintf(stderr, gettext("%s: "
3324 		    "createibss: yes or no\n"), gExecName);
3325 		exit(WIFI_FATAL_ERR);
3326 	}
3327 
3328 	(void) memmove(gbuf->wldp_buf, &create_ibss,
3329 	    sizeof (wl_create_ibss_t));
3330 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_CREATE_IBSS,
3331 	    sizeof (wl_create_ibss_t)));
3332 }
3333 
3334 static boolean_t
3335 do_set_channel(int fd, const char *arg)
3336 {
3337 	wl_phy_conf_t phy_conf;
3338 
3339 	assert(arg != NULL);
3340 	PRTDBG(("do_set_channel(%d, \"%s\")\n", fd, arg));
3341 
3342 	(void) memset(&phy_conf, 0xff, sizeof (phy_conf));
3343 
3344 	if (is_channel_valid(arg) == B_FALSE) {
3345 		(void) fprintf(stderr, gettext("%s: channel No. "
3346 		    "should be:\n"
3347 		    "\t802.11a: 0-99\n"
3348 		    "\t802.11b: 1-14\n"
3349 		    "\t802.11g: 1-14\n"), gExecName);
3350 		exit(WIFI_FATAL_ERR);
3351 	}
3352 	phy_conf.wl_phy_dsss_conf.wl_dsss_channel = atoi(arg);
3353 	PRTDBG(("channel=%d\n", phy_conf.wl_phy_dsss_conf.wl_dsss_channel));
3354 
3355 	(void) memmove(gbuf->wldp_buf, &phy_conf, sizeof (wl_phy_conf_t));
3356 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_PHY_CONFIG,
3357 	    sizeof (wl_phy_conf_t)));
3358 }
3359 /*
3360  * is_rates_support: Querying driver about supported rates.
3361  */
3362 static boolean_t
3363 is_rates_support(int fd, int num, uint8_t *rates)
3364 {
3365 	int rates_num = 0;
3366 	int i = 0, j = 0;
3367 	uint8_t value = 0;
3368 
3369 	assert((rates != NULL)&&(num != 0));
3370 	PRTDBG(("is_rates_support(%d, %d, 0x%x)\n", fd, num, rates));
3371 
3372 	if (call_ioctl(fd, WLAN_GET_PARAM, WL_SUPPORTED_RATES, 0)
3373 	    == B_TRUE) {
3374 		rates_num = ((wl_rates_t *)(gbuf->wldp_buf))->wl_rates_num;
3375 
3376 		for (i = 0; i < num; i++) {
3377 			PRTDBG(("rates[%d] = %d\n", i, rates[i]));
3378 			for (j = 0; j < rates_num; j++) {
3379 				value = ((wl_rates_t *)gbuf->wldp_buf)
3380 				    ->wl_rates_rates[j];
3381 				PRTDBG(("supported rates[%d]=%d\n", j, value));
3382 				if (value == rates[i]) {
3383 					break;
3384 				}
3385 			}
3386 			if (j == rates_num) {
3387 				if (rates[i] == 11) {
3388 					(void) fprintf(stderr,
3389 					    gettext("%s: "
3390 					    "rate 5.5M is not supported\n"),
3391 					    gExecName);
3392 				} else {
3393 					(void) fprintf(stderr,
3394 					    gettext("%s: "
3395 					    "rate %dM is not supported\n"),
3396 					    gExecName, rates[i]/2);
3397 				}
3398 				return (B_FALSE);
3399 			}
3400 		}
3401 		return (B_TRUE);
3402 	}
3403 	return (B_FALSE);
3404 }
3405 
3406 /*
3407  *
3408  */
3409 static uint8_t
3410 rates_convert(const char *rates)
3411 {
3412 	int i;
3413 	uint8_t ret;
3414 
3415 	for (i = 0; i < WIFI_RATES_NUM; i++) {
3416 		if (strcmp(rates, wifi_rates_s[i].rates_s) == 0) {
3417 			ret = wifi_rates_s[i].rates_i;
3418 			break;
3419 		}
3420 	}
3421 	if (i == WIFI_RATES_NUM) {
3422 		(void) fprintf(stderr, gettext("%s: "
3423 		    "invalid rates '%s'\n"), gExecName, rates);
3424 		exit(WIFI_FATAL_ERR);
3425 	}
3426 	return (ret);
3427 }
3428 
3429 /*
3430  * get_rates: convert string value arg into uint8_t array,
3431  * array length will be save into *len[i].
3432  * for example:
3433  * arg = "1,2,5.5,11"
3434  * then after call, rates[] = {2,4,11,22} will be returned.
3435  * and *len will equal to 4
3436  */
3437 static uint8_t *
3438 get_rates(const char *arg, uint32_t *len)
3439 {
3440 	int i = 1, j = 0;
3441 	uint8_t *rates = NULL;
3442 	char *pnext = NULL;
3443 	char *token;
3444 	char *pstart;
3445 	char *pstart_bak;
3446 
3447 	assert(arg != NULL);
3448 
3449 	if (strlen(arg) == 0) {
3450 		PRTDBG(("get_rates: empty rates string\n"));
3451 		return (NULL);
3452 	}
3453 	PRTDBG(("get_rates(\"%s\", 0x%x)\n", arg, len));
3454 	pstart = safe_strdup(arg);
3455 	pstart_bak = pstart;
3456 	while ((pnext = strchr(pstart, ',')) != NULL) {
3457 		pstart = pnext + 1;
3458 		i++;
3459 	}
3460 	*len = i;
3461 	rates = safe_calloc(sizeof (uint8_t), i);
3462 
3463 	pstart = pstart_bak;
3464 	if ((token = strtok(pstart, ",")) != NULL) {
3465 		PRTDBG(("rates[0]: %s\n", token));
3466 		rates[0] = rates_convert(token);
3467 		i = 1;
3468 		while ((token = strtok(NULL, ",")) != NULL) {
3469 			PRTDBG(("rates[%d]: %s\n", i, token));
3470 			rates[i++] = rates_convert(token);
3471 		}
3472 	}
3473 	free(pstart_bak);
3474 	for (i = 0; i < *len; i++) {
3475 		for (j = 0; j < i; j++)
3476 			if (rates[j] == rates[i]) {
3477 				(void) fprintf(stderr,
3478 				    gettext("%s: rates duplicated\n"),
3479 				    gExecName);
3480 				free(rates);
3481 				return (NULL);
3482 			}
3483 	}
3484 
3485 	return (rates);
3486 }
3487 
3488 static boolean_t
3489 do_set_rates(int fd, const char *arg)
3490 {
3491 	int i = 0;
3492 	uint32_t num = 0;
3493 	uint8_t *rates;
3494 
3495 	assert(arg != NULL);
3496 
3497 	PRTDBG(("do_set_rates(%d, \"%s\")\n", fd, arg));
3498 
3499 	rates = get_rates(arg, &num);
3500 	if ((rates == NULL) ||
3501 	    is_rates_support(fd, num, rates) == B_FALSE) {
3502 		exit(WIFI_FATAL_ERR);
3503 	}
3504 
3505 	((wl_rates_t *)(gbuf->wldp_buf))->wl_rates_num = num;
3506 	for (i = 0; i < num; i++) {
3507 		((wl_rates_t *)gbuf->wldp_buf)->wl_rates_rates[i]
3508 		    = rates[i];
3509 	}
3510 	free(rates);
3511 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_DESIRED_RATES,
3512 	    offsetof(wl_rates_t, wl_rates_rates) +
3513 	    num*sizeof (char)));
3514 }
3515 
3516 static boolean_t
3517 do_set_powermode(int fd, const char *arg)
3518 {
3519 	wl_ps_mode_t ps_mode;
3520 
3521 	assert(arg != NULL);
3522 
3523 	PRTDBG(("do_set_powermode(%d, \"%s\")\n", fd, arg));
3524 
3525 	(void) memset(&ps_mode, 0xff, sizeof (ps_mode));
3526 
3527 	if ((strcasecmp(arg, "OFF") == 0) ||
3528 	    (strcasecmp(arg, "MPS") == 0) ||
3529 	    (strcasecmp(arg, "FAST") == 0)) {
3530 		switch (arg[0]) {
3531 		case 'O':
3532 		case 'o':
3533 			ps_mode.wl_ps_mode = WL_PM_AM;
3534 			break;
3535 		case 'M':
3536 		case 'm':
3537 			ps_mode.wl_ps_mode = WL_PM_MPS;
3538 			break;
3539 		case 'F':
3540 		case 'f':
3541 			ps_mode.wl_ps_mode = WL_PM_FAST;
3542 			break;
3543 		default:
3544 			break;
3545 		}
3546 	} else {
3547 		(void) fprintf(stderr,
3548 		    gettext("%s: powermode: off mps or fast\n"), gExecName);
3549 		exit(WIFI_FATAL_ERR);
3550 	}
3551 
3552 	(void) memmove(gbuf->wldp_buf, &ps_mode, sizeof (wl_ps_mode_t));
3553 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_POWER_MODE,
3554 	    sizeof (wl_ps_mode_t)));
3555 }
3556 
3557 static boolean_t
3558 do_set_authmode(int fd, const char *arg)
3559 {
3560 	wl_authmode_t auth_mode;
3561 
3562 	assert(arg != NULL);
3563 	PRTDBG(("do_set_authmode(%d, \"%s\")\n", fd, arg));
3564 
3565 	(void) memset(&auth_mode, 0xff, sizeof (auth_mode));
3566 	/* Mark */
3567 	if (strcasecmp(arg, "OPENSYSTEM") == 0) {
3568 		auth_mode = WL_OPENSYSTEM;
3569 	} else if (strcasecmp(arg, "SHARED_KEY") == 0) {
3570 		auth_mode = WL_SHAREDKEY;
3571 	} else {
3572 		(void) fprintf(stderr,
3573 		    gettext("%s: authmode: "
3574 		    "opensystem or shared_key\n"), gExecName);
3575 		exit(WIFI_FATAL_ERR);
3576 	}
3577 
3578 	(void) memmove(gbuf->wldp_buf, &auth_mode, sizeof (wl_authmode_t));
3579 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_AUTH_MODE,
3580 	    sizeof (wl_authmode_t)));
3581 }
3582 
3583 static boolean_t
3584 do_set_encryption(int fd, const char *arg)
3585 {
3586 	wl_encryption_t encryption;
3587 
3588 	assert(arg != NULL);
3589 	PRTDBG(("do_set_encryption(%d, \"%s\")\n", fd, arg));
3590 
3591 	(void) memset(&encryption, 0xff, sizeof (encryption));
3592 
3593 	if (strcasecmp(arg, "NONE") == 0) {
3594 		encryption = WL_NOENCRYPTION;
3595 	} else if (strcasecmp(arg, "WEP") == 0) {
3596 		encryption = WL_ENC_WEP;
3597 	} else {
3598 		(void) fprintf(stderr, gettext("%s: encryption: "
3599 		    "none or wep\n"), gExecName);
3600 		exit(WIFI_FATAL_ERR);
3601 	}
3602 
3603 	(void) memmove(gbuf->wldp_buf, &encryption, sizeof (wl_encryption_t));
3604 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_ENCRYPTION,
3605 	    sizeof (wl_encryption_t)));
3606 }
3607 
3608 static boolean_t
3609 do_set_wepkeyid(int fd, const char *arg)
3610 {
3611 	wl_wep_key_id_t wep_key_id;
3612 
3613 	assert(arg != NULL);
3614 	PRTDBG(("do_set_wepkeyid(%d, \"%s\")\n", fd, arg));
3615 
3616 	(void) memset(&wep_key_id, 0xff, sizeof (wep_key_id));
3617 	if (is_wepkeyindex_valid(arg) == B_FALSE) {
3618 		(void) fprintf(stderr, gettext("%s: wepkeyindex "
3619 		    "should be an integer within the range 1-4\n"), gExecName);
3620 		exit(WIFI_FATAL_ERR);
3621 	}
3622 	wep_key_id = atoi(arg) - 1;
3623 
3624 	(void) memmove(gbuf->wldp_buf, &wep_key_id, sizeof (wl_wep_key_id_t));
3625 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_WEP_KEY_ID,
3626 	    sizeof (wl_wep_key_id_t)));
3627 }
3628 
3629 static boolean_t
3630 do_set_radioon(int fd, const char *arg)
3631 {
3632 	wl_radio_t radio;
3633 
3634 	assert(arg != NULL);
3635 	PRTDBG(("do_set_radioon(%d, \"%s\")\n", fd, arg));
3636 
3637 	(void) memset(&radio, 0xff, sizeof (radio));
3638 
3639 	if (strcasecmp(arg, "ON") == 0) {
3640 		radio = B_TRUE;
3641 	} else if (strcasecmp(arg, "OFF") == 0) {
3642 		radio = B_FALSE;
3643 	} else {
3644 		(void) fprintf(stderr,
3645 		    gettext("%s: radio : on or off\n"), gExecName);
3646 		exit(WIFI_FATAL_ERR);
3647 	}
3648 
3649 	(void) memmove(gbuf->wldp_buf, &radio, sizeof (wl_radio_t));
3650 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_RADIO, sizeof (wl_radio_t)));
3651 }
3652 /*
3653  * print_gbuf: After each ioctl system call, gbuf will contain result, gbuf
3654  * contents's format varies from each kind of ioctl system call.
3655  */
3656 static void
3657 print_gbuf(config_item_t index)
3658 {
3659 	int i = 0, j = 0;
3660 	uint32_t ess_num;
3661 	char **ess_argv;
3662 	uint32_t rates_num;
3663 	uint32_t subtype;
3664 	wl_bss_type_t bsstype;
3665 	wl_create_ibss_t createibss;
3666 	wl_ps_mode_t *ps_mode;
3667 	wl_authmode_t authmode;
3668 	wl_encryption_t encryption;
3669 	wl_wep_key_id_t wepkeyid;
3670 	wl_rssi_t signal;
3671 	wl_radio_t radioon;
3672 	wl_ess_conf_t **p_ess_conf;
3673 	wl_linkstatus_t linkstatus;
3674 	char format[256], *ntstr;
3675 	uint32_t maxessidlen = 0, nt = 0, cnt = 0;
3676 	int len;
3677 	uint8_t bssid[6];
3678 
3679 	PRTDBG(("print_gbuf(%d)\n", index));
3680 	assert(gbuf->wldp_length < MAX_BUF_LEN);
3681 
3682 	switch (index) {
3683 	case BSSID:
3684 		(void) printf("\tbssid: ");
3685 		(void) memset(bssid, 0, sizeof (bssid));
3686 		if (memcmp((uint8_t *)gbuf->wldp_buf, bssid, sizeof (bssid))
3687 		    == 0) {
3688 			(void) printf("none\n");
3689 			break;
3690 		}
3691 		(void) memset(bssid, 0xff, sizeof (bssid));
3692 		if (memcmp((uint8_t *)gbuf->wldp_buf, bssid, sizeof (bssid))
3693 		    == 0) {
3694 			(void) printf("none\n");
3695 			break;
3696 		}
3697 		for (i = 0; i < 5; i++)
3698 			(void) printf("%02x:", ((uint8_t *)gbuf->wldp_buf)[i]);
3699 		(void) printf("%02x\n", ((uint8_t *)gbuf->wldp_buf)[i]);
3700 		break;
3701 	case ESSID:
3702 		(void) printf("\tessid: %s\n", ((wl_essid_t *)(gbuf->wldp_buf))
3703 		    ->wl_essid_essid);
3704 		break;
3705 	case BSSTYPE:
3706 		bsstype = *(wl_bss_type_t *)(gbuf->wldp_buf);
3707 		switch (bsstype) {
3708 		case WL_BSS_BSS:
3709 			(void) printf("\tbsstype: bss(ap, infrastructure)\n");
3710 			break;
3711 		case WL_BSS_IBSS:
3712 			(void) printf("\tbsstype: ibss(ad-hoc)\n");
3713 			break;
3714 		case WL_BSS_ANY:
3715 			(void) printf("\tbsstype: auto\n");
3716 			break;
3717 		default:
3718 			(void) fprintf(stderr,
3719 			    gettext("%s: "
3720 			    "invalid bsstype value\n"), gExecName);
3721 		}
3722 		break;
3723 	case CREATEIBSS:
3724 		createibss = *(wl_create_ibss_t *)(gbuf->wldp_buf);
3725 		switch (createibss) {
3726 		case B_TRUE:
3727 			(void) printf("\tcreateibss: yes\n");
3728 			break;
3729 		case B_FALSE:
3730 			(void) printf("\tcreateibss: no\n");
3731 			break;
3732 		default:
3733 			(void) fprintf(stderr,
3734 			    gettext("%s: "
3735 			    "invalid createibss value\n"), gExecName);
3736 		}
3737 		break;
3738 	case CHANNEL:
3739 		subtype = ((wl_fhss_t *)(gbuf->wldp_buf))->wl_fhss_subtype;
3740 		switch (subtype) {
3741 		case WL_FHSS:
3742 		case WL_DSSS:
3743 		case WL_IRBASE:
3744 		case WL_HRDS:
3745 		case WL_ERP:
3746 			(void) printf("\tchannel: %d\n", ((wl_fhss_t *)
3747 			    (gbuf->wldp_buf))->wl_fhss_channel);
3748 			break;
3749 		case WL_OFDM:
3750 			(void) printf("\tchannel: %d\n", ((wl_ofdm_t *)
3751 			    (gbuf->wldp_buf))
3752 			    ->wl_ofdm_frequency);
3753 			break;
3754 		default:
3755 			(void) fprintf(stderr, gettext("%s: "
3756 			    "invalid subtype\n"), gExecName);
3757 			break;
3758 		}
3759 		break;
3760 	case RATES:
3761 		rates_num = ((wl_rates_t *)(gbuf->wldp_buf))->wl_rates_num;
3762 		(void) printf("\trates: ");
3763 		for (i = 0; i < rates_num; i++) {
3764 			char rate;
3765 			rate = ((wl_rates_t *)gbuf->wldp_buf)
3766 			    ->wl_rates_rates[i];
3767 			if (rate == WL_RATE_5_5M)
3768 				(void) printf("5.5");
3769 			else
3770 				(void) printf("%d", (uint8_t)(rate / 2));
3771 
3772 			if (i == (rates_num - 1))
3773 				(void) printf("\n");
3774 			else
3775 				(void) printf(",");
3776 		}
3777 		break;
3778 	case POWERMODE:
3779 		ps_mode = (wl_ps_mode_t *)(gbuf->wldp_buf);
3780 		switch (ps_mode->wl_ps_mode) {
3781 		case WL_PM_AM:
3782 			(void) printf("\tpowermode: off\n");
3783 			break;
3784 		case WL_PM_MPS:
3785 			(void) printf("\tpowermode: mps\n");
3786 			break;
3787 		case WL_PM_FAST:
3788 			(void) printf("\tpowermode: fast\n");
3789 			break;
3790 		default:
3791 			(void) fprintf(stderr,
3792 			    gettext("%s: "
3793 			    "invalid powermode value\n"), gExecName);
3794 			break;
3795 		}
3796 		break;
3797 	case AUTHMODE:
3798 		authmode = *(wl_authmode_t *)(gbuf->wldp_buf);
3799 		switch (authmode) {
3800 		case WL_OPENSYSTEM:
3801 			(void) printf("\tauthmode: opensystem\n");
3802 			break;
3803 		case WL_SHAREDKEY:
3804 			(void) printf("\tauthmode: shared_key\n");
3805 			break;
3806 		default:
3807 			(void) fprintf(stderr,
3808 			    gettext("%s: "
3809 			    "invalid authmode value\n"), gExecName);
3810 			break;
3811 		}
3812 		break;
3813 	case ENCRYPTION:
3814 		encryption = *(wl_encryption_t *)(gbuf->wldp_buf);
3815 		switch (encryption) {
3816 		case WL_NOENCRYPTION:
3817 			(void) printf("\tencryption: none\n");
3818 			break;
3819 		case WL_ENC_WEP:
3820 			(void) printf("\tencryption: wep\n");
3821 			break;
3822 		default:
3823 			(void) fprintf(stderr,
3824 			    gettext("%s: "
3825 			    "invalid encryption value\n"), gExecName);
3826 			break;
3827 		}
3828 		break;
3829 	case WEPKEYID:
3830 		wepkeyid = *(wl_wep_key_id_t *)(gbuf->wldp_buf);
3831 		(void) printf("\twepkeyindex: %d\n", wepkeyid + 1);
3832 		break;
3833 	case SIGNAL:
3834 		signal = *(wl_rssi_t *)(gbuf->wldp_buf);
3835 		(void) printf("\tsignal: %d\n", signal);
3836 		break;
3837 	case RADIOON:
3838 		radioon = *(wl_radio_t *)(gbuf->wldp_buf);
3839 		switch (radioon) {
3840 		case B_TRUE:
3841 			(void) printf("\tradio: on\n");
3842 			break;
3843 		case B_FALSE:
3844 			(void) printf("\tradio: off\n");
3845 			break;
3846 		default: /* Mark */
3847 			(void) fprintf(stderr,
3848 			    gettext("%s: "
3849 			    "invalid radioon value\n"), gExecName);
3850 		}
3851 		break;
3852 	case LINKSTATUS:
3853 		linkstatus = *(wl_linkstatus_t *)(gbuf->wldp_buf);
3854 		switch (linkstatus) {
3855 		case WL_CONNECTED:
3856 			(void) printf("\tlinkstatus: connected\n");
3857 			break;
3858 		case WL_NOTCONNECTED:
3859 			(void) printf("\tlinkstatus: not connected\n");
3860 			break;
3861 		default: /* Mark */
3862 			(void) fprintf(stderr,
3863 			    gettext("%s: "
3864 			    "invalid linkstatus value\n"), gExecName);
3865 		}
3866 		break;
3867 	case WLANLIST:
3868 		ess_num = ((wl_ess_list_t *)(gbuf->wldp_buf))->wl_ess_list_num;
3869 		ess_argv = safe_calloc(sizeof (char *), ess_num);
3870 		p_ess_conf = safe_calloc(sizeof (wl_ess_conf_t *), ess_num);
3871 		for (i = 0; i < ess_num; i++) {
3872 			p_ess_conf[i] = ((wl_ess_list_t *)gbuf->wldp_buf)
3873 			    ->wl_ess_list_ess + i;
3874 			maxessidlen = (maxessidlen >
3875 			    strlen(p_ess_conf[i]
3876 			    ->wl_ess_conf_essid.wl_essid_essid) ?
3877 			    maxessidlen :
3878 			    strlen(p_ess_conf[i]
3879 			    ->wl_ess_conf_essid.wl_essid_essid));
3880 		}
3881 		/*
3882 		 * construct the output format.
3883 		 */
3884 		if ((nt = (maxessidlen / 8 + 1)) > 4)
3885 			nt = 4;
3886 		len = snprintf(format, sizeof (format), gettext("essid"));
3887 		ntstr = construct_format(nt);
3888 		assert(ntstr != NULL);
3889 		len += snprintf(format + len, sizeof (format) - len, "%s",
3890 		    ntstr);
3891 		len += snprintf(format + len, sizeof (format) - len,
3892 		    gettext("bssid\t\t  type\t\tencryption\tsignallevel\n"));
3893 
3894 		if ((len <= 0) || (len > sizeof (format) - 1)) {
3895 			(void) printf("essid\t\t\t\tbssid\t\t  type\t\t"
3896 			    "encryption\tsignallevel\n");
3897 		} else {
3898 			(void) printf("%s", format);
3899 		}
3900 
3901 		for (i = 0; i < ess_num; i++) {
3902 			ess_argv[i] = safe_malloc(MAX_SCANBUF_LEN);
3903 			safe_snprintf(ess_argv[i], MAX_SCANBUF_LEN,
3904 			    "%s%c%02x:%02x:%02x:%02x:%02x:%02x%c%s",
3905 			    p_ess_conf[i]->wl_ess_conf_essid.wl_essid_essid,
3906 			    ',',
3907 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[0]),
3908 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[1]),
3909 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[2]),
3910 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[3]),
3911 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[4]),
3912 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[5]), ',',
3913 			    (p_ess_conf[i]->wl_ess_conf_wepenabled ==
3914 			    B_TRUE ? "wep":"none"));
3915 			len = strlen(p_ess_conf[i]->wl_ess_conf_essid.
3916 			    wl_essid_essid);
3917 			cnt = nt - (min(len /8 + 1, 4) - 1);
3918 			ntstr = construct_format(cnt);
3919 			assert(ntstr != NULL);
3920 			(void) printf("%s%s", p_ess_conf[i]->wl_ess_conf_essid.
3921 			    wl_essid_essid, ntstr);
3922 			free(ntstr);
3923 			for (j = 0; j < 5; j++) {
3924 				(void) printf("%02x:", (uint8_t)(p_ess_conf[i]
3925 				    ->wl_ess_conf_bssid[j]));
3926 			}
3927 			(void) printf("%02x ", (uint8_t)(p_ess_conf[i]
3928 			    ->wl_ess_conf_bssid[j]));
3929 
3930 			if (p_ess_conf[i]->wl_ess_conf_bsstype ==
3931 			    WL_BSS_BSS)
3932 				(void) printf("access point");
3933 			else
3934 				(void) printf("ad-hoc");
3935 			if (p_ess_conf[i]->wl_ess_conf_wepenabled ==
3936 			    WL_ENC_WEP)
3937 				(void) printf("\twep\t");
3938 			else
3939 				(void) printf("\tnone\t");
3940 			(void) printf("\t%d\n", p_ess_conf[i]->wl_ess_conf_sl);
3941 		}
3942 		add_to_history(gp_config_file, ess_num, ess_argv);
3943 		free(p_ess_conf);
3944 		for (i = 0; i < ess_num; i++) {
3945 			free(ess_argv[i]);
3946 		}
3947 		free(ess_argv);
3948 		break;
3949 	default:
3950 		(void) fprintf(stderr, gettext("%s: "
3951 		    "invalid parameter type\n"), gExecName);
3952 		break;
3953 	}
3954 }
3955 /*
3956  * do_get_xxx: will send ioctl to driver, then the driver will fill gbuf
3957  * with related value. gbuf has a format of wldp_t structure.
3958  */
3959 static boolean_t
3960 do_get_bssid(int fd)
3961 {
3962 	PRTDBG(("do_get_bssid(%d)\n", fd));
3963 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_BSSID, 0));
3964 }
3965 
3966 static boolean_t
3967 do_get_essid(int fd)
3968 {
3969 	PRTDBG(("do_get_essid(%d)\n", fd));
3970 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_ESSID, 0));
3971 }
3972 
3973 static boolean_t
3974 do_get_bsstype(int fd)
3975 {
3976 	PRTDBG(("do_get_bsstype(%d)\n", fd));
3977 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_BSS_TYPE, 0));
3978 }
3979 
3980 static boolean_t
3981 do_get_createibss(int fd)
3982 {
3983 	PRTDBG(("do_get_createibss(%d)\n", fd));
3984 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_CREATE_IBSS, 0));
3985 }
3986 
3987 static boolean_t
3988 do_get_channel(int fd)
3989 {
3990 	PRTDBG(("do_get_channel(%d)\n", fd));
3991 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_PHY_CONFIG, 0));
3992 }
3993 
3994 static boolean_t
3995 do_get_wlanlist(int fd)
3996 {
3997 	PRTDBG(("do_get_wlanlist(%d)\n", fd));
3998 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_ESS_LIST, 0));
3999 }
4000 
4001 static boolean_t
4002 do_get_linkstatus(int fd)
4003 {
4004 	PRTDBG(("do_get_linkstauts(%d)\n", fd));
4005 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_LINKSTATUS, 0));
4006 }
4007 
4008 static boolean_t
4009 do_get_rates(int fd)
4010 {
4011 	PRTDBG(("do_get_rates(%d)\n", fd));
4012 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_DESIRED_RATES, 0));
4013 }
4014 
4015 static boolean_t
4016 do_get_powermode(int fd)
4017 {
4018 	PRTDBG(("do_get_powermode(%d)\n", fd));
4019 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_POWER_MODE, 0));
4020 }
4021 
4022 static boolean_t
4023 do_get_authmode(int fd)
4024 {
4025 	PRTDBG(("do_get_authmode(%d)\n", fd));
4026 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_AUTH_MODE, 0));
4027 }
4028 
4029 static boolean_t
4030 do_get_encryption(int fd)
4031 {
4032 	PRTDBG(("do_get_encryption(%d)\n", fd));
4033 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_ENCRYPTION, 0));
4034 }
4035 
4036 static boolean_t
4037 do_get_wepkeyid(int fd)
4038 {
4039 	PRTDBG(("do_get_wepkeyid(%d)\n", fd));
4040 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_WEP_KEY_ID, 0));
4041 }
4042 static boolean_t
4043 do_get_signal(int fd)
4044 {
4045 	PRTDBG(("do_get_signal(%d)\n", fd));
4046 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_RSSI, 0));
4047 }
4048 
4049 static boolean_t
4050 do_get_radioon(int fd)
4051 {
4052 	PRTDBG(("do_get_radioon(%d)\n", fd));
4053 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_RADIO, 0));
4054 }
4055 
4056 /*
4057  * param has two kinds of forms:
4058  * 'wepkeyn=*****' (when equalflag == B_TRUE),
4059  * 'wepkeyn' (when equalflag == B_FALSE)
4060  */
4061 static boolean_t
4062 param_is_wepkey(char *param, boolean_t equalflag)
4063 {
4064 	if ((equalflag == B_FALSE) &&
4065 	    (strcmp(param, "wepkey1") == 0) ||
4066 	    (strcmp(param, "wepkey2") == 0) ||
4067 	    (strcmp(param, "wepkey3") == 0) ||
4068 	    (strcmp(param, "wepkey4") == 0))
4069 		return (B_TRUE);
4070 	else if ((equalflag == B_TRUE) &&
4071 	    (strncmp(param, "wepkey1=", strlen("wepkey1="))) == 0 ||
4072 	    (strncmp(param, "wepkey2=", strlen("wepkey2="))) == 0 ||
4073 	    (strncmp(param, "wepkey3=", strlen("wepkey3="))) == 0 ||
4074 	    (strncmp(param, "wepkey4=", strlen("wepkey4="))) == 0)
4075 		return (B_TRUE);
4076 	else
4077 		return (B_FALSE);
4078 }
4079 
4080 /*
4081  * update/add items in the profile
4082  */
4083 static boolean_t
4084 items_in_profile(aelist_t *cplist, aelist_t *wplist, int argc, char **argv)
4085 {
4086 	int i = 0, j = 0;
4087 	char *param;
4088 	char *pequal;
4089 	const char *wepkey;
4090 
4091 	for (i = 0; i < argc; i++) {
4092 		if (param_is_wepkey(argv[i], B_TRUE) == B_TRUE) {
4093 			wepkey = get_value(argv[i]);
4094 			if (value_is_valid(WEPKEY, wepkey) == B_FALSE) {
4095 				(void) fprintf(stderr, gettext("%s: "
4096 				    "invalid value '%s' for parameter "
4097 				    "'wepkey'\n"), gExecName, wepkey);
4098 				return (B_FALSE);
4099 			}
4100 			update_aelist(wplist, argv[i]);
4101 			continue;
4102 		}
4103 		param = safe_strdup(argv[i]);
4104 		pequal = strchr(param, '=');
4105 		if (pequal == NULL) {
4106 			(void) fprintf(stderr, gettext("%s: "
4107 			    "invalid argument '%s', use "
4108 			    "parameter=value'\n"),
4109 			    gExecName, argv[i]);
4110 			free(param);
4111 			return (B_FALSE);
4112 		}
4113 
4114 		*pequal++ = '\0';
4115 		for (j = 0; j < N_GS_FUNC; j++) {
4116 			if (strcmp(param, do_gs_func[j].cmd) == 0) {
4117 				break;
4118 			}
4119 		}
4120 		if (j == N_GS_FUNC) {
4121 			(void) fprintf(stderr, gettext("%s: "
4122 			    "unrecognized parameter '%s'\n"),
4123 			    gExecName, param);
4124 			free(param);
4125 			return (B_FALSE);
4126 		}
4127 		if (value_is_valid(do_gs_func[j].index, pequal) ==
4128 		    B_FALSE) {
4129 			(void) fprintf(stderr, gettext("%s: "
4130 			    "invalid value '%s' for parameter '%s'\n"),
4131 			    gExecName, pequal, param);
4132 			return (B_FALSE);
4133 		}
4134 		free(param);
4135 		update_aelist(cplist, argv[i]);
4136 	}
4137 	return (B_TRUE);
4138 }
4139 
4140 /*
4141  * do_createprofile: Called when create a profile off-line.
4142  */
4143 /*ARGSUSED*/
4144 static boolean_t
4145 do_createprofile(int fd, int argc, char **argv)
4146 {
4147 	int i = 0;
4148 	char *pbuf = NULL;
4149 	char *pfbuf = NULL;
4150 	const char *profilename;
4151 	aelist_t *plist_config = NULL, *plist_wepkey = NULL;
4152 
4153 	PRTDBG(("do_createprofile(%d, 0x%x)\n", argc, argv));
4154 	if (argc <= 0) {
4155 		do_print_usage();
4156 		exit(WIFI_IMPROPER_USE);
4157 	}
4158 	/*
4159 	 * When creating a profile, if the profile name is not specified,
4160 	 * the essid is selected as the profile name. the paramters are
4161 	 * saved into the section.
4162 	 */
4163 	if (strchr(argv[0], '=') == NULL) {
4164 		pfbuf = safe_strdup(argv[0]);
4165 		argc--;
4166 		argv++;
4167 	}
4168 	for (i = 0; i < argc; i++) {
4169 		if (strncmp(argv[i], "essid=", strlen("essid=")) == 0) {
4170 			break;
4171 		}
4172 	}
4173 	if (i == argc) {
4174 		(void) fprintf(stderr,
4175 		    gettext("%s: "
4176 		    "essid required when creating profile\n"),
4177 		    gExecName);
4178 		goto exit0;
4179 	}
4180 	profilename = (pfbuf ? pfbuf : get_value(argv[i]));
4181 	if (strlen(profilename) == 0) {
4182 		(void) fprintf(stderr,
4183 		    gettext("%s: "
4184 		    "non-empty essid required\n"),
4185 		    gExecName);
4186 		goto exit0;
4187 	}
4188 	/*
4189 	 * 'all', '{preference}', '{history}', '{active_profile}'
4190 	 * and any string with '[' as start and ']' as end should
4191 	 * not be a profile name
4192 	 */
4193 	if ((strcasecmp(profilename, "all") == 0) ||
4194 	    (strcmp(profilename, WIFI_HISTORY) == 0) ||
4195 	    (strcmp(profilename, WIFI_PREFER) == 0) ||
4196 	    (strcmp(profilename, WIFI_ACTIVEP) == 0) ||
4197 	    ((profilename[0] == '[') &&
4198 	    (profilename[strlen(profilename) - 1] == ']'))) {
4199 		(void) fprintf(stderr, gettext("%s: "
4200 		    "'%s' is an invalid profile name\n"),
4201 		    gExecName, profilename);
4202 		goto exit0;
4203 	}
4204 	pbuf = append_pa(profilename);
4205 
4206 	PRTDBG(("do_createprofile: profile_name = %s\n", pbuf));
4207 	if ((find_section(gp_config_file, pbuf) != NULL) ||
4208 	    find_section(gp_wepkey_file, pbuf) != NULL) {
4209 		(void) fprintf(stderr,
4210 		    gettext("%s: "
4211 		    "profile '%s' already exists\n"),
4212 		    gExecName, profilename);
4213 		goto exit1;
4214 	}
4215 	/*
4216 	 * Save each parameters in the profile.
4217 	 */
4218 	plist_config = new_ael(PROFILE);
4219 	new_section(gp_config_file, plist_config, pbuf);
4220 	plist_wepkey = new_ael(PROFILE);
4221 	new_section(gp_wepkey_file, plist_wepkey, pbuf);
4222 	free(pfbuf);
4223 	free(pbuf);
4224 	return (items_in_profile(plist_config, plist_wepkey,
4225 	    argc, argv));
4226 exit1:
4227 	free(pbuf);
4228 exit0:
4229 	free(pfbuf);
4230 	return (B_FALSE);
4231 }
4232 
4233 /*ARGSUSED*/
4234 static boolean_t
4235 do_setprofparam(int fd, int argc, char **argv)
4236 {
4237 	char *pbuf = NULL;
4238 	section_t *psection_config = NULL, *psection_wep = NULL;
4239 	aelist_t *plist_config = NULL, *plist_wepkey = NULL;
4240 
4241 	PRTDBG(("do_setprofparam(%d, 0x%x)\n", argc, argv));
4242 	if (argc < 1) {
4243 		do_print_usage();
4244 		exit(WIFI_IMPROPER_USE);
4245 	}
4246 	pbuf = append_pa(argv[0]);
4247 
4248 	psection_config = find_section(gp_config_file, pbuf);
4249 	psection_wep = find_section(gp_wepkey_file, pbuf);
4250 	if ((psection_config == NULL) || (psection_wep == NULL)) {
4251 		(void) fprintf(stderr, gettext("%s: "
4252 		    "profile '%s' doesn't exist\n"),
4253 		    gExecName, argv[0]);
4254 		free(pbuf);
4255 		return (B_FALSE);
4256 	}
4257 	free(pbuf);
4258 	/*
4259 	 * modify each parameters in the profile.
4260 	 */
4261 	plist_config = psection_config->list;
4262 	plist_wepkey = psection_wep->list;
4263 	argc--;
4264 	argv++;
4265 	return (items_in_profile(plist_config, plist_wepkey,
4266 	    argc, argv));
4267 }
4268 
4269 /*ARGSUSED*/
4270 static boolean_t
4271 do_getprofparam(int fd, int argc, char **argv)
4272 {
4273 	int i = 0, j = 0;
4274 	int flag;
4275 	boolean_t ret = B_TRUE;
4276 	section_t *p_section = NULL;
4277 	aelist_t *plist = NULL;
4278 	ae_t *pae = NULL;
4279 	char *pbuf = NULL;
4280 
4281 	PRTDBG(("do_getprofparam(%d, 0x%x)\n", argc, argv));
4282 	if (argc < 1) {
4283 		do_print_usage();
4284 		exit(WIFI_IMPROPER_USE);
4285 	}
4286 	pbuf = append_pa(argv[0]);
4287 	p_section = find_section(gp_config_file, pbuf);
4288 	if (p_section == NULL) {
4289 		(void) fprintf(stderr, gettext("%s: "
4290 		    "profile '%s' doesn't exist\n"),
4291 		    gExecName, argv[0]);
4292 		ret = B_FALSE;
4293 		goto exit0;
4294 	}
4295 	argc--;
4296 	argv++;
4297 
4298 	plist = p_section->list;
4299 	assert(plist != NULL);
4300 	/*
4301 	 * If no specific parameter typed, we print out all parameters
4302 	 */
4303 	if (argc == 0) {
4304 		pae = plist->ael_head;
4305 		while (pae != NULL) {
4306 			if (pae->ae_arg != NULL) {
4307 				(void) printf("\t%s\n", pae->ae_arg);
4308 			}
4309 			pae = pae->ae_next;
4310 		}
4311 		print_wepkey_info(p_section->section_id, NULL);
4312 		ret = B_TRUE;
4313 		goto exit0;
4314 	}
4315 
4316 	/*
4317 	 * Match function with do_gs_func[] table, and print its result
4318 	 */
4319 	for (i = 0; i < argc; i++) {
4320 		flag = 0;
4321 		for (j = 0; j < N_GS_FUNC; j++) {
4322 			if (strcmp(argv[i], do_gs_func[j].cmd) == 0) {
4323 				break;
4324 			}
4325 			if (param_is_wepkey(argv[i], B_FALSE) == B_TRUE) {
4326 				j = WEPKEY;
4327 				print_wepkey_info(p_section->section_id,
4328 				    argv[i]);
4329 				flag++;
4330 				break;
4331 			}
4332 		}
4333 		if (j == N_GS_FUNC) {
4334 			(void) fprintf(stderr,
4335 			    gettext("wificonifg: unrecognized parameter: "
4336 			    "%s\n"), argv[i]);
4337 			ret = B_FALSE;
4338 			goto exit0;
4339 		}
4340 
4341 		pae = plist->ael_head;
4342 		while ((pae != NULL) && (!flag)) {
4343 			if ((pae->ae_arg != NULL) &&
4344 			    (strncmp(pae->ae_arg, argv[i],
4345 			    strlen(argv[i])) == 0)) {
4346 				(void) printf("\t%s\n", pae->ae_arg);
4347 				flag++;
4348 			}
4349 			pae = pae->ae_next;
4350 		}
4351 		if (!flag) {
4352 			(void) fprintf(stderr, gettext("%s: "
4353 			    "parameter '%s' has not been set in profile %s\n"),
4354 			    gExecName, argv[i], pbuf);
4355 			ret = B_FALSE;
4356 			goto exit0;
4357 		}
4358 	}
4359 exit0:
4360 	free(pbuf);
4361 	return (ret);
4362 }
4363 
4364 /*
4365  * Verify whether the value in the parameter=value pair is valid or not.
4366  * For the channel, since we donot know what kind of wifi card(a,b,or g)
4367  * is in the system, so we just leave to verify the validity of the value
4368  * when the value is set to the card.
4369  * The same goes for the rates.
4370  */
4371 static boolean_t
4372 value_is_valid(config_item_t item, const char *value)
4373 {
4374 	uint32_t num = 0;
4375 	uint8_t *rates;
4376 	boolean_t ret;
4377 
4378 	assert(value != NULL);
4379 	switch (item) {
4380 	case ESSID:
4381 		if (strlen(value) > 32)
4382 			ret = B_FALSE;
4383 		else
4384 			ret = B_TRUE;
4385 		break;
4386 	case BSSTYPE:
4387 		if ((strcasecmp(value, "bss") == 0) ||
4388 		    (strcasecmp(value, "ap") == 0) ||
4389 		    (strcasecmp(value, "infrastructure") == 0) ||
4390 		    (strcasecmp(value, "ibss") == 0) ||
4391 		    (strcasecmp(value, "ad-hoc") == 0) ||
4392 		    (strcasecmp(value, "auto") == 0))
4393 			ret = B_TRUE;
4394 		else
4395 			ret = B_FALSE;
4396 		break;
4397 	case CREATEIBSS:
4398 		if ((strcasecmp(value, "yes") == 0) ||
4399 		    (strcasecmp(value, "no") == 0))
4400 			ret = B_TRUE;
4401 		else
4402 			ret = B_FALSE;
4403 		break;
4404 	case AUTHMODE:
4405 		if ((strcasecmp(value, "opensystem") == 0) ||
4406 		    (strcasecmp(value, "shared_key") == 0))
4407 			ret = B_TRUE;
4408 		else
4409 			ret = B_FALSE;
4410 		break;
4411 	case POWERMODE:
4412 		if ((strcasecmp(value, "off") == 0) ||
4413 		    (strcasecmp(value, "mps") == 0) ||
4414 		    (strcasecmp(value, "fast") == 0))
4415 			ret = B_TRUE;
4416 		else
4417 			ret = B_FALSE;
4418 		break;
4419 	case ENCRYPTION:
4420 		if ((strcasecmp(value, "wep") == 0) ||
4421 		    (strcasecmp(value, "none") == 0))
4422 			ret = B_TRUE;
4423 		else
4424 			ret = B_FALSE;
4425 		break;
4426 	case RADIOON:
4427 		if ((strcasecmp(value, "on") == 0) ||
4428 		    (strcasecmp(value, "off") == 0))
4429 			ret = B_TRUE;
4430 		else
4431 			ret = B_FALSE;
4432 		break;
4433 	case WEPKEYID:
4434 		ret = is_wepkeyindex_valid(value);
4435 		break;
4436 	case WEPKEY:
4437 		ret = is_wepkey_valid(value, strlen(value));
4438 		break;
4439 	case CHANNEL:
4440 		ret = is_channel_valid(value);
4441 		break;
4442 	case RATES:
4443 		rates = get_rates(value, &num);
4444 		if (rates == NULL) {
4445 			ret = B_FALSE;
4446 		} else {
4447 			free(rates);
4448 			ret = B_TRUE;
4449 		}
4450 		break;
4451 	default:
4452 		ret = B_FALSE;
4453 		break;
4454 	}
4455 
4456 	return (ret);
4457 }
4458 
4459 /*
4460  * do_set: Called when set a parameter, the format should be
4461  * parameter=value.
4462  */
4463 static boolean_t
4464 do_set(int fd, int argc, char **argv)
4465 {
4466 	int i = 0, j = 0;
4467 	char *param;
4468 	char *pequal;
4469 	char *value;
4470 	boolean_t ret;
4471 
4472 	PRTDBG(("do_set(%d, 0x%x)\n", argc, argv));
4473 	assert(fd > 0);
4474 	if (argc <= 0) {
4475 		(void) do_print_support_params(fd);
4476 		ret = B_FALSE;
4477 		goto exit0;
4478 	}
4479 	/*
4480 	 * Set each parameters, if one failed, others behind it will
4481 	 * not be set
4482 	 */
4483 	for (i = 0; i < argc; i++) {
4484 		/*
4485 		 * Separate param and its value, if the user types "param=",
4486 		 * then value will be set to "";if the user types "param",
4487 		 * it is an error.
4488 		 */
4489 		param = safe_strdup(argv[i]);
4490 		pequal = strchr(param, '=');
4491 		value = NULL;
4492 		if (pequal != NULL) {
4493 			*pequal = '\0';
4494 			value = pequal + 1;
4495 		} else {
4496 			(void) fprintf(stderr,
4497 			    gettext("%s: invalid setparam argument "
4498 			    "'%s', use 'parameter=value'\n"),
4499 			    gExecName, argv[i]);
4500 			free(param);
4501 			ret = B_FALSE;
4502 			goto exit0;
4503 		}
4504 		PRTDBG(("do_set: param = \"%s\", value = \"%s\"\n",
4505 		    param, value));
4506 		for (j = 0; j < N_GS_FUNC; j++) {
4507 			/*
4508 			 * Match each parameters with do_gs_func table,
4509 			 */
4510 			if (strcmp(param, do_gs_func[j].cmd) == 0)
4511 				break;
4512 			if (param_is_wepkey(param, B_FALSE) == B_TRUE) {
4513 				value = argv[i];
4514 				j = WEPKEY;
4515 				break;
4516 			}
4517 		}
4518 		if (j == N_GS_FUNC) {
4519 			(void) fprintf(stderr,
4520 			    gettext("%s: unrecognized parameter: "
4521 			    "%s\n"), gExecName, param);
4522 			free(param);
4523 			ret  = B_FALSE;
4524 			goto exit0;
4525 		}
4526 
4527 		if (do_gs_func[j].p_do_set_func == NULL) {
4528 			(void) fprintf(stderr,
4529 			    gettext("%s: parameter '%s' is read-only\n"),
4530 			    gExecName, do_gs_func[j].cmd);
4531 			free(param);
4532 			ret = B_FALSE;
4533 			goto exit0;
4534 		}
4535 		if (do_gs_func[j].p_do_set_func(fd, value)
4536 		    == B_TRUE) {
4537 			ret = B_TRUE;
4538 		} else {
4539 			if (gbuf->wldp_result != WL_SUCCESS) {
4540 				(void) fprintf(stderr,
4541 				    gettext("%s: "
4542 				    "failed to set '%s' for "),
4543 				    gExecName, param);
4544 				print_error(gbuf->wldp_result);
4545 			}
4546 			free(param);
4547 			ret = B_FALSE;
4548 			goto exit0;
4549 		}
4550 		free(param);
4551 	}
4552 exit0:
4553 	return (ret);
4554 }
4555 
4556 static boolean_t
4557 do_get(int fd, int argc, char **argv)
4558 {
4559 	int i = 0, j = 0, n = 0;
4560 	boolean_t ret = B_TRUE;
4561 
4562 	PRTDBG(("do_get(%d, 0x%x)\n", argc, argv));
4563 	assert(fd > 0);
4564 	/*
4565 	 * If no specific parameter typed, we print out all parameters
4566 	 */
4567 	if (argc <= 0) {
4568 		for (i = 0; i < N_GS_FUNC; i++) {
4569 			if ((do_gs_func[i].p_do_get_func != NULL) &&
4570 			    (do_gs_func[i].p_do_get_func(fd)
4571 			    == B_TRUE)) {
4572 				print_gbuf(do_gs_func[i].index);
4573 				n++;
4574 			}
4575 		}
4576 		ret = n ? B_TRUE:B_FALSE;
4577 		goto exit0;
4578 	}
4579 	/*
4580 	 * Match function with do_gs_func[] table, and print its result
4581 	 */
4582 	for (i = 0; i < argc; i++) {
4583 		for (j = 0; j < N_GS_FUNC; j++) {
4584 			if (strcmp(argv[i], do_gs_func[j].cmd) == 0) {
4585 				break;
4586 			}
4587 			if (param_is_wepkey(argv[i], B_FALSE) == B_TRUE) {
4588 				j = WEPKEY;
4589 				break;
4590 			}
4591 		}
4592 		if (j == N_GS_FUNC) {
4593 			(void) fprintf(stderr,
4594 			    gettext("wificonifg: unrecognized parameter: "
4595 			    "%s\n"), argv[i]);
4596 			ret = B_FALSE;
4597 			goto exit0;
4598 		}
4599 		if (do_gs_func[j].p_do_get_func == NULL) {
4600 			(void) fprintf(stderr,
4601 			    gettext("%s: parameter '%s' is write-only\n"),
4602 			    gExecName, do_gs_func[j].cmd);
4603 			ret = B_FALSE;
4604 			goto exit0;
4605 		}
4606 		if (do_gs_func[j].p_do_get_func(fd) == B_TRUE) {
4607 			print_gbuf(do_gs_func[j].index);
4608 			ret = B_TRUE;
4609 		} else {
4610 			(void) fprintf(stderr,
4611 			    gettext("%s: "
4612 			    "failed to read parameter '%s' : "),
4613 			    gExecName, argv[i]);
4614 			print_error(gbuf->wldp_result);
4615 			ret = B_FALSE;
4616 		}
4617 	}
4618 exit0:
4619 	return (ret);
4620 }
4621 
4622 /*
4623  * Only one wificonfig is running at one time.
4624  * The following wificonfig which tries to be run will return error,
4625  * and the pid of the process will own the filelock will be printed out.
4626  */
4627 static pid_t
4628 enter_wifi_lock(int *fd)
4629 {
4630 	int fd0 = -1;
4631 	struct flock lock;
4632 
4633 	fd0 = open(WIFI_LOCKF, O_CREAT|O_WRONLY, 0600);
4634 	if (fd0 < 0) {
4635 		(void) fprintf(stderr, gettext("%s: failed to open lockfile"
4636 		    " '"WIFI_LOCKF"': %s\n"), gExecName, strerror(errno));
4637 		exit(WIFI_FATAL_ERR);
4638 	}
4639 
4640 	*fd = fd0;
4641 	lock.l_type = F_WRLCK;
4642 	lock.l_whence = SEEK_SET;
4643 	lock.l_start = 0;
4644 	lock.l_len = 0;
4645 
4646 	if ((fcntl(fd0, F_SETLK, &lock) == -1) &&
4647 	    (errno == EAGAIN || errno == EDEADLK)) {
4648 		if (fcntl(fd0, F_GETLK, &lock) == -1) {
4649 			(void) fprintf(stderr,
4650 			    gettext("%s: enter_filelock"));
4651 			exit(WIFI_FATAL_ERR);
4652 		}
4653 		(void) fprintf(stderr, gettext("%s:"
4654 		    "enter_filelock:filelock is owned "
4655 		    "by 'process %d'\n"), gExecName, lock.l_pid);
4656 		return (lock.l_pid);
4657 	}
4658 
4659 	return (getpid());
4660 }
4661 
4662 static void
4663 exit_wifi_lock(int fd)
4664 {
4665 	struct flock lock;
4666 
4667 	lock.l_type = F_UNLCK;
4668 	lock.l_whence = SEEK_SET;
4669 	lock.l_start = 0;
4670 	lock.l_len = 0;
4671 	if (fcntl(fd, F_SETLK, &lock) == -1) {
4672 		(void) fprintf(stderr, gettext("%s: failed to"
4673 		    " exit_filelock: %s\n"),
4674 		    gExecName, strerror(errno));
4675 	}
4676 	(void) close(fd);
4677 }
4678 
4679 int
4680 main(int argc, char **argv)
4681 {
4682 	int i, ret;
4683 	int fddev = -1;
4684 	int c, iflag = 0, rflag = 0, fileonly = 0, readonly = 0;
4685 	int fd;
4686 	char *iname = NULL;
4687 	char *path = NULL;
4688 	extern char *optarg;
4689 	extern int optind;
4690 	char interface[LIFNAMSIZ];
4691 	char file_wifi[MAX_CONFIG_FILE_LENGTH];
4692 	char file_wifiwepkey[MAX_CONFIG_FILE_LENGTH];
4693 	priv_set_t *ppriv;
4694 	wifi_auth_t autht;
4695 
4696 	PRTDBG(("main(%d, 0x%x)\n", argc, argv));
4697 	PRTDBG(("uid=%d\n", getuid()));
4698 	PRTDBG(("euid=%d\n", geteuid()));
4699 
4700 #ifdef DEBUG
4701 	if (wifi_debug == 1) { /* for debuf purpose only */
4702 		(void) printf("Press RETURN to continue...\n");
4703 		(void) getchar();
4704 	}
4705 #endif
4706 	ret = WIFI_EXIT_DEF;
4707 
4708 	(void) setlocale(LC_ALL, "");
4709 	(void) textdomain(TEXT_DOMAIN);
4710 
4711 	gExecName = argv[0];
4712 
4713 	gbuf = safe_malloc(MAX_BUF_LEN);
4714 
4715 	if ((ppriv = priv_str_to_set("basic", ",", NULL)) == NULL) {
4716 		PRTDBG(("main: priviledge init error\n"));
4717 		(void) fprintf(stderr, gettext("%s: "
4718 		    "set priviledge to 'basic' error\n"),
4719 		    gExecName);
4720 		ret = WIFI_FATAL_ERR;
4721 		goto exit0;
4722 	}
4723 	(void) priv_addset(ppriv, PRIV_NET_RAWACCESS);
4724 	(void) priv_addset(ppriv, PRIV_SYS_NET_CONFIG);
4725 	if (setppriv(PRIV_SET, PRIV_PERMITTED, ppriv) == -1) {
4726 		(void) fprintf(stderr, gettext("%s: "
4727 		    "set permitted priviledge: %s\n"),
4728 		    gExecName, strerror(errno));
4729 		ret = WIFI_FATAL_ERR;
4730 		goto exit0;
4731 	}
4732 	if (setppriv(PRIV_SET, PRIV_LIMIT, ppriv) == -1) {
4733 		(void) fprintf(stderr, gettext("%s: "
4734 		    "set limit priviledge: %s\n"),
4735 		    gExecName, strerror(errno));
4736 		ret = WIFI_FATAL_ERR;
4737 		goto exit0;
4738 	}
4739 	if (setppriv(PRIV_SET, PRIV_INHERITABLE, ppriv) == -1) {
4740 		(void) fprintf(stderr, gettext("%s: "
4741 		    "set inherit priviledge: %s\n"),
4742 		    gExecName, strerror(errno));
4743 		ret = WIFI_FATAL_ERR;
4744 		goto exit0;
4745 	}
4746 	if (setppriv(PRIV_SET, PRIV_EFFECTIVE, ppriv) == -1) {
4747 		(void) fprintf(stderr, gettext("%s: "
4748 		    "set effective priviledge: %s\n"),
4749 		    gExecName, strerror(errno));
4750 		ret = WIFI_FATAL_ERR;
4751 		goto exit0;
4752 	}
4753 	priv_freeset(ppriv);
4754 
4755 	for (i = 0; i < argc; i++) {
4756 		PRTDBG(("%d\t\t\"%s\"\n", i, argv[i]));
4757 	}
4758 
4759 	while ((c = getopt(argc, argv, "i:R:")) != EOF) {
4760 		switch (c) {
4761 		case 'i':
4762 			if (iflag) {
4763 				do_print_usage();
4764 				ret = WIFI_IMPROPER_USE;
4765 				goto exit0;
4766 			}
4767 			iflag = 1;
4768 			iname = optarg;
4769 			break;
4770 		case 'R':
4771 			if (rflag) {
4772 				do_print_usage();
4773 				ret = WIFI_IMPROPER_USE;
4774 				goto exit0;
4775 			}
4776 			rflag = 1;
4777 			path = optarg;
4778 			break;
4779 		case '?':
4780 		default:
4781 			do_print_usage();
4782 			ret = WIFI_IMPROPER_USE;
4783 			goto exit0;
4784 		}
4785 	}
4786 	argc -= optind;
4787 	argv +=	optind;
4788 
4789 	if (argc <= 0) {
4790 		if (iname) {
4791 			if ((fddev = open_dev(iname)) == -1) {
4792 				ret = WIFI_FATAL_ERR;
4793 				goto exit0;
4794 			}
4795 			if (do_print_support_params(fddev) ==
4796 			    B_TRUE)
4797 				ret = WIFI_EXIT_DEF;
4798 			else
4799 				ret = WIFI_FATAL_ERR;
4800 			goto exit1;
4801 		} else {
4802 			do_print_usage();
4803 			ret = WIFI_IMPROPER_USE;
4804 			goto exit0;
4805 		}
4806 	}
4807 
4808 	for (i = 0; i < N_FUNC; i++) {
4809 		if (strcmp(argv[0], do_func[i].cmd) == 0) {
4810 			autht = ((strcmp(argv[0], "setwepkey") == 0) ||
4811 			    (strcmp(argv[0], "setprofwepkey") == 0)) ?
4812 			    AUTH_WEP:AUTH_OTHER;
4813 			if (do_func[i].b_auth &&
4814 			    !check_authority(autht)) {
4815 				ret = WIFI_FATAL_ERR;
4816 				goto exit0;
4817 			}
4818 			if (do_func[i].b_fileonly)
4819 				fileonly++;
4820 			if (do_func[i].b_readonly)
4821 				readonly++;
4822 			break;
4823 		}
4824 	}
4825 	if (i == N_FUNC) {
4826 		(void) fprintf(stderr, gettext("%s: unrecognized "
4827 		    "subcommand: %s\n"), gExecName, argv[0]);
4828 		do_print_usage();
4829 		ret = WIFI_IMPROPER_USE;
4830 		goto exit0;
4831 	}
4832 	if ((fileonly) && (iname)) {
4833 		do_print_usage();
4834 		ret = WIFI_IMPROPER_USE;
4835 		goto exit0;
4836 	}
4837 	if ((!fileonly) && (!iname)) {
4838 		if (search_interface(interface) != B_TRUE) {
4839 			(void) fprintf(stderr, gettext("%s: "
4840 			    "failed to find the default wifi interface;"
4841 			    " -i option should be used to specify the "
4842 			    "wifi interface\n"), gExecName);
4843 			ret = WIFI_FATAL_ERR;
4844 			goto exit0;
4845 		}
4846 		iname = interface;
4847 	}
4848 	if (iname) {
4849 		if ((fddev = open_dev(iname)) == -1) {
4850 			ret = WIFI_FATAL_ERR;
4851 			goto exit0;
4852 		}
4853 	}
4854 	if (rflag) {
4855 		safe_snprintf(file_wifi, sizeof (file_wifi),
4856 		    "%s%s", path, p_file_wifi);
4857 		safe_snprintf(file_wifiwepkey, sizeof (file_wifiwepkey),
4858 		    "%s%s", path, p_file_wifiwepkey);
4859 	} else {
4860 		safe_snprintf(file_wifi, sizeof (file_wifi),
4861 		    "%s", p_file_wifi);
4862 		safe_snprintf(file_wifiwepkey, sizeof (file_wifiwepkey),
4863 		    "%s", p_file_wifiwepkey);
4864 	}
4865 	/*
4866 	 * There is an occasion when more than one wificonfig processes
4867 	 * which attempt to write the <wifi> and <wifiwepkey> files are
4868 	 * running. We must be able to avoid this.
4869 	 * We use file lock here to implement this.
4870 	 */
4871 	if ((!readonly) && (enter_wifi_lock(&fd) != getpid())) {
4872 		ret = WIFI_FATAL_ERR;
4873 		goto exit1;
4874 	}
4875 	gp_config_file = parse_file(file_wifi);
4876 	if (gp_config_file == NULL) {
4877 		ret = WIFI_FATAL_ERR;
4878 		goto exit2;
4879 	}
4880 
4881 	gp_wepkey_file = parse_file(file_wifiwepkey);
4882 	if (gp_wepkey_file == NULL) {
4883 		destroy_config(gp_config_file);
4884 		ret = WIFI_FATAL_ERR;
4885 		goto exit2;
4886 	}
4887 	if (do_func[i].p_do_func(fddev, argc-1, argv+1)
4888 	    == B_TRUE) {
4889 		/*
4890 		 * can not write file when startconfing
4891 		 * during boot
4892 		 */
4893 		if (do_func[i].b_readonly)
4894 			ret = WIFI_EXIT_DEF;
4895 		else if ((fprint_config_file(gp_config_file,
4896 		    file_wifi) != B_TRUE) ||
4897 		    (fprint_config_file(gp_wepkey_file,
4898 		    file_wifiwepkey) != B_TRUE))
4899 			ret = WIFI_FATAL_ERR;
4900 		else
4901 			ret = WIFI_EXIT_DEF;
4902 	} else {
4903 		PRTDBG(("Command %s failed\n", argv[0]));
4904 		ret = WIFI_FATAL_ERR;
4905 	}
4906 	destroy_config(gp_wepkey_file);
4907 	destroy_config(gp_config_file);
4908 exit2:
4909 	if (!readonly)
4910 		exit_wifi_lock(fd);
4911 exit1:
4912 	if (iname)
4913 		(void) close(fddev);
4914 exit0:
4915 	free(gbuf);
4916 	return (ret);
4917 }
4918 
4919 #ifdef DEBUG
4920 static void
4921 wifi_dbgprintf(char *fmt, ...)
4922 {
4923 	va_list ap;
4924 	va_start(ap, fmt);
4925 	(void) vfprintf(stdout, fmt, ap);
4926 	va_end(ap);
4927 }
4928 #endif
4929