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