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
_init(void)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
_fini()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
_info(struct modinfo * modinfop)262 _info(struct modinfo *modinfop)
263 {
264 return (mod_info(&modlinkage, modinfop));
265 }
266
267 /* Create the global uwb dev list */
268 static void
uwba_init_lists(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
uwba_fini_lists(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
uwba_dev_search(dev_info_t * dip)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
uwba_dev_add_to_list(uwba_dev_t * uwba_dev)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
uwba_dev_rm_from_list(uwba_dev_t * uwba_dev)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
uwba_init_ctxt_id(uwba_dev_t * uwba_dev)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
uwba_fini_ctxt_id(uwba_dev_t * uwba_dev)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
uwba_get_ctxt_id(uwba_dev_t * uwba_dev)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
uwba_free_ctxt_id(uwba_dev_t * dev,uint8_t ctxt_id)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
uwba_fill_rccb_head(uwba_dev_t * uwba_dev,uint16_t cmd,mblk_t * data)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
uwba_alloc_uwb_dev(dev_info_t * dip,uwba_dev_t ** uwba_dev,uint_t rcd_intr_pri)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
uwba_free_uwb_dev(uwba_dev_t * uwba_dev)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
uwba_get_evt_code(uint8_t * data,int data_len)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
uwba_get_evt_size(uint8_t * data,int data_len,uint16_t evt_code)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
uwba_put_cmd_result(uwba_dev_t * uwba_dev,void * evt_struct,uint16_t evt_size)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
uwba_add_notif_to_list(uwba_dev_t * uwba_dev,void * evt_struct,uint16_t evt_size)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 *
uwba_find_cdev_by_mac(uwba_dev_t * uwba_dev,uwb_mac_addr_t * mac)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 *
uwba_find_cdev_by_channel(uwba_dev_t * uwba_dev,uint8_t channel)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
uwba_remove_cdev_list(uwba_dev_t * uwba_dev)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
uwba_add_cdev_to_list(uwba_dev_t * uwba_dev,uwb_beacon_frame_t * bc_frm)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
uwba_parse_data(char * format,uchar_t * data,size_t datalen,void * structure,size_t structlen)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
uwba_parse_rceb(uint8_t * data,size_t datalen,void * structure,size_t structlen)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
uwba_parse_dev_addr_mgmt(uint8_t * spec_data,int spec_data_len,uwb_rceb_dev_addr_mgmt_t * evt_struct)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
uwba_parse_get_ie(uwb_dev_handle_t uwb_dev_hdl,uint8_t * spec_data,int spec_data_len,uwb_rceb_get_ie_t * evt_struct)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
uwba_parse_beacon_info(uwba_dev_t * uwba_dev,uint8_t * bc_info)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
uwba_parse_bpoie_chg(uwb_dev_handle_t uwb_dev_hdl,uint8_t * spec_data,int spec_data_len,uwb_rceb_bpoie_change_t * evt_struct)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
uwba_parse_beacon_rcv(uwb_dev_handle_t uwb_dev_hdl,uint8_t * spec_data,int spec_data_len,uwb_rceb_beacon_t * evt_struct)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
uwba_get_phy_cap(uwb_dev_handle_t uwb_dev_hdl,uint8_t * ie_data,uint16_t ie_len)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
uwba_save_phy_cap_bm(uwb_dev_handle_t uwb_dev_hdl,uint8_t * phy_ie)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
uwba_list_phy_rates(uwb_dev_handle_t uwb_dev_hdl)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
uwba_list_phy_bandgroups(uwb_dev_handle_t uwb_dev_hdl)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
uwba_allocate_channel(uwb_dev_handle_t uwb_dev_hdl)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 *
uwba_find_ie(uwb_dev_handle_t uwb_dev_hdl,uint_t ie_id,uint8_t * ie_data,uint16_t ie_len)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
uwba_copy_rccb(uwb_rccb_cmd_t * src_rccb,uwb_rccb_cmd_t * des_rccb)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
uwba_log(uwba_dev_t * uwba_dev,uint_t msglevel,char * formatarg,...)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 *
uwba_event_msg(uint16_t wEvent)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 }
1375