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