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