whcdi.c revision 9797:4b03a6b797a8
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 */
52static kmutex_t whcdi_mutex;
53
54/* use 0-30 bit as wusb cluster_id bitmaps */
55static uint32_t cluster_id_mask = 0;
56
57_NOTE(MUTEX_PROTECTS_DATA(whcdi_mutex, cluster_id_mask))
58
59usb_log_handle_t	whcdi_log_handle;
60uint_t			whcdi_errlevel = USB_LOG_L4;
61uint_t			whcdi_errmask = (uint_t)-1;
62
63/*
64 * initialize private data
65 */
66void
67usba_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
78void
79usba_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 */
93uint8_t
94wusb_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 */
125void
126wusb_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 */
150int
151wusb_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 */
205void
206wusb_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 */
230int
231wusb_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 */
259int
260wusb_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 */
284int
285wusb_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 */
301int
302wusb_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 */
320int
321wusb_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 */
346int
347wusb_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 */
362int
363wusb_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 */
385int
386wusb_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 */
405void
406wusb_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 */
435int
436wusb_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 */
487void
488wusb_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 */
516uint_t
517wusb_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 */
546uint_t
547wusb_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 */
573usb_port_t
574wusb_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 */
593int
594wusb_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 */
647void
648wusb_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 */
680int
681wusb_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 */
747wusb_cc_t *
748wusb_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 */
771int
772wusb_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 */
846int
847wusb_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
963done:
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 */
982int
983wusb_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
1083done:
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 */
1103int
1104wusb_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 */
1162void
1163wusb_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 */
1184void
1185wusb_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 */
1227void
1228wusb_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 */
1261int
1262wusb_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 */
1299int
1300wusb_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 */
1419int
1420wusb_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 */
1481int
1482wusb_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 */
1509int
1510wusb_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
1689error:
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 */
1731void
1732wusb_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 */
1917void
1918wusb_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 */
1959void
1960wusb_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 */
1974void
1975wusb_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 */
1989int
1990wusb_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 */
2007int
2008wusb_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 */
2032void
2033wusb_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 */
2074void
2075wusb_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 */
2108void
2109wusb_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 */
2122int
2123wusb_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 */
2172int
2173wusb_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 */
2226static void
2227nonce_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 */
2253static int
2254wusb_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 */
2302int
2303PRF(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 */
2354int
2355wusb_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 */
2392int
2393wusb_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 */
2415int
2416wusb_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 */
2450int
2451wusb_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 */
2470int
2471wusb_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 */
2517int
2518wusb_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 */
2553int
2554wusb_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 */
2577int
2578wusb_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 */
2628int16_t
2629wusb_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
2649static void
2650wusb_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 */
2686int
2687wusb_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	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);
2875done:
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