ng_tty.c revision 52442
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 * 3752419Sjulian * Author: Archie Cobbs <archie@whistle.com> 3852419Sjulian * 3952419Sjulian * $FreeBSD: head/sys/netgraph/ng_tty.c 52442 1999-10-23 04:52:54Z julian $ 4052419Sjulian * $Whistle: ng_tty.c,v 1.18 1999/01/28 23:54:54 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/proc.h> 6652419Sjulian#include <sys/mbuf.h> 6752419Sjulian#include <sys/malloc.h> 6852419Sjulian#include <sys/socket.h> 6952419Sjulian#include <sys/fcntl.h> 7052419Sjulian#include <sys/file.h> 7152419Sjulian#include <sys/tty.h> 7252441Sjulian#include <sys/ttycom.h> 7352419Sjulian#include <sys/syslog.h> 7452419Sjulian#include <sys/errno.h> 7552419Sjulian#include <sys/ioccom.h> 7652419Sjulian 7752419Sjulian#include <netgraph/ng_message.h> 7852419Sjulian#include <netgraph/netgraph.h> 7952419Sjulian#include <netgraph/ng_tty.h> 8052419Sjulian 8152419Sjulian#ifdef __i386__ /* fiddle with the spl locking */ 8252419Sjulian#include <machine/ipl.h> 8352419Sjulian#include <i386/isa/intr_machdep.h> 8452419Sjulian#endif 8552419Sjulian 8652419Sjulian/* Misc defs */ 8752419Sjulian#define MAX_MBUFQ 3 /* Max number of queued mbufs */ 8852419Sjulian#define NGT_HIWATER 400 /* High water mark on output */ 8952419Sjulian 9052419Sjulian/* Per-node private info */ 9152419Sjulianstruct ngt_sc { 9252419Sjulian struct tty *tp; /* Terminal device */ 9352419Sjulian node_p node; /* Netgraph node */ 9452419Sjulian hook_p hook; /* Netgraph hook */ 9552419Sjulian struct mbuf *m; /* Incoming data buffer */ 9652419Sjulian struct mbuf *qhead, **qtail; /* Queue of outgoing mbuf's */ 9752419Sjulian short qlen; /* Length of queue */ 9852419Sjulian short hotchar; /* Hotchar, or -1 if none */ 9952419Sjulian u_int flags; /* Flags */ 10052419Sjulian struct callout_handle chand; /* See man timeout(9) */ 10152419Sjulian}; 10252419Sjuliantypedef struct ngt_sc *sc_p; 10352419Sjulian 10452419Sjulian/* Flags */ 10552419Sjulian#define FLG_TIMEOUT 0x0001 /* A timeout is pending */ 10652419Sjulian#define FLG_DEBUG 0x0002 10752419Sjulian 10852419Sjulian/* Debugging */ 10952419Sjulian#ifdef DIAGNOSTICS 11052419Sjulian#define QUEUECHECK(sc) \ 11152419Sjulian do { \ 11252419Sjulian struct mbuf **mp; \ 11352419Sjulian int k; \ 11452419Sjulian \ 11552419Sjulian for (k = 0, mp = &sc->qhead; \ 11652419Sjulian k <= MAX_MBUFQ && *mp; \ 11752419Sjulian k++, mp = &(*mp)->m_nextpkt); \ 11852419Sjulian if (k != sc->qlen || k > MAX_MBUFQ || *mp || mp != sc->qtail) \ 11952419Sjulian panic(__FUNCTION__ ": queue"); \ 12052419Sjulian } while (0) 12152419Sjulian#else 12252419Sjulian#define QUEUECHECK(sc) do {} while (0) 12352419Sjulian#endif 12452419Sjulian 12552419Sjulian/* Line discipline methods */ 12652419Sjulianstatic int ngt_open(dev_t dev, struct tty *tp); 12752419Sjulianstatic int ngt_close(struct tty *tp, int flag); 12852419Sjulianstatic int ngt_read(struct tty *tp, struct uio *uio, int flag); 12952419Sjulianstatic int ngt_write(struct tty *tp, struct uio *uio, int flag); 13052419Sjulianstatic int ngt_tioctl(struct tty *tp, 13152419Sjulian u_long cmd, caddr_t data, int flag, struct proc *); 13252419Sjulianstatic int ngt_input(int c, struct tty *tp); 13352419Sjulianstatic int ngt_start(struct tty *tp); 13452419Sjulian 13552419Sjulian/* Netgraph methods */ 13652419Sjulianstatic int ngt_constructor(node_p *node); 13752419Sjulianstatic int ngt_rcvmsg(node_p node, struct ng_mesg *msg, 13852419Sjulian const char *retaddr, struct ng_mesg **resp); 13952419Sjulianstatic int ngt_shutdown(node_p node); 14052419Sjulianstatic int ngt_newhook(node_p node, hook_p hook, const char *name); 14152419Sjulianstatic int ngt_rcvdata(hook_p hook, struct mbuf *m, meta_p meta); 14252419Sjulianstatic int ngt_disconnect(hook_p hook); 14352419Sjulianstatic int ngt_mod_event(module_t mod, int event, void *data); 14452419Sjulian 14552419Sjulian/* Other stuff */ 14652419Sjulianstatic void ngt_timeout(void *arg); 14752419Sjulian 14852419Sjulian#define ERROUT(x) do { error = (x); goto done; } while (0) 14952419Sjulian 15052419Sjulian/* Line discipline descriptor */ 15152419Sjulianstatic struct linesw ngt_disc = { 15252419Sjulian ngt_open, 15352419Sjulian ngt_close, 15452419Sjulian ngt_read, 15552419Sjulian ngt_write, 15652419Sjulian ngt_tioctl, 15752419Sjulian ngt_input, 15852419Sjulian ngt_start, 15952419Sjulian ttymodem, 16052419Sjulian NG_TTY_DFL_HOTCHAR /* XXX can't change this in serial driver */ 16152419Sjulian}; 16252419Sjulian 16352419Sjulian/* Netgraph node type descriptor */ 16452419Sjulianstatic struct ng_type typestruct = { 16552419Sjulian NG_VERSION, 16652419Sjulian NG_TTY_NODE_TYPE, 16752419Sjulian ngt_mod_event, 16852419Sjulian ngt_constructor, 16952419Sjulian ngt_rcvmsg, 17052419Sjulian ngt_shutdown, 17152419Sjulian ngt_newhook, 17252419Sjulian NULL, 17352419Sjulian NULL, 17452419Sjulian ngt_rcvdata, 17552419Sjulian ngt_rcvdata, 17652419Sjulian ngt_disconnect, 17752419Sjulian}; 17852419SjulianNETGRAPH_INIT(tty, &typestruct); 17952419Sjulian 18052419Sjulianstatic int ngt_unit; 18152419Sjulianstatic int ngt_nodeop_ok; /* OK to create/remove node */ 18252442Sjulianstatic int ngt_ldisc; 18352419Sjulian 18452419Sjulian/****************************************************************** 18552419Sjulian LINE DISCIPLINE METHODS 18652419Sjulian******************************************************************/ 18752419Sjulian 18852419Sjulian/* 18952419Sjulian * Set our line discipline on the tty. 19052419Sjulian * Called from device open routine or ttioctl() at >= splsofttty() 19152419Sjulian */ 19252419Sjulianstatic int 19352419Sjulianngt_open(dev_t dev, struct tty *tp) 19452419Sjulian{ 19552419Sjulian struct proc *const p = curproc; /* XXX */ 19652419Sjulian char name[sizeof(NG_TTY_NODE_TYPE) + 8]; 19752419Sjulian sc_p sc; 19852419Sjulian int s, error; 19952419Sjulian 20052419Sjulian /* Super-user only */ 20152419Sjulian if ((error = suser(p))) 20252419Sjulian return (error); 20352419Sjulian s = splnet(); 20452419Sjulian (void) spltty(); /* XXX is this necessary? */ 20552419Sjulian 20652419Sjulian /* Already installed? */ 20752441Sjulian if (tp->t_line == NETGRAPHDISC) { 20852419Sjulian sc = (sc_p) tp->t_sc; 20952419Sjulian if (sc != NULL && sc->tp == tp) 21052419Sjulian goto done; 21152419Sjulian } 21252419Sjulian 21352419Sjulian /* Initialize private struct */ 21452419Sjulian MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_WAITOK); 21552419Sjulian if (sc == NULL) { 21652419Sjulian error = ENOMEM; 21752419Sjulian goto done; 21852419Sjulian } 21952419Sjulian bzero(sc, sizeof(*sc)); 22052419Sjulian sc->tp = tp; 22152419Sjulian sc->hotchar = NG_TTY_DFL_HOTCHAR; 22252419Sjulian sc->qtail = &sc->qhead; 22352419Sjulian QUEUECHECK(sc); 22452419Sjulian callout_handle_init(&sc->chand); 22552419Sjulian 22652419Sjulian /* Setup netgraph node */ 22752419Sjulian ngt_nodeop_ok = 1; 22852419Sjulian error = ng_make_node_common(&typestruct, &sc->node); 22952419Sjulian ngt_nodeop_ok = 0; 23052419Sjulian if (error) { 23152419Sjulian FREE(sc, M_NETGRAPH); 23252419Sjulian goto done; 23352419Sjulian } 23452419Sjulian sprintf(name, "%s%d", typestruct.name, ngt_unit++); 23552419Sjulian 23652419Sjulian /* Set back pointers */ 23752419Sjulian sc->node->private = sc; 23852419Sjulian tp->t_sc = (caddr_t) sc; 23952419Sjulian 24052419Sjulian /* Assign node its name */ 24152419Sjulian if ((error = ng_name_node(sc->node, name))) { 24252419Sjulian log(LOG_ERR, "%s: node name exists?\n", name); 24352419Sjulian ngt_nodeop_ok = 1; 24452419Sjulian ng_rmnode(sc->node); 24552419Sjulian ngt_nodeop_ok = 0; 24652419Sjulian goto done; 24752419Sjulian } 24852419Sjulian 24952419Sjulian /* 25052419Sjulian * Pre-allocate cblocks to the an appropriate amount. 25152419Sjulian * I'm not sure what is appropriate. 25252419Sjulian */ 25352419Sjulian ttyflush(tp, FREAD | FWRITE); 25452419Sjulian clist_alloc_cblocks(&tp->t_canq, 0, 0); 25552419Sjulian clist_alloc_cblocks(&tp->t_rawq, 0, 0); 25652419Sjulian clist_alloc_cblocks(&tp->t_outq, 25752419Sjulian MLEN + NGT_HIWATER, MLEN + NGT_HIWATER); 25852419Sjulian 25952419Sjuliandone: 26052419Sjulian /* Done */ 26152419Sjulian splx(s); 26252419Sjulian return (error); 26352419Sjulian} 26452419Sjulian 26552419Sjulian/* 26652419Sjulian * Line specific close routine, called from device close routine 26752419Sjulian * and from ttioctl at >= splsofttty(). This causes the node to 26852419Sjulian * be destroyed as well. 26952419Sjulian */ 27052419Sjulianstatic int 27152419Sjulianngt_close(struct tty *tp, int flag) 27252419Sjulian{ 27352419Sjulian const sc_p sc = (sc_p) tp->t_sc; 27452419Sjulian int s; 27552419Sjulian 27652419Sjulian s = spltty(); 27752419Sjulian ttyflush(tp, FREAD | FWRITE); 27852419Sjulian clist_free_cblocks(&tp->t_outq); 27952419Sjulian tp->t_line = 0; 28052419Sjulian if (sc != NULL) { 28152419Sjulian if (sc->flags & FLG_TIMEOUT) { 28252419Sjulian untimeout(ngt_timeout, sc, sc->chand); 28352419Sjulian sc->flags &= ~FLG_TIMEOUT; 28452419Sjulian } 28552419Sjulian ngt_nodeop_ok = 1; 28652419Sjulian ng_rmnode(sc->node); 28752419Sjulian ngt_nodeop_ok = 0; 28852419Sjulian tp->t_sc = NULL; 28952419Sjulian } 29052419Sjulian splx(s); 29152419Sjulian return (0); 29252419Sjulian} 29352419Sjulian 29452419Sjulian/* 29552419Sjulian * Once the device has been turned into a node, we don't allow reading. 29652419Sjulian */ 29752419Sjulianstatic int 29852419Sjulianngt_read(struct tty *tp, struct uio *uio, int flag) 29952419Sjulian{ 30052419Sjulian return (EIO); 30152419Sjulian} 30252419Sjulian 30352419Sjulian/* 30452419Sjulian * Once the device has been turned into a node, we don't allow writing. 30552419Sjulian */ 30652419Sjulianstatic int 30752419Sjulianngt_write(struct tty *tp, struct uio *uio, int flag) 30852419Sjulian{ 30952419Sjulian return (EIO); 31052419Sjulian} 31152419Sjulian 31252419Sjulian/* 31352419Sjulian * We implement the NGIOCGINFO ioctl() defined in ng_message.h. 31452419Sjulian */ 31552419Sjulianstatic int 31652419Sjulianngt_tioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct proc *p) 31752419Sjulian{ 31852419Sjulian const sc_p sc = (sc_p) tp->t_sc; 31952419Sjulian int s, error = 0; 32052419Sjulian 32152419Sjulian s = spltty(); 32252419Sjulian switch (cmd) { 32352419Sjulian case NGIOCGINFO: 32452419Sjulian { 32552419Sjulian struct nodeinfo *const ni = (struct nodeinfo *) data; 32652419Sjulian const node_p node = sc->node; 32752419Sjulian 32852419Sjulian bzero(ni, sizeof(*ni)); 32952419Sjulian if (node->name) 33052419Sjulian strncpy(ni->name, node->name, sizeof(ni->name) - 1); 33152419Sjulian strncpy(ni->type, node->type->name, sizeof(ni->type) - 1); 33252419Sjulian ni->id = (u_int32_t) node; 33352419Sjulian ni->hooks = node->numhooks; 33452419Sjulian break; 33552419Sjulian } 33652419Sjulian default: 33752419Sjulian ERROUT(ENOIOCTL); 33852419Sjulian } 33952419Sjuliandone: 34052419Sjulian splx(s); 34152419Sjulian return (error); 34252419Sjulian} 34352419Sjulian 34452419Sjulian/* 34552419Sjulian * Receive data coming from the device. We get one character at 34652419Sjulian * a time, which is kindof silly. 34752419Sjulian * Only guaranteed to be at splsofttty() or spltty(). 34852419Sjulian */ 34952419Sjulianstatic int 35052419Sjulianngt_input(int c, struct tty *tp) 35152419Sjulian{ 35252419Sjulian const sc_p sc = (sc_p) tp->t_sc; 35352419Sjulian const node_p node = sc->node; 35452419Sjulian struct mbuf *m; 35552419Sjulian int s, error = 0; 35652419Sjulian 35752419Sjulian if (!sc || tp != sc->tp) 35852419Sjulian return (0); 35952419Sjulian s = spltty(); 36052419Sjulian if (!sc->hook) 36152419Sjulian ERROUT(0); 36252419Sjulian 36352419Sjulian /* Check for error conditions */ 36452419Sjulian if ((tp->t_state & TS_CONNECTED) == 0) { 36552419Sjulian if (sc->flags & FLG_DEBUG) 36652419Sjulian log(LOG_DEBUG, "%s: no carrier\n", node->name); 36752419Sjulian ERROUT(0); 36852419Sjulian } 36952419Sjulian if (c & TTY_ERRORMASK) { 37052419Sjulian /* framing error or overrun on this char */ 37152419Sjulian if (sc->flags & FLG_DEBUG) 37252419Sjulian log(LOG_DEBUG, "%s: line error %x\n", 37352419Sjulian node->name, c & TTY_ERRORMASK); 37452419Sjulian ERROUT(0); 37552419Sjulian } 37652419Sjulian c &= TTY_CHARMASK; 37752419Sjulian 37852419Sjulian /* Get a new header mbuf if we need one */ 37952419Sjulian if (!(m = sc->m)) { 38052419Sjulian MGETHDR(m, M_DONTWAIT, MT_DATA); 38152419Sjulian if (!m) { 38252419Sjulian if (sc->flags & FLG_DEBUG) 38352419Sjulian log(LOG_ERR, 38452419Sjulian "%s: can't get mbuf\n", node->name); 38552419Sjulian ERROUT(ENOBUFS); 38652419Sjulian } 38752419Sjulian m->m_len = 0; 38852419Sjulian m->m_pkthdr.len = 0; 38952419Sjulian sc->m = m; 39052419Sjulian } 39152419Sjulian 39252419Sjulian /* Add char to mbuf */ 39352419Sjulian *mtod(m, u_char *) = c; 39452419Sjulian m->m_data++; 39552419Sjulian m->m_len++; 39652419Sjulian m->m_pkthdr.len++; 39752419Sjulian 39852419Sjulian /* Ship off mbuf if it's time */ 39952419Sjulian if (sc->hotchar == -1 || c == sc->hotchar || m->m_len >= MHLEN) { 40052419Sjulian m->m_data = m->m_pktdat; 40152419Sjulian error = ng_queue_data(sc->hook, m, NULL); 40252419Sjulian sc->m = NULL; 40352419Sjulian } 40452419Sjuliandone: 40552419Sjulian splx(s); 40652419Sjulian return (error); 40752419Sjulian} 40852419Sjulian 40952419Sjulian/* 41052419Sjulian * This is called when the device driver is ready for more output. 41152419Sjulian * Called from tty system at splsofttty() or spltty(). 41252419Sjulian * Also call from ngt_rcv_data() when a new mbuf is available for output. 41352419Sjulian */ 41452419Sjulianstatic int 41552419Sjulianngt_start(struct tty *tp) 41652419Sjulian{ 41752419Sjulian const sc_p sc = (sc_p) tp->t_sc; 41852419Sjulian int s; 41952419Sjulian 42052419Sjulian s = spltty(); 42152419Sjulian while (tp->t_outq.c_cc < NGT_HIWATER) { /* XXX 2.2 specific ? */ 42252419Sjulian struct mbuf *m = sc->qhead; 42352419Sjulian 42452419Sjulian /* Remove first mbuf from queue */ 42552419Sjulian if (!m) 42652419Sjulian break; 42752419Sjulian if ((sc->qhead = m->m_nextpkt) == NULL) 42852419Sjulian sc->qtail = &sc->qhead; 42952419Sjulian sc->qlen--; 43052419Sjulian QUEUECHECK(sc); 43152419Sjulian 43252419Sjulian /* Send as much of it as possible */ 43352419Sjulian while (m) { 43452419Sjulian struct mbuf *m2; 43552419Sjulian int sent; 43652419Sjulian 43752419Sjulian sent = m->m_len 43852419Sjulian - b_to_q(mtod(m, u_char *), m->m_len, &tp->t_outq); 43952419Sjulian m->m_data += sent; 44052419Sjulian m->m_len -= sent; 44152419Sjulian if (m->m_len > 0) 44252419Sjulian break; /* device can't take no more */ 44352419Sjulian MFREE(m, m2); 44452419Sjulian m = m2; 44552419Sjulian } 44652419Sjulian 44752419Sjulian /* Put remainder of mbuf chain (if any) back on queue */ 44852419Sjulian if (m) { 44952419Sjulian m->m_nextpkt = sc->qhead; 45052419Sjulian sc->qhead = m; 45152419Sjulian if (sc->qtail == &sc->qhead) 45252419Sjulian sc->qtail = &m->m_nextpkt; 45352419Sjulian sc->qlen++; 45452419Sjulian QUEUECHECK(sc); 45552419Sjulian break; 45652419Sjulian } 45752419Sjulian } 45852419Sjulian 45952419Sjulian /* Call output process whether or not there is any output. We are 46052419Sjulian * being called in lieu of ttstart and must do what it would. */ 46152419Sjulian if (tp->t_oproc != NULL) 46252419Sjulian (*tp->t_oproc) (tp); 46352419Sjulian 46452419Sjulian /* This timeout is needed for operation on a pseudo-tty, because the 46552419Sjulian * pty code doesn't call pppstart after it has drained the t_outq. */ 46652419Sjulian if (sc->qhead && (sc->flags & FLG_TIMEOUT) == 0) { 46752419Sjulian sc->chand = timeout(ngt_timeout, sc, 1); 46852419Sjulian sc->flags |= FLG_TIMEOUT; 46952419Sjulian } 47052419Sjulian splx(s); 47152419Sjulian return (0); 47252419Sjulian} 47352419Sjulian 47452419Sjulian/* 47552419Sjulian * We still have data to output to the device, so try sending more. 47652419Sjulian */ 47752419Sjulianstatic void 47852419Sjulianngt_timeout(void *arg) 47952419Sjulian{ 48052419Sjulian const sc_p sc = (sc_p) arg; 48152419Sjulian int s; 48252419Sjulian 48352419Sjulian s = spltty(); 48452419Sjulian sc->flags &= ~FLG_TIMEOUT; 48552419Sjulian ngt_start(sc->tp); 48652419Sjulian splx(s); 48752419Sjulian} 48852419Sjulian 48952419Sjulian/****************************************************************** 49052419Sjulian NETGRAPH NODE METHODS 49152419Sjulian******************************************************************/ 49252419Sjulian 49352419Sjulian/* 49452419Sjulian * Initialize a new node of this type. 49552419Sjulian * 49652419Sjulian * We only allow nodes to be created as a result of setting 49752419Sjulian * the line discipline on a tty, so always return an error if not. 49852419Sjulian */ 49952419Sjulianstatic int 50052419Sjulianngt_constructor(node_p *nodep) 50152419Sjulian{ 50252419Sjulian if (!ngt_nodeop_ok) 50352419Sjulian return (EOPNOTSUPP); 50452419Sjulian return (ng_make_node_common(&typestruct, nodep)); 50552419Sjulian} 50652419Sjulian 50752419Sjulian/* 50852419Sjulian * Add a new hook. There can only be one. 50952419Sjulian */ 51052419Sjulianstatic int 51152419Sjulianngt_newhook(node_p node, hook_p hook, const char *name) 51252419Sjulian{ 51352419Sjulian const sc_p sc = node->private; 51452419Sjulian int s, error = 0; 51552419Sjulian 51652419Sjulian if (strcmp(name, NG_TTY_HOOK)) 51752419Sjulian return (EINVAL); 51852419Sjulian s = spltty(); 51952419Sjulian if (sc->hook) 52052419Sjulian ERROUT(EISCONN); 52152419Sjulian sc->hook = hook; 52252419Sjuliandone: 52352419Sjulian splx(s); 52452419Sjulian return (error); 52552419Sjulian} 52652419Sjulian 52752419Sjulian/* 52852419Sjulian * Disconnect the hook 52952419Sjulian */ 53052419Sjulianstatic int 53152419Sjulianngt_disconnect(hook_p hook) 53252419Sjulian{ 53352419Sjulian const sc_p sc = hook->node->private; 53452419Sjulian int s; 53552419Sjulian 53652419Sjulian s = spltty(); 53752419Sjulian if (hook != sc->hook) 53852419Sjulian panic(__FUNCTION__); 53952419Sjulian sc->hook = NULL; 54052419Sjulian m_freem(sc->m); 54152419Sjulian sc->m = NULL; 54252419Sjulian splx(s); 54352419Sjulian return (0); 54452419Sjulian} 54552419Sjulian 54652419Sjulian/* 54752419Sjulian * Remove this node. The does the netgraph portion of the shutdown. 54852419Sjulian * This should only be called indirectly from ngt_close(). 54952419Sjulian */ 55052419Sjulianstatic int 55152419Sjulianngt_shutdown(node_p node) 55252419Sjulian{ 55352419Sjulian const sc_p sc = node->private; 55452419Sjulian 55552419Sjulian if (!ngt_nodeop_ok) 55652419Sjulian return (EOPNOTSUPP); 55752419Sjulian ng_unname(node); 55852419Sjulian ng_cutlinks(node); 55952419Sjulian node->private = NULL; 56052419Sjulian ng_unref(sc->node); 56152419Sjulian m_freem(sc->qhead); 56252419Sjulian m_freem(sc->m); 56352419Sjulian bzero(sc, sizeof(*sc)); 56452419Sjulian FREE(sc, M_NETGRAPH); 56552419Sjulian return (0); 56652419Sjulian} 56752419Sjulian 56852419Sjulian/* 56952419Sjulian * Receive incoming data from netgraph system. Put it on our 57052419Sjulian * output queue and start output if necessary. 57152419Sjulian */ 57252419Sjulianstatic int 57352419Sjulianngt_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) 57452419Sjulian{ 57552419Sjulian const sc_p sc = hook->node->private; 57652419Sjulian int s, error = 0; 57752419Sjulian 57852419Sjulian if (hook != sc->hook) 57952419Sjulian panic(__FUNCTION__); 58052419Sjulian NG_FREE_META(meta); 58152419Sjulian s = spltty(); 58252419Sjulian if (sc->qlen >= MAX_MBUFQ) 58352419Sjulian ERROUT(ENOBUFS); 58452419Sjulian m->m_nextpkt = NULL; 58552419Sjulian *sc->qtail = m; 58652419Sjulian sc->qtail = &m->m_nextpkt; 58752419Sjulian sc->qlen++; 58852419Sjulian QUEUECHECK(sc); 58952419Sjulian m = NULL; 59052419Sjulian if (sc->qlen == 1) 59152419Sjulian ngt_start(sc->tp); 59252419Sjuliandone: 59352419Sjulian splx(s); 59452419Sjulian if (m) 59552419Sjulian m_freem(m); 59652419Sjulian return (error); 59752419Sjulian} 59852419Sjulian 59952419Sjulian/* 60052419Sjulian * Receive control message 60152419Sjulian */ 60252419Sjulianstatic int 60352419Sjulianngt_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr, 60452419Sjulian struct ng_mesg **rptr) 60552419Sjulian{ 60652419Sjulian const sc_p sc = (sc_p) node->private; 60752419Sjulian struct ng_mesg *resp = NULL; 60852419Sjulian int error = 0; 60952419Sjulian 61052419Sjulian switch (msg->header.typecookie) { 61152419Sjulian case NGM_TTY_COOKIE: 61252419Sjulian switch (msg->header.cmd) { 61352419Sjulian case NGM_TTY_SET_HOTCHAR: 61452419Sjulian { 61552419Sjulian int hotchar; 61652419Sjulian 61752419Sjulian if (msg->header.arglen != sizeof(int)) 61852419Sjulian ERROUT(EINVAL); 61952419Sjulian hotchar = *((int *) msg->data); 62052419Sjulian if (hotchar != (u_char) hotchar && hotchar != -1) 62152419Sjulian ERROUT(EINVAL); 62252419Sjulian sc->hotchar = hotchar; /* race condition is OK */ 62352419Sjulian break; 62452419Sjulian } 62552419Sjulian case NGM_TTY_GET_HOTCHAR: 62652419Sjulian NG_MKRESPONSE(resp, msg, sizeof(int), M_NOWAIT); 62752419Sjulian if (!resp) 62852419Sjulian ERROUT(ENOMEM); 62952419Sjulian /* Race condition here is OK */ 63052419Sjulian *((int *) resp->data) = sc->hotchar; 63152419Sjulian break; 63252419Sjulian default: 63352419Sjulian ERROUT(EINVAL); 63452419Sjulian } 63552419Sjulian break; 63652419Sjulian default: 63752419Sjulian ERROUT(EINVAL); 63852419Sjulian } 63952419Sjulian if (rptr) 64052419Sjulian *rptr = resp; 64152419Sjulian else if (resp) 64252419Sjulian FREE(resp, M_NETGRAPH); 64352419Sjulian 64452419Sjuliandone: 64552419Sjulian FREE(msg, M_NETGRAPH); 64652419Sjulian return (error); 64752419Sjulian} 64852419Sjulian 64952419Sjulian/****************************************************************** 65052419Sjulian INITIALIZATION 65152419Sjulian******************************************************************/ 65252419Sjulian 65352419Sjulian/* 65452419Sjulian * Handle loading and unloading for this node type 65552419Sjulian */ 65652419Sjulianstatic int 65752419Sjulianngt_mod_event(module_t mod, int event, void *data) 65852419Sjulian{ 65952442Sjulian /* struct ng_type *const type = data;*/ 66052419Sjulian int s, error = 0; 66152419Sjulian 66252419Sjulian switch (event) { 66352419Sjulian case MOD_LOAD: 66452419Sjulian#ifdef __i386__ 66552419Sjulian /* Insure the soft net "engine" can't run during spltty code */ 66652419Sjulian s = splhigh(); 66752419Sjulian tty_imask |= softnet_imask; /* spltty() block spl[soft]net() */ 66852419Sjulian net_imask |= softtty_imask; /* splimp() block splsofttty() */ 66952419Sjulian net_imask |= tty_imask; /* splimp() block spltty() */ 67052419Sjulian update_intr_masks(); 67152419Sjulian splx(s); 67252419Sjulian 67352419Sjulian if (bootverbose) 67452419Sjulian log(LOG_DEBUG, "new masks: bio %x, tty %x, net %x\n", 67552419Sjulian bio_imask, tty_imask, net_imask); 67652419Sjulian#endif 67752419Sjulian 67852419Sjulian /* Register line discipline */ 67952419Sjulian s = spltty(); 68052441Sjulian if ((ngt_ldisc = ldisc_register(NETGRAPHDISC, &ngt_disc)) < 0) { 68152419Sjulian splx(s); 68252419Sjulian log(LOG_ERR, "%s: can't register line discipline", 68352419Sjulian __FUNCTION__); 68452419Sjulian return (EIO); 68552419Sjulian } 68652419Sjulian splx(s); 68752419Sjulian break; 68852419Sjulian 68952419Sjulian case MOD_UNLOAD: 69052419Sjulian 69152419Sjulian /* Unregister line discipline */ 69252419Sjulian s = spltty(); 69352419Sjulian ldisc_deregister(ngt_ldisc); 69452419Sjulian splx(s); 69552419Sjulian break; 69652419Sjulian 69752419Sjulian default: 69852419Sjulian error = EOPNOTSUPP; 69952419Sjulian break; 70052419Sjulian } 70152419Sjulian return (error); 70252419Sjulian} 70352419Sjulian 704