6 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
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
30 * $Id: ng_h4.c,v 1.10 2005/10/31 17:57:43 max Exp $
31 * $FreeBSD: src/sys/netgraph/bluetooth/drivers/h4/ng_h4.c,v 1.17 2007/08/13 17:19:28 emax Exp $
36 * FreeBSD: src/sys/netgraph/ng_tty.c
37 * Author: Archie Cobbs <archie@freebsd.org>
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.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>
52 #include <sys/socket.h>
54 #include <sys/ttycom.h>
56 #include <net/if_var.h>
57 #include <netgraph/ng_message.h>
58 #include <netgraph/netgraph.h>
59 #include <netgraph/ng_parse.h>
60 #include <netgraph/bluetooth/include/ng_bluetooth.h>
61 #include <netgraph/bluetooth/include/ng_hci.h>
62 #include <netgraph/bluetooth/include/ng_h4.h>
63 #include <netgraph/bluetooth/drivers/h4/ng_h4_var.h>
64 #include <netgraph/bluetooth/drivers/h4/ng_h4_prse.h>
66 /*****************************************************************************
67 *****************************************************************************
68 ** This node implements a Bluetooth HCI UART transport layer as per chapter
69 ** H4 of the Bluetooth Specification Book v1.1. It is a terminal line
70 ** discipline that is also a netgraph node. Installing this line discipline
71 ** on a terminal device instantiates a new netgraph node of this type, which
72 ** allows access to the device via the "hook" hook of the node.
74 ** Once the line discipline is installed, you can find out the name of the
75 ** corresponding netgraph node via a NGIOCGINFO ioctl().
76 *****************************************************************************
77 *****************************************************************************/
80 #ifndef NG_SEPARATE_MALLOC
81 MALLOC_DEFINE(M_NETGRAPH_H4
, "netgraph_h4", "Netgraph Bluetooth H4 node");
83 #define M_NETGRAPH_H4 M_NETGRAPH
84 #endif /* NG_SEPARATE_MALLOC */
86 /* Line discipline methods */
87 static int ng_h4_open (struct cdev
*, struct tty
*);
88 static int ng_h4_close (struct tty
*, int);
89 static int ng_h4_read (struct tty
*, struct uio
*, int);
90 static int ng_h4_write (struct tty
*, struct uio
*, int);
91 static int ng_h4_input (int, struct tty
*);
92 static int ng_h4_start (struct tty
*);
93 static int ng_h4_ioctl (struct tty
*, u_long
, caddr_t
,
94 int, struct thread
*);
96 /* Line discipline descriptor */
97 static struct linesw ng_h4_disc
= {
98 ng_h4_open
, /* open */
99 ng_h4_close
, /* close */
100 ng_h4_read
, /* read */
101 ng_h4_write
, /* write */
102 ng_h4_ioctl
, /* ioctl */
103 ng_h4_input
, /* input */
104 ng_h4_start
, /* start */
108 /* Netgraph methods */
109 static ng_constructor_t ng_h4_constructor
;
110 static ng_rcvmsg_t ng_h4_rcvmsg
;
111 static ng_shutdown_t ng_h4_shutdown
;
112 static ng_newhook_t ng_h4_newhook
;
113 static ng_connect_t ng_h4_connect
;
114 static ng_rcvdata_t ng_h4_rcvdata
;
115 static ng_disconnect_t ng_h4_disconnect
;
118 static void ng_h4_process_timeout (node_p
, hook_p
, void *, int);
119 static int ng_h4_mod_event (module_t
, int, void *);
121 /* Netgraph node type descriptor */
122 static struct ng_type typestruct
= {
123 .version
= NG_ABI_VERSION
,
124 .name
= NG_H4_NODE_TYPE
,
125 .mod_event
= ng_h4_mod_event
,
126 .constructor
= ng_h4_constructor
,
127 .rcvmsg
= ng_h4_rcvmsg
,
128 .shutdown
= ng_h4_shutdown
,
129 .newhook
= ng_h4_newhook
,
130 .connect
= ng_h4_connect
,
131 .rcvdata
= ng_h4_rcvdata
,
132 .disconnect
= ng_h4_disconnect
,
133 .cmdlist
= ng_h4_cmdlist
135 NETGRAPH_INIT(h4
, &typestruct
);
136 MODULE_VERSION(ng_h4
, NG_BLUETOOTH_VERSION
);
138 static int ng_h4_node
= 0;
140 /*****************************************************************************
141 *****************************************************************************
142 ** Line discipline methods
143 *****************************************************************************
144 *****************************************************************************/
147 * Set our line discipline on the tty.
151 ng_h4_open(struct cdev
*dev
, struct tty
*tp
)
153 struct thread
*td
= curthread
;
154 char name
[NG_NODESIZ
];
155 ng_h4_info_p sc
= NULL
;
158 /* Super-user only */
159 error
= priv_check(td
, PRIV_NETGRAPH_TTY
); /* XXX */
163 /* Initialize private struct */
164 MALLOC(sc
, ng_h4_info_p
, sizeof(*sc
), M_NETGRAPH_H4
, M_NOWAIT
|M_ZERO
);
169 sc
->debug
= NG_H4_WARN_LEVEL
;
171 sc
->state
= NG_H4_W4_PKT_IND
;
175 mtx_init(&sc
->outq
.ifq_mtx
, "ng_h4 node+queue", NULL
, MTX_DEF
);
176 IFQ_SET_MAXLEN(&sc
->outq
, NG_H4_DEFAULTQLEN
);
177 ng_callout_init(&sc
->timo
);
181 /* Setup netgraph node */
182 error
= ng_make_node_common(&typestruct
, &sc
->node
);
186 printf("%s: Unable to create new node!\n", __func__
);
188 mtx_destroy(&sc
->outq
.ifq_mtx
);
189 bzero(sc
, sizeof(*sc
));
190 FREE(sc
, M_NETGRAPH_H4
);
195 /* Assign node its name */
196 snprintf(name
, sizeof(name
), "%s%d", typestruct
.name
, ng_h4_node
++);
198 error
= ng_name_node(sc
->node
, name
);
202 printf("%s: %s - node name exists?\n", __func__
, name
);
204 NG_NODE_UNREF(sc
->node
);
205 mtx_destroy(&sc
->outq
.ifq_mtx
);
206 bzero(sc
, sizeof(*sc
));
207 FREE(sc
, M_NETGRAPH_H4
);
212 /* Set back pointers */
213 NG_NODE_SET_PRIVATE(sc
->node
, sc
);
214 tp
->t_lsc
= (caddr_t
) sc
;
216 /* The node has to be a WRITER because data can change node status */
217 NG_NODE_FORCE_WRITER(sc
->node
);
220 * Pre-allocate cblocks to the an appropriate amount.
221 * I'm not sure what is appropriate.
224 ttyflush(tp
, FREAD
| FWRITE
);
225 clist_alloc_cblocks(&tp
->t_canq
, 0, 0);
226 clist_alloc_cblocks(&tp
->t_rawq
, 0, 0);
227 clist_alloc_cblocks(&tp
->t_outq
,
228 MLEN
+ NG_H4_HIWATER
, MLEN
+ NG_H4_HIWATER
);
236 * Line specific close routine, called from device close routine
237 * and from ttioctl. This causes the node to be destroyed as well.
241 ng_h4_close(struct tty
*tp
, int flag
)
243 ng_h4_info_p sc
= (ng_h4_info_p
) tp
->t_lsc
;
245 ttyflush(tp
, FREAD
| FWRITE
);
246 clist_free_cblocks(&tp
->t_outq
);
251 if (callout_pending(&sc
->timo
))
252 ng_uncallout(&sc
->timo
, sc
->node
);
259 ng_rmnode_self(sc
->node
);
266 * Once the device has been turned into a node, we don't allow reading.
270 ng_h4_read(struct tty
*tp
, struct uio
*uio
, int flag
)
276 * Once the device has been turned into a node, we don't allow writing.
280 ng_h4_write(struct tty
*tp
, struct uio
*uio
, int flag
)
286 * We implement the NGIOCGINFO ioctl() defined in ng_message.h.
290 ng_h4_ioctl(struct tty
*tp
, u_long cmd
, caddr_t data
, int flag
,
293 ng_h4_info_p sc
= (ng_h4_info_p
) tp
->t_lsc
;
304 #define NI(x) ((struct nodeinfo *)(x))
306 bzero(data
, sizeof(*NI(data
)));
308 if (NG_NODE_HAS_NAME(sc
->node
))
309 strncpy(NI(data
)->name
, NG_NODE_NAME(sc
->node
),
310 sizeof(NI(data
)->name
) - 1);
312 strncpy(NI(data
)->type
, sc
->node
->nd_type
->name
,
313 sizeof(NI(data
)->type
) - 1);
315 NI(data
)->id
= (u_int32_t
) ng_node2ID(sc
->node
);
316 NI(data
)->hooks
= NG_NODE_NUMHOOKS(sc
->node
);
330 * Receive data coming from the device. We get one character at a time, which
335 ng_h4_input(int c
, struct tty
*tp
)
337 ng_h4_info_p sc
= (ng_h4_info_p
) tp
->t_lsc
;
339 if (sc
== NULL
|| tp
!= sc
->tp
||
340 sc
->node
== NULL
|| NG_NODE_NOT_VALID(sc
->node
))
345 /* Check for error conditions */
346 if ((tp
->t_state
& TS_CONNECTED
) == 0) {
347 NG_H4_INFO("%s: %s - no carrier\n", __func__
,
348 NG_NODE_NAME(sc
->node
));
350 sc
->state
= NG_H4_W4_PKT_IND
;
356 return (0); /* XXX Loss of synchronization here! */
359 /* Check for framing error or overrun on this char */
360 if (c
& TTY_ERRORMASK
) {
361 NG_H4_ERR("%s: %s - line error %#x, c=%#x\n", __func__
,
362 NG_NODE_NAME(sc
->node
), c
& TTY_ERRORMASK
,
365 NG_H4_STAT_IERROR(sc
->stat
);
367 sc
->state
= NG_H4_W4_PKT_IND
;
373 return (0); /* XXX Loss of synchronization here! */
376 NG_H4_STAT_BYTES_RECV(sc
->stat
, 1);
378 /* Append char to mbuf */
379 if (sc
->got
>= sizeof(sc
->ibuf
)) {
380 NG_H4_ALERT("%s: %s - input buffer overflow, c=%#x, got=%d\n",
381 __func__
, NG_NODE_NAME(sc
->node
), c
& TTY_CHARMASK
,
384 NG_H4_STAT_IERROR(sc
->stat
);
386 sc
->state
= NG_H4_W4_PKT_IND
;
392 return (0); /* XXX Loss of synchronization here! */
395 sc
->ibuf
[sc
->got
++] = (c
& TTY_CHARMASK
);
397 NG_H4_INFO("%s: %s - got char %#x, want=%d, got=%d\n", __func__
,
398 NG_NODE_NAME(sc
->node
), c
, sc
->want
, sc
->got
);
400 if (sc
->got
< sc
->want
) {
403 return (0); /* Wait for more */
407 /* Got packet indicator */
408 case NG_H4_W4_PKT_IND
:
409 NG_H4_INFO("%s: %s - got packet indicator %#x\n", __func__
,
410 NG_NODE_NAME(sc
->node
), sc
->ibuf
[0]);
412 sc
->state
= NG_H4_W4_PKT_HDR
;
415 * Since packet indicator included in the packet header
416 * just set sc->want to sizeof(packet header).
419 switch (sc
->ibuf
[0]) {
420 case NG_HCI_ACL_DATA_PKT
:
421 sc
->want
= sizeof(ng_hci_acldata_pkt_t
);
424 case NG_HCI_SCO_DATA_PKT
:
425 sc
->want
= sizeof(ng_hci_scodata_pkt_t
);
428 case NG_HCI_EVENT_PKT
:
429 sc
->want
= sizeof(ng_hci_event_pkt_t
);
433 NG_H4_WARN("%s: %s - ignoring unknown packet " \
434 "type=%#x\n", __func__
, NG_NODE_NAME(sc
->node
),
437 NG_H4_STAT_IERROR(sc
->stat
);
439 sc
->state
= NG_H4_W4_PKT_IND
;
446 /* Got packet header */
447 case NG_H4_W4_PKT_HDR
:
448 sc
->state
= NG_H4_W4_PKT_DATA
;
450 switch (sc
->ibuf
[0]) {
451 case NG_HCI_ACL_DATA_PKT
:
452 c
= le16toh(((ng_hci_acldata_pkt_t
*)
453 (sc
->ibuf
))->length
);
456 case NG_HCI_SCO_DATA_PKT
:
457 c
= ((ng_hci_scodata_pkt_t
*)(sc
->ibuf
))->length
;
460 case NG_HCI_EVENT_PKT
:
461 c
= ((ng_hci_event_pkt_t
*)(sc
->ibuf
))->length
;
465 KASSERT((0), ("Invalid packet type=%#x\n",
470 NG_H4_INFO("%s: %s - got packet header, packet type=%#x, " \
471 "packet size=%d, payload size=%d\n", __func__
,
472 NG_NODE_NAME(sc
->node
), sc
->ibuf
[0], sc
->got
, c
);
478 * Try to prevent possible buffer overrun
480 * XXX I'm *really* confused here. It turns out
481 * that Xircom card sends us packets with length
482 * greater then 512 bytes! This is greater then
483 * our old receive buffer (ibuf) size. In the same
484 * time the card demands from us *not* to send
485 * packets greater then 192 bytes. Weird! How the
486 * hell i should know how big *receive* buffer
487 * should be? For now increase receiving buffer
488 * size to 1K and add the following check.
491 if (sc
->want
>= sizeof(sc
->ibuf
)) {
494 NG_H4_ALERT("%s: %s - packet too big for " \
495 "buffer, type=%#x, got=%d, want=%d, " \
496 "length=%d\n", __func__
,
497 NG_NODE_NAME(sc
->node
), sc
->ibuf
[0],
498 sc
->got
, sc
->want
, c
);
500 NG_H4_ALERT("Packet header:\n");
501 for (b
= 0; b
< sc
->got
; b
++)
502 NG_H4_ALERT("%#x ", sc
->ibuf
[b
]);
506 NG_H4_STAT_IERROR(sc
->stat
);
508 sc
->state
= NG_H4_W4_PKT_IND
;
516 /* else FALLTHROUGH and deliver frame */
517 /* XXX Is this true? Should we deliver empty frame? */
519 /* Got packet data */
520 case NG_H4_W4_PKT_DATA
:
521 NG_H4_INFO("%s: %s - got full packet, packet type=%#x, " \
522 "packet size=%d\n", __func__
,
523 NG_NODE_NAME(sc
->node
), sc
->ibuf
[0], sc
->got
);
525 if (sc
->hook
!= NULL
&& NG_HOOK_IS_VALID(sc
->hook
)) {
526 struct mbuf
*m
= NULL
;
528 MGETHDR(m
, M_DONTWAIT
, MT_DATA
);
532 /* XXX m_copyback() is stupid */
533 m
->m_len
= min(MHLEN
, sc
->got
);
535 m_copyback(m
, 0, sc
->got
, sc
->ibuf
);
536 NG_SEND_DATA_ONLY(c
, sc
->hook
, m
);
538 NG_H4_ERR("%s: %s - could not get mbuf\n",
539 __func__
, NG_NODE_NAME(sc
->node
));
541 NG_H4_STAT_IERROR(sc
->stat
);
545 sc
->state
= NG_H4_W4_PKT_IND
;
549 NG_H4_STAT_PCKTS_RECV(sc
->stat
);
553 KASSERT((0), ("Invalid H4 node state=%d", sc
->state
));
563 * This is called when the device driver is ready for more output. Called from
568 ng_h4_start(struct tty
*tp
)
570 ng_h4_info_p sc
= (ng_h4_info_p
) tp
->t_lsc
;
571 struct mbuf
*m
= NULL
;
574 if (sc
== NULL
|| tp
!= sc
->tp
||
575 sc
->node
== NULL
|| NG_NODE_NOT_VALID(sc
->node
))
579 while (tp
->t_outq
.c_cc
< NG_H4_HIWATER
) { /* XXX 2.2 specific ? */
583 /* Remove first mbuf from queue */
584 IF_DEQUEUE(&sc
->outq
, m
);
588 /* Send as much of it as possible */
590 size
= m
->m_len
- b_to_q(mtod(m
, u_char
*),
591 m
->m_len
, &tp
->t_outq
);
594 NG_H4_STAT_BYTES_SENT(sc
->stat
, size
);
600 break; /* device can't take no more */
605 /* Put remainder of mbuf chain (if any) back on queue */
607 IF_PREPEND(&sc
->outq
, m
);
611 /* Full packet has been sent */
613 NG_H4_STAT_PCKTS_SENT(sc
->stat
);
618 * Call output process whether or not there is any output. We are
619 * being called in lieu of ttstart and must do what it would.
625 * This timeout is needed for operation on a pseudo-tty, because the
626 * pty code doesn't call pppstart after it has drained the t_outq.
631 if (!IFQ_IS_EMPTY(&sc
->outq
) && !callout_pending(&sc
->timo
))
632 ng_callout(&sc
->timo
, sc
->node
, NULL
, 1,
633 ng_h4_process_timeout
, NULL
, 0);
640 /*****************************************************************************
641 *****************************************************************************
642 ** Netgraph node methods
643 *****************************************************************************
644 *****************************************************************************/
647 * Initialize a new node of this type. We only allow nodes to be created as
648 * a result of setting the line discipline on a tty, so always return an error
653 ng_h4_constructor(node_p node
)
656 } /* ng_h4_constructor */
659 * Add a new hook. There can only be one.
663 ng_h4_newhook(node_p node
, hook_p hook
, const char *name
)
665 ng_h4_info_p sc
= (ng_h4_info_p
) NG_NODE_PRIVATE(node
);
667 if (strcmp(name
, NG_H4_HOOK
) != 0)
672 if (sc
->hook
!= NULL
) {
681 } /* ng_h4_newhook */
684 * Connect hook. Just say yes.
688 ng_h4_connect(hook_p hook
)
690 ng_h4_info_p sc
= (ng_h4_info_p
) NG_NODE_PRIVATE(NG_HOOK_NODE(hook
));
692 if (hook
!= sc
->hook
)
693 panic("%s: hook != sc->hook\n", __func__
);
695 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook
));
696 NG_HOOK_FORCE_QUEUE(hook
);
699 } /* ng_h4_connect */
702 * Disconnect the hook
706 ng_h4_disconnect(hook_p hook
)
708 ng_h4_info_p sc
= (ng_h4_info_p
) NG_NODE_PRIVATE(NG_HOOK_NODE(hook
));
711 * We need to check for sc != NULL because we can be called from
712 * ng_h4_close() via ng_rmnode_self()
716 if (hook
!= sc
->hook
)
717 panic("%s: hook != sc->hook\n", __func__
);
721 /* XXX do we have to untimeout and drain out queue? */
722 if (callout_pending(&sc
->timo
))
723 ng_uncallout(&sc
->timo
, sc
->node
);
725 _IF_DRAIN(&sc
->outq
);
727 sc
->state
= NG_H4_W4_PKT_IND
;
737 } /* ng_h4_disconnect */
740 * Remove this node. The does the netgraph portion of the shutdown.
741 * This should only be called indirectly from ng_h4_close().
745 ng_h4_shutdown(node_p node
)
747 ng_h4_info_p sc
= (ng_h4_info_p
) NG_NODE_PRIVATE(node
);
754 NG_NODE_REVIVE(node
); /* we will persist */
761 NG_NODE_SET_PRIVATE(node
, NULL
);
763 _IF_DRAIN(&sc
->outq
);
766 mtx_destroy(&sc
->outq
.ifq_mtx
);
767 bzero(sc
, sizeof(*sc
));
768 FREE(sc
, M_NETGRAPH_H4
);
771 } /* ng_h4_shutdown */
774 * Receive incoming data from Netgraph system. Put it on our
775 * output queue and start output if necessary.
779 ng_h4_rcvdata(hook_p hook
, item_p item
)
781 ng_h4_info_p sc
= (ng_h4_info_p
)NG_NODE_PRIVATE(NG_HOOK_NODE(hook
));
782 struct mbuf
*m
= NULL
;
788 if (hook
!= sc
->hook
)
789 panic("%s: hook != sc->hook\n", __func__
);
796 if (_IF_QFULL(&sc
->outq
)) {
797 NG_H4_ERR("%s: %s - dropping mbuf, len=%d\n", __func__
,
798 NG_NODE_NAME(sc
->node
), m
->m_pkthdr
.len
);
800 NG_H4_STAT_OERROR(sc
->stat
);
810 NG_H4_INFO("%s: %s - queue mbuf, len=%d\n", __func__
,
811 NG_NODE_NAME(sc
->node
), m
->m_pkthdr
.len
);
813 _IF_ENQUEUE(&sc
->outq
, m
);
814 qlen
= _IF_QLEN(&sc
->outq
);
819 * If qlen > 1, then we should already have a scheduled callout
829 } /* ng_h4_rcvdata */
832 * Receive control message
836 ng_h4_rcvmsg(node_p node
, item_p item
, hook_p lasthook
)
838 ng_h4_info_p sc
= (ng_h4_info_p
) NG_NODE_PRIVATE(node
);
839 struct ng_mesg
*msg
= NULL
, *resp
= NULL
;
845 NGI_GET_MSG(item
, msg
);
848 switch (msg
->header
.typecookie
) {
849 case NGM_GENERIC_COOKIE
:
850 switch (msg
->header
.cmd
) {
851 case NGM_TEXT_STATUS
:
852 NG_MKRESPONSE(resp
, msg
, NG_TEXTRESPONSE
, M_NOWAIT
);
856 snprintf(resp
->data
, NG_TEXTRESPONSE
,
860 "Queue: [have:%d,max:%d]\n" \
861 "Input: [got:%d,want:%d]",
862 (sc
->hook
!= NULL
)? NG_H4_HOOK
: "",
878 switch (msg
->header
.cmd
) {
879 case NGM_H4_NODE_RESET
:
880 _IF_DRAIN(&sc
->outq
);
881 sc
->state
= NG_H4_W4_PKT_IND
;
886 case NGM_H4_NODE_GET_STATE
:
887 NG_MKRESPONSE(resp
, msg
, sizeof(ng_h4_node_state_ep
),
892 *((ng_h4_node_state_ep
*)(resp
->data
)) =
896 case NGM_H4_NODE_GET_DEBUG
:
897 NG_MKRESPONSE(resp
, msg
, sizeof(ng_h4_node_debug_ep
),
902 *((ng_h4_node_debug_ep
*)(resp
->data
)) =
906 case NGM_H4_NODE_SET_DEBUG
:
907 if (msg
->header
.arglen
!= sizeof(ng_h4_node_debug_ep
))
911 *((ng_h4_node_debug_ep
*)(msg
->data
));
914 case NGM_H4_NODE_GET_QLEN
:
915 NG_MKRESPONSE(resp
, msg
, sizeof(ng_h4_node_qlen_ep
),
920 *((ng_h4_node_qlen_ep
*)(resp
->data
)) =
924 case NGM_H4_NODE_SET_QLEN
:
925 if (msg
->header
.arglen
!= sizeof(ng_h4_node_qlen_ep
))
927 else if (*((ng_h4_node_qlen_ep
*)(msg
->data
)) <= 0)
930 IFQ_SET_MAXLEN(&sc
->outq
,
931 *((ng_h4_node_qlen_ep
*)(msg
->data
)));
934 case NGM_H4_NODE_GET_STAT
:
935 NG_MKRESPONSE(resp
, msg
, sizeof(ng_h4_node_stat_ep
),
940 bcopy(&sc
->stat
, resp
->data
,
941 sizeof(ng_h4_node_stat_ep
));
944 case NGM_H4_NODE_RESET_STAT
:
945 NG_H4_STAT_RESET(sc
->stat
);
961 NG_RESPOND_MSG(error
, node
, item
, resp
);
968 * Timeout processing function.
969 * We still have data to output to the device, so try sending more.
973 ng_h4_process_timeout(node_p node
, hook_p hook
, void *arg1
, int arg2
)
975 ng_h4_info_p sc
= (ng_h4_info_p
) NG_NODE_PRIVATE(node
);
980 } /* ng_h4_process_timeout */
983 * Handle loading and unloading for this node type
987 ng_h4_mod_event(module_t mod
, int event
, void *data
)
989 static int ng_h4_ldisc
;
994 /* Register line discipline */
996 ng_h4_ldisc
= ldisc_register(H4DISC
, &ng_h4_disc
);
999 if (ng_h4_ldisc
< 0) {
1000 printf("%s: can't register H4 line discipline\n",
1007 /* Unregister line discipline */
1009 ldisc_deregister(ng_h4_ldisc
);
1019 } /* ng_h4_mod_event */