xref: /onnv-gate/usr/src/uts/common/io/usb/usba/whcdi.c (revision 10912:bb04b6e33d44)
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 
27 /*
28  * USBA: Solaris USB Architecture support
29  *
30  * whcdi.c is part of the WUSB extension to the USBA framework.
31  *
32  * It mainly contains functions that can be shared by whci and hwahc
33  * drivers to enable WUSB host functionality, such as WUSB channel
34  * resource management, MMC IE handling, WUSB HC specific requests,
35  * WUSB device authentication, child connection/disconnection, etc.
36  */
37 #define	USBA_FRAMEWORK
38 #include <sys/usb/usba.h>
39 #include <sys/usb/usba/usba_impl.h>
40 #include <sys/usb/usba/usba_types.h>
41 #include <sys/usb/usba/hcdi_impl.h>	/* for usba_hcdi_t */
42 #include <sys/usb/usba/whcdi.h>
43 #include <sys/usb/usba/wa.h>
44 #include <sys/strsubr.h>
45 #include <sys/crypto/api.h>
46 #include <sys/strsun.h>
47 #include <sys/random.h>
48 
49 /*
50  * local variables
51  */
52 static kmutex_t whcdi_mutex;
53 
54 /* use 0-30 bit as wusb cluster_id bitmaps */
55 static uint32_t cluster_id_mask = 0;
56 
57 _NOTE(MUTEX_PROTECTS_DATA(whcdi_mutex, cluster_id_mask))
58 
59 usb_log_handle_t	whcdi_log_handle;
60 uint_t			whcdi_errlevel = USB_LOG_L4;
61 uint_t			whcdi_errmask = (uint_t)-1;
62 
63 /*
64  * initialize private data
65  */
66 void
usba_whcdi_initialization()67 usba_whcdi_initialization()
68 {
69 	whcdi_log_handle = usb_alloc_log_hdl(NULL, "whcdi", &whcdi_errlevel,
70 	    &whcdi_errmask, NULL, 0);
71 
72 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
73 	    "whcdi_initialization");
74 
75 	mutex_init(&whcdi_mutex, NULL, MUTEX_DRIVER, NULL);
76 }
77 
78 void
usba_whcdi_destroy()79 usba_whcdi_destroy()
80 {
81 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
82 	    "whcdi_destroy");
83 
84 	mutex_destroy(&whcdi_mutex);
85 
86 	usb_free_log_hdl(whcdi_log_handle);
87 }
88 
89 /*
90  * Assign a cluster id for a WUSB channel
91  * return 0 if no free cluster id is available
92  */
93 uint8_t
wusb_hc_get_cluster_id()94 wusb_hc_get_cluster_id()
95 {
96 	int	i;
97 	uint8_t	id;
98 
99 	mutex_enter(&whcdi_mutex);
100 	for (i = 0; i < WUSB_CLUSTER_ID_COUNT; i++) {
101 		/* find the first unused slot */
102 		if (cluster_id_mask & (1 << i)) {
103 			continue;
104 		}
105 
106 		/* set the bitmask */
107 		cluster_id_mask |= (1 << i);
108 		id = WUSB_MIN_CLUSTER_ID + i;
109 		USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
110 		    "new cluster id %d, mask %d", id, cluster_id_mask);
111 		mutex_exit(&whcdi_mutex);
112 
113 		return (id);
114 	}
115 
116 	mutex_exit(&whcdi_mutex);
117 
118 	USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
119 	    "no cluster id available");
120 
121 	return (0);
122 }
123 
124 /* Free the cluster id */
125 void
wusb_hc_free_cluster_id(uint8_t id)126 wusb_hc_free_cluster_id(uint8_t id)
127 {
128 	int	i = id - WUSB_MIN_CLUSTER_ID;
129 
130 	if ((i < 0) || (i >= WUSB_CLUSTER_ID_COUNT)) {
131 
132 		return;
133 	}
134 
135 	mutex_enter(&whcdi_mutex);
136 	if (cluster_id_mask & (1 << i)) {
137 		/* unset the bitmask */
138 		cluster_id_mask &= ~(1 << i);
139 	} else {
140 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
141 		    "cluster id already freed");
142 	}
143 	mutex_exit(&whcdi_mutex);
144 }
145 
146 /*
147  * Allocate iehdl according to the order specified in WUSB 1.0/7.5
148  * WUSB Errata 06.12 requires iehdl to be zero based
149  */
150 int
wusb_hc_get_iehdl(wusb_hc_data_t * hc_data,wusb_ie_header_t * hdr,uint8_t * iehdl)151 wusb_hc_get_iehdl(wusb_hc_data_t *hc_data, wusb_ie_header_t *hdr,
152 	uint8_t *iehdl)
153 {
154 	int	i, rval = USB_SUCCESS;
155 	uint8_t hdl = 0xFF;
156 
157 	switch (hdr->bIEIdentifier) {
158 	case WUSB_IE_HOSTINFO:
159 	/*
160 	 * 7.5.2(and 7.5 under Table 7-38) says this IE should be located
161 	 * in an MMC afte all WCTA_IEs. This mean its handle should
162 	 * be the last one. See also whci r0.95 page 105 top. HC sends
163 	 * IE blocks in ascending IE_HANDLE order.
164 	 */
165 		hdl = hc_data->hc_num_mmcies - 1;
166 		hc_data->hc_mmcie_list[hdl] = hdr;
167 		break;
168 	case WUSB_IE_ISOC_DISCARD:
169 	/*
170 	 * 7.5.10 says this IE must be included before any WxCTAs.
171 	 */
172 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
173 		    "IE type 0x%x unimplemented\n", hdr->bIEIdentifier);
174 		rval = USB_NOT_SUPPORTED;
175 		break;
176 	default:
177 		/*
178 		 * search for existing slot or find the last empty slot
179 		 * so that the other IEs would always set after WCTA_IEs
180 		 */
181 		for (i = hc_data->hc_num_mmcies - 2; i >= 0; i--) {
182 			if ((hc_data->hc_mmcie_list[i] == hdr) ||
183 			    (hc_data->hc_mmcie_list[i] == NULL)) {
184 				hdl = (uint8_t)i;
185 				hc_data->hc_mmcie_list[i] = hdr;
186 				break;
187 			}
188 		}
189 		if (hdl == 0xFF) {
190 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
191 			    "no IE handle available\n");
192 			rval = USB_NO_RESOURCES;
193 		}
194 		break;
195 	}
196 
197 	if (rval == USB_SUCCESS) {
198 		*iehdl = hdl;
199 	}
200 
201 	return (rval);
202 }
203 
204 /* Deallocate iehdl */
205 void
wusb_hc_free_iehdl(wusb_hc_data_t * hc_data,uint8_t iehdl)206 wusb_hc_free_iehdl(wusb_hc_data_t *hc_data, uint8_t iehdl)
207 {
208 	ASSERT(mutex_owned(&hc_data->hc_mutex));
209 
210 	if (iehdl >= hc_data->hc_num_mmcies) {
211 
212 		return;
213 	}
214 
215 	if (hc_data->hc_mmcie_list[iehdl] != NULL) {
216 		hc_data->hc_mmcie_list[iehdl] = NULL;
217 	}
218 }
219 
220 
221 /*
222  * ******************************************************************
223  * WUSB host controller specific requests, refer to WUSB 1.0/8.5.3
224  *
225  * WHCI driver needs to translate the requests to register operations
226  * ******************************************************************
227  */
228 
229 /* For HWA, see WUSB 8.5.3.11 - Set WUSB Cluster ID */
230 int
wusb_hc_set_cluster_id(wusb_hc_data_t * hc_data,uint8_t cluster_id)231 wusb_hc_set_cluster_id(wusb_hc_data_t *hc_data, uint8_t cluster_id)
232 {
233 	dev_info_t	*dip = hc_data->hc_dip;
234 	int		rval;
235 
236 	if (dip == NULL) {
237 
238 		return (USB_INVALID_ARGS);
239 	}
240 
241 	if ((rval = hc_data->set_cluster_id(dip, cluster_id))
242 	    != USB_SUCCESS) {
243 
244 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
245 		    "Set_Cluster_ID fails: rval=%d ", rval);
246 	} else {
247 		mutex_enter(&hc_data->hc_mutex);
248 		hc_data->hc_cluster_id = cluster_id;
249 		mutex_exit(&hc_data->hc_mutex);
250 	}
251 
252 	return (rval);
253 }
254 
255 /*
256  * WUSB 8.5.3.13 - Set WUSB Stream Index
257  * From 7.7, stream index should be 3bits and less than 8.
258  */
259 int
wusb_hc_set_stream_idx(wusb_hc_data_t * hc_data,uint8_t stream_idx)260 wusb_hc_set_stream_idx(wusb_hc_data_t *hc_data, uint8_t stream_idx)
261 {
262 	dev_info_t	*dip = hc_data->hc_dip;
263 	int		rval;
264 
265 	if (stream_idx > 7) {
266 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
267 		    "Set_Stream_Idx fails: invalid idx = %d",
268 		    stream_idx);
269 
270 		return (USB_INVALID_ARGS);
271 	}
272 
273 	rval = hc_data->set_stream_idx(dip, stream_idx);
274 	if (rval != USB_SUCCESS) {
275 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
276 		    "Set_Stream_Idx fails: rval=%d",
277 		    rval);
278 	}
279 
280 	return (rval);
281 }
282 
283 /* For HWA, see WUSB 8.5.3.12 - Set WUSB MAS */
284 int
wusb_hc_set_wusb_mas(wusb_hc_data_t * hc_data,uint8_t * data)285 wusb_hc_set_wusb_mas(wusb_hc_data_t *hc_data, uint8_t *data)
286 {
287 	dev_info_t	*dip = hc_data->hc_dip;
288 	int		rval;
289 
290 	rval = hc_data->set_wusb_mas(dip, data);
291 	if (rval != USB_SUCCESS) {
292 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
293 		    "Set_WUSB_MAS fails: rval=%d", rval);
294 	}
295 
296 	return (rval);
297 
298 }
299 
300 /* For HWA, see WUSB 8.5.3.1 - Add MMC IE */
301 int
wusb_hc_add_mmc_ie(wusb_hc_data_t * hc_data,uint8_t interval,uint8_t rcnt,uint8_t iehdl,uint16_t len,uint8_t * data)302 wusb_hc_add_mmc_ie(wusb_hc_data_t *hc_data, uint8_t interval,
303 	uint8_t rcnt, uint8_t iehdl, uint16_t len, uint8_t *data)
304 {
305 	dev_info_t	*dip = hc_data->hc_dip;
306 	int		rval;
307 
308 	rval = hc_data->add_mmc_ie(dip, interval, rcnt, iehdl, len, data);
309 
310 	if (rval != USB_SUCCESS) {
311 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
312 		    "Add_MMC_IE fails: rval=%d ",
313 		    rval);
314 	}
315 
316 	return (rval);
317 }
318 
319 /* For HWA, see WUSB 8.5.3.5 - Remove MMC IE */
320 int
wusb_hc_remove_mmc_ie(wusb_hc_data_t * hc_data,uint8_t iehdl)321 wusb_hc_remove_mmc_ie(wusb_hc_data_t *hc_data, uint8_t iehdl)
322 {
323 	dev_info_t	*dip = hc_data->hc_dip;
324 	int		rval;
325 
326 	ASSERT(mutex_owned(&hc_data->hc_mutex));
327 
328 	if ((iehdl >= hc_data->hc_num_mmcies) ||
329 	    (hc_data->hc_mmcie_list[iehdl] == NULL)) {
330 
331 		return (USB_FAILURE);
332 	}
333 
334 	mutex_exit(&hc_data->hc_mutex);
335 	rval = hc_data->rem_mmc_ie(dip, iehdl);
336 	mutex_enter(&hc_data->hc_mutex);
337 	if (rval != USB_SUCCESS) {
338 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
339 		    "Remove_MMC_IE fails: rval=%d ", rval);
340 	}
341 
342 	return (rval);
343 }
344 
345 /* For HWA, see WUSB 8.5.3.14 - WUSB Channel Stop */
346 int
wusb_hc_stop_ch(wusb_hc_data_t * hc_data,uint32_t timeoff)347 wusb_hc_stop_ch(wusb_hc_data_t *hc_data, uint32_t timeoff)
348 {
349 	dev_info_t	*dip = hc_data->hc_dip;
350 	int		rval;
351 
352 	rval = hc_data->stop_ch(dip, timeoff);
353 	if (rval != USB_SUCCESS) {
354 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
355 		    "WUSB_Ch_Stop fails: rval=%d ", rval);
356 	}
357 
358 	return (rval);
359 }
360 
361 /* For HWA, see WUSB 8.5. 3.10 - Set Num DNTS Slots */
362 int
wusb_hc_set_num_dnts(wusb_hc_data_t * hc_data,uint8_t interval,uint8_t nslots)363 wusb_hc_set_num_dnts(wusb_hc_data_t *hc_data, uint8_t interval,
364     uint8_t nslots)
365 {
366 	dev_info_t	*dip = hc_data->hc_dip;
367 	int		rval;
368 
369 	rval = hc_data->set_num_dnts(dip, interval, nslots);
370 	if (rval != USB_SUCCESS) {
371 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
372 		    "Set_Num_DNTS fails: rval=%d ", rval);
373 	}
374 
375 	return (rval);
376 }
377 
378 /*
379  * For HWA, see WUSB 8.5.3.2 - 8.5.3.4 Get Time
380  * time_type:
381  *	WUSB_TIME_ADJ	- Get BPST Adjustment
382  *	WUSB_TIME_BPST	- Get BPST Time
383  *	WUSB_TIME_WUSB	- Get WUSB Time
384  */
385 int
wusb_hc_get_time(wusb_hc_data_t * hc_data,uint8_t time_type,uint16_t len,uint32_t * time)386 wusb_hc_get_time(wusb_hc_data_t *hc_data, uint8_t time_type,
387     uint16_t len, uint32_t *time)
388 {
389 	dev_info_t	*dip = hc_data->hc_dip;
390 	int		rval;
391 
392 	/* call the HC's specific get_time function */
393 	rval = hc_data->get_time(dip, time_type, len, time);
394 	if (rval != USB_SUCCESS) {
395 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
396 		    "Set_Num_DNTS fails: rval=%d ", rval);
397 	}
398 
399 	return (rval);
400 }
401 
402 /*
403  * Remove the specified IE from host MMC and release the related IE handle
404  */
405 void
wusb_hc_rem_ie(wusb_hc_data_t * hc_data,wusb_ie_header_t * ieh)406 wusb_hc_rem_ie(wusb_hc_data_t *hc_data, wusb_ie_header_t *ieh)
407 {
408 	int	i;
409 	int16_t	iehdl = -1;
410 
411 	mutex_enter(&hc_data->hc_mutex);
412 	for (i = 0; i < hc_data->hc_num_mmcies; i++) {
413 		if (hc_data->hc_mmcie_list[i] == ieh) {
414 			iehdl = (int16_t)i;
415 
416 			break;
417 		}
418 	}
419 
420 	if (iehdl == -1) {
421 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
422 		    "wusb_hc_rem_ie: IE(%p) iehdl not found", (void *)ieh);
423 		mutex_exit(&hc_data->hc_mutex);
424 
425 		return;
426 	}
427 
428 	(void) wusb_hc_remove_mmc_ie(hc_data, (uint8_t)iehdl);
429 
430 	wusb_hc_free_iehdl(hc_data, (uint8_t)iehdl);
431 	mutex_exit(&hc_data->hc_mutex);
432 }
433 
434 /* Add Host Info IE */
435 int
wusb_hc_add_host_info(wusb_hc_data_t * hc_data,uint8_t stream_idx)436 wusb_hc_add_host_info(wusb_hc_data_t *hc_data, uint8_t stream_idx)
437 {
438 	wusb_ie_host_info_t	*hinfo;
439 	uint8_t			iehdl;
440 	int			rval;
441 
442 	hinfo = kmem_zalloc(sizeof (wusb_ie_host_info_t), KM_SLEEP);
443 
444 	mutex_enter(&hc_data->hc_mutex);
445 
446 	hinfo->bIEIdentifier = WUSB_IE_HOSTINFO;
447 	hinfo->bLength = sizeof (wusb_ie_host_info_t);
448 	if (hc_data->hc_newcon_enabled) {
449 		hinfo->bmAttributes[0] = (stream_idx << WUSB_HI_STRIDX_SHIFT) |
450 		    WUSB_HI_CONN_ALL;
451 	} else {
452 		hinfo->bmAttributes[0] = (stream_idx << WUSB_HI_STRIDX_SHIFT) |
453 		    WUSB_HI_CONN_LMTED;
454 	}
455 	(void) memcpy(hinfo->CHID, hc_data->hc_chid, sizeof (hinfo->CHID));
456 
457 	rval = wusb_hc_get_iehdl(hc_data, (wusb_ie_header_t *)hinfo, &iehdl);
458 	if (rval != USB_SUCCESS) {
459 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
460 		    "wusb_hc_add_host_info: get ie handle fails");
461 		mutex_exit(&hc_data->hc_mutex);
462 
463 		return (rval);
464 	}
465 
466 	USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
467 	    "wusb_hc_add_host_info: iehdl=%d", iehdl);
468 
469 	mutex_exit(&hc_data->hc_mutex);
470 	rval = wusb_hc_add_mmc_ie(hc_data, 10, 1, iehdl,
471 	    sizeof (wusb_ie_host_info_t), (uint8_t *)hinfo);
472 	if (rval != USB_SUCCESS) {
473 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
474 		    "wusb_hc_add_host_info: add host info mmc ie fails");
475 		mutex_enter(&hc_data->hc_mutex);
476 		wusb_hc_free_iehdl(hc_data, iehdl);
477 		mutex_exit(&hc_data->hc_mutex);
478 
479 		return (rval);
480 	}
481 
482 
483 	return (USB_SUCCESS);
484 }
485 
486 /* Remove Host Info IE */
487 void
wusb_hc_rem_host_info(wusb_hc_data_t * hc_data)488 wusb_hc_rem_host_info(wusb_hc_data_t *hc_data)
489 {
490 	int16_t	iehdl = -1;
491 	wusb_ie_header_t *iehead;
492 
493 	mutex_enter(&hc_data->hc_mutex);
494 	/* host info IE is always the last one */
495 	iehdl = hc_data->hc_num_mmcies - 1;
496 	iehead = hc_data->hc_mmcie_list[iehdl];
497 
498 	/* something wrong */
499 	if ((iehead == NULL) || (iehead->bIEIdentifier != WUSB_IE_HOSTINFO)) {
500 		mutex_exit(&hc_data->hc_mutex);
501 		return;
502 	}
503 
504 	(void) wusb_hc_remove_mmc_ie(hc_data, (uint8_t)iehdl);
505 	wusb_hc_free_iehdl(hc_data, (uint8_t)iehdl);
506 	kmem_free(iehead, sizeof (wusb_ie_host_info_t));
507 
508 	mutex_exit(&hc_data->hc_mutex);
509 }
510 
511 /*
512  * Check if a device with certain CDID is connected
513  * return 1 if a device with the same CDID is found;
514  * return 0 if not
515  */
516 uint_t
wusb_hc_is_dev_connected(wusb_hc_data_t * hc_data,uint8_t * cdid,usb_port_t * port)517 wusb_hc_is_dev_connected(wusb_hc_data_t *hc_data, uint8_t *cdid,
518 	usb_port_t *port)
519 {
520 	int			i;
521 	wusb_dev_info_t		*dev_info;
522 
523 	ASSERT(mutex_owned(&hc_data->hc_mutex));
524 
525 	for (i = 1; i <= hc_data->hc_num_ports; i++) {
526 		dev_info = hc_data->hc_dev_infos[i];
527 		if ((dev_info != NULL) &&
528 		    (memcmp(cdid, dev_info->wdev_cdid, 16) == 0)) {
529 			*port = (usb_port_t)i;
530 			USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
531 			    "wusb_hc_is_dev_connected: find dev at port "
532 			    "%d", *port);
533 
534 			return (1);
535 		}
536 	}
537 
538 	return (0);
539 }
540 
541 /*
542  * Check if a device with certain address is connected
543  * return 1 if a device with the same address is found;
544  * return 0 if not
545  */
546 uint_t
wusb_hc_is_addr_valid(wusb_hc_data_t * hc_data,uint8_t addr,usb_port_t * port)547 wusb_hc_is_addr_valid(wusb_hc_data_t *hc_data, uint8_t addr,
548 	usb_port_t *port)
549 {
550 	int			i;
551 	wusb_dev_info_t		*dev_info;
552 
553 	for (i = 1; i <= hc_data->hc_num_ports; i++) {
554 		dev_info = hc_data->hc_dev_infos[i];
555 		if ((dev_info != NULL) && (dev_info->wdev_addr == addr)) {
556 			*port = (usb_port_t)i;
557 			USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
558 			    "wusb_hc_is_addr_valid: find addr at port "
559 			    "%d", *port);
560 
561 			return (1);
562 		}
563 	}
564 
565 	return (0);
566 }
567 
568 
569 /*
570  * Assign port number for a newly connected device
571  * return the first free port number if any, or 0 if none
572  */
573 usb_port_t
wusb_hc_get_free_port(wusb_hc_data_t * hc_data)574 wusb_hc_get_free_port(wusb_hc_data_t *hc_data)
575 {
576 	int		i;
577 	usb_port_t	port;
578 
579 	for (i = 1; i <= hc_data->hc_num_ports; i++) {
580 		if (hc_data->hc_dev_infos[i] == NULL) {
581 			port = (usb_port_t)i;
582 			USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
583 			    "wusb_hc_get_free_port: find free port %d", port);
584 
585 			return (port);
586 		}
587 	}
588 
589 	return (0);
590 }
591 
592 /* Add Connect Acknowledge IE */
593 int
wusb_hc_ack_conn(wusb_hc_data_t * hc_data,usb_port_t port)594 wusb_hc_ack_conn(wusb_hc_data_t *hc_data, usb_port_t port)
595 {
596 	wusb_dev_info_t		*dev_info;
597 	wusb_ie_connect_ack_t	*ack_ie;
598 	wusb_connectack_block_t	*ack_block;
599 	uint8_t			iehdl;
600 	int			rval;
601 
602 	ASSERT(mutex_owned(&hc_data->hc_mutex));
603 
604 	dev_info = hc_data->hc_dev_infos[port];
605 	ASSERT(dev_info != NULL);
606 
607 	ack_ie = kmem_zalloc(sizeof (wusb_ie_connect_ack_t), KM_SLEEP);
608 
609 	ack_ie->bIEIdentifier = WUSB_IE_CONNECTACK;
610 	ack_block = (wusb_connectack_block_t *)ack_ie->bAckBlock;
611 	(void) memcpy(ack_block->CDID, dev_info->wdev_cdid, 16);
612 	ack_block->bDeviceAddress = dev_info->wdev_addr;
613 	ack_ie->bLength = 20;
614 
615 	rval = wusb_hc_get_iehdl(hc_data, (wusb_ie_header_t *)ack_ie, &iehdl);
616 	if (rval != USB_SUCCESS) {
617 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
618 		    "wusb_hc_ack_conn: get ie handle fails");
619 		kmem_free(ack_ie, sizeof (wusb_ie_connect_ack_t));
620 
621 		return (rval);
622 	}
623 
624 	rval = wusb_hc_add_mmc_ie(hc_data, 0, 3, iehdl,
625 	    ack_ie->bLength, (uint8_t *)ack_ie);
626 	if (rval != USB_SUCCESS) {
627 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
628 		    "wusb_hc_ack_conn: add connect ack ie fails");
629 		wusb_hc_free_iehdl(hc_data, iehdl);
630 		kmem_free(ack_ie, sizeof (wusb_ie_connect_ack_t));
631 
632 		return (rval);
633 	}
634 
635 	mutex_exit(&hc_data->hc_mutex);
636 	/*
637 	 * WUSB 1.0/7.5.1 requires at least 2ms delay between ConnectAck
638 	 * and WUSB transactions, wait for 2ms here
639 	 */
640 	delay(drv_usectohz(2000));
641 	mutex_enter(&hc_data->hc_mutex);
642 
643 	return (USB_SUCCESS);
644 }
645 
646 /* Remove Connect Acknowledge IE */
647 void
wusb_hc_rm_ack(wusb_hc_data_t * hc_data)648 wusb_hc_rm_ack(wusb_hc_data_t *hc_data)
649 {
650 	int	i;
651 	int16_t	iehdl = -1;
652 	wusb_ie_header_t *ieh;
653 
654 	for (i = 0; i < hc_data->hc_num_mmcies; i++) {
655 		ieh = hc_data->hc_mmcie_list[i];
656 		if ((ieh != NULL) &&
657 		    (ieh->bIEIdentifier == WUSB_IE_CONNECTACK)) {
658 			iehdl = (int16_t)i;
659 
660 			break;
661 		}
662 	}
663 
664 	if (iehdl == -1) {
665 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
666 		    "wusb_hc_rm_ack: ack iehdl not found");
667 
668 		return;
669 	}
670 
671 	/* remove mmc ie and free handle & memory */
672 	(void) wusb_hc_remove_mmc_ie(hc_data, (uint8_t)iehdl);
673 	wusb_hc_free_iehdl(hc_data, iehdl);
674 	kmem_free(ieh, sizeof (wusb_ie_connect_ack_t));
675 }
676 
677 /*
678  * Send a KeepAlive IE to the device. See WUSB 1.0 section 7.5.9
679  */
680 int
wusb_hc_send_keepalive_ie(wusb_hc_data_t * hc_data,uint8_t addr)681 wusb_hc_send_keepalive_ie(wusb_hc_data_t *hc_data, uint8_t addr)
682 {
683 	wusb_ie_keepalive_t	*alive_ie;
684 	uint8_t			iehdl;
685 	int			rval;
686 
687 	mutex_enter(&hc_data->hc_mutex);
688 	/*
689 	 * the scheme ensures each time only one device addr
690 	 * is set each time
691 	 */
692 	alive_ie = &hc_data->hc_alive_ie;
693 	alive_ie->bDeviceAddress[0] = addr;
694 	/* padding, no active wusb device addr will be 1 */
695 	alive_ie->bDeviceAddress[1] = 1;
696 	alive_ie->bLength = 4;
697 
698 	rval = wusb_hc_get_iehdl(hc_data, (wusb_ie_header_t *)alive_ie,
699 	    &iehdl);
700 	if (rval != USB_SUCCESS) {
701 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
702 		    "wusb_hc_send_keepalive_ie: get ie handle fails");
703 		mutex_exit(&hc_data->hc_mutex);
704 
705 		return (rval);
706 	}
707 
708 	USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
709 	    "wusb_hc_send_keepalive_ie: get ie handle = %d", iehdl);
710 	/*
711 	 * we must release the lock so that the DN notification
712 	 * thread can update the device active bit
713 	 */
714 	mutex_exit(&hc_data->hc_mutex);
715 
716 	rval = wusb_hc_add_mmc_ie(hc_data, 0, 0, iehdl,
717 	    alive_ie->bLength, (uint8_t *)alive_ie);
718 	if (rval != USB_SUCCESS) {
719 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
720 		    "wusb_hc_send_keepalive_ie: add keepalive ie fails");
721 
722 		/* no need to free the ack iehdl since it is reused */
723 		return (rval);
724 	}
725 
726 	/*
727 	 * wait 400ms for the device to reply a DN_Alive notification
728 	 */
729 	delay(drv_usectohz(400000));
730 
731 	/*
732 	 * cease transmitting the IE and release the IE handle,
733 	 * no matter we receive a response or not.
734 	 */
735 	mutex_enter(&hc_data->hc_mutex);
736 	(void) wusb_hc_remove_mmc_ie(hc_data, iehdl);
737 	wusb_hc_free_iehdl(hc_data, iehdl);
738 	mutex_exit(&hc_data->hc_mutex);
739 
740 	return (USB_SUCCESS);
741 }
742 
743 /*
744  * Check the hc_cc_list for matching CDID and return the pointer
745  * to the matched cc. Return NULL if no matching cc is found.
746  */
747 wusb_cc_t *
wusb_hc_cc_matched(wusb_hc_cc_list_t * cc_list,uint8_t * cdid)748 wusb_hc_cc_matched(wusb_hc_cc_list_t *cc_list, uint8_t *cdid)
749 {
750 	wusb_cc_t	*cc = NULL, *tcc;
751 
752 	while (cc_list != NULL) {
753 		tcc = &cc_list->cc;
754 		if (memcmp(tcc->CDID, cdid, 16) == 0) {
755 			cc = tcc;
756 
757 			break;
758 		}
759 		cc_list = cc_list->next;
760 	}
761 
762 	return (cc);
763 }
764 
765 /*
766  * ***************************************************************
767  * WUSB specific standard device requests, refer to WUSB 1.0/7.3.1
768  * ***************************************************************
769  */
770 /* Get WUSB device BOS descr and UWB capability descr */
771 int
wusb_get_dev_uwb_descr(wusb_hc_data_t * hc_data,usb_port_t port)772 wusb_get_dev_uwb_descr(wusb_hc_data_t *hc_data, usb_port_t port)
773 {
774 	dev_info_t		*child_dip;
775 	usba_device_t		*child_ud;
776 	wusb_dev_info_t		*dev_info;
777 	int			rval;
778 	uint8_t			*buf;
779 	size_t			size, buflen;
780 
781 	ASSERT(mutex_owned(&hc_data->hc_mutex));
782 
783 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
784 	    "wusb_get_dev_uwb_descr: port = %d", port);
785 
786 	dev_info = hc_data->hc_dev_infos[port];
787 	child_dip = hc_data->hc_children_dips[port];
788 	if (child_dip == NULL) {
789 
790 		return (USB_FAILURE);
791 	}
792 
793 	child_ud = usba_get_usba_device(child_dip);
794 	if (child_ud == NULL) {
795 
796 		return (USB_FAILURE);
797 	}
798 
799 	/* only get bos descr the first time */
800 	if (dev_info->wdev_uwb_descr == NULL) {
801 		mutex_exit(&hc_data->hc_mutex);
802 		rval = wusb_get_bos_cloud(child_dip, child_ud);
803 		if (rval != USB_SUCCESS) {
804 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
805 			    "wusb_get_dev_uwb_descr: failed to "
806 			    "get bos descriptor");
807 
808 			mutex_enter(&hc_data->hc_mutex);
809 
810 			return (rval);
811 		}
812 		mutex_enter(&hc_data->hc_mutex);
813 
814 		buf = child_ud->usb_wireless_data->wusb_bos;
815 		buflen = child_ud->usb_wireless_data->wusb_bos_length;
816 
817 		dev_info->wdev_uwb_descr = kmem_zalloc(
818 		    sizeof (usb_uwb_cap_descr_t), KM_SLEEP);
819 
820 		size = usb_parse_uwb_bos_descr(buf, buflen,
821 		    dev_info->wdev_uwb_descr, sizeof (usb_uwb_cap_descr_t));
822 
823 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
824 		    "wusb_get_dev_uwb_descr: parsed uwb descr size is %d",
825 		    (int)size);
826 		if (size < USB_UWB_CAP_DESCR_SIZE) {
827 			kmem_free(dev_info->wdev_uwb_descr,
828 			    sizeof (usb_uwb_cap_descr_t));
829 			dev_info->wdev_uwb_descr = NULL;
830 
831 			return (USB_FAILURE);
832 		}
833 
834 		/* store a parsed uwb descriptor */
835 		child_ud->usb_wireless_data->uwb_descr =
836 		    dev_info->wdev_uwb_descr;
837 	} else {
838 		USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
839 		    "wusb_get_dev_uwb_descr: already done");
840 	}
841 
842 	return (USB_SUCCESS);
843 }
844 
845 /* Get WUSB device BOS descr cloud, refer to WUSB 1.0/7.4.1 */
846 int
wusb_get_bos_cloud(dev_info_t * child_dip,usba_device_t * child_ud)847 wusb_get_bos_cloud(dev_info_t *child_dip, usba_device_t *child_ud)
848 {
849 	usb_bos_descr_t		*bos_descr;
850 	mblk_t			*pdata = NULL;
851 	int			rval;
852 	size_t			size;
853 	usb_cr_t		completion_reason;
854 	usb_cb_flags_t		cb_flags;
855 	usb_pipe_handle_t	def_ph;
856 	usba_wireless_data_t	*wireless_data;
857 
858 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
859 	    "wusb_get_bos_cloud: ");
860 
861 	bos_descr = (usb_bos_descr_t *)kmem_zalloc(sizeof (usb_bos_descr_t),
862 	    KM_SLEEP);
863 
864 	def_ph = usba_get_dflt_pipe_handle(child_dip);
865 
866 	if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, def_ph,
867 	    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
868 	    USB_REQ_GET_DESCR,
869 	    USB_DESCR_TYPE_BOS << 8,
870 	    0,
871 	    USB_BOS_DESCR_SIZE,
872 	    &pdata,
873 	    0,
874 	    &completion_reason,
875 	    &cb_flags,
876 	    0)) == USB_SUCCESS) {
877 
878 		/* this must be true since we didn't allow data underruns */
879 		if (MBLKL(pdata) != USB_BOS_DESCR_SIZE) {
880 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
881 			    "device returned incorrect bos "
882 			    "descriptor size.");
883 
884 			rval = USB_FAILURE;
885 			goto done;
886 		}
887 
888 		/*
889 		 * Parse the bos descriptor
890 		 */
891 		size = usb_parse_bos_descr(pdata->b_rptr,
892 		    MBLKL(pdata), bos_descr,
893 		    sizeof (usb_bos_descr_t));
894 
895 		/* if parse bos descr error, it should return failure */
896 		if (size == USB_PARSE_ERROR) {
897 
898 			if (pdata->b_rptr[1] != USB_DESCR_TYPE_BOS) {
899 				USB_DPRINTF_L2(DPRINT_MASK_WHCDI,
900 				    whcdi_log_handle,
901 				    "device returned incorrect "
902 				    "bos descriptor type.");
903 			}
904 			rval = USB_FAILURE;
905 			goto done;
906 		}
907 
908 		if (bos_descr->wTotalLength < USB_BOS_DESCR_SIZE) {
909 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
910 			    "device returned incorrect "
911 			    "bos descriptor size.");
912 
913 			rval = USB_FAILURE;
914 			goto done;
915 		}
916 
917 		freemsg(pdata);
918 		pdata = NULL;
919 
920 		/* Now fetch the complete bos cloud */
921 		if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, def_ph,
922 		    USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
923 		    USB_REQ_GET_DESCR,
924 		    USB_DESCR_TYPE_BOS << 8,
925 		    0,
926 		    bos_descr->wTotalLength,
927 		    &pdata,
928 		    0,
929 		    &completion_reason,
930 		    &cb_flags,
931 		    0)) == USB_SUCCESS) {
932 
933 			if (MBLKL(pdata) != bos_descr->wTotalLength) {
934 
935 				USB_DPRINTF_L2(DPRINT_MASK_WHCDI,
936 				    whcdi_log_handle,
937 				    "device returned incorrect "
938 				    "bos descriptor cloud.");
939 
940 				rval = USB_FAILURE;
941 				goto done;
942 			}
943 
944 			/*
945 			 * copy bos descriptor into usba_device
946 			 */
947 			mutex_enter(&child_ud->usb_mutex);
948 			wireless_data = child_ud->usb_wireless_data;
949 			wireless_data->wusb_bos =
950 			    kmem_zalloc(bos_descr->wTotalLength, KM_SLEEP);
951 			wireless_data->wusb_bos_length =
952 			    bos_descr->wTotalLength;
953 			bcopy((caddr_t)pdata->b_rptr,
954 			    (caddr_t)wireless_data->wusb_bos,
955 			    bos_descr->wTotalLength);
956 			USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
957 			    "bos_length = %d",
958 			    wireless_data->wusb_bos_length);
959 			mutex_exit(&child_ud->usb_mutex);
960 		}
961 	}
962 
963 done:
964 	if (rval != USB_SUCCESS) {
965 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
966 		    "wusb_get_bos_cloud: "
967 		    "error in retrieving bos descriptor, rval=%d cr=%d",
968 		    rval, completion_reason);
969 	}
970 
971 	if (pdata) {
972 		freemsg(pdata);
973 		pdata = NULL;
974 	}
975 
976 	kmem_free(bos_descr, sizeof (usb_bos_descr_t));
977 
978 	return (rval);
979 }
980 
981 /* Get WUSB device security descriptors, refer to WUSB 1.0/7.4.5 */
982 int
wusb_get_dev_security_descr(usb_pipe_handle_t ph,wusb_secrt_data_t * secrt_data)983 wusb_get_dev_security_descr(usb_pipe_handle_t ph,
984 	wusb_secrt_data_t *secrt_data)
985 {
986 	usb_ctrl_setup_t	setup;
987 	mblk_t			*pdata = NULL;
988 	usb_cr_t		cr;
989 	usb_cb_flags_t		cb_flags;
990 	int			i, rval;
991 	size_t			size, len;
992 	uint8_t			*p;
993 
994 	setup.bmRequestType = USB_DEV_REQ_DEV_TO_HOST;
995 	setup.bRequest = USB_REQ_GET_DESCR;
996 	setup.wValue = USB_DESCR_TYPE_SECURITY << 8;
997 	setup.wIndex = 0;
998 	setup.wLength = USB_SECURITY_DESCR_SIZE;
999 	setup.attrs = USB_ATTRS_NONE;
1000 
1001 	rval = usb_pipe_ctrl_xfer_wait(ph, &setup, &pdata, &cr, &cb_flags,
1002 	    USB_FLAGS_SLEEP);
1003 	if (rval != USB_SUCCESS) {
1004 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1005 		    "wusb_get_dev_security_descr "
1006 		    "failed, rval = %d, cr = %d", rval, cr);
1007 
1008 		return (rval);
1009 	}
1010 
1011 	if (MBLKL(pdata) != USB_SECURITY_DESCR_SIZE) {
1012 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1013 		    "received incorrect security descriptor size");
1014 		rval = USB_FAILURE;
1015 
1016 		goto done;
1017 	}
1018 
1019 	/* Parse the security descriptor */
1020 	size = usb_parse_data("ccsc", pdata->b_rptr,
1021 	    MBLKL(pdata), &secrt_data->secrt_descr,
1022 	    sizeof (usb_security_descr_t));
1023 
1024 	/* check if the parsed descr is good */
1025 	if (size < USB_SECURITY_DESCR_SIZE) {
1026 		rval = USB_FAILURE;
1027 
1028 		goto done;
1029 	}
1030 
1031 	if (secrt_data->secrt_descr.wTotalLength < USB_SECURITY_DESCR_SIZE) {
1032 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1033 		    "device returned incorrect security descriptor size");
1034 		rval = USB_FAILURE;
1035 
1036 		goto done;
1037 	}
1038 
1039 	freemsg(pdata);
1040 	pdata = NULL;
1041 
1042 	secrt_data->secrt_n_encry =
1043 	    secrt_data->secrt_descr.bNumEncryptionTypes;
1044 	len = sizeof (usb_encryption_descr_t) * secrt_data->secrt_n_encry;
1045 	secrt_data->secrt_encry_descr =
1046 	    (usb_encryption_descr_t *)kmem_zalloc(len, KM_SLEEP);
1047 
1048 	/* Now fetch the complete security descr cloud */
1049 	setup.wLength = secrt_data->secrt_descr.wTotalLength;
1050 	rval = usb_pipe_ctrl_xfer_wait(ph, &setup, &pdata, &cr, &cb_flags,
1051 	    USB_FLAGS_SLEEP);
1052 	if (rval != USB_SUCCESS) {
1053 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1054 		    "wusb_get_dev_security_descr "
1055 		    "for total cloud failed, rval = %d, cr = %d", rval, cr);
1056 
1057 		goto done;
1058 	}
1059 
1060 	if (MBLKL(pdata) != secrt_data->secrt_descr.wTotalLength) {
1061 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1062 		    "received incorrect security descriptor cloud size");
1063 		rval = USB_FAILURE;
1064 
1065 		goto done;
1066 	}
1067 
1068 	p = pdata->b_rptr + USB_SECURITY_DESCR_SIZE;
1069 	for (i = 0; i < secrt_data->secrt_n_encry; i++) {
1070 		size = usb_parse_data("ccccc", p, _PTRDIFF(pdata->b_wptr, p),
1071 		    &secrt_data->secrt_encry_descr[i],
1072 		    sizeof (usb_encryption_descr_t));
1073 		if (size < USB_ENCRYPTION_DESCR_SIZE) {
1074 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1075 			    "parse %dth encryption descr failed", i);
1076 			rval = USB_FAILURE;
1077 
1078 			goto done;
1079 		}
1080 		p += USB_ENCRYPTION_DESCR_SIZE;
1081 	}
1082 
1083 done:
1084 	if (rval != USB_SUCCESS) {
1085 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1086 		    "wusb_get_dev_security_descr: "
1087 		    "error in retrieving security descriptors");
1088 		if (secrt_data->secrt_encry_descr) {
1089 			kmem_free(secrt_data->secrt_encry_descr, len);
1090 			secrt_data->secrt_encry_descr = NULL;
1091 		}
1092 	}
1093 
1094 	if (pdata) {
1095 		freemsg(pdata);
1096 		pdata = NULL;
1097 	}
1098 
1099 	return (rval);
1100 }
1101 
1102 /* Get WUSB device status, refer to WUSB 1.0/7.3.1.2 */
1103 int
wusb_get_dev_status(usb_pipe_handle_t ph,uint16_t selector,uint16_t len,uint8_t * status)1104 wusb_get_dev_status(usb_pipe_handle_t ph, uint16_t selector,
1105 	uint16_t len, uint8_t *status)
1106 {
1107 	usb_ctrl_setup_t	setup;
1108 	mblk_t			*pdata = NULL;
1109 	usb_cr_t		cr;
1110 	usb_cb_flags_t		cb_flags;
1111 	int			rval;
1112 
1113 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1114 	    "wusb_get_dev_status: selector = %d, len = %d", selector, len);
1115 
1116 	setup.bmRequestType = USB_DEV_REQ_DEV_TO_HOST;
1117 	setup.bRequest = USB_REQ_GET_STATUS;
1118 	setup.wValue = 0;
1119 	setup.wIndex = selector;
1120 	setup.wLength = len;
1121 	setup.attrs = USB_ATTRS_NONE;
1122 
1123 	rval = usb_pipe_ctrl_xfer_wait(ph, &setup, &pdata, &cr, &cb_flags,
1124 	    USB_FLAGS_SLEEP);
1125 	if (rval != USB_SUCCESS) {
1126 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1127 		    "wusb_get_dev_status failed, rval = %d, cr = %d", rval, cr);
1128 
1129 		return (rval);
1130 	}
1131 	if (pdata == NULL) {
1132 		return (USB_FAILURE);
1133 	}
1134 	if (MBLKL(pdata) != len) {
1135 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1136 		    "received incorrect dev status size");
1137 		freemsg(pdata);
1138 
1139 		return (USB_FAILURE);
1140 	}
1141 
1142 	bcopy(pdata->b_rptr, status, len);
1143 	freemsg(pdata);
1144 
1145 	if ((selector == WUSB_STS_TYPE_MAS_AVAIL) &&
1146 	    (len == WUSB_SET_WUSB_MAS_LEN)) {
1147 		uint8_t	*p = status;
1148 
1149 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1150 		    "mas_avail: %x %x %x %x %x %x %x %x %x %x %x %x "
1151 		    "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x "
1152 		    "%x %x %x %x", p[0], p[1], p[2], p[3], p[4], p[5], p[6],
1153 		    p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15],
1154 		    p[16], p[17], p[18], p[19], p[20], p[21], p[22], p[23],
1155 		    p[24], p[25], p[26], p[27], p[28], p[29], p[30], p[31]);
1156 	}
1157 
1158 	return (USB_SUCCESS);
1159 }
1160 
1161 /* test function, can be removed */
1162 void
wusb_test_ctrlreq(usb_pipe_handle_t ph)1163 wusb_test_ctrlreq(usb_pipe_handle_t ph)
1164 {
1165 	int	i, rval;
1166 	uint8_t	mas[WUSB_SET_WUSB_MAS_LEN];
1167 
1168 	for (i = 0; i < 10; i++) {
1169 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1170 		    "wusb_test_ctrlreq %d started:", i);
1171 		rval = wusb_get_dev_status(ph,
1172 		    WUSB_STS_TYPE_MAS_AVAIL, WUSB_SET_WUSB_MAS_LEN, mas);
1173 		if (rval != USB_SUCCESS) {
1174 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1175 			    "get mas availability status %d failed, "
1176 			    "rval = %d", i, rval);
1177 
1178 			continue;
1179 		}
1180 	}
1181 }
1182 
1183 /* test function, can be removed */
1184 void
wusb_test_loopback(usb_pipe_handle_t ph)1185 wusb_test_loopback(usb_pipe_handle_t ph)
1186 {
1187 	usb_ctrl_setup_t	setup;
1188 	mblk_t			*pdata;
1189 	usb_cr_t		cr;
1190 	usb_cb_flags_t		cb_flags;
1191 	int			i, j, rval;
1192 	uint16_t		len = 20;
1193 
1194 	for (j = 0; j < 10; j++) {
1195 		pdata = allocb_wait(len, BPRI_LO, STR_NOSIG, NULL);
1196 		for (i = 0; i < len; i++) {
1197 			*pdata->b_wptr++ = (uint8_t)j;
1198 		}
1199 
1200 		setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV;
1201 		setup.bRequest = USB_REQ_LOOPBACK_DATA_WRITE;
1202 		setup.wValue = 0;
1203 		setup.wIndex = 0;
1204 		setup.wLength = len;
1205 		setup.attrs = USB_ATTRS_NONE;
1206 
1207 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1208 		    "wusb_test_loopback_write %d start:", j);
1209 
1210 		rval = usb_pipe_ctrl_xfer_wait(ph, &setup, &pdata, &cr,
1211 		    &cb_flags, USB_FLAGS_SLEEP);
1212 		if (rval != USB_SUCCESS) {
1213 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1214 			    "wusb_test_loopback_write %d failed, "
1215 			    "rval = %d, cr = %d", j, rval, cr);
1216 			freemsg(pdata);
1217 
1218 			return;
1219 		}
1220 
1221 		freemsg(pdata);
1222 		pdata = NULL;
1223 	}
1224 }
1225 
1226 /* test function, can be removed */
1227 void
wusb_test_write(wusb_dev_info_t * dev_info)1228 wusb_test_write(wusb_dev_info_t *dev_info)
1229 {
1230 	int16_t		value;
1231 	int		i, rval;
1232 	usb_pipe_handle_t dev_ph;
1233 
1234 	value = wusb_get_ccm_encryption_value(&dev_info->wdev_secrt_data);
1235 	if (value == -1) {
1236 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1237 		    "wusb_test_write: cannot find ccm encryption type");
1238 
1239 		return;
1240 	}
1241 	/* failed at 2nd write */
1242 	for (i = 0; i < 1; i++) {
1243 		USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1244 		    "wusb_test_write %d start:", i);
1245 		mutex_enter(&dev_info->wdev_hc->hc_mutex);
1246 		dev_ph = dev_info->wdev_ph;
1247 		mutex_exit(&dev_info->wdev_hc->hc_mutex);
1248 
1249 		rval = wusb_dev_set_encrypt(dev_ph, (uint8_t)value);
1250 		if (rval != USB_SUCCESS) {
1251 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1252 			    "wusb_test_write: %dth set encryption failed", i);
1253 
1254 			continue;
1255 		}
1256 	}
1257 }
1258 
1259 
1260 /* enable CCM encryption on the device */
1261 int
wusb_enable_dev_encrypt(wusb_hc_data_t * hc_data,wusb_dev_info_t * dev_info)1262 wusb_enable_dev_encrypt(wusb_hc_data_t *hc_data, wusb_dev_info_t *dev_info)
1263 {
1264 	int16_t		value;
1265 	int		rval;
1266 	usb_pipe_handle_t ph;
1267 
1268 	USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
1269 	    "wusb_enable_dev_encrypt:enter");
1270 
1271 	value = wusb_get_ccm_encryption_value(&dev_info->wdev_secrt_data);
1272 	if (value == -1) {
1273 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1274 		    "wusb_enable_dev_encrypt: cannot find ccm encryption type");
1275 
1276 		return (USB_FAILURE);
1277 	}
1278 
1279 	mutex_enter(&hc_data->hc_mutex);
1280 	ph = dev_info->wdev_ph;
1281 	mutex_exit(&hc_data->hc_mutex);
1282 
1283 	rval = wusb_dev_set_encrypt(ph, (uint8_t)value);
1284 	if (rval != USB_SUCCESS) {
1285 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1286 		    "wusb_enable_dev_encrypt: set encryption failed");
1287 	}
1288 	USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
1289 	    "wusb_enable_dev_encrypti:exit");
1290 
1291 	return (rval);
1292 }
1293 
1294 /*
1295  * Perform the authentication process, refer to WUSB 1.0/7.1.2.
1296  * host secrt_data will be used for 4-way handshake
1297  */
1298 /* ARGSUSED */
1299 int
wusb_hc_auth_dev(wusb_hc_data_t * hc_data,usb_port_t port,usb_pipe_handle_t ph,uint8_t ifc,wusb_secrt_data_t * secrt_data)1300 wusb_hc_auth_dev(wusb_hc_data_t *hc_data, usb_port_t port,
1301 	usb_pipe_handle_t ph, uint8_t ifc,
1302 	wusb_secrt_data_t *secrt_data)
1303 {
1304 	wusb_dev_info_t		*dev_info;
1305 	usb_pipe_handle_t	child_ph;
1306 	dev_info_t		*child_dip;
1307 
1308 	ASSERT(mutex_owned(&hc_data->hc_mutex));
1309 
1310 	dev_info = hc_data->hc_dev_infos[port];
1311 	USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1312 	    "wusb_hc_auth_dev: dev addr =  %d",  dev_info->wdev_addr);
1313 	if (dev_info == NULL) {
1314 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1315 		    "wusb_hc_auth_dev: port %d invalid", port);
1316 
1317 		return (USB_INVALID_ARGS);
1318 	}
1319 	child_ph = dev_info->wdev_ph;
1320 	child_dip = hc_data->hc_children_dips[port];
1321 
1322 	mutex_exit(&hc_data->hc_mutex);
1323 	/* get device security descrs */
1324 	if (wusb_get_dev_security_descr(child_ph,
1325 	    &dev_info->wdev_secrt_data) != USB_SUCCESS) {
1326 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1327 		    "wusb_hc_auth_dev: failed to get device security descrs");
1328 		mutex_enter(&hc_data->hc_mutex);
1329 
1330 		return (USB_FAILURE);
1331 	}
1332 
1333 	/*
1334 	 * enable CCM encryption on the device, this needs to be done
1335 	 * before 4-way handshake. [WUSB 1.0/7.3.2.5]
1336 	 */
1337 	if (wusb_enable_dev_encrypt(hc_data, dev_info) != USB_SUCCESS) {
1338 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1339 		    "wusb_hc_auth_dev: set encryption failed");
1340 
1341 		mutex_enter(&hc_data->hc_mutex);
1342 		return (USB_FAILURE);
1343 	}
1344 
1345 
1346 	/* this seems to relieve the non-response issue somehow */
1347 	usb_pipe_close(child_dip, child_ph,
1348 	    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
1349 
1350 	mutex_enter(&hc_data->hc_mutex);
1351 	dev_info->wdev_ph = NULL;
1352 
1353 	/* unauthenticated state */
1354 	/* check cc_list for existing cc with the same CDID */
1355 	if ((dev_info->wdev_cc = wusb_hc_cc_matched(hc_data->hc_cc_list,
1356 	    dev_info->wdev_cdid)) == NULL) {
1357 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1358 		    "wusb_hc_auth_dev: no matching cc found");
1359 
1360 		if (dev_info->wdev_is_newconn == 0) {
1361 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1362 			    "wusb_hc_auth_dev: not new connection, "
1363 			    "just fail");
1364 
1365 			return (USB_FAILURE);
1366 		}
1367 
1368 		/* now we simply return not supported */
1369 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1370 		    "wusb_hc_auth_dev: numeric association not supported");
1371 
1372 		return (USB_NOT_SUPPORTED);
1373 	}
1374 
1375 	USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
1376 	    "wusb_hc_auth_dev: matching cc found 0x%p",
1377 	    (void *)dev_info->wdev_cc);
1378 
1379 	mutex_exit(&hc_data->hc_mutex);
1380 	if (usb_pipe_open(child_dip, NULL, NULL,
1381 	    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &child_ph) !=
1382 	    USB_SUCCESS) {
1383 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1384 		    "usb_pipe_open failed");
1385 
1386 		mutex_enter(&hc_data->hc_mutex);
1387 
1388 		return (USB_FAILURE);
1389 	}
1390 
1391 	mutex_enter(&hc_data->hc_mutex);
1392 	/* recording the default pipe */
1393 	dev_info->wdev_ph = child_ph;
1394 
1395 	mutex_exit(&hc_data->hc_mutex);
1396 	/* perform 4-way handshake */
1397 	if (wusb_4way_handshake(hc_data, port, ph, ifc) != 0) {
1398 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1399 		    "port(%d) 4-way handshake authentication failed!",
1400 		    port);
1401 
1402 		/* perhaps resetting the device is better */
1403 		usb_pipe_reset(child_dip, child_ph,
1404 		    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
1405 		    NULL, NULL);
1406 		(void) wusb_dev_set_encrypt(child_ph, 0);
1407 
1408 		mutex_enter(&hc_data->hc_mutex);
1409 
1410 		return (USB_FAILURE);
1411 	}
1412 
1413 	mutex_enter(&hc_data->hc_mutex);
1414 
1415 	return (USB_SUCCESS);
1416 }
1417 
1418 /* Acknowledge WUSB Device Disconnect notification, refer to WUSB 1.0/7.6.2 */
1419 int
wusb_hc_ack_disconn(wusb_hc_data_t * hc_data,uint8_t addr)1420 wusb_hc_ack_disconn(wusb_hc_data_t *hc_data, uint8_t addr)
1421 {
1422 	wusb_ie_dev_disconnect_t	*disconn_ie;
1423 	uint8_t				iehdl;
1424 	int				rval;
1425 
1426 	ASSERT(mutex_owned(&hc_data->hc_mutex));
1427 
1428 	/*
1429 	 * the scheme ensures each time only one device addr
1430 	 * is set each time
1431 	 */
1432 	disconn_ie = kmem_zalloc(sizeof (wusb_ie_dev_disconnect_t), KM_SLEEP);
1433 	if (!disconn_ie) {
1434 		return (USB_NO_RESOURCES);
1435 	}
1436 
1437 	disconn_ie->bIEIdentifier = WUSB_IE_DEV_DISCONNECT;
1438 	disconn_ie->bDeviceAddress[0] = addr;
1439 	/* padding, no active wusb device addr will be 1 */
1440 	disconn_ie->bDeviceAddress[1] = 1;
1441 	disconn_ie->bLength = 4;
1442 
1443 	rval = wusb_hc_get_iehdl(hc_data, (wusb_ie_header_t *)disconn_ie,
1444 	    &iehdl);
1445 	if (rval != USB_SUCCESS) {
1446 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1447 		    "wusb_hc_ack_disconn: get ie handle fails");
1448 		kmem_free(disconn_ie, sizeof (wusb_ie_dev_disconnect_t));
1449 
1450 		return (rval);
1451 	}
1452 
1453 	rval = wusb_hc_add_mmc_ie(hc_data, 0, 0, iehdl,
1454 	    disconn_ie->bLength, (uint8_t *)disconn_ie);
1455 	if (rval != USB_SUCCESS) {
1456 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1457 		    "wusb_hc_ack_disconn: add dev disconnect ie fails");
1458 		wusb_hc_free_iehdl(hc_data, iehdl);
1459 		kmem_free(disconn_ie, sizeof (wusb_ie_dev_disconnect_t));
1460 
1461 		return (rval);
1462 	}
1463 
1464 	mutex_exit(&hc_data->hc_mutex);
1465 	/*
1466 	 * WUSB 1.0/7.5.4 requires the IE to be transmitted at least
1467 	 * 100ms before ceasing, wait for 150ms here
1468 	 */
1469 	delay(drv_usectohz(150000));
1470 	mutex_enter(&hc_data->hc_mutex);
1471 
1472 	/* cease transmitting the IE */
1473 	(void) wusb_hc_remove_mmc_ie(hc_data, (uint8_t)iehdl);
1474 	wusb_hc_free_iehdl(hc_data, iehdl);
1475 	kmem_free(disconn_ie, sizeof (wusb_ie_dev_disconnect_t));
1476 
1477 	return (USB_SUCCESS);
1478 }
1479 
1480 /* create child devinfo node and usba_device structure */
1481 int
wusb_create_child_devi(dev_info_t * dip,char * node_name,usba_hcdi_ops_t * usba_hcdi_ops,dev_info_t * usb_root_hub_dip,usb_port_status_t port_status,usba_device_t * usba_device,dev_info_t ** child_dip)1482 wusb_create_child_devi(dev_info_t *dip, char *node_name,
1483 	usba_hcdi_ops_t *usba_hcdi_ops, dev_info_t *usb_root_hub_dip,
1484 	usb_port_status_t port_status, usba_device_t *usba_device,
1485 	dev_info_t **child_dip)
1486 {
1487 	ndi_devi_alloc_sleep(dip, node_name, (pnode_t)DEVI_SID_NODEID,
1488 	    child_dip);
1489 
1490 	usba_device = usba_alloc_usba_device(usb_root_hub_dip);
1491 
1492 	/* grab the mutex to keep warlock happy */
1493 	mutex_enter(&usba_device->usb_mutex);
1494 	usba_device->usb_hcdi_ops = usba_hcdi_ops;
1495 	usba_device->usb_port_status = port_status;
1496 	usba_device->usb_is_wireless = B_TRUE;
1497 	mutex_exit(&usba_device->usb_mutex);
1498 
1499 	/* store the usba_device point in the dip */
1500 	usba_set_usba_device(*child_dip, usba_device);
1501 
1502 	return (USB_SUCCESS);
1503 }
1504 
1505 /*
1506  * Handle WUSB child device connection, including creating child devinfo
1507  * and usba strutures, authentication, configuration and attach.
1508  */
1509 int
wusb_hc_handle_port_connect(wusb_hc_data_t * hc_data,usb_port_t port,usb_pipe_handle_t ph,uint8_t ifc,wusb_secrt_data_t * secrt_data)1510 wusb_hc_handle_port_connect(wusb_hc_data_t *hc_data, usb_port_t port,
1511 	usb_pipe_handle_t ph, uint8_t ifc, wusb_secrt_data_t *secrt_data)
1512 {
1513 	dev_info_t	*dip = hc_data->hc_dip;
1514 	dev_info_t	*child_dip = NULL;
1515 	usba_device_t	*child_ud = NULL;
1516 	usba_device_t	*parent_ud;
1517 	usba_hcdi_t	*hcdi = usba_hcdi_get_hcdi(dip);
1518 	usb_pipe_handle_t child_ph = NULL;
1519 	int		rval;
1520 	int		child_created = 0;
1521 	wusb_dev_info_t	*dev_info;
1522 	usb_dev_descr_t	usb_dev_descr;
1523 	int		ackie_removed = 0;
1524 
1525 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1526 	    "wusb_hc_handle_port_connect: hc_data=0x%p, port=%d",
1527 	    (void *)hc_data, port);
1528 
1529 	ASSERT(mutex_owned(&hc_data->hc_mutex));
1530 	dev_info = hc_data->hc_dev_infos[port];
1531 	if (dev_info == NULL) {
1532 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1533 		    "wusb_hc_handle_port_connect: port %d invalid", port);
1534 		wusb_hc_rm_ack(hc_data);
1535 
1536 		return (USB_INVALID_ARGS);
1537 	}
1538 
1539 	dev_info->wdev_hc = hc_data;
1540 
1541 	/* prepare child devinfo and usba structures */
1542 	if (hc_data->hc_children_dips[port]) {
1543 		child_dip = hc_data->hc_children_dips[port];
1544 		child_ud = hc_data->hc_usba_devices[port];
1545 		child_ph = usba_get_dflt_pipe_handle(child_dip);
1546 		mutex_exit(&hc_data->hc_mutex);
1547 		usb_pipe_close(child_dip, child_ph,
1548 		    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
1549 		mutex_enter(&hc_data->hc_mutex);
1550 	} else {
1551 		rval = wusb_create_child_devi(dip,
1552 		    "device",
1553 		    hcdi->hcdi_ops,
1554 		    dip,
1555 		    USBA_HIGH_SPEED_DEV,
1556 		    child_ud,
1557 		    &child_dip);
1558 		if (rval != USB_SUCCESS) {
1559 			wusb_hc_rm_ack(hc_data); // , ph, ifc);
1560 
1561 			return (rval);
1562 		}
1563 		child_ud = usba_get_usba_device(child_dip);
1564 		ASSERT(child_ud != NULL);
1565 
1566 		mutex_enter(&child_ud->usb_mutex);
1567 		child_ud->usb_dev_descr = kmem_zalloc(sizeof (usb_dev_descr_t),
1568 		    KM_SLEEP);
1569 		child_ud->usb_wireless_data =
1570 		    kmem_zalloc(sizeof (usba_wireless_data_t), KM_SLEEP);
1571 		mutex_exit(&child_ud->usb_mutex);
1572 		child_created = 1;
1573 		hc_data->hc_children_dips[port] = child_dip;
1574 		hc_data->hc_usba_devices[port] = child_ud;
1575 	}
1576 
1577 	/* do necessary setup */
1578 	parent_ud = usba_get_usba_device(dip);
1579 	mutex_enter(&child_ud->usb_mutex);
1580 	child_ud->usb_addr = dev_info->wdev_addr;
1581 	child_ud->usb_port = port;
1582 
1583 	/*
1584 	 * TODO: now only consider the situation that HWA is high
1585 	 * speed dev for the children. The situation that HWA is
1586 	 * connected to the USB 1.1 port is not considered. The
1587 	 * available HWA devices can't work behind USB1.1 port.
1588 	 */
1589 	child_ud->usb_hs_hub_usba_dev = parent_ud;
1590 	child_ud->usb_hs_hub_addr = parent_ud->usb_addr;
1591 	child_ud->usb_hs_hub_port = port;
1592 	bzero(&usb_dev_descr, sizeof (usb_dev_descr_t));
1593 
1594 	/*
1595 	 * 255 for WUSB devices, refer to WUSB 1.0/4.8.1.
1596 	 * default ctrl pipe will ignore this value
1597 	 */
1598 	usb_dev_descr.bMaxPacketSize0 = 255;
1599 	bcopy(&usb_dev_descr, child_ud->usb_dev_descr,
1600 	    sizeof (usb_dev_descr_t));
1601 	mutex_exit(&child_ud->usb_mutex);
1602 
1603 	dev_info->wdev_ph = NULL;
1604 
1605 	/*
1606 	 * set device info and encryption mode for the host so that
1607 	 * open child pipe can work later
1608 	 */
1609 	rval = wusb_hc_set_device_info(hc_data, port);
1610 	if (rval != USB_SUCCESS) {
1611 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1612 		    "wusb_hc_handle_port_connect: set device info for"
1613 		    " host failed, rval = %d", rval);
1614 
1615 		goto error;
1616 	}
1617 
1618 	/* set the host to unsecure mode before authentication starts */
1619 	rval = wusb_hc_set_encrypt(hc_data, port, WUSB_ENCRYP_TYPE_UNSECURE);
1620 	if (rval != USB_SUCCESS) {
1621 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1622 		    "wusb_hc_handle_port_connect:set unsecure encryption"
1623 		    " for host failed, rval = %d", rval);
1624 
1625 		goto error;
1626 	}
1627 
1628 	/*
1629 	 * Open the default pipe for the child device
1630 	 * the MaxPacketSize for the default ctrl pipe is
1631 	 * set in usba_init_pipe_handle().
1632 	 */
1633 	mutex_exit(&hc_data->hc_mutex);
1634 	if ((rval = usb_pipe_open(child_dip, NULL, NULL,
1635 	    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &child_ph)) !=
1636 	    USB_SUCCESS) {
1637 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1638 		    "wusb_hc_handle_port_connect:open default pipe failed (%d)",
1639 		    rval);
1640 		mutex_enter(&hc_data->hc_mutex);
1641 
1642 		goto error;
1643 	}
1644 	mutex_enter(&hc_data->hc_mutex);
1645 
1646 	/* recording the default pipe */
1647 	dev_info->wdev_ph = child_ph;
1648 
1649 	/* verify the default child pipe works */
1650 	if (wusb_get_dev_uwb_descr(hc_data, port) != USB_SUCCESS) {
1651 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1652 		    "wusb_hc_handle_port_connect: failed to get"
1653 		    " device uwb descr");
1654 
1655 		goto error;
1656 	}
1657 
1658 	/* remove connect acknowledge IE */
1659 	wusb_hc_rm_ack(hc_data);
1660 	ackie_removed = 1;
1661 
1662 	/* do authentication */
1663 	if (wusb_hc_auth_dev(hc_data, port, ph, ifc, secrt_data) !=
1664 	    USB_SUCCESS) {
1665 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1666 		    "wusb_hc_handle_port_connect: "
1667 		    "device authentication fails");
1668 
1669 		goto error;
1670 	}
1671 
1672 	/* online child */
1673 	if (dev_info->wdev_state == WUSB_STATE_RECONNTING) {
1674 		dev_info->wdev_state = WUSB_STATE_CONFIGURED;
1675 		/* post reconnect event to child */
1676 		wusb_hc_reconnect_dev(hc_data, port);
1677 	} else {
1678 		if (wusb_hc_create_child(hc_data, port) != USB_SUCCESS) {
1679 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1680 			    "wusb_hc_handle_port_connect: create child fails");
1681 
1682 			goto error;
1683 		}
1684 		dev_info->wdev_state = WUSB_STATE_CONFIGURED;
1685 	}
1686 
1687 	return (USB_SUCCESS);
1688 
1689 error:
1690 	if (dev_info->wdev_ph != NULL) {
1691 		mutex_exit(&hc_data->hc_mutex);
1692 		usb_pipe_close(child_dip, child_ph,
1693 		    USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
1694 		mutex_enter(&hc_data->hc_mutex);
1695 
1696 		dev_info->wdev_ph = NULL;
1697 	}
1698 
1699 	if (child_created) {
1700 
1701 		rval = usba_destroy_child_devi(child_dip,
1702 		    NDI_DEVI_REMOVE);
1703 
1704 		if (rval != USB_SUCCESS) {
1705 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1706 			    "wusb_hc_handle_port_connect: "
1707 			    "failure to remove child node");
1708 		}
1709 
1710 		mutex_exit(&hc_data->hc_mutex);
1711 		usba_free_usba_device(child_ud);
1712 		mutex_enter(&hc_data->hc_mutex);
1713 
1714 		hc_data->hc_children_dips[port] = NULL;
1715 		hc_data->hc_usba_devices[port] = NULL;
1716 	}
1717 
1718 	if (ackie_removed == 0) {
1719 		wusb_hc_rm_ack(hc_data);
1720 	}
1721 
1722 	return (USB_FAILURE);
1723 }
1724 
1725 /*
1726  * Handle device connect notification: assign port number, acknowledge
1727  * device connection, and online child
1728  * Refer to WUSB 1.0 4.13, 6.10, 7.1 for connection process handling
1729  * and device state diagram
1730  */
1731 void
wusb_hc_handle_dn_connect(wusb_hc_data_t * hc_data,usb_pipe_handle_t ph,uint8_t ifc,uint8_t * data,size_t len,wusb_secrt_data_t * secrt_data)1732 wusb_hc_handle_dn_connect(wusb_hc_data_t *hc_data, usb_pipe_handle_t ph,
1733 	uint8_t ifc, uint8_t *data, size_t len,
1734 	wusb_secrt_data_t *secrt_data)
1735 {
1736 	wusb_dn_connect_t	*dn_con;
1737 	uint8_t			addr;
1738 	wusb_dev_info_t		*dev_info = NULL;
1739 	usb_port_t		port = 0;
1740 	uint_t			new_alloc = 0;
1741 	wusb_secrt_data_t	*csecrt_data;
1742 
1743 	if (len < WUSB_DN_CONN_PKT_LEN) {
1744 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1745 		    "wusb_hc_handle_dn_connect: short pkt len %d", (int)len);
1746 
1747 		return;
1748 	}
1749 
1750 	dn_con = (wusb_dn_connect_t *)data;
1751 	ASSERT(dn_con->bType == WUSB_DN_CONNECT);
1752 	addr = dn_con->bmConnAttributes[0];
1753 
1754 	mutex_enter(&hc_data->hc_mutex);
1755 
1756 	/*
1757 	 * check if the device requesting to connect was ever connected
1758 	 * and decide connect request type
1759 	 */
1760 	if (wusb_hc_is_dev_connected(hc_data, dn_con->CDID, &port) == 0) {
1761 		/*
1762 		 * the device with the CDID was not connected.
1763 		 * It should be a connect or new connect request
1764 		 */
1765 		if (addr) {
1766 			/*
1767 			 * the device may have been disconnected by the host
1768 			 * the host expects to see a connect request instead
1769 			 * of a reconnect request. The reconnect request is
1770 			 * ignored.
1771 			 */
1772 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1773 			    "wusb_hc_handle_dn_connect: device has "
1774 			    "disconnected, need to connect again");
1775 			mutex_exit(&hc_data->hc_mutex);
1776 
1777 			return;
1778 		}
1779 
1780 		/* assign port number */
1781 		port = wusb_hc_get_free_port(hc_data);
1782 		if (port == 0) {
1783 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1784 			    "wusb_hc_handle_dn_connect: cannot find "
1785 			    "a free port for the device connecting");
1786 			mutex_exit(&hc_data->hc_mutex);
1787 
1788 			return;
1789 		}
1790 
1791 		/* initialize dev_info structure */
1792 		dev_info = kmem_zalloc(sizeof (wusb_dev_info_t), KM_SLEEP);
1793 		/* unconnected dev addr is 0xff, refer to WUSB 1.0/7.6.1 */
1794 		dev_info->wdev_addr = 0xff;
1795 		(void) memcpy(dev_info->wdev_cdid, dn_con->CDID, 16);
1796 		dev_info->wdev_state = WUSB_STATE_CONNTING;
1797 		hc_data->hc_dev_infos[port] = dev_info;
1798 		new_alloc = 1;
1799 	} else {
1800 		/*
1801 		 * the device with the CDID was found connected.
1802 		 * It should be a reconnect or connect request.
1803 		 */
1804 		dev_info = hc_data->hc_dev_infos[port];
1805 		if ((addr != 0) && (addr == dev_info->wdev_addr)) {
1806 			dev_info->wdev_state = WUSB_STATE_RECONNTING;
1807 		} else if (addr == 0) {
1808 			dev_info->wdev_state = WUSB_STATE_CONNTING;
1809 			dev_info->wdev_addr = 0xff;
1810 		} else {
1811 			USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1812 			    "wusb_hc_handle_dn_connect: reconnecting, but "
1813 			    "device addr doesn't match");
1814 			mutex_exit(&hc_data->hc_mutex);
1815 
1816 			return;
1817 		}
1818 
1819 		/*
1820 		 * post removal event to child device before
1821 		 * reconnecting it
1822 		 */
1823 		wusb_hc_disconnect_dev(hc_data, port);
1824 	}
1825 
1826 	dev_info->wdev_beacon_attr = dn_con->bmConnAttributes[1] &
1827 	    WUSB_DN_CONN_BEACON_MASK;
1828 
1829 	/* refer to WUSB 1.0/7.6.1/4.13 for how New Connection bit works */
1830 	if (addr == 0) {
1831 		dev_info->wdev_is_newconn = dn_con->bmConnAttributes[1] &
1832 		    WUSB_DN_CONN_NEW;
1833 	} else {
1834 		dev_info->wdev_is_newconn = 0;
1835 	}
1836 
1837 	/*
1838 	 * state=connting means new dev addr needs to be assigned
1839 	 * new_alloc=1 means newly allocated dev_info structure needs to
1840 	 * be freed later if the connection process fails
1841 	 * To simplify, the assigned address corresponds to the faked
1842 	 * port number.
1843 	 */
1844 	if (dev_info->wdev_addr == 0xff) {
1845 		dev_info->wdev_addr = port + 0x7f;
1846 	}
1847 
1848 	/*
1849 	 * Acknowledge dn connect notification.
1850 	 * The notif queue scheme will ensure only one ack_ie exists
1851 	 * at one time. Don't deal with multiple ack_ie elements now
1852 	 */
1853 	if (wusb_hc_ack_conn(hc_data, port) != USB_SUCCESS) {
1854 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1855 		    "wusb_hc_handle_dn_connect: acknowledge "
1856 		    "connection fails");
1857 
1858 		if (new_alloc == 1) {
1859 			kmem_free(dev_info, sizeof (wusb_dev_info_t));
1860 			hc_data->hc_dev_infos[port] = NULL;
1861 		} else {
1862 			dev_info->wdev_state = WUSB_STATE_UNCONNTED;
1863 		}
1864 		mutex_exit(&hc_data->hc_mutex);
1865 
1866 		return;
1867 	}
1868 
1869 	/*
1870 	 * Handle device connection according to connect request type
1871 	 * Connect Acknowledge IE is removed inside the function
1872 	 */
1873 	if (wusb_hc_handle_port_connect(hc_data, port, ph, ifc, secrt_data) !=
1874 	    USB_SUCCESS) {
1875 		char *pathname = kmem_alloc(MAXPATHLEN, KM_NOSLEEP);
1876 
1877 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1878 		    "wusb_hc_handle_dn_connect: connect port %d fails", port);
1879 
1880 		if (new_alloc == 1) {
1881 			if (dev_info->wdev_secrt_data.secrt_encry_descr) {
1882 				csecrt_data = &dev_info->wdev_secrt_data;
1883 				kmem_free(csecrt_data->secrt_encry_descr,
1884 				    sizeof (usb_encryption_descr_t) *
1885 				    csecrt_data->secrt_n_encry);
1886 			}
1887 			if (dev_info->wdev_uwb_descr) {
1888 				kmem_free(dev_info->wdev_uwb_descr,
1889 				    sizeof (usb_uwb_cap_descr_t));
1890 			}
1891 			kmem_free(dev_info, sizeof (wusb_dev_info_t));
1892 			hc_data->hc_dev_infos[port] = NULL;
1893 		} else {
1894 			dev_info->wdev_state = WUSB_STATE_UNCONNTED;
1895 		}
1896 		mutex_exit(&hc_data->hc_mutex);
1897 
1898 		if (pathname) {
1899 			/* output error message to syslog */
1900 			cmn_err(CE_WARN, "%s %s%d: Connecting device"
1901 			    " on WUSB port %d fails",
1902 			    ddi_pathname(hc_data->hc_dip, pathname),
1903 			    ddi_driver_name(hc_data->hc_dip),
1904 			    ddi_get_instance(hc_data->hc_dip),
1905 			    port);
1906 
1907 			kmem_free(pathname, MAXPATHLEN);
1908 		}
1909 
1910 		return;
1911 	}
1912 
1913 	mutex_exit(&hc_data->hc_mutex);
1914 }
1915 
1916 /* Handle device disconnect notification, refer to WUSB 1.0/7.6.2 */
1917 void
wusb_hc_handle_dn_disconnect(wusb_hc_data_t * hc_data,uint8_t addr,uint8_t * data,size_t len)1918 wusb_hc_handle_dn_disconnect(wusb_hc_data_t *hc_data, uint8_t addr,
1919 	uint8_t *data, size_t len)
1920 {
1921 	wusb_dn_disconnect_t	*dn_discon;
1922 	usb_port_t		port;
1923 
1924 	if (len < WUSB_DN_DISCONN_PKT_LEN) {
1925 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1926 		    "wusb_hc_handle_dn_disconnect: short pkt len %d",
1927 		    (int)len);
1928 
1929 		return;
1930 	}
1931 
1932 	dn_discon = (wusb_dn_disconnect_t *)data;
1933 	ASSERT(dn_discon->bType == WUSB_DN_DISCONNECT);
1934 
1935 	mutex_enter(&hc_data->hc_mutex);
1936 
1937 	/* send WDEV_DISCONNECT_IE to acknowledge the notification */
1938 	if (wusb_hc_ack_disconn(hc_data, addr) != USB_SUCCESS) {
1939 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1940 		    "wusb_hc_handle_dn_disconnect: send disconnect ie fails");
1941 		mutex_exit(&hc_data->hc_mutex);
1942 
1943 		return;
1944 	}
1945 
1946 	/* offline the device requesting disconnection */
1947 	if (wusb_hc_is_addr_valid(hc_data, addr, &port)) {
1948 		(void) wusb_hc_destroy_child(hc_data, port);
1949 	} else {
1950 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1951 		    "wusb_hc_handle_dn_disconnect: device with addr "
1952 		    "0x%x not found", addr);
1953 	}
1954 
1955 	mutex_exit(&hc_data->hc_mutex);
1956 }
1957 
1958 /* post disconnect event to the device driver */
1959 void
wusb_hc_disconnect_dev(wusb_hc_data_t * hc_data,usb_port_t port)1960 wusb_hc_disconnect_dev(wusb_hc_data_t *hc_data, usb_port_t port)
1961 {
1962 	dev_info_t	*dip = hc_data->hc_dip;
1963 
1964 	ASSERT(dip != NULL);
1965 
1966 	mutex_exit(&hc_data->hc_mutex);
1967 
1968 	hc_data->disconnect_dev(dip, port);
1969 
1970 	mutex_enter(&hc_data->hc_mutex);
1971 }
1972 
1973 /* post reconnect event to the device driver */
1974 void
wusb_hc_reconnect_dev(wusb_hc_data_t * hc_data,usb_port_t port)1975 wusb_hc_reconnect_dev(wusb_hc_data_t *hc_data, usb_port_t port)
1976 {
1977 	dev_info_t	*dip = hc_data->hc_dip;
1978 
1979 	ASSERT(dip != NULL);
1980 
1981 	mutex_exit(&hc_data->hc_mutex);
1982 
1983 	hc_data->reconnect_dev(dip, port);
1984 
1985 	mutex_enter(&hc_data->hc_mutex);
1986 }
1987 
1988 /* configure child device and online it */
1989 int
wusb_hc_create_child(wusb_hc_data_t * hc_data,usb_port_t port)1990 wusb_hc_create_child(wusb_hc_data_t *hc_data, usb_port_t port)
1991 {
1992 	dev_info_t	*dip = hc_data->hc_dip;
1993 	int		rval;
1994 
1995 	ASSERT(dip != NULL);
1996 
1997 	mutex_exit(&hc_data->hc_mutex);
1998 
1999 	rval = hc_data->create_child(dip, port);
2000 
2001 	mutex_enter(&hc_data->hc_mutex);
2002 
2003 	return (rval);
2004 }
2005 
2006 /* offline child device */
2007 int
wusb_hc_destroy_child(wusb_hc_data_t * hc_data,usb_port_t port)2008 wusb_hc_destroy_child(wusb_hc_data_t *hc_data, usb_port_t port)
2009 {
2010 	dev_info_t	*dip = hc_data->hc_dip;
2011 	int		rval;
2012 
2013 	ASSERT(dip != NULL);
2014 
2015 	mutex_exit(&hc_data->hc_mutex);
2016 
2017 	rval = hc_data->destroy_child(dip, port);
2018 
2019 	mutex_enter(&hc_data->hc_mutex);
2020 
2021 	return (rval);
2022 }
2023 
2024 
2025 /*
2026  * ***********************
2027  * CC management functions
2028  * ***********************
2029  */
2030 
2031 /* add a CC to the CC list */
2032 void
wusb_hc_add_cc(wusb_hc_cc_list_t ** cc_list,wusb_hc_cc_list_t * new_cc)2033 wusb_hc_add_cc(wusb_hc_cc_list_t **cc_list, wusb_hc_cc_list_t *new_cc)
2034 {
2035 	wusb_hc_cc_list_t	*head;
2036 
2037 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2038 	    "wusb_hc_add_cc: cc_list = 0x%p, new_cc = 0x%p",
2039 	    (void *)cc_list, (void *)new_cc);
2040 
2041 	if (new_cc == NULL) {
2042 
2043 		return;
2044 	}
2045 
2046 	if (*cc_list == NULL) {
2047 		*cc_list = new_cc;
2048 
2049 		return;
2050 	}
2051 
2052 	head = *cc_list;
2053 	while (head != NULL) {
2054 		/* update an existing CC */
2055 		if (memcmp(head->cc.CDID, new_cc->cc.CDID, 16) == 0) {
2056 			(void) memcpy(head->cc.CK, new_cc->cc.CK, 16);
2057 			kmem_free(new_cc, sizeof (wusb_hc_cc_list_t));
2058 
2059 			return;
2060 		}
2061 
2062 		/* add a new CC */
2063 		if (head->next == NULL) {
2064 			head->next = new_cc;
2065 
2066 			return;
2067 		}
2068 
2069 		head = head->next;
2070 	}
2071 }
2072 
2073 /* remove a CC from the CC list */
2074 void
wusb_hc_rem_cc(wusb_hc_cc_list_t ** cc_list,wusb_cc_t * old_cc)2075 wusb_hc_rem_cc(wusb_hc_cc_list_t **cc_list, wusb_cc_t *old_cc)
2076 {
2077 	wusb_cc_t		*cc;
2078 	wusb_hc_cc_list_t	*prev, *next;
2079 
2080 	if (*cc_list == NULL || old_cc == NULL) {
2081 
2082 		return;
2083 	}
2084 
2085 	prev = *cc_list;
2086 	cc = &prev->cc;
2087 	if (memcmp(cc, old_cc, sizeof (wusb_cc_t)) == 0) {
2088 		*cc_list = prev->next;
2089 		kmem_free(prev, sizeof (wusb_hc_cc_list_t));
2090 
2091 		return;
2092 	}
2093 	next = prev->next;
2094 	while (next != NULL) {
2095 		cc = &next->cc;
2096 		if (memcmp(cc, old_cc, sizeof (wusb_cc_t)) == 0) {
2097 			prev->next = next->next;
2098 			kmem_free(next, sizeof (wusb_hc_cc_list_t));
2099 
2100 			return;
2101 		}
2102 		prev = next;
2103 		next = prev->next;
2104 	}
2105 }
2106 
2107 /* remove all CCs from the list */
2108 void
wusb_hc_free_cc_list(wusb_hc_cc_list_t * cc_list)2109 wusb_hc_free_cc_list(wusb_hc_cc_list_t *cc_list)
2110 {
2111 	wusb_hc_cc_list_t	*list, *next;
2112 
2113 	list = cc_list;
2114 	while (list != NULL) {
2115 		next = list->next;
2116 		kmem_free(list, sizeof (wusb_hc_cc_list_t));
2117 		list = next;
2118 	}
2119 }
2120 
2121 /* Send Host Disconnect notification */
2122 int
wusb_hc_send_host_disconnect(wusb_hc_data_t * hc_data)2123 wusb_hc_send_host_disconnect(wusb_hc_data_t *hc_data)
2124 {
2125 	wusb_ie_host_disconnect_t	*disconn_ie;
2126 	uint8_t				iehdl;
2127 	int				rval;
2128 
2129 	disconn_ie = kmem_zalloc(sizeof (wusb_ie_host_disconnect_t), KM_SLEEP);
2130 	disconn_ie->bIEIdentifier = WUSB_IE_HOST_DISCONNECT;
2131 	disconn_ie->bLength = sizeof (wusb_ie_host_disconnect_t);
2132 
2133 	mutex_enter(&hc_data->hc_mutex);
2134 	rval = wusb_hc_get_iehdl(hc_data, (wusb_ie_header_t *)disconn_ie,
2135 	    &iehdl);
2136 	mutex_exit(&hc_data->hc_mutex);
2137 	if (rval != USB_SUCCESS) {
2138 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2139 		    "wusb_hc_send_host_disconnect: get ie handle fails");
2140 		kmem_free(disconn_ie, sizeof (wusb_ie_host_disconnect_t));
2141 
2142 		return (rval);
2143 	}
2144 
2145 	rval = wusb_hc_add_mmc_ie(hc_data, 0, 0, iehdl,
2146 	    disconn_ie->bLength, (uint8_t *)disconn_ie);
2147 	if (rval != USB_SUCCESS) {
2148 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2149 		    "wusb_hc_send_host_disconnect: add host "
2150 		    "disconnect ie fails");
2151 		mutex_enter(&hc_data->hc_mutex);
2152 		wusb_hc_free_iehdl(hc_data, iehdl);
2153 		mutex_exit(&hc_data->hc_mutex);
2154 		kmem_free(disconn_ie, sizeof (wusb_ie_host_disconnect_t));
2155 
2156 		return (rval);
2157 	}
2158 
2159 	delay(drv_usectohz(100000));	/* WUSB 1.0/7.5.5 */
2160 
2161 	mutex_enter(&hc_data->hc_mutex);
2162 	(void) wusb_hc_remove_mmc_ie(hc_data, iehdl);
2163 	wusb_hc_free_iehdl(hc_data, iehdl);
2164 	mutex_exit(&hc_data->hc_mutex);
2165 
2166 	kmem_free(disconn_ie, sizeof (wusb_ie_host_disconnect_t));
2167 
2168 	return (USB_SUCCESS);
2169 }
2170 
2171 /* Get RC dev_t by HC dip */
2172 int
wusb_get_rc_dev_by_hc(dev_info_t * dip,dev_t * dev)2173 wusb_get_rc_dev_by_hc(dev_info_t *dip, dev_t *dev)
2174 {
2175 	dev_info_t	*pdip = ddi_get_parent(dip);
2176 	dev_info_t	*rcdip;
2177 	int		found = 0;
2178 	major_t		major;
2179 	minor_t		minor;
2180 	int		inst;
2181 
2182 	if (strcmp(ddi_driver_name(dip), "whci") == 0) {
2183 		/* For WHCI, RC and HC share the same dip */
2184 		rcdip = dip;
2185 		inst = ddi_get_instance(rcdip);
2186 		/* need to change when whci driver is ready */
2187 		minor = inst;
2188 		found = 1;
2189 	} else {
2190 		/* For HWA, RC and HC share the same parent dip */
2191 		rcdip = ddi_get_child(pdip);
2192 		while (rcdip != NULL) {
2193 			if (strcmp(ddi_driver_name(rcdip), "hwarc") == 0) {
2194 				found = 1;
2195 				inst = ddi_get_instance(rcdip);
2196 				// minor = HWAHC_CONSTRUCT_MINOR(inst);
2197 				/*
2198 				 * now hwarc driver uses inst# as minor#.
2199 				 * this may change
2200 				 */
2201 				minor = inst;
2202 
2203 				break;
2204 			}
2205 			rcdip = ddi_get_next_sibling(rcdip);
2206 		}
2207 	}
2208 
2209 	if (found == 0) {
2210 		*dev = 0;
2211 
2212 		return (USB_FAILURE);
2213 	}
2214 
2215 	major = ddi_driver_major(rcdip);
2216 	*dev = makedevice(major, minor);
2217 
2218 	USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2219 	    "wusb_get_rc_dev_by_hc: rc device(%s%d) major = %d, minor = %d",
2220 	    ddi_driver_name(rcdip), inst, major, minor);
2221 
2222 	return (USB_SUCCESS);
2223 }
2224 
2225 /* format nonce to a buffer according to WUSB Table 6-3 */
2226 static void
nonce_to_buf(wusb_ccm_nonce_t * nonce,uchar_t * nbuf,int sfn_only)2227 nonce_to_buf(wusb_ccm_nonce_t *nonce, uchar_t *nbuf, int sfn_only)
2228 {
2229 	int i, offset;
2230 	uchar_t *p = nbuf;
2231 
2232 	for (i = 0, offset = 0; i < 6; i++, offset += 8) {
2233 		*p++ = (nonce->sfn >> offset) & 0xff;
2234 	}
2235 
2236 	if (sfn_only) {
2237 
2238 		return;
2239 	}
2240 
2241 	*p++ = (nonce->tkid) & 0xff;
2242 	*p++ = (nonce->tkid >> 8) & 0xff;
2243 	*p++ = (nonce->tkid >> 16) & 0xff;
2244 
2245 	*p++ = (nonce->daddr) & 0xff;
2246 	*p++ = (nonce->daddr >> 8) & 0xff;
2247 
2248 	*p++ = (nonce->saddr) & 0xff;
2249 	*p++ = (nonce->saddr >> 8) & 0xff;
2250 }
2251 
2252 /* Call the crypto framework to compute CCM MAC data */
2253 static int
wusb_ccm_mac(CK_AES_CCM_PARAMS * ccm_params,const uchar_t * key,size_t klen,uchar_t * out,int olen)2254 wusb_ccm_mac(
2255 	CK_AES_CCM_PARAMS *ccm_params,
2256 	const uchar_t *key, size_t klen,
2257 	uchar_t *out, int olen)
2258 {
2259 	crypto_mechanism_t mech;
2260 	crypto_key_t crkey;
2261 	crypto_context_t ctx;
2262 	crypto_data_t dmac;
2263 	int ret;
2264 
2265 	bzero(&crkey, sizeof (crkey));
2266 	crkey.ck_format = CRYPTO_KEY_RAW;
2267 	crkey.ck_data   = (char *)key;
2268 	crkey.ck_length = klen * 8;
2269 
2270 	mech.cm_type	  = crypto_mech2id(SUN_CKM_AES_CCM);
2271 	mech.cm_param	  = (caddr_t)ccm_params;
2272 	mech.cm_param_len = sizeof (CK_AES_CCM_PARAMS);
2273 
2274 	if ((ret = crypto_encrypt_init(&mech, &crkey, NULL, &ctx, NULL)) !=
2275 	    CRYPTO_SUCCESS) {
2276 
2277 		return (ret);
2278 	}
2279 
2280 	/*
2281 	 * Since we've known the encrypted data is none (l(m) = 0),
2282 	 * the middle procedure crypto_encrypt_update() is ignored.
2283 	 * The last 8-byte MAC is calculated directly.
2284 	 */
2285 
2286 	bzero(&dmac, sizeof (dmac));
2287 	dmac.cd_format = CRYPTO_DATA_RAW;
2288 	dmac.cd_offset = 0;
2289 	dmac.cd_length = olen;
2290 	dmac.cd_raw.iov_base = (char *)out;
2291 	dmac.cd_raw.iov_len = olen;
2292 
2293 	if ((ret = crypto_encrypt_final(ctx, &dmac, NULL)) != CRYPTO_SUCCESS) {
2294 
2295 		return (ret);
2296 	}
2297 
2298 	return (CRYPTO_SUCCESS);
2299 }
2300 
2301 /* Pseudo-Random Function according to WUSB 1.0/6.5 */
2302 int
PRF(const uchar_t * key,size_t klen,wusb_ccm_nonce_t * nonce,const uchar_t * adata,size_t alen,const uchar_t * bdata,size_t blen,uchar_t * out,size_t bitlen)2303 PRF(const uchar_t *key, size_t klen,
2304 	wusb_ccm_nonce_t *nonce,
2305 	const uchar_t *adata, size_t alen,
2306 	const uchar_t *bdata, size_t blen,
2307 	uchar_t *out,
2308 	size_t bitlen)
2309 {
2310 	CK_AES_CCM_PARAMS ccm_params;
2311 	uchar_t *ab;
2312 	uchar_t nbuf[CCM_NONCE_LEN];
2313 	size_t lm, la;
2314 	int i, offset, ret;
2315 
2316 	/* from WUSB 6.4 */
2317 	lm = 0;
2318 	la = alen + blen;
2319 	ab = (uchar_t *)kmem_alloc(la, KM_SLEEP);
2320 	bcopy(adata, ab, alen);
2321 	bcopy(bdata, ab + alen, blen);
2322 
2323 	nonce_to_buf(nonce, nbuf, 0);
2324 
2325 	ccm_params.ulMACSize = CCM_MAC_LEN;
2326 	ccm_params.ulNonceSize = CCM_NONCE_LEN;
2327 	ccm_params.nonce = nbuf;
2328 	ccm_params.ulAuthDataSize = la;	/* l(a) */
2329 	ccm_params.authData = ab;
2330 	ccm_params.ulDataSize = lm;	/* l(m) */
2331 
2332 	offset = 0;
2333 	for (i = 0; i < (bitlen + 63)/64; i++) {
2334 		ret = wusb_ccm_mac(&ccm_params, key, klen,
2335 		    out + offset, CCM_MAC_LEN);
2336 
2337 		if (ret != CRYPTO_SUCCESS) {
2338 			kmem_free(ab, la);
2339 
2340 			return (ret);
2341 		};
2342 
2343 		offset += CCM_MAC_LEN;
2344 		nonce->sfn++;
2345 		nonce_to_buf(nonce, nbuf, 1);
2346 	}
2347 
2348 	kmem_free(ab, la);
2349 
2350 	return (CRYPTO_SUCCESS);
2351 }
2352 
2353 /* rbuf is a 16-byte buffer to store the random nonce */
2354 int
wusb_gen_random_nonce(wusb_hc_data_t * hc_data,wusb_dev_info_t * dev_info,uchar_t * rbuf)2355 wusb_gen_random_nonce(wusb_hc_data_t *hc_data,
2356 	wusb_dev_info_t *dev_info, uchar_t *rbuf)
2357 {
2358 	usba_device_t *udev = usba_get_usba_device(hc_data->hc_dip);
2359 	wusb_ccm_nonce_t n;
2360 	uint16_t vid, pid;
2361 	uint64_t ht;
2362 	uint8_t kbuf[16], *p;
2363 	uchar_t a[] = "Random Numbers";
2364 
2365 	n.sfn = 0;
2366 	n.tkid = dev_info->wdev_tkid[0] | (dev_info->wdev_tkid[1] << 8) |
2367 	    (dev_info->wdev_tkid[2] << 16);
2368 	n.daddr = hc_data->hc_addr;
2369 	n.saddr = dev_info->wdev_addr;
2370 
2371 	vid = udev->usb_dev_descr->idVendor;
2372 	pid = udev->usb_dev_descr->idProduct;
2373 	ht = gethrtime();
2374 
2375 	p = kbuf;
2376 	bcopy((uint8_t *)&vid, p, sizeof (uint16_t));
2377 	p += sizeof (uint16_t);
2378 
2379 	bcopy((uint8_t *)&pid, p, sizeof (uint16_t));
2380 	p += sizeof (uint16_t);
2381 
2382 	bcopy((uint8_t *)&p, p, sizeof (uint32_t));
2383 	p += sizeof (uint32_t);
2384 
2385 	bcopy((uint8_t *)&ht, p, sizeof (uint64_t));
2386 
2387 	return (PRF_128(kbuf, 16, &n, a, sizeof (a),
2388 	    (uchar_t *)hc_data, sizeof (wusb_hc_data_t), rbuf));
2389 }
2390 
2391 /* Set WUSB device encryption type, refer to WUSB 1.0/7.3.2.2 */
2392 int
wusb_dev_set_encrypt(usb_pipe_handle_t ph,uint8_t value)2393 wusb_dev_set_encrypt(usb_pipe_handle_t ph, uint8_t value)
2394 {
2395 	usb_ctrl_setup_t	setup;
2396 	usb_cr_t		cr;
2397 	usb_cb_flags_t		cb_flags;
2398 
2399 	setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV;
2400 	setup.bRequest = USB_REQ_SET_ENCRYPTION;
2401 	setup.wValue = value;
2402 	setup.wIndex = 0;
2403 	setup.wLength = 0;
2404 	setup.attrs = USB_ATTRS_NONE;
2405 
2406 	return (usb_pipe_ctrl_xfer_wait(ph, &setup, NULL,
2407 	    &cr, &cb_flags, USB_FLAGS_SLEEP));
2408 }
2409 
2410 /*
2411  * Set WUSB device key descriptor, refer to WUSB 1.0/7.3.2.4
2412  *	ph - Device's default control pipe
2413  *	key_index - Key Index
2414  */
2415 int
wusb_dev_set_key(usb_pipe_handle_t ph,uint8_t key_index,usb_key_descr_t * key,size_t klen)2416 wusb_dev_set_key(usb_pipe_handle_t ph, uint8_t key_index,
2417 	usb_key_descr_t *key, size_t klen)
2418 {
2419 	usb_ctrl_setup_t	setup;
2420 	usb_cr_t		cr;
2421 	usb_cb_flags_t		cb_flags;
2422 	mblk_t			*pdata;
2423 	int			rval;
2424 
2425 	setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV;
2426 	setup.bRequest = USB_REQ_SET_DESCR;
2427 	setup.wValue = (USB_DESCR_TYPE_KEY << 8) | key_index;
2428 	setup.wIndex = 0;
2429 	setup.wLength = (uint16_t)klen;
2430 	setup.attrs = USB_ATTRS_NONE;
2431 
2432 	if ((pdata = allocb(klen, BPRI_HI)) == NULL) {
2433 
2434 		return (USB_FAILURE);
2435 	}
2436 	bcopy(key, pdata->b_wptr, klen);
2437 	pdata->b_wptr += klen;
2438 
2439 	rval = usb_pipe_ctrl_xfer_wait(ph, &setup, &pdata,
2440 	    &cr, &cb_flags, USB_FLAGS_SLEEP);
2441 
2442 	freemsg(pdata);
2443 
2444 	return (rval);
2445 }
2446 
2447 /*
2448  * Set encryption type for the specified device.
2449  */
2450 int
wusb_hc_set_encrypt(wusb_hc_data_t * hc_data,usb_port_t port,uint8_t type)2451 wusb_hc_set_encrypt(wusb_hc_data_t *hc_data, usb_port_t port, uint8_t type)
2452 {
2453 	dev_info_t	*dip = hc_data->hc_dip;
2454 	int		rval;
2455 
2456 	if ((rval = hc_data->set_encrypt(dip, port, type)) != USB_SUCCESS) {
2457 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2458 		    "wusb_hc_set_encrypt: set encryption type %d "
2459 		    "for port %d failed, rval = %d", type, port, rval);
2460 	}
2461 
2462 	return (rval);
2463 }
2464 
2465 /*
2466  * Set Device Key for WUSB host, refer to WUSB 1.0/8.5.3.8
2467  * Call the HC's specific set_ptk function to set PTK for a device
2468  * len: length of key_data
2469  */
2470 int
wusb_hc_set_ptk(wusb_hc_data_t * hc_data,uint8_t * key_data,usb_port_t port)2471 wusb_hc_set_ptk(wusb_hc_data_t *hc_data, uint8_t *key_data, usb_port_t port)
2472 {
2473 	dev_info_t	*dip = hc_data->hc_dip;
2474 	wusb_dev_info_t	*dev_info = hc_data->hc_dev_infos[port];
2475 	usb_key_descr_t	*key_descr;
2476 	size_t		klen;
2477 	int		rval;
2478 	uint8_t		*p;
2479 
2480 	ASSERT(mutex_owned(&hc_data->hc_mutex));
2481 
2482 	if ((key_data == NULL) || (dev_info == NULL)) {
2483 
2484 		return (USB_INVALID_ARGS);
2485 	}
2486 
2487 	klen = sizeof (usb_key_descr_t) + 15;
2488 	key_descr = kmem_zalloc(klen, KM_SLEEP);
2489 
2490 	key_descr->bLength = (uint16_t)klen;
2491 	key_descr->bDescriptorType = USB_DESCR_TYPE_KEY;
2492 	(void) memcpy(key_descr->tTKID, dev_info->wdev_tkid, 3);
2493 	p = &key_descr->KeyData[0];
2494 	(void) memcpy(p, key_data, 16);
2495 
2496 	mutex_exit(&hc_data->hc_mutex);
2497 
2498 	if ((rval = hc_data->set_ptk(dip, key_descr, klen, port)) !=
2499 	    USB_SUCCESS) {
2500 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2501 		    "wusb_hc_set_pkt: set ptk for port %d failed", port);
2502 	}
2503 
2504 	kmem_free(key_descr, klen);
2505 	mutex_enter(&hc_data->hc_mutex);
2506 
2507 	return (rval);
2508 }
2509 
2510 /*
2511  * Set GTK for a host
2512  * Call HC's specific set_gtk function
2513  *
2514  * Default gtk is set at hc_initial_start, and to be changed whenever
2515  * a device leaves the current group (refer to WUSB spec 6.2.11.2)
2516  */
2517 int
wusb_hc_set_gtk(wusb_hc_data_t * hc_data,uint8_t * key_data,uint8_t * tkid)2518 wusb_hc_set_gtk(wusb_hc_data_t *hc_data, uint8_t *key_data, uint8_t *tkid)
2519 {
2520 	dev_info_t	*dip = hc_data->hc_dip;
2521 	usb_key_descr_t	*key_descr;
2522 	size_t		klen;
2523 	int		rval;
2524 	uint8_t		*p;
2525 
2526 	if ((key_data == NULL) || (tkid == NULL)) {
2527 
2528 		return (USB_INVALID_ARGS);
2529 	}
2530 
2531 	klen = sizeof (usb_key_descr_t) + 15;
2532 	key_descr = kmem_zalloc(klen, KM_SLEEP);
2533 
2534 	key_descr->bLength = (uint16_t)klen;
2535 	key_descr->bDescriptorType = USB_DESCR_TYPE_KEY;
2536 	(void) memcpy(key_descr->tTKID, tkid, 3);
2537 	p = &key_descr->KeyData[0];
2538 	(void) memcpy(p, key_data, 16);
2539 
2540 	if ((rval = hc_data->set_gtk(dip, key_descr, klen)) !=
2541 	    USB_SUCCESS) {
2542 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2543 		    "wusb_hc_set_gkt: set gtk failed");
2544 	}
2545 
2546 	(void) memcpy(&hc_data->hc_gtk, key_descr, klen);
2547 	kmem_free(key_descr, klen);
2548 
2549 	return (rval);
2550 }
2551 
2552 /* Set Device Info for WUSB host, refer to WUSB 1.0/8.5.3.7 */
2553 int
wusb_hc_set_device_info(wusb_hc_data_t * hc_data,usb_port_t port)2554 wusb_hc_set_device_info(wusb_hc_data_t *hc_data, usb_port_t port)
2555 {
2556 	wusb_dev_info_t		*dev_info;
2557 	int			rval;
2558 
2559 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2560 	    "wusb_hc_set_device_info: port = %d", port);
2561 
2562 	dev_info = hc_data->hc_dev_infos[port];
2563 	rval = hc_data->set_device_info(hc_data->hc_dip, dev_info, port);
2564 	if (rval != USB_SUCCESS) {
2565 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2566 		    "wusb_hc_set_device_info: the host failed to set "
2567 		    "device info, rval = %d", rval);
2568 	}
2569 
2570 	return (rval);
2571 }
2572 
2573 /*
2574  * Set/Get Handshake Data to/from WUSB device, refer to WUSB 1.0/7.3.2.5
2575  * step = 1, 2, 3
2576  */
2577 int
wusb_handshake(usb_pipe_handle_t pipe,wusb_hndshk_data_t * hs,int step)2578 wusb_handshake(usb_pipe_handle_t pipe, wusb_hndshk_data_t *hs, int step)
2579 {
2580 	usb_ctrl_setup_t	setup;
2581 	mblk_t			*pdata;
2582 	usb_cr_t		cr;
2583 	usb_cb_flags_t		cb_flags;
2584 	int			rval;
2585 
2586 	if (step == 2) {
2587 		/* get handshake */
2588 		setup.bmRequestType = USB_DEV_REQ_DEV_TO_HOST;
2589 		setup.bRequest = USB_REQ_GET_HANDSHAKE;
2590 		pdata = NULL;
2591 	} else if ((step == 1) || (step == 3)) {
2592 		/* set handshake */
2593 		setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV;
2594 		setup.bRequest = USB_REQ_SET_HANDSHAKE;
2595 
2596 		if ((pdata = allocb(WUSB_HNDSHK_DATA_LEN, BPRI_HI)) == NULL) {
2597 
2598 			return (USB_NO_RESOURCES);
2599 		}
2600 		bcopy(hs, pdata->b_wptr, WUSB_HNDSHK_DATA_LEN);
2601 		pdata->b_wptr += WUSB_HNDSHK_DATA_LEN;
2602 	} else {
2603 		/* step value is invalid */
2604 		return (USB_INVALID_ARGS);
2605 	}
2606 
2607 	setup.wValue = (uint16_t)step;
2608 	setup.wIndex = 0;
2609 	setup.wLength = WUSB_HNDSHK_DATA_LEN;
2610 	setup.attrs = USB_ATTRS_NONE;
2611 
2612 	rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
2613 	    &cr, &cb_flags, USB_FLAGS_SLEEP);
2614 
2615 	if (step == 2) {
2616 		if (pdata) {
2617 			bcopy(pdata->b_rptr, hs, msgsize(pdata));
2618 			freemsg(pdata);
2619 		}
2620 	} else {
2621 		freemsg(pdata);
2622 	}
2623 
2624 	return (rval);
2625 }
2626 
2627 /* search the security descrs for CCM encryption type descr */
2628 int16_t
wusb_get_ccm_encryption_value(wusb_secrt_data_t * secrt_data)2629 wusb_get_ccm_encryption_value(wusb_secrt_data_t *secrt_data)
2630 {
2631 	usb_encryption_descr_t	*encry_descr;
2632 	int			i;
2633 	int16_t			value = -1;
2634 
2635 	for (i = 0; i < secrt_data->secrt_n_encry; i++) {
2636 		encry_descr = &secrt_data->secrt_encry_descr[i];
2637 		if (encry_descr->bEncryptionType == USB_ENC_TYPE_CCM_1) {
2638 			value = encry_descr->bEncryptionValue;
2639 			USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2640 			    "ccm encryption value is %d", value);
2641 
2642 			break;
2643 		}
2644 	}
2645 
2646 	return (value);
2647 }
2648 
2649 static void
wusb_print_handshake_data(wusb_hndshk_data_t * hs,int step)2650 wusb_print_handshake_data(wusb_hndshk_data_t *hs, int step)
2651 {
2652 	uint8_t		*p;
2653 
2654 	USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2655 	    "handshake %d data:", step);
2656 	USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2657 	    "%x %x (TKID)%x %x %x %x", hs->bMessageNumber, hs->bStatus,
2658 	    hs->tTKID[0], hs->tTKID[1], hs->tTKID[2], hs->bReserved);
2659 
2660 	p = hs->CDID;
2661 
2662 	USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2663 	    "(CDID)%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
2664 	    p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9],
2665 	    p[10], p[11], p[12], p[13], p[14], p[15]);
2666 
2667 	p = hs->Nonce;
2668 	USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2669 	    "(Nonce)%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
2670 	    p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9],
2671 	    p[10], p[11], p[12], p[13], p[14], p[15]);
2672 
2673 	p = hs->MIC;
2674 	USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2675 	    "(MIC)%x %x %x %x %x %x %x %x",
2676 	    p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
2677 }
2678 
2679 /* ARGSUSED */
2680 /*
2681  * Do 4way handshake and other necessary control operations to
2682  * transit the device to authenticated state
2683  * refer to WUSB 1.0 [7.3.2.5, 6.2.10.9.1, 7.1.2]
2684  * ph - pipe handle of the host controller
2685  */
2686 int
wusb_4way_handshake(wusb_hc_data_t * hc_data,usb_port_t port,usb_pipe_handle_t ph,uint8_t ifc)2687 wusb_4way_handshake(wusb_hc_data_t *hc_data, usb_port_t port,
2688 	usb_pipe_handle_t ph, uint8_t ifc)
2689 {
2690 	uint8_t			tkid[3];
2691 	wusb_ccm_nonce_t	n;
2692 	wusb_hndshk_data_t	*hs;
2693 	wusb_dev_info_t		*dev_info;
2694 	wusb_cc_t		*cc;
2695 	uchar_t			adata1[] = "Pair-wise keys";
2696 	uchar_t			adata2[] = "out-of-bandMIC";
2697 	uchar_t			bdata[32], keyout[32], mic[8];
2698 	int			rval;
2699 	usb_pipe_handle_t	w_ph;
2700 
2701 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2702 	    "wusb_4way_handshake: port = %d", port);
2703 
2704 	mutex_enter(&hc_data->hc_mutex);
2705 	dev_info = hc_data->hc_dev_infos[port];
2706 	if (dev_info == NULL) {
2707 		mutex_exit(&hc_data->hc_mutex);
2708 
2709 		return (USB_FAILURE);
2710 	}
2711 	cc = dev_info->wdev_cc;
2712 	if (dev_info->wdev_ph == NULL || cc == NULL) {
2713 		mutex_exit(&hc_data->hc_mutex);
2714 
2715 		return (USB_FAILURE);
2716 	}
2717 
2718 	w_ph = dev_info->wdev_ph;
2719 
2720 	hs = (wusb_hndshk_data_t *)kmem_zalloc(
2721 	    3 * sizeof (wusb_hndshk_data_t), KM_SLEEP);
2722 
2723 	/* tkid is generated dynamically and saved in dev_info */
2724 	(void) random_get_pseudo_bytes(tkid, 3);
2725 
2726 	(void) memcpy(dev_info->wdev_tkid, tkid, 3);
2727 
2728 	/* handshake 1 */
2729 	hs[0].bMessageNumber = 1;
2730 	hs[0].bStatus = 0;
2731 	(void) memcpy(hs[0].tTKID, tkid, 3);
2732 	hs[0].bReserved = 0;
2733 	bcopy(cc->CDID, hs[0].CDID, WUSB_CDID_LEN);
2734 
2735 	if ((rval = wusb_gen_random_nonce(hc_data, dev_info, hs[0].Nonce))
2736 	    != USB_SUCCESS) {
2737 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2738 		    "Nonce generation failed: %d", rval);
2739 		mutex_exit(&hc_data->hc_mutex);
2740 
2741 		goto done;
2742 	}
2743 
2744 	wusb_print_handshake_data(&hs[0], 1);
2745 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2746 	    "wusb_4way_handshake: shake 1.............");
2747 
2748 	mutex_exit(&hc_data->hc_mutex);
2749 	rval = wusb_handshake(w_ph, &(hs[0]), 1);
2750 	if (rval != USB_SUCCESS) {
2751 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2752 		    "handshake 1 failed, rval = %d", rval);
2753 
2754 		goto done;
2755 	}
2756 
2757 	/* handshake 2 */
2758 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2759 	    "wusb_4way_handshake: shake 2.............");
2760 	rval = wusb_handshake(w_ph, &(hs[1]), 2);
2761 	if (rval != USB_SUCCESS) {
2762 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2763 		    "handshake 2 failed, rval = %d", rval);
2764 
2765 		goto done;
2766 	}
2767 
2768 	if (hs[1].bMessageNumber != 2 || hs[1].bStatus != 0) {
2769 		rval = USB_FAILURE;
2770 
2771 		goto done;
2772 	}
2773 
2774 	wusb_print_handshake_data(&hs[1], 2);
2775 
2776 	/* derived session keys, refer to WUSB 1.0/6.5.1 */
2777 	n.sfn = 0;
2778 	n.tkid = tkid[0] | (tkid[1]<<8) | (tkid[2] << 16);
2779 
2780 	mutex_enter(&hc_data->hc_mutex);
2781 	n.daddr = dev_info->wdev_addr;
2782 
2783 	n.saddr = hc_data->hc_addr;
2784 	bcopy(hs[0].Nonce, bdata, 16);
2785 	bcopy(hs[1].Nonce, bdata + 16, 16);
2786 	mutex_exit(&hc_data->hc_mutex);
2787 
2788 	rval = PRF_256(cc->CK, 16, &n, adata1, 14, bdata, 32, keyout);
2789 	if (rval != 0) {
2790 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2791 		    "compute keys failed, rval = %d", rval);
2792 
2793 		goto done;
2794 	}
2795 
2796 	/* sfn was changed in PRF(). Need to reset it to 0 */
2797 	n.sfn = 0;
2798 
2799 	/* used the derived KCK to verify received MIC (WUSB 1.0/6.5.2] */
2800 	rval = PRF_64(keyout, 16, &n, adata2, 14, (uchar_t *)(&hs[1]),
2801 	    WUSB_HNDSHK_DATA_LEN - 8, mic);
2802 	if (rval != 0) {
2803 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2804 		    "compute MIC failed, rval = %d", rval);
2805 
2806 		goto done;
2807 	}
2808 
2809 	if (memcmp(hs[1].MIC, mic, 8) != 0) {
2810 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2811 		    "verify mic failed");
2812 		rval = USB_FAILURE;
2813 
2814 		goto done;
2815 	}
2816 
2817 	/* handshake 3 */
2818 	bcopy(&hs[0], &hs[2], WUSB_HNDSHK_DATA_LEN - 8);
2819 	hs[2].bMessageNumber = 3;
2820 	n.sfn = 0;
2821 	rval = PRF_64(keyout, 16, &n, adata2, 14, (uchar_t *)(&hs[2]),
2822 	    WUSB_HNDSHK_DATA_LEN - 8, hs[2].MIC);
2823 	if (rval != 0) {
2824 		goto done;
2825 	}
2826 
2827 	wusb_print_handshake_data(&hs[2], 3);
2828 
2829 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2830 	    "wusb_4way_handshake: shake 3.............");
2831 	rval = wusb_handshake(w_ph, &(hs[2]), 3);
2832 	if (rval != USB_SUCCESS) {
2833 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2834 		    "handshake 3 failed, rval = %d", rval);
2835 
2836 		goto done;
2837 	}
2838 
2839 	mutex_enter(&hc_data->hc_mutex);
2840 	/* set PTK for host */
2841 	(void) memcpy(dev_info->wdev_ptk, keyout + 16, 16);
2842 
2843 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2844 	    "wusb_4way_handshake: set ptk .............");
2845 	rval = wusb_hc_set_ptk(hc_data, dev_info->wdev_ptk, port);
2846 	mutex_exit(&hc_data->hc_mutex);
2847 	if (rval != USB_SUCCESS) {
2848 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2849 		    "set ptk for host failed, rval = %d", rval);
2850 
2851 		goto done;
2852 	}
2853 
2854 	/*
2855 	 * enable CCM encryption on the host
2856 	 * according to WUSB 1.0/7.1.2, the encryption mode must be
2857 	 * enabled before setting GTK onto device
2858 	 */
2859 	USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2860 	    "wusb_4way_handshake: hc set encrypt .............");
2861 	rval = wusb_hc_set_encrypt(hc_data, port, WUSB_ENCRYP_TYPE_CCM_1);
2862 	if (rval != USB_SUCCESS) {
2863 		USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2864 		    "set encryption for host failed, rval = %d", rval);
2865 
2866 		goto done;
2867 	}
2868 
2869 	/*
2870 	 * set GTK for device
2871 	 * GTK is initialized when hc_data is inited
2872 	 */
2873 	rval = wusb_dev_set_key(w_ph, 2 << 4,
2874 	    &hc_data->hc_gtk, hc_data->hc_gtk.bLength);
2875 done:
2876 	kmem_free(hs, 3 * sizeof (wusb_hndshk_data_t));
2877 	if (rval != USB_SUCCESS) {
2878 		/* restore the host to unsecure mode */
2879 		(void) wusb_hc_set_encrypt(hc_data, port,
2880 		    WUSB_ENCRYP_TYPE_UNSECURE);
2881 	}
2882 
2883 	return (rval);
2884 }
2885