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
 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 *
 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 *
 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 *
 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
 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
 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
 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 *
 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 *
 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
 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
 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 *
 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 **
 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
 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 *
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 *
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 *
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
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
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
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
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
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
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
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
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
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
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 *
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 *
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
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 *
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
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
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
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 *
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
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
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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 *
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
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 *
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
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
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
3130 do_wlanlist(int fd, int argc, char **argv)
3131 {
3132         PRTDBG(("do_wlanlist(%d, 0x%x)\n", argc, argv));
3133         assert(fd > 0);
3134         if (argc > 0) {
3135                 (void) fprintf(stderr, gettext("%s: trailing useless tokens "
3136                     "after 'scan'\n"), gExecName);
3137         }
3138         if (call_ioctl(fd, WLAN_COMMAND, WL_SCAN, 0) == B_FALSE) {
3139                 (void) fprintf(stderr, gettext("%s: failed to scan\n"),
3140                     gExecName);
3141                 return (B_FALSE);
3142         }
3143         if (do_get_wlanlist(fd) == B_TRUE) {
3144                 print_gbuf(WLANLIST);
3145         }
3146         return (B_TRUE);
3147 }
3148 
3149 /*
3150  * do_showstatus: show the basic status of the interface, including
3151  * linkstauts, essid, encryption and signal strength.
3152  */
3153 /*ARGSUSED*/
3154 static boolean_t
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
4005 do_get_linkstatus(int fd)
4006 {
4007         PRTDBG(("do_get_linkstauts(%d)\n", fd));
4008         return (call_ioctl(fd, WLAN_GET_PARAM, WL_LINKSTATUS, 0));
4009 }
4010 
4011 static boolean_t
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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