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