Deleted Added
sdiff udiff text old ( 171345 ) new ( 171818 )
full compact
1/*
2 * ng_h4.c
3 */
4
5/*-
6 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7 * All rights reserved.
8 *

--- 13 unchanged lines hidden (view full) ---

22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * $Id: ng_h4.c,v 1.7 2004/08/23 18:08:15 max Exp $
31 * $FreeBSD: head/sys/netgraph/bluetooth/drivers/h4/ng_h4.c 171345 2007-07-10 16:38:43Z emax $
32 *
33 * Based on:
34 * ---------
35 *
36 * FreeBSD: src/sys/netgraph/ng_tty.c
37 * Author: Archie Cobbs <archie@freebsd.org>
38 *
39 */

--- 4 unchanged lines hidden (view full) ---

44#include <sys/conf.h>
45#include <sys/endian.h>
46#include <sys/errno.h>
47#include <sys/fcntl.h>
48#include <sys/ioccom.h>
49#include <sys/malloc.h>
50#include <sys/mbuf.h>
51#include <sys/priv.h>
52#include <sys/tty.h>
53#include <sys/ttycom.h>
54#include <netgraph/ng_message.h>
55#include <netgraph/netgraph.h>
56#include <netgraph/ng_parse.h>
57#include <netgraph/bluetooth/include/ng_bluetooth.h>
58#include <netgraph/bluetooth/include/ng_hci.h>
59#include <netgraph/bluetooth/include/ng_h4.h>
60#include <netgraph/bluetooth/drivers/h4/ng_h4_var.h>
61#include <netgraph/bluetooth/drivers/h4/ng_h4_prse.h>

--- 6 unchanged lines hidden (view full) ---

68 ** on a terminal device instantiates a new netgraph node of this type, which
69 ** allows access to the device via the "hook" hook of the node.
70 **
71 ** Once the line discipline is installed, you can find out the name of the
72 ** corresponding netgraph node via a NGIOCGINFO ioctl().
73 *****************************************************************************
74 *****************************************************************************/
75
76#error "NET_NEEDS_GIANT"
77
78/* MALLOC define */
79#ifndef NG_SEPARATE_MALLOC
80MALLOC_DEFINE(M_NETGRAPH_H4, "netgraph_h4", "Netgraph Bluetooth H4 node");
81#else
82#define M_NETGRAPH_H4 M_NETGRAPH
83#endif /* NG_SEPARATE_MALLOC */
84
85/* Line discipline methods */
86static int ng_h4_open (struct cdev *, struct tty *);
87static int ng_h4_close (struct tty *, int);
88static int ng_h4_read (struct tty *, struct uio *, int);
89static int ng_h4_write (struct tty *, struct uio *, int);
90static int ng_h4_input (int, struct tty *);
91static int ng_h4_start (struct tty *);
92static void ng_h4_start2 (node_p, hook_p, void *, int);
93static int ng_h4_ioctl (struct tty *, u_long, caddr_t,
94 int, struct thread *);
95
96/* Line discipline descriptor */
97static struct linesw ng_h4_disc = {
98 ng_h4_open, /* open */
99 ng_h4_close, /* close */
100 ng_h4_read, /* read */

--- 9 unchanged lines hidden (view full) ---

110static ng_rcvmsg_t ng_h4_rcvmsg;
111static ng_shutdown_t ng_h4_shutdown;
112static ng_newhook_t ng_h4_newhook;
113static ng_connect_t ng_h4_connect;
114static ng_rcvdata_t ng_h4_rcvdata;
115static ng_disconnect_t ng_h4_disconnect;
116
117/* Other stuff */
118static void ng_h4_timeout (node_p);
119static void ng_h4_untimeout (node_p);
120static void ng_h4_process_timeout (node_p, hook_p, void *, int);
121static int ng_h4_mod_event (module_t, int, void *);
122
123/* Netgraph node type descriptor */
124static struct ng_type typestruct = {
125 .version = NG_ABI_VERSION,
126 .name = NG_H4_NODE_TYPE,
127 .mod_event = ng_h4_mod_event,

--- 19 unchanged lines hidden (view full) ---

147
148/*
149 * Set our line discipline on the tty.
150 */
151
152static int
153ng_h4_open(struct cdev *dev, struct tty *tp)
154{
155 char name[NG_NODESIZ];
156 ng_h4_info_p sc = NULL;
157 int s, error;
158
159 /* Super-user only */
160 error = priv_check(curthread, PRIV_NETGRAPH_TTY); /* XXX */
161 if (error != 0)
162 return (error);
163
164 s = splnet(); /* XXX */
165 spltty(); /* XXX */
166
167 /* Initialize private struct */
168 MALLOC(sc, ng_h4_info_p, sizeof(*sc), M_NETGRAPH_H4, M_NOWAIT|M_ZERO);
169 if (sc == NULL) {
170 error = ENOMEM;
171 goto out;
172 }
173
174 sc->tp = tp;
175 sc->debug = NG_H4_WARN_LEVEL;
176
177 sc->state = NG_H4_W4_PKT_IND;
178 sc->want = 1;
179 sc->got = 0;
180
181 NG_BT_MBUFQ_INIT(&sc->outq, NG_H4_DEFAULTQLEN);
182 ng_callout_init(&sc->timo);
183
184 /* Setup netgraph node */
185 error = ng_make_node_common(&typestruct, &sc->node);
186 if (error != 0) {
187 bzero(sc, sizeof(*sc));
188 FREE(sc, M_NETGRAPH_H4);
189 goto out;
190 }
191
192 /* Assign node its name */
193 snprintf(name, sizeof(name), "%s%d", typestruct.name, ng_h4_node ++);
194
195 error = ng_name_node(sc->node, name);
196 if (error != 0) {
197 NG_H4_ALERT("%s: %s - node name exists?\n", __func__, name);
198 NG_NODE_UNREF(sc->node);
199 bzero(sc, sizeof(*sc));
200 FREE(sc, M_NETGRAPH_H4);
201 goto out;
202 }
203
204 /* Set back pointers */
205 NG_NODE_SET_PRIVATE(sc->node, sc);
206 tp->t_lsc = (caddr_t) sc;
207
208 /* The node has to be a WRITER because data can change node status */
209 NG_NODE_FORCE_WRITER(sc->node);
210
211 /*
212 * Pre-allocate cblocks to the an appropriate amount.
213 * I'm not sure what is appropriate.
214 */
215
216 ttyflush(tp, FREAD | FWRITE);
217 clist_alloc_cblocks(&tp->t_canq, 0, 0);
218 clist_alloc_cblocks(&tp->t_rawq, 0, 0);
219 clist_alloc_cblocks(&tp->t_outq,
220 MLEN + NG_H4_HIWATER, MLEN + NG_H4_HIWATER);
221out:
222 splx(s); /* XXX */
223
224 return (error);
225} /* ng_h4_open */
226
227/*
228 * Line specific close routine, called from device close routine
229 * and from ttioctl. This causes the node to be destroyed as well.
230 */
231
232static int
233ng_h4_close(struct tty *tp, int flag)
234{
235 ng_h4_info_p sc = (ng_h4_info_p) tp->t_lsc;
236 int s;
237
238 s = spltty(); /* XXX */
239
240 ttyflush(tp, FREAD | FWRITE);
241 clist_free_cblocks(&tp->t_outq);
242 if (sc != NULL) {
243 tp->t_lsc = NULL;
244
245 if (sc->node != NULL) {
246 if (sc->flags & NG_H4_TIMEOUT)
247 ng_h4_untimeout(sc->node);
248
249 NG_NODE_SET_PRIVATE(sc->node, NULL);
250 ng_rmnode_self(sc->node);
251 sc->node = NULL;
252 }
253
254 NG_BT_MBUFQ_DESTROY(&sc->outq);
255 bzero(sc, sizeof(*sc));
256 FREE(sc, M_NETGRAPH_H4);
257 }
258
259 splx(s); /* XXX */
260
261 return (0);
262} /* ng_h4_close */
263
264/*
265 * Once the device has been turned into a node, we don't allow reading.
266 */
267
268static int

--- 16 unchanged lines hidden (view full) ---

285 * We implement the NGIOCGINFO ioctl() defined in ng_message.h.
286 */
287
288static int
289ng_h4_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
290 struct thread *td)
291{
292 ng_h4_info_p sc = (ng_h4_info_p) tp->t_lsc;
293 int s, error = 0;
294
295 s = spltty(); /* XXX */
296
297 switch (cmd) {
298 case NGIOCGINFO:
299#undef NI
300#define NI(x) ((struct nodeinfo *)(x))
301
302 bzero(data, sizeof(*NI(data)));
303
304 if (NG_NODE_HAS_NAME(sc->node))

--- 7 unchanged lines hidden (view full) ---

312 NI(data)->hooks = NG_NODE_NUMHOOKS(sc->node);
313 break;
314
315 default:
316 error = ENOIOCTL;
317 break;
318 }
319
320 splx(s); /* XXX */
321
322 return (error);
323} /* ng_h4_ioctl */
324
325/*
326 * Receive data coming from the device. We get one character at a time, which
327 * is kindof silly.
328 */
329
330static int
331ng_h4_input(int c, struct tty *tp)
332{
333 ng_h4_info_p sc = (ng_h4_info_p) tp->t_lsc;
334
335 if (sc == NULL || tp != sc->tp ||
336 sc->node == NULL || NG_NODE_NOT_VALID(sc->node))
337 return (0);
338
339 /* Check for error conditions */
340 if ((sc->tp->t_state & TS_CONNECTED) == 0) {
341 NG_H4_INFO("%s: %s - no carrier\n", __func__,
342 NG_NODE_NAME(sc->node));
343
344 sc->state = NG_H4_W4_PKT_IND;
345 sc->want = 1;
346 sc->got = 0;
347
348 return (0); /* XXX Loss of synchronization here! */
349 }
350
351 /* Check for framing error or overrun on this char */
352 if (c & TTY_ERRORMASK) {
353 NG_H4_ERR("%s: %s - line error %#x, c=%#x\n", __func__,
354 NG_NODE_NAME(sc->node), c & TTY_ERRORMASK,
355 c & TTY_CHARMASK);
356
357 NG_H4_STAT_IERROR(sc->stat);
358
359 sc->state = NG_H4_W4_PKT_IND;
360 sc->want = 1;
361 sc->got = 0;
362
363 return (0); /* XXX Loss of synchronization here! */
364 }
365
366 NG_H4_STAT_BYTES_RECV(sc->stat, 1);
367
368 /* Append char to mbuf */
369 if (sc->got >= sizeof(sc->ibuf)) {
370 NG_H4_ALERT("%s: %s - input buffer overflow, c=%#x, got=%d\n",
371 __func__, NG_NODE_NAME(sc->node), c & TTY_CHARMASK,
372 sc->got);
373
374 NG_H4_STAT_IERROR(sc->stat);
375
376 sc->state = NG_H4_W4_PKT_IND;
377 sc->want = 1;
378 sc->got = 0;
379
380 return (0); /* XXX Loss of synchronization here! */
381 }
382
383 sc->ibuf[sc->got ++] = (c & TTY_CHARMASK);
384
385 NG_H4_INFO("%s: %s - got char %#x, want=%d, got=%d\n", __func__,
386 NG_NODE_NAME(sc->node), c, sc->want, sc->got);
387
388 if (sc->got < sc->want)
389 return (0); /* Wait for more */
390
391 switch (sc->state) {
392 /* Got packet indicator */
393 case NG_H4_W4_PKT_IND:
394 NG_H4_INFO("%s: %s - got packet indicator %#x\n", __func__,
395 NG_NODE_NAME(sc->node), sc->ibuf[0]);
396
397 sc->state = NG_H4_W4_PKT_HDR;

--- 136 unchanged lines hidden (view full) ---

534 NG_H4_STAT_PCKTS_RECV(sc->stat);
535 break;
536
537 default:
538 KASSERT((0), ("Invalid H4 node state=%d", sc->state));
539 break;
540 }
541
542 return (0);
543} /* ng_h4_input */
544
545/*
546 * This is called when the device driver is ready for more output. Called from
547 * tty system.
548 */
549
550static int
551ng_h4_start(struct tty *tp)
552{
553 ng_h4_info_p sc = (ng_h4_info_p) tp->t_lsc;
554
555 if (sc == NULL || tp != sc->tp ||
556 sc->node == NULL || NG_NODE_NOT_VALID(sc->node))
557 return (0);
558
559 return (ng_send_fn(sc->node, NULL, ng_h4_start2, NULL, 0));
560} /* ng_h4_start */
561
562/*
563 * Device driver is ready for more output. Part 2. Called (via ng_send_fn)
564 * ng_h4_start() and from ng_h4_rcvdata() when a new mbuf is available for
565 * output.
566 */
567
568static void
569ng_h4_start2(node_p node, hook_p hook, void *arg1, int arg2)
570{
571 ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(node);
572 struct mbuf *m = NULL;
573 int s, size;
574
575 s = spltty(); /* XXX */
576
577#if 0
578 while (sc->tp->t_outq.c_cc < NG_H4_HIWATER) { /* XXX 2.2 specific ? */
579#else
580 while (1) {
581#endif
582 /* Remove first mbuf from queue */
583 NG_BT_MBUFQ_DEQUEUE(&sc->outq, m);
584 if (m == NULL)
585 break;
586
587 /* Send as much of it as possible */
588 while (m != NULL) {
589 size = m->m_len - b_to_q(mtod(m, u_char *),
590 m->m_len, &sc->tp->t_outq);
591
592 NG_H4_STAT_BYTES_SENT(sc->stat, size);
593
594 m->m_data += size;
595 m->m_len -= size;
596 if (m->m_len > 0)
597 break; /* device can't take no more */
598
599 m = m_free(m);
600 }
601
602 /* Put remainder of mbuf chain (if any) back on queue */
603 if (m != NULL) {
604 NG_BT_MBUFQ_PREPEND(&sc->outq, m);
605 break;
606 }
607
608 /* Full packet has been sent */
609 NG_H4_STAT_PCKTS_SENT(sc->stat);
610 }
611
612 /*
613 * Call output process whether or not there is any output. We are
614 * being called in lieu of ttstart and must do what it would.
615 */
616
617 tt_oproc(sc->tp);
618
619 /*
620 * This timeout is needed for operation on a pseudo-tty, because the
621 * pty code doesn't call pppstart after it has drained the t_outq.
622 */
623
624 if (NG_BT_MBUFQ_LEN(&sc->outq) > 0 && (sc->flags & NG_H4_TIMEOUT) == 0)
625 ng_h4_timeout(node);
626
627 splx(s); /* XXX */
628} /* ng_h4_start2 */
629
630/*****************************************************************************
631 *****************************************************************************
632 ** Netgraph node methods
633 *****************************************************************************
634 *****************************************************************************/
635
636/*
637 * Initialize a new node of this type. We only allow nodes to be created as

--- 14 unchanged lines hidden (view full) ---

652static int
653ng_h4_newhook(node_p node, hook_p hook, const char *name)
654{
655 ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(node);
656
657 if (strcmp(name, NG_H4_HOOK) != 0)
658 return (EINVAL);
659
660 if (sc->hook != NULL)
661 return (EISCONN);
662
663 sc->hook = hook;
664
665 return (0);
666} /* ng_h4_newhook */
667
668/*
669 * Connect hook. Just say yes.
670 */
671
672static int
673ng_h4_connect(hook_p hook)
674{
675 ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
676
677 if (hook != sc->hook) {
678 sc->hook = NULL;
679 return (EINVAL);
680 }
681
682 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
683
684 return (0);
685} /* ng_h4_connect */
686
687/*
688 * Disconnect the hook
689 */
690
691static int
692ng_h4_disconnect(hook_p hook)
693{
694 ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
695
696 /*
697 * We need to check for sc != NULL because we can be called from
698 * ng_h4_clsoe() via ng_rmnode_self()
699 */
700
701 if (sc != NULL) {
702 if (hook != sc->hook)
703 return (EINVAL);
704
705 /* XXX do we have to untimeout and drain out queue? */
706 if (sc->flags & NG_H4_TIMEOUT)
707 ng_h4_untimeout(NG_HOOK_NODE(hook));
708
709 NG_BT_MBUFQ_DRAIN(&sc->outq);
710 sc->state = NG_H4_W4_PKT_IND;
711 sc->want = 1;
712 sc->got = 0;
713
714 sc->hook = NULL;
715 }
716
717 return (0);
718} /* ng_h4_disconnect */
719
720/*
721 * Remove this node. The does the netgraph portion of the shutdown.
722 * This should only be called indirectly from ng_h4_close().
723 */
724
725static int
726ng_h4_shutdown(node_p node)
727{
728 ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(node);
729 char name[NG_NODESIZ];
730
731 /* Let old node go */
732 NG_NODE_SET_PRIVATE(node, NULL);
733 NG_NODE_UNREF(node);
734
735 /* Check if device was closed */
736 if (sc == NULL)
737 goto out;
738
739 /* Setup new netgraph node */
740 if (ng_make_node_common(&typestruct, &sc->node) != 0) {
741 printf("%s: Unable to create new node!\n", __func__);
742 sc->node = NULL;
743 goto out;
744 }
745
746 /* Assign node its name */
747 snprintf(name, sizeof(name), "%s%d", typestruct.name, ng_h4_node ++);
748
749 if (ng_name_node(sc->node, name) != 0) {
750 printf("%s: %s - node name exists?\n", __func__, name);
751 NG_NODE_UNREF(sc->node);
752 sc->node = NULL;
753 goto out;
754 }
755
756 /* The node has to be a WRITER because data can change node status */
757 NG_NODE_FORCE_WRITER(sc->node);
758 NG_NODE_SET_PRIVATE(sc->node, sc);
759out:
760 return (0);
761} /* ng_h4_shutdown */
762
763/*
764 * Receive incoming data from Netgraph system. Put it on our
765 * output queue and start output if necessary.
766 */
767
768static int
769ng_h4_rcvdata(hook_p hook, item_p item)
770{
771 ng_h4_info_p sc = (ng_h4_info_p)NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
772 int error = 0;
773 struct mbuf *m = NULL;
774
775 if (sc == NULL) {
776 error = EHOSTDOWN;
777 goto out;
778 }
779
780 if (hook != sc->hook) {
781 error = EINVAL;
782 goto out;
783 }
784
785 NGI_GET_M(item, m);
786
787 if (NG_BT_MBUFQ_FULL(&sc->outq)) {
788 NG_H4_ERR("%s: %s - dropping mbuf, len=%d\n", __func__,
789 NG_NODE_NAME(sc->node), m->m_pkthdr.len);
790
791 NG_BT_MBUFQ_DROP(&sc->outq);
792 NG_H4_STAT_OERROR(sc->stat);
793
794 NG_FREE_M(m);
795 error = ENOBUFS;
796 } else {
797 NG_H4_INFO("%s: %s - queue mbuf, len=%d\n", __func__,
798 NG_NODE_NAME(sc->node), m->m_pkthdr.len);
799
800 NG_BT_MBUFQ_ENQUEUE(&sc->outq, m);
801
802 /*
803 * We have lock on the node, so we can call ng_h4_start2()
804 * directly
805 */
806
807 ng_h4_start2(sc->node, NULL, NULL, 0);
808 }
809out:
810 NG_FREE_ITEM(item);
811
812 return (error);
813} /* ng_h4_rcvdata */
814
815/*
816 * Receive control message
817 */
818
819static int
820ng_h4_rcvmsg(node_p node, item_p item, hook_p lasthook)
821{
822 ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(node);
823 struct ng_mesg *msg = NULL, *resp = NULL;
824 int error = 0;
825
826 if (sc == NULL) {
827 error = EHOSTDOWN;
828 goto out;
829 }
830
831 NGI_GET_MSG(item, msg);
832
833 switch (msg->header.typecookie) {
834 case NGM_GENERIC_COOKIE:
835 switch (msg->header.cmd) {
836 case NGM_TEXT_STATUS:
837 NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT);
838 if (resp == NULL)
839 error = ENOMEM;
840 else
841 snprintf(resp->data, NG_TEXTRESPONSE,
842 "Hook: %s\n" \
843 "Flags: %#x\n" \
844 "Debug: %d\n" \
845 "State: %d\n" \
846 "Queue: [have:%d,max:%d]\n" \
847 "Input: [got:%d,want:%d]",
848 (sc->hook != NULL)? NG_H4_HOOK : "",
849 sc->flags,
850 sc->debug,
851 sc->state,
852 NG_BT_MBUFQ_LEN(&sc->outq),
853 sc->outq.maxlen,
854 sc->got,
855 sc->want);
856 break;
857
858 default:
859 error = EINVAL;
860 break;
861 }
862 break;
863
864 case NGM_H4_COOKIE:
865 switch (msg->header.cmd) {
866 case NGM_H4_NODE_RESET:
867 NG_BT_MBUFQ_DRAIN(&sc->outq);
868 sc->state = NG_H4_W4_PKT_IND;
869 sc->want = 1;
870 sc->got = 0;
871 break;
872
873 case NGM_H4_NODE_GET_STATE:
874 NG_MKRESPONSE(resp, msg, sizeof(ng_h4_node_state_ep),
875 M_NOWAIT);

--- 24 unchanged lines hidden (view full) ---

900
901 case NGM_H4_NODE_GET_QLEN:
902 NG_MKRESPONSE(resp, msg, sizeof(ng_h4_node_qlen_ep),
903 M_NOWAIT);
904 if (resp == NULL)
905 error = ENOMEM;
906 else
907 *((ng_h4_node_qlen_ep *)(resp->data)) =
908 sc->outq.maxlen;
909 break;
910
911 case NGM_H4_NODE_SET_QLEN:
912 if (msg->header.arglen != sizeof(ng_h4_node_qlen_ep))
913 error = EMSGSIZE;
914 else if (*((ng_h4_node_qlen_ep *)(msg->data)) <= 0)
915 error = EINVAL;
916 else
917 sc->outq.maxlen =
918 *((ng_h4_node_qlen_ep *)(msg->data));
919 break;
920
921 case NGM_H4_NODE_GET_STAT:
922 NG_MKRESPONSE(resp, msg, sizeof(ng_h4_node_stat_ep),
923 M_NOWAIT);
924 if (resp == NULL)
925 error = ENOMEM;
926 else

--- 10 unchanged lines hidden (view full) ---

937 break;
938 }
939 break;
940
941 default:
942 error = EINVAL;
943 break;
944 }
945out:
946 NG_RESPOND_MSG(error, node, item, resp);
947 NG_FREE_MSG(msg);
948
949 return (error);
950} /* ng_h4_rcvmsg */
951
952/*
953 * Set timeout
954 */
955
956static void
957ng_h4_timeout(node_p node)
958{
959 ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(node);
960
961 ng_callout(&sc->timo, node, NULL, 1, ng_h4_process_timeout, NULL, 0);
962 sc->flags |= NG_H4_TIMEOUT;
963} /* ng_h4_timeout */
964
965/*
966 * Unset timeout
967 */
968
969static void
970ng_h4_untimeout(node_p node)
971{
972 ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(node);
973
974 sc->flags &= ~NG_H4_TIMEOUT;
975 ng_uncallout(&sc->timo, node);
976} /* ng_h4_untimeout */
977
978/*
979 * Timeout processing function.
980 * We still have data to output to the device, so try sending more.
981 */
982
983static void
984ng_h4_process_timeout(node_p node, hook_p hook, void *arg1, int arg2)
985{
986 ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(node);
987
988 sc->flags &= ~NG_H4_TIMEOUT;
989
990 /*
991 * We can call ng_h4_start2() directly here because we have lock
992 * on the node.
993 */
994
995 ng_h4_start2(node, NULL, NULL, 0);
996} /* ng_h4_process_timeout */
997
998/*
999 * Handle loading and unloading for this node type
1000 */
1001
1002static int
1003ng_h4_mod_event(module_t mod, int event, void *data)
1004{
1005 static int ng_h4_ldisc;
1006 int s, error = 0;
1007
1008 s = spltty(); /* XXX */
1009
1010 switch (event) {
1011 case MOD_LOAD:
1012 /* Register line discipline */
1013 ng_h4_ldisc = ldisc_register(H4DISC, &ng_h4_disc);
1014 if (ng_h4_ldisc < 0) {
1015 printf("%s: can't register H4 line discipline\n",
1016 __func__);
1017 error = EIO;
1018 }
1019 break;
1020
1021 case MOD_UNLOAD:
1022 /* Unregister line discipline */
1023 ldisc_deregister(ng_h4_ldisc);
1024 break;
1025
1026 default:
1027 error = EOPNOTSUPP;
1028 break;
1029 }
1030
1031 splx(s); /* XXX */
1032
1033 return (error);
1034} /* ng_h4_mod_event */
1035