1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Copyright (c) 2018, Joyent, Inc.
28  */
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stddef.h>
33 #include <errno.h>
34 #include <ctype.h>
35 #include <stdarg.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <net/if.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/wait.h>
42 #include <sys/ipc.h>
43 #include <sys/ddi.h>
44 #include <stropts.h>
45 #include <assert.h>
46 #include <termios.h>
47 #include <time.h>
48 #include <string.h>
49 #include <strings.h>
50 #include <auth_attr.h>
51 #include <auth_list.h>
52 #include <libdevinfo.h>
53 #include <secdb.h>
54 #include <priv.h>
55 #include <pwd.h>
56 #include <umem.h>
57 #include <locale.h>
58 #include <libintl.h>
59 #include <dirent.h>
60 #include <inet/wifi_ioctl.h>
61 
62 /*
63  * Debug information
64  */
65 #ifdef	DEBUG
66 int wifi_debug = 0;
67 void wifi_dbgprintf(char *fmt, ...);
68 #define	PRTDBG(msg) if (wifi_debug > 1) wifi_dbgprintf msg
69 #else /* DEBUG */
70 #define	PRTDBG(msg)
71 #endif /* DEBUG */
72 
73 #define	MAX_HISTORY_NUM			10
74 #define	MAX_PREFERENCE_NUM		10
75 #define	MAX_SCANBUF_LEN			256
76 #define	MAX_CONFIG_FILE_LENGTH		256
77 #define	MAX_LOADPF_LENGTH		256
78 #define	LOADPROFILE_TIMEOUT		10
79 #define	RECORD_ADD		0
80 #define	RECORD_DEL		1
81 /*
82  * Wificonfig exit status
83  */
84 #define	WIFI_EXIT_DEF		0
85 #define	WIFI_FATAL_ERR		1
86 #define	WIFI_IMPROPER_USE	2
87 #define	WIFI_MINOR_ERR		3
88 
89 #define	WIFI_LOCKF "/var/run/lockf_wifi"
90 
91 typedef enum {
92 	PREFERENCE,
93 	HISTORY,
94 	ACTIVEP,
95 	PROFILE,
96 	OTHER
97 } list_type_t;
98 
99 #define	WIFI_PREFER	"{preference}"
100 #define	WIFI_HISTORY	"{history}"
101 #define	WIFI_ACTIVEP	"{active_profile}"
102 
103 typedef enum {
104 	LINKSTATUS = 0,
105 	BSSID,
106 	ESSID,
107 	BSSTYPE,
108 	CREATEIBSS,
109 	CHANNEL,
110 	RATES,
111 	POWERMODE,
112 	AUTHMODE,
113 	ENCRYPTION,
114 	WEPKEYID,
115 	WEPKEY,
116 	SIGNAL,
117 	RADIOON,
118 	WLANLIST,
119 	CONFIG_ITEM_END /* 15 */
120 } config_item_t;
121 typedef struct ae {
122 	struct ae *ae_next;
123 	char *ae_arg;
124 }ae_t;
125 typedef struct aelist {
126 	int ael_argc;
127 	ae_t *ael_head, *ael_tail;
128 	list_type_t type;
129 }aelist_t;
130 typedef struct section {
131 	struct section *section_next;
132 	aelist_t *list;
133 	char *section_id;
134 }section_t;
135 
136 /*
137  * config_file_t is an abstract of configration file,
138  * either/etc/inet/wifi/wifi.<interface> or /etc/inet/secret/
139  * wifi/wifiwepkey.<interface>
140  */
141 typedef struct config_file {
142 	int section_argc;
143 	section_t *section_head, *section_tail;
144 }config_file_t;
145 
146 static config_file_t *gp_config_file = NULL;
147 static config_file_t *gp_wepkey_file = NULL;
148 static char *p_file_wifi = "/etc/inet/wifi";
149 static char *p_file_wifiwepkey = "/etc/inet/secret/wifiwepkey";
150 
151 typedef enum {
152 	AUTH_WEP = 0,
153 	AUTH_OTHER = 1
154 } wifi_auth_t;
155 
156 static char *p_auth_string[] = {
157 	WIFI_WEP_AUTH,
158 	WIFI_CONFIG_AUTH
159 };
160 
161 /*
162  * gbuf: is a global buf, which is used to communicate between the user and
163  * the driver
164  */
165 static wldp_t *gbuf = NULL;
166 static char *gExecName = NULL;
167 
168 static void print_error(uint32_t);
169 static void *safe_malloc(size_t);
170 static void *safe_calloc(size_t, size_t);
171 static char *safe_strdup(const char *s1);
172 static void safe_snprintf(char *s, size_t n,
173     const char *format, ...);
174 static void safe_fclose(FILE *stream);
175 static void new_ae(aelist_t *ael, const char *arg);
176 static aelist_t *new_ael(list_type_t type);
177 static config_file_t *new_config_file();
178 static void new_section(config_file_t *p_config_file, aelist_t *p_list,
179 	const char *section_id);
180 static void destroy_config(config_file_t *p_config_file);
181 static config_file_t *parse_file(const char *pfile);
182 static char **aeltoargv(aelist_t *ael, int *ael_num);
183 static boolean_t fprint_config_file(config_file_t *p_config_file,
184 	const char *file_name);
185 static char *append_pa(const char *arg);
186 static section_t *find_section(config_file_t *p_config_file,
187 	const char *section_id);
188 static ae_t *find_ae(aelist_t *plist, const char *arg);
189 static void update_aelist(aelist_t *plist, const char *arg);
190 static const char *get_value(const char *arg);
191 static char *find_active_profile(int);
192 static const char *essid_of_profile(const char *profile);
193 static boolean_t search_interface(char *interface);
194 static int open_dev(char *devname);
195 static boolean_t call_ioctl(int, int, uint32_t, uint32_t);
196 static boolean_t del_prefer(config_file_t *p_config_file, const char *prefer,
197     boolean_t rflag);
198 static boolean_t del_section(config_file_t *p_config_file, char *section_id);
199 static boolean_t set_prefer(config_file_t *p_config_file, const char *prefer,
200 	int rank);
201 static void add_to_history(config_file_t *p_config_file,
202     int argc, char **argv);
203 static boolean_t check_authority(wifi_auth_t type);
204 static void heuristic_load(int fd, uint32_t ess_num, wl_ess_conf_t **);
205 static char *select_profile(int fd, int readonly, int timeout);
206 static char *construct_format(uint32_t nt);
207 static void print_gbuf(config_item_t index);
208 static boolean_t items_in_profile(aelist_t *, aelist_t *, int, char **);
209 static char *get_commit_key(int, int, char **);
210 static void print_wepkey_info(const char *id, const char *wepkeyn);
211 static void  do_print_usage();
212 static boolean_t do_print_support_params(int fd);
213 static boolean_t do_autoconf(int fd, int argc, char **argv);
214 static boolean_t do_startconf(int fd, int argc, char **argv);
215 static boolean_t do_loadpf(int fd, int argc, char **argv);
216 static boolean_t do_disconnect(int fd, int argc, char **argv);
217 static boolean_t do_printpf(int fd, int argc, char **argv);
218 static boolean_t do_restoredef(int fd, int argc, char **argv);
219 static boolean_t do_history(int fd, int argc, char **argv);
220 static boolean_t do_deletepf(int fd, int argc, char **argv);
221 static boolean_t do_wepkey(int fd, int argc, char **argv);
222 static boolean_t do_setprefer(int fd, int argc, char **arg);
223 static boolean_t do_rmprefer(int fd, int argc, char **argv);
224 static boolean_t do_lsprefer(int fd, int argc, char **argv);
225 static boolean_t do_wlanlist(int fd, int argc, char **argv);
226 static boolean_t do_showstatus(int fd, int argc, char **argv);
227 static boolean_t do_getprofparam(int fd, int argc, char **argv);
228 static boolean_t do_setprofparam(int fd, int argc, char **argv);
229 static boolean_t do_setprofwepkey(int fd, int argc, char **argv);
230 static boolean_t is_rates_support(int fd, int num, uint8_t *rates);
231 static boolean_t do_set_bsstype(int fd, const char *arg);
232 static boolean_t do_set_essid(int fd, const char *arg);
233 static boolean_t do_set_powermode(int fd, const char *arg);
234 static boolean_t do_set_rates(int fd, const char *arg);
235 static boolean_t do_set_channel(int fd, const char *arg);
236 static boolean_t do_set_createibss(int fd, const char *arg);
237 static boolean_t do_set_radioon(int fd, const char *arg);
238 static boolean_t do_set_wepkeyid(int fd, const char *arg);
239 static boolean_t do_set_encryption(int fd, const char *arg);
240 static boolean_t do_set_authmode(int fd, const char *arg);
241 static boolean_t do_set_wepkey(int fd, const char *pbuf);
242 static boolean_t do_get_createibss(int fd);
243 static boolean_t do_get_bsstype(int fd);
244 static boolean_t do_get_essid(int fd);
245 static boolean_t do_get_bssid(int fd);
246 static boolean_t do_get_radioon(int fd);
247 static boolean_t do_get_signal(int fd);
248 static boolean_t do_get_wepkeyid(int fd);
249 static boolean_t do_get_encryption(int fd);
250 static boolean_t do_get_authmode(int fd);
251 static boolean_t do_get_powermode(int fd);
252 static boolean_t do_get_rates(int fd);
253 static boolean_t do_get_wlanlist(int fd);
254 static boolean_t do_get_linkstatus(int fd);
255 static boolean_t do_get_channel(int fd);
256 static boolean_t do_get(int fd, int argc, char **argv);
257 static boolean_t do_set(int fd, int argc, char **argv);
258 static boolean_t do_createprofile(int fd, int argc, char **argv);
259 static boolean_t value_is_valid(config_item_t item, const char *value);
260 
261 typedef struct cmd_ops {
262 	char cmd[32];
263 	boolean_t (*p_do_func)(int fd, int argc, char **argv);
264 	boolean_t b_auth;
265 	boolean_t b_fileonly; /* operation only on the config file */
266 	boolean_t b_readonly; /* only read from the card or config file */
267 } cmd_ops_t;
268 static cmd_ops_t do_func[] = {
269 	{
270 		"autoconf",
271 		do_autoconf,
272 		B_TRUE,
273 		B_FALSE,
274 		B_FALSE
275 	},
276 	{
277 		"startconf",
278 		do_startconf,
279 		B_TRUE,
280 		B_FALSE,
281 		B_TRUE
282 	},
283 	{
284 		"connect",
285 		do_loadpf,
286 		B_TRUE,
287 		B_FALSE,
288 		B_FALSE
289 	},
290 	{
291 		"disconnect",
292 		do_disconnect,
293 		B_TRUE,
294 		B_FALSE,
295 		B_FALSE
296 	},
297 	{
298 		"showprofile",
299 		do_printpf,
300 		B_FALSE,
301 		B_TRUE,
302 		B_TRUE
303 	},
304 	{
305 		"deleteprofile",
306 		do_deletepf,
307 		B_TRUE,
308 		B_TRUE,
309 		B_FALSE
310 	},
311 	{
312 		"history",
313 		do_history,
314 		B_FALSE,
315 		B_TRUE,
316 		B_TRUE
317 	},
318 	{
319 		"listprefer",
320 		do_lsprefer,
321 		B_FALSE,
322 		B_TRUE,
323 		B_TRUE
324 	},
325 	{
326 		"removeprefer",
327 		do_rmprefer,
328 		B_TRUE,
329 		B_TRUE,
330 		B_FALSE
331 	},
332 	{
333 		"setprefer",
334 		do_setprefer,
335 		B_TRUE,
336 		B_TRUE,
337 		B_FALSE
338 	},
339 	{
340 		"setwepkey",
341 		do_wepkey,
342 		B_TRUE,
343 		B_FALSE,
344 		B_FALSE
345 	},
346 	{
347 		"restoredef",
348 		do_restoredef,
349 		B_TRUE,
350 		B_FALSE,
351 		B_FALSE
352 	},
353 	{
354 		"getparam",
355 		do_get,
356 		B_FALSE,
357 		B_FALSE,
358 		B_TRUE
359 	},
360 	{
361 		"setparam",
362 		do_set,
363 		B_TRUE,
364 		B_FALSE,
365 		B_FALSE
366 	},
367 	{
368 		"createprofile",
369 		do_createprofile,
370 		B_TRUE,
371 		B_TRUE,
372 		B_FALSE
373 	},
374 	{
375 		"scan",
376 		do_wlanlist,
377 		B_FALSE,
378 		B_FALSE,
379 		B_FALSE
380 	},
381 	{
382 		"showstatus",
383 		do_showstatus,
384 		B_FALSE,
385 		B_FALSE,
386 		B_TRUE
387 	},
388 	{
389 		"setprofileparam",
390 		do_setprofparam,
391 		B_TRUE,
392 		B_TRUE,
393 		B_FALSE
394 	},
395 	{
396 		"getprofileparam",
397 		do_getprofparam,
398 		B_FALSE,
399 		B_TRUE,
400 		B_TRUE
401 	},
402 	{
403 		"setprofilewepkey",
404 		do_setprofwepkey,
405 		B_TRUE,
406 		B_TRUE,
407 		B_FALSE
408 	}
409 };
410 
411 
412 typedef enum {RW, RO, WO} rw_property_t;
413 typedef struct gs_ops {
414 	config_item_t index;
415 	char cmd[32];
416 	boolean_t (*p_do_get_func)(int fd);
417 	boolean_t (*p_do_set_func)(int fd, const char *arg);
418 	rw_property_t rw;
419 } gs_ops_t;
420 static gs_ops_t do_gs_func[] = {
421 	{LINKSTATUS, "linkstatus", NULL, NULL, RO},
422 	{BSSID, "bssid", do_get_bssid, NULL, RO},
423 	{ESSID, "essid", do_get_essid, do_set_essid, RW},
424 	{BSSTYPE, "bsstype", do_get_bsstype, do_set_bsstype, RW},
425 	{CREATEIBSS, "createibss", do_get_createibss, do_set_createibss, RW},
426 	{CHANNEL, "channel", do_get_channel, do_set_channel, RW},
427 	{RATES, "rates", do_get_rates, do_set_rates, RW},
428 	{POWERMODE, "powermode", do_get_powermode, do_set_powermode, RW},
429 	{AUTHMODE, "authmode", do_get_authmode, do_set_authmode, RW},
430 	{ENCRYPTION, "encryption", do_get_encryption, do_set_encryption, RW},
431 	{WEPKEYID, "wepkeyindex", do_get_wepkeyid, do_set_wepkeyid, RW},
432 	{WEPKEY, "wepkey|1-4", NULL, do_set_wepkey, WO},
433 	{SIGNAL, "signal", do_get_signal, NULL, RO},
434 	{RADIOON, "radio",	do_get_radioon, do_set_radioon, RW},
435 };
436 
437 #define	N_FUNC		sizeof (do_func) / sizeof (cmd_ops_t)
438 #define	N_GS_FUNC 	sizeof (do_gs_func) / sizeof (gs_ops_t)
439 
440 /*
441  * valid rate value
442  */
443 typedef	struct wifi_rates_tab {
444 	char *rates_s;
445 	uint8_t rates_i;
446 	uint8_t rates_reserve0;
447 	uint8_t rates_reserve1;
448 	uint8_t rates_reserve2;
449 } wifi_rates_tab_t;
450 
451 /*
452  * the rates value is in increments of 500kb/s.
453  * according to the 802.11 a/b/g specs(IEEE):
454  * 802.11b(IEEE Std 802.11b-1999) page35, rates should be:
455  *	X02, X04, X0b, X16
456  * 802.11a(IEEE Std 802.11a-1999) page47, rates should be:
457  *	6,9,12,18,24,36,48,54 Mb/s
458  * 802.11g(IEEE Std 802.11g-2003) page44, rates should be:
459  *	1,2,5.5,11,6,9,12,18,22,24,33,36,48,54 Mb/s
460  */
461 #define	WIFI_RATES_NUM	14
462 static wifi_rates_tab_t wifi_rates_s[WIFI_RATES_NUM] = {
463 	{"1",	WL_RATE_1M,	0,	0,	0},
464 	{"2",	WL_RATE_2M,	0,	0,	0},
465 	{"5.5",	WL_RATE_5_5M,	0,	0,	0},
466 	{"6",	WL_RATE_6M,	0,	0,	0},
467 	{"9",	WL_RATE_9M,	0,	0,	0},
468 	{"11",	WL_RATE_11M,	0,	0,	0},
469 	{"12",	WL_RATE_12M,	0,	0,	0},
470 	{"18",	WL_RATE_18M,	0,	0,	0},
471 	{"22",	WL_RATE_22M,	0,	0,	0},
472 	{"24",	WL_RATE_24M,	0,	0,	0},
473 	{"33",	WL_RATE_33M,	0,	0,	0},
474 	{"36",	WL_RATE_36M,	0,	0,	0},
475 	{"48",	WL_RATE_48M,	0,	0,	0},
476 	{"54",	WL_RATE_54M,	0,	0,	0}
477 };
478 /* print the error message on why set or get ioctl command failed. */
479 static void
print_error(uint32_t errorno)480 print_error(uint32_t errorno)
481 {
482 	char *buf;
483 
484 	switch (errorno) {
485 	case WL_SUCCESS:
486 		buf = gettext("command succeeded");
487 		break;
488 	case WL_NOTSUPPORTED:
489 	case WL_LACK_FEATURE:
490 	case WL_HW_ERROR:
491 	case WL_ACCESS_DENIED:
492 		buf = strerror(errorno);
493 		break;
494 	case WL_READONLY:
495 		buf = gettext("parameter read-only");
496 		break;
497 	case WL_WRITEONLY:
498 		buf = gettext("parameter write-only");
499 		break;
500 	case WL_NOAP:
501 		buf = gettext("no access point available");
502 		break;
503 	default:
504 		buf = gettext("unknown error");
505 		break;
506 	}
507 	(void) fprintf(stderr, "%s\n", buf);
508 }
509 
510 static void *
safe_malloc(size_t size)511 safe_malloc(size_t size)
512 {
513 	void *buf;
514 
515 	buf = malloc(size);
516 	if (buf == NULL) {
517 		(void) fprintf(stderr, gettext("%s: malloc: %s\n"),
518 		    gExecName, strerror(errno));
519 		exit(WIFI_FATAL_ERR);
520 	}
521 	return (buf);
522 }
523 
524 static void *
safe_calloc(size_t nelem,size_t elsize)525 safe_calloc(size_t nelem, size_t elsize)
526 {
527 	void *buf;
528 
529 	buf = calloc(nelem, elsize);
530 	if (buf == NULL) {
531 		(void) fprintf(stderr, gettext("%s: calloc: %s\n"),
532 		    gExecName, strerror(errno));
533 		exit(WIFI_FATAL_ERR);
534 	}
535 	return (buf);
536 }
537 
538 static char *
safe_strdup(const char * s1)539 safe_strdup(const char *s1)
540 {
541 	char *p;
542 
543 	p = strdup(s1);
544 	if (p == NULL) {
545 		(void) fprintf(stderr, gettext("%s: strdup: %s\n"),
546 		    gExecName, strerror(errno));
547 		exit(WIFI_FATAL_ERR);
548 	}
549 	return (p);
550 }
551 
552 static void
safe_snprintf(char * s,size_t n,const char * format,...)553 safe_snprintf(char *s, size_t n,  const  char  *format, ...)
554 {
555 	int len;
556 	va_list ap;
557 	va_start(ap, format);
558 
559 	len = vsnprintf(s, n, format, ap);
560 	if ((len <= 0) || (len > n - 1)) {
561 		(void) fprintf(stderr,
562 		    gettext("%s: snprintf: %s\n"),
563 		    gExecName, strerror(errno));
564 		exit(WIFI_FATAL_ERR);
565 	}
566 	va_end(ap);
567 }
568 
569 static void
safe_fclose(FILE * stream)570 safe_fclose(FILE *stream)
571 {
572 	int err;
573 
574 	err = fclose(stream);
575 	if (err == EOF) {
576 		(void) fprintf(stderr, gettext("%s: fclose: %s\n"),
577 		    gExecName, strerror(errno));
578 		exit(WIFI_FATAL_ERR);
579 	}
580 }
581 /*
582  * new_ae: Add an element with content pointed by arg to the list *ael.
583  */
584 static void
new_ae(aelist_t * ael,const char * arg)585 new_ae(aelist_t *ael, const char *arg)
586 {
587 	ae_t *pae = NULL;
588 
589 	PRTDBG(("new_ae(0x%x, \"%s\")\n", ael, arg));
590 	assert((ael != NULL) && (arg != NULL));
591 
592 	pae = safe_calloc(sizeof (*pae), 1);
593 	pae->ae_arg = safe_strdup(arg);
594 	pae->ae_next = NULL;
595 
596 	if (ael->ael_tail == NULL) {
597 		ael->ael_head = pae;
598 	} else {
599 		ael->ael_tail->ae_next = pae;
600 	}
601 	ael->ael_tail = pae;
602 	ael->ael_argc++;
603 }
604 /*
605  * new_ael:  Create a new aelist with list_type "type"
606  * and return the list pointer.
607  */
608 static aelist_t *
new_ael(list_type_t type)609 new_ael(list_type_t type)
610 {
611 	aelist_t *plist;
612 
613 	plist = safe_calloc(sizeof (*plist), 1);
614 	plist->type = type;
615 	plist->ael_argc = 0;
616 	plist->ael_head = plist->ael_tail = NULL;
617 
618 	PRTDBG(("new_ael(%d) = 0x%x\n", type, plist));
619 	return (plist);
620 }
621 
622 /*
623  * new_config_file: Creates a new config_file_t struct which is counterpart of
624  * of the configration file, and return the pointer.
625  */
626 static config_file_t *
new_config_file()627 new_config_file()
628 {
629 	config_file_t *p_config_file;
630 
631 	p_config_file = safe_calloc(sizeof (config_file_t), 1);
632 	p_config_file->section_argc = 0;
633 	p_config_file->section_head = p_config_file->section_tail = NULL;
634 
635 	PRTDBG(("new_config_file() = 0x%x\n", p_config_file));
636 	return (p_config_file);
637 }
638 
639 /*
640  * new_section: Add a list pointed by "p_list", with identity "section_id" to
641  * the config_file_t struct pointed by "p_config_file"
642  */
643 static void
new_section(config_file_t * p_config_file,aelist_t * p_list,const char * section_id)644 new_section(config_file_t *p_config_file, aelist_t *p_list,
645     const char *section_id)
646 {
647 	section_t *p_section = NULL;
648 
649 	PRTDBG(("new_section(0x%x, 0x%x, \"%s\")\n", p_config_file, p_list,
650 	    section_id));
651 	assert((p_config_file != NULL) && (p_list != NULL) &&
652 	    (section_id != NULL));
653 
654 	p_section = safe_calloc(sizeof (*p_section), 1);
655 	p_section->list = p_list;
656 	p_section->section_next = NULL;
657 	p_section->section_id = safe_strdup(section_id);
658 
659 	if (p_config_file->section_tail == NULL) {
660 		p_config_file->section_head = p_section;
661 	} else {
662 		p_config_file->section_tail->section_next = p_section;
663 	}
664 	p_config_file->section_tail = p_section;
665 	p_config_file->section_argc++;
666 }
667 
668 /*
669  * destroy_config:Destroy the config_file struct
670  */
671 static void
destroy_config(config_file_t * p_config_file)672 destroy_config(config_file_t *p_config_file)
673 {
674 	section_t *p_section = NULL;
675 	aelist_t *p_list = NULL;
676 	ae_t *pae = NULL;
677 
678 	PRTDBG(("destory_config(0x%x)\n", p_config_file));
679 	assert(p_config_file != NULL);
680 
681 	p_section = p_config_file->section_head;
682 	while (p_section != NULL) {
683 		p_list = p_section->list;
684 		if (p_list != NULL) {
685 			pae = p_list->ael_head;
686 			while (pae != NULL) {
687 				if (pae->ae_arg != NULL)
688 					free(pae->ae_arg);
689 				pae->ae_arg = NULL;
690 				pae = pae->ae_next;
691 				free(p_list->ael_head);
692 				p_list->ael_head = pae;
693 			}
694 			free(p_list);
695 			p_list = NULL;
696 		}
697 		if (p_section->section_id != NULL)
698 			free(p_section->section_id);
699 		p_section->section_id = NULL;
700 		p_section = p_section->section_next;
701 		free(p_config_file->section_head);
702 		p_config_file->section_head = p_section;
703 	}
704 	free(p_config_file);
705 	p_config_file = NULL;
706 }
707 
708 /*
709  * parse_file: Parse each section of the configration file
710  * and construct the config_file_t structure.
711  * Example:
712  * A config file has contents below:
713  *
714  * {preferrence}
715  * essid=ap7-3
716  * essid=linksys
717  *
718  * {history}
719  * essid=ap7-3
720  * essid=ap7-2
721  *
722  * [ap7-3]
723  * essid=ap7-3
724  * wepkeyid=3
725  * channel=11
726  * rates=1,2
727  *
728  * [linksys]
729  * essid=linksys
730  * createibss=BSS
731  * authmode=OPENSYSTEM
732  * wepkeyid=1
733  *
734  * then its config_file_t structure will be:
735  *
736  *                        config_file_t
737  *                       |~~~~~~~~~~~~~~~~~~~~~~~~~~|
738  *                       |      section_argc=5      |
739  *                       |~~~~~~~~~~~~T~~~~~~~~~~~~~|
740  *                      /|   *head    |    *tail    |\
741  *                     / ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \
742  *                    /                                \
743  *                   /	                                \
744  *                  /                                    \
745  *                 /                                      \
746  *                /                                        \
747  *  section_t    V           section_t                      V section_t
748  * |~~~~~~~~~~~~~~~|~~|     |~~~~~~~~~~~~~~~|~~|      |~~~~~~~~~~~~~~|~~|
749  * |"{preferrence}"|  |     |  "{history}"  |  |      | "[linksys]"  |  |
750  * |~~~~~~~~~~~~~~~| -+---->|~~~~~~~~~~~~~~~| -+->..->|~~~~~~~~~~~~~~| -+->NULL
751  * |    *list      |  |     |    *list      |  |      |    *list     |  |
752  * ~~T~~~~~~~~~~~~~~~~~     ~~~T~~~~~~~~~~~~~~~~      ~~~T~~~~~~~~~~~~~~~
753  *   |                         |                         |
754  *   |                         |                         |
755  *   V aelist_t                V aelist_t                V aelist_t
756  * |~~~~~~~~~~~~~|          |~~~~~~~~~~~~~|           |~~~~~~~~~~~~~|
757  * |  argc=2     |          |  argc=3     |           |  argc=4     |
758  * |~~~~~~~~~~~~~|          |~~~~~~~~~~~~~|           |~~~~~~~~~~~~~|
759  * |PREFFERRENCE |          |   HISTORY   |           |   PROFILE   |
760  * |~~~~~~T~~~~~~|          |~~~~~~T~~~~~~|           |~~~~~~T~~~~~~|
761  * |*head |*tail |\         |*head |*tail |\          |*head |*tail |
762  * ~~T~~~~~~~~~~~~ \        ~~T~~~~~~~~~~~~ \        /~~~~~~~~~~~~~~~\
763  *   |              \         V              V      /                 \
764  *   |               \        ...            ...   /                   \
765  *   V ae_t           V  ae_t             ae_t    V           ae_t      V
766  * |~~~~~~~~~T~~|  |~~~~~~~~~T~~|       |~~~~~~~~~T~~|      |~~~~~~~~~T~~|
767  * |"essid=  | -+->|"essid=  | -+->NULL |"essid=  | -+->..->|"wepkeyid| -+->NULL
768  * | ap7-3"  |  |  | linksys"|  |       | linksys"|  |      | =1"     |  |
769  * ~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~       ~~~~~~~~~~~~~~      ~~~~~~~~~~~~~~
770  *
771  */
772 
773 static config_file_t *
parse_file(const char * pfile)774 parse_file(const char *pfile)
775 {
776 	FILE *file = NULL;
777 	int fd = 0;
778 	char buf_line[256];
779 	config_file_t *p_config_file;
780 	list_type_t cur_list = OTHER;
781 	aelist_t *prefer_list = NULL;
782 	aelist_t *history_list = NULL;
783 	aelist_t *profile_list = NULL;
784 	aelist_t *activep_list = NULL;
785 
786 	assert(pfile != NULL);
787 	/*
788 	 * The files /etc/inet/wifi and /etc/inet/secret/wifiwepkey should
789 	 * be opened with "r" attribute. If these two files do not exist,
790 	 * create them here.
791 	 */
792 	file = fopen(pfile, "r");
793 
794 	if (file == NULL) {
795 		fd = open(pfile, O_CREAT|O_EXCL|O_RDWR, 0600);
796 		if (fd < 0) {
797 			(void) fprintf(stderr, gettext("%s: failed to open %s"
798 			    "\n"), gExecName, pfile);
799 			goto error1;
800 		}
801 		file = fdopen(fd, "w");
802 		(void) chmod(pfile, S_IRUSR);
803 	}
804 
805 	p_config_file = new_config_file();
806 
807 	while (fgets(buf_line, sizeof (buf_line), file) != NULL) {
808 		if ((buf_line[0] == '\n') || (buf_line[0] == ' '))
809 			continue;
810 		/* replace the old '\n' to '\0' */
811 		buf_line[strlen(buf_line) - 1] = '\0';
812 		if (strstr(buf_line, WIFI_PREFER) == buf_line) {
813 			if (prefer_list == NULL) {
814 				cur_list = PREFERENCE;
815 				prefer_list = new_ael(PREFERENCE);
816 				new_section(p_config_file, prefer_list,
817 				    WIFI_PREFER);
818 			} else {
819 				(void) fprintf(stderr, gettext("%s: "
820 				    "%s : duplicated %s section\n"),
821 				    gExecName, pfile, WIFI_PREFER);
822 				goto error;
823 			}
824 		} else if (strstr(buf_line, WIFI_HISTORY) == buf_line) {
825 			if (history_list == NULL) {
826 				cur_list = HISTORY;
827 				history_list = new_ael(HISTORY);
828 				new_section(p_config_file, history_list,
829 				    WIFI_HISTORY);
830 			} else {
831 				(void) fprintf(stderr, gettext("%s: "
832 				    "%s : duplicated %s section\n"),
833 				    gExecName, pfile, WIFI_HISTORY);
834 				goto error;
835 			}
836 		} else if (strstr(buf_line, WIFI_ACTIVEP) == buf_line) {
837 			if (activep_list == NULL) {
838 				cur_list = ACTIVEP;
839 				activep_list = new_ael(ACTIVEP);
840 				new_section(p_config_file, activep_list,
841 				    WIFI_ACTIVEP);
842 			} else {
843 				(void) fprintf(stderr, gettext("%s: "
844 				    "%s : duplicated %s section\n"),
845 				    gExecName, pfile, WIFI_ACTIVEP);
846 				goto error;
847 			}
848 		} else if ((strchr(buf_line, '[') == buf_line) &&
849 		    (buf_line[strlen(buf_line) - 1] == ']')) {
850 			cur_list = PROFILE;
851 			profile_list = new_ael(PROFILE);
852 			new_section(p_config_file, profile_list,
853 			    buf_line);
854 		} else {
855 			switch (cur_list) {
856 			case PREFERENCE:
857 				if (prefer_list->ael_argc <=
858 				    MAX_PREFERENCE_NUM)
859 					new_ae(prefer_list, buf_line);
860 				break;
861 			case HISTORY:
862 				if (history_list->ael_argc <=
863 				    MAX_HISTORY_NUM)
864 					new_ae(history_list, buf_line);
865 				break;
866 			case ACTIVEP:
867 				if ((activep_list->ael_argc <= 1) &&
868 				    (strpbrk(buf_line, "=") != NULL))
869 					new_ae(activep_list, buf_line);
870 				break;
871 			case PROFILE:
872 				if (strpbrk(buf_line, "=") != NULL)
873 					new_ae(profile_list, buf_line);
874 				break;
875 			default:
876 				(void) fprintf(stderr,
877 				    gettext("%s: %s: file format error\n"),
878 				    gExecName, pfile);
879 				goto error;
880 			}
881 		}
882 	}
883 	PRTDBG(("parse_file(\"%s\")=0x%x\n", pfile, p_config_file));
884 	(void) fclose(file);
885 	return (p_config_file);
886 error:
887 	destroy_config(p_config_file);
888 	(void) fclose(file);
889 error1:
890 	return (NULL);
891 }
892 /*
893  * construct an argument vector from an aelist
894  */
895 static char **
aeltoargv(aelist_t * ael,int * ael_num)896 aeltoargv(aelist_t *ael, int *ael_num)
897 {
898 	ae_t *ae = NULL;
899 	char **argv = NULL;
900 	int argc = 0;
901 
902 	PRTDBG(("aeltoargv(%x)\n", ael));
903 	assert(ael != NULL);
904 
905 	argv = safe_calloc(sizeof (*argv), ael->ael_argc);
906 
907 	for (argc = 0, ae = ael->ael_head; ae; ae = ae->ae_next) {
908 		/* skip bssid since it can not be set */
909 		if (strncmp(ae->ae_arg, "bssid=", strlen("bssid=")) == 0)
910 			continue;
911 		argv[argc] = safe_strdup(ae->ae_arg);
912 		argc++;
913 		if (ae == ael->ael_tail)
914 			break;
915 	}
916 
917 	PRTDBG(("aeltoargv(0x%x) = 0x%x\n\n", ael, argv));
918 	*ael_num = argc;
919 	return (argv);
920 }
921 
922 /*
923  * archived contents into a file
924  */
925 static boolean_t
fprint_config_file(config_file_t * p_config_file,const char * file_name)926 fprint_config_file(config_file_t *p_config_file, const char *file_name)
927 {
928 	FILE *file = NULL;
929 	int fd = 0;
930 	int len;
931 	section_t *p_section = NULL;
932 	aelist_t *p_list = NULL;
933 	ae_t *pae = NULL;
934 	char temp_file[256];
935 	struct stat buf;
936 
937 	PRTDBG(("fprint_config_file(0x%x, \"%s\")\n", p_config_file,
938 	    file_name));
939 	assert((p_config_file != NULL)&&(strcmp(file_name, "") != 0));
940 
941 	safe_snprintf(temp_file, sizeof (temp_file),
942 	    "%s.tmp", file_name);
943 	fd = open(temp_file, O_CREAT|O_WRONLY|O_TRUNC, 0600);
944 	if (fd < 0) {
945 		(void) fprintf(stderr, gettext("%s: failed to open %s\n"),
946 		    gExecName, temp_file);
947 		return (B_FALSE);
948 	}
949 	file = fdopen(fd, "w");
950 
951 	p_section = p_config_file->section_head;
952 	while (p_section != NULL) {
953 		p_list = p_section->list;
954 		if (p_list != NULL) {
955 			PRTDBG(("fprint_config_file: section_id=%s\n",
956 			    p_section->section_id));
957 			len = fprintf(file, "\n%s\n", p_section->section_id);
958 			if (len < 0) {
959 				(void) fprintf(stderr, gettext("%s: "
960 				    "failed to update %s: %s\n"),
961 				    gExecName, file_name, strerror(errno));
962 				safe_fclose(file);
963 				return (B_FALSE);
964 			}
965 			pae = p_list->ael_head;
966 			while (pae != NULL) {
967 				if (pae->ae_arg != NULL) {
968 					len = fprintf(file, "%s\n",
969 					    pae->ae_arg);
970 					if (len < 0) {
971 						(void) fprintf(stderr,
972 						    gettext("%s: failed to "
973 						    "update %s: %s\n"),
974 						    gExecName, file_name,
975 						    strerror(errno));
976 						safe_fclose(file);
977 						return (B_FALSE);
978 					}
979 				}
980 				pae = pae->ae_next;
981 			}
982 		}
983 		p_section = p_section->section_next;
984 	}
985 	safe_fclose(file);
986 	/*
987 	 * The attribute of the file /etc/inet/wifi and
988 	 * /etc/inet/security/wifiwepkey should be retained.
989 	 * if those file do not exist, set default file mode.
990 	 */
991 	if (stat(file_name, &buf) != 0) {
992 		if (errno == ENOENT) {
993 			buf.st_mode = 0600;
994 		} else {
995 			(void) fprintf(stderr, gettext("%s: failed to get "
996 			    "file %s stat: %s\n"),
997 			    gExecName, file_name, strerror(errno));
998 			return (B_FALSE);
999 		}
1000 	}
1001 	if (rename(temp_file, file_name) != 0) {
1002 		(void) fprintf(stderr, gettext("%s: failed to update %s: %s"
1003 		    "\n"), gExecName, file_name, strerror(errno));
1004 		return (B_FALSE);
1005 	}
1006 	(void) chmod(file_name, buf.st_mode);
1007 	return (B_TRUE);
1008 }
1009 /*
1010  * append_pa: Each section holds a section_id which identifies a section
1011  * a profile uses its essid appending "[]" to denote its section_id.
1012  * note: new memory is allocated, remember to free.
1013  */
1014 static char *
append_pa(const char * arg)1015 append_pa(const char *arg)
1016 {
1017 	char *pbuf = NULL;
1018 	int len;
1019 
1020 	assert(arg != NULL);
1021 
1022 	len = strlen(arg) + 3;
1023 	pbuf = safe_malloc(len);
1024 	safe_snprintf(pbuf, len, "[%s]", arg);
1025 	PRTDBG(("append_pa(\"%s\") = \"%s\"\n", arg, pbuf));
1026 	return (pbuf);
1027 }
1028 /*
1029  * find a section by section_id from p_config_file,
1030  * return the section pointer.
1031  */
1032 static section_t *
find_section(config_file_t * p_config_file,const char * section_id)1033 find_section(config_file_t *p_config_file, const char *section_id)
1034 {
1035 	section_t *p_section = NULL;
1036 
1037 	PRTDBG(("find_section(0x%x, \"%s\")\n", p_config_file, section_id));
1038 	assert((section_id != NULL)&&(p_config_file != NULL));
1039 
1040 	p_section = p_config_file->section_head;
1041 
1042 	while (p_section != NULL) {
1043 		if ((p_section->section_id != NULL) &&
1044 		    (strcmp(p_section->section_id, section_id) == 0))
1045 			return (p_section);
1046 		p_section = p_section->section_next;
1047 	}
1048 	return (NULL);
1049 }
1050 
1051 /*
1052  * get_value: Get rid of "parameter=" from a "parameter=value", for example:
1053  * when we read an line from file, we gets "essid=ap7-2", this function
1054  * returns the pointer to string "ap7-2";
1055  */
1056 
1057 static const char *
get_value(const char * arg)1058 get_value(const char *arg)
1059 {
1060 	char *p;
1061 	assert(arg != NULL);
1062 
1063 	p = strchr(arg, '=');
1064 	PRTDBG(("get_value(\"%s\") = \"%s\"\n", arg, p + 1));
1065 	if (p != NULL)
1066 		return (p + 1);
1067 	else
1068 		return (NULL);
1069 }
1070 
1071 /*
1072  * search /dev/wifi to see which interface is available
1073  */
1074 static boolean_t
search_interface(char * interface)1075 search_interface(char *interface)
1076 {
1077 	DIR *dirp;
1078 	struct dirent *dp;
1079 	char buf[256];
1080 	int fd;
1081 
1082 	PRTDBG(("search interface\n"));
1083 	assert(interface != NULL);
1084 
1085 	/*
1086 	 * Try to return the first found wifi interface.
1087 	 * If no wifi interface is available, return B_FALSE
1088 	 */
1089 
1090 	if ((dirp = opendir("/dev/wifi")) == NULL) {
1091 		PRTDBG(("failed to open '/dev/wifi'\n"));
1092 		return (B_FALSE);
1093 	}
1094 	while ((dp = readdir(dirp)) != NULL) {
1095 		if (strcmp(dp->d_name, ".") == 0 ||
1096 		    strcmp(dp->d_name, "..") == 0)
1097 			continue;
1098 		if (dp->d_name[strlen(dp->d_name) - 1] < '0' ||
1099 		    dp->d_name[strlen(dp->d_name) - 1] > '9')
1100 			continue;
1101 		safe_snprintf(buf, sizeof (buf), "%s%s",
1102 		    "/dev/wifi/", dp->d_name);
1103 		fd = open(buf, O_RDWR);
1104 		if (fd == -1) {
1105 			PRTDBG(("interface %s doesn't exist\n", dp->d_name));
1106 			continue;
1107 		} else {
1108 			PRTDBG(("interface %s is the first found interface\n",
1109 			    dp->d_name));
1110 			(void) strlcpy(interface, buf, LIFNAMSIZ);
1111 			(void) close(fd);
1112 			(void) closedir(dirp);
1113 			return (B_TRUE);
1114 		}
1115 	}
1116 
1117 	PRTDBG(("failed to find available wireless interface\n"));
1118 	(void) closedir(dirp);
1119 	return (B_FALSE);
1120 
1121 }
1122 /*
1123  * open_dev: Open the driver.
1124  * if the 'devname' has format like 'ath0', we should add the path to that
1125  * device(/dev/ath0) and open it; if the 'devname' has format like
1126  * '/dev/wifi/ath0', we open it directly.
1127  */
1128 static int
open_dev(char * devname)1129 open_dev(char *devname)
1130 {
1131 	int fd;
1132 	int len;
1133 	char *pbuf = NULL;
1134 
1135 	PRTDBG(("open_dev(\"%s\")\n", devname));
1136 	assert(devname != NULL);
1137 	/*
1138 	 * If the devname is got from the user input, we
1139 	 * add '/dev/' to that relative devname. If it
1140 	 * is got from the 'search interface', it is an
1141 	 * absolute path.
1142 	 */
1143 	if (strncmp(devname, "/dev/wifi/", strlen("/dev/wifi/")) == 0) {
1144 		pbuf = safe_strdup(devname);
1145 	} else {
1146 		len = strlen(devname) + strlen("/dev/") + 1;
1147 		pbuf = safe_malloc(len);
1148 		safe_snprintf(pbuf, len, "/dev/%s", devname);
1149 	}
1150 	fd = open(pbuf, O_RDWR);
1151 	free(pbuf);
1152 
1153 	if (fd == -1) {
1154 		(void) fprintf(stderr, gettext("%s: failed to open '%s': %s"
1155 		    "\n"), gExecName, devname, strerror(errno));
1156 		return (-1);
1157 	}
1158 	if (!isastream(fd)) {
1159 		(void) fprintf(stderr, gettext("%s: %s is "
1160 		    "not a stream device\n"),
1161 		    gExecName, devname);
1162 		(void) close(fd);
1163 		return (-1);
1164 	}
1165 	return (fd);
1166 }
1167 /*
1168  * call_ioctl: Fill strioctl structure and issue an ioctl system call
1169  */
1170 static boolean_t
call_ioctl(int fd,int cmd,uint32_t params,uint32_t buf_len)1171 call_ioctl(int fd, int cmd, uint32_t params, uint32_t buf_len)
1172 {
1173 	struct strioctl stri;
1174 
1175 	PRTDBG(("call_ioctl_gs(%d, 0x%x, 0x%x, 0x%x)\n",
1176 	    fd, cmd, params, buf_len));
1177 
1178 	switch (cmd) {
1179 	case WLAN_GET_PARAM:
1180 		(void) memset(gbuf, 0, MAX_BUF_LEN);
1181 		stri.ic_len = MAX_BUF_LEN;
1182 		break;
1183 	case WLAN_SET_PARAM:
1184 		gbuf->wldp_length = buf_len + WIFI_BUF_OFFSET;
1185 		stri.ic_len = gbuf->wldp_length;
1186 		break;
1187 	case WLAN_COMMAND:
1188 		gbuf->wldp_length = sizeof (wldp_t);
1189 		stri.ic_len = gbuf->wldp_length;
1190 		break;
1191 	default:
1192 		(void) fprintf(stderr, gettext("%s: ioctl : "
1193 		    "unsupported ioctl command\n"), gExecName);
1194 		return (B_FALSE);
1195 	}
1196 	gbuf->wldp_type = NET_802_11;
1197 	gbuf->wldp_id = params;
1198 
1199 	stri.ic_cmd = cmd;
1200 	stri.ic_timout = 0;
1201 	stri.ic_dp = (char *)gbuf;
1202 
1203 	if (ioctl(fd, I_STR, &stri) == -1) {
1204 		gbuf->wldp_result = 0xffff;
1205 		return (B_FALSE);
1206 	}
1207 	if (cmd == WLAN_COMMAND) {
1208 		return (B_TRUE);
1209 	} else {
1210 		return (gbuf->wldp_result != WL_SUCCESS ?
1211 		    B_FALSE:B_TRUE);
1212 	}
1213 }
1214 
1215 /*
1216  * del_prefer: Delete an item from the {preferrence} list, the idea is
1217  * simply free the ae_t element, and set ae_arg to NULL, then when archive
1218  * the config_file_t struct to the file, it will be delete.
1219  * The last flag is used to identify whether this function is invoked due to
1220  * the 'removeprefer' subcommand or due to 'deleteprofile' subcommand.
1221  */
1222 static boolean_t
del_prefer(config_file_t * p_config_file,const char * prefer,boolean_t rflag)1223 del_prefer(config_file_t *p_config_file, const char *prefer, boolean_t rflag)
1224 {
1225 	section_t *p_section = NULL;
1226 	aelist_t *plist = NULL;
1227 	ae_t *pae = NULL;
1228 	int i = 0, position = 0;
1229 	int number;
1230 	ae_t *prm_ae = NULL;
1231 
1232 	PRTDBG(("del_prefer(0x%x, \"%s\")\n", p_config_file, prefer));
1233 	assert((prefer != NULL)&&(p_config_file != NULL));
1234 
1235 	p_section = find_section(p_config_file, WIFI_PREFER);
1236 	if (p_section != NULL)
1237 		plist = p_section->list;
1238 
1239 	if ((p_section == NULL) || (plist == NULL))
1240 		return (B_FALSE);
1241 
1242 	number = plist->ael_argc;
1243 	pae = plist->ael_head;
1244 	prm_ae = plist->ael_head;
1245 	while (pae != NULL) {
1246 		if (strcmp(prefer, pae->ae_arg) == 0) {
1247 			free(pae->ae_arg);
1248 			pae->ae_arg = NULL; /* mark */
1249 			if (!position) {
1250 				plist->ael_head = pae->ae_next;
1251 				if (pae->ae_next == NULL)
1252 					plist->ael_tail = NULL;
1253 			} else {
1254 				for (i = 0; i < position - 1; i++)
1255 					prm_ae = prm_ae->ae_next;
1256 				prm_ae->ae_next = pae->ae_next;
1257 				if (pae->ae_next == NULL)
1258 					plist->ael_tail = prm_ae;
1259 			}
1260 			free(pae);
1261 			pae = NULL;
1262 			plist->ael_argc--;
1263 			break;
1264 		}
1265 		position++;
1266 		pae = pae->ae_next;
1267 	}
1268 	if ((number == plist->ael_argc) && (rflag == B_TRUE)) {
1269 		(void) fprintf(stderr, gettext("%s: removeprefer : "
1270 		    "no such profile: '%s' in the preference list\n"),
1271 		    gExecName, prefer);
1272 		return (B_FALSE);
1273 	}
1274 	return (B_TRUE);
1275 }
1276 
1277 /*
1278  * del_section: Delete an section from p_config_file, the idea is
1279  * simply free the aelist_t struct and set it to NULL, when archiving
1280  * config_file_t struct to the file, we will find section list is NULL,
1281  * and will not write it to file, so it will be deleted.
1282  */
1283 static boolean_t
del_section(config_file_t * p_config_file,char * section_id)1284 del_section(config_file_t *p_config_file, char *section_id)
1285 {
1286 	section_t *p_section = NULL;
1287 	section_t *prm_section = NULL;
1288 	aelist_t *plist = NULL;
1289 	ae_t *pae = NULL;
1290 	int i = 0, position = 0;
1291 
1292 	PRTDBG(("del_section(0x%x, \"%s\")\n", p_config_file, section_id));
1293 	PRTDBG(("del_section: %d section(s) in config file\n",
1294 	    p_config_file->section_argc));
1295 	assert((section_id != NULL)&&(p_config_file != NULL));
1296 
1297 	if (find_section(p_config_file, section_id) == NULL) {
1298 		return (B_FALSE);
1299 	}
1300 	p_section = p_config_file->section_head;
1301 	prm_section = p_config_file->section_head;
1302 	while (p_section != NULL) {
1303 		if (p_section->section_id != NULL) {
1304 			if (strcmp(p_section->section_id, section_id) == 0) {
1305 				plist = p_section->list;
1306 				pae = plist->ael_head;
1307 				while (pae != NULL) {
1308 					free(pae->ae_arg);
1309 					pae->ae_arg = NULL;
1310 					pae = pae->ae_next;
1311 					free(plist->ael_head);
1312 					plist->ael_head = pae;
1313 				}
1314 				free(plist);
1315 				p_section->list = NULL;
1316 				free(p_section->section_id);
1317 				p_section->section_id = NULL;
1318 
1319 				if (!position) {
1320 					p_config_file->section_head =
1321 					    p_section->section_next;
1322 					if (p_section->section_next == NULL)
1323 						p_config_file->section_tail =
1324 						    NULL;
1325 				} else {
1326 					for (i = 0; i < position - 1; i++) {
1327 						prm_section =
1328 						    prm_section->section_next;
1329 					}
1330 					prm_section->section_next =
1331 					    p_section->section_next;
1332 					if (p_section->section_next == NULL)
1333 						p_config_file->section_tail =
1334 						    prm_section;
1335 				}
1336 				free(p_section);
1337 				p_config_file->section_argc--;
1338 				break;
1339 			}
1340 			position++;
1341 		}
1342 		p_section = p_section->section_next;
1343 	}
1344 	return (B_TRUE);
1345 }
1346 
1347 /*
1348  * set_prefer: Reorder the preferrence list.
1349  */
1350 static boolean_t
set_prefer(config_file_t * p_config_file,const char * prefer,int rank)1351 set_prefer(config_file_t *p_config_file, const char *prefer, int rank)
1352 {
1353 	char *pbuf = NULL;
1354 	aelist_t *plist = NULL;
1355 	section_t *p_section = NULL;
1356 	ae_t *pae = NULL;
1357 	int i = 0, position = 0;
1358 	ae_t *pae_move = NULL;
1359 
1360 	assert(prefer != NULL);
1361 	PRTDBG(("set_prefer(0x%x, \"%s\", %d)\n", p_config_file, prefer, rank));
1362 
1363 	pbuf = append_pa(prefer);
1364 	if (find_section(p_config_file, pbuf) == NULL) {
1365 		(void) fprintf(stderr, gettext("%s: setprefer: "
1366 		    "no such profile: '%s'\n"),
1367 		    gExecName, prefer);
1368 		free(pbuf);
1369 		return (B_FALSE);
1370 	}
1371 	free(pbuf);
1372 
1373 	p_section = find_section(p_config_file, WIFI_PREFER);
1374 
1375 	if (p_section == NULL) {
1376 		plist = new_ael(PREFERENCE);
1377 		new_section(p_config_file, plist, WIFI_PREFER);
1378 		new_ae(plist, prefer);
1379 		return (B_TRUE);
1380 	} else {
1381 		plist = p_section->list;
1382 	}
1383 
1384 	pae = plist->ael_head;
1385 	pae_move = plist->ael_head;
1386 	while (pae != NULL) {
1387 		if (strcmp(prefer, pae->ae_arg) == 0) {
1388 			free(pae->ae_arg);
1389 			pae->ae_arg = NULL;
1390 			if (!position) {
1391 				plist->ael_head = pae->ae_next;
1392 				if (pae->ae_next == NULL)
1393 					plist->ael_tail = NULL;
1394 			} else {
1395 				for (i = 0; i < position - 1; i++)
1396 					pae_move = pae_move->ae_next;
1397 				pae_move->ae_next = pae->ae_next;
1398 				if (pae->ae_next == NULL)
1399 					plist->ael_tail = pae_move;
1400 			}
1401 			free(pae);
1402 			plist->ael_argc--;
1403 			break;
1404 		}
1405 		position++;
1406 		pae = pae->ae_next;
1407 	}
1408 	PRTDBG(("set_prefer: %d Profiles in prefer list\n", plist->ael_argc));
1409 	if (rank > plist->ael_argc) {
1410 		new_ae(plist, prefer);
1411 	} else if (rank <= 1) {
1412 		pae = safe_calloc(sizeof (ae_t), 1);
1413 		pae->ae_arg = safe_strdup(prefer);
1414 		pae->ae_next = plist->ael_head;
1415 		plist->ael_head = pae;
1416 		plist->ael_argc++;
1417 	} else {
1418 		pae_move = plist->ael_head;
1419 		for (i = 1; i < rank-1; i++) {
1420 			pae_move = pae_move->ae_next;
1421 		}
1422 		pae = safe_calloc(sizeof (ae_t), 1);
1423 		pae->ae_arg = safe_strdup(prefer);
1424 		pae->ae_next = pae_move->ae_next;
1425 		pae_move->ae_next = pae;
1426 		plist->ael_argc++;
1427 	}
1428 	/*
1429 	 * If number of prefer list items is larger than the MAX_PREFERENCE_NUM
1430 	 * delete those items whose No is larger than MAX_PREFERENCE_NUM.
1431 	 */
1432 	if (plist->ael_argc > MAX_PREFERENCE_NUM) {
1433 		pae = plist->ael_head;
1434 		while (pae->ae_next != plist->ael_tail)
1435 			pae = pae->ae_next;
1436 		free(plist->ael_tail->ae_arg);
1437 		plist->ael_tail->ae_arg = NULL;
1438 		free(plist->ael_tail);
1439 		plist->ael_tail = pae;
1440 		plist->ael_tail->ae_next = NULL;
1441 		plist->ael_argc--;
1442 	}
1443 	PRTDBG(("set_prefer: %d Profiles in prefer list\n", plist->ael_argc));
1444 	return (B_TRUE);
1445 }
1446 /*
1447  * add_to_history: Save the scanlist argv into history section
1448  */
1449 static void
add_to_history(config_file_t * p_config_file,int argc,char ** argv)1450 add_to_history(config_file_t *p_config_file, int argc, char **argv)
1451 {
1452 	int i = 0, j = 0, pos = 0;
1453 	aelist_t *plist = NULL;
1454 	section_t *p_section = NULL;
1455 	ae_t *pae = NULL;
1456 	ae_t *pae_m = NULL;
1457 	char item[256];
1458 	time_t cltime;
1459 
1460 	PRTDBG(("add_to_history(0x%x, %d, 0x%x)\n", p_config_file, argc, argv));
1461 	assert(p_config_file != NULL);
1462 
1463 	p_section = find_section(p_config_file, WIFI_HISTORY);
1464 
1465 	if (p_section == NULL) {
1466 		plist = new_ael(HISTORY);
1467 		new_section(p_config_file, plist, WIFI_HISTORY);
1468 	} else {
1469 		plist = p_section->list;
1470 	}
1471 
1472 	if (plist != NULL) {
1473 		for (i = 0; i < argc; i++) {
1474 			if (!strlen(argv[i]))
1475 				continue;
1476 			pos = 0;
1477 			pae = plist->ael_head;
1478 			pae_m = plist->ael_head;
1479 			/*
1480 			 * add time stamp to the history record
1481 			 */
1482 			cltime = time(&cltime);
1483 			(void) snprintf(item, sizeof (item), "%s%c%ld",
1484 			    argv[i], ',', cltime);
1485 			while (pae != NULL) {
1486 				if (strncmp(item, pae->ae_arg,
1487 				    strlen(argv[i])) == 0) {
1488 					free(pae->ae_arg);
1489 					pae->ae_arg = NULL;
1490 					if (!pos) {
1491 						plist->ael_head = pae->ae_next;
1492 						if (pae->ae_next == NULL)
1493 							plist->ael_tail = NULL;
1494 					} else {
1495 						for (j = 0; j < pos - 1; j++)
1496 							pae_m = pae_m->ae_next;
1497 						pae_m->ae_next = pae->ae_next;
1498 						if (pae->ae_next == NULL)
1499 							plist->ael_tail = pae_m;
1500 					}
1501 					free(pae);
1502 					plist->ael_argc--;
1503 					break;
1504 				}
1505 				pos++;
1506 				pae = pae->ae_next;
1507 			}
1508 			new_ae(plist, item);
1509 		}
1510 
1511 		if (plist->ael_argc > MAX_HISTORY_NUM) {
1512 			for (i = 0; i < plist->ael_argc - MAX_HISTORY_NUM;
1513 			    i++) {
1514 				pae = plist->ael_head;
1515 				free(pae->ae_arg);
1516 				plist->ael_head = pae->ae_next;
1517 				free(pae);
1518 			}
1519 			plist->ael_argc = MAX_HISTORY_NUM;
1520 		}
1521 	}
1522 }
1523 
1524 static void
do_print_usage()1525 do_print_usage()
1526 {
1527 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1528 	    " autoconf [wait={n|forever}]\n"), gExecName);
1529 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1530 	    " connect profile [wait={n|forever}]\n"), gExecName);
1531 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1532 	    " connect essid [wait={n|forever}]\n"), gExecName);
1533 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1534 	    " disconnect\n"), gExecName);
1535 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1536 	    " getparam [parameter [...]]\n"), gExecName);
1537 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1538 	    " setparam [parameter=value [...]]\n"), gExecName);
1539 	(void) fprintf(stderr, gettext(
1540 	    "\tparameters:\n"
1541 	    "\t\tbssid\t\t - read only: 6 byte mac address of "
1542 	    "base station\n"
1543 	    "\t\tessid\t\t - name of the network, a string of up "
1544 	    "to 32 chars\n"
1545 	    "\t\tbsstype\t\t - bss(ap, infrastructure), ibss(ad-hoc)"
1546 	    " or auto\n"
1547 	    "\t\tcreateibss\t - flag to identify whether a ibss is to be\n"
1548 	    "\t\t\t\t   created when the network to connect is\n"
1549 	    "\t\t\t\t   not available, yes or no\n"
1550 	    "\t\tchannel\t\t - channel(used only when creating an ibss)\n"
1551 	    "\t\t\t\t   valid value:\n"
1552 	    "\t\t\t\t\t 802.11a: 0-99\n"
1553 	    "\t\t\t\t\t 802.11b: 1-14\n"
1554 	    "\t\t\t\t\t 802.11g: 1-14\n"
1555 	    "\t\trates\t\t - set of rates, seperated by ',' valid rates:\n"
1556 	    "\t\t\t\t   1,2,5.5,6,9,11,12,18,22,24,33,36,48 and 54\n"
1557 	    "\t\tpowermode\t - off, mps or fast\n"
1558 	    "\t\tauthmode\t - opensystem or shared_key\n"
1559 	    "\t\tencryption\t - none or wep\n"
1560 	    "\t\twepkey|1-4\t - write only:\n"
1561 	    "\t\t\t\t   5 chars or 10 hex digits for 40bit wepkey;\n"
1562 	    "\t\t\t\t   13 chars or 26 hex digits for 128bit wepkey\n"
1563 	    "\t\twepkeyindex\t - an integer within the range 1-4\n"
1564 	    "\t\tsignal\t\t - read only: signal strength from 0 to 15\n"
1565 	    "\t\tradio\t\t - on or off\n"));
1566 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1567 	    " restoredef\n"), gExecName);
1568 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1569 	    " scan\n"), gExecName);
1570 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1571 	    " showstatus\n"), gExecName);
1572 	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
1573 	    " setwepkey 1|2|3|4\n"), gExecName);
1574 
1575 	(void) fprintf(stderr, "\n");
1576 
1577 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1578 	    " createprofile profile parameter=value [...]\n"), gExecName);
1579 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1580 	    " deleteprofile profile1 [profile2 [...]]\n"), gExecName);
1581 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1582 	    " showprofile profile1 [profile2 [...]]\n"), gExecName);
1583 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1584 	    " setprofilewepkey profile 1|2|3|4\n"), gExecName);
1585 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1586 	    " getprofileparam profile [parameter [...]]\n"), gExecName);
1587 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1588 	    " setprofileparam profile [parameter=value [...]]\n"), gExecName);
1589 
1590 	(void) fprintf(stderr, "\n");
1591 
1592 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1593 	    " history\n"), gExecName);
1594 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1595 	    " listprefer\n"), gExecName);
1596 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1597 	    " removeprefer profile\n"), gExecName);
1598 	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
1599 	    " setprefer profile [n]\n"), gExecName);
1600 }
1601 
1602 /*
1603  * do_print_support_params: Query interface which cmd is supported
1604  */
1605 static boolean_t
do_print_support_params(int fd)1606 do_print_support_params(int fd)
1607 {
1608 	int i = 0, n = 0;
1609 
1610 	PRTDBG(("do_print_support_params(\"%d\")\n", fd));
1611 	assert(fd != -1);
1612 
1613 	(void) printf(gettext("\t  parameter\tproperty\n"));
1614 	for (i = 0; i < N_GS_FUNC; i++) {
1615 		gbuf->wldp_result = WL_LACK_FEATURE;
1616 		if ((do_gs_func[i].p_do_get_func != NULL) &&
1617 		    (do_gs_func[i].p_do_get_func(fd) != B_TRUE)) {
1618 				continue;
1619 		}
1620 		if (gbuf->wldp_result == WL_SUCCESS) {
1621 			(void) printf("\t%11s", do_gs_func[i].cmd);
1622 			if (do_gs_func[i].rw == RO)
1623 				(void) printf(gettext("\tread only\n"));
1624 			else
1625 				(void) printf(gettext("\tread/write\n"));
1626 			n++;
1627 		}
1628 	}
1629 
1630 	return (n ? B_TRUE : B_FALSE);
1631 }
1632 
1633 /*
1634  * check_authority: Check if command is permitted.
1635  */
1636 static boolean_t
check_authority(wifi_auth_t type)1637 check_authority(wifi_auth_t type)
1638 {
1639 	struct passwd *pw = NULL;
1640 
1641 	PRTDBG(("check_authority()\n"));
1642 
1643 	pw = getpwuid(getuid());
1644 	if (pw == NULL)
1645 		return (B_FALSE);
1646 	if (chkauthattr(p_auth_string[type], pw->pw_name) == 0) {
1647 		if (type == AUTH_WEP)
1648 			(void) fprintf(stderr, gettext("%s: "
1649 			    "privilege '%s' is required for setting "
1650 			    "wepkey.\n"), gExecName, WIFI_WEP_AUTH);
1651 		else
1652 			(void) fprintf(stderr, gettext("%s: "
1653 			    "privilege '%s' is required.\n"),
1654 			    gExecName, WIFI_CONFIG_AUTH);
1655 		return (B_FALSE);
1656 	} else {
1657 		return (B_TRUE);
1658 	}
1659 }
1660 
1661 /*
1662  * construct the 'history' and 'scan' output format
1663  * memory allocated. need to free after the function is invoked.
1664  */
1665 static char *
construct_format(uint32_t nt)1666 construct_format(uint32_t nt)
1667 {
1668 	char *format;
1669 	int len = 0, i;
1670 
1671 #define	FORMAT_LEN 256
1672 	assert((nt >= 1) && (nt <= 4));
1673 	format = safe_malloc(FORMAT_LEN);
1674 
1675 	for (i = 0; i < nt; i++)
1676 		len += snprintf(format + len, FORMAT_LEN - len, "\t");
1677 	if ((len <= 0) || (len > FORMAT_LEN - 1)) {
1678 		return ("\t\t\t\t");
1679 	}
1680 	return (format);
1681 }
1682 
1683 /*
1684  * find the essid of the named profile.
1685  * gp_config_file is golable, so the return is gloable too.
1686  */
1687 static const char *
essid_of_profile(const char * profile)1688 essid_of_profile(const char *profile)
1689 {
1690 	section_t *p_section = NULL;
1691 	aelist_t *plist = NULL;
1692 	ae_t *pae = NULL;
1693 	char *pbuf;
1694 
1695 	PRTDBG(("essid_of_profile: profile = %s\n", profile));
1696 	pbuf = append_pa(profile);
1697 	p_section = find_section(gp_config_file, pbuf);
1698 	free(pbuf);
1699 
1700 	if (p_section == NULL) {
1701 		return (NULL);
1702 	} else {
1703 		plist = p_section->list;
1704 	}
1705 	pae = plist->ael_head;
1706 	while (pae != NULL) {
1707 		if (strncmp(pae->ae_arg, "essid=", strlen("essid=")) == 0) {
1708 			PRTDBG(("essid_of_profile: essid = %s\n",
1709 			    pae->ae_arg));
1710 			return (get_value(pae->ae_arg));
1711 		}
1712 		pae = pae->ae_next;
1713 	}
1714 	return (NULL);
1715 }
1716 
1717 /*
1718  * If we don't know which profile is our favorate in 'autoconf',
1719  * we select the wifi network based on the following heuristic
1720  * 1. the network without wep.
1721  * 2. the network with the strongst signal.
1722  * 3. the network with the faster speed(not implemented since signal affects
1723  * the speed in some degree).
1724  */
1725 static void
heuristic_load(int fd,uint32_t ess_num,wl_ess_conf_t ** p_ess_conf)1726 heuristic_load(int fd, uint32_t ess_num, wl_ess_conf_t **p_ess_conf)
1727 {
1728 	int i = 0;
1729 	char *flag = NULL;
1730 	int have_nowep_wlan = 0;
1731 	wl_rssi_t maxsignal = 0;
1732 	char essid[34];
1733 	int timeout = LOADPROFILE_TIMEOUT;
1734 
1735 	PRTDBG(("heuristic_load: enter\n"));
1736 	(void) call_ioctl(fd, WLAN_COMMAND, WL_LOAD_DEFAULTS, 0);
1737 	flag = calloc(sizeof (char), ess_num);
1738 	for (i = 0; i < ess_num; i++) { /* extract none-wep network */
1739 		if (p_ess_conf[i]->wl_ess_conf_wepenabled == B_FALSE) {
1740 			flag[i] = 1;
1741 			have_nowep_wlan = 1;
1742 		}
1743 	}
1744 	/*
1745 	 * if all the wlans are weped, we select the one with strongest signal
1746 	 * in all of them, otherwise we just select in the none weped ones.
1747 	 */
1748 	if (!have_nowep_wlan)
1749 		(void) memset(flag, 1, ess_num);
1750 	for (i = 0; i < ess_num; i++) { /* extract the strongest signal ones */
1751 		if (flag[i] == 1) {
1752 			if (p_ess_conf[i]->wl_ess_conf_sl > maxsignal) {
1753 				maxsignal = p_ess_conf[i]->wl_ess_conf_sl;
1754 				(void) memset(flag, 0, i);
1755 			} else if (p_ess_conf[i]->wl_ess_conf_sl == maxsignal)
1756 				continue;
1757 			else
1758 				flag[i] = 0;
1759 		}
1760 	}
1761 	for (i = 0; i < ess_num; i++) {
1762 		if (flag[i] == 1)
1763 			break;
1764 	}
1765 	free(flag);
1766 	PRTDBG(("heuristic_load: %s is selected\n",
1767 	    p_ess_conf[i]->wl_ess_conf_essid.wl_essid_essid));
1768 	/* select one in all the networks which meet the preceding stardands */
1769 	if (i == ess_num)
1770 		(void) do_set_essid(fd, "");
1771 	else
1772 		(void) do_set_essid(fd,
1773 		    p_ess_conf[i]->wl_ess_conf_essid.wl_essid_essid);
1774 
1775 	if ((ess_num == 0) || (do_get_essid(fd) == B_FALSE)) {
1776 		(void) fprintf(stderr, gettext("%s: autoconf:"
1777 		    " failed to connect to any essid\n"),
1778 		    gExecName);
1779 		exit(WIFI_MINOR_ERR);
1780 	}
1781 	(void) strlcpy(essid, ((wl_essid_t *)(gbuf->wldp_buf))->wl_essid_essid,
1782 	    sizeof (essid));
1783 	(void) printf(gettext("%s: autoconf: essid '%s' is selected%s\n"),
1784 	    gExecName, essid,
1785 	    have_nowep_wlan ? "" : ": this is a WEPed "
1786 	    "access point");
1787 
1788 	if (!have_nowep_wlan)
1789 		exit(WIFI_FATAL_ERR);
1790 
1791 	while (timeout > 0) {
1792 		if ((do_get_linkstatus(fd) == B_TRUE) &&
1793 		    (*(wl_linkstatus_t *)(gbuf->wldp_buf) == WL_CONNECTED)) {
1794 			(void) printf(gettext("%s: connecting to "
1795 			    "essid '%s'\n"), gExecName, essid);
1796 			return;
1797 		}
1798 		(void) sleep(1);
1799 		timeout--;
1800 	}
1801 	(void) fprintf(stderr, gettext("%s: failed to connect to "
1802 	    "essid '%s'\n"), gExecName, essid);
1803 	exit(WIFI_FATAL_ERR);
1804 }
1805 
1806 /*
1807  * Called in autoconf and startconf to find which 'profile' is selected.
1808  * The process is: check profile names in the prefer list item by item,
1809  * if the essid of the profile is in the scan list, then it is the wanted.
1810  * readonly: 1 for startconf
1811  *           0 for autoconf
1812  * for autoconf, the scan result will be recorded in the history list.
1813  */
1814 static char *
select_profile(int fd,int readonly,int timeout)1815 select_profile(int fd, int readonly, int timeout)
1816 {
1817 	uint32_t ess_num = 0;
1818 	int nprefer = 1;
1819 	char **ess_argv;
1820 	char **hisess_argv;
1821 	wl_ess_conf_t **p_ess_conf;
1822 	section_t *p_section = NULL;
1823 	aelist_t *plist = NULL;
1824 	ae_t *pae = NULL;
1825 	int i;
1826 	const char *parg;
1827 	char *selected = NULL;
1828 	boolean_t flag = B_FALSE;
1829 
1830 	if ((call_ioctl(fd, WLAN_COMMAND, WL_SCAN, 0) == B_FALSE) ||
1831 	    (do_get_wlanlist(fd) == B_FALSE)) {
1832 		(void) fprintf(stderr, gettext("%s: "
1833 		    "autoconf : failed to scan\n"), gExecName);
1834 		exit(WIFI_FATAL_ERR);
1835 	}
1836 	ess_num = ((wl_ess_list_t *)(gbuf->wldp_buf))->wl_ess_list_num;
1837 	ess_argv = safe_calloc(sizeof (char *), ess_num);
1838 	hisess_argv = safe_calloc(sizeof (char *), ess_num);
1839 	p_ess_conf = safe_calloc(sizeof (wl_ess_list_t *), ess_num);
1840 	for (i = 0; i < ess_num; i++) {
1841 		p_ess_conf[i] = ((wl_ess_list_t *)gbuf->wldp_buf)
1842 		    ->wl_ess_list_ess + i;
1843 		ess_argv[i] = safe_malloc(MAX_SCANBUF_LEN);
1844 		if (readonly == 0) {
1845 			hisess_argv[i] = safe_malloc(MAX_SCANBUF_LEN);
1846 			(void) snprintf(hisess_argv[i], MAX_SCANBUF_LEN,
1847 			    "%s%c%02x:%02x:%02x:%02x:%02x:%02x%c%s",
1848 			    p_ess_conf[i]->wl_ess_conf_essid.wl_essid_essid,
1849 			    ',',
1850 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[0]),
1851 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[1]),
1852 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[2]),
1853 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[3]),
1854 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[4]),
1855 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[5]), ',',
1856 			    (p_ess_conf[i]->wl_ess_conf_wepenabled == B_TRUE
1857 			    ?  "wep":"none"));
1858 		}
1859 		(void) snprintf(ess_argv[i], MAX_SCANBUF_LEN, "%s",
1860 		    p_ess_conf[i]->wl_ess_conf_essid.wl_essid_essid);
1861 	}
1862 	if (readonly == 0) {
1863 		add_to_history(gp_config_file, ess_num, hisess_argv);
1864 		for (i = 0; i < ess_num; i++) {
1865 			free(hisess_argv[i]);
1866 		}
1867 		free(hisess_argv);
1868 	}
1869 
1870 	p_section = find_section(gp_config_file, WIFI_PREFER);
1871 	if (p_section == NULL) {
1872 		if (ess_num > 0) {
1873 			heuristic_load(fd, ess_num, p_ess_conf);
1874 			exit(WIFI_EXIT_DEF);
1875 		}
1876 		goto done;
1877 	}
1878 	plist = p_section->list;
1879 	assert(plist != NULL);
1880 	if (plist != NULL) {
1881 		nprefer = plist->ael_argc;
1882 		if (nprefer == 0) {
1883 			if (ess_num > 0) {
1884 				heuristic_load(fd, ess_num, p_ess_conf);
1885 				exit(WIFI_EXIT_DEF);
1886 			}
1887 			goto done;
1888 		}
1889 	}
1890 	pae = plist->ael_head;
1891 	while ((pae != NULL) && (flag != B_TRUE)) {
1892 		parg = essid_of_profile(pae->ae_arg);
1893 		if (parg != NULL) {
1894 			for (i = 0; i < ess_num; i++) {
1895 				if (strcmp(parg, ess_argv[i]) == 0) {
1896 					selected = pae->ae_arg;
1897 					flag = B_TRUE;
1898 					break;
1899 				}
1900 			}
1901 		}
1902 		pae = pae->ae_next;
1903 	}
1904 done:
1905 	if ((selected == NULL) && (timeout == 0)) {
1906 		heuristic_load(fd, ess_num, p_ess_conf);
1907 	}
1908 	for (i = 0; i < ess_num; i++) {
1909 		free(ess_argv[i]);
1910 	}
1911 	free(ess_argv);
1912 	free(p_ess_conf);
1913 	return (selected);
1914 }
1915 
1916 static boolean_t
is_waittime_valid(char * pbuf)1917 is_waittime_valid(char *pbuf)
1918 {
1919 	int i;
1920 
1921 	i = atoi(pbuf);
1922 	if (i == -1)
1923 		return (B_TRUE);
1924 	for (i = 0; i < strlen(pbuf); i++) {
1925 		if (isdigit(pbuf[i]) == 0) {
1926 			return (B_FALSE);
1927 		}
1928 	}
1929 	return (B_TRUE);
1930 }
1931 /*
1932  * do_autoconf: First scan the wlanlist, and select one essid from scan result
1933  * by the order in {preferrence} list. If no match, then heuristic_load;
1934  */
1935 /*ARGSUSED*/
1936 static boolean_t
do_autoconf(int fd,int argc,char ** argv)1937 do_autoconf(int fd, int argc, char **argv)
1938 {
1939 	const char *selected = NULL;
1940 	int timeout = LOADPROFILE_TIMEOUT, forever = 0, len = 0;
1941 	char *pequal, *param;
1942 	char **ld_argv = NULL;
1943 	boolean_t ret = B_TRUE;
1944 
1945 	PRTDBG(("do_autoconf(%d, 0x%x)\n", argc, argv));
1946 	assert(fd > 0);
1947 	if (argc > 0) {
1948 		param = safe_strdup(argv[0]);
1949 		pequal = strchr(param, '=');
1950 		if (pequal != NULL) {
1951 			*pequal++ = '\0';
1952 		} else {
1953 			do_print_usage();
1954 			exit(WIFI_IMPROPER_USE);
1955 		}
1956 		if (strcmp(param, "wait") != 0) {
1957 			do_print_usage();
1958 			exit(WIFI_IMPROPER_USE);
1959 		} else {
1960 			if (strcmp(pequal, "forever") == 0) {
1961 				forever = 1;
1962 			} else {
1963 				if (is_waittime_valid(pequal) == B_FALSE) {
1964 					(void) fprintf(stderr, gettext("%s: "
1965 					    "invalid value %s for 'wait'\n"),
1966 					    gExecName, pequal);
1967 					exit(WIFI_FATAL_ERR);
1968 				}
1969 				if (sscanf(pequal, "%d", &timeout) != 1) {
1970 					do_print_usage();
1971 					exit(WIFI_IMPROPER_USE);
1972 				}
1973 				if (timeout == -1) {
1974 					forever = 1;
1975 				}
1976 			}
1977 		}
1978 		free(param);
1979 		if (argc > 1) {
1980 			(void) fprintf(stderr, gettext("%s: trailing "
1981 			    "useless tokens after '%s'\n"),
1982 			    gExecName, argv[0]);
1983 		}
1984 	}
1985 
1986 	while ((forever == 1) || (timeout > 0)) {
1987 		timeout--;
1988 		selected = select_profile(fd, 0, max(timeout, forever));
1989 		if (selected != NULL)
1990 			break;
1991 		(void) sleep(1);
1992 	}
1993 	if (selected == NULL) {
1994 		return (B_TRUE);
1995 	}
1996 	(void) printf(gettext("%s: autoconf: profile [%s]"
1997 	    " is selected\n"), gExecName, selected);
1998 	ld_argv = safe_calloc(sizeof (char *), argc+1);
1999 	ld_argv[0] = safe_strdup(selected);
2000 	if (argc > 0) {
2001 		len = max(strlen(argv[0]), strlen("wait=forever"));
2002 		ld_argv[1] = safe_malloc(len);
2003 		safe_snprintf(ld_argv[1], len + 1, forever == 1 ?
2004 		    "wait=forever" : "wait=%d", timeout);
2005 	}
2006 	ret = do_loadpf(fd, argc+1, ld_argv);
2007 	free(ld_argv[0]);
2008 	if (argc > 0) {
2009 		free(ld_argv[1]);
2010 	}
2011 	free(ld_argv);
2012 	return (ret);
2013 }
2014 
2015 /*
2016  * do_startconf: almost the same as the do_autoconf, except that doesn't
2017  * write file.
2018  */
2019 /*ARGSUSED*/
2020 static boolean_t
do_startconf(int fd,int argc,char ** argv)2021 do_startconf(int fd, int argc, char **argv)
2022 {
2023 	int i = 0, ael_num = 0;
2024 	section_t *p_section = NULL;
2025 	section_t *p_wep_section = NULL;
2026 	aelist_t *plist = NULL;
2027 	const char *selected = NULL;
2028 	ae_t *pae = NULL;
2029 	char *pbuf = NULL;
2030 	char **argvnew = NULL;
2031 
2032 	PRTDBG(("do_startconf(%d, 0x%x)\n", argc, argv));
2033 	assert(fd > 0);
2034 
2035 	selected = select_profile(fd, 1, 0);
2036 	if (selected == NULL) {
2037 		return (B_TRUE);
2038 	}
2039 
2040 	(void) call_ioctl(fd, WLAN_COMMAND, WL_LOAD_DEFAULTS, 0);
2041 
2042 	pbuf = append_pa(selected);
2043 	p_wep_section = find_section(gp_wepkey_file, pbuf);
2044 	p_section = find_section(gp_config_file, pbuf);
2045 	free(pbuf);
2046 
2047 	if (p_wep_section != NULL) {
2048 		plist = p_wep_section->list;
2049 		pae = plist->ael_head;
2050 		while (pae != NULL) {
2051 			if (pae->ae_arg != NULL)
2052 				(void) do_set_wepkey(fd, pae->ae_arg);
2053 			pae = pae->ae_next;
2054 		}
2055 	}
2056 
2057 	if (p_section != NULL) {
2058 		plist = p_section->list;
2059 		if (plist->ael_argc == 0) {
2060 			return (B_TRUE);
2061 		}
2062 		argvnew = aeltoargv(plist, &ael_num);
2063 		(void) do_set(fd, ael_num, argvnew);
2064 
2065 		for (i = 0; i < ael_num; i++)
2066 			free(argvnew[i]);
2067 		free(argvnew);
2068 	}
2069 	return (B_TRUE);
2070 }
2071 
2072 static char *
find_active_profile(int fd)2073 find_active_profile(int fd)
2074 {
2075 	section_t *p_section = NULL, *activep_section = NULL;
2076 	aelist_t *plist = NULL;
2077 	ae_t *pae = NULL;
2078 	const char *pessid = NULL, *pbssid = NULL;
2079 	char essid[34], bssid[32];
2080 	const char *activeprofile = NULL;
2081 
2082 	PRTDBG(("find_active_profile: %d\n", fd));
2083 	if (do_get_essid(fd) == B_FALSE) {
2084 		return (NULL);
2085 	}
2086 	(void) strlcpy(essid, ((wl_essid_t *)(gbuf->wldp_buf))->wl_essid_essid,
2087 	    sizeof (essid));
2088 	if (do_get_bssid(fd) == B_FALSE) {
2089 		return (NULL);
2090 	}
2091 	safe_snprintf(bssid, sizeof (bssid), "%02x:%02x:%02x:%02x:%02x:%02x",
2092 	    ((uint8_t *)gbuf->wldp_buf)[0],
2093 	    ((uint8_t *)gbuf->wldp_buf)[1],
2094 	    ((uint8_t *)gbuf->wldp_buf)[2],
2095 	    ((uint8_t *)gbuf->wldp_buf)[3],
2096 	    ((uint8_t *)gbuf->wldp_buf)[4],
2097 	    ((uint8_t *)gbuf->wldp_buf)[5]);
2098 	activep_section = find_section(gp_config_file, WIFI_ACTIVEP);
2099 	if (activep_section == NULL)
2100 		return (NULL);
2101 	activeprofile = get_value(activep_section->list->
2102 	    ael_head->ae_arg);
2103 	if (activeprofile == NULL)
2104 		return (NULL);
2105 	p_section = gp_config_file->section_head;
2106 	while (p_section != NULL) {
2107 		if (((plist = p_section->list) != NULL) &&
2108 		    (plist->type == PROFILE) &&
2109 		    (strcmp(p_section->section_id, activeprofile) == 0)) {
2110 			pae = plist->ael_head;
2111 			while (pae != NULL) {
2112 				if (strncmp(pae->ae_arg, "essid=",
2113 				    strlen("essid=")) == 0) {
2114 					pessid = get_value(pae->ae_arg);
2115 				}
2116 				if (strncmp(pae->ae_arg, "bssid=",
2117 				    strlen("bssid=")) == 0) {
2118 					pbssid = get_value(pae->ae_arg);
2119 				}
2120 				pae = pae->ae_next;
2121 			}
2122 			if (pessid && pbssid &&
2123 			    (strcmp(essid, pessid) == 0) &&
2124 			    (strcmp(bssid, pbssid) == 0)) {
2125 				return (p_section->section_id);
2126 			}
2127 		}
2128 		p_section = p_section->section_next;
2129 	}
2130 	return (NULL);
2131 }
2132 
2133 static void
record_active_profile(char * pname,int action)2134 record_active_profile(char *pname, int action)
2135 {
2136 	section_t *p_section = NULL;
2137 	aelist_t *plist = NULL;
2138 	char pbuf[256];
2139 
2140 	p_section = find_section(gp_config_file, WIFI_ACTIVEP);
2141 	if (p_section == NULL) {
2142 		plist = new_ael(ACTIVEP);
2143 		new_section(gp_config_file, plist, WIFI_ACTIVEP);
2144 	} else {
2145 		plist = p_section->list;
2146 	}
2147 
2148 	if (action == RECORD_ADD) {
2149 		assert(pname != NULL);
2150 		safe_snprintf(pbuf, sizeof (pbuf), "activep=%s", pname);
2151 		update_aelist(plist, pbuf);
2152 	} else if (action == RECORD_DEL) {
2153 		assert(pname == NULL);
2154 		update_aelist(plist, "activep= ");
2155 	}
2156 }
2157 
2158 /*
2159  * do_loadpf: load a profile, set related parameters both in wifi
2160  * and in wifiwepkey, if network name is not exist in the
2161  * configration files, then we clean all parameters and set essid only
2162  */
2163 static boolean_t
do_loadpf(int fd,int argc,char ** argv)2164 do_loadpf(int fd, int argc, char ** argv)
2165 {
2166 	int i = 0, ael_num = 0;
2167 	int timeout = LOADPROFILE_TIMEOUT, forever = 0;
2168 	section_t *p_section = NULL;
2169 	section_t *p_wep_section = NULL;
2170 	aelist_t *plist = NULL;
2171 	ae_t *pae = NULL;
2172 	char *pbuf = NULL;
2173 	char **argvnew = NULL;
2174 	char *connect;
2175 	char *pequal, *param;
2176 
2177 	PRTDBG(("do_loadpf(%d, %x)\n", argc, argv));
2178 	assert(fd > 0);
2179 	if (argc == 0) {
2180 		(void) fprintf(stderr, gettext("%s: connect: "
2181 		    "profile name missing\n"), gExecName);
2182 		return (B_FALSE);
2183 	}
2184 	if (argc > 1) {
2185 		param = safe_strdup(argv[1]);
2186 		pequal = strchr(param, '=');
2187 		if (pequal != NULL) {
2188 			*pequal++ = '\0';
2189 		} else {
2190 			do_print_usage();
2191 			exit(WIFI_IMPROPER_USE);
2192 		}
2193 		if (strcmp(param, "wait") != 0) {
2194 			do_print_usage();
2195 			exit(WIFI_IMPROPER_USE);
2196 		} else {
2197 			if (strcmp(pequal, "forever") == 0) {
2198 				forever = 1;
2199 			} else {
2200 				if (is_waittime_valid(pequal) == B_FALSE) {
2201 					(void) fprintf(stderr, gettext("%s: "
2202 					    "invalid value %s for 'wait'\n"),
2203 					    gExecName, pequal);
2204 					exit(WIFI_FATAL_ERR);
2205 				}
2206 				if (sscanf(pequal, "%d", &timeout) != 1) {
2207 					do_print_usage();
2208 					exit(WIFI_IMPROPER_USE);
2209 				}
2210 				if (timeout == -1) {
2211 					forever = 1;
2212 				}
2213 			}
2214 		}
2215 		free(param);
2216 		if (argc > 2) {
2217 			(void) fprintf(stderr, gettext("%s: trailing "
2218 			    "useless tokens after '%s'\n"),
2219 			    gExecName, argv[1]);
2220 		}
2221 	}
2222 	(void) call_ioctl(fd, WLAN_COMMAND, WL_LOAD_DEFAULTS, 0);
2223 
2224 	pbuf = append_pa(argv[0]);
2225 	p_wep_section = find_section(gp_wepkey_file, pbuf);
2226 	p_section = find_section(gp_config_file, pbuf);
2227 
2228 	if (p_wep_section != NULL) {
2229 		(void) set_prefer(gp_config_file, argv[0], 1);
2230 		plist = p_wep_section->list;
2231 		pae = plist->ael_head;
2232 		while (pae != NULL) {
2233 			if (pae->ae_arg != NULL) {
2234 				(void) do_set_wepkey(fd, pae->ae_arg);
2235 			}
2236 			pae = pae->ae_next;
2237 		}
2238 	}
2239 
2240 	if (p_section != NULL) {
2241 		connect = "profile";
2242 
2243 		(void) set_prefer(gp_config_file, argv[0], 1);
2244 		plist = p_section->list;
2245 		if (plist->ael_argc == 0) {
2246 			free(pbuf);
2247 			return (B_TRUE);
2248 		}
2249 		argvnew = aeltoargv(plist, &ael_num);
2250 		/*
2251 		 * if there is no 'essid' item in argvnew, the profile
2252 		 * name(argv[0]) is treated as essid.
2253 		 */
2254 		for (i = 0; i < ael_num; i++) {
2255 			if (strncmp(argvnew[i], "essid=", strlen("essid="))
2256 			    == 0)
2257 				break;
2258 		}
2259 		if (i == ael_num)
2260 			(void) do_set_essid(fd, argv[0]);
2261 
2262 		(void) do_set(fd, ael_num, argvnew);
2263 
2264 		for (i = 0; i < ael_num; i++)
2265 			free(argvnew[i]);
2266 		free(argvnew);
2267 
2268 		/*
2269 		 * set flag in {active_profile} so that showprofile knows
2270 		 * which profile is active when more than one profiles are
2271 		 * created for the same WLAN.
2272 		 */
2273 		record_active_profile(pbuf, RECORD_ADD);
2274 	} else {
2275 		(void) do_set_essid(fd, argv[0]);
2276 		connect = "essid";
2277 	}
2278 
2279 	while ((forever == 1) || (timeout > 0)) {
2280 		if ((do_get_linkstatus(fd) == B_TRUE) &&
2281 		    (*(wl_linkstatus_t *)(gbuf->wldp_buf) == WL_CONNECTED)) {
2282 			section_t *p_section = NULL;
2283 			aelist_t *plist = NULL;
2284 			char bssid[32];
2285 			/* record bssid in the profile */
2286 			if (do_get_bssid(fd) == B_FALSE) {
2287 				free(pbuf);
2288 				return (B_TRUE);
2289 			}
2290 			safe_snprintf(bssid, sizeof (bssid),
2291 			    "bssid=%02x:%02x:%02x:%02x:%02x:%02x",
2292 			    ((uint8_t *)gbuf->wldp_buf)[0],
2293 			    ((uint8_t *)gbuf->wldp_buf)[1],
2294 			    ((uint8_t *)gbuf->wldp_buf)[2],
2295 			    ((uint8_t *)gbuf->wldp_buf)[3],
2296 			    ((uint8_t *)gbuf->wldp_buf)[4],
2297 			    ((uint8_t *)gbuf->wldp_buf)[5]);
2298 
2299 			p_section = find_section(gp_config_file, pbuf);
2300 			if (p_section != NULL) {
2301 				plist = p_section->list;
2302 				update_aelist(plist, bssid);
2303 			}
2304 			free(pbuf);
2305 			(void) printf(gettext("%s: connecting to "
2306 			    "%s '%s'\n"), gExecName, connect, argv[0]);
2307 			return (B_TRUE);
2308 		}
2309 		(void) sleep(1);
2310 		timeout--;
2311 		PRTDBG(("connect counting:......%d\n", timeout));
2312 	}
2313 	(void) fprintf(stderr, gettext("%s: failed to connect to "
2314 	    "%s '%s'\n"), gExecName, connect, argv[0]);
2315 	free(pbuf);
2316 	return (B_FALSE);
2317 }
2318 
2319 /*
2320  * if wepkey is set in the profile, display wepkey|n=*****
2321  * when showprofile and getprofilewepkey.
2322  * if wepkeyn is NULL, all the wepkeys will be display,
2323  * otherwise, just display the matching one.
2324  */
2325 static void
print_wepkey_info(const char * id,const char * wepkeyn)2326 print_wepkey_info(const char *id, const char *wepkeyn)
2327 {
2328 	char *pequal, *param;
2329 	section_t *p_section = NULL;
2330 	aelist_t *plist = NULL;
2331 	ae_t *pae = NULL;
2332 
2333 	p_section = find_section(gp_wepkey_file, id);
2334 	if (p_section != NULL) {
2335 		plist = p_section->list;
2336 		pae = plist->ael_head;
2337 		while (pae != NULL) {
2338 			if (pae->ae_arg != NULL) {
2339 				param = safe_strdup(pae->ae_arg);
2340 				pequal = strchr(param, '=');
2341 				if (pequal == NULL)
2342 					return;
2343 				*pequal = '\0';
2344 				if (wepkeyn != NULL) {
2345 					if (strcmp(wepkeyn, param) == 0)
2346 						(void) printf("\t%s=*****\n",
2347 						    param);
2348 					free(param);
2349 					return;
2350 				} else {
2351 					(void) printf("\t%s=*****\n", param);
2352 					free(param);
2353 				}
2354 			}
2355 			pae = pae->ae_next;
2356 		}
2357 	}
2358 }
2359 
2360 /*
2361  * do_printpf: print each parameters of the profile, if no network name
2362  * assigned, then print all profile saved in configration file.
2363  */
2364 /*ARGSUSED*/
2365 static boolean_t
do_printpf(int fd,int argc,char ** argv)2366 do_printpf(int fd, int argc, char ** argv)
2367 {
2368 	section_t *p_section = NULL;
2369 	aelist_t *plist = NULL;
2370 	ae_t *pae = NULL;
2371 	char *pbuf = NULL;
2372 	int i;
2373 
2374 	PRTDBG(("do_printpf(%d, %x)\n", argc, argv));
2375 
2376 	/*
2377 	 * if no profile name is inputted, all the profiles will be displayed.
2378 	 */
2379 	if (argc == 0) {
2380 		p_section = gp_config_file->section_head;
2381 		while (p_section != NULL) {
2382 			plist = p_section->list;
2383 			if (plist->type == PROFILE) {
2384 				(void) printf("%s\n", p_section->section_id);
2385 				pae = plist->ael_head;
2386 				while (pae != NULL) {
2387 					if (pae->ae_arg != NULL) {
2388 						(void) printf("\t%s\n",
2389 						    pae->ae_arg);
2390 					}
2391 					pae = pae->ae_next;
2392 				}
2393 				/*
2394 				 * identify whether wepkey is set
2395 				 * in the profile
2396 				 */
2397 				print_wepkey_info(p_section->section_id, NULL);
2398 			}
2399 			p_section = p_section->section_next;
2400 		}
2401 		return (B_TRUE);
2402 	}
2403 
2404 	for (i = 0; i < argc; i++) {
2405 		pbuf =	append_pa(argv[i]);
2406 		p_section = find_section(gp_config_file, pbuf);
2407 		free(pbuf);
2408 		if (p_section != NULL)	{
2409 			(void) printf("%s\n", p_section->section_id);
2410 			plist = p_section->list;
2411 			if (plist != NULL) {
2412 				pae = plist->ael_head;
2413 				while (pae != NULL) {
2414 					if (pae->ae_arg != NULL) {
2415 						(void) printf("\t%s\n",
2416 						    pae->ae_arg);
2417 					}
2418 					pae = pae->ae_next;
2419 				}
2420 				/*
2421 				 * identify whether wepkey is set
2422 				 * in the profile
2423 				 */
2424 				print_wepkey_info(p_section->section_id, NULL);
2425 			}
2426 		} else {
2427 			(void) fprintf(stderr,
2428 			    gettext("%s: showprofile : "
2429 			    "no such profile: '%s'\n"),
2430 			    gExecName, argv[i]);
2431 			return (B_FALSE);
2432 		}
2433 	}
2434 	return (B_TRUE);
2435 }
2436 /*
2437  * find_ae: Find an ae by its contents, return its pointer.
2438  */
2439 static ae_t *
find_ae(aelist_t * plist,const char * arg)2440 find_ae(aelist_t *plist, const char *arg)
2441 {
2442 	char *param = NULL;
2443 	char *pnext = NULL;
2444 	ae_t *pae = NULL;
2445 
2446 	if ((arg == NULL) || (plist == NULL)) {
2447 		PRTDBG(("find_ae: arg= NULL or plist=NULL\n"));
2448 		return (NULL);
2449 	}
2450 	PRTDBG(("find_ae(0x%x, \"%s\")\n", plist, arg));
2451 	param = safe_strdup(arg);
2452 	pnext = strchr(param, '=');
2453 	if (pnext != NULL) {
2454 		*pnext = '\0';
2455 	} else {
2456 		PRTDBG(("find_ae: param = \"%s\"\n", param));
2457 		free(param);
2458 		return (NULL);
2459 	}
2460 
2461 	pae = plist->ael_head;
2462 	while (pae != NULL) {
2463 		if ((pae->ae_arg != NULL) &&
2464 		    (strncmp(pae->ae_arg, param, strlen(param)) == 0)) {
2465 			PRTDBG(("find_ae: param = \"%s\"\n", param));
2466 			free(param);
2467 			return (pae);
2468 		}
2469 		pae = pae->ae_next;
2470 	}
2471 	free(param);
2472 	return (NULL);
2473 }
2474 
2475 /*
2476  * update_aelist: Update an aelist by arg, for example:
2477  * there are an item with content"essid=ap7-2",
2478  * update_aelist(0x..., "essid=myssid2") will update it as "essid=myssid2"
2479  */
2480 static void
update_aelist(aelist_t * plist,const char * arg)2481 update_aelist(aelist_t *plist, const char *arg)
2482 {
2483 	ae_t *pae = NULL;
2484 
2485 	assert((arg != NULL)&&(plist != NULL));
2486 	PRTDBG(("update_aelist(0x%x, \"%s\")\n", plist, arg));
2487 	pae = find_ae(plist, arg);
2488 	if (pae == NULL) {
2489 		new_ae(plist, arg);
2490 	} else {
2491 		free(pae->ae_arg);
2492 		pae->ae_arg = safe_strdup(arg);
2493 	}
2494 }
2495 
2496 /*
2497  * do_deletepf: delete a profile in configration files.
2498  */
2499 /*ARGSUSED*/
2500 static boolean_t
do_deletepf(int fd,int argc,char ** argv)2501 do_deletepf(int fd, int argc, char **argv)
2502 {
2503 	int i = 0;
2504 	char *section_id;
2505 	char *prefer;
2506 	section_t *p_section = NULL, *p_sectionbak = NULL;
2507 	aelist_t *plist = NULL;
2508 
2509 	PRTDBG(("do_deletepf(%d, \"%s\")\n", argc, argv));
2510 	if (argc <= 0) {
2511 		do_print_usage();
2512 		exit(WIFI_IMPROPER_USE);
2513 	}
2514 
2515 	/*
2516 	 * if a "all" is inputted, all the profiles will be deleted.
2517 	 */
2518 	if (strcasecmp(argv[0], "all") == 0) {
2519 		p_section = gp_config_file->section_head;
2520 		while ((p_section != NULL) &&
2521 		    ((plist = p_section->list) != NULL)) {
2522 			if (plist->type == PROFILE) {
2523 				p_sectionbak = p_section->section_next;
2524 				section_id = safe_strdup(p_section->section_id);
2525 				(void) del_section(gp_config_file, section_id);
2526 				(void) del_section(gp_wepkey_file, section_id);
2527 				/*
2528 				 * remove the '[]' of the [section_id]
2529 				 */
2530 				prefer = section_id + 1;
2531 				*(prefer + strlen(section_id) - 2) = '\0';
2532 				(void) del_prefer(gp_config_file, prefer,
2533 				    B_FALSE);
2534 				free(section_id);
2535 				p_section = p_sectionbak;
2536 				continue;
2537 			}
2538 			p_section = p_section->section_next;
2539 		}
2540 		return (B_TRUE);
2541 	}
2542 	if (gp_config_file != NULL) {
2543 		for (i = 0; i < argc; i++) {
2544 			section_id = append_pa(argv[i]);
2545 			if (del_section(gp_config_file, section_id)
2546 			    == B_FALSE) {
2547 				if (del_section(gp_wepkey_file, section_id)
2548 				    == B_TRUE) {
2549 					(void) del_prefer(gp_config_file,
2550 					    argv[i], B_FALSE);
2551 					free(section_id);
2552 					return (B_TRUE);
2553 				} else {
2554 					(void) fprintf(stderr,
2555 					    gettext("%s: deleteprofile"
2556 					    ": no such profile: '%s'\n"),
2557 					    gExecName, argv[i]);
2558 					free(section_id);
2559 					return (B_FALSE);
2560 				}
2561 			}
2562 			(void) del_prefer(gp_config_file, argv[i], B_FALSE);
2563 			(void) del_section(gp_wepkey_file, section_id);
2564 			free(section_id);
2565 		}
2566 	}
2567 	return (B_TRUE);
2568 }
2569 
2570 /*
2571  * do_history: Print the list in {history} section.
2572  */
2573 /*ARGSUSED*/
2574 static boolean_t
do_history(int fd,int argc,char ** argv)2575 do_history(int fd, int argc, char **argv)
2576 {
2577 	section_t *p_section = NULL;
2578 	aelist_t *plist = NULL;
2579 	ae_t *pae = NULL;
2580 	char *param, *param_bak, *pcomma;
2581 	uint32_t maxessidlen = 0, ulen;
2582 	char format[256], *ntstr;
2583 	uint32_t nt = 0, cnt = 0;
2584 	int len;
2585 	time_t cltime;
2586 
2587 	PRTDBG(("do_history(%d, 0x%x)\n", argc, argv));
2588 	if (argc > 0) {
2589 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
2590 		    "after 'history'\n"), gExecName);
2591 	}
2592 	p_section = find_section(gp_config_file, WIFI_HISTORY);
2593 	if (p_section == NULL) {
2594 		PRTDBG(("no history section\n"));
2595 		return (B_FALSE);
2596 	}
2597 	plist = p_section->list;
2598 
2599 	/*
2600 	 * If history section is empty, directly return.
2601 	 */
2602 	if (plist == NULL)
2603 		return (B_TRUE);
2604 	/*
2605 	 * construct the output format in terms of the
2606 	 * maxmium essid length
2607 	 */
2608 	pae = NULL;
2609 	pae = plist->ael_head;
2610 	while (pae != NULL) {
2611 		if (pae->ae_arg != NULL) {
2612 			param = safe_strdup(pae->ae_arg);
2613 			pcomma = strchr(param, ',');
2614 			if (pcomma == NULL) {
2615 				(void) fprintf(stderr,
2616 				    gettext("%s: history : "
2617 				    "data format error\n"),
2618 				    gExecName);
2619 				free(param);
2620 				return (B_FALSE);
2621 			}
2622 			*pcomma = '\0';
2623 			ulen = strlen(param);
2624 			maxessidlen = (maxessidlen > ulen
2625 			    ? maxessidlen:ulen);
2626 			free(param);
2627 		}
2628 		pae = pae->ae_next;
2629 	}
2630 	if ((nt = (maxessidlen / 8 + 1)) > 4)
2631 		nt = 4;
2632 	len = snprintf(format, sizeof (format), gettext("essid"));
2633 	ntstr = construct_format(nt);
2634 	assert((ntstr != NULL) && (strlen(ntstr) <= 4));
2635 	len += snprintf(format + len, sizeof (format) - len, "%s", ntstr);
2636 	len += snprintf(format + len, sizeof (format) - len,
2637 	    gettext("bssid\t\t  encryption\tlast seen\n"));
2638 
2639 	if ((len <= 0) || (len > sizeof (format) - 1)) {
2640 		(void) printf(gettext("essid\t\t\t\tbssid\t\t  encryption"
2641 		    "\tlast seen\n"));
2642 	} else {
2643 		(void) printf("%s", format);
2644 	}
2645 	/*
2646 	 * output the contents of the history section.
2647 	 */
2648 	pae = plist->ael_head;
2649 	while (pae != NULL) {
2650 		if (pae->ae_arg != NULL) {
2651 			param = safe_strdup(pae->ae_arg);
2652 			param_bak = param;
2653 			if ((pcomma = strchr(param, ',')) != NULL) {
2654 				*pcomma = '\0';
2655 				cnt = nt - (min((strlen(param)/8 + 1), 4) - 1);
2656 				ntstr = construct_format(cnt);
2657 				assert(ntstr != NULL);
2658 				/* display essid */
2659 				(void) printf("%s%s", param, ntstr);
2660 				free(ntstr);
2661 			}
2662 			param = pcomma + 1;
2663 			if ((pcomma = strchr(param, ',')) != NULL) {
2664 				*pcomma = '\0';
2665 				/* display bssid */
2666 				(void) printf("%s ", param);
2667 			}
2668 			param = pcomma + 1;
2669 			if ((pcomma = strchr(param, ',')) != NULL) {
2670 				*pcomma = '\0';
2671 				/* display wep */
2672 				(void) printf("%s\t\t", param);
2673 			}
2674 			param = pcomma + 1;
2675 			/* display time stamp */
2676 			cltime = (time_t)atol(param);
2677 			(void) printf("%s", ctime(&cltime));
2678 			free(param_bak);
2679 		}
2680 		pae = pae->ae_next;
2681 	}
2682 
2683 	return (B_TRUE);
2684 }
2685 
2686 /*
2687  * do_lsprefer: Print the list in {preferrence} section
2688  */
2689 /*ARGSUSED*/
2690 static boolean_t
do_lsprefer(int fd,int argc,char ** argv)2691 do_lsprefer(int fd, int argc, char **argv)
2692 {
2693 	int i = 0;
2694 	section_t *p_section = NULL;
2695 	aelist_t *plist = NULL;
2696 	ae_t *pae = NULL;
2697 	char *pbuf;
2698 
2699 	PRTDBG(("do_lsprefer(%d, 0x%x)\n", argc, argv));
2700 	if (argc > 0) {
2701 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
2702 		    "after 'listprefer'\n"), gExecName);
2703 	}
2704 	p_section = find_section(gp_config_file, WIFI_PREFER);
2705 	if (p_section != NULL) {
2706 		plist = p_section->list;
2707 		if (plist != NULL) {
2708 			pae = NULL;
2709 			pae = plist->ael_head;
2710 			while (pae != NULL) {
2711 				if (pae->ae_arg != NULL) {
2712 					pbuf = append_pa(pae->ae_arg);
2713 					(void) printf("%d\t%s\n", ++i, pbuf);
2714 				}
2715 				pae = pae->ae_next;
2716 			}
2717 		}
2718 		return (B_TRUE);
2719 	} else {
2720 		PRTDBG(("no preference section\n"));
2721 		return (B_FALSE);
2722 	}
2723 }
2724 
2725 /*
2726  * do_rmprefer: Remove an item in {preferrence} list
2727  */
2728 /*ARGSUSED*/
2729 static boolean_t
do_rmprefer(int fd,int argc,char ** argv)2730 do_rmprefer(int fd, int argc, char **argv)
2731 {
2732 	int i = 0;
2733 	section_t *p_section = NULL;
2734 	aelist_t *plist = NULL;
2735 	ae_t *pae = NULL;
2736 
2737 	PRTDBG(("do_rmprefer(%d, 0x%x)\n", argc, argv));
2738 	if (argc <= 0) {
2739 		do_print_usage();
2740 		exit(WIFI_IMPROPER_USE);
2741 	}
2742 
2743 	/*
2744 	 * if a "all" is inputted, all the items in the preference
2745 	 * list will be deleted.
2746 	 */
2747 	if (strcasecmp(argv[0], "all") == 0) {
2748 		p_section = find_section(gp_config_file, WIFI_PREFER);
2749 		if (p_section != NULL)
2750 			plist = p_section->list;
2751 
2752 		if ((p_section == NULL) || (plist == NULL))
2753 			return (B_FALSE);
2754 		pae = plist->ael_head;
2755 		while (pae != NULL) {
2756 			ae_t *next = pae->ae_next;
2757 			free(pae);
2758 			pae = next;
2759 		}
2760 		plist->ael_head = plist->ael_tail = NULL;
2761 		plist->ael_argc = 0;
2762 	} else if (gp_config_file != NULL) {
2763 		for (i = 0; i < argc; i++) {
2764 			if (del_prefer(gp_config_file, argv[i], B_TRUE)
2765 			    == B_FALSE) {
2766 				return (B_FALSE);
2767 			}
2768 		}
2769 	}
2770 	return (B_TRUE);
2771 }
2772 
2773 static boolean_t
is_prefer_rank_valid(const char * pbuf)2774 is_prefer_rank_valid(const char *pbuf)
2775 {
2776 	int i;
2777 	boolean_t ret = B_FALSE;
2778 
2779 	for (i = 0; i < strlen(pbuf); i++) {
2780 		if (isdigit(pbuf[i]) == 0) {
2781 			ret = B_FALSE;
2782 			goto exit0;
2783 		}
2784 	}
2785 	i = atoi(pbuf);
2786 	if ((i >= 1) && (i <= MAX_PREFERENCE_NUM))
2787 		ret = B_TRUE;
2788 exit0:
2789 	return (ret);
2790 }
2791 
2792 /*
2793  * do_setprefer: Set network preferrence
2794  */
2795 /*ARGSUSED*/
2796 static boolean_t
do_setprefer(int fd,int argc,char ** argv)2797 do_setprefer(int fd, int argc, char **argv)
2798 {
2799 	int rank = 0;
2800 
2801 	PRTDBG(("do_setprefer(%d, 0x%x)\n", argc, argv));
2802 	if (argc <= 0) {
2803 		do_print_usage();
2804 		exit(WIFI_IMPROPER_USE);
2805 	}
2806 	if (argc == 1) {
2807 		rank = 1;
2808 	} else {
2809 		if (is_prefer_rank_valid(argv[1]) == B_FALSE) {
2810 			(void) fprintf(stderr, gettext("%s: preference rank "
2811 			    "should be an integer within 1-10\n"), gExecName);
2812 			return (B_FALSE);
2813 		}
2814 		rank = atoi(argv[1]);
2815 	}
2816 	return (set_prefer(gp_config_file, argv[0], rank));
2817 }
2818 
2819 static boolean_t
is_wepkeyindex_valid(const char * pbuf)2820 is_wepkeyindex_valid(const char *pbuf)
2821 {
2822 	int i;
2823 	boolean_t ret = B_FALSE;
2824 
2825 	for (i = 0; i < strlen(pbuf); i++) {
2826 		if (isdigit(pbuf[i]) == 0) {
2827 			ret = B_FALSE;
2828 			goto exit0;
2829 		}
2830 	}
2831 	i = atoi(pbuf);
2832 	if ((i >= 1) && (i <= MAX_NWEPKEYS))
2833 		ret = B_TRUE;
2834 exit0:
2835 	return (ret);
2836 }
2837 
2838 static boolean_t
is_channel_valid(const char * pbuf)2839 is_channel_valid(const char *pbuf)
2840 {
2841 	int i;
2842 	boolean_t ret = B_FALSE;
2843 
2844 	for (i = 0; i < strlen(pbuf); i++) {
2845 		if (isdigit(pbuf[i]) == 0) {
2846 			ret = B_FALSE;
2847 			goto exit0;
2848 		}
2849 	}
2850 	i = atoi(pbuf);
2851 	if ((i >= 0) && (i <= MAX_CHANNEL_NUM))
2852 		ret = B_TRUE;
2853 exit0:
2854 	return (ret);
2855 }
2856 
2857 static boolean_t
is_wepkey_valid(const char * pbuf,uint32_t length)2858 is_wepkey_valid(const char *pbuf, uint32_t length)
2859 {
2860 	int i;
2861 	boolean_t ret = B_FALSE;
2862 
2863 	switch (length) {
2864 	case 10:
2865 	case 26:
2866 		for (i = 0; i < length; i++) {
2867 			if (isxdigit(pbuf[i]) == 0) {
2868 				ret = B_FALSE;
2869 				goto exit0;
2870 			}
2871 		}
2872 		ret = B_TRUE;
2873 		break;
2874 	case 5:
2875 	case 13:
2876 		ret = B_TRUE;
2877 		break;
2878 	default:
2879 		ret = B_FALSE;
2880 		break;
2881 	}
2882 exit0:
2883 	if (ret == B_FALSE) {
2884 		(void) fprintf(stderr, gettext("%s: "
2885 		    "wepkey should be:\n"
2886 		    "\t 40bits: 5 char or 10 hex digits.\n"
2887 		    "\t 128bits: 13 char or 26 hex digits.\n"),
2888 		    gExecName);
2889 	}
2890 	return (ret);
2891 }
2892 
2893 /*
2894  * get_valid_wepkey: get an valid wepkey from stdin
2895  */
2896 static char *
get_valid_wepkey()2897 get_valid_wepkey()
2898 {
2899 	int i = 0;
2900 	char *buf = NULL;
2901 	uint8_t length = 0;
2902 	struct termios stored_settings;
2903 	struct termios new_settings;
2904 
2905 	PRTDBG(("get_valid_wepkey()\n"));
2906 	buf = safe_calloc(sizeof (char), MAX_KEY_LENGTH + 2);
2907 	/*
2908 	 * Because we need to get single char from terminal, so we need to
2909 	 * disable canonical mode and set buffer size to 1 tyte. And because
2910 	 * wepkey should not be see by others, so we disable echo too.
2911 	 */
2912 	(void) fflush(stdin);
2913 	(void) tcgetattr(0, &stored_settings);
2914 	new_settings = stored_settings;
2915 	new_settings.c_lflag &= (~ICANON);
2916 	new_settings.c_lflag &= (~ECHO);
2917 	new_settings.c_cc[VTIME] = 0;
2918 	new_settings.c_cc[VMIN] = 1;
2919 	/* Set new terminal attributes */
2920 	(void) tcsetattr(0, TCSANOW, &new_settings);
2921 	while (((buf[i++] = getchar()) != '\n') && (i < MAX_KEY_LENGTH + 1)) {
2922 		(void) putchar('*');
2923 	}
2924 	(void) putchar('\n');
2925 	/* Restore terminal attributes */
2926 	(void) tcsetattr(0, TCSANOW, &stored_settings);
2927 	(void) fflush(stdin);
2928 
2929 	if (buf[--i] != '\n') {
2930 		(void) fprintf(stderr, gettext("%s: wepkey length "
2931 		    "exceeds 26 hex digits\n"), gExecName);
2932 		free(buf);
2933 		return (NULL);
2934 	}
2935 	/* Replace last char '\n' with '\0' */
2936 	buf[i] = '\0';
2937 	length = (uint8_t)i;
2938 	return ((is_wepkey_valid(buf, length) == B_TRUE)?
2939 	    buf : NULL);
2940 }
2941 
2942 /*
2943  * do_set_wepkey: Set parameters in wepkey, and call ioctl
2944  */
2945 static boolean_t
do_set_wepkey(int fd,const char * pbuf)2946 do_set_wepkey(int fd, const char *pbuf)
2947 {
2948 	int id = 0;
2949 	char i = 0;
2950 	uint8_t len = 0;
2951 	uint8_t length;
2952 	const char *wepkey = NULL;
2953 	char key[MAX_KEY_LENGTH] = {0};
2954 	unsigned int keytmp;
2955 	wl_wep_key_tab_t wepkey_tab;
2956 
2957 	PRTDBG(("do_set_wepkey(%d, \"%s\")\n", fd, pbuf));
2958 	if (!check_authority(AUTH_WEP)) {
2959 		exit(WIFI_FATAL_ERR);
2960 	}
2961 	id = pbuf[strlen("wepkeyn") - 1] - '0';
2962 	wepkey = get_value(pbuf);
2963 	length = strlen(wepkey);
2964 	switch (length) {
2965 	case 10:
2966 	case 26:
2967 		for (i = 0; i < length / 2; i++) {
2968 			(void) sscanf(wepkey + i * 2, "%2x", &keytmp);
2969 			key[i] = (char)keytmp;
2970 		}
2971 		len = length / 2;
2972 		break;
2973 	case 5:
2974 	case 13:
2975 		(void) strlcpy(key, wepkey, MAX_KEY_LENGTH);
2976 		len = length;
2977 		break;
2978 	default:
2979 		PRTDBG(("do_set_wepkey: error pbuf size\n"));
2980 		(void) fprintf(stderr, gettext("%s: "
2981 		    "wepkey should be:\n"
2982 		    "\t 40bits: 5 char or 10 hex digits.\n"
2983 		    "\t 128bits: 13 char or 26 hex digits.\n"),
2984 		    gExecName);
2985 		exit(WIFI_FATAL_ERR);
2986 	}
2987 
2988 	(void) memset(wepkey_tab, 0, sizeof (wepkey_tab));
2989 	for (i = 0; i < MAX_NWEPKEYS; i++) {
2990 		wepkey_tab[i].wl_wep_operation = WL_NUL;
2991 	}
2992 
2993 	if (id > 0 && id <= MAX_NWEPKEYS) {
2994 		wepkey_tab[id-1].wl_wep_operation = WL_ADD;
2995 		wepkey_tab[id-1].wl_wep_length = len;
2996 		(void) memcpy(wepkey_tab[id-1].wl_wep_key, key, len);
2997 	} else {
2998 		(void) fprintf(stderr, gettext("%s: wepkeyindex "
2999 		    "should be an integer within the range 1-4\n"), gExecName);
3000 		exit(WIFI_FATAL_ERR);
3001 	}
3002 	(void) memmove(gbuf->wldp_buf, &wepkey_tab, sizeof (wl_wep_key_tab_t));
3003 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_WEP_KEY_TAB,
3004 	    sizeof (wl_wep_key_tab_t)));
3005 }
3006 
3007 /*
3008  * get the committed wepkey. the return form is like wepkey1=*****;
3009  */
3010 /*ARGSUSED*/
3011 static char *
get_commit_key(int fd,int argc,char ** argv)3012 get_commit_key(int fd, int argc, char **argv)
3013 {
3014 	int key;
3015 	int len;
3016 	char *wepkey = NULL;
3017 	char *wepkey_confirm = NULL;
3018 	char *pbuf = NULL;
3019 
3020 	key = atoi(argv[0]);
3021 	if (key <= 0 || key > MAX_NWEPKEYS) {
3022 		(void) fprintf(stderr, gettext("%s: wepkeyindex "
3023 		    "should be an integer within the range 1-4\n"), gExecName);
3024 		goto exit0;
3025 	}
3026 	(void) printf(gettext("input wepkey%d:"), key);
3027 	wepkey = get_valid_wepkey();
3028 	if (wepkey == NULL) {
3029 		goto exit0;
3030 	}
3031 	(void) printf(gettext("confirm wepkey%d:"), key);
3032 	wepkey_confirm = get_valid_wepkey();
3033 	if (wepkey_confirm == NULL) {
3034 		free(wepkey);
3035 		goto exit0;
3036 	}
3037 	if (strcmp(wepkey, wepkey_confirm) != 0) {
3038 		free(wepkey);
3039 		free(wepkey_confirm);
3040 		(void) fprintf(stderr,
3041 		    gettext("%s: wepkey: "
3042 		    "two inputs are not identical\n"), gExecName);
3043 		goto exit0;
3044 	}
3045 	free(wepkey_confirm); /* wepkey_confirm is no longer used */
3046 
3047 	len = MAX_KEY_LENGTH + strlen("wepkey1=\n") + 1;
3048 	pbuf = safe_malloc(len);
3049 	safe_snprintf(pbuf, len, "%s%d=%s", "wepkey", key, wepkey);
3050 
3051 	free(wepkey); /* wepkey is no longer used */
3052 	return (pbuf);
3053 exit0:
3054 	return (NULL);
3055 }
3056 
3057 /*
3058  * do_wepkey: Get input from user, call do_set_wepkey
3059  */
3060 /*ARGSUSED*/
3061 static boolean_t
do_wepkey(int fd,int argc,char ** argv)3062 do_wepkey(int fd, int argc, char **argv)
3063 {
3064 	char *pbuf;
3065 
3066 	PRTDBG(("do_wepkey(%d, 0x%x)\n", argc, argv));
3067 	assert(fd > 0);
3068 	if (argc <= 0) {
3069 		do_print_usage();
3070 		exit(WIFI_IMPROPER_USE);
3071 	}
3072 	if (argc > 1) {
3073 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
3074 		    "after 'setwepkey'\n"), gExecName);
3075 	}
3076 	pbuf = get_commit_key(fd, argc, argv);
3077 	if ((pbuf != NULL) && (do_set_wepkey(fd, pbuf) == B_TRUE)) {
3078 		free(pbuf);
3079 		return (B_TRUE);
3080 	}
3081 	free(pbuf);
3082 	return (B_FALSE);
3083 }
3084 
3085 /*ARGSUSED*/
3086 static boolean_t
do_setprofwepkey(int fd,int argc,char ** argv)3087 do_setprofwepkey(int fd, int argc, char **argv)
3088 {
3089 	char *pbuf;
3090 	char *section_id = NULL;
3091 	section_t *p_section = NULL;
3092 	aelist_t *plist = NULL;
3093 
3094 	PRTDBG(("do_setprofwepkey(%d, 0x%x)\n", argc, argv));
3095 	if (argc < 2) {
3096 		do_print_usage();
3097 		exit(WIFI_IMPROPER_USE);
3098 	}
3099 	if (argc > 2) {
3100 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
3101 		    "after 'setprofwepkey'\n"), gExecName);
3102 	}
3103 
3104 	section_id = append_pa(argv[0]);
3105 	p_section = find_section(gp_wepkey_file, section_id);
3106 	free(section_id);
3107 	if (p_section == NULL) {
3108 		(void) fprintf(stderr, gettext("%s: "
3109 		    "no such profile: '%s'\n"),
3110 		    gExecName, argv[0]);
3111 		return (B_FALSE);
3112 	}
3113 
3114 	argc--;
3115 	argv++;
3116 	pbuf = get_commit_key(fd, argc, argv);
3117 	if (pbuf == NULL)
3118 		return (B_FALSE);
3119 	plist = p_section->list;
3120 	update_aelist(plist, pbuf);
3121 
3122 	return (B_TRUE);
3123 }
3124 
3125 /*
3126  * do_wlanlist: Scan for wlanlist
3127  */
3128 /*ARGSUSED*/
3129 static boolean_t
do_wlanlist(int fd,int argc,char ** argv)3130 do_wlanlist(int fd, int argc, char **argv)
3131 {
3132 	PRTDBG(("do_wlanlist(%d, 0x%x)\n", argc, argv));
3133 	assert(fd > 0);
3134 	if (argc > 0) {
3135 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
3136 		    "after 'scan'\n"), gExecName);
3137 	}
3138 	if (call_ioctl(fd, WLAN_COMMAND, WL_SCAN, 0) == B_FALSE) {
3139 		(void) fprintf(stderr, gettext("%s: failed to scan\n"),
3140 		    gExecName);
3141 		return (B_FALSE);
3142 	}
3143 	if (do_get_wlanlist(fd) == B_TRUE) {
3144 		print_gbuf(WLANLIST);
3145 	}
3146 	return (B_TRUE);
3147 }
3148 
3149 /*
3150  * do_showstatus: show the basic status of the interface, including
3151  * linkstauts, essid, encryption and signal strength.
3152  */
3153 /*ARGSUSED*/
3154 static boolean_t
do_showstatus(int fd,int argc,char ** argv)3155 do_showstatus(int fd, int argc, char **argv)
3156 {
3157 	wl_rssi_t signal;
3158 	char *active_profile = NULL;
3159 
3160 	PRTDBG(("do_showstatus(%d, 0x%x)\n", argc, argv));
3161 	assert(fd > 0);
3162 
3163 	if (argc > 0) {
3164 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
3165 		    "after 'showstatus'\n"), gExecName);
3166 	}
3167 	if (do_get_linkstatus(fd) == B_TRUE) {
3168 		print_gbuf(LINKSTATUS);
3169 		if (*(wl_linkstatus_t *)(gbuf->wldp_buf) == WL_NOTCONNECTED) {
3170 			return (B_TRUE);
3171 		}
3172 	}
3173 	active_profile = find_active_profile(fd);
3174 	(void) printf("\tactive profile: %s\n",
3175 	    active_profile ? active_profile : "none");
3176 	if (do_get_essid(fd) == B_TRUE) {
3177 		print_gbuf(ESSID);
3178 	}
3179 	if (do_get_bssid(fd) == B_TRUE) {
3180 		print_gbuf(BSSID);
3181 	}
3182 	if (do_get_encryption(fd) == B_TRUE) {
3183 		print_gbuf(ENCRYPTION);
3184 	}
3185 	if (do_get_signal(fd) == B_TRUE) {
3186 		signal = *(wl_rssi_t *)(gbuf->wldp_buf);
3187 		if (signal < 4) {
3188 			(void) printf("\tsignal strength: weak(%d)\n",
3189 			    signal);
3190 		} else if ((signal >= 4) && (signal <= 11)) {
3191 			(void) printf("\tsignal strength: medium(%d)\n",
3192 			    signal);
3193 		} else {
3194 			(void) printf("\tsignal strength: strong(%d)\n",
3195 			    signal);
3196 		}
3197 	}
3198 
3199 	return (B_TRUE);
3200 }
3201 
3202 
3203 /*
3204  * do_restoredef: Ask driver for loading default parameters
3205  */
3206 /*ARGSUSED*/
3207 static boolean_t
do_restoredef(int fd,int argc,char ** argv)3208 do_restoredef(int fd, int argc, char **argv)
3209 {
3210 	PRTDBG(("do_restoredef(%d, 0x%x)\n", argc, argv));
3211 	assert(fd > 0);
3212 
3213 	if (argc > 0) {
3214 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
3215 		    "after 'restoredef'\n"), gExecName);
3216 	}
3217 	record_active_profile(NULL, RECORD_DEL);
3218 	if (call_ioctl(fd, WLAN_COMMAND, WL_LOAD_DEFAULTS, 0) == B_FALSE) {
3219 		return (B_FALSE);
3220 	} else {
3221 		return (B_TRUE);
3222 	}
3223 }
3224 
3225 /*
3226  * do_disconnect: disconnect from the current connectted network
3227  */
3228 /*ARGSUSED*/
3229 static boolean_t
do_disconnect(int fd,int argc,char ** argv)3230 do_disconnect(int fd, int argc, char **argv)
3231 {
3232 	PRTDBG(("do_disconnect(%d, 0x%x)\n", argc, argv));
3233 	assert(fd > 0);
3234 
3235 	if (argc > 0) {
3236 		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
3237 		    "after 'disconnect'\n"), gExecName);
3238 	}
3239 	record_active_profile(NULL, RECORD_DEL);
3240 	if (call_ioctl(fd, WLAN_COMMAND, WL_DISASSOCIATE, 0) == B_FALSE) {
3241 		return (B_FALSE);
3242 	} else {
3243 		return (B_TRUE);
3244 	}
3245 }
3246 
3247 static boolean_t
do_set_essid(int fd,const char * arg)3248 do_set_essid(int fd, const char *arg)
3249 {
3250 	wl_essid_t essid;
3251 
3252 	PRTDBG(("do_set_essid(%d, \"%s\")\n", fd, arg));
3253 
3254 	/*
3255 	 * a trick here: clean the active_profile flag
3256 	 * in section{active_profile}
3257 	 */
3258 	record_active_profile(NULL, RECORD_DEL);
3259 
3260 	(void) memset(&essid, 0x0, sizeof (essid));
3261 
3262 	if (arg == NULL || strcmp(arg, "") == 0) {
3263 		essid.wl_essid_length = 0;
3264 		essid.wl_essid_essid[0] = '\0';
3265 	} else {
3266 		essid.wl_essid_length = strlen(arg);
3267 		if (essid.wl_essid_length > MAX_ESSID_LENGTH - 1) {
3268 			(void) fprintf(stderr, gettext("%s: "
3269 			    "essid exceeds 32 bytes\n"), gExecName);
3270 			exit(WIFI_FATAL_ERR);
3271 		}
3272 		(void) strcpy(essid.wl_essid_essid, arg);
3273 	}
3274 	(void) memmove(gbuf->wldp_buf, &essid, sizeof (wl_essid_t));
3275 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_ESSID, sizeof (wl_essid_t)));
3276 }
3277 
3278 static boolean_t
do_set_bsstype(int fd,const char * arg)3279 do_set_bsstype(int fd, const char *arg)
3280 {
3281 	wl_bss_type_t bsstype;
3282 
3283 	assert(arg != NULL);
3284 
3285 	PRTDBG(("do_set_bsstype(%d, \"%s\")\n", fd, arg));
3286 
3287 	(void) memset(&bsstype, 0xff, sizeof (bsstype));
3288 
3289 	if ((strcasecmp(arg, "BSS") == 0) ||
3290 	    (strcasecmp(arg, "AP") == 0) ||
3291 	    (strcasecmp(arg, "INFRASTRUCTURE") == 0)) {
3292 		bsstype = WL_BSS_BSS;
3293 	} else if ((strcasecmp(arg, "IBSS") == 0) ||
3294 	    (strcasecmp(arg, "AD-HOC") == 0)) {
3295 		bsstype = WL_BSS_IBSS;
3296 	} else if (strcasecmp(arg, "AUTO") == 0) {
3297 		bsstype = WL_BSS_ANY;
3298 	} else {
3299 		(void) fprintf(stderr, gettext("%s: bsstype: "
3300 		    "bss(ap,infrastructure) ibss(ad-hoc) or auto\n"),
3301 		    gExecName);
3302 		exit(WIFI_FATAL_ERR);
3303 	}
3304 
3305 	(void) memmove(gbuf->wldp_buf, &bsstype, sizeof (wl_bss_type_t));
3306 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_BSS_TYPE,
3307 	    sizeof (wl_bss_type_t)));
3308 }
3309 
3310 static boolean_t
do_set_createibss(int fd,const char * arg)3311 do_set_createibss(int fd, const char *arg)
3312 {
3313 	wl_create_ibss_t create_ibss;
3314 
3315 	assert(arg != NULL);
3316 
3317 	PRTDBG(("do_set_createibss(%d, \"%s\")\n", fd, arg));
3318 
3319&nbs