ng_tty.c revision 70159
152419Sjulian 252419Sjulian/* 352419Sjulian * ng_tty.c 452419Sjulian * 552419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc. 652419Sjulian * All rights reserved. 752419Sjulian * 852419Sjulian * Subject to the following obligations and disclaimer of warranty, use and 952419Sjulian * redistribution of this software, in source or object code forms, with or 1052419Sjulian * without modifications are expressly permitted by Whistle Communications; 1152419Sjulian * provided, however, that: 1252419Sjulian * 1. Any and all reproductions of the source or object code must include the 1352419Sjulian * copyright notice above and the following disclaimer of warranties; and 1452419Sjulian * 2. No rights are granted, in any manner or form, to use Whistle 1552419Sjulian * Communications, Inc. trademarks, including the mark "WHISTLE 1652419Sjulian * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1752419Sjulian * such appears in the above copyright notice or in the software. 1852419Sjulian * 1952419Sjulian * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2052419Sjulian * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2152419Sjulian * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2252419Sjulian * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2352419Sjulian * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2452419Sjulian * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2552419Sjulian * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2652419Sjulian * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2752419Sjulian * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2852419Sjulian * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 2952419Sjulian * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3052419Sjulian * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3152419Sjulian * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3252419Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3352419Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3452419Sjulian * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3552419Sjulian * OF SUCH DAMAGE. 3652419Sjulian * 3767506Sjulian * Author: Archie Cobbs <archie@freebsd.org> 3852419Sjulian * 3952419Sjulian * $FreeBSD: head/sys/netgraph/ng_tty.c 70159 2000-12-18 20:03:32Z julian $ 4052752Sjulian * $Whistle: ng_tty.c,v 1.21 1999/11/01 09:24:52 julian Exp $ 4152419Sjulian */ 4252419Sjulian 4352419Sjulian/* 4452419Sjulian * This file implements a terminal line discipline that is also a 4552419Sjulian * netgraph node. Installing this line discipline on a terminal device 4652419Sjulian * instantiates a new netgraph node of this type, which allows access 4752419Sjulian * to the device via the "hook" hook of the node. 4852419Sjulian * 4952419Sjulian * Once the line discipline is installed, you can find out the name 5052419Sjulian * of the corresponding netgraph node via a NGIOCGINFO ioctl(). 5152419Sjulian * 5252419Sjulian * Incoming characters are delievered to the hook one at a time, each 5352419Sjulian * in its own mbuf. You may optionally define a ``hotchar,'' which causes 5452419Sjulian * incoming characters to be buffered up until either the hotchar is 5552419Sjulian * seen or the mbuf is full (MHLEN bytes). Then all buffered characters 5652419Sjulian * are immediately delivered. 5752419Sjulian * 5852419Sjulian * NOTE: This node operates at spltty(). 5952419Sjulian */ 6052419Sjulian 6152419Sjulian#include <sys/param.h> 6252419Sjulian#include <sys/systm.h> 6352419Sjulian#include <sys/kernel.h> 6452419Sjulian#include <sys/conf.h> 6552419Sjulian#include <sys/mbuf.h> 6652419Sjulian#include <sys/malloc.h> 6752419Sjulian#include <sys/fcntl.h> 6852419Sjulian#include <sys/tty.h> 6952441Sjulian#include <sys/ttycom.h> 7052419Sjulian#include <sys/syslog.h> 7152419Sjulian#include <sys/errno.h> 7252419Sjulian#include <sys/ioccom.h> 7352419Sjulian 7452419Sjulian#include <netgraph/ng_message.h> 7552419Sjulian#include <netgraph/netgraph.h> 7652419Sjulian#include <netgraph/ng_tty.h> 7752419Sjulian 7852419Sjulian#ifdef __i386__ /* fiddle with the spl locking */ 7965557Sjasone#include <sys/bus.h> 8052419Sjulian#include <machine/ipl.h> 8152419Sjulian#endif 8252419Sjulian 8352419Sjulian/* Misc defs */ 8452419Sjulian#define MAX_MBUFQ 3 /* Max number of queued mbufs */ 8552419Sjulian#define NGT_HIWATER 400 /* High water mark on output */ 8652419Sjulian 8752419Sjulian/* Per-node private info */ 8852419Sjulianstruct ngt_sc { 8953913Sarchie struct tty *tp; /* Terminal device */ 9053913Sarchie node_p node; /* Netgraph node */ 9153913Sarchie hook_p hook; /* Netgraph hook */ 9253913Sarchie struct mbuf *m; /* Incoming data buffer */ 9353913Sarchie struct mbuf *qhead, **qtail; /* Queue of outgoing mbuf's */ 9453913Sarchie short qlen; /* Length of queue */ 9553913Sarchie short hotchar; /* Hotchar, or -1 if none */ 9653913Sarchie u_int flags; /* Flags */ 9753913Sarchie struct callout_handle chand; /* See man timeout(9) */ 9852419Sjulian}; 9952419Sjuliantypedef struct ngt_sc *sc_p; 10052419Sjulian 10152419Sjulian/* Flags */ 10252419Sjulian#define FLG_TIMEOUT 0x0001 /* A timeout is pending */ 10352419Sjulian#define FLG_DEBUG 0x0002 10452419Sjulian 10552419Sjulian/* Debugging */ 10653913Sarchie#ifdef INVARIANTS 10752419Sjulian#define QUEUECHECK(sc) \ 10852419Sjulian do { \ 10952419Sjulian struct mbuf **mp; \ 11052419Sjulian int k; \ 11152419Sjulian \ 11252419Sjulian for (k = 0, mp = &sc->qhead; \ 11352419Sjulian k <= MAX_MBUFQ && *mp; \ 11452419Sjulian k++, mp = &(*mp)->m_nextpkt); \ 11552419Sjulian if (k != sc->qlen || k > MAX_MBUFQ || *mp || mp != sc->qtail) \ 11652419Sjulian panic(__FUNCTION__ ": queue"); \ 11752419Sjulian } while (0) 11852419Sjulian#else 11952419Sjulian#define QUEUECHECK(sc) do {} while (0) 12052419Sjulian#endif 12152419Sjulian 12252419Sjulian/* Line discipline methods */ 12352419Sjulianstatic int ngt_open(dev_t dev, struct tty *tp); 12452419Sjulianstatic int ngt_close(struct tty *tp, int flag); 12552419Sjulianstatic int ngt_read(struct tty *tp, struct uio *uio, int flag); 12652419Sjulianstatic int ngt_write(struct tty *tp, struct uio *uio, int flag); 12752419Sjulianstatic int ngt_tioctl(struct tty *tp, 12852419Sjulian u_long cmd, caddr_t data, int flag, struct proc *); 12952419Sjulianstatic int ngt_input(int c, struct tty *tp); 13052419Sjulianstatic int ngt_start(struct tty *tp); 13152419Sjulian 13252419Sjulian/* Netgraph methods */ 13352752Sjulianstatic ng_constructor_t ngt_constructor; 13452752Sjulianstatic ng_rcvmsg_t ngt_rcvmsg; 13552752Sjulianstatic ng_shutdown_t ngt_shutdown; 13652752Sjulianstatic ng_newhook_t ngt_newhook; 13769922Sjulianstatic ng_connect_t ngt_connect; 13852752Sjulianstatic ng_rcvdata_t ngt_rcvdata; 13952752Sjulianstatic ng_disconnect_t ngt_disconnect; 14052419Sjulianstatic int ngt_mod_event(module_t mod, int event, void *data); 14152419Sjulian 14252419Sjulian/* Other stuff */ 14352419Sjulianstatic void ngt_timeout(void *arg); 14452419Sjulian 14552419Sjulian#define ERROUT(x) do { error = (x); goto done; } while (0) 14652419Sjulian 14752419Sjulian/* Line discipline descriptor */ 14852419Sjulianstatic struct linesw ngt_disc = { 14952419Sjulian ngt_open, 15052419Sjulian ngt_close, 15152419Sjulian ngt_read, 15252419Sjulian ngt_write, 15352419Sjulian ngt_tioctl, 15452419Sjulian ngt_input, 15552419Sjulian ngt_start, 15652419Sjulian ttymodem, 15752419Sjulian NG_TTY_DFL_HOTCHAR /* XXX can't change this in serial driver */ 15852419Sjulian}; 15952419Sjulian 16052419Sjulian/* Netgraph node type descriptor */ 16152419Sjulianstatic struct ng_type typestruct = { 16270159Sjulian NG_ABI_VERSION, 16352419Sjulian NG_TTY_NODE_TYPE, 16452419Sjulian ngt_mod_event, 16552419Sjulian ngt_constructor, 16652419Sjulian ngt_rcvmsg, 16752419Sjulian ngt_shutdown, 16852419Sjulian ngt_newhook, 16952419Sjulian NULL, 17069922Sjulian ngt_connect, 17152419Sjulian ngt_rcvdata, 17252419Sjulian ngt_disconnect, 17353913Sarchie NULL 17452419Sjulian}; 17552419SjulianNETGRAPH_INIT(tty, &typestruct); 17652419Sjulian 17752419Sjulianstatic int ngt_unit; 17852419Sjulianstatic int ngt_nodeop_ok; /* OK to create/remove node */ 17952442Sjulianstatic int ngt_ldisc; 18052419Sjulian 18152419Sjulian/****************************************************************** 18252419Sjulian LINE DISCIPLINE METHODS 18352419Sjulian******************************************************************/ 18452419Sjulian 18552419Sjulian/* 18652419Sjulian * Set our line discipline on the tty. 18752419Sjulian * Called from device open routine or ttioctl() at >= splsofttty() 18852419Sjulian */ 18952419Sjulianstatic int 19052419Sjulianngt_open(dev_t dev, struct tty *tp) 19152419Sjulian{ 19252419Sjulian struct proc *const p = curproc; /* XXX */ 19352419Sjulian char name[sizeof(NG_TTY_NODE_TYPE) + 8]; 19452419Sjulian sc_p sc; 19552419Sjulian int s, error; 19652419Sjulian 19752419Sjulian /* Super-user only */ 19852419Sjulian if ((error = suser(p))) 19952419Sjulian return (error); 20052419Sjulian s = splnet(); 20152419Sjulian (void) spltty(); /* XXX is this necessary? */ 20252419Sjulian 20352419Sjulian /* Already installed? */ 20452441Sjulian if (tp->t_line == NETGRAPHDISC) { 20552419Sjulian sc = (sc_p) tp->t_sc; 20652419Sjulian if (sc != NULL && sc->tp == tp) 20752419Sjulian goto done; 20852419Sjulian } 20952419Sjulian 21052419Sjulian /* Initialize private struct */ 21168876Sdwmalone MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_WAITOK | M_ZERO); 21252419Sjulian if (sc == NULL) { 21352419Sjulian error = ENOMEM; 21452419Sjulian goto done; 21552419Sjulian } 21652419Sjulian sc->tp = tp; 21752419Sjulian sc->hotchar = NG_TTY_DFL_HOTCHAR; 21852419Sjulian sc->qtail = &sc->qhead; 21952419Sjulian QUEUECHECK(sc); 22052419Sjulian callout_handle_init(&sc->chand); 22152419Sjulian 22252419Sjulian /* Setup netgraph node */ 22352419Sjulian ngt_nodeop_ok = 1; 22452419Sjulian error = ng_make_node_common(&typestruct, &sc->node); 22552419Sjulian ngt_nodeop_ok = 0; 22652419Sjulian if (error) { 22752419Sjulian FREE(sc, M_NETGRAPH); 22852419Sjulian goto done; 22952419Sjulian } 23058012Sarchie snprintf(name, sizeof(name), "%s%d", typestruct.name, ngt_unit++); 23152419Sjulian 23252419Sjulian /* Set back pointers */ 23352419Sjulian sc->node->private = sc; 23452419Sjulian tp->t_sc = (caddr_t) sc; 23552419Sjulian 23652419Sjulian /* Assign node its name */ 23752419Sjulian if ((error = ng_name_node(sc->node, name))) { 23852419Sjulian log(LOG_ERR, "%s: node name exists?\n", name); 23952419Sjulian ngt_nodeop_ok = 1; 24052419Sjulian ng_rmnode(sc->node); 24152419Sjulian ngt_nodeop_ok = 0; 24252419Sjulian goto done; 24352419Sjulian } 24452419Sjulian 24552419Sjulian /* 24652419Sjulian * Pre-allocate cblocks to the an appropriate amount. 24752419Sjulian * I'm not sure what is appropriate. 24852419Sjulian */ 24952419Sjulian ttyflush(tp, FREAD | FWRITE); 25052419Sjulian clist_alloc_cblocks(&tp->t_canq, 0, 0); 25152419Sjulian clist_alloc_cblocks(&tp->t_rawq, 0, 0); 25252419Sjulian clist_alloc_cblocks(&tp->t_outq, 25352419Sjulian MLEN + NGT_HIWATER, MLEN + NGT_HIWATER); 25452419Sjulian 25552419Sjuliandone: 25652419Sjulian /* Done */ 25752419Sjulian splx(s); 25852419Sjulian return (error); 25952419Sjulian} 26052419Sjulian 26152419Sjulian/* 26252419Sjulian * Line specific close routine, called from device close routine 26352419Sjulian * and from ttioctl at >= splsofttty(). This causes the node to 26452419Sjulian * be destroyed as well. 26552419Sjulian */ 26652419Sjulianstatic int 26752419Sjulianngt_close(struct tty *tp, int flag) 26852419Sjulian{ 26952419Sjulian const sc_p sc = (sc_p) tp->t_sc; 27052419Sjulian int s; 27152419Sjulian 27252419Sjulian s = spltty(); 27352419Sjulian ttyflush(tp, FREAD | FWRITE); 27452419Sjulian clist_free_cblocks(&tp->t_outq); 27552419Sjulian tp->t_line = 0; 27652419Sjulian if (sc != NULL) { 27752419Sjulian if (sc->flags & FLG_TIMEOUT) { 27852419Sjulian untimeout(ngt_timeout, sc, sc->chand); 27952419Sjulian sc->flags &= ~FLG_TIMEOUT; 28052419Sjulian } 28152419Sjulian ngt_nodeop_ok = 1; 28252419Sjulian ng_rmnode(sc->node); 28352419Sjulian ngt_nodeop_ok = 0; 28452419Sjulian tp->t_sc = NULL; 28552419Sjulian } 28652419Sjulian splx(s); 28752419Sjulian return (0); 28852419Sjulian} 28952419Sjulian 29052419Sjulian/* 29152419Sjulian * Once the device has been turned into a node, we don't allow reading. 29252419Sjulian */ 29352419Sjulianstatic int 29452419Sjulianngt_read(struct tty *tp, struct uio *uio, int flag) 29552419Sjulian{ 29652419Sjulian return (EIO); 29752419Sjulian} 29852419Sjulian 29952419Sjulian/* 30052419Sjulian * Once the device has been turned into a node, we don't allow writing. 30152419Sjulian */ 30252419Sjulianstatic int 30352419Sjulianngt_write(struct tty *tp, struct uio *uio, int flag) 30452419Sjulian{ 30552419Sjulian return (EIO); 30652419Sjulian} 30752419Sjulian 30852419Sjulian/* 30952419Sjulian * We implement the NGIOCGINFO ioctl() defined in ng_message.h. 31052419Sjulian */ 31152419Sjulianstatic int 31252419Sjulianngt_tioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct proc *p) 31352419Sjulian{ 31452419Sjulian const sc_p sc = (sc_p) tp->t_sc; 31552419Sjulian int s, error = 0; 31652419Sjulian 31752419Sjulian s = spltty(); 31852419Sjulian switch (cmd) { 31952419Sjulian case NGIOCGINFO: 32052419Sjulian { 32152419Sjulian struct nodeinfo *const ni = (struct nodeinfo *) data; 32252419Sjulian const node_p node = sc->node; 32352419Sjulian 32452419Sjulian bzero(ni, sizeof(*ni)); 32552419Sjulian if (node->name) 32652419Sjulian strncpy(ni->name, node->name, sizeof(ni->name) - 1); 32752419Sjulian strncpy(ni->type, node->type->name, sizeof(ni->type) - 1); 32852419Sjulian ni->id = (u_int32_t) node; 32952419Sjulian ni->hooks = node->numhooks; 33052419Sjulian break; 33152419Sjulian } 33252419Sjulian default: 33352419Sjulian ERROUT(ENOIOCTL); 33452419Sjulian } 33552419Sjuliandone: 33652419Sjulian splx(s); 33752419Sjulian return (error); 33852419Sjulian} 33952419Sjulian 34052419Sjulian/* 34152419Sjulian * Receive data coming from the device. We get one character at 34252419Sjulian * a time, which is kindof silly. 34352419Sjulian * Only guaranteed to be at splsofttty() or spltty(). 34452419Sjulian */ 34552419Sjulianstatic int 34652419Sjulianngt_input(int c, struct tty *tp) 34752419Sjulian{ 34852419Sjulian const sc_p sc = (sc_p) tp->t_sc; 34952419Sjulian const node_p node = sc->node; 35052419Sjulian struct mbuf *m; 35152419Sjulian int s, error = 0; 35252419Sjulian 35352419Sjulian if (!sc || tp != sc->tp) 35452419Sjulian return (0); 35552419Sjulian s = spltty(); 35652419Sjulian if (!sc->hook) 35752419Sjulian ERROUT(0); 35852419Sjulian 35952419Sjulian /* Check for error conditions */ 36052419Sjulian if ((tp->t_state & TS_CONNECTED) == 0) { 36152419Sjulian if (sc->flags & FLG_DEBUG) 36252419Sjulian log(LOG_DEBUG, "%s: no carrier\n", node->name); 36352419Sjulian ERROUT(0); 36452419Sjulian } 36552419Sjulian if (c & TTY_ERRORMASK) { 36652419Sjulian /* framing error or overrun on this char */ 36752419Sjulian if (sc->flags & FLG_DEBUG) 36852419Sjulian log(LOG_DEBUG, "%s: line error %x\n", 36952419Sjulian node->name, c & TTY_ERRORMASK); 37052419Sjulian ERROUT(0); 37152419Sjulian } 37252419Sjulian c &= TTY_CHARMASK; 37352419Sjulian 37452419Sjulian /* Get a new header mbuf if we need one */ 37552419Sjulian if (!(m = sc->m)) { 37652419Sjulian MGETHDR(m, M_DONTWAIT, MT_DATA); 37752419Sjulian if (!m) { 37852419Sjulian if (sc->flags & FLG_DEBUG) 37952419Sjulian log(LOG_ERR, 38052419Sjulian "%s: can't get mbuf\n", node->name); 38152419Sjulian ERROUT(ENOBUFS); 38252419Sjulian } 38353284Sarchie m->m_len = m->m_pkthdr.len = 0; 38453284Sarchie m->m_pkthdr.rcvif = NULL; 38552419Sjulian sc->m = m; 38652419Sjulian } 38752419Sjulian 38852419Sjulian /* Add char to mbuf */ 38952419Sjulian *mtod(m, u_char *) = c; 39052419Sjulian m->m_data++; 39152419Sjulian m->m_len++; 39252419Sjulian m->m_pkthdr.len++; 39352419Sjulian 39452419Sjulian /* Ship off mbuf if it's time */ 39552419Sjulian if (sc->hotchar == -1 || c == sc->hotchar || m->m_len >= MHLEN) { 39652419Sjulian m->m_data = m->m_pktdat; 39769922Sjulian NG_SEND_DATA_ONLY(error, sc->hook, m); 39852419Sjulian sc->m = NULL; 39952419Sjulian } 40052419Sjuliandone: 40152419Sjulian splx(s); 40252419Sjulian return (error); 40352419Sjulian} 40452419Sjulian 40552419Sjulian/* 40652419Sjulian * This is called when the device driver is ready for more output. 40752419Sjulian * Called from tty system at splsofttty() or spltty(). 40852419Sjulian * Also call from ngt_rcv_data() when a new mbuf is available for output. 40952419Sjulian */ 41052419Sjulianstatic int 41152419Sjulianngt_start(struct tty *tp) 41252419Sjulian{ 41352419Sjulian const sc_p sc = (sc_p) tp->t_sc; 41452419Sjulian int s; 41552419Sjulian 41652419Sjulian s = spltty(); 41752419Sjulian while (tp->t_outq.c_cc < NGT_HIWATER) { /* XXX 2.2 specific ? */ 41852419Sjulian struct mbuf *m = sc->qhead; 41952419Sjulian 42052419Sjulian /* Remove first mbuf from queue */ 42152419Sjulian if (!m) 42252419Sjulian break; 42352419Sjulian if ((sc->qhead = m->m_nextpkt) == NULL) 42452419Sjulian sc->qtail = &sc->qhead; 42552419Sjulian sc->qlen--; 42652419Sjulian QUEUECHECK(sc); 42752419Sjulian 42852419Sjulian /* Send as much of it as possible */ 42952419Sjulian while (m) { 43052419Sjulian struct mbuf *m2; 43152419Sjulian int sent; 43252419Sjulian 43352419Sjulian sent = m->m_len 43452419Sjulian - b_to_q(mtod(m, u_char *), m->m_len, &tp->t_outq); 43552419Sjulian m->m_data += sent; 43652419Sjulian m->m_len -= sent; 43752419Sjulian if (m->m_len > 0) 43852419Sjulian break; /* device can't take no more */ 43952419Sjulian MFREE(m, m2); 44052419Sjulian m = m2; 44152419Sjulian } 44252419Sjulian 44352419Sjulian /* Put remainder of mbuf chain (if any) back on queue */ 44452419Sjulian if (m) { 44552419Sjulian m->m_nextpkt = sc->qhead; 44652419Sjulian sc->qhead = m; 44752419Sjulian if (sc->qtail == &sc->qhead) 44852419Sjulian sc->qtail = &m->m_nextpkt; 44952419Sjulian sc->qlen++; 45052419Sjulian QUEUECHECK(sc); 45152419Sjulian break; 45252419Sjulian } 45352419Sjulian } 45452419Sjulian 45552419Sjulian /* Call output process whether or not there is any output. We are 45652419Sjulian * being called in lieu of ttstart and must do what it would. */ 45752419Sjulian if (tp->t_oproc != NULL) 45852419Sjulian (*tp->t_oproc) (tp); 45952419Sjulian 46052419Sjulian /* This timeout is needed for operation on a pseudo-tty, because the 46152419Sjulian * pty code doesn't call pppstart after it has drained the t_outq. */ 46252419Sjulian if (sc->qhead && (sc->flags & FLG_TIMEOUT) == 0) { 46352419Sjulian sc->chand = timeout(ngt_timeout, sc, 1); 46452419Sjulian sc->flags |= FLG_TIMEOUT; 46552419Sjulian } 46652419Sjulian splx(s); 46752419Sjulian return (0); 46852419Sjulian} 46952419Sjulian 47052419Sjulian/* 47152419Sjulian * We still have data to output to the device, so try sending more. 47252419Sjulian */ 47352419Sjulianstatic void 47452419Sjulianngt_timeout(void *arg) 47552419Sjulian{ 47652419Sjulian const sc_p sc = (sc_p) arg; 47752419Sjulian int s; 47852419Sjulian 47952419Sjulian s = spltty(); 48052419Sjulian sc->flags &= ~FLG_TIMEOUT; 48152419Sjulian ngt_start(sc->tp); 48252419Sjulian splx(s); 48352419Sjulian} 48452419Sjulian 48552419Sjulian/****************************************************************** 48652419Sjulian NETGRAPH NODE METHODS 48752419Sjulian******************************************************************/ 48852419Sjulian 48952419Sjulian/* 49052419Sjulian * Initialize a new node of this type. 49152419Sjulian * 49252419Sjulian * We only allow nodes to be created as a result of setting 49352419Sjulian * the line discipline on a tty, so always return an error if not. 49452419Sjulian */ 49552419Sjulianstatic int 49652419Sjulianngt_constructor(node_p *nodep) 49752419Sjulian{ 49852419Sjulian if (!ngt_nodeop_ok) 49952419Sjulian return (EOPNOTSUPP); 50052419Sjulian return (ng_make_node_common(&typestruct, nodep)); 50152419Sjulian} 50252419Sjulian 50352419Sjulian/* 50452419Sjulian * Add a new hook. There can only be one. 50552419Sjulian */ 50652419Sjulianstatic int 50752419Sjulianngt_newhook(node_p node, hook_p hook, const char *name) 50852419Sjulian{ 50952419Sjulian const sc_p sc = node->private; 51052419Sjulian int s, error = 0; 51152419Sjulian 51252419Sjulian if (strcmp(name, NG_TTY_HOOK)) 51352419Sjulian return (EINVAL); 51452419Sjulian s = spltty(); 51552419Sjulian if (sc->hook) 51652419Sjulian ERROUT(EISCONN); 51752419Sjulian sc->hook = hook; 51852419Sjuliandone: 51952419Sjulian splx(s); 52052419Sjulian return (error); 52152419Sjulian} 52252419Sjulian 52352419Sjulian/* 52469922Sjulian * set the hooks into queueing mode (for outgoing packets) 52569922Sjulian */ 52669922Sjulianstatic int 52769922Sjulianngt_connect(hook_p hook) 52869922Sjulian{ 52969922Sjulian hook->peer->flags |= HK_QUEUE; 53069922Sjulian return (0); 53169922Sjulian} 53269922Sjulian 53369922Sjulian/* 53452419Sjulian * Disconnect the hook 53552419Sjulian */ 53652419Sjulianstatic int 53752419Sjulianngt_disconnect(hook_p hook) 53852419Sjulian{ 53952419Sjulian const sc_p sc = hook->node->private; 54052419Sjulian int s; 54152419Sjulian 54252419Sjulian s = spltty(); 54352419Sjulian if (hook != sc->hook) 54452419Sjulian panic(__FUNCTION__); 54552419Sjulian sc->hook = NULL; 54652419Sjulian m_freem(sc->m); 54752419Sjulian sc->m = NULL; 54852419Sjulian splx(s); 54952419Sjulian return (0); 55052419Sjulian} 55152419Sjulian 55252419Sjulian/* 55352419Sjulian * Remove this node. The does the netgraph portion of the shutdown. 55452419Sjulian * This should only be called indirectly from ngt_close(). 55552419Sjulian */ 55652419Sjulianstatic int 55752419Sjulianngt_shutdown(node_p node) 55852419Sjulian{ 55952419Sjulian const sc_p sc = node->private; 56052419Sjulian 56152419Sjulian if (!ngt_nodeop_ok) 56252419Sjulian return (EOPNOTSUPP); 56352419Sjulian ng_unname(node); 56452419Sjulian ng_cutlinks(node); 56552419Sjulian node->private = NULL; 56652419Sjulian ng_unref(sc->node); 56752419Sjulian m_freem(sc->qhead); 56852419Sjulian m_freem(sc->m); 56952419Sjulian bzero(sc, sizeof(*sc)); 57052419Sjulian FREE(sc, M_NETGRAPH); 57152419Sjulian return (0); 57252419Sjulian} 57352419Sjulian 57452419Sjulian/* 57552419Sjulian * Receive incoming data from netgraph system. Put it on our 57652419Sjulian * output queue and start output if necessary. 57752419Sjulian */ 57852419Sjulianstatic int 57959728Sjulianngt_rcvdata(hook_p hook, struct mbuf *m, meta_p meta, 58069922Sjulian struct mbuf **ret_m, meta_p *ret_meta, struct ng_mesg **resp) 58152419Sjulian{ 58252419Sjulian const sc_p sc = hook->node->private; 58352419Sjulian int s, error = 0; 58452419Sjulian 58552419Sjulian if (hook != sc->hook) 58652419Sjulian panic(__FUNCTION__); 58752419Sjulian NG_FREE_META(meta); 58852419Sjulian s = spltty(); 58952419Sjulian if (sc->qlen >= MAX_MBUFQ) 59052419Sjulian ERROUT(ENOBUFS); 59152419Sjulian m->m_nextpkt = NULL; 59252419Sjulian *sc->qtail = m; 59352419Sjulian sc->qtail = &m->m_nextpkt; 59452419Sjulian sc->qlen++; 59552419Sjulian QUEUECHECK(sc); 59652419Sjulian m = NULL; 59752419Sjulian if (sc->qlen == 1) 59852419Sjulian ngt_start(sc->tp); 59952419Sjuliandone: 60052419Sjulian splx(s); 60152419Sjulian if (m) 60252419Sjulian m_freem(m); 60352419Sjulian return (error); 60452419Sjulian} 60552419Sjulian 60652419Sjulian/* 60752419Sjulian * Receive control message 60852419Sjulian */ 60952419Sjulianstatic int 61052419Sjulianngt_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr, 61159728Sjulian struct ng_mesg **rptr, hook_p lasthook) 61252419Sjulian{ 61352419Sjulian const sc_p sc = (sc_p) node->private; 61452419Sjulian struct ng_mesg *resp = NULL; 61552419Sjulian int error = 0; 61652419Sjulian 61752419Sjulian switch (msg->header.typecookie) { 61852419Sjulian case NGM_TTY_COOKIE: 61952419Sjulian switch (msg->header.cmd) { 62052419Sjulian case NGM_TTY_SET_HOTCHAR: 62152419Sjulian { 62252419Sjulian int hotchar; 62352419Sjulian 62452419Sjulian if (msg->header.arglen != sizeof(int)) 62552419Sjulian ERROUT(EINVAL); 62652419Sjulian hotchar = *((int *) msg->data); 62752419Sjulian if (hotchar != (u_char) hotchar && hotchar != -1) 62852419Sjulian ERROUT(EINVAL); 62952419Sjulian sc->hotchar = hotchar; /* race condition is OK */ 63052419Sjulian break; 63152419Sjulian } 63252419Sjulian case NGM_TTY_GET_HOTCHAR: 63352419Sjulian NG_MKRESPONSE(resp, msg, sizeof(int), M_NOWAIT); 63452419Sjulian if (!resp) 63552419Sjulian ERROUT(ENOMEM); 63652419Sjulian /* Race condition here is OK */ 63752419Sjulian *((int *) resp->data) = sc->hotchar; 63852419Sjulian break; 63952419Sjulian default: 64052419Sjulian ERROUT(EINVAL); 64152419Sjulian } 64252419Sjulian break; 64352419Sjulian default: 64452419Sjulian ERROUT(EINVAL); 64552419Sjulian } 64652419Sjulian if (rptr) 64752419Sjulian *rptr = resp; 64852419Sjulian else if (resp) 64952419Sjulian FREE(resp, M_NETGRAPH); 65052419Sjulian 65152419Sjuliandone: 65252419Sjulian FREE(msg, M_NETGRAPH); 65352419Sjulian return (error); 65452419Sjulian} 65552419Sjulian 65652419Sjulian/****************************************************************** 65752419Sjulian INITIALIZATION 65852419Sjulian******************************************************************/ 65952419Sjulian 66052419Sjulian/* 66152419Sjulian * Handle loading and unloading for this node type 66252419Sjulian */ 66352419Sjulianstatic int 66452419Sjulianngt_mod_event(module_t mod, int event, void *data) 66552419Sjulian{ 66652442Sjulian /* struct ng_type *const type = data;*/ 66752419Sjulian int s, error = 0; 66852419Sjulian 66952419Sjulian switch (event) { 67052419Sjulian case MOD_LOAD: 67152419Sjulian 67252419Sjulian /* Register line discipline */ 67352419Sjulian s = spltty(); 67452441Sjulian if ((ngt_ldisc = ldisc_register(NETGRAPHDISC, &ngt_disc)) < 0) { 67552419Sjulian splx(s); 67652419Sjulian log(LOG_ERR, "%s: can't register line discipline", 67752419Sjulian __FUNCTION__); 67852419Sjulian return (EIO); 67952419Sjulian } 68052419Sjulian splx(s); 68152419Sjulian break; 68252419Sjulian 68352419Sjulian case MOD_UNLOAD: 68452419Sjulian 68552419Sjulian /* Unregister line discipline */ 68652419Sjulian s = spltty(); 68752419Sjulian ldisc_deregister(ngt_ldisc); 68852419Sjulian splx(s); 68952419Sjulian break; 69052419Sjulian 69152419Sjulian default: 69252419Sjulian error = EOPNOTSUPP; 69352419Sjulian break; 69452419Sjulian } 69552419Sjulian return (error); 69652419Sjulian} 69752419Sjulian 698