6 * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
30 * $Id: ng_hci_evnt.c,v 1.6 2003/09/08 18:57:51 max Exp $
31 * $FreeBSD: src/sys/netgraph/bluetooth/hci/ng_hci_evnt.c,v 1.8 2005/01/07 01:45:43 imp Exp $
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>
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>
51 /******************************************************************************
52 ******************************************************************************
53 ** HCI event processing module
54 ******************************************************************************
55 ******************************************************************************/
58 * Event processing routines
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);
81 * Process HCI event packet
85 ng_hci_process_event(ng_hci_unit_p unit
, struct mbuf
*event
)
87 ng_hci_event_pkt_t
*hdr
= NULL
;
90 /* Get event packet header */
91 NG_HCI_M_PULLUP(event
, sizeof(*hdr
));
95 hdr
= mtod(event
, ng_hci_event_pkt_t
*);
98 "%s: %s - got HCI event=%#x, length=%d\n",
99 __func__
, NG_NODE_NAME(unit
->node
), hdr
->event
, hdr
->length
);
101 /* Get rid of event header and process event */
102 m_adj(event
, sizeof(*hdr
));
104 switch (hdr
->event
) {
105 case NG_HCI_EVENT_INQUIRY_COMPL
:
106 case NG_HCI_EVENT_RETURN_LINK_KEYS
:
107 case NG_HCI_EVENT_PIN_CODE_REQ
:
108 case NG_HCI_EVENT_LINK_KEY_REQ
:
109 case NG_HCI_EVENT_LINK_KEY_NOTIFICATION
:
110 case NG_HCI_EVENT_LOOPBACK_COMMAND
:
111 case NG_HCI_EVENT_AUTH_COMPL
:
112 case NG_HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL
:
113 case NG_HCI_EVENT_MASTER_LINK_KEY_COMPL
:
114 case NG_HCI_EVENT_FLUSH_OCCUR
: /* XXX Do we have to handle it? */
115 case NG_HCI_EVENT_MAX_SLOT_CHANGE
:
116 case NG_HCI_EVENT_CON_PKT_TYPE_CHANGED
:
117 case NG_HCI_EVENT_BT_LOGO
:
118 case NG_HCI_EVENT_VENDOR
:
119 case NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL
:
120 case NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL
:
121 /* These do not need post processing */
125 case NG_HCI_EVENT_INQUIRY_RESULT
:
126 error
= inquiry_result(unit
, event
);
129 case NG_HCI_EVENT_CON_COMPL
:
130 error
= con_compl(unit
, event
);
133 case NG_HCI_EVENT_CON_REQ
:
134 error
= con_req(unit
, event
);
137 case NG_HCI_EVENT_DISCON_COMPL
:
138 error
= discon_compl(unit
, event
);
141 case NG_HCI_EVENT_ENCRYPTION_CHANGE
:
142 error
= encryption_change(unit
, event
);
145 case NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL
:
146 error
= read_remote_features_compl(unit
, event
);
149 case NG_HCI_EVENT_QOS_SETUP_COMPL
:
150 error
= qos_setup_compl(unit
, event
);
153 case NG_HCI_EVENT_COMMAND_COMPL
:
154 error
= ng_hci_process_command_complete(unit
, event
);
157 case NG_HCI_EVENT_COMMAND_STATUS
:
158 error
= ng_hci_process_command_status(unit
, event
);
161 case NG_HCI_EVENT_HARDWARE_ERROR
:
162 error
= hardware_error(unit
, event
);
165 case NG_HCI_EVENT_ROLE_CHANGE
:
166 error
= role_change(unit
, event
);
169 case NG_HCI_EVENT_NUM_COMPL_PKTS
:
170 error
= num_compl_pkts(unit
, event
);
173 case NG_HCI_EVENT_MODE_CHANGE
:
174 error
= mode_change(unit
, event
);
177 case NG_HCI_EVENT_DATA_BUFFER_OVERFLOW
:
178 error
= data_buffer_overflow(unit
, event
);
181 case NG_HCI_EVENT_READ_CLOCK_OFFSET_COMPL
:
182 error
= read_clock_offset_compl(unit
, event
);
185 case NG_HCI_EVENT_QOS_VIOLATION
:
186 error
= qos_violation(unit
, event
);
189 case NG_HCI_EVENT_PAGE_SCAN_MODE_CHANGE
:
190 error
= page_scan_mode_change(unit
, event
);
193 case NG_HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE
:
194 error
= page_scan_rep_mode_change(unit
, event
);
204 } /* ng_hci_process_event */
207 * Send ACL and/or SCO data to the unit driver
211 ng_hci_send_data(ng_hci_unit_p unit
)
216 NG_HCI_BUFF_ACL_AVAIL(unit
->buffer
, count
);
219 "%s: %s - sending ACL data packets, count=%d\n",
220 __func__
, NG_NODE_NAME(unit
->node
), count
);
223 count
= send_data_packets(unit
, NG_HCI_LINK_ACL
, count
);
224 NG_HCI_STAT_ACL_SENT(unit
->stat
, count
);
225 NG_HCI_BUFF_ACL_USE(unit
->buffer
, count
);
229 NG_HCI_BUFF_SCO_AVAIL(unit
->buffer
, count
);
232 "%s: %s - sending SCO data packets, count=%d\n",
233 __func__
, NG_NODE_NAME(unit
->node
), count
);
236 count
= send_data_packets(unit
, NG_HCI_LINK_SCO
, count
);
237 NG_HCI_STAT_SCO_SENT(unit
->stat
, count
);
238 NG_HCI_BUFF_SCO_USE(unit
->buffer
, count
);
240 } /* ng_hci_send_data */
243 * Send data packets to the lower layer.
247 send_data_packets(ng_hci_unit_p unit
, int link_type
, int limit
)
249 ng_hci_unit_con_p con
= NULL
, winner
= NULL
;
251 int min_pending
, total_sent
, sent
, error
, v
;
253 for (total_sent
= 0; limit
> 0; ) {
254 min_pending
= 0x0fffffff;
258 * Find the connection that has has data to send
259 * and the smallest number of pending packets
262 LIST_FOREACH(con
, &unit
->con_list
, next
) {
263 if (con
->link_type
!= link_type
)
265 if (NG_BT_ITEMQ_LEN(&con
->conq
) == 0)
268 if (con
->pending
< min_pending
) {
270 min_pending
= con
->pending
;
278 * OK, we have a winner now send as much packets as we can
279 * Count the number of packets we have sent and then sync
280 * winner connection queue.
283 for (sent
= 0; limit
> 0; limit
--, total_sent
++, sent
++) {
284 NG_BT_ITEMQ_DEQUEUE(&winner
->conq
, item
);
289 "%s: %s - sending data packet, handle=%d, len=%d\n",
290 __func__
, NG_NODE_NAME(unit
->node
),
291 winner
->con_handle
, NGI_M(item
)->m_pkthdr
.len
);
293 /* Check if driver hook still there */
294 v
= (unit
->drv
!= NULL
&& NG_HOOK_IS_VALID(unit
->drv
));
295 if (!v
|| (unit
->state
& NG_HCI_UNIT_READY
) !=
298 "%s: %s - could not send data. Hook \"%s\" is %svalid, state=%#x\n",
299 __func__
, NG_NODE_NAME(unit
->node
),
300 NG_HCI_HOOK_DRV
, ((v
)? "" : "not "),
306 v
= NGI_M(item
)->m_pkthdr
.len
;
308 /* Give packet to raw hook */
309 ng_hci_mtap(unit
, NGI_M(item
));
311 /* ... and forward item to the driver */
312 NG_FWD_ITEM_HOOK(error
, item
, unit
->drv
);
317 "%s: %s - could not send data packet, handle=%d, error=%d\n",
318 __func__
, NG_NODE_NAME(unit
->node
),
319 winner
->con_handle
, error
);
324 NG_HCI_STAT_BYTES_SENT(unit
->stat
, v
);
328 * Sync connection queue for the winner
331 sync_con_queue(unit
, winner
, sent
);
335 } /* send_data_packets */
338 * Send flow control messages to the upper layer
342 sync_con_queue(ng_hci_unit_p unit
, ng_hci_unit_con_p con
, int completed
)
345 struct ng_mesg
*msg
= NULL
;
346 ng_hci_sync_con_queue_ep
*state
= NULL
;
349 hook
= (con
->link_type
== NG_HCI_LINK_ACL
)? unit
->acl
: unit
->sco
;
350 if (hook
== NULL
|| NG_HOOK_NOT_VALID(hook
))
353 NG_MKMESSAGE(msg
, NGM_HCI_COOKIE
, NGM_HCI_SYNC_CON_QUEUE
,
354 sizeof(*state
), M_NOWAIT
);
358 state
= (ng_hci_sync_con_queue_ep
*)(msg
->data
);
359 state
->con_handle
= con
->con_handle
;
360 state
->completed
= completed
;
362 NG_SEND_MSG_HOOK(error
, unit
->node
, msg
, hook
, 0);
365 } /* sync_con_queue */
367 /* Inquiry result event */
369 inquiry_result(ng_hci_unit_p unit
, struct mbuf
*event
)
371 ng_hci_inquiry_result_ep
*ep
= NULL
;
372 ng_hci_neighbor_p n
= NULL
;
376 NG_HCI_M_PULLUP(event
, sizeof(*ep
));
380 ep
= mtod(event
, ng_hci_inquiry_result_ep
*);
381 m_adj(event
, sizeof(*ep
));
383 for (; ep
->num_responses
> 0; ep
->num_responses
--) {
384 /* Get remote unit address */
385 m_copydata(event
, 0, sizeof(bdaddr
), (caddr_t
) &bdaddr
);
386 m_adj(event
, sizeof(bdaddr
));
388 /* Lookup entry in the cache */
389 n
= ng_hci_get_neighbor(unit
, &bdaddr
);
391 /* Create new entry */
392 n
= ng_hci_new_neighbor(unit
);
398 getmicrotime(&n
->updated
);
400 bcopy(&bdaddr
, &n
->bdaddr
, sizeof(n
->bdaddr
));
402 /* XXX call m_pullup here? */
404 n
->page_scan_rep_mode
= *mtod(event
, u_int8_t
*);
405 m_adj(event
, sizeof(u_int8_t
));
407 /* page_scan_period_mode */
408 m_adj(event
, sizeof(u_int8_t
));
410 n
->page_scan_mode
= *mtod(event
, u_int8_t
*);
411 m_adj(event
, sizeof(u_int8_t
));
414 m_adj(event
, NG_HCI_CLASS_SIZE
);
417 m_copydata(event
, 0, sizeof(n
->clock_offset
),
418 (caddr_t
) &n
->clock_offset
);
419 n
->clock_offset
= le16toh(n
->clock_offset
);
425 } /* inquiry_result */
427 /* Connection complete event */
429 con_compl(ng_hci_unit_p unit
, struct mbuf
*event
)
431 ng_hci_con_compl_ep
*ep
= NULL
;
432 ng_hci_unit_con_p con
= NULL
;
435 NG_HCI_M_PULLUP(event
, sizeof(*ep
));
439 ep
= mtod(event
, ng_hci_con_compl_ep
*);
442 * Find the first connection descriptor that matches the following:
444 * 1) con->link_type == ep->link_type
445 * 2) con->state == NG_HCI_CON_W4_CONN_COMPLETE
446 * 3) con->bdaddr == ep->bdaddr
449 LIST_FOREACH(con
, &unit
->con_list
, next
)
450 if (con
->link_type
== ep
->link_type
&&
451 con
->state
== NG_HCI_CON_W4_CONN_COMPLETE
&&
452 bcmp(&con
->bdaddr
, &ep
->bdaddr
, sizeof(bdaddr_t
)) == 0)
456 * Two possible cases:
458 * 1) We have found connection descriptor. That means upper layer has
459 * requested this connection via LP_CON_REQ message. In this case
460 * connection must have timeout set. If ng_hci_con_untimeout() fails
461 * then timeout message already went into node's queue. In this case
462 * ignore Connection_Complete event and let timeout deal with it.
464 * 2) We do not have connection descriptor. That means upper layer
465 * nas not requested this connection or (less likely) we gave up
466 * on this connection (timeout). The most likely scenario is that
467 * we have received Create_Connection/Add_SCO_Connection command
475 con
= ng_hci_new_con(unit
, ep
->link_type
);
481 bcopy(&ep
->bdaddr
, &con
->bdaddr
, sizeof(con
->bdaddr
));
482 } else if ((error
= ng_hci_con_untimeout(con
)) != 0)
486 * Update connection descriptor and send notification
487 * to the upper layers.
490 con
->con_handle
= NG_HCI_CON_HANDLE(le16toh(ep
->con_handle
));
491 con
->encryption_mode
= ep
->encryption_mode
;
493 ng_hci_lp_con_cfm(con
, ep
->status
);
495 /* Adjust connection state */
497 ng_hci_free_con(con
);
499 con
->state
= NG_HCI_CON_OPEN
;
502 * Change link policy for the ACL connections. Enable all
503 * supported link modes. Enable Role switch as well if
504 * device supports it.
507 if (ep
->link_type
== NG_HCI_LINK_ACL
) {
508 struct __link_policy
{
509 ng_hci_cmd_pkt_t hdr
;
510 ng_hci_write_link_policy_settings_cp cp
;
511 } __attribute__ ((packed
)) *lp
;
514 MGETHDR(m
, M_DONTWAIT
, MT_DATA
);
516 m
->m_pkthdr
.len
= m
->m_len
= sizeof(*lp
);
517 lp
= mtod(m
, struct __link_policy
*);
519 lp
->hdr
.type
= NG_HCI_CMD_PKT
;
520 lp
->hdr
.opcode
= htole16(NG_HCI_OPCODE(
521 NG_HCI_OGF_LINK_POLICY
,
522 NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS
));
523 lp
->hdr
.length
= sizeof(lp
->cp
);
525 lp
->cp
.con_handle
= ep
->con_handle
;
528 if ((unit
->features
[0] & NG_HCI_LMP_SWITCH
) &&
530 lp
->cp
.settings
|= 0x1;
531 if (unit
->features
[0] & NG_HCI_LMP_HOLD_MODE
)
532 lp
->cp
.settings
|= 0x2;
533 if (unit
->features
[0] & NG_HCI_LMP_SNIFF_MODE
)
534 lp
->cp
.settings
|= 0x4;
535 if (unit
->features
[1] & NG_HCI_LMP_PARK_MODE
)
536 lp
->cp
.settings
|= 0x8;
538 lp
->cp
.settings
&= unit
->link_policy_mask
;
539 lp
->cp
.settings
= htole16(lp
->cp
.settings
);
541 NG_BT_MBUFQ_ENQUEUE(&unit
->cmdq
, m
);
542 if (!(unit
->state
& NG_HCI_UNIT_COMMAND_PENDING
))
543 ng_hci_send_command(unit
);
553 /* Connection request event */
555 con_req(ng_hci_unit_p unit
, struct mbuf
*event
)
557 ng_hci_con_req_ep
*ep
= NULL
;
558 ng_hci_unit_con_p con
= NULL
;
561 NG_HCI_M_PULLUP(event
, sizeof(*ep
));
565 ep
= mtod(event
, ng_hci_con_req_ep
*);
568 * Find the first connection descriptor that matches the following:
570 * 1) con->link_type == ep->link_type
572 * 2) con->state == NG_HCI_CON_W4_LP_CON_RSP ||
573 * con->state == NG_HCI_CON_W4_CONN_COMPL
575 * 3) con->bdaddr == ep->bdaddr
579 * 1) We do not have connection descriptor. This is simple. Create
580 * new fresh connection descriptor and send notification to the
581 * appropriate upstream hook (based on link_type).
583 * 2) We found connection handle. This is more complicated.
587 * Since only one ACL link can exist between each pair of
588 * units then we have a race. Our upper layer has requested
589 * an ACL connection to the remote unit, but we did not send
590 * command yet. At the same time the remote unit has requested
591 * an ACL connection from us. In this case we will ignore
592 * Connection_Request event. This probably will cause connect
593 * failure on both units.
597 * The spec on page 45 says :
599 * "The master can support up to three SCO links to the same
600 * slave or to different slaves. A slave can support up to
601 * three SCO links from the same master, or two SCO links if
602 * the links originate from different masters."
604 * The only problem is how to handle multiple SCO links between
605 * matster and slave. For now we will assume that multiple SCO
606 * links MUST be opened one after another.
609 LIST_FOREACH(con
, &unit
->con_list
, next
)
610 if (con
->link_type
== ep
->link_type
&&
611 (con
->state
== NG_HCI_CON_W4_LP_CON_RSP
||
612 con
->state
== NG_HCI_CON_W4_CONN_COMPLETE
) &&
613 bcmp(&con
->bdaddr
, &ep
->bdaddr
, sizeof(bdaddr_t
)) == 0)
617 con
= ng_hci_new_con(unit
, ep
->link_type
);
619 bcopy(&ep
->bdaddr
, &con
->bdaddr
, sizeof(con
->bdaddr
));
621 con
->state
= NG_HCI_CON_W4_LP_CON_RSP
;
622 ng_hci_con_timeout(con
);
624 error
= ng_hci_lp_con_ind(con
, ep
->uclass
);
626 ng_hci_con_untimeout(con
);
627 ng_hci_free_con(con
);
638 /* Disconnect complete event */
640 discon_compl(ng_hci_unit_p unit
, struct mbuf
*event
)
642 ng_hci_discon_compl_ep
*ep
= NULL
;
643 ng_hci_unit_con_p con
= NULL
;
647 NG_HCI_M_PULLUP(event
, sizeof(*ep
));
651 ep
= mtod(event
, ng_hci_discon_compl_ep
*);
655 * Do we have to send notification if ep->status != 0?
656 * For now we will send notification for both ACL and SCO connections
657 * ONLY if ep->status == 0.
660 if (ep
->status
== 0) {
661 h
= NG_HCI_CON_HANDLE(le16toh(ep
->con_handle
));
662 con
= ng_hci_con_by_handle(unit
, h
);
664 error
= ng_hci_lp_discon_ind(con
, ep
->reason
);
666 /* Remove all timeouts (if any) */
667 if (con
->flags
& NG_HCI_CON_TIMEOUT_PENDING
)
668 ng_hci_con_untimeout(con
);
670 ng_hci_free_con(con
);
673 "%s: %s - invalid connection handle=%d\n",
674 __func__
, NG_NODE_NAME(unit
->node
), h
);
684 /* Encryption change event */
686 encryption_change(ng_hci_unit_p unit
, struct mbuf
*event
)
688 ng_hci_encryption_change_ep
*ep
= NULL
;
689 ng_hci_unit_con_p con
= NULL
;
692 NG_HCI_M_PULLUP(event
, sizeof(*ep
));
696 ep
= mtod(event
, ng_hci_encryption_change_ep
*);
698 if (ep
->status
== 0) {
699 u_int16_t h
= NG_HCI_CON_HANDLE(le16toh(ep
->con_handle
));
701 con
= ng_hci_con_by_handle(unit
, h
);
704 "%s: %s - invalid connection handle=%d\n",
705 __func__
, NG_NODE_NAME(unit
->node
), h
);
707 } else if (con
->link_type
!= NG_HCI_LINK_ACL
) {
709 "%s: %s - invalid link type=%d\n",
710 __func__
, NG_NODE_NAME(unit
->node
),
713 } else if (ep
->encryption_enable
)
714 /* XXX is that true? */
715 con
->encryption_mode
= NG_HCI_ENCRYPTION_MODE_P2P
;
717 con
->encryption_mode
= NG_HCI_ENCRYPTION_MODE_NONE
;
720 "%s: %s - failed to change encryption mode, status=%d\n",
721 __func__
, NG_NODE_NAME(unit
->node
), ep
->status
);
726 } /* encryption_change */
728 /* Read remote feature complete event */
730 read_remote_features_compl(ng_hci_unit_p unit
, struct mbuf
*event
)
732 ng_hci_read_remote_features_compl_ep
*ep
= NULL
;
733 ng_hci_unit_con_p con
= NULL
;
734 ng_hci_neighbor_p n
= NULL
;
738 NG_HCI_M_PULLUP(event
, sizeof(*ep
));
742 ep
= mtod(event
, ng_hci_read_remote_features_compl_ep
*);
744 if (ep
->status
== 0) {
745 /* Check if we have this connection handle */
746 h
= NG_HCI_CON_HANDLE(le16toh(ep
->con_handle
));
747 con
= ng_hci_con_by_handle(unit
, h
);
750 "%s: %s - invalid connection handle=%d\n",
751 __func__
, NG_NODE_NAME(unit
->node
), h
);
756 /* Update cache entry */
757 n
= ng_hci_get_neighbor(unit
, &con
->bdaddr
);
759 n
= ng_hci_new_neighbor(unit
);
765 bcopy(&con
->bdaddr
, &n
->bdaddr
, sizeof(n
->bdaddr
));
767 getmicrotime(&n
->updated
);
769 bcopy(ep
->features
, n
->features
, sizeof(n
->features
));
772 "%s: %s - failed to read remote unit features, status=%d\n",
773 __func__
, NG_NODE_NAME(unit
->node
), ep
->status
);
778 } /* read_remote_features_compl */
780 /* QoS setup complete event */
782 qos_setup_compl(ng_hci_unit_p unit
, struct mbuf
*event
)
784 ng_hci_qos_setup_compl_ep
*ep
= NULL
;
785 ng_hci_unit_con_p con
= NULL
;
789 NG_HCI_M_PULLUP(event
, sizeof(*ep
));
793 ep
= mtod(event
, ng_hci_qos_setup_compl_ep
*);
795 /* Check if we have this connection handle */
796 h
= NG_HCI_CON_HANDLE(le16toh(ep
->con_handle
));
797 con
= ng_hci_con_by_handle(unit
, h
);
800 "%s: %s - invalid connection handle=%d\n",
801 __func__
, NG_NODE_NAME(unit
->node
), h
);
803 } else if (con
->link_type
!= NG_HCI_LINK_ACL
) {
805 "%s: %s - invalid link type=%d, handle=%d\n",
806 __func__
, NG_NODE_NAME(unit
->node
), con
->link_type
, h
);
808 } else if (con
->state
!= NG_HCI_CON_OPEN
) {
810 "%s: %s - invalid connection state=%d, handle=%d\n",
811 __func__
, NG_NODE_NAME(unit
->node
),
814 } else /* Notify upper layer */
815 error
= ng_hci_lp_qos_cfm(con
, ep
->status
);
820 } /* qos_setup_compl */
822 /* Hardware error event */
824 hardware_error(ng_hci_unit_p unit
, struct mbuf
*event
)
827 "%s: %s - hardware error %#x\n",
828 __func__
, NG_NODE_NAME(unit
->node
), *mtod(event
, u_int8_t
*));
833 } /* hardware_error */
835 /* Role change event */
837 role_change(ng_hci_unit_p unit
, struct mbuf
*event
)
839 ng_hci_role_change_ep
*ep
= NULL
;
840 ng_hci_unit_con_p con
= NULL
;
842 NG_HCI_M_PULLUP(event
, sizeof(*ep
));
846 ep
= mtod(event
, ng_hci_role_change_ep
*);
848 if (ep
->status
== 0) {
849 /* XXX shoud we also change "role" for SCO connections? */
850 con
= ng_hci_con_by_bdaddr(unit
, &ep
->bdaddr
, NG_HCI_LINK_ACL
);
852 con
->role
= ep
->role
;
855 "%s: %s - ACL connection does not exist, bdaddr=%x:%x:%x:%x:%x:%x\n",
856 __func__
, NG_NODE_NAME(unit
->node
),
857 ep
->bdaddr
.b
[5], ep
->bdaddr
.b
[4],
858 ep
->bdaddr
.b
[3], ep
->bdaddr
.b
[2],
859 ep
->bdaddr
.b
[1], ep
->bdaddr
.b
[0]);
862 "%s: %s - failed to change role, status=%d, bdaddr=%x:%x:%x:%x:%x:%x\n",
863 __func__
, NG_NODE_NAME(unit
->node
), ep
->status
,
864 ep
->bdaddr
.b
[5], ep
->bdaddr
.b
[4], ep
->bdaddr
.b
[3],
865 ep
->bdaddr
.b
[2], ep
->bdaddr
.b
[1], ep
->bdaddr
.b
[0]);
872 /* Number of completed packets event */
874 num_compl_pkts(ng_hci_unit_p unit
, struct mbuf
*event
)
876 ng_hci_num_compl_pkts_ep
*ep
= NULL
;
877 ng_hci_unit_con_p con
= NULL
;
880 NG_HCI_M_PULLUP(event
, sizeof(*ep
));
884 ep
= mtod(event
, ng_hci_num_compl_pkts_ep
*);
885 m_adj(event
, sizeof(*ep
));
887 for (; ep
->num_con_handles
> 0; ep
->num_con_handles
--) {
888 /* Get connection handle */
889 m_copydata(event
, 0, sizeof(h
), (caddr_t
) &h
);
890 m_adj(event
, sizeof(h
));
891 h
= NG_HCI_CON_HANDLE(le16toh(h
));
893 /* Get number of completed packets */
894 m_copydata(event
, 0, sizeof(p
), (caddr_t
) &p
);
895 m_adj(event
, sizeof(p
));
898 /* Check if we have this connection handle */
899 con
= ng_hci_con_by_handle(unit
, h
);
902 if (con
->pending
< 0) {
904 "%s: %s - pending packet counter is out of sync! " \
905 "handle=%d, pending=%d, ncp=%d\n", __func__
, NG_NODE_NAME(unit
->node
),
906 con
->con_handle
, con
->pending
, p
);
911 /* Update buffer descriptor */
912 if (con
->link_type
== NG_HCI_LINK_ACL
)
913 NG_HCI_BUFF_ACL_FREE(unit
->buffer
, p
);
915 NG_HCI_BUFF_SCO_FREE(unit
->buffer
, p
);
918 "%s: %s - invalid connection handle=%d\n",
919 __func__
, NG_NODE_NAME(unit
->node
), h
);
925 ng_hci_send_data(unit
);
928 } /* num_compl_pkts */
930 /* Mode change event */
932 mode_change(ng_hci_unit_p unit
, struct mbuf
*event
)
934 ng_hci_mode_change_ep
*ep
= NULL
;
935 ng_hci_unit_con_p con
= NULL
;
938 NG_HCI_M_PULLUP(event
, sizeof(*ep
));
942 ep
= mtod(event
, ng_hci_mode_change_ep
*);
944 if (ep
->status
== 0) {
945 u_int16_t h
= NG_HCI_CON_HANDLE(le16toh(ep
->con_handle
));
947 con
= ng_hci_con_by_handle(unit
, h
);
950 "%s: %s - invalid connection handle=%d\n",
951 __func__
, NG_NODE_NAME(unit
->node
), h
);
953 } else if (con
->link_type
!= NG_HCI_LINK_ACL
) {
955 "%s: %s - invalid link type=%d\n",
956 __func__
, NG_NODE_NAME(unit
->node
),
960 con
->mode
= ep
->unit_mode
;
963 "%s: %s - failed to change mode, status=%d\n",
964 __func__
, NG_NODE_NAME(unit
->node
), ep
->status
);
971 /* Data buffer overflow event */
973 data_buffer_overflow(ng_hci_unit_p unit
, struct mbuf
*event
)
976 "%s: %s - %s data buffer overflow\n",
977 __func__
, NG_NODE_NAME(unit
->node
),
978 (*mtod(event
, u_int8_t
*) == NG_HCI_LINK_ACL
)? "ACL" : "SCO");
983 } /* data_buffer_overflow */
985 /* Read clock offset complete event */
987 read_clock_offset_compl(ng_hci_unit_p unit
, struct mbuf
*event
)
989 ng_hci_read_clock_offset_compl_ep
*ep
= NULL
;
990 ng_hci_unit_con_p con
= NULL
;
991 ng_hci_neighbor_p n
= NULL
;
994 NG_HCI_M_PULLUP(event
, sizeof(*ep
));
998 ep
= mtod(event
, ng_hci_read_clock_offset_compl_ep
*);
1000 if (ep
->status
== 0) {
1001 u_int16_t h
= NG_HCI_CON_HANDLE(le16toh(ep
->con_handle
));
1003 con
= ng_hci_con_by_handle(unit
, h
);
1006 "%s: %s - invalid connection handle=%d\n",
1007 __func__
, NG_NODE_NAME(unit
->node
), h
);
1012 /* Update cache entry */
1013 n
= ng_hci_get_neighbor(unit
, &con
->bdaddr
);
1015 n
= ng_hci_new_neighbor(unit
);
1021 bcopy(&con
->bdaddr
, &n
->bdaddr
, sizeof(n
->bdaddr
));
1023 getmicrotime(&n
->updated
);
1025 n
->clock_offset
= le16toh(ep
->clock_offset
);
1028 "%s: %s - failed to Read Remote Clock Offset, status=%d\n",
1029 __func__
, NG_NODE_NAME(unit
->node
), ep
->status
);
1034 } /* read_clock_offset_compl */
1036 /* QoS violation event */
1038 qos_violation(ng_hci_unit_p unit
, struct mbuf
*event
)
1040 ng_hci_qos_violation_ep
*ep
= NULL
;
1041 ng_hci_unit_con_p con
= NULL
;
1045 NG_HCI_M_PULLUP(event
, sizeof(*ep
));
1049 ep
= mtod(event
, ng_hci_qos_violation_ep
*);
1051 /* Check if we have this connection handle */
1052 h
= NG_HCI_CON_HANDLE(le16toh(ep
->con_handle
));
1053 con
= ng_hci_con_by_handle(unit
, h
);
1056 "%s: %s - invalid connection handle=%d\n",
1057 __func__
, NG_NODE_NAME(unit
->node
), h
);
1059 } else if (con
->link_type
!= NG_HCI_LINK_ACL
) {
1061 "%s: %s - invalid link type=%d\n",
1062 __func__
, NG_NODE_NAME(unit
->node
), con
->link_type
);
1064 } else if (con
->state
!= NG_HCI_CON_OPEN
) {
1066 "%s: %s - invalid connection state=%d, handle=%d\n",
1067 __func__
, NG_NODE_NAME(unit
->node
), con
->state
, h
);
1069 } else /* Notify upper layer */
1070 error
= ng_hci_lp_qos_ind(con
);
1075 } /* qos_violation */
1077 /* Page scan mode change event */
1079 page_scan_mode_change(ng_hci_unit_p unit
, struct mbuf
*event
)
1081 ng_hci_page_scan_mode_change_ep
*ep
= NULL
;
1082 ng_hci_neighbor_p n
= NULL
;
1085 NG_HCI_M_PULLUP(event
, sizeof(*ep
));
1089 ep
= mtod(event
, ng_hci_page_scan_mode_change_ep
*);
1091 /* Update cache entry */
1092 n
= ng_hci_get_neighbor(unit
, &ep
->bdaddr
);
1094 n
= ng_hci_new_neighbor(unit
);
1100 bcopy(&ep
->bdaddr
, &n
->bdaddr
, sizeof(n
->bdaddr
));
1102 getmicrotime(&n
->updated
);
1104 n
->page_scan_mode
= ep
->page_scan_mode
;
1109 } /* page_scan_mode_change */
1111 /* Page scan repetition mode change event */
1113 page_scan_rep_mode_change(ng_hci_unit_p unit
, struct mbuf
*event
)
1115 ng_hci_page_scan_rep_mode_change_ep
*ep
= NULL
;
1116 ng_hci_neighbor_p n
= NULL
;
1119 NG_HCI_M_PULLUP(event
, sizeof(*ep
));
1123 ep
= mtod(event
, ng_hci_page_scan_rep_mode_change_ep
*);
1125 /* Update cache entry */
1126 n
= ng_hci_get_neighbor(unit
, &ep
->bdaddr
);
1128 n
= ng_hci_new_neighbor(unit
);
1134 bcopy(&ep
->bdaddr
, &n
->bdaddr
, sizeof(n
->bdaddr
));
1136 getmicrotime(&n
->updated
);
1138 n
->page_scan_rep_mode
= ep
->page_scan_rep_mode
;
1143 } /* page_scan_rep_mode_change */