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