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