xref: /onnv-gate/usr/src/uts/common/io/uwb/uwba/uwba.c (revision 9430:637732b28916)
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