]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netgraph/bluetooth/hci/ng_hci_evnt.c
Update llvm to trunk r256633.
[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 #if 0
421                 {
422                         /* 
423                          * TODO: Make these information 
424                          * Available from userland.
425                          */
426                         u_int8_t length_data;
427                         
428                         char *rssi;
429                         
430                         NG_HCI_M_PULLUP(event, sizeof(u_int8_t));
431                         length_data = *mtod(event, u_int8_t *);
432                         m_adj(event, sizeof(u_int8_t));
433                         /*Advertizement data*/
434                         NG_HCI_M_PULLUP(event, length_data);
435                         m_adj(event, length_data);
436                         NG_HCI_M_PULLUP(event, sizeof(char ));
437                         /*Get RSSI*/
438                         rssi = mtod(event, char *);
439                         m_adj(event, sizeof(u_int8_t));
440                 }
441 #endif
442         }
443         NG_FREE_M(event);
444
445         return (error);
446 } /* inquiry_result */
447
448 static int le_connection_complete(ng_hci_unit_p unit, struct mbuf *event)
449 {
450         int                      error = 0;
451
452         ng_hci_le_connection_complete_ep        *ep = NULL;
453         ng_hci_unit_con_p        con = NULL;
454         int link_type;
455         uint8_t uclass[3] = {0,0,0};//dummy uclass
456
457         NG_HCI_M_PULLUP(event, sizeof(*ep));
458         if (event == NULL)
459                 return (ENOBUFS);
460
461         ep = mtod(event, ng_hci_le_connection_complete_ep *);
462         link_type = (ep->address_type)? NG_HCI_LINK_LE_RANDOM :
463           NG_HCI_LINK_LE_PUBLIC;
464         /*
465          * Find the first connection descriptor that matches the following:
466          *
467          * 1) con->link_type == link_type
468          * 2) con->state == NG_HCI_CON_W4_CONN_COMPLETE
469          * 3) con->bdaddr == ep->address
470          */
471         LIST_FOREACH(con, &unit->con_list, next)
472                 if (con->link_type == link_type &&
473                     con->state == NG_HCI_CON_W4_CONN_COMPLETE &&
474                     bcmp(&con->bdaddr, &ep->address, sizeof(bdaddr_t)) == 0)
475                         break;
476
477         /*
478          * Two possible cases:
479          *
480          * 1) We have found connection descriptor. That means upper layer has
481          *    requested this connection via LP_CON_REQ message. In this case
482          *    connection must have timeout set. If ng_hci_con_untimeout() fails
483          *    then timeout message already went into node's queue. In this case
484          *    ignore Connection_Complete event and let timeout deal with it.
485          *
486          * 2) We do not have connection descriptor. That means upper layer
487          *    nas not requested this connection , (less likely) we gave up
488          *    on this connection (timeout) or as node act as slave role.
489          *    The most likely scenario is that
490          *    we have received LE_Create_Connection command 
491          *    from the RAW hook
492          */
493
494         if (con == NULL) {
495                 if (ep->status != 0)
496                         goto out;
497
498                 con = ng_hci_new_con(unit, link_type);
499                 if (con == NULL) {
500                         error = ENOMEM;
501                         goto out;
502                 }
503
504                 con->state = NG_HCI_CON_W4_LP_CON_RSP;
505                 ng_hci_con_timeout(con);
506
507                 bcopy(&ep->address, &con->bdaddr, sizeof(con->bdaddr));
508                 error = ng_hci_lp_con_ind(con, uclass);
509                 if (error != 0) {
510                         ng_hci_con_untimeout(con);
511                         ng_hci_free_con(con);
512                 }
513
514         } else if ((error = ng_hci_con_untimeout(con)) != 0)
515                         goto out;
516
517         /*
518          * Update connection descriptor and send notification 
519          * to the upper layers.
520          */
521
522         con->con_handle = NG_HCI_CON_HANDLE(le16toh(ep->handle));
523         con->encryption_mode = NG_HCI_ENCRYPTION_MODE_NONE;
524
525         ng_hci_lp_con_cfm(con, ep->status);
526
527         /* Adjust connection state */
528         if (ep->status != 0)
529                 ng_hci_free_con(con);
530         else {
531                 con->state = NG_HCI_CON_OPEN;
532
533                 /*      
534                  * Change link policy for the ACL connections. Enable all 
535                  * supported link modes. Enable Role switch as well if
536                  * device supports it.
537                  */
538
539         }
540
541 out:
542         NG_FREE_M(event);
543
544         return (error);
545
546 }
547
548 static int le_connection_update(ng_hci_unit_p unit, struct mbuf *event)
549 {
550         int error = 0;
551         /*TBD*/
552         
553         NG_FREE_M(event);
554         return error;
555
556 }
557 static int
558 le_event(ng_hci_unit_p unit, struct mbuf *event)
559 {
560         int error = 0;
561         ng_hci_le_ep *lep;
562
563         NG_HCI_M_PULLUP(event, sizeof(*lep));
564         if(event ==NULL){
565                 return ENOBUFS;
566         }
567         lep = mtod(event, ng_hci_le_ep *);
568         m_adj(event, sizeof(*lep));
569         switch(lep->subevent_code){
570         case NG_HCI_LEEV_CON_COMPL:
571                 le_connection_complete(unit, event);
572                 break;
573         case NG_HCI_LEEV_ADVREP:
574                 le_advertizing_report(unit, event);
575                 break;
576         case NG_HCI_LEEV_CON_UPDATE_COMPL:
577                 le_connection_update(unit, event);
578                 break;
579         case NG_HCI_LEEV_READ_REMOTE_FEATURES_COMPL:
580                 //TBD
581           /*FALLTHROUGH*/
582         case NG_HCI_LEEV_LONG_TERM_KEY_REQUEST:
583                 //TBD
584           /*FALLTHROUGH*/
585         default:
586                 NG_FREE_M(event);
587         }
588         return error;
589 }
590
591 /* Inquiry result event */
592 static int
593 inquiry_result(ng_hci_unit_p unit, struct mbuf *event)
594 {
595         ng_hci_inquiry_result_ep        *ep = NULL;
596         ng_hci_neighbor_p                n = NULL;
597         bdaddr_t                         bdaddr;
598         int                              error = 0;
599
600         NG_HCI_M_PULLUP(event, sizeof(*ep));
601         if (event == NULL)
602                 return (ENOBUFS);
603
604         ep = mtod(event, ng_hci_inquiry_result_ep *);
605         m_adj(event, sizeof(*ep));
606
607         for (; ep->num_responses > 0; ep->num_responses --) {
608                 /* Get remote unit address */
609                 m_copydata(event, 0, sizeof(bdaddr), (caddr_t) &bdaddr);
610                 m_adj(event, sizeof(bdaddr));
611
612                 /* Lookup entry in the cache */
613                 n = ng_hci_get_neighbor(unit, &bdaddr, NG_HCI_LINK_ACL);
614                 if (n == NULL) {
615                         /* Create new entry */
616                         n = ng_hci_new_neighbor(unit);
617                         if (n == NULL) {
618                                 error = ENOMEM;
619                                 break;
620                         }
621                 } else
622                         getmicrotime(&n->updated);
623
624                 bcopy(&bdaddr, &n->bdaddr, sizeof(n->bdaddr));
625                 n->addrtype = NG_HCI_LINK_ACL;
626
627                 /* XXX call m_pullup here? */
628
629                 n->page_scan_rep_mode = *mtod(event, u_int8_t *);
630                 m_adj(event, sizeof(u_int8_t));
631
632                 /* page_scan_period_mode */
633                 m_adj(event, sizeof(u_int8_t));
634
635                 n->page_scan_mode = *mtod(event, u_int8_t *);
636                 m_adj(event, sizeof(u_int8_t));
637
638                 /* class */
639                 m_adj(event, NG_HCI_CLASS_SIZE);
640
641                 /* clock offset */
642                 m_copydata(event, 0, sizeof(n->clock_offset), 
643                         (caddr_t) &n->clock_offset);
644                 n->clock_offset = le16toh(n->clock_offset);
645         }
646
647         NG_FREE_M(event);
648
649         return (error);
650 } /* inquiry_result */
651
652 /* Connection complete event */
653 static int
654 con_compl(ng_hci_unit_p unit, struct mbuf *event)
655 {
656         ng_hci_con_compl_ep     *ep = NULL;
657         ng_hci_unit_con_p        con = NULL;
658         int                      error = 0;
659
660         NG_HCI_M_PULLUP(event, sizeof(*ep));
661         if (event == NULL)
662                 return (ENOBUFS);
663
664         ep = mtod(event, ng_hci_con_compl_ep *);
665
666         /*
667          * Find the first connection descriptor that matches the following:
668          *
669          * 1) con->link_type == ep->link_type
670          * 2) con->state == NG_HCI_CON_W4_CONN_COMPLETE
671          * 3) con->bdaddr == ep->bdaddr
672          */
673
674         LIST_FOREACH(con, &unit->con_list, next)
675                 if (con->link_type == ep->link_type &&
676                     con->state == NG_HCI_CON_W4_CONN_COMPLETE &&
677                     bcmp(&con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0)
678                         break;
679
680         /*
681          * Two possible cases:
682          *
683          * 1) We have found connection descriptor. That means upper layer has
684          *    requested this connection via LP_CON_REQ message. In this case
685          *    connection must have timeout set. If ng_hci_con_untimeout() fails
686          *    then timeout message already went into node's queue. In this case
687          *    ignore Connection_Complete event and let timeout deal with it.
688          *
689          * 2) We do not have connection descriptor. That means upper layer
690          *    nas not requested this connection or (less likely) we gave up
691          *    on this connection (timeout). The most likely scenario is that
692          *    we have received Create_Connection/Add_SCO_Connection command 
693          *    from the RAW hook
694          */
695
696         if (con == NULL) {
697                 if (ep->status != 0)
698                         goto out;
699
700                 con = ng_hci_new_con(unit, ep->link_type);
701                 if (con == NULL) {
702                         error = ENOMEM;
703                         goto out;
704                 }
705
706                 bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr));
707         } else if ((error = ng_hci_con_untimeout(con)) != 0)
708                         goto out;
709
710         /*
711          * Update connection descriptor and send notification 
712          * to the upper layers.
713          */
714
715         con->con_handle = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
716         con->encryption_mode = ep->encryption_mode;
717
718         ng_hci_lp_con_cfm(con, ep->status);
719
720         /* Adjust connection state */
721         if (ep->status != 0)
722                 ng_hci_free_con(con);
723         else {
724                 con->state = NG_HCI_CON_OPEN;
725
726                 /*      
727                  * Change link policy for the ACL connections. Enable all 
728                  * supported link modes. Enable Role switch as well if
729                  * device supports it.
730                  */
731
732                 if (ep->link_type == NG_HCI_LINK_ACL) {
733                         struct __link_policy {
734                                 ng_hci_cmd_pkt_t                         hdr;
735                                 ng_hci_write_link_policy_settings_cp     cp;
736                         } __attribute__ ((packed))                      *lp;
737                         struct mbuf                                     *m;
738
739                         MGETHDR(m, M_NOWAIT, MT_DATA);
740                         if (m != NULL) {
741                                 m->m_pkthdr.len = m->m_len = sizeof(*lp);
742                                 lp = mtod(m, struct __link_policy *);
743
744                                 lp->hdr.type = NG_HCI_CMD_PKT;
745                                 lp->hdr.opcode = htole16(NG_HCI_OPCODE(
746                                         NG_HCI_OGF_LINK_POLICY,
747                                         NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS));
748                                 lp->hdr.length = sizeof(lp->cp);
749
750                                 lp->cp.con_handle = ep->con_handle;
751
752                                 lp->cp.settings = 0;
753                                 if ((unit->features[0] & NG_HCI_LMP_SWITCH) &&
754                                     unit->role_switch)
755                                         lp->cp.settings |= 0x1;
756                                 if (unit->features[0] & NG_HCI_LMP_HOLD_MODE)
757                                         lp->cp.settings |= 0x2;
758                                 if (unit->features[0] & NG_HCI_LMP_SNIFF_MODE)
759                                         lp->cp.settings |= 0x4;
760                                 if (unit->features[1] & NG_HCI_LMP_PARK_MODE)
761                                         lp->cp.settings |= 0x8;
762
763                                 lp->cp.settings &= unit->link_policy_mask;
764                                 lp->cp.settings = htole16(lp->cp.settings);
765
766                                 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m);
767                                 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
768                                         ng_hci_send_command(unit);
769                         }
770                 }
771         }
772 out:
773         NG_FREE_M(event);
774
775         return (error);
776 } /* con_compl */
777
778 /* Connection request event */
779 static int
780 con_req(ng_hci_unit_p unit, struct mbuf *event)
781 {
782         ng_hci_con_req_ep       *ep = NULL;
783         ng_hci_unit_con_p        con = NULL;
784         int                      error = 0;
785
786         NG_HCI_M_PULLUP(event, sizeof(*ep));
787         if (event == NULL)
788                 return (ENOBUFS);
789
790         ep = mtod(event, ng_hci_con_req_ep *);
791
792         /*
793          * Find the first connection descriptor that matches the following:
794          *
795          * 1) con->link_type == ep->link_type
796          *
797          * 2) con->state == NG_HCI_CON_W4_LP_CON_RSP ||
798          *    con->state == NG_HCI_CON_W4_CONN_COMPL
799          * 
800          * 3) con->bdaddr == ep->bdaddr
801          *
802          * Possible cases:
803          *
804          * 1) We do not have connection descriptor. This is simple. Create
805          *    new fresh connection descriptor and send notification to the
806          *    appropriate upstream hook (based on link_type).
807          *
808          * 2) We found connection handle. This is more complicated.
809          * 
810          * 2.1) ACL links
811          *
812          *      Since only one ACL link can exist between each pair of
813          *      units then we have a race. Our upper layer has requested 
814          *      an ACL connection to the remote unit, but we did not send 
815          *      command yet. At the same time the remote unit has requested
816          *      an ACL connection from us. In this case we will ignore 
817          *      Connection_Request event. This probably will cause connect
818          *      failure on both units.
819          *
820          * 2.2) SCO links
821          *
822          *      The spec on page 45 says :
823          *
824          *      "The master can support up to three SCO links to the same 
825          *       slave or to different slaves. A slave can support up to 
826          *       three SCO links from the same master, or two SCO links if 
827          *       the links originate from different masters."
828          *
829          *      The only problem is how to handle multiple SCO links between
830          *      matster and slave. For now we will assume that multiple SCO
831          *      links MUST be opened one after another. 
832          */
833
834         LIST_FOREACH(con, &unit->con_list, next)
835                 if (con->link_type == ep->link_type &&
836                     (con->state == NG_HCI_CON_W4_LP_CON_RSP ||
837                      con->state == NG_HCI_CON_W4_CONN_COMPLETE) &&
838                     bcmp(&con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0)
839                         break;
840
841         if (con == NULL) {
842                 con = ng_hci_new_con(unit, ep->link_type);
843                 if (con != NULL) {
844                         bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr));
845
846                         con->state = NG_HCI_CON_W4_LP_CON_RSP;
847                         ng_hci_con_timeout(con);
848
849                         error = ng_hci_lp_con_ind(con, ep->uclass);
850                         if (error != 0) {
851                                 ng_hci_con_untimeout(con);
852                                 ng_hci_free_con(con);
853                         }
854                 } else
855                         error = ENOMEM;
856         }
857
858         NG_FREE_M(event);
859
860         return (error);
861 } /* con_req */
862
863 /* Disconnect complete event */
864 static int
865 discon_compl(ng_hci_unit_p unit, struct mbuf *event)
866 {
867         ng_hci_discon_compl_ep  *ep = NULL;
868         ng_hci_unit_con_p        con = NULL;
869         int                      error = 0;
870         u_int16_t                h;
871
872         NG_HCI_M_PULLUP(event, sizeof(*ep));
873         if (event == NULL)
874                 return (ENOBUFS);
875
876         ep = mtod(event, ng_hci_discon_compl_ep *);
877
878         /* 
879          * XXX 
880          * Do we have to send notification if ep->status != 0? 
881          * For now we will send notification for both ACL and SCO connections
882          * ONLY if ep->status == 0.
883          */
884
885         if (ep->status == 0) {
886                 h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
887                 con = ng_hci_con_by_handle(unit, h);
888                 if (con != NULL) {
889                         error = ng_hci_lp_discon_ind(con, ep->reason);
890
891                         /* Remove all timeouts (if any) */
892                         if (con->flags & NG_HCI_CON_TIMEOUT_PENDING)
893                                 ng_hci_con_untimeout(con);
894
895                         ng_hci_free_con(con);
896                 } else {
897                         NG_HCI_ALERT(
898 "%s: %s - invalid connection handle=%d\n",
899                                 __func__, NG_NODE_NAME(unit->node), h);
900                         error = ENOENT;
901                 }
902         }
903
904         NG_FREE_M(event);
905
906         return (error);
907 } /* discon_compl */
908
909 /* Encryption change event */
910 static int
911 encryption_change(ng_hci_unit_p unit, struct mbuf *event)
912 {
913         ng_hci_encryption_change_ep     *ep = NULL;
914         ng_hci_unit_con_p                con = NULL;
915         int                              error = 0;
916         u_int16_t       h;
917
918         NG_HCI_M_PULLUP(event, sizeof(*ep));
919         if (event == NULL)
920                 return (ENOBUFS);
921
922         ep = mtod(event, ng_hci_encryption_change_ep *);
923         h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
924         con = ng_hci_con_by_handle(unit, h);
925
926         if (ep->status == 0) {
927                 if (con == NULL) {
928                         NG_HCI_ALERT(
929 "%s: %s - invalid connection handle=%d\n",
930                                 __func__, NG_NODE_NAME(unit->node), h);
931                         error = ENOENT;
932                 } else if (con->link_type == NG_HCI_LINK_SCO) {
933                         NG_HCI_ALERT(
934 "%s: %s - invalid link type=%d\n",
935                                 __func__, NG_NODE_NAME(unit->node), 
936                                 con->link_type);
937                         error = EINVAL;
938                 } else if (ep->encryption_enable)
939                         /* XXX is that true? */
940                         con->encryption_mode = NG_HCI_ENCRYPTION_MODE_P2P;
941                 else
942                         con->encryption_mode = NG_HCI_ENCRYPTION_MODE_NONE;
943         } else
944                 NG_HCI_ERR(
945 "%s: %s - failed to change encryption mode, status=%d\n",
946                         __func__, NG_NODE_NAME(unit->node), ep->status);
947
948         /*Anyway, propagete encryption status to upper layer*/
949         ng_hci_lp_enc_change(con, con->encryption_mode);
950
951         NG_FREE_M(event);
952
953         return (error);
954 } /* encryption_change */
955
956 /* Read remote feature complete event */
957 static int
958 read_remote_features_compl(ng_hci_unit_p unit, struct mbuf *event)
959 {
960         ng_hci_read_remote_features_compl_ep    *ep = NULL;
961         ng_hci_unit_con_p                        con = NULL;
962         ng_hci_neighbor_p                        n = NULL;
963         u_int16_t                                h;
964         int                                      error = 0;
965
966         NG_HCI_M_PULLUP(event, sizeof(*ep));
967         if (event == NULL)
968                 return (ENOBUFS);
969
970         ep = mtod(event, ng_hci_read_remote_features_compl_ep *);
971
972         if (ep->status == 0) {
973                 /* Check if we have this connection handle */
974                 h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
975                 con = ng_hci_con_by_handle(unit, h);
976                 if (con == NULL) {
977                         NG_HCI_ALERT(
978 "%s: %s - invalid connection handle=%d\n",
979                                 __func__, NG_NODE_NAME(unit->node), h);
980                         error = ENOENT;
981                         goto out;
982                 }
983
984                 /* Update cache entry */
985                 n = ng_hci_get_neighbor(unit, &con->bdaddr, NG_HCI_LINK_ACL);
986                 if (n == NULL) {
987                         n = ng_hci_new_neighbor(unit);
988                         if (n == NULL) {
989                                 error = ENOMEM;
990                                 goto out;
991                         }
992
993                         bcopy(&con->bdaddr, &n->bdaddr, sizeof(n->bdaddr));
994                         n->addrtype = NG_HCI_LINK_ACL;
995                 } else
996                         getmicrotime(&n->updated);
997
998                 bcopy(ep->features, n->features, sizeof(n->features));
999         } else
1000                 NG_HCI_ERR(
1001 "%s: %s - failed to read remote unit features, status=%d\n",
1002                         __func__, NG_NODE_NAME(unit->node), ep->status);
1003 out:
1004         NG_FREE_M(event);
1005
1006         return (error);
1007 } /* read_remote_features_compl */
1008
1009 /* QoS setup complete event */
1010 static int
1011 qos_setup_compl(ng_hci_unit_p unit, struct mbuf *event)
1012 {
1013         ng_hci_qos_setup_compl_ep       *ep = NULL;
1014         ng_hci_unit_con_p                con = NULL;
1015         u_int16_t                        h;
1016         int                              error = 0;
1017
1018         NG_HCI_M_PULLUP(event, sizeof(*ep));
1019         if (event == NULL)
1020                 return (ENOBUFS);
1021
1022         ep = mtod(event, ng_hci_qos_setup_compl_ep *);
1023
1024         /* Check if we have this connection handle */
1025         h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
1026         con = ng_hci_con_by_handle(unit, h);
1027         if (con == NULL) {
1028                 NG_HCI_ALERT(
1029 "%s: %s - invalid connection handle=%d\n",
1030                         __func__, NG_NODE_NAME(unit->node), h);
1031                 error = ENOENT;
1032         } else if (con->link_type != NG_HCI_LINK_ACL) {
1033                 NG_HCI_ALERT(
1034 "%s: %s - invalid link type=%d, handle=%d\n",
1035                         __func__, NG_NODE_NAME(unit->node), con->link_type, h);
1036                 error = EINVAL;
1037         } else if (con->state != NG_HCI_CON_OPEN) {
1038                 NG_HCI_ALERT(
1039 "%s: %s - invalid connection state=%d, handle=%d\n",
1040                         __func__, NG_NODE_NAME(unit->node), 
1041                         con->state, h);
1042                 error = EINVAL;
1043         } else /* Notify upper layer */
1044                 error = ng_hci_lp_qos_cfm(con, ep->status);
1045
1046         NG_FREE_M(event);
1047
1048         return (error);
1049 } /* qos_setup_compl */
1050
1051 /* Hardware error event */
1052 static int
1053 hardware_error(ng_hci_unit_p unit, struct mbuf *event)
1054 {
1055         NG_HCI_ALERT(
1056 "%s: %s - hardware error %#x\n",
1057                 __func__, NG_NODE_NAME(unit->node), *mtod(event, u_int8_t *));
1058
1059         NG_FREE_M(event);
1060
1061         return (0);
1062 } /* hardware_error */
1063
1064 /* Role change event */
1065 static int
1066 role_change(ng_hci_unit_p unit, struct mbuf *event)
1067 {
1068         ng_hci_role_change_ep   *ep = NULL;
1069         ng_hci_unit_con_p        con = NULL;
1070
1071         NG_HCI_M_PULLUP(event, sizeof(*ep));
1072         if (event == NULL)
1073                 return (ENOBUFS);
1074
1075         ep = mtod(event, ng_hci_role_change_ep *);
1076
1077         if (ep->status == 0) {
1078                 /* XXX shoud we also change "role" for SCO connections? */
1079                 con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, NG_HCI_LINK_ACL);
1080                 if (con != NULL)
1081                         con->role = ep->role;
1082                 else
1083                         NG_HCI_ALERT(
1084 "%s: %s - ACL connection does not exist, bdaddr=%x:%x:%x:%x:%x:%x\n",
1085                                 __func__, NG_NODE_NAME(unit->node),
1086                                 ep->bdaddr.b[5], ep->bdaddr.b[4], 
1087                                 ep->bdaddr.b[3], ep->bdaddr.b[2], 
1088                                 ep->bdaddr.b[1], ep->bdaddr.b[0]);
1089         } else
1090                 NG_HCI_ERR(
1091 "%s: %s - failed to change role, status=%d, bdaddr=%x:%x:%x:%x:%x:%x\n",
1092                         __func__, NG_NODE_NAME(unit->node), ep->status,
1093                         ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3],
1094                         ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]);
1095
1096         NG_FREE_M(event);
1097
1098         return (0);
1099 } /* role_change */
1100
1101 /* Number of completed packets event */
1102 static int
1103 num_compl_pkts(ng_hci_unit_p unit, struct mbuf *event)
1104 {
1105         ng_hci_num_compl_pkts_ep        *ep = NULL;
1106         ng_hci_unit_con_p                con = NULL;
1107         u_int16_t                        h, p;
1108
1109         NG_HCI_M_PULLUP(event, sizeof(*ep));
1110         if (event == NULL)
1111                 return (ENOBUFS);
1112
1113         ep = mtod(event, ng_hci_num_compl_pkts_ep *);
1114         m_adj(event, sizeof(*ep));
1115
1116         for (; ep->num_con_handles > 0; ep->num_con_handles --) {
1117                 /* Get connection handle */
1118                 m_copydata(event, 0, sizeof(h), (caddr_t) &h);
1119                 m_adj(event, sizeof(h));
1120                 h = NG_HCI_CON_HANDLE(le16toh(h));
1121
1122                 /* Get number of completed packets */
1123                 m_copydata(event, 0, sizeof(p), (caddr_t) &p);
1124                 m_adj(event, sizeof(p));
1125                 p = le16toh(p);
1126
1127                 /* Check if we have this connection handle */
1128                 con = ng_hci_con_by_handle(unit, h);
1129                 if (con != NULL) {
1130                         con->pending -= p;
1131                         if (con->pending < 0) {
1132                                 NG_HCI_WARN(
1133 "%s: %s - pending packet counter is out of sync! " \
1134 "handle=%d, pending=%d, ncp=%d\n",      __func__, NG_NODE_NAME(unit->node), 
1135                                         con->con_handle, con->pending, p);
1136
1137                                 con->pending = 0;
1138                         }
1139
1140                         /* Update buffer descriptor */
1141                         if (con->link_type != NG_HCI_LINK_SCO)
1142                                 NG_HCI_BUFF_ACL_FREE(unit->buffer, p);
1143                         else 
1144                                 NG_HCI_BUFF_SCO_FREE(unit->buffer, p);
1145                 } else
1146                         NG_HCI_ALERT(
1147 "%s: %s - invalid connection handle=%d\n",
1148                                 __func__, NG_NODE_NAME(unit->node), h);
1149         }
1150
1151         NG_FREE_M(event);
1152
1153         /* Send more data */
1154         ng_hci_send_data(unit);
1155
1156         return (0);
1157 } /* num_compl_pkts */
1158
1159 /* Mode change event */
1160 static int
1161 mode_change(ng_hci_unit_p unit, struct mbuf *event)
1162 {
1163         ng_hci_mode_change_ep   *ep = NULL;
1164         ng_hci_unit_con_p        con = NULL;
1165         int                      error = 0;
1166         
1167         NG_HCI_M_PULLUP(event, sizeof(*ep));
1168         if (event == NULL)
1169                 return (ENOBUFS);
1170
1171         ep = mtod(event, ng_hci_mode_change_ep *);
1172
1173         if (ep->status == 0) {
1174                 u_int16_t       h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
1175
1176                 con = ng_hci_con_by_handle(unit, h);
1177                 if (con == NULL) {
1178                         NG_HCI_ALERT(
1179 "%s: %s - invalid connection handle=%d\n",
1180                                 __func__, NG_NODE_NAME(unit->node), h);
1181                         error = ENOENT;
1182                 } else if (con->link_type != NG_HCI_LINK_ACL) {
1183                         NG_HCI_ALERT(
1184 "%s: %s - invalid link type=%d\n",
1185                                 __func__, NG_NODE_NAME(unit->node), 
1186                                 con->link_type);
1187                         error = EINVAL;
1188                 } else
1189                         con->mode = ep->unit_mode;
1190         } else
1191                 NG_HCI_ERR(
1192 "%s: %s - failed to change mode, status=%d\n",
1193                         __func__, NG_NODE_NAME(unit->node), ep->status);
1194
1195         NG_FREE_M(event);
1196
1197         return (error);
1198 } /* mode_change */
1199
1200 /* Data buffer overflow event */
1201 static int
1202 data_buffer_overflow(ng_hci_unit_p unit, struct mbuf *event)
1203 {
1204         NG_HCI_ALERT(
1205 "%s: %s - %s data buffer overflow\n",
1206                 __func__, NG_NODE_NAME(unit->node),
1207                 (*mtod(event, u_int8_t *) == NG_HCI_LINK_ACL)? "ACL" : "SCO");
1208
1209         NG_FREE_M(event);
1210
1211         return (0);
1212 } /* data_buffer_overflow */
1213
1214 /* Read clock offset complete event */
1215 static int
1216 read_clock_offset_compl(ng_hci_unit_p unit, struct mbuf *event)
1217 {
1218         ng_hci_read_clock_offset_compl_ep       *ep = NULL;
1219         ng_hci_unit_con_p                        con = NULL;
1220         ng_hci_neighbor_p                        n = NULL;
1221         int                                      error = 0;
1222
1223         NG_HCI_M_PULLUP(event, sizeof(*ep));
1224         if (event == NULL)
1225                 return (ENOBUFS);
1226
1227         ep = mtod(event, ng_hci_read_clock_offset_compl_ep *);
1228
1229         if (ep->status == 0) {
1230                 u_int16_t       h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
1231
1232                 con = ng_hci_con_by_handle(unit, h);
1233                 if (con == NULL) {
1234                         NG_HCI_ALERT(
1235 "%s: %s - invalid connection handle=%d\n",
1236                                 __func__, NG_NODE_NAME(unit->node), h);
1237                         error = ENOENT;
1238                         goto out;
1239                 }
1240
1241                 /* Update cache entry */
1242                 n = ng_hci_get_neighbor(unit, &con->bdaddr, NG_HCI_LINK_ACL);
1243                 if (n == NULL) {
1244                         n = ng_hci_new_neighbor(unit);
1245                         if (n == NULL) {
1246                                 error = ENOMEM;
1247                                 goto out;
1248                         }
1249
1250                         bcopy(&con->bdaddr, &n->bdaddr, sizeof(n->bdaddr));
1251                         n->addrtype = NG_HCI_LINK_ACL;
1252                 } else
1253                         getmicrotime(&n->updated);
1254
1255                 n->clock_offset = le16toh(ep->clock_offset);
1256         } else
1257                 NG_HCI_ERR(
1258 "%s: %s - failed to Read Remote Clock Offset, status=%d\n",
1259                         __func__, NG_NODE_NAME(unit->node), ep->status);
1260 out:
1261         NG_FREE_M(event);
1262
1263         return (error);
1264 } /* read_clock_offset_compl */
1265
1266 /* QoS violation event */
1267 static int
1268 qos_violation(ng_hci_unit_p unit, struct mbuf *event)
1269 {
1270         ng_hci_qos_violation_ep *ep = NULL;
1271         ng_hci_unit_con_p        con = NULL;
1272         u_int16_t                h;
1273         int                      error = 0;
1274
1275         NG_HCI_M_PULLUP(event, sizeof(*ep));
1276         if (event == NULL)
1277                 return (ENOBUFS);
1278
1279         ep = mtod(event, ng_hci_qos_violation_ep *);
1280
1281         /* Check if we have this connection handle */
1282         h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle));
1283         con = ng_hci_con_by_handle(unit, h);
1284         if (con == NULL) {
1285                 NG_HCI_ALERT(
1286 "%s: %s - invalid connection handle=%d\n",
1287                         __func__, NG_NODE_NAME(unit->node), h);
1288                 error = ENOENT;
1289         } else if (con->link_type != NG_HCI_LINK_ACL) {
1290                 NG_HCI_ALERT(
1291 "%s: %s - invalid link type=%d\n",
1292                         __func__, NG_NODE_NAME(unit->node), con->link_type);
1293                 error = EINVAL;
1294         } else if (con->state != NG_HCI_CON_OPEN) {
1295                 NG_HCI_ALERT(
1296 "%s: %s - invalid connection state=%d, handle=%d\n",
1297                         __func__, NG_NODE_NAME(unit->node), con->state, h);
1298                 error = EINVAL;
1299         } else /* Notify upper layer */
1300                 error = ng_hci_lp_qos_ind(con); 
1301
1302         NG_FREE_M(event);
1303
1304         return (error);
1305 } /* qos_violation */
1306
1307 /* Page scan mode change event */
1308 static int
1309 page_scan_mode_change(ng_hci_unit_p unit, struct mbuf *event)
1310 {
1311         ng_hci_page_scan_mode_change_ep *ep = NULL;
1312         ng_hci_neighbor_p                n = NULL;
1313         int                              error = 0;
1314
1315         NG_HCI_M_PULLUP(event, sizeof(*ep));
1316         if (event == NULL)
1317                 return (ENOBUFS);
1318
1319         ep = mtod(event, ng_hci_page_scan_mode_change_ep *);
1320
1321         /* Update cache entry */
1322         n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL);
1323         if (n == NULL) {
1324                 n = ng_hci_new_neighbor(unit);
1325                 if (n == NULL) {
1326                         error = ENOMEM;
1327                         goto out;
1328                 }
1329
1330                 bcopy(&ep->bdaddr, &n->bdaddr, sizeof(n->bdaddr));
1331                 n->addrtype = NG_HCI_LINK_ACL;
1332         } else
1333                 getmicrotime(&n->updated);
1334
1335         n->page_scan_mode = ep->page_scan_mode;
1336 out:
1337         NG_FREE_M(event);
1338
1339         return (error);
1340 } /* page_scan_mode_change */
1341
1342 /* Page scan repetition mode change event */
1343 static int
1344 page_scan_rep_mode_change(ng_hci_unit_p unit, struct mbuf *event)
1345 {
1346         ng_hci_page_scan_rep_mode_change_ep     *ep = NULL;
1347         ng_hci_neighbor_p                        n = NULL;
1348         int                                      error = 0;
1349
1350         NG_HCI_M_PULLUP(event, sizeof(*ep));
1351         if (event == NULL)
1352                 return (ENOBUFS);
1353
1354         ep = mtod(event, ng_hci_page_scan_rep_mode_change_ep *);
1355
1356         /* Update cache entry */
1357         n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL);
1358         if (n == NULL) {
1359                 n = ng_hci_new_neighbor(unit);
1360                 if (n == NULL) {
1361                         error = ENOMEM;
1362                         goto out;
1363                 }
1364
1365                 bcopy(&ep->bdaddr, &n->bdaddr, sizeof(n->bdaddr));
1366                 n->addrtype = NG_HCI_LINK_ACL;
1367         } else
1368                 getmicrotime(&n->updated);
1369
1370         n->page_scan_rep_mode = ep->page_scan_rep_mode;
1371 out:
1372         NG_FREE_M(event);
1373
1374         return (error);
1375 } /* page_scan_rep_mode_change */
1376