]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netgraph/bluetooth/hci/ng_hci_evnt.c
MFV r318946: 8021 ARC buf data scatter-ization
[FreeBSD/FreeBSD.git] / sys / netgraph / bluetooth / hci / ng_hci_evnt.c
1 /*
2  * ng_hci_evnt.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_evnt.c,v 1.6 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 event processing module
54  ******************************************************************************
55  ******************************************************************************/
56
57 /* 
58  * Event processing routines 
59  */
60
61 static int inquiry_result             (ng_hci_unit_p, struct mbuf *);
62 static int con_compl                  (ng_hci_unit_p, struct mbuf *);
63 static int con_req                    (ng_hci_unit_p, struct mbuf *);
64 static int discon_compl               (ng_hci_unit_p, struct mbuf *);
65 static int encryption_change          (ng_hci_unit_p, struct mbuf *);
66 static int read_remote_features_compl (ng_hci_unit_p, struct mbuf *);
67 static int qos_setup_compl            (ng_hci_unit_p, struct mbuf *);
68 static int hardware_error             (ng_hci_unit_p, struct mbuf *);
69 static int role_change                (ng_hci_unit_p, struct mbuf *);
70 static int num_compl_pkts             (ng_hci_unit_p, struct mbuf *);
71 static int mode_change                (ng_hci_unit_p, struct mbuf *);
72 static int data_buffer_overflow       (ng_hci_unit_p, struct mbuf *);
73 static int read_clock_offset_compl    (ng_hci_unit_p, struct mbuf *);
74 static int qos_violation              (ng_hci_unit_p, struct mbuf *);
75 static int page_scan_mode_change      (ng_hci_unit_p, struct mbuf *);
76 static int page_scan_rep_mode_change  (ng_hci_unit_p, struct mbuf *);
77 static int sync_con_queue             (ng_hci_unit_p, ng_hci_unit_con_p, int);
78 static int send_data_packets          (ng_hci_unit_p, int, int);
79 static int le_event                   (ng_hci_unit_p, struct mbuf *);
80
81 /*
82  * Process HCI event packet
83  */
84  
85 int
86 ng_hci_process_event(ng_hci_unit_p unit, struct mbuf *event)
87 {
88         ng_hci_event_pkt_t      *hdr = NULL;
89         int                      error = 0;
90
91         /* Get event packet header */
92         NG_HCI_M_PULLUP(event, sizeof(*hdr));
93         if (event == NULL)
94                 return (ENOBUFS);
95
96         hdr = mtod(event, ng_hci_event_pkt_t *);
97
98         NG_HCI_INFO(
99 "%s: %s - got HCI event=%#x, length=%d\n",
100                 __func__, NG_NODE_NAME(unit->node), hdr->event, hdr->length);
101
102         /* Get rid of event header and process event */
103         m_adj(event, sizeof(*hdr));
104
105         switch (hdr->event) {
106         case NG_HCI_EVENT_INQUIRY_COMPL:
107         case NG_HCI_EVENT_RETURN_LINK_KEYS:
108         case NG_HCI_EVENT_PIN_CODE_REQ:
109         case NG_HCI_EVENT_LINK_KEY_REQ:
110         case NG_HCI_EVENT_LINK_KEY_NOTIFICATION:
111         case NG_HCI_EVENT_LOOPBACK_COMMAND:
112         case NG_HCI_EVENT_AUTH_COMPL:
113         case NG_HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL:
114         case NG_HCI_EVENT_MASTER_LINK_KEY_COMPL:
115         case NG_HCI_EVENT_FLUSH_OCCUR:  /* XXX Do we have to handle it? */
116         case NG_HCI_EVENT_MAX_SLOT_CHANGE:
117         case NG_HCI_EVENT_CON_PKT_TYPE_CHANGED:
118         case NG_HCI_EVENT_BT_LOGO:
119         case NG_HCI_EVENT_VENDOR:
120         case NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL:
121         case NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL:
122                 /* These do not need post processing */
123                 NG_FREE_M(event);
124                 break;
125         case NG_HCI_EVENT_LE:
126                 error = le_event(unit, event);
127                 break;
128
129         case NG_HCI_EVENT_INQUIRY_RESULT:
130                 error = inquiry_result(unit, event);
131                 break;
132
133         case NG_HCI_EVENT_CON_COMPL:
134                 error = con_compl(unit, event);
135                 break;
136
137         case NG_HCI_EVENT_CON_REQ:
138                 error = con_req(unit, event);
139                 break;
140
141         case NG_HCI_EVENT_DISCON_COMPL:
142                 error = discon_compl(unit, event);
143                 break;
144
145         case NG_HCI_EVENT_ENCRYPTION_CHANGE:
146                 error = encryption_change(unit, event);
147                 break;
148
149         case NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL:
150                 error = read_remote_features_compl(unit, event);
151                 break;
152
153         case NG_HCI_EVENT_QOS_SETUP_COMPL:
154                 error = qos_setup_compl(unit, event);
155                 break;
156
157         case NG_HCI_EVENT_COMMAND_COMPL:
158                 error = ng_hci_process_command_complete(unit, event);
159                 break;
160
161         case NG_HCI_EVENT_COMMAND_STATUS:
162                 error = ng_hci_process_command_status(unit, event);
163                 break;
164
165         case NG_HCI_EVENT_HARDWARE_ERROR:
166                 error = hardware_error(unit, event);
167                 break;
168
169         case NG_HCI_EVENT_ROLE_CHANGE:
170                 error = role_change(unit, event);
171                 break;
172
173         case NG_HCI_EVENT_NUM_COMPL_PKTS:
174                 error = num_compl_pkts(unit, event);
175                 break;
176
177         case NG_HCI_EVENT_MODE_CHANGE:
178                 error = mode_change(unit, event);
179                 break;
180
181         case NG_HCI_EVENT_DATA_BUFFER_OVERFLOW:
182                 error = data_buffer_overflow(unit, event);
183                 break;
184
185         case NG_HCI_EVENT_READ_CLOCK_OFFSET_COMPL:
186                 error = read_clock_offset_compl(unit, event);
187                 break;
188
189         case NG_HCI_EVENT_QOS_VIOLATION:
190                 error = qos_violation(unit, event);
191                 break;
192
193         case NG_HCI_EVENT_PAGE_SCAN_MODE_CHANGE:
194                 error = page_scan_mode_change(unit, event);
195                 break;
196
197         case NG_HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE:
198                 error = page_scan_rep_mode_change(unit, event);
199                 break;
200
201         default:
202                 NG_FREE_M(event);
203                 error = EINVAL;
204                 break;
205         }
206
207         return (error);
208 } /* ng_hci_process_event */
209
210 /*
211  * Send ACL and/or SCO data to the unit driver
212  */
213
214 void
215 ng_hci_send_data(ng_hci_unit_p unit)
216 {
217         int     count;
218
219         /* Send ACL data */
220         NG_HCI_BUFF_ACL_AVAIL(unit->buffer, count);
221
222         NG_HCI_INFO(
223 "%s: %s - sending ACL data packets, count=%d\n",
224                 __func__, NG_NODE_NAME(unit->node), count);
225
226         if (count > 0) {
227                 count = send_data_packets(unit, NG_HCI_LINK_ACL, count);
228                 NG_HCI_STAT_ACL_SENT(unit->stat, count);
229                 NG_HCI_BUFF_ACL_USE(unit->buffer, count);
230         }
231
232         /* Send SCO data */
233         NG_HCI_BUFF_SCO_AVAIL(unit->buffer, count);
234
235         NG_HCI_INFO(
236 "%s: %s - sending SCO data packets, count=%d\n",
237                 __func__, NG_NODE_NAME(unit->node), count);
238
239         if (count > 0) {
240                 count = send_data_packets(unit, NG_HCI_LINK_SCO, count);
241                 NG_HCI_STAT_SCO_SENT(unit->stat, count);
242                 NG_HCI_BUFF_SCO_USE(unit->buffer, count);
243         }
244 } /* ng_hci_send_data */
245
246 /*
247  * Send data packets to the lower layer.
248  */
249
250 static int
251 send_data_packets(ng_hci_unit_p unit, int link_type, int limit)
252 {
253         ng_hci_unit_con_p       con = NULL, winner = NULL;
254         int                     reallink_type;
255         item_p                  item = NULL;
256         int                     min_pending, total_sent, sent, error, v;
257
258         for (total_sent = 0; limit > 0; ) {
259                 min_pending = 0x0fffffff;
260                 winner = NULL;
261
262                 /*
263                  * Find the connection that has has data to send 
264                  * and the smallest number of pending packets
265                  */
266
267                 LIST_FOREACH(con, &unit->con_list, next) {
268                         reallink_type = (con->link_type == NG_HCI_LINK_SCO)?
269                                 NG_HCI_LINK_SCO: NG_HCI_LINK_ACL;
270                         if (reallink_type != link_type){
271                                 continue;
272                         }
273                         if (NG_BT_ITEMQ_LEN(&con->conq) == 0)
274                                 continue;
275         
276                         if (con->pending < min_pending) {
277                                 winner = con;
278                                 min_pending = con->pending;
279                         }
280                 }
281
282                 if (winner == NULL)
283                         break;
284
285                 /* 
286                  * OK, we have a winner now send as much packets as we can
287                  * Count the number of packets we have sent and then sync
288                  * winner connection queue.
289                  */
290
291                 for (sent = 0; limit > 0; limit --, total_sent ++, sent ++) {
292                         NG_BT_ITEMQ_DEQUEUE(&winner->conq, item);
293                         if (item == NULL)
294                                 break;
295                 
296                         NG_HCI_INFO(
297 "%s: %s - sending data packet, handle=%d, len=%d\n",
298                                 __func__, NG_NODE_NAME(unit->node), 
299                                 winner->con_handle, NGI_M(item)->m_pkthdr.len);
300
301                         /* Check if driver hook still there */
302                         v = (unit->drv != NULL && NG_HOOK_IS_VALID(unit->drv));
303                         if (!v || (unit->state & NG_HCI_UNIT_READY) != 
304                                         NG_HCI_UNIT_READY) {
305                                 NG_HCI_ERR(
306 "%s: %s - could not send data. Hook \"%s\" is %svalid, state=%#x\n",
307                                         __func__, NG_NODE_NAME(unit->node),
308                                         NG_HCI_HOOK_DRV, ((v)? "" : "not "),
309                                         unit->state);
310
311                                 NG_FREE_ITEM(item);
312                                 error = ENOTCONN;
313                         } else {
314                                 v = NGI_M(item)->m_pkthdr.len;
315
316                                 /* Give packet to raw hook */
317                                 ng_hci_mtap(unit, NGI_M(item));
318
319                                 /* ... and forward item to the driver */
320                                 NG_FWD_ITEM_HOOK(error, item, unit->drv);
321                         }
322
323                         if (error != 0) {
324                                 NG_HCI_ERR(
325 "%s: %s - could not send data packet, handle=%d, error=%d\n",
326                                         __func__, NG_NODE_NAME(unit->node),
327                                         winner->con_handle, error);
328                                 break;
329                         }
330
331                         winner->pending ++;
332                         NG_HCI_STAT_BYTES_SENT(unit->stat, v);
333                 }
334
335                 /*
336                  * Sync connection queue for the winner
337                  */
338                 sync_con_queue(unit, winner, sent);
339         }
340
341         return (total_sent);
342 } /* send_data_packets */
343
344 /*
345  * Send flow control messages to the upper layer
346  */
347
348 static int
349 sync_con_queue(ng_hci_unit_p unit, ng_hci_unit_con_p con, int completed)
350 {
351         hook_p                           hook = NULL;
352         struct ng_mesg                  *msg = NULL;
353         ng_hci_sync_con_queue_ep        *state = NULL;
354         int                              error;
355
356         hook = (con->link_type != NG_HCI_LINK_SCO)? unit->acl : unit->sco;
357         if (hook == NULL || NG_HOOK_NOT_VALID(hook))
358                 return (ENOTCONN);
359
360         NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_SYNC_CON_QUEUE,
361                 sizeof(*state), M_NOWAIT);
362         if (msg == NULL)
363                 return (ENOMEM);
364
365         state = (ng_hci_sync_con_queue_ep *)(msg->data);
366         state->con_handle = con->con_handle;
367         state->completed = completed;
368
369         NG_SEND_MSG_HOOK(error, unit->node, msg, hook, 0);
370
371         return (error);
372 } /* sync_con_queue */
373 /* le meta event */
374 /* Inquiry result event */
375 static int
376 le_advertizing_report(ng_hci_unit_p unit, struct mbuf *event)
377 {
378         ng_hci_le_advertising_report_ep *ep = NULL;
379         ng_hci_neighbor_p                n = NULL;
380         bdaddr_t                         bdaddr;
381         int                              error = 0;
382         u_int8_t event_type;
383         u_int8_t addr_type;
384
385         NG_HCI_M_PULLUP(event, sizeof(*ep));
386         if (event == NULL)
387                 return (ENOBUFS);
388
389         ep = mtod(event, ng_hci_le_advertising_report_ep *);
390         m_adj(event, sizeof(*ep));
391
392         for (; ep->num_reports > 0; ep->num_reports --) {
393                 /* Get remote unit address */
394                 NG_HCI_M_PULLUP(event, sizeof(u_int8_t));
395                 event_type = *mtod(event, u_int8_t *);
396                 m_adj(event, sizeof(u_int8_t));
397                 NG_HCI_M_PULLUP(event, sizeof(u_int8_t));
398                 addr_type = *mtod(event, u_int8_t *);
399                 m_adj(event, sizeof(u_int8_t));
400
401                 m_copydata(event, 0, sizeof(bdaddr), (caddr_t) &bdaddr);
402                 m_adj(event, sizeof(bdaddr));
403                 
404                 /* Lookup entry in the cache */
405                 n = ng_hci_get_neighbor(unit, &bdaddr, (addr_type) ? NG_HCI_LINK_LE_RANDOM:NG_HCI_LINK_LE_PUBLIC);
406                 if (n == NULL) {
407                         /* Create new entry */
408                         n = ng_hci_new_neighbor(unit);
409                         if (n == NULL) {
410                                 error = ENOMEM;
411                                 break;
412                         }
413                         bcopy(&bdaddr, &n->bdaddr, sizeof(n->bdaddr));
414                         n->addrtype = (addr_type)? NG_HCI_LINK_LE_RANDOM :
415                           NG_HCI_LINK_LE_PUBLIC;
416                         
417                 } else
418                         getmicrotime(&n->updated);
419                 
420                 {
421                         /* 
422                          * TODO: Make these information 
423                          * Available from userland.
424                          */
425                         u_int8_t length_data;
426                         
427                         event = m_pullup(event, sizeof(u_int8_t));
428                         if(event == NULL){
429                                 NG_HCI_WARN("%s: Event datasize Pullup Failed\n", __func__);
430                                 goto out;
431                         }
432                         length_data = *mtod(event, u_int8_t *);
433                         m_adj(event, sizeof(u_int8_t));
434                         n->extinq_size = (length_data < NG_HCI_EXTINQ_MAX)?
435                                 length_data : NG_HCI_EXTINQ_MAX;
436                         
437                         /*Advertizement data*/
438                         event = m_pullup(event, n->extinq_size);
439                         if(event == NULL){
440                                 NG_HCI_WARN("%s: Event data pullup Failed\n", __func__);
441                                 goto out;
442                         }
443                         m_copydata(event, 0, n->extinq_size, n->extinq_data);
444                         m_adj(event, n->extinq_size);
445                         event = m_pullup(event, sizeof(char ));
446                         /*Get RSSI*/
447                         if(event == NULL){
448                                 NG_HCI_WARN("%s: Event rssi pull up Failed\n", __func__);
449                                 
450                                 goto out;
451                         }                               
452                         n->page_scan_mode = *mtod(event, char *);
453                         m_adj(event, sizeof(u_int8_t));
454                 }
455         }
456  out:
457         NG_FREE_M(event);
458
459         return (error);
460 } /* inquiry_result */
461
462 static int le_connection_complete(ng_hci_unit_p unit, struct mbuf *event)
463 {
464         int                      error = 0;
465
466         ng_hci_le_connection_complete_ep        *ep = NULL;
467         ng_hci_unit_con_p        con = NULL;
468         int link_type;
469         uint8_t uclass[3] = {0,0,0};//dummy uclass
470
471         NG_HCI_M_PULLUP(event, sizeof(*ep));
472         if (event == NULL)
473                 return (ENOBUFS);
474
475         ep = mtod(event, ng_hci_le_connection_complete_ep *);
476         link_type = (ep->address_type)? NG_HCI_LINK_LE_RANDOM :
477           NG_HCI_LINK_LE_PUBLIC;
478         /*
479          * Find the first connection descriptor that matches the following:
480          *
481          * 1) con->link_type == link_type
482          * 2) con->state == NG_HCI_CON_W4_CONN_COMPLETE
483          * 3) con->bdaddr == ep->address
484          */
485         LIST_FOREACH(con, &unit->con_list, next)
486                 if (con->link_type == link_type &&
487                     con->state == NG_HCI_CON_W4_CONN_COMPLETE &&
488                     bcmp(&con->bdaddr, &ep->address, sizeof(bdaddr_t)) == 0)
489                         break;
490
491         /*
492          * Two possible cases:
493          *
494          * 1) We have found connection descriptor. That means upper layer has
495          *    requested this connection via LP_CON_REQ message. In this case
496          *    connection must have timeout set. If ng_hci_con_untimeout() fails
497          *    then timeout message already went into node's queue. In this case
498          *    ignore Connection_Complete event and let timeout deal with it.
499          *
500          * 2) We do not have connection descriptor. That means upper layer
501          *    nas not requested this connection , (less likely) we gave up
502          *    on this connection (timeout) or as node act as slave role.
503          *    The most likely scenario is that
504          *    we have received LE_Create_Connection command 
505          *    from the RAW hook
506          */
507
508         if (con == NULL) {
509                 if (ep->status != 0)
510                         goto out;
511
512                 con = ng_hci_new_con(unit, link_type);
513                 if (con == NULL) {
514                         error = ENOMEM;
515                         goto out;
516                 }
517
518                 con->state = NG_HCI_CON_W4_LP_CON_RSP;
519                 ng_hci_con_timeout(con);
520
521                 bcopy(&ep->address, &con->bdaddr, sizeof(con->bdaddr));
522                 error = ng_hci_lp_con_ind(con, uclass);
523                 if (error != 0) {
524                         ng_hci_con_untimeout(con);
525                         ng_hci_free_con(con);
526                 }
527
528         } else if ((error = ng_hci_con_untimeout(con)) != 0)
529                         goto out;
530
531         /*
532          * Update connection descriptor and send notification 
533          * to the upper layers.
534          */
535
536         con->con_handle = NG_HCI_CON_HANDLE(le16toh(ep->handle));
537         con->encryption_mode = NG_HCI_ENCRYPTION_MODE_NONE;
538
539         ng_hci_lp_con_cfm(con, ep->status);
540
541         /* Adjust connection state */
542         if (ep->status != 0)
543                 ng_hci_free_con(con);
544         else {
545                 con->state = NG_HCI_CON_OPEN;
546
547                 /*      
548                  * Change link policy for the ACL connections. Enable all 
549                  * supported link modes. Enable Role switch as well if
550                  * device supports it.
551                  */
552
553         }
554
555 out:
556         NG_FREE_M(event);
557
558         return (error);
559
560 }
561
562 static int le_connection_update(ng_hci_unit_p unit, struct mbuf *event)
563 {
564         int error = 0;
565         /*TBD*/
566         
567         NG_FREE_M(event);
568         return error;
569
570 }
571 static int
572 le_event(ng_hci_unit_p unit, struct mbuf *event)
573 {
574         int error = 0;
575         ng_hci_le_ep *lep;
576
577         NG_HCI_M_PULLUP(event, sizeof(*lep));
578         if(event ==NULL){
579                 return ENOBUFS;
580         }
581         lep = mtod(event, ng_hci_le_ep *);
582         m_adj(event, sizeof(*lep));
583         switch(lep->subevent_code){
584         case NG_HCI_LEEV_CON_COMPL:
585                 le_connection_complete(unit, event);
586                 break;
587         case NG_HCI_LEEV_ADVREP:
588                 le_advertizing_report(unit, event);
589                 break;
590         case NG_HCI_LEEV_CON_UPDATE_COMPL:
591                 le_connection_update(unit, event);
592                 break;
593         case NG_HCI_LEEV_READ_REMOTE_FEATURES_COMPL:
594                 //TBD
595           /*FALLTHROUGH*/
596         case NG_HCI_LEEV_LONG_TERM_KEY_REQUEST:
597                 //TBD
598           /*FALLTHROUGH*/
599         default:
600                 NG_FREE_M(event);
601         }
602         return error;
603 }
604
605 /* Inquiry result event */
606 static int
607 inquiry_result(ng_hci_unit_p unit, struct mbuf *event)
608 {
609         ng_hci_inquiry_result_ep        *ep = NULL;
610         ng_hci_neighbor_p                n = NULL;
611         bdaddr_t                         bdaddr;
612         int                              error = 0;
613
614         NG_HCI_M_PULLUP(event, sizeof(*ep));
615         if (event == NULL)
616                 return (ENOBUFS);
617
618         ep = mtod(event, ng_hci_inquiry_result_ep *);
619         m_adj(event, sizeof(*ep));
620
621         for (; ep->num_responses > 0; ep->num_responses --) {
622                 /* Get remote unit address */
623                 m_copydata(event, 0, sizeof(bdaddr), (caddr_t) &bdaddr);
624                 m_adj(event, sizeof(bdaddr));
625
626                 /* Lookup entry in the cache */
627                 n = ng_hci_get_neighbor(unit, &bdaddr, NG_HCI_LINK_ACL);
628                 if (n == NULL) {
629                         /* Create new entry */
630                         n = ng_hci_new_neighbor(unit);
631                         if (n == NULL) {
632                                 error = ENOMEM;
633                                 break;
634                         }
635                 } else
636                         getmicrotime(&n->updated);
637
638                 bcopy(&bdaddr, &n->bdaddr, sizeof(n->bdaddr));
639                 n->addrtype = NG_HCI_LINK_ACL;
640
641                 /* XXX call m_pullup here? */
642
643                 n->page_scan_rep_mode = *mtod(event, u_int8_t *);
644                 m_adj(event, sizeof(u_int8_t));
645
646                 /* page_scan_period_mode */
647                 m_adj(event, sizeof(u_int8_t));
648
649                 n->page_scan_mode = *mtod(event, u_int8_t *);
650                 m_adj(event, sizeof(u_int8_t));
651
652                 /* class */
653                 m_adj(event, NG_HCI_CLASS_SIZE);
654
655                 /* clock offset */
656                 m_copydata(event, 0, sizeof(n->clock_offset), 
657                         (caddr_t) &n->clock_offset);
658                 n->clock_offset = le16toh(n->clock_offset);
659         }
660
661         NG_FREE_M(event);
662
663         return (error);
664 } /* inquiry_result */
665
666 /* Connection complete event */
667 static int
668 con_compl(ng_hci_unit_p unit, struct mbuf *event)
669 {
670         ng_hci_con_compl_ep     *ep = NULL;
671         ng_hci_unit_con_p        con = NULL;
672         int                      error = 0;
673
674         NG_HCI_M_PULLUP(event, sizeof(*ep));
675         if (event == NULL)
676                 return (ENOBUFS);
677
678         ep = mtod(event, ng_hci_con_compl_ep *);
679
680         /*
681          * Find the first connection descriptor that matches the following:
682          *
683          * 1) con->link_type == ep->link_type
684          * 2) con->state == NG_HCI_CON_W4_CONN_COMPLETE
685          * 3) con->bdaddr == ep->bdaddr
686          */
687
688         LIST_FOREACH(con, &unit->con_list, next)
689                 if (con->link_type == ep->link_type &&
690                     con->state == NG_HCI_CON_W4_CONN_COMPLETE &&
691                     bcmp(&con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0)
692                         break;
693
694         /*
695          * Two possible cases:
696          *
697          * 1) We have found connection descriptor. That means upper layer has
698          *    requested this connection via LP_CON_REQ message. In this case
699          *    connection must have timeout set. If ng_hci_con_untimeout() fails
700          *    then timeout message already went into node's queue. In this case
701          *    ignore Connection_Complete event and let timeout deal with it.
702          *
703          * 2) We do not have connection descriptor. That means upper layer
704          *    nas not requested this connection or (less likely) we gave up
705          *    on this connection (timeout). The most likely scenario is that
706          *    we have received Create_Connection/Add_SCO_Connection command 
707          *    from the RAW hook
708          */
709
710         if (con == NULL) {
711                 if (ep->status != 0)
712                         goto out;
713
714                 con = ng_hci_new_con(unit, ep->link_type);
715                 if (con == NULL) {
716                         error = ENOMEM;
717                         goto out;
718                 }
719
720                 bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr));
721         } else if ((error = ng_hci_con_untimeout(con)) != 0)
722                         goto out;
723
724         /*
725          * Update connection descriptor and send notification 
726          * to the upper layers.
727          */
728
729         con->con_handle = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
730         con->encryption_mode = ep->encryption_mode;
731
732         ng_hci_lp_con_cfm(con, ep->status);
733
734         /* Adjust connection state */
735         if (ep->status != 0)
736                 ng_hci_free_con(con);
737         else {
738                 con->state = NG_HCI_CON_OPEN;
739
740                 /*      
741                  * Change link policy for the ACL connections. Enable all 
742                  * supported link modes. Enable Role switch as well if
743                  * device supports it.
744                  */
745
746                 if (ep->link_type == NG_HCI_LINK_ACL) {
747                         struct __link_policy {
748                                 ng_hci_cmd_pkt_t                         hdr;
749                                 ng_hci_write_link_policy_settings_cp     cp;
750                         } __attribute__ ((packed))                      *lp;
751                         struct mbuf                                     *m;
752
753                         MGETHDR(m, M_NOWAIT, MT_DATA);
754                         if (m != NULL) {
755                                 m->m_pkthdr.len = m->m_len = sizeof(*lp);
756                                 lp = mtod(m, struct __link_policy *);
757
758                                 lp->hdr.type = NG_HCI_CMD_PKT;
759                                 lp->hdr.opcode = htole16(NG_HCI_OPCODE(
760                                         NG_HCI_OGF_LINK_POLICY,
761                                         NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS));
762                                 lp->hdr.length = sizeof(lp->cp);
763
764                                 lp->cp.con_handle = ep->con_handle;
765
766                                 lp->cp.settings = 0;
767                                 if ((unit->features[0] & NG_HCI_LMP_SWITCH) &&
768                                     unit->role_switch)
769                                         lp->cp.settings |= 0x1;
770                                 if (unit->features[0] & NG_HCI_LMP_HOLD_MODE)
771                                         lp->cp.settings |= 0x2;
772                                 if (unit->features[0] & NG_HCI_LMP_SNIFF_MODE)
773                                         lp->cp.settings |= 0x4;
774                                 if (unit->features[1] & NG_HCI_LMP_PARK_MODE)
775                                         lp->cp.settings |= 0x8;
776
777                                 lp->cp.settings &= unit->link_policy_mask;
778                                 lp->cp.settings = htole16(lp->cp.settings);
779
780                                 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m);
781                                 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
782                                         ng_hci_send_command(unit);
783                         }
784                 }
785         }
786 out:
787         NG_FREE_M(event);
788
789         return (error);
790 } /* con_compl */
791
792 /* Connection request event */
793 static int
794 con_req(ng_hci_unit_p unit, struct mbuf *event)
795 {
796         ng_hci_con_req_ep       *ep = NULL;
797         ng_hci_unit_con_p        con = NULL;
798         int                      error = 0;
799
800         NG_HCI_M_PULLUP(event, sizeof(*ep));
801         if (event == NULL)
802                 return (ENOBUFS);
803
804         ep = mtod(event, ng_hci_con_req_ep *);
805
806         /*
807          * Find the first connection descriptor that matches the following:
808          *
809          * 1) con->link_type == ep->link_type
810          *
811          * 2) con->state == NG_HCI_CON_W4_LP_CON_RSP ||
812          *    con->state == NG_HCI_CON_W4_CONN_COMPL
813          * 
814          * 3) con->bdaddr == ep->bdaddr
815          *
816          * Possible cases:
817          *
818          * 1) We do not have connection descriptor. This is simple. Create
819          *    new fresh connection descriptor and send notification to the
820          *    appropriate upstream hook (based on link_type).
821          *
822          * 2) We found connection handle. This is more complicated.
823          * 
824          * 2.1) ACL links
825          *
826          *      Since only one ACL link can exist between each pair of
827          *      units then we have a race. Our upper layer has requested 
828          *      an ACL connection to the remote unit, but we did not send 
829          *      command yet. At the same time the remote unit has requested
830          *      an ACL connection from us. In this case we will ignore 
831          *      Connection_Request event. This probably will cause connect
832          *      failure on both units.
833          *
834          * 2.2) SCO links
835          *
836          *      The spec on page 45 says :
837          *
838          *      "The master can support up to three SCO links to the same 
839          *       slave or to different slaves. A slave can support up to 
840          *       three SCO links from the same master, or two SCO links if 
841          *       the links originate from different masters."
842          *
843          *      The only problem is how to handle multiple SCO links between
844          *      matster and slave. For now we will assume that multiple SCO
845          *      links MUST be opened one after another. 
846          */
847
848         LIST_FOREACH(con, &unit->con_list, next)
849                 if (con->link_type == ep->link_type &&
850                     (con->state == NG_HCI_CON_W4_LP_CON_RSP ||
851                      con->state == NG_HCI_CON_W4_CONN_COMPLETE) &&
852                     bcmp(&con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0)
853                         break;
854
855         if (con == NULL) {
856                 con = ng_hci_new_con(unit, ep->link_type);
857                 if (con != NULL) {
858                         bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr));
859
860                         con->state = NG_HCI_CON_W4_LP_CON_RSP;
861                         ng_hci_con_timeout(con);
862
863                         error = ng_hci_lp_con_ind(con, ep->uclass);
864                         if (error != 0) {
865                                 ng_hci_con_untimeout(con);
866                                 ng_hci_free_con(con);
867                         }
868                 } else
869                         error = ENOMEM;
870         }
871
872         NG_FREE_M(event);
873
874         return (error);
875 } /* con_req */
876
877 /* Disconnect complete event */
878 static int
879 discon_compl(ng_hci_unit_p unit, struct mbuf *event)
880 {
881         ng_hci_discon_compl_ep  *ep = NULL;
882         ng_hci_unit_con_p        con = NULL;
883         int                      error = 0;
884         u_int16_t                h;
885
886         NG_HCI_M_PULLUP(event, sizeof(*ep));
887         if (event == NULL)
888                 return (ENOBUFS);
889
890         ep = mtod(event, ng_hci_discon_compl_ep *);
891
892         /* 
893          * XXX 
894          * Do we have to send notification if ep->status != 0? 
895          * For now we will send notification for both ACL and SCO connections
896          * ONLY if ep->status == 0.
897          */
898
899         if (ep->status == 0) {
900                 h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
901                 con = ng_hci_con_by_handle(unit, h);
902                 if (con != NULL) {
903                         error = ng_hci_lp_discon_ind(con, ep->reason);
904
905                         /* Remove all timeouts (if any) */
906                         if (con->flags & NG_HCI_CON_TIMEOUT_PENDING)
907                                 ng_hci_con_untimeout(con);
908
909                         ng_hci_free_con(con);
910                 } else {
911                         NG_HCI_ALERT(
912 "%s: %s - invalid connection handle=%d\n",
913                                 __func__, NG_NODE_NAME(unit->node), h);
914                         error = ENOENT;
915                 }
916         }
917
918         NG_FREE_M(event);
919
920         return (error);
921 } /* discon_compl */
922
923 /* Encryption change event */
924 static int
925 encryption_change(ng_hci_unit_p unit, struct mbuf *event)
926 {
927         ng_hci_encryption_change_ep     *ep = NULL;
928         ng_hci_unit_con_p                con = NULL;
929         int                              error = 0;
930         u_int16_t       h;
931
932         NG_HCI_M_PULLUP(event, sizeof(*ep));
933         if (event == NULL)
934                 return (ENOBUFS);
935
936         ep = mtod(event, ng_hci_encryption_change_ep *);
937         h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
938         con = ng_hci_con_by_handle(unit, h);
939
940         if (ep->status == 0) {
941                 if (con == NULL) {
942                         NG_HCI_ALERT(
943 "%s: %s - invalid connection handle=%d\n",
944                                 __func__, NG_NODE_NAME(unit->node), h);
945                         error = ENOENT;
946                 } else if (con->link_type == NG_HCI_LINK_SCO) {
947                         NG_HCI_ALERT(
948 "%s: %s - invalid link type=%d\n",
949                                 __func__, NG_NODE_NAME(unit->node), 
950                                 con->link_type);
951                         error = EINVAL;
952                 } else if (ep->encryption_enable)
953                         /* XXX is that true? */
954                         con->encryption_mode = NG_HCI_ENCRYPTION_MODE_P2P;
955                 else
956                         con->encryption_mode = NG_HCI_ENCRYPTION_MODE_NONE;
957         } else
958                 NG_HCI_ERR(
959 "%s: %s - failed to change encryption mode, status=%d\n",
960                         __func__, NG_NODE_NAME(unit->node), ep->status);
961
962         /*Anyway, propagete encryption status to upper layer*/
963         ng_hci_lp_enc_change(con, con->encryption_mode);
964
965         NG_FREE_M(event);
966
967         return (error);
968 } /* encryption_change */
969
970 /* Read remote feature complete event */
971 static int
972 read_remote_features_compl(ng_hci_unit_p unit, struct mbuf *event)
973 {
974         ng_hci_read_remote_features_compl_ep    *ep = NULL;
975         ng_hci_unit_con_p                        con = NULL;
976         ng_hci_neighbor_p                        n = NULL;
977         u_int16_t                                h;
978         int                                      error = 0;
979
980         NG_HCI_M_PULLUP(event, sizeof(*ep));
981         if (event == NULL)
982                 return (ENOBUFS);
983
984         ep = mtod(event, ng_hci_read_remote_features_compl_ep *);
985
986         if (ep->status == 0) {
987                 /* Check if we have this connection handle */
988                 h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
989                 con = ng_hci_con_by_handle(unit, h);
990                 if (con == NULL) {
991                         NG_HCI_ALERT(
992 "%s: %s - invalid connection handle=%d\n",
993                                 __func__, NG_NODE_NAME(unit->node), h);
994                         error = ENOENT;
995                         goto out;
996                 }
997
998                 /* Update cache entry */
999                 n = ng_hci_get_neighbor(unit, &con->bdaddr, NG_HCI_LINK_ACL);
1000                 if (n == NULL) {
1001                         n = ng_hci_new_neighbor(unit);
1002                         if (n == NULL) {
1003                                 error = ENOMEM;
1004                                 goto out;
1005                         }
1006
1007                         bcopy(&con->bdaddr, &n->bdaddr, sizeof(n->bdaddr));
1008                         n->addrtype = NG_HCI_LINK_ACL;
1009                 } else
1010                         getmicrotime(&n->updated);
1011
1012                 bcopy(ep->features, n->features, sizeof(n->features));
1013         } else
1014                 NG_HCI_ERR(
1015 "%s: %s - failed to read remote unit features, status=%d\n",
1016                         __func__, NG_NODE_NAME(unit->node), ep->status);
1017 out:
1018         NG_FREE_M(event);
1019
1020         return (error);
1021 } /* read_remote_features_compl */
1022
1023 /* QoS setup complete event */
1024 static int
1025 qos_setup_compl(ng_hci_unit_p unit, struct mbuf *event)
1026 {
1027         ng_hci_qos_setup_compl_ep       *ep = NULL;
1028         ng_hci_unit_con_p                con = NULL;
1029         u_int16_t                        h;
1030         int                              error = 0;
1031
1032         NG_HCI_M_PULLUP(event, sizeof(*ep));
1033         if (event == NULL)
1034                 return (ENOBUFS);
1035
1036         ep = mtod(event, ng_hci_qos_setup_compl_ep *);
1037
1038         /* Check if we have this connection handle */
1039         h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
1040         con = ng_hci_con_by_handle(unit, h);
1041         if (con == NULL) {
1042                 NG_HCI_ALERT(
1043 "%s: %s - invalid connection handle=%d\n",
1044                         __func__, NG_NODE_NAME(unit->node), h);
1045                 error = ENOENT;
1046         } else if (con->link_type != NG_HCI_LINK_ACL) {
1047                 NG_HCI_ALERT(
1048 "%s: %s - invalid link type=%d, handle=%d\n",
1049                         __func__, NG_NODE_NAME(unit->node), con->link_type, h);
1050                 error = EINVAL;
1051         } else if (con->state != NG_HCI_CON_OPEN) {
1052                 NG_HCI_ALERT(
1053 "%s: %s - invalid connection state=%d, handle=%d\n",
1054                         __func__, NG_NODE_NAME(unit->node), 
1055                         con->state, h);
1056                 error = EINVAL;
1057         } else /* Notify upper layer */
1058                 error = ng_hci_lp_qos_cfm(con, ep->status);
1059
1060         NG_FREE_M(event);
1061
1062         return (error);
1063 } /* qos_setup_compl */
1064
1065 /* Hardware error event */
1066 static int
1067 hardware_error(ng_hci_unit_p unit, struct mbuf *event)
1068 {
1069         NG_HCI_ALERT(
1070 "%s: %s - hardware error %#x\n",
1071                 __func__, NG_NODE_NAME(unit->node), *mtod(event, u_int8_t *));
1072
1073         NG_FREE_M(event);
1074
1075         return (0);
1076 } /* hardware_error */
1077
1078 /* Role change event */
1079 static int
1080 role_change(ng_hci_unit_p unit, struct mbuf *event)
1081 {
1082         ng_hci_role_change_ep   *ep = NULL;
1083         ng_hci_unit_con_p        con = NULL;
1084
1085         NG_HCI_M_PULLUP(event, sizeof(*ep));
1086         if (event == NULL)
1087                 return (ENOBUFS);
1088
1089         ep = mtod(event, ng_hci_role_change_ep *);
1090
1091         if (ep->status == 0) {
1092                 /* XXX shoud we also change "role" for SCO connections? */
1093                 con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, NG_HCI_LINK_ACL);
1094                 if (con != NULL)
1095                         con->role = ep->role;
1096                 else
1097                         NG_HCI_ALERT(
1098 "%s: %s - ACL connection does not exist, bdaddr=%x:%x:%x:%x:%x:%x\n",
1099                                 __func__, NG_NODE_NAME(unit->node),
1100                                 ep->bdaddr.b[5], ep->bdaddr.b[4], 
1101                                 ep->bdaddr.b[3], ep->bdaddr.b[2], 
1102                                 ep->bdaddr.b[1], ep->bdaddr.b[0]);
1103         } else
1104                 NG_HCI_ERR(
1105 "%s: %s - failed to change role, status=%d, bdaddr=%x:%x:%x:%x:%x:%x\n",
1106                         __func__, NG_NODE_NAME(unit->node), ep->status,
1107                         ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3],
1108                         ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]);
1109
1110         NG_FREE_M(event);
1111
1112         return (0);
1113 } /* role_change */
1114
1115 /* Number of completed packets event */
1116 static int
1117 num_compl_pkts(ng_hci_unit_p unit, struct mbuf *event)
1118 {
1119         ng_hci_num_compl_pkts_ep        *ep = NULL;
1120         ng_hci_unit_con_p                con = NULL;
1121         u_int16_t                        h, p;
1122
1123         NG_HCI_M_PULLUP(event, sizeof(*ep));
1124         if (event == NULL)
1125                 return (ENOBUFS);
1126
1127         ep = mtod(event, ng_hci_num_compl_pkts_ep *);
1128         m_adj(event, sizeof(*ep));
1129
1130         for (; ep->num_con_handles > 0; ep->num_con_handles --) {
1131                 /* Get connection handle */
1132                 m_copydata(event, 0, sizeof(h), (caddr_t) &h);
1133                 m_adj(event, sizeof(h));
1134                 h = NG_HCI_CON_HANDLE(le16toh(h));
1135
1136                 /* Get number of completed packets */
1137                 m_copydata(event, 0, sizeof(p), (caddr_t) &p);
1138                 m_adj(event, sizeof(p));
1139                 p = le16toh(p);
1140
1141                 /* Check if we have this connection handle */
1142                 con = ng_hci_con_by_handle(unit, h);
1143                 if (con != NULL) {
1144                         con->pending -= p;
1145                         if (con->pending < 0) {
1146                                 NG_HCI_WARN(
1147 "%s: %s - pending packet counter is out of sync! " \
1148 "handle=%d, pending=%d, ncp=%d\n",      __func__, NG_NODE_NAME(unit->node), 
1149                                         con->con_handle, con->pending, p);
1150
1151                                 con->pending = 0;
1152                         }
1153
1154                         /* Update buffer descriptor */
1155                         if (con->link_type != NG_HCI_LINK_SCO)
1156                                 NG_HCI_BUFF_ACL_FREE(unit->buffer, p);
1157                         else 
1158                                 NG_HCI_BUFF_SCO_FREE(unit->buffer, p);
1159                 } else
1160                         NG_HCI_ALERT(
1161 "%s: %s - invalid connection handle=%d\n",
1162                                 __func__, NG_NODE_NAME(unit->node), h);
1163         }
1164
1165         NG_FREE_M(event);
1166
1167         /* Send more data */
1168         ng_hci_send_data(unit);
1169
1170         return (0);
1171 } /* num_compl_pkts */
1172
1173 /* Mode change event */
1174 static int
1175 mode_change(ng_hci_unit_p unit, struct mbuf *event)
1176 {
1177         ng_hci_mode_change_ep   *ep = NULL;
1178         ng_hci_unit_con_p        con = NULL;
1179         int                      error = 0;
1180         
1181         NG_HCI_M_PULLUP(event, sizeof(*ep));
1182         if (event == NULL)
1183                 return (ENOBUFS);
1184
1185         ep = mtod(event, ng_hci_mode_change_ep *);
1186
1187         if (ep->status == 0) {
1188                 u_int16_t       h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
1189
1190                 con = ng_hci_con_by_handle(unit, h);
1191                 if (con == NULL) {
1192                         NG_HCI_ALERT(
1193 "%s: %s - invalid connection handle=%d\n",
1194                                 __func__, NG_NODE_NAME(unit->node), h);
1195                         error = ENOENT;
1196                 } else if (con->link_type != NG_HCI_LINK_ACL) {
1197                         NG_HCI_ALERT(
1198 "%s: %s - invalid link type=%d\n",
1199                                 __func__, NG_NODE_NAME(unit->node), 
1200                                 con->link_type);
1201                         error = EINVAL;
1202                 } else
1203                         con->mode = ep->unit_mode;
1204         } else
1205                 NG_HCI_ERR(
1206 "%s: %s - failed to change mode, status=%d\n",
1207                         __func__, NG_NODE_NAME(unit->node), ep->status);
1208
1209         NG_FREE_M(event);
1210
1211         return (error);
1212 } /* mode_change */
1213
1214 /* Data buffer overflow event */
1215 static int
1216 data_buffer_overflow(ng_hci_unit_p unit, struct mbuf *event)
1217 {
1218         NG_HCI_ALERT(
1219 "%s: %s - %s data buffer overflow\n",
1220                 __func__, NG_NODE_NAME(unit->node),
1221                 (*mtod(event, u_int8_t *) == NG_HCI_LINK_ACL)? "ACL" : "SCO");
1222
1223         NG_FREE_M(event);
1224
1225         return (0);
1226 } /* data_buffer_overflow */
1227
1228 /* Read clock offset complete event */
1229 static int
1230 read_clock_offset_compl(ng_hci_unit_p unit, struct mbuf *event)
1231 {
1232         ng_hci_read_clock_offset_compl_ep       *ep = NULL;
1233         ng_hci_unit_con_p                        con = NULL;
1234         ng_hci_neighbor_p                        n = NULL;
1235         int                                      error = 0;
1236
1237         NG_HCI_M_PULLUP(event, sizeof(*ep));
1238         if (event == NULL)
1239                 return (ENOBUFS);
1240
1241         ep = mtod(event, ng_hci_read_clock_offset_compl_ep *);
1242
1243         if (ep->status == 0) {
1244                 u_int16_t       h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
1245
1246                 con = ng_hci_con_by_handle(unit, h);
1247                 if (con == NULL) {
1248                         NG_HCI_ALERT(
1249 "%s: %s - invalid connection handle=%d\n",
1250                                 __func__, NG_NODE_NAME(unit->node), h);
1251                         error = ENOENT;
1252                         goto out;
1253                 }
1254
1255                 /* Update cache entry */
1256                 n = ng_hci_get_neighbor(unit, &con->bdaddr, NG_HCI_LINK_ACL);
1257                 if (n == NULL) {
1258                         n = ng_hci_new_neighbor(unit);
1259                         if (n == NULL) {
1260                                 error = ENOMEM;
1261                                 goto out;
1262                         }
1263
1264                         bcopy(&con->bdaddr, &n->bdaddr, sizeof(n->bdaddr));
1265                         n->addrtype = NG_HCI_LINK_ACL;
1266                 } else
1267                         getmicrotime(&n->updated);
1268
1269                 n->clock_offset = le16toh(ep->clock_offset);
1270         } else
1271                 NG_HCI_ERR(
1272 "%s: %s - failed to Read Remote Clock Offset, status=%d\n",
1273                         __func__, NG_NODE_NAME(unit->node), ep->status);
1274 out:
1275         NG_FREE_M(event);
1276
1277         return (error);
1278 } /* read_clock_offset_compl */
1279
1280 /* QoS violation event */
1281 static int
1282 qos_violation(ng_hci_unit_p unit, struct mbuf *event)
1283 {
1284         ng_hci_qos_violation_ep *ep = NULL;
1285         ng_hci_unit_con_p        con = NULL;
1286         u_int16_t                h;
1287         int                      error = 0;
1288
1289         NG_HCI_M_PULLUP(event, sizeof(*ep));
1290         if (event == NULL)
1291                 return (ENOBUFS);
1292
1293         ep = mtod(event, ng_hci_qos_violation_ep *);
1294
1295         /* Check if we have this connection handle */
1296         h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
1297         con = ng_hci_con_by_handle(unit, h);
1298         if (con == NULL) {
1299                 NG_HCI_ALERT(
1300 "%s: %s - invalid connection handle=%d\n",
1301                         __func__, NG_NODE_NAME(unit->node), h);
1302                 error = ENOENT;
1303         } else if (con->link_type != NG_HCI_LINK_ACL) {
1304                 NG_HCI_ALERT(
1305 "%s: %s - invalid link type=%d\n",
1306                         __func__, NG_NODE_NAME(unit->node), con->link_type);
1307                 error = EINVAL;
1308         } else if (con->state != NG_HCI_CON_OPEN) {
1309                 NG_HCI_ALERT(
1310 "%s: %s - invalid connection state=%d, handle=%d\n",
1311                         __func__, NG_NODE_NAME(unit->node), con->state, h);
1312                 error = EINVAL;
1313         } else /* Notify upper layer */
1314                 error = ng_hci_lp_qos_ind(con); 
1315
1316         NG_FREE_M(event);
1317
1318         return (error);
1319 } /* qos_violation */
1320
1321 /* Page scan mode change event */
1322 static int
1323 page_scan_mode_change(ng_hci_unit_p unit, struct mbuf *event)
1324 {
1325         ng_hci_page_scan_mode_change_ep *ep = NULL;
1326         ng_hci_neighbor_p                n = NULL;
1327         int                              error = 0;
1328
1329         NG_HCI_M_PULLUP(event, sizeof(*ep));
1330         if (event == NULL)
1331                 return (ENOBUFS);
1332
1333         ep = mtod(event, ng_hci_page_scan_mode_change_ep *);
1334
1335         /* Update cache entry */
1336         n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL);
1337         if (n == NULL) {
1338                 n = ng_hci_new_neighbor(unit);
1339                 if (n == NULL) {
1340                         error = ENOMEM;
1341                         goto out;
1342                 }
1343
1344                 bcopy(&ep->bdaddr, &n->bdaddr, sizeof(n->bdaddr));
1345                 n->addrtype = NG_HCI_LINK_ACL;
1346         } else
1347                 getmicrotime(&n->updated);
1348
1349         n->page_scan_mode = ep->page_scan_mode;
1350 out:
1351         NG_FREE_M(event);
1352
1353         return (error);
1354 } /* page_scan_mode_change */
1355
1356 /* Page scan repetition mode change event */
1357 static int
1358 page_scan_rep_mode_change(ng_hci_unit_p unit, struct mbuf *event)
1359 {
1360         ng_hci_page_scan_rep_mode_change_ep     *ep = NULL;
1361         ng_hci_neighbor_p                        n = NULL;
1362         int                                      error = 0;
1363
1364         NG_HCI_M_PULLUP(event, sizeof(*ep));
1365         if (event == NULL)
1366                 return (ENOBUFS);
1367
1368         ep = mtod(event, ng_hci_page_scan_rep_mode_change_ep *);
1369
1370         /* Update cache entry */
1371         n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL);
1372         if (n == NULL) {
1373                 n = ng_hci_new_neighbor(unit);
1374                 if (n == NULL) {
1375                         error = ENOMEM;
1376                         goto out;
1377                 }
1378
1379                 bcopy(&ep->bdaddr, &n->bdaddr, sizeof(n->bdaddr));
1380                 n->addrtype = NG_HCI_LINK_ACL;
1381         } else
1382                 getmicrotime(&n->updated);
1383
1384         n->page_scan_rep_mode = ep->page_scan_rep_mode;
1385 out:
1386         NG_FREE_M(event);
1387
1388         return (error);
1389 } /* page_scan_rep_mode_change */
1390