Vendor import of netgraph from FreeBSD-current 20080626
[dragonfly.git] / sys / netgraph7 / bluetooth / drivers / h4 / ng_h4.c
bloba6c8316b75d961b11d3d73b5b55338e4caf687a0
1 /*
2 * ng_h4.c
3 */
5 /*-
6 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7 * All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
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
28 * SUCH DAMAGE.
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 $
33 * Based on:
34 * ---------
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>
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/socket.h>
53 #include <sys/tty.h>
54 #include <sys/ttycom.h>
55 #include <net/if.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 *****************************************************************************/
79 /* MALLOC define */
80 #ifndef NG_SEPARATE_MALLOC
81 MALLOC_DEFINE(M_NETGRAPH_H4, "netgraph_h4", "Netgraph Bluetooth H4 node");
82 #else
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 */
105 ttymodem /* modem */
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;
117 /* Other stuff */
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.
150 static int
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;
156 int error;
158 /* Super-user only */
159 error = priv_check(td, PRIV_NETGRAPH_TTY); /* XXX */
160 if (error != 0)
161 return (error);
163 /* Initialize private struct */
164 MALLOC(sc, ng_h4_info_p, sizeof(*sc), M_NETGRAPH_H4, M_NOWAIT|M_ZERO);
165 if (sc == NULL)
166 return (ENOMEM);
168 sc->tp = tp;
169 sc->debug = NG_H4_WARN_LEVEL;
171 sc->state = NG_H4_W4_PKT_IND;
172 sc->want = 1;
173 sc->got = 0;
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);
179 NG_H4_LOCK(sc);
181 /* Setup netgraph node */
182 error = ng_make_node_common(&typestruct, &sc->node);
183 if (error != 0) {
184 NG_H4_UNLOCK(sc);
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);
192 return (error);
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);
199 if (error != 0) {
200 NG_H4_UNLOCK(sc);
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);
209 return (error);
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);
230 NG_H4_UNLOCK(sc);
232 return (error);
233 } /* ng_h4_open */
236 * Line specific close routine, called from device close routine
237 * and from ttioctl. This causes the node to be destroyed as well.
240 static int
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);
248 if (sc != NULL) {
249 NG_H4_LOCK(sc);
251 if (callout_pending(&sc->timo))
252 ng_uncallout(&sc->timo, sc->node);
254 tp->t_lsc = NULL;
255 sc->dying = 1;
257 NG_H4_UNLOCK(sc);
259 ng_rmnode_self(sc->node);
262 return (0);
263 } /* ng_h4_close */
266 * Once the device has been turned into a node, we don't allow reading.
269 static int
270 ng_h4_read(struct tty *tp, struct uio *uio, int flag)
272 return (EIO);
273 } /* ng_h4_read */
276 * Once the device has been turned into a node, we don't allow writing.
279 static int
280 ng_h4_write(struct tty *tp, struct uio *uio, int flag)
282 return (EIO);
283 } /* ng_h4_write */
286 * We implement the NGIOCGINFO ioctl() defined in ng_message.h.
289 static int
290 ng_h4_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
291 struct thread *td)
293 ng_h4_info_p sc = (ng_h4_info_p) tp->t_lsc;
294 int error = 0;
296 if (sc == NULL)
297 return (ENXIO);
299 NG_H4_LOCK(sc);
301 switch (cmd) {
302 case NGIOCGINFO:
303 #undef NI
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);
317 break;
319 default:
320 error = ENOIOCTL;
321 break;
324 NG_H4_UNLOCK(sc);
326 return (error);
327 } /* ng_h4_ioctl */
330 * Receive data coming from the device. We get one character at a time, which
331 * is kindof silly.
334 static int
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))
341 return (0);
343 NG_H4_LOCK(sc);
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;
351 sc->want = 1;
352 sc->got = 0;
354 NG_H4_UNLOCK(sc);
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,
363 c & TTY_CHARMASK);
365 NG_H4_STAT_IERROR(sc->stat);
367 sc->state = NG_H4_W4_PKT_IND;
368 sc->want = 1;
369 sc->got = 0;
371 NG_H4_UNLOCK(sc);
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,
382 sc->got);
384 NG_H4_STAT_IERROR(sc->stat);
386 sc->state = NG_H4_W4_PKT_IND;
387 sc->want = 1;
388 sc->got = 0;
390 NG_H4_UNLOCK(sc);
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) {
401 NG_H4_UNLOCK(sc);
403 return (0); /* Wait for more */
406 switch (sc->state) {
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);
422 break;
424 case NG_HCI_SCO_DATA_PKT:
425 sc->want = sizeof(ng_hci_scodata_pkt_t);
426 break;
428 case NG_HCI_EVENT_PKT:
429 sc->want = sizeof(ng_hci_event_pkt_t);
430 break;
432 default:
433 NG_H4_WARN("%s: %s - ignoring unknown packet " \
434 "type=%#x\n", __func__, NG_NODE_NAME(sc->node),
435 sc->ibuf[0]);
437 NG_H4_STAT_IERROR(sc->stat);
439 sc->state = NG_H4_W4_PKT_IND;
440 sc->want = 1;
441 sc->got = 0;
442 break;
444 break;
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);
454 break;
456 case NG_HCI_SCO_DATA_PKT:
457 c = ((ng_hci_scodata_pkt_t *)(sc->ibuf))->length;
458 break;
460 case NG_HCI_EVENT_PKT:
461 c = ((ng_hci_event_pkt_t *)(sc->ibuf))->length;
462 break;
464 default:
465 KASSERT((0), ("Invalid packet type=%#x\n",
466 sc->ibuf[0]));
467 break;
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);
474 if (c > 0) {
475 sc->want += 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)) {
492 int b;
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]);
503 NG_H4_ALERT("\n");
505 /* Reset state */
506 NG_H4_STAT_IERROR(sc->stat);
508 sc->state = NG_H4_W4_PKT_IND;
509 sc->want = 1;
510 sc->got = 0;
513 break;
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);
529 if (m != NULL) {
530 m->m_pkthdr.len = 0;
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);
537 } else {
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;
546 sc->want = 1;
547 sc->got = 0;
549 NG_H4_STAT_PCKTS_RECV(sc->stat);
550 break;
552 default:
553 KASSERT((0), ("Invalid H4 node state=%d", sc->state));
554 break;
557 NG_H4_UNLOCK(sc);
559 return (0);
560 } /* ng_h4_input */
563 * This is called when the device driver is ready for more output. Called from
564 * tty system.
567 static int
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;
572 int size;
574 if (sc == NULL || tp != sc->tp ||
575 sc->node == NULL || NG_NODE_NOT_VALID(sc->node))
576 return (0);
578 #if 0
579 while (tp->t_outq.c_cc < NG_H4_HIWATER) { /* XXX 2.2 specific ? */
580 #else
581 while (1) {
582 #endif
583 /* Remove first mbuf from queue */
584 IF_DEQUEUE(&sc->outq, m);
585 if (m == NULL)
586 break;
588 /* Send as much of it as possible */
589 while (m != NULL) {
590 size = m->m_len - b_to_q(mtod(m, u_char *),
591 m->m_len, &tp->t_outq);
593 NG_H4_LOCK(sc);
594 NG_H4_STAT_BYTES_SENT(sc->stat, size);
595 NG_H4_UNLOCK(sc);
597 m->m_data += size;
598 m->m_len -= size;
599 if (m->m_len > 0)
600 break; /* device can't take no more */
602 m = m_free(m);
605 /* Put remainder of mbuf chain (if any) back on queue */
606 if (m != NULL) {
607 IF_PREPEND(&sc->outq, m);
608 break;
611 /* Full packet has been sent */
612 NG_H4_LOCK(sc);
613 NG_H4_STAT_PCKTS_SENT(sc->stat);
614 NG_H4_UNLOCK(sc);
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.
622 tt_oproc(sc->tp);
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.
629 NG_H4_LOCK(sc);
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);
635 NG_H4_UNLOCK(sc);
637 return (0);
638 } /* ng_h4_start */
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
649 * if not.
652 static int
653 ng_h4_constructor(node_p node)
655 return (EOPNOTSUPP);
656 } /* ng_h4_constructor */
659 * Add a new hook. There can only be one.
662 static int
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)
668 return (EINVAL);
670 NG_H4_LOCK(sc);
672 if (sc->hook != NULL) {
673 NG_H4_UNLOCK(sc);
674 return (EISCONN);
676 sc->hook = hook;
678 NG_H4_UNLOCK(sc);
680 return (0);
681 } /* ng_h4_newhook */
684 * Connect hook. Just say yes.
687 static int
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);
698 return (0);
699 } /* ng_h4_connect */
702 * Disconnect the hook
705 static int
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()
715 if (sc != NULL) {
716 if (hook != sc->hook)
717 panic("%s: hook != sc->hook\n", __func__);
719 NG_H4_LOCK(sc);
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;
728 sc->want = 1;
729 sc->got = 0;
731 sc->hook = NULL;
733 NG_H4_UNLOCK(sc);
736 return (0);
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().
744 static int
745 ng_h4_shutdown(node_p node)
747 ng_h4_info_p sc = (ng_h4_info_p) NG_NODE_PRIVATE(node);
749 NG_H4_LOCK(sc);
751 if (!sc->dying) {
752 NG_H4_UNLOCK(sc);
754 NG_NODE_REVIVE(node); /* we will persist */
756 return (EOPNOTSUPP);
759 NG_H4_UNLOCK(sc);
761 NG_NODE_SET_PRIVATE(node, NULL);
763 _IF_DRAIN(&sc->outq);
765 NG_NODE_UNREF(node);
766 mtx_destroy(&sc->outq.ifq_mtx);
767 bzero(sc, sizeof(*sc));
768 FREE(sc, M_NETGRAPH_H4);
770 return (0);
771 } /* ng_h4_shutdown */
774 * Receive incoming data from Netgraph system. Put it on our
775 * output queue and start output if necessary.
778 static int
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;
783 int qlen;
785 if (sc == NULL)
786 return (EHOSTDOWN);
788 if (hook != sc->hook)
789 panic("%s: hook != sc->hook\n", __func__);
791 NGI_GET_M(item, m);
792 NG_FREE_ITEM(item);
794 NG_H4_LOCK(sc);
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);
801 _IF_DROP(&sc->outq);
803 NG_H4_UNLOCK(sc);
805 NG_FREE_M(m);
807 return (ENOBUFS);
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);
816 NG_H4_UNLOCK(sc);
819 * If qlen > 1, then we should already have a scheduled callout
822 if (qlen == 1) {
823 mtx_lock(&Giant);
824 ng_h4_start(sc->tp);
825 mtx_unlock(&Giant);
828 return (0);
829 } /* ng_h4_rcvdata */
832 * Receive control message
835 static int
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;
840 int error = 0;
842 if (sc == NULL)
843 return (EHOSTDOWN);
845 NGI_GET_MSG(item, msg);
846 NG_H4_LOCK(sc);
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);
853 if (resp == NULL)
854 error = ENOMEM;
855 else
856 snprintf(resp->data, NG_TEXTRESPONSE,
857 "Hook: %s\n" \
858 "Debug: %d\n" \
859 "State: %d\n" \
860 "Queue: [have:%d,max:%d]\n" \
861 "Input: [got:%d,want:%d]",
862 (sc->hook != NULL)? NG_H4_HOOK : "",
863 sc->debug,
864 sc->state,
865 _IF_QLEN(&sc->outq),
866 sc->outq.ifq_maxlen,
867 sc->got,
868 sc->want);
869 break;
871 default:
872 error = EINVAL;
873 break;
875 break;
877 case NGM_H4_COOKIE:
878 switch (msg->header.cmd) {
879 case NGM_H4_NODE_RESET:
880 _IF_DRAIN(&sc->outq);
881 sc->state = NG_H4_W4_PKT_IND;
882 sc->want = 1;
883 sc->got = 0;
884 break;
886 case NGM_H4_NODE_GET_STATE:
887 NG_MKRESPONSE(resp, msg, sizeof(ng_h4_node_state_ep),
888 M_NOWAIT);
889 if (resp == NULL)
890 error = ENOMEM;
891 else
892 *((ng_h4_node_state_ep *)(resp->data)) =
893 sc->state;
894 break;
896 case NGM_H4_NODE_GET_DEBUG:
897 NG_MKRESPONSE(resp, msg, sizeof(ng_h4_node_debug_ep),
898 M_NOWAIT);
899 if (resp == NULL)
900 error = ENOMEM;
901 else
902 *((ng_h4_node_debug_ep *)(resp->data)) =
903 sc->debug;
904 break;
906 case NGM_H4_NODE_SET_DEBUG:
907 if (msg->header.arglen != sizeof(ng_h4_node_debug_ep))
908 error = EMSGSIZE;
909 else
910 sc->debug =
911 *((ng_h4_node_debug_ep *)(msg->data));
912 break;
914 case NGM_H4_NODE_GET_QLEN:
915 NG_MKRESPONSE(resp, msg, sizeof(ng_h4_node_qlen_ep),
916 M_NOWAIT);
917 if (resp == NULL)
918 error = ENOMEM;
919 else
920 *((ng_h4_node_qlen_ep *)(resp->data)) =
921 sc->outq.ifq_maxlen;
922 break;
924 case NGM_H4_NODE_SET_QLEN:
925 if (msg->header.arglen != sizeof(ng_h4_node_qlen_ep))
926 error = EMSGSIZE;
927 else if (*((ng_h4_node_qlen_ep *)(msg->data)) <= 0)
928 error = EINVAL;
929 else
930 IFQ_SET_MAXLEN(&sc->outq,
931 *((ng_h4_node_qlen_ep *)(msg->data)));
932 break;
934 case NGM_H4_NODE_GET_STAT:
935 NG_MKRESPONSE(resp, msg, sizeof(ng_h4_node_stat_ep),
936 M_NOWAIT);
937 if (resp == NULL)
938 error = ENOMEM;
939 else
940 bcopy(&sc->stat, resp->data,
941 sizeof(ng_h4_node_stat_ep));
942 break;
944 case NGM_H4_NODE_RESET_STAT:
945 NG_H4_STAT_RESET(sc->stat);
946 break;
948 default:
949 error = EINVAL;
950 break;
952 break;
954 default:
955 error = EINVAL;
956 break;
959 NG_H4_UNLOCK(sc);
961 NG_RESPOND_MSG(error, node, item, resp);
962 NG_FREE_MSG(msg);
964 return (error);
965 } /* ng_h4_rcvmsg */
968 * Timeout processing function.
969 * We still have data to output to the device, so try sending more.
972 static void
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);
977 mtx_lock(&Giant);
978 ng_h4_start(sc->tp);
979 mtx_unlock(&Giant);
980 } /* ng_h4_process_timeout */
983 * Handle loading and unloading for this node type
986 static int
987 ng_h4_mod_event(module_t mod, int event, void *data)
989 static int ng_h4_ldisc;
990 int error = 0;
992 switch (event) {
993 case MOD_LOAD:
994 /* Register line discipline */
995 mtx_lock(&Giant);
996 ng_h4_ldisc = ldisc_register(H4DISC, &ng_h4_disc);
997 mtx_unlock(&Giant);
999 if (ng_h4_ldisc < 0) {
1000 printf("%s: can't register H4 line discipline\n",
1001 __func__);
1002 error = EIO;
1004 break;
1006 case MOD_UNLOAD:
1007 /* Unregister line discipline */
1008 mtx_lock(&Giant);
1009 ldisc_deregister(ng_h4_ldisc);
1010 mtx_unlock(&Giant);
1011 break;
1013 default:
1014 error = EOPNOTSUPP;
1015 break;
1018 return (error);
1019 } /* ng_h4_mod_event */