xref: /netbsd-src/sys/dev/bluetooth/bth5.c (revision 481d3881954fd794ca5f2d880b68c53a5db8620e)
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