Deleted Added
full compact
ng_hci_cmds.c (107120) ng_hci_cmds.c (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 $
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 107120 2002-11-20 23:01:59Z julian $
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
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_DONTWAIT);
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
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