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