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  * linkstatus, 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 	(void) memset(&create_ibss, 0x0, sizeof (create_ibss));
3320 
3321 	if (strcasecmp(arg, "YES") == 0) {
3322 		create_ibss = B_TRUE;
3323 	} else if (strcasecmp(arg, "NO") == 0) {
3324 		create_ibss = B_FALSE;
3325 	} else {
3326 		(void) fprintf(stderr, gettext("%s: "
3327 		    "createibss: yes or no\n"), gExecName);
3328 		exit(WIFI_FATAL_ERR);
3329 	}
3330 
3331 	(void) memmove(gbuf->wldp_buf, &create_ibss,
3332 	    sizeof (wl_create_ibss_t));
3333 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_CREATE_IBSS,
3334 	    sizeof (wl_create_ibss_t)));
3335 }
3336 
3337 static boolean_t
do_set_channel(int fd,const char * arg)3338 do_set_channel(int fd, const char *arg)
3339 {
3340 	wl_phy_conf_t phy_conf;
3341 
3342 	assert(arg != NULL);
3343 	PRTDBG(("do_set_channel(%d, \"%s\")\n", fd, arg));
3344 
3345 	(void) memset(&phy_conf, 0xff, sizeof (phy_conf));
3346 
3347 	if (is_channel_valid(arg) == B_FALSE) {
3348 		(void) fprintf(stderr, gettext("%s: channel No. "
3349 		    "should be:\n"
3350 		    "\t802.11a: 0-99\n"
3351 		    "\t802.11b: 1-14\n"
3352 		    "\t802.11g: 1-14\n"), gExecName);
3353 		exit(WIFI_FATAL_ERR);
3354 	}
3355 	phy_conf.wl_phy_dsss_conf.wl_dsss_channel = atoi(arg);
3356 	PRTDBG(("channel=%d\n", phy_conf.wl_phy_dsss_conf.wl_dsss_channel));
3357 
3358 	(void) memmove(gbuf->wldp_buf, &phy_conf, sizeof (wl_phy_conf_t));
3359 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_PHY_CONFIG,
3360 	    sizeof (wl_phy_conf_t)));
3361 }
3362 /*
3363  * is_rates_support: Querying driver about supported rates.
3364  */
3365 static boolean_t
is_rates_support(int fd,int num,uint8_t * rates)3366 is_rates_support(int fd, int num, uint8_t *rates)
3367 {
3368 	int rates_num = 0;
3369 	int i = 0, j = 0;
3370 	uint8_t value = 0;
3371 
3372 	assert((rates != NULL)&&(num != 0));
3373 	PRTDBG(("is_rates_support(%d, %d, 0x%x)\n", fd, num, rates));
3374 
3375 	if (call_ioctl(fd, WLAN_GET_PARAM, WL_SUPPORTED_RATES, 0)
3376 	    == B_TRUE) {
3377 		rates_num = ((wl_rates_t *)(gbuf->wldp_buf))->wl_rates_num;
3378 
3379 		for (i = 0; i < num; i++) {
3380 			PRTDBG(("rates[%d] = %d\n", i, rates[i]));
3381 			for (j = 0; j < rates_num; j++) {
3382 				value = ((wl_rates_t *)gbuf->wldp_buf)
3383 				    ->wl_rates_rates[j];
3384 				PRTDBG(("supported rates[%d]=%d\n", j, value));
3385 				if (value == rates[i]) {
3386 					break;
3387 				}
3388 			}
3389 			if (j == rates_num) {
3390 				if (rates[i] == 11) {
3391 					(void) fprintf(stderr,
3392 					    gettext("%s: "
3393 					    "rate 5.5M is not supported\n"),
3394 					    gExecName);
3395 				} else {
3396 					(void) fprintf(stderr,
3397 					    gettext("%s: "
3398 					    "rate %dM is not supported\n"),
3399 					    gExecName, rates[i]/2);
3400 				}
3401 				return (B_FALSE);
3402 			}
3403 		}
3404 		return (B_TRUE);
3405 	}
3406 	return (B_FALSE);
3407 }
3408 
3409 /*
3410  *
3411  */
3412 static uint8_t
rates_convert(const char * rates)3413 rates_convert(const char *rates)
3414 {
3415 	int i;
3416 	uint8_t ret;
3417 
3418 	for (i = 0; i < WIFI_RATES_NUM; i++) {
3419 		if (strcmp(rates, wifi_rates_s[i].rates_s) == 0) {
3420 			ret = wifi_rates_s[i].rates_i;
3421 			break;
3422 		}
3423 	}
3424 	if (i == WIFI_RATES_NUM) {
3425 		(void) fprintf(stderr, gettext("%s: "
3426 		    "invalid rates '%s'\n"), gExecName, rates);
3427 		exit(WIFI_FATAL_ERR);
3428 	}
3429 	return (ret);
3430 }
3431 
3432 /*
3433  * get_rates: convert string value arg into uint8_t array,
3434  * array length will be save into *len[i].
3435  * for example:
3436  * arg = "1,2,5.5,11"
3437  * then after call, rates[] = {2,4,11,22} will be returned.
3438  * and *len will equal to 4
3439  */
3440 static uint8_t *
get_rates(const char * arg,uint32_t * len)3441 get_rates(const char *arg, uint32_t *len)
3442 {
3443 	int i = 1, j = 0;
3444 	uint8_t *rates = NULL;
3445 	char *pnext = NULL;
3446 	char *token;
3447 	char *pstart;
3448 	char *pstart_bak;
3449 
3450 	assert(arg != NULL);
3451 
3452 	if (strlen(arg) == 0) {
3453 		PRTDBG(("get_rates: empty rates string\n"));
3454 		return (NULL);
3455 	}
3456 	PRTDBG(("get_rates(\"%s\", 0x%x)\n", arg, len));
3457 	pstart = safe_strdup(arg);
3458 	pstart_bak = pstart;
3459 	while ((pnext = strchr(pstart, ',')) != NULL) {
3460 		pstart = pnext + 1;
3461 		i++;
3462 	}
3463 	*len = i;
3464 	rates = safe_calloc(sizeof (uint8_t), i);
3465 
3466 	pstart = pstart_bak;
3467 	if ((token = strtok(pstart, ",")) != NULL) {
3468 		PRTDBG(("rates[0]: %s\n", token));
3469 		rates[0] = rates_convert(token);
3470 		i = 1;
3471 		while ((token = strtok(NULL, ",")) != NULL) {
3472 			PRTDBG(("rates[%d]: %s\n", i, token));
3473 			rates[i++] = rates_convert(token);
3474 		}
3475 	}
3476 	free(pstart_bak);
3477 	for (i = 0; i < *len; i++) {
3478 		for (j = 0; j < i; j++)
3479 			if (rates[j] == rates[i]) {
3480 				(void) fprintf(stderr,
3481 				    gettext("%s: rates duplicated\n"),
3482 				    gExecName);
3483 				free(rates);
3484 				return (NULL);
3485 			}
3486 	}
3487 
3488 	return (rates);
3489 }
3490 
3491 static boolean_t
do_set_rates(int fd,const char * arg)3492 do_set_rates(int fd, const char *arg)
3493 {
3494 	int i = 0;
3495 	uint32_t num = 0;
3496 	uint8_t *rates;
3497 
3498 	assert(arg != NULL);
3499 
3500 	PRTDBG(("do_set_rates(%d, \"%s\")\n", fd, arg));
3501 
3502 	rates = get_rates(arg, &num);
3503 	if ((rates == NULL) ||
3504 	    is_rates_support(fd, num, rates) == B_FALSE) {
3505 		exit(WIFI_FATAL_ERR);
3506 	}
3507 
3508 	((wl_rates_t *)(gbuf->wldp_buf))->wl_rates_num = num;
3509 	for (i = 0; i < num; i++) {
3510 		((wl_rates_t *)gbuf->wldp_buf)->wl_rates_rates[i]
3511 		    = rates[i];
3512 	}
3513 	free(rates);
3514 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_DESIRED_RATES,
3515 	    offsetof(wl_rates_t, wl_rates_rates) +
3516 	    num*sizeof (char)));
3517 }
3518 
3519 static boolean_t
do_set_powermode(int fd,const char * arg)3520 do_set_powermode(int fd, const char *arg)
3521 {
3522 	wl_ps_mode_t ps_mode;
3523 
3524 	assert(arg != NULL);
3525 
3526 	PRTDBG(("do_set_powermode(%d, \"%s\")\n", fd, arg));
3527 
3528 	(void) memset(&ps_mode, 0xff, sizeof (ps_mode));
3529 
3530 	if ((strcasecmp(arg, "OFF") == 0) ||
3531 	    (strcasecmp(arg, "MPS") == 0) ||
3532 	    (strcasecmp(arg, "FAST") == 0)) {
3533 		switch (arg[0]) {
3534 		case 'O':
3535 		case 'o':
3536 			ps_mode.wl_ps_mode = WL_PM_AM;
3537 			break;
3538 		case 'M':
3539 		case 'm':
3540 			ps_mode.wl_ps_mode = WL_PM_MPS;
3541 			break;
3542 		case 'F':
3543 		case 'f':
3544 			ps_mode.wl_ps_mode = WL_PM_FAST;
3545 			break;
3546 		default:
3547 			break;
3548 		}
3549 	} else {
3550 		(void) fprintf(stderr,
3551 		    gettext("%s: powermode: off mps or fast\n"), gExecName);
3552 		exit(WIFI_FATAL_ERR);
3553 	}
3554 
3555 	(void) memmove(gbuf->wldp_buf, &ps_mode, sizeof (wl_ps_mode_t));
3556 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_POWER_MODE,
3557 	    sizeof (wl_ps_mode_t)));
3558 }
3559 
3560 static boolean_t
do_set_authmode(int fd,const char * arg)3561 do_set_authmode(int fd, const char *arg)
3562 {
3563 	wl_authmode_t auth_mode;
3564 
3565 	assert(arg != NULL);
3566 	PRTDBG(("do_set_authmode(%d, \"%s\")\n", fd, arg));
3567 
3568 	(void) memset(&auth_mode, 0xff, sizeof (auth_mode));
3569 	/* Mark */
3570 	if (strcasecmp(arg, "OPENSYSTEM") == 0) {
3571 		auth_mode = WL_OPENSYSTEM;
3572 	} else if (strcasecmp(arg, "SHARED_KEY") == 0) {
3573 		auth_mode = WL_SHAREDKEY;
3574 	} else {
3575 		(void) fprintf(stderr,
3576 		    gettext("%s: authmode: "
3577 		    "opensystem or shared_key\n"), gExecName);
3578 		exit(WIFI_FATAL_ERR);
3579 	}
3580 
3581 	(void) memmove(gbuf->wldp_buf, &auth_mode, sizeof (wl_authmode_t));
3582 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_AUTH_MODE,
3583 	    sizeof (wl_authmode_t)));
3584 }
3585 
3586 static boolean_t
do_set_encryption(int fd,const char * arg)3587 do_set_encryption(int fd, const char *arg)
3588 {
3589 	wl_encryption_t encryption;
3590 
3591 	assert(arg != NULL);
3592 	PRTDBG(("do_set_encryption(%d, \"%s\")\n", fd, arg));
3593 
3594 	(void) memset(&encryption, 0xff, sizeof (encryption));
3595 
3596 	if (strcasecmp(arg, "NONE") == 0) {
3597 		encryption = WL_NOENCRYPTION;
3598 	} else if (strcasecmp(arg, "WEP") == 0) {
3599 		encryption = WL_ENC_WEP;
3600 	} else {
3601 		(void) fprintf(stderr, gettext("%s: encryption: "
3602 		    "none or wep\n"), gExecName);
3603 		exit(WIFI_FATAL_ERR);
3604 	}
3605 
3606 	(void) memmove(gbuf->wldp_buf, &encryption, sizeof (wl_encryption_t));
3607 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_ENCRYPTION,
3608 	    sizeof (wl_encryption_t)));
3609 }
3610 
3611 static boolean_t
do_set_wepkeyid(int fd,const char * arg)3612 do_set_wepkeyid(int fd, const char *arg)
3613 {
3614 	wl_wep_key_id_t wep_key_id;
3615 
3616 	assert(arg != NULL);
3617 	PRTDBG(("do_set_wepkeyid(%d, \"%s\")\n", fd, arg));
3618 
3619 	(void) memset(&wep_key_id, 0xff, sizeof (wep_key_id));
3620 	if (is_wepkeyindex_valid(arg) == B_FALSE) {
3621 		(void) fprintf(stderr, gettext("%s: wepkeyindex "
3622 		    "should be an integer within the range 1-4\n"), gExecName);
3623 		exit(WIFI_FATAL_ERR);
3624 	}
3625 	wep_key_id = atoi(arg) - 1;
3626 
3627 	(void) memmove(gbuf->wldp_buf, &wep_key_id, sizeof (wl_wep_key_id_t));
3628 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_WEP_KEY_ID,
3629 	    sizeof (wl_wep_key_id_t)));
3630 }
3631 
3632 static boolean_t
do_set_radioon(int fd,const char * arg)3633 do_set_radioon(int fd, const char *arg)
3634 {
3635 	wl_radio_t radio;
3636 
3637 	assert(arg != NULL);
3638 	PRTDBG(("do_set_radioon(%d, \"%s\")\n", fd, arg));
3639 
3640 	(void) memset(&radio, 0xff, sizeof (radio));
3641 
3642 	if (strcasecmp(arg, "ON") == 0) {
3643 		radio = B_TRUE;
3644 	} else if (strcasecmp(arg, "OFF") == 0) {
3645 		radio = B_FALSE;
3646 	} else {
3647 		(void) fprintf(stderr,
3648 		    gettext("%s: radio : on or off\n"), gExecName);
3649 		exit(WIFI_FATAL_ERR);
3650 	}
3651 
3652 	(void) memmove(gbuf->wldp_buf, &radio, sizeof (wl_radio_t));
3653 	return (call_ioctl(fd, WLAN_SET_PARAM, WL_RADIO, sizeof (wl_radio_t)));
3654 }
3655 /*
3656  * print_gbuf: After each ioctl system call, gbuf will contain result, gbuf
3657  * contents's format varies from each kind of ioctl system call.
3658  */
3659 static void
print_gbuf(config_item_t index)3660 print_gbuf(config_item_t index)
3661 {
3662 	int i = 0, j = 0;
3663 	uint32_t ess_num;
3664 	char **ess_argv;
3665 	uint32_t rates_num;
3666 	uint32_t subtype;
3667 	wl_bss_type_t bsstype;
3668 	wl_create_ibss_t createibss;
3669 	wl_ps_mode_t *ps_mode;
3670 	wl_authmode_t authmode;
3671 	wl_encryption_t encryption;
3672 	wl_wep_key_id_t wepkeyid;
3673 	wl_rssi_t signal;
3674 	wl_radio_t radioon;
3675 	wl_ess_conf_t **p_ess_conf;
3676 	wl_linkstatus_t linkstatus;
3677 	char format[256], *ntstr;
3678 	uint32_t maxessidlen = 0, nt = 0, cnt = 0;
3679 	int len;
3680 	uint8_t bssid[6];
3681 
3682 	PRTDBG(("print_gbuf(%d)\n", index));
3683 	assert(gbuf->wldp_length < MAX_BUF_LEN);
3684 
3685 	switch (index) {
3686 	case BSSID:
3687 		(void) printf("\tbssid: ");
3688 		(void) memset(bssid, 0, sizeof (bssid));
3689 		if (memcmp((uint8_t *)gbuf->wldp_buf, bssid, sizeof (bssid))
3690 		    == 0) {
3691 			(void) printf("none\n");
3692 			break;
3693 		}
3694 		(void) memset(bssid, 0xff, sizeof (bssid));
3695 		if (memcmp((uint8_t *)gbuf->wldp_buf, bssid, sizeof (bssid))
3696 		    == 0) {
3697 			(void) printf("none\n");
3698 			break;
3699 		}
3700 		for (i = 0; i < 5; i++)
3701 			(void) printf("%02x:", ((uint8_t *)gbuf->wldp_buf)[i]);
3702 		(void) printf("%02x\n", ((uint8_t *)gbuf->wldp_buf)[i]);
3703 		break;
3704 	case ESSID:
3705 		(void) printf("\tessid: %s\n", ((wl_essid_t *)(gbuf->wldp_buf))
3706 		    ->wl_essid_essid);
3707 		break;
3708 	case BSSTYPE:
3709 		bsstype = *(wl_bss_type_t *)(gbuf->wldp_buf);
3710 		switch (bsstype) {
3711 		case WL_BSS_BSS:
3712 			(void) printf("\tbsstype: bss(ap, infrastructure)\n");
3713 			break;
3714 		case WL_BSS_IBSS:
3715 			(void) printf("\tbsstype: ibss(ad-hoc)\n");
3716 			break;
3717 		case WL_BSS_ANY:
3718 			(void) printf("\tbsstype: auto\n");
3719 			break;
3720 		default:
3721 			(void) fprintf(stderr,
3722 			    gettext("%s: "
3723 			    "invalid bsstype value\n"), gExecName);
3724 		}
3725 		break;
3726 	case CREATEIBSS:
3727 		createibss = *(wl_create_ibss_t *)(gbuf->wldp_buf);
3728 		switch (createibss) {
3729 		case B_TRUE:
3730 			(void) printf("\tcreateibss: yes\n");
3731 			break;
3732 		case B_FALSE:
3733 			(void) printf("\tcreateibss: no\n");
3734 			break;
3735 		default:
3736 			(void) fprintf(stderr,
3737 			    gettext("%s: "
3738 			    "invalid createibss value\n"), gExecName);
3739 		}
3740 		break;
3741 	case CHANNEL:
3742 		subtype = ((wl_fhss_t *)(gbuf->wldp_buf))->wl_fhss_subtype;
3743 		switch (subtype) {
3744 		case WL_FHSS:
3745 		case WL_DSSS:
3746 		case WL_IRBASE:
3747 		case WL_HRDS:
3748 		case WL_ERP:
3749 			(void) printf("\tchannel: %d\n", ((wl_fhss_t *)
3750 			    (gbuf->wldp_buf))->wl_fhss_channel);
3751 			break;
3752 		case WL_OFDM:
3753 			(void) printf("\tchannel: %d\n", ((wl_ofdm_t *)
3754 			    (gbuf->wldp_buf))
3755 			    ->wl_ofdm_frequency);
3756 			break;
3757 		default:
3758 			(void) fprintf(stderr, gettext("%s: "
3759 			    "invalid subtype\n"), gExecName);
3760 			break;
3761 		}
3762 		break;
3763 	case RATES:
3764 		rates_num = ((wl_rates_t *)(gbuf->wldp_buf))->wl_rates_num;
3765 		(void) printf("\trates: ");
3766 		for (i = 0; i < rates_num; i++) {
3767 			char rate;
3768 			rate = ((wl_rates_t *)gbuf->wldp_buf)
3769 			    ->wl_rates_rates[i];
3770 			if (rate == WL_RATE_5_5M)
3771 				(void) printf("5.5");
3772 			else
3773 				(void) printf("%d", (uint8_t)(rate / 2));
3774 
3775 			if (i == (rates_num - 1))
3776 				(void) printf("\n");
3777 			else
3778 				(void) printf(",");
3779 		}
3780 		break;
3781 	case POWERMODE:
3782 		ps_mode = (wl_ps_mode_t *)(gbuf->wldp_buf);
3783 		switch (ps_mode->wl_ps_mode) {
3784 		case WL_PM_AM:
3785 			(void) printf("\tpowermode: off\n");
3786 			break;
3787 		case WL_PM_MPS:
3788 			(void) printf("\tpowermode: mps\n");
3789 			break;
3790 		case WL_PM_FAST:
3791 			(void) printf("\tpowermode: fast\n");
3792 			break;
3793 		default:
3794 			(void) fprintf(stderr,
3795 			    gettext("%s: "
3796 			    "invalid powermode value\n"), gExecName);
3797 			break;
3798 		}
3799 		break;
3800 	case AUTHMODE:
3801 		authmode = *(wl_authmode_t *)(gbuf->wldp_buf);
3802 		switch (authmode) {
3803 		case WL_OPENSYSTEM:
3804 			(void) printf("\tauthmode: opensystem\n");
3805 			break;
3806 		case WL_SHAREDKEY:
3807 			(void) printf("\tauthmode: shared_key\n");
3808 			break;
3809 		default:
3810 			(void) fprintf(stderr,
3811 			    gettext("%s: "
3812 			    "invalid authmode value\n"), gExecName);
3813 			break;
3814 		}
3815 		break;
3816 	case ENCRYPTION:
3817 		encryption = *(wl_encryption_t *)(gbuf->wldp_buf);
3818 		switch (encryption) {
3819 		case WL_NOENCRYPTION:
3820 			(void) printf("\tencryption: none\n");
3821 			break;
3822 		case WL_ENC_WEP:
3823 			(void) printf("\tencryption: wep\n");
3824 			break;
3825 		default:
3826 			(void) fprintf(stderr,
3827 			    gettext("%s: "
3828 			    "invalid encryption value\n"), gExecName);
3829 			break;
3830 		}
3831 		break;
3832 	case WEPKEYID:
3833 		wepkeyid = *(wl_wep_key_id_t *)(gbuf->wldp_buf);
3834 		(void) printf("\twepkeyindex: %d\n", wepkeyid + 1);
3835 		break;
3836 	case SIGNAL:
3837 		signal = *(wl_rssi_t *)(gbuf->wldp_buf);
3838 		(void) printf("\tsignal: %d\n", signal);
3839 		break;
3840 	case RADIOON:
3841 		radioon = *(wl_radio_t *)(gbuf->wldp_buf);
3842 		switch (radioon) {
3843 		case B_TRUE:
3844 			(void) printf("\tradio: on\n");
3845 			break;
3846 		case B_FALSE:
3847 			(void) printf("\tradio: off\n");
3848 			break;
3849 		default: /* Mark */
3850 			(void) fprintf(stderr,
3851 			    gettext("%s: "
3852 			    "invalid radioon value\n"), gExecName);
3853 		}
3854 		break;
3855 	case LINKSTATUS:
3856 		linkstatus = *(wl_linkstatus_t *)(gbuf->wldp_buf);
3857 		switch (linkstatus) {
3858 		case WL_CONNECTED:
3859 			(void) printf("\tlinkstatus: connected\n");
3860 			break;
3861 		case WL_NOTCONNECTED:
3862 			(void) printf("\tlinkstatus: not connected\n");
3863 			break;
3864 		default: /* Mark */
3865 			(void) fprintf(stderr,
3866 			    gettext("%s: "
3867 			    "invalid linkstatus value\n"), gExecName);
3868 		}
3869 		break;
3870 	case WLANLIST:
3871 		ess_num = ((wl_ess_list_t *)(gbuf->wldp_buf))->wl_ess_list_num;
3872 		ess_argv = safe_calloc(sizeof (char *), ess_num);
3873 		p_ess_conf = safe_calloc(sizeof (wl_ess_conf_t *), ess_num);
3874 		for (i = 0; i < ess_num; i++) {
3875 			p_ess_conf[i] = ((wl_ess_list_t *)gbuf->wldp_buf)
3876 			    ->wl_ess_list_ess + i;
3877 			maxessidlen = (maxessidlen >
3878 			    strlen(p_ess_conf[i]
3879 			    ->wl_ess_conf_essid.wl_essid_essid) ?
3880 			    maxessidlen :
3881 			    strlen(p_ess_conf[i]
3882 			    ->wl_ess_conf_essid.wl_essid_essid));
3883 		}
3884 		/*
3885 		 * construct the output format.
3886 		 */
3887 		if ((nt = (maxessidlen / 8 + 1)) > 4)
3888 			nt = 4;
3889 		len = snprintf(format, sizeof (format), gettext("essid"));
3890 		ntstr = construct_format(nt);
3891 		assert(ntstr != NULL);
3892 		len += snprintf(format + len, sizeof (format) - len, "%s",
3893 		    ntstr);
3894 		len += snprintf(format + len, sizeof (format) - len,
3895 		    gettext("bssid\t\t  type\t\tencryption\tsignallevel\n"));
3896 
3897 		if ((len <= 0) || (len > sizeof (format) - 1)) {
3898 			(void) printf("essid\t\t\t\tbssid\t\t  type\t\t"
3899 			    "encryption\tsignallevel\n");
3900 		} else {
3901 			(void) printf("%s", format);
3902 		}
3903 
3904 		for (i = 0; i < ess_num; i++) {
3905 			ess_argv[i] = safe_malloc(MAX_SCANBUF_LEN);
3906 			safe_snprintf(ess_argv[i], MAX_SCANBUF_LEN,
3907 			    "%s%c%02x:%02x:%02x:%02x:%02x:%02x%c%s",
3908 			    p_ess_conf[i]->wl_ess_conf_essid.wl_essid_essid,
3909 			    ',',
3910 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[0]),
3911 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[1]),
3912 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[2]),
3913 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[3]),
3914 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[4]),
3915 			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[5]), ',',
3916 			    (p_ess_conf[i]->wl_ess_conf_wepenabled ==
3917 			    B_TRUE ? "wep":"none"));
3918 			len = strlen(p_ess_conf[i]->wl_ess_conf_essid.
3919 			    wl_essid_essid);
3920 			cnt = nt - (min(len /8 + 1, 4) - 1);
3921 			ntstr = construct_format(cnt);
3922 			assert(ntstr != NULL);
3923 			(void) printf("%s%s", p_ess_conf[i]->wl_ess_conf_essid.
3924 			    wl_essid_essid, ntstr);
3925 			free(ntstr);
3926 			for (j = 0; j < 5; j++) {
3927 				(void) printf("%02x:", (uint8_t)(p_ess_conf[i]
3928 				    ->wl_ess_conf_bssid[j]));
3929 			}
3930 			(void) printf("%02x ", (uint8_t)(p_ess_conf[i]
3931 			    ->wl_ess_conf_bssid[j]));
3932 
3933 			if (p_ess_conf[i]->wl_ess_conf_bsstype ==
3934 			    WL_BSS_BSS)
3935 				(void) printf("access point");
3936 			else
3937 				(void) printf("ad-hoc");
3938 			if (p_ess_conf[i]->wl_ess_conf_wepenabled ==
3939 			    WL_ENC_WEP)
3940 				(void) printf("\twep\t");
3941 			else
3942 				(void) printf("\tnone\t");
3943 			(void) printf("\t%d\n", p_ess_conf[i]->wl_ess_conf_sl);
3944 		}
3945 		add_to_history(gp_config_file, ess_num, ess_argv);
3946 		free(p_ess_conf);
3947 		for (i = 0; i < ess_num; i++) {
3948 			free(ess_argv[i]);
3949 		}
3950 		free(ess_argv);
3951 		break;
3952 	default:
3953 		(void) fprintf(stderr, gettext("%s: "
3954 		    "invalid parameter type\n"), gExecName);
3955 		break;
3956 	}
3957 }
3958 /*
3959  * do_get_xxx: will send ioctl to driver, then the driver will fill gbuf
3960  * with related value. gbuf has a format of wldp_t structure.
3961  */
3962 static boolean_t
do_get_bssid(int fd)3963 do_get_bssid(int fd)
3964 {
3965 	PRTDBG(("do_get_bssid(%d)\n", fd));
3966 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_BSSID, 0));
3967 }
3968 
3969 static boolean_t
do_get_essid(int fd)3970 do_get_essid(int fd)
3971 {
3972 	PRTDBG(("do_get_essid(%d)\n", fd));
3973 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_ESSID, 0));
3974 }
3975 
3976 static boolean_t
do_get_bsstype(int fd)3977 do_get_bsstype(int fd)
3978 {
3979 	PRTDBG(("do_get_bsstype(%d)\n", fd));
3980 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_BSS_TYPE, 0));
3981 }
3982 
3983 static boolean_t
do_get_createibss(int fd)3984 do_get_createibss(int fd)
3985 {
3986 	PRTDBG(("do_get_createibss(%d)\n", fd));
3987 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_CREATE_IBSS, 0));
3988 }
3989 
3990 static boolean_t
do_get_channel(int fd)3991 do_get_channel(int fd)
3992 {
3993 	PRTDBG(("do_get_channel(%d)\n", fd));
3994 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_PHY_CONFIG, 0));
3995 }
3996 
3997 static boolean_t
do_get_wlanlist(int fd)3998 do_get_wlanlist(int fd)
3999 {
4000 	PRTDBG(("do_get_wlanlist(%d)\n", fd));
4001 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_ESS_LIST, 0));
4002 }
4003 
4004 static boolean_t
do_get_linkstatus(int fd)4005 do_get_linkstatus(int fd)
4006 {
4007 	PRTDBG(("do_get_linkstatus(%d)\n", fd));
4008 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_LINKSTATUS, 0));
4009 }
4010 
4011 static boolean_t
do_get_rates(int fd)4012 do_get_rates(int fd)
4013 {
4014 	PRTDBG(("do_get_rates(%d)\n", fd));
4015 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_DESIRED_RATES, 0));
4016 }
4017 
4018 static boolean_t
do_get_powermode(int fd)4019 do_get_powermode(int fd)
4020 {
4021 	PRTDBG(("do_get_powermode(%d)\n", fd));
4022 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_POWER_MODE, 0));
4023 }
4024 
4025 static boolean_t
do_get_authmode(int fd)4026 do_get_authmode(int fd)
4027 {
4028 	PRTDBG(("do_get_authmode(%d)\n", fd));
4029 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_AUTH_MODE, 0));
4030 }
4031 
4032 static boolean_t
do_get_encryption(int fd)4033 do_get_encryption(int fd)
4034 {
4035 	PRTDBG(("do_get_encryption(%d)\n", fd));
4036 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_ENCRYPTION, 0));
4037 }
4038 
4039 static boolean_t
do_get_wepkeyid(int fd)4040 do_get_wepkeyid(int fd)
4041 {
4042 	PRTDBG(("do_get_wepkeyid(%d)\n", fd));
4043 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_WEP_KEY_ID, 0));
4044 }
4045 static boolean_t
do_get_signal(int fd)4046 do_get_signal(int fd)
4047 {
4048 	PRTDBG(("do_get_signal(%d)\n", fd));
4049 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_RSSI, 0));
4050 }
4051 
4052 static boolean_t
do_get_radioon(int fd)4053 do_get_radioon(int fd)
4054 {
4055 	PRTDBG(("do_get_radioon(%d)\n", fd));
4056 	return (call_ioctl(fd, WLAN_GET_PARAM, WL_RADIO, 0));
4057 }
4058 
4059 /*
4060  * param has two kinds of forms:
4061  * 'wepkeyn=*****' (when equalflag == B_TRUE),
4062  * 'wepkeyn' (when equalflag == B_FALSE)
4063  */
4064 static boolean_t
param_is_wepkey(char * param,boolean_t equalflag)4065 param_is_wepkey(char *param, boolean_t equalflag)
4066 {
4067 	if ((equalflag == B_FALSE) &&
4068 	    (strcmp(param, "wepkey1") == 0) ||
4069 	    (strcmp(param, "wepkey2") == 0) ||
4070 	    (strcmp(param, "wepkey3") == 0) ||
4071 	    (strcmp(param, "wepkey4") == 0))
4072 		return (B_TRUE);
4073 	else if ((equalflag == B_TRUE) &&
4074 	    (strncmp(param, "wepkey1=", strlen("wepkey1="))) == 0 ||
4075 	    (strncmp(param, "wepkey2=", strlen("wepkey2="))) == 0 ||
4076 	    (strncmp(param, "wepkey3=", strlen("wepkey3="))) == 0 ||
4077 	    (strncmp(param, "wepkey4=", strlen("wepkey4="))) == 0)
4078 		return (B_TRUE);
4079 	else
4080 		return (B_FALSE);
4081 }
4082 
4083 /*
4084  * update/add items in the profile
4085  */
4086 static boolean_t
items_in_profile(aelist_t * cplist,aelist_t * wplist,int argc,char ** argv)4087 items_in_profile(aelist_t *cplist, aelist_t *wplist, int argc, char **argv)
4088 {
4089 	int i = 0, j = 0;
4090 	char *param;
4091 	char *pequal;
4092 	const char *wepkey;
4093 
4094 	for (i = 0; i < argc; i++) {
4095 		if (param_is_wepkey(argv[i], B_TRUE) == B_TRUE) {
4096 			wepkey = get_value(argv[i]);
4097 			if (value_is_valid(WEPKEY, wepkey) == B_FALSE) {
4098 				(void) fprintf(stderr, gettext("%s: "
4099 				    "invalid value '%s' for parameter "
4100 				    "'wepkey'\n"), gExecName, wepkey);
4101 				return (B_FALSE);
4102 			}
4103 			update_aelist(wplist, argv[i]);
4104 			continue;
4105 		}
4106 		param = safe_strdup(argv[i]);
4107 		pequal = strchr(param, '=');
4108 		if (pequal == NULL) {
4109 			(void) fprintf(stderr, gettext("%s: "
4110 			    "invalid argument '%s', use "
4111 			    "parameter=value'\n"),
4112 			    gExecName, argv[i]);
4113 			free(param);
4114 			return (B_FALSE);
4115 		}
4116 
4117 		*pequal++ = '\0';
4118 		for (j = 0; j < N_GS_FUNC; j++) {
4119 			if (strcmp(param, do_gs_func[j].cmd) == 0) {
4120 				break;
4121 			}
4122 		}
4123 		if (j == N_GS_FUNC) {
4124 			(void) fprintf(stderr, gettext("%s: "
4125 			    "unrecognized parameter '%s'\n"),
4126 			    gExecName, param);
4127 			free(param);
4128 			return (B_FALSE);
4129 		}
4130 		if (value_is_valid(do_gs_func[j].index, pequal) ==
4131 		    B_FALSE) {
4132 			(void) fprintf(stderr, gettext("%s: "
4133 			    "invalid value '%s' for parameter '%s'\n"),
4134 			    gExecName, pequal, param);
4135 			return (B_FALSE);
4136 		}
4137 		free(param);
4138 		update_aelist(cplist, argv[i]);
4139 	}
4140 	return (B_TRUE);
4141 }
4142 
4143 /*
4144  * do_createprofile: Called when create a profile off-line.
4145  */
4146 /*ARGSUSED*/
4147 static boolean_t
do_createprofile(int fd,int argc,char ** argv)4148 do_createprofile(int fd, int argc, char **argv)
4149 {
4150 	int i = 0;
4151 	char *pbuf = NULL;
4152 	char *pfbuf = NULL;
4153 	const char *profilename;
4154 	aelist_t *plist_config = NULL, *plist_wepkey = NULL;
4155 
4156 	PRTDBG(("do_createprofile(%d, 0x%x)\n", argc, argv));
4157 	if (argc <= 0) {
4158 		do_print_usage();
4159 		exit(WIFI_IMPROPER_USE);
4160 	}
4161 	/*
4162 	 * When creating a profile, if the profile name is not specified,
4163 	 * the essid is selected as the profile name. the paramters are
4164 	 * saved into the section.
4165 	 */
4166 	if (strchr(argv[0], '=') == NULL) {
4167 		pfbuf = safe_strdup(argv[0]);
4168 		argc--;
4169 		argv++;
4170 	}
4171 	for (i = 0; i < argc; i++) {
4172 		if (strncmp(argv[i], "essid=", strlen("essid=")) == 0) {
4173 			break;
4174 		}
4175 	}
4176 	if (i == argc) {
4177 		(void) fprintf(stderr,
4178 		    gettext("%s: "
4179 		    "essid required when creating profile\n"),
4180 		    gExecName);
4181 		goto exit0;
4182 	}
4183 	profilename = (pfbuf ? pfbuf : get_value(argv[i]));
4184 	if (strlen(profilename) == 0) {
4185 		(void) fprintf(stderr,
4186 		    gettext("%s: "
4187 		    "non-empty essid required\n"),
4188 		    gExecName);
4189 		goto exit0;
4190 	}
4191 	/*
4192 	 * 'all', '{preference}', '{history}', '{active_profile}'
4193 	 * and any string with '[' as start and ']' as end should
4194 	 * not be a profile name
4195 	 */
4196 	if ((strcasecmp(profilename, "all") == 0) ||
4197 	    (strcmp(profilename, WIFI_HISTORY) == 0) ||
4198 	    (strcmp(profilename, WIFI_PREFER) == 0) ||
4199 	    (strcmp(profilename, WIFI_ACTIVEP) == 0) ||
4200 	    ((profilename[0] == '[') &&
4201 	    (profilename[strlen(profilename) - 1] == ']'))) {
4202 		(void) fprintf(stderr, gettext("%s: "
4203 		    "'%s' is an invalid profile name\n"),
4204 		    gExecName, profilename);
4205 		goto exit0;
4206 	}
4207 	pbuf = append_pa(profilename);
4208 
4209 	PRTDBG(("do_createprofile: profile_name = %s\n", pbuf));
4210 	if ((find_section(gp_config_file, pbuf) != NULL) ||
4211 	    find_section(gp_wepkey_file, pbuf) != NULL) {
4212 		(void) fprintf(stderr,
4213 		    gettext("%s: "
4214 		    "profile '%s' already exists\n"),
4215 		    gExecName, profilename);
4216 		goto exit1;
4217 	}
4218 	/*
4219 	 * Save each parameters in the profile.
4220 	 */
4221 	plist_config = new_ael(PROFILE);
4222 	new_section(gp_config_file, plist_config, pbuf);
4223 	plist_wepkey = new_ael(PROFILE);
4224 	new_section(gp_wepkey_file, plist_wepkey, pbuf);
4225 	free(pfbuf);
4226 	free(pbuf);
4227 	return (items_in_profile(plist_config, plist_wepkey,
4228 	    argc, argv));
4229 exit1:
4230 	free(pbuf);
4231 exit0:
4232 	free(pfbuf);
4233 	return (B_FALSE);
4234 }
4235 
4236 /*ARGSUSED*/
4237 static boolean_t
do_setprofparam(int fd,int argc,char ** argv)4238 do_setprofparam(int fd, int argc, char **argv)
4239 {
4240 	char *pbuf = NULL;
4241 	section_t *psection_config = NULL, *psection_wep = NULL;
4242 	aelist_t *plist_config = NULL, *plist_wepkey = NULL;
4243 
4244 	PRTDBG(("do_setprofparam(%d, 0x%x)\n", argc, argv));
4245 	if (argc < 1) {
4246 		do_print_usage();
4247 		exit(WIFI_IMPROPER_USE);
4248 	}
4249 	pbuf = append_pa(argv[0]);
4250 
4251 	psection_config = find_section(gp_config_file, pbuf);
4252 	psection_wep = find_section(gp_wepkey_file, pbuf);
4253 	if ((psection_config == NULL) || (psection_wep == NULL)) {
4254 		(void) fprintf(stderr, gettext("%s: "
4255 		    "profile '%s' doesn't exist\n"),
4256 		    gExecName, argv[0]);
4257 		free(pbuf);
4258 		return (B_FALSE);
4259 	}
4260 	free(pbuf);
4261 	/*
4262 	 * modify each parameters in the profile.
4263 	 */
4264 	plist_config = psection_config->list;
4265 	plist_wepkey = psection_wep->list;
4266 	argc--;
4267 	argv++;
4268 	return (items_in_profile(plist_config, plist_wepkey,
4269 	    argc, argv));
4270 }
4271 
4272 /*ARGSUSED*/
4273 static boolean_t
do_getprofparam(int fd,int argc,char ** argv)4274 do_getprofparam(int fd, int argc, char **argv)
4275 {
4276 	int i = 0, j = 0;
4277 	int flag;
4278 	boolean_t ret = B_TRUE;
4279 	section_t *p_section = NULL;
4280 	aelist_t *plist = NULL;
4281 	ae_t *pae = NULL;
4282 	char *pbuf = NULL;
4283 
4284 	PRTDBG(("do_getprofparam(%d, 0x%x)\n", argc, argv));
4285 	if (argc < 1) {
4286 		do_print_usage();
4287 		exit(WIFI_IMPROPER_USE);
4288 	}
4289 	pbuf = append_pa(argv[0]);
4290 	p_section = find_section(gp_config_file, pbuf);
4291 	if (p_section == NULL) {
4292 		(void) fprintf(stderr, gettext("%s: "
4293 		    "profile '%s' doesn't exist\n"),
4294 		    gExecName, argv[0]);
4295 		ret = B_FALSE;
4296 		goto exit0;
4297 	}
4298 	argc--;
4299 	argv++;
4300 
4301 	plist = p_section->list;
4302 	assert(plist != NULL);
4303 	/*
4304 	 * If no specific parameter typed, we print out all parameters
4305 	 */
4306 	if (argc == 0) {
4307 		pae = plist->ael_head;
4308 		while (pae != NULL) {
4309 			if (pae->ae_arg != NULL) {
4310 				(void) printf("\t%s\n", pae->ae_arg);
4311 			}
4312 			pae = pae->ae_next;
4313 		}
4314 		print_wepkey_info(p_section->section_id, NULL);
4315 		ret = B_TRUE;
4316 		goto exit0;
4317 	}
4318 
4319 	/*
4320 	 * Match function with do_gs_func[] table, and print its result
4321 	 */
4322 	for (i = 0; i < argc; i++) {
4323 		flag = 0;
4324 		for (j = 0; j < N_GS_FUNC; j++) {
4325 			if (strcmp(argv[i], do_gs_func[j].cmd) == 0) {
4326 				break;
4327 			}
4328 			if (param_is_wepkey(argv[i], B_FALSE) == B_TRUE) {
4329 				j = WEPKEY;
4330 				print_wepkey_info(p_section->section_id,
4331 				    argv[i]);
4332 				flag++;
4333 				break;
4334 			}
4335 		}
4336 		if (j == N_GS_FUNC) {
4337 			(void) fprintf(stderr,
4338 			    gettext("wificonifg: unrecognized parameter: "
4339 			    "%s\n"), argv[i]);
4340 			ret = B_FALSE;
4341 			goto exit0;
4342 		}
4343 
4344 		pae = plist->ael_head;
4345 		while ((pae != NULL) && (!flag)) {
4346 			if ((pae->ae_arg != NULL) &&
4347 			    (strncmp(pae->ae_arg, argv[i],
4348 			    strlen(argv[i])) == 0)) {
4349 				(void) printf("\t%s\n", pae->ae_arg);
4350 				flag++;
4351 			}
4352 			pae = pae->ae_next;
4353 		}
4354 		if (!flag) {
4355 			(void) fprintf(stderr, gettext("%s: "
4356 			    "parameter '%s' has not been set in profile %s\n"),
4357 			    gExecName, argv[i], pbuf);
4358 			ret = B_FALSE;
4359 			goto exit0;
4360 		}
4361 	}
4362 exit0:
4363 	free(pbuf);
4364 	return (ret);
4365 }
4366 
4367 /*
4368  * Verify whether the value in the parameter=value pair is valid or not.
4369  * For the channel, since we donot know what kind of wifi card(a,b,or g)
4370  * is in the system, so we just leave to verify the validity of the value
4371  * when the value is set to the card.
4372  * The same goes for the rates.
4373  */
4374 static boolean_t
value_is_valid(config_item_t item,const char * value)4375 value_is_valid(config_item_t item, const char *value)
4376 {
4377 	uint32_t num = 0;
4378 	uint8_t *rates;
4379 	boolean_t ret;
4380 
4381 	assert(value != NULL);
4382 	switch (item) {
4383 	case ESSID:
4384 		if (strlen(value) > 32)
4385 			ret = B_FALSE;
4386 		else
4387 			ret = B_TRUE;
4388 		break;
4389 	case BSSTYPE:
4390 		if ((strcasecmp(value, "bss") == 0) ||
4391 		    (strcasecmp(value, "ap") == 0) ||
4392 		    (strcasecmp(value, "infrastructure") == 0) ||
4393 		    (strcasecmp(value, "ibss") == 0) ||
4394 		    (strcasecmp(value, "ad-hoc") == 0) ||
4395 		    (strcasecmp(value, "auto") == 0))
4396 			ret = B_TRUE;
4397 		else
4398 			ret = B_FALSE;
4399 		break;
4400 	case CREATEIBSS:
4401 		if ((strcasecmp(value, "yes") == 0) ||
4402 		    (strcasecmp(value, "no") == 0))
4403 			ret = B_TRUE;
4404 		else
4405 			ret = B_FALSE;
4406 		break;
4407 	case AUTHMODE:
4408 		if ((strcasecmp(value, "opensystem") == 0) ||
4409 		    (strcasecmp(value, "shared_key") == 0))
4410 			ret = B_TRUE;
4411 		else
4412 			ret = B_FALSE;
4413 		break;
4414 	case POWERMODE:
4415 		if ((strcasecmp(value, "off") == 0) ||
4416 		    (strcasecmp(value, "mps") == 0) ||
4417 		    (strcasecmp(value, "fast") == 0))
4418 			ret = B_TRUE;
4419 		else
4420 			ret = B_FALSE;
4421 		break;
4422 	case ENCRYPTION:
4423 		if ((strcasecmp(value, "wep") == 0) ||
4424 		    (strcasecmp(value, "none") == 0))
4425 			ret = B_TRUE;
4426 		else
4427 			ret = B_FALSE;
4428 		break;
4429 	case RADIOON:
4430 		if ((strcasecmp(value, "on") == 0) ||
4431 		    (strcasecmp(value, "off") == 0))
4432 			ret = B_TRUE;
4433 		else
4434 			ret = B_FALSE;
4435 		break;
4436 	case WEPKEYID:
4437 		ret = is_wepkeyindex_valid(value);
4438 		break;
4439 	case WEPKEY:
4440 		ret = is_wepkey_valid(value, strlen(value));
4441 		break;
4442 	case CHANNEL:
4443 		ret = is_channel_valid(value);
4444 		break;
4445 	case RATES:
4446 		rates = get_rates(value, &num);
4447 		if (rates == NULL) {
4448 			ret = B_FALSE;
4449 		} else {
4450 			free(rates);
4451 			ret = B_TRUE;
4452 		}
4453 		break;
4454 	default:
4455 		ret = B_FALSE;
4456 		break;
4457 	}
4458 
4459 	return (ret);
4460 }
4461 
4462 /*
4463  * do_set: Called when set a parameter, the format should be
4464  * parameter=value.
4465  */
4466 static boolean_t
do_set(int fd,int argc,char ** argv)4467 do_set(int fd, int argc, char **argv)
4468 {
4469 	int i = 0, j = 0;
4470 	char *param;
4471 	char *pequal;
4472 	char *value;
4473 	boolean_t ret;
4474 
4475 	PRTDBG(("do_set(%d, 0x%x)\n", argc, argv));
4476 	assert(fd > 0);
4477 	if (argc <= 0) {
4478 		(void) do_print_support_params(fd);
4479 		ret = B_FALSE;
4480 		goto exit0;
4481 	}
4482 	/*
4483 	 * Set each parameters, if one failed, others behind it will
4484 	 * not be set
4485 	 */
4486 	for (i = 0; i < argc; i++) {
4487 		/*
4488 		 * Separate param and its value, if the user types "param=",
4489 		 * then value will be set to "";if the user types "param",
4490 		 * it is an error.
4491 		 */
4492 		param = safe_strdup(argv[i]);
4493 		pequal = strchr(param, '=');
4494 		value = NULL;
4495 		if (pequal != NULL) {
4496 			*pequal = '\0';
4497 			value = pequal + 1;
4498 		} else {
4499 			(void) fprintf(stderr,
4500 			    gettext("%s: invalid setparam argument "
4501 			    "'%s', use 'parameter=value'\n"),
4502 			    gExecName, argv[i]);
4503 			free(param);
4504 			ret = B_FALSE;
4505 			goto exit0;
4506 		}
4507 		PRTDBG(("do_set: param = \"%s\", value = \"%s\"\n",
4508 		    param, value));
4509 		for (j = 0; j < N_GS_FUNC; j++) {
4510 			/*
4511 			 * Match each parameters with do_gs_func table,
4512 			 */
4513 			if (strcmp(param, do_gs_func[j].cmd) == 0)
4514 				break;
4515 			if (param_is_wepkey(param, B_FALSE) == B_TRUE) {
4516 				value = argv[i];
4517 				j = WEPKEY;
4518 				break;
4519 			}
4520 		}
4521 		if (j == N_GS_FUNC) {
4522 			(void) fprintf(stderr,
4523 			    gettext("%s: unrecognized parameter: "
4524 			    "%s\n"), gExecName, param);
4525 			free(param);
4526 			ret  = B_FALSE;
4527 			goto exit0;
4528 		}
4529 
4530 		if (do_gs_func[j].p_do_set_func == NULL) {
4531 			(void) fprintf(stderr,
4532 			    gettext("%s: parameter '%s' is read-only\n"),
4533 			    gExecName, do_gs_func[j].cmd);
4534 			free(param);
4535 			ret = B_FALSE;
4536 			goto exit0;
4537 		}
4538 		if (do_gs_func[j].p_do_set_func(fd, value)
4539 		    == B_TRUE) {
4540 			ret = B_TRUE;
4541 		} else {
4542 			if (gbuf->wldp_result != WL_SUCCESS) {
4543 				(void) fprintf(stderr,
4544 				    gettext("%s: "
4545 				    "failed to set '%s' for "),
4546 				    gExecName, param);
4547 				print_error(gbuf->wldp_result);
4548 			}
4549 			free(param);
4550 			ret = B_FALSE;
4551 			goto exit0;
4552 		}
4553 		free(param);
4554 	}
4555 exit0:
4556 	return (ret);
4557 }
4558 
4559 static boolean_t
do_get(int fd,int argc,char ** argv)4560 do_get(int fd, int argc, char **argv)
4561 {
4562 	int i = 0, j = 0, n = 0;
4563 	boolean_t ret = B_TRUE;
4564 
4565 	PRTDBG(("do_get(%d, 0x%x)\n", argc, argv));
4566 	assert(fd > 0);
4567 	/*
4568 	 * If no specific parameter typed, we print out all parameters
4569 	 */
4570 	if (argc <= 0) {
4571 		for (i = 0; i < N_GS_FUNC; i++) {
4572 			if ((do_gs_func[i].p_do_get_func != NULL) &&
4573 			    (do_gs_func[i].p_do_get_func(fd)
4574 			    == B_TRUE)) {
4575 				print_gbuf(do_gs_func[i].index);
4576 				n++;
4577 			}
4578 		}
4579 		ret = n ? B_TRUE:B_FALSE;
4580 		goto exit0;
4581 	}
4582 	/*
4583 	 * Match function with do_gs_func[] table, and print its result
4584 	 */
4585 	for (i = 0; i < argc; i++) {
4586 		for (j = 0; j < N_GS_FUNC; j++) {
4587 			if (strcmp(argv[i], do_gs_func[j].cmd) == 0) {
4588 				break;
4589 			}
4590 			if (param_is_wepkey(argv[i], B_FALSE) == B_TRUE) {
4591 				j = WEPKEY;
4592 				break;
4593 			}
4594 		}
4595 		if (j == N_GS_FUNC) {
4596 			(void) fprintf(stderr,
4597 			    gettext("wificonifg: unrecognized parameter: "
4598 			    "%s\n"), argv[i]);
4599 			ret = B_FALSE;
4600 			goto exit0;
4601 		}
4602 		if (do_gs_func[j].p_do_get_func == NULL) {
4603 			(void) fprintf(stderr,
4604 			    gettext("%s: parameter '%s' is write-only\n"),
4605 			    gExecName, do_gs_func[j].cmd);
4606 			ret = B_FALSE;
4607 			goto exit0;
4608 		}
4609 		if (do_gs_func[j].p_do_get_func(fd) == B_TRUE) {
4610 			print_gbuf(do_gs_func[j].index);
4611 			ret = B_TRUE;
4612 		} else {
4613 			(void) fprintf(stderr,
4614 			    gettext("%s: "
4615 			    "failed to read parameter '%s' : "),
4616 			    gExecName, argv[i]);
4617 			print_error(gbuf->wldp_result);
4618 			ret = B_FALSE;
4619 		}
4620 	}
4621 exit0:
4622 	return (ret);
4623 }
4624 
4625 /*
4626  * Only one wificonfig is running at one time.
4627  * The following wificonfig which tries to be run will return error,
4628  * and the pid of the process will own the filelock will be printed out.
4629  */
4630 static pid_t
enter_wifi_lock(int * fd)4631 enter_wifi_lock(int *fd)
4632 {
4633 	int fd0 = -1;
4634 	struct flock lock;
4635 
4636 	fd0 = open(WIFI_LOCKF, O_CREAT|O_WRONLY, 0600);
4637 	if (fd0 < 0) {
4638 		(void) fprintf(stderr, gettext("%s: failed to open lockfile"
4639 		    " '"WIFI_LOCKF"': %s\n"), gExecName, strerror(errno));
4640 		exit(WIFI_FATAL_ERR);
4641 	}
4642 
4643 	*fd = fd0;
4644 	lock.l_type = F_WRLCK;
4645 	lock.l_whence = SEEK_SET;
4646 	lock.l_start = 0;
4647 	lock.l_len = 0;
4648 
4649 	if ((fcntl(fd0, F_SETLK, &lock) == -1) &&
4650 	    (errno == EAGAIN || errno == EDEADLK)) {
4651 		if (fcntl(fd0, F_GETLK, &lock) == -1) {
4652 			(void) fprintf(stderr,
4653 			    gettext("%s: enter_filelock"));
4654 			exit(WIFI_FATAL_ERR);
4655 		}
4656 		(void) fprintf(stderr, gettext("%s:"
4657 		    "enter_filelock:filelock is owned "
4658 		    "by 'process %d'\n"), gExecName, lock.l_pid);
4659 		return (lock.l_pid);
4660 	}
4661 
4662 	return (getpid());
4663 }
4664 
4665 static void
exit_wifi_lock(int fd)4666 exit_wifi_lock(int fd)
4667 {
4668 	struct flock lock;
4669 
4670 	lock.l_type = F_UNLCK;
4671 	lock.l_whence = SEEK_SET;
4672 	lock.l_start = 0;
4673 	lock.l_len = 0;
4674 	if (fcntl(fd, F_SETLK, &lock) == -1) {
4675 		(void) fprintf(stderr, gettext("%s: failed to"
4676 		    " exit_filelock: %s\n"),
4677 		    gExecName, strerror(errno));
4678 	}
4679 	(void) close(fd);
4680 }
4681 
4682 int
main(int argc,char ** argv)4683 main(int argc, char **argv)
4684 {
4685 	int i, ret;
4686 	int fddev = -1;
4687 	int c, iflag = 0, rflag = 0, fileonly = 0, readonly = 0;
4688 	int fd;
4689 	char *iname = NULL;
4690 	char *path = NULL;
4691 	extern char *optarg;
4692 	extern int optind;
4693 	char interface[LIFNAMSIZ];
4694 	char file_wifi[MAX_CONFIG_FILE_LENGTH];
4695 	char file_wifiwepkey[MAX_CONFIG_FILE_LENGTH];
4696 	priv_set_t *ppriv;
4697 	wifi_auth_t autht;
4698 
4699 	PRTDBG(("main(%d, 0x%x)\n", argc, argv));
4700 	PRTDBG(("uid=%d\n", getuid()));
4701 	PRTDBG(("euid=%d\n", geteuid()));
4702 
4703 #ifdef DEBUG
4704 	if (wifi_debug == 1) { /* for debuf purpose only */
4705 		(void) printf("Press RETURN to continue...\n");
4706 		(void) getchar();
4707 	}
4708 #endif
4709 	ret = WIFI_EXIT_DEF;
4710 
4711 	(void) setlocale(LC_ALL, "");
4712 	(void) textdomain(TEXT_DOMAIN);
4713 
4714 	gExecName = argv[0];
4715 
4716 	gbuf = safe_malloc(MAX_BUF_LEN);
4717 
4718 	if ((ppriv = priv_str_to_set("basic", ",", NULL)) == NULL) {
4719 		PRTDBG(("main: priviledge init error\n"));
4720 		(void) fprintf(stderr, gettext("%s: "
4721 		    "set priviledge to 'basic' error\n"),
4722 		    gExecName);
4723 		ret = WIFI_FATAL_ERR;
4724 		goto exit0;
4725 	}
4726 	(void) priv_addset(ppriv, PRIV_NET_RAWACCESS);
4727 	(void) priv_addset(ppriv, PRIV_SYS_NET_CONFIG);
4728 	if (setppriv(PRIV_SET, PRIV_PERMITTED, ppriv) == -1) {
4729 		(void) fprintf(stderr, gettext("%s: "
4730 		    "set permitted priviledge: %s\n"),
4731 		    gExecName, strerror(errno));
4732 		ret = WIFI_FATAL_ERR;
4733 		goto exit0;
4734 	}
4735 	if (setppriv(PRIV_SET, PRIV_LIMIT, ppriv) == -1) {
4736 		(void) fprintf(stderr, gettext("%s: "
4737 		    "set limit priviledge: %s\n"),
4738 		    gExecName, strerror(errno));
4739 		ret = WIFI_FATAL_ERR;
4740 		goto exit0;
4741 	}
4742 	if (setppriv(PRIV_SET, PRIV_INHERITABLE, ppriv) == -1) {
4743 		(void) fprintf(stderr, gettext("%s: "
4744 		    "set inherit priviledge: %s\n"),
4745 		    gExecName, strerror(errno));
4746 		ret = WIFI_FATAL_ERR;
4747 		goto exit0;
4748 	}
4749 	if (setppriv(PRIV_SET, PRIV_EFFECTIVE, ppriv) == -1) {
4750 		(void) fprintf(stderr, gettext("%s: "
4751 		    "set effective priviledge: %s\n"),
4752 		    gExecName, strerror(errno));
4753 		ret = WIFI_FATAL_ERR;
4754 		goto exit0;
4755 	}
4756 	priv_freeset(ppriv);
4757 
4758 	for (i = 0; i < argc; i++) {
4759 		PRTDBG(("%d\t\t\"%s\"\n", i, argv[i]));
4760 	}
4761 
4762 	while ((c = getopt(argc, argv, "i:R:")) != EOF) {
4763 		switch (c) {
4764 		case 'i':
4765 			if (iflag) {
4766 				do_print_usage();
4767 				ret = WIFI_IMPROPER_USE;
4768 				goto exit0;
4769 			}
4770 			iflag = 1;
4771 			iname = optarg;
4772 			break;
4773 		case 'R':
4774 			if (rflag) {
4775 				do_print_usage();
4776 				ret = WIFI_IMPROPER_USE;
4777 				goto exit0;
4778 			}
4779 			rflag = 1;
4780 			path = optarg;
4781 			break;
4782 		case '?':
4783 		default:
4784 			do_print_usage();
4785 			ret = WIFI_IMPROPER_USE;
4786 			goto exit0;
4787 		}
4788 	}
4789 	argc -= optind;
4790 	argv +=	optind;
4791 
4792 	if (argc <= 0) {
4793 		if (iname) {
4794 			if ((fddev = open_dev(iname)) == -1) {
4795 				ret = WIFI_FATAL_ERR;
4796 				goto exit0;
4797 			}
4798 			if (do_print_support_params(fddev) ==
4799 			    B_TRUE)
4800 				ret = WIFI_EXIT_DEF;
4801 			else
4802 				ret = WIFI_FATAL_ERR;
4803 			goto exit1;
4804 		} else {
4805 			do_print_usage();
4806 			ret = WIFI_IMPROPER_USE;
4807 			goto exit0;
4808 		}
4809 	}
4810 
4811 	for (i = 0; i < N_FUNC; i++) {
4812 		if (strcmp(argv[0], do_func[i].cmd) == 0) {
4813 			autht = ((strcmp(argv[0], "setwepkey") == 0) ||
4814 			    (strcmp(argv[0], "setprofwepkey") == 0)) ?
4815 			    AUTH_WEP:AUTH_OTHER;
4816 			if (do_func[i].b_auth &&
4817 			    !check_authority(autht)) {
4818 				ret = WIFI_FATAL_ERR;
4819 				goto exit0;
4820 			}
4821 			if (do_func[i].b_fileonly)
4822 				fileonly++;
4823 			if (do_func[i].b_readonly)
4824 				readonly++;
4825 			break;
4826 		}
4827 	}
4828 	if (i == N_FUNC) {
4829 		(void) fprintf(stderr, gettext("%s: unrecognized "
4830 		    "subcommand: %s\n"), gExecName, argv[0]);
4831 		do_print_usage();
4832 		ret = WIFI_IMPROPER_USE;
4833 		goto exit0;
4834 	}
4835 	if ((fileonly) && (iname)) {
4836 		do_print_usage();
4837 		ret = WIFI_IMPROPER_USE;
4838 		goto exit0;
4839 	}
4840 	if ((!fileonly) && (!iname)) {
4841 		if (search_interface(interface) != B_TRUE) {
4842 			(void) fprintf(stderr, gettext("%s: "
4843 			    "failed to find the default wifi interface;"
4844 			    " -i option should be used to specify the "
4845 			    "wifi interface\n"), gExecName);
4846 			ret = WIFI_FATAL_ERR;
4847 			goto exit0;
4848 		}
4849 		iname = interface;
4850 	}
4851 	if (iname) {
4852 		if ((fddev = open_dev(iname)) == -1) {
4853 			ret = WIFI_FATAL_ERR;
4854 			goto exit0;
4855 		}
4856 	}
4857 	if (rflag) {
4858 		safe_snprintf(file_wifi, sizeof (file_wifi),
4859 		    "%s%s", path, p_file_wifi);
4860 		safe_snprintf(file_wifiwepkey, sizeof (file_wifiwepkey),
4861 		    "%s%s", path, p_file_wifiwepkey);
4862 	} else {
4863 		safe_snprintf(file_wifi, sizeof (file_wifi),
4864 		    "%s", p_file_wifi);
4865 		safe_snprintf(file_wifiwepkey, sizeof (file_wifiwepkey),
4866 		    "%s", p_file_wifiwepkey);
4867 	}
4868 	/*
4869 	 * There is an occasion when more than one wificonfig processes
4870 	 * which attempt to write the <wifi> and <wifiwepkey> files are
4871 	 * running. We must be able to avoid this.
4872 	 * We use file lock here to implement this.
4873 	 */
4874 	if ((!readonly) && (enter_wifi_lock(&fd) != getpid())) {
4875 		ret = WIFI_FATAL_ERR;
4876 		goto exit1;
4877 	}
4878 	gp_config_file = parse_file(file_wifi);
4879 	if (gp_config_file == NULL) {
4880 		ret = WIFI_FATAL_ERR;
4881 		goto exit2;
4882 	}
4883 
4884 	gp_wepkey_file = parse_file(file_wifiwepkey);
4885 	if (gp_wepkey_file == NULL) {
4886 		destroy_config(gp_config_file);
4887 		ret = WIFI_FATAL_ERR;
4888 		goto exit2;
4889 	}
4890 	if (do_func[i].p_do_func(fddev, argc-1, argv+1)
4891 	    == B_TRUE) {
4892 		/*
4893 		 * can not write file when startconfing
4894 		 * during boot
4895 		 */
4896 		if (do_func[i].b_readonly)
4897 			ret = WIFI_EXIT_DEF;
4898 		else if ((fprint_config_file(gp_config_file,
4899 		    file_wifi) != B_TRUE) ||
4900 		    (fprint_config_file(gp_wepkey_file,
4901 		    file_wifiwepkey) != B_TRUE))
4902 			ret = WIFI_FATAL_ERR;
4903 		else
4904 			ret = WIFI_EXIT_DEF;
4905 	} else {
4906 		PRTDBG(("Command %s failed\n", argv[0]));
4907 		ret = WIFI_FATAL_ERR;
4908 	}
4909 	destroy_config(gp_wepkey_file);
4910 	destroy_config(gp_config_file);
4911 exit2:
4912 	if (!readonly)
4913 		exit_wifi_lock(fd);
4914 exit1:
4915 	if (iname)
4916 		(void) close(fddev);
4917 exit0:
4918 	free(gbuf);
4919 	return (ret);
4920 }
4921 
4922 #ifdef DEBUG
4923 static void
wifi_dbgprintf(char * fmt,...)4924 wifi_dbgprintf(char *fmt, ...)
4925 {
4926 	va_list ap;
4927 	va_start(ap, fmt);
4928 	(void) vfprintf(stdout, fmt, ap);
4929 	va_end(ap);
4930 }
4931 #endif
4932