152419Sjulian/* 252419Sjulian * ng_tty.c 3139823Simp */ 4139823Simp 5139823Simp/*- 652419Sjulian * Copyright (c) 1996-1999 Whistle Communications, Inc. 752419Sjulian * All rights reserved. 852419Sjulian * 952419Sjulian * Subject to the following obligations and disclaimer of warranty, use and 1052419Sjulian * redistribution of this software, in source or object code forms, with or 1152419Sjulian * without modifications are expressly permitted by Whistle Communications; 1252419Sjulian * provided, however, that: 1352419Sjulian * 1. Any and all reproductions of the source or object code must include the 1452419Sjulian * copyright notice above and the following disclaimer of warranties; and 1552419Sjulian * 2. No rights are granted, in any manner or form, to use Whistle 1652419Sjulian * Communications, Inc. trademarks, including the mark "WHISTLE 1752419Sjulian * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1852419Sjulian * such appears in the above copyright notice or in the software. 1952419Sjulian * 2052419Sjulian * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2152419Sjulian * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2252419Sjulian * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2352419Sjulian * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2452419Sjulian * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2552419Sjulian * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2652419Sjulian * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2752419Sjulian * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2852419Sjulian * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2952419Sjulian * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 3052419Sjulian * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3152419Sjulian * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3252419Sjulian * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3352419Sjulian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3452419Sjulian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3552419Sjulian * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3652419Sjulian * OF SUCH DAMAGE. 3752419Sjulian * 3867506Sjulian * Author: Archie Cobbs <archie@freebsd.org> 3952419Sjulian * 40183562Sthompsa * Updated by Andrew Thompson <thompsa@FreeBSD.org> for MPSAFE TTY. 41183562Sthompsa * 4252419Sjulian * $FreeBSD$ 4352752Sjulian * $Whistle: ng_tty.c,v 1.21 1999/11/01 09:24:52 julian Exp $ 4452419Sjulian */ 4552419Sjulian 4652419Sjulian/* 47183562Sthompsa * This file implements TTY hooks to link in to the netgraph system. The node 48183562Sthompsa * is created and then passed the callers opened TTY file descriptor number to 49183562Sthompsa * NGM_TTY_SET_TTY, this will hook the tty via ttyhook_register(). 5052419Sjulian * 51183562Sthompsa * Incoming data is delivered directly to ng_tty via the TTY bypass hook as a 52183562Sthompsa * buffer pointer and length, this is converted to a mbuf and passed to the 53183562Sthompsa * peer. 5452419Sjulian * 55183562Sthompsa * If the TTY device does not support bypass then incoming characters are 56183562Sthompsa * delivered to the hook one at a time, each in its own mbuf. You may 57183562Sthompsa * optionally define a ``hotchar,'' which causes incoming characters to be 58183562Sthompsa * buffered up until either the hotchar is seen or the mbuf is full (MHLEN 59183562Sthompsa * bytes). Then all buffered characters are immediately delivered. 6052419Sjulian */ 6152419Sjulian 6252419Sjulian#include <sys/param.h> 6352419Sjulian#include <sys/systm.h> 64140164Sglebius#include <sys/conf.h> 65140164Sglebius#include <sys/errno.h> 66140164Sglebius#include <sys/fcntl.h> 67140164Sglebius#include <sys/ioccom.h> 6852419Sjulian#include <sys/kernel.h> 69140164Sglebius#include <sys/malloc.h> 7052419Sjulian#include <sys/mbuf.h> 71164033Srwatson#include <sys/priv.h> 72140164Sglebius#include <sys/socket.h> 73140164Sglebius#include <sys/syslog.h> 7452419Sjulian#include <sys/tty.h> 7552441Sjulian#include <sys/ttycom.h> 76184762Smav#include <sys/proc.h> 7752419Sjulian 78140164Sglebius#include <net/if.h> 79140164Sglebius#include <net/if_var.h> 80140164Sglebius 8152419Sjulian#include <netgraph/ng_message.h> 8252419Sjulian#include <netgraph/netgraph.h> 8352419Sjulian#include <netgraph/ng_tty.h> 8452419Sjulian 8552419Sjulian/* Per-node private info */ 86183562Sthompsastruct ngt_softc { 87183562Sthompsa struct tty *tp; /* Terminal device */ 88183562Sthompsa node_p node; /* Netgraph node */ 89183562Sthompsa hook_p hook; /* Netgraph hook */ 90183562Sthompsa struct ifqueue outq; /* Queue of outgoing data */ 91183562Sthompsa size_t outqlen; /* Number of bytes in outq */ 92183562Sthompsa struct mbuf *m; /* Incoming non-bypass data buffer */ 93183562Sthompsa short hotchar; /* Hotchar, or -1 if none */ 94183562Sthompsa u_int flags; /* Flags */ 9552419Sjulian}; 96183562Sthompsatypedef struct ngt_softc *sc_p; 9752419Sjulian 9852419Sjulian/* Flags */ 9952419Sjulian#define FLG_DEBUG 0x0002 10052419Sjulian 10152419Sjulian/* Netgraph methods */ 102183562Sthompsastatic ng_constructor_t ngt_constructor; 103183562Sthompsastatic ng_rcvmsg_t ngt_rcvmsg; 104183562Sthompsastatic ng_shutdown_t ngt_shutdown; 105183562Sthompsastatic ng_newhook_t ngt_newhook; 106183562Sthompsastatic ng_connect_t ngt_connect; 107183562Sthompsastatic ng_rcvdata_t ngt_rcvdata; 108183562Sthompsastatic ng_disconnect_t ngt_disconnect; 10952419Sjulian 11052419Sjulian#define ERROUT(x) do { error = (x); goto done; } while (0) 11152419Sjulian 112183562Sthompsastatic th_getc_inject_t ngt_getc_inject; 113183562Sthompsastatic th_getc_poll_t ngt_getc_poll; 114183562Sthompsastatic th_rint_t ngt_rint; 115183562Sthompsastatic th_rint_bypass_t ngt_rint_bypass; 116183562Sthompsastatic th_rint_poll_t ngt_rint_poll; 117183562Sthompsa 118183562Sthompsastatic struct ttyhook ngt_hook = { 119183562Sthompsa .th_getc_inject = ngt_getc_inject, 120183562Sthompsa .th_getc_poll = ngt_getc_poll, 121183562Sthompsa .th_rint = ngt_rint, 122183562Sthompsa .th_rint_bypass = ngt_rint_bypass, 123183562Sthompsa .th_rint_poll = ngt_rint_poll, 12452419Sjulian}; 12552419Sjulian 12652419Sjulian/* Netgraph node type descriptor */ 12752419Sjulianstatic struct ng_type typestruct = { 128129823Sjulian .version = NG_ABI_VERSION, 129129823Sjulian .name = NG_TTY_NODE_TYPE, 130129823Sjulian .constructor = ngt_constructor, 131129823Sjulian .rcvmsg = ngt_rcvmsg, 132129823Sjulian .shutdown = ngt_shutdown, 133129823Sjulian .newhook = ngt_newhook, 134129823Sjulian .connect = ngt_connect, 135129823Sjulian .rcvdata = ngt_rcvdata, 136129823Sjulian .disconnect = ngt_disconnect, 13752419Sjulian}; 13852419SjulianNETGRAPH_INIT(tty, &typestruct); 13952419Sjulian 140140164Sglebius#define NGTLOCK(sc) IF_LOCK(&sc->outq) 141140164Sglebius#define NGTUNLOCK(sc) IF_UNLOCK(&sc->outq) 142140164Sglebius 14352419Sjulian/****************************************************************** 144183562Sthompsa NETGRAPH NODE METHODS 14552419Sjulian******************************************************************/ 14652419Sjulian 14752419Sjulian/* 148183562Sthompsa * Initialize a new node of this type. 149183562Sthompsa * 150183562Sthompsa * We only allow nodes to be created as a result of setting 151183562Sthompsa * the line discipline on a tty, so always return an error if not. 15252419Sjulian */ 15352419Sjulianstatic int 154183562Sthompsangt_constructor(node_p node) 15552419Sjulian{ 156183562Sthompsa sc_p sc; 15752419Sjulian 158183562Sthompsa /* Allocate private structure */ 159220768Sglebius sc = malloc(sizeof(*sc), M_NETGRAPH, M_WAITOK | M_ZERO); 160140164Sglebius 161183562Sthompsa NG_NODE_SET_PRIVATE(node, sc); 162183562Sthompsa sc->node = node; 163183562Sthompsa 164140164Sglebius mtx_init(&sc->outq.ifq_mtx, "ng_tty node+queue", NULL, MTX_DEF); 165207554Ssobomax IFQ_SET_MAXLEN(&sc->outq, ifqmaxlen); 16652419Sjulian 167140164Sglebius return (0); 16852419Sjulian} 16952419Sjulian 17052419Sjulian/* 17152419Sjulian * Add a new hook. There can only be one. 17252419Sjulian */ 17352419Sjulianstatic int 17452419Sjulianngt_newhook(node_p node, hook_p hook, const char *name) 17552419Sjulian{ 17670784Sjulian const sc_p sc = NG_NODE_PRIVATE(node); 17752419Sjulian 17852419Sjulian if (strcmp(name, NG_TTY_HOOK)) 17952419Sjulian return (EINVAL); 180140164Sglebius 18152419Sjulian if (sc->hook) 182140164Sglebius return (EISCONN); 183140164Sglebius 184140164Sglebius NGTLOCK(sc); 18552419Sjulian sc->hook = hook; 186140164Sglebius NGTUNLOCK(sc); 187140164Sglebius 188140164Sglebius return (0); 18952419Sjulian} 19052419Sjulian 19152419Sjulian/* 192140164Sglebius * Set the hook into queueing mode (for outgoing packets), 193140164Sglebius * so that we wont deliver mbuf thru the whole graph holding 194140164Sglebius * tty locks. 19569922Sjulian */ 19669922Sjulianstatic int 19769922Sjulianngt_connect(hook_p hook) 19869922Sjulian{ 199140164Sglebius NG_HOOK_FORCE_QUEUE(hook); 20069922Sjulian return (0); 20169922Sjulian} 20269922Sjulian 20369922Sjulian/* 20452419Sjulian * Disconnect the hook 20552419Sjulian */ 20652419Sjulianstatic int 20752419Sjulianngt_disconnect(hook_p hook) 20852419Sjulian{ 20970784Sjulian const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 21052419Sjulian 21152419Sjulian if (hook != sc->hook) 212213794Srpaulo panic("%s", __func__); 213140164Sglebius 214140164Sglebius NGTLOCK(sc); 21552419Sjulian sc->hook = NULL; 216140164Sglebius NGTUNLOCK(sc); 217140164Sglebius 21852419Sjulian return (0); 21952419Sjulian} 22052419Sjulian 22152419Sjulian/* 22252419Sjulian * Remove this node. The does the netgraph portion of the shutdown. 22352419Sjulian */ 22452419Sjulianstatic int 22552419Sjulianngt_shutdown(node_p node) 22652419Sjulian{ 22770784Sjulian const sc_p sc = NG_NODE_PRIVATE(node); 228183562Sthompsa struct tty *tp; 22952419Sjulian 230183562Sthompsa tp = sc->tp; 231183562Sthompsa if (tp != NULL) { 232183562Sthompsa tty_lock(tp); 233183562Sthompsa ttyhook_unregister(tp); 234140164Sglebius } 235140164Sglebius /* Free resources */ 236183562Sthompsa IF_DRAIN(&sc->outq); 237140164Sglebius mtx_destroy(&(sc)->outq.ifq_mtx); 23870784Sjulian NG_NODE_UNREF(sc->node); 239184205Sdes free(sc, M_NETGRAPH); 240140164Sglebius 24152419Sjulian return (0); 24252419Sjulian} 24352419Sjulian 24452419Sjulian/* 24552419Sjulian * Receive control message 24652419Sjulian */ 24752419Sjulianstatic int 24870700Sjulianngt_rcvmsg(node_p node, item_p item, hook_p lasthook) 24952419Sjulian{ 250184762Smav struct proc *p; 25170784Sjulian const sc_p sc = NG_NODE_PRIVATE(node); 252140164Sglebius struct ng_mesg *msg, *resp = NULL; 25352419Sjulian int error = 0; 25452419Sjulian 25570700Sjulian NGI_GET_MSG(item, msg); 25652419Sjulian switch (msg->header.typecookie) { 25752419Sjulian case NGM_TTY_COOKIE: 25852419Sjulian switch (msg->header.cmd) { 259183562Sthompsa case NGM_TTY_SET_TTY: 260183562Sthompsa if (sc->tp != NULL) 261183562Sthompsa return (EBUSY); 262184762Smav 263184762Smav p = pfind(((int *)msg->data)[0]); 264186056Smav if (p == NULL || (p->p_flag & P_WEXIT)) 265184762Smav return (ESRCH); 266186056Smav _PHOLD(p); 267186056Smav PROC_UNLOCK(p); 268186056Smav error = ttyhook_register(&sc->tp, p, ((int *)msg->data)[1], 269183562Sthompsa &ngt_hook, sc); 270186056Smav PRELE(p); 271183562Sthompsa if (error != 0) 272183562Sthompsa return (error); 273183562Sthompsa break; 27452419Sjulian case NGM_TTY_SET_HOTCHAR: 27552419Sjulian { 27652419Sjulian int hotchar; 27752419Sjulian 27852419Sjulian if (msg->header.arglen != sizeof(int)) 27952419Sjulian ERROUT(EINVAL); 28052419Sjulian hotchar = *((int *) msg->data); 28152419Sjulian if (hotchar != (u_char) hotchar && hotchar != -1) 28252419Sjulian ERROUT(EINVAL); 28352419Sjulian sc->hotchar = hotchar; /* race condition is OK */ 28452419Sjulian break; 28552419Sjulian } 28652419Sjulian case NGM_TTY_GET_HOTCHAR: 28752419Sjulian NG_MKRESPONSE(resp, msg, sizeof(int), M_NOWAIT); 28852419Sjulian if (!resp) 28952419Sjulian ERROUT(ENOMEM); 29052419Sjulian /* Race condition here is OK */ 29152419Sjulian *((int *) resp->data) = sc->hotchar; 29252419Sjulian break; 29352419Sjulian default: 29452419Sjulian ERROUT(EINVAL); 29552419Sjulian } 29652419Sjulian break; 29752419Sjulian default: 29852419Sjulian ERROUT(EINVAL); 29952419Sjulian } 30052419Sjuliandone: 30170700Sjulian NG_RESPOND_MSG(error, node, item, resp); 30270700Sjulian NG_FREE_MSG(msg); 30352419Sjulian return (error); 30452419Sjulian} 30552419Sjulian 306183562Sthompsa/* 307183562Sthompsa * Receive incoming data from netgraph system. Put it on our 308183562Sthompsa * output queue and start output if necessary. 309183562Sthompsa */ 310183562Sthompsastatic int 311183562Sthompsangt_rcvdata(hook_p hook, item_p item) 312183562Sthompsa{ 313183562Sthompsa const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 314183562Sthompsa struct tty *tp = sc->tp; 315183562Sthompsa struct mbuf *m; 31652419Sjulian 317183562Sthompsa if (hook != sc->hook) 318213794Srpaulo panic("%s", __func__); 319183562Sthompsa 320183562Sthompsa NGI_GET_M(item, m); 321183562Sthompsa NG_FREE_ITEM(item); 322183562Sthompsa 323183562Sthompsa if (tp == NULL) { 324183562Sthompsa NG_FREE_M(m); 325183562Sthompsa return (ENXIO); 326183562Sthompsa } 327183562Sthompsa 328183562Sthompsa IF_LOCK(&sc->outq); 329183562Sthompsa if (_IF_QFULL(&sc->outq)) { 330183562Sthompsa _IF_DROP(&sc->outq); 331183562Sthompsa IF_UNLOCK(&sc->outq); 332183562Sthompsa NG_FREE_M(m); 333183562Sthompsa return (ENOBUFS); 334183562Sthompsa } 335183562Sthompsa 336183562Sthompsa _IF_ENQUEUE(&sc->outq, m); 337183562Sthompsa sc->outqlen += m->m_pkthdr.len; 338183562Sthompsa IF_UNLOCK(&sc->outq); 339183562Sthompsa 340183562Sthompsa /* notify the TTY that data is ready */ 341183562Sthompsa tty_lock(tp); 342183562Sthompsa if (!tty_gone(tp)) 343183562Sthompsa ttydevsw_outwakeup(tp); 344183562Sthompsa tty_unlock(tp); 345183562Sthompsa 346183562Sthompsa return (0); 347183562Sthompsa} 348183562Sthompsa 349183562Sthompsastatic size_t 350183562Sthompsangt_getc_inject(struct tty *tp, void *buf, size_t len) 351183562Sthompsa{ 352183562Sthompsa sc_p sc = ttyhook_softc(tp); 353183562Sthompsa size_t total = 0; 354183562Sthompsa int length; 355183562Sthompsa 356183562Sthompsa while (len) { 357183562Sthompsa struct mbuf *m; 358183562Sthompsa 359183562Sthompsa /* Remove first mbuf from queue */ 360183562Sthompsa IF_DEQUEUE(&sc->outq, m); 361183562Sthompsa if (m == NULL) 362183562Sthompsa break; 363183562Sthompsa 364183562Sthompsa /* Send as much of it as possible */ 365183562Sthompsa while (m != NULL) { 366183562Sthompsa length = min(m->m_len, len); 367183562Sthompsa memcpy((char *)buf + total, mtod(m, char *), length); 368183562Sthompsa 369183562Sthompsa m->m_data += length; 370183562Sthompsa m->m_len -= length; 371183562Sthompsa total += length; 372183562Sthompsa len -= length; 373183562Sthompsa 374183562Sthompsa if (m->m_len > 0) 375183562Sthompsa break; /* device can't take any more */ 376183562Sthompsa m = m_free(m); 377183562Sthompsa } 378183562Sthompsa 379183562Sthompsa /* Put remainder of mbuf chain (if any) back on queue */ 380183562Sthompsa if (m != NULL) { 381183562Sthompsa IF_PREPEND(&sc->outq, m); 382183562Sthompsa break; 383183562Sthompsa } 384183562Sthompsa } 385183562Sthompsa IF_LOCK(&sc->outq); 386183562Sthompsa sc->outqlen -= total; 387183562Sthompsa IF_UNLOCK(&sc->outq); 388183562Sthompsa MPASS(sc->outqlen >= 0); 389183562Sthompsa 390183562Sthompsa return (total); 391183562Sthompsa} 392183562Sthompsa 393183562Sthompsastatic size_t 394183562Sthompsangt_getc_poll(struct tty *tp) 395183562Sthompsa{ 396183562Sthompsa sc_p sc = ttyhook_softc(tp); 397183562Sthompsa 398183562Sthompsa return (sc->outqlen); 399183562Sthompsa} 400183562Sthompsa 40152419Sjulian/* 402183562Sthompsa * Optimised TTY input. 403183562Sthompsa * 404183562Sthompsa * We get a buffer pointer to hopefully a complete data frame. Do not check for 405183562Sthompsa * the hotchar, just pass it on. 40652419Sjulian */ 407183562Sthompsastatic size_t 408183562Sthompsangt_rint_bypass(struct tty *tp, const void *buf, size_t len) 409183562Sthompsa{ 410183562Sthompsa sc_p sc = ttyhook_softc(tp); 411183562Sthompsa node_p node = sc->node; 412183562Sthompsa struct mbuf *m, *mb; 413183562Sthompsa size_t total = 0; 414183562Sthompsa int error = 0, length; 415183562Sthompsa 416183562Sthompsa tty_lock_assert(tp, MA_OWNED); 417183562Sthompsa 418183562Sthompsa if (sc->hook == NULL) 419183562Sthompsa return (0); 420183562Sthompsa 421243882Sglebius m = m_getm2(NULL, len, M_NOWAIT, MT_DATA, M_PKTHDR); 422183562Sthompsa if (m == NULL) { 423183562Sthompsa if (sc->flags & FLG_DEBUG) 424183562Sthompsa log(LOG_ERR, 425183562Sthompsa "%s: can't get mbuf\n", NG_NODE_NAME(node)); 426183562Sthompsa return (0); 427183562Sthompsa } 428183562Sthompsa m->m_pkthdr.rcvif = NULL; 429183562Sthompsa 430183562Sthompsa for (mb = m; mb != NULL; mb = mb->m_next) { 431183562Sthompsa length = min(M_TRAILINGSPACE(mb), len - total); 432183562Sthompsa 433183562Sthompsa memcpy(mtod(m, char *), (const char *)buf + total, length); 434183562Sthompsa mb->m_len = length; 435183562Sthompsa total += length; 436183562Sthompsa m->m_pkthdr.len += length; 437183562Sthompsa } 438183562Sthompsa if (sc->m != NULL) { 439183562Sthompsa /* 440183562Sthompsa * Odd, we have changed from non-bypass to bypass. It is 441183562Sthompsa * unlikely but not impossible, flush the data first. 442183562Sthompsa */ 443183562Sthompsa sc->m->m_data = sc->m->m_pktdat; 444183562Sthompsa NG_SEND_DATA_ONLY(error, sc->hook, sc->m); 445183562Sthompsa sc->m = NULL; 446183562Sthompsa } 447183562Sthompsa NG_SEND_DATA_ONLY(error, sc->hook, m); 448183562Sthompsa 449183562Sthompsa return (total); 450183562Sthompsa} 451183562Sthompsa 452183562Sthompsa/* 453183562Sthompsa * Receive data coming from the device one char at a time, when it is not in 454183562Sthompsa * bypass mode. 455183562Sthompsa */ 45652419Sjulianstatic int 457183562Sthompsangt_rint(struct tty *tp, char c, int flags) 45852419Sjulian{ 459183562Sthompsa sc_p sc = ttyhook_softc(tp); 460183562Sthompsa node_p node = sc->node; 461183562Sthompsa struct mbuf *m; 462140164Sglebius int error = 0; 46352419Sjulian 464183562Sthompsa tty_lock_assert(tp, MA_OWNED); 46552419Sjulian 466183562Sthompsa if (sc->hook == NULL) 467183562Sthompsa return (0); 468183562Sthompsa 469183562Sthompsa if (flags != 0) { 470183562Sthompsa /* framing error or overrun on this char */ 471183562Sthompsa if (sc->flags & FLG_DEBUG) 472183562Sthompsa log(LOG_DEBUG, "%s: line error %x\n", 473183562Sthompsa NG_NODE_NAME(node), flags); 474183562Sthompsa return (0); 475183562Sthompsa } 476183562Sthompsa 477183562Sthompsa /* Get a new header mbuf if we need one */ 478183562Sthompsa if (!(m = sc->m)) { 479243882Sglebius MGETHDR(m, M_NOWAIT, MT_DATA); 480183562Sthompsa if (!m) { 481183562Sthompsa if (sc->flags & FLG_DEBUG) 482183562Sthompsa log(LOG_ERR, 483183562Sthompsa "%s: can't get mbuf\n", NG_NODE_NAME(node)); 484183562Sthompsa return (ENOBUFS); 48552419Sjulian } 486183562Sthompsa m->m_len = m->m_pkthdr.len = 0; 487183562Sthompsa m->m_pkthdr.rcvif = NULL; 488183562Sthompsa sc->m = m; 489183562Sthompsa } 49052419Sjulian 491183562Sthompsa /* Add char to mbuf */ 492183562Sthompsa *mtod(m, u_char *) = c; 493183562Sthompsa m->m_data++; 494183562Sthompsa m->m_len++; 495183562Sthompsa m->m_pkthdr.len++; 49652419Sjulian 497183562Sthompsa /* Ship off mbuf if it's time */ 498183562Sthompsa if (sc->hotchar == -1 || c == sc->hotchar || m->m_len >= MHLEN) { 499183562Sthompsa m->m_data = m->m_pktdat; 500183562Sthompsa sc->m = NULL; 501183562Sthompsa NG_SEND_DATA_ONLY(error, sc->hook, m); /* Will queue */ 502183562Sthompsa } 50352419Sjulian 50452419Sjulian return (error); 50552419Sjulian} 506183562Sthompsa 507183562Sthompsastatic size_t 508183562Sthompsangt_rint_poll(struct tty *tp) 509183562Sthompsa{ 510183562Sthompsa /* We can always accept input */ 511183562Sthompsa return (1); 512183562Sthompsa} 513183562Sthompsa 514