ng_tty.c revision 83366
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 83366 2001-09-12 08:38:13Z 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/* Misc defs */ 7952419Sjulian#define MAX_MBUFQ 3 /* Max number of queued mbufs */ 8052419Sjulian#define NGT_HIWATER 400 /* High water mark on output */ 8152419Sjulian 8252419Sjulian/* Per-node private info */ 8352419Sjulianstruct ngt_sc { 8453913Sarchie struct tty *tp; /* Terminal device */ 8553913Sarchie node_p node; /* Netgraph node */ 8653913Sarchie hook_p hook; /* Netgraph hook */ 8753913Sarchie struct mbuf *m; /* Incoming data buffer */ 8853913Sarchie struct mbuf *qhead, **qtail; /* Queue of outgoing mbuf's */ 8953913Sarchie short qlen; /* Length of queue */ 9053913Sarchie short hotchar; /* Hotchar, or -1 if none */ 9153913Sarchie u_int flags; /* Flags */ 9253913Sarchie struct callout_handle chand; /* See man timeout(9) */ 9352419Sjulian}; 9452419Sjuliantypedef struct ngt_sc *sc_p; 9552419Sjulian 9652419Sjulian/* Flags */ 9752419Sjulian#define FLG_TIMEOUT 0x0001 /* A timeout is pending */ 9852419Sjulian#define FLG_DEBUG 0x0002 9952419Sjulian 10052419Sjulian/* Debugging */ 10153913Sarchie#ifdef INVARIANTS 10252419Sjulian#define QUEUECHECK(sc) \ 10352419Sjulian do { \ 10452419Sjulian struct mbuf **mp; \ 10552419Sjulian int k; \ 10652419Sjulian \ 10752419Sjulian for (k = 0, mp = &sc->qhead; \ 10852419Sjulian k <= MAX_MBUFQ && *mp; \ 10952419Sjulian k++, mp = &(*mp)->m_nextpkt); \ 11052419Sjulian if (k != sc->qlen || k > MAX_MBUFQ || *mp || mp != sc->qtail) \ 11152419Sjulian panic(__FUNCTION__ ": queue"); \ 11252419Sjulian } while (0) 11352419Sjulian#else 11452419Sjulian#define QUEUECHECK(sc) do {} while (0) 11552419Sjulian#endif 11652419Sjulian 11752419Sjulian/* Line discipline methods */ 11852419Sjulianstatic int ngt_open(dev_t dev, struct tty *tp); 11952419Sjulianstatic int ngt_close(struct tty *tp, int flag); 12052419Sjulianstatic int ngt_read(struct tty *tp, struct uio *uio, int flag); 12152419Sjulianstatic int ngt_write(struct tty *tp, struct uio *uio, int flag); 12252419Sjulianstatic int ngt_tioctl(struct tty *tp, 12383366Sjulian u_long cmd, caddr_t data, int flag, struct thread *); 12452419Sjulianstatic int ngt_input(int c, struct tty *tp); 12552419Sjulianstatic int ngt_start(struct tty *tp); 12652419Sjulian 12752419Sjulian/* Netgraph methods */ 12852752Sjulianstatic ng_constructor_t ngt_constructor; 12952752Sjulianstatic ng_rcvmsg_t ngt_rcvmsg; 13052752Sjulianstatic ng_shutdown_t ngt_shutdown; 13152752Sjulianstatic ng_newhook_t ngt_newhook; 13269922Sjulianstatic ng_connect_t ngt_connect; 13352752Sjulianstatic ng_rcvdata_t ngt_rcvdata; 13452752Sjulianstatic ng_disconnect_t ngt_disconnect; 13552419Sjulianstatic int ngt_mod_event(module_t mod, int event, void *data); 13652419Sjulian 13752419Sjulian/* Other stuff */ 13852419Sjulianstatic void ngt_timeout(void *arg); 13952419Sjulian 14052419Sjulian#define ERROUT(x) do { error = (x); goto done; } while (0) 14152419Sjulian 14252419Sjulian/* Line discipline descriptor */ 14352419Sjulianstatic struct linesw ngt_disc = { 14452419Sjulian ngt_open, 14552419Sjulian ngt_close, 14652419Sjulian ngt_read, 14752419Sjulian ngt_write, 14852419Sjulian ngt_tioctl, 14952419Sjulian ngt_input, 15052419Sjulian ngt_start, 15152419Sjulian ttymodem, 15252419Sjulian NG_TTY_DFL_HOTCHAR /* XXX can't change this in serial driver */ 15352419Sjulian}; 15452419Sjulian 15552419Sjulian/* Netgraph node type descriptor */ 15652419Sjulianstatic struct ng_type typestruct = { 15770159Sjulian NG_ABI_VERSION, 15852419Sjulian NG_TTY_NODE_TYPE, 15952419Sjulian ngt_mod_event, 16052419Sjulian ngt_constructor, 16152419Sjulian ngt_rcvmsg, 16252419Sjulian ngt_shutdown, 16352419Sjulian ngt_newhook, 16452419Sjulian NULL, 16569922Sjulian ngt_connect, 16652419Sjulian ngt_rcvdata, 16752419Sjulian ngt_disconnect, 16853913Sarchie NULL 16952419Sjulian}; 17052419SjulianNETGRAPH_INIT(tty, &typestruct); 17152419Sjulian 17252419Sjulianstatic int ngt_unit; 17352419Sjulianstatic int ngt_nodeop_ok; /* OK to create/remove node */ 17452442Sjulianstatic int ngt_ldisc; 17552419Sjulian 17652419Sjulian/****************************************************************** 17752419Sjulian LINE DISCIPLINE METHODS 17852419Sjulian******************************************************************/ 17952419Sjulian 18052419Sjulian/* 18152419Sjulian * Set our line discipline on the tty. 18252419Sjulian * Called from device open routine or ttioctl() at >= splsofttty() 18352419Sjulian */ 18452419Sjulianstatic int 18552419Sjulianngt_open(dev_t dev, struct tty *tp) 18652419Sjulian{ 18783366Sjulian struct thread *const td = curthread; /* XXX */ 18852419Sjulian char name[sizeof(NG_TTY_NODE_TYPE) + 8]; 18952419Sjulian sc_p sc; 19052419Sjulian int s, error; 19152419Sjulian 19252419Sjulian /* Super-user only */ 19383366Sjulian if ((error = suser_td(td))) 19452419Sjulian return (error); 19552419Sjulian s = splnet(); 19652419Sjulian (void) spltty(); /* XXX is this necessary? */ 19752419Sjulian 19852419Sjulian /* Already installed? */ 19952441Sjulian if (tp->t_line == NETGRAPHDISC) { 20052419Sjulian sc = (sc_p) tp->t_sc; 20152419Sjulian if (sc != NULL && sc->tp == tp) 20252419Sjulian goto done; 20352419Sjulian } 20452419Sjulian 20552419Sjulian /* Initialize private struct */ 20668876Sdwmalone MALLOC(sc, sc_p, sizeof(*sc), M_NETGRAPH, M_WAITOK | M_ZERO); 20752419Sjulian if (sc == NULL) { 20852419Sjulian error = ENOMEM; 20952419Sjulian goto done; 21052419Sjulian } 21152419Sjulian sc->tp = tp; 21252419Sjulian sc->hotchar = NG_TTY_DFL_HOTCHAR; 21352419Sjulian sc->qtail = &sc->qhead; 21452419Sjulian QUEUECHECK(sc); 21552419Sjulian callout_handle_init(&sc->chand); 21652419Sjulian 21752419Sjulian /* Setup netgraph node */ 21852419Sjulian ngt_nodeop_ok = 1; 21952419Sjulian error = ng_make_node_common(&typestruct, &sc->node); 22052419Sjulian ngt_nodeop_ok = 0; 22152419Sjulian if (error) { 22252419Sjulian FREE(sc, M_NETGRAPH); 22352419Sjulian goto done; 22452419Sjulian } 22558012Sarchie snprintf(name, sizeof(name), "%s%d", typestruct.name, ngt_unit++); 22652419Sjulian 22752419Sjulian /* Assign node its name */ 22852419Sjulian if ((error = ng_name_node(sc->node, name))) { 22952419Sjulian log(LOG_ERR, "%s: node name exists?\n", name); 23052419Sjulian ngt_nodeop_ok = 1; 23170784Sjulian NG_NODE_UNREF(sc->node); 23252419Sjulian ngt_nodeop_ok = 0; 23352419Sjulian goto done; 23452419Sjulian } 23552419Sjulian 23670700Sjulian /* Set back pointers */ 23770784Sjulian NG_NODE_SET_PRIVATE(sc->node, sc); 23870700Sjulian tp->t_sc = (caddr_t) sc; 23970700Sjulian 24052419Sjulian /* 24152419Sjulian * Pre-allocate cblocks to the an appropriate amount. 24252419Sjulian * I'm not sure what is appropriate. 24352419Sjulian */ 24452419Sjulian ttyflush(tp, FREAD | FWRITE); 24552419Sjulian clist_alloc_cblocks(&tp->t_canq, 0, 0); 24652419Sjulian clist_alloc_cblocks(&tp->t_rawq, 0, 0); 24752419Sjulian clist_alloc_cblocks(&tp->t_outq, 24852419Sjulian MLEN + NGT_HIWATER, MLEN + NGT_HIWATER); 24952419Sjulian 25052419Sjuliandone: 25152419Sjulian /* Done */ 25252419Sjulian splx(s); 25352419Sjulian return (error); 25452419Sjulian} 25552419Sjulian 25652419Sjulian/* 25752419Sjulian * Line specific close routine, called from device close routine 25852419Sjulian * and from ttioctl at >= splsofttty(). This causes the node to 25952419Sjulian * be destroyed as well. 26052419Sjulian */ 26152419Sjulianstatic int 26252419Sjulianngt_close(struct tty *tp, int flag) 26352419Sjulian{ 26452419Sjulian const sc_p sc = (sc_p) tp->t_sc; 26552419Sjulian int s; 26652419Sjulian 26752419Sjulian s = spltty(); 26852419Sjulian ttyflush(tp, FREAD | FWRITE); 26952419Sjulian clist_free_cblocks(&tp->t_outq); 27052419Sjulian tp->t_line = 0; 27152419Sjulian if (sc != NULL) { 27252419Sjulian if (sc->flags & FLG_TIMEOUT) { 27352419Sjulian untimeout(ngt_timeout, sc, sc->chand); 27452419Sjulian sc->flags &= ~FLG_TIMEOUT; 27552419Sjulian } 27652419Sjulian ngt_nodeop_ok = 1; 27770700Sjulian ng_rmnode_self(sc->node); 27852419Sjulian ngt_nodeop_ok = 0; 27952419Sjulian tp->t_sc = NULL; 28052419Sjulian } 28152419Sjulian splx(s); 28252419Sjulian return (0); 28352419Sjulian} 28452419Sjulian 28552419Sjulian/* 28652419Sjulian * Once the device has been turned into a node, we don't allow reading. 28752419Sjulian */ 28852419Sjulianstatic int 28952419Sjulianngt_read(struct tty *tp, struct uio *uio, int flag) 29052419Sjulian{ 29152419Sjulian return (EIO); 29252419Sjulian} 29352419Sjulian 29452419Sjulian/* 29552419Sjulian * Once the device has been turned into a node, we don't allow writing. 29652419Sjulian */ 29752419Sjulianstatic int 29852419Sjulianngt_write(struct tty *tp, struct uio *uio, int flag) 29952419Sjulian{ 30052419Sjulian return (EIO); 30152419Sjulian} 30252419Sjulian 30352419Sjulian/* 30452419Sjulian * We implement the NGIOCGINFO ioctl() defined in ng_message.h. 30552419Sjulian */ 30652419Sjulianstatic int 30783366Sjulianngt_tioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct thread *td) 30852419Sjulian{ 30952419Sjulian const sc_p sc = (sc_p) tp->t_sc; 31052419Sjulian int s, error = 0; 31152419Sjulian 31252419Sjulian s = spltty(); 31352419Sjulian switch (cmd) { 31452419Sjulian case NGIOCGINFO: 31552419Sjulian { 31652419Sjulian struct nodeinfo *const ni = (struct nodeinfo *) data; 31752419Sjulian const node_p node = sc->node; 31852419Sjulian 31952419Sjulian bzero(ni, sizeof(*ni)); 32070784Sjulian if (NG_NODE_HAS_NAME(node)) 32170784Sjulian strncpy(ni->name, NG_NODE_NAME(node), sizeof(ni->name) - 1); 32270784Sjulian strncpy(ni->type, node->nd_type->name, sizeof(ni->type) - 1); 32370784Sjulian ni->id = (u_int32_t) ng_node2ID(node); 32470784Sjulian ni->hooks = NG_NODE_NUMHOOKS(node); 32552419Sjulian break; 32652419Sjulian } 32752419Sjulian default: 32852419Sjulian ERROUT(ENOIOCTL); 32952419Sjulian } 33052419Sjuliandone: 33152419Sjulian splx(s); 33252419Sjulian return (error); 33352419Sjulian} 33452419Sjulian 33552419Sjulian/* 33652419Sjulian * Receive data coming from the device. We get one character at 33752419Sjulian * a time, which is kindof silly. 33852419Sjulian * Only guaranteed to be at splsofttty() or spltty(). 33952419Sjulian */ 34052419Sjulianstatic int 34152419Sjulianngt_input(int c, struct tty *tp) 34252419Sjulian{ 34352419Sjulian const sc_p sc = (sc_p) tp->t_sc; 34452419Sjulian const node_p node = sc->node; 34552419Sjulian struct mbuf *m; 34652419Sjulian int s, error = 0; 34752419Sjulian 34852419Sjulian if (!sc || tp != sc->tp) 34952419Sjulian return (0); 35052419Sjulian s = spltty(); 35152419Sjulian if (!sc->hook) 35252419Sjulian ERROUT(0); 35352419Sjulian 35452419Sjulian /* Check for error conditions */ 35552419Sjulian if ((tp->t_state & TS_CONNECTED) == 0) { 35652419Sjulian if (sc->flags & FLG_DEBUG) 35770784Sjulian log(LOG_DEBUG, "%s: no carrier\n", NG_NODE_NAME(node)); 35852419Sjulian ERROUT(0); 35952419Sjulian } 36052419Sjulian if (c & TTY_ERRORMASK) { 36152419Sjulian /* framing error or overrun on this char */ 36252419Sjulian if (sc->flags & FLG_DEBUG) 36352419Sjulian log(LOG_DEBUG, "%s: line error %x\n", 36470784Sjulian NG_NODE_NAME(node), c & TTY_ERRORMASK); 36552419Sjulian ERROUT(0); 36652419Sjulian } 36752419Sjulian c &= TTY_CHARMASK; 36852419Sjulian 36952419Sjulian /* Get a new header mbuf if we need one */ 37052419Sjulian if (!(m = sc->m)) { 37152419Sjulian MGETHDR(m, M_DONTWAIT, MT_DATA); 37252419Sjulian if (!m) { 37352419Sjulian if (sc->flags & FLG_DEBUG) 37452419Sjulian log(LOG_ERR, 37570784Sjulian "%s: can't get mbuf\n", NG_NODE_NAME(node)); 37652419Sjulian ERROUT(ENOBUFS); 37752419Sjulian } 37853284Sarchie m->m_len = m->m_pkthdr.len = 0; 37953284Sarchie m->m_pkthdr.rcvif = NULL; 38052419Sjulian sc->m = m; 38152419Sjulian } 38252419Sjulian 38352419Sjulian /* Add char to mbuf */ 38452419Sjulian *mtod(m, u_char *) = c; 38552419Sjulian m->m_data++; 38652419Sjulian m->m_len++; 38752419Sjulian m->m_pkthdr.len++; 38852419Sjulian 38952419Sjulian /* Ship off mbuf if it's time */ 39052419Sjulian if (sc->hotchar == -1 || c == sc->hotchar || m->m_len >= MHLEN) { 39152419Sjulian m->m_data = m->m_pktdat; 39269922Sjulian NG_SEND_DATA_ONLY(error, sc->hook, m); 39352419Sjulian sc->m = NULL; 39452419Sjulian } 39552419Sjuliandone: 39652419Sjulian splx(s); 39752419Sjulian return (error); 39852419Sjulian} 39952419Sjulian 40052419Sjulian/* 40152419Sjulian * This is called when the device driver is ready for more output. 40252419Sjulian * Called from tty system at splsofttty() or spltty(). 40352419Sjulian * Also call from ngt_rcv_data() when a new mbuf is available for output. 40452419Sjulian */ 40552419Sjulianstatic int 40652419Sjulianngt_start(struct tty *tp) 40752419Sjulian{ 40852419Sjulian const sc_p sc = (sc_p) tp->t_sc; 40952419Sjulian int s; 41052419Sjulian 41152419Sjulian s = spltty(); 41252419Sjulian while (tp->t_outq.c_cc < NGT_HIWATER) { /* XXX 2.2 specific ? */ 41352419Sjulian struct mbuf *m = sc->qhead; 41452419Sjulian 41552419Sjulian /* Remove first mbuf from queue */ 41652419Sjulian if (!m) 41752419Sjulian break; 41852419Sjulian if ((sc->qhead = m->m_nextpkt) == NULL) 41952419Sjulian sc->qtail = &sc->qhead; 42052419Sjulian sc->qlen--; 42152419Sjulian QUEUECHECK(sc); 42252419Sjulian 42352419Sjulian /* Send as much of it as possible */ 42452419Sjulian while (m) { 42552419Sjulian struct mbuf *m2; 42652419Sjulian int sent; 42752419Sjulian 42852419Sjulian sent = m->m_len 42952419Sjulian - b_to_q(mtod(m, u_char *), m->m_len, &tp->t_outq); 43052419Sjulian m->m_data += sent; 43152419Sjulian m->m_len -= sent; 43252419Sjulian if (m->m_len > 0) 43352419Sjulian break; /* device can't take no more */ 43452419Sjulian MFREE(m, m2); 43552419Sjulian m = m2; 43652419Sjulian } 43752419Sjulian 43852419Sjulian /* Put remainder of mbuf chain (if any) back on queue */ 43952419Sjulian if (m) { 44052419Sjulian m->m_nextpkt = sc->qhead; 44152419Sjulian sc->qhead = m; 44252419Sjulian if (sc->qtail == &sc->qhead) 44352419Sjulian sc->qtail = &m->m_nextpkt; 44452419Sjulian sc->qlen++; 44552419Sjulian QUEUECHECK(sc); 44652419Sjulian break; 44752419Sjulian } 44852419Sjulian } 44952419Sjulian 45052419Sjulian /* Call output process whether or not there is any output. We are 45152419Sjulian * being called in lieu of ttstart and must do what it would. */ 45252419Sjulian if (tp->t_oproc != NULL) 45352419Sjulian (*tp->t_oproc) (tp); 45452419Sjulian 45552419Sjulian /* This timeout is needed for operation on a pseudo-tty, because the 45652419Sjulian * pty code doesn't call pppstart after it has drained the t_outq. */ 45752419Sjulian if (sc->qhead && (sc->flags & FLG_TIMEOUT) == 0) { 45852419Sjulian sc->chand = timeout(ngt_timeout, sc, 1); 45952419Sjulian sc->flags |= FLG_TIMEOUT; 46052419Sjulian } 46152419Sjulian splx(s); 46252419Sjulian return (0); 46352419Sjulian} 46452419Sjulian 46552419Sjulian/* 46652419Sjulian * We still have data to output to the device, so try sending more. 46752419Sjulian */ 46852419Sjulianstatic void 46952419Sjulianngt_timeout(void *arg) 47052419Sjulian{ 47152419Sjulian const sc_p sc = (sc_p) arg; 47252419Sjulian int s; 47352419Sjulian 47452419Sjulian s = spltty(); 47552419Sjulian sc->flags &= ~FLG_TIMEOUT; 47652419Sjulian ngt_start(sc->tp); 47752419Sjulian splx(s); 47852419Sjulian} 47952419Sjulian 48052419Sjulian/****************************************************************** 48152419Sjulian NETGRAPH NODE METHODS 48252419Sjulian******************************************************************/ 48352419Sjulian 48452419Sjulian/* 48552419Sjulian * Initialize a new node of this type. 48652419Sjulian * 48752419Sjulian * We only allow nodes to be created as a result of setting 48852419Sjulian * the line discipline on a tty, so always return an error if not. 48952419Sjulian */ 49052419Sjulianstatic int 49170700Sjulianngt_constructor(node_p node) 49252419Sjulian{ 49370700Sjulian return (EOPNOTSUPP); 49452419Sjulian} 49552419Sjulian 49652419Sjulian/* 49752419Sjulian * Add a new hook. There can only be one. 49852419Sjulian */ 49952419Sjulianstatic int 50052419Sjulianngt_newhook(node_p node, hook_p hook, const char *name) 50152419Sjulian{ 50270784Sjulian const sc_p sc = NG_NODE_PRIVATE(node); 50352419Sjulian int s, error = 0; 50452419Sjulian 50552419Sjulian if (strcmp(name, NG_TTY_HOOK)) 50652419Sjulian return (EINVAL); 50752419Sjulian s = spltty(); 50852419Sjulian if (sc->hook) 50952419Sjulian ERROUT(EISCONN); 51052419Sjulian sc->hook = hook; 51152419Sjuliandone: 51252419Sjulian splx(s); 51352419Sjulian return (error); 51452419Sjulian} 51552419Sjulian 51652419Sjulian/* 51770700Sjulian * Set the hooks into queueing mode (for outgoing packets) 51870700Sjulian * Force single client at a time. 51969922Sjulian */ 52069922Sjulianstatic int 52169922Sjulianngt_connect(hook_p hook) 52269922Sjulian{ 52370784Sjulian /*NG_HOOK_FORCE_WRITER(hook); 52470784Sjulian NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));*/ 52569922Sjulian return (0); 52669922Sjulian} 52769922Sjulian 52869922Sjulian/* 52952419Sjulian * Disconnect the hook 53052419Sjulian */ 53152419Sjulianstatic int 53252419Sjulianngt_disconnect(hook_p hook) 53352419Sjulian{ 53470784Sjulian const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 53552419Sjulian int s; 53652419Sjulian 53752419Sjulian s = spltty(); 53852419Sjulian if (hook != sc->hook) 53952419Sjulian panic(__FUNCTION__); 54052419Sjulian sc->hook = NULL; 54152419Sjulian m_freem(sc->m); 54252419Sjulian sc->m = NULL; 54352419Sjulian splx(s); 54452419Sjulian return (0); 54552419Sjulian} 54652419Sjulian 54752419Sjulian/* 54852419Sjulian * Remove this node. The does the netgraph portion of the shutdown. 54952419Sjulian * This should only be called indirectly from ngt_close(). 55052419Sjulian */ 55152419Sjulianstatic int 55252419Sjulianngt_shutdown(node_p node) 55352419Sjulian{ 55470784Sjulian const sc_p sc = NG_NODE_PRIVATE(node); 55552419Sjulian 55652419Sjulian if (!ngt_nodeop_ok) 55752419Sjulian return (EOPNOTSUPP); 55870784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 55970784Sjulian NG_NODE_UNREF(sc->node); 56052419Sjulian m_freem(sc->qhead); 56152419Sjulian m_freem(sc->m); 56252419Sjulian bzero(sc, sizeof(*sc)); 56352419Sjulian FREE(sc, M_NETGRAPH); 56452419Sjulian return (0); 56552419Sjulian} 56652419Sjulian 56752419Sjulian/* 56852419Sjulian * Receive incoming data from netgraph system. Put it on our 56952419Sjulian * output queue and start output if necessary. 57052419Sjulian */ 57152419Sjulianstatic int 57270700Sjulianngt_rcvdata(hook_p hook, item_p item) 57352419Sjulian{ 57470784Sjulian const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 57552419Sjulian int s, error = 0; 57670700Sjulian struct mbuf *m; 57752419Sjulian 57852419Sjulian if (hook != sc->hook) 57952419Sjulian panic(__FUNCTION__); 58070700Sjulian 58170700Sjulian NGI_GET_M(item, m); 58270700Sjulian NG_FREE_ITEM(item); 58352419Sjulian s = spltty(); 58452419Sjulian if (sc->qlen >= MAX_MBUFQ) 58552419Sjulian ERROUT(ENOBUFS); 58652419Sjulian m->m_nextpkt = NULL; 58752419Sjulian *sc->qtail = m; 58852419Sjulian sc->qtail = &m->m_nextpkt; 58952419Sjulian sc->qlen++; 59052419Sjulian QUEUECHECK(sc); 59152419Sjulian m = NULL; 59252419Sjulian if (sc->qlen == 1) 59352419Sjulian ngt_start(sc->tp); 59452419Sjuliandone: 59552419Sjulian splx(s); 59652419Sjulian if (m) 59752419Sjulian m_freem(m); 59852419Sjulian return (error); 59952419Sjulian} 60052419Sjulian 60152419Sjulian/* 60252419Sjulian * Receive control message 60352419Sjulian */ 60452419Sjulianstatic int 60570700Sjulianngt_rcvmsg(node_p node, item_p item, hook_p lasthook) 60652419Sjulian{ 60770784Sjulian const sc_p sc = NG_NODE_PRIVATE(node); 60852419Sjulian struct ng_mesg *resp = NULL; 60952419Sjulian int error = 0; 61070700Sjulian struct ng_mesg *msg; 61152419Sjulian 61270700Sjulian NGI_GET_MSG(item, msg); 61352419Sjulian switch (msg->header.typecookie) { 61452419Sjulian case NGM_TTY_COOKIE: 61552419Sjulian switch (msg->header.cmd) { 61652419Sjulian case NGM_TTY_SET_HOTCHAR: 61752419Sjulian { 61852419Sjulian int hotchar; 61952419Sjulian 62052419Sjulian if (msg->header.arglen != sizeof(int)) 62152419Sjulian ERROUT(EINVAL); 62252419Sjulian hotchar = *((int *) msg->data); 62352419Sjulian if (hotchar != (u_char) hotchar && hotchar != -1) 62452419Sjulian ERROUT(EINVAL); 62552419Sjulian sc->hotchar = hotchar; /* race condition is OK */ 62652419Sjulian break; 62752419Sjulian } 62852419Sjulian case NGM_TTY_GET_HOTCHAR: 62952419Sjulian NG_MKRESPONSE(resp, msg, sizeof(int), M_NOWAIT); 63052419Sjulian if (!resp) 63152419Sjulian ERROUT(ENOMEM); 63252419Sjulian /* Race condition here is OK */ 63352419Sjulian *((int *) resp->data) = sc->hotchar; 63452419Sjulian break; 63552419Sjulian default: 63652419Sjulian ERROUT(EINVAL); 63752419Sjulian } 63852419Sjulian break; 63952419Sjulian default: 64052419Sjulian ERROUT(EINVAL); 64152419Sjulian } 64252419Sjuliandone: 64370700Sjulian NG_RESPOND_MSG(error, node, item, resp); 64470700Sjulian NG_FREE_MSG(msg); 64552419Sjulian return (error); 64652419Sjulian} 64752419Sjulian 64852419Sjulian/****************************************************************** 64952419Sjulian INITIALIZATION 65052419Sjulian******************************************************************/ 65152419Sjulian 65252419Sjulian/* 65352419Sjulian * Handle loading and unloading for this node type 65452419Sjulian */ 65552419Sjulianstatic int 65652419Sjulianngt_mod_event(module_t mod, int event, void *data) 65752419Sjulian{ 65852442Sjulian /* struct ng_type *const type = data;*/ 65952419Sjulian int s, error = 0; 66052419Sjulian 66152419Sjulian switch (event) { 66252419Sjulian case MOD_LOAD: 66352419Sjulian 66452419Sjulian /* Register line discipline */ 66552419Sjulian s = spltty(); 66652441Sjulian if ((ngt_ldisc = ldisc_register(NETGRAPHDISC, &ngt_disc)) < 0) { 66752419Sjulian splx(s); 66852419Sjulian log(LOG_ERR, "%s: can't register line discipline", 66952419Sjulian __FUNCTION__); 67052419Sjulian return (EIO); 67152419Sjulian } 67252419Sjulian splx(s); 67352419Sjulian break; 67452419Sjulian 67552419Sjulian case MOD_UNLOAD: 67652419Sjulian 67752419Sjulian /* Unregister line discipline */ 67852419Sjulian s = spltty(); 67952419Sjulian ldisc_deregister(ngt_ldisc); 68052419Sjulian splx(s); 68152419Sjulian break; 68252419Sjulian 68352419Sjulian default: 68452419Sjulian error = EOPNOTSUPP; 68552419Sjulian break; 68652419Sjulian } 68752419Sjulian return (error); 68852419Sjulian} 68952419Sjulian 690