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