ng_hci_cmds.c revision 121054
1231990Smp/*
259243Sobrien * ng_hci_cmds.c
359243Sobrien *
459243Sobrien * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
559243Sobrien * All rights reserved.
659243Sobrien *
759243Sobrien * Redistribution and use in source and binary forms, with or without
859243Sobrien * modification, are permitted provided that the following conditions
959243Sobrien * are met:
1059243Sobrien * 1. Redistributions of source code must retain the above copyright
1159243Sobrien *    notice, this list of conditions and the following disclaimer.
1259243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1359243Sobrien *    notice, this list of conditions and the following disclaimer in the
1459243Sobrien *    documentation and/or other materials provided with the distribution.
1559243Sobrien *
1659243Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1759243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1859243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1959243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2059243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2159243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22167465Smp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23167465Smp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24167465Smp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2559243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26167465Smp * SUCH DAMAGE.
27167465Smp *
2859243Sobrien * $Id: ng_hci_cmds.c,v 1.4 2003/09/08 18:57:51 max Exp $
2959243Sobrien * $FreeBSD: head/sys/netgraph/bluetooth/hci/ng_hci_cmds.c 121054 2003-10-12 22:04:24Z emax $
3059243Sobrien */
3159243Sobrien
3259243Sobrien#include <sys/param.h>
3359243Sobrien#include <sys/systm.h>
3459243Sobrien#include <sys/kernel.h>
3559243Sobrien#include <sys/endian.h>
3659243Sobrien#include <sys/malloc.h>
37167465Smp#include <sys/mbuf.h>
3859243Sobrien#include <sys/queue.h>
3959243Sobrien#include <netgraph/ng_message.h>
4059243Sobrien#include <netgraph/netgraph.h>
4159243Sobrien#include "ng_bluetooth.h"
4259243Sobrien#include "ng_hci.h"
4359243Sobrien#include "ng_hci_var.h"
4459243Sobrien#include "ng_hci_cmds.h"
4559243Sobrien#include "ng_hci_evnt.h"
4659243Sobrien#include "ng_hci_ulpi.h"
4759243Sobrien#include "ng_hci_misc.h"
4859243Sobrien
4959243Sobrien/******************************************************************************
5059243Sobrien ******************************************************************************
51167465Smp **                     HCI commands processing module
5259243Sobrien ******************************************************************************
5359243Sobrien ******************************************************************************/
5459243Sobrien
5559243Sobrien#undef	min
5659243Sobrien#define	min(a, b)	((a) < (b))? (a) : (b)
5759243Sobrien
58167465Smpstatic int  complete_command (ng_hci_unit_p, int, struct mbuf **);
5959243Sobrien
60167465Smpstatic int process_link_control_params
6159243Sobrien	(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
6259243Sobrienstatic int process_link_policy_params
6359243Sobrien	(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
6459243Sobrienstatic int process_hc_baseband_params
65167465Smp	(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
6659243Sobrienstatic int process_info_params
6759243Sobrien	(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
6859243Sobrienstatic int process_status_params
6959243Sobrien	(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
7059243Sobrienstatic int process_testing_params
7159243Sobrien	(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);
7259243Sobrien
7359243Sobrienstatic int process_link_control_status
7459243Sobrien	(ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *);
7559243Sobrienstatic int process_link_policy_status
7659243Sobrien	(ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *);
7759243Sobrien
7859243Sobrien/*
7959243Sobrien * Send HCI command to the driver.
8059243Sobrien */
8159243Sobrien
8259243Sobrienint
83167465Smpng_hci_send_command(ng_hci_unit_p unit)
8459243Sobrien{
8559243Sobrien	struct mbuf	*m0 = NULL, *m = NULL;
8659243Sobrien	int		 free, error = 0;
8759243Sobrien
88167465Smp	/* Check if other command is pending */
8959243Sobrien	if (unit->state & NG_HCI_UNIT_COMMAND_PENDING)
90231990Smp		return (0);
9159243Sobrien
92145479Smp	/* Check if unit can accept our command */
93145479Smp	NG_HCI_BUFF_CMD_GET(unit->buffer, free);
94145479Smp	if (free == 0)
95145479Smp		return (0);
96131962Smp
97131962Smp	/* Check if driver hook is still ok */
9859243Sobrien	if (unit->drv == NULL || NG_HOOK_NOT_VALID(unit->drv)) {
9959243Sobrien		NG_HCI_WARN(
10059243Sobrien"%s: %s - hook \"%s\" is not connected or valid\n",
10159243Sobrien			__func__, NG_NODE_NAME(unit->node), NG_HCI_HOOK_DRV);
10259243Sobrien
10359243Sobrien		NG_BT_MBUFQ_DRAIN(&unit->cmdq);
10459243Sobrien
10559243Sobrien		return (ENOTCONN);
10659243Sobrien	}
107145479Smp
10859243Sobrien	/*
10959243Sobrien	 * Get first command from queue, give it to RAW hook then
11059243Sobrien	 * make copy of it and send it to the driver
11159243Sobrien	 */
11259243Sobrien
11359243Sobrien	m0 = NG_BT_MBUFQ_FIRST(&unit->cmdq);
11459243Sobrien	if (m0 == NULL)
11559243Sobrien		return (0);
11659243Sobrien
11759243Sobrien	ng_hci_mtap(unit, m0);
11859243Sobrien
11959243Sobrien	m = m_dup(m0, M_DONTWAIT);
12059243Sobrien	if (m != NULL)
12159243Sobrien		NG_SEND_DATA_ONLY(error, unit->drv, m);
12259243Sobrien	else
12359243Sobrien		error = ENOBUFS;
12459243Sobrien
12559243Sobrien	if (error != 0)
12659243Sobrien		NG_HCI_ERR(
12759243Sobrien"%s: %s - could not send HCI command, error=%d\n",
12859243Sobrien			__func__, NG_NODE_NAME(unit->node), error);
12959243Sobrien
13059243Sobrien	/*
13159243Sobrien	 * Even if we were not able to send command we still pretend
13259243Sobrien	 * that everything is OK and let timeout handle that.
13359243Sobrien	 */
13459243Sobrien
13559243Sobrien	NG_HCI_BUFF_CMD_USE(unit->buffer, 1);
13659243Sobrien	NG_HCI_STAT_CMD_SENT(unit->stat);
13759243Sobrien	NG_HCI_STAT_BYTES_SENT(unit->stat, m0->m_pkthdr.len);
13859243Sobrien
13959243Sobrien	/*
14059243Sobrien	 * Note: ng_hci_command_timeout() will set
14159243Sobrien	 * NG_HCI_UNIT_COMMAND_PENDING flag
14259243Sobrien	 */
14359243Sobrien
14459243Sobrien	ng_hci_command_timeout(unit);
14559243Sobrien
14659243Sobrien	return (0);
14759243Sobrien} /* ng_hci_send_command */
14859243Sobrien
14959243Sobrien/*
15059243Sobrien * Process HCI Command_Compete event. Complete HCI command, and do post
15159243Sobrien * processing on the command parameters (cp) and command return parameters
15259243Sobrien * (e) if required (for example adjust state).
15359243Sobrien */
15459243Sobrien
15559243Sobrienint
15659243Sobrienng_hci_process_command_complete(ng_hci_unit_p unit, struct mbuf *e)
15759243Sobrien{
15859243Sobrien	ng_hci_command_compl_ep		*ep = NULL;
15959243Sobrien	struct mbuf			*cp = NULL;
16059243Sobrien	int				 error = 0;
16159243Sobrien
16259243Sobrien	/* Get event packet and update command buffer info */
16359243Sobrien	NG_HCI_M_PULLUP(e, sizeof(*ep));
16459243Sobrien	if (e == NULL)
16559243Sobrien		return (ENOBUFS); /* XXX this is bad */
16659243Sobrien
16759243Sobrien	ep = mtod(e, ng_hci_command_compl_ep *);
16859243Sobrien        NG_HCI_BUFF_CMD_SET(unit->buffer, ep->num_cmd_pkts);
16959243Sobrien
17059243Sobrien	/* Check for special NOOP command */
17159243Sobrien	if (ep->opcode == 0x0000) {
17259243Sobrien		NG_FREE_M(e);
17359243Sobrien		goto out;
17459243Sobrien	}
17559243Sobrien
17659243Sobrien	/* Try to match first command item in the queue */
17759243Sobrien	error = complete_command(unit, ep->opcode, &cp);
17859243Sobrien	if (error != 0) {
17959243Sobrien		NG_FREE_M(e);
18059243Sobrien		goto out;
18159243Sobrien	}
18259243Sobrien
18359243Sobrien	/*
18459243Sobrien	 * Perform post processing on command parameters and return parameters
18559243Sobrien	 * do it only if status is OK (status == 0). Status is the first byte
18659243Sobrien	 * of any command return parameters.
18759243Sobrien	 */
18859243Sobrien
18959243Sobrien	ep->opcode = le16toh(ep->opcode);
19059243Sobrien	m_adj(e, sizeof(*ep));
19159243Sobrien
19259243Sobrien	if (*mtod(e, u_int8_t *) == 0) { /* XXX m_pullup here? */
19359243Sobrien		switch (NG_HCI_OGF(ep->opcode)) {
19459243Sobrien		case NG_HCI_OGF_LINK_CONTROL:
19559243Sobrien			error = process_link_control_params(unit,
19659243Sobrien					NG_HCI_OCF(ep->opcode), cp, e);
19759243Sobrien			break;
19859243Sobrien
19959243Sobrien		case NG_HCI_OGF_LINK_POLICY:
20059243Sobrien			error = process_link_policy_params(unit,
20159243Sobrien					NG_HCI_OCF(ep->opcode), cp, e);
20259243Sobrien			break;
20359243Sobrien
20459243Sobrien		case NG_HCI_OGF_HC_BASEBAND:
20559243Sobrien			error = process_hc_baseband_params(unit,
20659243Sobrien					NG_HCI_OCF(ep->opcode), cp, e);
20759243Sobrien			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. ng_hci_command_untimeout will
359	 * drop NG_HCI_UNIT_COMMAND_PENDING flag.
360	 * Note: if ng_hci_command_untimeout() fails (returns non-zero)
361	 * then timeout aready happened and timeout message went info node
362	 * queue. In this case we ignore command completion and pretend
363	 * there is a timeout.
364	 */
365
366	if (ng_hci_command_untimeout(unit) != 0)
367		return (ETIMEDOUT);
368
369	NG_BT_MBUFQ_DEQUEUE(&unit->cmdq, *cp);
370	m_adj(*cp, sizeof(ng_hci_cmd_pkt_t));
371
372	return (0);
373} /* complete_command */
374
375/*
376 * Process HCI command timeout
377 */
378
379void
380ng_hci_process_command_timeout(node_p node, hook_p hook, void *arg1, int arg2)
381{
382	ng_hci_unit_p	 unit = NULL;
383	struct mbuf	*m = NULL;
384	u_int16_t	 opcode;
385
386	if (NG_NODE_NOT_VALID(node)) {
387		printf("%s: Netgraph node is not valid\n", __func__);
388		return;
389	}
390
391	unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node);
392
393	if (unit->state & NG_HCI_UNIT_COMMAND_PENDING) {
394		unit->state &= ~NG_HCI_UNIT_COMMAND_PENDING;
395
396		NG_BT_MBUFQ_DEQUEUE(&unit->cmdq, m);
397		if (m == NULL) {
398			NG_HCI_ALERT(
399"%s: %s - command queue is out of sync!\n", __func__, NG_NODE_NAME(unit->node));
400
401			return;
402		}
403
404		opcode = le16toh(mtod(m, ng_hci_cmd_pkt_t *)->opcode);
405		NG_FREE_M(m);
406
407		NG_HCI_ERR(
408"%s: %s - unable to complete HCI command OGF=%#x, OCF=%#x. Timeout\n",
409			__func__, NG_NODE_NAME(unit->node), NG_HCI_OGF(opcode),
410			NG_HCI_OCF(opcode));
411
412		/* Try to send more commands */
413 		NG_HCI_BUFF_CMD_SET(unit->buffer, 1);
414		ng_hci_send_command(unit);
415	} else
416		NG_HCI_ALERT(
417"%s: %s - no pending command\n", __func__, NG_NODE_NAME(unit->node));
418} /* ng_hci_process_command_timeout */
419
420/*
421 * Process link command return parameters
422 */
423
424static int
425process_link_control_params(ng_hci_unit_p unit, u_int16_t ocf,
426		struct mbuf *mcp, struct mbuf *mrp)
427{
428	int	error  = 0;
429
430	switch (ocf) {
431	case NG_HCI_OCF_INQUIRY_CANCEL:
432	case NG_HCI_OCF_PERIODIC_INQUIRY:
433	case NG_HCI_OCF_EXIT_PERIODIC_INQUIRY:
434	case NG_HCI_OCF_LINK_KEY_REP:
435	case NG_HCI_OCF_LINK_KEY_NEG_REP:
436	case NG_HCI_OCF_PIN_CODE_REP:
437	case NG_HCI_OCF_PIN_CODE_NEG_REP:
438		/* These do not need post processing */
439		break;
440
441	case NG_HCI_OCF_INQUIRY:
442	case NG_HCI_OCF_CREATE_CON:
443	case NG_HCI_OCF_DISCON:
444	case NG_HCI_OCF_ADD_SCO_CON:
445	case NG_HCI_OCF_ACCEPT_CON:
446	case NG_HCI_OCF_REJECT_CON:
447	case NG_HCI_OCF_CHANGE_CON_PKT_TYPE:
448	case NG_HCI_OCF_AUTH_REQ:
449	case NG_HCI_OCF_SET_CON_ENCRYPTION:
450	case NG_HCI_OCF_CHANGE_CON_LINK_KEY:
451	case NG_HCI_OCF_MASTER_LINK_KEY:
452	case NG_HCI_OCF_REMOTE_NAME_REQ:
453	case NG_HCI_OCF_READ_REMOTE_FEATURES:
454	case NG_HCI_OCF_READ_REMOTE_VER_INFO:
455	case NG_HCI_OCF_READ_CLOCK_OFFSET:
456	default:
457
458		/*
459		 * None of these command was supposed to generate
460		 * Command_Complete event. Instead Command_Status event
461		 * should have been generated and then appropriate event
462		 * should have been sent to indicate the final result.
463		 */
464
465		error = EINVAL;
466		break;
467	}
468
469	NG_FREE_M(mcp);
470	NG_FREE_M(mrp);
471
472	return (error);
473} /* process_link_control_params */
474
475/*
476 * Process link policy command return parameters
477 */
478
479static int
480process_link_policy_params(ng_hci_unit_p unit, u_int16_t ocf,
481		struct mbuf *mcp, struct mbuf *mrp)
482{
483	int	error = 0;
484
485	switch (ocf){
486	case NG_HCI_OCF_ROLE_DISCOVERY: {
487		ng_hci_role_discovery_rp	*rp = NULL;
488		ng_hci_unit_con_t		*con = NULL;
489		u_int16_t			 h;
490
491		NG_HCI_M_PULLUP(mrp, sizeof(*rp));
492		if (mrp != NULL) {
493			rp = mtod(mrp, ng_hci_role_discovery_rp *);
494
495			h = NG_HCI_CON_HANDLE(le16toh(rp->con_handle));
496			con = ng_hci_con_by_handle(unit, h);
497			if (con == NULL) {
498				NG_HCI_ALERT(
499"%s: %s - invalid connection handle=%d\n",
500					__func__, NG_NODE_NAME(unit->node), h);
501				error = ENOENT;
502			} else if (con->link_type != NG_HCI_LINK_ACL) {
503				NG_HCI_ALERT(
504"%s: %s - invalid link type=%d\n", __func__, NG_NODE_NAME(unit->node),
505					con->link_type);
506				error = EINVAL;
507			} else
508				con->role = rp->role;
509		} else
510			error = ENOBUFS;
511		} break;
512
513	case NG_HCI_OCF_READ_LINK_POLICY_SETTINGS:
514	case NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS:
515		/* These do not need post processing */
516		break;
517
518	case NG_HCI_OCF_HOLD_MODE:
519	case NG_HCI_OCF_SNIFF_MODE:
520	case NG_HCI_OCF_EXIT_SNIFF_MODE:
521	case NG_HCI_OCF_PARK_MODE:
522	case NG_HCI_OCF_EXIT_PARK_MODE:
523	case NG_HCI_OCF_QOS_SETUP:
524	case NG_HCI_OCF_SWITCH_ROLE:
525	default:
526
527		/*
528		 * None of these command was supposed to generate
529		 * Command_Complete event. Instead Command_Status event
530		 * should have been generated and then appropriate event
531		 * should have been sent to indicate the final result.
532		 */
533
534		error = EINVAL;
535		break;
536	}
537
538	NG_FREE_M(mcp);
539	NG_FREE_M(mrp);
540
541	return (error);
542} /* process_link_policy_params */
543
544/*
545 * Process HC and baseband command return parameters
546 */
547
548int
549process_hc_baseband_params(ng_hci_unit_p unit, u_int16_t ocf,
550		struct mbuf *mcp, struct mbuf *mrp)
551{
552	int	error = 0;
553
554	switch (ocf) {
555	case NG_HCI_OCF_SET_EVENT_MASK:
556	case NG_HCI_OCF_SET_EVENT_FILTER:
557	case NG_HCI_OCF_FLUSH:	/* XXX Do we need to handle that? */
558	case NG_HCI_OCF_READ_PIN_TYPE:
559	case NG_HCI_OCF_WRITE_PIN_TYPE:
560	case NG_HCI_OCF_CREATE_NEW_UNIT_KEY:
561	case NG_HCI_OCF_WRITE_STORED_LINK_KEY:
562	case NG_HCI_OCF_WRITE_CON_ACCEPT_TIMO:
563	case NG_HCI_OCF_WRITE_PAGE_TIMO:
564	case NG_HCI_OCF_READ_SCAN_ENABLE:
565	case NG_HCI_OCF_WRITE_SCAN_ENABLE:
566	case NG_HCI_OCF_WRITE_PAGE_SCAN_ACTIVITY:
567	case NG_HCI_OCF_WRITE_INQUIRY_SCAN_ACTIVITY:
568	case NG_HCI_OCF_READ_AUTH_ENABLE:
569	case NG_HCI_OCF_WRITE_AUTH_ENABLE:
570	case NG_HCI_OCF_READ_ENCRYPTION_MODE:
571	case NG_HCI_OCF_WRITE_ENCRYPTION_MODE:
572	case NG_HCI_OCF_WRITE_VOICE_SETTINGS:
573	case NG_HCI_OCF_READ_NUM_BROADCAST_RETRANS:
574	case NG_HCI_OCF_WRITE_NUM_BROADCAST_RETRANS:
575	case NG_HCI_OCF_READ_HOLD_MODE_ACTIVITY:
576	case NG_HCI_OCF_WRITE_HOLD_MODE_ACTIVITY:
577	case NG_HCI_OCF_READ_SCO_FLOW_CONTROL:
578	case NG_HCI_OCF_WRITE_SCO_FLOW_CONTROL:
579	case NG_HCI_OCF_H2HC_FLOW_CONTROL: /* XXX Not supported this time */
580	case NG_HCI_OCF_HOST_BUFFER_SIZE:
581	case NG_HCI_OCF_READ_IAC_LAP:
582	case NG_HCI_OCF_WRITE_IAC_LAP:
583	case NG_HCI_OCF_READ_PAGE_SCAN_PERIOD:
584	case NG_HCI_OCF_WRITE_PAGE_SCAN_PERIOD:
585	case NG_HCI_OCF_READ_PAGE_SCAN:
586	case NG_HCI_OCF_WRITE_PAGE_SCAN:
587	case NG_HCI_OCF_READ_LINK_SUPERVISION_TIMO:
588	case NG_HCI_OCF_WRITE_LINK_SUPERVISION_TIMO:
589	case NG_HCI_OCF_READ_SUPPORTED_IAC_NUM:
590	case NG_HCI_OCF_READ_STORED_LINK_KEY:
591	case NG_HCI_OCF_DELETE_STORED_LINK_KEY:
592	case NG_HCI_OCF_READ_CON_ACCEPT_TIMO:
593	case NG_HCI_OCF_READ_PAGE_TIMO:
594	case NG_HCI_OCF_READ_PAGE_SCAN_ACTIVITY:
595	case NG_HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY:
596	case NG_HCI_OCF_READ_VOICE_SETTINGS:
597	case NG_HCI_OCF_READ_AUTO_FLUSH_TIMO:
598	case NG_HCI_OCF_WRITE_AUTO_FLUSH_TIMO:
599	case NG_HCI_OCF_READ_XMIT_LEVEL:
600	case NG_HCI_OCF_HOST_NUM_COMPL_PKTS:	/* XXX Can get here? */
601	case NG_HCI_OCF_CHANGE_LOCAL_NAME:
602	case NG_HCI_OCF_READ_LOCAL_NAME:
603	case NG_HCI_OCF_READ_UNIT_CLASS:
604	case NG_HCI_OCF_WRITE_UNIT_CLASS:
605		/* These do not need post processing */
606		break;
607
608	case NG_HCI_OCF_RESET: {
609		ng_hci_unit_con_p	con = NULL;
610		int			size;
611
612		/*
613		 * XXX
614		 *
615		 * After RESET command unit goes into standby mode
616		 * and all operational state is lost. Host controller
617		 * will revert to default values for all parameters.
618		 *
619		 * For now we shall terminate all connections and drop
620		 * inited bit. After RESET unit must be re-initialized.
621		 */
622
623		while (!LIST_EMPTY(&unit->con_list)) {
624			con = LIST_FIRST(&unit->con_list);
625
626			/* Remove all timeouts (if any) */
627			if (con->flags & NG_HCI_CON_TIMEOUT_PENDING)
628				ng_hci_con_untimeout(con);
629
630			/* Connection terminated by local host */
631			ng_hci_lp_discon_ind(con, 0x16);
632			ng_hci_free_con(con);
633		}
634
635		NG_HCI_BUFF_ACL_TOTAL(unit->buffer, size);
636		NG_HCI_BUFF_ACL_FREE(unit->buffer, size);
637
638		NG_HCI_BUFF_SCO_TOTAL(unit->buffer, size);
639		NG_HCI_BUFF_SCO_FREE(unit->buffer, size);
640
641		unit->state &= ~NG_HCI_UNIT_INITED;
642		} break;
643
644	default:
645		error = EINVAL;
646		break;
647	}
648
649	NG_FREE_M(mcp);
650	NG_FREE_M(mrp);
651
652	return (error);
653} /* process_hc_baseband_params */
654
655/*
656 * Process info command return parameters
657 */
658
659static int
660process_info_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp,
661		struct mbuf *mrp)
662{
663	int	error = 0, len;
664
665	switch (ocf) {
666	case NG_HCI_OCF_READ_LOCAL_VER:
667	case NG_HCI_OCF_READ_COUNTRY_CODE:
668		break;
669
670	case NG_HCI_OCF_READ_LOCAL_FEATURES:
671		m_adj(mrp, sizeof(u_int8_t));
672		len = min(mrp->m_pkthdr.len, sizeof(unit->features));
673		m_copydata(mrp, 0, len, (caddr_t) unit->features);
674		break;
675
676	case NG_HCI_OCF_READ_BUFFER_SIZE: {
677		ng_hci_read_buffer_size_rp	*rp = NULL;
678
679		/* Do not update buffer descriptor if node was initialized */
680		if ((unit->state & NG_HCI_UNIT_READY) == NG_HCI_UNIT_READY)
681			break;
682
683		NG_HCI_M_PULLUP(mrp, sizeof(*rp));
684		if (mrp != NULL) {
685			rp = mtod(mrp, ng_hci_read_buffer_size_rp *);
686
687			NG_HCI_BUFF_ACL_SET(
688				unit->buffer,
689				le16toh(rp->num_acl_pkt),  /* number */
690				le16toh(rp->max_acl_size), /* size */
691				le16toh(rp->num_acl_pkt)   /* free */
692			);
693
694			NG_HCI_BUFF_SCO_SET(
695				unit->buffer,
696				le16toh(rp->num_sco_pkt), /* number */
697				rp->max_sco_size,         /* size */
698				le16toh(rp->num_sco_pkt)  /* free */
699			);
700
701			/* Let upper layers know */
702			ng_hci_node_is_up(unit->node, unit->acl, NULL, 0);
703			ng_hci_node_is_up(unit->node, unit->sco, NULL, 0);
704		} else
705			error = ENOBUFS;
706		} break;
707
708	case NG_HCI_OCF_READ_BDADDR:
709		/* Do not update BD_ADDR if node was initialized */
710		if ((unit->state & NG_HCI_UNIT_READY) == NG_HCI_UNIT_READY)
711			break;
712
713		m_adj(mrp, sizeof(u_int8_t));
714		len = min(mrp->m_pkthdr.len, sizeof(unit->bdaddr));
715		m_copydata(mrp, 0, len, (caddr_t) &unit->bdaddr);
716
717		/* Let upper layers know */
718		ng_hci_node_is_up(unit->node, unit->acl, NULL, 0);
719		ng_hci_node_is_up(unit->node, unit->sco, NULL, 0);
720		break;
721
722	default:
723		error = EINVAL;
724		break;
725	}
726
727	NG_FREE_M(mcp);
728	NG_FREE_M(mrp);
729
730	return (error);
731} /* process_info_params */
732
733/*
734 * Process status command return parameters
735 */
736
737static int
738process_status_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp,
739		struct mbuf *mrp)
740{
741	int	error = 0;
742
743	switch (ocf) {
744	case NG_HCI_OCF_READ_FAILED_CONTACT_CNTR:
745	case NG_HCI_OCF_RESET_FAILED_CONTACT_CNTR:
746	case NG_HCI_OCF_GET_LINK_QUALITY:
747	case NG_HCI_OCF_READ_RSSI:
748		/* These do not need post processing */
749		break;
750
751	default:
752		error = EINVAL;
753		break;
754	}
755
756	NG_FREE_M(mcp);
757	NG_FREE_M(mrp);
758
759	return (error);
760} /* process_status_params */
761
762/*
763 * Process testing command return parameters
764 */
765
766int
767process_testing_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp,
768		struct mbuf *mrp)
769{
770	int	error = 0;
771
772	switch (ocf) {
773
774	/*
775	 * XXX FIXME
776	 * We do not support these features at this time. However,
777	 * HCI node could support this and do something smart. At least
778	 * node can change unit state.
779	 */
780
781	case NG_HCI_OCF_READ_LOOPBACK_MODE:
782	case NG_HCI_OCF_WRITE_LOOPBACK_MODE:
783	case NG_HCI_OCF_ENABLE_UNIT_UNDER_TEST:
784		break;
785
786	default:
787		error = EINVAL;
788		break;
789	}
790
791	NG_FREE_M(mcp);
792	NG_FREE_M(mrp);
793
794	return (error);
795} /* process_testing_params */
796
797/*
798 * Process link control command status
799 */
800
801static int
802process_link_control_status(ng_hci_unit_p unit, ng_hci_command_status_ep *ep,
803		struct mbuf *mcp)
804{
805	int	error = 0;
806
807	switch (NG_HCI_OCF(ep->opcode)) {
808	case NG_HCI_OCF_INQUIRY:
809	case NG_HCI_OCF_DISCON:		/* XXX */
810	case NG_HCI_OCF_REJECT_CON:	/* XXX */
811	case NG_HCI_OCF_CHANGE_CON_PKT_TYPE:
812	case NG_HCI_OCF_AUTH_REQ:
813	case NG_HCI_OCF_SET_CON_ENCRYPTION:
814	case NG_HCI_OCF_CHANGE_CON_LINK_KEY:
815	case NG_HCI_OCF_MASTER_LINK_KEY:
816	case NG_HCI_OCF_REMOTE_NAME_REQ:
817	case NG_HCI_OCF_READ_REMOTE_FEATURES:
818	case NG_HCI_OCF_READ_REMOTE_VER_INFO:
819	case NG_HCI_OCF_READ_CLOCK_OFFSET:
820		/* These do not need post processing */
821		break;
822
823	case NG_HCI_OCF_CREATE_CON:
824		break;
825
826	case NG_HCI_OCF_ADD_SCO_CON:
827		break;
828
829	case NG_HCI_OCF_ACCEPT_CON:
830		break;
831
832	case NG_HCI_OCF_INQUIRY_CANCEL:
833	case NG_HCI_OCF_PERIODIC_INQUIRY:
834	case NG_HCI_OCF_EXIT_PERIODIC_INQUIRY:
835	case NG_HCI_OCF_LINK_KEY_REP:
836	case NG_HCI_OCF_LINK_KEY_NEG_REP:
837	case NG_HCI_OCF_PIN_CODE_REP:
838	case NG_HCI_OCF_PIN_CODE_NEG_REP:
839	default:
840
841		/*
842		 * None of these command was supposed to generate
843		 * Command_Status event. Instead Command_Complete event
844		 * should have been sent.
845		 */
846
847		error = EINVAL;
848		break;
849	}
850
851	NG_FREE_M(mcp);
852
853	return (error);
854} /* process_link_control_status */
855
856/*
857 * Process link policy command status
858 */
859
860static int
861process_link_policy_status(ng_hci_unit_p unit, ng_hci_command_status_ep *ep,
862		struct mbuf *mcp)
863{
864	int	error = 0;
865
866	switch (NG_HCI_OCF(ep->opcode)) {
867	case NG_HCI_OCF_HOLD_MODE:
868	case NG_HCI_OCF_SNIFF_MODE:
869	case NG_HCI_OCF_EXIT_SNIFF_MODE:
870	case NG_HCI_OCF_PARK_MODE:
871	case NG_HCI_OCF_EXIT_PARK_MODE:
872	case NG_HCI_OCF_SWITCH_ROLE:
873		/* These do not need post processing */
874		break;
875
876	case NG_HCI_OCF_QOS_SETUP:
877		break;
878
879	case NG_HCI_OCF_ROLE_DISCOVERY:
880	case NG_HCI_OCF_READ_LINK_POLICY_SETTINGS:
881	case NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS:
882	default:
883
884		/*
885		 * None of these command was supposed to generate
886		 * Command_Status event. Instead Command_Complete event
887		 * should have been sent.
888		 */
889
890		error = EINVAL;
891		break;
892	}
893
894	NG_FREE_M(mcp);
895
896	return (error);
897} /* process_link_policy_status */
898
899