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