19430SRaymond.Chen@Sun.COM /*
29430SRaymond.Chen@Sun.COM * CDDL HEADER START
39430SRaymond.Chen@Sun.COM *
49430SRaymond.Chen@Sun.COM * The contents of this file are subject to the terms of the
59430SRaymond.Chen@Sun.COM * Common Development and Distribution License (the "License").
69430SRaymond.Chen@Sun.COM * You may not use this file except in compliance with the License.
79430SRaymond.Chen@Sun.COM *
89430SRaymond.Chen@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99430SRaymond.Chen@Sun.COM * or http://www.opensolaris.org/os/licensing.
109430SRaymond.Chen@Sun.COM * See the License for the specific language governing permissions
119430SRaymond.Chen@Sun.COM * and limitations under the License.
129430SRaymond.Chen@Sun.COM *
139430SRaymond.Chen@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
149430SRaymond.Chen@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159430SRaymond.Chen@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
169430SRaymond.Chen@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
179430SRaymond.Chen@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
189430SRaymond.Chen@Sun.COM *
199430SRaymond.Chen@Sun.COM * CDDL HEADER END
209430SRaymond.Chen@Sun.COM */
219430SRaymond.Chen@Sun.COM /*
229430SRaymond.Chen@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
239430SRaymond.Chen@Sun.COM * Use is subject to license terms.
249430SRaymond.Chen@Sun.COM */
259430SRaymond.Chen@Sun.COM
269430SRaymond.Chen@Sun.COM
279430SRaymond.Chen@Sun.COM /*
289430SRaymond.Chen@Sun.COM * USBA: Solaris USB Architecture support
299430SRaymond.Chen@Sun.COM *
309430SRaymond.Chen@Sun.COM * whcdi.c is part of the WUSB extension to the USBA framework.
319430SRaymond.Chen@Sun.COM *
329430SRaymond.Chen@Sun.COM * It mainly contains functions that can be shared by whci and hwahc
339430SRaymond.Chen@Sun.COM * drivers to enable WUSB host functionality, such as WUSB channel
349430SRaymond.Chen@Sun.COM * resource management, MMC IE handling, WUSB HC specific requests,
359430SRaymond.Chen@Sun.COM * WUSB device authentication, child connection/disconnection, etc.
369430SRaymond.Chen@Sun.COM */
379430SRaymond.Chen@Sun.COM #define USBA_FRAMEWORK
389430SRaymond.Chen@Sun.COM #include <sys/usb/usba.h>
399430SRaymond.Chen@Sun.COM #include <sys/usb/usba/usba_impl.h>
409430SRaymond.Chen@Sun.COM #include <sys/usb/usba/usba_types.h>
419430SRaymond.Chen@Sun.COM #include <sys/usb/usba/hcdi_impl.h> /* for usba_hcdi_t */
429430SRaymond.Chen@Sun.COM #include <sys/usb/usba/whcdi.h>
439430SRaymond.Chen@Sun.COM #include <sys/usb/usba/wa.h>
449430SRaymond.Chen@Sun.COM #include <sys/strsubr.h>
459430SRaymond.Chen@Sun.COM #include <sys/crypto/api.h>
469430SRaymond.Chen@Sun.COM #include <sys/strsun.h>
479430SRaymond.Chen@Sun.COM #include <sys/random.h>
489430SRaymond.Chen@Sun.COM
499430SRaymond.Chen@Sun.COM /*
509430SRaymond.Chen@Sun.COM * local variables
519430SRaymond.Chen@Sun.COM */
529430SRaymond.Chen@Sun.COM static kmutex_t whcdi_mutex;
539430SRaymond.Chen@Sun.COM
549430SRaymond.Chen@Sun.COM /* use 0-30 bit as wusb cluster_id bitmaps */
559430SRaymond.Chen@Sun.COM static uint32_t cluster_id_mask = 0;
569430SRaymond.Chen@Sun.COM
579797SRaymond.Chen@Sun.COM _NOTE(MUTEX_PROTECTS_DATA(whcdi_mutex, cluster_id_mask))
589430SRaymond.Chen@Sun.COM
599430SRaymond.Chen@Sun.COM usb_log_handle_t whcdi_log_handle;
609430SRaymond.Chen@Sun.COM uint_t whcdi_errlevel = USB_LOG_L4;
619430SRaymond.Chen@Sun.COM uint_t whcdi_errmask = (uint_t)-1;
629430SRaymond.Chen@Sun.COM
639430SRaymond.Chen@Sun.COM /*
649430SRaymond.Chen@Sun.COM * initialize private data
659430SRaymond.Chen@Sun.COM */
669430SRaymond.Chen@Sun.COM void
usba_whcdi_initialization()679430SRaymond.Chen@Sun.COM usba_whcdi_initialization()
689430SRaymond.Chen@Sun.COM {
699430SRaymond.Chen@Sun.COM whcdi_log_handle = usb_alloc_log_hdl(NULL, "whcdi", &whcdi_errlevel,
709430SRaymond.Chen@Sun.COM &whcdi_errmask, NULL, 0);
719430SRaymond.Chen@Sun.COM
729430SRaymond.Chen@Sun.COM USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
739430SRaymond.Chen@Sun.COM "whcdi_initialization");
749430SRaymond.Chen@Sun.COM
759430SRaymond.Chen@Sun.COM mutex_init(&whcdi_mutex, NULL, MUTEX_DRIVER, NULL);
769430SRaymond.Chen@Sun.COM }
779430SRaymond.Chen@Sun.COM
789430SRaymond.Chen@Sun.COM void
usba_whcdi_destroy()799430SRaymond.Chen@Sun.COM usba_whcdi_destroy()
809430SRaymond.Chen@Sun.COM {
819430SRaymond.Chen@Sun.COM USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
829430SRaymond.Chen@Sun.COM "whcdi_destroy");
839430SRaymond.Chen@Sun.COM
849430SRaymond.Chen@Sun.COM mutex_destroy(&whcdi_mutex);
859430SRaymond.Chen@Sun.COM
869430SRaymond.Chen@Sun.COM usb_free_log_hdl(whcdi_log_handle);
879430SRaymond.Chen@Sun.COM }
889430SRaymond.Chen@Sun.COM
899430SRaymond.Chen@Sun.COM /*
909430SRaymond.Chen@Sun.COM * Assign a cluster id for a WUSB channel
919430SRaymond.Chen@Sun.COM * return 0 if no free cluster id is available
929430SRaymond.Chen@Sun.COM */
939430SRaymond.Chen@Sun.COM uint8_t
wusb_hc_get_cluster_id()949430SRaymond.Chen@Sun.COM wusb_hc_get_cluster_id()
959430SRaymond.Chen@Sun.COM {
969430SRaymond.Chen@Sun.COM int i;
979430SRaymond.Chen@Sun.COM uint8_t id;
989430SRaymond.Chen@Sun.COM
999430SRaymond.Chen@Sun.COM mutex_enter(&whcdi_mutex);
1009430SRaymond.Chen@Sun.COM for (i = 0; i < WUSB_CLUSTER_ID_COUNT; i++) {
1019430SRaymond.Chen@Sun.COM /* find the first unused slot */
1029430SRaymond.Chen@Sun.COM if (cluster_id_mask & (1 << i)) {
1039430SRaymond.Chen@Sun.COM continue;
1049430SRaymond.Chen@Sun.COM }
1059430SRaymond.Chen@Sun.COM
1069430SRaymond.Chen@Sun.COM /* set the bitmask */
1079430SRaymond.Chen@Sun.COM cluster_id_mask |= (1 << i);
1089430SRaymond.Chen@Sun.COM id = WUSB_MIN_CLUSTER_ID + i;
1099430SRaymond.Chen@Sun.COM USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
1109430SRaymond.Chen@Sun.COM "new cluster id %d, mask %d", id, cluster_id_mask);
1119797SRaymond.Chen@Sun.COM mutex_exit(&whcdi_mutex);
1129430SRaymond.Chen@Sun.COM
1139430SRaymond.Chen@Sun.COM return (id);
1149430SRaymond.Chen@Sun.COM }
1159430SRaymond.Chen@Sun.COM
1169430SRaymond.Chen@Sun.COM mutex_exit(&whcdi_mutex);
1179430SRaymond.Chen@Sun.COM
1189430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1199430SRaymond.Chen@Sun.COM "no cluster id available");
1209430SRaymond.Chen@Sun.COM
1219430SRaymond.Chen@Sun.COM return (0);
1229430SRaymond.Chen@Sun.COM }
1239430SRaymond.Chen@Sun.COM
1249430SRaymond.Chen@Sun.COM /* Free the cluster id */
1259430SRaymond.Chen@Sun.COM void
wusb_hc_free_cluster_id(uint8_t id)1269430SRaymond.Chen@Sun.COM wusb_hc_free_cluster_id(uint8_t id)
1279430SRaymond.Chen@Sun.COM {
1289430SRaymond.Chen@Sun.COM int i = id - WUSB_MIN_CLUSTER_ID;
1299430SRaymond.Chen@Sun.COM
1309430SRaymond.Chen@Sun.COM if ((i < 0) || (i >= WUSB_CLUSTER_ID_COUNT)) {
1319430SRaymond.Chen@Sun.COM
1329430SRaymond.Chen@Sun.COM return;
1339430SRaymond.Chen@Sun.COM }
1349430SRaymond.Chen@Sun.COM
1359430SRaymond.Chen@Sun.COM mutex_enter(&whcdi_mutex);
1369430SRaymond.Chen@Sun.COM if (cluster_id_mask & (1 << i)) {
1379430SRaymond.Chen@Sun.COM /* unset the bitmask */
1389430SRaymond.Chen@Sun.COM cluster_id_mask &= ~(1 << i);
1399430SRaymond.Chen@Sun.COM } else {
1409430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1419430SRaymond.Chen@Sun.COM "cluster id already freed");
1429430SRaymond.Chen@Sun.COM }
1439430SRaymond.Chen@Sun.COM mutex_exit(&whcdi_mutex);
1449430SRaymond.Chen@Sun.COM }
1459430SRaymond.Chen@Sun.COM
1469430SRaymond.Chen@Sun.COM /*
1479430SRaymond.Chen@Sun.COM * Allocate iehdl according to the order specified in WUSB 1.0/7.5
1489430SRaymond.Chen@Sun.COM * WUSB Errata 06.12 requires iehdl to be zero based
1499430SRaymond.Chen@Sun.COM */
1509430SRaymond.Chen@Sun.COM int
wusb_hc_get_iehdl(wusb_hc_data_t * hc_data,wusb_ie_header_t * hdr,uint8_t * iehdl)1519430SRaymond.Chen@Sun.COM wusb_hc_get_iehdl(wusb_hc_data_t *hc_data, wusb_ie_header_t *hdr,
1529430SRaymond.Chen@Sun.COM uint8_t *iehdl)
1539430SRaymond.Chen@Sun.COM {
1549430SRaymond.Chen@Sun.COM int i, rval = USB_SUCCESS;
1559430SRaymond.Chen@Sun.COM uint8_t hdl = 0xFF;
1569430SRaymond.Chen@Sun.COM
1579430SRaymond.Chen@Sun.COM switch (hdr->bIEIdentifier) {
1589430SRaymond.Chen@Sun.COM case WUSB_IE_HOSTINFO:
1599430SRaymond.Chen@Sun.COM /*
1609430SRaymond.Chen@Sun.COM * 7.5.2(and 7.5 under Table 7-38) says this IE should be located
1619430SRaymond.Chen@Sun.COM * in an MMC afte all WCTA_IEs. This mean its handle should
1629430SRaymond.Chen@Sun.COM * be the last one. See also whci r0.95 page 105 top. HC sends
1639430SRaymond.Chen@Sun.COM * IE blocks in ascending IE_HANDLE order.
1649430SRaymond.Chen@Sun.COM */
1659430SRaymond.Chen@Sun.COM hdl = hc_data->hc_num_mmcies - 1;
1669430SRaymond.Chen@Sun.COM hc_data->hc_mmcie_list[hdl] = hdr;
1679430SRaymond.Chen@Sun.COM break;
1689430SRaymond.Chen@Sun.COM case WUSB_IE_ISOC_DISCARD:
1699430SRaymond.Chen@Sun.COM /*
1709430SRaymond.Chen@Sun.COM * 7.5.10 says this IE must be included before any WxCTAs.
1719430SRaymond.Chen@Sun.COM */
1729430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1739430SRaymond.Chen@Sun.COM "IE type 0x%x unimplemented\n", hdr->bIEIdentifier);
1749430SRaymond.Chen@Sun.COM rval = USB_NOT_SUPPORTED;
1759430SRaymond.Chen@Sun.COM break;
1769430SRaymond.Chen@Sun.COM default:
1779430SRaymond.Chen@Sun.COM /*
1789430SRaymond.Chen@Sun.COM * search for existing slot or find the last empty slot
1799430SRaymond.Chen@Sun.COM * so that the other IEs would always set after WCTA_IEs
1809430SRaymond.Chen@Sun.COM */
1819430SRaymond.Chen@Sun.COM for (i = hc_data->hc_num_mmcies - 2; i >= 0; i--) {
1829430SRaymond.Chen@Sun.COM if ((hc_data->hc_mmcie_list[i] == hdr) ||
1839430SRaymond.Chen@Sun.COM (hc_data->hc_mmcie_list[i] == NULL)) {
1849430SRaymond.Chen@Sun.COM hdl = (uint8_t)i;
1859430SRaymond.Chen@Sun.COM hc_data->hc_mmcie_list[i] = hdr;
1869430SRaymond.Chen@Sun.COM break;
1879430SRaymond.Chen@Sun.COM }
1889430SRaymond.Chen@Sun.COM }
1899430SRaymond.Chen@Sun.COM if (hdl == 0xFF) {
1909430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
1919430SRaymond.Chen@Sun.COM "no IE handle available\n");
1929430SRaymond.Chen@Sun.COM rval = USB_NO_RESOURCES;
1939430SRaymond.Chen@Sun.COM }
1949430SRaymond.Chen@Sun.COM break;
1959430SRaymond.Chen@Sun.COM }
1969430SRaymond.Chen@Sun.COM
1979430SRaymond.Chen@Sun.COM if (rval == USB_SUCCESS) {
1989430SRaymond.Chen@Sun.COM *iehdl = hdl;
1999430SRaymond.Chen@Sun.COM }
2009430SRaymond.Chen@Sun.COM
2019430SRaymond.Chen@Sun.COM return (rval);
2029430SRaymond.Chen@Sun.COM }
2039430SRaymond.Chen@Sun.COM
2049430SRaymond.Chen@Sun.COM /* Deallocate iehdl */
2059430SRaymond.Chen@Sun.COM void
wusb_hc_free_iehdl(wusb_hc_data_t * hc_data,uint8_t iehdl)2069430SRaymond.Chen@Sun.COM wusb_hc_free_iehdl(wusb_hc_data_t *hc_data, uint8_t iehdl)
2079430SRaymond.Chen@Sun.COM {
2089430SRaymond.Chen@Sun.COM ASSERT(mutex_owned(&hc_data->hc_mutex));
2099430SRaymond.Chen@Sun.COM
2109430SRaymond.Chen@Sun.COM if (iehdl >= hc_data->hc_num_mmcies) {
2119430SRaymond.Chen@Sun.COM
2129430SRaymond.Chen@Sun.COM return;
2139430SRaymond.Chen@Sun.COM }
2149430SRaymond.Chen@Sun.COM
2159430SRaymond.Chen@Sun.COM if (hc_data->hc_mmcie_list[iehdl] != NULL) {
2169430SRaymond.Chen@Sun.COM hc_data->hc_mmcie_list[iehdl] = NULL;
2179430SRaymond.Chen@Sun.COM }
2189430SRaymond.Chen@Sun.COM }
2199430SRaymond.Chen@Sun.COM
2209430SRaymond.Chen@Sun.COM
2219430SRaymond.Chen@Sun.COM /*
2229430SRaymond.Chen@Sun.COM * ******************************************************************
2239430SRaymond.Chen@Sun.COM * WUSB host controller specific requests, refer to WUSB 1.0/8.5.3
2249430SRaymond.Chen@Sun.COM *
2259430SRaymond.Chen@Sun.COM * WHCI driver needs to translate the requests to register operations
2269430SRaymond.Chen@Sun.COM * ******************************************************************
2279430SRaymond.Chen@Sun.COM */
2289430SRaymond.Chen@Sun.COM
2299430SRaymond.Chen@Sun.COM /* For HWA, see WUSB 8.5.3.11 - Set WUSB Cluster ID */
2309430SRaymond.Chen@Sun.COM int
wusb_hc_set_cluster_id(wusb_hc_data_t * hc_data,uint8_t cluster_id)2319430SRaymond.Chen@Sun.COM wusb_hc_set_cluster_id(wusb_hc_data_t *hc_data, uint8_t cluster_id)
2329430SRaymond.Chen@Sun.COM {
2339430SRaymond.Chen@Sun.COM dev_info_t *dip = hc_data->hc_dip;
2349430SRaymond.Chen@Sun.COM int rval;
2359430SRaymond.Chen@Sun.COM
2369430SRaymond.Chen@Sun.COM if (dip == NULL) {
2379430SRaymond.Chen@Sun.COM
2389430SRaymond.Chen@Sun.COM return (USB_INVALID_ARGS);
2399430SRaymond.Chen@Sun.COM }
2409430SRaymond.Chen@Sun.COM
2419430SRaymond.Chen@Sun.COM if ((rval = hc_data->set_cluster_id(dip, cluster_id))
2429430SRaymond.Chen@Sun.COM != USB_SUCCESS) {
2439430SRaymond.Chen@Sun.COM
2449430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2459430SRaymond.Chen@Sun.COM "Set_Cluster_ID fails: rval=%d ", rval);
2469430SRaymond.Chen@Sun.COM } else {
2479797SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
2489430SRaymond.Chen@Sun.COM hc_data->hc_cluster_id = cluster_id;
2499797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
2509430SRaymond.Chen@Sun.COM }
2519430SRaymond.Chen@Sun.COM
2529430SRaymond.Chen@Sun.COM return (rval);
2539430SRaymond.Chen@Sun.COM }
2549430SRaymond.Chen@Sun.COM
2559430SRaymond.Chen@Sun.COM /*
2569430SRaymond.Chen@Sun.COM * WUSB 8.5.3.13 - Set WUSB Stream Index
2579430SRaymond.Chen@Sun.COM * From 7.7, stream index should be 3bits and less than 8.
2589430SRaymond.Chen@Sun.COM */
2599430SRaymond.Chen@Sun.COM int
wusb_hc_set_stream_idx(wusb_hc_data_t * hc_data,uint8_t stream_idx)2609430SRaymond.Chen@Sun.COM wusb_hc_set_stream_idx(wusb_hc_data_t *hc_data, uint8_t stream_idx)
2619430SRaymond.Chen@Sun.COM {
2629430SRaymond.Chen@Sun.COM dev_info_t *dip = hc_data->hc_dip;
2639430SRaymond.Chen@Sun.COM int rval;
2649430SRaymond.Chen@Sun.COM
2659430SRaymond.Chen@Sun.COM if (stream_idx > 7) {
2669430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2679430SRaymond.Chen@Sun.COM "Set_Stream_Idx fails: invalid idx = %d",
2689430SRaymond.Chen@Sun.COM stream_idx);
2699430SRaymond.Chen@Sun.COM
2709430SRaymond.Chen@Sun.COM return (USB_INVALID_ARGS);
2719430SRaymond.Chen@Sun.COM }
2729430SRaymond.Chen@Sun.COM
2739430SRaymond.Chen@Sun.COM rval = hc_data->set_stream_idx(dip, stream_idx);
2749430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
2759430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2769430SRaymond.Chen@Sun.COM "Set_Stream_Idx fails: rval=%d",
2779430SRaymond.Chen@Sun.COM rval);
2789430SRaymond.Chen@Sun.COM }
2799430SRaymond.Chen@Sun.COM
2809430SRaymond.Chen@Sun.COM return (rval);
2819430SRaymond.Chen@Sun.COM }
2829430SRaymond.Chen@Sun.COM
2839430SRaymond.Chen@Sun.COM /* For HWA, see WUSB 8.5.3.12 - Set WUSB MAS */
2849430SRaymond.Chen@Sun.COM int
wusb_hc_set_wusb_mas(wusb_hc_data_t * hc_data,uint8_t * data)2859430SRaymond.Chen@Sun.COM wusb_hc_set_wusb_mas(wusb_hc_data_t *hc_data, uint8_t *data)
2869430SRaymond.Chen@Sun.COM {
2879430SRaymond.Chen@Sun.COM dev_info_t *dip = hc_data->hc_dip;
2889430SRaymond.Chen@Sun.COM int rval;
2899430SRaymond.Chen@Sun.COM
2909430SRaymond.Chen@Sun.COM rval = hc_data->set_wusb_mas(dip, data);
2919430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
2929430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
2939430SRaymond.Chen@Sun.COM "Set_WUSB_MAS fails: rval=%d", rval);
2949430SRaymond.Chen@Sun.COM }
2959430SRaymond.Chen@Sun.COM
2969430SRaymond.Chen@Sun.COM return (rval);
2979430SRaymond.Chen@Sun.COM
2989430SRaymond.Chen@Sun.COM }
2999430SRaymond.Chen@Sun.COM
3009430SRaymond.Chen@Sun.COM /* For HWA, see WUSB 8.5.3.1 - Add MMC IE */
3019430SRaymond.Chen@Sun.COM int
wusb_hc_add_mmc_ie(wusb_hc_data_t * hc_data,uint8_t interval,uint8_t rcnt,uint8_t iehdl,uint16_t len,uint8_t * data)3029430SRaymond.Chen@Sun.COM wusb_hc_add_mmc_ie(wusb_hc_data_t *hc_data, uint8_t interval,
3039430SRaymond.Chen@Sun.COM uint8_t rcnt, uint8_t iehdl, uint16_t len, uint8_t *data)
3049430SRaymond.Chen@Sun.COM {
3059430SRaymond.Chen@Sun.COM dev_info_t *dip = hc_data->hc_dip;
3069430SRaymond.Chen@Sun.COM int rval;
3079430SRaymond.Chen@Sun.COM
3089430SRaymond.Chen@Sun.COM rval = hc_data->add_mmc_ie(dip, interval, rcnt, iehdl, len, data);
3099430SRaymond.Chen@Sun.COM
3109430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
3119430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3129430SRaymond.Chen@Sun.COM "Add_MMC_IE fails: rval=%d ",
3139430SRaymond.Chen@Sun.COM rval);
3149430SRaymond.Chen@Sun.COM }
3159430SRaymond.Chen@Sun.COM
3169430SRaymond.Chen@Sun.COM return (rval);
3179430SRaymond.Chen@Sun.COM }
3189430SRaymond.Chen@Sun.COM
3199430SRaymond.Chen@Sun.COM /* For HWA, see WUSB 8.5.3.5 - Remove MMC IE */
3209430SRaymond.Chen@Sun.COM int
wusb_hc_remove_mmc_ie(wusb_hc_data_t * hc_data,uint8_t iehdl)3219430SRaymond.Chen@Sun.COM wusb_hc_remove_mmc_ie(wusb_hc_data_t *hc_data, uint8_t iehdl)
3229430SRaymond.Chen@Sun.COM {
3239430SRaymond.Chen@Sun.COM dev_info_t *dip = hc_data->hc_dip;
3249430SRaymond.Chen@Sun.COM int rval;
3259430SRaymond.Chen@Sun.COM
3269797SRaymond.Chen@Sun.COM ASSERT(mutex_owned(&hc_data->hc_mutex));
3279797SRaymond.Chen@Sun.COM
3289430SRaymond.Chen@Sun.COM if ((iehdl >= hc_data->hc_num_mmcies) ||
3299430SRaymond.Chen@Sun.COM (hc_data->hc_mmcie_list[iehdl] == NULL)) {
3309430SRaymond.Chen@Sun.COM
3319430SRaymond.Chen@Sun.COM return (USB_FAILURE);
3329430SRaymond.Chen@Sun.COM }
3339430SRaymond.Chen@Sun.COM
3349797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
3359430SRaymond.Chen@Sun.COM rval = hc_data->rem_mmc_ie(dip, iehdl);
3369797SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
3379430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
3389430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3399430SRaymond.Chen@Sun.COM "Remove_MMC_IE fails: rval=%d ", rval);
3409430SRaymond.Chen@Sun.COM }
3419430SRaymond.Chen@Sun.COM
3429430SRaymond.Chen@Sun.COM return (rval);
3439430SRaymond.Chen@Sun.COM }
3449430SRaymond.Chen@Sun.COM
3459430SRaymond.Chen@Sun.COM /* For HWA, see WUSB 8.5.3.14 - WUSB Channel Stop */
3469430SRaymond.Chen@Sun.COM int
wusb_hc_stop_ch(wusb_hc_data_t * hc_data,uint32_t timeoff)3479430SRaymond.Chen@Sun.COM wusb_hc_stop_ch(wusb_hc_data_t *hc_data, uint32_t timeoff)
3489430SRaymond.Chen@Sun.COM {
3499430SRaymond.Chen@Sun.COM dev_info_t *dip = hc_data->hc_dip;
3509430SRaymond.Chen@Sun.COM int rval;
3519430SRaymond.Chen@Sun.COM
3529430SRaymond.Chen@Sun.COM rval = hc_data->stop_ch(dip, timeoff);
3539430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
3549430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3559430SRaymond.Chen@Sun.COM "WUSB_Ch_Stop fails: rval=%d ", rval);
3569430SRaymond.Chen@Sun.COM }
3579430SRaymond.Chen@Sun.COM
3589430SRaymond.Chen@Sun.COM return (rval);
3599430SRaymond.Chen@Sun.COM }
3609430SRaymond.Chen@Sun.COM
3619430SRaymond.Chen@Sun.COM /* For HWA, see WUSB 8.5. 3.10 - Set Num DNTS Slots */
3629430SRaymond.Chen@Sun.COM int
wusb_hc_set_num_dnts(wusb_hc_data_t * hc_data,uint8_t interval,uint8_t nslots)3639430SRaymond.Chen@Sun.COM wusb_hc_set_num_dnts(wusb_hc_data_t *hc_data, uint8_t interval,
3649430SRaymond.Chen@Sun.COM uint8_t nslots)
3659430SRaymond.Chen@Sun.COM {
3669430SRaymond.Chen@Sun.COM dev_info_t *dip = hc_data->hc_dip;
3679430SRaymond.Chen@Sun.COM int rval;
3689430SRaymond.Chen@Sun.COM
3699430SRaymond.Chen@Sun.COM rval = hc_data->set_num_dnts(dip, interval, nslots);
3709430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
3719430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3729430SRaymond.Chen@Sun.COM "Set_Num_DNTS fails: rval=%d ", rval);
3739430SRaymond.Chen@Sun.COM }
3749430SRaymond.Chen@Sun.COM
3759430SRaymond.Chen@Sun.COM return (rval);
3769430SRaymond.Chen@Sun.COM }
3779430SRaymond.Chen@Sun.COM
3789430SRaymond.Chen@Sun.COM /*
3799430SRaymond.Chen@Sun.COM * For HWA, see WUSB 8.5.3.2 - 8.5.3.4 Get Time
3809430SRaymond.Chen@Sun.COM * time_type:
3819430SRaymond.Chen@Sun.COM * WUSB_TIME_ADJ - Get BPST Adjustment
3829430SRaymond.Chen@Sun.COM * WUSB_TIME_BPST - Get BPST Time
3839430SRaymond.Chen@Sun.COM * WUSB_TIME_WUSB - Get WUSB Time
3849430SRaymond.Chen@Sun.COM */
3859430SRaymond.Chen@Sun.COM int
wusb_hc_get_time(wusb_hc_data_t * hc_data,uint8_t time_type,uint16_t len,uint32_t * time)3869430SRaymond.Chen@Sun.COM wusb_hc_get_time(wusb_hc_data_t *hc_data, uint8_t time_type,
3879430SRaymond.Chen@Sun.COM uint16_t len, uint32_t *time)
3889430SRaymond.Chen@Sun.COM {
3899430SRaymond.Chen@Sun.COM dev_info_t *dip = hc_data->hc_dip;
3909430SRaymond.Chen@Sun.COM int rval;
3919430SRaymond.Chen@Sun.COM
3929430SRaymond.Chen@Sun.COM /* call the HC's specific get_time function */
3939430SRaymond.Chen@Sun.COM rval = hc_data->get_time(dip, time_type, len, time);
3949430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
3959430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
3969430SRaymond.Chen@Sun.COM "Set_Num_DNTS fails: rval=%d ", rval);
3979430SRaymond.Chen@Sun.COM }
3989430SRaymond.Chen@Sun.COM
3999430SRaymond.Chen@Sun.COM return (rval);
4009430SRaymond.Chen@Sun.COM }
4019430SRaymond.Chen@Sun.COM
4029430SRaymond.Chen@Sun.COM /*
4039430SRaymond.Chen@Sun.COM * Remove the specified IE from host MMC and release the related IE handle
4049430SRaymond.Chen@Sun.COM */
4059430SRaymond.Chen@Sun.COM void
wusb_hc_rem_ie(wusb_hc_data_t * hc_data,wusb_ie_header_t * ieh)4069430SRaymond.Chen@Sun.COM wusb_hc_rem_ie(wusb_hc_data_t *hc_data, wusb_ie_header_t *ieh)
4079430SRaymond.Chen@Sun.COM {
4089430SRaymond.Chen@Sun.COM int i;
4099430SRaymond.Chen@Sun.COM int16_t iehdl = -1;
4109430SRaymond.Chen@Sun.COM
4119797SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
4129430SRaymond.Chen@Sun.COM for (i = 0; i < hc_data->hc_num_mmcies; i++) {
4139430SRaymond.Chen@Sun.COM if (hc_data->hc_mmcie_list[i] == ieh) {
4149430SRaymond.Chen@Sun.COM iehdl = (int16_t)i;
4159430SRaymond.Chen@Sun.COM
4169430SRaymond.Chen@Sun.COM break;
4179430SRaymond.Chen@Sun.COM }
4189430SRaymond.Chen@Sun.COM }
4199430SRaymond.Chen@Sun.COM
4209430SRaymond.Chen@Sun.COM if (iehdl == -1) {
4219430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
4229430SRaymond.Chen@Sun.COM "wusb_hc_rem_ie: IE(%p) iehdl not found", (void *)ieh);
4239797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
4249430SRaymond.Chen@Sun.COM
4259430SRaymond.Chen@Sun.COM return;
4269430SRaymond.Chen@Sun.COM }
4279430SRaymond.Chen@Sun.COM
4289430SRaymond.Chen@Sun.COM (void) wusb_hc_remove_mmc_ie(hc_data, (uint8_t)iehdl);
4299797SRaymond.Chen@Sun.COM
4309430SRaymond.Chen@Sun.COM wusb_hc_free_iehdl(hc_data, (uint8_t)iehdl);
4319797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
4329430SRaymond.Chen@Sun.COM }
4339430SRaymond.Chen@Sun.COM
4349430SRaymond.Chen@Sun.COM /* Add Host Info IE */
4359430SRaymond.Chen@Sun.COM int
wusb_hc_add_host_info(wusb_hc_data_t * hc_data,uint8_t stream_idx)4369430SRaymond.Chen@Sun.COM wusb_hc_add_host_info(wusb_hc_data_t *hc_data, uint8_t stream_idx)
4379430SRaymond.Chen@Sun.COM {
4389430SRaymond.Chen@Sun.COM wusb_ie_host_info_t *hinfo;
4399430SRaymond.Chen@Sun.COM uint8_t iehdl;
4409430SRaymond.Chen@Sun.COM int rval;
4419430SRaymond.Chen@Sun.COM
4429430SRaymond.Chen@Sun.COM hinfo = kmem_zalloc(sizeof (wusb_ie_host_info_t), KM_SLEEP);
4439430SRaymond.Chen@Sun.COM
4449797SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
4459797SRaymond.Chen@Sun.COM
4469430SRaymond.Chen@Sun.COM hinfo->bIEIdentifier = WUSB_IE_HOSTINFO;
4479430SRaymond.Chen@Sun.COM hinfo->bLength = sizeof (wusb_ie_host_info_t);
4489430SRaymond.Chen@Sun.COM if (hc_data->hc_newcon_enabled) {
4499430SRaymond.Chen@Sun.COM hinfo->bmAttributes[0] = (stream_idx << WUSB_HI_STRIDX_SHIFT) |
4509430SRaymond.Chen@Sun.COM WUSB_HI_CONN_ALL;
4519430SRaymond.Chen@Sun.COM } else {
4529430SRaymond.Chen@Sun.COM hinfo->bmAttributes[0] = (stream_idx << WUSB_HI_STRIDX_SHIFT) |
4539430SRaymond.Chen@Sun.COM WUSB_HI_CONN_LMTED;
4549430SRaymond.Chen@Sun.COM }
4559430SRaymond.Chen@Sun.COM (void) memcpy(hinfo->CHID, hc_data->hc_chid, sizeof (hinfo->CHID));
4569430SRaymond.Chen@Sun.COM
4579430SRaymond.Chen@Sun.COM rval = wusb_hc_get_iehdl(hc_data, (wusb_ie_header_t *)hinfo, &iehdl);
4589430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
4599430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
4609430SRaymond.Chen@Sun.COM "wusb_hc_add_host_info: get ie handle fails");
4619797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
4629430SRaymond.Chen@Sun.COM
4639430SRaymond.Chen@Sun.COM return (rval);
4649430SRaymond.Chen@Sun.COM }
4659430SRaymond.Chen@Sun.COM
4669430SRaymond.Chen@Sun.COM USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
4679430SRaymond.Chen@Sun.COM "wusb_hc_add_host_info: iehdl=%d", iehdl);
4689430SRaymond.Chen@Sun.COM
4699797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
4709430SRaymond.Chen@Sun.COM rval = wusb_hc_add_mmc_ie(hc_data, 10, 1, iehdl,
4719430SRaymond.Chen@Sun.COM sizeof (wusb_ie_host_info_t), (uint8_t *)hinfo);
4729430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
4739430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
4749430SRaymond.Chen@Sun.COM "wusb_hc_add_host_info: add host info mmc ie fails");
4759797SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
4769430SRaymond.Chen@Sun.COM wusb_hc_free_iehdl(hc_data, iehdl);
4779797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
4789430SRaymond.Chen@Sun.COM
4799430SRaymond.Chen@Sun.COM return (rval);
4809430SRaymond.Chen@Sun.COM }
4819430SRaymond.Chen@Sun.COM
4829797SRaymond.Chen@Sun.COM
4839430SRaymond.Chen@Sun.COM return (USB_SUCCESS);
4849430SRaymond.Chen@Sun.COM }
4859430SRaymond.Chen@Sun.COM
4869430SRaymond.Chen@Sun.COM /* Remove Host Info IE */
4879430SRaymond.Chen@Sun.COM void
wusb_hc_rem_host_info(wusb_hc_data_t * hc_data)4889430SRaymond.Chen@Sun.COM wusb_hc_rem_host_info(wusb_hc_data_t *hc_data)
4899430SRaymond.Chen@Sun.COM {
4909430SRaymond.Chen@Sun.COM int16_t iehdl = -1;
4919430SRaymond.Chen@Sun.COM wusb_ie_header_t *iehead;
4929430SRaymond.Chen@Sun.COM
4939430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
4949430SRaymond.Chen@Sun.COM /* host info IE is always the last one */
4959430SRaymond.Chen@Sun.COM iehdl = hc_data->hc_num_mmcies - 1;
4969430SRaymond.Chen@Sun.COM iehead = hc_data->hc_mmcie_list[iehdl];
4979430SRaymond.Chen@Sun.COM
4989430SRaymond.Chen@Sun.COM /* something wrong */
4999430SRaymond.Chen@Sun.COM if ((iehead == NULL) || (iehead->bIEIdentifier != WUSB_IE_HOSTINFO)) {
5009430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
5019430SRaymond.Chen@Sun.COM return;
5029430SRaymond.Chen@Sun.COM }
5039430SRaymond.Chen@Sun.COM
5049430SRaymond.Chen@Sun.COM (void) wusb_hc_remove_mmc_ie(hc_data, (uint8_t)iehdl);
5059430SRaymond.Chen@Sun.COM wusb_hc_free_iehdl(hc_data, (uint8_t)iehdl);
5069430SRaymond.Chen@Sun.COM kmem_free(iehead, sizeof (wusb_ie_host_info_t));
5079430SRaymond.Chen@Sun.COM
5089430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
5099430SRaymond.Chen@Sun.COM }
5109430SRaymond.Chen@Sun.COM
5119430SRaymond.Chen@Sun.COM /*
5129430SRaymond.Chen@Sun.COM * Check if a device with certain CDID is connected
5139430SRaymond.Chen@Sun.COM * return 1 if a device with the same CDID is found;
5149430SRaymond.Chen@Sun.COM * return 0 if not
5159430SRaymond.Chen@Sun.COM */
5169430SRaymond.Chen@Sun.COM uint_t
wusb_hc_is_dev_connected(wusb_hc_data_t * hc_data,uint8_t * cdid,usb_port_t * port)5179430SRaymond.Chen@Sun.COM wusb_hc_is_dev_connected(wusb_hc_data_t *hc_data, uint8_t *cdid,
5189430SRaymond.Chen@Sun.COM usb_port_t *port)
5199430SRaymond.Chen@Sun.COM {
5209430SRaymond.Chen@Sun.COM int i;
5219430SRaymond.Chen@Sun.COM wusb_dev_info_t *dev_info;
5229430SRaymond.Chen@Sun.COM
5239430SRaymond.Chen@Sun.COM ASSERT(mutex_owned(&hc_data->hc_mutex));
5249430SRaymond.Chen@Sun.COM
5259430SRaymond.Chen@Sun.COM for (i = 1; i <= hc_data->hc_num_ports; i++) {
5269430SRaymond.Chen@Sun.COM dev_info = hc_data->hc_dev_infos[i];
5279430SRaymond.Chen@Sun.COM if ((dev_info != NULL) &&
5289430SRaymond.Chen@Sun.COM (memcmp(cdid, dev_info->wdev_cdid, 16) == 0)) {
5299430SRaymond.Chen@Sun.COM *port = (usb_port_t)i;
5309430SRaymond.Chen@Sun.COM USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
5319430SRaymond.Chen@Sun.COM "wusb_hc_is_dev_connected: find dev at port "
5329430SRaymond.Chen@Sun.COM "%d", *port);
5339430SRaymond.Chen@Sun.COM
5349430SRaymond.Chen@Sun.COM return (1);
5359430SRaymond.Chen@Sun.COM }
5369430SRaymond.Chen@Sun.COM }
5379430SRaymond.Chen@Sun.COM
5389430SRaymond.Chen@Sun.COM return (0);
5399430SRaymond.Chen@Sun.COM }
5409430SRaymond.Chen@Sun.COM
5419430SRaymond.Chen@Sun.COM /*
5429430SRaymond.Chen@Sun.COM * Check if a device with certain address is connected
5439430SRaymond.Chen@Sun.COM * return 1 if a device with the same address is found;
5449430SRaymond.Chen@Sun.COM * return 0 if not
5459430SRaymond.Chen@Sun.COM */
5469430SRaymond.Chen@Sun.COM uint_t
wusb_hc_is_addr_valid(wusb_hc_data_t * hc_data,uint8_t addr,usb_port_t * port)5479430SRaymond.Chen@Sun.COM wusb_hc_is_addr_valid(wusb_hc_data_t *hc_data, uint8_t addr,
5489430SRaymond.Chen@Sun.COM usb_port_t *port)
5499430SRaymond.Chen@Sun.COM {
5509430SRaymond.Chen@Sun.COM int i;
5519430SRaymond.Chen@Sun.COM wusb_dev_info_t *dev_info;
5529430SRaymond.Chen@Sun.COM
5539430SRaymond.Chen@Sun.COM for (i = 1; i <= hc_data->hc_num_ports; i++) {
5549430SRaymond.Chen@Sun.COM dev_info = hc_data->hc_dev_infos[i];
5559430SRaymond.Chen@Sun.COM if ((dev_info != NULL) && (dev_info->wdev_addr == addr)) {
5569430SRaymond.Chen@Sun.COM *port = (usb_port_t)i;
5579430SRaymond.Chen@Sun.COM USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
5589430SRaymond.Chen@Sun.COM "wusb_hc_is_addr_valid: find addr at port "
5599430SRaymond.Chen@Sun.COM "%d", *port);
5609430SRaymond.Chen@Sun.COM
5619430SRaymond.Chen@Sun.COM return (1);
5629430SRaymond.Chen@Sun.COM }
5639430SRaymond.Chen@Sun.COM }
5649430SRaymond.Chen@Sun.COM
5659430SRaymond.Chen@Sun.COM return (0);
5669430SRaymond.Chen@Sun.COM }
5679430SRaymond.Chen@Sun.COM
5689430SRaymond.Chen@Sun.COM
5699430SRaymond.Chen@Sun.COM /*
5709430SRaymond.Chen@Sun.COM * Assign port number for a newly connected device
5719430SRaymond.Chen@Sun.COM * return the first free port number if any, or 0 if none
5729430SRaymond.Chen@Sun.COM */
5739430SRaymond.Chen@Sun.COM usb_port_t
wusb_hc_get_free_port(wusb_hc_data_t * hc_data)5749430SRaymond.Chen@Sun.COM wusb_hc_get_free_port(wusb_hc_data_t *hc_data)
5759430SRaymond.Chen@Sun.COM {
5769430SRaymond.Chen@Sun.COM int i;
5779430SRaymond.Chen@Sun.COM usb_port_t port;
5789430SRaymond.Chen@Sun.COM
5799430SRaymond.Chen@Sun.COM for (i = 1; i <= hc_data->hc_num_ports; i++) {
5809430SRaymond.Chen@Sun.COM if (hc_data->hc_dev_infos[i] == NULL) {
5819430SRaymond.Chen@Sun.COM port = (usb_port_t)i;
5829430SRaymond.Chen@Sun.COM USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
5839430SRaymond.Chen@Sun.COM "wusb_hc_get_free_port: find free port %d", port);
5849430SRaymond.Chen@Sun.COM
5859430SRaymond.Chen@Sun.COM return (port);
5869430SRaymond.Chen@Sun.COM }
5879430SRaymond.Chen@Sun.COM }
5889430SRaymond.Chen@Sun.COM
5899430SRaymond.Chen@Sun.COM return (0);
5909430SRaymond.Chen@Sun.COM }
5919430SRaymond.Chen@Sun.COM
5929430SRaymond.Chen@Sun.COM /* Add Connect Acknowledge IE */
5939430SRaymond.Chen@Sun.COM int
wusb_hc_ack_conn(wusb_hc_data_t * hc_data,usb_port_t port)5949430SRaymond.Chen@Sun.COM wusb_hc_ack_conn(wusb_hc_data_t *hc_data, usb_port_t port)
5959430SRaymond.Chen@Sun.COM {
5969430SRaymond.Chen@Sun.COM wusb_dev_info_t *dev_info;
5979430SRaymond.Chen@Sun.COM wusb_ie_connect_ack_t *ack_ie;
5989430SRaymond.Chen@Sun.COM wusb_connectack_block_t *ack_block;
5999430SRaymond.Chen@Sun.COM uint8_t iehdl;
6009430SRaymond.Chen@Sun.COM int rval;
6019430SRaymond.Chen@Sun.COM
6029430SRaymond.Chen@Sun.COM ASSERT(mutex_owned(&hc_data->hc_mutex));
6039430SRaymond.Chen@Sun.COM
6049430SRaymond.Chen@Sun.COM dev_info = hc_data->hc_dev_infos[port];
6059430SRaymond.Chen@Sun.COM ASSERT(dev_info != NULL);
6069430SRaymond.Chen@Sun.COM
6079430SRaymond.Chen@Sun.COM ack_ie = kmem_zalloc(sizeof (wusb_ie_connect_ack_t), KM_SLEEP);
6089430SRaymond.Chen@Sun.COM
6099430SRaymond.Chen@Sun.COM ack_ie->bIEIdentifier = WUSB_IE_CONNECTACK;
6109430SRaymond.Chen@Sun.COM ack_block = (wusb_connectack_block_t *)ack_ie->bAckBlock;
6119430SRaymond.Chen@Sun.COM (void) memcpy(ack_block->CDID, dev_info->wdev_cdid, 16);
6129430SRaymond.Chen@Sun.COM ack_block->bDeviceAddress = dev_info->wdev_addr;
6139430SRaymond.Chen@Sun.COM ack_ie->bLength = 20;
6149430SRaymond.Chen@Sun.COM
6159430SRaymond.Chen@Sun.COM rval = wusb_hc_get_iehdl(hc_data, (wusb_ie_header_t *)ack_ie, &iehdl);
6169430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
6179430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
6189430SRaymond.Chen@Sun.COM "wusb_hc_ack_conn: get ie handle fails");
6199430SRaymond.Chen@Sun.COM kmem_free(ack_ie, sizeof (wusb_ie_connect_ack_t));
6209430SRaymond.Chen@Sun.COM
6219430SRaymond.Chen@Sun.COM return (rval);
6229430SRaymond.Chen@Sun.COM }
6239430SRaymond.Chen@Sun.COM
6249430SRaymond.Chen@Sun.COM rval = wusb_hc_add_mmc_ie(hc_data, 0, 3, iehdl,
6259430SRaymond.Chen@Sun.COM ack_ie->bLength, (uint8_t *)ack_ie);
6269430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
6279430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
6289430SRaymond.Chen@Sun.COM "wusb_hc_ack_conn: add connect ack ie fails");
6299430SRaymond.Chen@Sun.COM wusb_hc_free_iehdl(hc_data, iehdl);
6309430SRaymond.Chen@Sun.COM kmem_free(ack_ie, sizeof (wusb_ie_connect_ack_t));
6319430SRaymond.Chen@Sun.COM
6329430SRaymond.Chen@Sun.COM return (rval);
6339430SRaymond.Chen@Sun.COM }
6349430SRaymond.Chen@Sun.COM
6359430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
6369430SRaymond.Chen@Sun.COM /*
6379430SRaymond.Chen@Sun.COM * WUSB 1.0/7.5.1 requires at least 2ms delay between ConnectAck
6389430SRaymond.Chen@Sun.COM * and WUSB transactions, wait for 2ms here
6399430SRaymond.Chen@Sun.COM */
6409430SRaymond.Chen@Sun.COM delay(drv_usectohz(2000));
6419430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
6429430SRaymond.Chen@Sun.COM
6439430SRaymond.Chen@Sun.COM return (USB_SUCCESS);
6449430SRaymond.Chen@Sun.COM }
6459430SRaymond.Chen@Sun.COM
6469430SRaymond.Chen@Sun.COM /* Remove Connect Acknowledge IE */
6479430SRaymond.Chen@Sun.COM void
wusb_hc_rm_ack(wusb_hc_data_t * hc_data)6489430SRaymond.Chen@Sun.COM wusb_hc_rm_ack(wusb_hc_data_t *hc_data)
6499430SRaymond.Chen@Sun.COM {
6509430SRaymond.Chen@Sun.COM int i;
6519430SRaymond.Chen@Sun.COM int16_t iehdl = -1;
6529430SRaymond.Chen@Sun.COM wusb_ie_header_t *ieh;
6539430SRaymond.Chen@Sun.COM
6549430SRaymond.Chen@Sun.COM for (i = 0; i < hc_data->hc_num_mmcies; i++) {
6559430SRaymond.Chen@Sun.COM ieh = hc_data->hc_mmcie_list[i];
6569430SRaymond.Chen@Sun.COM if ((ieh != NULL) &&
6579430SRaymond.Chen@Sun.COM (ieh->bIEIdentifier == WUSB_IE_CONNECTACK)) {
6589430SRaymond.Chen@Sun.COM iehdl = (int16_t)i;
6599430SRaymond.Chen@Sun.COM
6609430SRaymond.Chen@Sun.COM break;
6619430SRaymond.Chen@Sun.COM }
6629430SRaymond.Chen@Sun.COM }
6639430SRaymond.Chen@Sun.COM
6649430SRaymond.Chen@Sun.COM if (iehdl == -1) {
6659430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
6669430SRaymond.Chen@Sun.COM "wusb_hc_rm_ack: ack iehdl not found");
6679430SRaymond.Chen@Sun.COM
6689430SRaymond.Chen@Sun.COM return;
6699430SRaymond.Chen@Sun.COM }
6709430SRaymond.Chen@Sun.COM
6719430SRaymond.Chen@Sun.COM /* remove mmc ie and free handle & memory */
6729430SRaymond.Chen@Sun.COM (void) wusb_hc_remove_mmc_ie(hc_data, (uint8_t)iehdl);
6739430SRaymond.Chen@Sun.COM wusb_hc_free_iehdl(hc_data, iehdl);
6749430SRaymond.Chen@Sun.COM kmem_free(ieh, sizeof (wusb_ie_connect_ack_t));
6759430SRaymond.Chen@Sun.COM }
6769430SRaymond.Chen@Sun.COM
6779430SRaymond.Chen@Sun.COM /*
6789430SRaymond.Chen@Sun.COM * Send a KeepAlive IE to the device. See WUSB 1.0 section 7.5.9
6799430SRaymond.Chen@Sun.COM */
6809430SRaymond.Chen@Sun.COM int
wusb_hc_send_keepalive_ie(wusb_hc_data_t * hc_data,uint8_t addr)6819430SRaymond.Chen@Sun.COM wusb_hc_send_keepalive_ie(wusb_hc_data_t *hc_data, uint8_t addr)
6829430SRaymond.Chen@Sun.COM {
6839430SRaymond.Chen@Sun.COM wusb_ie_keepalive_t *alive_ie;
6849430SRaymond.Chen@Sun.COM uint8_t iehdl;
6859430SRaymond.Chen@Sun.COM int rval;
6869430SRaymond.Chen@Sun.COM
6879797SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
6889430SRaymond.Chen@Sun.COM /*
6899430SRaymond.Chen@Sun.COM * the scheme ensures each time only one device addr
6909430SRaymond.Chen@Sun.COM * is set each time
6919430SRaymond.Chen@Sun.COM */
6929430SRaymond.Chen@Sun.COM alive_ie = &hc_data->hc_alive_ie;
6939430SRaymond.Chen@Sun.COM alive_ie->bDeviceAddress[0] = addr;
6949430SRaymond.Chen@Sun.COM /* padding, no active wusb device addr will be 1 */
6959430SRaymond.Chen@Sun.COM alive_ie->bDeviceAddress[1] = 1;
6969430SRaymond.Chen@Sun.COM alive_ie->bLength = 4;
6979430SRaymond.Chen@Sun.COM
6989430SRaymond.Chen@Sun.COM rval = wusb_hc_get_iehdl(hc_data, (wusb_ie_header_t *)alive_ie,
6999430SRaymond.Chen@Sun.COM &iehdl);
7009430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
7019430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
7029430SRaymond.Chen@Sun.COM "wusb_hc_send_keepalive_ie: get ie handle fails");
7039797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
7049430SRaymond.Chen@Sun.COM
7059430SRaymond.Chen@Sun.COM return (rval);
7069430SRaymond.Chen@Sun.COM }
7079430SRaymond.Chen@Sun.COM
7089430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
7099430SRaymond.Chen@Sun.COM "wusb_hc_send_keepalive_ie: get ie handle = %d", iehdl);
7109430SRaymond.Chen@Sun.COM /*
7119430SRaymond.Chen@Sun.COM * we must release the lock so that the DN notification
7129430SRaymond.Chen@Sun.COM * thread can update the device active bit
7139430SRaymond.Chen@Sun.COM */
7149430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
7159430SRaymond.Chen@Sun.COM
7169430SRaymond.Chen@Sun.COM rval = wusb_hc_add_mmc_ie(hc_data, 0, 0, iehdl,
7179430SRaymond.Chen@Sun.COM alive_ie->bLength, (uint8_t *)alive_ie);
7189430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
7199430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
7209430SRaymond.Chen@Sun.COM "wusb_hc_send_keepalive_ie: add keepalive ie fails");
7219430SRaymond.Chen@Sun.COM
7229430SRaymond.Chen@Sun.COM /* no need to free the ack iehdl since it is reused */
7239430SRaymond.Chen@Sun.COM return (rval);
7249430SRaymond.Chen@Sun.COM }
7259430SRaymond.Chen@Sun.COM
7269430SRaymond.Chen@Sun.COM /*
7279430SRaymond.Chen@Sun.COM * wait 400ms for the device to reply a DN_Alive notification
7289430SRaymond.Chen@Sun.COM */
7299430SRaymond.Chen@Sun.COM delay(drv_usectohz(400000));
7309430SRaymond.Chen@Sun.COM
7319430SRaymond.Chen@Sun.COM /*
7329430SRaymond.Chen@Sun.COM * cease transmitting the IE and release the IE handle,
7339430SRaymond.Chen@Sun.COM * no matter we receive a response or not.
7349430SRaymond.Chen@Sun.COM */
7359430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
7369430SRaymond.Chen@Sun.COM (void) wusb_hc_remove_mmc_ie(hc_data, iehdl);
7379430SRaymond.Chen@Sun.COM wusb_hc_free_iehdl(hc_data, iehdl);
7389797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
7399430SRaymond.Chen@Sun.COM
7409430SRaymond.Chen@Sun.COM return (USB_SUCCESS);
7419430SRaymond.Chen@Sun.COM }
7429430SRaymond.Chen@Sun.COM
7439430SRaymond.Chen@Sun.COM /*
7449430SRaymond.Chen@Sun.COM * Check the hc_cc_list for matching CDID and return the pointer
7459430SRaymond.Chen@Sun.COM * to the matched cc. Return NULL if no matching cc is found.
7469430SRaymond.Chen@Sun.COM */
7479430SRaymond.Chen@Sun.COM wusb_cc_t *
wusb_hc_cc_matched(wusb_hc_cc_list_t * cc_list,uint8_t * cdid)7489430SRaymond.Chen@Sun.COM wusb_hc_cc_matched(wusb_hc_cc_list_t *cc_list, uint8_t *cdid)
7499430SRaymond.Chen@Sun.COM {
7509430SRaymond.Chen@Sun.COM wusb_cc_t *cc = NULL, *tcc;
7519430SRaymond.Chen@Sun.COM
7529430SRaymond.Chen@Sun.COM while (cc_list != NULL) {
7539430SRaymond.Chen@Sun.COM tcc = &cc_list->cc;
7549430SRaymond.Chen@Sun.COM if (memcmp(tcc->CDID, cdid, 16) == 0) {
7559430SRaymond.Chen@Sun.COM cc = tcc;
7569430SRaymond.Chen@Sun.COM
7579430SRaymond.Chen@Sun.COM break;
7589430SRaymond.Chen@Sun.COM }
7599430SRaymond.Chen@Sun.COM cc_list = cc_list->next;
7609430SRaymond.Chen@Sun.COM }
7619430SRaymond.Chen@Sun.COM
7629430SRaymond.Chen@Sun.COM return (cc);
7639430SRaymond.Chen@Sun.COM }
7649430SRaymond.Chen@Sun.COM
7659430SRaymond.Chen@Sun.COM /*
7669430SRaymond.Chen@Sun.COM * ***************************************************************
7679430SRaymond.Chen@Sun.COM * WUSB specific standard device requests, refer to WUSB 1.0/7.3.1
7689430SRaymond.Chen@Sun.COM * ***************************************************************
7699430SRaymond.Chen@Sun.COM */
7709430SRaymond.Chen@Sun.COM /* Get WUSB device BOS descr and UWB capability descr */
7719430SRaymond.Chen@Sun.COM int
wusb_get_dev_uwb_descr(wusb_hc_data_t * hc_data,usb_port_t port)7729430SRaymond.Chen@Sun.COM wusb_get_dev_uwb_descr(wusb_hc_data_t *hc_data, usb_port_t port)
7739430SRaymond.Chen@Sun.COM {
7749430SRaymond.Chen@Sun.COM dev_info_t *child_dip;
7759430SRaymond.Chen@Sun.COM usba_device_t *child_ud;
7769430SRaymond.Chen@Sun.COM wusb_dev_info_t *dev_info;
7779430SRaymond.Chen@Sun.COM int rval;
7789430SRaymond.Chen@Sun.COM uint8_t *buf;
7799430SRaymond.Chen@Sun.COM size_t size, buflen;
7809430SRaymond.Chen@Sun.COM
7819430SRaymond.Chen@Sun.COM ASSERT(mutex_owned(&hc_data->hc_mutex));
7829430SRaymond.Chen@Sun.COM
7839430SRaymond.Chen@Sun.COM USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
7849430SRaymond.Chen@Sun.COM "wusb_get_dev_uwb_descr: port = %d", port);
7859430SRaymond.Chen@Sun.COM
7869430SRaymond.Chen@Sun.COM dev_info = hc_data->hc_dev_infos[port];
7879430SRaymond.Chen@Sun.COM child_dip = hc_data->hc_children_dips[port];
7889430SRaymond.Chen@Sun.COM if (child_dip == NULL) {
7899430SRaymond.Chen@Sun.COM
7909430SRaymond.Chen@Sun.COM return (USB_FAILURE);
7919430SRaymond.Chen@Sun.COM }
7929430SRaymond.Chen@Sun.COM
7939430SRaymond.Chen@Sun.COM child_ud = usba_get_usba_device(child_dip);
7949430SRaymond.Chen@Sun.COM if (child_ud == NULL) {
7959430SRaymond.Chen@Sun.COM
7969430SRaymond.Chen@Sun.COM return (USB_FAILURE);
7979430SRaymond.Chen@Sun.COM }
7989430SRaymond.Chen@Sun.COM
7999430SRaymond.Chen@Sun.COM /* only get bos descr the first time */
8009430SRaymond.Chen@Sun.COM if (dev_info->wdev_uwb_descr == NULL) {
8019430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
8029430SRaymond.Chen@Sun.COM rval = wusb_get_bos_cloud(child_dip, child_ud);
8039430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
8049430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
8059430SRaymond.Chen@Sun.COM "wusb_get_dev_uwb_descr: failed to "
8069430SRaymond.Chen@Sun.COM "get bos descriptor");
8079430SRaymond.Chen@Sun.COM
8089430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
8099430SRaymond.Chen@Sun.COM
8109430SRaymond.Chen@Sun.COM return (rval);
8119430SRaymond.Chen@Sun.COM }
8129430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
8139430SRaymond.Chen@Sun.COM
8149430SRaymond.Chen@Sun.COM buf = child_ud->usb_wireless_data->wusb_bos;
8159430SRaymond.Chen@Sun.COM buflen = child_ud->usb_wireless_data->wusb_bos_length;
8169430SRaymond.Chen@Sun.COM
8179430SRaymond.Chen@Sun.COM dev_info->wdev_uwb_descr = kmem_zalloc(
8189430SRaymond.Chen@Sun.COM sizeof (usb_uwb_cap_descr_t), KM_SLEEP);
8199430SRaymond.Chen@Sun.COM
8209430SRaymond.Chen@Sun.COM size = usb_parse_uwb_bos_descr(buf, buflen,
8219430SRaymond.Chen@Sun.COM dev_info->wdev_uwb_descr, sizeof (usb_uwb_cap_descr_t));
8229430SRaymond.Chen@Sun.COM
8239430SRaymond.Chen@Sun.COM USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
8249430SRaymond.Chen@Sun.COM "wusb_get_dev_uwb_descr: parsed uwb descr size is %d",
8259430SRaymond.Chen@Sun.COM (int)size);
8269430SRaymond.Chen@Sun.COM if (size < USB_UWB_CAP_DESCR_SIZE) {
8279430SRaymond.Chen@Sun.COM kmem_free(dev_info->wdev_uwb_descr,
8289430SRaymond.Chen@Sun.COM sizeof (usb_uwb_cap_descr_t));
8299430SRaymond.Chen@Sun.COM dev_info->wdev_uwb_descr = NULL;
8309430SRaymond.Chen@Sun.COM
8319430SRaymond.Chen@Sun.COM return (USB_FAILURE);
8329430SRaymond.Chen@Sun.COM }
8339430SRaymond.Chen@Sun.COM
8349430SRaymond.Chen@Sun.COM /* store a parsed uwb descriptor */
8359430SRaymond.Chen@Sun.COM child_ud->usb_wireless_data->uwb_descr =
8369430SRaymond.Chen@Sun.COM dev_info->wdev_uwb_descr;
8379430SRaymond.Chen@Sun.COM } else {
8389430SRaymond.Chen@Sun.COM USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
8399430SRaymond.Chen@Sun.COM "wusb_get_dev_uwb_descr: already done");
8409430SRaymond.Chen@Sun.COM }
8419430SRaymond.Chen@Sun.COM
8429430SRaymond.Chen@Sun.COM return (USB_SUCCESS);
8439430SRaymond.Chen@Sun.COM }
8449430SRaymond.Chen@Sun.COM
8459430SRaymond.Chen@Sun.COM /* Get WUSB device BOS descr cloud, refer to WUSB 1.0/7.4.1 */
8469430SRaymond.Chen@Sun.COM int
wusb_get_bos_cloud(dev_info_t * child_dip,usba_device_t * child_ud)8479430SRaymond.Chen@Sun.COM wusb_get_bos_cloud(dev_info_t *child_dip, usba_device_t *child_ud)
8489430SRaymond.Chen@Sun.COM {
8499430SRaymond.Chen@Sun.COM usb_bos_descr_t *bos_descr;
8509430SRaymond.Chen@Sun.COM mblk_t *pdata = NULL;
8519430SRaymond.Chen@Sun.COM int rval;
8529430SRaymond.Chen@Sun.COM size_t size;
8539430SRaymond.Chen@Sun.COM usb_cr_t completion_reason;
8549430SRaymond.Chen@Sun.COM usb_cb_flags_t cb_flags;
8559430SRaymond.Chen@Sun.COM usb_pipe_handle_t def_ph;
8569430SRaymond.Chen@Sun.COM usba_wireless_data_t *wireless_data;
8579430SRaymond.Chen@Sun.COM
8589430SRaymond.Chen@Sun.COM USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
8599430SRaymond.Chen@Sun.COM "wusb_get_bos_cloud: ");
8609430SRaymond.Chen@Sun.COM
8619430SRaymond.Chen@Sun.COM bos_descr = (usb_bos_descr_t *)kmem_zalloc(sizeof (usb_bos_descr_t),
8629430SRaymond.Chen@Sun.COM KM_SLEEP);
8639430SRaymond.Chen@Sun.COM
8649430SRaymond.Chen@Sun.COM def_ph = usba_get_dflt_pipe_handle(child_dip);
8659430SRaymond.Chen@Sun.COM
8669430SRaymond.Chen@Sun.COM if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, def_ph,
8679430SRaymond.Chen@Sun.COM USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
8689430SRaymond.Chen@Sun.COM USB_REQ_GET_DESCR,
8699430SRaymond.Chen@Sun.COM USB_DESCR_TYPE_BOS << 8,
8709430SRaymond.Chen@Sun.COM 0,
8719430SRaymond.Chen@Sun.COM USB_BOS_DESCR_SIZE,
8729430SRaymond.Chen@Sun.COM &pdata,
8739430SRaymond.Chen@Sun.COM 0,
8749430SRaymond.Chen@Sun.COM &completion_reason,
8759430SRaymond.Chen@Sun.COM &cb_flags,
8769430SRaymond.Chen@Sun.COM 0)) == USB_SUCCESS) {
8779430SRaymond.Chen@Sun.COM
8789430SRaymond.Chen@Sun.COM /* this must be true since we didn't allow data underruns */
8799430SRaymond.Chen@Sun.COM if (MBLKL(pdata) != USB_BOS_DESCR_SIZE) {
8809430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
8819430SRaymond.Chen@Sun.COM "device returned incorrect bos "
8829430SRaymond.Chen@Sun.COM "descriptor size.");
8839430SRaymond.Chen@Sun.COM
8849430SRaymond.Chen@Sun.COM rval = USB_FAILURE;
8859430SRaymond.Chen@Sun.COM goto done;
8869430SRaymond.Chen@Sun.COM }
8879430SRaymond.Chen@Sun.COM
8889430SRaymond.Chen@Sun.COM /*
8899430SRaymond.Chen@Sun.COM * Parse the bos descriptor
8909430SRaymond.Chen@Sun.COM */
8919430SRaymond.Chen@Sun.COM size = usb_parse_bos_descr(pdata->b_rptr,
8929430SRaymond.Chen@Sun.COM MBLKL(pdata), bos_descr,
8939430SRaymond.Chen@Sun.COM sizeof (usb_bos_descr_t));
8949430SRaymond.Chen@Sun.COM
8959430SRaymond.Chen@Sun.COM /* if parse bos descr error, it should return failure */
8969430SRaymond.Chen@Sun.COM if (size == USB_PARSE_ERROR) {
8979430SRaymond.Chen@Sun.COM
8989430SRaymond.Chen@Sun.COM if (pdata->b_rptr[1] != USB_DESCR_TYPE_BOS) {
8999430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI,
9009430SRaymond.Chen@Sun.COM whcdi_log_handle,
9019430SRaymond.Chen@Sun.COM "device returned incorrect "
9029430SRaymond.Chen@Sun.COM "bos descriptor type.");
9039430SRaymond.Chen@Sun.COM }
9049430SRaymond.Chen@Sun.COM rval = USB_FAILURE;
9059430SRaymond.Chen@Sun.COM goto done;
9069430SRaymond.Chen@Sun.COM }
9079430SRaymond.Chen@Sun.COM
9089430SRaymond.Chen@Sun.COM if (bos_descr->wTotalLength < USB_BOS_DESCR_SIZE) {
9099430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
9109430SRaymond.Chen@Sun.COM "device returned incorrect "
9119430SRaymond.Chen@Sun.COM "bos descriptor size.");
9129430SRaymond.Chen@Sun.COM
9139430SRaymond.Chen@Sun.COM rval = USB_FAILURE;
9149430SRaymond.Chen@Sun.COM goto done;
9159430SRaymond.Chen@Sun.COM }
9169430SRaymond.Chen@Sun.COM
9179430SRaymond.Chen@Sun.COM freemsg(pdata);
9189430SRaymond.Chen@Sun.COM pdata = NULL;
9199430SRaymond.Chen@Sun.COM
9209430SRaymond.Chen@Sun.COM /* Now fetch the complete bos cloud */
9219430SRaymond.Chen@Sun.COM if ((rval = usb_pipe_sync_ctrl_xfer(child_dip, def_ph,
9229430SRaymond.Chen@Sun.COM USB_DEV_REQ_DEV_TO_HOST | USB_DEV_REQ_TYPE_STANDARD,
9239430SRaymond.Chen@Sun.COM USB_REQ_GET_DESCR,
9249430SRaymond.Chen@Sun.COM USB_DESCR_TYPE_BOS << 8,
9259430SRaymond.Chen@Sun.COM 0,
9269430SRaymond.Chen@Sun.COM bos_descr->wTotalLength,
9279430SRaymond.Chen@Sun.COM &pdata,
9289430SRaymond.Chen@Sun.COM 0,
9299430SRaymond.Chen@Sun.COM &completion_reason,
9309430SRaymond.Chen@Sun.COM &cb_flags,
9319430SRaymond.Chen@Sun.COM 0)) == USB_SUCCESS) {
9329430SRaymond.Chen@Sun.COM
9339430SRaymond.Chen@Sun.COM if (MBLKL(pdata) != bos_descr->wTotalLength) {
9349430SRaymond.Chen@Sun.COM
9359430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI,
9369430SRaymond.Chen@Sun.COM whcdi_log_handle,
9379430SRaymond.Chen@Sun.COM "device returned incorrect "
9389430SRaymond.Chen@Sun.COM "bos descriptor cloud.");
9399430SRaymond.Chen@Sun.COM
9409430SRaymond.Chen@Sun.COM rval = USB_FAILURE;
9419430SRaymond.Chen@Sun.COM goto done;
9429430SRaymond.Chen@Sun.COM }
9439430SRaymond.Chen@Sun.COM
9449430SRaymond.Chen@Sun.COM /*
9459430SRaymond.Chen@Sun.COM * copy bos descriptor into usba_device
9469430SRaymond.Chen@Sun.COM */
9479430SRaymond.Chen@Sun.COM mutex_enter(&child_ud->usb_mutex);
9489430SRaymond.Chen@Sun.COM wireless_data = child_ud->usb_wireless_data;
9499430SRaymond.Chen@Sun.COM wireless_data->wusb_bos =
9509430SRaymond.Chen@Sun.COM kmem_zalloc(bos_descr->wTotalLength, KM_SLEEP);
9519430SRaymond.Chen@Sun.COM wireless_data->wusb_bos_length =
9529430SRaymond.Chen@Sun.COM bos_descr->wTotalLength;
9539430SRaymond.Chen@Sun.COM bcopy((caddr_t)pdata->b_rptr,
9549430SRaymond.Chen@Sun.COM (caddr_t)wireless_data->wusb_bos,
9559430SRaymond.Chen@Sun.COM bos_descr->wTotalLength);
9569430SRaymond.Chen@Sun.COM USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
9579430SRaymond.Chen@Sun.COM "bos_length = %d",
9589430SRaymond.Chen@Sun.COM wireless_data->wusb_bos_length);
9599430SRaymond.Chen@Sun.COM mutex_exit(&child_ud->usb_mutex);
9609430SRaymond.Chen@Sun.COM }
9619430SRaymond.Chen@Sun.COM }
9629430SRaymond.Chen@Sun.COM
9639430SRaymond.Chen@Sun.COM done:
9649430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
9659430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
9669430SRaymond.Chen@Sun.COM "wusb_get_bos_cloud: "
9679430SRaymond.Chen@Sun.COM "error in retrieving bos descriptor, rval=%d cr=%d",
9689430SRaymond.Chen@Sun.COM rval, completion_reason);
9699430SRaymond.Chen@Sun.COM }
9709430SRaymond.Chen@Sun.COM
9719430SRaymond.Chen@Sun.COM if (pdata) {
9729430SRaymond.Chen@Sun.COM freemsg(pdata);
9739430SRaymond.Chen@Sun.COM pdata = NULL;
9749430SRaymond.Chen@Sun.COM }
9759430SRaymond.Chen@Sun.COM
9769430SRaymond.Chen@Sun.COM kmem_free(bos_descr, sizeof (usb_bos_descr_t));
9779430SRaymond.Chen@Sun.COM
9789430SRaymond.Chen@Sun.COM return (rval);
9799430SRaymond.Chen@Sun.COM }
9809430SRaymond.Chen@Sun.COM
9819430SRaymond.Chen@Sun.COM /* Get WUSB device security descriptors, refer to WUSB 1.0/7.4.5 */
9829430SRaymond.Chen@Sun.COM int
wusb_get_dev_security_descr(usb_pipe_handle_t ph,wusb_secrt_data_t * secrt_data)9839430SRaymond.Chen@Sun.COM wusb_get_dev_security_descr(usb_pipe_handle_t ph,
9849430SRaymond.Chen@Sun.COM wusb_secrt_data_t *secrt_data)
9859430SRaymond.Chen@Sun.COM {
9869430SRaymond.Chen@Sun.COM usb_ctrl_setup_t setup;
9879430SRaymond.Chen@Sun.COM mblk_t *pdata = NULL;
9889430SRaymond.Chen@Sun.COM usb_cr_t cr;
9899430SRaymond.Chen@Sun.COM usb_cb_flags_t cb_flags;
9909430SRaymond.Chen@Sun.COM int i, rval;
9919430SRaymond.Chen@Sun.COM size_t size, len;
9929430SRaymond.Chen@Sun.COM uint8_t *p;
9939430SRaymond.Chen@Sun.COM
9949430SRaymond.Chen@Sun.COM setup.bmRequestType = USB_DEV_REQ_DEV_TO_HOST;
9959430SRaymond.Chen@Sun.COM setup.bRequest = USB_REQ_GET_DESCR;
9969430SRaymond.Chen@Sun.COM setup.wValue = USB_DESCR_TYPE_SECURITY << 8;
9979430SRaymond.Chen@Sun.COM setup.wIndex = 0;
9989430SRaymond.Chen@Sun.COM setup.wLength = USB_SECURITY_DESCR_SIZE;
9999430SRaymond.Chen@Sun.COM setup.attrs = USB_ATTRS_NONE;
10009430SRaymond.Chen@Sun.COM
10019430SRaymond.Chen@Sun.COM rval = usb_pipe_ctrl_xfer_wait(ph, &setup, &pdata, &cr, &cb_flags,
10029430SRaymond.Chen@Sun.COM USB_FLAGS_SLEEP);
10039430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
10049430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
10059430SRaymond.Chen@Sun.COM "wusb_get_dev_security_descr "
10069430SRaymond.Chen@Sun.COM "failed, rval = %d, cr = %d", rval, cr);
10079430SRaymond.Chen@Sun.COM
10089430SRaymond.Chen@Sun.COM return (rval);
10099430SRaymond.Chen@Sun.COM }
10109430SRaymond.Chen@Sun.COM
10119430SRaymond.Chen@Sun.COM if (MBLKL(pdata) != USB_SECURITY_DESCR_SIZE) {
10129430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
10139430SRaymond.Chen@Sun.COM "received incorrect security descriptor size");
10149430SRaymond.Chen@Sun.COM rval = USB_FAILURE;
10159430SRaymond.Chen@Sun.COM
10169430SRaymond.Chen@Sun.COM goto done;
10179430SRaymond.Chen@Sun.COM }
10189430SRaymond.Chen@Sun.COM
10199430SRaymond.Chen@Sun.COM /* Parse the security descriptor */
10209430SRaymond.Chen@Sun.COM size = usb_parse_data("ccsc", pdata->b_rptr,
10219430SRaymond.Chen@Sun.COM MBLKL(pdata), &secrt_data->secrt_descr,
10229430SRaymond.Chen@Sun.COM sizeof (usb_security_descr_t));
10239430SRaymond.Chen@Sun.COM
10249430SRaymond.Chen@Sun.COM /* check if the parsed descr is good */
10259430SRaymond.Chen@Sun.COM if (size < USB_SECURITY_DESCR_SIZE) {
10269430SRaymond.Chen@Sun.COM rval = USB_FAILURE;
10279430SRaymond.Chen@Sun.COM
10289430SRaymond.Chen@Sun.COM goto done;
10299430SRaymond.Chen@Sun.COM }
10309430SRaymond.Chen@Sun.COM
10319430SRaymond.Chen@Sun.COM if (secrt_data->secrt_descr.wTotalLength < USB_SECURITY_DESCR_SIZE) {
10329430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
10339430SRaymond.Chen@Sun.COM "device returned incorrect security descriptor size");
10349430SRaymond.Chen@Sun.COM rval = USB_FAILURE;
10359430SRaymond.Chen@Sun.COM
10369430SRaymond.Chen@Sun.COM goto done;
10379430SRaymond.Chen@Sun.COM }
10389430SRaymond.Chen@Sun.COM
10399430SRaymond.Chen@Sun.COM freemsg(pdata);
10409430SRaymond.Chen@Sun.COM pdata = NULL;
10419430SRaymond.Chen@Sun.COM
10429430SRaymond.Chen@Sun.COM secrt_data->secrt_n_encry =
10439430SRaymond.Chen@Sun.COM secrt_data->secrt_descr.bNumEncryptionTypes;
10449430SRaymond.Chen@Sun.COM len = sizeof (usb_encryption_descr_t) * secrt_data->secrt_n_encry;
10459430SRaymond.Chen@Sun.COM secrt_data->secrt_encry_descr =
10469430SRaymond.Chen@Sun.COM (usb_encryption_descr_t *)kmem_zalloc(len, KM_SLEEP);
10479430SRaymond.Chen@Sun.COM
10489430SRaymond.Chen@Sun.COM /* Now fetch the complete security descr cloud */
10499430SRaymond.Chen@Sun.COM setup.wLength = secrt_data->secrt_descr.wTotalLength;
10509430SRaymond.Chen@Sun.COM rval = usb_pipe_ctrl_xfer_wait(ph, &setup, &pdata, &cr, &cb_flags,
10519430SRaymond.Chen@Sun.COM USB_FLAGS_SLEEP);
10529430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
10539430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
10549430SRaymond.Chen@Sun.COM "wusb_get_dev_security_descr "
10559430SRaymond.Chen@Sun.COM "for total cloud failed, rval = %d, cr = %d", rval, cr);
10569430SRaymond.Chen@Sun.COM
10579430SRaymond.Chen@Sun.COM goto done;
10589430SRaymond.Chen@Sun.COM }
10599430SRaymond.Chen@Sun.COM
10609430SRaymond.Chen@Sun.COM if (MBLKL(pdata) != secrt_data->secrt_descr.wTotalLength) {
10619430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
10629430SRaymond.Chen@Sun.COM "received incorrect security descriptor cloud size");
10639430SRaymond.Chen@Sun.COM rval = USB_FAILURE;
10649430SRaymond.Chen@Sun.COM
10659430SRaymond.Chen@Sun.COM goto done;
10669430SRaymond.Chen@Sun.COM }
10679430SRaymond.Chen@Sun.COM
10689430SRaymond.Chen@Sun.COM p = pdata->b_rptr + USB_SECURITY_DESCR_SIZE;
10699430SRaymond.Chen@Sun.COM for (i = 0; i < secrt_data->secrt_n_encry; i++) {
10709430SRaymond.Chen@Sun.COM size = usb_parse_data("ccccc", p, _PTRDIFF(pdata->b_wptr, p),
10719430SRaymond.Chen@Sun.COM &secrt_data->secrt_encry_descr[i],
10729430SRaymond.Chen@Sun.COM sizeof (usb_encryption_descr_t));
10739430SRaymond.Chen@Sun.COM if (size < USB_ENCRYPTION_DESCR_SIZE) {
10749430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
10759430SRaymond.Chen@Sun.COM "parse %dth encryption descr failed", i);
10769430SRaymond.Chen@Sun.COM rval = USB_FAILURE;
10779430SRaymond.Chen@Sun.COM
10789430SRaymond.Chen@Sun.COM goto done;
10799430SRaymond.Chen@Sun.COM }
10809430SRaymond.Chen@Sun.COM p += USB_ENCRYPTION_DESCR_SIZE;
10819430SRaymond.Chen@Sun.COM }
10829430SRaymond.Chen@Sun.COM
10839430SRaymond.Chen@Sun.COM done:
10849430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
10859430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
10869430SRaymond.Chen@Sun.COM "wusb_get_dev_security_descr: "
10879430SRaymond.Chen@Sun.COM "error in retrieving security descriptors");
10889430SRaymond.Chen@Sun.COM if (secrt_data->secrt_encry_descr) {
10899430SRaymond.Chen@Sun.COM kmem_free(secrt_data->secrt_encry_descr, len);
10909430SRaymond.Chen@Sun.COM secrt_data->secrt_encry_descr = NULL;
10919430SRaymond.Chen@Sun.COM }
10929430SRaymond.Chen@Sun.COM }
10939430SRaymond.Chen@Sun.COM
10949430SRaymond.Chen@Sun.COM if (pdata) {
10959430SRaymond.Chen@Sun.COM freemsg(pdata);
10969430SRaymond.Chen@Sun.COM pdata = NULL;
10979430SRaymond.Chen@Sun.COM }
10989430SRaymond.Chen@Sun.COM
10999430SRaymond.Chen@Sun.COM return (rval);
11009430SRaymond.Chen@Sun.COM }
11019430SRaymond.Chen@Sun.COM
11029430SRaymond.Chen@Sun.COM /* Get WUSB device status, refer to WUSB 1.0/7.3.1.2 */
11039430SRaymond.Chen@Sun.COM int
wusb_get_dev_status(usb_pipe_handle_t ph,uint16_t selector,uint16_t len,uint8_t * status)11049430SRaymond.Chen@Sun.COM wusb_get_dev_status(usb_pipe_handle_t ph, uint16_t selector,
11059430SRaymond.Chen@Sun.COM uint16_t len, uint8_t *status)
11069430SRaymond.Chen@Sun.COM {
11079430SRaymond.Chen@Sun.COM usb_ctrl_setup_t setup;
11089430SRaymond.Chen@Sun.COM mblk_t *pdata = NULL;
11099430SRaymond.Chen@Sun.COM usb_cr_t cr;
11109430SRaymond.Chen@Sun.COM usb_cb_flags_t cb_flags;
11119430SRaymond.Chen@Sun.COM int rval;
11129430SRaymond.Chen@Sun.COM
11139430SRaymond.Chen@Sun.COM USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
11149430SRaymond.Chen@Sun.COM "wusb_get_dev_status: selector = %d, len = %d", selector, len);
11159430SRaymond.Chen@Sun.COM
11169430SRaymond.Chen@Sun.COM setup.bmRequestType = USB_DEV_REQ_DEV_TO_HOST;
11179430SRaymond.Chen@Sun.COM setup.bRequest = USB_REQ_GET_STATUS;
11189430SRaymond.Chen@Sun.COM setup.wValue = 0;
11199430SRaymond.Chen@Sun.COM setup.wIndex = selector;
11209430SRaymond.Chen@Sun.COM setup.wLength = len;
11219430SRaymond.Chen@Sun.COM setup.attrs = USB_ATTRS_NONE;
11229430SRaymond.Chen@Sun.COM
11239430SRaymond.Chen@Sun.COM rval = usb_pipe_ctrl_xfer_wait(ph, &setup, &pdata, &cr, &cb_flags,
11249430SRaymond.Chen@Sun.COM USB_FLAGS_SLEEP);
11259430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
11269430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
11279430SRaymond.Chen@Sun.COM "wusb_get_dev_status failed, rval = %d, cr = %d", rval, cr);
11289430SRaymond.Chen@Sun.COM
11299430SRaymond.Chen@Sun.COM return (rval);
11309430SRaymond.Chen@Sun.COM }
11319430SRaymond.Chen@Sun.COM if (pdata == NULL) {
11329430SRaymond.Chen@Sun.COM return (USB_FAILURE);
11339430SRaymond.Chen@Sun.COM }
11349430SRaymond.Chen@Sun.COM if (MBLKL(pdata) != len) {
11359430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
11369430SRaymond.Chen@Sun.COM "received incorrect dev status size");
11379430SRaymond.Chen@Sun.COM freemsg(pdata);
11389430SRaymond.Chen@Sun.COM
11399430SRaymond.Chen@Sun.COM return (USB_FAILURE);
11409430SRaymond.Chen@Sun.COM }
11419430SRaymond.Chen@Sun.COM
11429430SRaymond.Chen@Sun.COM bcopy(pdata->b_rptr, status, len);
11439430SRaymond.Chen@Sun.COM freemsg(pdata);
11449430SRaymond.Chen@Sun.COM
11459430SRaymond.Chen@Sun.COM if ((selector == WUSB_STS_TYPE_MAS_AVAIL) &&
11469430SRaymond.Chen@Sun.COM (len == WUSB_SET_WUSB_MAS_LEN)) {
11479430SRaymond.Chen@Sun.COM uint8_t *p = status;
11489430SRaymond.Chen@Sun.COM
11499430SRaymond.Chen@Sun.COM USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
11509430SRaymond.Chen@Sun.COM "mas_avail: %x %x %x %x %x %x %x %x %x %x %x %x "
11519430SRaymond.Chen@Sun.COM "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x "
11529430SRaymond.Chen@Sun.COM "%x %x %x %x", p[0], p[1], p[2], p[3], p[4], p[5], p[6],
11539430SRaymond.Chen@Sun.COM p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15],
11549430SRaymond.Chen@Sun.COM p[16], p[17], p[18], p[19], p[20], p[21], p[22], p[23],
11559430SRaymond.Chen@Sun.COM p[24], p[25], p[26], p[27], p[28], p[29], p[30], p[31]);
11569430SRaymond.Chen@Sun.COM }
11579430SRaymond.Chen@Sun.COM
11589430SRaymond.Chen@Sun.COM return (USB_SUCCESS);
11599430SRaymond.Chen@Sun.COM }
11609430SRaymond.Chen@Sun.COM
11619430SRaymond.Chen@Sun.COM /* test function, can be removed */
11629430SRaymond.Chen@Sun.COM void
wusb_test_ctrlreq(usb_pipe_handle_t ph)11639430SRaymond.Chen@Sun.COM wusb_test_ctrlreq(usb_pipe_handle_t ph)
11649430SRaymond.Chen@Sun.COM {
11659430SRaymond.Chen@Sun.COM int i, rval;
11669430SRaymond.Chen@Sun.COM uint8_t mas[WUSB_SET_WUSB_MAS_LEN];
11679430SRaymond.Chen@Sun.COM
11689430SRaymond.Chen@Sun.COM for (i = 0; i < 10; i++) {
11699430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
11709430SRaymond.Chen@Sun.COM "wusb_test_ctrlreq %d started:", i);
11719430SRaymond.Chen@Sun.COM rval = wusb_get_dev_status(ph,
11729430SRaymond.Chen@Sun.COM WUSB_STS_TYPE_MAS_AVAIL, WUSB_SET_WUSB_MAS_LEN, mas);
11739430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
11749430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
11759430SRaymond.Chen@Sun.COM "get mas availability status %d failed, "
11769430SRaymond.Chen@Sun.COM "rval = %d", i, rval);
11779430SRaymond.Chen@Sun.COM
11789430SRaymond.Chen@Sun.COM continue;
11799430SRaymond.Chen@Sun.COM }
11809430SRaymond.Chen@Sun.COM }
11819430SRaymond.Chen@Sun.COM }
11829430SRaymond.Chen@Sun.COM
11839430SRaymond.Chen@Sun.COM /* test function, can be removed */
11849430SRaymond.Chen@Sun.COM void
wusb_test_loopback(usb_pipe_handle_t ph)11859430SRaymond.Chen@Sun.COM wusb_test_loopback(usb_pipe_handle_t ph)
11869430SRaymond.Chen@Sun.COM {
11879430SRaymond.Chen@Sun.COM usb_ctrl_setup_t setup;
11889430SRaymond.Chen@Sun.COM mblk_t *pdata;
11899430SRaymond.Chen@Sun.COM usb_cr_t cr;
11909430SRaymond.Chen@Sun.COM usb_cb_flags_t cb_flags;
11919430SRaymond.Chen@Sun.COM int i, j, rval;
11929430SRaymond.Chen@Sun.COM uint16_t len = 20;
11939430SRaymond.Chen@Sun.COM
11949430SRaymond.Chen@Sun.COM for (j = 0; j < 10; j++) {
11959430SRaymond.Chen@Sun.COM pdata = allocb_wait(len, BPRI_LO, STR_NOSIG, NULL);
11969430SRaymond.Chen@Sun.COM for (i = 0; i < len; i++) {
11979430SRaymond.Chen@Sun.COM *pdata->b_wptr++ = (uint8_t)j;
11989430SRaymond.Chen@Sun.COM }
11999430SRaymond.Chen@Sun.COM
12009430SRaymond.Chen@Sun.COM setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV;
12019430SRaymond.Chen@Sun.COM setup.bRequest = USB_REQ_LOOPBACK_DATA_WRITE;
12029430SRaymond.Chen@Sun.COM setup.wValue = 0;
12039430SRaymond.Chen@Sun.COM setup.wIndex = 0;
12049430SRaymond.Chen@Sun.COM setup.wLength = len;
12059430SRaymond.Chen@Sun.COM setup.attrs = USB_ATTRS_NONE;
12069430SRaymond.Chen@Sun.COM
12079430SRaymond.Chen@Sun.COM USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
12089430SRaymond.Chen@Sun.COM "wusb_test_loopback_write %d start:", j);
12099430SRaymond.Chen@Sun.COM
12109430SRaymond.Chen@Sun.COM rval = usb_pipe_ctrl_xfer_wait(ph, &setup, &pdata, &cr,
12119430SRaymond.Chen@Sun.COM &cb_flags, USB_FLAGS_SLEEP);
12129430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
12139430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
12149430SRaymond.Chen@Sun.COM "wusb_test_loopback_write %d failed, "
12159430SRaymond.Chen@Sun.COM "rval = %d, cr = %d", j, rval, cr);
12169430SRaymond.Chen@Sun.COM freemsg(pdata);
12179430SRaymond.Chen@Sun.COM
12189430SRaymond.Chen@Sun.COM return;
12199430SRaymond.Chen@Sun.COM }
12209430SRaymond.Chen@Sun.COM
12219430SRaymond.Chen@Sun.COM freemsg(pdata);
12229430SRaymond.Chen@Sun.COM pdata = NULL;
12239430SRaymond.Chen@Sun.COM }
12249430SRaymond.Chen@Sun.COM }
12259430SRaymond.Chen@Sun.COM
12269430SRaymond.Chen@Sun.COM /* test function, can be removed */
12279430SRaymond.Chen@Sun.COM void
wusb_test_write(wusb_dev_info_t * dev_info)12289430SRaymond.Chen@Sun.COM wusb_test_write(wusb_dev_info_t *dev_info)
12299430SRaymond.Chen@Sun.COM {
12309430SRaymond.Chen@Sun.COM int16_t value;
12319430SRaymond.Chen@Sun.COM int i, rval;
12329797SRaymond.Chen@Sun.COM usb_pipe_handle_t dev_ph;
12339430SRaymond.Chen@Sun.COM
12349430SRaymond.Chen@Sun.COM value = wusb_get_ccm_encryption_value(&dev_info->wdev_secrt_data);
12359430SRaymond.Chen@Sun.COM if (value == -1) {
12369430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
12379430SRaymond.Chen@Sun.COM "wusb_test_write: cannot find ccm encryption type");
12389430SRaymond.Chen@Sun.COM
12399430SRaymond.Chen@Sun.COM return;
12409430SRaymond.Chen@Sun.COM }
12419430SRaymond.Chen@Sun.COM /* failed at 2nd write */
12429430SRaymond.Chen@Sun.COM for (i = 0; i < 1; i++) {
12439430SRaymond.Chen@Sun.COM USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
12449430SRaymond.Chen@Sun.COM "wusb_test_write %d start:", i);
12459797SRaymond.Chen@Sun.COM mutex_enter(&dev_info->wdev_hc->hc_mutex);
12469797SRaymond.Chen@Sun.COM dev_ph = dev_info->wdev_ph;
12479797SRaymond.Chen@Sun.COM mutex_exit(&dev_info->wdev_hc->hc_mutex);
12489797SRaymond.Chen@Sun.COM
12499797SRaymond.Chen@Sun.COM rval = wusb_dev_set_encrypt(dev_ph, (uint8_t)value);
12509430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
12519430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
12529430SRaymond.Chen@Sun.COM "wusb_test_write: %dth set encryption failed", i);
12539430SRaymond.Chen@Sun.COM
12549430SRaymond.Chen@Sun.COM continue;
12559430SRaymond.Chen@Sun.COM }
12569430SRaymond.Chen@Sun.COM }
12579430SRaymond.Chen@Sun.COM }
12589430SRaymond.Chen@Sun.COM
12599430SRaymond.Chen@Sun.COM
12609430SRaymond.Chen@Sun.COM /* enable CCM encryption on the device */
12619430SRaymond.Chen@Sun.COM int
wusb_enable_dev_encrypt(wusb_hc_data_t * hc_data,wusb_dev_info_t * dev_info)12629797SRaymond.Chen@Sun.COM wusb_enable_dev_encrypt(wusb_hc_data_t *hc_data, wusb_dev_info_t *dev_info)
12639430SRaymond.Chen@Sun.COM {
12649430SRaymond.Chen@Sun.COM int16_t value;
12659430SRaymond.Chen@Sun.COM int rval;
12669797SRaymond.Chen@Sun.COM usb_pipe_handle_t ph;
12679797SRaymond.Chen@Sun.COM
12689430SRaymond.Chen@Sun.COM USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
12699430SRaymond.Chen@Sun.COM "wusb_enable_dev_encrypt:enter");
12709430SRaymond.Chen@Sun.COM
12719430SRaymond.Chen@Sun.COM value = wusb_get_ccm_encryption_value(&dev_info->wdev_secrt_data);
12729430SRaymond.Chen@Sun.COM if (value == -1) {
12739430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
12749430SRaymond.Chen@Sun.COM "wusb_enable_dev_encrypt: cannot find ccm encryption type");
12759430SRaymond.Chen@Sun.COM
12769430SRaymond.Chen@Sun.COM return (USB_FAILURE);
12779430SRaymond.Chen@Sun.COM }
12789430SRaymond.Chen@Sun.COM
12799797SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
12809797SRaymond.Chen@Sun.COM ph = dev_info->wdev_ph;
12819797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
12829797SRaymond.Chen@Sun.COM
12839797SRaymond.Chen@Sun.COM rval = wusb_dev_set_encrypt(ph, (uint8_t)value);
12849430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
12859430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
12869430SRaymond.Chen@Sun.COM "wusb_enable_dev_encrypt: set encryption failed");
12879430SRaymond.Chen@Sun.COM }
12889430SRaymond.Chen@Sun.COM USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
12899430SRaymond.Chen@Sun.COM "wusb_enable_dev_encrypti:exit");
12909430SRaymond.Chen@Sun.COM
12919430SRaymond.Chen@Sun.COM return (rval);
12929430SRaymond.Chen@Sun.COM }
12939430SRaymond.Chen@Sun.COM
12949430SRaymond.Chen@Sun.COM /*
12959430SRaymond.Chen@Sun.COM * Perform the authentication process, refer to WUSB 1.0/7.1.2.
12969430SRaymond.Chen@Sun.COM * host secrt_data will be used for 4-way handshake
12979430SRaymond.Chen@Sun.COM */
12989430SRaymond.Chen@Sun.COM /* ARGSUSED */
12999430SRaymond.Chen@Sun.COM int
wusb_hc_auth_dev(wusb_hc_data_t * hc_data,usb_port_t port,usb_pipe_handle_t ph,uint8_t ifc,wusb_secrt_data_t * secrt_data)13009430SRaymond.Chen@Sun.COM wusb_hc_auth_dev(wusb_hc_data_t *hc_data, usb_port_t port,
13019430SRaymond.Chen@Sun.COM usb_pipe_handle_t ph, uint8_t ifc,
13029430SRaymond.Chen@Sun.COM wusb_secrt_data_t *secrt_data)
13039430SRaymond.Chen@Sun.COM {
13049430SRaymond.Chen@Sun.COM wusb_dev_info_t *dev_info;
13059430SRaymond.Chen@Sun.COM usb_pipe_handle_t child_ph;
13069797SRaymond.Chen@Sun.COM dev_info_t *child_dip;
13079430SRaymond.Chen@Sun.COM
13089430SRaymond.Chen@Sun.COM ASSERT(mutex_owned(&hc_data->hc_mutex));
13099430SRaymond.Chen@Sun.COM
13109430SRaymond.Chen@Sun.COM dev_info = hc_data->hc_dev_infos[port];
13119430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
13129430SRaymond.Chen@Sun.COM "wusb_hc_auth_dev: dev addr = %d", dev_info->wdev_addr);
13139430SRaymond.Chen@Sun.COM if (dev_info == NULL) {
13149430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
13159430SRaymond.Chen@Sun.COM "wusb_hc_auth_dev: port %d invalid", port);
13169430SRaymond.Chen@Sun.COM
13179430SRaymond.Chen@Sun.COM return (USB_INVALID_ARGS);
13189430SRaymond.Chen@Sun.COM }
13199430SRaymond.Chen@Sun.COM child_ph = dev_info->wdev_ph;
13209797SRaymond.Chen@Sun.COM child_dip = hc_data->hc_children_dips[port];
13219430SRaymond.Chen@Sun.COM
13229430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
13239430SRaymond.Chen@Sun.COM /* get device security descrs */
13249430SRaymond.Chen@Sun.COM if (wusb_get_dev_security_descr(child_ph,
13259430SRaymond.Chen@Sun.COM &dev_info->wdev_secrt_data) != USB_SUCCESS) {
13269430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
13279430SRaymond.Chen@Sun.COM "wusb_hc_auth_dev: failed to get device security descrs");
13289430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
13299430SRaymond.Chen@Sun.COM
13309430SRaymond.Chen@Sun.COM return (USB_FAILURE);
13319430SRaymond.Chen@Sun.COM }
13329430SRaymond.Chen@Sun.COM
13339430SRaymond.Chen@Sun.COM /*
13349430SRaymond.Chen@Sun.COM * enable CCM encryption on the device, this needs to be done
13359430SRaymond.Chen@Sun.COM * before 4-way handshake. [WUSB 1.0/7.3.2.5]
13369430SRaymond.Chen@Sun.COM */
13379797SRaymond.Chen@Sun.COM if (wusb_enable_dev_encrypt(hc_data, dev_info) != USB_SUCCESS) {
13389430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
13399430SRaymond.Chen@Sun.COM "wusb_hc_auth_dev: set encryption failed");
13409430SRaymond.Chen@Sun.COM
13419430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
13429430SRaymond.Chen@Sun.COM return (USB_FAILURE);
13439430SRaymond.Chen@Sun.COM }
13449430SRaymond.Chen@Sun.COM
13459430SRaymond.Chen@Sun.COM
13469430SRaymond.Chen@Sun.COM /* this seems to relieve the non-response issue somehow */
13479797SRaymond.Chen@Sun.COM usb_pipe_close(child_dip, child_ph,
13489430SRaymond.Chen@Sun.COM USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
13499797SRaymond.Chen@Sun.COM
13509797SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
13519430SRaymond.Chen@Sun.COM dev_info->wdev_ph = NULL;
13529430SRaymond.Chen@Sun.COM
13539430SRaymond.Chen@Sun.COM /* unauthenticated state */
13549430SRaymond.Chen@Sun.COM /* check cc_list for existing cc with the same CDID */
13559430SRaymond.Chen@Sun.COM if ((dev_info->wdev_cc = wusb_hc_cc_matched(hc_data->hc_cc_list,
13569430SRaymond.Chen@Sun.COM dev_info->wdev_cdid)) == NULL) {
13579430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
13589430SRaymond.Chen@Sun.COM "wusb_hc_auth_dev: no matching cc found");
13599430SRaymond.Chen@Sun.COM
13609430SRaymond.Chen@Sun.COM if (dev_info->wdev_is_newconn == 0) {
13619430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
13629430SRaymond.Chen@Sun.COM "wusb_hc_auth_dev: not new connection, "
13639430SRaymond.Chen@Sun.COM "just fail");
13649430SRaymond.Chen@Sun.COM
13659430SRaymond.Chen@Sun.COM return (USB_FAILURE);
13669430SRaymond.Chen@Sun.COM }
13679430SRaymond.Chen@Sun.COM
13689430SRaymond.Chen@Sun.COM /* now we simply return not supported */
13699430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
13709430SRaymond.Chen@Sun.COM "wusb_hc_auth_dev: numeric association not supported");
13719430SRaymond.Chen@Sun.COM
13729430SRaymond.Chen@Sun.COM return (USB_NOT_SUPPORTED);
13739430SRaymond.Chen@Sun.COM }
13749430SRaymond.Chen@Sun.COM
13759430SRaymond.Chen@Sun.COM USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
13769430SRaymond.Chen@Sun.COM "wusb_hc_auth_dev: matching cc found 0x%p",
13779430SRaymond.Chen@Sun.COM (void *)dev_info->wdev_cc);
13789430SRaymond.Chen@Sun.COM
13799430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
13809797SRaymond.Chen@Sun.COM if (usb_pipe_open(child_dip, NULL, NULL,
13819430SRaymond.Chen@Sun.COM USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &child_ph) !=
13829430SRaymond.Chen@Sun.COM USB_SUCCESS) {
13839430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
13849430SRaymond.Chen@Sun.COM "usb_pipe_open failed");
13859430SRaymond.Chen@Sun.COM
13869430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
13879430SRaymond.Chen@Sun.COM
13889430SRaymond.Chen@Sun.COM return (USB_FAILURE);
13899430SRaymond.Chen@Sun.COM }
13909430SRaymond.Chen@Sun.COM
13919430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
13929430SRaymond.Chen@Sun.COM /* recording the default pipe */
13939430SRaymond.Chen@Sun.COM dev_info->wdev_ph = child_ph;
13949430SRaymond.Chen@Sun.COM
13959430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
13969430SRaymond.Chen@Sun.COM /* perform 4-way handshake */
13979430SRaymond.Chen@Sun.COM if (wusb_4way_handshake(hc_data, port, ph, ifc) != 0) {
13989430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
13999430SRaymond.Chen@Sun.COM "port(%d) 4-way handshake authentication failed!",
14009430SRaymond.Chen@Sun.COM port);
14019430SRaymond.Chen@Sun.COM
14029430SRaymond.Chen@Sun.COM /* perhaps resetting the device is better */
14039797SRaymond.Chen@Sun.COM usb_pipe_reset(child_dip, child_ph,
14049430SRaymond.Chen@Sun.COM USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED,
14059430SRaymond.Chen@Sun.COM NULL, NULL);
14069430SRaymond.Chen@Sun.COM (void) wusb_dev_set_encrypt(child_ph, 0);
14079430SRaymond.Chen@Sun.COM
14089430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
14099430SRaymond.Chen@Sun.COM
14109430SRaymond.Chen@Sun.COM return (USB_FAILURE);
14119430SRaymond.Chen@Sun.COM }
14129430SRaymond.Chen@Sun.COM
14139430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
14149430SRaymond.Chen@Sun.COM
14159430SRaymond.Chen@Sun.COM return (USB_SUCCESS);
14169430SRaymond.Chen@Sun.COM }
14179430SRaymond.Chen@Sun.COM
14189430SRaymond.Chen@Sun.COM /* Acknowledge WUSB Device Disconnect notification, refer to WUSB 1.0/7.6.2 */
14199430SRaymond.Chen@Sun.COM int
wusb_hc_ack_disconn(wusb_hc_data_t * hc_data,uint8_t addr)14209430SRaymond.Chen@Sun.COM wusb_hc_ack_disconn(wusb_hc_data_t *hc_data, uint8_t addr)
14219430SRaymond.Chen@Sun.COM {
14229430SRaymond.Chen@Sun.COM wusb_ie_dev_disconnect_t *disconn_ie;
14239430SRaymond.Chen@Sun.COM uint8_t iehdl;
14249430SRaymond.Chen@Sun.COM int rval;
14259430SRaymond.Chen@Sun.COM
14269430SRaymond.Chen@Sun.COM ASSERT(mutex_owned(&hc_data->hc_mutex));
14279430SRaymond.Chen@Sun.COM
14289430SRaymond.Chen@Sun.COM /*
14299430SRaymond.Chen@Sun.COM * the scheme ensures each time only one device addr
14309430SRaymond.Chen@Sun.COM * is set each time
14319430SRaymond.Chen@Sun.COM */
14329430SRaymond.Chen@Sun.COM disconn_ie = kmem_zalloc(sizeof (wusb_ie_dev_disconnect_t), KM_SLEEP);
14339430SRaymond.Chen@Sun.COM if (!disconn_ie) {
14349430SRaymond.Chen@Sun.COM return (USB_NO_RESOURCES);
14359430SRaymond.Chen@Sun.COM }
14369430SRaymond.Chen@Sun.COM
14379430SRaymond.Chen@Sun.COM disconn_ie->bIEIdentifier = WUSB_IE_DEV_DISCONNECT;
14389430SRaymond.Chen@Sun.COM disconn_ie->bDeviceAddress[0] = addr;
14399430SRaymond.Chen@Sun.COM /* padding, no active wusb device addr will be 1 */
14409430SRaymond.Chen@Sun.COM disconn_ie->bDeviceAddress[1] = 1;
14419430SRaymond.Chen@Sun.COM disconn_ie->bLength = 4;
14429430SRaymond.Chen@Sun.COM
14439430SRaymond.Chen@Sun.COM rval = wusb_hc_get_iehdl(hc_data, (wusb_ie_header_t *)disconn_ie,
14449430SRaymond.Chen@Sun.COM &iehdl);
14459430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
14469430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
14479430SRaymond.Chen@Sun.COM "wusb_hc_ack_disconn: get ie handle fails");
14489430SRaymond.Chen@Sun.COM kmem_free(disconn_ie, sizeof (wusb_ie_dev_disconnect_t));
14499430SRaymond.Chen@Sun.COM
14509430SRaymond.Chen@Sun.COM return (rval);
14519430SRaymond.Chen@Sun.COM }
14529430SRaymond.Chen@Sun.COM
14539430SRaymond.Chen@Sun.COM rval = wusb_hc_add_mmc_ie(hc_data, 0, 0, iehdl,
14549430SRaymond.Chen@Sun.COM disconn_ie->bLength, (uint8_t *)disconn_ie);
14559430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
14569430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
14579430SRaymond.Chen@Sun.COM "wusb_hc_ack_disconn: add dev disconnect ie fails");
14589430SRaymond.Chen@Sun.COM wusb_hc_free_iehdl(hc_data, iehdl);
14599430SRaymond.Chen@Sun.COM kmem_free(disconn_ie, sizeof (wusb_ie_dev_disconnect_t));
14609430SRaymond.Chen@Sun.COM
14619430SRaymond.Chen@Sun.COM return (rval);
14629430SRaymond.Chen@Sun.COM }
14639430SRaymond.Chen@Sun.COM
14649430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
14659430SRaymond.Chen@Sun.COM /*
14669430SRaymond.Chen@Sun.COM * WUSB 1.0/7.5.4 requires the IE to be transmitted at least
14679430SRaymond.Chen@Sun.COM * 100ms before ceasing, wait for 150ms here
14689430SRaymond.Chen@Sun.COM */
14699430SRaymond.Chen@Sun.COM delay(drv_usectohz(150000));
14709430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
14719430SRaymond.Chen@Sun.COM
14729430SRaymond.Chen@Sun.COM /* cease transmitting the IE */
14739430SRaymond.Chen@Sun.COM (void) wusb_hc_remove_mmc_ie(hc_data, (uint8_t)iehdl);
14749430SRaymond.Chen@Sun.COM wusb_hc_free_iehdl(hc_data, iehdl);
14759430SRaymond.Chen@Sun.COM kmem_free(disconn_ie, sizeof (wusb_ie_dev_disconnect_t));
14769430SRaymond.Chen@Sun.COM
14779430SRaymond.Chen@Sun.COM return (USB_SUCCESS);
14789430SRaymond.Chen@Sun.COM }
14799430SRaymond.Chen@Sun.COM
14809430SRaymond.Chen@Sun.COM /* create child devinfo node and usba_device structure */
14819430SRaymond.Chen@Sun.COM int
wusb_create_child_devi(dev_info_t * dip,char * node_name,usba_hcdi_ops_t * usba_hcdi_ops,dev_info_t * usb_root_hub_dip,usb_port_status_t port_status,usba_device_t * usba_device,dev_info_t ** child_dip)14829430SRaymond.Chen@Sun.COM wusb_create_child_devi(dev_info_t *dip, char *node_name,
14839430SRaymond.Chen@Sun.COM usba_hcdi_ops_t *usba_hcdi_ops, dev_info_t *usb_root_hub_dip,
14849430SRaymond.Chen@Sun.COM usb_port_status_t port_status, usba_device_t *usba_device,
14859430SRaymond.Chen@Sun.COM dev_info_t **child_dip)
14869430SRaymond.Chen@Sun.COM {
14879430SRaymond.Chen@Sun.COM ndi_devi_alloc_sleep(dip, node_name, (pnode_t)DEVI_SID_NODEID,
14889430SRaymond.Chen@Sun.COM child_dip);
14899430SRaymond.Chen@Sun.COM
14909430SRaymond.Chen@Sun.COM usba_device = usba_alloc_usba_device(usb_root_hub_dip);
14919430SRaymond.Chen@Sun.COM
14929430SRaymond.Chen@Sun.COM /* grab the mutex to keep warlock happy */
14939430SRaymond.Chen@Sun.COM mutex_enter(&usba_device->usb_mutex);
14949430SRaymond.Chen@Sun.COM usba_device->usb_hcdi_ops = usba_hcdi_ops;
14959430SRaymond.Chen@Sun.COM usba_device->usb_port_status = port_status;
14969430SRaymond.Chen@Sun.COM usba_device->usb_is_wireless = B_TRUE;
14979430SRaymond.Chen@Sun.COM mutex_exit(&usba_device->usb_mutex);
14989430SRaymond.Chen@Sun.COM
14999430SRaymond.Chen@Sun.COM /* store the usba_device point in the dip */
15009430SRaymond.Chen@Sun.COM usba_set_usba_device(*child_dip, usba_device);
15019430SRaymond.Chen@Sun.COM
15029430SRaymond.Chen@Sun.COM return (USB_SUCCESS);
15039430SRaymond.Chen@Sun.COM }
15049430SRaymond.Chen@Sun.COM
15059430SRaymond.Chen@Sun.COM /*
15069430SRaymond.Chen@Sun.COM * Handle WUSB child device connection, including creating child devinfo
15079430SRaymond.Chen@Sun.COM * and usba strutures, authentication, configuration and attach.
15089430SRaymond.Chen@Sun.COM */
15099430SRaymond.Chen@Sun.COM int
wusb_hc_handle_port_connect(wusb_hc_data_t * hc_data,usb_port_t port,usb_pipe_handle_t ph,uint8_t ifc,wusb_secrt_data_t * secrt_data)15109430SRaymond.Chen@Sun.COM wusb_hc_handle_port_connect(wusb_hc_data_t *hc_data, usb_port_t port,
15119430SRaymond.Chen@Sun.COM usb_pipe_handle_t ph, uint8_t ifc, wusb_secrt_data_t *secrt_data)
15129430SRaymond.Chen@Sun.COM {
15139430SRaymond.Chen@Sun.COM dev_info_t *dip = hc_data->hc_dip;
15149430SRaymond.Chen@Sun.COM dev_info_t *child_dip = NULL;
15159430SRaymond.Chen@Sun.COM usba_device_t *child_ud = NULL;
15169430SRaymond.Chen@Sun.COM usba_device_t *parent_ud;
15179430SRaymond.Chen@Sun.COM usba_hcdi_t *hcdi = usba_hcdi_get_hcdi(dip);
15189430SRaymond.Chen@Sun.COM usb_pipe_handle_t child_ph = NULL;
15199430SRaymond.Chen@Sun.COM int rval;
15209430SRaymond.Chen@Sun.COM int child_created = 0;
15219430SRaymond.Chen@Sun.COM wusb_dev_info_t *dev_info;
15229430SRaymond.Chen@Sun.COM usb_dev_descr_t usb_dev_descr;
15239430SRaymond.Chen@Sun.COM int ackie_removed = 0;
15249430SRaymond.Chen@Sun.COM
15259430SRaymond.Chen@Sun.COM USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
15269430SRaymond.Chen@Sun.COM "wusb_hc_handle_port_connect: hc_data=0x%p, port=%d",
15279430SRaymond.Chen@Sun.COM (void *)hc_data, port);
15289430SRaymond.Chen@Sun.COM
15299430SRaymond.Chen@Sun.COM ASSERT(mutex_owned(&hc_data->hc_mutex));
15309430SRaymond.Chen@Sun.COM dev_info = hc_data->hc_dev_infos[port];
15319430SRaymond.Chen@Sun.COM if (dev_info == NULL) {
15329430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
15339430SRaymond.Chen@Sun.COM "wusb_hc_handle_port_connect: port %d invalid", port);
15349430SRaymond.Chen@Sun.COM wusb_hc_rm_ack(hc_data);
15359430SRaymond.Chen@Sun.COM
15369430SRaymond.Chen@Sun.COM return (USB_INVALID_ARGS);
15379430SRaymond.Chen@Sun.COM }
15389430SRaymond.Chen@Sun.COM
15399430SRaymond.Chen@Sun.COM dev_info->wdev_hc = hc_data;
15409430SRaymond.Chen@Sun.COM
15419430SRaymond.Chen@Sun.COM /* prepare child devinfo and usba structures */
15429430SRaymond.Chen@Sun.COM if (hc_data->hc_children_dips[port]) {
15439430SRaymond.Chen@Sun.COM child_dip = hc_data->hc_children_dips[port];
15449430SRaymond.Chen@Sun.COM child_ud = hc_data->hc_usba_devices[port];
15459430SRaymond.Chen@Sun.COM child_ph = usba_get_dflt_pipe_handle(child_dip);
15469430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
15479430SRaymond.Chen@Sun.COM usb_pipe_close(child_dip, child_ph,
15489430SRaymond.Chen@Sun.COM USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
15499430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
15509430SRaymond.Chen@Sun.COM } else {
15519430SRaymond.Chen@Sun.COM rval = wusb_create_child_devi(dip,
15529430SRaymond.Chen@Sun.COM "device",
15539430SRaymond.Chen@Sun.COM hcdi->hcdi_ops,
15549430SRaymond.Chen@Sun.COM dip,
15559430SRaymond.Chen@Sun.COM USBA_HIGH_SPEED_DEV,
15569430SRaymond.Chen@Sun.COM child_ud,
15579430SRaymond.Chen@Sun.COM &child_dip);
15589430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
15599430SRaymond.Chen@Sun.COM wusb_hc_rm_ack(hc_data); // , ph, ifc);
15609430SRaymond.Chen@Sun.COM
15619430SRaymond.Chen@Sun.COM return (rval);
15629430SRaymond.Chen@Sun.COM }
15639430SRaymond.Chen@Sun.COM child_ud = usba_get_usba_device(child_dip);
15649430SRaymond.Chen@Sun.COM ASSERT(child_ud != NULL);
15659430SRaymond.Chen@Sun.COM
15669430SRaymond.Chen@Sun.COM mutex_enter(&child_ud->usb_mutex);
15679430SRaymond.Chen@Sun.COM child_ud->usb_dev_descr = kmem_zalloc(sizeof (usb_dev_descr_t),
15689430SRaymond.Chen@Sun.COM KM_SLEEP);
15699430SRaymond.Chen@Sun.COM child_ud->usb_wireless_data =
15709430SRaymond.Chen@Sun.COM kmem_zalloc(sizeof (usba_wireless_data_t), KM_SLEEP);
15719430SRaymond.Chen@Sun.COM mutex_exit(&child_ud->usb_mutex);
15729430SRaymond.Chen@Sun.COM child_created = 1;
15739430SRaymond.Chen@Sun.COM hc_data->hc_children_dips[port] = child_dip;
15749430SRaymond.Chen@Sun.COM hc_data->hc_usba_devices[port] = child_ud;
15759430SRaymond.Chen@Sun.COM }
15769430SRaymond.Chen@Sun.COM
15779430SRaymond.Chen@Sun.COM /* do necessary setup */
15789430SRaymond.Chen@Sun.COM parent_ud = usba_get_usba_device(dip);
15799430SRaymond.Chen@Sun.COM mutex_enter(&child_ud->usb_mutex);
15809430SRaymond.Chen@Sun.COM child_ud->usb_addr = dev_info->wdev_addr;
15819430SRaymond.Chen@Sun.COM child_ud->usb_port = port;
15829430SRaymond.Chen@Sun.COM
15839430SRaymond.Chen@Sun.COM /*
15849430SRaymond.Chen@Sun.COM * TODO: now only consider the situation that HWA is high
15859430SRaymond.Chen@Sun.COM * speed dev for the children. The situation that HWA is
15869430SRaymond.Chen@Sun.COM * connected to the USB 1.1 port is not considered. The
15879430SRaymond.Chen@Sun.COM * available HWA devices can't work behind USB1.1 port.
15889430SRaymond.Chen@Sun.COM */
15899430SRaymond.Chen@Sun.COM child_ud->usb_hs_hub_usba_dev = parent_ud;
15909430SRaymond.Chen@Sun.COM child_ud->usb_hs_hub_addr = parent_ud->usb_addr;
15919430SRaymond.Chen@Sun.COM child_ud->usb_hs_hub_port = port;
15929430SRaymond.Chen@Sun.COM bzero(&usb_dev_descr, sizeof (usb_dev_descr_t));
15939430SRaymond.Chen@Sun.COM
15949430SRaymond.Chen@Sun.COM /*
15959430SRaymond.Chen@Sun.COM * 255 for WUSB devices, refer to WUSB 1.0/4.8.1.
15969430SRaymond.Chen@Sun.COM * default ctrl pipe will ignore this value
15979430SRaymond.Chen@Sun.COM */
15989430SRaymond.Chen@Sun.COM usb_dev_descr.bMaxPacketSize0 = 255;
15999430SRaymond.Chen@Sun.COM bcopy(&usb_dev_descr, child_ud->usb_dev_descr,
16009430SRaymond.Chen@Sun.COM sizeof (usb_dev_descr_t));
16019430SRaymond.Chen@Sun.COM mutex_exit(&child_ud->usb_mutex);
16029430SRaymond.Chen@Sun.COM
16039430SRaymond.Chen@Sun.COM dev_info->wdev_ph = NULL;
16049430SRaymond.Chen@Sun.COM
16059430SRaymond.Chen@Sun.COM /*
16069430SRaymond.Chen@Sun.COM * set device info and encryption mode for the host so that
16079430SRaymond.Chen@Sun.COM * open child pipe can work later
16089430SRaymond.Chen@Sun.COM */
16099430SRaymond.Chen@Sun.COM rval = wusb_hc_set_device_info(hc_data, port);
16109430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
16119430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
16129430SRaymond.Chen@Sun.COM "wusb_hc_handle_port_connect: set device info for"
16139430SRaymond.Chen@Sun.COM " host failed, rval = %d", rval);
16149430SRaymond.Chen@Sun.COM
16159430SRaymond.Chen@Sun.COM goto error;
16169430SRaymond.Chen@Sun.COM }
16179430SRaymond.Chen@Sun.COM
16189430SRaymond.Chen@Sun.COM /* set the host to unsecure mode before authentication starts */
16199430SRaymond.Chen@Sun.COM rval = wusb_hc_set_encrypt(hc_data, port, WUSB_ENCRYP_TYPE_UNSECURE);
16209430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
16219430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
16229430SRaymond.Chen@Sun.COM "wusb_hc_handle_port_connect:set unsecure encryption"
16239430SRaymond.Chen@Sun.COM " for host failed, rval = %d", rval);
16249430SRaymond.Chen@Sun.COM
16259430SRaymond.Chen@Sun.COM goto error;
16269430SRaymond.Chen@Sun.COM }
16279430SRaymond.Chen@Sun.COM
16289430SRaymond.Chen@Sun.COM /*
16299430SRaymond.Chen@Sun.COM * Open the default pipe for the child device
16309430SRaymond.Chen@Sun.COM * the MaxPacketSize for the default ctrl pipe is
16319430SRaymond.Chen@Sun.COM * set in usba_init_pipe_handle().
16329430SRaymond.Chen@Sun.COM */
16339430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
16349430SRaymond.Chen@Sun.COM if ((rval = usb_pipe_open(child_dip, NULL, NULL,
16359430SRaymond.Chen@Sun.COM USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, &child_ph)) !=
16369430SRaymond.Chen@Sun.COM USB_SUCCESS) {
16379430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
16389430SRaymond.Chen@Sun.COM "wusb_hc_handle_port_connect:open default pipe failed (%d)",
16399430SRaymond.Chen@Sun.COM rval);
16409430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
16419430SRaymond.Chen@Sun.COM
16429430SRaymond.Chen@Sun.COM goto error;
16439430SRaymond.Chen@Sun.COM }
16449430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
16459430SRaymond.Chen@Sun.COM
16469430SRaymond.Chen@Sun.COM /* recording the default pipe */
16479430SRaymond.Chen@Sun.COM dev_info->wdev_ph = child_ph;
16489430SRaymond.Chen@Sun.COM
16499430SRaymond.Chen@Sun.COM /* verify the default child pipe works */
16509430SRaymond.Chen@Sun.COM if (wusb_get_dev_uwb_descr(hc_data, port) != USB_SUCCESS) {
16519430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
16529430SRaymond.Chen@Sun.COM "wusb_hc_handle_port_connect: failed to get"
16539430SRaymond.Chen@Sun.COM " device uwb descr");
16549430SRaymond.Chen@Sun.COM
16559430SRaymond.Chen@Sun.COM goto error;
16569430SRaymond.Chen@Sun.COM }
16579430SRaymond.Chen@Sun.COM
16589430SRaymond.Chen@Sun.COM /* remove connect acknowledge IE */
16599430SRaymond.Chen@Sun.COM wusb_hc_rm_ack(hc_data);
16609430SRaymond.Chen@Sun.COM ackie_removed = 1;
16619430SRaymond.Chen@Sun.COM
16629430SRaymond.Chen@Sun.COM /* do authentication */
16639430SRaymond.Chen@Sun.COM if (wusb_hc_auth_dev(hc_data, port, ph, ifc, secrt_data) !=
16649430SRaymond.Chen@Sun.COM USB_SUCCESS) {
16659430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
16669430SRaymond.Chen@Sun.COM "wusb_hc_handle_port_connect: "
16679430SRaymond.Chen@Sun.COM "device authentication fails");
16689430SRaymond.Chen@Sun.COM
16699430SRaymond.Chen@Sun.COM goto error;
16709430SRaymond.Chen@Sun.COM }
16719430SRaymond.Chen@Sun.COM
16729430SRaymond.Chen@Sun.COM /* online child */
16739430SRaymond.Chen@Sun.COM if (dev_info->wdev_state == WUSB_STATE_RECONNTING) {
16749430SRaymond.Chen@Sun.COM dev_info->wdev_state = WUSB_STATE_CONFIGURED;
16759430SRaymond.Chen@Sun.COM /* post reconnect event to child */
16769430SRaymond.Chen@Sun.COM wusb_hc_reconnect_dev(hc_data, port);
16779430SRaymond.Chen@Sun.COM } else {
16789430SRaymond.Chen@Sun.COM if (wusb_hc_create_child(hc_data, port) != USB_SUCCESS) {
16799430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
16809430SRaymond.Chen@Sun.COM "wusb_hc_handle_port_connect: create child fails");
16819430SRaymond.Chen@Sun.COM
16829430SRaymond.Chen@Sun.COM goto error;
16839430SRaymond.Chen@Sun.COM }
16849430SRaymond.Chen@Sun.COM dev_info->wdev_state = WUSB_STATE_CONFIGURED;
16859430SRaymond.Chen@Sun.COM }
16869430SRaymond.Chen@Sun.COM
16879430SRaymond.Chen@Sun.COM return (USB_SUCCESS);
16889430SRaymond.Chen@Sun.COM
16899430SRaymond.Chen@Sun.COM error:
16909430SRaymond.Chen@Sun.COM if (dev_info->wdev_ph != NULL) {
16919797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
16929797SRaymond.Chen@Sun.COM usb_pipe_close(child_dip, child_ph,
16939430SRaymond.Chen@Sun.COM USB_FLAGS_SLEEP | USBA_FLAGS_PRIVILEGED, NULL, NULL);
16949797SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
16959797SRaymond.Chen@Sun.COM
16969430SRaymond.Chen@Sun.COM dev_info->wdev_ph = NULL;
16979430SRaymond.Chen@Sun.COM }
16989430SRaymond.Chen@Sun.COM
16999430SRaymond.Chen@Sun.COM if (child_created) {
17009430SRaymond.Chen@Sun.COM
17019430SRaymond.Chen@Sun.COM rval = usba_destroy_child_devi(child_dip,
17029430SRaymond.Chen@Sun.COM NDI_DEVI_REMOVE);
17039430SRaymond.Chen@Sun.COM
17049430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
17059430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
17069430SRaymond.Chen@Sun.COM "wusb_hc_handle_port_connect: "
17079430SRaymond.Chen@Sun.COM "failure to remove child node");
17089430SRaymond.Chen@Sun.COM }
17099430SRaymond.Chen@Sun.COM
17109797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
17119430SRaymond.Chen@Sun.COM usba_free_usba_device(child_ud);
17129797SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
17139797SRaymond.Chen@Sun.COM
17149430SRaymond.Chen@Sun.COM hc_data->hc_children_dips[port] = NULL;
17159430SRaymond.Chen@Sun.COM hc_data->hc_usba_devices[port] = NULL;
17169430SRaymond.Chen@Sun.COM }
17179430SRaymond.Chen@Sun.COM
17189430SRaymond.Chen@Sun.COM if (ackie_removed == 0) {
17199430SRaymond.Chen@Sun.COM wusb_hc_rm_ack(hc_data);
17209430SRaymond.Chen@Sun.COM }
17219430SRaymond.Chen@Sun.COM
17229430SRaymond.Chen@Sun.COM return (USB_FAILURE);
17239430SRaymond.Chen@Sun.COM }
17249430SRaymond.Chen@Sun.COM
17259430SRaymond.Chen@Sun.COM /*
17269430SRaymond.Chen@Sun.COM * Handle device connect notification: assign port number, acknowledge
17279430SRaymond.Chen@Sun.COM * device connection, and online child
17289430SRaymond.Chen@Sun.COM * Refer to WUSB 1.0 4.13, 6.10, 7.1 for connection process handling
17299430SRaymond.Chen@Sun.COM * and device state diagram
17309430SRaymond.Chen@Sun.COM */
17319430SRaymond.Chen@Sun.COM void
wusb_hc_handle_dn_connect(wusb_hc_data_t * hc_data,usb_pipe_handle_t ph,uint8_t ifc,uint8_t * data,size_t len,wusb_secrt_data_t * secrt_data)17329430SRaymond.Chen@Sun.COM wusb_hc_handle_dn_connect(wusb_hc_data_t *hc_data, usb_pipe_handle_t ph,
17339430SRaymond.Chen@Sun.COM uint8_t ifc, uint8_t *data, size_t len,
17349430SRaymond.Chen@Sun.COM wusb_secrt_data_t *secrt_data)
17359430SRaymond.Chen@Sun.COM {
17369430SRaymond.Chen@Sun.COM wusb_dn_connect_t *dn_con;
17379430SRaymond.Chen@Sun.COM uint8_t addr;
17389430SRaymond.Chen@Sun.COM wusb_dev_info_t *dev_info = NULL;
17399430SRaymond.Chen@Sun.COM usb_port_t port = 0;
17409430SRaymond.Chen@Sun.COM uint_t new_alloc = 0;
17419430SRaymond.Chen@Sun.COM wusb_secrt_data_t *csecrt_data;
17429430SRaymond.Chen@Sun.COM
17439430SRaymond.Chen@Sun.COM if (len < WUSB_DN_CONN_PKT_LEN) {
17449430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
17459430SRaymond.Chen@Sun.COM "wusb_hc_handle_dn_connect: short pkt len %d", (int)len);
17469430SRaymond.Chen@Sun.COM
17479430SRaymond.Chen@Sun.COM return;
17489430SRaymond.Chen@Sun.COM }
17499430SRaymond.Chen@Sun.COM
17509430SRaymond.Chen@Sun.COM dn_con = (wusb_dn_connect_t *)data;
17519430SRaymond.Chen@Sun.COM ASSERT(dn_con->bType == WUSB_DN_CONNECT);
17529430SRaymond.Chen@Sun.COM addr = dn_con->bmConnAttributes[0];
17539430SRaymond.Chen@Sun.COM
17549430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
17559430SRaymond.Chen@Sun.COM
17569430SRaymond.Chen@Sun.COM /*
17579430SRaymond.Chen@Sun.COM * check if the device requesting to connect was ever connected
17589430SRaymond.Chen@Sun.COM * and decide connect request type
17599430SRaymond.Chen@Sun.COM */
17609430SRaymond.Chen@Sun.COM if (wusb_hc_is_dev_connected(hc_data, dn_con->CDID, &port) == 0) {
17619430SRaymond.Chen@Sun.COM /*
17629430SRaymond.Chen@Sun.COM * the device with the CDID was not connected.
17639430SRaymond.Chen@Sun.COM * It should be a connect or new connect request
17649430SRaymond.Chen@Sun.COM */
17659430SRaymond.Chen@Sun.COM if (addr) {
17669430SRaymond.Chen@Sun.COM /*
17679430SRaymond.Chen@Sun.COM * the device may have been disconnected by the host
17689430SRaymond.Chen@Sun.COM * the host expects to see a connect request instead
17699430SRaymond.Chen@Sun.COM * of a reconnect request. The reconnect request is
17709430SRaymond.Chen@Sun.COM * ignored.
17719430SRaymond.Chen@Sun.COM */
17729430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
17739430SRaymond.Chen@Sun.COM "wusb_hc_handle_dn_connect: device has "
17749430SRaymond.Chen@Sun.COM "disconnected, need to connect again");
17759430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
17769430SRaymond.Chen@Sun.COM
17779430SRaymond.Chen@Sun.COM return;
17789430SRaymond.Chen@Sun.COM }
17799430SRaymond.Chen@Sun.COM
17809430SRaymond.Chen@Sun.COM /* assign port number */
17819430SRaymond.Chen@Sun.COM port = wusb_hc_get_free_port(hc_data);
17829430SRaymond.Chen@Sun.COM if (port == 0) {
17839430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
17849430SRaymond.Chen@Sun.COM "wusb_hc_handle_dn_connect: cannot find "
17859430SRaymond.Chen@Sun.COM "a free port for the device connecting");
17869430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
17879430SRaymond.Chen@Sun.COM
17889430SRaymond.Chen@Sun.COM return;
17899430SRaymond.Chen@Sun.COM }
17909430SRaymond.Chen@Sun.COM
17919430SRaymond.Chen@Sun.COM /* initialize dev_info structure */
17929430SRaymond.Chen@Sun.COM dev_info = kmem_zalloc(sizeof (wusb_dev_info_t), KM_SLEEP);
17939430SRaymond.Chen@Sun.COM /* unconnected dev addr is 0xff, refer to WUSB 1.0/7.6.1 */
17949430SRaymond.Chen@Sun.COM dev_info->wdev_addr = 0xff;
17959430SRaymond.Chen@Sun.COM (void) memcpy(dev_info->wdev_cdid, dn_con->CDID, 16);
17969430SRaymond.Chen@Sun.COM dev_info->wdev_state = WUSB_STATE_CONNTING;
17979430SRaymond.Chen@Sun.COM hc_data->hc_dev_infos[port] = dev_info;
17989430SRaymond.Chen@Sun.COM new_alloc = 1;
17999430SRaymond.Chen@Sun.COM } else {
18009430SRaymond.Chen@Sun.COM /*
18019430SRaymond.Chen@Sun.COM * the device with the CDID was found connected.
18029430SRaymond.Chen@Sun.COM * It should be a reconnect or connect request.
18039430SRaymond.Chen@Sun.COM */
18049430SRaymond.Chen@Sun.COM dev_info = hc_data->hc_dev_infos[port];
18059430SRaymond.Chen@Sun.COM if ((addr != 0) && (addr == dev_info->wdev_addr)) {
18069430SRaymond.Chen@Sun.COM dev_info->wdev_state = WUSB_STATE_RECONNTING;
18079430SRaymond.Chen@Sun.COM } else if (addr == 0) {
18089430SRaymond.Chen@Sun.COM dev_info->wdev_state = WUSB_STATE_CONNTING;
18099430SRaymond.Chen@Sun.COM dev_info->wdev_addr = 0xff;
18109430SRaymond.Chen@Sun.COM } else {
18119430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
18129430SRaymond.Chen@Sun.COM "wusb_hc_handle_dn_connect: reconnecting, but "
18139430SRaymond.Chen@Sun.COM "device addr doesn't match");
18149430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
18159430SRaymond.Chen@Sun.COM
18169430SRaymond.Chen@Sun.COM return;
18179430SRaymond.Chen@Sun.COM }
18189430SRaymond.Chen@Sun.COM
18199430SRaymond.Chen@Sun.COM /*
18209430SRaymond.Chen@Sun.COM * post removal event to child device before
18219430SRaymond.Chen@Sun.COM * reconnecting it
18229430SRaymond.Chen@Sun.COM */
18239430SRaymond.Chen@Sun.COM wusb_hc_disconnect_dev(hc_data, port);
18249430SRaymond.Chen@Sun.COM }
18259430SRaymond.Chen@Sun.COM
18269430SRaymond.Chen@Sun.COM dev_info->wdev_beacon_attr = dn_con->bmConnAttributes[1] &
18279430SRaymond.Chen@Sun.COM WUSB_DN_CONN_BEACON_MASK;
18289430SRaymond.Chen@Sun.COM
18299430SRaymond.Chen@Sun.COM /* refer to WUSB 1.0/7.6.1/4.13 for how New Connection bit works */
18309430SRaymond.Chen@Sun.COM if (addr == 0) {
18319430SRaymond.Chen@Sun.COM dev_info->wdev_is_newconn = dn_con->bmConnAttributes[1] &
18329430SRaymond.Chen@Sun.COM WUSB_DN_CONN_NEW;
18339430SRaymond.Chen@Sun.COM } else {
18349430SRaymond.Chen@Sun.COM dev_info->wdev_is_newconn = 0;
18359430SRaymond.Chen@Sun.COM }
18369430SRaymond.Chen@Sun.COM
18379430SRaymond.Chen@Sun.COM /*
18389430SRaymond.Chen@Sun.COM * state=connting means new dev addr needs to be assigned
18399430SRaymond.Chen@Sun.COM * new_alloc=1 means newly allocated dev_info structure needs to
18409430SRaymond.Chen@Sun.COM * be freed later if the connection process fails
18419430SRaymond.Chen@Sun.COM * To simplify, the assigned address corresponds to the faked
18429430SRaymond.Chen@Sun.COM * port number.
18439430SRaymond.Chen@Sun.COM */
18449430SRaymond.Chen@Sun.COM if (dev_info->wdev_addr == 0xff) {
18459430SRaymond.Chen@Sun.COM dev_info->wdev_addr = port + 0x7f;
18469430SRaymond.Chen@Sun.COM }
18479430SRaymond.Chen@Sun.COM
18489430SRaymond.Chen@Sun.COM /*
18499430SRaymond.Chen@Sun.COM * Acknowledge dn connect notification.
18509430SRaymond.Chen@Sun.COM * The notif queue scheme will ensure only one ack_ie exists
18519430SRaymond.Chen@Sun.COM * at one time. Don't deal with multiple ack_ie elements now
18529430SRaymond.Chen@Sun.COM */
18539430SRaymond.Chen@Sun.COM if (wusb_hc_ack_conn(hc_data, port) != USB_SUCCESS) {
18549430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
18559430SRaymond.Chen@Sun.COM "wusb_hc_handle_dn_connect: acknowledge "
18569430SRaymond.Chen@Sun.COM "connection fails");
18579430SRaymond.Chen@Sun.COM
18589430SRaymond.Chen@Sun.COM if (new_alloc == 1) {
18599430SRaymond.Chen@Sun.COM kmem_free(dev_info, sizeof (wusb_dev_info_t));
18609430SRaymond.Chen@Sun.COM hc_data->hc_dev_infos[port] = NULL;
18619430SRaymond.Chen@Sun.COM } else {
18629430SRaymond.Chen@Sun.COM dev_info->wdev_state = WUSB_STATE_UNCONNTED;
18639430SRaymond.Chen@Sun.COM }
18649430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
18659430SRaymond.Chen@Sun.COM
18669430SRaymond.Chen@Sun.COM return;
18679430SRaymond.Chen@Sun.COM }
18689430SRaymond.Chen@Sun.COM
18699430SRaymond.Chen@Sun.COM /*
18709430SRaymond.Chen@Sun.COM * Handle device connection according to connect request type
18719430SRaymond.Chen@Sun.COM * Connect Acknowledge IE is removed inside the function
18729430SRaymond.Chen@Sun.COM */
18739430SRaymond.Chen@Sun.COM if (wusb_hc_handle_port_connect(hc_data, port, ph, ifc, secrt_data) !=
18749430SRaymond.Chen@Sun.COM USB_SUCCESS) {
18759430SRaymond.Chen@Sun.COM char *pathname = kmem_alloc(MAXPATHLEN, KM_NOSLEEP);
18769430SRaymond.Chen@Sun.COM
18779430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
18789430SRaymond.Chen@Sun.COM "wusb_hc_handle_dn_connect: connect port %d fails", port);
18799430SRaymond.Chen@Sun.COM
18809430SRaymond.Chen@Sun.COM if (new_alloc == 1) {
18819430SRaymond.Chen@Sun.COM if (dev_info->wdev_secrt_data.secrt_encry_descr) {
18829430SRaymond.Chen@Sun.COM csecrt_data = &dev_info->wdev_secrt_data;
18839430SRaymond.Chen@Sun.COM kmem_free(csecrt_data->secrt_encry_descr,
18849430SRaymond.Chen@Sun.COM sizeof (usb_encryption_descr_t) *
18859430SRaymond.Chen@Sun.COM csecrt_data->secrt_n_encry);
18869430SRaymond.Chen@Sun.COM }
18879430SRaymond.Chen@Sun.COM if (dev_info->wdev_uwb_descr) {
18889430SRaymond.Chen@Sun.COM kmem_free(dev_info->wdev_uwb_descr,
18899430SRaymond.Chen@Sun.COM sizeof (usb_uwb_cap_descr_t));
18909430SRaymond.Chen@Sun.COM }
18919430SRaymond.Chen@Sun.COM kmem_free(dev_info, sizeof (wusb_dev_info_t));
18929430SRaymond.Chen@Sun.COM hc_data->hc_dev_infos[port] = NULL;
18939430SRaymond.Chen@Sun.COM } else {
18949430SRaymond.Chen@Sun.COM dev_info->wdev_state = WUSB_STATE_UNCONNTED;
18959430SRaymond.Chen@Sun.COM }
18969430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
18979430SRaymond.Chen@Sun.COM
18989430SRaymond.Chen@Sun.COM if (pathname) {
18999430SRaymond.Chen@Sun.COM /* output error message to syslog */
19009430SRaymond.Chen@Sun.COM cmn_err(CE_WARN, "%s %s%d: Connecting device"
19019430SRaymond.Chen@Sun.COM " on WUSB port %d fails",
19029430SRaymond.Chen@Sun.COM ddi_pathname(hc_data->hc_dip, pathname),
19039430SRaymond.Chen@Sun.COM ddi_driver_name(hc_data->hc_dip),
19049430SRaymond.Chen@Sun.COM ddi_get_instance(hc_data->hc_dip),
19059430SRaymond.Chen@Sun.COM port);
19069430SRaymond.Chen@Sun.COM
19079430SRaymond.Chen@Sun.COM kmem_free(pathname, MAXPATHLEN);
19089430SRaymond.Chen@Sun.COM }
19099430SRaymond.Chen@Sun.COM
19109430SRaymond.Chen@Sun.COM return;
19119430SRaymond.Chen@Sun.COM }
19129430SRaymond.Chen@Sun.COM
19139430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
19149430SRaymond.Chen@Sun.COM }
19159430SRaymond.Chen@Sun.COM
19169430SRaymond.Chen@Sun.COM /* Handle device disconnect notification, refer to WUSB 1.0/7.6.2 */
19179430SRaymond.Chen@Sun.COM void
wusb_hc_handle_dn_disconnect(wusb_hc_data_t * hc_data,uint8_t addr,uint8_t * data,size_t len)19189430SRaymond.Chen@Sun.COM wusb_hc_handle_dn_disconnect(wusb_hc_data_t *hc_data, uint8_t addr,
19199430SRaymond.Chen@Sun.COM uint8_t *data, size_t len)
19209430SRaymond.Chen@Sun.COM {
19219430SRaymond.Chen@Sun.COM wusb_dn_disconnect_t *dn_discon;
19229430SRaymond.Chen@Sun.COM usb_port_t port;
19239430SRaymond.Chen@Sun.COM
19249430SRaymond.Chen@Sun.COM if (len < WUSB_DN_DISCONN_PKT_LEN) {
19259430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
19269430SRaymond.Chen@Sun.COM "wusb_hc_handle_dn_disconnect: short pkt len %d",
19279430SRaymond.Chen@Sun.COM (int)len);
19289430SRaymond.Chen@Sun.COM
19299430SRaymond.Chen@Sun.COM return;
19309430SRaymond.Chen@Sun.COM }
19319430SRaymond.Chen@Sun.COM
19329430SRaymond.Chen@Sun.COM dn_discon = (wusb_dn_disconnect_t *)data;
19339430SRaymond.Chen@Sun.COM ASSERT(dn_discon->bType == WUSB_DN_DISCONNECT);
19349430SRaymond.Chen@Sun.COM
19359430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
19369430SRaymond.Chen@Sun.COM
19379430SRaymond.Chen@Sun.COM /* send WDEV_DISCONNECT_IE to acknowledge the notification */
19389430SRaymond.Chen@Sun.COM if (wusb_hc_ack_disconn(hc_data, addr) != USB_SUCCESS) {
19399430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
19409430SRaymond.Chen@Sun.COM "wusb_hc_handle_dn_disconnect: send disconnect ie fails");
19419430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
19429430SRaymond.Chen@Sun.COM
19439430SRaymond.Chen@Sun.COM return;
19449430SRaymond.Chen@Sun.COM }
19459430SRaymond.Chen@Sun.COM
19469430SRaymond.Chen@Sun.COM /* offline the device requesting disconnection */
19479430SRaymond.Chen@Sun.COM if (wusb_hc_is_addr_valid(hc_data, addr, &port)) {
19489430SRaymond.Chen@Sun.COM (void) wusb_hc_destroy_child(hc_data, port);
19499430SRaymond.Chen@Sun.COM } else {
19509430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
19519430SRaymond.Chen@Sun.COM "wusb_hc_handle_dn_disconnect: device with addr "
19529430SRaymond.Chen@Sun.COM "0x%x not found", addr);
19539430SRaymond.Chen@Sun.COM }
19549430SRaymond.Chen@Sun.COM
19559430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
19569430SRaymond.Chen@Sun.COM }
19579430SRaymond.Chen@Sun.COM
19589430SRaymond.Chen@Sun.COM /* post disconnect event to the device driver */
19599430SRaymond.Chen@Sun.COM void
wusb_hc_disconnect_dev(wusb_hc_data_t * hc_data,usb_port_t port)19609430SRaymond.Chen@Sun.COM wusb_hc_disconnect_dev(wusb_hc_data_t *hc_data, usb_port_t port)
19619430SRaymond.Chen@Sun.COM {
19629430SRaymond.Chen@Sun.COM dev_info_t *dip = hc_data->hc_dip;
19639430SRaymond.Chen@Sun.COM
19649430SRaymond.Chen@Sun.COM ASSERT(dip != NULL);
19659430SRaymond.Chen@Sun.COM
19669430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
19679430SRaymond.Chen@Sun.COM
19689430SRaymond.Chen@Sun.COM hc_data->disconnect_dev(dip, port);
19699430SRaymond.Chen@Sun.COM
19709430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
19719430SRaymond.Chen@Sun.COM }
19729430SRaymond.Chen@Sun.COM
19739430SRaymond.Chen@Sun.COM /* post reconnect event to the device driver */
19749430SRaymond.Chen@Sun.COM void
wusb_hc_reconnect_dev(wusb_hc_data_t * hc_data,usb_port_t port)19759430SRaymond.Chen@Sun.COM wusb_hc_reconnect_dev(wusb_hc_data_t *hc_data, usb_port_t port)
19769430SRaymond.Chen@Sun.COM {
19779430SRaymond.Chen@Sun.COM dev_info_t *dip = hc_data->hc_dip;
19789430SRaymond.Chen@Sun.COM
19799430SRaymond.Chen@Sun.COM ASSERT(dip != NULL);
19809430SRaymond.Chen@Sun.COM
19819430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
19829430SRaymond.Chen@Sun.COM
19839430SRaymond.Chen@Sun.COM hc_data->reconnect_dev(dip, port);
19849430SRaymond.Chen@Sun.COM
19859430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
19869430SRaymond.Chen@Sun.COM }
19879430SRaymond.Chen@Sun.COM
19889430SRaymond.Chen@Sun.COM /* configure child device and online it */
19899430SRaymond.Chen@Sun.COM int
wusb_hc_create_child(wusb_hc_data_t * hc_data,usb_port_t port)19909430SRaymond.Chen@Sun.COM wusb_hc_create_child(wusb_hc_data_t *hc_data, usb_port_t port)
19919430SRaymond.Chen@Sun.COM {
19929430SRaymond.Chen@Sun.COM dev_info_t *dip = hc_data->hc_dip;
19939430SRaymond.Chen@Sun.COM int rval;
19949430SRaymond.Chen@Sun.COM
19959430SRaymond.Chen@Sun.COM ASSERT(dip != NULL);
19969430SRaymond.Chen@Sun.COM
19979430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
19989430SRaymond.Chen@Sun.COM
19999430SRaymond.Chen@Sun.COM rval = hc_data->create_child(dip, port);
20009430SRaymond.Chen@Sun.COM
20019430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
20029430SRaymond.Chen@Sun.COM
20039430SRaymond.Chen@Sun.COM return (rval);
20049430SRaymond.Chen@Sun.COM }
20059430SRaymond.Chen@Sun.COM
20069430SRaymond.Chen@Sun.COM /* offline child device */
20079430SRaymond.Chen@Sun.COM int
wusb_hc_destroy_child(wusb_hc_data_t * hc_data,usb_port_t port)20089430SRaymond.Chen@Sun.COM wusb_hc_destroy_child(wusb_hc_data_t *hc_data, usb_port_t port)
20099430SRaymond.Chen@Sun.COM {
20109430SRaymond.Chen@Sun.COM dev_info_t *dip = hc_data->hc_dip;
20119430SRaymond.Chen@Sun.COM int rval;
20129430SRaymond.Chen@Sun.COM
20139430SRaymond.Chen@Sun.COM ASSERT(dip != NULL);
20149430SRaymond.Chen@Sun.COM
20159430SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
20169430SRaymond.Chen@Sun.COM
20179430SRaymond.Chen@Sun.COM rval = hc_data->destroy_child(dip, port);
20189430SRaymond.Chen@Sun.COM
20199430SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
20209430SRaymond.Chen@Sun.COM
20219430SRaymond.Chen@Sun.COM return (rval);
20229430SRaymond.Chen@Sun.COM }
20239430SRaymond.Chen@Sun.COM
20249430SRaymond.Chen@Sun.COM
20259430SRaymond.Chen@Sun.COM /*
20269430SRaymond.Chen@Sun.COM * ***********************
20279430SRaymond.Chen@Sun.COM * CC management functions
20289430SRaymond.Chen@Sun.COM * ***********************
20299430SRaymond.Chen@Sun.COM */
20309430SRaymond.Chen@Sun.COM
20319430SRaymond.Chen@Sun.COM /* add a CC to the CC list */
20329430SRaymond.Chen@Sun.COM void
wusb_hc_add_cc(wusb_hc_cc_list_t ** cc_list,wusb_hc_cc_list_t * new_cc)20339430SRaymond.Chen@Sun.COM wusb_hc_add_cc(wusb_hc_cc_list_t **cc_list, wusb_hc_cc_list_t *new_cc)
20349430SRaymond.Chen@Sun.COM {
20359430SRaymond.Chen@Sun.COM wusb_hc_cc_list_t *head;
20369430SRaymond.Chen@Sun.COM
20379430SRaymond.Chen@Sun.COM USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
20389430SRaymond.Chen@Sun.COM "wusb_hc_add_cc: cc_list = 0x%p, new_cc = 0x%p",
20399430SRaymond.Chen@Sun.COM (void *)cc_list, (void *)new_cc);
20409430SRaymond.Chen@Sun.COM
20419430SRaymond.Chen@Sun.COM if (new_cc == NULL) {
20429430SRaymond.Chen@Sun.COM
20439430SRaymond.Chen@Sun.COM return;
20449430SRaymond.Chen@Sun.COM }
20459430SRaymond.Chen@Sun.COM
20469430SRaymond.Chen@Sun.COM if (*cc_list == NULL) {
20479430SRaymond.Chen@Sun.COM *cc_list = new_cc;
20489430SRaymond.Chen@Sun.COM
20499430SRaymond.Chen@Sun.COM return;
20509430SRaymond.Chen@Sun.COM }
20519430SRaymond.Chen@Sun.COM
20529430SRaymond.Chen@Sun.COM head = *cc_list;
20539430SRaymond.Chen@Sun.COM while (head != NULL) {
20549430SRaymond.Chen@Sun.COM /* update an existing CC */
20559430SRaymond.Chen@Sun.COM if (memcmp(head->cc.CDID, new_cc->cc.CDID, 16) == 0) {
20569430SRaymond.Chen@Sun.COM (void) memcpy(head->cc.CK, new_cc->cc.CK, 16);
20579430SRaymond.Chen@Sun.COM kmem_free(new_cc, sizeof (wusb_hc_cc_list_t));
20589430SRaymond.Chen@Sun.COM
20599430SRaymond.Chen@Sun.COM return;
20609430SRaymond.Chen@Sun.COM }
20619430SRaymond.Chen@Sun.COM
20629430SRaymond.Chen@Sun.COM /* add a new CC */
20639430SRaymond.Chen@Sun.COM if (head->next == NULL) {
20649430SRaymond.Chen@Sun.COM head->next = new_cc;
20659430SRaymond.Chen@Sun.COM
20669430SRaymond.Chen@Sun.COM return;
20679430SRaymond.Chen@Sun.COM }
20689430SRaymond.Chen@Sun.COM
20699430SRaymond.Chen@Sun.COM head = head->next;
20709430SRaymond.Chen@Sun.COM }
20719430SRaymond.Chen@Sun.COM }
20729430SRaymond.Chen@Sun.COM
20739430SRaymond.Chen@Sun.COM /* remove a CC from the CC list */
20749430SRaymond.Chen@Sun.COM void
wusb_hc_rem_cc(wusb_hc_cc_list_t ** cc_list,wusb_cc_t * old_cc)20759430SRaymond.Chen@Sun.COM wusb_hc_rem_cc(wusb_hc_cc_list_t **cc_list, wusb_cc_t *old_cc)
20769430SRaymond.Chen@Sun.COM {
20779430SRaymond.Chen@Sun.COM wusb_cc_t *cc;
20789430SRaymond.Chen@Sun.COM wusb_hc_cc_list_t *prev, *next;
20799430SRaymond.Chen@Sun.COM
20809430SRaymond.Chen@Sun.COM if (*cc_list == NULL || old_cc == NULL) {
20819430SRaymond.Chen@Sun.COM
20829430SRaymond.Chen@Sun.COM return;
20839430SRaymond.Chen@Sun.COM }
20849430SRaymond.Chen@Sun.COM
20859430SRaymond.Chen@Sun.COM prev = *cc_list;
20869430SRaymond.Chen@Sun.COM cc = &prev->cc;
20879430SRaymond.Chen@Sun.COM if (memcmp(cc, old_cc, sizeof (wusb_cc_t)) == 0) {
20889430SRaymond.Chen@Sun.COM *cc_list = prev->next;
20899430SRaymond.Chen@Sun.COM kmem_free(prev, sizeof (wusb_hc_cc_list_t));
20909430SRaymond.Chen@Sun.COM
20919430SRaymond.Chen@Sun.COM return;
20929430SRaymond.Chen@Sun.COM }
20939430SRaymond.Chen@Sun.COM next = prev->next;
20949430SRaymond.Chen@Sun.COM while (next != NULL) {
20959430SRaymond.Chen@Sun.COM cc = &next->cc;
20969430SRaymond.Chen@Sun.COM if (memcmp(cc, old_cc, sizeof (wusb_cc_t)) == 0) {
20979430SRaymond.Chen@Sun.COM prev->next = next->next;
20989430SRaymond.Chen@Sun.COM kmem_free(next, sizeof (wusb_hc_cc_list_t));
20999430SRaymond.Chen@Sun.COM
21009430SRaymond.Chen@Sun.COM return;
21019430SRaymond.Chen@Sun.COM }
21029430SRaymond.Chen@Sun.COM prev = next;
21039430SRaymond.Chen@Sun.COM next = prev->next;
21049430SRaymond.Chen@Sun.COM }
21059430SRaymond.Chen@Sun.COM }
21069430SRaymond.Chen@Sun.COM
21079430SRaymond.Chen@Sun.COM /* remove all CCs from the list */
21089430SRaymond.Chen@Sun.COM void
wusb_hc_free_cc_list(wusb_hc_cc_list_t * cc_list)21099430SRaymond.Chen@Sun.COM wusb_hc_free_cc_list(wusb_hc_cc_list_t *cc_list)
21109430SRaymond.Chen@Sun.COM {
21119430SRaymond.Chen@Sun.COM wusb_hc_cc_list_t *list, *next;
21129430SRaymond.Chen@Sun.COM
21139430SRaymond.Chen@Sun.COM list = cc_list;
21149430SRaymond.Chen@Sun.COM while (list != NULL) {
21159430SRaymond.Chen@Sun.COM next = list->next;
21169430SRaymond.Chen@Sun.COM kmem_free(list, sizeof (wusb_hc_cc_list_t));
21179430SRaymond.Chen@Sun.COM list = next;
21189430SRaymond.Chen@Sun.COM }
21199430SRaymond.Chen@Sun.COM }
21209430SRaymond.Chen@Sun.COM
21219430SRaymond.Chen@Sun.COM /* Send Host Disconnect notification */
21229430SRaymond.Chen@Sun.COM int
wusb_hc_send_host_disconnect(wusb_hc_data_t * hc_data)21239430SRaymond.Chen@Sun.COM wusb_hc_send_host_disconnect(wusb_hc_data_t *hc_data)
21249430SRaymond.Chen@Sun.COM {
21259430SRaymond.Chen@Sun.COM wusb_ie_host_disconnect_t *disconn_ie;
21269430SRaymond.Chen@Sun.COM uint8_t iehdl;
21279430SRaymond.Chen@Sun.COM int rval;
21289430SRaymond.Chen@Sun.COM
21299430SRaymond.Chen@Sun.COM disconn_ie = kmem_zalloc(sizeof (wusb_ie_host_disconnect_t), KM_SLEEP);
21309430SRaymond.Chen@Sun.COM disconn_ie->bIEIdentifier = WUSB_IE_HOST_DISCONNECT;
21319430SRaymond.Chen@Sun.COM disconn_ie->bLength = sizeof (wusb_ie_host_disconnect_t);
21329430SRaymond.Chen@Sun.COM
21339797SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
21349430SRaymond.Chen@Sun.COM rval = wusb_hc_get_iehdl(hc_data, (wusb_ie_header_t *)disconn_ie,
21359430SRaymond.Chen@Sun.COM &iehdl);
21369797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
21379430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
21389430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
21399430SRaymond.Chen@Sun.COM "wusb_hc_send_host_disconnect: get ie handle fails");
21409430SRaymond.Chen@Sun.COM kmem_free(disconn_ie, sizeof (wusb_ie_host_disconnect_t));
21419430SRaymond.Chen@Sun.COM
21429430SRaymond.Chen@Sun.COM return (rval);
21439430SRaymond.Chen@Sun.COM }
21449430SRaymond.Chen@Sun.COM
21459430SRaymond.Chen@Sun.COM rval = wusb_hc_add_mmc_ie(hc_data, 0, 0, iehdl,
21469430SRaymond.Chen@Sun.COM disconn_ie->bLength, (uint8_t *)disconn_ie);
21479430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
21489430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
21499430SRaymond.Chen@Sun.COM "wusb_hc_send_host_disconnect: add host "
21509430SRaymond.Chen@Sun.COM "disconnect ie fails");
21519797SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
21529430SRaymond.Chen@Sun.COM wusb_hc_free_iehdl(hc_data, iehdl);
21539797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
21549430SRaymond.Chen@Sun.COM kmem_free(disconn_ie, sizeof (wusb_ie_host_disconnect_t));
21559430SRaymond.Chen@Sun.COM
21569430SRaymond.Chen@Sun.COM return (rval);
21579430SRaymond.Chen@Sun.COM }
21589430SRaymond.Chen@Sun.COM
21599430SRaymond.Chen@Sun.COM delay(drv_usectohz(100000)); /* WUSB 1.0/7.5.5 */
21609797SRaymond.Chen@Sun.COM
21619797SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
21629430SRaymond.Chen@Sun.COM (void) wusb_hc_remove_mmc_ie(hc_data, iehdl);
21639430SRaymond.Chen@Sun.COM wusb_hc_free_iehdl(hc_data, iehdl);
21649797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
21659797SRaymond.Chen@Sun.COM
21669430SRaymond.Chen@Sun.COM kmem_free(disconn_ie, sizeof (wusb_ie_host_disconnect_t));
21679430SRaymond.Chen@Sun.COM
21689430SRaymond.Chen@Sun.COM return (USB_SUCCESS);
21699430SRaymond.Chen@Sun.COM }
21709430SRaymond.Chen@Sun.COM
21719430SRaymond.Chen@Sun.COM /* Get RC dev_t by HC dip */
21729430SRaymond.Chen@Sun.COM int
wusb_get_rc_dev_by_hc(dev_info_t * dip,dev_t * dev)21739430SRaymond.Chen@Sun.COM wusb_get_rc_dev_by_hc(dev_info_t *dip, dev_t *dev)
21749430SRaymond.Chen@Sun.COM {
21759430SRaymond.Chen@Sun.COM dev_info_t *pdip = ddi_get_parent(dip);
21769430SRaymond.Chen@Sun.COM dev_info_t *rcdip;
21779430SRaymond.Chen@Sun.COM int found = 0;
21789430SRaymond.Chen@Sun.COM major_t major;
21799430SRaymond.Chen@Sun.COM minor_t minor;
21809430SRaymond.Chen@Sun.COM int inst;
21819430SRaymond.Chen@Sun.COM
21829430SRaymond.Chen@Sun.COM if (strcmp(ddi_driver_name(dip), "whci") == 0) {
21839430SRaymond.Chen@Sun.COM /* For WHCI, RC and HC share the same dip */
21849430SRaymond.Chen@Sun.COM rcdip = dip;
21859430SRaymond.Chen@Sun.COM inst = ddi_get_instance(rcdip);
21869430SRaymond.Chen@Sun.COM /* need to change when whci driver is ready */
21879430SRaymond.Chen@Sun.COM minor = inst;
21889430SRaymond.Chen@Sun.COM found = 1;
21899430SRaymond.Chen@Sun.COM } else {
21909430SRaymond.Chen@Sun.COM /* For HWA, RC and HC share the same parent dip */
21919430SRaymond.Chen@Sun.COM rcdip = ddi_get_child(pdip);
21929430SRaymond.Chen@Sun.COM while (rcdip != NULL) {
21939430SRaymond.Chen@Sun.COM if (strcmp(ddi_driver_name(rcdip), "hwarc") == 0) {
21949430SRaymond.Chen@Sun.COM found = 1;
21959430SRaymond.Chen@Sun.COM inst = ddi_get_instance(rcdip);
21969430SRaymond.Chen@Sun.COM // minor = HWAHC_CONSTRUCT_MINOR(inst);
21979430SRaymond.Chen@Sun.COM /*
21989430SRaymond.Chen@Sun.COM * now hwarc driver uses inst# as minor#.
21999430SRaymond.Chen@Sun.COM * this may change
22009430SRaymond.Chen@Sun.COM */
22019430SRaymond.Chen@Sun.COM minor = inst;
22029430SRaymond.Chen@Sun.COM
22039430SRaymond.Chen@Sun.COM break;
22049430SRaymond.Chen@Sun.COM }
22059430SRaymond.Chen@Sun.COM rcdip = ddi_get_next_sibling(rcdip);
22069430SRaymond.Chen@Sun.COM }
22079430SRaymond.Chen@Sun.COM }
22089430SRaymond.Chen@Sun.COM
22099430SRaymond.Chen@Sun.COM if (found == 0) {
22109430SRaymond.Chen@Sun.COM *dev = 0;
22119430SRaymond.Chen@Sun.COM
22129430SRaymond.Chen@Sun.COM return (USB_FAILURE);
22139430SRaymond.Chen@Sun.COM }
22149430SRaymond.Chen@Sun.COM
22159430SRaymond.Chen@Sun.COM major = ddi_driver_major(rcdip);
22169430SRaymond.Chen@Sun.COM *dev = makedevice(major, minor);
22179430SRaymond.Chen@Sun.COM
22189430SRaymond.Chen@Sun.COM USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
22199430SRaymond.Chen@Sun.COM "wusb_get_rc_dev_by_hc: rc device(%s%d) major = %d, minor = %d",
22209430SRaymond.Chen@Sun.COM ddi_driver_name(rcdip), inst, major, minor);
22219430SRaymond.Chen@Sun.COM
22229430SRaymond.Chen@Sun.COM return (USB_SUCCESS);
22239430SRaymond.Chen@Sun.COM }
22249430SRaymond.Chen@Sun.COM
22259430SRaymond.Chen@Sun.COM /* format nonce to a buffer according to WUSB Table 6-3 */
22269430SRaymond.Chen@Sun.COM static void
nonce_to_buf(wusb_ccm_nonce_t * nonce,uchar_t * nbuf,int sfn_only)22279430SRaymond.Chen@Sun.COM nonce_to_buf(wusb_ccm_nonce_t *nonce, uchar_t *nbuf, int sfn_only)
22289430SRaymond.Chen@Sun.COM {
22299430SRaymond.Chen@Sun.COM int i, offset;
22309430SRaymond.Chen@Sun.COM uchar_t *p = nbuf;
22319430SRaymond.Chen@Sun.COM
22329430SRaymond.Chen@Sun.COM for (i = 0, offset = 0; i < 6; i++, offset += 8) {
22339430SRaymond.Chen@Sun.COM *p++ = (nonce->sfn >> offset) & 0xff;
22349430SRaymond.Chen@Sun.COM }
22359430SRaymond.Chen@Sun.COM
22369430SRaymond.Chen@Sun.COM if (sfn_only) {
22379430SRaymond.Chen@Sun.COM
22389430SRaymond.Chen@Sun.COM return;
22399430SRaymond.Chen@Sun.COM }
22409430SRaymond.Chen@Sun.COM
22419430SRaymond.Chen@Sun.COM *p++ = (nonce->tkid) & 0xff;
22429430SRaymond.Chen@Sun.COM *p++ = (nonce->tkid >> 8) & 0xff;
22439430SRaymond.Chen@Sun.COM *p++ = (nonce->tkid >> 16) & 0xff;
22449430SRaymond.Chen@Sun.COM
22459430SRaymond.Chen@Sun.COM *p++ = (nonce->daddr) & 0xff;
22469430SRaymond.Chen@Sun.COM *p++ = (nonce->daddr >> 8) & 0xff;
22479430SRaymond.Chen@Sun.COM
22489430SRaymond.Chen@Sun.COM *p++ = (nonce->saddr) & 0xff;
22499430SRaymond.Chen@Sun.COM *p++ = (nonce->saddr >> 8) & 0xff;
22509430SRaymond.Chen@Sun.COM }
22519430SRaymond.Chen@Sun.COM
22529430SRaymond.Chen@Sun.COM /* Call the crypto framework to compute CCM MAC data */
22539430SRaymond.Chen@Sun.COM static int
wusb_ccm_mac(CK_AES_CCM_PARAMS * ccm_params,const uchar_t * key,size_t klen,uchar_t * out,int olen)22549430SRaymond.Chen@Sun.COM wusb_ccm_mac(
22559430SRaymond.Chen@Sun.COM CK_AES_CCM_PARAMS *ccm_params,
22569430SRaymond.Chen@Sun.COM const uchar_t *key, size_t klen,
22579430SRaymond.Chen@Sun.COM uchar_t *out, int olen)
22589430SRaymond.Chen@Sun.COM {
22599430SRaymond.Chen@Sun.COM crypto_mechanism_t mech;
22609430SRaymond.Chen@Sun.COM crypto_key_t crkey;
22619430SRaymond.Chen@Sun.COM crypto_context_t ctx;
22629430SRaymond.Chen@Sun.COM crypto_data_t dmac;
22639430SRaymond.Chen@Sun.COM int ret;
22649430SRaymond.Chen@Sun.COM
22659430SRaymond.Chen@Sun.COM bzero(&crkey, sizeof (crkey));
22669430SRaymond.Chen@Sun.COM crkey.ck_format = CRYPTO_KEY_RAW;
22679430SRaymond.Chen@Sun.COM crkey.ck_data = (char *)key;
22689430SRaymond.Chen@Sun.COM crkey.ck_length = klen * 8;
22699430SRaymond.Chen@Sun.COM
22709430SRaymond.Chen@Sun.COM mech.cm_type = crypto_mech2id(SUN_CKM_AES_CCM);
22719430SRaymond.Chen@Sun.COM mech.cm_param = (caddr_t)ccm_params;
22729430SRaymond.Chen@Sun.COM mech.cm_param_len = sizeof (CK_AES_CCM_PARAMS);
22739430SRaymond.Chen@Sun.COM
22749430SRaymond.Chen@Sun.COM if ((ret = crypto_encrypt_init(&mech, &crkey, NULL, &ctx, NULL)) !=
22759430SRaymond.Chen@Sun.COM CRYPTO_SUCCESS) {
22769430SRaymond.Chen@Sun.COM
22779430SRaymond.Chen@Sun.COM return (ret);
22789430SRaymond.Chen@Sun.COM }
22799430SRaymond.Chen@Sun.COM
22809430SRaymond.Chen@Sun.COM /*
22819430SRaymond.Chen@Sun.COM * Since we've known the encrypted data is none (l(m) = 0),
22829430SRaymond.Chen@Sun.COM * the middle procedure crypto_encrypt_update() is ignored.
22839430SRaymond.Chen@Sun.COM * The last 8-byte MAC is calculated directly.
22849430SRaymond.Chen@Sun.COM */
22859430SRaymond.Chen@Sun.COM
22869430SRaymond.Chen@Sun.COM bzero(&dmac, sizeof (dmac));
22879430SRaymond.Chen@Sun.COM dmac.cd_format = CRYPTO_DATA_RAW;
22889430SRaymond.Chen@Sun.COM dmac.cd_offset = 0;
22899430SRaymond.Chen@Sun.COM dmac.cd_length = olen;
22909430SRaymond.Chen@Sun.COM dmac.cd_raw.iov_base = (char *)out;
22919430SRaymond.Chen@Sun.COM dmac.cd_raw.iov_len = olen;
22929430SRaymond.Chen@Sun.COM
22939430SRaymond.Chen@Sun.COM if ((ret = crypto_encrypt_final(ctx, &dmac, NULL)) != CRYPTO_SUCCESS) {
22949430SRaymond.Chen@Sun.COM
22959430SRaymond.Chen@Sun.COM return (ret);
22969430SRaymond.Chen@Sun.COM }
22979430SRaymond.Chen@Sun.COM
22989430SRaymond.Chen@Sun.COM return (CRYPTO_SUCCESS);
22999430SRaymond.Chen@Sun.COM }
23009430SRaymond.Chen@Sun.COM
23019430SRaymond.Chen@Sun.COM /* Pseudo-Random Function according to WUSB 1.0/6.5 */
23029430SRaymond.Chen@Sun.COM int
PRF(const uchar_t * key,size_t klen,wusb_ccm_nonce_t * nonce,const uchar_t * adata,size_t alen,const uchar_t * bdata,size_t blen,uchar_t * out,size_t bitlen)23039430SRaymond.Chen@Sun.COM PRF(const uchar_t *key, size_t klen,
23049430SRaymond.Chen@Sun.COM wusb_ccm_nonce_t *nonce,
23059430SRaymond.Chen@Sun.COM const uchar_t *adata, size_t alen,
23069430SRaymond.Chen@Sun.COM const uchar_t *bdata, size_t blen,
23079430SRaymond.Chen@Sun.COM uchar_t *out,
23089430SRaymond.Chen@Sun.COM size_t bitlen)
23099430SRaymond.Chen@Sun.COM {
23109430SRaymond.Chen@Sun.COM CK_AES_CCM_PARAMS ccm_params;
23119430SRaymond.Chen@Sun.COM uchar_t *ab;
23129430SRaymond.Chen@Sun.COM uchar_t nbuf[CCM_NONCE_LEN];
23139430SRaymond.Chen@Sun.COM size_t lm, la;
23149430SRaymond.Chen@Sun.COM int i, offset, ret;
23159430SRaymond.Chen@Sun.COM
23169430SRaymond.Chen@Sun.COM /* from WUSB 6.4 */
23179430SRaymond.Chen@Sun.COM lm = 0;
23189430SRaymond.Chen@Sun.COM la = alen + blen;
23199430SRaymond.Chen@Sun.COM ab = (uchar_t *)kmem_alloc(la, KM_SLEEP);
23209430SRaymond.Chen@Sun.COM bcopy(adata, ab, alen);
23219430SRaymond.Chen@Sun.COM bcopy(bdata, ab + alen, blen);
23229430SRaymond.Chen@Sun.COM
23239430SRaymond.Chen@Sun.COM nonce_to_buf(nonce, nbuf, 0);
23249430SRaymond.Chen@Sun.COM
23259430SRaymond.Chen@Sun.COM ccm_params.ulMACSize = CCM_MAC_LEN;
23269430SRaymond.Chen@Sun.COM ccm_params.ulNonceSize = CCM_NONCE_LEN;
23279430SRaymond.Chen@Sun.COM ccm_params.nonce = nbuf;
23289430SRaymond.Chen@Sun.COM ccm_params.ulAuthDataSize = la; /* l(a) */
23299430SRaymond.Chen@Sun.COM ccm_params.authData = ab;
23309430SRaymond.Chen@Sun.COM ccm_params.ulDataSize = lm; /* l(m) */
23319430SRaymond.Chen@Sun.COM
23329430SRaymond.Chen@Sun.COM offset = 0;
23339430SRaymond.Chen@Sun.COM for (i = 0; i < (bitlen + 63)/64; i++) {
23349430SRaymond.Chen@Sun.COM ret = wusb_ccm_mac(&ccm_params, key, klen,
23359430SRaymond.Chen@Sun.COM out + offset, CCM_MAC_LEN);
23369430SRaymond.Chen@Sun.COM
23379430SRaymond.Chen@Sun.COM if (ret != CRYPTO_SUCCESS) {
23389430SRaymond.Chen@Sun.COM kmem_free(ab, la);
23399430SRaymond.Chen@Sun.COM
23409430SRaymond.Chen@Sun.COM return (ret);
23419430SRaymond.Chen@Sun.COM };
23429430SRaymond.Chen@Sun.COM
23439430SRaymond.Chen@Sun.COM offset += CCM_MAC_LEN;
23449430SRaymond.Chen@Sun.COM nonce->sfn++;
23459430SRaymond.Chen@Sun.COM nonce_to_buf(nonce, nbuf, 1);
23469430SRaymond.Chen@Sun.COM }
23479430SRaymond.Chen@Sun.COM
23489430SRaymond.Chen@Sun.COM kmem_free(ab, la);
23499430SRaymond.Chen@Sun.COM
23509430SRaymond.Chen@Sun.COM return (CRYPTO_SUCCESS);
23519430SRaymond.Chen@Sun.COM }
23529430SRaymond.Chen@Sun.COM
23539430SRaymond.Chen@Sun.COM /* rbuf is a 16-byte buffer to store the random nonce */
23549430SRaymond.Chen@Sun.COM int
wusb_gen_random_nonce(wusb_hc_data_t * hc_data,wusb_dev_info_t * dev_info,uchar_t * rbuf)23559430SRaymond.Chen@Sun.COM wusb_gen_random_nonce(wusb_hc_data_t *hc_data,
23569430SRaymond.Chen@Sun.COM wusb_dev_info_t *dev_info, uchar_t *rbuf)
23579430SRaymond.Chen@Sun.COM {
23589430SRaymond.Chen@Sun.COM usba_device_t *udev = usba_get_usba_device(hc_data->hc_dip);
23599430SRaymond.Chen@Sun.COM wusb_ccm_nonce_t n;
23609430SRaymond.Chen@Sun.COM uint16_t vid, pid;
23619430SRaymond.Chen@Sun.COM uint64_t ht;
23629430SRaymond.Chen@Sun.COM uint8_t kbuf[16], *p;
23639430SRaymond.Chen@Sun.COM uchar_t a[] = "Random Numbers";
23649430SRaymond.Chen@Sun.COM
23659430SRaymond.Chen@Sun.COM n.sfn = 0;
23669430SRaymond.Chen@Sun.COM n.tkid = dev_info->wdev_tkid[0] | (dev_info->wdev_tkid[1] << 8) |
23679430SRaymond.Chen@Sun.COM (dev_info->wdev_tkid[2] << 16);
23689430SRaymond.Chen@Sun.COM n.daddr = hc_data->hc_addr;
23699430SRaymond.Chen@Sun.COM n.saddr = dev_info->wdev_addr;
23709430SRaymond.Chen@Sun.COM
23719430SRaymond.Chen@Sun.COM vid = udev->usb_dev_descr->idVendor;
23729430SRaymond.Chen@Sun.COM pid = udev->usb_dev_descr->idProduct;
23739430SRaymond.Chen@Sun.COM ht = gethrtime();
23749430SRaymond.Chen@Sun.COM
23759430SRaymond.Chen@Sun.COM p = kbuf;
23769430SRaymond.Chen@Sun.COM bcopy((uint8_t *)&vid, p, sizeof (uint16_t));
23779430SRaymond.Chen@Sun.COM p += sizeof (uint16_t);
23789430SRaymond.Chen@Sun.COM
23799430SRaymond.Chen@Sun.COM bcopy((uint8_t *)&pid, p, sizeof (uint16_t));
23809430SRaymond.Chen@Sun.COM p += sizeof (uint16_t);
23819430SRaymond.Chen@Sun.COM
23829430SRaymond.Chen@Sun.COM bcopy((uint8_t *)&p, p, sizeof (uint32_t));
23839430SRaymond.Chen@Sun.COM p += sizeof (uint32_t);
23849430SRaymond.Chen@Sun.COM
23859430SRaymond.Chen@Sun.COM bcopy((uint8_t *)&ht, p, sizeof (uint64_t));
23869430SRaymond.Chen@Sun.COM
23879430SRaymond.Chen@Sun.COM return (PRF_128(kbuf, 16, &n, a, sizeof (a),
23889430SRaymond.Chen@Sun.COM (uchar_t *)hc_data, sizeof (wusb_hc_data_t), rbuf));
23899430SRaymond.Chen@Sun.COM }
23909430SRaymond.Chen@Sun.COM
23919430SRaymond.Chen@Sun.COM /* Set WUSB device encryption type, refer to WUSB 1.0/7.3.2.2 */
23929430SRaymond.Chen@Sun.COM int
wusb_dev_set_encrypt(usb_pipe_handle_t ph,uint8_t value)23939430SRaymond.Chen@Sun.COM wusb_dev_set_encrypt(usb_pipe_handle_t ph, uint8_t value)
23949430SRaymond.Chen@Sun.COM {
23959430SRaymond.Chen@Sun.COM usb_ctrl_setup_t setup;
23969430SRaymond.Chen@Sun.COM usb_cr_t cr;
23979430SRaymond.Chen@Sun.COM usb_cb_flags_t cb_flags;
23989430SRaymond.Chen@Sun.COM
23999430SRaymond.Chen@Sun.COM setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV;
24009430SRaymond.Chen@Sun.COM setup.bRequest = USB_REQ_SET_ENCRYPTION;
24019430SRaymond.Chen@Sun.COM setup.wValue = value;
24029430SRaymond.Chen@Sun.COM setup.wIndex = 0;
24039430SRaymond.Chen@Sun.COM setup.wLength = 0;
24049430SRaymond.Chen@Sun.COM setup.attrs = USB_ATTRS_NONE;
24059430SRaymond.Chen@Sun.COM
24069430SRaymond.Chen@Sun.COM return (usb_pipe_ctrl_xfer_wait(ph, &setup, NULL,
24079430SRaymond.Chen@Sun.COM &cr, &cb_flags, USB_FLAGS_SLEEP));
24089430SRaymond.Chen@Sun.COM }
24099430SRaymond.Chen@Sun.COM
24109430SRaymond.Chen@Sun.COM /*
24119430SRaymond.Chen@Sun.COM * Set WUSB device key descriptor, refer to WUSB 1.0/7.3.2.4
24129430SRaymond.Chen@Sun.COM * ph - Device's default control pipe
24139430SRaymond.Chen@Sun.COM * key_index - Key Index
24149430SRaymond.Chen@Sun.COM */
24159430SRaymond.Chen@Sun.COM int
wusb_dev_set_key(usb_pipe_handle_t ph,uint8_t key_index,usb_key_descr_t * key,size_t klen)24169430SRaymond.Chen@Sun.COM wusb_dev_set_key(usb_pipe_handle_t ph, uint8_t key_index,
24179430SRaymond.Chen@Sun.COM usb_key_descr_t *key, size_t klen)
24189430SRaymond.Chen@Sun.COM {
24199430SRaymond.Chen@Sun.COM usb_ctrl_setup_t setup;
24209430SRaymond.Chen@Sun.COM usb_cr_t cr;
24219430SRaymond.Chen@Sun.COM usb_cb_flags_t cb_flags;
24229430SRaymond.Chen@Sun.COM mblk_t *pdata;
24239430SRaymond.Chen@Sun.COM int rval;
24249430SRaymond.Chen@Sun.COM
24259430SRaymond.Chen@Sun.COM setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV;
24269430SRaymond.Chen@Sun.COM setup.bRequest = USB_REQ_SET_DESCR;
24279430SRaymond.Chen@Sun.COM setup.wValue = (USB_DESCR_TYPE_KEY << 8) | key_index;
24289430SRaymond.Chen@Sun.COM setup.wIndex = 0;
24299430SRaymond.Chen@Sun.COM setup.wLength = (uint16_t)klen;
24309430SRaymond.Chen@Sun.COM setup.attrs = USB_ATTRS_NONE;
24319430SRaymond.Chen@Sun.COM
24329430SRaymond.Chen@Sun.COM if ((pdata = allocb(klen, BPRI_HI)) == NULL) {
24339430SRaymond.Chen@Sun.COM
24349430SRaymond.Chen@Sun.COM return (USB_FAILURE);
24359430SRaymond.Chen@Sun.COM }
24369430SRaymond.Chen@Sun.COM bcopy(key, pdata->b_wptr, klen);
24379430SRaymond.Chen@Sun.COM pdata->b_wptr += klen;
24389430SRaymond.Chen@Sun.COM
24399430SRaymond.Chen@Sun.COM rval = usb_pipe_ctrl_xfer_wait(ph, &setup, &pdata,
24409430SRaymond.Chen@Sun.COM &cr, &cb_flags, USB_FLAGS_SLEEP);
24419430SRaymond.Chen@Sun.COM
24429430SRaymond.Chen@Sun.COM freemsg(pdata);
24439430SRaymond.Chen@Sun.COM
24449430SRaymond.Chen@Sun.COM return (rval);
24459430SRaymond.Chen@Sun.COM }
24469430SRaymond.Chen@Sun.COM
24479430SRaymond.Chen@Sun.COM /*
24489430SRaymond.Chen@Sun.COM * Set encryption type for the specified device.
24499430SRaymond.Chen@Sun.COM */
24509430SRaymond.Chen@Sun.COM int
wusb_hc_set_encrypt(wusb_hc_data_t * hc_data,usb_port_t port,uint8_t type)24519430SRaymond.Chen@Sun.COM wusb_hc_set_encrypt(wusb_hc_data_t *hc_data, usb_port_t port, uint8_t type)
24529430SRaymond.Chen@Sun.COM {
24539430SRaymond.Chen@Sun.COM dev_info_t *dip = hc_data->hc_dip;
24549430SRaymond.Chen@Sun.COM int rval;
24559430SRaymond.Chen@Sun.COM
24569430SRaymond.Chen@Sun.COM if ((rval = hc_data->set_encrypt(dip, port, type)) != USB_SUCCESS) {
24579430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
24589430SRaymond.Chen@Sun.COM "wusb_hc_set_encrypt: set encryption type %d "
24599430SRaymond.Chen@Sun.COM "for port %d failed, rval = %d", type, port, rval);
24609430SRaymond.Chen@Sun.COM }
24619430SRaymond.Chen@Sun.COM
24629430SRaymond.Chen@Sun.COM return (rval);
24639430SRaymond.Chen@Sun.COM }
24649430SRaymond.Chen@Sun.COM
24659430SRaymond.Chen@Sun.COM /*
24669430SRaymond.Chen@Sun.COM * Set Device Key for WUSB host, refer to WUSB 1.0/8.5.3.8
24679430SRaymond.Chen@Sun.COM * Call the HC's specific set_ptk function to set PTK for a device
24689430SRaymond.Chen@Sun.COM * len: length of key_data
24699430SRaymond.Chen@Sun.COM */
24709430SRaymond.Chen@Sun.COM int
wusb_hc_set_ptk(wusb_hc_data_t * hc_data,uint8_t * key_data,usb_port_t port)24719430SRaymond.Chen@Sun.COM wusb_hc_set_ptk(wusb_hc_data_t *hc_data, uint8_t *key_data, usb_port_t port)
24729430SRaymond.Chen@Sun.COM {
24739430SRaymond.Chen@Sun.COM dev_info_t *dip = hc_data->hc_dip;
24749430SRaymond.Chen@Sun.COM wusb_dev_info_t *dev_info = hc_data->hc_dev_infos[port];
24759430SRaymond.Chen@Sun.COM usb_key_descr_t *key_descr;
24769430SRaymond.Chen@Sun.COM size_t klen;
24779430SRaymond.Chen@Sun.COM int rval;
24789430SRaymond.Chen@Sun.COM uint8_t *p;
24799430SRaymond.Chen@Sun.COM
24809797SRaymond.Chen@Sun.COM ASSERT(mutex_owned(&hc_data->hc_mutex));
24819797SRaymond.Chen@Sun.COM
24829430SRaymond.Chen@Sun.COM if ((key_data == NULL) || (dev_info == NULL)) {
24839430SRaymond.Chen@Sun.COM
24849430SRaymond.Chen@Sun.COM return (USB_INVALID_ARGS);
24859430SRaymond.Chen@Sun.COM }
24869430SRaymond.Chen@Sun.COM
24879430SRaymond.Chen@Sun.COM klen = sizeof (usb_key_descr_t) + 15;
24889430SRaymond.Chen@Sun.COM key_descr = kmem_zalloc(klen, KM_SLEEP);
24899430SRaymond.Chen@Sun.COM
24909430SRaymond.Chen@Sun.COM key_descr->bLength = (uint16_t)klen;
24919430SRaymond.Chen@Sun.COM key_descr->bDescriptorType = USB_DESCR_TYPE_KEY;
24929430SRaymond.Chen@Sun.COM (void) memcpy(key_descr->tTKID, dev_info->wdev_tkid, 3);
24939430SRaymond.Chen@Sun.COM p = &key_descr->KeyData[0];
24949430SRaymond.Chen@Sun.COM (void) memcpy(p, key_data, 16);
24959430SRaymond.Chen@Sun.COM
24969797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
24979797SRaymond.Chen@Sun.COM
24989430SRaymond.Chen@Sun.COM if ((rval = hc_data->set_ptk(dip, key_descr, klen, port)) !=
24999430SRaymond.Chen@Sun.COM USB_SUCCESS) {
25009430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
25019430SRaymond.Chen@Sun.COM "wusb_hc_set_pkt: set ptk for port %d failed", port);
25029430SRaymond.Chen@Sun.COM }
25039430SRaymond.Chen@Sun.COM
25049430SRaymond.Chen@Sun.COM kmem_free(key_descr, klen);
25059797SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
25069430SRaymond.Chen@Sun.COM
25079430SRaymond.Chen@Sun.COM return (rval);
25089430SRaymond.Chen@Sun.COM }
25099430SRaymond.Chen@Sun.COM
25109430SRaymond.Chen@Sun.COM /*
25119430SRaymond.Chen@Sun.COM * Set GTK for a host
25129430SRaymond.Chen@Sun.COM * Call HC's specific set_gtk function
25139430SRaymond.Chen@Sun.COM *
25149430SRaymond.Chen@Sun.COM * Default gtk is set at hc_initial_start, and to be changed whenever
25159430SRaymond.Chen@Sun.COM * a device leaves the current group (refer to WUSB spec 6.2.11.2)
25169430SRaymond.Chen@Sun.COM */
25179430SRaymond.Chen@Sun.COM int
wusb_hc_set_gtk(wusb_hc_data_t * hc_data,uint8_t * key_data,uint8_t * tkid)25189430SRaymond.Chen@Sun.COM wusb_hc_set_gtk(wusb_hc_data_t *hc_data, uint8_t *key_data, uint8_t *tkid)
25199430SRaymond.Chen@Sun.COM {
25209430SRaymond.Chen@Sun.COM dev_info_t *dip = hc_data->hc_dip;
25219430SRaymond.Chen@Sun.COM usb_key_descr_t *key_descr;
25229430SRaymond.Chen@Sun.COM size_t klen;
25239430SRaymond.Chen@Sun.COM int rval;
25249430SRaymond.Chen@Sun.COM uint8_t *p;
25259430SRaymond.Chen@Sun.COM
25269430SRaymond.Chen@Sun.COM if ((key_data == NULL) || (tkid == NULL)) {
25279430SRaymond.Chen@Sun.COM
25289430SRaymond.Chen@Sun.COM return (USB_INVALID_ARGS);
25299430SRaymond.Chen@Sun.COM }
25309430SRaymond.Chen@Sun.COM
25319430SRaymond.Chen@Sun.COM klen = sizeof (usb_key_descr_t) + 15;
25329430SRaymond.Chen@Sun.COM key_descr = kmem_zalloc(klen, KM_SLEEP);
25339430SRaymond.Chen@Sun.COM
25349430SRaymond.Chen@Sun.COM key_descr->bLength = (uint16_t)klen;
25359430SRaymond.Chen@Sun.COM key_descr->bDescriptorType = USB_DESCR_TYPE_KEY;
25369430SRaymond.Chen@Sun.COM (void) memcpy(key_descr->tTKID, tkid, 3);
25379430SRaymond.Chen@Sun.COM p = &key_descr->KeyData[0];
25389430SRaymond.Chen@Sun.COM (void) memcpy(p, key_data, 16);
25399430SRaymond.Chen@Sun.COM
25409430SRaymond.Chen@Sun.COM if ((rval = hc_data->set_gtk(dip, key_descr, klen)) !=
25419430SRaymond.Chen@Sun.COM USB_SUCCESS) {
25429430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
25439430SRaymond.Chen@Sun.COM "wusb_hc_set_gkt: set gtk failed");
25449430SRaymond.Chen@Sun.COM }
25459430SRaymond.Chen@Sun.COM
25469430SRaymond.Chen@Sun.COM (void) memcpy(&hc_data->hc_gtk, key_descr, klen);
25479430SRaymond.Chen@Sun.COM kmem_free(key_descr, klen);
25489430SRaymond.Chen@Sun.COM
25499430SRaymond.Chen@Sun.COM return (rval);
25509430SRaymond.Chen@Sun.COM }
25519430SRaymond.Chen@Sun.COM
25529430SRaymond.Chen@Sun.COM /* Set Device Info for WUSB host, refer to WUSB 1.0/8.5.3.7 */
25539430SRaymond.Chen@Sun.COM int
wusb_hc_set_device_info(wusb_hc_data_t * hc_data,usb_port_t port)25549430SRaymond.Chen@Sun.COM wusb_hc_set_device_info(wusb_hc_data_t *hc_data, usb_port_t port)
25559430SRaymond.Chen@Sun.COM {
25569430SRaymond.Chen@Sun.COM wusb_dev_info_t *dev_info;
25579430SRaymond.Chen@Sun.COM int rval;
25589430SRaymond.Chen@Sun.COM
25599430SRaymond.Chen@Sun.COM USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
25609430SRaymond.Chen@Sun.COM "wusb_hc_set_device_info: port = %d", port);
25619430SRaymond.Chen@Sun.COM
25629430SRaymond.Chen@Sun.COM dev_info = hc_data->hc_dev_infos[port];
25639430SRaymond.Chen@Sun.COM rval = hc_data->set_device_info(hc_data->hc_dip, dev_info, port);
25649430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
25659430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
25669430SRaymond.Chen@Sun.COM "wusb_hc_set_device_info: the host failed to set "
25679430SRaymond.Chen@Sun.COM "device info, rval = %d", rval);
25689430SRaymond.Chen@Sun.COM }
25699430SRaymond.Chen@Sun.COM
25709430SRaymond.Chen@Sun.COM return (rval);
25719430SRaymond.Chen@Sun.COM }
25729430SRaymond.Chen@Sun.COM
25739430SRaymond.Chen@Sun.COM /*
25749430SRaymond.Chen@Sun.COM * Set/Get Handshake Data to/from WUSB device, refer to WUSB 1.0/7.3.2.5
25759430SRaymond.Chen@Sun.COM * step = 1, 2, 3
25769430SRaymond.Chen@Sun.COM */
25779430SRaymond.Chen@Sun.COM int
wusb_handshake(usb_pipe_handle_t pipe,wusb_hndshk_data_t * hs,int step)25789430SRaymond.Chen@Sun.COM wusb_handshake(usb_pipe_handle_t pipe, wusb_hndshk_data_t *hs, int step)
25799430SRaymond.Chen@Sun.COM {
25809430SRaymond.Chen@Sun.COM usb_ctrl_setup_t setup;
25819430SRaymond.Chen@Sun.COM mblk_t *pdata;
25829430SRaymond.Chen@Sun.COM usb_cr_t cr;
25839430SRaymond.Chen@Sun.COM usb_cb_flags_t cb_flags;
25849430SRaymond.Chen@Sun.COM int rval;
25859430SRaymond.Chen@Sun.COM
25869430SRaymond.Chen@Sun.COM if (step == 2) {
25879430SRaymond.Chen@Sun.COM /* get handshake */
25889430SRaymond.Chen@Sun.COM setup.bmRequestType = USB_DEV_REQ_DEV_TO_HOST;
25899430SRaymond.Chen@Sun.COM setup.bRequest = USB_REQ_GET_HANDSHAKE;
25909430SRaymond.Chen@Sun.COM pdata = NULL;
25919430SRaymond.Chen@Sun.COM } else if ((step == 1) || (step == 3)) {
25929430SRaymond.Chen@Sun.COM /* set handshake */
25939430SRaymond.Chen@Sun.COM setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV;
25949430SRaymond.Chen@Sun.COM setup.bRequest = USB_REQ_SET_HANDSHAKE;
25959430SRaymond.Chen@Sun.COM
25969430SRaymond.Chen@Sun.COM if ((pdata = allocb(WUSB_HNDSHK_DATA_LEN, BPRI_HI)) == NULL) {
25979430SRaymond.Chen@Sun.COM
25989430SRaymond.Chen@Sun.COM return (USB_NO_RESOURCES);
25999430SRaymond.Chen@Sun.COM }
26009430SRaymond.Chen@Sun.COM bcopy(hs, pdata->b_wptr, WUSB_HNDSHK_DATA_LEN);
26019430SRaymond.Chen@Sun.COM pdata->b_wptr += WUSB_HNDSHK_DATA_LEN;
26029430SRaymond.Chen@Sun.COM } else {
26039430SRaymond.Chen@Sun.COM /* step value is invalid */
26049430SRaymond.Chen@Sun.COM return (USB_INVALID_ARGS);
26059430SRaymond.Chen@Sun.COM }
26069430SRaymond.Chen@Sun.COM
26079430SRaymond.Chen@Sun.COM setup.wValue = (uint16_t)step;
26089430SRaymond.Chen@Sun.COM setup.wIndex = 0;
26099430SRaymond.Chen@Sun.COM setup.wLength = WUSB_HNDSHK_DATA_LEN;
26109430SRaymond.Chen@Sun.COM setup.attrs = USB_ATTRS_NONE;
26119430SRaymond.Chen@Sun.COM
26129430SRaymond.Chen@Sun.COM rval = usb_pipe_ctrl_xfer_wait(pipe, &setup, &pdata,
26139430SRaymond.Chen@Sun.COM &cr, &cb_flags, USB_FLAGS_SLEEP);
26149430SRaymond.Chen@Sun.COM
26159430SRaymond.Chen@Sun.COM if (step == 2) {
26169430SRaymond.Chen@Sun.COM if (pdata) {
26179430SRaymond.Chen@Sun.COM bcopy(pdata->b_rptr, hs, msgsize(pdata));
26189430SRaymond.Chen@Sun.COM freemsg(pdata);
26199430SRaymond.Chen@Sun.COM }
26209430SRaymond.Chen@Sun.COM } else {
26219430SRaymond.Chen@Sun.COM freemsg(pdata);
26229430SRaymond.Chen@Sun.COM }
26239430SRaymond.Chen@Sun.COM
26249430SRaymond.Chen@Sun.COM return (rval);
26259430SRaymond.Chen@Sun.COM }
26269430SRaymond.Chen@Sun.COM
26279430SRaymond.Chen@Sun.COM /* search the security descrs for CCM encryption type descr */
26289430SRaymond.Chen@Sun.COM int16_t
wusb_get_ccm_encryption_value(wusb_secrt_data_t * secrt_data)26299430SRaymond.Chen@Sun.COM wusb_get_ccm_encryption_value(wusb_secrt_data_t *secrt_data)
26309430SRaymond.Chen@Sun.COM {
26319430SRaymond.Chen@Sun.COM usb_encryption_descr_t *encry_descr;
26329430SRaymond.Chen@Sun.COM int i;
26339430SRaymond.Chen@Sun.COM int16_t value = -1;
26349430SRaymond.Chen@Sun.COM
26359430SRaymond.Chen@Sun.COM for (i = 0; i < secrt_data->secrt_n_encry; i++) {
26369430SRaymond.Chen@Sun.COM encry_descr = &secrt_data->secrt_encry_descr[i];
26379430SRaymond.Chen@Sun.COM if (encry_descr->bEncryptionType == USB_ENC_TYPE_CCM_1) {
26389430SRaymond.Chen@Sun.COM value = encry_descr->bEncryptionValue;
26399430SRaymond.Chen@Sun.COM USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
26409430SRaymond.Chen@Sun.COM "ccm encryption value is %d", value);
26419430SRaymond.Chen@Sun.COM
26429430SRaymond.Chen@Sun.COM break;
26439430SRaymond.Chen@Sun.COM }
26449430SRaymond.Chen@Sun.COM }
26459430SRaymond.Chen@Sun.COM
26469430SRaymond.Chen@Sun.COM return (value);
26479430SRaymond.Chen@Sun.COM }
26489430SRaymond.Chen@Sun.COM
26499430SRaymond.Chen@Sun.COM static void
wusb_print_handshake_data(wusb_hndshk_data_t * hs,int step)26509430SRaymond.Chen@Sun.COM wusb_print_handshake_data(wusb_hndshk_data_t *hs, int step)
26519430SRaymond.Chen@Sun.COM {
26529430SRaymond.Chen@Sun.COM uint8_t *p;
26539430SRaymond.Chen@Sun.COM
26549430SRaymond.Chen@Sun.COM USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
26559430SRaymond.Chen@Sun.COM "handshake %d data:", step);
26569430SRaymond.Chen@Sun.COM USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
26579430SRaymond.Chen@Sun.COM "%x %x (TKID)%x %x %x %x", hs->bMessageNumber, hs->bStatus,
26589430SRaymond.Chen@Sun.COM hs->tTKID[0], hs->tTKID[1], hs->tTKID[2], hs->bReserved);
26599430SRaymond.Chen@Sun.COM
26609430SRaymond.Chen@Sun.COM p = hs->CDID;
26619430SRaymond.Chen@Sun.COM
26629430SRaymond.Chen@Sun.COM USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
26639430SRaymond.Chen@Sun.COM "(CDID)%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
26649430SRaymond.Chen@Sun.COM p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9],
26659430SRaymond.Chen@Sun.COM p[10], p[11], p[12], p[13], p[14], p[15]);
26669430SRaymond.Chen@Sun.COM
26679430SRaymond.Chen@Sun.COM p = hs->Nonce;
26689430SRaymond.Chen@Sun.COM USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
26699430SRaymond.Chen@Sun.COM "(Nonce)%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
26709430SRaymond.Chen@Sun.COM p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9],
26719430SRaymond.Chen@Sun.COM p[10], p[11], p[12], p[13], p[14], p[15]);
26729430SRaymond.Chen@Sun.COM
26739430SRaymond.Chen@Sun.COM p = hs->MIC;
26749430SRaymond.Chen@Sun.COM USB_DPRINTF_L3(DPRINT_MASK_WHCDI, whcdi_log_handle,
26759430SRaymond.Chen@Sun.COM "(MIC)%x %x %x %x %x %x %x %x",
26769430SRaymond.Chen@Sun.COM p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
26779430SRaymond.Chen@Sun.COM }
26789430SRaymond.Chen@Sun.COM
26799430SRaymond.Chen@Sun.COM /* ARGSUSED */
26809430SRaymond.Chen@Sun.COM /*
26819430SRaymond.Chen@Sun.COM * Do 4way handshake and other necessary control operations to
26829430SRaymond.Chen@Sun.COM * transit the device to authenticated state
26839430SRaymond.Chen@Sun.COM * refer to WUSB 1.0 [7.3.2.5, 6.2.10.9.1, 7.1.2]
26849430SRaymond.Chen@Sun.COM * ph - pipe handle of the host controller
26859430SRaymond.Chen@Sun.COM */
26869430SRaymond.Chen@Sun.COM int
wusb_4way_handshake(wusb_hc_data_t * hc_data,usb_port_t port,usb_pipe_handle_t ph,uint8_t ifc)26879430SRaymond.Chen@Sun.COM wusb_4way_handshake(wusb_hc_data_t *hc_data, usb_port_t port,
26889430SRaymond.Chen@Sun.COM usb_pipe_handle_t ph, uint8_t ifc)
26899430SRaymond.Chen@Sun.COM {
26909430SRaymond.Chen@Sun.COM uint8_t tkid[3];
26919430SRaymond.Chen@Sun.COM wusb_ccm_nonce_t n;
26929430SRaymond.Chen@Sun.COM wusb_hndshk_data_t *hs;
26939430SRaymond.Chen@Sun.COM wusb_dev_info_t *dev_info;
26949430SRaymond.Chen@Sun.COM wusb_cc_t *cc;
26959430SRaymond.Chen@Sun.COM uchar_t adata1[] = "Pair-wise keys";
26969430SRaymond.Chen@Sun.COM uchar_t adata2[] = "out-of-bandMIC";
26979430SRaymond.Chen@Sun.COM uchar_t bdata[32], keyout[32], mic[8];
26989430SRaymond.Chen@Sun.COM int rval;
26999797SRaymond.Chen@Sun.COM usb_pipe_handle_t w_ph;
27009430SRaymond.Chen@Sun.COM
27019430SRaymond.Chen@Sun.COM USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
27029430SRaymond.Chen@Sun.COM "wusb_4way_handshake: port = %d", port);
27039430SRaymond.Chen@Sun.COM
27049797SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
27059430SRaymond.Chen@Sun.COM dev_info = hc_data->hc_dev_infos[port];
27069430SRaymond.Chen@Sun.COM if (dev_info == NULL) {
27079797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
27089430SRaymond.Chen@Sun.COM
27099430SRaymond.Chen@Sun.COM return (USB_FAILURE);
27109430SRaymond.Chen@Sun.COM }
27119430SRaymond.Chen@Sun.COM cc = dev_info->wdev_cc;
27129430SRaymond.Chen@Sun.COM if (dev_info->wdev_ph == NULL || cc == NULL) {
27139797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
27149430SRaymond.Chen@Sun.COM
27159430SRaymond.Chen@Sun.COM return (USB_FAILURE);
27169430SRaymond.Chen@Sun.COM }
27179430SRaymond.Chen@Sun.COM
27189797SRaymond.Chen@Sun.COM w_ph = dev_info->wdev_ph;
27199797SRaymond.Chen@Sun.COM
27209430SRaymond.Chen@Sun.COM hs = (wusb_hndshk_data_t *)kmem_zalloc(
27219430SRaymond.Chen@Sun.COM 3 * sizeof (wusb_hndshk_data_t), KM_SLEEP);
27229430SRaymond.Chen@Sun.COM
27239430SRaymond.Chen@Sun.COM /* tkid is generated dynamically and saved in dev_info */
2724*10912SRaymond.Chen@Sun.COM (void) random_get_pseudo_bytes(tkid, 3);
27259430SRaymond.Chen@Sun.COM
27269430SRaymond.Chen@Sun.COM (void) memcpy(dev_info->wdev_tkid, tkid, 3);
27279430SRaymond.Chen@Sun.COM
27289430SRaymond.Chen@Sun.COM /* handshake 1 */
27299430SRaymond.Chen@Sun.COM hs[0].bMessageNumber = 1;
27309430SRaymond.Chen@Sun.COM hs[0].bStatus = 0;
27319430SRaymond.Chen@Sun.COM (void) memcpy(hs[0].tTKID, tkid, 3);
27329430SRaymond.Chen@Sun.COM hs[0].bReserved = 0;
27339430SRaymond.Chen@Sun.COM bcopy(cc->CDID, hs[0].CDID, WUSB_CDID_LEN);
27349430SRaymond.Chen@Sun.COM
27359430SRaymond.Chen@Sun.COM if ((rval = wusb_gen_random_nonce(hc_data, dev_info, hs[0].Nonce))
27369430SRaymond.Chen@Sun.COM != USB_SUCCESS) {
27379430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
27389430SRaymond.Chen@Sun.COM "Nonce generation failed: %d", rval);
27399797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
27409430SRaymond.Chen@Sun.COM
27419430SRaymond.Chen@Sun.COM goto done;
27429430SRaymond.Chen@Sun.COM }
27439430SRaymond.Chen@Sun.COM
27449430SRaymond.Chen@Sun.COM wusb_print_handshake_data(&hs[0], 1);
27459430SRaymond.Chen@Sun.COM USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
27469430SRaymond.Chen@Sun.COM "wusb_4way_handshake: shake 1.............");
27479430SRaymond.Chen@Sun.COM
27489797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
27499797SRaymond.Chen@Sun.COM rval = wusb_handshake(w_ph, &(hs[0]), 1);
27509430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
27519430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
27529430SRaymond.Chen@Sun.COM "handshake 1 failed, rval = %d", rval);
27539430SRaymond.Chen@Sun.COM
27549430SRaymond.Chen@Sun.COM goto done;
27559430SRaymond.Chen@Sun.COM }
27569430SRaymond.Chen@Sun.COM
27579430SRaymond.Chen@Sun.COM /* handshake 2 */
27589430SRaymond.Chen@Sun.COM USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
27599430SRaymond.Chen@Sun.COM "wusb_4way_handshake: shake 2.............");
27609797SRaymond.Chen@Sun.COM rval = wusb_handshake(w_ph, &(hs[1]), 2);
27619430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
27629430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
27639430SRaymond.Chen@Sun.COM "handshake 2 failed, rval = %d", rval);
27649430SRaymond.Chen@Sun.COM
27659430SRaymond.Chen@Sun.COM goto done;
27669430SRaymond.Chen@Sun.COM }
27679430SRaymond.Chen@Sun.COM
27689430SRaymond.Chen@Sun.COM if (hs[1].bMessageNumber != 2 || hs[1].bStatus != 0) {
27699430SRaymond.Chen@Sun.COM rval = USB_FAILURE;
27709430SRaymond.Chen@Sun.COM
27719430SRaymond.Chen@Sun.COM goto done;
27729430SRaymond.Chen@Sun.COM }
27739430SRaymond.Chen@Sun.COM
27749430SRaymond.Chen@Sun.COM wusb_print_handshake_data(&hs[1], 2);
27759430SRaymond.Chen@Sun.COM
27769430SRaymond.Chen@Sun.COM /* derived session keys, refer to WUSB 1.0/6.5.1 */
27779430SRaymond.Chen@Sun.COM n.sfn = 0;
27789430SRaymond.Chen@Sun.COM n.tkid = tkid[0] | (tkid[1]<<8) | (tkid[2] << 16);
27799797SRaymond.Chen@Sun.COM
27809797SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
27819430SRaymond.Chen@Sun.COM n.daddr = dev_info->wdev_addr;
27829797SRaymond.Chen@Sun.COM
27839430SRaymond.Chen@Sun.COM n.saddr = hc_data->hc_addr;
27849430SRaymond.Chen@Sun.COM bcopy(hs[0].Nonce, bdata, 16);
27859430SRaymond.Chen@Sun.COM bcopy(hs[1].Nonce, bdata + 16, 16);
27869797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
27879430SRaymond.Chen@Sun.COM
27889430SRaymond.Chen@Sun.COM rval = PRF_256(cc->CK, 16, &n, adata1, 14, bdata, 32, keyout);
27899430SRaymond.Chen@Sun.COM if (rval != 0) {
27909430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
27919430SRaymond.Chen@Sun.COM "compute keys failed, rval = %d", rval);
27929430SRaymond.Chen@Sun.COM
27939430SRaymond.Chen@Sun.COM goto done;
27949430SRaymond.Chen@Sun.COM }
27959430SRaymond.Chen@Sun.COM
27969430SRaymond.Chen@Sun.COM /* sfn was changed in PRF(). Need to reset it to 0 */
27979430SRaymond.Chen@Sun.COM n.sfn = 0;
27989430SRaymond.Chen@Sun.COM
27999430SRaymond.Chen@Sun.COM /* used the derived KCK to verify received MIC (WUSB 1.0/6.5.2] */
28009430SRaymond.Chen@Sun.COM rval = PRF_64(keyout, 16, &n, adata2, 14, (uchar_t *)(&hs[1]),
28019430SRaymond.Chen@Sun.COM WUSB_HNDSHK_DATA_LEN - 8, mic);
28029430SRaymond.Chen@Sun.COM if (rval != 0) {
28039430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
28049430SRaymond.Chen@Sun.COM "compute MIC failed, rval = %d", rval);
28059430SRaymond.Chen@Sun.COM
28069430SRaymond.Chen@Sun.COM goto done;
28079430SRaymond.Chen@Sun.COM }
28089430SRaymond.Chen@Sun.COM
28099430SRaymond.Chen@Sun.COM if (memcmp(hs[1].MIC, mic, 8) != 0) {
28109430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
28119430SRaymond.Chen@Sun.COM "verify mic failed");
28129430SRaymond.Chen@Sun.COM rval = USB_FAILURE;
28139430SRaymond.Chen@Sun.COM
28149430SRaymond.Chen@Sun.COM goto done;
28159430SRaymond.Chen@Sun.COM }
28169430SRaymond.Chen@Sun.COM
28179430SRaymond.Chen@Sun.COM /* handshake 3 */
28189430SRaymond.Chen@Sun.COM bcopy(&hs[0], &hs[2], WUSB_HNDSHK_DATA_LEN - 8);
28199430SRaymond.Chen@Sun.COM hs[2].bMessageNumber = 3;
28209430SRaymond.Chen@Sun.COM n.sfn = 0;
28219430SRaymond.Chen@Sun.COM rval = PRF_64(keyout, 16, &n, adata2, 14, (uchar_t *)(&hs[2]),
28229430SRaymond.Chen@Sun.COM WUSB_HNDSHK_DATA_LEN - 8, hs[2].MIC);
28239430SRaymond.Chen@Sun.COM if (rval != 0) {
28249430SRaymond.Chen@Sun.COM goto done;
28259430SRaymond.Chen@Sun.COM }
28269430SRaymond.Chen@Sun.COM
28279430SRaymond.Chen@Sun.COM wusb_print_handshake_data(&hs[2], 3);
28289430SRaymond.Chen@Sun.COM
28299430SRaymond.Chen@Sun.COM USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
28309430SRaymond.Chen@Sun.COM "wusb_4way_handshake: shake 3.............");
28319797SRaymond.Chen@Sun.COM rval = wusb_handshake(w_ph, &(hs[2]), 3);
28329430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
28339430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
28349430SRaymond.Chen@Sun.COM "handshake 3 failed, rval = %d", rval);
28359430SRaymond.Chen@Sun.COM
28369430SRaymond.Chen@Sun.COM goto done;
28379430SRaymond.Chen@Sun.COM }
28389430SRaymond.Chen@Sun.COM
28399797SRaymond.Chen@Sun.COM mutex_enter(&hc_data->hc_mutex);
28409430SRaymond.Chen@Sun.COM /* set PTK for host */
28419430SRaymond.Chen@Sun.COM (void) memcpy(dev_info->wdev_ptk, keyout + 16, 16);
28429430SRaymond.Chen@Sun.COM
28439430SRaymond.Chen@Sun.COM USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
28449430SRaymond.Chen@Sun.COM "wusb_4way_handshake: set ptk .............");
28459430SRaymond.Chen@Sun.COM rval = wusb_hc_set_ptk(hc_data, dev_info->wdev_ptk, port);
28469797SRaymond.Chen@Sun.COM mutex_exit(&hc_data->hc_mutex);
28479430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
28489430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
28499430SRaymond.Chen@Sun.COM "set ptk for host failed, rval = %d", rval);
28509430SRaymond.Chen@Sun.COM
28519430SRaymond.Chen@Sun.COM goto done;
28529430SRaymond.Chen@Sun.COM }
28539430SRaymond.Chen@Sun.COM
28549430SRaymond.Chen@Sun.COM /*
28559430SRaymond.Chen@Sun.COM * enable CCM encryption on the host
28569430SRaymond.Chen@Sun.COM * according to WUSB 1.0/7.1.2, the encryption mode must be
28579430SRaymond.Chen@Sun.COM * enabled before setting GTK onto device
28589430SRaymond.Chen@Sun.COM */
28599430SRaymond.Chen@Sun.COM USB_DPRINTF_L4(DPRINT_MASK_WHCDI, whcdi_log_handle,
28609430SRaymond.Chen@Sun.COM "wusb_4way_handshake: hc set encrypt .............");
28619430SRaymond.Chen@Sun.COM rval = wusb_hc_set_encrypt(hc_data, port, WUSB_ENCRYP_TYPE_CCM_1);
28629430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
28639430SRaymond.Chen@Sun.COM USB_DPRINTF_L2(DPRINT_MASK_WHCDI, whcdi_log_handle,
28649430SRaymond.Chen@Sun.COM "set encryption for host failed, rval = %d", rval);
28659430SRaymond.Chen@Sun.COM
28669430SRaymond.Chen@Sun.COM goto done;
28679430SRaymond.Chen@Sun.COM }
28689430SRaymond.Chen@Sun.COM
28699430SRaymond.Chen@Sun.COM /*
28709430SRaymond.Chen@Sun.COM * set GTK for device
28719430SRaymond.Chen@Sun.COM * GTK is initialized when hc_data is inited
28729430SRaymond.Chen@Sun.COM */
28739797SRaymond.Chen@Sun.COM rval = wusb_dev_set_key(w_ph, 2 << 4,
28749430SRaymond.Chen@Sun.COM &hc_data->hc_gtk, hc_data->hc_gtk.bLength);
28759430SRaymond.Chen@Sun.COM done:
28769430SRaymond.Chen@Sun.COM kmem_free(hs, 3 * sizeof (wusb_hndshk_data_t));
28779430SRaymond.Chen@Sun.COM if (rval != USB_SUCCESS) {
28789430SRaymond.Chen@Sun.COM /* restore the host to unsecure mode */
28799430SRaymond.Chen@Sun.COM (void) wusb_hc_set_encrypt(hc_data, port,
28809430SRaymond.Chen@Sun.COM WUSB_ENCRYP_TYPE_UNSECURE);
28819430SRaymond.Chen@Sun.COM }
28829430SRaymond.Chen@Sun.COM
28839430SRaymond.Chen@Sun.COM return (rval);
28849430SRaymond.Chen@Sun.COM }
2885