1177867Sjfv/*
2169240Sjfv * ng_tty.c
3190872Sjfv */
4169240Sjfv
5169240Sjfv/*-
6169240Sjfv * Copyright (c) 1996-1999 Whistle Communications, Inc.
7169240Sjfv * All rights reserved.
8169240Sjfv *
9169240Sjfv * Subject to the following obligations and disclaimer of warranty, use and
10169240Sjfv * redistribution of this software, in source or object code forms, with or
11169240Sjfv * without modifications are expressly permitted by Whistle Communications;
12169240Sjfv * provided, however, that:
13169240Sjfv * 1. Any and all reproductions of the source or object code must include the
14169240Sjfv *    copyright notice above and the following disclaimer of warranties; and
15169240Sjfv * 2. No rights are granted, in any manner or form, to use Whistle
16169240Sjfv *    Communications, Inc. trademarks, including the mark "WHISTLE
17169240Sjfv *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
18169240Sjfv *    such appears in the above copyright notice or in the software.
19169240Sjfv *
20169240Sjfv * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
21169240Sjfv * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
22169240Sjfv * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
23169240Sjfv * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
24169240Sjfv * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
25169240Sjfv * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
26169240Sjfv * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
27169240Sjfv * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
28169240Sjfv * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
29169240Sjfv * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
30169240Sjfv * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31169240Sjfv * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
32177867Sjfv * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
33177867Sjfv * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34169240Sjfv * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35185353Sjfv * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
36185353Sjfv * OF SUCH DAMAGE.
37185353Sjfv *
38185353Sjfv * Author: Archie Cobbs <archie@freebsd.org>
39185353Sjfv *
40185353Sjfv * Updated by Andrew Thompson <thompsa@FreeBSD.org> for MPSAFE TTY.
41185353Sjfv *
42169240Sjfv * $FreeBSD$
43169240Sjfv * $Whistle: ng_tty.c,v 1.21 1999/11/01 09:24:52 julian Exp $
44169589Sjfv */
45169240Sjfv
46177867Sjfv/*
47177867Sjfv * This file implements TTY hooks to link in to the netgraph system.  The node
48177867Sjfv * is created and then passed the callers opened TTY file descriptor number to
49177867Sjfv * NGM_TTY_SET_TTY, this will hook the tty via ttyhook_register().
50177867Sjfv *
51177867Sjfv * Incoming data is delivered directly to ng_tty via the TTY bypass hook as a
52169240Sjfv * buffer pointer and length, this is converted to a mbuf and passed to the
53177867Sjfv * peer.
54177867Sjfv *
55177867Sjfv * If the TTY device does not support bypass then incoming characters are
56177867Sjfv * delivered to the hook one at a time, each in its own mbuf. You may
57177867Sjfv * optionally define a ``hotchar,'' which causes incoming characters to be
58173788Sjfv * buffered up until either the hotchar is seen or the mbuf is full (MHLEN
59177867Sjfv * bytes). Then all buffered characters are immediately delivered.
60177867Sjfv */
61177867Sjfv
62169240Sjfv#include <sys/param.h>
63173788Sjfv#include <sys/systm.h>
64169240Sjfv#include <sys/conf.h>
65177867Sjfv#include <sys/errno.h>
66169240Sjfv#include <sys/fcntl.h>
67173788Sjfv#include <sys/ioccom.h>
68169240Sjfv#include <sys/kernel.h>
69169240Sjfv#include <sys/malloc.h>
70169240Sjfv#include <sys/mbuf.h>
71169240Sjfv#include <sys/priv.h>
72169240Sjfv#include <sys/socket.h>
73169240Sjfv#include <sys/syslog.h>
74169240Sjfv#include <sys/tty.h>
75169240Sjfv#include <sys/ttycom.h>
76169240Sjfv#include <sys/proc.h>
77169240Sjfv
78169240Sjfv#include <net/if.h>
79169240Sjfv#include <net/if_var.h>
80169240Sjfv
81169240Sjfv#include <netgraph/ng_message.h>
82169589Sjfv#include <netgraph/netgraph.h>
83169240Sjfv#include <netgraph/ng_tty.h>
84177867Sjfv
85169240Sjfv/* Per-node private info */
86169240Sjfvstruct ngt_softc {
87169240Sjfv	struct tty	*tp;		/* Terminal device */
88169240Sjfv	node_p		node;		/* Netgraph node */
89169240Sjfv	hook_p		hook;		/* Netgraph hook */
90169240Sjfv	struct ifqueue	outq;		/* Queue of outgoing data */
91177867Sjfv	size_t		outqlen;	/* Number of bytes in outq */
92177867Sjfv	struct mbuf	*m;		/* Incoming non-bypass data buffer */
93177867Sjfv	short		hotchar;	/* Hotchar, or -1 if none */
94177867Sjfv	u_int		flags;		/* Flags */
95169240Sjfv};
96169240Sjfvtypedef struct ngt_softc *sc_p;
97177867Sjfv
98177867Sjfv/* Flags */
99177867Sjfv#define FLG_DEBUG		0x0002
100177867Sjfv
101177867Sjfv/* Netgraph methods */
102177867Sjfvstatic ng_constructor_t		ngt_constructor;
103177867Sjfvstatic ng_rcvmsg_t		ngt_rcvmsg;
104177867Sjfvstatic ng_shutdown_t		ngt_shutdown;
105177867Sjfvstatic ng_newhook_t		ngt_newhook;
106177867Sjfvstatic ng_connect_t		ngt_connect;
107177867Sjfvstatic ng_rcvdata_t		ngt_rcvdata;
108169240Sjfvstatic ng_disconnect_t		ngt_disconnect;
109169240Sjfv
110169240Sjfv#define ERROUT(x)		do { error = (x); goto done; } while (0)
111169240Sjfv
112169240Sjfvstatic th_getc_inject_t		ngt_getc_inject;
113169240Sjfvstatic th_getc_poll_t		ngt_getc_poll;
114169240Sjfvstatic th_rint_t		ngt_rint;
115169240Sjfvstatic th_rint_bypass_t		ngt_rint_bypass;
116169240Sjfvstatic th_rint_poll_t		ngt_rint_poll;
117169240Sjfv
118169240Sjfvstatic struct ttyhook ngt_hook = {
119169240Sjfv	.th_getc_inject = ngt_getc_inject,
120169240Sjfv	.th_getc_poll = ngt_getc_poll,
121169240Sjfv	.th_rint = ngt_rint,
122169240Sjfv	.th_rint_bypass = ngt_rint_bypass,
123169240Sjfv	.th_rint_poll = ngt_rint_poll,
124169240Sjfv};
125169589Sjfv
126169240Sjfv/* Netgraph node type descriptor */
127177867Sjfvstatic struct ng_type typestruct = {
128169240Sjfv	.version =	NG_ABI_VERSION,
129169240Sjfv	.name =		NG_TTY_NODE_TYPE,
130169240Sjfv	.constructor =	ngt_constructor,
131169240Sjfv	.rcvmsg =	ngt_rcvmsg,
132169240Sjfv	.shutdown =	ngt_shutdown,
133169240Sjfv	.newhook =	ngt_newhook,
134169240Sjfv	.connect =	ngt_connect,
135169240Sjfv	.rcvdata =	ngt_rcvdata,
136169240Sjfv	.disconnect =	ngt_disconnect,
137169240Sjfv};
138169240SjfvNETGRAPH_INIT(tty, &typestruct);
139169240Sjfv
140169240Sjfv#define	NGTLOCK(sc)	IF_LOCK(&sc->outq)
141169240Sjfv#define	NGTUNLOCK(sc)	IF_UNLOCK(&sc->outq)
142169240Sjfv
143169240Sjfv/******************************************************************
144169240Sjfv		    NETGRAPH NODE METHODS
145169240Sjfv******************************************************************/
146169240Sjfv
147169240Sjfv/*
148169240Sjfv * Initialize a new node of this type.
149169240Sjfv *
150169240Sjfv * We only allow nodes to be created as a result of setting
151169240Sjfv * the line discipline on a tty, so always return an error if not.
152169240Sjfv */
153169240Sjfvstatic int
154169240Sjfvngt_constructor(node_p node)
155169240Sjfv{
156169240Sjfv	sc_p sc;
157169240Sjfv
158169240Sjfv	/* Allocate private structure */
159169240Sjfv	sc = malloc(sizeof(*sc), M_NETGRAPH, M_WAITOK | M_ZERO);
160169240Sjfv
161169240Sjfv	NG_NODE_SET_PRIVATE(node, sc);
162169240Sjfv	sc->node = node;
163169240Sjfv
164169240Sjfv	mtx_init(&sc->outq.ifq_mtx, "ng_tty node+queue", NULL, MTX_DEF);
165169240Sjfv	IFQ_SET_MAXLEN(&sc->outq, ifqmaxlen);
166169240Sjfv
167169240Sjfv	return (0);
168169240Sjfv}
169177867Sjfv
170177867Sjfv/*
171177867Sjfv * Add a new hook. There can only be one.
172177867Sjfv */
173177867Sjfvstatic int
174177867Sjfvngt_newhook(node_p node, hook_p hook, const char *name)
175177867Sjfv{
176169240Sjfv	const sc_p sc = NG_NODE_PRIVATE(node);
177173788Sjfv
178173788Sjfv	if (strcmp(name, NG_TTY_HOOK))
179169240Sjfv		return (EINVAL);
180169240Sjfv
181169240Sjfv	if (sc->hook)
182169240Sjfv		return (EISCONN);
183169240Sjfv
184177867Sjfv	NGTLOCK(sc);
185169240Sjfv	sc->hook = hook;
186169240Sjfv	NGTUNLOCK(sc);
187169240Sjfv
188173788Sjfv	return (0);
189173788Sjfv}
190169240Sjfv
191169240Sjfv/*
192169240Sjfv * Set the hook into queueing mode (for outgoing packets),
193169240Sjfv * so that we wont deliver mbuf thru the whole graph holding
194169240Sjfv * tty locks.
195169240Sjfv */
196169240Sjfvstatic int
197169240Sjfvngt_connect(hook_p hook)
198169240Sjfv{
199169240Sjfv	NG_HOOK_FORCE_QUEUE(hook);
200169240Sjfv	return (0);
201169240Sjfv}
202169240Sjfv
203169240Sjfv/*
204169240Sjfv * Disconnect the hook
205169240Sjfv */
206177867Sjfvstatic int
207177867Sjfvngt_disconnect(hook_p hook)
208177867Sjfv{
209177867Sjfv	const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
210177867Sjfv
211177867Sjfv	if (hook != sc->hook)
212177867Sjfv		panic("%s", __func__);
213169240Sjfv
214169240Sjfv	NGTLOCK(sc);
215169240Sjfv	sc->hook = NULL;
216169240Sjfv	NGTUNLOCK(sc);
217169240Sjfv
218169240Sjfv	return (0);
219169240Sjfv}
220169240Sjfv
221169589Sjfv/*
222169240Sjfv * Remove this node. The does the netgraph portion of the shutdown.
223177867Sjfv */
224169240Sjfvstatic int
225169240Sjfvngt_shutdown(node_p node)
226169240Sjfv{
227169240Sjfv	const sc_p sc = NG_NODE_PRIVATE(node);
228169240Sjfv	struct tty *tp;
229169240Sjfv
230173788Sjfv	tp = sc->tp;
231169240Sjfv	if (tp != NULL) {
232169240Sjfv		tty_lock(tp);
233169240Sjfv		ttyhook_unregister(tp);
234169240Sjfv	}
235169240Sjfv	/* Free resources */
236169240Sjfv	IF_DRAIN(&sc->outq);
237169240Sjfv	mtx_destroy(&(sc)->outq.ifq_mtx);
238169240Sjfv	NG_NODE_UNREF(sc->node);
239169240Sjfv	free(sc, M_NETGRAPH);
240169240Sjfv
241177867Sjfv	return (0);
242185353Sjfv}
243185353Sjfv
244169240Sjfv/*
245177867Sjfv * Receive control message
246169240Sjfv */
247177867Sjfvstatic int
248169240Sjfvngt_rcvmsg(node_p node, item_p item, hook_p lasthook)
249177867Sjfv{
250169240Sjfv	struct proc *p;
251177867Sjfv	const sc_p sc = NG_NODE_PRIVATE(node);
252169240Sjfv	struct ng_mesg *msg, *resp = NULL;
253177867Sjfv	int error = 0;
254169240Sjfv
255177867Sjfv	NGI_GET_MSG(item, msg);
256169240Sjfv	switch (msg->header.typecookie) {
257177867Sjfv	case NGM_TTY_COOKIE:
258169240Sjfv		switch (msg->header.cmd) {
259177867Sjfv		case NGM_TTY_SET_TTY:
260169240Sjfv			if (sc->tp != NULL)
261177867Sjfv				return (EBUSY);
262169240Sjfv
263177867Sjfv			p = pfind(((int *)msg->data)[0]);
264190872Sjfv			if (p == NULL || (p->p_flag & P_WEXIT))
265190872Sjfv				return (ESRCH);
266169240Sjfv			_PHOLD(p);
267177867Sjfv			PROC_UNLOCK(p);
268169240Sjfv			error = ttyhook_register(&sc->tp, p, ((int *)msg->data)[1],
269177867Sjfv			    &ngt_hook, sc);
270169240Sjfv			PRELE(p);
271177867Sjfv			if (error != 0)
272177867Sjfv				return (error);
273169240Sjfv			break;
274177867Sjfv		case NGM_TTY_SET_HOTCHAR:
275169240Sjfv		    {
276185353Sjfv			int     hotchar;
277169240Sjfv
278169240Sjfv			if (msg->header.arglen != sizeof(int))
279169240Sjfv				ERROUT(EINVAL);
280169240Sjfv			hotchar = *((int *) msg->data);
281169589Sjfv			if (hotchar != (u_char) hotchar && hotchar != -1)
282169240Sjfv				ERROUT(EINVAL);
283185353Sjfv			sc->hotchar = hotchar;	/* race condition is OK */
284169240Sjfv			break;
285173788Sjfv		    }
286169240Sjfv		case NGM_TTY_GET_HOTCHAR:
287169240Sjfv			NG_MKRESPONSE(resp, msg, sizeof(int), M_NOWAIT);
288169240Sjfv			if (!resp)
289177867Sjfv				ERROUT(ENOMEM);
290177867Sjfv			/* Race condition here is OK */
291177867Sjfv			*((int *) resp->data) = sc->hotchar;
292169240Sjfv			break;
293169240Sjfv		default:
294169240Sjfv			ERROUT(EINVAL);
295169240Sjfv		}
296169589Sjfv		break;
297169240Sjfv	default:
298185353Sjfv		ERROUT(EINVAL);
299169240Sjfv	}
300177867Sjfvdone:
301169240Sjfv	NG_RESPOND_MSG(error, node, item, resp);
302169240Sjfv	NG_FREE_MSG(msg);
303169240Sjfv	return (error);
304169240Sjfv}
305169240Sjfv
306169240Sjfv/*
307169240Sjfv * Receive incoming data from netgraph system. Put it on our
308169240Sjfv * output queue and start output if necessary.
309169240Sjfv */
310169240Sjfvstatic int
311169240Sjfvngt_rcvdata(hook_p hook, item_p item)
312169240Sjfv{
313173788Sjfv	const sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
314173788Sjfv	struct tty *tp = sc->tp;
315169240Sjfv	struct mbuf *m;
316169240Sjfv
317169240Sjfv	if (hook != sc->hook)
318169240Sjfv		panic("%s", __func__);
319169240Sjfv
320169240Sjfv	NGI_GET_M(item, m);
321169240Sjfv	NG_FREE_ITEM(item);
322169240Sjfv
323169240Sjfv	if (tp == NULL) {
324169240Sjfv		NG_FREE_M(m);
325169240Sjfv		return (ENXIO);
326169240Sjfv	}
327169240Sjfv
328169240Sjfv	IF_LOCK(&sc->outq);
329169240Sjfv	if (_IF_QFULL(&sc->outq)) {
330169240Sjfv		_IF_DROP(&sc->outq);
331173788Sjfv		IF_UNLOCK(&sc->outq);
332173788Sjfv		NG_FREE_M(m);
333169240Sjfv		return (ENOBUFS);
334169240Sjfv	}
335169240Sjfv
336169240Sjfv	_IF_ENQUEUE(&sc->outq, m);
337169240Sjfv	sc->outqlen += m->m_pkthdr.len;
338169240Sjfv	IF_UNLOCK(&sc->outq);
339169240Sjfv
340169240Sjfv	/* notify the TTY that data is ready */
341169240Sjfv	tty_lock(tp);
342169240Sjfv	if (!tty_gone(tp))
343169240Sjfv		ttydevsw_outwakeup(tp);
344169240Sjfv	tty_unlock(tp);
345169240Sjfv
346169240Sjfv	return (0);
347169240Sjfv}
348169240Sjfv
349169240Sjfvstatic size_t
350169240Sjfvngt_getc_inject(struct tty *tp, void *buf, size_t len)
351169240Sjfv{
352169240Sjfv	sc_p sc = ttyhook_softc(tp);
353169240Sjfv	size_t total = 0;
354169240Sjfv	int length;
355169240Sjfv
356169240Sjfv	while (len) {
357169240Sjfv		struct mbuf *m;
358169240Sjfv
359169240Sjfv		/* Remove first mbuf from queue */
360169240Sjfv		IF_DEQUEUE(&sc->outq, m);
361169240Sjfv		if (m == NULL)
362169240Sjfv			break;
363169240Sjfv
364169240Sjfv		/* Send as much of it as possible */
365169240Sjfv		while (m != NULL) {
366169240Sjfv			length = min(m->m_len, len);
367169240Sjfv			memcpy((char *)buf + total, mtod(m, char *), length);
368169240Sjfv
369169240Sjfv			m->m_data += length;
370169240Sjfv			m->m_len -= length;
371169240Sjfv			total += length;
372169240Sjfv			len -= length;
373169589Sjfv
374169240Sjfv			if (m->m_len > 0)
375185353Sjfv				break;	/* device can't take any more */
376169240Sjfv			m = m_free(m);
377177867Sjfv		}
378169240Sjfv
379169240Sjfv		/* Put remainder of mbuf chain (if any) back on queue */
380169240Sjfv		if (m != NULL) {
381169240Sjfv			IF_PREPEND(&sc->outq, m);
382169240Sjfv			break;
383169240Sjfv		}
384169240Sjfv	}
385169240Sjfv	IF_LOCK(&sc->outq);
386190872Sjfv	sc->outqlen -= total;
387169240Sjfv	IF_UNLOCK(&sc->outq);
388169240Sjfv	MPASS(sc->outqlen >= 0);
389173788Sjfv
390169240Sjfv	return (total);
391169240Sjfv}
392169240Sjfv
393169240Sjfvstatic size_t
394177867Sjfvngt_getc_poll(struct tty *tp)
395169240Sjfv{
396169240Sjfv	sc_p sc = ttyhook_softc(tp);
397169240Sjfv
398169240Sjfv	return (sc->outqlen);
399169240Sjfv}
400169240Sjfv
401169240Sjfv/*
402169240Sjfv * Optimised TTY input.
403173788Sjfv *
404173788Sjfv * We get a buffer pointer to hopefully a complete data frame. Do not check for
405169240Sjfv * the hotchar, just pass it on.
406169240Sjfv */
407169240Sjfvstatic size_t
408169240Sjfvngt_rint_bypass(struct tty *tp, const void *buf, size_t len)
409169240Sjfv{
410169240Sjfv	sc_p sc = ttyhook_softc(tp);
411169240Sjfv	node_p node = sc->node;
412169240Sjfv	struct mbuf *m, *mb;
413177867Sjfv	size_t total = 0;
414169240Sjfv	int error = 0, length;
415173788Sjfv
416169240Sjfv	tty_lock_assert(tp, MA_OWNED);
417169240Sjfv
418173788Sjfv	if (sc->hook == NULL)
419169240Sjfv		return (0);
420173788Sjfv
421173788Sjfv	m = m_getm2(NULL, len, M_NOWAIT, MT_DATA, M_PKTHDR);
422169240Sjfv	if (m == NULL) {
423169240Sjfv		if (sc->flags & FLG_DEBUG)
424169240Sjfv			log(LOG_ERR,
425169240Sjfv			    "%s: can't get mbuf\n", NG_NODE_NAME(node));
426169240Sjfv		return (0);
427169240Sjfv	}
428169240Sjfv	m->m_pkthdr.rcvif = NULL;
429169240Sjfv
430169240Sjfv	for (mb = m; mb != NULL; mb = mb->m_next) {
431169240Sjfv		length = min(M_TRAILINGSPACE(mb), len - total);
432169240Sjfv
433169589Sjfv		memcpy(mtod(m, char *), (const char *)buf + total, length);
434169589Sjfv		mb->m_len = length;
435169589Sjfv		total += length;
436169240Sjfv		m->m_pkthdr.len += length;
437169240Sjfv	}
438169240Sjfv	if (sc->m != NULL) {
439177867Sjfv		/*
440173788Sjfv		 * Odd, we have changed from non-bypass to bypass. It is
441169240Sjfv		 * unlikely but not impossible, flush the data first.
442169240Sjfv		 */
443169240Sjfv		sc->m->m_data = sc->m->m_pktdat;
444169240Sjfv		NG_SEND_DATA_ONLY(error, sc->hook, sc->m);
445169240Sjfv		sc->m = NULL;
446169240Sjfv	}
447169240Sjfv	NG_SEND_DATA_ONLY(error, sc->hook, m);
448169240Sjfv
449169240Sjfv	return (total);
450169240Sjfv}
451169240Sjfv
452169240Sjfv/*
453169240Sjfv * Receive data coming from the device one char at a time, when it is not in
454169240Sjfv * bypass mode.
455173788Sjfv */
456173788Sjfvstatic int
457169240Sjfvngt_rint(struct tty *tp, char c, int flags)
458169240Sjfv{
459169240Sjfv	sc_p sc = ttyhook_softc(tp);
460169240Sjfv	node_p node = sc->node;
461177867Sjfv	struct mbuf *m;
462169240Sjfv	int error = 0;
463169240Sjfv
464169240Sjfv	tty_lock_assert(tp, MA_OWNED);
465173788Sjfv
466169240Sjfv	if (sc->hook == NULL)
467173788Sjfv		return (0);
468177867Sjfv
469169240Sjfv	if (flags != 0) {
470169240Sjfv		/* framing error or overrun on this char */
471169240Sjfv		if (sc->flags & FLG_DEBUG)
472169240Sjfv			log(LOG_DEBUG, "%s: line error %x\n",
473169240Sjfv			    NG_NODE_NAME(node), flags);
474169240Sjfv		return (0);
475169240Sjfv	}
476169240Sjfv
477169240Sjfv	/* Get a new header mbuf if we need one */
478169240Sjfv	if (!(m = sc->m)) {
479169240Sjfv		MGETHDR(m, M_NOWAIT, MT_DATA);
480169240Sjfv		if (!m) {
481169240Sjfv			if (sc->flags & FLG_DEBUG)
482169240Sjfv				log(LOG_ERR,
483169240Sjfv				    "%s: can't get mbuf\n", NG_NODE_NAME(node));
484169240Sjfv			return (ENOBUFS);
485169240Sjfv		}
486169240Sjfv		m->m_len = m->m_pkthdr.len = 0;
487169589Sjfv		m->m_pkthdr.rcvif = NULL;
488169240Sjfv		sc->m = m;
489169240Sjfv	}
490169240Sjfv
491169240Sjfv	/* Add char to mbuf */
492176667Sjfv	*mtod(m, u_char *) = c;
493169240Sjfv	m->m_data++;
494177867Sjfv	m->m_len++;
495169240Sjfv	m->m_pkthdr.len++;
496169240Sjfv
497169240Sjfv	/* Ship off mbuf if it's time */
498169240Sjfv	if (sc->hotchar == -1 || c == sc->hotchar || m->m_len >= MHLEN) {
499169240Sjfv		m->m_data = m->m_pktdat;
500169240Sjfv		sc->m = NULL;
501169240Sjfv		NG_SEND_DATA_ONLY(error, sc->hook, m);	/* Will queue */
502169240Sjfv	}
503169240Sjfv
504169240Sjfv	return (error);
505169240Sjfv}
506169240Sjfv
507169240Sjfvstatic size_t
508169240Sjfvngt_rint_poll(struct tty *tp)
509169240Sjfv{
510169240Sjfv	/* We can always accept input */
511169240Sjfv	return (1);
512169240Sjfv}
513169240Sjfv
514169240Sjfv