xref: /onnv-gate/usr/src/cmd/wusbadm/wusbd.c (revision 9430:637732b28916)
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