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         if (!disconn_ie) {
1434                 return (USB_NO_RESOURCES);
1435         }
1436 
1437         disconn_ie->bIEIdentifier = WUSB_IE_DEV_DISCONNECT;
1438         disconn_ie->bDeviceAddress[0] = addr;
1439         /* padding, no active wusb device addr will be 1 */
1440         disconn_ie->bDeviceAddress[1] = 1;
1441         disconn_ie->bLength = 4;
1442 
1443         rval = wusb_hc_get_iehdl(hc_data, (wusb_ie_header_t *)disconn_ie,
1444             &iehdl);
1445         if (rval != USB_SUCCESS) {
1446                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1447                     "wusb_hc_ack_disconn: get ie handle fails");
1448                 kmem_free(disconn_ie, sizeof (wusb_ie_dev_disconnect_t));
1449 
1450                 return (rval);
1451         }
1452 
1453         rval = wusb_hc_add_mmc_ie(hc_data, 0, 0, iehdl,
1454             disconn_ie->bLength, (uint8_t *)disconn_ie);
1455         if (rval != USB_SUCCESS) {
1456                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1457                     "wusb_hc_ack_disconn: add dev disconnect ie fails");
1458                 wusb_hc_free_iehdl(hc_data, iehdl);
1459                 kmem_free(disconn_ie, sizeof (wusb_ie_dev_disconnect_t));
1460 
1461                 return (rval);
1462         }
1463 
1464         mutex_exit(&hc_data->hc_mutex);
1465         /*
1466          * WUSB 1.0/7.5.4 requires the IE to be transmitted at least
1467          * 100ms before ceasing, wait for 150ms here
1468          */
1469         delay(drv_usectohz(150000));
1470         mutex_enter(&hc_data->hc_mutex);
1471 
1472         /* cease transmitting the IE */
1473         (void) wusb_hc_remove_mmc_ie(hc_data, (uint8_t)iehdl);
1474         wusb_hc_free_iehdl(hc_data, iehdl);
1475         kmem_free(disconn_ie, sizeof (wusb_ie_dev_disconnect_t));
1476 
1477         return (USB_SUCCESS);
1478 }
1479 
1480 /* create child devinfo node and usba_device structure */
1481 int
1482 wusb_create_child_devi(dev_info_t *dip, char *node_name,
1483         usba_hcdi_ops_t *usba_hcdi_ops, dev_info_t *usb_root_hub_dip,
1484         usb_port_status_t port_status, usba_device_t *usba_device,
1485         dev_info_t **child_dip)
1486 {
1487         ndi_devi_alloc_sleep(dip, node_name, (pnode_t)DEVI_SID_NODEID,
1488             child_dip);
1489 
1490         usba_device = usba_alloc_usba_device(usb_root_hub_dip);
1491 
1492         /* grab the mutex to keep warlock happy */
1493         mutex_enter(&usba_device->usb_mutex);
1494         usba_device->usb_hcdi_ops = usba_hcdi_ops;
1495         usba_device->usb_port_status = port_status;
1496         usba_device->usb_is_wireless = B_TRUE;
1497         mutex_exit(&usba_device->usb_mutex);
1498 
1499         /* store the usba_device point in the dip */
1500         usba_set_usba_device(*child_dip, usba_device);
1501 
1502         return (USB_SUCCESS);
1503 }
1504 
1505 /*
1506  * Handle WUSB child device connection, including creating child devinfo
1507  * and usba strutures, authentication, configuration and attach.
1508  */
1509 int
1510 wusb_hc_handle_port_connect(wusb_hc_data_t *hc_data, usb_port_t port,
1511         usb_pipe_handle_t ph, uint8_t ifc, wusb_secrt_data_t *secrt_data)
1512 {
1513         dev_info_t      *dip = hc_data->hc_dip;
1514         dev_info_t      *child_dip = NULL;
1515         usba_device_t   *child_ud = NULL;
1516         usba_device_t   *parent_ud;
1517         usba_hcdi_t     *hcdi = usba_hcdi_get_hcdi(dip);
1518         usb_pipe_handle_t child_ph = NULL;
1519         int             rval;
1520         int             child_created = 0;
1521         wusb_dev_info_t *dev_info;
1522         usb_dev_descr_t usb_dev_descr;
1523         int             ackie_removed = 0;
1524 
1525         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
1526             "wusb_hc_handle_port_connect: hc_data=0x%p, port=%d",
1527             (void *)hc_data, port);
1528 
1529         ASSERT(mutex_owned(&hc_data->hc_mutex));
1530         dev_info = hc_data->hc_dev_infos[port];
1531         if (dev_info == NULL) {
1532                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1533                     "wusb_hc_handle_port_connect: port %d invalid", port);
1534                 wusb_hc_rm_ack(hc_data);
1535 
1536                 return (USB_INVALID_ARGS);
1537         }
1538 
1539         dev_info->wdev_hc = hc_data;
1540 
1541         /* prepare child devinfo and usba structures */
1542         if (hc_data->hc_children_dips[port]) {
1543                 child_dip = hc_data->hc_children_dips[port];
1544                 child_ud = hc_data->hc_usba_devices[port];
1545                 child_ph = usba_get_dflt_pipe_handle(child_dip);
1546                 mutex_exit(&hc_data->hc_mutex);
1547                 usb_pipe_close(child_dip, child_ph,
1548                     USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
1549                 mutex_enter(&hc_data->hc_mutex);
1550         } else {
1551                 rval = wusb_create_child_devi(dip,
1552                     "device",
1553                     hcdi->hcdi_ops,
1554                     dip,
1555                     USBA_HIGH_SPEED_DEV,
1556                     child_ud,
1557                     &child_dip);
1558                 if (rval != USB_SUCCESS) {
1559                         wusb_hc_rm_ack(hc_data); // , ph, ifc);
1560 
1561                         return (rval);
1562                 }
1563                 child_ud = usba_get_usba_device(child_dip);
1564                 ASSERT(child_ud != NULL);
1565 
1566                 mutex_enter(&child_ud->usb_mutex);
1567                 child_ud->usb_dev_descr = kmem_zalloc(sizeof (usb_dev_descr_t),
1568                     KM_SLEEP);
1569                 child_ud->usb_wireless_data =
1570                     kmem_zalloc(sizeof (usba_wireless_data_t), KM_SLEEP);
1571                 mutex_exit(&child_ud->usb_mutex);
1572                 child_created = 1;
1573                 hc_data->hc_children_dips[port] = child_dip;
1574                 hc_data->hc_usba_devices[port] = child_ud;
1575         }
1576 
1577         /* do necessary setup */
1578         parent_ud = usba_get_usba_device(dip);
1579         mutex_enter(&child_ud->usb_mutex);
1580         child_ud->usb_addr = dev_info->wdev_addr;
1581         child_ud->usb_port = port;
1582 
1583         /*
1584          * TODO: now only consider the situation that HWA is high
1585          * speed dev for the children. The situation that HWA is
1586          * connected to the USB 1.1 port is not considered. The
1587          * available HWA devices can't work behind USB1.1 port.
1588          */
1589         child_ud->usb_hs_hub_usba_dev = parent_ud;
1590         child_ud->usb_hs_hub_addr = parent_ud->usb_addr;
1591         child_ud->usb_hs_hub_port = port;
1592         bzero(&usb_dev_descr, sizeof (usb_dev_descr_t));
1593 
1594         /*
1595          * 255 for WUSB devices, refer to WUSB 1.0/4.8.1.
1596          * default ctrl pipe will ignore this value
1597          */
1598         usb_dev_descr.bMaxPacketSize0 = 255;
1599         bcopy(&usb_dev_descr, child_ud->usb_dev_descr,
1600             sizeof (usb_dev_descr_t));
1601         mutex_exit(&child_ud->usb_mutex);
1602 
1603         dev_info->wdev_ph = NULL;
1604 
1605         /*
1606          * set device info and encryption mode for the host so that
1607          * open child pipe can work later
1608          */
1609         rval = wusb_hc_set_device_info(hc_data, port);
1610         if (rval != USB_SUCCESS) {
1611                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1612                     "wusb_hc_handle_port_connect: set device info for"
1613                     " host failed, rval = %d", rval);
1614 
1615                 goto error;
1616         }
1617 
1618         /* set the host to unsecure mode before authentication starts */
1619         rval = wusb_hc_set_encrypt(hc_data, port, WUSB_ENCRYP_TYPE_UNSECURE);
1620         if (rval != USB_SUCCESS) {
1621                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1622                     "wusb_hc_handle_port_connect:set unsecure encryption"
1623                     " for host failed, rval = %d", rval);
1624 
1625                 goto error;
1626         }
1627 
1628         /*
1629          * Open the default pipe for the child device
1630          * the MaxPacketSize for the default ctrl pipe is
1631          * set in usba_init_pipe_handle().
1632          */
1633         mutex_exit(&hc_data->hc_mutex);
1634         if ((rval = usb_pipe_open(child_dip, NULL, NULL,
1635             USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &child_ph)) !=
1636             USB_SUCCESS) {
1637                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1638                     "wusb_hc_handle_port_connect:open default pipe failed (%d)",
1639                     rval);
1640                 mutex_enter(&hc_data->hc_mutex);
1641 
1642                 goto error;
1643         }
1644         mutex_enter(&hc_data->hc_mutex);
1645 
1646         /* recording the default pipe */
1647         dev_info->wdev_ph = child_ph;
1648 
1649         /* verify the default child pipe works */
1650         if (wusb_get_dev_uwb_descr(hc_data, port) != USB_SUCCESS) {
1651                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1652                     "wusb_hc_handle_port_connect: failed to get"
1653                     " device uwb descr");
1654 
1655                 goto error;
1656         }
1657 
1658         /* remove connect acknowledge IE */
1659         wusb_hc_rm_ack(hc_data);
1660         ackie_removed = 1;
1661 
1662         /* do authentication */
1663         if (wusb_hc_auth_dev(hc_data, port, ph, ifc, secrt_data) !=
1664             USB_SUCCESS) {
1665                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1666                     "wusb_hc_handle_port_connect: "
1667                     "device authentication fails");
1668 
1669                 goto error;
1670         }
1671 
1672         /* online child */
1673         if (dev_info->wdev_state == WUSB_STATE_RECONNTING) {
1674                 dev_info->wdev_state = WUSB_STATE_CONFIGURED;
1675                 /* post reconnect event to child */
1676                 wusb_hc_reconnect_dev(hc_data, port);
1677         } else {
1678                 if (wusb_hc_create_child(hc_data, port) != USB_SUCCESS) {
1679                         USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1680                             "wusb_hc_handle_port_connect: create child fails");
1681 
1682                         goto error;
1683                 }
1684                 dev_info->wdev_state = WUSB_STATE_CONFIGURED;
1685         }
1686 
1687         return (USB_SUCCESS);
1688 
1689 error:
1690         if (dev_info->wdev_ph != NULL) {
1691                 mutex_exit(&hc_data->hc_mutex);
1692                 usb_pipe_close(child_dip, child_ph,
1693                     USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
1694                 mutex_enter(&hc_data->hc_mutex);
1695 
1696                 dev_info->wdev_ph = NULL;
1697         }
1698 
1699         if (child_created) {
1700 
1701                 rval = usba_destroy_child_devi(child_dip,
1702                     NDI_DEVI_REMOVE);
1703 
1704                 if (rval != USB_SUCCESS) {
1705                         USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1706                             "wusb_hc_handle_port_connect: "
1707                             "failure to remove child node");
1708                 }
1709 
1710                 mutex_exit(&hc_data->hc_mutex);
1711                 usba_free_usba_device(child_ud);
1712                 mutex_enter(&hc_data->hc_mutex);
1713 
1714                 hc_data->hc_children_dips[port] = NULL;
1715                 hc_data->hc_usba_devices[port] = NULL;
1716         }
1717 
1718         if (ackie_removed == 0) {
1719                 wusb_hc_rm_ack(hc_data);
1720         }
1721 
1722         return (USB_FAILURE);
1723 }
1724 
1725 /*
1726  * Handle device connect notification: assign port number, acknowledge
1727  * device connection, and online child
1728  * Refer to WUSB 1.0 4.13, 6.10, 7.1 for connection process handling
1729  * and device state diagram
1730  */
1731 void
1732 wusb_hc_handle_dn_connect(wusb_hc_data_t *hc_data, usb_pipe_handle_t ph,
1733         uint8_t ifc, uint8_t *data, size_t len,
1734         wusb_secrt_data_t *secrt_data)
1735 {
1736         wusb_dn_connect_t       *dn_con;
1737         uint8_t                 addr;
1738         wusb_dev_info_t         *dev_info = NULL;
1739         usb_port_t              port = 0;
1740         uint_t                  new_alloc = 0;
1741         wusb_secrt_data_t       *csecrt_data;
1742 
1743         if (len < WUSB_DN_CONN_PKT_LEN) {
1744                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1745                     "wusb_hc_handle_dn_connect: short pkt len %d", (int)len);
1746 
1747                 return;
1748         }
1749 
1750         dn_con = (wusb_dn_connect_t *)data;
1751         ASSERT(dn_con->bType == WUSB_DN_CONNECT);
1752         addr = dn_con->bmConnAttributes[0];
1753 
1754         mutex_enter(&hc_data->hc_mutex);
1755 
1756         /*
1757          * check if the device requesting to connect was ever connected
1758          * and decide connect request type
1759          */
1760         if (wusb_hc_is_dev_connected(hc_data, dn_con->CDID, &port) == 0) {
1761                 /*
1762                  * the device with the CDID was not connected.
1763                  * It should be a connect or new connect request
1764                  */
1765                 if (addr) {
1766                         /*
1767                          * the device may have been disconnected by the host
1768                          * the host expects to see a connect request instead
1769                          * of a reconnect request. The reconnect request is
1770                          * ignored.
1771                          */
1772                         USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1773                             "wusb_hc_handle_dn_connect: device has "
1774                             "disconnected, need to connect again");
1775                         mutex_exit(&hc_data->hc_mutex);
1776 
1777                         return;
1778                 }
1779 
1780                 /* assign port number */
1781                 port = wusb_hc_get_free_port(hc_data);
1782                 if (port == 0) {
1783                         USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1784                             "wusb_hc_handle_dn_connect: cannot find "
1785                             "a free port for the device connecting");
1786                         mutex_exit(&hc_data->hc_mutex);
1787 
1788                         return;
1789                 }
1790 
1791                 /* initialize dev_info structure */
1792                 dev_info = kmem_zalloc(sizeof (wusb_dev_info_t), KM_SLEEP);
1793                 /* unconnected dev addr is 0xff, refer to WUSB 1.0/7.6.1 */
1794                 dev_info->wdev_addr = 0xff;
1795                 (void) memcpy(dev_info->wdev_cdid, dn_con->CDID, 16);
1796                 dev_info->wdev_state = WUSB_STATE_CONNTING;
1797                 hc_data->hc_dev_infos[port] = dev_info;
1798                 new_alloc = 1;
1799         } else {
1800                 /*
1801                  * the device with the CDID was found connected.
1802                  * It should be a reconnect or connect request.
1803                  */
1804                 dev_info = hc_data->hc_dev_infos[port];
1805                 if ((addr != 0) && (addr == dev_info->wdev_addr)) {
1806                         dev_info->wdev_state = WUSB_STATE_RECONNTING;
1807                 } else if (addr == 0) {
1808                         dev_info->wdev_state = WUSB_STATE_CONNTING;
1809                         dev_info->wdev_addr = 0xff;
1810                 } else {
1811                         USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1812                             "wusb_hc_handle_dn_connect: reconnecting, but "
1813                             "device addr doesn't match");
1814                         mutex_exit(&hc_data->hc_mutex);
1815 
1816                         return;
1817                 }
1818 
1819                 /*
1820                  * post removal event to child device before
1821                  * reconnecting it
1822                  */
1823                 wusb_hc_disconnect_dev(hc_data, port);
1824         }
1825 
1826         dev_info->wdev_beacon_attr = dn_con->bmConnAttributes[1] &
1827             WUSB_DN_CONN_BEACON_MASK;
1828 
1829         /* refer to WUSB 1.0/7.6.1/4.13 for how New Connection bit works */
1830         if (addr == 0) {
1831                 dev_info->wdev_is_newconn = dn_con->bmConnAttributes[1] &
1832                     WUSB_DN_CONN_NEW;
1833         } else {
1834                 dev_info->wdev_is_newconn = 0;
1835         }
1836 
1837         /*
1838          * state=connting means new dev addr needs to be assigned
1839          * new_alloc=1 means newly allocated dev_info structure needs to
1840          * be freed later if the connection process fails
1841          * To simplify, the assigned address corresponds to the faked
1842          * port number.
1843          */
1844         if (dev_info->wdev_addr == 0xff) {
1845                 dev_info->wdev_addr = port + 0x7f;
1846         }
1847 
1848         /*
1849          * Acknowledge dn connect notification.
1850          * The notif queue scheme will ensure only one ack_ie exists
1851          * at one time. Don't deal with multiple ack_ie elements now
1852          */
1853         if (wusb_hc_ack_conn(hc_data, port) != USB_SUCCESS) {
1854                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1855                     "wusb_hc_handle_dn_connect: acknowledge "
1856                     "connection fails");
1857 
1858                 if (new_alloc == 1) {
1859                         kmem_free(dev_info, sizeof (wusb_dev_info_t));
1860                         hc_data->hc_dev_infos[port] = NULL;
1861                 } else {
1862                         dev_info->wdev_state = WUSB_STATE_UNCONNTED;
1863                 }
1864                 mutex_exit(&hc_data->hc_mutex);
1865 
1866                 return;
1867         }
1868 
1869         /*
1870          * Handle device connection according to connect request type
1871          * Connect Acknowledge IE is removed inside the function
1872          */
1873         if (wusb_hc_handle_port_connect(hc_data, port, ph, ifc, secrt_data) !=
1874             USB_SUCCESS) {
1875                 char *pathname = kmem_alloc(MAXPATHLEN, KM_NOSLEEP);
1876 
1877                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1878                     "wusb_hc_handle_dn_connect: connect port %d fails", port);
1879 
1880                 if (new_alloc == 1) {
1881                         if (dev_info->wdev_secrt_data.secrt_encry_descr) {
1882                                 csecrt_data = &dev_info->wdev_secrt_data;
1883                                 kmem_free(csecrt_data->secrt_encry_descr,
1884                                     sizeof (usb_encryption_descr_t) *
1885                                     csecrt_data->secrt_n_encry);
1886                         }
1887                         if (dev_info->wdev_uwb_descr) {
1888                                 kmem_free(dev_info->wdev_uwb_descr,
1889                                     sizeof (usb_uwb_cap_descr_t));
1890                         }
1891                         kmem_free(dev_info, sizeof (wusb_dev_info_t));
1892                         hc_data->hc_dev_infos[port] = NULL;
1893                 } else {
1894                         dev_info->wdev_state = WUSB_STATE_UNCONNTED;
1895                 }
1896                 mutex_exit(&hc_data->hc_mutex);
1897 
1898                 if (pathname) {
1899                         /* output error message to syslog */
1900                         cmn_err(CE_WARN, "%s %s%d: Connecting device"
1901                             " on WUSB port %d fails",
1902                             ddi_pathname(hc_data->hc_dip, pathname),
1903                             ddi_driver_name(hc_data->hc_dip),
1904                             ddi_get_instance(hc_data->hc_dip),
1905                             port);
1906 
1907                         kmem_free(pathname, MAXPATHLEN);
1908                 }
1909 
1910                 return;
1911         }
1912 
1913         mutex_exit(&hc_data->hc_mutex);
1914 }
1915 
1916 /* Handle device disconnect notification, refer to WUSB 1.0/7.6.2 */
1917 void
1918 wusb_hc_handle_dn_disconnect(wusb_hc_data_t *hc_data, uint8_t addr,
1919         uint8_t *data, size_t len)
1920 {
1921         wusb_dn_disconnect_t    *dn_discon;
1922         usb_port_t              port;
1923 
1924         if (len < WUSB_DN_DISCONN_PKT_LEN) {
1925                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1926                     "wusb_hc_handle_dn_disconnect: short pkt len %d",
1927                     (int)len);
1928 
1929                 return;
1930         }
1931 
1932         dn_discon = (wusb_dn_disconnect_t *)data;
1933         ASSERT(dn_discon->bType == WUSB_DN_DISCONNECT);
1934 
1935         mutex_enter(&hc_data->hc_mutex);
1936 
1937         /* send WDEV_DISCONNECT_IE to acknowledge the notification */
1938         if (wusb_hc_ack_disconn(hc_data, addr) != USB_SUCCESS) {
1939                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1940                     "wusb_hc_handle_dn_disconnect: send disconnect ie fails");
1941                 mutex_exit(&hc_data->hc_mutex);
1942 
1943                 return;
1944         }
1945 
1946         /* offline the device requesting disconnection */
1947         if (wusb_hc_is_addr_valid(hc_data, addr, &port)) {
1948                 (void) wusb_hc_destroy_child(hc_data, port);
1949         } else {
1950                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1951                     "wusb_hc_handle_dn_disconnect: device with addr "
1952                     "0x%x not found", addr);
1953         }
1954 
1955         mutex_exit(&hc_data->hc_mutex);
1956 }
1957 
1958 /* post disconnect event to the device driver */
1959 void
1960 wusb_hc_disconnect_dev(wusb_hc_data_t *hc_data, usb_port_t port)
1961 {
1962         dev_info_t      *dip = hc_data->hc_dip;
1963 
1964         ASSERT(dip != NULL);
1965 
1966         mutex_exit(&hc_data->hc_mutex);
1967 
1968         hc_data->disconnect_dev(dip, port);
1969 
1970         mutex_enter(&hc_data->hc_mutex);
1971 }
1972 
1973 /* post reconnect event to the device driver */
1974 void
1975 wusb_hc_reconnect_dev(wusb_hc_data_t *hc_data, usb_port_t port)
1976 {
1977         dev_info_t      *dip = hc_data->hc_dip;
1978 
1979         ASSERT(dip != NULL);
1980 
1981         mutex_exit(&hc_data->hc_mutex);
1982 
1983         hc_data->reconnect_dev(dip, port);
1984 
1985         mutex_enter(&hc_data->hc_mutex);
1986 }
1987 
1988 /* configure child device and online it */
1989 int
1990 wusb_hc_create_child(wusb_hc_data_t *hc_data, usb_port_t port)
1991 {
1992         dev_info_t      *dip = hc_data->hc_dip;
1993         int             rval;
1994 
1995         ASSERT(dip != NULL);
1996 
1997         mutex_exit(&hc_data->hc_mutex);
1998 
1999         rval = hc_data->create_child(dip, port);
2000 
2001         mutex_enter(&hc_data->hc_mutex);
2002 
2003         return (rval);
2004 }
2005 
2006 /* offline child device */
2007 int
2008 wusb_hc_destroy_child(wusb_hc_data_t *hc_data, usb_port_t port)
2009 {
2010         dev_info_t      *dip = hc_data->hc_dip;
2011         int             rval;
2012 
2013         ASSERT(dip != NULL);
2014 
2015         mutex_exit(&hc_data->hc_mutex);
2016 
2017         rval = hc_data->destroy_child(dip, port);
2018 
2019         mutex_enter(&hc_data->hc_mutex);
2020 
2021         return (rval);
2022 }
2023 
2024 
2025 /*
2026  * ***********************
2027  * CC management functions
2028  * ***********************
2029  */
2030 
2031 /* add a CC to the CC list */
2032 void
2033 wusb_hc_add_cc(wusb_hc_cc_list_t **cc_list, wusb_hc_cc_list_t *new_cc)
2034 {
2035         wusb_hc_cc_list_t       *head;
2036 
2037         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2038             "wusb_hc_add_cc: cc_list = 0x%p, new_cc = 0x%p",
2039             (void *)cc_list, (void *)new_cc);
2040 
2041         if (new_cc == NULL) {
2042 
2043                 return;
2044         }
2045 
2046         if (*cc_list == NULL) {
2047                 *cc_list = new_cc;
2048 
2049                 return;
2050         }
2051 
2052         head = *cc_list;
2053         while (head != NULL) {
2054                 /* update an existing CC */
2055                 if (memcmp(head->cc.CDID, new_cc->cc.CDID, 16) == 0) {
2056                         (void) memcpy(head->cc.CK, new_cc->cc.CK, 16);
2057                         kmem_free(new_cc, sizeof (wusb_hc_cc_list_t));
2058 
2059                         return;
2060                 }
2061 
2062                 /* add a new CC */
2063                 if (head->next == NULL) {
2064                         head->next = new_cc;
2065 
2066                         return;
2067                 }
2068 
2069                 head = head->next;
2070         }
2071 }
2072 
2073 /* remove a CC from the CC list */
2074 void
2075 wusb_hc_rem_cc(wusb_hc_cc_list_t **cc_list, wusb_cc_t *old_cc)
2076 {
2077         wusb_cc_t               *cc;
2078         wusb_hc_cc_list_t       *prev, *next;
2079 
2080         if (*cc_list == NULL || old_cc == NULL) {
2081 
2082                 return;
2083         }
2084 
2085         prev = *cc_list;
2086         cc = &prev->cc;
2087         if (memcmp(cc, old_cc, sizeof (wusb_cc_t)) == 0) {
2088                 *cc_list = prev->next;
2089                 kmem_free(prev, sizeof (wusb_hc_cc_list_t));
2090 
2091                 return;
2092         }
2093         next = prev->next;
2094         while (next != NULL) {
2095                 cc = &next->cc;
2096                 if (memcmp(cc, old_cc, sizeof (wusb_cc_t)) == 0) {
2097                         prev->next = next->next;
2098                         kmem_free(next, sizeof (wusb_hc_cc_list_t));
2099 
2100                         return;
2101                 }
2102                 prev = next;
2103                 next = prev->next;
2104         }
2105 }
2106 
2107 /* remove all CCs from the list */
2108 void
2109 wusb_hc_free_cc_list(wusb_hc_cc_list_t *cc_list)
2110 {
2111         wusb_hc_cc_list_t       *list, *next;
2112 
2113         list = cc_list;
2114         while (list != NULL) {
2115                 next = list->next;
2116                 kmem_free(list, sizeof (wusb_hc_cc_list_t));
2117                 list = next;
2118         }
2119 }
2120 
2121 /* Send Host Disconnect notification */
2122 int
2123 wusb_hc_send_host_disconnect(wusb_hc_data_t *hc_data)
2124 {
2125         wusb_ie_host_disconnect_t       *disconn_ie;
2126         uint8_t                         iehdl;
2127         int                             rval;
2128 
2129         disconn_ie = kmem_zalloc(sizeof (wusb_ie_host_disconnect_t), KM_SLEEP);
2130         disconn_ie->bIEIdentifier = WUSB_IE_HOST_DISCONNECT;
2131         disconn_ie->bLength = sizeof (wusb_ie_host_disconnect_t);
2132 
2133         mutex_enter(&hc_data->hc_mutex);
2134         rval = wusb_hc_get_iehdl(hc_data, (wusb_ie_header_t *)disconn_ie,
2135             &iehdl);
2136         mutex_exit(&hc_data->hc_mutex);
2137         if (rval != USB_SUCCESS) {
2138                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2139                     "wusb_hc_send_host_disconnect: get ie handle fails");
2140                 kmem_free(disconn_ie, sizeof (wusb_ie_host_disconnect_t));
2141 
2142                 return (rval);
2143         }
2144 
2145         rval = wusb_hc_add_mmc_ie(hc_data, 0, 0, iehdl,
2146             disconn_ie->bLength, (uint8_t *)disconn_ie);
2147         if (rval != USB_SUCCESS) {
2148                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2149                     "wusb_hc_send_host_disconnect: add host "
2150                     "disconnect ie fails");
2151                 mutex_enter(&hc_data->hc_mutex);
2152                 wusb_hc_free_iehdl(hc_data, iehdl);
2153                 mutex_exit(&hc_data->hc_mutex);
2154                 kmem_free(disconn_ie, sizeof (wusb_ie_host_disconnect_t));
2155 
2156                 return (rval);
2157         }
2158 
2159         delay(drv_usectohz(100000));    /* WUSB 1.0/7.5.5 */
2160 
2161         mutex_enter(&hc_data->hc_mutex);
2162         (void) wusb_hc_remove_mmc_ie(hc_data, iehdl);
2163         wusb_hc_free_iehdl(hc_data, iehdl);
2164         mutex_exit(&hc_data->hc_mutex);
2165 
2166         kmem_free(disconn_ie, sizeof (wusb_ie_host_disconnect_t));
2167 
2168         return (USB_SUCCESS);
2169 }
2170 
2171 /* Get RC dev_t by HC dip */
2172 int
2173 wusb_get_rc_dev_by_hc(dev_info_t *dip, dev_t *dev)
2174 {
2175         dev_info_t      *pdip = ddi_get_parent(dip);
2176         dev_info_t      *rcdip;
2177         int             found = 0;
2178         major_t         major;
2179         minor_t         minor;
2180         int             inst;
2181 
2182         if (strcmp(ddi_driver_name(dip), "whci") == 0) {
2183                 /* For WHCI, RC and HC share the same dip */
2184                 rcdip = dip;
2185                 inst = ddi_get_instance(rcdip);
2186                 /* need to change when whci driver is ready */
2187                 minor = inst;
2188                 found = 1;
2189         } else {
2190                 /* For HWA, RC and HC share the same parent dip */
2191                 rcdip = ddi_get_child(pdip);
2192                 while (rcdip != NULL) {
2193                         if (strcmp(ddi_driver_name(rcdip), "hwarc") == 0) {
2194                                 found = 1;
2195                                 inst = ddi_get_instance(rcdip);
2196                                 // minor = HWAHC_CONSTRUCT_MINOR(inst);
2197                                 /*
2198                                  * now hwarc driver uses inst# as minor#.
2199                                  * this may change
2200                                  */
2201                                 minor = inst;
2202 
2203                                 break;
2204                         }
2205                         rcdip = ddi_get_next_sibling(rcdip);
2206                 }
2207         }
2208 
2209         if (found == 0) {
2210                 *dev = 0;
2211 
2212                 return (USB_FAILURE);
2213         }
2214 
2215         major = ddi_driver_major(rcdip);
2216         *dev = makedevice(major, minor);
2217 
2218         USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2219             "wusb_get_rc_dev_by_hc: rc device(%s%d) major = %d, minor = %d",
2220             ddi_driver_name(rcdip), inst, major, minor);
2221 
2222         return (USB_SUCCESS);
2223 }
2224 
2225 /* format nonce to a buffer according to WUSB Table 6-3 */
2226 static void
2227 nonce_to_buf(wusb_ccm_nonce_t *nonce, uchar_t *nbuf, int sfn_only)
2228 {
2229         int i, offset;
2230         uchar_t *p = nbuf;
2231 
2232         for (i = 0, offset = 0; i < 6; i++, offset += 8) {
2233                 *p++ = (nonce->sfn >> offset) & 0xff;
2234         }
2235 
2236         if (sfn_only) {
2237 
2238                 return;
2239         }
2240 
2241         *p++ = (nonce->tkid) & 0xff;
2242         *p++ = (nonce->tkid >> 8) & 0xff;
2243         *p++ = (nonce->tkid >> 16) & 0xff;
2244 
2245         *p++ = (nonce->daddr) & 0xff;
2246         *p++ = (nonce->daddr >> 8) & 0xff;
2247 
2248         *p++ = (nonce->saddr) & 0xff;
2249         *p++ = (nonce->saddr >> 8) & 0xff;
2250 }
2251 
2252 /* Call the crypto framework to compute CCM MAC data */
2253 static int
2254 wusb_ccm_mac(
2255         CK_AES_CCM_PARAMS *ccm_params,
2256         const uchar_t *key, size_t klen,
2257         uchar_t *out, int olen)
2258 {
2259         crypto_mechanism_t mech;
2260         crypto_key_t crkey;
2261         crypto_context_t ctx;
2262         crypto_data_t dmac;
2263         int ret;
2264 
2265         bzero(&crkey, sizeof (crkey));
2266         crkey.ck_format = CRYPTO_KEY_RAW;
2267         crkey.ck_data   = (char *)key;
2268         crkey.ck_length = klen * 8;
2269 
2270         mech.cm_type      = crypto_mech2id(SUN_CKM_AES_CCM);
2271         mech.cm_param     = (caddr_t)ccm_params;
2272         mech.cm_param_len = sizeof (CK_AES_CCM_PARAMS);
2273 
2274         if ((ret = crypto_encrypt_init(&mech, &crkey, NULL, &ctx, NULL)) !=
2275             CRYPTO_SUCCESS) {
2276 
2277                 return (ret);
2278         }
2279 
2280         /*
2281          * Since we've known the encrypted data is none (l(m) = 0),
2282          * the middle procedure crypto_encrypt_update() is ignored.
2283          * The last 8-byte MAC is calculated directly.
2284          */
2285 
2286         bzero(&dmac, sizeof (dmac));
2287         dmac.cd_format = CRYPTO_DATA_RAW;
2288         dmac.cd_offset = 0;
2289         dmac.cd_length = olen;
2290         dmac.cd_raw.iov_base = (char *)out;
2291         dmac.cd_raw.iov_len = olen;
2292 
2293         if ((ret = crypto_encrypt_final(ctx, &dmac, NULL)) != CRYPTO_SUCCESS) {
2294 
2295                 return (ret);
2296         }
2297 
2298         return (CRYPTO_SUCCESS);
2299 }
2300 
2301 /* Pseudo-Random Function according to WUSB 1.0/6.5 */
2302 int
2303 PRF(const uchar_t *key, size_t klen,
2304         wusb_ccm_nonce_t *nonce,
2305         const uchar_t *adata, size_t alen,
2306         const uchar_t *bdata, size_t blen,
2307         uchar_t *out,
2308         size_t bitlen)
2309 {
2310         CK_AES_CCM_PARAMS ccm_params;
2311         uchar_t *ab;
2312         uchar_t nbuf[CCM_NONCE_LEN];
2313         size_t lm, la;
2314         int i, offset, ret;
2315 
2316         /* from WUSB 6.4 */
2317         lm = 0;
2318         la = alen + blen;
2319         ab = (uchar_t *)kmem_alloc(la, KM_SLEEP);
2320         bcopy(adata, ab, alen);
2321         bcopy(bdata, ab + alen, blen);
2322 
2323         nonce_to_buf(nonce, nbuf, 0);
2324 
2325         ccm_params.ulMACSize = CCM_MAC_LEN;
2326         ccm_params.ulNonceSize = CCM_NONCE_LEN;
2327         ccm_params.nonce = nbuf;
2328         ccm_params.ulAuthDataSize = la; /* l(a) */
2329         ccm_params.authData = ab;
2330         ccm_params.ulDataSize = lm;     /* l(m) */
2331 
2332         offset = 0;
2333         for (i = 0; i < (bitlen + 63)/64; i++) {
2334                 ret = wusb_ccm_mac(&ccm_params, key, klen,
2335                     out + offset, CCM_MAC_LEN);
2336 
2337                 if (ret != CRYPTO_SUCCESS) {
2338                         kmem_free(ab, la);
2339 
2340                         return (ret);
2341                 };
2342 
2343                 offset += CCM_MAC_LEN;
2344                 nonce->sfn++;
2345                 nonce_to_buf(nonce, nbuf, 1);
2346         }
2347 
2348         kmem_free(ab, la);
2349 
2350         return (CRYPTO_SUCCESS);
2351 }
2352 
2353 /* rbuf is a 16-byte buffer to store the random nonce */
2354 int
2355 wusb_gen_random_nonce(wusb_hc_data_t *hc_data,
2356         wusb_dev_info_t *dev_info, uchar_t *rbuf)
2357 {
2358         usba_device_t *udev = usba_get_usba_device(hc_data->hc_dip);
2359         wusb_ccm_nonce_t n;
2360         uint16_t vid, pid;
2361         uint64_t ht;
2362         uint8_t kbuf[16], *p;
2363         uchar_t a[] = "Random Numbers";
2364 
2365         n.sfn = 0;
2366         n.tkid = dev_info->wdev_tkid[0] | (dev_info->wdev_tkid[1] << 8) |
2367             (dev_info->wdev_tkid[2] << 16);
2368         n.daddr = hc_data->hc_addr;
2369         n.saddr = dev_info->wdev_addr;
2370 
2371         vid = udev->usb_dev_descr->idVendor;
2372         pid = udev->usb_dev_descr->idProduct;
2373         ht = gethrtime();
2374 
2375         p = kbuf;
2376         bcopy((uint8_t *)&vid, p, sizeof (uint16_t));
2377         p += sizeof (uint16_t);
2378 
2379         bcopy((uint8_t *)&pid, p, sizeof (uint16_t));
2380         p += sizeof (uint16_t);
2381 
2382         bcopy((uint8_t *)&p, p, sizeof (uint32_t));
2383         p += sizeof (uint32_t);
2384 
2385         bcopy((uint8_t *)&ht, p, sizeof (uint64_t));
2386 
2387         return (PRF_128(kbuf, 16, &n, a, sizeof (a),
2388             (uchar_t *)hc_data, sizeof (wusb_hc_data_t), rbuf));
2389 }
2390 
2391 /* Set WUSB device encryption type, refer to WUSB 1.0/7.3.2.2 */
2392 int
2393 wusb_dev_set_encrypt(usb_pipe_handle_t ph, uint8_t value)
2394 {
2395         usb_ctrl_setup_t        setup;
2396         usb_cr_t                cr;
2397         usb_cb_flags_t          cb_flags;
2398 
2399         setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV;
2400         setup.bRequest = USB_REQ_SET_ENCRYPTION;
2401         setup.wValue = value;
2402         setup.wIndex = 0;
2403         setup.wLength = 0;
2404         setup.attrs = USB_ATTRS_NONE;
2405 
2406         return (usb_pipe_ctrl_xfer_wait(ph, &setup, NULL,
2407             &cr, &cb_flags, USB_FLAGS_SLEEP));
2408 }
2409 
2410 /*
2411  * Set WUSB device key descriptor, refer to WUSB 1.0/7.3.2.4
2412  *      ph - Device's default control pipe
2413  *      key_index - Key Index
2414  */
2415 int
2416 wusb_dev_set_key(usb_pipe_handle_t ph, uint8_t key_index,
2417         usb_key_descr_t *key, size_t klen)
2418 {
2419         usb_ctrl_setup_t        setup;
2420         usb_cr_t                cr;
2421         usb_cb_flags_t          cb_flags;
2422         mblk_t                  *pdata;
2423         int                     rval;
2424 
2425         setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV;
2426         setup.bRequest = USB_REQ_SET_DESCR;
2427         setup.wValue = (USB_DESCR_TYPE_KEY << 8) | key_index;
2428         setup.wIndex = 0;
2429         setup.wLength = (uint16_t)klen;
2430         setup.attrs = USB_ATTRS_NONE;
2431 
2432         if ((pdata = allocb(klen, BPRI_HI)) == NULL) {
2433 
2434                 return (USB_FAILURE);
2435         }
2436         bcopy(key, pdata->b_wptr, klen);
2437         pdata->b_wptr += klen;
2438 
2439         rval = usb_pipe_ctrl_xfer_wait(ph, &setup, &pdata,
2440             &cr, &cb_flags, USB_FLAGS_SLEEP);
2441 
2442         freemsg(pdata);
2443 
2444         return (rval);
2445 }
2446 
2447 /*
2448  * Set encryption type for the specified device.
2449  */
2450 int
2451 wusb_hc_set_encrypt(wusb_hc_data_t *hc_data, usb_port_t port, uint8_t type)
2452 {
2453         dev_info_t      *dip = hc_data->hc_dip;
2454         int             rval;
2455 
2456         if ((rval = hc_data->set_encrypt(dip, port, type)) != USB_SUCCESS) {
2457                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2458                     "wusb_hc_set_encrypt: set encryption type %d "
2459                     "for port %d failed, rval = %d", type, port, rval);
2460         }
2461 
2462         return (rval);
2463 }
2464 
2465 /*
2466  * Set Device Key for WUSB host, refer to WUSB 1.0/8.5.3.8
2467  * Call the HC's specific set_ptk function to set PTK for a device
2468  * len: length of key_data
2469  */
2470 int
2471 wusb_hc_set_ptk(wusb_hc_data_t *hc_data, uint8_t *key_data, usb_port_t port)
2472 {
2473         dev_info_t      *dip = hc_data->hc_dip;
2474         wusb_dev_info_t *dev_info = hc_data->hc_dev_infos[port];
2475         usb_key_descr_t *key_descr;
2476         size_t          klen;
2477         int             rval;
2478         uint8_t         *p;
2479 
2480         ASSERT(mutex_owned(&hc_data->hc_mutex));
2481 
2482         if ((key_data == NULL) || (dev_info == NULL)) {
2483 
2484                 return (USB_INVALID_ARGS);
2485         }
2486 
2487         klen = sizeof (usb_key_descr_t) + 15;
2488         key_descr = kmem_zalloc(klen, KM_SLEEP);
2489 
2490         key_descr->bLength = (uint16_t)klen;
2491         key_descr->bDescriptorType = USB_DESCR_TYPE_KEY;
2492         (void) memcpy(key_descr->tTKID, dev_info->wdev_tkid, 3);
2493         p = &key_descr->KeyData[0];
2494         (void) memcpy(p, key_data, 16);
2495 
2496         mutex_exit(&hc_data->hc_mutex);
2497 
2498         if ((rval = hc_data->set_ptk(dip, key_descr, klen, port)) !=
2499             USB_SUCCESS) {
2500                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2501                     "wusb_hc_set_pkt: set ptk for port %d failed", port);
2502         }
2503 
2504         kmem_free(key_descr, klen);
2505         mutex_enter(&hc_data->hc_mutex);
2506 
2507         return (rval);
2508 }
2509 
2510 /*
2511  * Set GTK for a host
2512  * Call HC's specific set_gtk function
2513  *
2514  * Default gtk is set at hc_initial_start, and to be changed whenever
2515  * a device leaves the current group (refer to WUSB spec 6.2.11.2)
2516  */
2517 int
2518 wusb_hc_set_gtk(wusb_hc_data_t *hc_data, uint8_t *key_data, uint8_t *tkid)
2519 {
2520         dev_info_t      *dip = hc_data->hc_dip;
2521         usb_key_descr_t *key_descr;
2522         size_t          klen;
2523         int             rval;
2524         uint8_t         *p;
2525 
2526         if ((key_data == NULL) || (tkid == NULL)) {
2527 
2528                 return (USB_INVALID_ARGS);
2529         }
2530 
2531         klen = sizeof (usb_key_descr_t) + 15;
2532         key_descr = kmem_zalloc(klen, KM_SLEEP);
2533 
2534         key_descr->bLength = (uint16_t)klen;
2535         key_descr->bDescriptorType = USB_DESCR_TYPE_KEY;
2536         (void) memcpy(key_descr->tTKID, tkid, 3);
2537         p = &key_descr->KeyData[0];
2538         (void) memcpy(p, key_data, 16);
2539 
2540         if ((rval = hc_data->set_gtk(dip, key_descr, klen)) !=
2541             USB_SUCCESS) {
2542                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2543                     "wusb_hc_set_gkt: set gtk failed");
2544         }
2545 
2546         (void) memcpy(&hc_data->hc_gtk, key_descr, klen);
2547         kmem_free(key_descr, klen);
2548 
2549         return (rval);
2550 }
2551 
2552 /* Set Device Info for WUSB host, refer to WUSB 1.0/8.5.3.7 */
2553 int
2554 wusb_hc_set_device_info(wusb_hc_data_t *hc_data, usb_port_t port)
2555 {
2556         wusb_dev_info_t         *dev_info;
2557         int                     rval;
2558 
2559         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2560             "wusb_hc_set_device_info: port = %d", port);
2561 
2562         dev_info = hc_data->hc_dev_infos[port];
2563         rval = hc_data->set_device_info(hc_data->hc_dip, dev_info, port);
2564         if (rval != USB_SUCCESS) {
2565                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2566                     "wusb_hc_set_device_info: the host failed to set "
2567                     "device info, rval = %d", rval);
2568         }
2569 
2570         return (rval);
2571 }
2572 
2573 /*
2574  * Set/Get Handshake Data to/from WUSB device, refer to WUSB 1.0/7.3.2.5
2575  * step = 1, 2, 3
2576  */
2577 int
2578 wusb_handshake(usb_pipe_handle_t pipe, wusb_hndshk_data_t *hs, int step)
2579 {
2580         usb_ctrl_setup_t        setup;
2581         mblk_t                  *pdata;
2582         usb_cr_t                cr;
2583         usb_cb_flags_t          cb_flags;
2584         int                     rval;
2585 
2586         if (step == 2) {
2587                 /* get handshake */
2588                 setup.bmRequestType = USB_DEV_REQ_DEV_TO_HOST;
2589                 setup.bRequest = USB_REQ_GET_HANDSHAKE;
2590                 pdata = NULL;
2591         } else if ((step == 1) || (step == 3)) {
2592                 /* set handshake */
2593                 setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV;
2594                 setup.bRequest = USB_REQ_SET_HANDSHAKE;
2595 
2596                 if ((pdata = allocb(WUSB_HNDSHK_DATA_LEN, BPRI_HI)) == NULL) {
2597 
2598                         return (USB_NO_RESOURCES);
2599                 }
2600                 bcopy(hs, pdata->b_wptr, WUSB_HNDSHK_DATA_LEN);
2601                 pdata->b_wptr += WUSB_HNDSHK_DATA_LEN;
2602         } else {
2603                 /* step value is invalid */
2604                 return (USB_INVALID_ARGS);
2605         }
2606 
2607         setup.wValue = (uint16_t)step;
2608         setup.wIndex = 0;
2609         setup.wLength = WUSB_HNDSHK_DATA_LEN;
2610         setup.attrs = USB_ATTRS_NONE;
2611 
2612         rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
2613             &cr, &cb_flags, USB_FLAGS_SLEEP);
2614 
2615         if (step == 2) {
2616                 if (pdata) {
2617                         bcopy(pdata->b_rptr, hs, msgsize(pdata));
2618                         freemsg(pdata);
2619                 }
2620         } else {
2621                 freemsg(pdata);
2622         }
2623 
2624         return (rval);
2625 }
2626 
2627 /* search the security descrs for CCM encryption type descr */
2628 int16_t
2629 wusb_get_ccm_encryption_value(wusb_secrt_data_t *secrt_data)
2630 {
2631         usb_encryption_descr_t  *encry_descr;
2632         int                     i;
2633         int16_t                 value = -1;
2634 
2635         for (i = 0; i < secrt_data->secrt_n_encry; i++) {
2636                 encry_descr = &secrt_data->secrt_encry_descr[i];
2637                 if (encry_descr->bEncryptionType == USB_ENC_TYPE_CCM_1) {
2638                         value = encry_descr->bEncryptionValue;
2639                         USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2640                             "ccm encryption value is %d", value);
2641 
2642                         break;
2643                 }
2644         }
2645 
2646         return (value);
2647 }
2648 
2649 static void
2650 wusb_print_handshake_data(wusb_hndshk_data_t *hs, int step)
2651 {
2652         uint8_t         *p;
2653 
2654         USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2655             "handshake %d data:", step);
2656         USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2657             "%x %x (TKID)%x %x %x %x", hs->bMessageNumber, hs->bStatus,
2658             hs->tTKID[0], hs->tTKID[1], hs->tTKID[2], hs->bReserved);
2659 
2660         p = hs->CDID;
2661 
2662         USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2663             "(CDID)%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
2664             p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9],
2665             p[10], p[11], p[12], p[13], p[14], p[15]);
2666 
2667         p = hs->Nonce;
2668         USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2669             "(Nonce)%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
2670             p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9],
2671             p[10], p[11], p[12], p[13], p[14], p[15]);
2672 
2673         p = hs->MIC;
2674         USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
2675             "(MIC)%x %x %x %x %x %x %x %x",
2676             p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
2677 }
2678 
2679 /* ARGSUSED */
2680 /*
2681  * Do 4way handshake and other necessary control operations to
2682  * transit the device to authenticated state
2683  * refer to WUSB 1.0 [7.3.2.5, 6.2.10.9.1, 7.1.2]
2684  * ph - pipe handle of the host controller
2685  */
2686 int
2687 wusb_4way_handshake(wusb_hc_data_t *hc_data, usb_port_t port,
2688         usb_pipe_handle_t ph, uint8_t ifc)
2689 {
2690         uint8_t                 tkid[3];
2691         wusb_ccm_nonce_t        n;
2692         wusb_hndshk_data_t      *hs;
2693         wusb_dev_info_t         *dev_info;
2694         wusb_cc_t               *cc;
2695         uchar_t                 adata1[] = "Pair-wise keys";
2696         uchar_t                 adata2[] = "out-of-bandMIC";
2697         uchar_t                 bdata[32], keyout[32], mic[8];
2698         int                     rval;
2699         usb_pipe_handle_t       w_ph;
2700 
2701         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2702             "wusb_4way_handshake: port = %d", port);
2703 
2704         mutex_enter(&hc_data->hc_mutex);
2705         dev_info = hc_data->hc_dev_infos[port];
2706         if (dev_info == NULL) {
2707                 mutex_exit(&hc_data->hc_mutex);
2708 
2709                 return (USB_FAILURE);
2710         }
2711         cc = dev_info->wdev_cc;
2712         if (dev_info->wdev_ph == NULL || cc == NULL) {
2713                 mutex_exit(&hc_data->hc_mutex);
2714 
2715                 return (USB_FAILURE);
2716         }
2717 
2718         w_ph = dev_info->wdev_ph;
2719 
2720         hs = (wusb_hndshk_data_t *)kmem_zalloc(
2721             3 * sizeof (wusb_hndshk_data_t), KM_SLEEP);
2722 
2723         /* tkid is generated dynamically and saved in dev_info */
2724         (void) random_get_pseudo_bytes(tkid, 3);
2725 
2726         (void) memcpy(dev_info->wdev_tkid, tkid, 3);
2727 
2728         /* handshake 1 */
2729         hs[0].bMessageNumber = 1;
2730         hs[0].bStatus = 0;
2731         (void) memcpy(hs[0].tTKID, tkid, 3);
2732         hs[0].bReserved = 0;
2733         bcopy(cc->CDID, hs[0].CDID, WUSB_CDID_LEN);
2734 
2735         if ((rval = wusb_gen_random_nonce(hc_data, dev_info, hs[0].Nonce))
2736             != USB_SUCCESS) {
2737                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2738                     "Nonce generation failed: %d", rval);
2739                 mutex_exit(&hc_data->hc_mutex);
2740 
2741                 goto done;
2742         }
2743 
2744         wusb_print_handshake_data(&hs[0], 1);
2745         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2746             "wusb_4way_handshake: shake 1.............");
2747 
2748         mutex_exit(&hc_data->hc_mutex);
2749         rval = wusb_handshake(w_ph, &(hs[0]), 1);
2750         if (rval != USB_SUCCESS) {
2751                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2752                     "handshake 1 failed, rval = %d", rval);
2753 
2754                 goto done;
2755         }
2756 
2757         /* handshake 2 */
2758         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2759             "wusb_4way_handshake: shake 2.............");
2760         rval = wusb_handshake(w_ph, &(hs[1]), 2);
2761         if (rval != USB_SUCCESS) {
2762                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2763                     "handshake 2 failed, rval = %d", rval);
2764 
2765                 goto done;
2766         }
2767 
2768         if (hs[1].bMessageNumber != 2 || hs[1].bStatus != 0) {
2769                 rval = USB_FAILURE;
2770 
2771                 goto done;
2772         }
2773 
2774         wusb_print_handshake_data(&hs[1], 2);
2775 
2776         /* derived session keys, refer to WUSB 1.0/6.5.1 */
2777         n.sfn = 0;
2778         n.tkid = tkid[0] | (tkid[1]<<8) | (tkid[2] << 16);
2779 
2780         mutex_enter(&hc_data->hc_mutex);
2781         n.daddr = dev_info->wdev_addr;
2782 
2783         n.saddr = hc_data->hc_addr;
2784         bcopy(hs[0].Nonce, bdata, 16);
2785         bcopy(hs[1].Nonce, bdata + 16, 16);
2786         mutex_exit(&hc_data->hc_mutex);
2787 
2788         rval = PRF_256(cc->CK, 16, &n, adata1, 14, bdata, 32, keyout);
2789         if (rval != 0) {
2790                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2791                     "compute keys failed, rval = %d", rval);
2792 
2793                 goto done;
2794         }
2795 
2796         /* sfn was changed in PRF(). Need to reset it to 0 */
2797         n.sfn = 0;
2798 
2799         /* used the derived KCK to verify received MIC (WUSB 1.0/6.5.2] */
2800         rval = PRF_64(keyout, 16, &n, adata2, 14, (uchar_t *)(&hs[1]),
2801             WUSB_HNDSHK_DATA_LEN - 8, mic);
2802         if (rval != 0) {
2803                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2804                     "compute MIC failed, rval = %d", rval);
2805 
2806                 goto done;
2807         }
2808 
2809         if (memcmp(hs[1].MIC, mic, 8) != 0) {
2810                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2811                     "verify mic failed");
2812                 rval = USB_FAILURE;
2813 
2814                 goto done;
2815         }
2816 
2817         /* handshake 3 */
2818         bcopy(&hs[0], &hs[2], WUSB_HNDSHK_DATA_LEN - 8);
2819         hs[2].bMessageNumber = 3;
2820         n.sfn = 0;
2821         rval = PRF_64(keyout, 16, &n, adata2, 14, (uchar_t *)(&hs[2]),
2822             WUSB_HNDSHK_DATA_LEN - 8, hs[2].MIC);
2823         if (rval != 0) {
2824                 goto done;
2825         }
2826 
2827         wusb_print_handshake_data(&hs[2], 3);
2828 
2829         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2830             "wusb_4way_handshake: shake 3.............");
2831         rval = wusb_handshake(w_ph, &(hs[2]), 3);
2832         if (rval != USB_SUCCESS) {
2833                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2834                     "handshake 3 failed, rval = %d", rval);
2835 
2836                 goto done;
2837         }
2838 
2839         mutex_enter(&hc_data->hc_mutex);
2840         /* set PTK for host */
2841         (void) memcpy(dev_info->wdev_ptk, keyout + 16, 16);
2842 
2843         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2844             "wusb_4way_handshake: set ptk .............");
2845         rval = wusb_hc_set_ptk(hc_data, dev_info->wdev_ptk, port);
2846         mutex_exit(&hc_data->hc_mutex);
2847         if (rval != USB_SUCCESS) {
2848                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2849                     "set ptk for host failed, rval = %d", rval);
2850 
2851                 goto done;
2852         }
2853 
2854         /*
2855          * enable CCM encryption on the host
2856          * according to WUSB 1.0/7.1.2, the encryption mode must be
2857          * enabled before setting GTK onto device
2858          */
2859         USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
2860             "wusb_4way_handshake: hc set encrypt .............");
2861         rval = wusb_hc_set_encrypt(hc_data, port, WUSB_ENCRYP_TYPE_CCM_1);
2862         if (rval != USB_SUCCESS) {
2863                 USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2864                     "set encryption for host failed, rval = %d", rval);
2865 
2866                 goto done;
2867         }
2868 
2869         /*
2870          * set GTK for device
2871          * GTK is initialized when hc_data is inited
2872          */
2873         rval = wusb_dev_set_key(w_ph, 2 << 4,
2874             &hc_data->hc_gtk, hc_data->hc_gtk.bLength);
2875 done:
2876         kmem_free(hs, 3 * sizeof (wusb_hndshk_data_t));
2877         if (rval != USB_SUCCESS) {
2878                 /* restore the host to unsecure mode */
2879                 (void) wusb_hc_set_encrypt(hc_data, port,
2880                     WUSB_ENCRYP_TYPE_UNSECURE);
2881         }
2882 
2883         return (rval);
2884 }