ng_tty.c revision 213794
117680Spst/* 217680Spst * ng_tty.c 317680Spst */ 417680Spst 517680Spst/*- 617680Spst * Copyright (c) 1996-1999 Whistle Communications, Inc. 717680Spst * All rights reserved. 817680Spst * 917680Spst * Subject to the following obligations and disclaimer of warranty, use and 1017680Spst * redistribution of this software, in source or object code forms, with or 1117680Spst * without modifications are expressly permitted by Whistle Communications; 1217680Spst * provided, however, that: 1317680Spst * 1. Any and all reproductions of the source or object code must include the 1417680Spst * copyright notice above and the following disclaimer of warranties; and 1517680Spst * 2. No rights are granted, in any manner or form, to use Whistle 1617680Spst * Communications, Inc. trademarks, including the mark "WHISTLE 1717680Spst * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1817680Spst * such appears in the above copyright notice or in the software. 1917680Spst * 2057278Sfenner * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2157278Sfenner * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2217680Spst * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2317680Spst * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2417680Spst * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 25127675Sbms * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 26190207Srpaulo * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2717680Spst * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2817680Spst * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2956893Sfenner * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 3056893Sfenner * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3156893Sfenner * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3256893Sfenner * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 33127675Sbms * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34235530Sdelphij * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35235530Sdelphij * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 36235530Sdelphij * OF SUCH DAMAGE. 37235530Sdelphij * 38146778Ssam * Author: Archie Cobbs <archie@freebsd.org> 39235530Sdelphij * 40235530Sdelphij * Updated by Andrew Thompson <thompsa@FreeBSD.org> for MPSAFE TTY. 4117680Spst * 42235530Sdelphij * $FreeBSD: head/sys/netgraph/ng_tty.c 213794 2010-10-13 17:21:21Z rpaulo $ 43235530Sdelphij * $Whistle: ng_tty.c,v 1.21 1999/11/01 09:24:52 julian Exp $ 44146778Ssam */ 45146778Ssam 46146778Ssam/* 47146778Ssam * This file implements TTY hooks to link in to the netgraph system. The node 48146778Ssam * is created and then passed the callers opened TTY file descriptor number to 49146778Ssam * NGM_TTY_SET_TTY, this will hook the tty via ttyhook_register(). 50146778Ssam * 51146778Ssam * Incoming data is delivered directly to ng_tty via the TTY bypass hook as a 52146778Ssam * buffer pointer and length, this is converted to a mbuf and passed to the 53146778Ssam * peer. 54146778Ssam * 55146778Ssam * If the TTY device does not support bypass then incoming characters are 56146778Ssam * delivered to the hook one at a time, each in its own mbuf. You may 57146778Ssam * optionally define a ``hotchar,'' which causes incoming characters to be 58146778Ssam * buffered up until either the hotchar is seen or the mbuf is full (MHLEN 59146778Ssam * bytes). Then all buffered characters are immediately delivered. 60146778Ssam */ 61146778Ssam 62146778Ssam#include <sys/param.h> 63146778Ssam#include <sys/systm.h> 64146778Ssam#include <sys/conf.h> 65146778Ssam#include <sys/errno.h> 66146778Ssam#include <sys/fcntl.h> 67146778Ssam#include <sys/ioccom.h> 68146778Ssam#include <sys/kernel.h> 69146778Ssam#include <sys/malloc.h> 70146778Ssam#include <sys/mbuf.h> 71146778Ssam#include <sys/priv.h> 72146778Ssam#include <sys/socket.h> 73146778Ssam#include <sys/syslog.h> 74146778Ssam#include <sys/tty.h> 75146778Ssam#include <sys/ttycom.h> 76146778Ssam#include <sys/proc.h> 77146778Ssam 78146778Ssam#include <net/if.h> 79146778Ssam#include <net/if_var.h> 80146778Ssam 81146778Ssam#include <netgraph/ng_message.h> 82146778Ssam#include <netgraph/netgraph.h> 83146778Ssam#include <netgraph/ng_tty.h> 84146778Ssam 85146778Ssam/* Per-node private info */ 86146778Ssamstruct ngt_softc { 87146778Ssam struct tty *tp; /* Terminal device */ 88146778Ssam node_p node; /* Netgraph node */ 89146778Ssam hook_p hook; /* Netgraph hook */ 90146778Ssam struct ifqueue outq; /* Queue of outgoing data */ 91146778Ssam size_t outqlen; /* Number of bytes in outq */ 92172686Smlaier struct mbuf *m; /* Incoming non-bypass data buffer */ 93172686Smlaier short hotchar; /* Hotchar, or -1 if none */ 94172686Smlaier u_int flags; /* Flags */ 95146778Ssam}; 96172686Smlaiertypedef struct ngt_softc *sc_p; 97172686Smlaier 98172686Smlaier/* Flags */ 99172686Smlaier#define FLG_DEBUG 0x0002 100172686Smlaier 101172686Smlaier/* Netgraph methods */ 10256893Sfennerstatic ng_constructor_t ngt_constructor; 10356893Sfennerstatic ng_rcvmsg_t ngt_rcvmsg; 10456893Sfennerstatic ng_shutdown_t ngt_shutdown; 10556893Sfennerstatic ng_newhook_t ngt_newhook; 10656893Sfennerstatic ng_connect_t ngt_connect; 10756893Sfennerstatic ng_rcvdata_t ngt_rcvdata; 10856893Sfennerstatic ng_disconnect_t ngt_disconnect; 10957278Sfenner 11057278Sfenner#define ERROUT(x) do { error = (x); goto done; } while (0) 11156893Sfenner 11256893Sfennerstatic th_getc_inject_t ngt_getc_inject; 11356893Sfennerstatic th_getc_poll_t ngt_getc_poll; 11456893Sfennerstatic th_rint_t ngt_rint; 11557278Sfennerstatic th_rint_bypass_t ngt_rint_bypass; 11657278Sfennerstatic th_rint_poll_t ngt_rint_poll; 11756893Sfenner 11856893Sfennerstatic struct ttyhook ngt_hook = { 11956893Sfenner .th_getc_inject = ngt_getc_inject, 12056893Sfenner .th_getc_poll = ngt_getc_poll, 121214478Srpaulo .th_rint = ngt_rint, 12256893Sfenner .th_rint_bypass = ngt_rint_bypass, 12356893Sfenner .th_rint_poll = ngt_rint_poll, 12456893Sfenner}; 12556893Sfenner 12698527Sfenner/* Netgraph node type descriptor */ 12798527Sfennerstatic struct ng_type typestruct = { 12856893Sfenner .version = NG_ABI_VERSION, 12998527Sfenner .name = NG_TTY_NODE_TYPE, 13098527Sfenner .constructor = ngt_constructor, 13198527Sfenner .rcvmsg = ngt_rcvmsg, 13298527Sfenner .shutdown = ngt_shutdown, 13356893Sfenner .newhook = ngt_newhook, 13498527Sfenner .connect = ngt_connect, 13598527Sfenner .rcvdata = ngt_rcvdata, 13698527Sfenner .disconnect = ngt_disconnect, 13798527Sfenner}; 13898527SfennerNETGRAPH_INIT(tty, &typestruct); 13998527Sfenner 14098527Sfenner#define NGTLOCK(sc) IF_LOCK(&sc->outq) 14198527Sfenner#define NGTUNLOCK(sc) IF_UNLOCK(&sc->outq) 14298527Sfenner 14398527Sfenner/****************************************************************** 14498527Sfenner NETGRAPH NODE METHODS 14598527Sfenner******************************************************************/ 14656893Sfenner 14756893Sfenner/* 14856893Sfenner * Initialize a new node of this type. 14998527Sfenner * 15098527Sfenner * We only allow nodes to be created as a result of setting 15156893Sfenner * the line discipline on a tty, so always return an error if not. 152162021Ssam */ 15398527Sfennerstatic int 15498527Sfennerngt_constructor(node_p node) 15598527Sfenner{ 15698527Sfenner sc_p sc; 15798527Sfenner 15898527Sfenner /* Allocate private structure */ 15998527Sfenner sc = malloc(sizeof(*sc), M_NETGRAPH, M_NOWAIT | M_ZERO); 16098527Sfenner if (sc == NULL) 16198527Sfenner return (ENOMEM); 16298527Sfenner 16398527Sfenner NG_NODE_SET_PRIVATE(node, sc); 16498527Sfenner sc->node = node; 16556893Sfenner 16698527Sfenner mtx_init(&sc->outq.ifq_mtx, "ng_tty node+queue", NULL, MTX_DEF); 16798527Sfenner IFQ_SET_MAXLEN(&sc->outq, ifqmaxlen); 16898527Sfenner 16998527Sfenner return (0); 17098527Sfenner} 17198527Sfenner 17298527Sfenner/* 173147904Ssam * Add a new hook. There can only be one. 174147904Ssam */ 175147904Ssamstatic int 176147904Ssamngt_newhook(node_p node, hook_p hook, const char *name) 177162021Ssam{ 17898527Sfenner const sc_p sc = NG_NODE_PRIVATE(node); 179162021Ssam 18098527Sfenner if (strcmp(name, NG_TTY_HOOK)) 18198527Sfenner return (EINVAL); 18298527Sfenner 18398527Sfenner if (sc->hook) 18498527Sfenner return (EISCONN); 18598527Sfenner 18698527Sfenner NGTLOCK(sc); 18798527Sfenner sc->hook = hook; 18898527Sfenner NGTUNLOCK(sc); 189127675Sbms 19098527Sfenner return (0); 19198527Sfenner} 19298527Sfenner 19398527Sfenner/* 19498527Sfenner * Set the hook into queueing mode (for outgoing packets), 19598527Sfenner * so that we wont deliver mbuf thru the whole graph holding 19698527Sfenner * tty locks. 19756893Sfenner */ 19856893Sfennerstatic int 19956893Sfennerngt_connect(hook_p hook) 20098527Sfenner{ 20198527Sfenner NG_HOOK_FORCE_QUEUE(hook); 20298527Sfenner return (0); 20398527Sfenner} 20456893Sfenner 20598527Sfenner/* 20656893Sfenner * Disconnect the hook 20798527Sfenner */ 20898527Sfennerstatic int 20956893Sfennerngt_disconnect(hook_p hook) 21056893Sfenner{ 21117680Spst const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 21256893Sfenner 21317680Spst if (hook != sc->hook) 21498527Sfenner panic("%s", __func__); 21598527Sfenner 21617680Spst NGTLOCK(sc); 21798527Sfenner sc->hook = NULL; 21898527Sfenner NGTUNLOCK(sc); 21998527Sfenner 22017680Spst return (0); 221127675Sbms} 22298527Sfenner 22317680Spst/* 22498527Sfenner * Remove this node. The does the netgraph portion of the shutdown. 22598527Sfenner */ 22698527Sfennerstatic int 22798527Sfennerngt_shutdown(node_p node) 22898527Sfenner{ 22998527Sfenner const sc_p sc = NG_NODE_PRIVATE(node); 23098527Sfenner struct tty *tp; 23156893Sfenner 23298527Sfenner tp = sc->tp; 23398527Sfenner if (tp != NULL) { 23456893Sfenner tty_lock(tp); 23598527Sfenner ttyhook_unregister(tp); 23698527Sfenner } 23756893Sfenner /* Free resources */ 23898527Sfenner IF_DRAIN(&sc->outq); 23998527Sfenner mtx_destroy(&(sc)->outq.ifq_mtx); 24056893Sfenner NG_NODE_UNREF(sc->node); 24198527Sfenner free(sc, M_NETGRAPH); 24256893Sfenner 24398527Sfenner return (0); 24498527Sfenner} 24598527Sfenner 24698527Sfenner/* 24798527Sfenner * Receive control message 24898527Sfenner */ 24998527Sfennerstatic int 25017680Spstngt_rcvmsg(node_p node, item_p item, hook_p lasthook) 25198527Sfenner{ 25298527Sfenner struct proc *p; 25398527Sfenner const sc_p sc = NG_NODE_PRIVATE(node); 25498527Sfenner struct ng_mesg *msg, *resp = NULL; 25598527Sfenner int error = 0; 25698527Sfenner 25798527Sfenner NGI_GET_MSG(item, msg); 25898527Sfenner switch (msg->header.typecookie) { 259162021Ssam case NGM_TTY_COOKIE: 26098527Sfenner switch (msg->header.cmd) { 26198527Sfenner case NGM_TTY_SET_TTY: 26298527Sfenner if (sc->tp != NULL) 26398527Sfenner return (EBUSY); 26498527Sfenner 26598527Sfenner p = pfind(((int *)msg->data)[0]); 26698527Sfenner if (p == NULL || (p->p_flag & P_WEXIT)) 26798527Sfenner return (ESRCH); 26898527Sfenner _PHOLD(p); 26998527Sfenner PROC_UNLOCK(p); 27098527Sfenner error = ttyhook_register(&sc->tp, p, ((int *)msg->data)[1], 27198527Sfenner &ngt_hook, sc); 27298527Sfenner PRELE(p); 27356893Sfenner if (error != 0) 27498527Sfenner return (error); 27598527Sfenner break; 27698527Sfenner case NGM_TTY_SET_HOTCHAR: 27798527Sfenner { 27898527Sfenner int hotchar; 27998527Sfenner 28098527Sfenner if (msg->header.arglen != sizeof(int)) 28198527Sfenner ERROUT(EINVAL); 282162021Ssam hotchar = *((int *) msg->data); 28398527Sfenner if (hotchar != (u_char) hotchar && hotchar != -1) 28498527Sfenner ERROUT(EINVAL); 28556893Sfenner sc->hotchar = hotchar; /* race condition is OK */ 28656893Sfenner break; 28798527Sfenner } 28898527Sfenner case NGM_TTY_GET_HOTCHAR: 28998527Sfenner NG_MKRESPONSE(resp, msg, sizeof(int), M_NOWAIT); 29056893Sfenner if (!resp) 29156893Sfenner ERROUT(ENOMEM); 29298527Sfenner /* Race condition here is OK */ 29398527Sfenner *((int *) resp->data) = sc->hotchar; 29498527Sfenner break; 29598527Sfenner default: 29698527Sfenner ERROUT(EINVAL); 29798527Sfenner } 29898527Sfenner break; 29998527Sfenner default: 30098527Sfenner ERROUT(EINVAL); 30198527Sfenner } 30298527Sfennerdone: 30398527Sfenner NG_RESPOND_MSG(error, node, item, resp); 30498527Sfenner NG_FREE_MSG(msg); 30598527Sfenner return (error); 30698527Sfenner} 30798527Sfenner 30898527Sfenner/* 30956893Sfenner * Receive incoming data from netgraph system. Put it on our 31098527Sfenner * output queue and start output if necessary. 31198527Sfenner */ 31298527Sfennerstatic int 31317680Spstngt_rcvdata(hook_p hook, item_p item) 31456893Sfenner{ 31598527Sfenner const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 31698527Sfenner struct tty *tp = sc->tp; 31717680Spst struct mbuf *m; 31856893Sfenner 31956893Sfenner if (hook != sc->hook) 32056893Sfenner panic("%s", __func__); 32198527Sfenner 32298527Sfenner NGI_GET_M(item, m); 32398527Sfenner NG_FREE_ITEM(item); 32456893Sfenner 32556893Sfenner if (tp == NULL) { 32656893Sfenner NG_FREE_M(m); 32756893Sfenner return (ENXIO); 32898527Sfenner } 32998527Sfenner 33098527Sfenner IF_LOCK(&sc->outq); 33156893Sfenner if (_IF_QFULL(&sc->outq)) { 33298527Sfenner _IF_DROP(&sc->outq); 33398527Sfenner IF_UNLOCK(&sc->outq); 33498527Sfenner NG_FREE_M(m); 33598527Sfenner return (ENOBUFS); 33698527Sfenner } 33798527Sfenner 33898527Sfenner _IF_ENQUEUE(&sc->outq, m); 33998527Sfenner sc->outqlen += m->m_pkthdr.len; 34098527Sfenner IF_UNLOCK(&sc->outq); 34198527Sfenner 34298527Sfenner /* notify the TTY that data is ready */ 34398527Sfenner tty_lock(tp); 34498527Sfenner if (!tty_gone(tp)) 34598527Sfenner ttydevsw_outwakeup(tp); 34656893Sfenner tty_unlock(tp); 34798527Sfenner 34898527Sfenner return (0); 34956893Sfenner} 35098527Sfenner 35198527Sfennerstatic size_t 35298527Sfennerngt_getc_inject(struct tty *tp, void *buf, size_t len) 35398527Sfenner{ 35498527Sfenner sc_p sc = ttyhook_softc(tp); 35598527Sfenner size_t total = 0; 35698527Sfenner int length; 35756893Sfenner 35898527Sfenner while (len) { 35956893Sfenner struct mbuf *m; 36098527Sfenner 36156893Sfenner /* Remove first mbuf from queue */ 36298527Sfenner IF_DEQUEUE(&sc->outq, m); 36356893Sfenner if (m == NULL) 36498527Sfenner break; 36598527Sfenner 36698527Sfenner /* Send as much of it as possible */ 36798527Sfenner while (m != NULL) { 36898527Sfenner length = min(m->m_len, len); 36998527Sfenner memcpy((char *)buf + total, mtod(m, char *), length); 37098527Sfenner 37198527Sfenner m->m_data += length; 37298527Sfenner m->m_len -= length; 37398527Sfenner total += length; 37498527Sfenner len -= length; 37598527Sfenner 37698527Sfenner if (m->m_len > 0) 37798527Sfenner break; /* device can't take any more */ 37856893Sfenner m = m_free(m); 37998527Sfenner } 38098527Sfenner 38198527Sfenner /* Put remainder of mbuf chain (if any) back on queue */ 38298527Sfenner if (m != NULL) { 38398527Sfenner IF_PREPEND(&sc->outq, m); 38498527Sfenner break; 38598527Sfenner } 38698527Sfenner } 38798527Sfenner IF_LOCK(&sc->outq); 38898527Sfenner sc->outqlen -= total; 38998527Sfenner IF_UNLOCK(&sc->outq); 39098527Sfenner MPASS(sc->outqlen >= 0); 39198527Sfenner 39298527Sfenner return (total); 39398527Sfenner} 39498527Sfenner 39598527Sfennerstatic size_t 39698527Sfennerngt_getc_poll(struct tty *tp) 39798527Sfenner{ 39898527Sfenner sc_p sc = ttyhook_softc(tp); 39998527Sfenner 40098527Sfenner return (sc->outqlen); 40198527Sfenner} 402235530Sdelphij 403235530Sdelphij/* 404235530Sdelphij * Optimised TTY input. 405235530Sdelphij * 406235530Sdelphij * We get a buffer pointer to hopefully a complete data frame. Do not check for 407235530Sdelphij * the hotchar, just pass it on. 40898527Sfenner */ 40998527Sfennerstatic size_t 41098527Sfennerngt_rint_bypass(struct tty *tp, const void *buf, size_t len) 41156893Sfenner{ 41298527Sfenner sc_p sc = ttyhook_softc(tp); 41356893Sfenner node_p node = sc->node; 41456893Sfenner struct mbuf *m, *mb; 41598527Sfenner size_t total = 0; 41698527Sfenner int error = 0, length; 41756893Sfenner 41856893Sfenner tty_lock_assert(tp, MA_OWNED); 41956893Sfenner 420214478Srpaulo if (sc->hook == NULL) 42156893Sfenner return (0); 42256893Sfenner 42356893Sfenner m = m_getm2(NULL, len, M_DONTWAIT, MT_DATA, M_PKTHDR); 42456893Sfenner if (m == NULL) { 42556893Sfenner if (sc->flags & FLG_DEBUG) 42656893Sfenner log(LOG_ERR, 42756893Sfenner "%s: can't get mbuf\n", NG_NODE_NAME(node)); 42856893Sfenner return (0); 42956893Sfenner } 43056893Sfenner m->m_pkthdr.rcvif = NULL; 43156893Sfenner 43275118Sfenner for (mb = m; mb != NULL; mb = mb->m_next) { 433146778Ssam length = min(M_TRAILINGSPACE(mb), len - total); 434146778Ssam 435172686Smlaier memcpy(mtod(m, char *), (const char *)buf + total, length); 436146778Ssam mb->m_len = length; 437146778Ssam total += length; 438146778Ssam m->m_pkthdr.len += length; 439146778Ssam } 440146778Ssam if (sc->m != NULL) { 441172686Smlaier /* 442146778Ssam * Odd, we have changed from non-bypass to bypass. It is 443146778Ssam * unlikely but not impossible, flush the data first. 444146778Ssam */ 445214478Srpaulo sc->m->m_data = sc->m->m_pktdat; 446146778Ssam NG_SEND_DATA_ONLY(error, sc->hook, sc->m); 447146778Ssam sc->m = NULL; 44898527Sfenner } 449172686Smlaier NG_SEND_DATA_ONLY(error, sc->hook, m); 450146778Ssam 451146778Ssam return (total); 45256893Sfenner} 45356893Sfenner 45456893Sfenner/* 45556893Sfenner * Receive data coming from the device one char at a time, when it is not in 45656893Sfenner * bypass mode. 45756893Sfenner */ 45856893Sfennerstatic int 45956893Sfennerngt_rint(struct tty *tp, char c, int flags) 46056893Sfenner{ 46156893Sfenner sc_p sc = ttyhook_softc(tp); 46256893Sfenner node_p node = sc->node; 46356893Sfenner struct mbuf *m; 46456893Sfenner int error = 0; 46556893Sfenner 46656893Sfenner tty_lock_assert(tp, MA_OWNED); 46756893Sfenner 46856893Sfenner if (sc->hook == NULL) 46956893Sfenner return (0); 47056893Sfenner 47156893Sfenner if (flags != 0) { 47256893Sfenner /* framing error or overrun on this char */ 47356893Sfenner if (sc->flags & FLG_DEBUG) 47456893Sfenner log(LOG_DEBUG, "%s: line error %x\n", 47556893Sfenner NG_NODE_NAME(node), flags); 47656893Sfenner return (0); 47756893Sfenner } 47856893Sfenner 47956893Sfenner /* Get a new header mbuf if we need one */ 48056893Sfenner if (!(m = sc->m)) { 48156893Sfenner MGETHDR(m, M_DONTWAIT, MT_DATA); 48256893Sfenner if (!m) { 48356893Sfenner if (sc->flags & FLG_DEBUG) 48456893Sfenner log(LOG_ERR, 48556893Sfenner "%s: can't get mbuf\n", NG_NODE_NAME(node)); 48656893Sfenner return (ENOBUFS); 48756893Sfenner } 48856893Sfenner m->m_len = m->m_pkthdr.len = 0; 48956893Sfenner m->m_pkthdr.rcvif = NULL; 49056893Sfenner sc->m = m; 49156893Sfenner } 49256893Sfenner 49356893Sfenner /* Add char to mbuf */ 49456893Sfenner *mtod(m, u_char *) = c; 49556893Sfenner m->m_data++; 49656893Sfenner m->m_len++; 49756893Sfenner m->m_pkthdr.len++; 49856893Sfenner 49956893Sfenner /* Ship off mbuf if it's time */ 50056893Sfenner if (sc->hotchar == -1 || c == sc->hotchar || m->m_len >= MHLEN) { 50156893Sfenner m->m_data = m->m_pktdat; 50256893Sfenner sc->m = NULL; 50356893Sfenner NG_SEND_DATA_ONLY(error, sc->hook, m); /* Will queue */ 50456893Sfenner } 50556893Sfenner 50656893Sfenner return (error); 50756893Sfenner} 50856893Sfenner 50956893Sfennerstatic size_t 51056893Sfennerngt_rint_poll(struct tty *tp) 51156893Sfenner{ 51256893Sfenner /* We can always accept input */ 51356893Sfenner return (1); 51456893Sfenner} 51556893Sfenner 51656893Sfenner