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