ng_hci_cmds.c revision 109623
1/*
2 * ng_hci_cmds.c
3 *
4 * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $Id: ng_hci_cmds.c,v 1.22 2002/10/30 00:18:18 max Exp $
29 * $FreeBSD: head/sys/netgraph/bluetooth/hci/ng_hci_cmds.c 109623 2003-01-21 08:56:16Z alfred $
30 */
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/kernel.h>
35#include <sys/endian.h>
36#include <sys/malloc.h>
37#include <sys/mbuf.h>
38#include <sys/queue.h>
39#include <netgraph/ng_message.h>
40#include <netgraph/netgraph.h>
41#include "ng_bluetooth.h"
42#include "ng_hci.h"
43#include "ng_hci_var.h"
44#include "ng_hci_cmds.h"
45#include "ng_hci_evnt.h"
46#include "ng_hci_ulpi.h"
47#include "ng_hci_misc.h"
48
49/******************************************************************************
50 ******************************************************************************
51 **                     HCI commands processing module
52 ******************************************************************************
53 ******************************************************************************/
54
55#undef	min
56#define	min(a, b)	((a) < (b))? (a) : (b)
57
58static int  complete_command (ng_hci_unit_p, int, struct mbuf **);
59
60static int process_link_control_params
61	(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
62static int process_link_policy_params
63	(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
64static int process_hc_baseband_params
65	(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
66static int process_info_params
67	(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
68static int process_status_params
69	(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
70static int process_testing_params
71	(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
72
73static int process_link_control_status
74	(ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *);
75static int process_link_policy_status
76	(ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *);
77
78/*
79 * Send HCI command to the driver.
80 */
81
82int
83ng_hci_send_command(ng_hci_unit_p unit)
84{
85	struct mbuf	*m0 = NULL, *m = NULL;
86	int		 free, error = 0;
87
88	/* Check if other command is pending */
89	if (unit->state & NG_HCI_UNIT_COMMAND_PENDING)
90		return (0);
91
92	/* Check if unit can accept our command */
93	NG_HCI_BUFF_CMD_GET(unit->buffer, free);
94	if (free == 0)
95		return (0);
96
97	/* Check if driver hook is still ok */
98	if (unit->drv == NULL || NG_HOOK_NOT_VALID(unit->drv)) {
99		NG_HCI_WARN(
100"%s: %s - hook \"%s\" is not connected or valid\n",
101			__func__, NG_NODE_NAME(unit->node), NG_HCI_HOOK_DRV);
102
103		NG_BT_MBUFQ_DRAIN(&unit->cmdq);
104
105		return (ENOTCONN);
106	}
107
108	/*
109	 * Get first command from queue, give it to RAW hook then
110	 * make copy of it and send it to the driver
111	 */
112
113	m0 = NG_BT_MBUFQ_FIRST(&unit->cmdq);
114	if (m0 == NULL)
115		return (0);
116
117	ng_hci_mtap(unit, m0);
118
119	m = m_dup(m0, M_NOWAIT);
120	if (m != NULL)
121		NG_SEND_DATA_ONLY(error, unit->drv, m);
122	else
123		error = ENOBUFS;
124
125	if (error != 0)
126		NG_HCI_ERR(
127"%s: %s - could not send HCI command, error=%d\n",
128			__func__, NG_NODE_NAME(unit->node), error);
129
130	/*
131	 * Even if we were not able to send command we still pretend
132	 * that everything is OK and let timeout handle that.
133	 */
134
135	NG_HCI_BUFF_CMD_USE(unit->buffer, 1);
136	NG_HCI_STAT_CMD_SENT(unit->stat);
137	NG_HCI_STAT_BYTES_SENT(unit->stat, m0->m_pkthdr.len);
138
139	/*
140	 * Note: ng_hci_command_timeout() will set
141	 * NG_HCI_UNIT_COMMAND_PENDING flag
142	 */
143
144	ng_hci_command_timeout(unit);
145
146	return (0);
147} /* ng_hci_send_command */
148
149/*
150 * Process HCI Command_Compete event. Complete HCI command, and do post
151 * processing on the command parameters (cp) and command return parameters
152 * (e) if required (for example adjust state).
153 */
154
155int
156ng_hci_process_command_complete(ng_hci_unit_p unit, struct mbuf *e)
157{
158	ng_hci_command_compl_ep		*ep = NULL;
159	struct mbuf			*cp = NULL;
160	int				 error = 0;
161
162	/* Get event packet and update command buffer info */
163	NG_HCI_M_PULLUP(e, sizeof(*ep));
164	if (e == NULL)
165		return (ENOBUFS); /* XXX this is bad */
166
167	ep = mtod(e, ng_hci_command_compl_ep *);
168        NG_HCI_BUFF_CMD_SET(unit->buffer, ep->num_cmd_pkts);
169
170	/* Check for special NOOP command */
171	if (ep->opcode == 0x0000) {
172		NG_FREE_M(e);
173		goto out;
174	}
175
176	/* Try to match first command item in the queue */
177	error = complete_command(unit, ep->opcode, &cp);
178	if (error != 0) {
179		NG_FREE_M(e);
180		goto out;
181	}
182
183	/*
184	 * Perform post processing on command parameters and return parameters
185	 * do it only if status is OK (status == 0). Status is the first byte
186	 * of any command return parameters.
187	 */
188
189	ep->opcode = le16toh(ep->opcode);
190	m_adj(e, sizeof(*ep));
191
192	if (*mtod(e, u_int8_t *) == 0) { /* XXX m_pullup here? */
193		switch (NG_HCI_OGF(ep->opcode)) {
194		case NG_HCI_OGF_LINK_CONTROL:
195			error = process_link_control_params(unit,
196					NG_HCI_OCF(ep->opcode), cp, e);
197			break;
198
199		case NG_HCI_OGF_LINK_POLICY:
200			error = process_link_policy_params(unit,
201					NG_HCI_OCF(ep->opcode), cp, e);
202			break;
203
204		case NG_HCI_OGF_HC_BASEBAND:
205			error = process_hc_baseband_params(unit,
206					NG_HCI_OCF(ep->opcode), cp, e);
207			break;
208
209		case NG_HCI_OGF_INFO:
210			error = process_info_params(unit,
211					NG_HCI_OCF(ep->opcode), cp, e);
212			break;
213
214		case NG_HCI_OGF_STATUS:
215			error = process_status_params(unit,
216					NG_HCI_OCF(ep->opcode), cp, e);
217			break;
218
219		case NG_HCI_OGF_TESTING:
220			error = process_testing_params(unit,
221					NG_HCI_OCF(ep->opcode), cp, e);
222			break;
223
224		case NG_HCI_OGF_BT_LOGO:
225		case NG_HCI_OGF_VENDOR:
226			NG_FREE_M(cp);
227			NG_FREE_M(e);
228			break;
229
230		default:
231			NG_FREE_M(cp);
232			NG_FREE_M(e);
233			error = EINVAL;
234			break;
235		}
236	} else {
237		NG_HCI_ERR(
238"%s: %s - HCI command failed, OGF=%#x, OCF=%#x, status=%#x\n",
239			__func__, NG_NODE_NAME(unit->node),
240			NG_HCI_OGF(ep->opcode), NG_HCI_OCF(ep->opcode),
241			*mtod(e, u_int8_t *));
242
243		NG_FREE_M(cp);
244		NG_FREE_M(e);
245	}
246out:
247	ng_hci_send_command(unit);
248
249	return (error);
250} /* ng_hci_process_command_complete */
251
252/*
253 * Process HCI Command_Status event. Check the status (mst) and do post
254 * processing (if required).
255 */
256
257int
258ng_hci_process_command_status(ng_hci_unit_p unit, struct mbuf *e)
259{
260	ng_hci_command_status_ep	*ep = NULL;
261	struct mbuf			*cp = NULL;
262	int				 error = 0;
263
264	/* Update command buffer info */
265	NG_HCI_M_PULLUP(e, sizeof(*ep));
266	if (e == NULL)
267		return (ENOBUFS); /* XXX this is bad */
268
269	ep = mtod(e, ng_hci_command_status_ep *);
270	NG_HCI_BUFF_CMD_SET(unit->buffer, ep->num_cmd_pkts);
271
272	/* Check for special NOOP command */
273	if (ep->opcode == 0x0000)
274		goto out;
275
276	/* Try to match first command item in the queue */
277	error = complete_command(unit, ep->opcode, &cp);
278        if (error != 0)
279		goto out;
280
281	/*
282	 * Perform post processing on HCI Command_Status event
283	 */
284
285	ep->opcode = le16toh(ep->opcode);
286
287	switch (NG_HCI_OGF(ep->opcode)) {
288	case NG_HCI_OGF_LINK_CONTROL:
289		error = process_link_control_status(unit, ep, cp);
290		break;
291
292	case NG_HCI_OGF_LINK_POLICY:
293		error = process_link_policy_status(unit, ep, cp);
294		break;
295
296	case NG_HCI_OGF_BT_LOGO:
297	case NG_HCI_OGF_VENDOR:
298		NG_FREE_M(cp);
299		break;
300
301	case NG_HCI_OGF_HC_BASEBAND:
302	case NG_HCI_OGF_INFO:
303	case NG_HCI_OGF_STATUS:
304	case NG_HCI_OGF_TESTING:
305	default:
306		NG_FREE_M(cp);
307		error = EINVAL;
308		break;
309	}
310out:
311	NG_FREE_M(e);
312	ng_hci_send_command(unit);
313
314	return (error);
315} /* ng_hci_process_command_status */
316
317/*
318 * Complete queued HCI command.
319 */
320
321static int
322complete_command(ng_hci_unit_p unit, int opcode, struct mbuf **cp)
323{
324	struct mbuf	*m = NULL;
325
326	/* Check unit state */
327	if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) {
328		NG_HCI_ALERT(
329"%s: %s - no pending command, state=%#x\n",
330			__func__, NG_NODE_NAME(unit->node), unit->state);
331
332		return (EINVAL);
333	}
334
335	/* Get first command in the queue */
336	m = NG_BT_MBUFQ_FIRST(&unit->cmdq);
337	if (m == NULL) {
338		NG_HCI_ALERT(
339"%s: %s - empty command queue?!\n", __func__, NG_NODE_NAME(unit->node));
340
341		return (EINVAL);
342	}
343
344	/*
345	 * Match command opcode, if does not match - do nothing and
346	 * let timeout handle that.
347	 */
348
349	if (mtod(m, ng_hci_cmd_pkt_t *)->opcode != opcode) {
350		NG_HCI_ALERT(
351"%s: %s - command queue is out of sync\n", __func__, NG_NODE_NAME(unit->node));
352
353		return (EINVAL);
354	}
355
356	/*
357	 * Now we can remove command timeout, dequeue completed command
358	 * and return command parameters. Note: ng_hci_command_untimeout()
359	 * will drop NG_HCI_UNIT_COMMAND_PENDING flag.
360	 */
361
362	ng_hci_command_untimeout(unit);
363	NG_BT_MBUFQ_DEQUEUE(&unit->cmdq, *cp);
364	m_adj(*cp, sizeof(ng_hci_cmd_pkt_t));
365
366	return (0);
367} /* complete_command */
368
369/*
370 * Process HCI command timeout
371 */
372
373void
374ng_hci_process_command_timeout(node_p node, hook_p hook, void *arg1, int arg2)
375{
376	ng_hci_unit_p	 unit = (ng_hci_unit_p) arg1;
377	struct mbuf	*m = NULL;
378	u_int16_t	 opcode;
379
380	if (unit->state & NG_HCI_UNIT_COMMAND_PENDING) {
381		NG_BT_MBUFQ_DEQUEUE(&unit->cmdq, m);
382
383		if (m == NULL) {
384			KASSERT(0,
385("%s: %s - command queue is out of sync!\n",
386				__func__, NG_NODE_NAME(unit->node)));
387
388			return;
389		}
390
391		opcode = le16toh(mtod(m, ng_hci_cmd_pkt_t *)->opcode);
392		NG_FREE_M(m);
393
394		NG_HCI_ERR(
395"%s: %s - unable to complete HCI command OGF=%#x, OCF=%#x. Timeout\n",
396			__func__, NG_NODE_NAME(unit->node), NG_HCI_OGF(opcode),
397			NG_HCI_OCF(opcode));
398
399		/*
400		 * Try to send more commands
401		 */
402
403 		NG_HCI_BUFF_CMD_SET(unit->buffer, 1);
404
405		unit->state &= ~NG_HCI_UNIT_COMMAND_PENDING;
406		ng_hci_send_command(unit);
407	} else
408		KASSERT(0,
409("%s: %s - no pending command, state=%#x\n",
410			__func__, NG_NODE_NAME(unit->node), unit->state));
411} /* ng_hci_process_command_timeout */
412
413/*
414 * Process link command return parameters
415 */
416
417static int
418process_link_control_params(ng_hci_unit_p unit, u_int16_t ocf,
419		struct mbuf *mcp, struct mbuf *mrp)
420{
421	int	error  = 0;
422
423	switch (ocf) {
424	case NG_HCI_OCF_INQUIRY_CANCEL:
425	case NG_HCI_OCF_PERIODIC_INQUIRY:
426	case NG_HCI_OCF_EXIT_PERIODIC_INQUIRY:
427	case NG_HCI_OCF_LINK_KEY_REP:
428	case NG_HCI_OCF_LINK_KEY_NEG_REP:
429	case NG_HCI_OCF_PIN_CODE_REP:
430	case NG_HCI_OCF_PIN_CODE_NEG_REP:
431		/* These do not need post processing */
432		break;
433
434	case NG_HCI_OCF_INQUIRY:
435	case NG_HCI_OCF_CREATE_CON:
436	case NG_HCI_OCF_DISCON:
437	case NG_HCI_OCF_ADD_SCO_CON:
438	case NG_HCI_OCF_ACCEPT_CON:
439	case NG_HCI_OCF_REJECT_CON:
440	case NG_HCI_OCF_CHANGE_CON_PKT_TYPE:
441	case NG_HCI_OCF_AUTH_REQ:
442	case NG_HCI_OCF_SET_CON_ENCRYPTION:
443	case NG_HCI_OCF_CHANGE_CON_LINK_KEY:
444	case NG_HCI_OCF_MASTER_LINK_KEY:
445	case NG_HCI_OCF_REMOTE_NAME_REQ:
446	case NG_HCI_OCF_READ_REMOTE_FEATURES:
447	case NG_HCI_OCF_READ_REMOTE_VER_INFO:
448	case NG_HCI_OCF_READ_CLOCK_OFFSET:
449	default:
450
451		/*
452		 * None of these command was supposed to generate
453		 * Command_Complete event. Instead Command_Status event
454		 * should have been generated and then appropriate event
455		 * should have been sent to indicate the final result.
456		 */
457
458		error = EINVAL;
459		break;
460	}
461
462	NG_FREE_M(mcp);
463	NG_FREE_M(mrp);
464
465	return (error);
466} /* process_link_control_params */
467
468/*
469 * Process link policy command return parameters
470 */
471
472static int
473process_link_policy_params(ng_hci_unit_p unit, u_int16_t ocf,
474		struct mbuf *mcp, struct mbuf *mrp)
475{
476	int	error = 0;
477
478	switch (ocf){
479	case NG_HCI_OCF_ROLE_DISCOVERY: {
480		ng_hci_role_discovery_rp	*rp = NULL;
481		ng_hci_unit_con_t		*con = NULL;
482		u_int16_t			 h;
483
484		NG_HCI_M_PULLUP(mrp, sizeof(*rp));
485		if (mrp != NULL) {
486			rp = mtod(mrp, ng_hci_role_discovery_rp *);
487
488			h = NG_HCI_CON_HANDLE(le16toh(rp->con_handle));
489			con = ng_hci_con_by_handle(unit, h);
490			if (con == NULL) {
491				NG_HCI_ALERT(
492"%s: %s - invalid connection handle=%d\n",
493					__func__, NG_NODE_NAME(unit->node), h);
494				error = ENOENT;
495			} else if (con->link_type != NG_HCI_LINK_ACL) {
496				NG_HCI_ALERT(
497"%s: %s - invalid link type=%d\n", __func__, NG_NODE_NAME(unit->node),
498					con->link_type);
499				error = EINVAL;
500			} else
501				con->role = rp->role;
502		} else
503			error = ENOBUFS;
504		} break;
505
506	case NG_HCI_OCF_READ_LINK_POLICY_SETTINGS:
507	case NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS:
508		/* These do not need post processing */
509		break;
510
511	case NG_HCI_OCF_HOLD_MODE:
512	case NG_HCI_OCF_SNIFF_MODE:
513	case NG_HCI_OCF_EXIT_SNIFF_MODE:
514	case NG_HCI_OCF_PARK_MODE:
515	case NG_HCI_OCF_EXIT_PARK_MODE:
516	case NG_HCI_OCF_QOS_SETUP:
517	case NG_HCI_OCF_SWITCH_ROLE:
518	default:
519
520		/*
521		 * None of these command was supposed to generate
522		 * Command_Complete event. Instead Command_Status event
523		 * should have been generated and then appropriate event
524		 * should have been sent to indicate the final result.
525		 */
526
527		error = EINVAL;
528		break;
529	}
530
531	NG_FREE_M(mcp);
532	NG_FREE_M(mrp);
533
534	return (error);
535} /* process_link_policy_params */
536
537/*
538 * Process HC and baseband command return parameters
539 */
540
541int
542process_hc_baseband_params(ng_hci_unit_p unit, u_int16_t ocf,
543		struct mbuf *mcp, struct mbuf *mrp)
544{
545	int	error = 0;
546
547	switch (ocf) {
548	case NG_HCI_OCF_SET_EVENT_MASK:
549	case NG_HCI_OCF_SET_EVENT_FILTER:
550	case NG_HCI_OCF_FLUSH:	/* XXX Do we need to handle that? */
551	case NG_HCI_OCF_READ_PIN_TYPE:
552	case NG_HCI_OCF_WRITE_PIN_TYPE:
553	case NG_HCI_OCF_CREATE_NEW_UNIT_KEY:
554	case NG_HCI_OCF_WRITE_STORED_LINK_KEY:
555	case NG_HCI_OCF_WRITE_CON_ACCEPT_TIMO:
556	case NG_HCI_OCF_WRITE_PAGE_TIMO:
557	case NG_HCI_OCF_READ_SCAN_ENABLE:
558	case NG_HCI_OCF_WRITE_SCAN_ENABLE:
559	case NG_HCI_OCF_WRITE_PAGE_SCAN_ACTIVITY:
560	case NG_HCI_OCF_WRITE_INQUIRY_SCAN_ACTIVITY:
561	case NG_HCI_OCF_READ_AUTH_ENABLE:
562	case NG_HCI_OCF_WRITE_AUTH_ENABLE:
563	case NG_HCI_OCF_READ_ENCRYPTION_MODE:
564	case NG_HCI_OCF_WRITE_ENCRYPTION_MODE:
565	case NG_HCI_OCF_WRITE_VOICE_SETTINGS:
566	case NG_HCI_OCF_READ_NUM_BROADCAST_RETRANS:
567	case NG_HCI_OCF_WRITE_NUM_BROADCAST_RETRANS:
568	case NG_HCI_OCF_READ_HOLD_MODE_ACTIVITY:
569	case NG_HCI_OCF_WRITE_HOLD_MODE_ACTIVITY:
570	case NG_HCI_OCF_READ_SCO_FLOW_CONTROL:
571	case NG_HCI_OCF_WRITE_SCO_FLOW_CONTROL:
572	case NG_HCI_OCF_H2HC_FLOW_CONTROL: /* XXX Not supported this time */
573	case NG_HCI_OCF_HOST_BUFFER_SIZE:
574	case NG_HCI_OCF_READ_IAC_LAP:
575	case NG_HCI_OCF_WRITE_IAC_LAP:
576	case NG_HCI_OCF_READ_PAGE_SCAN_PERIOD:
577	case NG_HCI_OCF_WRITE_PAGE_SCAN_PERIOD:
578	case NG_HCI_OCF_READ_PAGE_SCAN:
579	case NG_HCI_OCF_WRITE_PAGE_SCAN:
580	case NG_HCI_OCF_READ_LINK_SUPERVISION_TIMO:
581	case NG_HCI_OCF_WRITE_LINK_SUPERVISION_TIMO:
582	case NG_HCI_OCF_READ_SUPPORTED_IAC_NUM:
583	case NG_HCI_OCF_READ_STORED_LINK_KEY:
584	case NG_HCI_OCF_DELETE_STORED_LINK_KEY:
585	case NG_HCI_OCF_READ_CON_ACCEPT_TIMO:
586	case NG_HCI_OCF_READ_PAGE_TIMO:
587	case NG_HCI_OCF_READ_PAGE_SCAN_ACTIVITY:
588	case NG_HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY:
589	case NG_HCI_OCF_READ_VOICE_SETTINGS:
590	case NG_HCI_OCF_READ_AUTO_FLUSH_TIMO:
591	case NG_HCI_OCF_WRITE_AUTO_FLUSH_TIMO:
592	case NG_HCI_OCF_READ_XMIT_LEVEL:
593	case NG_HCI_OCF_HOST_NUM_COMPL_PKTS:	/* XXX Can get here? */
594	case NG_HCI_OCF_CHANGE_LOCAL_NAME:
595	case NG_HCI_OCF_READ_LOCAL_NAME:
596	case NG_HCI_OCF_READ_UNIT_CLASS:
597	case NG_HCI_OCF_WRITE_UNIT_CLASS:
598		/* These do not need post processing */
599		break;
600
601	case NG_HCI_OCF_RESET: {
602		ng_hci_unit_con_p	con = NULL;
603		int			size;
604
605		/*
606		 * XXX
607		 *
608		 * After RESET command unit goes into standby mode
609		 * and all operational state is lost. Host controller
610		 * will revert to default values for all parameters.
611		 *
612		 * For now we shall terminate all connections and drop
613		 * inited bit. After RESET unit must be re-initialized.
614		 */
615
616		while (!LIST_EMPTY(&unit->con_list)) {
617			con = LIST_FIRST(&unit->con_list);
618
619			/* Connection terminated by local host */
620			ng_hci_lp_discon_ind(con, 0x16);
621			ng_hci_free_con(con);
622		}
623
624		NG_HCI_BUFF_ACL_TOTAL(unit->buffer, size);
625		NG_HCI_BUFF_ACL_FREE(unit->buffer, size);
626
627		NG_HCI_BUFF_SCO_TOTAL(unit->buffer, size);
628		NG_HCI_BUFF_SCO_FREE(unit->buffer, size);
629
630		unit->state &= ~NG_HCI_UNIT_INITED;
631		} break;
632
633	default:
634		error = EINVAL;
635		break;
636	}
637
638	NG_FREE_M(mcp);
639	NG_FREE_M(mrp);
640
641	return (error);
642} /* process_hc_baseband_params */
643
644/*
645 * Process info command return parameters
646 */
647
648static int
649process_info_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp,
650		struct mbuf *mrp)
651{
652	int	error = 0, len;
653
654	switch (ocf) {
655	case NG_HCI_OCF_READ_LOCAL_VER:
656	case NG_HCI_OCF_READ_COUNTRY_CODE:
657		break;
658
659	case NG_HCI_OCF_READ_LOCAL_FEATURES:
660		m_adj(mrp, sizeof(u_int8_t));
661		len = min(mrp->m_pkthdr.len, sizeof(unit->features));
662		m_copydata(mrp, 0, len, (caddr_t) unit->features);
663		break;
664
665	case NG_HCI_OCF_READ_BUFFER_SIZE: {
666		ng_hci_read_buffer_size_rp	*rp = NULL;
667
668		/* Do not update buffer descriptor if node was initialized */
669		if ((unit->state & NG_HCI_UNIT_READY) == NG_HCI_UNIT_READY)
670			break;
671
672		NG_HCI_M_PULLUP(mrp, sizeof(*rp));
673		if (mrp != NULL) {
674			rp = mtod(mrp, ng_hci_read_buffer_size_rp *);
675
676			NG_HCI_BUFF_ACL_SET(
677				unit->buffer,
678				le16toh(rp->num_acl_pkt),  /* number */
679				le16toh(rp->max_acl_size), /* size */
680				le16toh(rp->num_acl_pkt)   /* free */
681			);
682
683			NG_HCI_BUFF_SCO_SET(
684				unit->buffer,
685				le16toh(rp->num_sco_pkt), /* number */
686				rp->max_sco_size,         /* size */
687				le16toh(rp->num_sco_pkt)  /* free */
688			);
689
690			/* Let upper layers know */
691			ng_hci_node_is_up(unit->node, unit->acl, NULL, 0);
692			ng_hci_node_is_up(unit->node, unit->sco, NULL, 0);
693		} else
694			error = ENOBUFS;
695		} break;
696
697	case NG_HCI_OCF_READ_BDADDR:
698		/* Do not update BD_ADDR if node was initialized */
699		if ((unit->state & NG_HCI_UNIT_READY) == NG_HCI_UNIT_READY)
700			break;
701
702		m_adj(mrp, sizeof(u_int8_t));
703		len = min(mrp->m_pkthdr.len, sizeof(unit->bdaddr));
704		m_copydata(mrp, 0, len, (caddr_t) &unit->bdaddr);
705
706		/* Let upper layers know */
707		ng_hci_node_is_up(unit->node, unit->acl, NULL, 0);
708		ng_hci_node_is_up(unit->node, unit->sco, NULL, 0);
709		break;
710
711	default:
712		error = EINVAL;
713		break;
714	}
715
716	NG_FREE_M(mcp);
717	NG_FREE_M(mrp);
718
719	return (error);
720} /* process_info_params */
721
722/*
723 * Process status command return parameters
724 */
725
726static int
727process_status_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp,
728		struct mbuf *mrp)
729{
730	int	error = 0;
731
732	switch (ocf) {
733	case NG_HCI_OCF_READ_FAILED_CONTACT_CNTR:
734	case NG_HCI_OCF_RESET_FAILED_CONTACT_CNTR:
735	case NG_HCI_OCF_GET_LINK_QUALITY:
736	case NG_HCI_OCF_READ_RSSI:
737		/* These do not need post processing */
738		break;
739
740	default:
741		error = EINVAL;
742		break;
743	}
744
745	NG_FREE_M(mcp);
746	NG_FREE_M(mrp);
747
748	return (error);
749} /* process_status_params */
750
751/*
752 * Process testing command return parameters
753 */
754
755int
756process_testing_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp,
757		struct mbuf *mrp)
758{
759	int	error = 0;
760
761	switch (ocf) {
762
763	/*
764	 * XXX FIXME
765	 * We do not support these features at this time. However,
766	 * HCI node could support this and do something smart. At least
767	 * node can change unit state.
768	 */
769
770	case NG_HCI_OCF_READ_LOOPBACK_MODE:
771	case NG_HCI_OCF_WRITE_LOOPBACK_MODE:
772	case NG_HCI_OCF_ENABLE_UNIT_UNDER_TEST:
773		break;
774
775	default:
776		error = EINVAL;
777		break;
778	}
779
780	NG_FREE_M(mcp);
781	NG_FREE_M(mrp);
782
783	return (error);
784} /* process_testing_params */
785
786/*
787 * Process link control command status
788 */
789
790static int
791process_link_control_status(ng_hci_unit_p unit, ng_hci_command_status_ep *ep,
792		struct mbuf *mcp)
793{
794	int	error = 0;
795
796	switch (NG_HCI_OCF(ep->opcode)) {
797	case NG_HCI_OCF_INQUIRY:
798	case NG_HCI_OCF_DISCON:		/* XXX */
799	case NG_HCI_OCF_REJECT_CON:	/* XXX */
800	case NG_HCI_OCF_CHANGE_CON_PKT_TYPE:
801	case NG_HCI_OCF_AUTH_REQ:
802	case NG_HCI_OCF_SET_CON_ENCRYPTION:
803	case NG_HCI_OCF_CHANGE_CON_LINK_KEY:
804	case NG_HCI_OCF_MASTER_LINK_KEY:
805	case NG_HCI_OCF_REMOTE_NAME_REQ:
806	case NG_HCI_OCF_READ_REMOTE_FEATURES:
807	case NG_HCI_OCF_READ_REMOTE_VER_INFO:
808	case NG_HCI_OCF_READ_CLOCK_OFFSET:
809		/* These do not need post processing */
810		break;
811
812	case NG_HCI_OCF_CREATE_CON:
813		break;
814
815	case NG_HCI_OCF_ADD_SCO_CON:
816		break;
817
818	case NG_HCI_OCF_ACCEPT_CON:
819		break;
820
821	case NG_HCI_OCF_INQUIRY_CANCEL:
822	case NG_HCI_OCF_PERIODIC_INQUIRY:
823	case NG_HCI_OCF_EXIT_PERIODIC_INQUIRY:
824	case NG_HCI_OCF_LINK_KEY_REP:
825	case NG_HCI_OCF_LINK_KEY_NEG_REP:
826	case NG_HCI_OCF_PIN_CODE_REP:
827	case NG_HCI_OCF_PIN_CODE_NEG_REP:
828	default:
829
830		/*
831		 * None of these command was supposed to generate
832		 * Command_Status event. Instead Command_Complete event
833		 * should have been sent.
834		 */
835
836		error = EINVAL;
837		break;
838	}
839
840	NG_FREE_M(mcp);
841
842	return (error);
843} /* process_link_control_status */
844
845/*
846 * Process link policy command status
847 */
848
849static int
850process_link_policy_status(ng_hci_unit_p unit, ng_hci_command_status_ep *ep,
851		struct mbuf *mcp)
852{
853	int	error = 0;
854
855	switch (NG_HCI_OCF(ep->opcode)) {
856	case NG_HCI_OCF_HOLD_MODE:
857	case NG_HCI_OCF_SNIFF_MODE:
858	case NG_HCI_OCF_EXIT_SNIFF_MODE:
859	case NG_HCI_OCF_PARK_MODE:
860	case NG_HCI_OCF_EXIT_PARK_MODE:
861	case NG_HCI_OCF_SWITCH_ROLE:
862		/* These do not need post processing */
863		break;
864
865	case NG_HCI_OCF_QOS_SETUP:
866		break;
867
868	case NG_HCI_OCF_ROLE_DISCOVERY:
869	case NG_HCI_OCF_READ_LINK_POLICY_SETTINGS:
870	case NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS:
871	default:
872
873		/*
874		 * None of these command was supposed to generate
875		 * Command_Status event. Instead Command_Complete event
876		 * should have been sent.
877		 */
878
879		error = EINVAL;
880		break;
881	}
882
883	NG_FREE_M(mcp);
884
885	return (error);
886} /* process_link_policy_status */
887
888