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