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 }