ng_tty.c revision 70784
1193640Sariff 2193640Sariff/* 3193640Sariff * ng_tty.c 4193640Sariff * 5193640Sariff * Copyright (c) 1996-1999 Whistle Communications, Inc. 6193640Sariff * All rights reserved. 7193640Sariff * 8193640Sariff * Subject to the following obligations and disclaimer of warranty, use and 9193640Sariff * redistribution of this software, in source or object code forms, with or 10193640Sariff * without modifications are expressly permitted by Whistle Communications; 11193640Sariff * provided, however, that: 12193640Sariff * 1. Any and all reproductions of the source or object code must include the 13193640Sariff * copyright notice above and the following disclaimer of warranties; and 14193640Sariff * 2. No rights are granted, in any manner or form, to use Whistle 15193640Sariff * Communications, Inc. trademarks, including the mark "WHISTLE 16193640Sariff * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 17193640Sariff * such appears in the above copyright notice or in the software. 18193640Sariff * 19193640Sariff * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 20193640Sariff * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 21193640Sariff * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 22193640Sariff * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 23193640Sariff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 24193640Sariff * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 25193640Sariff * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 26193640Sariff * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 27193640Sariff * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 28193640Sariff * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 29193640Sariff * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 30193640Sariff * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 31193640Sariff * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 32193640Sariff * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33193640Sariff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34193640Sariff * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 35193640Sariff * OF SUCH DAMAGE. 36193640Sariff * 37193640Sariff * Author: Archie Cobbs <archie@freebsd.org> 38193640Sariff * 39193640Sariff * $FreeBSD: head/sys/netgraph/ng_tty.c 70784 2001-01-08 05:34:06Z julian $ 40193640Sariff * $Whistle: ng_tty.c,v 1.21 1999/11/01 09:24:52 julian Exp $ 41193640Sariff */ 42193640Sariff 43193640Sariff/* 44193640Sariff * This file implements a terminal line discipline that is also a 45193640Sariff * netgraph node. Installing this line discipline on a terminal device 46193640Sariff * instantiates a new netgraph node of this type, which allows access 47193640Sariff * to the device via the "hook" hook of the node. 48193640Sariff * 49193640Sariff * Once the line discipline is installed, you can find out the name 50193640Sariff * of the corresponding netgraph node via a NGIOCGINFO ioctl(). 51193640Sariff * 52193640Sariff * Incoming characters are delievered to the hook one at a time, each 53193640Sariff * in its own mbuf. You may optionally define a ``hotchar,'' which causes 54193640Sariff * incoming characters to be buffered up until either the hotchar is 55193640Sariff * seen or the mbuf is full (MHLEN bytes). Then all buffered characters 56193640Sariff * are immediately delivered. 57193640Sariff * 58193640Sariff * NOTE: This node operates at spltty(). 59193640Sariff */ 60193640Sariff 61193640Sariff#include <sys/param.h> 62193640Sariff#include <sys/systm.h> 63193640Sariff#include <sys/kernel.h> 64193640Sariff#include <sys/conf.h> 65193640Sariff#include <sys/mbuf.h> 66193640Sariff#include <sys/malloc.h> 67193640Sariff#include <sys/fcntl.h> 68193640Sariff#include <sys/tty.h> 69193640Sariff#include <sys/ttycom.h> 70193640Sariff#include <sys/syslog.h> 71193640Sariff#include <sys/errno.h> 72193640Sariff#include <sys/ioccom.h> 73193640Sariff 74193640Sariff#include <netgraph/ng_message.h> 75193640Sariff#include <netgraph/netgraph.h> 76193640Sariff#include <netgraph/ng_tty.h> 77193640Sariff 78193640Sariff#ifdef __i386__ /* fiddle with the spl locking */ 79193640Sariff#include <sys/bus.h> 80193640Sariff#include <machine/ipl.h> 81193640Sariff#endif 82193640Sariff 83193640Sariff/* Misc defs */ 84193640Sariff#define MAX_MBUFQ 3 /* Max number of queued mbufs */ 85193640Sariff#define NGT_HIWATER 400 /* High water mark on output */ 86193640Sariff 87193640Sariff/* Per-node private info */ 88193640Sariffstruct ngt_sc { 89193640Sariff struct tty *tp; /* Terminal device */ 90193640Sariff node_p node; /* Netgraph node */ 91193640Sariff hook_p hook; /* Netgraph hook */ 92193640Sariff struct mbuf *m; /* Incoming data buffer */ 93193640Sariff struct mbuf *qhead, **qtail; /* Queue of outgoing mbuf's */ 94193640Sariff short qlen; /* Length of queue */ 95193640Sariff short hotchar; /* Hotchar, or -1 if none */ 96193640Sariff u_int flags; /* Flags */ 97193640Sariff struct callout_handle chand; /* See man timeout(9) */ 98193640Sariff}; 99193640Sarifftypedef struct ngt_sc *sc_p; 100193640Sariff 101193640Sariff/* Flags */ 102193640Sariff#define FLG_TIMEOUT 0x0001 /* A timeout is pending */ 103193640Sariff#define FLG_DEBUG 0x0002 104193640Sariff 105193640Sariff/* Debugging */ 106193640Sariff#ifdef INVARIANTS 107193640Sariff#define QUEUECHECK(sc) \ 108193640Sariff do { \ 109193640Sariff struct mbuf **mp; \ 110193640Sariff int k; \ 111193640Sariff \ 112193640Sariff for (k = 0, mp = &sc->qhead; \ 113193640Sariff k <= MAX_MBUFQ && *mp; \ 114193640Sariff k++, mp = &(*mp)->m_nextpkt); \ 115193640Sariff if (k != sc->qlen || k > MAX_MBUFQ || *mp || mp != sc->qtail) \ 116193640Sariff panic(__FUNCTION__ ": queue"); \ 117193640Sariff } while (0) 118193640Sariff#else 119193640Sariff#define QUEUECHECK(sc) do {} while (0) 120193640Sariff#endif 121193640Sariff 122193640Sariff/* Line discipline methods */ 123193640Sariffstatic int ngt_open(dev_t dev, struct tty *tp); 124193640Sariffstatic int ngt_close(struct tty *tp, int flag); 125193640Sariffstatic int ngt_read(struct tty *tp, struct uio *uio, int flag); 126193640Sariffstatic int ngt_write(struct tty *tp, struct uio *uio, int flag); 127193640Sariffstatic int ngt_tioctl(struct tty *tp, 128193640Sariff u_long cmd, caddr_t data, int flag, struct proc *); 129193640Sariffstatic int ngt_input(int c, struct tty *tp); 130193640Sariffstatic int ngt_start(struct tty *tp); 131193640Sariff 132193640Sariff/* Netgraph methods */ 133193640Sariffstatic ng_constructor_t ngt_constructor; 134193640Sariffstatic ng_rcvmsg_t ngt_rcvmsg; 135193640Sariffstatic ng_shutdown_t ngt_shutdown; 136193640Sariffstatic ng_newhook_t ngt_newhook; 137193640Sariffstatic ng_connect_t ngt_connect; 138193640Sariffstatic ng_rcvdata_t ngt_rcvdata; 139193640Sariffstatic ng_disconnect_t ngt_disconnect; 140193640Sariffstatic int ngt_mod_event(module_t mod, int event, void *data); 141193640Sariff 142193640Sariff/* Other stuff */ 143193640Sariffstatic void ngt_timeout(void *arg); 144193640Sariff 145193640Sariff#define ERROUT(x) do { error = (x); goto done; } while (0) 146193640Sariff 147193640Sariff/* Line discipline descriptor */ 148193640Sariffstatic struct linesw ngt_disc = { 149193640Sariff ngt_open, 150193640Sariff ngt_close, 151193640Sariff ngt_read, 152193640Sariff ngt_write, 153193640Sariff ngt_tioctl, 154193640Sariff ngt_input, 155193640Sariff ngt_start, 156193640Sariff ttymodem, 157193640Sariff NG_TTY_DFL_HOTCHAR /* XXX can't change this in serial driver */ 158193640Sariff}; 159193640Sariff 160193640Sariff/* Netgraph node type descriptor */ 161193640Sariffstatic struct ng_type typestruct = { 162193640Sariff NG_ABI_VERSION, 163193640Sariff NG_TTY_NODE_TYPE, 164193640Sariff ngt_mod_event, 165193640Sariff ngt_constructor, 166193640Sariff ngt_rcvmsg, 167193640Sariff ngt_shutdown, 168193640Sariff ngt_newhook, 169193640Sariff NULL, 170193640Sariff ngt_connect, 171193640Sariff ngt_rcvdata, 172193640Sariff ngt_disconnect, 173193640Sariff NULL 174193640Sariff}; 175193640SariffNETGRAPH_INIT(tty, &typestruct); 176193640Sariff 177193640Sariffstatic int ngt_unit; 178193640Sariffstatic int ngt_nodeop_ok; /* OK to create/remove node */ 179193640Sariffstatic int ngt_ldisc; 180193640Sariff 181193640Sariff/****************************************************************** 182193640Sariff LINE DISCIPLINE METHODS 183193640Sariff******************************************************************/ 184193640Sariff 185193640Sariff/* 186193640Sariff * Set our line discipline on the tty. 187193640Sariff * Called from device open routine or ttioctl() at >= splsofttty() 188193640Sariff */ 189193640Sariffstatic int 190193640Sariffngt_open(dev_t dev, struct tty *tp) 191193640Sariff{ 192193640Sariff struct proc *const p = curproc; /* XXX */ 193193640Sariff char name[sizeof(NG_TTY_NODE_TYPE) + 8]; 194193640Sariff sc_p sc; 195193640Sariff int s, error; 196193640Sariff 197193640Sariff /* Super-user only */ 198193640Sariff if ((error = suser(p))) 199193640Sariff return (error); 200193640Sariff s = splnet(); 201193640Sariff (void) spltty(); /* XXX is this necessary? */ 202193640Sariff 203193640Sariff /* Already installed? */ 204193640Sariff if (tp->t_line == NETGRAPHDISC) { 205193640Sariff sc = (sc_p) tp->t_sc; 206193640Sariff if (sc != NULL && sc->tp == tp) 207193640Sariff goto done; 208193640Sariff } 209193640Sariff 210193640Sariff /* Initialize private struct */ 211193640Sariff MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_WAITOK | M_ZERO); 212193640Sariff if (sc == NULL) { 213193640Sariff error = ENOMEM; 214193640Sariff goto done; 215193640Sariff } 216193640Sariff sc->tp = tp; 217193640Sariff sc->hotchar = NG_TTY_DFL_HOTCHAR; 218193640Sariff sc->qtail = &sc->qhead; 219193640Sariff QUEUECHECK(sc); 220193640Sariff callout_handle_init(&sc->chand); 221193640Sariff 222193640Sariff /* Setup netgraph node */ 223193640Sariff ngt_nodeop_ok = 1; 224193640Sariff error = ng_make_node_common(&typestruct, &sc->node); 225193640Sariff ngt_nodeop_ok = 0; 226193640Sariff if (error) { 227193640Sariff FREE(sc, M_NETGRAPH); 228193640Sariff goto done; 229193640Sariff } 230193640Sariff snprintf(name, sizeof(name), "%s%d", typestruct.name, ngt_unit++); 231193640Sariff 232193640Sariff /* Assign node its name */ 233193640Sariff if ((error = ng_name_node(sc->node, name))) { 234193640Sariff log(LOG_ERR, "%s: node name exists?\n", name); 235193640Sariff ngt_nodeop_ok = 1; 236193640Sariff NG_NODE_UNREF(sc->node); 237193640Sariff ngt_nodeop_ok = 0; 238193640Sariff goto done; 239193640Sariff } 240193640Sariff 241193640Sariff /* Set back pointers */ 242193640Sariff NG_NODE_SET_PRIVATE(sc->node, sc); 243193640Sariff tp->t_sc = (caddr_t) sc; 244193640Sariff 245193640Sariff /* 246193640Sariff * Pre-allocate cblocks to the an appropriate amount. 247193640Sariff * I'm not sure what is appropriate. 248193640Sariff */ 249193640Sariff ttyflush(tp, FREAD | FWRITE); 250193640Sariff clist_alloc_cblocks(&tp->t_canq, 0, 0); 251193640Sariff clist_alloc_cblocks(&tp->t_rawq, 0, 0); 252193640Sariff clist_alloc_cblocks(&tp->t_outq, 253193640Sariff MLEN + NGT_HIWATER, MLEN + NGT_HIWATER); 254193640Sariff 255193640Sariffdone: 256193640Sariff /* Done */ 257193640Sariff splx(s); 258193640Sariff return (error); 259193640Sariff} 260193640Sariff 261193640Sariff/* 262193640Sariff * Line specific close routine, called from device close routine 263193640Sariff * and from ttioctl at >= splsofttty(). This causes the node to 264193640Sariff * be destroyed as well. 265193640Sariff */ 266193640Sariffstatic int 267193640Sariffngt_close(struct tty *tp, int flag) 268193640Sariff{ 269193640Sariff const sc_p sc = (sc_p) tp->t_sc; 270193640Sariff int s; 271193640Sariff 272193640Sariff s = spltty(); 273193640Sariff ttyflush(tp, FREAD | FWRITE); 274193640Sariff clist_free_cblocks(&tp->t_outq); 275193640Sariff tp->t_line = 0; 276193640Sariff if (sc != NULL) { 277193640Sariff if (sc->flags & FLG_TIMEOUT) { 278193640Sariff untimeout(ngt_timeout, sc, sc->chand); 279193640Sariff sc->flags &= ~FLG_TIMEOUT; 280193640Sariff } 281193640Sariff ngt_nodeop_ok = 1; 282193640Sariff ng_rmnode_self(sc->node); 283193640Sariff ngt_nodeop_ok = 0; 284193640Sariff tp->t_sc = NULL; 285193640Sariff } 286193640Sariff splx(s); 287193640Sariff return (0); 288193640Sariff} 289193640Sariff 290193640Sariff/* 291193640Sariff * Once the device has been turned into a node, we don't allow reading. 292193640Sariff */ 293193640Sariffstatic int 294193640Sariffngt_read(struct tty *tp, struct uio *uio, int flag) 295193640Sariff{ 296193640Sariff return (EIO); 297193640Sariff} 298193640Sariff 299193640Sariff/* 300193640Sariff * Once the device has been turned into a node, we don't allow writing. 301193640Sariff */ 302193640Sariffstatic int 303193640Sariffngt_write(struct tty *tp, struct uio *uio, int flag) 304193640Sariff{ 305193640Sariff return (EIO); 306193640Sariff} 307193640Sariff 308193640Sariff/* 309193640Sariff * We implement the NGIOCGINFO ioctl() defined in ng_message.h. 310193640Sariff */ 311193640Sariffstatic int 312193640Sariffngt_tioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct proc *p) 313193640Sariff{ 314193640Sariff const sc_p sc = (sc_p) tp->t_sc; 315193640Sariff int s, error = 0; 316193640Sariff 317193640Sariff s = spltty(); 318193640Sariff switch (cmd) { 319193640Sariff case NGIOCGINFO: 320193640Sariff { 321193640Sariff struct nodeinfo *const ni = (struct nodeinfo *) data; 322193640Sariff const node_p node = sc->node; 323193640Sariff 324193640Sariff bzero(ni, sizeof(*ni)); 325193640Sariff if (NG_NODE_HAS_NAME(node)) 326193640Sariff strncpy(ni->name, NG_NODE_NAME(node), sizeof(ni->name) - 1); 327193640Sariff strncpy(ni->type, node->nd_type->name, sizeof(ni->type) - 1); 328193640Sariff ni->id = (u_int32_t) ng_node2ID(node); 329193640Sariff ni->hooks = NG_NODE_NUMHOOKS(node); 330193640Sariff break; 331193640Sariff } 332193640Sariff default: 333193640Sariff ERROUT(ENOIOCTL); 334193640Sariff } 335193640Sariffdone: 336193640Sariff splx(s); 337193640Sariff return (error); 338193640Sariff} 339193640Sariff 340193640Sariff/* 341193640Sariff * Receive data coming from the device. We get one character at 342193640Sariff * a time, which is kindof silly. 343193640Sariff * Only guaranteed to be at splsofttty() or spltty(). 344193640Sariff */ 345193640Sariffstatic int 346193640Sariffngt_input(int c, struct tty *tp) 347193640Sariff{ 348193640Sariff const sc_p sc = (sc_p) tp->t_sc; 349193640Sariff const node_p node = sc->node; 350193640Sariff struct mbuf *m; 351193640Sariff int s, error = 0; 352193640Sariff 353193640Sariff if (!sc || tp != sc->tp) 354193640Sariff return (0); 355193640Sariff s = spltty(); 356193640Sariff if (!sc->hook) 357193640Sariff ERROUT(0); 358193640Sariff 359193640Sariff /* Check for error conditions */ 360193640Sariff if ((tp->t_state & TS_CONNECTED) == 0) { 361193640Sariff if (sc->flags & FLG_DEBUG) 362193640Sariff log(LOG_DEBUG, "%s: no carrier\n", NG_NODE_NAME(node)); 363193640Sariff ERROUT(0); 364193640Sariff } 365193640Sariff if (c & TTY_ERRORMASK) { 366193640Sariff /* framing error or overrun on this char */ 367193640Sariff if (sc->flags & FLG_DEBUG) 368193640Sariff log(LOG_DEBUG, "%s: line error %x\n", 369193640Sariff NG_NODE_NAME(node), c & TTY_ERRORMASK); 370193640Sariff ERROUT(0); 371193640Sariff } 372193640Sariff c &= TTY_CHARMASK; 373193640Sariff 374193640Sariff /* Get a new header mbuf if we need one */ 375193640Sariff if (!(m = sc->m)) { 376193640Sariff MGETHDR(m, M_DONTWAIT, MT_DATA); 377193640Sariff if (!m) { 378193640Sariff if (sc->flags & FLG_DEBUG) 379193640Sariff log(LOG_ERR, 380193640Sariff "%s: can't get mbuf\n", NG_NODE_NAME(node)); 381193640Sariff ERROUT(ENOBUFS); 382193640Sariff } 383193640Sariff m->m_len = m->m_pkthdr.len = 0; 384193640Sariff m->m_pkthdr.rcvif = NULL; 385193640Sariff sc->m = m; 386193640Sariff } 387193640Sariff 388193640Sariff /* Add char to mbuf */ 389193640Sariff *mtod(m, u_char *) = c; 390193640Sariff m->m_data++; 391193640Sariff m->m_len++; 392193640Sariff m->m_pkthdr.len++; 393193640Sariff 394193640Sariff /* Ship off mbuf if it's time */ 395193640Sariff if (sc->hotchar == -1 || c == sc->hotchar || m->m_len >= MHLEN) { 396193640Sariff m->m_data = m->m_pktdat; 397193640Sariff NG_SEND_DATA_ONLY(error, sc->hook, m); 398193640Sariff sc->m = NULL; 399193640Sariff } 400193640Sariffdone: 401193640Sariff splx(s); 402193640Sariff return (error); 403193640Sariff} 404193640Sariff 405193640Sariff/* 406193640Sariff * This is called when the device driver is ready for more output. 407193640Sariff * Called from tty system at splsofttty() or spltty(). 408193640Sariff * Also call from ngt_rcv_data() when a new mbuf is available for output. 409193640Sariff */ 410193640Sariffstatic int 411193640Sariffngt_start(struct tty *tp) 412193640Sariff{ 413193640Sariff const sc_p sc = (sc_p) tp->t_sc; 414193640Sariff int s; 415193640Sariff 416193640Sariff s = spltty(); 417193640Sariff while (tp->t_outq.c_cc < NGT_HIWATER) { /* XXX 2.2 specific ? */ 418193640Sariff struct mbuf *m = sc->qhead; 419193640Sariff 420193640Sariff /* Remove first mbuf from queue */ 421193640Sariff if (!m) 422193640Sariff break; 423193640Sariff if ((sc->qhead = m->m_nextpkt) == NULL) 424193640Sariff sc->qtail = &sc->qhead; 425193640Sariff sc->qlen--; 426193640Sariff QUEUECHECK(sc); 427193640Sariff 428193640Sariff /* Send as much of it as possible */ 429193640Sariff while (m) { 430193640Sariff struct mbuf *m2; 431193640Sariff int sent; 432193640Sariff 433193640Sariff sent = m->m_len 434193640Sariff - b_to_q(mtod(m, u_char *), m->m_len, &tp->t_outq); 435193640Sariff m->m_data += sent; 436193640Sariff m->m_len -= sent; 437193640Sariff if (m->m_len > 0) 438193640Sariff break; /* device can't take no more */ 439 MFREE(m, m2); 440 m = m2; 441 } 442 443 /* Put remainder of mbuf chain (if any) back on queue */ 444 if (m) { 445 m->m_nextpkt = sc->qhead; 446 sc->qhead = m; 447 if (sc->qtail == &sc->qhead) 448 sc->qtail = &m->m_nextpkt; 449 sc->qlen++; 450 QUEUECHECK(sc); 451 break; 452 } 453 } 454 455 /* Call output process whether or not there is any output. We are 456 * being called in lieu of ttstart and must do what it would. */ 457 if (tp->t_oproc != NULL) 458 (*tp->t_oproc) (tp); 459 460 /* This timeout is needed for operation on a pseudo-tty, because the 461 * pty code doesn't call pppstart after it has drained the t_outq. */ 462 if (sc->qhead && (sc->flags & FLG_TIMEOUT) == 0) { 463 sc->chand = timeout(ngt_timeout, sc, 1); 464 sc->flags |= FLG_TIMEOUT; 465 } 466 splx(s); 467 return (0); 468} 469 470/* 471 * We still have data to output to the device, so try sending more. 472 */ 473static void 474ngt_timeout(void *arg) 475{ 476 const sc_p sc = (sc_p) arg; 477 int s; 478 479 s = spltty(); 480 sc->flags &= ~FLG_TIMEOUT; 481 ngt_start(sc->tp); 482 splx(s); 483} 484 485/****************************************************************** 486 NETGRAPH NODE METHODS 487******************************************************************/ 488 489/* 490 * Initialize a new node of this type. 491 * 492 * We only allow nodes to be created as a result of setting 493 * the line discipline on a tty, so always return an error if not. 494 */ 495static int 496ngt_constructor(node_p node) 497{ 498 return (EOPNOTSUPP); 499} 500 501/* 502 * Add a new hook. There can only be one. 503 */ 504static int 505ngt_newhook(node_p node, hook_p hook, const char *name) 506{ 507 const sc_p sc = NG_NODE_PRIVATE(node); 508 int s, error = 0; 509 510 if (strcmp(name, NG_TTY_HOOK)) 511 return (EINVAL); 512 s = spltty(); 513 if (sc->hook) 514 ERROUT(EISCONN); 515 sc->hook = hook; 516done: 517 splx(s); 518 return (error); 519} 520 521/* 522 * Set the hooks into queueing mode (for outgoing packets) 523 * Force single client at a time. 524 */ 525static int 526ngt_connect(hook_p hook) 527{ 528 /*NG_HOOK_FORCE_WRITER(hook); 529 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));*/ 530 return (0); 531} 532 533/* 534 * Disconnect the hook 535 */ 536static int 537ngt_disconnect(hook_p hook) 538{ 539 const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 540 int s; 541 542 s = spltty(); 543 if (hook != sc->hook) 544 panic(__FUNCTION__); 545 sc->hook = NULL; 546 m_freem(sc->m); 547 sc->m = NULL; 548 splx(s); 549 return (0); 550} 551 552/* 553 * Remove this node. The does the netgraph portion of the shutdown. 554 * This should only be called indirectly from ngt_close(). 555 */ 556static int 557ngt_shutdown(node_p node) 558{ 559 const sc_p sc = NG_NODE_PRIVATE(node); 560 561 if (!ngt_nodeop_ok) 562 return (EOPNOTSUPP); 563 NG_NODE_SET_PRIVATE(node, NULL); 564 NG_NODE_UNREF(sc->node); 565 m_freem(sc->qhead); 566 m_freem(sc->m); 567 bzero(sc, sizeof(*sc)); 568 FREE(sc, M_NETGRAPH); 569 return (0); 570} 571 572/* 573 * Receive incoming data from netgraph system. Put it on our 574 * output queue and start output if necessary. 575 */ 576static int 577ngt_rcvdata(hook_p hook, item_p item) 578{ 579 const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 580 int s, error = 0; 581 struct mbuf *m; 582 583 if (hook != sc->hook) 584 panic(__FUNCTION__); 585 586 NGI_GET_M(item, m); 587 NG_FREE_ITEM(item); 588 s = spltty(); 589 if (sc->qlen >= MAX_MBUFQ) 590 ERROUT(ENOBUFS); 591 m->m_nextpkt = NULL; 592 *sc->qtail = m; 593 sc->qtail = &m->m_nextpkt; 594 sc->qlen++; 595 QUEUECHECK(sc); 596 m = NULL; 597 if (sc->qlen == 1) 598 ngt_start(sc->tp); 599done: 600 splx(s); 601 if (m) 602 m_freem(m); 603 return (error); 604} 605 606/* 607 * Receive control message 608 */ 609static int 610ngt_rcvmsg(node_p node, item_p item, hook_p lasthook) 611{ 612 const sc_p sc = NG_NODE_PRIVATE(node); 613 struct ng_mesg *resp = NULL; 614 int error = 0; 615 struct ng_mesg *msg; 616 617 NGI_GET_MSG(item, msg); 618 switch (msg->header.typecookie) { 619 case NGM_TTY_COOKIE: 620 switch (msg->header.cmd) { 621 case NGM_TTY_SET_HOTCHAR: 622 { 623 int hotchar; 624 625 if (msg->header.arglen != sizeof(int)) 626 ERROUT(EINVAL); 627 hotchar = *((int *) msg->data); 628 if (hotchar != (u_char) hotchar && hotchar != -1) 629 ERROUT(EINVAL); 630 sc->hotchar = hotchar; /* race condition is OK */ 631 break; 632 } 633 case NGM_TTY_GET_HOTCHAR: 634 NG_MKRESPONSE(resp, msg, sizeof(int), M_NOWAIT); 635 if (!resp) 636 ERROUT(ENOMEM); 637 /* Race condition here is OK */ 638 *((int *) resp->data) = sc->hotchar; 639 break; 640 default: 641 ERROUT(EINVAL); 642 } 643 break; 644 default: 645 ERROUT(EINVAL); 646 } 647done: 648 NG_RESPOND_MSG(error, node, item, resp); 649 NG_FREE_MSG(msg); 650 return (error); 651} 652 653/****************************************************************** 654 INITIALIZATION 655******************************************************************/ 656 657/* 658 * Handle loading and unloading for this node type 659 */ 660static int 661ngt_mod_event(module_t mod, int event, void *data) 662{ 663 /* struct ng_type *const type = data;*/ 664 int s, error = 0; 665 666 switch (event) { 667 case MOD_LOAD: 668 669 /* Register line discipline */ 670 s = spltty(); 671 if ((ngt_ldisc = ldisc_register(NETGRAPHDISC, &ngt_disc)) < 0) { 672 splx(s); 673 log(LOG_ERR, "%s: can't register line discipline", 674 __FUNCTION__); 675 return (EIO); 676 } 677 splx(s); 678 break; 679 680 case MOD_UNLOAD: 681 682 /* Unregister line discipline */ 683 s = spltty(); 684 ldisc_deregister(ngt_ldisc); 685 splx(s); 686 break; 687 688 default: 689 error = EOPNOTSUPP; 690 break; 691 } 692 return (error); 693} 694 695