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
wusbd_sig_handler(int sigval)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
daemonize()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
wusbd_do_list(char * argp,size_t arg_size,door_desc_t * dp,uint_t n_desc)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
wusbd_do_association(char * argp,size_t arg_size,door_desc_t * dp,uint_t n_desc)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
wusbd_do_remove_dev(char * argp,size_t arg_size,door_desc_t * dp,uint_t n_desc)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
wusbd_do_remove_host(char * argp,size_t arg_size,door_desc_t * dp,uint_t n_desc)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
wusbd_do_enable_host(char * argp,size_t arg_size,door_desc_t * dp,uint_t n_desc)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
wusbd_do_disable_host(char * argp,size_t arg_size,door_desc_t * dp,uint_t n_desc)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
wusbd_do_host(char * argp,size_t arg_size,door_desc_t * dp,uint_t n_desc,int flag)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
door_srv(void * cookie,char * argp,size_t arg_size,door_desc_t * dp,uint_t n_desc)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
update_cc_list(const char * host)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 *
find_host_cc(uint8_t host_id)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 *
find_dev_cc(uint8_t host_id,uint8_t * CDID)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
find_host_id(uint8_t * mac)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
update_cc_file()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
ca_get_info(int fd,wusb_cbaf_asso_info_t * first)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
ca_set_host(int fd,wusb_cc_info_t * info)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
ca_get_req(int fd,wusb_cbaf_asso_info_t * first)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
ca_get_devinfo(int fd,wusb_cbaf_device_info_t * device_info)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
ca_connect_cc(int fd,wusb_cc_info_t * newinfo,wusb_cbaf_device_info_t * device_info)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
ca_create_cc(wusb_cc_info_t * newinfo,wusb_cc_info_t * host_cc)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
ca_add_cc(wusb_cc_info_t * newinfo,const char * filename)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
ca_save_cc(wusb_cc_info_t * newinfo,wusb_cc_info_t * hostinfo)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
wusbd_do_ca(const char * host_path,const char * ca_dev,wusb_cc_info_t * host_cc,char onetime)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
generate_wusb_CC(wusb_cc_t * cc)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
generate_wusb_CHID(wusb_cc_t * cc,uint8_t * mac)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
generate_wusb_CDID(CK_SESSION_HANDLE pkhandle,wusb_cc_t * cc)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
generate_wusb_CK(CK_SESSION_HANDLE pkhandle,wusb_cc_t * cc)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
wusbd_warn(const char * format,...)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
wusbd_log(const char * format,...)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
wusbd_info(const char * format,...)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
assign_host_id(void)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
assign_dev_id(uint8_t hostid)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
free_dev_id(uint8_t hostid,uint16_t devid)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
init_door_srv()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
print_cc_list(wusb_cc_list_t * list,void * data)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
write_cc_list(wusb_cc_list_t * list,void * data)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
clean_cc_list(wusb_cc_list_t * list,void * data)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
copy_cc_list(wusb_cc_list_t * list,void * data)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
save_cc(const wusb_cc_info_t * ccinfo)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
save_cc_to_list(const wusb_cc_info_t * ccinfo)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
save_cc_to_store(const wusb_cc_info_t * ccinfo)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
add_all_cc_to_host(const char * host_path,uint8_t hostid)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
remove_all_cc_from_host(uint8_t hostid)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
init_global_cc_list(void)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
destroy_global_cc_list(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
add_to_global_list(wusb_cc_list_t * list)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
remove_from_global_list(wusb_cc_list_t * list)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
global_list_iterate(cc_list_func func,void * data)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
clean_all_cc_list()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
copy_list_back(char * buf)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
all_hosts_iterate(host_func func)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
get_host_path(int hostid,char * path)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
check_all_host()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
stop_all_host()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
update_all_cc_list()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
wusbd_check_auth(const char * auth_str)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
load_host_mac(const char * filename,uint8_t * mac)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
create_host_cc(const char * filename)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
check_host(const char * host)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
remove_cc_from_host(uint8_t hostid,uint16_t devid)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
stop_host(const char * host)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
start_host(const char * host)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
check_dev_ctrl(wusb_dev_ctrl_t * dev_ctrl)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
check_host_ctrl(wusb_dev_ctrl_t * dev_ctrl)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
remove_one_dev(uint8_t hostid,uint16_t devid)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
remove_all_dev(uint8_t hostid)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
init_sys_evnt()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
init_daemon_pid()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
exit_clean(int ret)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
refresh(int signo)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
event_handler(sysevent_t * ev)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
print_prv()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
wusbd_daemonize_init()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
wusbd_daemonize_fini(int fd,int exit_status)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
wusbd_daemon_enter()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
wusbd_daemon_leave(char * buf,int len)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 }
2579