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