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