1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * This file is for uwba private functions
  28  */
  29 
  30 #include <sys/uwb/uwba/uwba.h>
  31 
  32 uint_t uwba_errlevel = UWBA_LOG_CONSOLE;
  33 
  34 static kmutex_t uwba_mutex;
  35 
  36 /* list for uwba_dev, the radio host devices */
  37 static list_t   uwba_dev_list;
  38 
  39 /* modload support */
  40 extern struct mod_ops mod_miscops;
  41 
  42 static struct modlmisc modlmisc = {
  43         &mod_miscops,       /* Type of module */
  44         "UWBA: UWB Architecture"
  45 };
  46 
  47 static struct modlinkage modlinkage = {
  48         MODREV_1, (void *)&modlmisc, NULL
  49 };
  50 
  51 _NOTE(SCHEME_PROTECTS_DATA("unique per call", uwba_client_dev))
  52 _NOTE(SCHEME_PROTECTS_DATA("unique per call", uwb_notif_wrapper))
  53 /* This table is for data decode */
  54 uwba_evt_size_t uwba_evt_size_table[] = {
  55         [UWB_NOTIF_IE_RECEIVED] = {
  56                 .struct_len = UWB_RESULT_CODE_SIZE,
  57                 .buf_len_offset = 6
  58         },
  59         [UWB_NOTIF_BEACON_RECEIVED] = {
  60                 .struct_len = sizeof (uwb_rceb_beacon_t),
  61                 .buf_len_offset = UWB_BEACONINFOLEN_OFFSET
  62         },
  63         [UWB_NOTIF_BEACON_SIZE_CHANGE] = {
  64                 .struct_len = sizeof (uwb_rceb_beacon_size_change_t),
  65                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
  66         },
  67         [UWB_NOTIF_BPOIE_CHANGE] = {
  68                 .struct_len = sizeof (uwb_rceb_bpoie_change_t),
  69                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
  70         },
  71         [UWB_NOTIF_BP_SLOT_CHANGE] = {
  72                 .struct_len = sizeof (uwb_rceb_bp_slot_change_t),
  73                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
  74         },
  75         [UWB_NOTIF_BP_SWITCH_IE_RECEIVED] = {
  76                 .struct_len = UWB_RESULT_CODE_SIZE,
  77                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
  78         },
  79         [UWB_NOTIF_DEV_ADDR_CONFLICT] = {
  80                 .struct_len = UWB_RESULT_CODE_SIZE,
  81                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
  82         },
  83         [UWB_NOTIF_DRP_AVAILABILITY_CHANGE] = {
  84                 .struct_len = sizeof (uwb_rceb_drp_availability_t),
  85                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
  86         },
  87         [UWB_NOTIF_DRP] = {
  88                 .struct_len = sizeof (uwb_rceb_drp_t),
  89                 .buf_len_offset = 8
  90         },
  91         [UWB_NOTIF_BP_SWITCH_STATUS] = {
  92                 .struct_len = UWB_RESULT_CODE_SIZE,
  93                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
  94         },
  95         [UWB_NOTIF_CMD_FRAME_RCV] = {
  96                 .struct_len = UWB_RESULT_CODE_SIZE,
  97                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
  98         },
  99         [UWB_NOTIF_CHANNEL_CHANGE_IE_RCV] = {
 100                 .struct_len = UWB_RESULT_CODE_SIZE,
 101                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
 102         },
 103         [UWB_NOTIF_RESERVED] = {
 104                 .struct_len = UWB_RESULT_CODE_SIZE,
 105                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
 106         },
 107         [UWB_NOTIF_RESERVED + 1] = {
 108                 .struct_len = UWB_RESULT_CODE_SIZE,
 109                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
 110         },
 111         [UWB_NOTIF_RESERVED + 2] = {
 112                 .struct_len = UWB_RESULT_CODE_SIZE,
 113                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
 114         },
 115         [UWB_NOTIF_RESERVED + 3] = {
 116                 .struct_len = UWB_RESULT_CODE_SIZE,
 117                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
 118         },
 119         [UWB_CE_CHANNEL_CHANGE] = {
 120                 .struct_len = sizeof (uwb_rceb_head_t),
 121                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
 122         },
 123         [UWB_CE_DEV_ADDR_MGMT] = {
 124                 .struct_len = sizeof (uwb_rceb_dev_addr_mgmt_t),
 125                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
 126         },
 127         [UWB_CE_GET_IE] = {
 128                 .struct_len = sizeof (uwb_rceb_get_ie_t),
 129                 .buf_len_offset = 4
 130         },
 131         [UWB_CE_RESET] = {
 132                 .struct_len = UWB_RESULT_CODE_SIZE,
 133                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
 134         },
 135         [UWB_CE_SCAN] = {
 136                 .struct_len = UWB_RESULT_CODE_SIZE,
 137                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
 138         },
 139         [UWB_CE_SET_BEACON_FILTER] = {
 140                 .struct_len = UWB_RESULT_CODE_SIZE,
 141                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
 142         },
 143         [UWB_CE_SET_DRP_IE] = {
 144                 .struct_len = sizeof (uwb_rceb_set_drp_ie_t),
 145                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
 146         },
 147         [UWB_CE_SET_IE] = {
 148                 .struct_len = sizeof (uwb_rceb_set_ie_t),
 149                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
 150         },
 151         [UWB_CE_SET_NOTIFICATION_FILTER] = {
 152                 .struct_len = UWB_RESULT_CODE_SIZE,
 153                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
 154         },
 155         [UWB_CE_SET_TX_POWER] = {
 156                 .struct_len = UWB_RESULT_CODE_SIZE,
 157                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
 158         },
 159         [UWB_CE_SLEEP] = {
 160                 .struct_len = UWB_RESULT_CODE_SIZE,
 161                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
 162         },
 163         [UWB_CE_START_BEACON] = {
 164                 .struct_len = UWB_RESULT_CODE_SIZE,
 165                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
 166         },
 167         [UWB_CE_STOP_BEACON] = {
 168                 .struct_len = UWB_RESULT_CODE_SIZE,
 169                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
 170         },
 171         [UWB_CE_BP_MERGE] = {
 172                 .struct_len = UWB_RESULT_CODE_SIZE,
 173                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
 174         },
 175         [UWB_CE_SEND_COMMAND_FRAME] = {
 176                 .struct_len = UWB_RESULT_CODE_SIZE,
 177                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
 178         },
 179         [UWB_CE_SET_ASIE_NOTIFICATION] = {
 180                 .struct_len = UWB_RESULT_CODE_SIZE,
 181                 .buf_len_offset = UWB_EVT_NO_BUF_LEN_OFFSET
 182         },
 183 };
 184 /* This table is used for debug only */
 185 const char *uwba_evt_msg_table[] = {
 186         [UWB_NOTIF_IE_RECEIVED]         = "UWB_NOTIF_IE_RECEIVED",
 187         [UWB_NOTIF_BEACON_RECEIVED]     = "UWB_NOTIF_BEACON_RECEIVED",
 188         [UWB_NOTIF_BEACON_SIZE_CHANGE]  = "UWB_NOTIF_BEACON_SIZE_CHANGE",
 189         [UWB_NOTIF_BPOIE_CHANGE]        = "UWB_NOTIF_BPOIE_CHANGE",
 190         [UWB_NOTIF_BP_SLOT_CHANGE]      = "UWB_NOTIF_BP_SLOT_CHANGE",
 191         [UWB_NOTIF_BP_SWITCH_IE_RECEIVED] = "UWB_NOTIF_BP_SWITCH_IE_RECEIVED",
 192         [UWB_NOTIF_DEV_ADDR_CONFLICT]   = "UWB_NOTIF_DEV_ADDR_CONFLICT",
 193         [UWB_NOTIF_DRP_AVAILABILITY_CHANGE] =
 194                                         "UWB_NOTIF_DRP_AVAILABILITY_CHANGE",
 195         [UWB_NOTIF_DRP]                 = "UWB_NOTIF_DRP",
 196         [UWB_NOTIF_BP_SWITCH_STATUS]    = "UWB_NOTIF_BP_SWITCH_STATUS",
 197         [UWB_NOTIF_CMD_FRAME_RCV]       = "UWB_NOTIF_CMD_FRAME_RCV",
 198         [UWB_NOTIF_CHANNEL_CHANGE_IE_RCV] = "UWB_NOTIF_CHANNEL_CHANGE_IE_RCV",
 199         [UWB_NOTIF_RESERVED]            = "UWB_NOTIF_RESERVED",
 200         [UWB_NOTIF_RESERVED + 1]        = "UWB_NOTIF_RESERVED + 1",
 201         [UWB_NOTIF_RESERVED + 2]        = "UWB_NOTIF_RESERVED + 2",
 202         [UWB_NOTIF_RESERVED + 3]        = "UWB_NOTIF_RESERVED + 2",
 203         [UWB_CE_CHANNEL_CHANGE]         = "UWB_CE_CHANNEL_CHANGE",
 204         [UWB_CE_DEV_ADDR_MGMT]          = "UWB_CE_DEV_ADDR_MGMT",
 205         [UWB_CE_GET_IE]                 = "UWB_CE_GET_IE",
 206         [UWB_CE_RESET]                  = "UWB_CE_RESET",
 207         [UWB_CE_SCAN]                   = "UWB_CE_SCAN",
 208         [UWB_CE_SET_BEACON_FILTER]      = "UWB_CE_SET_BEACON_FILTER",
 209         [UWB_CE_SET_DRP_IE]             = "UWB_CE_SET_DRP_IE",
 210         [UWB_CE_SET_IE]                 = "UWB_CE_SET_IE",
 211         [UWB_CE_SET_NOTIFICATION_FILTER] = "UWB_CE_SET_NOTIFICATION_FILTER",
 212         [UWB_CE_SET_TX_POWER]           = "UWB_CE_SET_TX_POWER",
 213         [UWB_CE_SLEEP]                  = "UWB_CE_SLEEP",
 214         [UWB_CE_START_BEACON]           = "UWB_CE_START_BEACON",
 215         [UWB_CE_STOP_BEACON]            = "UWB_CE_STOP_BEACON",
 216         [UWB_CE_BP_MERGE]               = "UWB_CE_BP_MERGE",
 217         [UWB_CE_SEND_COMMAND_FRAME]     = "UWB_CE_SEND_COMMAND_FRAME",
 218         [UWB_CE_SET_ASIE_NOTIFICATION]  = "UWB_CE_SET_ASIE_NOTIFICATION",
 219 };
 220 
 221 
 222 static void uwba_init_lists(void);
 223 static void uwba_fini_lists(void);
 224 static void uwba_remove_cdev_list(uwba_dev_t *);
 225 
 226 static void uwba_list_phy_rates(uwb_dev_handle_t);
 227 static void uwba_list_phy_bandgroups(uwb_dev_handle_t);
 228 static void uwba_get_phy_cap(uwb_dev_handle_t, uint8_t *, uint16_t);
 229 static void uwba_save_phy_cap_bm(uwb_dev_handle_t, uint8_t *);
 230 int
 231 _init(void)
 232 {
 233         int rval;
 234         /*
 235          * uwba providing uwb device list support needs to be init'ed first
 236          * and destroyed last
 237          */
 238         uwba_init_lists();
 239         mutex_init(&uwba_mutex, NULL, MUTEX_DRIVER, NULL);
 240         if ((rval = mod_install(&modlinkage)) != 0) {
 241                 uwba_fini_lists();
 242                 mutex_destroy(&uwba_mutex);
 243         }
 244 
 245         return (rval);
 246 }
 247 
 248 int
 249 _fini()
 250 {
 251         int rval;
 252 
 253         if ((rval = mod_remove(&modlinkage)) == 0) {
 254                 mutex_destroy(&uwba_mutex);
 255                 uwba_fini_lists();
 256         }
 257 
 258         return (rval);
 259 }
 260 
 261 int
 262 _info(struct modinfo *modinfop)
 263 {
 264         return (mod_info(&modlinkage, modinfop));
 265 }
 266 
 267 /* Create the global uwb dev list */
 268 static void
 269 uwba_init_lists(void)
 270 {
 271         list_create(&(uwba_dev_list), sizeof (uwba_dev_t),
 272             offsetof(uwba_dev_t, uwba_dev_node));
 273 }
 274 
 275 /* Destroy  the global uwb dev list */
 276 static void
 277 uwba_fini_lists(void)
 278 {
 279         uwba_dev_t      *dev;
 280 
 281         /* Free all uwb dev node from dev_list */
 282         while (!list_is_empty(&uwba_dev_list)) {
 283                 dev = list_head(&uwba_dev_list);
 284                 if (dev != NULL) {
 285                         list_remove(&uwba_dev_list, dev);
 286                         kmem_free(dev, sizeof (uwba_dev_t));
 287                 }
 288         }
 289 }
 290 /* Search the uwb handle with a hwarc/hwahc dip */
 291 uwb_dev_handle_t
 292 uwba_dev_search(dev_info_t *dip)
 293 {
 294         mutex_enter(&uwba_mutex);
 295         uwba_dev_t *uwba_dev = list_head(&uwba_dev_list);
 296 
 297         while (uwba_dev != NULL) {
 298                 if (ddi_get_parent(uwba_dev->dip)  == ddi_get_parent(dip)) {
 299 
 300                         goto done;
 301                 }
 302                 uwba_dev = list_next(&uwba_dev_list, uwba_dev);
 303         }
 304 done:
 305         mutex_exit(&uwba_mutex);
 306 
 307         return (uwb_dev_handle_t)(uwba_dev);
 308 }
 309 
 310 /* Add a uwb device (hwarc/whci) to the uwb dev list */
 311 void
 312 uwba_dev_add_to_list(uwba_dev_t *uwba_dev)
 313 {
 314         mutex_enter(&uwba_mutex);
 315         uwba_log(uwba_dev, UWBA_LOG_DEBUG,
 316             "add uwba_dev = %x", uwba_dev);
 317         list_insert_tail(&uwba_dev_list, uwba_dev);
 318         mutex_exit(&uwba_mutex);
 319 }
 320 
 321 /* Remove a uwb device (hwarc/whci) from the uwb dev list */
 322 void
 323 uwba_dev_rm_from_list(uwba_dev_t *uwba_dev)
 324 {
 325         mutex_enter(&uwba_mutex);
 326         if (list_is_empty(&uwba_dev_list)) {
 327                 mutex_exit(&uwba_mutex);
 328 
 329                 return;
 330         }
 331 
 332         uwba_log(uwba_dev, UWBA_LOG_DEBUG,
 333             "remove uwba_dev = %x", uwba_dev);
 334 
 335         list_remove(&uwba_dev_list, uwba_dev);
 336         mutex_exit(&uwba_mutex);
 337 }
 338 
 339 /* Init context bitset for a radio device (hwarc/whci) */
 340 void
 341 uwba_init_ctxt_id(uwba_dev_t *uwba_dev)
 342 {
 343         bitset_init(&uwba_dev->ctxt_bits); /* this bzero sizeof(bitset_t) */
 344         bitset_resize(&uwba_dev->ctxt_bits, 256); /* alloc mem */
 345         bitset_add(&uwba_dev->ctxt_bits, 0);
 346         bitset_add(&uwba_dev->ctxt_bits, 255);
 347 }
 348 
 349 /* Free context bitset for a radio device (hwarc/whci) */
 350 void
 351 uwba_fini_ctxt_id(uwba_dev_t *uwba_dev)
 352 {
 353         /* bitset_fini will free the mem allocated by bitset_resize. */
 354         bitset_fini(&uwba_dev->ctxt_bits);
 355 }
 356 
 357 /* Get a free context id from bitset */
 358 uint8_t
 359 uwba_get_ctxt_id(uwba_dev_t *uwba_dev)
 360 {
 361         uint8_t ctxt_id;
 362 
 363         /* if reaches the top, turn around */
 364         if (uwba_dev->ctxt_id >= UWB_CTXT_ID_TOP) {
 365                 uwba_dev->ctxt_id = UWB_CTXT_ID_BOTTOM -1;
 366         }
 367         ctxt_id = uwba_dev->ctxt_id;
 368 
 369         /* Search ctxt_id+1  to UWB_CTXT_ID_UNVALID */
 370         do {
 371                 ctxt_id++;
 372 
 373                 /* test bit and returen if it is not set */
 374                 if (!bitset_in_set(&uwba_dev->ctxt_bits, ctxt_id)) {
 375                         bitset_add(&uwba_dev->ctxt_bits, ctxt_id);
 376                         uwba_dev->ctxt_id = ctxt_id;
 377 
 378                         return (ctxt_id);
 379                 }
 380 
 381         } while (ctxt_id < UWB_CTXT_ID_UNVALID);
 382 
 383         /* Search 1  to ctxt_id */
 384         if (uwba_dev->ctxt_id != 0) {
 385                 ctxt_id = UWB_CTXT_ID_BOTTOM;
 386                 do {
 387                         ctxt_id++;
 388 
 389                         /* test bit and returen if it is not set */
 390                         if (!bitset_in_set(&uwba_dev->ctxt_bits, ctxt_id)) {
 391                                 bitset_add(&uwba_dev->ctxt_bits, ctxt_id);
 392                                 uwba_dev->ctxt_id = ctxt_id;
 393 
 394                                 return (ctxt_id);
 395                         }
 396                 } while (ctxt_id < uwba_dev->ctxt_id);
 397         }
 398 
 399         /* All ids are in use, just force to re-use one. */
 400         uwba_dev->ctxt_id++;
 401 
 402         return (uwba_dev->ctxt_id);
 403 }
 404 
 405 /* Reset the bit (offset at ctxt_id) to zero */
 406 void
 407 uwba_free_ctxt_id(uwba_dev_t *dev, uint8_t      ctxt_id)
 408 {
 409         bitset_del(&dev->ctxt_bits, ctxt_id);
 410 
 411 }
 412 
 413 /* Fill the rccb to ctrl req's data block */
 414 void
 415 uwba_fill_rccb_head(uwba_dev_t *uwba_dev, uint16_t cmd, mblk_t *data)
 416 {
 417         data->b_rptr[0] = UWB_CE_TYPE_GENERAL;
 418         UINT16_TO_LE(cmd, 1, data->b_rptr);
 419         data->b_rptr[3] = uwba_get_ctxt_id(uwba_dev);
 420         uwba_log(uwba_dev, UWBA_LOG_DEBUG,
 421             "the new ctxt_id is %d", data->b_rptr[3]);
 422 }
 423 
 424 /*
 425  * Allocate uwb_dev_t for a radio controller device. Arg rcd_intr_pri is the
 426  * interrupt priority of the interrupt handler of the radio controller driver.
 427  * If there is no interrupt handler in the driver, then pass 0 to this arg.
 428  */
 429 void
 430 uwba_alloc_uwb_dev(dev_info_t *dip, uwba_dev_t **uwba_dev, uint_t rcd_intr_pri)
 431 {
 432         char    *devinst;
 433         int     devinstlen;
 434         int     instance = ddi_get_instance(dip);
 435 
 436         *uwba_dev = (uwba_dev_t *)kmem_zalloc(sizeof (uwba_dev_t), KM_SLEEP);
 437 
 438         /*
 439          * HWA radio controller will not call uwb_* functions in interrupt
 440          * level, while WHCI radio controller will.
 441          */
 442         if (rcd_intr_pri == 0) {
 443                 mutex_init(&(*uwba_dev)->dev_mutex, NULL, MUTEX_DRIVER, NULL);
 444         } else {
 445                 mutex_init(&(*uwba_dev)->dev_mutex, NULL, MUTEX_DRIVER,
 446                     DDI_INTR_PRI(rcd_intr_pri));
 447         }
 448         mutex_enter(&(*uwba_dev)->dev_mutex);
 449 
 450         (*uwba_dev)->dip = dip;
 451         (*uwba_dev)->dev_state = UWB_STATE_IDLE;
 452 
 453         /* create a string for driver name and instance number */
 454         devinst = kmem_zalloc(UWB_MAXSTRINGLEN, KM_SLEEP);
 455         devinstlen = snprintf(devinst, UWB_MAXSTRINGLEN, "%s%d: ",
 456             ddi_driver_name(dip), instance);
 457         (*uwba_dev)->devinst = kmem_zalloc(devinstlen + 1, KM_SLEEP);
 458         (void) strncpy((*uwba_dev)->devinst, devinst, devinstlen);
 459         kmem_free(devinst, UWB_MAXSTRINGLEN);
 460 
 461         /* list to cache the notifications from radio controller device */
 462         list_create(&(*uwba_dev)->notif_list, sizeof (uwb_notif_wrapper_t),
 463             offsetof(uwb_notif_wrapper_t, notif_node));
 464         (*uwba_dev)->notif_cnt = 0;
 465 
 466         /* list to record the client devices according to beacons received */
 467         list_create(&(*uwba_dev)->client_dev_list, sizeof (uwba_client_dev_t),
 468             offsetof(uwba_client_dev_t, dev_node));
 469         (*uwba_dev)->client_dev_cnt = 0;
 470 
 471         cv_init(&(*uwba_dev)->cmd_result_cv, NULL, CV_DRIVER, NULL);
 472         cv_init(&(*uwba_dev)->cmd_handler_cv, NULL, CV_DRIVER, NULL);
 473 
 474         mutex_exit(&(*uwba_dev)->dev_mutex);
 475 
 476 }
 477 
 478 /* Free a uwb dev for a radio device (hwarc/whci) */
 479 void
 480 uwba_free_uwb_dev(uwba_dev_t *uwba_dev)
 481 {
 482         uwb_notif_wrapper_t *nw;
 483 
 484         mutex_enter(&(uwba_dev)->dev_mutex);
 485         cv_destroy(&uwba_dev->cmd_result_cv);
 486         cv_destroy(&uwba_dev->cmd_handler_cv);
 487 
 488         /*
 489          * remove all the notifications in this device's list, and then destroy
 490          * the list
 491          */
 492         while (!list_is_empty(&uwba_dev->notif_list)) {
 493 
 494                 nw = list_head(&uwba_dev->notif_list);
 495                 if (nw != NULL) {
 496                         list_remove(&(uwba_dev->notif_list), nw);
 497                 } else {
 498                         break;
 499                 }
 500 
 501                 /* Free notification struct */
 502                 if (nw->notif) {
 503                         kmem_free(nw->notif, nw->length);
 504                 }
 505                 kmem_free(nw, sizeof (uwb_notif_wrapper_t));
 506         }
 507         uwba_dev->notif_cnt = 0;
 508         list_destroy(&uwba_dev->notif_list);
 509 
 510         uwba_remove_cdev_list(uwba_dev);
 511         if (uwba_dev->devinst != NULL) {
 512                 kmem_free(uwba_dev->devinst,
 513                     strlen(uwba_dev->devinst) + 1);
 514         }
 515         mutex_exit(&(uwba_dev)->dev_mutex);
 516 
 517         /* Destroy mutex and dev structure */
 518         mutex_destroy(&uwba_dev->dev_mutex);
 519         kmem_free(uwba_dev, sizeof (uwba_dev_t));
 520 }
 521 
 522 
 523 /* Get a event or notification code from the data stream */
 524 uint16_t
 525 uwba_get_evt_code(uint8_t *data, int data_len)
 526 {
 527         uint16_t        evt_code;
 528 
 529         /*
 530          * UWB_RAW_RESULT_CODE_SIZE is the minimum size for any events or
 531          * notifications.
 532          */
 533         if (data_len < UWB_RAW_RESULT_CODE_SIZE) {
 534 
 535                 uwba_log(NULL, UWBA_LOG_LOG,
 536                     "uwba_get_evt_code: invalid data_len=%d",
 537                     data_len);
 538                 return (UWB_INVALID_EVT_CODE);
 539         }
 540 
 541         LE_TO_UINT16(data, UWB_RAW_WEVENT_OFFSET, evt_code);
 542 
 543         /* if out of range */
 544         if (evt_code > UWB_CE_SET_ASIE_NOTIFICATION) {
 545                 uwba_log(NULL, UWBA_LOG_LOG,
 546                     "uwba_get_evt_code: invalid evt_code=%d",
 547                     evt_code);
 548                 return (UWB_INVALID_EVT_CODE);
 549         }
 550 
 551         /* if fall into the reserved range */
 552         if (evt_code >= UWB_NOTIF_RESERVED &&
 553             evt_code < UWB_CE_CHANNEL_CHANGE) {
 554                 uwba_log(NULL, UWBA_LOG_LOG,
 555                     "uwba_get_evt_code: reserved evt_code=%d", evt_code);
 556 
 557                 return (UWB_INVALID_EVT_CODE);
 558         }
 559 
 560         return (evt_code);
 561 }
 562 
 563 /* Get the size of notif/evt struct */
 564 uint16_t
 565 uwba_get_evt_size(uint8_t *data, int data_len, uint16_t evt_code)
 566 {
 567         uint16_t        buf_len_off, buf_len, evt_size;
 568 
 569         evt_size = uwba_evt_size_table[evt_code].struct_len;
 570         buf_len_off = uwba_evt_size_table[evt_code].buf_len_offset;
 571 
 572         /* If the offset of the variable data length is out of range. */
 573         if (buf_len_off >= data_len) {
 574 
 575                 return (UWB_INVALID_EVT_SIZE);
 576         }
 577 
 578         /* If this event has variable length data, add up the length. */
 579         if (buf_len_off) {
 580                 LE_TO_UINT16(data, buf_len_off, buf_len);
 581 
 582                 /* in case buf_len is not a reasonable value. */
 583                 if ((buf_len_off + 2 + buf_len) > data_len) {
 584                         uwba_log(NULL, UWBA_LOG_DEBUG,
 585                             "uwba_get_evt_size: data_len=%d, buf_len_off=%d,"
 586                             " buf_len=%d", data_len, buf_len_off, buf_len);
 587 
 588                         return (UWB_INVALID_EVT_SIZE);
 589                 }
 590 
 591                 /*
 592                  * after add up, the evt size may be a couple of bytes greater
 593                  * (depends on the structure alignment) than we actually need,
 594                  * but it does not matter.
 595                  */
 596                 evt_size += buf_len;
 597         }
 598 
 599         /*
 600          * TODO: check if data_len is less than expected raw event data, for the
 601          * fixed length events/notifs.
 602          */
 603 
 604         return (evt_size);
 605 }
 606 
 607 /*
 608  * hook the new event to uwb device handle, replace the old one if there is.
 609  * Signal the cmd thread which is waiting this cmd result.
 610  */
 611 void
 612 uwba_put_cmd_result(uwba_dev_t *uwba_dev, void *evt_struct,
 613         uint16_t  evt_size)
 614 {
 615         uwb_cmd_result_t *cmd_rlt = (uwb_cmd_result_t *)evt_struct;
 616 
 617         mutex_enter(&uwba_dev->dev_mutex);
 618         if (uwba_dev->cmd_result_wrap.cmd_result) {
 619                 uwba_log(uwba_dev, UWBA_LOG_LOG,
 620                     "previous command result not processed "
 621                     "bEventType = %d, wEvent = %d, ctxt_id = %d",
 622                     uwba_dev->cmd_result_wrap.cmd_result->rceb.bEventType,
 623                     uwba_dev->cmd_result_wrap.cmd_result->rceb.wEvent,
 624                     uwba_dev->cmd_result_wrap.cmd_result->rceb.bEventContext);
 625 
 626                 kmem_free(uwba_dev->cmd_result_wrap.cmd_result,
 627                     uwba_dev->cmd_result_wrap.length);
 628         }
 629 
 630         uwba_log(uwba_dev, UWBA_LOG_DEBUG,
 631             "uwba_put_cmd_result: wEvent= %d, msg= %s",
 632             cmd_rlt->rceb.wEvent, uwba_event_msg(cmd_rlt->rceb.wEvent));
 633         uwba_dev->cmd_result_wrap.length = evt_size;
 634         uwba_dev->cmd_result_wrap.cmd_result = cmd_rlt;
 635         if (cmd_rlt->rceb.bEventContext == uwba_dev->ctxt_id) {
 636                 cv_signal(&uwba_dev->cmd_result_cv);
 637         } else {
 638                 uwba_log(uwba_dev, UWBA_LOG_LOG,
 639                     "the cmd result ctxt_id %d is not matching the"
 640                     "current cmd ctxt_id %d",
 641                     cmd_rlt->rceb.bEventContext, uwba_dev->ctxt_id);
 642         }
 643         mutex_exit(&uwba_dev->dev_mutex);
 644 }
 645 
 646 /* add the notification to the tail of uwba_dev->notif_list */
 647 int
 648 uwba_add_notif_to_list(uwba_dev_t *uwba_dev, void *evt_struct,
 649         uint16_t  evt_size)
 650 {
 651         uwb_notif_wrapper_t *nw, *ow;
 652 
 653         nw = (uwb_notif_wrapper_t *)kmem_alloc(sizeof (uwb_notif_wrapper_t),
 654             KM_NOSLEEP);
 655         if (nw == NULL) {
 656                 uwba_log(uwba_dev, UWBA_LOG_LOG,
 657                     "uwba_add_notif_to_list: allocate notif wrapper failed");
 658 
 659                 return (UWB_NO_RESOURCES);
 660         }
 661         nw->length = evt_size;
 662         nw->notif = (uwb_rceb_notif_t *)evt_struct;
 663 
 664         mutex_enter(&uwba_dev->dev_mutex);
 665 
 666         list_insert_tail(&uwba_dev->notif_list, nw);
 667         uwba_dev->notif_cnt++;
 668 
 669         if (uwba_dev->notif_cnt >= UWB_MAX_NOTIF_NUMBER) {
 670                 /* remove oldest one */
 671                 ow = list_head(&uwba_dev->notif_list);
 672                 list_remove(&uwba_dev->notif_list, ow);
 673                 uwba_dev->notif_cnt--;
 674 
 675                 /* Free it */
 676                 if (ow->notif) {
 677                         kmem_free(ow->notif, ow->length);
 678                 }
 679                 kmem_free(ow, sizeof (uwb_notif_wrapper_t));
 680         }
 681 
 682         uwba_log(uwba_dev, UWBA_LOG_DEBUG,
 683             "uwba_add_notif_to_list: notification code=%d, notif_cnt=%d",
 684             nw->notif->rceb.wEvent, uwba_dev->notif_cnt);
 685 
 686         mutex_exit(&uwba_dev->dev_mutex);
 687 
 688         return (UWB_SUCCESS);
 689 }
 690 
 691 /*
 692  * find the specific client device in the client_dev_list by comparing the MAC
 693  * address
 694  */
 695 uwba_client_dev_t *
 696 uwba_find_cdev_by_mac(uwba_dev_t *uwba_dev, uwb_mac_addr_t *mac)
 697 {
 698         uwba_client_dev_t *cdev = NULL;
 699 
 700         cdev = list_head(&uwba_dev->client_dev_list);
 701         while (cdev != NULL) {
 702                 if (memcmp(mac, cdev->beacon_frame.Device_Identifier.addr,
 703                     sizeof (uwb_mac_addr_t)) == 0) {
 704 
 705                         return (cdev);
 706                 }
 707                 cdev = list_next(&uwba_dev->client_dev_list, cdev);
 708         }
 709 
 710         return (cdev);
 711 }
 712 /* find the client device beconing in a specific channel */
 713 uwba_client_dev_t *
 714 uwba_find_cdev_by_channel(uwba_dev_t *uwba_dev, uint8_t channel)
 715 {
 716         uwba_client_dev_t *cdev = NULL;
 717 
 718         cdev = list_head(&uwba_dev->client_dev_list);
 719         while (cdev != NULL) {
 720                 if (cdev->bChannelNumber == channel) {
 721 
 722                         return (cdev);
 723                 }
 724                 cdev = list_next(&uwba_dev->client_dev_list, cdev);
 725         }
 726 
 727         return (cdev);
 728 }
 729 
 730 /* remove all cdev list for uwb dev */
 731 static void
 732 uwba_remove_cdev_list(uwba_dev_t *uwba_dev)
 733 {
 734         uwba_client_dev_t *cdev = NULL;
 735 
 736         while (!list_is_empty(&uwba_dev->client_dev_list)) {
 737 
 738                 cdev = list_head(&uwba_dev->client_dev_list);
 739                 if (cdev != NULL) {
 740 
 741                         list_remove(&(uwba_dev->client_dev_list), cdev);
 742                 } else {
 743 
 744                         break;
 745                 }
 746 
 747                 kmem_free(cdev, sizeof (uwba_client_dev_t));
 748         }
 749 }
 750 
 751 /* add a client radio device to the tail of uwba_dev->client_dev_list */
 752 int
 753 uwba_add_cdev_to_list(uwba_dev_t *uwba_dev, uwb_beacon_frame_t *bc_frm)
 754 {
 755         uwb_mac_addr_t  *mac;
 756         uwba_client_dev_t *cdev;
 757         int rval = UWB_SUCCESS;
 758 
 759         mutex_enter(&uwba_dev->dev_mutex);
 760 
 761         if (uwba_dev->client_dev_cnt >= UWB_MAX_CDEV_NUMBER) {
 762                 uwba_log(uwba_dev, UWBA_LOG_LOG,
 763                     "uwba_add_cdev_to_list: can not add this dev,"
 764                     "client dev number reached max,  client_dev_cnt=%d",
 765                     uwba_dev->client_dev_cnt);
 766                 rval = UWB_FAILURE;
 767                 goto done;
 768         }
 769 
 770         mac = &bc_frm->Device_Identifier;
 771         if (uwba_find_cdev_by_mac(uwba_dev, mac) != NULL) {
 772                 uwba_log(uwba_dev, UWBA_LOG_DEBUG,
 773                     "uwba_add_cdev_to_list: this client dev is added before");
 774 
 775                 rval = UWB_SUCCESS;
 776                 goto done;
 777         }
 778         cdev = (uwba_client_dev_t *)kmem_alloc(sizeof (uwba_client_dev_t),
 779             KM_NOSLEEP);
 780         if (cdev == NULL) {
 781                 uwba_log(uwba_dev, UWBA_LOG_LOG,
 782                     "uwba_add_client_device: allocate "
 783                     "uwba_client_dev_t failed");
 784 
 785                 rval = UWB_NO_RESOURCES;
 786                 goto done;
 787         }
 788         (void) memcpy(&cdev->beacon_frame, bc_frm, sizeof (uwb_beacon_frame_t));
 789 
 790         list_insert_tail(&uwba_dev->client_dev_list, cdev);
 791         uwba_dev->client_dev_cnt++;
 792 
 793         uwba_log(uwba_dev, UWBA_LOG_DEBUG,
 794             "uwba_add_cdev_to_list: a new client dev added. MAC: "
 795             "%x %x %x %x %x %x, client_dev_cnt=%d",
 796             cdev->beacon_frame.Device_Identifier.addr[0],
 797             cdev->beacon_frame.Device_Identifier.addr[1],
 798             cdev->beacon_frame.Device_Identifier.addr[2],
 799             cdev->beacon_frame.Device_Identifier.addr[3],
 800             cdev->beacon_frame.Device_Identifier.addr[4],
 801             cdev->beacon_frame.Device_Identifier.addr[5],
 802             uwba_dev->client_dev_cnt);
 803 done:
 804 
 805         mutex_exit(&uwba_dev->dev_mutex);
 806 
 807         return (rval);
 808 }
 809 
 810 /*
 811  * Return the actual parsed raw data length. Stop parse if datalen or structlen
 812  * is out of range, and then return UWB_PARSE_ERROR.
 813  */
 814 int
 815 uwba_parse_data(char    *format,
 816         uchar_t         *data,
 817         size_t          datalen,
 818         void            *structure,
 819         size_t          structlen)
 820 {
 821         int     fmt;
 822         int     counter = 1;
 823         int     multiplier = 0;
 824         uchar_t *datastart = data;
 825         uchar_t *dataend = data + datalen;
 826         void    *structend = (void *)((intptr_t)structure + structlen);
 827 
 828         if ((format == NULL) || (data == NULL) || (structure == NULL)) {
 829 
 830                 return (UWB_PARSE_ERROR);
 831         }
 832 
 833         while ((fmt = *format) != '\0') {
 834 
 835                 /*
 836                  * Could some one pass a "format" that is greater than
 837                  * the structlen? Conversely, one could pass a ret_buf_len
 838                  * that is less than the "format" length.
 839                  * If so, we need to protect against writing over memory.
 840                  */
 841                 if (counter++ > structlen) {
 842                         return (UWB_PARSE_ERROR);
 843                 }
 844 
 845                 if (fmt == 'c') {
 846                         uint8_t *cp = (uint8_t *)structure;
 847 
 848                         cp = (uint8_t *)(((uintptr_t)cp + _CHAR_ALIGNMENT - 1) &
 849                             ~(_CHAR_ALIGNMENT - 1));
 850 
 851                         /*
 852                          * If data or structure is out of range, stop parse.
 853                          */
 854                         if (((data + 1) > dataend) ||
 855                             ((cp + 1) > (uint8_t *)structend))
 856                                 return (UWB_PARSE_ERROR);
 857 
 858                         *cp++ = *data++;
 859                         structure = (void *)cp;
 860                         if (multiplier) {
 861                                 multiplier--;
 862                         }
 863                         if (multiplier == 0) {
 864                                 format++;
 865                         }
 866                 } else if (fmt == 's') {
 867                         uint16_t        *sp = (uint16_t *)structure;
 868 
 869                         sp = (uint16_t *)
 870                             (((uintptr_t)sp + _SHORT_ALIGNMENT - 1) &
 871                             ~(_SHORT_ALIGNMENT - 1));
 872                         if (((data + 2) > dataend) ||
 873                             ((sp + 1) > (uint16_t *)structend))
 874                                 return (UWB_PARSE_ERROR);
 875 
 876                         *sp++ = (data[1] << 8) + data[0];
 877                         data += 2;
 878                         structure = (void *)sp;
 879                         if (multiplier) {
 880                                 multiplier--;
 881                         }
 882                         if (multiplier == 0) {
 883                                 format++;
 884                         }
 885                 } else if (isdigit(fmt)) {
 886                         multiplier = (multiplier * 10) + (fmt - '0');
 887                         format++;
 888                         counter--;
 889                 } else {
 890                         multiplier = 0;
 891 
 892                         return (UWB_PARSE_ERROR);
 893                 }
 894         }
 895 
 896         return ((intptr_t)data - (intptr_t)datastart);
 897 }
 898 
 899 
 900 /*
 901  * parse rceb, check if the context id is in the reasonable range (0x0 - 0xfe).
 902  * If success, return the offset just after the rceb struct.
 903  */
 904 int
 905 uwba_parse_rceb(uint8_t *data,
 906         size_t          datalen,
 907         void            *structure,
 908         size_t          structlen)
 909 {
 910         int parsed_len;
 911         uwb_rceb_head_t *rceb;
 912 
 913         parsed_len = uwba_parse_data("csc", data, datalen,
 914             structure, structlen);
 915         if (parsed_len  == UWB_PARSE_ERROR) {
 916 
 917                 return (UWB_PARSE_ERROR);
 918         }
 919         rceb = (uwb_rceb_head_t *)structure;
 920         if (rceb->bEventContext > UWB_CTXT_ID_TOP) {
 921 
 922                 return (UWB_PARSE_ERROR);
 923         }
 924 
 925         return (parsed_len);
 926 }
 927 
 928 int
 929 uwba_parse_dev_addr_mgmt(uint8_t *spec_data, int spec_data_len,
 930     uwb_rceb_dev_addr_mgmt_t *evt_struct)
 931 {
 932         /* 6 bytes for address, 1 for result code. */
 933         if (uwba_parse_data("7c", spec_data,
 934             spec_data_len, evt_struct->baAddr, 7) == UWB_PARSE_ERROR) {
 935 
 936                 return (UWB_PARSE_ERROR);
 937         }
 938 
 939         return (UWB_SUCCESS);
 940 }
 941 
 942 /* Parse UWB IEs that got by get_ie radio controller command */
 943 int
 944 uwba_parse_get_ie(uwb_dev_handle_t uwb_dev_hdl, uint8_t *spec_data,
 945         int spec_data_len, uwb_rceb_get_ie_t *evt_struct)
 946 {
 947         int i;
 948         uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
 949 
 950         /* At least, it should have wIELength. */
 951         if (spec_data_len < 2) {
 952 
 953                 return (UWB_PARSE_ERROR);
 954         }
 955         LE_TO_UINT16(spec_data, 0, evt_struct->wIELength);
 956 
 957         /*
 958          * Except wIELength, it should have the number of bytes of indicated by
 959          * wIELength.
 960          */
 961         if (spec_data_len < (evt_struct->wIELength + 2)) {
 962 
 963                 return (UWB_PARSE_ERROR);
 964         }
 965 
 966         /*
 967          * Proper memory for evt_struct is already allocated for evt_struct in
 968          * uwb_parse_evt_notif()
 969          */
 970         bcopy(spec_data + 2, evt_struct->IEData, evt_struct->wIELength);
 971 
 972         uwba_log(uwba_dev, UWBA_LOG_DEBUG,
 973             "uwba_parse_get_ie: wIELength=%d", evt_struct->wIELength);
 974 
 975         for (i = 0; i < evt_struct->wIELength; i++) {
 976                 uwba_log(uwba_dev, UWBA_LOG_DEBUG,
 977                     "0x%x ", evt_struct->IEData[i]);
 978         }
 979 
 980         /* Todo: continue to parse other IE Data? */
 981         uwba_get_phy_cap(uwb_dev_hdl, evt_struct->IEData,
 982             evt_struct->wIELength);
 983         uwba_list_phy_rates(uwb_dev_hdl);
 984         uwba_list_phy_bandgroups(uwb_dev_hdl);
 985 
 986         return (UWB_SUCCESS);
 987 }
 988 
 989 
 990 /*
 991  * Parse the beacon frame and add the client radio device to the dev_list in
 992  * uwb_dev_handle
 993  */
 994 void
 995 uwba_parse_beacon_info(uwba_dev_t *uwba_dev, uint8_t *bc_info)
 996 {
 997         uwb_beacon_frame_t *bc_frm;
 998 
 999         bc_frm = (uwb_beacon_frame_t *)bc_info;
1000 
1001         /*
1002          * add the uwb device to list if it is a newly found device according to
1003          * its MAC addr in the beacon
1004          */
1005         if (uwba_add_cdev_to_list(uwba_dev, bc_frm) == UWB_SUCCESS) {
1006 
1007                 /* TODO: log messages */
1008 
1009                 return;
1010         }
1011 }
1012 
1013 int
1014 uwba_parse_bpoie_chg(uwb_dev_handle_t uwb_dev_hdl,
1015         uint8_t *spec_data, int spec_data_len,
1016         uwb_rceb_bpoie_change_t *evt_struct) {
1017         int parsed_len;
1018         uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1019         parsed_len = uwba_parse_data("s", spec_data,
1020             spec_data_len, &(evt_struct->wBPOIELength), 2);
1021 
1022         if (parsed_len  == UWB_PARSE_ERROR) {
1023                 uwba_log(uwba_dev, UWBA_LOG_LOG,
1024                     "uwba_parse_bpoie_chg: parse error, parsed_len=%d",
1025                     parsed_len);
1026 
1027                 return (UWB_PARSE_ERROR);
1028         }
1029         /* Todo: not supported now */
1030         return (UWB_SUCCESS);
1031 }
1032 /* Parse the beacon_receive notif */
1033 int
1034 uwba_parse_beacon_rcv(uwb_dev_handle_t uwb_dev_hdl,
1035         uint8_t *spec_data, int spec_data_len,
1036         uwb_rceb_beacon_t *evt_struct)
1037 {
1038         int parsed_len;
1039         uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1040         uwb_beacon_frame_t *bc_frm = NULL;
1041         uwba_client_dev_t *client_dev = NULL;
1042 
1043         /* parse the elements except BeaconInfo */
1044         parsed_len = uwba_parse_data("ccsccs", spec_data,
1045             spec_data_len, &(evt_struct->bChannelNumber), 8);
1046         if (parsed_len  == UWB_PARSE_ERROR) {
1047                 uwba_log(uwba_dev, UWBA_LOG_LOG,
1048                     "uwba_parse_beacon_rcv: parse error, parsed_len=%d",
1049                     parsed_len);
1050 
1051                 return (UWB_PARSE_ERROR);
1052         }
1053 
1054         /*
1055          * Except the elements before BeaconInfo, it should have the number of
1056          * bytes of indicated by wBeaconInfoLength.
1057          */
1058         if ((spec_data_len -UWB_BEACONINFO_OFFSET) <
1059             evt_struct->wBeaconInfoLength) {
1060                 uwba_log(uwba_dev, UWBA_LOG_LOG,
1061                     "uwba_parse_beacon_rcv: parse error: spec_data_len=%d,"
1062                     "evt_struct->wBeaconInfoLength=%d, bc_info_offset=%d",
1063                     spec_data_len, evt_struct->wBeaconInfoLength,
1064                     UWB_BEACONINFO_OFFSET);
1065 
1066                 return (UWB_PARSE_ERROR);
1067         }
1068         if (evt_struct->wBeaconInfoLength < sizeof (uwb_beacon_frame_t)) {
1069                 uwba_log(uwba_dev, UWBA_LOG_LOG,
1070                     "uwba_parse_beacon_rcv: too small size, "
1071                     "wBeaconInfoLength=%d, data[0]=%d, data[1]=%d, data[4]=%d,"
1072                     " data[5]=%d, data[6]=%d, data[7]=%d, spec_data_len=%d",
1073                     evt_struct->wBeaconInfoLength, spec_data[0], spec_data[1],
1074                     spec_data[4], spec_data[5], spec_data[6], spec_data[7],
1075                     spec_data_len);
1076 
1077                 return (UWB_PARSE_ERROR);
1078         }
1079         uwba_log(uwba_dev, UWBA_LOG_DEBUG, "uwba_parse_beacon_rcv:"
1080             "bChannelNumber = %d bBeaconType = %d "
1081             "wBPSTOffset = %d bLQI = %d bRSSI = %d "
1082             "wBeaconInfoLength = %d",
1083             evt_struct->bChannelNumber, evt_struct->bBeaconType,
1084             evt_struct->wBPSTOffset, evt_struct->bLQI, evt_struct->bRSSI,
1085             evt_struct->wBeaconInfoLength);
1086 
1087         /*
1088          * Proper memory for evt_struct is already allocated for evt_struct in
1089          * uwb_parse_evt_notif()
1090          */
1091         bcopy(spec_data + UWB_BEACONINFO_OFFSET,
1092             evt_struct->BeaconInfo, evt_struct->wBeaconInfoLength);
1093 
1094         /*
1095          * Parse the beacon frame and add the client radio device
1096          * to the dev_list in uwb_dev_handle
1097          */
1098         uwba_parse_beacon_info(uwba_dev, evt_struct->BeaconInfo);
1099 
1100         bc_frm = (uwb_beacon_frame_t *)evt_struct->BeaconInfo;
1101 
1102         client_dev = uwba_find_cdev_by_mac(uwba_dev,
1103             &(bc_frm->Device_Identifier));
1104 
1105         /* Update the client device's beconing information */
1106         client_dev->bChannelNumber = evt_struct->bChannelNumber;
1107         client_dev->bBeaconType = evt_struct->bBeaconType;
1108         client_dev->wBPSTOffset = evt_struct->wBPSTOffset;
1109         return (UWB_SUCCESS);
1110 }
1111 
1112 
1113 /*
1114  * find the phy capability ie from ie_data, then save the capability bitmap to
1115  * uwb_dev_hdl
1116  */
1117 static void
1118 uwba_get_phy_cap(uwb_dev_handle_t uwb_dev_hdl,
1119     uint8_t *ie_data, uint16_t ie_len)
1120 {
1121         uint8_t *phy_ie;
1122 
1123         /* traverse ie_data to find PHY Capabilities IE */
1124         phy_ie = uwba_find_ie(uwb_dev_hdl,
1125             UWB_IE_PHY_CAP, ie_data, ie_len);
1126 
1127         if (phy_ie == NULL) {
1128 
1129                 return;
1130         }
1131         /* copy the phy capabilities bitmap to uwba_dev->phy_cap_bm */
1132         uwba_save_phy_cap_bm(uwb_dev_hdl, phy_ie);
1133 }
1134 
1135 /* Copy the PHY capability bitmap from phy_ie to uwb device handle */
1136 static void
1137 uwba_save_phy_cap_bm(uwb_dev_handle_t uwb_dev_hdl, uint8_t *phy_ie)
1138 {
1139         uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1140 
1141         mutex_enter(&uwba_dev->dev_mutex);
1142         uwba_dev->phy_cap_bm = 0;
1143 
1144         uwba_dev->phy_cap_bm = phy_ie[4];
1145         uwba_dev->phy_cap_bm = phy_ie[3] | uwba_dev->phy_cap_bm << 8;
1146         uwba_dev->phy_cap_bm = phy_ie[2] | uwba_dev->phy_cap_bm << 8;
1147         mutex_exit(&uwba_dev->dev_mutex);
1148 }
1149 
1150 /* List all supported PHY data rates by checking the PHY capability bitmap */
1151 static void
1152 uwba_list_phy_rates(uwb_dev_handle_t uwb_dev_hdl)
1153 {
1154         uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1155         int i;
1156         const char *uwb_phy_rate_table[] = {
1157                 [UWB_RATE_OFFSET_53 - UWB_RATE_OFFSET_BASE] = "53.3",
1158                 [UWB_RATE_OFFSET_80 - UWB_RATE_OFFSET_BASE] = "80",
1159                 [UWB_RATE_OFFSET_106 - UWB_RATE_OFFSET_BASE] = "106.7",
1160                 [UWB_RATE_OFFSET_160 - UWB_RATE_OFFSET_BASE] = "160",
1161                 [UWB_RATE_OFFSET_200 - UWB_RATE_OFFSET_BASE] = "200",
1162                 [UWB_RATE_OFFSET_320 - UWB_RATE_OFFSET_BASE] = "320",
1163                 [UWB_RATE_OFFSET_400 - UWB_RATE_OFFSET_BASE] = "400",
1164                 [UWB_RATE_OFFSET_480 - UWB_RATE_OFFSET_BASE] = "480",
1165         };
1166 
1167         for (i = UWB_RATE_OFFSET_BASE; i <= UWB_RATE_OFFSET_480; i++) {
1168                 if (BT_TEST(&uwba_dev->phy_cap_bm, i)) {
1169                         uwba_log(uwba_dev, UWBA_LOG_DEBUG,
1170                             "uwba_list_phy_rates: Rate supported=%s",
1171                             uwb_phy_rate_table[i - UWB_RATE_OFFSET_BASE]);
1172                 }
1173         }
1174         uwba_log(uwba_dev, UWBA_LOG_DEBUG,
1175             "uwba_list_phy_rates: phy_cap_bm=%u",
1176             uwba_dev->phy_cap_bm);
1177 }
1178 
1179 /* List all supported PHY band groups by checking the PHY capability bitmap */
1180 static void
1181 uwba_list_phy_bandgroups(uwb_dev_handle_t uwb_dev_hdl)
1182 {
1183         uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1184         int i;
1185 
1186         /* group 1 to 4 [ECMA, Table 112] */
1187         for (i = 0; i <= 7; i++) {
1188                 if (BT_TEST(&uwba_dev->phy_cap_bm, i)) {
1189                         uwba_log(uwba_dev, UWBA_LOG_DEBUG,
1190                             "uwba_list_phy_bandgroups: band groups "
1191                             "supported=%d", i);
1192                 }
1193         }
1194 
1195         /* group 5 [ECMA, Table 112] */
1196         if (BT_TEST(&uwba_dev->phy_cap_bm, 9)) {
1197                 uwba_log(uwba_dev, UWBA_LOG_DEBUG,
1198                     "uwba_list_phy_bandgroups: band groups supported=%d", i);
1199         }
1200 }
1201 
1202 
1203 
1204 /*
1205  * Allocate a channel for the HC. Scan every channel supported,
1206  * if beacon information from the channel received, scan the next
1207  * channel, or else, stop.
1208  * Return:
1209  *      first channel with no beacon recieved
1210  *      last channel if every channel is busy
1211  *      0 if scan failure
1212  * uwba_channel_table is used to decode the PHY capability IE.
1213  * The array index is the bit in the PHY IE. base is the first
1214  * TFC code.offset is the length from the first TFC code.
1215  * Refer to:
1216  * [ECM-368]. CHAP 11.2. Table 25-30.
1217  * [ECM-368]. CHAP 16.8.16. Table 112
1218  *
1219  */
1220 uint8_t
1221 uwba_allocate_channel(uwb_dev_handle_t uwb_dev_hdl) {
1222         uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1223         int i, j;
1224         uwba_channel_range_t uwba_channel_table[] = {
1225                 { .base =  9, .offset = 4 }, /* Band group 1 TFI */
1226                 { .base = 13, .offset = 3 }, /* Band group 1 FFI */
1227                 { .base = 17, .offset = 4 }, /* Band group 2 TFI */
1228                 { .base = 21, .offset = 3 }, /* Band group 2 FFI */
1229                 { .base = 25, .offset = 4 }, /* Band group 3 TFI */
1230                 { .base = 29, .offset = 3 }, /* Band group 3 FFI */
1231                 { .base = 33, .offset = 4 }, /* Band group 4 TFI */
1232                 { .base = 37, .offset = 3 }, /* Band group 4 FFI */
1233                 { .base =  0, .offset = 0 }, /* Bit reserved     */
1234                 { .base = 45, .offset = 2 }  /* Band group 5 FFI */
1235         };
1236         int tbl_size = sizeof (uwba_channel_table) /
1237             sizeof (uwba_channel_range_t);
1238 
1239         uint8_t channel = 0;
1240         for (i = 0; i < tbl_size; i++) {
1241                 if ((uwba_dev->phy_cap_bm & (0x01<<i)) == 0x0) continue;
1242 
1243                 for (j = 0; j < uwba_channel_table[i].offset; j++) {
1244 
1245                         channel = uwba_channel_table[i].base + j;
1246                         if (uwb_scan_channel(uwb_dev_hdl, channel)
1247                             != UWB_SUCCESS) {
1248                                 uwba_log(uwba_dev, UWBA_LOG_LOG,
1249                                     "uwba_allocate_channel: scan chanel"
1250                                     " %d failed", channel);
1251 
1252                                 return (0);
1253                         }
1254                         /* No beacon recevied in this channel, return */
1255                         if (!uwba_find_cdev_by_channel(uwba_dev, channel)) {
1256 
1257                                 return (channel);
1258                         }
1259                         uwba_log(uwba_dev, UWBA_LOG_DEBUG,
1260                             "uwba_allocate_channel: exsting device becaoning"
1261                             "in channel = %d ", channel);
1262                 }
1263 
1264         }
1265 
1266         /*
1267          * when we reach here, it means all the channel has beconning device,
1268          * return the last channel
1269          */
1270 done:
1271         uwba_log(uwba_dev, UWBA_LOG_DEBUG,
1272             "uwba_allocate_channel: return channel = %d",
1273             channel);
1274 
1275         return (channel);
1276 }
1277 /*
1278  * Find a IE with a specific ID in ie_data. Return the pointer to the IE head if
1279  * found, else return NULL.
1280  */
1281 uint8_t *
1282 uwba_find_ie(uwb_dev_handle_t uwb_dev_hdl, uint_t ie_id,
1283         uint8_t *ie_data, uint16_t ie_len)
1284 {
1285         int i = 0;
1286         uint8_t curr_ie_len;
1287         boolean_t matched = B_FALSE;
1288         uwba_dev_t *uwba_dev = (uwba_dev_t *)uwb_dev_hdl;
1289 
1290         while (i < (ie_len - 1)) {
1291                 if (ie_data[i] == ie_id) {
1292                         matched = B_TRUE;
1293 
1294                         break;
1295                 }
1296                 i++; /* move to the length item of the current IE */
1297                 curr_ie_len = ie_data[i];
1298                 i =  i + curr_ie_len + 1; /* move to the next IE's head */
1299         }
1300         if (matched) {
1301                 curr_ie_len = ie_data[i + 1];
1302 
1303                 /*
1304                  * if the rest ie data are less than that indicated in the
1305                  * matched IE's length, then this is not valid IE
1306                  */
1307                 if ((ie_len - i -1) < curr_ie_len) {
1308                         uwba_log(uwba_dev, UWBA_LOG_LOG,
1309                             "the matched IE is not valid. "
1310                             "curr_ie_len=%d, i=%d", curr_ie_len, i);
1311 
1312                         return (NULL);
1313                 }
1314 
1315                 return (&ie_data[i]);
1316         }
1317 
1318         return (NULL);
1319 }
1320 
1321 void
1322 uwba_copy_rccb(uwb_rccb_cmd_t *src_rccb, uwb_rccb_cmd_t *des_rccb)
1323 {
1324         bcopy(src_rccb, des_rccb,       sizeof (uwb_rccb_cmd_t));
1325 }
1326 
1327 /* uwba_log, log the message output to dmesg according to err level */
1328 void
1329 uwba_log(uwba_dev_t *uwba_dev, uint_t msglevel, char *formatarg, ...)
1330 {
1331         va_list ap;
1332         const char *devinst = NULL;
1333 
1334         if (msglevel <= uwba_errlevel) {
1335                 char *format;
1336                 int formatlen = strlen(formatarg) + 2;  /* '!' and NULL char */
1337                 int devinst_start = 0;
1338                 if (uwba_dev) {
1339                         devinst = uwba_dev->devinst;
1340                 } else {
1341                         devinst = "uwba: ";
1342                 }
1343                 ASSERT(devinst != NULL);
1344 
1345                 /* Allocate extra room if driver name and instance is present */
1346                 formatlen += strlen(devinst);
1347 
1348                 format = kmem_zalloc(formatlen, KM_SLEEP);
1349 
1350                 if (msglevel >= UWBA_LOG_LOG) {
1351                         format[0] = '!';
1352                         devinst_start = 1;
1353                 }
1354 
1355                 (void) strcpy(&format[devinst_start], devinst);
1356 
1357                 va_start(ap, formatarg);
1358                 (void) strcat(format, formatarg);
1359                 vcmn_err(CE_CONT, format, ap);
1360                 va_end(ap);
1361 
1362                 kmem_free(format, formatlen);
1363         }
1364 }
1365 
1366 /* Get a msg string of a event or notfication */
1367 const char *
1368 uwba_event_msg(uint16_t wEvent) {
1369         if (wEvent > UWB_CE_SET_ASIE_NOTIFICATION) {
1370                 return ("Unknown Message");
1371         } else {
1372                 return (uwba_evt_msg_table[wEvent]);
1373         }
1374 }