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 }