1 /*- 2 * (MPSAFE) 3 * 4 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5 * All rights reserved. 6 * 7 * ng_h4.c 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $Id: ng_h4.c,v 1.10 2005/10/31 17:57:43 max Exp $ 31 * $FreeBSD: head/sys/netgraph/bluetooth/drivers/h4/ng_h4.c 243882 2012-12-05 08:04:20Z glebius $ 32 * 33 * Based on: 34 * --------- 35 * 36 * FreeBSD: src/sys/netgraph/ng_tty.c 37 * Author: Archie Cobbs <archie@freebsd.org> 38 * 39 */ 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/kernel.h> 44 #include <sys/conf.h> 45 #include <sys/endian.h> 46 #include <sys/errno.h> 47 #include <sys/fcntl.h> 48 #include <sys/malloc.h> 49 #include <sys/mbuf.h> 50 #include <sys/priv.h> 51 #include <sys/socket.h> 52 #include <sys/tty.h> 53 #include <sys/ttycom.h> 54 #include <net/if.h> 55 #include <net/if_var.h> 56 #include <netgraph7/ng_message.h> 57 #include <netgraph7/netgraph.h> 58 #include <netgraph7/ng_parse.h> 59 #include <netgraph7/bluetooth/include/ng_bluetooth.h> 60 #include <netgraph7/bluetooth/include/ng_hci.h> 61 #include <netgraph7/bluetooth/include/ng_h4.h> 62 #include <netgraph7/bluetooth/drivers/h4/ng_h4_var.h> 63 #include <netgraph7/bluetooth/drivers/h4/ng_h4_prse.h> 64 65 /***************************************************************************** 66 ***************************************************************************** 67 ** This node implements a Bluetooth HCI UART transport layer as per chapter 68 ** H4 of the Bluetooth Specification Book v1.1. It is a terminal line 69 ** discipline that is also a netgraph node. Installing this line discipline 70 ** on a terminal device instantiates a new netgraph node of this type, which 71 ** allows access to the device via the "hook" hook of the node. 72 ** 73 ** Once the line discipline is installed, you can find out the name of the 74 ** corresponding netgraph node via a NGIOCGINFO ioctl(). 75 ***************************************************************************** 76 *****************************************************************************/ 77 78 /* MALLOC define */ 79 #ifndef NG_SEPARATE_MALLOC 80 MALLOC_DEFINE(M_NETGRAPH_H4, "netgraph_h4", "Netgraph Bluetooth H4 node"); 81 #else 82 #define M_NETGRAPH_H4 M_NETGRAPH 83 #endif /* NG_SEPARATE_MALLOC */ 84 85 /* Line discipline methods */ 86 static int ng_h4_open (struct cdev *, struct tty *); 87 static int ng_h4_close (struct tty *, int); 88 static int ng_h4_read (struct tty *, struct uio *, int); 89 static int ng_h4_write (struct tty *, struct uio *, int); 90 static int ng_h4_input (int, struct tty *); 91 static int ng_h4_start (struct tty *); 92 static int ng_h4_ioctl (struct tty *, u_long, caddr_t, 93 int, struct ucred *); 94 95 /* Line discipline descriptor */ 96 static struct linesw ng_h4_disc = { 97 ng_h4_open, /* open */ 98 ng_h4_close, /* close */ 99 ng_h4_read, /* read */ 100 ng_h4_write, /* write */ 101 ng_h4_ioctl, /* ioctl */ 102 ng_h4_input, /* input */ 103 ng_h4_start, /* start */ 104 ttymodem /* modem */ 105 }; 106 107 /* Netgraph methods */ 108 static ng_constructor_t ng_h4_constructor; 109 static ng_rcvmsg_t ng_h4_rcvmsg; 110 static ng_shutdown_t ng_h4_shutdown; 111 static ng_newhook_t ng_h4_newhook; 112 static ng_connect_t ng_h4_connect; 113 static ng_rcvdata_t ng_h4_rcvdata; 114 static ng_disconnect_t ng_h4_disconnect; 115 116 /* Other stuff */ 117 static void ng_h4_process_timeout (node_p, hook_p, void *, int); 118 static int ng_h4_mod_event (module_t, int, void *); 119 120 /* Netgraph node type descriptor */ 121 static struct ng_type typestruct = { 122 .version = NG_ABI_VERSION, 123 .name = NG_H4_NODE_TYPE, 124 .mod_event = ng_h4_mod_event, 125 .constructor = ng_h4_constructor, 126 .rcvmsg = ng_h4_rcvmsg, 127 .shutdown = ng_h4_shutdown, 128 .newhook = ng_h4_newhook, 129 .connect = ng_h4_connect, 130 .rcvdata = ng_h4_rcvdata, 131 .disconnect = ng_h4_disconnect, 132 .cmdlist = ng_h4_cmdlist 133 }; 134 NETGRAPH_INIT(h4, &typestruct); 135 MODULE_VERSION(ng_h4, NG_BLUETOOTH_VERSION); 136 137 static int ng_h4_node = 0; 138 139 /***************************************************************************** 140 ***************************************************************************** 141 ** Line discipline methods 142 ***************************************************************************** 143 *****************************************************************************/ 144 145 /* 146 * Set our line discipline on the tty. 147 */ 148 149 static int 150 ng_h4_open(struct cdev *dev, struct tty *tp) 151 { 152 struct thread *td = curthread; 153 char name[NG_NODESIZ]; 154 ng_h4_info_p sc = NULL; 155 int error; 156 157 /* Super-user only */ 158 error = priv_check(td, PRIV_NETGRAPH_TTY); /* XXX */ 159 if (error != 0) 160 return (error); 161 162 /* Initialize private struct */ 163 sc = kmalloc(sizeof(*sc), M_NETGRAPH_H4, M_WAITOK | M_NULLOK | M_ZERO); 164 if (sc == NULL) 165 return (ENOMEM); 166 167 lwkt_gettoken(&tp->t_token); 168 sc->tp = tp; 169 sc->debug = NG_H4_WARN_LEVEL; 170 171 sc->state = NG_H4_W4_PKT_IND; 172 sc->want = 1; 173 sc->got = 0; 174 175 sc->outq.ifq_maxlen = NG_H4_DEFAULTQLEN; 176 ng_callout_init(&sc->timo); 177 178 NG_H4_LOCK(sc); 179 180 /* Setup netgraph node */ 181 error = ng_make_node_common(&typestruct, &sc->node); 182 if (error != 0) { 183 NG_H4_UNLOCK(sc); 184 185 kprintf("%s: Unable to create new node!\n", __func__); 186 187 bzero(sc, sizeof(*sc)); 188 kfree(sc, M_NETGRAPH_H4); 189 190 lwkt_reltoken(&tp->t_token); 191 return (error); 192 } 193 194 /* Assign node its name */ 195 ksnprintf(name, sizeof(name), "%s%d", typestruct.name, ng_h4_node ++); 196 197 error = ng_name_node(sc->node, name); 198 if (error != 0) { 199 NG_H4_UNLOCK(sc); 200 201 kprintf("%s: %s - node name exists?\n", __func__, name); 202 203 NG_NODE_UNREF(sc->node); 204 bzero(sc, sizeof(*sc)); 205 kfree(sc, M_NETGRAPH_H4); 206 207 lwkt_reltoken(&tp->t_token); 208 return (error); 209 } 210 211 /* Set back pointers */ 212 NG_NODE_SET_PRIVATE(sc->node, sc); 213 tp->t_sc = (caddr_t) sc; 214 215 /* The node has to be a WRITER because data can change node status */ 216 NG_NODE_FORCE_WRITER(sc->node); 217 218 /* 219 * Pre-allocate cblocks to the an appropriate amount. 220 * I'm not sure what is appropriate. 221 */ 222 223 ttyflush(tp, FREAD | FWRITE); 224 clist_alloc_cblocks(&tp->t_canq, 0); 225 clist_alloc_cblocks(&tp->t_rawq, 0); 226 clist_alloc_cblocks(&tp->t_outq, MLEN + NG_H4_HIWATER); 227 228 NG_H4_UNLOCK(sc); 229 230 lwkt_reltoken(&tp->t_token); 231 return (error); 232 } /* ng_h4_open */ 233 234 /* 235 * Line specific close routine, called from device close routine 236 * and from ttioctl. This causes the node to be destroyed as well. 237 */ 238 239 static int 240 ng_h4_close(struct tty *tp, int flag) 241 { 242 ng_h4_info_p sc = (ng_h4_info_p) tp->t_sc; 243 244 lwkt_gettoken(&tp->t_token); 245 ttyflush(tp, FREAD | FWRITE); 246 clist_free_cblocks(&tp->t_outq); 247 248 if (sc != NULL) { 249 NG_H4_LOCK(sc); 250 251 if (callout_pending(&sc->timo)) 252 ng_uncallout(&sc->timo, sc->node); 253 254 tp->t_sc = NULL; 255 sc->dying = 1; 256 257 NG_H4_UNLOCK(sc); 258 259 ng_rmnode_self(sc->node); 260 } 261 262 lwkt_reltoken(&tp->t_token); 263 return (0); 264 } /* ng_h4_close */ 265 266 /* 267 * Once the device has been turned into a node, we don't allow reading. 268 */ 269 270 static int 271 ng_h4_read(struct tty *tp, struct uio *uio, int flag) 272 { 273 return (EIO); 274 } /* ng_h4_read */ 275 276 /* 277 * Once the device has been turned into a node, we don't allow writing. 278 */ 279 280 static int 281 ng_h4_write(struct tty *tp, struct uio *uio, int flag) 282 { 283 return (EIO); 284 } /* ng_h4_write */ 285 286 /* 287 * We implement the NGIOCGINFO ioctl() defined in ng_message.h. 288 */ 289 290 static int 291 ng_h4_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, 292 struct ucred *cred) 293 { 294 ng_h4_info_p sc = (ng_h4_info_p) tp->t_sc; 295 int error = 0; 296 297 if (sc == NULL) 298 return (ENXIO); 299 300 lwkt_gettoken(&tp->t_token); 301 NG_H4_LOCK(sc); 302 303 switch (cmd) { 304 case NGIOCGINFO: 305 #undef NI 306 #define NI(x) ((struct nodeinfo *)(x)) 307 308 bzero(data, sizeof(*NI(data))); 309 310 if (NG_NODE_HAS_NAME(sc->node)) 311 strncpy(NI(data)->name, NG_NODE_NAME(sc->node), 312 sizeof(NI(data)->name) - 1); 313 314 strncpy(NI(data)->type, sc->node->nd_type->name, 315 sizeof(NI(data)->type) - 1); 316 317 NI(data)->id = (u_int32_t) ng_node2ID(sc->node); 318 NI(data)->hooks = NG_NODE_NUMHOOKS(sc->node); 319 break; 320 321 default: 322 error = ENOIOCTL; 323 break; 324 } 325 326 NG_H4_UNLOCK(sc); 327 328 lwkt_reltoken(&tp->t_token); 329 return (error); 330 } /* ng_h4_ioctl */ 331 332 /* 333 * Receive data coming from the device. We get one character at a time, which 334 * is kindof silly. 335 */ 336 337 static int 338 ng_h4_input(int c, struct tty *tp) 339 { 340 ng_h4_info_p sc = (ng_h4_info_p) tp->t_sc; 341 342 lwkt_gettoken(&tp->t_token); 343 if (sc == NULL || tp != sc->tp || 344 sc->node == NULL || NG_NODE_NOT_VALID(sc->node)) { 345 lwkt_reltoken(&tp->t_token); 346 return (0); 347 } 348 349 NG_H4_LOCK(sc); 350 351 /* Check for error conditions */ 352 if ((tp->t_state & TS_CONNECTED) == 0) { 353 NG_H4_INFO("%s: %s - no carrier\n", __func__, 354 NG_NODE_NAME(sc->node)); 355 356 sc->state = NG_H4_W4_PKT_IND; 357 sc->want = 1; 358 sc->got = 0; 359 360 NG_H4_UNLOCK(sc); 361 362 lwkt_reltoken(&tp->t_token); 363 return (0); /* XXX Loss of synchronization here! */ 364 } 365 366 /* Check for framing error or overrun on this char */ 367 if (c & TTY_ERRORMASK) { 368 NG_H4_ERR("%s: %s - line error %#x, c=%#x\n", __func__, 369 NG_NODE_NAME(sc->node), c & TTY_ERRORMASK, 370 c & TTY_CHARMASK); 371 372 NG_H4_STAT_IERROR(sc->stat); 373 374 sc->state = NG_H4_W4_PKT_IND; 375 sc->want = 1; 376 sc->got = 0; 377 378 NG_H4_UNLOCK(sc); 379 380 lwkt_reltoken(&tp->t_token); 381 return (0); /* XXX Loss of synchronization here! */ 382 } 383 384 NG_H4_STAT_BYTES_RECV(sc->stat, 1); 385 386 /* Append char to mbuf */ 387 if (sc->got >= sizeof(sc->ibuf)) { 388 NG_H4_ALERT("%s: %s - input buffer overflow, c=%#x, got=%d\n", 389 __func__, NG_NODE_NAME(sc->node), c & TTY_CHARMASK, 390 sc->got); 391 392 NG_H4_STAT_IERROR(sc->stat); 393 394 sc->state = NG_H4_W4_PKT_IND; 395 sc->want = 1; 396 sc->got = 0; 397 398 NG_H4_UNLOCK(sc); 399 400 lwkt_reltoken(&tp->t_token); 401 return (0); /* XXX Loss of synchronization here! */ 402 } 403 404 sc->ibuf[sc->got ++] = (c & TTY_CHARMASK); 405 406 NG_H4_INFO("%s: %s - got char %#x, want=%d, got=%d\n", __func__, 407 NG_NODE_NAME(sc->node), c, sc->want, sc->got); 408 409 if (sc->got < sc->want) { 410 NG_H4_UNLOCK(sc); 411 412 lwkt_reltoken(&tp->t_token); 413 return (0); /* Wait for more */ 414 } 415 416 switch (sc->state) { 417 /* Got packet indicator */ 418 case NG_H4_W4_PKT_IND: 419 NG_H4_INFO("%s: %s - got packet indicator %#x\n", __func__, 420 NG_NODE_NAME(sc->node), sc->ibuf[0]); 421 422 sc->state = NG_H4_W4_PKT_HDR; 423 424 /* 425 * Since packet indicator included in the packet header 426 * just set sc->want to sizeof(packet header). 427 */ 428 429 switch (sc->ibuf[0]) { 430 case NG_HCI_ACL_DATA_PKT: 431 sc->want = sizeof(ng_hci_acldata_pkt_t); 432 break; 433 434 case NG_HCI_SCO_DATA_PKT: 435 sc->want = sizeof(ng_hci_scodata_pkt_t); 436 break; 437 438 case NG_HCI_EVENT_PKT: 439 sc->want = sizeof(ng_hci_event_pkt_t); 440 break; 441 442 default: 443 NG_H4_WARN("%s: %s - ignoring unknown packet " \ 444 "type=%#x\n", __func__, NG_NODE_NAME(sc->node), 445 sc->ibuf[0]); 446 447 NG_H4_STAT_IERROR(sc->stat); 448 449 sc->state = NG_H4_W4_PKT_IND; 450 sc->want = 1; 451 sc->got = 0; 452 break; 453 } 454 break; 455 456 /* Got packet header */ 457 case NG_H4_W4_PKT_HDR: 458 sc->state = NG_H4_W4_PKT_DATA; 459 460 switch (sc->ibuf[0]) { 461 case NG_HCI_ACL_DATA_PKT: 462 c = le16toh(((ng_hci_acldata_pkt_t *) 463 (sc->ibuf))->length); 464 break; 465 466 case NG_HCI_SCO_DATA_PKT: 467 c = ((ng_hci_scodata_pkt_t *)(sc->ibuf))->length; 468 break; 469 470 case NG_HCI_EVENT_PKT: 471 c = ((ng_hci_event_pkt_t *)(sc->ibuf))->length; 472 break; 473 474 default: 475 KASSERT((0), ("Invalid packet type=%#x", 476 sc->ibuf[0])); 477 break; 478 } 479 480 NG_H4_INFO("%s: %s - got packet header, packet type=%#x, " \ 481 "packet size=%d, payload size=%d\n", __func__, 482 NG_NODE_NAME(sc->node), sc->ibuf[0], sc->got, c); 483 484 if (c > 0) { 485 sc->want += c; 486 487 /* 488 * Try to prevent possible buffer overrun 489 * 490 * XXX I'm *really* confused here. It turns out 491 * that Xircom card sends us packets with length 492 * greater then 512 bytes! This is greater then 493 * our old receive buffer (ibuf) size. In the same 494 * time the card demands from us *not* to send 495 * packets greater then 192 bytes. Weird! How the 496 * hell i should know how big *receive* buffer 497 * should be? For now increase receiving buffer 498 * size to 1K and add the following check. 499 */ 500 501 if (sc->want >= sizeof(sc->ibuf)) { 502 int b; 503 504 NG_H4_ALERT("%s: %s - packet too big for " \ 505 "buffer, type=%#x, got=%d, want=%d, " \ 506 "length=%d\n", __func__, 507 NG_NODE_NAME(sc->node), sc->ibuf[0], 508 sc->got, sc->want, c); 509 510 NG_H4_ALERT("Packet header:\n"); 511 for (b = 0; b < sc->got; b++) 512 NG_H4_ALERT("%#x ", sc->ibuf[b]); 513 NG_H4_ALERT("\n"); 514 515 /* Reset state */ 516 NG_H4_STAT_IERROR(sc->stat); 517 518 sc->state = NG_H4_W4_PKT_IND; 519 sc->want = 1; 520 sc->got = 0; 521 } 522 523 break; 524 } 525 526 /* else FALLTHROUGH and deliver frame */ 527 /* XXX Is this true? Should we deliver empty frame? */ 528 529 /* Got packet data */ 530 case NG_H4_W4_PKT_DATA: 531 NG_H4_INFO("%s: %s - got full packet, packet type=%#x, " \ 532 "packet size=%d\n", __func__, 533 NG_NODE_NAME(sc->node), sc->ibuf[0], sc->got); 534 535 if (sc->hook != NULL && NG_HOOK_IS_VALID(sc->hook)) { 536 struct mbuf *m = NULL; 537 538 MGETHDR(m, M_NOWAIT, MT_DATA); 539 if (m != NULL) { 540 m->m_pkthdr.len = 0; 541 542 /* XXX m_copyback() is stupid */ 543 m->m_len = min(MHLEN, sc->got); 544 545 m_copyback(m, 0, sc->got, sc->ibuf); 546 NG_SEND_DATA_ONLY(c, sc->hook, m); 547 } else { 548 NG_H4_ERR("%s: %s - could not get mbuf\n", 549 __func__, NG_NODE_NAME(sc->node)); 550 551 NG_H4_STAT_IERROR(sc->stat); 552 } 553 } 554 555 sc->state = NG_H4_W4_PKT_IND; 556 sc->want = 1; 557 sc->got = 0; 558 559 NG_H4_STAT_PCKTS_RECV(sc->stat); 560 break; 561 562 default: 563 KASSERT((0), ("Invalid H4 node state=%d", sc->state)); 564 break; 565 } 566 567 NG_H4_UNLOCK(sc); 568 569 lwkt_reltoken(&tp->t_token); 570 return (0); 571 } /* ng_h4_input */ 572 573 /* 574 * This is called when the device driver is ready for more output. Called from 575 * tty system. 576 */ 577 578 static int 579 ng_h4_start(struct tty *tp) 580 { 581 ng_h4_info_p sc = (ng_h4_info_p) tp->t_sc; 582 struct mbuf *m = NULL; 583 int size; 584 585 lwkt_gettoken(&tp->t_token); 586 if (sc == NULL || tp != sc->tp || 587 sc->node == NULL || NG_NODE_NOT_VALID(sc->node)) { 588 lwkt_reltoken(&tp->t_token); 589 return (0); 590 } 591 592 #if 0 593 while (tp->t_outq.c_cc < NG_H4_HIWATER) { /* XXX 2.2 specific ? */ 594 #else 595 while (1) { 596 #endif 597 /* Remove first mbuf from queue */ 598 IF_DEQUEUE(&sc->outq, m); 599 if (m == NULL) 600 break; 601 602 /* Send as much of it as possible */ 603 while (m != NULL) { 604 size = m->m_len - clist_btoq(mtod(m, u_char *), 605 m->m_len, &tp->t_outq); 606 607 NG_H4_LOCK(sc); 608 NG_H4_STAT_BYTES_SENT(sc->stat, size); 609 NG_H4_UNLOCK(sc); 610 611 m->m_data += size; 612 m->m_len -= size; 613 if (m->m_len > 0) 614 break; /* device can't take no more */ 615 616 m = m_free(m); 617 } 618 619 /* Put remainder of mbuf chain (if any) back on queue */ 620 if (m != NULL) { 621 IF_PREPEND(&sc->outq, m); 622 break; 623 } 624 625 /* Full packet has been sent */ 626 NG_H4_LOCK(sc); 627 NG_H4_STAT_PCKTS_SENT(sc->stat); 628 NG_H4_UNLOCK(sc); 629 } 630 631 /* 632 * Call output process whether or not there is any output. We are 633 * being called in lieu of ttstart and must do what it would. 634 */ 635 636 if (tp->t_oproc != NULL) 637 (*tp->t_oproc) (tp); 638 639 /* 640 * This timeout is needed for operation on a pseudo-tty, because the 641 * pty code doesn't call pppstart after it has drained the t_outq. 642 */ 643 644 NG_H4_LOCK(sc); 645 646 if (!IF_QEMPTY(&sc->outq) && !callout_pending(&sc->timo)) 647 ng_callout(&sc->timo, sc->node, NULL, 1, 648 ng_h4_process_timeout, NULL, 0); 649 650 NG_H4_UNLOCK(sc); 651 652 lwkt_reltoken(&tp->t_token); 653 return (0); 654 } /* ng_h4_start */ 655 656 /***************************************************************************** 657 ***************************************************************************** 658 ** Netgraph node methods 659 ***************************************************************************** 660 *****************************************************************************/ 661 662 /* 663 * Initialize a new node of this type. We only allow nodes to be created as 664 * a result of setting the line discipline on a tty, so always return an error 665 * if not. 666 */ 667 668 static int 669 ng_h4_constructor(node_p node) 670 { 671 return (EOPNOTSUPP); 672 } /* ng_h4_constructor */ 673 674 /* 675 * Add a new hook. There can only be one. 676 */ 677 678 static int 679 ng_h4_newhook(node_p node, hook_p hook, const char *name) 680 { 681 ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(node); 682 683 if (strcmp(name, NG_H4_HOOK) != 0) 684 return (EINVAL); 685 686 NG_H4_LOCK(sc); 687 688 if (sc->hook != NULL) { 689 NG_H4_UNLOCK(sc); 690 return (EISCONN); 691 } 692 sc->hook = hook; 693 694 NG_H4_UNLOCK(sc); 695 696 return (0); 697 } /* ng_h4_newhook */ 698 699 /* 700 * Connect hook. Just say yes. 701 */ 702 703 static int 704 ng_h4_connect(hook_p hook) 705 { 706 ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 707 708 if (hook != sc->hook) 709 panic("%s: hook != sc->hook", __func__); 710 711 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); 712 NG_HOOK_FORCE_QUEUE(hook); 713 714 return (0); 715 } /* ng_h4_connect */ 716 717 /* 718 * Disconnect the hook 719 */ 720 721 static int 722 ng_h4_disconnect(hook_p hook) 723 { 724 ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 725 726 /* 727 * We need to check for sc != NULL because we can be called from 728 * ng_h4_close() via ng_rmnode_self() 729 */ 730 731 if (sc != NULL) { 732 if (hook != sc->hook) 733 panic("%s: hook != sc->hook", __func__); 734 735 NG_H4_LOCK(sc); 736 737 /* XXX do we have to untimeout and drain out queue? */ 738 if (callout_pending(&sc->timo)) 739 ng_uncallout(&sc->timo, sc->node); 740 741 IF_DRAIN(&sc->outq); 742 743 sc->state = NG_H4_W4_PKT_IND; 744 sc->want = 1; 745 sc->got = 0; 746 747 sc->hook = NULL; 748 749 NG_H4_UNLOCK(sc); 750 } 751 752 return (0); 753 } /* ng_h4_disconnect */ 754 755 /* 756 * Remove this node. The does the netgraph portion of the shutdown. 757 * This should only be called indirectly from ng_h4_close(). 758 */ 759 760 static int 761 ng_h4_shutdown(node_p node) 762 { 763 ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(node); 764 765 NG_H4_LOCK(sc); 766 767 if (!sc->dying) { 768 NG_H4_UNLOCK(sc); 769 770 NG_NODE_REVIVE(node); /* we will persist */ 771 772 return (EOPNOTSUPP); 773 } 774 775 NG_H4_UNLOCK(sc); 776 777 NG_NODE_SET_PRIVATE(node, NULL); 778 779 IF_DRAIN(&sc->outq); 780 781 NG_NODE_UNREF(node); 782 bzero(sc, sizeof(*sc)); 783 kfree(sc, M_NETGRAPH_H4); 784 785 return (0); 786 } /* ng_h4_shutdown */ 787 788 /* 789 * Receive incoming data from Netgraph system. Put it on our 790 * output queue and start output if necessary. 791 */ 792 793 static int 794 ng_h4_rcvdata(hook_p hook, item_p item) 795 { 796 ng_h4_info_p sc = (ng_h4_info_p)NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 797 struct mbuf *m = NULL; 798 int qlen; 799 800 if (sc == NULL) 801 return (EHOSTDOWN); 802 803 if (hook != sc->hook) 804 panic("%s: hook != sc->hook", __func__); 805 806 NGI_GET_M(item, m); 807 NG_FREE_ITEM(item); 808 809 NG_H4_LOCK(sc); 810 811 if (IF_QFULL(&sc->outq)) { 812 NG_H4_ERR("%s: %s - dropping mbuf, len=%d\n", __func__, 813 NG_NODE_NAME(sc->node), m->m_pkthdr.len); 814 815 NG_H4_STAT_OERROR(sc->stat); 816 IF_DROP(&sc->outq); 817 818 NG_H4_UNLOCK(sc); 819 820 NG_FREE_M(m); 821 822 return (ENOBUFS); 823 } 824 825 NG_H4_INFO("%s: %s - queue mbuf, len=%d\n", __func__, 826 NG_NODE_NAME(sc->node), m->m_pkthdr.len); 827 828 IF_ENQUEUE(&sc->outq, m); 829 qlen = IF_QLEN(&sc->outq); 830 831 NG_H4_UNLOCK(sc); 832 833 /* 834 * If qlen > 1, then we should already have a scheduled callout 835 */ 836 837 if (qlen == 1) 838 ng_h4_start(sc->tp); 839 840 return (0); 841 } /* ng_h4_rcvdata */ 842 843 /* 844 * Receive control message 845 */ 846 847 static int 848 ng_h4_rcvmsg(node_p node, item_p item, hook_p lasthook) 849 { 850 ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(node); 851 struct ng_mesg *msg = NULL, *resp = NULL; 852 int error = 0; 853 854 if (sc == NULL) 855 return (EHOSTDOWN); 856 857 NGI_GET_MSG(item, msg); 858 NG_H4_LOCK(sc); 859 860 switch (msg->header.typecookie) { 861 case NGM_GENERIC_COOKIE: 862 switch (msg->header.cmd) { 863 case NGM_TEXT_STATUS: 864 NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_WAITOK | M_NULLOK); 865 if (resp == NULL) 866 error = ENOMEM; 867 else 868 ksnprintf(resp->data, NG_TEXTRESPONSE, 869 "Hook: %s\n" \ 870 "Debug: %d\n" \ 871 "State: %d\n" \ 872 "Queue: [have:%d,max:%d]\n" \ 873 "Input: [got:%d,want:%d]", 874 (sc->hook != NULL)? NG_H4_HOOK : "", 875 sc->debug, 876 sc->state, 877 IF_QLEN(&sc->outq), 878 sc->outq.ifq_maxlen, 879 sc->got, 880 sc->want); 881 break; 882 883 default: 884 error = EINVAL; 885 break; 886 } 887 break; 888 889 case NGM_H4_COOKIE: 890 switch (msg->header.cmd) { 891 case NGM_H4_NODE_RESET: 892 IF_DRAIN(&sc->outq); 893 sc->state = NG_H4_W4_PKT_IND; 894 sc->want = 1; 895 sc->got = 0; 896 break; 897 898 case NGM_H4_NODE_GET_STATE: 899 NG_MKRESPONSE(resp, msg, sizeof(ng_h4_node_state_ep), 900 M_WAITOK | M_NULLOK); 901 if (resp == NULL) 902 error = ENOMEM; 903 else 904 *((ng_h4_node_state_ep *)(resp->data)) = 905 sc->state; 906 break; 907 908 case NGM_H4_NODE_GET_DEBUG: 909 NG_MKRESPONSE(resp, msg, sizeof(ng_h4_node_debug_ep), 910 M_WAITOK | M_NULLOK); 911 if (resp == NULL) 912 error = ENOMEM; 913 else 914 *((ng_h4_node_debug_ep *)(resp->data)) = 915 sc->debug; 916 break; 917 918 case NGM_H4_NODE_SET_DEBUG: 919 if (msg->header.arglen != sizeof(ng_h4_node_debug_ep)) 920 error = EMSGSIZE; 921 else 922 sc->debug = 923 *((ng_h4_node_debug_ep *)(msg->data)); 924 break; 925 926 case NGM_H4_NODE_GET_QLEN: 927 NG_MKRESPONSE(resp, msg, sizeof(ng_h4_node_qlen_ep), 928 M_WAITOK | M_NULLOK); 929 if (resp == NULL) 930 error = ENOMEM; 931 else 932 *((ng_h4_node_qlen_ep *)(resp->data)) = 933 sc->outq.ifq_maxlen; 934 break; 935 936 case NGM_H4_NODE_SET_QLEN: 937 if (msg->header.arglen != sizeof(ng_h4_node_qlen_ep)) 938 error = EMSGSIZE; 939 else if (*((ng_h4_node_qlen_ep *)(msg->data)) <= 0) 940 error = EINVAL; 941 else 942 sc->outq.ifq_maxlen = 943 *((ng_h4_node_qlen_ep *)(msg->data)); 944 break; 945 946 case NGM_H4_NODE_GET_STAT: 947 NG_MKRESPONSE(resp, msg, sizeof(ng_h4_node_stat_ep), 948 M_WAITOK | M_NULLOK); 949 if (resp == NULL) 950 error = ENOMEM; 951 else 952 bcopy(&sc->stat, resp->data, 953 sizeof(ng_h4_node_stat_ep)); 954 break; 955 956 case NGM_H4_NODE_RESET_STAT: 957 NG_H4_STAT_RESET(sc->stat); 958 break; 959 960 default: 961 error = EINVAL; 962 break; 963 } 964 break; 965 966 default: 967 error = EINVAL; 968 break; 969 } 970 971 NG_H4_UNLOCK(sc); 972 973 NG_RESPOND_MSG(error, node, item, resp); 974 NG_FREE_MSG(msg); 975 976 return (error); 977 } /* ng_h4_rcvmsg */ 978 979 /* 980 * Timeout processing function. 981 * We still have data to output to the device, so try sending more. 982 */ 983 984 static void 985 ng_h4_process_timeout(node_p node, hook_p hook, void *arg1, int arg2) 986 { 987 ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(node); 988 989 ng_h4_start(sc->tp); 990 } /* ng_h4_process_timeout */ 991 992 /* 993 * Handle loading and unloading for this node type 994 */ 995 996 static int 997 ng_h4_mod_event(module_t mod, int event, void *data) 998 { 999 static int ng_h4_ldisc; 1000 int error = 0; 1001 1002 switch (event) { 1003 case MOD_LOAD: 1004 /* Register line discipline */ 1005 crit_enter(); 1006 ng_h4_ldisc = ldisc_register(BTUARTDISC, &ng_h4_disc); 1007 crit_exit(); 1008 1009 if (ng_h4_ldisc < 0) { 1010 kprintf("%s: can't register H4 line discipline\n", 1011 __func__); 1012 error = EIO; 1013 } 1014 break; 1015 1016 case MOD_UNLOAD: 1017 /* Unregister line discipline */ 1018 crit_enter(); 1019 ldisc_deregister(ng_h4_ldisc); 1020 crit_exit(); 1021 break; 1022 1023 default: 1024 error = EOPNOTSUPP; 1025 break; 1026 } 1027 1028 return (error); 1029 } /* ng_h4_mod_event */ 1030 1031