1 /*        $NetBSD: bth5.c,v 1.9 2024/07/05 04:31:50 rin Exp $         */
2 /*
3  * Copyright (c) 2017 Nathanial Sloss <nathanialsloss@yahoo.com.au>
4  * All rights reserved.
5  *
6  * Copyright (c) 2007 KIYOHARA Takashi
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 ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
22  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: bth5.c,v 1.9 2024/07/05 04:31:50 rin Exp $");
33 
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/callout.h>
37 #include <sys/conf.h>
38 #include <sys/device.h>
39 #include <sys/errno.h>
40 #include <sys/fcntl.h>
41 #include <sys/kauth.h>
42 #include <sys/kernel.h>
43 #include <sys/malloc.h>
44 #include <sys/mbuf.h>
45 #include <sys/proc.h>
46 #include <sys/sysctl.h>
47 #include <sys/syslimits.h>
48 #include <sys/systm.h>
49 #include <sys/tty.h>
50 
51 #include <netbt/bluetooth.h>
52 #include <netbt/hci.h>
53 
54 #include <dev/bluetooth/bth5.h>
55 
56 #include "ioconf.h"
57 
58 #ifdef BTH5_DEBUG
59 #ifdef DPRINTF
60 #undef DPRINTF
61 #endif
62 #ifdef DPRINTFN
63 #undef DPRINTFN
64 #endif
65 
66 #define DPRINTF(x)  printf x
67 #define DPRINTFN(n, x)        do { if (bth5_debug > (n)) printf x; } while (0)
68 int bth5_debug = 3;
69 #else
70 #undef DPRINTF
71 #undef DPRINTFN
72 
73 #define DPRINTF(x)
74 #define DPRINTFN(n, x)
75 #endif
76 
77 struct bth5_softc {
78           device_t sc_dev;
79 
80           struct tty *sc_tp;
81           struct hci_unit *sc_unit;               /* Bluetooth HCI Unit */
82           struct bt_stats sc_stats;
83 
84           int sc_flags;
85 
86           /* output queues */
87           MBUFQ_HEAD()        sc_cmdq;
88           MBUFQ_HEAD()        sc_aclq;
89           MBUFQ_HEAD()        sc_scoq;
90 
91           int sc_baud;
92           int sc_init_baud;
93 
94           /* variables of SLIP Layer */
95           struct mbuf *sc_txp;                              /* outgoing packet */
96           struct mbuf *sc_rxp;                              /* incoming packet */
97           int sc_slip_txrsv;                      /* reserved byte data */
98           int sc_slip_rxexp;                      /* expected byte data */
99           void (*sc_transmit_callback)(struct bth5_softc *, struct mbuf *);
100 
101           /* variables of Packet Integrity Layer */
102           int sc_pi_txcrc;                        /* use CRC, if true */
103 
104           /* variables of MUX Layer */
105           bool sc_mux_send_ack;                             /* flag for send_ack */
106           bool sc_mux_choke;                      /* Choke signal */
107           struct timeval sc_mux_lastrx;           /* Last Rx Pkt Time */
108 
109           /* variables of Sequencing Layer */
110           MBUFQ_HEAD() sc_seqq;                             /* Sequencing Layer queue */
111           MBUFQ_HEAD() sc_seq_retryq;             /* retry queue */
112           uint32_t sc_seq_txseq;
113           uint32_t sc_seq_expected_rxseq;
114           uint32_t sc_seq_total_rxpkts;
115           uint32_t sc_seq_winack;
116           uint32_t sc_seq_winspace;
117           uint32_t sc_seq_retries;
118           callout_t sc_seq_timer;
119           uint32_t sc_seq_timeout;
120           uint32_t sc_seq_winsize;
121           uint32_t sc_seq_retry_limit;
122           bool       sc_oof_flow_control;
123 
124           /* variables of Datagram Queue Layer */
125           MBUFQ_HEAD() sc_dgq;                              /* Datagram Queue Layer queue */
126 
127           /* variables of BTH5 Link Establishment Protocol */
128           bool sc_le_muzzled;
129           bth5_le_state_t sc_le_state;
130           callout_t sc_le_timer;
131 
132           struct sysctllog *sc_log;               /* sysctl log */
133 };
134 
135 /* sc_flags */
136 #define   BTH5_XMIT (1 << 0)  /* transmit active */
137 #define   BTH5_ENABLED        (1 << 1)  /* is enabled */
138 
139 static int bthfive_match(device_t, cfdata_t, void *);
140 static void bthfive_attach(device_t, device_t, void *);
141 static int bthfive_detach(device_t, int);
142 
143 /* tty functions */
144 static int bth5open(dev_t, struct tty *);
145 static int bth5close(struct tty *, int);
146 static int bth5ioctl(struct tty *, u_long, void *, int, struct lwp *);
147 
148 static int bth5_slip_transmit(struct tty *);
149 static int bth5_slip_receive(int, struct tty *);
150 
151 static void bth5_pktintegrity_transmit(struct bth5_softc *);
152 static void bth5_pktintegrity_receive(struct bth5_softc *, struct mbuf *);
153 static void bth5_crc_update(uint16_t *, uint8_t);
154 static uint16_t bth5_crc_reverse(uint16_t);
155 
156 static void bth5_mux_transmit(struct bth5_softc *sc);
157 static void bth5_mux_receive(struct bth5_softc *sc, struct mbuf *m);
158 static __inline void bth5_send_ack_command(struct bth5_softc *sc);
159 static __inline struct mbuf *bth5_create_ackpkt(void);
160 static __inline void bth5_set_choke(struct bth5_softc *, bool);
161 
162 static void bth5_sequencing_receive(struct bth5_softc *, struct mbuf *);
163 static bool bth5_tx_reliable_pkt(struct bth5_softc *, struct mbuf *, u_int);
164 static __inline u_int bth5_get_txack(struct bth5_softc *);
165 static void bth5_signal_rxack(struct bth5_softc *, uint32_t);
166 static void bth5_reliabletx_callback(struct bth5_softc *, struct mbuf *);
167 static void bth5_timer_timeout(void *);
168 static void bth5_sequencing_reset(struct bth5_softc *);
169 
170 static void bth5_datagramq_receive(struct bth5_softc *, struct mbuf *);
171 static bool bth5_tx_unreliable_pkt(struct bth5_softc *, struct mbuf *, u_int);
172 static void bth5_unreliabletx_callback(struct bth5_softc *, struct mbuf *);
173 
174 static int bth5_start_le(struct bth5_softc *);
175 static void bth5_terminate_le(struct bth5_softc *);
176 static void bth5_input_le(struct bth5_softc *, struct mbuf *);
177 static void bth5_le_timeout(void *);
178 
179 static void bth5_start(struct bth5_softc *);
180 
181 /* bluetooth hci functions */
182 static int bth5_enable(device_t);
183 static void bth5_disable(device_t);
184 static void bth5_output_cmd(device_t, struct mbuf *);
185 static void bth5_output_acl(device_t, struct mbuf *);
186 static void bth5_output_sco(device_t, struct mbuf *);
187 static void bth5_stats(device_t, struct bt_stats *, int);
188 
189 #ifdef BTH5_DEBUG
190 static void bth5_packet_print(struct mbuf *m);
191 #endif
192 
193 
194 /*
195  * It doesn't need to be exported, as only bth5attach() uses it,
196  * but there's no "official" way to make it static.
197  */
198 CFATTACH_DECL_NEW(bthfive, sizeof(struct bth5_softc),
199     bthfive_match, bthfive_attach, bthfive_detach, NULL);
200 
201 static struct linesw bth5_disc = {
202           .l_name = "bth5",
203           .l_open = bth5open,
204           .l_close = bth5close,
205           .l_read = ttyerrio,
206           .l_write = ttyerrio,
207           .l_ioctl = bth5ioctl,
208           .l_rint = bth5_slip_receive,
209           .l_start = bth5_slip_transmit,
210           .l_modem = ttymodem,
211           .l_poll = ttyerrpoll
212 };
213 
214 static const struct hci_if bth5_hci = {
215           .enable = bth5_enable,
216           .disable = bth5_disable,
217           .output_cmd = bth5_output_cmd,
218           .output_acl = bth5_output_acl,
219           .output_sco = bth5_output_sco,
220           .get_stats = bth5_stats,
221           .ipl = IPL_TTY,
222 };
223 
224 /* ARGSUSED */
225 void
bthfiveattach(int num __unused)226 bthfiveattach(int num __unused)
227 {
228           int error;
229 
230           error = ttyldisc_attach(&bth5_disc);
231           if (error) {
232                     aprint_error("%s: unable to register line discipline, "
233                         "error = %d\n", bthfive_cd.cd_name, error);
234                     return;
235           }
236 
237           error = config_cfattach_attach(bthfive_cd.cd_name, &bthfive_ca);
238           if (error) {
239                     aprint_error("%s: unable to register cfattach, error = %d\n",
240                         bthfive_cd.cd_name, error);
241                     config_cfdriver_detach(&bthfive_cd);
242                     (void) ttyldisc_detach(&bth5_disc);
243           }
244 }
245 
246 /*
247  * Autoconf match routine.
248  *
249  * XXX: unused: config_attach_pseudo(9) does not call ca_match.
250  */
251 /* ARGSUSED */
252 static int
bthfive_match(device_t self __unused,cfdata_t cfdata __unused,void * arg __unused)253 bthfive_match(device_t self __unused, cfdata_t cfdata __unused,
254              void *arg __unused)
255 {
256 
257           /* pseudo-device; always present */
258           return 1;
259 }
260 
261 /*
262  * Autoconf attach routine.  Called by config_attach_pseudo(9) when we
263  * open the line discipline.
264  */
265 /* ARGSUSED */
266 static void
bthfive_attach(device_t parent __unused,device_t self,void * aux __unused)267 bthfive_attach(device_t parent __unused, device_t self, void *aux __unused)
268 {
269           struct bth5_softc *sc = device_private(self);
270           const struct sysctlnode *node;
271           int rc, bth5_node_num;
272 
273           aprint_normal("\n");
274           aprint_naive("\n");
275 
276           sc->sc_dev = self;
277           callout_init(&sc->sc_seq_timer, 0);
278           callout_setfunc(&sc->sc_seq_timer, bth5_timer_timeout, sc);
279           callout_init(&sc->sc_le_timer, 0);
280           callout_setfunc(&sc->sc_le_timer, bth5_le_timeout, sc);
281           sc->sc_seq_timeout = BTH5_SEQ_TX_TIMEOUT;
282           sc->sc_seq_winsize = BTH5_SEQ_TX_WINSIZE;
283           sc->sc_seq_retry_limit = BTH5_SEQ_TX_RETRY_LIMIT;
284           MBUFQ_INIT(&sc->sc_seqq);
285           MBUFQ_INIT(&sc->sc_seq_retryq);
286           MBUFQ_INIT(&sc->sc_dgq);
287           MBUFQ_INIT(&sc->sc_cmdq);
288           MBUFQ_INIT(&sc->sc_aclq);
289           MBUFQ_INIT(&sc->sc_scoq);
290 
291           /* Attach Bluetooth unit */
292           sc->sc_unit = hci_attach_pcb(&bth5_hci, self, 0);
293 
294           if ((rc = sysctl_createv(&sc->sc_log, 0, NULL, &node,
295               0, CTLTYPE_NODE, device_xname(self),
296               SYSCTL_DESCR("bth5 controls"),
297               NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) {
298                     goto err;
299           }
300           bth5_node_num = node->sysctl_num;
301           if ((rc = sysctl_createv(&sc->sc_log, 0, NULL, &node,
302               CTLFLAG_READWRITE, CTLTYPE_BOOL,
303               "muzzled", SYSCTL_DESCR("muzzled for Link-establishment Layer"),
304               NULL, 0, &sc->sc_le_muzzled,
305               0, CTL_HW, bth5_node_num, CTL_CREATE, CTL_EOL)) != 0) {
306                     goto err;
307           }
308           if ((rc = sysctl_createv(&sc->sc_log, 0, NULL, &node,
309               CTLFLAG_READWRITE, CTLTYPE_INT,
310               "txcrc", SYSCTL_DESCR("txcrc for Packet Integrity Layer"),
311               NULL, 0, &sc->sc_pi_txcrc,
312               0, CTL_HW, bth5_node_num, CTL_CREATE, CTL_EOL)) != 0) {
313                     goto err;
314           }
315           if ((rc = sysctl_createv(&sc->sc_log, 0, NULL, &node,
316               CTLFLAG_READWRITE, CTLTYPE_INT,
317               "timeout", SYSCTL_DESCR("timeout for Sequencing Layer"),
318               NULL, 0, &sc->sc_seq_timeout,
319               0, CTL_HW, bth5_node_num, CTL_CREATE, CTL_EOL)) != 0) {
320                     goto err;
321           }
322           if ((rc = sysctl_createv(&sc->sc_log, 0, NULL, &node,
323               CTLFLAG_READWRITE, CTLTYPE_INT,
324               "winsize", SYSCTL_DESCR("winsize for Sequencing Layer"),
325               NULL, 0, &sc->sc_seq_winsize,
326               0, CTL_HW, bth5_node_num, CTL_CREATE, CTL_EOL)) != 0) {
327                     goto err;
328           }
329           if ((rc = sysctl_createv(&sc->sc_log, 0, NULL, &node,
330               CTLFLAG_READWRITE, CTLTYPE_INT,
331               "retry_limit", SYSCTL_DESCR("retry limit for Sequencing Layer"),
332               NULL, 0, &sc->sc_seq_retry_limit,
333               0, CTL_HW, bth5_node_num, CTL_CREATE, CTL_EOL)) != 0) {
334                     goto err;
335           }
336           return;
337 
338 err:
339           aprint_error_dev(self, "sysctl_createv failed (rc = %d)\n", rc);
340 }
341 
342 /*
343  * Autoconf detach routine.  Called when we close the line discipline.
344  */
345 /* ARGSUSED */
346 static int
bthfive_detach(device_t self,int flags __unused)347 bthfive_detach(device_t self, int flags __unused)
348 {
349           struct bth5_softc *sc = device_private(self);
350 
351           if (sc->sc_unit != NULL) {
352                     hci_detach_pcb(sc->sc_unit);
353                     sc->sc_unit = NULL;
354           }
355 
356           callout_halt(&sc->sc_seq_timer, NULL);
357           callout_destroy(&sc->sc_seq_timer);
358 
359           callout_halt(&sc->sc_le_timer, NULL);
360           callout_destroy(&sc->sc_le_timer);
361 
362           return 0;
363 }
364 
365 
366 /*
367  * Line discipline functions.
368  */
369 /* ARGSUSED */
370 static int
bth5open(dev_t device __unused,struct tty * tp)371 bth5open(dev_t device __unused, struct tty *tp)
372 {
373           struct bth5_softc *sc;
374           device_t dev;
375           cfdata_t cfdata;
376           struct lwp *l = curlwp;                 /* XXX */
377           int error, unit, s;
378           static char name[] = "bthfive";
379 
380           error = kauth_authorize_device(l->l_cred, KAUTH_DEVICE_BLUETOOTH_BCSP,
381               KAUTH_ARG(KAUTH_REQ_DEVICE_BLUETOOTH_BCSP_ADD), NULL, NULL, NULL);
382           if (error)
383                     return (error);
384 
385           s = spltty();
386 
387           if (tp->t_linesw == &bth5_disc) {
388                     sc = tp->t_sc;
389                     if (sc != NULL) {
390                               splx(s);
391                               return EBUSY;
392                     }
393           }
394 
395           cfdata = malloc(sizeof(struct cfdata), M_DEVBUF, M_WAITOK);
396           for (unit = 0; unit < bthfive_cd.cd_ndevs; unit++)
397                     if (device_lookup(&bthfive_cd, unit) == NULL)
398                               break;
399           cfdata->cf_name = name;
400           cfdata->cf_atname = name;
401           cfdata->cf_unit = unit;
402           cfdata->cf_fstate = FSTATE_STAR;
403 
404           aprint_normal("%s%d at tty major %llu minor %llu",
405               name, unit, (unsigned long long)major(tp->t_dev),
406               (unsigned long long)minor(tp->t_dev));
407           dev = config_attach_pseudo(cfdata);
408           if (dev == NULL) {
409                     splx(s);
410                     return EIO;
411           }
412           sc = device_private(dev);
413 
414           ttylock(tp);
415           tp->t_sc = sc;
416           sc->sc_tp = tp;
417           ttyflush(tp, FREAD | FWRITE);
418           ttyunlock(tp);
419 
420           splx(s);
421 
422           sc->sc_slip_txrsv = BTH5_SLIP_PKTSTART;
423           bth5_sequencing_reset(sc);
424 
425           /* start link-establishment */
426           bth5_start_le(sc);
427 
428           return 0;
429 }
430 
431 /* ARGSUSED */
432 static int
bth5close(struct tty * tp,int flag __unused)433 bth5close(struct tty *tp, int flag __unused)
434 {
435           struct bth5_softc *sc = tp->t_sc;
436           cfdata_t cfdata;
437           int s;
438 
439           /* terminate link-establishment */
440           bth5_terminate_le(sc);
441 
442           s = spltty();
443 
444           MBUFQ_DRAIN(&sc->sc_dgq);
445           bth5_sequencing_reset(sc);
446 
447           ttylock(tp);
448           ttyflush(tp, FREAD | FWRITE);
449           ttyunlock(tp);      /* XXX */
450           ttyldisc_release(tp->t_linesw);
451           tp->t_linesw = ttyldisc_default();
452           if (sc != NULL) {
453                     tp->t_sc = NULL;
454                     if (sc->sc_tp == tp) {
455                               cfdata = device_cfdata(sc->sc_dev);
456                               config_detach(sc->sc_dev, 0);
457                               free(cfdata, M_DEVBUF);
458                     }
459 
460           }
461           splx(s);
462           return 0;
463 }
464 
465 /* ARGSUSED */
466 static int
bth5ioctl(struct tty * tp,u_long cmd,void * data,int flag __unused,struct lwp * l __unused)467 bth5ioctl(struct tty *tp, u_long cmd, void *data, int flag __unused,
468             struct lwp *l __unused)
469 {
470           struct bth5_softc *sc = tp->t_sc;
471           int error;
472 
473           if (sc == NULL || tp != sc->sc_tp)
474                     return EPASSTHROUGH;
475 
476           error = 0;
477           switch (cmd) {
478           default:
479                     error = EPASSTHROUGH;
480                     break;
481           }
482 
483           return error;
484 }
485 
486 
487 /*
488  * UART Driver Layer is supported by com-driver.
489  */
490 
491 /*
492  * BTH5 SLIP Layer functions:
493  *   Supports to transmit/receive a byte stream.
494  *   SLIP protocol described in Internet standard RFC 1055.
495  */
496 static int
bth5_slip_transmit(struct tty * tp)497 bth5_slip_transmit(struct tty *tp)
498 {
499           struct bth5_softc *sc = tp->t_sc;
500           struct mbuf *m;
501           int count, rlen;
502           uint8_t *rptr;
503           int s;
504 
505           m = sc->sc_txp;
506           if (m == NULL) {
507                     s = spltty();
508                     sc->sc_flags &= ~BTH5_XMIT;
509                     splx(s);
510                     bth5_mux_transmit(sc);
511                     return 0;
512           }
513 
514           count = 0;
515           rlen = 0;
516           rptr = mtod(m, uint8_t *);
517 
518           if (sc->sc_slip_txrsv != 0) {
519 #ifdef BTH5_DEBUG
520                     if (sc->sc_slip_txrsv == BTH5_SLIP_PKTSTART)
521                               DPRINTFN(4, ("%s: slip transmit start\n",
522                                   device_xname(sc->sc_dev)));
523                     else
524                               DPRINTFN(4, ("0x%02x ", sc->sc_slip_txrsv));
525 #endif
526 
527                     if (putc(sc->sc_slip_txrsv, &tp->t_outq) < 0)
528                               return 0;
529                     count++;
530 
531                     if (sc->sc_slip_txrsv == BTH5_SLIP_ESCAPE_PKTEND ||
532                         sc->sc_slip_txrsv == BTH5_SLIP_ESCAPE_ESCAPE) {
533                               rlen++;
534                               rptr++;
535                     }
536                     if (sc->sc_oof_flow_control == true) {
537                               if (sc->sc_slip_txrsv == BTH5_SLIP_ESCAPE_XON ||
538                                   sc->sc_slip_txrsv == BTH5_SLIP_ESCAPE_XOFF) {
539                                         rlen++;
540                                         rptr++;
541                               }
542                     }
543 
544                     sc->sc_slip_txrsv = 0;
545           }
546 
547           for(;;) {
548                     if (rlen >= m->m_len) {
549                               m = m->m_next;
550                               if (m == NULL) {
551                                         if (putc(BTH5_SLIP_PKTEND, &tp->t_outq) < 0)
552                                                   break;
553 
554                                         DPRINTFN(4, ("\n%s: slip transmit end\n",
555                                             device_xname(sc->sc_dev)));
556 
557                                         m = sc->sc_txp;
558                                         sc->sc_txp = NULL;
559                                         sc->sc_slip_txrsv = BTH5_SLIP_PKTSTART;
560 
561                                         sc->sc_transmit_callback(sc, m);
562                                         m = NULL;
563                                         break;
564                               }
565 
566                               rlen = 0;
567                               rptr = mtod(m, uint8_t *);
568                               continue;
569                     }
570 
571                     if (*rptr == BTH5_SLIP_PKTEND) {
572                               if (putc(BTH5_SLIP_ESCAPE, &tp->t_outq) < 0)
573                                         break;
574                               count++;
575                               DPRINTFN(4, (" esc "));
576 
577                               if (putc(BTH5_SLIP_ESCAPE_PKTEND, &tp->t_outq) < 0) {
578                                         sc->sc_slip_txrsv = BTH5_SLIP_ESCAPE_PKTEND;
579                                         break;
580                               }
581                               DPRINTFN(4, ("0x%02x ", BTH5_SLIP_ESCAPE_PKTEND));
582                               rptr++;
583                     } else if (sc->sc_oof_flow_control == true && *rptr ==
584                                                                        BTH5_SLIP_XON) {
585                               if (putc(BTH5_SLIP_ESCAPE, &tp->t_outq) < 0)
586                                         break;
587                               count++;
588                               DPRINTFN(4, (" esc "));
589 
590                               if (putc(BTH5_SLIP_ESCAPE_XON, &tp->t_outq) < 0) {
591                                         sc->sc_slip_txrsv = BTH5_SLIP_ESCAPE_XON;
592                                         break;
593                               }
594                               DPRINTFN(4, ("0x%02x ", BTH5_SLIP_ESCAPE_XON));
595                               rptr++;
596                     } else if (sc->sc_oof_flow_control == true && *rptr ==
597                                                                        BTH5_SLIP_XOFF) {
598                               if (putc(BTH5_SLIP_ESCAPE, &tp->t_outq) < 0)
599                                         break;
600                               count++;
601                               DPRINTFN(4, (" esc "));
602 
603                               if (putc(BTH5_SLIP_ESCAPE_XOFF, &tp->t_outq) < 0) {
604                                         sc->sc_slip_txrsv = BTH5_SLIP_ESCAPE_XOFF;
605                                         break;
606                               }
607                               DPRINTFN(4, ("0x%02x ", BTH5_SLIP_ESCAPE_XOFF));
608                               rptr++;
609                     } else if (*rptr == BTH5_SLIP_ESCAPE) {
610                               if (putc(BTH5_SLIP_ESCAPE, &tp->t_outq) < 0)
611                                         break;
612                               count++;
613                               DPRINTFN(4, (" esc "));
614 
615                               if (putc(BTH5_SLIP_ESCAPE_ESCAPE, &tp->t_outq) < 0) {
616                                         sc->sc_slip_txrsv = BTH5_SLIP_ESCAPE_ESCAPE;
617                                         break;
618                               }
619                               DPRINTFN(4, ("0x%02x ", BTH5_SLIP_ESCAPE_ESCAPE));
620                               rptr++;
621                     } else {
622                               if (putc(*rptr++, &tp->t_outq) < 0)
623                                         break;
624                               DPRINTFN(4, ("0x%02x ", *(rptr - 1)));
625                     }
626                     rlen++;
627                     count++;
628           }
629           if (m != NULL)
630                     m_adj(m, rlen);
631 
632           sc->sc_stats.byte_tx += count;
633 
634           if (tp->t_outq.c_cc != 0 && tp->t_oproc != NULL)
635                     (*tp->t_oproc)(tp);
636 
637           return 0;
638 }
639 
640 static int
bth5_slip_receive(int c,struct tty * tp)641 bth5_slip_receive(int c, struct tty *tp)
642 {
643           struct bth5_softc *sc = tp->t_sc;
644           struct mbuf *m = sc->sc_rxp;
645           int discard = 0;
646           const char *errstr;
647 
648           c &= TTY_CHARMASK;
649 
650           /* If we already started a packet, find the trailing end of it. */
651           if (m) {
652                     while (m->m_next)
653                               m = m->m_next;
654 
655                     if (M_TRAILINGSPACE(m) == 0) {
656                               /* extend mbuf */
657                               MGET(m->m_next, M_DONTWAIT, MT_DATA);
658                               if (m->m_next == NULL) {
659                                         aprint_error_dev(sc->sc_dev,
660                                             "out of memory\n");
661                                         sc->sc_stats.err_rx++;
662                                         return 0; /* (lost sync) */
663                               }
664 
665                               m = m->m_next;
666                               m->m_len = 0;
667                     }
668           } else
669                     if (c != BTH5_SLIP_PKTSTART) {
670                               discard = 1;
671                               errstr = "not sync";
672                               goto discarded;
673                     }
674 
675           switch (c) {
676           case BTH5_SLIP_PKTSTART /* or _PKTEND */:
677                     if (m == NULL) {
678                               /* BTH5_SLIP_PKTSTART */
679 
680                               DPRINTFN(4, ("%s: slip receive start\n",
681                                   device_xname(sc->sc_dev)));
682 
683                               /* new packet */
684                               MGETHDR(m, M_DONTWAIT, MT_DATA);
685                               if (m == NULL) {
686                                         aprint_error_dev(sc->sc_dev,
687                                             "out of memory\n");
688                                         sc->sc_stats.err_rx++;
689                                         return 0; /* (lost sync) */
690                               }
691 
692                               sc->sc_rxp = m;
693                               m->m_pkthdr.len = m->m_len = 0;
694                               sc->sc_slip_rxexp = 0;
695                     } else {
696                               /* BTH5_SLIP_PKTEND */
697 
698                               if (m == sc->sc_rxp && m->m_len == 0) {
699                                         DPRINTFN(4, ("%s: resynchronises\n",
700                                             device_xname(sc->sc_dev)));
701 
702                                         sc->sc_stats.byte_rx++;
703                                         return 0;
704                               }
705 
706                               DPRINTFN(4, ("%s%s: slip receive end\n",
707                                   (m->m_len % 16 != 0) ? "\n" :  "",
708                                   device_xname(sc->sc_dev)));
709 
710                               bth5_pktintegrity_receive(sc, sc->sc_rxp);
711                               sc->sc_rxp = NULL;
712                               sc->sc_slip_rxexp = BTH5_SLIP_PKTSTART;
713                     }
714                     sc->sc_stats.byte_rx++;
715                     return 0;
716 
717           case BTH5_SLIP_ESCAPE:
718 
719                     DPRINTFN(4, ("  esc"));
720 
721                     if (sc->sc_slip_rxexp == BTH5_SLIP_ESCAPE) {
722                               discard = 1;
723                               errstr = "waiting 0xdc or 0xdb or 0xde of 0xdf";
724                     } else
725                               sc->sc_slip_rxexp = BTH5_SLIP_ESCAPE;
726                     break;
727 
728           default:
729                     DPRINTFN(4, (" 0x%02x%s",
730                         c, (m->m_len % 16 == 15) ? "\n" :  ""));
731 
732                     switch (sc->sc_slip_rxexp) {
733                     case BTH5_SLIP_PKTSTART:
734                               discard = 1;
735                               errstr = "waiting 0xc0";
736                               break;
737 
738                     case BTH5_SLIP_ESCAPE:
739                               if (c == BTH5_SLIP_ESCAPE_PKTEND)
740                                         mtod(m, uint8_t *)[m->m_len++] =
741                                             BTH5_SLIP_PKTEND;
742                               else if (sc->sc_oof_flow_control == true &&
743                                                             c == BTH5_SLIP_ESCAPE_XON)
744                                         mtod(m, uint8_t *)[m->m_len++] =
745                                             BTH5_SLIP_XON;
746                               else if (sc->sc_oof_flow_control == true &&
747                                                             c == BTH5_SLIP_ESCAPE_XOFF)
748                                         mtod(m, uint8_t *)[m->m_len++] =
749                                             BTH5_SLIP_XOFF;
750                               else if (c == BTH5_SLIP_ESCAPE_ESCAPE)
751                                         mtod(m, uint8_t *)[m->m_len++] =
752                                             BTH5_SLIP_ESCAPE;
753                               else {
754                                         discard = 1;
755                                         errstr = "unknown escape";
756                               }
757                               sc->sc_slip_rxexp = 0;
758                               break;
759 
760                     default:
761                               mtod(m, uint8_t *)[m->m_len++] = c;
762                     }
763                     sc->sc_rxp->m_pkthdr.len++;
764           }
765           if (discard) {
766 discarded:
767 #ifdef BTH5_DEBUG
768                     DPRINTFN(4, ("%s: receives unexpected byte 0x%02x: %s\n",
769                         device_xname(sc->sc_dev), c, errstr));
770 #else
771                     __USE(errstr);
772 #endif
773           }
774           sc->sc_stats.byte_rx++;
775 
776           return 0;
777 }
778 
779 
780 /*
781  * BTH5 Packet Integrity Layer functions:
782  *   handling Payload Length, Checksum, CRC.
783  */
784 static void
bth5_pktintegrity_transmit(struct bth5_softc * sc)785 bth5_pktintegrity_transmit(struct bth5_softc *sc)
786 {
787           struct mbuf *m = sc->sc_txp;
788           bth5_hdr_t *hdrp = mtod(m, bth5_hdr_t *);
789           int pldlen;
790 
791           DPRINTFN(3, ("%s: pi transmit\n", device_xname(sc->sc_dev)));
792 
793           pldlen = m->m_pkthdr.len - sizeof(bth5_hdr_t);
794 
795           if (sc->sc_pi_txcrc)
796                     hdrp->flags |= BTH5_FLAGS_CRC_PRESENT;
797 
798           BTH5_SET_PLEN(hdrp, pldlen);
799           BTH5_SET_CSUM(hdrp);
800 
801           if (sc->sc_pi_txcrc) {
802                     struct mbuf *_m;
803                     int n = 0;
804                     uint16_t crc = 0xffff;
805                     uint8_t *buf;
806 
807                     for (_m = m; _m != NULL; _m = _m->m_next) {
808                               buf = mtod(_m, uint8_t *);
809                               for (n = 0; n < _m->m_len; n++)
810                                         bth5_crc_update(&crc, *(buf + n));
811                     }
812                     crc = htobe16(bth5_crc_reverse(crc));
813                     m_copyback(m, m->m_pkthdr.len, sizeof(crc), &crc);
814           }
815 
816 #ifdef BTH5_DEBUG
817           if (bth5_debug == 3)
818                     bth5_packet_print(m);
819 #endif
820 
821           bth5_slip_transmit(sc->sc_tp);
822 }
823 
824 static void
bth5_pktintegrity_receive(struct bth5_softc * sc,struct mbuf * m)825 bth5_pktintegrity_receive(struct bth5_softc *sc, struct mbuf *m)
826 {
827           bth5_hdr_t *hdrp = mtod(m, bth5_hdr_t *);
828           u_int pldlen;
829           int discard = 0;
830           uint16_t crc = 0xffff;
831           const char *errstr;
832 
833           DPRINTFN(3, ("%s: pi receive\n", device_xname(sc->sc_dev)));
834 #ifdef BTH5_DEBUG
835           if (bth5_debug == 4)
836                     bth5_packet_print(m);
837 #endif
838 
839           KASSERT(m->m_len >= sizeof(bth5_hdr_t));
840 
841           pldlen = m->m_pkthdr.len - sizeof(bth5_hdr_t) -
842               ((hdrp->flags & BTH5_FLAGS_CRC_PRESENT) ? sizeof(crc) : 0);
843           if (pldlen > 0xfff) {
844                     discard = 1;
845                     errstr = "Payload Length";
846                     goto discarded;
847           }
848           if (hdrp->csum != BTH5_GET_CSUM(hdrp)) {
849                     discard = 1;
850                     errstr = "Checksum";
851                     goto discarded;
852           }
853           if (BTH5_GET_PLEN(hdrp) != pldlen) {
854                     discard = 1;
855                     errstr = "Payload Length";
856                     goto discarded;
857           }
858           if (hdrp->flags & BTH5_FLAGS_CRC_PRESENT) {
859                     struct mbuf *_m;
860                     int i, n;
861                     uint16_t crc0;
862                     uint8_t *buf;
863 
864                     i = 0;
865                     n = 0;
866                     for (_m = m; _m != NULL; _m = _m->m_next) {
867                               buf = mtod(m, uint8_t *);
868                               for (n = 0;
869                                   n < _m->m_len && i < sizeof(bth5_hdr_t) + pldlen;
870                                   n++, i++)
871                                         bth5_crc_update(&crc, *(buf + n));
872                     }
873 
874                     m_copydata(_m, n, sizeof(crc0), &crc0);
875                     if (be16toh(crc0) != bth5_crc_reverse(crc)) {
876                               discard = 1;
877                               errstr = "CRC";
878                     } else
879                               /* Shaves CRC */
880                               m_adj(m, (int)(0 - sizeof(crc)));
881           }
882 
883           if (discard) {
884 discarded:
885 #ifdef BTH5_DEBUG
886                     DPRINTFN(3, ("%s: receives unexpected packet: %s\n",
887                         device_xname(sc->sc_dev), errstr));
888 #else
889                     __USE(errstr);
890 #endif
891                     m_freem(m);
892           } else
893                     bth5_mux_receive(sc, m);
894 }
895 
896 static const uint16_t crctbl[] = {
897           0x0000, 0x1081, 0x2102, 0x3183,
898           0x4204, 0x5285, 0x6306, 0x7387,
899           0x8408, 0x9489, 0xa50a, 0xb58b,
900           0xc60c, 0xd68d, 0xe70e, 0xf78f,
901 };
902 
903 static void
bth5_crc_update(uint16_t * crc,uint8_t d)904 bth5_crc_update(uint16_t *crc, uint8_t d)
905 {
906           uint16_t reg = *crc;
907 
908           reg = (reg >> 4) ^ crctbl[(reg ^ d) & 0x000f];
909           reg = (reg >> 4) ^ crctbl[(reg ^ (d >> 4)) & 0x000f];
910 
911           *crc = reg;
912 }
913 
914 static uint16_t
bth5_crc_reverse(uint16_t crc)915 bth5_crc_reverse(uint16_t crc)
916 {
917           uint16_t b, rev;
918 
919           for (b = 0, rev = 0; b < 16; b++) {
920                     rev = rev << 1;
921                     rev |= (crc & 1);
922                     crc = crc >> 1;
923           }
924 
925           return rev;
926 }
927 
928 
929 /*
930  * BTH5 MUX Layer functions
931  */
932 static void
bth5_mux_transmit(struct bth5_softc * sc)933 bth5_mux_transmit(struct bth5_softc *sc)
934 {
935           struct mbuf *m;
936           bth5_hdr_t *hdrp;
937           int s;
938 
939           DPRINTFN(2, ("%s: mux transmit: sc_flags=0x%x, choke=%d",
940               device_xname(sc->sc_dev), sc->sc_flags, sc->sc_mux_choke));
941 
942           if (sc->sc_mux_choke) {
943                     struct mbuf *_m = NULL;
944 
945                     /* In this case, send only Link Establishment packet */
946                     for (m = MBUFQ_FIRST(&sc->sc_dgq); m != NULL;
947                         _m = m, m = MBUFQ_NEXT(m)) {
948                               hdrp = mtod(m, bth5_hdr_t *);
949                               if (hdrp->ident == BTH5_CHANNEL_LE) {
950                                         if (m == MBUFQ_FIRST(&sc->sc_dgq))
951                                                   MBUFQ_DEQUEUE(&sc->sc_dgq, m);
952                                         else {
953                                                   if (m->m_nextpkt == NULL)
954                                                             sc->sc_dgq.mq_last =
955                                                                 &_m->m_nextpkt;
956                                                   _m->m_nextpkt = m->m_nextpkt;
957                                                   m->m_nextpkt = NULL;
958                                         }
959                                         goto transmit;
960                               }
961                     }
962                     DPRINTFN(2, ("\n"));
963                     return;
964           }
965 
966           /*
967            * The MUX Layer always gives priority to packets from the Datagram
968            * Queue Layer over the Sequencing Layer.
969            */
970           if (MBUFQ_FIRST(&sc->sc_dgq)) {
971                     MBUFQ_DEQUEUE(&sc->sc_dgq, m);
972                     goto transmit;
973           }
974           if (MBUFQ_FIRST(&sc->sc_seqq)) {
975                     MBUFQ_DEQUEUE(&sc->sc_seqq, m);
976                     hdrp = mtod(m, bth5_hdr_t *);
977                     hdrp->flags |= BTH5_FLAGS_PROTOCOL_REL;           /* Reliable */
978                     goto transmit;
979           }
980 
981           s = spltty();
982           if ((sc->sc_flags & BTH5_XMIT) == 0)
983                     bth5_start(sc);
984           splx(s);
985 
986           if (sc->sc_mux_send_ack == true) {
987                     m = bth5_create_ackpkt();
988                     if (m != NULL)
989                               goto transmit;
990                     aprint_error_dev(sc->sc_dev, "out of memory\n");
991                     sc->sc_stats.err_tx++;
992           }
993 
994           /* Nothing to send */
995           DPRINTFN(2, ("\n"));
996 
997           return;
998 
999 transmit:
1000           DPRINTFN(2, (", txack=%d, send_ack=%d\n",
1001               bth5_get_txack(sc), sc->sc_mux_send_ack));
1002 
1003           hdrp = mtod(m, bth5_hdr_t *);
1004           hdrp->flags |=
1005               (bth5_get_txack(sc) << BTH5_FLAGS_ACK_SHIFT) & BTH5_FLAGS_ACK_MASK;
1006           if (sc->sc_mux_send_ack == true)
1007                     sc->sc_mux_send_ack = false;
1008 
1009 #ifdef BTH5_DEBUG
1010           if (bth5_debug == 3)
1011                     bth5_packet_print(m);
1012 #endif
1013 
1014           sc->sc_txp = m;
1015           bth5_pktintegrity_transmit(sc);
1016 }
1017 
1018 static void
bth5_mux_receive(struct bth5_softc * sc,struct mbuf * m)1019 bth5_mux_receive(struct bth5_softc *sc, struct mbuf *m)
1020 {
1021           bth5_hdr_t *hdrp = mtod(m, bth5_hdr_t *);
1022           const u_int rxack = BTH5_FLAGS_ACK(hdrp->flags);
1023 
1024           DPRINTFN(2, ("%s: mux receive: flags=0x%x, ident=%d, rxack=%d\n",
1025               device_xname(sc->sc_dev), hdrp->flags, hdrp->ident, rxack));
1026 #ifdef BTH5_DEBUG
1027           if (bth5_debug == 3)
1028                     bth5_packet_print(m);
1029 #endif
1030 
1031           bth5_signal_rxack(sc, rxack);
1032 
1033           microtime(&sc->sc_mux_lastrx);
1034 
1035           /* if the Ack Packet received then discard */
1036           if (BTH5_FLAGS_SEQ(hdrp->flags) == 0 &&
1037               hdrp->ident == BTH5_IDENT_ACKPKT &&
1038               BTH5_GET_PLEN(hdrp) == 0) {
1039                     sc->sc_seq_txseq = BTH5_FLAGS_ACK(hdrp->flags);
1040                     bth5_send_ack_command(sc);
1041                     bth5_mux_transmit(sc);
1042                     m_freem(m);
1043                     return;
1044           }
1045 
1046           if (hdrp->flags & BTH5_FLAGS_PROTOCOL_REL)
1047                     bth5_sequencing_receive(sc, m);
1048           else
1049                     bth5_datagramq_receive(sc, m);
1050 }
1051 
1052 static __inline void
bth5_send_ack_command(struct bth5_softc * sc)1053 bth5_send_ack_command(struct bth5_softc *sc)
1054 {
1055 
1056           DPRINTFN(2, ("%s: mux send_ack_command\n", device_xname(sc->sc_dev)));
1057 
1058           sc->sc_mux_send_ack = true;
1059 }
1060 
1061 static __inline struct mbuf *
bth5_create_ackpkt(void)1062 bth5_create_ackpkt(void)
1063 {
1064           struct mbuf *m;
1065           bth5_hdr_t *hdrp;
1066 
1067           MGETHDR(m, M_DONTWAIT, MT_DATA);
1068           if (m != NULL) {
1069                     m->m_pkthdr.len = m->m_len = sizeof(bth5_hdr_t);
1070                     hdrp = mtod(m, bth5_hdr_t *);
1071                     /*
1072                      * An Ack Packet has the following fields:
1073                      *        Ack Field:                              txack (not set yet)
1074                      *        Seq Field:                              0
1075                      *        Protocol Identifier Field:    0
1076                      *        Protocol Type Field:                    Any value
1077                      *        Payload Length Field:                   0
1078                      */
1079                     memset(hdrp, 0, sizeof(bth5_hdr_t));
1080           }
1081           return m;
1082 }
1083 
1084 static __inline void
bth5_set_choke(struct bth5_softc * sc,bool choke)1085 bth5_set_choke(struct bth5_softc *sc, bool choke)
1086 {
1087 
1088           DPRINTFN(2, ("%s: mux set choke=%d\n", device_xname(sc->sc_dev), choke));
1089 
1090           sc->sc_mux_choke = choke;
1091 }
1092 
1093 
1094 /*
1095  * BTH5 Sequencing Layer functions
1096  */
1097 static void
bth5_sequencing_receive(struct bth5_softc * sc,struct mbuf * m)1098 bth5_sequencing_receive(struct bth5_softc *sc, struct mbuf *m)
1099 {
1100           bth5_hdr_t hdr;
1101           uint32_t exp_rxseq, rxack, rxseq;
1102 
1103           exp_rxseq = sc->sc_seq_expected_rxseq & BTH5_FLAGS_SEQ_MASK;
1104           m_copydata(m, 0, sizeof(bth5_hdr_t), &hdr);
1105           rxseq = BTH5_FLAGS_SEQ(hdr.flags);
1106           rxack = BTH5_FLAGS_ACK(hdr.flags);
1107 
1108           DPRINTFN(1, ("%s: seq receive: rxseq=%d, expected %d\n",
1109               device_xname(sc->sc_dev), rxseq, exp_rxseq));
1110 #ifdef BTH5_DEBUG
1111           if (bth5_debug == 2)
1112                     bth5_packet_print(m);
1113 #endif
1114 
1115           /*
1116            * We remove the header of BTH5 and add the 'uint8_t type' of
1117            * hci_*_hdr_t to the head.
1118            */
1119           m_adj(m, sizeof(bth5_hdr_t) - sizeof(uint8_t));
1120 
1121           if (rxseq != exp_rxseq) {
1122                     m_freem(m);
1123 
1124                     bth5_send_ack_command(sc);
1125                     /* send ack packet, if needly */
1126                     bth5_mux_transmit(sc);
1127 
1128                     return;
1129           }
1130 
1131           switch (hdr.ident) {
1132           case BTH5_CHANNEL_HCI_CMD:
1133                     *(mtod(m, uint8_t *)) = HCI_CMD_PKT;
1134                     if (!hci_input_event(sc->sc_unit, m))
1135                               sc->sc_stats.err_rx++;
1136 
1137                     sc->sc_stats.evt_rx++;
1138                     break;
1139 
1140           case BTH5_CHANNEL_HCI_EVT:
1141                     *(mtod(m, uint8_t *)) = HCI_EVENT_PKT;
1142                     if (!hci_input_event(sc->sc_unit, m))
1143                               sc->sc_stats.err_rx++;
1144 
1145                     sc->sc_stats.evt_rx++;
1146                     break;
1147 
1148           case BTH5_CHANNEL_HCI_ACL:
1149                     *(mtod(m, uint8_t *)) = HCI_ACL_DATA_PKT;
1150                     if (!hci_input_acl(sc->sc_unit, m))
1151                               sc->sc_stats.err_rx++;
1152 
1153                     sc->sc_stats.acl_rx++;
1154                     break;
1155 
1156           case BTH5_CHANNEL_HCI_SCO:
1157                     *(mtod(m, uint8_t *)) = HCI_SCO_DATA_PKT;
1158                     if (!hci_input_sco(sc->sc_unit, m))
1159                               sc->sc_stats.err_rx++;
1160 
1161                     sc->sc_stats.sco_rx++;
1162                     break;
1163 
1164           default:
1165                     aprint_error_dev(sc->sc_dev,
1166                         "received reliable packet with not support channel %d\n",
1167                         hdr.ident);
1168                     m_freem(m);
1169                     break;
1170           }
1171           bth5_send_ack_command(sc);
1172           sc->sc_seq_txseq = rxack;
1173           sc->sc_seq_expected_rxseq = (rxseq + 1) & BTH5_FLAGS_SEQ_MASK;
1174           sc->sc_seq_total_rxpkts++;
1175 
1176           if (sc->sc_seq_total_rxpkts % sc->sc_seq_winack == 0)
1177                     bth5_mux_transmit(sc);
1178 }
1179 
1180 static bool
bth5_tx_reliable_pkt(struct bth5_softc * sc,struct mbuf * m,u_int protocol_id)1181 bth5_tx_reliable_pkt(struct bth5_softc *sc, struct mbuf *m, u_int protocol_id)
1182 {
1183           bth5_hdr_t *hdrp;
1184           struct mbuf *_m;
1185           struct mbuf *_retrans;
1186           u_int pldlen;
1187           int s;
1188 
1189           DPRINTFN(1, ("%s: seq transmit:"
1190               "protocol_id=%d, winspace=%d, txseq=%d\n", device_xname(sc->sc_dev),
1191               protocol_id, sc->sc_seq_winspace, sc->sc_seq_txseq));
1192 
1193           for (pldlen = 0, _m = m; _m != NULL; _m = _m->m_next) {
1194                     if (_m->m_len < 0)
1195                               goto out;
1196                     pldlen += _m->m_len;
1197           }
1198           if (pldlen > 0xfff)
1199                     goto out;
1200           if (protocol_id == BTH5_IDENT_ACKPKT || protocol_id > 15)
1201                     goto out;
1202 
1203           if (sc->sc_seq_winspace == 0)
1204                     goto out;
1205 
1206           M_PREPEND(m, sizeof(bth5_hdr_t), M_DONTWAIT);
1207           if (m == NULL) {
1208                     aprint_error_dev(sc->sc_dev, "out of memory\n");
1209                     return false;
1210           }
1211           KASSERT(m->m_len >= sizeof(bth5_hdr_t));
1212 
1213           hdrp = mtod(m, bth5_hdr_t *);
1214           memset(hdrp, 0, sizeof(bth5_hdr_t));
1215           hdrp->flags |= sc->sc_seq_txseq;
1216           hdrp->ident = protocol_id;
1217 
1218           callout_schedule(&sc->sc_seq_timer, sc->sc_seq_timeout);
1219 
1220           s = splserial();
1221           MBUFQ_ENQUEUE(&sc->sc_seqq, m);
1222           splx(s);
1223           sc->sc_transmit_callback = bth5_reliabletx_callback;
1224 
1225 #ifdef BTH5_DEBUG
1226           if (bth5_debug == 2)
1227                     bth5_packet_print(m);
1228 #endif
1229 
1230           sc->sc_seq_winspace--;
1231           _retrans = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
1232           if (_retrans == NULL) {
1233                     aprint_error_dev(sc->sc_dev, "out of memory\n");
1234                     goto out;
1235           }
1236           MBUFQ_ENQUEUE(&sc->sc_seq_retryq, _retrans);
1237           bth5_mux_transmit(sc);
1238           sc->sc_seq_txseq = (sc->sc_seq_txseq + 1) & BTH5_FLAGS_SEQ_MASK;
1239 
1240           return true;
1241 out:
1242           m_freem(m);
1243           return false;
1244 }
1245 
1246 static __inline u_int
bth5_get_txack(struct bth5_softc * sc)1247 bth5_get_txack(struct bth5_softc *sc)
1248 {
1249 
1250           return sc->sc_seq_expected_rxseq;
1251 }
1252 
1253 static void
bth5_signal_rxack(struct bth5_softc * sc,uint32_t rxack)1254 bth5_signal_rxack(struct bth5_softc *sc, uint32_t rxack)
1255 {
1256           bth5_hdr_t *hdrp;
1257           struct mbuf *m;
1258           uint32_t seqno = (rxack - 1) & BTH5_FLAGS_SEQ_MASK;
1259           int s;
1260 
1261           DPRINTFN(1, ("%s: seq signal rxack: rxack=%d\n",
1262               device_xname(sc->sc_dev), rxack));
1263 
1264           s = splserial();
1265           m = MBUFQ_FIRST(&sc->sc_seq_retryq);
1266           while (m != NULL) {
1267                     hdrp = mtod(m, bth5_hdr_t *);
1268                     if (BTH5_FLAGS_SEQ(hdrp->flags) == seqno) {
1269                               struct mbuf *m0;
1270 
1271                               for (m0 = MBUFQ_FIRST(&sc->sc_seq_retryq);
1272                                   m0 != MBUFQ_NEXT(m);
1273                                   m0 = MBUFQ_FIRST(&sc->sc_seq_retryq)) {
1274                                         MBUFQ_DEQUEUE(&sc->sc_seq_retryq, m0);
1275                                         m_freem(m0);
1276                                         sc->sc_seq_winspace++;
1277                                         if (sc->sc_seq_winspace > sc->sc_seq_winsize)
1278                                                   sc->sc_seq_winspace = sc->sc_seq_winsize;
1279                               }
1280                               break;
1281                     }
1282                     m = MBUFQ_NEXT(m);
1283           }
1284           splx(s);
1285           sc->sc_seq_retries = 0;
1286 
1287           if (sc->sc_seq_winspace == sc->sc_seq_winsize)
1288                     callout_stop(&sc->sc_seq_timer);
1289           else
1290                     callout_schedule(&sc->sc_seq_timer, sc->sc_seq_timeout);
1291 }
1292 
1293 static void
bth5_reliabletx_callback(struct bth5_softc * sc,struct mbuf * m)1294 bth5_reliabletx_callback(struct bth5_softc *sc, struct mbuf *m)
1295 {
1296 
1297           m_freem(m);
1298 }
1299 
1300 static void
bth5_timer_timeout(void * arg)1301 bth5_timer_timeout(void *arg)
1302 {
1303           struct bth5_softc *sc = arg;
1304           struct mbuf *m, *_m;
1305           int s, i = 0;
1306 
1307           DPRINTFN(1, ("%s: seq timeout: retries=%d\n",
1308               device_xname(sc->sc_dev), sc->sc_seq_retries));
1309 
1310           bth5_send_ack_command(sc);
1311           bth5_mux_transmit(sc);
1312           s = splserial();
1313           for (m = MBUFQ_FIRST(&sc->sc_seq_retryq); m != NULL;
1314               m = MBUFQ_NEXT(m)) {
1315                     _m = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
1316                     if (_m == NULL) {
1317                               aprint_error_dev(sc->sc_dev, "out of memory\n");
1318                               return;
1319                     }
1320                     MBUFQ_ENQUEUE(&sc->sc_seqq, _m);
1321                     i++;
1322           }
1323           splx(s);
1324 
1325           if (i != 0) {
1326                     if (++sc->sc_seq_retries < sc->sc_seq_retry_limit)
1327                               callout_schedule(&sc->sc_seq_timer, sc->sc_seq_timeout);
1328                     else {
1329                               aprint_error_dev(sc->sc_dev,
1330                                   "reached the retry limit."
1331                                   " restart the link-establishment\n");
1332                               bth5_sequencing_reset(sc);
1333                               bth5_start_le(sc);
1334                               return;
1335                     }
1336           }
1337           bth5_mux_transmit(sc);
1338 }
1339 
1340 static void
bth5_sequencing_reset(struct bth5_softc * sc)1341 bth5_sequencing_reset(struct bth5_softc *sc)
1342 {
1343           int s;
1344 
1345           s = splserial();
1346           MBUFQ_DRAIN(&sc->sc_seqq);
1347           MBUFQ_DRAIN(&sc->sc_seq_retryq);
1348           splx(s);
1349 
1350 
1351           sc->sc_seq_txseq = 0;
1352           sc->sc_seq_winspace = sc->sc_seq_winsize;
1353           sc->sc_seq_retries = 0;
1354           callout_stop(&sc->sc_seq_timer);
1355 
1356           sc->sc_mux_send_ack = false;
1357 
1358           /* XXXX: expected_rxseq should be set by MUX Layer */
1359           sc->sc_seq_expected_rxseq = 0;
1360           sc->sc_seq_total_rxpkts = 0;
1361 }
1362 
1363 
1364 /*
1365  * BTH5 Datagram Queue Layer functions
1366  */
1367 static void
bth5_datagramq_receive(struct bth5_softc * sc,struct mbuf * m)1368 bth5_datagramq_receive(struct bth5_softc *sc, struct mbuf *m)
1369 {
1370           bth5_hdr_t hdr;
1371 
1372           DPRINTFN(1, ("%s: dgq receive\n", device_xname(sc->sc_dev)));
1373 #ifdef BTH5_DEBUG
1374           if (bth5_debug == 2)
1375                     bth5_packet_print(m);
1376 #endif
1377 
1378           m_copydata(m, 0, sizeof(bth5_hdr_t), &hdr);
1379 
1380           switch (hdr.ident) {
1381           case BTH5_CHANNEL_LE:
1382                     m_adj(m, sizeof(bth5_hdr_t));
1383                     bth5_input_le(sc, m);
1384                     break;
1385 
1386           case BTH5_CHANNEL_HCI_SCO:
1387                     /*
1388                      * We remove the header of BTH5 and add the 'uint8_t type' of
1389                      * hci_scodata_hdr_t to the head.
1390                      */
1391                     m_adj(m, sizeof(bth5_hdr_t) - sizeof(uint8_t));
1392                     *(mtod(m, uint8_t *)) = HCI_SCO_DATA_PKT;
1393                     if (!hci_input_sco(sc->sc_unit, m))
1394                               sc->sc_stats.err_rx++;
1395 
1396                     sc->sc_stats.sco_rx++;
1397                     break;
1398 
1399           default:
1400                     aprint_error_dev(sc->sc_dev,
1401                         "received unreliable packet with not support channel %d\n",
1402                         hdr.ident);
1403                     m_freem(m);
1404                     break;
1405           }
1406 }
1407 
1408 static bool
bth5_tx_unreliable_pkt(struct bth5_softc * sc,struct mbuf * m,u_int protocol_id)1409 bth5_tx_unreliable_pkt(struct bth5_softc *sc, struct mbuf *m, u_int protocol_id)
1410 {
1411           bth5_hdr_t *hdrp;
1412           struct mbuf *_m;
1413           u_int pldlen;
1414           int s;
1415 
1416           DPRINTFN(1, ("%s: dgq transmit: protocol_id=%d,",
1417               device_xname(sc->sc_dev), protocol_id));
1418 
1419           for (pldlen = 0, _m = m; _m != NULL; _m = m->m_next) {
1420                     if (_m->m_len < 0)
1421                               goto out;
1422                     pldlen += _m->m_len;
1423           }
1424           DPRINTFN(1, (" pldlen=%d\n", pldlen));
1425           if (pldlen > 0xfff)
1426                     goto out;
1427           if (protocol_id == BTH5_IDENT_ACKPKT || protocol_id > 15)
1428                     goto out;
1429 
1430           M_PREPEND(m, sizeof(bth5_hdr_t), M_DONTWAIT);
1431           if (m == NULL) {
1432                     aprint_error_dev(sc->sc_dev, "out of memory\n");
1433                     return false;
1434           }
1435           KASSERT(m->m_len >= sizeof(bth5_hdr_t));
1436 
1437           hdrp = mtod(m, bth5_hdr_t *);
1438           memset(hdrp, 0, sizeof(bth5_hdr_t));
1439           hdrp->ident = protocol_id;
1440 
1441           s = splserial();
1442           MBUFQ_ENQUEUE(&sc->sc_dgq, m);
1443           splx(s);
1444           sc->sc_transmit_callback = bth5_unreliabletx_callback;
1445 
1446 #ifdef BTH5_DEBUG
1447           if (bth5_debug == 2)
1448                     bth5_packet_print(m);
1449 #endif
1450 
1451           bth5_mux_transmit(sc);
1452 
1453           return true;
1454 out:
1455           m_freem(m);
1456           return false;
1457 }
1458 
1459 static void
bth5_unreliabletx_callback(struct bth5_softc * sc,struct mbuf * m)1460 bth5_unreliabletx_callback(struct bth5_softc *sc, struct mbuf *m)
1461 {
1462 
1463           if (M_GETCTX(m, void *) == NULL)
1464                     m_freem(m);
1465           else if (!hci_complete_sco(sc->sc_unit, m))
1466                     sc->sc_stats.err_tx++;
1467 }
1468 
1469 
1470 /*
1471  * BTUART H5 Link Establishment Protocol functions
1472  */
1473 static const uint8_t sync[] = BTH5_LE_SYNC;
1474 static const uint8_t syncresp[] = BTH5_LE_SYNCRESP;
1475 static const uint8_t conf[] = BTH5_LE_CONF;
1476 static const uint8_t confresp[] = BTH5_LE_CONFRESP;
1477 
1478 static int
bth5_start_le(struct bth5_softc * sc)1479 bth5_start_le(struct bth5_softc *sc)
1480 {
1481 
1482           DPRINTF(("%s: start link-establish\n", device_xname(sc->sc_dev)));
1483 
1484           bth5_set_choke(sc, true);
1485 
1486           if (!sc->sc_le_muzzled) {
1487                     struct mbuf *m;
1488 
1489                     m = m_gethdr(M_DONTWAIT, MT_DATA);
1490                     if (m == NULL) {
1491                               aprint_error_dev(sc->sc_dev,
1492                                   "le-packet transmit out of memory\n");
1493                               return ENOMEM;
1494                     }
1495                     m->m_pkthdr.len = m->m_len = 0;
1496                     m_copyback(m, 0, sizeof(sync), sync);
1497                     if (!bth5_tx_unreliable_pkt(sc, m, BTH5_CHANNEL_LE)) {
1498                               aprint_error_dev(sc->sc_dev,
1499                                   "le-packet transmit failed\n");
1500                               return EINVAL;
1501                     }
1502           }
1503           callout_schedule(&sc->sc_le_timer, BTH5_LE_TSHY_TIMEOUT);
1504 
1505           sc->sc_le_state = le_state_shy;
1506           return 0;
1507 }
1508 
1509 static void
bth5_terminate_le(struct bth5_softc * sc)1510 bth5_terminate_le(struct bth5_softc *sc)
1511 {
1512           struct mbuf *m;
1513 
1514           /* terminate link-establishment */
1515           callout_stop(&sc->sc_le_timer);
1516           bth5_set_choke(sc, true);
1517           MGETHDR(m, M_DONTWAIT, MT_DATA);
1518           if (m == NULL)
1519                     aprint_error_dev(sc->sc_dev, "out of memory\n");
1520           else {
1521                     /* length of le packets is 4 */
1522                     m->m_pkthdr.len = m->m_len = 0;
1523                     m_copyback(m, 0, sizeof(sync), sync);
1524                     if (!bth5_tx_unreliable_pkt(sc, m, BTH5_CHANNEL_LE))
1525                               aprint_error_dev(sc->sc_dev,
1526                                   "link-establishment terminations failed\n");
1527           }
1528 }
1529 
1530 static void
bth5_input_le(struct bth5_softc * sc,struct mbuf * m)1531 bth5_input_le(struct bth5_softc *sc, struct mbuf *m)
1532 {
1533           uint16_t *rcvpkt;
1534           int i, len;
1535           uint8_t config[3];
1536           const uint8_t *rplypkt;
1537           static struct {
1538                     const char *type;
1539                     const uint8_t *datap;
1540           } pkt[] = {
1541                     { "sync", sync },
1542                     { "sync-resp",      syncresp },
1543                     { "conf", conf },
1544                     { "conf-resp",      confresp },
1545 
1546                     { NULL, 0 }
1547           };
1548 
1549           DPRINTFN(0, ("%s: le input: state %d, muzzled %d\n",
1550               device_xname(sc->sc_dev), sc->sc_le_state, sc->sc_le_muzzled));
1551 #ifdef BTH5_DEBUG
1552           if (bth5_debug == 1)
1553                     bth5_packet_print(m);
1554 #endif
1555 
1556           rcvpkt = mtod(m, uint16_t *);
1557           i = 0;
1558 
1559           /* length of le packets is 2 */
1560           if (m->m_len >= sizeof(uint16_t))
1561                     for (i = 0; pkt[i].type != NULL; i++)
1562                               if (*(const uint16_t *)pkt[i].datap == *rcvpkt)
1563                                         break;
1564           if (m->m_len < sizeof(uint16_t) || pkt[i].type == NULL) {
1565                     aprint_error_dev(sc->sc_dev, "received unknown packet\n");
1566                     m_freem(m);
1567                     return;
1568           }
1569 
1570           len = m->m_len;
1571 
1572           rplypkt = NULL;
1573           switch (sc->sc_le_state) {
1574           case le_state_shy:
1575                     if (*rcvpkt == *(const uint16_t *)sync) {
1576                               sc->sc_le_muzzled = false;
1577                               rplypkt = syncresp;
1578                     } else if (*rcvpkt == *(const uint16_t *)syncresp) {
1579                               DPRINTF(("%s: state change to curious\n",
1580                                   device_xname(sc->sc_dev)));
1581                               rplypkt = conf;
1582                               callout_schedule(&sc->sc_le_timer,
1583                                   BTH5_LE_TCONF_TIMEOUT);
1584                               sc->sc_le_state = le_state_curious;
1585                     } else
1586                               aprint_error_dev(sc->sc_dev,
1587                                   "received an unknown packet at shy\n");
1588                     break;
1589 
1590           case le_state_curious:
1591                     if (*rcvpkt == *(const uint16_t *)sync)
1592                               rplypkt = syncresp;
1593                     else if (*rcvpkt == *(const uint16_t *)syncresp) {
1594                               rplypkt = conf;
1595                               len = 3;
1596                     }
1597                     else if (*rcvpkt == *(const uint16_t *)conf)
1598                               rplypkt = confresp;
1599                     else if (*rcvpkt == *(const uint16_t *)confresp &&
1600                                         m->m_len == 3) {
1601                               DPRINTF(("%s: state change to garrulous:\n",
1602                                   device_xname(sc->sc_dev)));
1603 
1604                               memcpy(config, conf, sizeof(uint16_t));
1605                               config[2] = (uint8_t)rcvpkt[1];
1606                               sc->sc_seq_winack = config[2] & BTH5_CONFIG_ACK_MASK;
1607                               if (config[2] & BTH5_CONFIG_FLOW_MASK)
1608                                         sc->sc_oof_flow_control = true;
1609                               else
1610                                         sc->sc_oof_flow_control = false;
1611 
1612                               bth5_sequencing_reset(sc);
1613                               bth5_set_choke(sc, false);
1614                               callout_stop(&sc->sc_le_timer);
1615                               sc->sc_le_state = le_state_garrulous;
1616                     } else
1617                               aprint_error_dev(sc->sc_dev,
1618                                   "received unknown packet at curious\n");
1619                     break;
1620 
1621           case le_state_garrulous:
1622                     if (*rcvpkt == *(const uint16_t *)conf)
1623                               rplypkt = confresp;
1624                     else if (*rcvpkt == *(const uint16_t *)sync) {
1625                               /* XXXXX */
1626                               aprint_error_dev(sc->sc_dev,
1627                                   "received sync! peer to reset?\n");
1628 
1629                               bth5_sequencing_reset(sc);
1630                               rplypkt = syncresp;
1631                               sc->sc_le_state = le_state_shy;
1632                     } else
1633                               aprint_error_dev(sc->sc_dev,
1634                                   "received unknown packet at garrulous\n");
1635                     break;
1636           }
1637 
1638           m_freem(m);
1639 
1640           if (rplypkt != NULL) {
1641                     MGETHDR(m, M_DONTWAIT, MT_DATA);
1642                     if (m == NULL)
1643                               aprint_error_dev(sc->sc_dev, "out of memory\n");
1644                     else {
1645                               /* length of le packets is 2 */
1646                               m->m_pkthdr.len = m->m_len = 0;
1647                               if (rplypkt == (const uint8_t *)&config
1648                                   || rplypkt == confresp || rplypkt == conf)
1649                                         m_copyback(m, 0, len, rplypkt);
1650                               else
1651                                         m_copyback(m, 0, 2, rplypkt);
1652                               if (!bth5_tx_unreliable_pkt(sc, m, BTH5_CHANNEL_LE))
1653                                         aprint_error_dev(sc->sc_dev,
1654                                             "le-packet transmit failed\n");
1655                     }
1656           }
1657 }
1658 
1659 static void
bth5_le_timeout(void * arg)1660 bth5_le_timeout(void *arg)
1661 {
1662           struct bth5_softc *sc = arg;
1663           struct mbuf *m;
1664           int timeout;
1665           const uint8_t *sndpkt = NULL;
1666 
1667           DPRINTFN(0, ("%s: le timeout: state %d, muzzled %d\n",
1668               device_xname(sc->sc_dev), sc->sc_le_state, sc->sc_le_muzzled));
1669 
1670           switch (sc->sc_le_state) {
1671           case le_state_shy:
1672                     if (!sc->sc_le_muzzled)
1673                               sndpkt = sync;
1674                     timeout = BTH5_LE_TSHY_TIMEOUT;
1675                     break;
1676 
1677           case le_state_curious:
1678                     sndpkt = conf;
1679                     timeout = BTH5_LE_TCONF_TIMEOUT;
1680                     break;
1681 
1682           default:
1683                     aprint_error_dev(sc->sc_dev,
1684                         "timeout happen at unknown state %d\n", sc->sc_le_state);
1685                     return;
1686           }
1687 
1688           if (sndpkt != NULL) {
1689                     MGETHDR(m, M_DONTWAIT, MT_DATA);
1690                     if (m == NULL)
1691                               aprint_error_dev(sc->sc_dev, "out of memory\n");
1692                     else {
1693                               /* length of le packets is 4 */
1694                               m->m_pkthdr.len = m->m_len = 0;
1695                               if (sndpkt == conf || sndpkt == confresp)
1696                                         m_copyback(m, 0, 3, sndpkt);
1697                               else
1698                                         m_copyback(m, 0, 2, sndpkt);
1699                               if (!bth5_tx_unreliable_pkt(sc, m, BTH5_CHANNEL_LE))
1700                                         aprint_error_dev(sc->sc_dev,
1701                                             "le-packet transmit failed\n");
1702                     }
1703           }
1704 
1705           callout_schedule(&sc->sc_le_timer, timeout);
1706 }
1707 
1708 
1709 /*
1710  * BTUART H5 Serial Protocol functions.
1711  */
1712 static int
bth5_enable(device_t self)1713 bth5_enable(device_t self)
1714 {
1715           struct bth5_softc *sc = device_private(self);
1716           int s;
1717 
1718           if (sc->sc_flags & BTH5_ENABLED)
1719                     return 0;
1720 
1721           s = spltty();
1722 
1723           sc->sc_flags |= BTH5_ENABLED;
1724           sc->sc_flags &= ~BTH5_XMIT;
1725 
1726           splx(s);
1727 
1728           return 0;
1729 }
1730 
1731 static void
bth5_disable(device_t self)1732 bth5_disable(device_t self)
1733 {
1734           struct bth5_softc *sc = device_private(self);
1735           int s;
1736 
1737           if ((sc->sc_flags & BTH5_ENABLED) == 0)
1738                     return;
1739 
1740           s = spltty();
1741 
1742           m_freem(sc->sc_rxp);
1743           sc->sc_rxp = NULL;
1744 
1745           m_freem(sc->sc_txp);
1746           sc->sc_txp = NULL;
1747 
1748           MBUFQ_DRAIN(&sc->sc_cmdq);
1749           MBUFQ_DRAIN(&sc->sc_aclq);
1750           MBUFQ_DRAIN(&sc->sc_scoq);
1751 
1752           sc->sc_flags &= ~BTH5_ENABLED;
1753           splx(s);
1754 }
1755 
1756 static void
bth5_start(struct bth5_softc * sc)1757 bth5_start(struct bth5_softc *sc)
1758 {
1759           struct mbuf *m;
1760 
1761           KASSERT((sc->sc_flags & BTH5_XMIT) == 0);
1762           KASSERT(sc->sc_txp == NULL);
1763 
1764           if (MBUFQ_FIRST(&sc->sc_aclq)) {
1765                     MBUFQ_DEQUEUE(&sc->sc_aclq, m);
1766                     sc->sc_stats.acl_tx++;
1767                     sc->sc_flags |= BTH5_XMIT;
1768                     bth5_tx_reliable_pkt(sc, m, BTH5_CHANNEL_HCI_ACL);
1769           }
1770 
1771           if (MBUFQ_FIRST(&sc->sc_cmdq)) {
1772                     MBUFQ_DEQUEUE(&sc->sc_cmdq, m);
1773                     sc->sc_stats.cmd_tx++;
1774                     sc->sc_flags |= BTH5_XMIT;
1775                     bth5_tx_reliable_pkt(sc, m, BTH5_CHANNEL_HCI_CMD);
1776           }
1777 
1778           if (MBUFQ_FIRST(&sc->sc_scoq)) {
1779                     MBUFQ_DEQUEUE(&sc->sc_scoq, m);
1780                     sc->sc_stats.sco_tx++;
1781                     /* XXXX: We can transmit with reliable */
1782                     sc->sc_flags |= BTH5_XMIT;
1783                     bth5_tx_unreliable_pkt(sc, m, BTH5_CHANNEL_HCI_SCO);
1784           }
1785 
1786           return;
1787 }
1788 
1789 static void
bth5_output_cmd(device_t self,struct mbuf * m)1790 bth5_output_cmd(device_t self, struct mbuf *m)
1791 {
1792           struct bth5_softc *sc = device_private(self);
1793           int s;
1794 
1795           KASSERT(sc->sc_flags & BTH5_ENABLED);
1796 
1797           m_adj(m, sizeof(uint8_t));
1798           M_SETCTX(m, NULL);
1799 
1800           s = spltty();
1801           MBUFQ_ENQUEUE(&sc->sc_cmdq, m);
1802           if ((sc->sc_flags & BTH5_XMIT) == 0)
1803                     bth5_start(sc);
1804 
1805           splx(s);
1806 }
1807 
1808 static void
bth5_output_acl(device_t self,struct mbuf * m)1809 bth5_output_acl(device_t self, struct mbuf *m)
1810 {
1811           struct bth5_softc *sc = device_private(self);
1812           int s;
1813 
1814           KASSERT(sc->sc_flags & BTH5_ENABLED);
1815 
1816           m_adj(m, sizeof(uint8_t));
1817           M_SETCTX(m, NULL);
1818 
1819           s = spltty();
1820           MBUFQ_ENQUEUE(&sc->sc_aclq, m);
1821           if ((sc->sc_flags & BTH5_XMIT) == 0)
1822                     bth5_start(sc);
1823 
1824           splx(s);
1825 }
1826 
1827 static void
bth5_output_sco(device_t self,struct mbuf * m)1828 bth5_output_sco(device_t self, struct mbuf *m)
1829 {
1830           struct bth5_softc *sc = device_private(self);
1831           int s;
1832 
1833           KASSERT(sc->sc_flags & BTH5_ENABLED);
1834 
1835           m_adj(m, sizeof(uint8_t));
1836 
1837           s = spltty();
1838           MBUFQ_ENQUEUE(&sc->sc_scoq, m);
1839           if ((sc->sc_flags & BTH5_XMIT) == 0)
1840                     bth5_start(sc);
1841 
1842           splx(s);
1843 }
1844 
1845 static void
bth5_stats(device_t self,struct bt_stats * dest,int flush)1846 bth5_stats(device_t self, struct bt_stats *dest, int flush)
1847 {
1848           struct bth5_softc *sc = device_private(self);
1849           int s;
1850 
1851           s = spltty();
1852           memcpy(dest, &sc->sc_stats, sizeof(struct bt_stats));
1853 
1854           if (flush)
1855                     memset(&sc->sc_stats, 0, sizeof(struct bt_stats));
1856 
1857           splx(s);
1858 }
1859 
1860 
1861 #ifdef BTH5_DEBUG
1862 static void
bth5_packet_print(struct mbuf * m)1863 bth5_packet_print(struct mbuf *m)
1864 {
1865           int i;
1866           uint8_t *p;
1867 
1868           for ( ; m != NULL; m = m->m_next) {
1869                     p = mtod(m, uint8_t *);
1870                     for (i = 0; i < m->m_len; i++) {
1871                               if (i % 16 == 0)
1872                                         printf(" ");
1873                               printf(" %02x", *(p + i));
1874                               if (i % 16 == 15)
1875                                         printf("\n");
1876                     }
1877                     printf("\n");
1878           }
1879 }
1880 #endif
1881