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 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <unistd.h>
  27 #include <stdarg.h>
  28 #include <sys/stat.h>
  29 #include <stdio.h>
  30 #include <signal.h>
  31 #include <door.h>
  32 #include <libsysevent.h>
  33 #include <sys/sunddi.h>
  34 #include <sys/wait.h>
  35 #include <fcntl.h>
  36 #include <syslog.h>
  37 #include <pthread.h>
  38 #include <dirent.h>
  39 #include <locale.h>
  40 #include <alloca.h> /* alloca */
  41 #include <errno.h>
  42 #include <pwd.h>
  43 
  44 #include <priv_utils.h>
  45 #include <priv.h>
  46 
  47 #include <sys/usb/usba/wusba_io.h>
  48 #include <sys/usb/clients/wusb_ca/wusb_ca.h>
  49 #include "crypto_util.h"
  50 #include "wusbd.h"
  51 
  52 
  53 /* deamon exit status code */
  54 #define CONFIG_ERROR    1
  55 #define FATAL_ERROR     2
  56 
  57 #define PKTOKEN         "Sun Software PKCS#11 softtoken  "
  58 #define TOKENDIR        "/etc/usb"
  59 
  60 /* Restrict the max number association for one host to 200 */
  61 #define HOST_MAX        100
  62 #define DEV_MAX         200
  63 
  64 /* global mutext for door service */
  65 static pthread_mutex_t  mutex_cclock = PTHREAD_MUTEX_INITIALIZER;
  66 static void             wusbd_daemon_enter();
  67 static void             wusbd_daemon_leave(char *, int);
  68 
  69 
  70 static wusb_cc_list_t   *global_cclist = NULL;
  71 static  uint32_t        cc_cnt          = 0;
  72 static wusb_cc_list_t   *devids[HOST_MAX][DEV_MAX];
  73 
  74 
  75 /* cc utility funcs */
  76 static int      save_cc(const wusb_cc_info_t *);
  77 static int      save_cc_to_list(const wusb_cc_info_t *);
  78 static int      save_cc_to_store(const wusb_cc_info_t *);
  79 
  80 
  81 static void     refresh(int);
  82 static void     event_handler(sysevent_t *);
  83 
  84 /* daemon init functions */
  85 static int      wusbd_daemonize_init(void);
  86 static void     wusbd_daemonize_fini(int, int);
  87 static int      init_daemon_pid();
  88 static int      init_sys_evnt();
  89 static int      init_door_srv();
  90 static int      init_global_cc_list();
  91 static void     print_prv();
  92 
  93 static void     exit_clean(int);
  94 
  95 /* walk on all hosts in system */
  96 typedef void (* host_func)(const char *);
  97 static void     all_hosts_iterate(host_func);
  98 
  99 
 100 /* walk on all cc list */
 101 typedef int (* cc_list_func)(wusb_cc_list_t *, void *);
 102 static void     global_list_iterate(cc_list_func, void *);
 103 static void     add_to_global_list(wusb_cc_list_t *);
 104 static void     remove_from_global_list(wusb_cc_list_t *);
 105 
 106 /* update cc list device status */
 107 static void     clean_all_cc_list();
 108 static void     update_cc_list(const char *);
 109 static void     update_all_cc_list();
 110 static int      update_cc_file();
 111 
 112 static int      add_all_cc_to_host(const char *, uint8_t);
 113 static int      remove_cc_from_host(uint8_t, uint16_t);
 114 static int      remove_all_cc_from_host(uint8_t);
 115 
 116 static int      create_host_cc(const char *);
 117 static void     check_host(const char *);
 118 static void     check_all_host();
 119 static void     stop_all_host();
 120 
 121 /* cc list entry funcs */
 122 static int      clean_cc_list(wusb_cc_list_t *, void *);
 123 static int      print_cc_list(wusb_cc_list_t *, void *);
 124 static int      copy_cc_list(wusb_cc_list_t *, void *);
 125 static int      write_cc_list(wusb_cc_list_t *, void *);
 126 
 127 /* door service utility funcs */
 128 static void     door_srv(void *, char *, size_t, door_desc_t *, uint_t);
 129 static int      wusbd_check_auth(const char *);
 130 
 131 
 132 /* daemon log utilities */
 133 static void     wusbd_info(const char *, ...);
 134 static void     wusbd_warn(const char *, ...);
 135 static void     wusbd_log(const char *, ...);
 136 
 137 /* host-id / dev-id util funcs */
 138 static uint8_t  assign_host_id(void);
 139 static uint16_t assign_dev_id(uint8_t);
 140 static void     free_dev_id(uint8_t, uint16_t);
 141 
 142 static int      get_host_path(int, char *);
 143 
 144 static int      load_host_mac(const char *, uint8_t *);
 145 
 146 /* searching helper funcs */
 147 static int              find_host_id(uint8_t *);
 148 static wusb_cc_info_t   *find_dev_cc(uint8_t, uint8_t *);
 149 static wusb_cc_info_t   *find_host_cc(uint8_t);
 150 static void             copy_list_back(char *);
 151 
 152 
 153 /* enable/disable host funcs */
 154 static int      start_host(const char *);
 155 static int      stop_host(const char *);
 156 
 157 
 158 /* remove dev funcs */
 159 static int      remove_one_dev(uint8_t, uint16_t);
 160 static int      remove_all_dev(uint8_t);
 161 
 162 /* dev_ctrl check funcs */
 163 static uint16_t check_dev_ctrl(wusb_dev_ctrl_t *);
 164 static uint16_t check_host_ctrl(wusb_dev_ctrl_t *);
 165 
 166 static int      wusbd_do_ca(const char *, const char *, wusb_cc_info_t *, char);
 167 static int      wusbd_do_host(char *, size_t, door_desc_t *, uint_t, int);
 168 
 169 /* cc generation methods */
 170 static int      generate_wusb_CDID(CK_SESSION_HANDLE, wusb_cc_t *);
 171 static int      generate_wusb_CK(CK_SESSION_HANDLE, wusb_cc_t *);
 172 static int      generate_wusb_CC(wusb_cc_t *);
 173 static int      generate_wusb_CHID(wusb_cc_t *, uint8_t *);
 174 
 175 static int      wusbd_do_list(char *, size_t, door_desc_t *, uint_t);
 176 static int      wusbd_do_association(char *, size_t, door_desc_t *, uint_t);
 177 static int      wusbd_do_remove_host(char *, size_t, door_desc_t *, uint_t);
 178 static int      wusbd_do_remove_dev(char *, size_t, door_desc_t *, uint_t);
 179 static int      wusbd_do_enable_host(char *, size_t, door_desc_t *, uint_t);
 180 static int      wusbd_do_disable_host(char *, size_t, door_desc_t *, uint_t);
 181 
 182 typedef struct {
 183         const char *auth;
 184         int (* dfunc)(char *, size_t, door_desc_t *, uint_t);
 185 } wusbd_door_func_t;
 186 static wusbd_door_func_t dfuncs[] =
 187 {
 188                 { WUSB_AUTH_READ,       wusbd_do_list           },
 189                 { WUSB_AUTH_MODIFY,     wusbd_do_association    },
 190                 { WUSB_AUTH_MODIFY,     wusbd_do_remove_dev     },
 191                 { WUSB_AUTH_HOST,       wusbd_do_remove_host    },
 192                 { WUSB_AUTH_HOST,       wusbd_do_enable_host    },
 193                 { WUSB_AUTH_HOST,       wusbd_do_disable_host   },
 194 };
 195 
 196 
 197 static void
 198 wusbd_sig_handler(int sigval)
 199 {
 200         wusbd_info("received signal %d\n", sigval);
 201         switch (sigval) {
 202                 case 0:
 203                 case SIGPIPE:
 204                         wusbd_info("SIG PIPE received");
 205                         break;
 206 
 207                 case SIGHUP:
 208                         wusbd_info("Refreshing dameon");
 209                         /* Refresh config was triggered */
 210                         refresh(sigval);
 211                         break;
 212 
 213                 default:
 214                         (void) pthread_mutex_lock(&mutex_cclock);
 215                         wusbd_info("Stop all host before exit");
 216                         stop_all_host();
 217                         (void) pthread_mutex_unlock(&mutex_cclock);
 218                         exit_clean(0);
 219                         break;
 220         }
 221 
 222 }
 223 
 224 
 225 /*
 226  * Daemon.
 227  *    use "--daemon" to start daemon
 228  */
 229 void
 230 daemonize() {
 231 
 232         int pfd = -1;
 233 
 234         struct sigaction        act;
 235         sigset_t                set;
 236 
 237         openlog("wusbd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
 238 
 239         (void) sigfillset(&set);
 240         (void) sigdelset(&set, SIGABRT);
 241 
 242         (void) sigfillset(&act.sa_mask);
 243         act.sa_handler = wusbd_sig_handler;
 244         act.sa_flags = 0;
 245 
 246         (void) sigaction(SIGTERM, &act, NULL);
 247         (void) sigaction(SIGHUP, &act, NULL);
 248         (void) sigaction(SIGINT, &act, NULL);
 249         (void) sigaction(SIGPIPE, &act, NULL);
 250 
 251         (void) sigdelset(&set, SIGTERM);
 252         (void) sigdelset(&set, SIGHUP);
 253         (void) sigdelset(&set, SIGINT);
 254         (void) sigdelset(&set, SIGPIPE);
 255 
 256         pfd = wusbd_daemonize_init();
 257 
 258         wusbd_info("daemonize: start daemon ");
 259         if (pthread_mutex_init(&mutex_cclock, NULL) != 0) {
 260                 wusbd_log("daemonize: mutext cclock init failed!");
 261                 exit(FATAL_ERROR);
 262         }
 263         if (init_daemon_pid() < 0) {
 264                 wusbd_log("daemonize: init daemon pid fail");
 265                 goto fail;
 266         }
 267         if (init_global_cc_list() < 0) {
 268                 wusbd_log("daemonize: init global cc fail");
 269                 goto fail;
 270         }
 271 
 272         check_all_host();
 273 
 274         if (init_sys_evnt() < 0) {
 275                 wusbd_log("daemonize: init sys evnt fail");
 276                 goto fail;
 277         }
 278 
 279         if (init_door_srv() < 0) {
 280                 wusbd_log("daemonize: init door serv fail");
 281                 goto fail;
 282         }
 283 
 284         wusbd_daemonize_fini(pfd, 0);
 285 
 286         /*CONSTCOND*/
 287         while (1) {
 288                 (void) pause();
 289         }
 290 fail:
 291 
 292         exit_clean(FATAL_ERROR);
 293 }
 294 
 295 /* Respond client's list request. */
 296 /*ARGSUSED*/
 297 static int
 298 wusbd_do_list(char *argp, size_t arg_size,
 299         door_desc_t *dp, uint_t n_desc)
 300 {
 301 
 302         char *buf = NULL;
 303         size_t buflen = 0;
 304 
 305         uint16_t rval = WUSBADM_OK;
 306         wusbd_daemon_enter();
 307 
 308         /* update CC status */
 309         clean_all_cc_list();
 310         update_all_cc_list();
 311 
 312         /* 2 bytes command result */
 313         buflen += sizeof (uint16_t);
 314 
 315         /* 4 bytes cc list number */
 316         buflen += sizeof (uint32_t);
 317 
 318         /* length of all clists */
 319         buflen += sizeof (wusb_device_info_t) * cc_cnt;
 320 
 321         /* use alloca here */
 322         if ((buf = (char *)alloca(buflen)) == NULL) {
 323                 wusbd_warn("wusb_do_list: alloca buffer failed");
 324 
 325                 rval = WUSBADM_FAILURE;
 326                 wusbd_daemon_leave((char *)&rval, sizeof (uint16_t));
 327 
 328                 return (WUSBA_FAILURE);
 329         }
 330         bzero(buf, buflen);
 331 
 332         /* command result */
 333         (void) memcpy(buf, &rval, sizeof (uint16_t));
 334 
 335         /* cc number */
 336         (void) memcpy(buf + sizeof (uint16_t), &cc_cnt, sizeof (uint32_t));
 337 
 338         /* wusb_device_info_t * cc_cnt */
 339         copy_list_back(buf + sizeof (uint16_t) + sizeof (uint32_t));
 340 
 341         /* debug only */
 342         global_list_iterate(print_cc_list, NULL);
 343 
 344         /*
 345          * Update the cc file because we may get the device type if
 346          * device is connected
 347          */
 348         (void) update_cc_file();
 349 
 350         wusbd_daemon_leave(buf, buflen);
 351 
 352         return (WUSBA_SUCCESS);
 353 
 354 }
 355 
 356 /* Respond client's associate request. */
 357 /* ARGSUSED */
 358 static int
 359 wusbd_do_association(char *argp, size_t arg_size,
 360         door_desc_t *dp, uint_t n_desc)
 361 {
 362         uint16_t rval = WUSBADM_OK;
 363         wusb_cc_info_t *host_cc = NULL;
 364         wusb_door_call_t *dcall;
 365         wusb_asso_ctrl_t *asso_ctrl;
 366         char host_path[MAXPATHLEN];
 367 
 368         /* get associate request */
 369         /* LINTED E_BAD_PTR_CAST_ALIGN */
 370         dcall = (wusb_door_call_t *)argp;
 371         asso_ctrl = (wusb_asso_ctrl_t *)dcall->buf;
 372 
 373         wusbd_daemon_enter();
 374 
 375         /* check if host id exist */
 376         if ((host_cc = find_host_cc(asso_ctrl->host)) == NULL) {
 377                 wusbd_warn("wusbd_do_association:asso_ctrl.host = %d err = %s",
 378                     asso_ctrl->host, strerror(errno));
 379                 rval = WUSBADM_INVAL_HOSTID;
 380                 goto done;
 381         }
 382         if (get_host_path(asso_ctrl->host, host_path) < 0) {
 383                 wusbd_warn("wusbd_do_association:host = %d not attached",
 384                     asso_ctrl->host);
 385                 rval = WUSBADM_HOST_NOT_ATTACH;
 386                 goto done;
 387         }
 388 
 389         /* check if it is cable device */
 390         if (asso_ctrl->type != ASSO_TYPE_CABLE) {
 391                 wusbd_warn("wusbd_do_association: asso_ctrl.type = %d",
 392                     asso_ctrl->type);
 393                 rval = WUSBADM_NO_SUPPORT;
 394                 goto done;
 395         }
 396         /* do assocation now */
 397         if (wusbd_do_ca(host_path, asso_ctrl->path,
 398             host_cc, asso_ctrl->onetime) < 0) {
 399                 wusbd_warn("wusbd_do_association: wusbd_do_ca failed");
 400                 rval = WUSBADM_FAILURE;
 401                 goto done;
 402         }
 403 
 404 done:
 405         wusbd_daemon_leave((char *)&rval, sizeof (uint16_t));
 406 
 407         return (rval);
 408 }
 409 
 410 /* Respond client's remove-dev request. */
 411 /* ARGSUSED */
 412 static int
 413 wusbd_do_remove_dev(char *argp, size_t arg_size,
 414                 door_desc_t *dp, uint_t n_desc)
 415 {
 416         wusb_door_call_t *dcall;
 417         wusb_dev_ctrl_t *rmctrl;
 418         uint16_t rval = WUSBADM_OK;
 419 
 420         /* LINTED E_BAD_PTR_CAST_ALIGN */
 421         dcall = (wusb_door_call_t *)argp;
 422         /* LINTED E_BAD_PTR_CAST_ALIGN */
 423         rmctrl = (wusb_dev_ctrl_t *)dcall->buf;
 424 
 425         wusbd_daemon_enter();
 426 
 427         if ((rval = check_dev_ctrl(rmctrl)) != WUSBADM_OK) {
 428                 wusbd_warn("wusbd_do_remove_dev: dev-id = %d.%d failed",
 429                     rmctrl->host, rmctrl->dev);
 430                 goto done;
 431         }
 432 
 433         if (rmctrl->dev) {
 434                 /* remove only one device */
 435                 if (remove_one_dev(rmctrl->host, rmctrl->dev) < 0) {
 436                         wusbd_warn("wusbd_do_remove_dev: dev-id = %d.%d failed",
 437                             rmctrl->host, rmctrl->dev);
 438                         rval = WUSBADM_FAILURE;
 439                         goto done;
 440                 }
 441         } else {
 442                 /* remove all the device associated to the host */
 443                 if (remove_all_dev(rmctrl->host) < 0) {
 444                         wusbd_warn("wusbd_do_remove_dev: host-id = %d failed",
 445                             rmctrl->host);
 446                         rval = WUSBADM_FAILURE;
 447                         goto done;
 448                 }
 449         }
 450 
 451         if (update_cc_file() < 0) {
 452                 wusbd_warn("wusbd_do_remove_dev: update cc file failed");
 453                 rval = WUSBADM_CCSTORE_ACC;
 454                 goto done;
 455         }
 456 
 457 
 458 done:
 459         wusbd_daemon_leave((char *)&rval, sizeof (uint16_t));
 460 
 461         return (rval);
 462 }
 463 
 464 /* Respond client's remove-host request. */
 465 /* ARGSUSED */
 466 static int
 467 wusbd_do_remove_host(char *argp, size_t arg_size,
 468                 door_desc_t *dp, uint_t n_desc)
 469 {
 470         wusb_door_call_t *dcall;
 471         wusb_dev_ctrl_t *host_ctrl;
 472         uint16_t rval = WUSBADM_OK;
 473 
 474         char host_path[MAXPATHLEN];
 475 
 476         wusbd_daemon_enter();
 477         /* LINTED E_BAD_PTR_CAST_ALIGN */
 478         dcall = (wusb_door_call_t *)argp;
 479         /* LINTED E_BAD_PTR_CAST_ALIGN */
 480         host_ctrl = (wusb_dev_ctrl_t *)dcall->buf;
 481         wusbd_info("wusbd_do_remove_host start: hostid = %d", host_ctrl->host);
 482 
 483         if ((rval = check_host_ctrl(host_ctrl)) != WUSBADM_OK) {
 484                 wusbd_warn("wusbd_do_remove_host :host_ctrl->host = %d failed",
 485                     host_ctrl->host);
 486                 goto done;
 487         }
 488 
 489         if (remove_all_dev(host_ctrl->host) < 0) {
 490                 wusbd_warn("wusbd_do_remove_host :host_ctrl->host = %d failed",
 491                     host_ctrl->host);
 492                 rval = WUSBADM_FAILURE;
 493                 goto done;
 494         }
 495 
 496         if (get_host_path(host_ctrl->host, host_path) < 0) {
 497                 wusbd_warn("wusbd_do_host:host_ctrl->host = %d not attached",
 498                     host_ctrl->host);
 499         } else {
 500 
 501                 /*
 502                  * Stop host if possible, if the host can not
 503                  * be stoped we just remove the host cc from
 504                  * system, this means the host should be re-plugged
 505                  * before any new association since the CHID info is
 506                  * gone.
 507                  */
 508                 if (stop_host(host_path) < 0) {
 509                         wusbd_warn("wusbd_do_remove_host: host_path = %s",
 510                             host_path);
 511                 }
 512         }
 513 
 514         /* remove the last CC for host */
 515         remove_from_global_list(devids[host_ctrl->host][0]);
 516         free_dev_id(host_ctrl->host, 0);
 517 
 518         if (update_cc_file() < 0) {
 519                 wusbd_warn("wusbd_do_remove_host: update cc failed");
 520                 rval = WUSBADM_CCSTORE_ACC;
 521                 goto done;
 522         }
 523         wusbd_info("wusbd_do_remove_host complete ");
 524 
 525 done:
 526         wusbd_daemon_leave((char *)&rval, sizeof (uint16_t));
 527 
 528         return (rval);
 529 
 530 
 531 }
 532 
 533 /* Respond client's enable-host request. */
 534 static int
 535 wusbd_do_enable_host(char *argp, size_t arg_size,
 536                 door_desc_t *dp, uint_t n_desc)
 537 {
 538         (void) wusbd_do_host(argp, arg_size, dp, n_desc, 1);
 539 
 540         return (WUSBA_SUCCESS);
 541 }
 542 
 543 /* Respond client's disable-host request. */
 544 static int
 545 wusbd_do_disable_host(char *argp, size_t arg_size,
 546                 door_desc_t *dp, uint_t n_desc)
 547 {
 548         (void) wusbd_do_host(argp, arg_size, dp, n_desc, 0);
 549 
 550         return (WUSBA_SUCCESS);
 551 }
 552 
 553 /*
 554  * wusbd_do_host is the only wrapper for any host related cmds.
 555  * It will call door_return, so it will
 556  * not return and its return val should be omitted by callers
 557  */
 558 /* ARGSUSED */
 559 static int
 560 wusbd_do_host(char *argp, size_t arg_size,
 561                 door_desc_t *dp, uint_t n_desc, int flag)
 562 {
 563         wusb_door_call_t *dcall;
 564         wusb_dev_ctrl_t *host_ctrl;
 565         uint16_t rval = WUSBADM_OK;
 566 
 567         char host_path[MAXPATHLEN];
 568 
 569         /* LINTED E_BAD_PTR_CAST_ALIGN */
 570         dcall = (wusb_door_call_t *)argp;
 571         /* LINTED E_BAD_PTR_CAST_ALIGN */
 572         host_ctrl = (wusb_dev_ctrl_t *)dcall->buf;
 573 
 574         wusbd_daemon_enter();
 575         if ((rval = check_host_ctrl(host_ctrl)) != WUSBADM_OK) {
 576                 wusbd_warn("wusbd_do_host:  host-id = %d failed",
 577                     host_ctrl->host);
 578                 goto done;
 579         }
 580 
 581         if (get_host_path(host_ctrl->host, host_path) < 0) {
 582                 wusbd_warn("wusbd_do_host:host_ctrl->host = %d not attached",
 583                     host_ctrl->host);
 584                 rval = WUSBADM_HOST_NOT_ATTACH;
 585                 goto done;
 586         }
 587 
 588         wusbd_info("wusbd_do_host: host = %s flag = %d", host_path, flag);
 589         if (!flag) {
 590                 if (stop_host(host_path) < 0) {
 591                         wusbd_warn("wusbd_do_host: host_path = %s stop failed",
 592                             host_path);
 593                         rval = WUSBADM_HOST_NOT_ATTACH;
 594                         goto done;
 595                 }
 596         } else {
 597                 (void) add_all_cc_to_host(host_path, host_ctrl->host);
 598                 /* start the host */
 599                 if (start_host(host_path) < 0) {
 600                         wusbd_warn("wusbd_do_host: host = %s start failed",
 601                             host_path);
 602                         rval = WUSBADM_HOST_NOT_ATTACH;
 603                         goto done;
 604                 }
 605 
 606         }
 607 
 608 done:
 609         wusbd_daemon_leave((char *)&rval, sizeof (uint16_t));
 610 
 611         return (rval);
 612 
 613 
 614 }
 615 /*
 616  * door server handler
 617  * Do not allocate memory dynamically in this function. Upon
 618  * door_return(), the server is blocked in the kernel context. No
 619  * place to free that memory. see
 620  * http://blogs.sun.com/tucker/entry/door_api_details
 621  */
 622 /* ARGSUSED */
 623 static void
 624 door_srv(void *cookie, char *argp, size_t arg_size,
 625                 door_desc_t *dp, uint_t n_desc)
 626 {
 627         wusb_door_call_t *dcall;
 628 
 629         uint16_t rval = WUSBADM_FAILURE;
 630 
 631         /* check if it is an valid wusb door call */
 632         if (argp == NULL || arg_size != sizeof (wusb_door_call_t)) {
 633 
 634                 wusbd_warn("door_srv: argp = 0x%p arg_size = %d",
 635                     argp, arg_size);
 636                 rval = WUSBADM_FAILURE;
 637                 goto fail;
 638         }
 639 
 640         /* LINTED E_BAD_PTR_CAST_ALIGN */
 641         dcall = (wusb_door_call_t *)argp;
 642 
 643         if (dcall->cmdss >= (sizeof (dfuncs)/sizeof (wusbd_door_func_t))) {
 644                 wusbd_warn("door_srv: dcall->cmdss = %d",
 645                     dcall->cmdss);
 646                 rval = WUSBADM_NO_SUPPORT;
 647 
 648                 goto fail;
 649         }
 650 
 651         /* chk auths should be done first for any cmd */
 652         if (wusbd_check_auth(dfuncs[dcall->cmdss].auth) < 0) {
 653                 wusbd_warn("door_srv: cmdss = %d, auth = %s",
 654                     dcall->cmdss, dfuncs[dcall->cmdss].auth);
 655                 rval = WUSBADM_AUTH_FAILURE;
 656 
 657                 goto fail;
 658         }
 659 
 660 
 661         /*
 662          * Any wusbd_do_xx will return the door service
 663          */
 664         dfuncs[dcall->cmdss].dfunc(argp, arg_size, dp, n_desc);
 665 
 666         return;
 667 
 668 fail:
 669         (void) door_return((char *)&rval, sizeof (uint16_t), NULL, 0);
 670 
 671 }
 672 
 673 /*
 674  * Check the status of every CC. And update it in the list so that
 675  * client can know if it's connected/disconnected.
 676  */
 677 static void
 678 update_cc_list(const char *host)
 679 {
 680         uint8_t mac[WUSB_DEV_MAC_LENGTH];
 681         wusb_hc_get_dstate_t dstate;
 682         wusb_cc_list_t *list = NULL;
 683         int hostid = 0;
 684         int hstate = -1;
 685         int fd = -1;
 686         int i;
 687 
 688         wusbd_info("update_cc_list: host = %s", host);
 689         if (load_host_mac(host, mac) < 0) {
 690                 wusbd_warn("update_cc_list: host = %s failed", host);
 691 
 692                 return;
 693         }
 694 
 695         if ((hostid = find_host_id(mac)) == 0) {
 696 
 697                 return;
 698         }
 699 
 700         if ((fd = open(host, O_RDONLY)) == -1) {
 701                 wusbd_warn("update_cc_list: host = %s, err =  %s",
 702                     host, strerror(errno));
 703 
 704                 return;
 705         }
 706 
 707         /* update host states */
 708         if (ioctl(fd, WUSB_HC_GET_HSTATE, &hstate) < 0) {
 709                 wusbd_warn("update_cc_list: WUSB_HC_GET_HSTATE, err =  %s",
 710                     strerror(errno));
 711                 (void) close(fd);
 712 
 713                 return;
 714         }
 715 
 716         list = devids[hostid][0];
 717         list->stat = hstate;
 718 
 719         bzero(&dstate, sizeof (wusb_hc_get_dstate_t));
 720 
 721         for (i = 1; i < DEV_MAX; i++) {
 722                 if ((list = devids[hostid][i]) == NULL) {
 723                         continue;
 724                 }
 725                 (void) memcpy(dstate.cdid, list->info.cc.CDID, 16);
 726                 if (ioctl(fd, WUSB_HC_GET_DSTATE, &dstate) == 0) {
 727                         list = devids[hostid][i];
 728                         list->stat = dstate.state;
 729                         if (dstate.state == WUSB_STATE_CONFIGURED) {
 730                                 (void) snprintf(list->info.type, WUSB_TYPE_LEN,
 731                                     "%s", dstate.nodename);
 732                         }
 733                         wusbd_info("update_cc_list: type = %s, state = %d",
 734                             dstate.nodename, dstate.state);
 735                 }
 736 
 737         }
 738 
 739         (void) close(fd);
 740 }
 741 /* find the host cc infor with host id */
 742 static wusb_cc_info_t *
 743 find_host_cc(uint8_t host_id)
 744 {
 745         wusb_cc_list_t *list = NULL;
 746 
 747         if (host_id == 0 || host_id >= HOST_MAX) {
 748 
 749                 return (NULL);
 750         }
 751 
 752         list = devids[host_id][0];
 753 
 754         return (list? &(list->info):NULL);
 755 }
 756 
 757 /* find the device CDID with host id */
 758 static wusb_cc_info_t *
 759 find_dev_cc(uint8_t host_id, uint8_t *CDID)
 760 {
 761         wusb_cc_list_t *list = NULL;
 762         int j = 0;
 763 
 764         for (j = 1; j < DEV_MAX; j++) {
 765                 list = devids[host_id][j];
 766                 if (list && (memcmp(list->info.cc.CDID, CDID, 16) == 0)) {
 767 
 768                         return (&list->info);
 769                 }
 770         }
 771         return (NULL);
 772 }
 773 
 774 /* find the host id with mac address */
 775 static int
 776 find_host_id(uint8_t *mac)
 777 {
 778         wusb_cc_list_t *list = NULL;
 779         int i = 0;
 780 
 781         for (i = 1; i < HOST_MAX; i++) {
 782                 list = devids[i][0];
 783                 if (list && memcmp(mac,
 784                     list->info.mac, WUSB_DEV_MAC_LENGTH) == 0) {
 785                         return (i);
 786                 }
 787         }
 788 
 789         return (0);
 790 }
 791 
 792 /* Save the cc infor from dame to /etc/usb/wusbcc */
 793 static int
 794 update_cc_file()
 795 {
 796         int ccfd = -1;
 797 
 798         if ((ccfd = open(WUSB_CC, O_RDWR|O_TRUNC)) < 0) {
 799                 wusbd_warn("update_cc_file: CC store file = %s, %s",
 800                     WUSB_CC, strerror(errno));
 801 
 802                 return (WUSBA_FAILURE);
 803         }
 804 
 805         global_list_iterate(write_cc_list, &ccfd);
 806         (void) close(ccfd);
 807 
 808         return (WUSBA_SUCCESS);
 809 
 810 }
 811 /*
 812  * ca_****: Cable Assocation helpers
 813  * to setup an association for host and device
 814  */
 815 static int
 816 ca_get_info(int fd, wusb_cbaf_asso_info_t *first)
 817 {
 818         bzero(first, sizeof (wusb_cbaf_asso_info_t));
 819         if (0 != ioctl(fd, CBAF_IOCTL_GET_ASSO_INFO, first)) {
 820                 wusbd_warn("ca_get_info: CBAF_IOCTL_GET_ASSO_INFO: err = %s",
 821                     strerror(errno));
 822 
 823                 return (WUSBA_FAILURE);
 824         }
 825 
 826         return (WUSBA_SUCCESS);
 827 }
 828 
 829 static int
 830 ca_set_host(int fd, wusb_cc_info_t *info)
 831 {
 832         wusb_cbaf_host_info_t host_info;
 833 
 834         host_info.AssociationTypeId = 1;
 835         host_info.AssociationSubTypeId = 0;
 836         host_info.LangID = 0;
 837 
 838         (void) memcpy(host_info.CHID, info->cc.CHID, 16);
 839         (void) memset(host_info.HostFriendlyName, 0, 64);
 840 
 841         mac_to_label(info->mac, host_info.HostFriendlyName);
 842 
 843         if (0 != ioctl(fd, CBAF_IOCTL_SET_HOST_INFO, &host_info)) {
 844                 wusbd_warn("ca_set_host: CBAF_IOCTL_SET_HOST_INFO: err = %s",
 845                     strerror(errno));
 846 
 847                 return (WUSBA_FAILURE);
 848         }
 849 
 850         return (WUSBA_SUCCESS);
 851 }
 852 
 853 static int
 854 ca_get_req(int fd, wusb_cbaf_asso_info_t *first)
 855 {
 856         void *ca_buf;
 857         wusb_cbaf_asso_info_t *ca_info;
 858 
 859         wusbd_info("ca_get_req: NumAssociates = %d",
 860             first->NumAssociationRequests);
 861 
 862         ca_buf =  malloc(sizeof (wusb_cbaf_asso_info_t) +
 863             first->NumAssociationRequests * sizeof (wusb_cbaf_asso_req_t));
 864 
 865         if (ca_buf == NULL) {
 866                 wusbd_warn("ca_get_req: ca_buf = NULL");
 867 
 868                 return (WUSBA_FAILURE);
 869         }
 870 
 871         ca_info = (wusb_cbaf_asso_info_t *)ca_buf;
 872         (void) memcpy(ca_info, first, sizeof (wusb_cbaf_asso_info_t));
 873 
 874         if (0 != ioctl(fd, CBAF_IOCTL_GET_ASSO_REQS, ca_buf)) {
 875                 wusbd_warn("ca_get_req: CBAF_IOCTL_GET_ASSO_REQS: err = %s",
 876                     strerror(errno));
 877                 free(ca_info);
 878 
 879                 return (WUSBA_FAILURE);
 880         }
 881         /* currently not used */
 882         free(ca_buf);
 883 
 884         return (WUSBA_SUCCESS);
 885 
 886 }
 887 
 888 static int
 889 ca_get_devinfo(int fd, wusb_cbaf_device_info_t *device_info)
 890 {
 891         bzero(device_info, sizeof (wusb_cbaf_device_info_t));
 892         if (0 != ioctl(fd, CBAF_IOCTL_GET_DEVICE_INFO, device_info)) {
 893                 wusbd_warn("ca_get_dev failed");
 894 
 895                 return (WUSBA_FAILURE);
 896         }
 897         wusbd_info("ca_get_devinfo: DeviceFriendlyName =  %s",
 898             device_info->DeviceFriendlyName);
 899         wusbd_info("ca_get_devinfo: bandgroup = %d",
 900             device_info->BandGroups);
 901         wusbd_info("ca_get_devinfo: LangID = %d",
 902             device_info->LangID);
 903 
 904         print_array("CDID from device", device_info->CDID, 16);
 905 
 906         return (WUSBA_SUCCESS);
 907 }
 908 
 909 static int
 910 ca_connect_cc(int fd, wusb_cc_info_t *newinfo,
 911                 wusb_cbaf_device_info_t *device_info)
 912 {
 913         wusb_cbaf_cc_data_t cc_data;
 914 
 915         cc_data.AssociationTypeId = 1;
 916         cc_data.AssociationSubTypeId = 1;
 917         cc_data.Length = WUSB_CC_DATA_SIZE;
 918         cc_data.BandGroups = device_info->BandGroups;
 919         (void) memcpy(&(cc_data.CC), &(newinfo->cc), sizeof (wusb_cc_t));
 920 
 921 
 922         if (0 != ioctl(fd, CBAF_IOCTL_SET_CONNECTION, &cc_data)) {
 923                 wusbd_warn("ca_connect_cc: CBAF_IOCTL_SET_CONNECTION: err = %s",
 924                     strerror(errno));
 925 
 926                 return (WUSBA_FAILURE);
 927         }
 928         print_array("New CC to device", cc_data.CC.CHID, 48);
 929 
 930         return (WUSBA_SUCCESS);
 931 }
 932 
 933 static int
 934 ca_create_cc(wusb_cc_info_t *newinfo, wusb_cc_info_t *host_cc)
 935 {
 936         (void) memcpy(newinfo->cc.CHID, host_cc->cc.CHID, 16);
 937 
 938         if (generate_wusb_CC(&(newinfo->cc)) < 0) {
 939                 wusbd_warn("ca_create_cc: generate cc failed!");
 940 
 941                 return (WUSBA_FAILURE);
 942         }
 943 
 944         return (WUSBA_SUCCESS);
 945 }
 946 
 947 static int
 948 ca_add_cc(wusb_cc_info_t *newinfo, const char *filename)
 949 {
 950         int fd = -1;
 951         int hstate = -1;
 952 
 953         wusbd_info("ca_add_cc: filename = %s start", filename);
 954 
 955         if ((fd = open(filename, O_RDONLY)) == -1) {
 956                 wusbd_warn("ca_add_cc: filename = %s, err = %s",
 957                     filename, strerror(errno));
 958 
 959                 return (WUSBA_FAILURE);
 960         }
 961         if (ioctl(fd, WUSB_HC_ADD_CC, &(newinfo->cc)) != 0) {
 962                 wusbd_warn("ca_add_cc: ioctl = WUSB_HC_ADD_CC, err = %s",
 963                     strerror(errno));
 964                 goto fail;
 965         }
 966         if (ioctl(fd, WUSB_HC_GET_HSTATE, &hstate) < 0) {
 967                 wusbd_warn("ca_add_cc: ioctl = WUSB_HC_GET_HSTATE, err =  %s",
 968                     strerror(errno));
 969                 goto fail;
 970         }
 971         if (hstate != WUSB_HC_STARTED) {
 972                 if (ioctl(fd, WUSB_HC_START, WUSB_HC_INITIAL_START) == -1) {
 973                         wusbd_warn("ca_add_cc: ioctl = WUSB_HC_START, err = %s",
 974                             strerror(errno));
 975                         goto fail;
 976                 }
 977         }
 978 
 979         (void) close(fd);
 980 
 981         print_array("New CC to host", newinfo->cc.CHID, 48);
 982 
 983         return (WUSBA_SUCCESS);
 984 
 985 fail:
 986         (void) close(fd);
 987 
 988         return (WUSBA_FAILURE);
 989 }
 990 
 991 static int
 992 ca_save_cc(wusb_cc_info_t *newinfo, wusb_cc_info_t *hostinfo)
 993 {
 994         newinfo->host = hostinfo->host;
 995         if ((newinfo->dev  = assign_dev_id(newinfo->host)) == 0) {
 996                 wusbd_warn("ca_save_cc: host-id:%d", newinfo->host);
 997 
 998                 return (WUSBA_FAILURE);
 999         }
1000 
1001         if (save_cc(newinfo) < 0) {
1002                 wusbd_warn("ca_save_cc: save cc failed");
1003 
1004                 return (WUSBA_FAILURE);
1005         }
1006 
1007         return (WUSBA_SUCCESS);
1008 }
1009 
1010 static int
1011 wusbd_do_ca(const char *host_path, const char *ca_dev,
1012                 wusb_cc_info_t *host_cc, char onetime)
1013 {
1014         wusb_cbaf_asso_info_t first;
1015         wusb_cbaf_device_info_t device_info;
1016         wusb_cc_info_t newinfo;
1017         int fd;
1018         wusb_cc_info_t *old_cc = NULL;
1019 
1020         wusbd_info("wusbd_do_ca start\n");
1021         /* IMPORTANT: Do NOT open it with O_RDWR */
1022         fd = open(ca_dev, O_RDONLY);
1023         if (fd == -1) {
1024                 wusbd_warn("wusbd_do_ca: ca_dev = %s err = %s", ca_dev,
1025                     strerror(errno));
1026 
1027                 return (WUSBA_FAILURE);
1028         }
1029         /*
1030          * The first parts to set up a cable associaiton.
1031          * Refer to: [Association Models Supplement to the
1032          * Certified Wireless Universal Serial Bus Specification]
1033          * chapter 4.
1034          *
1035          * 1. Send GET_ASSOCIATION_INFORMATION to the cable device
1036          * and get the number of association requests.
1037          *
1038          * 2. Send GET_ASSOCIATION_INFORMATION again to get the
1039          * all the association requests.
1040          *
1041          * 3. Send SET_ASSOCIATION_RESPONSE with the host CHID
1042          *
1043          * 4. Send GET_ASSOCIATION_REQUEST to get the exisiting CC
1044          * infor from the device.
1045          *
1046          */
1047         if (ca_get_info(fd, &first) < 0) {
1048                 wusbd_warn("wusbd_do_ca: get asso info failed!");
1049                 goto cleanup;
1050         }
1051         if (ca_get_req(fd, &first) < 0) {
1052                 wusbd_warn("wusbd_do_ca: get asso req failed!");
1053                 goto cleanup;
1054         }
1055         if (ca_set_host(fd, host_cc)) {
1056                 wusbd_warn("wusbd_do_ca: set host info failred");
1057                 goto cleanup;
1058         }
1059         if (ca_get_devinfo(fd, &device_info)) {
1060                 wusbd_warn("wusbd_do_ca: get device infor failed");
1061                 goto cleanup;
1062         }
1063 
1064 
1065         (void) snprintf(newinfo.type, WUSB_TYPE_LEN, "unknown");
1066         newinfo.flag = onetime;
1067 
1068         /*
1069          * The second part to setup cable association.
1070          *
1071          * 1. Create a CC from exsiting host_cc for the devices
1072          *
1073          * 2. Send new cc to the cable device to save in its hardware
1074          *
1075          * 3. Add new cc to the host controller
1076          *
1077          * 4. Save the cc to the cc list and cc store file
1078          *
1079          * Done!
1080          */
1081         if (ca_create_cc(&newinfo, host_cc) < 0) {
1082                 wusbd_warn("wusbd_do_ca: ca create cc failed!");
1083                 goto cleanup;
1084         }
1085         /*
1086          * Check if CDID exist in the host cc list, if so, We need to update
1087          * the exisiting cc infor with a new ck, do the association with the
1088          * updated cc.
1089          * See "Association Models Supplement to the WUSB Specification"
1090          * Chapter 4
1091          */
1092         old_cc = find_dev_cc(host_cc->host, device_info.CDID);
1093         if (old_cc) {
1094                 wusbd_warn("wusbd_do_ca: Association exist, use old CDID");
1095                 (void) remove_cc_from_host(old_cc->host, old_cc->dev);
1096 
1097                 /* update old cc with the new ck and copy back */
1098                 (void) memcpy(old_cc->cc.CK, newinfo.cc.CK, 16);
1099                 (void) memcpy(&(newinfo.cc), &(old_cc->cc), sizeof (wusb_cc_t));
1100         }
1101         if (ca_connect_cc(fd, &newinfo, &device_info) < 0) {
1102                 wusbd_warn("wusbd_do_ca: ca connect cc failed!");
1103                 goto cleanup;
1104         }
1105 
1106         (void) close(fd);
1107 
1108         if (ca_add_cc(&newinfo, host_path) < 0) {
1109                 wusbd_warn("wusbd_do_ca: ca add cc failed!");
1110 
1111                 return (WUSBA_FAILURE);
1112         }
1113 
1114         if (!old_cc) {
1115                 /* a new cc save to file */
1116                 if (ca_save_cc(&newinfo, host_cc) < 0) {
1117                         wusbd_warn("wusbd_do_ca: ca save cc failed!");
1118 
1119                         return (WUSBA_FAILURE);
1120                 }
1121         } else {
1122                 /* Just update the cc file */
1123                 if (update_cc_file() < 0) {
1124                         wusbd_warn("wusbd_do_ca: update old cc failed");
1125 
1126                         return (WUSBA_FAILURE);
1127                 }
1128         }
1129 
1130         wusbd_info("wusbd_do_ca: Set cable connection complete!");
1131 
1132         return (WUSBA_SUCCESS);
1133 
1134 cleanup:
1135         (void) close(fd);
1136 
1137         return (WUSBA_FAILURE);
1138 }
1139 /*
1140  * wusb cc infor generation helpers
1141  * generate_wusb_CC: Generate CC infor for a device and host
1142  * generate_wusb_CHID: Generate CHID for a host
1143  * generate_wusb_CDID: Generate CDID for a device
1144  * generate_wusb_CK  : Generate CK for an assocation
1145  */
1146 
1147 static int
1148 generate_wusb_CC(wusb_cc_t *cc)
1149 {
1150         CK_SESSION_HANDLE pkhandle;
1151         KMF_HANDLE_T kmfhandle;
1152         int rval = WUSBA_SUCCESS;
1153         wusbd_info("generate_wusb_CC: start");
1154 
1155         if (wusb_crypto_init(&kmfhandle, &pkhandle, PKTOKEN, TOKENDIR) != 0) {
1156                 wusbd_warn("generate_wusb_CC: Crypto init failed");
1157 
1158                 return (WUSBA_FAILURE);
1159         }
1160         if (generate_wusb_CDID(pkhandle, cc) < 0) {
1161                 wusbd_warn("generate_wusb_CC: crate cdid failed");
1162                 rval = WUSBA_FAILURE;
1163 
1164                 goto done;
1165         }
1166         if (generate_wusb_CK(pkhandle, cc) < 0) {
1167                 wusbd_warn("generate_wusb_CC: crate ck failed");
1168                 rval = WUSBA_FAILURE;
1169 
1170                 goto done;
1171         }
1172 done:
1173         wusb_crypto_fini(kmfhandle);
1174 
1175         wusbd_info("generate_wusb_CC: complete");
1176 
1177         return (rval);
1178 }
1179 
1180 
1181 static int
1182 generate_wusb_CHID(wusb_cc_t *cc, uint8_t *mac)
1183 {
1184         /*
1185          * CHID construction :
1186          * 0 - 5  : MAC serial
1187          * 6 - 7  : arbitrary
1188          * 8 - 15 : random from seed = (MAC..) || (hostid||time)) || hrtime
1189          */
1190         uint8_t *p = cc->CHID;
1191         uint8_t seed[24];
1192         time_t tt;
1193         uint64_t prod, hrtime;
1194         int rval = WUSBA_SUCCESS;
1195 
1196         KMF_HANDLE_T kmfhandle;
1197         CK_SESSION_HANDLE pkhandle;
1198 
1199         wusbd_info("generate_wusb_CHID: start");
1200         if (wusb_crypto_init(&kmfhandle, &pkhandle, PKTOKEN, TOKENDIR) != 0) {
1201                 wusbd_warn("generate_wusb_CHID: Crypto init failed");
1202                 rval = WUSBA_FAILURE;
1203                 goto done;
1204         }
1205 
1206         (void) memcpy(p, mac, WUSB_DEV_MAC_LENGTH);
1207         p += 8;
1208 
1209         (void) time(&tt);
1210         prod = gethostid();
1211         prod = (prod << 32) | tt;
1212         hrtime = gethrtime();
1213 
1214         (void) memcpy(seed, cc->CHID, 8);
1215         (void) memcpy(seed + 8, &prod, 8);
1216         (void) memcpy(seed + 16, &hrtime, 8);
1217 
1218         if (wusb_random(pkhandle, seed, 24, p, 8) < 0) {
1219                 wusbd_warn("generate_wusb_CHID: random failed");
1220                 rval = WUSBA_FAILURE;
1221         }
1222         wusb_crypto_fini(kmfhandle);
1223         wusbd_info("generate_wusb_CHID complete");
1224 done:
1225 
1226         return (rval);
1227 }
1228 
1229 static int
1230 generate_wusb_CDID(CK_SESSION_HANDLE pkhandle, wusb_cc_t *cc)
1231 {
1232         /* TODO : need better generation mechanism */
1233         return (wusb_random(pkhandle, NULL, 0, cc->CDID, 16));
1234 
1235 }
1236 
1237 static int
1238 generate_wusb_CK(CK_SESSION_HANDLE pkhandle,  wusb_cc_t *cc)
1239 {
1240         /* TODO : need better generation mechanism */
1241         return (wusb_random(pkhandle, NULL, 0, cc->CK, 16));
1242 }
1243 
1244 /* Log to dmesg and smf log */
1245 static void
1246 wusbd_warn(const char *format, ...)
1247 {
1248         va_list alist;
1249 
1250         format = gettext(format);
1251         va_start(alist, format);
1252         (void) fprintf(stderr, gettext("[WUSBD]"));
1253         (void) vfprintf(stderr, format, alist);
1254         (void) fputc('\n', stderr);
1255         va_end(alist);
1256 }
1257 static void
1258 wusbd_log(const char *format, ...)
1259 {
1260         va_list alist;
1261 
1262         format = gettext(format);
1263         va_start(alist, format);
1264         (void) vsyslog(LOG_WARNING, format, alist);
1265         va_end(alist);
1266 }
1267 
1268 
1269 /* Log to smf log in DEBUG version */
1270 /* ARGSUSED */
1271 static void
1272 wusbd_info(const char *format, ...)
1273 {
1274 #ifdef DEBUG
1275         va_list alist;
1276 
1277         format = gettext(format);
1278         va_start(alist, format);
1279         (void) fprintf(stderr, gettext("[WUSBD]"));
1280         (void) vfprintf(stderr, format, alist);
1281         (void) fputc('\n', stderr);
1282         va_end(alist);
1283 #endif
1284 }
1285 
1286 /*
1287  * Find an unused host id and return it.
1288  * The wusbadm use two digits to represent a host. This means
1289  * hostid can't be greater than 99.
1290  */
1291 static uint8_t
1292 assign_host_id(void)
1293 {
1294         uint8_t i;
1295         for (i = 1; i < HOST_MAX; i++) {
1296                 if (devids[i][0] == 0) {
1297                         wusbd_info("assign_host_id:  rval = %d", i);
1298 
1299                         return (i);
1300                 }
1301         }
1302 
1303         return (0); /* illegal value */
1304 }
1305 
1306 /*
1307  * traverse the CC store, search in the specified host,
1308  * find an unused device id, return it.
1309  * The wusbadm use 3 digits to represent a device. This means
1310  * devid can't be greater than 999.
1311  */
1312 static uint16_t
1313 assign_dev_id(uint8_t hostid)
1314 {
1315         uint16_t i;
1316         if (hostid >= HOST_MAX) {
1317 
1318                 return (0);
1319         }
1320         for (i = 1; i < DEV_MAX; i++) {
1321                 if (devids[hostid][i] == 0) {
1322                         wusbd_info("assign_dev_id: devid = %d.%d", hostid, i);
1323 
1324                         return (i);
1325                 }
1326         }
1327 
1328         return (0); /* illegal value */
1329 }
1330 
1331 /* Release a dev id, eg: remove dev */
1332 static void
1333 free_dev_id(uint8_t hostid, uint16_t devid)
1334 {
1335         if (hostid >= HOST_MAX || devid >= DEV_MAX) {
1336 
1337                 return;
1338         }
1339         devids[hostid][devid] = 0;
1340 }
1341 
1342 /*
1343  * init_door_srv.
1344  * Create the door file and attach door service
1345  * to the door file
1346  */
1347 static int
1348 init_door_srv()
1349 {
1350         int fd, dd;
1351 
1352         (void) fdetach(DOOR_FILE);
1353         (void) unlink(DOOR_FILE);
1354 
1355         if ((dd = door_create(door_srv, 0, 0)) < 0) {
1356                 wusbd_warn("init_door_srv: door_creat: err = %s",
1357                     strerror(errno));
1358 
1359                 goto fail;
1360         }
1361         if ((fd = creat(DOOR_FILE, S_IRUSR | S_IRGRP | S_IROTH)) < 0) {
1362                 wusbd_warn("init_door_srv: creat: err = %s",
1363                     strerror(errno));
1364 
1365                 goto fail;
1366         }
1367 
1368         (void) close(fd);
1369 
1370         wusbd_info("init_door_srv: file = %s created", DOOR_FILE);
1371 
1372         if (fattach(dd, DOOR_FILE) < 0) {
1373                 wusbd_warn("init_door_srv: fattach err = %s",
1374                     strerror(errno));
1375 
1376                 goto fail;
1377         }
1378 
1379         return (WUSBA_SUCCESS);
1380 fail:
1381 
1382         return (WUSBA_FAILURE);
1383 }
1384 
1385 
1386 /* Print a cc list entry */
1387 /* ARGSUSED */
1388 static int
1389 print_cc_list(wusb_cc_list_t *list, void *data)
1390 {
1391         wusbd_info("list:%x", list);
1392         wusbd_info("\thostid:%x", list->info.host);
1393         wusbd_info("\tdevid:%x", list->info.dev);
1394 
1395         return (WUSBA_SUCCESS);
1396 }
1397 
1398 /* write a cc list entry back to file fd */
1399 static int
1400 write_cc_list(wusb_cc_list_t *list, void *data)
1401 {
1402         int ccfd =  *((int *)data);
1403         wusbd_info("write_cc_list: host-id = %d dev-id = %d",
1404             list->info.host, list->info.dev);
1405 
1406         if (list->info.flag) {
1407 
1408                 return (WUSBA_SUCCESS);
1409         }
1410         if (write(ccfd, &(list->info), sizeof (wusb_cc_info_t)) !=
1411             sizeof (wusb_cc_info_t)) {
1412                 wusbd_warn("write_cc_list: write err = %s ",
1413                     strerror(errno));
1414 
1415                 return (WUSBA_FAILURE);
1416         }
1417 
1418         return (WUSBA_SUCCESS);
1419 }
1420 
1421 /* clean up the status of the cc list entry */
1422 /* ARGSUSED */
1423 static int
1424 clean_cc_list(wusb_cc_list_t *list, void *data)
1425 {
1426         list->stat = list->info.dev? DEV_STAT_DISCONN:WUSB_HC_DISCONNTED;
1427 
1428         return (WUSBA_SUCCESS);
1429 }
1430 
1431 /* copy a cc list entry to a device info buffer */
1432 static int
1433 copy_cc_list(wusb_cc_list_t *list, void *data)
1434 {
1435         char **buf      = (char **)data;
1436 
1437         wusb_device_info_t devinfo;
1438         devinfo.dev     = list->info.dev;
1439         devinfo.host    = list->info.host;
1440         devinfo.stat    = list->stat;
1441 
1442         (void) snprintf(devinfo.type, WUSB_TYPE_LEN, "%s", list->info.type);
1443         (void) memcpy(*buf, &devinfo, sizeof (wusb_device_info_t));
1444 
1445         *buf += sizeof (wusb_device_info_t);
1446 
1447         return (WUSBA_SUCCESS);
1448 
1449 }
1450 
1451 /* save cc to list and file */
1452 static int
1453 save_cc(const wusb_cc_info_t *ccinfo)
1454 {
1455         /* save CC to file */
1456         if (save_cc_to_store(ccinfo) < 0) {
1457                 wusbd_warn("save_cc: Failed to save CC to file");
1458 
1459                 return (WUSBA_FAILURE);
1460         }
1461 
1462         /* save cc to global list */
1463         if (save_cc_to_list(ccinfo) < 0) {
1464                 wusbd_warn("save_cc: Failed to save CC to list");
1465 
1466                 return (WUSBA_FAILURE);
1467 
1468         }
1469 
1470         return (WUSBA_SUCCESS);
1471 }
1472 
1473 /* create cc list entry and add to global list */
1474 static int
1475 save_cc_to_list(const wusb_cc_info_t *ccinfo)
1476 {
1477         wusb_cc_list_t *newlist =
1478             (wusb_cc_list_t *)malloc(sizeof (wusb_cc_list_t));
1479         if (newlist == NULL) {
1480                 wusbd_warn("save_cc_to_list: newlist = NULL");
1481 
1482                 return (WUSBA_FAILURE);
1483         }
1484         bzero(newlist, sizeof (wusb_cc_list_t));
1485         (void) memcpy(&(newlist->info), ccinfo, sizeof (wusb_cc_info_t));
1486         devids[ccinfo->host][ccinfo->dev] = newlist;
1487 
1488         add_to_global_list(newlist);
1489 
1490         return (WUSBA_SUCCESS);
1491 
1492 }
1493 
1494 /* save cc info to the host */
1495 static int
1496 save_cc_to_store(const wusb_cc_info_t *ccinfo)
1497 {
1498         int rval = WUSBA_FAILURE;
1499         int ccfd = -1;
1500 
1501         /*
1502          * If a device association is just used for one time
1503          * we will not save it to the store file. See wusbadm(1)
1504          */
1505         if (ccinfo->flag) {
1506 
1507                 return (WUSBA_SUCCESS);
1508         }
1509 
1510         /* open cc file */
1511         if ((ccfd = open(WUSB_CC, O_RDWR)) < 0) {
1512                 wusbd_warn("save_cc_to_store:CC file = %s, err = %s",
1513                     WUSB_CC, strerror(errno));
1514                 goto done;
1515         }
1516 
1517         /* seek to the end of the file */
1518         if ((rval = lseek(ccfd, 0, SEEK_END)) == (offset_t)-1) {
1519                 wusbd_warn("save_cc_to_store: seek fail err = %s",
1520                     strerror(errno));
1521                 (void) close(ccfd);
1522                 goto done;
1523         }
1524 
1525         /* save ccinfo to cc file */
1526         if ((rval = write(ccfd, ccinfo, sizeof (wusb_cc_info_t))) !=
1527             sizeof (wusb_cc_info_t)) {
1528                 wusbd_warn("write to store fail: %s - %d",
1529                     strerror(errno), rval);
1530                 (void) close(ccfd);
1531                 goto done;
1532         }
1533 
1534         (void) close(ccfd);
1535         rval = WUSBA_SUCCESS;
1536 
1537 done:
1538         wusbd_info("save_cc_to_store: complete");
1539 
1540         return (rval);
1541 
1542 }
1543 /*
1544  * load all the cc to the host controller
1545  *     1. walk thru the cc list and find the device cc info
1546  *        related to this host.
1547  *     2. add the cc to the host controller
1548  *     3. start the host controller
1549  */
1550 static int
1551 add_all_cc_to_host(const char *host_path, uint8_t hostid)
1552 {
1553         wusb_cc_list_t *list = NULL;
1554         int fd = -1;
1555         int j = 0;
1556         wusbd_warn("add_all_cc_to_host: host = %s", host_path);
1557         /* open host file */
1558         if ((fd = open(host_path, O_RDONLY)) == -1) {
1559                 wusbd_warn("add_all_cc_to_host: host = %s err = %s",
1560                     host_path, strerror(errno));
1561 
1562                 return (WUSBA_FAILURE);
1563         }
1564 
1565         /* Find all the device cc and add cc to host controler */
1566         for (j = 0; j < DEV_MAX; j++) {
1567                 if ((list = devids[hostid][j]) == NULL) {
1568                         continue;
1569                 }
1570                 if (ioctl(fd, WUSB_HC_ADD_CC, &list->info.cc) == -1) {
1571                         wusbd_warn(" add_all_cc_to_host: ioctl = WUSB_HC_ADD_CC"
1572                             "hostid = %d, fail  ", hostid);
1573                         (void) close(fd);
1574 
1575                         return (WUSBA_FAILURE);
1576                 }
1577         }
1578 
1579         (void) close(fd);
1580 
1581         wusbd_info("add_all_cc_to_host complete");
1582 
1583         return (WUSBA_SUCCESS);
1584 }
1585 
1586 /* Remove all the cc infor from a host device */
1587 static int
1588 remove_all_cc_from_host(uint8_t hostid)
1589 {
1590         int fd = -1;
1591         int rval = 0;
1592         char host_path[MAXPATHLEN];
1593 
1594         if (get_host_path(hostid, host_path) < 0) {
1595                 wusbd_warn("remove_all_cc_from_host:hostid = %d not attached",
1596                     hostid);
1597 
1598                 return (WUSBA_FAILURE);
1599         }
1600 
1601 
1602         if ((fd = open(host_path, O_RDONLY)) == -1) {
1603                 wusbd_warn("remove_all_cc_from host: host = %s err = %s",
1604                     host_path, strerror(errno));
1605 
1606                 return (WUSBA_FAILURE);
1607         }
1608         rval = ioctl(fd, WUSB_HC_STOP, WUSB_HC_REM_ALL_CC | WUSB_HC_FINAL_STOP);
1609 
1610         if (rval < 0) {
1611                 wusbd_warn("remove_all_cc_from_host: WUSB_HC_STOP: err = %s",
1612                     strerror(errno));
1613                 (void) close(fd);
1614 
1615                 return (WUSBA_FAILURE);
1616         }
1617         (void) close(fd);
1618 
1619         return (WUSBA_SUCCESS);
1620 }
1621 /*
1622  * Initialize the global cc list from the store file
1623  * "/etc/usb/wusbcc", the hostid/devid would also be
1624  * set in the global devids
1625  */
1626 static int
1627 init_global_cc_list(void)
1628 {
1629         wusb_cc_list_t *list = NULL;
1630         char buf[sizeof (wusb_cc_list_t) + 1];
1631         int ccfd = -1;
1632 
1633         bzero(devids, HOST_MAX * DEV_MAX * sizeof (wusb_cc_list_t *));
1634 
1635         /*
1636          * open the cc file. when daemon starts for the first time
1637          * cc file will be created in /etc/usb, all the wusb host
1638          * and device Conection Context informaion is stored in this
1639          * file. global cc list is the map in the dameon for the
1640          * file.
1641          */
1642         wusbd_info("init_global_cc_list: load cc from %s", WUSB_CC);
1643         if ((ccfd = open(WUSB_CC, O_RDWR|O_CREAT, S_IRUSR | S_IWUSR)) < 0) {
1644                 wusbd_warn("init_global_cc_list: CC store file = %s, err = %s",
1645                     WUSB_CC, strerror(errno));
1646 
1647                 goto fail;
1648         }
1649 
1650         (void) lseek(ccfd, 0, SEEK_SET);
1651 
1652         /* initialize globle cc list from cc file */
1653         while ((read(ccfd, buf, sizeof (wusb_cc_info_t))) > 0) {
1654 
1655                 list = (wusb_cc_list_t *)calloc(sizeof (wusb_cc_list_t), 1);
1656 
1657                 if (list == NULL) {
1658                         wusbd_warn("init_global_cc_list: list = NULL");
1659                         (void) close(ccfd);
1660                         goto fail;
1661                 }
1662 
1663                 (void) memcpy(&(list->info), buf, sizeof (wusb_cc_info_t));
1664 
1665                 /* set devids */
1666                 devids[list->info.host][list->info.dev] = list;
1667 
1668                 /* add the list to the global cc list */
1669                 add_to_global_list(list);
1670         }
1671         (void) close(ccfd);
1672 
1673         return (WUSBA_SUCCESS);
1674 fail:
1675 
1676         return (WUSBA_FAILURE);
1677 }
1678 
1679 /* destroy the global CC list */
1680 static void
1681 destroy_global_cc_list(void)
1682 {
1683         wusb_cc_list_t *list = NULL;
1684         wusb_cc_list_t *next = NULL;
1685 
1686         for (list = global_cclist; list; list = next) {
1687                 next = list->next;
1688                 free(list);
1689                 cc_cnt--;
1690         }
1691         global_cclist = NULL;
1692         wusbd_info("destroy_global_cc_list: cc_cnt = %d", cc_cnt);
1693         cc_cnt = 0;
1694         bzero(devids, HOST_MAX * DEV_MAX * sizeof (wusb_cc_list_t *));
1695 }
1696 
1697 /*
1698  * Add a new list to the global cc list.
1699  * The new cc list will be inserted in an hostid/devid
1700  * incremental order.
1701  */
1702 static void
1703 add_to_global_list(wusb_cc_list_t *list)
1704 {
1705 
1706         wusb_cc_list_t *tmp;
1707         wusb_cc_list_t *next;
1708 
1709 
1710         wusbd_info("add_to_global_list: start");
1711         wusbd_info("host-id = %d, dev-id = %d, type = %s",
1712             list->info.host, list->info.dev, list->info.type);
1713 
1714         /* first cc list */
1715         if (global_cclist == NULL) {
1716                 global_cclist = list;
1717                 list->next = NULL;
1718 
1719                 goto done;
1720         }
1721 
1722         /* new cc list header */
1723         tmp = global_cclist;
1724         if (tmp->info.host > list->info.host) {
1725                 list->next = tmp;
1726                 global_cclist = list;
1727                 goto done;
1728         }
1729 
1730         /* find where to insert the new cc */
1731         for (tmp = global_cclist; tmp->next; tmp = tmp->next) {
1732                 next = tmp->next;
1733                 if (next->info.host < list->info.host) {
1734                         continue;
1735                 }
1736                 if (next->info.host == list->info.host) {
1737                         if (next->info.dev < list->info.dev)
1738                                 continue;
1739                 }
1740                 break;
1741         }
1742         list->next = tmp->next;
1743         tmp->next = list;
1744 
1745 done:
1746         cc_cnt++;
1747         wusbd_info("add_to_global_list: complete");
1748 }
1749 
1750 /* Remove a list from the global cc list */
1751 static void
1752 remove_from_global_list(wusb_cc_list_t *list)
1753 {
1754 
1755         wusb_cc_list_t *tmp = NULL;
1756 
1757         wusbd_info("remove_from_global_list: host-id:%d, dev-id:%d, path:%s",
1758             list->info.host, list->info.dev, list->info.type);
1759 
1760         /* first list */
1761         if (global_cclist == list) {
1762                 global_cclist = list->next;
1763                 goto found;
1764         }
1765 
1766         for (tmp = global_cclist; tmp; tmp = tmp->next) {
1767                 if (tmp->next  == list) {
1768                         tmp->next = list->next;
1769                         goto found;
1770                 }
1771         }
1772 
1773         wusbd_warn("remove_from_global_list: cc not found ");
1774         return;
1775 found:
1776         free(list);
1777         cc_cnt--;
1778         wusbd_info("remove_from_global_list: complete");
1779 }
1780 
1781 /*
1782  * It is useful make a wrapper to work thru each entry in the global
1783  * lists. it is used widely for to travers the whole list
1784  */
1785 static void
1786 global_list_iterate(cc_list_func func, void *data)
1787 {
1788         wusb_cc_list_t *list = global_cclist;
1789         while (list) {
1790                 if (func(list, (void*)data) < 0)
1791                         break;
1792                 list = list->next;
1793         }
1794 }
1795 
1796 /* Set all the device/host state to be disabled or disconnected */
1797 static void
1798 clean_all_cc_list()
1799 {
1800         wusbd_info("clean_all_cc_list: start");
1801         global_list_iterate(clean_cc_list, NULL);
1802         wusbd_info("clean_all_cc_list: complete");
1803 }
1804 
1805 /* Copy the cc list to buffer */
1806 static void
1807 copy_list_back(char *buf)
1808 {
1809         global_list_iterate(copy_cc_list, &buf);
1810 }
1811 
1812 /* work on each entry in the /dev/usb/whost */
1813 static void
1814 all_hosts_iterate(host_func func)
1815 {
1816         struct dirent *entry;
1817         char filename[MAXPATHLEN];
1818         DIR *dirp = NULL;
1819 
1820         if ((dirp = opendir(WUSB_HOST_PATH)) == NULL) {
1821                 wusbd_warn("all_hosts_iterate: dir = %s, err = %s",
1822                     WUSB_HOST_PATH, strerror(errno));
1823 
1824                 return;
1825         }
1826         while ((entry = readdir(dirp)) != NULL) {
1827                 if (strstr(entry->d_name, WUSB_HOST_NAME)) {
1828 
1829                         (void) snprintf(filename, MAXPATHLEN, "%s/%s",
1830                             WUSB_HOST_PATH, entry->d_name);
1831                         func(filename);
1832                 }
1833         }
1834         (void) closedir(dirp);
1835 }
1836 
1837 /* Get the host file path in /dev/usb from a host id */
1838 static int
1839 get_host_path(int hostid, char *path)
1840 {
1841         struct dirent *entry;
1842         char filename[MAXPATHLEN];
1843         DIR *dirp = NULL;
1844         uint8_t mac[WUSB_DEV_MAC_LENGTH];
1845         int rval = WUSBA_FAILURE;
1846 
1847         wusbd_info("get_host_path :host = %d", hostid);
1848         if ((dirp = opendir(WUSB_HOST_PATH)) == NULL) {
1849                 wusbd_warn("all_hosts_iterate: dir = %s, err = %s",
1850                     WUSB_HOST_PATH, strerror(errno));
1851 
1852                 return (rval);
1853         }
1854         while ((entry = readdir(dirp)) != NULL) {
1855                 if (strstr(entry->d_name, WUSB_HOST_NAME)) {
1856                         (void) snprintf(filename, MAXPATHLEN, "%s/%s",
1857                             WUSB_HOST_PATH, entry->d_name);
1858                         if (load_host_mac(filename, mac) < 0) {
1859                                 wusbd_warn("get_host_path: host = %s failed",
1860                                     filename);
1861 
1862                                 continue;
1863                         }
1864 
1865                         if (hostid == find_host_id(mac)) {
1866                                 (void) snprintf(path, MAXPATHLEN, "%s",
1867                                     filename);
1868                                 rval = WUSBA_SUCCESS;
1869 
1870 
1871                                 break;
1872                         }
1873 
1874 
1875                 }
1876         }
1877         (void) closedir(dirp);
1878 
1879         return (rval);
1880 }
1881 
1882 /* Check all the host device */
1883 static void
1884 check_all_host()
1885 {
1886         wusbd_info("check_all_host :start");
1887         all_hosts_iterate(check_host);
1888         wusbd_info("check_all_host :finished");
1889 }
1890 
1891 /* Stop the host device */
1892 static void
1893 stop_all_host()
1894 {
1895         wusbd_info("stop_all_host :start");
1896         all_hosts_iterate((host_func)stop_host);
1897         wusbd_info("stop_all_host :finished");
1898 }
1899 
1900 /*
1901  * update the cc list information
1902  *    stat of the device and host, device nodename
1903  */
1904 static void
1905 update_all_cc_list()
1906 {
1907         wusbd_info("update_all_cc_list :start");
1908         if (global_cclist) {
1909                 all_hosts_iterate(update_cc_list);
1910         } else {
1911                 wusbd_info("update_all_cc_list :global_cclist = NULL");
1912         }
1913         wusbd_info("update_all_cc_list :complete");
1914 }
1915 
1916 /*
1917  * Get credential of the door_call client and check
1918  * authorizations of caller's uid/euid
1919  */
1920 static int
1921 wusbd_check_auth(const char *auth_str)
1922 {
1923         uid_t   uid;
1924         ucred_t *pcred = NULL;
1925         if (door_ucred(&pcred) < 0) {
1926                 wusbd_warn("chk_auths: door_ucred: err = %s ", strerror(errno));
1927 
1928                 return (WUSBA_FAILURE);
1929         }
1930 
1931         uid = ucred_geteuid(pcred);
1932 
1933         /* remember to do this */
1934         ucred_free(pcred);
1935 
1936         if (chk_auths(uid, auth_str) < 0) {
1937 
1938                 return (WUSBA_FAILURE);
1939         }
1940 
1941         return (WUSBA_SUCCESS);
1942 }
1943 
1944 static int
1945 load_host_mac(const char *filename, uint8_t *mac)
1946 {
1947         int fd = -1;
1948         int rval = WUSBA_FAILURE;
1949 
1950         wusbd_info("load_host_mac: host = %s\n", filename);
1951         /* open host/dev file */
1952         if ((fd = open(filename, O_RDONLY)) == -1) {
1953                 wusbd_warn("load_host_mac: filename = %s , err = %s", filename,
1954                     strerror(errno));
1955                 goto done;
1956         }
1957 
1958         /* Get the mac address of the host */
1959         if (ioctl(fd, WUSB_HC_GET_MAC_ADDR, mac) == -1) {
1960                 wusbd_warn("load_host_mac: WUSB_HC_GET_MAC_ADDR: err = %s",
1961                     strerror(errno));
1962                 (void) close(fd);
1963                 goto done;
1964         }
1965 
1966         (void) close(fd);
1967 
1968 
1969         rval = WUSBA_SUCCESS;
1970 done:
1971         wusbd_info("load_host_mac complete");
1972 
1973         return (rval);
1974 }
1975 
1976 /*
1977  * create host cc
1978  *    1. create the cc for host
1979  *    2. save the cc to list & cc store file
1980  */
1981 static int
1982 create_host_cc(const char *filename)
1983 {
1984         wusb_cc_info_t ccinfo;
1985         uint8_t mac[WUSB_DEV_MAC_LENGTH];
1986         wusbd_info("create host cc for :%s", filename);
1987 
1988         if (load_host_mac(filename, mac) < 0) {
1989                 wusbd_warn("create_host_cc: host = %s, load mac failed",
1990                     filename);
1991 
1992                 return (WUSBA_FAILURE);
1993         }
1994 
1995         bzero(&ccinfo, sizeof (wusb_cc_info_t));
1996 
1997         /* assign CHID */
1998         if (generate_wusb_CHID(&(ccinfo.cc), mac) < 0) {
1999 
2000                 wusbd_warn("create_host_cc: host = %s, reate chid failed",
2001                     filename);
2002 
2003                 return (WUSBA_FAILURE);
2004         }
2005 
2006         print_array("New CC for host:", ccinfo.cc.CHID, 48);
2007 
2008         (void) memcpy(ccinfo.mac, mac, WUSB_DEV_MAC_LENGTH);
2009 
2010         /* Todo: only support hwa */
2011         (void) snprintf(ccinfo.type, WUSB_TYPE_LEN, "hwa");
2012 
2013         /* don't allocate dev id here , for host, dev id set to 0 */
2014         if ((ccinfo.host = assign_host_id()) == 0) {
2015                 wusbd_warn("create_host_cc: assign_host_id = 0");
2016 
2017                 return (WUSBA_FAILURE);
2018         }
2019         ccinfo.dev = 0;
2020 
2021         /* save cc infor to host and cc file */
2022         if (save_cc(&ccinfo) < 0) {
2023                 wusbd_warn("create_host_cc: save_cc failed");
2024 
2025                 return (WUSBA_FAILURE);
2026         }
2027 
2028         return (WUSBA_SUCCESS);
2029 
2030 }
2031 
2032 /*
2033  * Add CCs to hosts upon startup
2034  * OR add CCs to the host which is newly hotplugged in
2035  */
2036 static void
2037 check_host(const char *host)
2038 {
2039         int hostid = 0;
2040 
2041         uint8_t mac[WUSB_DEV_MAC_LENGTH];
2042 
2043         wusbd_info("check_host: host = %s", host);
2044         if (load_host_mac(host, mac) < 0) {
2045                 wusbd_warn("check_host: host = %s load mac fail", host);
2046 
2047                 return;
2048         }
2049         if ((hostid = find_host_id(mac)) != 0) {
2050                 wusbd_info("check_host: host = %s host-id = %d found",
2051                     host, hostid);
2052                 (void) add_all_cc_to_host(host, hostid);
2053                 /* start the host */
2054                 (void) start_host(host);
2055 
2056         } else {
2057                 wusbd_info("check_host: newhost = %s found", host);
2058                 if (WUSBA_SUCCESS == create_host_cc(host)) {
2059                         /* check host again */
2060                         (void) check_host(host);
2061                 }
2062         }
2063 }
2064 
2065 /*
2066  * Remove one cc from host
2067  * Args:
2068  *      hostid - hostid for the cc
2069  *      devid - devid for the cc
2070  */
2071 static int
2072 remove_cc_from_host(uint8_t hostid, uint16_t devid)
2073 {
2074         int fd = -1;
2075         wusb_cc_list_t *list = devids[hostid][0];
2076         char host_path[MAXPATHLEN];
2077 
2078         if (get_host_path(hostid, host_path) < 0) {
2079                 wusbd_warn("remove_cc_from_host:hostid = %d not attached",
2080                     hostid);
2081 
2082                 return (WUSBA_FAILURE);
2083         }
2084 
2085         if ((fd = open(host_path, O_RDWR)) == -1) {
2086                 wusbd_warn("remove_cc_from_host: host = %s err = %s",
2087                     host_path, strerror(errno));
2088 
2089                 return (WUSBA_FAILURE);
2090         }
2091 
2092         list = devids[hostid][devid];
2093         if (ioctl(fd, WUSB_HC_REM_CC, &(list->info.cc)) != 0) {
2094                 wusbd_warn("remove_cc_from_host: WUSB_HC_REM_CC err = %s",
2095                     strerror(errno));
2096                 (void) close(fd);
2097 
2098                 return (WUSBA_FAILURE);
2099         }
2100         (void) close(fd);
2101 
2102         return (WUSBA_SUCCESS);
2103 }
2104 
2105 /* Stop/disable a host device */
2106 static int
2107 stop_host(const char *host)
2108 {
2109         int fd = -1;
2110         int hstate = -1;
2111         wusbd_info("stop_host: host = %s", host);
2112         if ((fd = open(host, O_RDONLY)) == -1) {
2113                 wusbd_warn("stop_host:host = %s err = %s", host,
2114                     strerror(errno));
2115 
2116                 return (WUSBA_FAILURE);
2117         }
2118         /*
2119          * We'll only send the cmd to stop host while host has already
2120          * been startd. start/stop host takes time becasue host controller
2121          * need to reset hardware or may cause issue while it it is stopping.
2122          * So just do it at the right time.
2123          */
2124         if (ioctl(fd, WUSB_HC_GET_HSTATE, &hstate) < 0) {
2125                 wusbd_warn("stop_host: WUSB_HC_GET_HSTATE: err = %s",
2126                     strerror(errno));
2127                 goto fail;
2128         }
2129 
2130         if (hstate == WUSB_HC_STARTED) {
2131                 if (ioctl(fd, WUSB_HC_STOP, WUSB_HC_FINAL_STOP) != 0) {
2132                         wusbd_warn("stop_host: WUSB_HC_STOP: err = %s",
2133                             strerror(errno));
2134                         goto fail;
2135                 }
2136         }
2137         (void) close(fd);
2138 
2139         return (WUSBA_SUCCESS);
2140 fail:
2141         (void) close(fd);
2142 
2143         return (WUSBA_FAILURE);
2144 }
2145 
2146 /* start/enable a host device */
2147 static int
2148 start_host(const char *host)
2149 {
2150         int fd = -1;
2151         int hstate = -1;
2152         wusbd_warn("start_host : host = %s", host);
2153         if ((fd = open(host, O_RDONLY)) == -1) {
2154                 wusbd_warn("start_host: host = %s err = %s", host,
2155                     strerror(errno));
2156 
2157                 return (WUSBA_FAILURE);
2158         }
2159         /*
2160          * Check if the host is already start. if the host has been started.
2161          * it is not proper to send the start command to the host controller,
2162          * because it may cause some issue for host contoller reset the
2163          * hardware
2164          */
2165         if (ioctl(fd, WUSB_HC_GET_HSTATE, &hstate) < 0) {
2166                 wusbd_warn("start_host: ioctl = WUSB_HC_GET_HSTATE err = %s",
2167                     strerror(errno));
2168                 goto fail;
2169         }
2170 
2171         if (hstate != WUSB_HC_STARTED) {
2172                 if (ioctl(fd, WUSB_HC_START, WUSB_HC_INITIAL_START) == -1) {
2173                         wusbd_warn("start_host: WUSB_HC_START: err = %s",
2174                             strerror(errno));
2175                         goto fail;
2176                 }
2177         }
2178         (void) close(fd);
2179         wusbd_info("start_host: complete");
2180 
2181         return (WUSBA_SUCCESS);
2182 fail:
2183         (void) close(fd);
2184 
2185         return (WUSBA_FAILURE);
2186 }
2187 
2188 /* Check the args of a dev ctrl door call request */
2189 static uint16_t
2190 check_dev_ctrl(wusb_dev_ctrl_t *dev_ctrl)
2191 {
2192         if ((dev_ctrl->host == 0) || (dev_ctrl->host >= HOST_MAX)) {
2193                 wusbd_warn("check_dev_ctrl: host-id = %02d", dev_ctrl->host);
2194 
2195                 return (WUSBADM_INVAL_HOSTID);
2196         }
2197         if (!devids[dev_ctrl->host][0]) {
2198                 wusbd_warn("check_dev_ctrl: host-id = %02d cc = NULL",
2199                     dev_ctrl->host);
2200 
2201                 return (WUSBADM_NO_HOST);
2202         }
2203         if (dev_ctrl->dev >= DEV_MAX) {
2204                 wusbd_warn("check_dev_ctrl: dev-id = %03d, max: %d",
2205                     dev_ctrl->dev, DEV_MAX);
2206 
2207                 return (WUSBADM_INVAL_DEVID);
2208 
2209         }
2210         if (!devids[dev_ctrl->host][dev_ctrl->dev]) {
2211                 wusbd_warn("check_dev_ctl: dev-id = %02d.%03d, cc = NULL",
2212                     dev_ctrl->host, dev_ctrl->dev);
2213 
2214                 return (WUSBADM_NO_DEVICE);
2215         }
2216 
2217         return (WUSBADM_OK);
2218 }
2219 
2220 /* Check the args of a host ctrl door call request */
2221 static uint16_t
2222 check_host_ctrl(wusb_dev_ctrl_t *dev_ctrl)
2223 {
2224         if ((dev_ctrl->host == 0) || (dev_ctrl->host >= HOST_MAX)) {
2225                 wusbd_warn("check_host_ctrl: host-id = %02d", dev_ctrl->host);
2226 
2227                 return (WUSBADM_INVAL_HOSTID);
2228         }
2229         if (!devids[dev_ctrl->host][0]) {
2230                 wusbd_warn("check_host_ctrl: host-id = %02d, cc = NULL",
2231                     dev_ctrl->host);
2232 
2233                 return (WUSBADM_NO_HOST);
2234         }
2235         if (dev_ctrl->dev != 0) {
2236                 wusbd_warn("check_host_ctrl: dev-id = %03d no zero",
2237                     dev_ctrl->dev);
2238 
2239                 return (WUSBADM_INVAL_DEVID);
2240         }
2241 
2242         return (WUSBADM_OK);
2243 }
2244 
2245 /* Remove one dev from the cc list */
2246 static int
2247 remove_one_dev(uint8_t hostid, uint16_t devid)
2248 {
2249         wusb_cc_list_t *list = NULL;
2250         if (remove_cc_from_host(hostid, devid) < 0) {
2251                 wusbd_warn("remove_one_dev: hostid = %d, devid = %d"
2252                 "remove cc from host failed", hostid, devid);
2253         }
2254         list = devids[hostid][devid];
2255         remove_from_global_list(list);
2256 
2257         free_dev_id(hostid, devid);
2258 
2259         return (WUSBA_SUCCESS);
2260 
2261 }
2262 
2263 /* Remove all dev from the cc list */
2264 static int
2265 remove_all_dev(uint8_t hostid)
2266 {
2267         int i = 0;
2268         wusbd_warn("remove_all_dev enter, hostid = %d", hostid);
2269         if (remove_all_cc_from_host(hostid) < 0) {
2270                 wusbd_warn("remove_all_dev: hostid = %d. remove all cc failed",
2271                     hostid);
2272         }
2273         for (i = 1; i < DEV_MAX; i++) {
2274                 wusb_cc_list_t *list = devids[hostid][i];
2275                 if (list) {
2276                         remove_from_global_list(list);
2277                         free_dev_id(hostid, i);
2278                 }
2279         }
2280         wusbd_warn("remove_all_dev  complete");
2281 
2282         return (WUSBA_SUCCESS);
2283 }
2284 
2285 /* register device add/remove event to update the cc list */
2286 static int
2287 init_sys_evnt()
2288 {
2289         sysevent_handle_t *shp;
2290         const char *subclass_list[] = {
2291             ESC_DEVFS_DEVI_ADD,
2292             0
2293         };
2294         if ((shp = sysevent_bind_handle(event_handler)) == NULL) {
2295                 wusbd_warn("init_sys_evnt: sysevent bind handle: err = %s",
2296                     strerror(errno));
2297                 goto fail;
2298         }
2299         if (sysevent_subscribe_event(shp, EC_DEVFS, subclass_list, 1) != 0) {
2300                 wusbd_warn("init_sys_evnt: sysevent subscribe: err = %s",
2301                     strerror(errno));
2302                 sysevent_unbind_handle(shp);
2303                 goto fail;
2304         }
2305 
2306         return (WUSBA_SUCCESS);
2307 fail:
2308 
2309         return (WUSBA_FAILURE);
2310 }
2311 
2312 /*
2313  * Only one daemon is running in the system
2314  * Create pid file to save the pid of the daemon
2315  * process, the pid file is also used by svcadm to
2316  * stop the daemon
2317  */
2318 static int
2319 init_daemon_pid()
2320 {
2321         int fd;
2322         char pid[20];
2323 
2324         if ((fd = open(PID_FILE, O_RDWR|O_CREAT|O_EXCL, S_IRUSR | S_IWUSR))
2325             == -1) {
2326                 wusbd_warn("dameon is already running! ");
2327 
2328                 return (WUSBA_FAILURE);
2329         }
2330 
2331         /* save pid to the file */
2332         (void) snprintf(pid, 19, "%d", getpid());
2333 
2334         if (write(fd, pid, strlen(pid)) != strlen(pid)) {
2335                 wusbd_warn("write pid file failed! ");
2336                 (void) close(fd);
2337 
2338                 return (WUSBA_FAILURE);
2339 
2340         }
2341         (void) close(fd);
2342 
2343         return (WUSBA_SUCCESS);
2344 
2345 }
2346 
2347 static void
2348 exit_clean(int ret)
2349 {
2350         wusbd_warn("Remove door file, pid file");
2351         (void) fdetach(DOOR_FILE);
2352         (void) unlink(DOOR_FILE);
2353         (void) unlink(PID_FILE);
2354 
2355         (void) pthread_mutex_destroy(&mutex_cclock);
2356 
2357         closelog();
2358 
2359         exit(ret);
2360 }
2361 
2362 /*
2363  * Refresh daemon. svcadm restart will send a SIGHUP to the daemon
2364  * destroy the cc list and reload it from cc now. Update the status
2365  * of each cc list by checking all the hosts in the system.
2366  */
2367 /* ARGSUSED */
2368 static void
2369 refresh(int signo)
2370 {
2371         wusbd_info("refresh: daemon is restarting..");
2372 
2373         (void) pthread_mutex_lock(&mutex_cclock);
2374 
2375         destroy_global_cc_list();
2376         (void) init_global_cc_list();
2377         check_all_host();
2378 
2379         (void) pthread_mutex_unlock(&mutex_cclock);
2380 
2381         wusbd_info("refresh: daemon is ok now");
2382 }
2383 
2384 /* update host CC when a wireless host is plugged */
2385 static void
2386 event_handler(sysevent_t *ev)
2387 {
2388         nvlist_t *attr_list = NULL;
2389         char *path = NULL;
2390 
2391         if (sysevent_get_attr_list(ev, &attr_list) != 0) {
2392                 wusbd_warn("event_handler: can not get attr list");
2393 
2394                 return;
2395         }
2396 
2397         (void) nvlist_lookup_string(attr_list, DEVFS_PATHNAME, &path);
2398 
2399         wusbd_info("event_handler: device path  %s", path);
2400 
2401 
2402         /* check if the device is host device and update cc list */
2403         if (path && strstr(path, WUSB_HWA_HOST_NODE)) {
2404                 char filename[MAXPATHLEN];
2405                 (void) snprintf(filename, MAXPATHLEN, "/devices%s:hwahc", path);
2406 
2407                 (void) pthread_mutex_lock(&mutex_cclock);
2408                 check_host(filename);
2409                 (void) pthread_mutex_unlock(&mutex_cclock);
2410         }
2411 
2412         nvlist_free(attr_list);
2413 }
2414 
2415 
2416 /* For debug only */
2417 void
2418 print_prv()
2419 {
2420 #ifdef DEBUG
2421         priv_set_t *tt = priv_allocset();
2422         if (getppriv(PRIV_PERMITTED, tt) == 0) {
2423                 wusbd_info("PRIV_PERMITTED:\n");
2424                 wusbd_info("\t%s\n",
2425                     priv_set_to_str(tt, ',', PRIV_STR_SHORT));
2426         }
2427         if (getppriv(PRIV_EFFECTIVE, tt) == 0) {
2428                 wusbd_info("PRIV_EFFECTIVE:\n");
2429                 wusbd_info("\t%s\n",
2430                     priv_set_to_str(tt, ',', PRIV_STR_SHORT));
2431         }
2432         if (getppriv(PRIV_INHERITABLE, tt) == 0) {
2433                 wusbd_info("PRIV_INHERITABLE:\n");
2434                 wusbd_info("\t%s\n",
2435                     priv_set_to_str(tt, ',', PRIV_STR_SHORT));
2436         }
2437         if (getppriv(PRIV_LIMIT, tt) == 0) {
2438                 wusbd_info("PRIV_LIMIT:\n");
2439                 wusbd_info("\t%s\n",
2440                     priv_set_to_str(tt, ',', PRIV_STR_SHORT));
2441         }
2442         priv_freeset(tt);
2443 #endif
2444 }
2445 
2446 /* wusb daemon init */
2447 static int
2448 wusbd_daemonize_init()
2449 {
2450         int status, pfds[2];
2451         sigset_t set, oset;
2452         pid_t pid;
2453         int rc;
2454 
2455         /*
2456          * Remove all the privs not needed for the daemon.
2457          *    PRIV_SYS_MOUNT: requred by starting door serv.
2458          *    PRIV_FILE_DAC_WRITE: requred by attach door file.
2459          *    PRIV_SYS_CONFIG, required by register sys event.
2460          *    PRIV_SYS_DEVICES, required by driver ioctl.
2461          */
2462         rc =  __init_daemon_priv(PU_RESETGROUPS | PU_CLEARLIMITSET,
2463             0, 0,
2464             PRIV_SYS_MOUNT,
2465             PRIV_FILE_DAC_WRITE,
2466             PRIV_SYS_CONFIG,
2467             PRIV_SYS_DEVICES,
2468             NULL);
2469 
2470         if (rc != 0) {
2471                 wusbd_warn("insufficient privileges");
2472                 exit(FATAL_ERROR);
2473         }
2474 
2475         /*
2476          * Block all signals prior to the fork and leave them blocked in the
2477          * parent so we don't get in a situation where the parent gets SIGINT
2478          * and returns non-zero exit status and the child is actually running.
2479          * In the child, restore the signal mask once we've done our setsid().
2480          */
2481         (void) sigfillset(&set);
2482         (void) sigdelset(&set, SIGABRT);
2483         (void) sigprocmask(SIG_BLOCK, &set, &oset);
2484 
2485         if (pipe(pfds) == -1) {
2486                 wusbd_warn("unable to create pipe");
2487                 closelog();
2488                 exit(FATAL_ERROR);
2489         }
2490 
2491         closelog();
2492 
2493 
2494         if ((pid = fork()) == -1) {
2495                 openlog("wusbd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
2496                 wusbd_warn("unable to fork");
2497                 closelog();
2498                 exit(FATAL_ERROR);
2499         }
2500 
2501         /*
2502          * If we're the parent process, wait for either the child to send us
2503          * the appropriate exit status over the pipe or for the read to fail
2504          * (presumably with 0 for EOF if our child terminated abnormally).
2505          * If the read fails, exit with either the child's exit status if it
2506          * exited or with SMF_EXIT_ERR_FATAL if it died from a fatal signal.
2507          */
2508         if (pid != 0) {
2509                 (void) close(pfds[1]);
2510 
2511                 if (read(pfds[0], &status, sizeof (status)) == sizeof (status))
2512                         _exit(status);
2513 
2514                 if (waitpid(pid, &status, 0) == pid && WIFEXITED(status))
2515                         _exit(WEXITSTATUS(status));
2516 
2517                 _exit(FATAL_ERROR);
2518         }
2519         openlog("wusbd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
2520         (void) setsid();
2521         (void) sigprocmask(SIG_SETMASK, &oset, NULL);
2522         (void) chdir("/");
2523         (void) umask(022);
2524         (void) close(pfds[0]);
2525 
2526         return (pfds[1]);
2527 }
2528 
2529 /* wusb daemon fini */
2530 static void
2531 wusbd_daemonize_fini(int fd, int exit_status)
2532 {
2533         /*
2534          * Now that we're running, if a pipe fd was specified, write an exit
2535          * status to it to indicate that our parent process can safely detach.
2536          * Then proceed to loading the remaining non-built-in modules.
2537          */
2538         if (fd >= 0) {
2539                 (void) write(fd, &exit_status, sizeof (exit_status));
2540         }
2541 
2542         (void) close(fd);
2543         if ((fd = open("/dev/null", O_RDWR)) >= 0) {
2544                 (void) fcntl(fd, F_DUP2FD, STDIN_FILENO);
2545                 (void) fcntl(fd, F_DUP2FD, STDOUT_FILENO);
2546 #if 0
2547                 /* Leave the stderr for smf log */
2548                 (void) fcntl(fd, F_DUP2FD, STDERR_FILENO);
2549 #endif
2550                 (void) close(fd);
2551         }
2552         /* Remove all the privs not needed. leave SYS_DEVICE only */
2553         __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
2554             PRIV_FILE_LINK_ANY,
2555             PRIV_PROC_INFO,
2556             PRIV_FILE_DAC_WRITE,
2557             PRIV_SYS_MOUNT,
2558             PRIV_SYS_CONFIG,
2559             (char *)NULL);
2560 
2561 
2562         print_prv();
2563 }
2564 /* Each door call handler should get the lock */
2565 static void
2566 wusbd_daemon_enter()
2567 {
2568         wusbd_info("wusbd_daemon_enter: enter");
2569         (void) pthread_mutex_lock(&mutex_cclock);
2570 }
2571 /* Each door call handler should release the lock */
2572 static void
2573 wusbd_daemon_leave(char *buf, int len)
2574 {
2575         wusbd_info("wusbd_daemon_leave");
2576         (void) pthread_mutex_unlock(&mutex_cclock);
2577         (void) door_return(buf, len, NULL, 0);
2578 }