Vendor import of netgraph from FreeBSD-current 20080626
[dragonfly.git] / sys / netgraph7 / bluetooth / drivers / h4 / ng_h4.c
1 /*
2  * ng_h4.c
3  */
4
5 /*-
6  * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7  * All rights reserved.
8  *
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.
17  *
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.
29  *
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 $
32  * 
33  * Based on:
34  * ---------
35  *
36  * FreeBSD: src/sys/netgraph/ng_tty.c
37  * Author: Archie Cobbs <archie@freebsd.org>
38  *
39  */
40
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>
65
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.
73  **
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  *****************************************************************************/
78
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 */
85
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 *);
95
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 */
106 };
107
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;
116
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 *);
120
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
134 };
135 NETGRAPH_INIT(h4, &typestruct);
136 MODULE_VERSION(ng_h4, NG_BLUETOOTH_VERSION);
137
138 static int      ng_h4_node = 0;
139
140 /*****************************************************************************
141  *****************************************************************************
142  **                         Line discipline methods
143  *****************************************************************************
144  *****************************************************************************/
145
146 /*
147  * Set our line discipline on the tty.
148  */
149
150 static int
151 ng_h4_open(struct cdev *dev, struct tty *tp)
152 {
153         struct thread   *td = curthread;
154         char             name[NG_NODESIZ];
155         ng_h4_info_p     sc = NULL;
156         int              error;
157
158         /* Super-user only */
159         error = priv_check(td, PRIV_NETGRAPH_TTY); /* XXX */
160         if (error != 0)
161                 return (error);
162
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);
167
168         sc->tp = tp;
169         sc->debug = NG_H4_WARN_LEVEL;
170
171         sc->state = NG_H4_W4_PKT_IND;
172         sc->want = 1;
173         sc->got = 0;
174
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);
178
179         NG_H4_LOCK(sc);
180
181         /* Setup netgraph node */
182         error = ng_make_node_common(&typestruct, &sc->node);
183         if (error != 0) {
184                 NG_H4_UNLOCK(sc);
185
186                 printf("%s: Unable to create new node!\n", __func__);
187
188                 mtx_destroy(&sc->outq.ifq_mtx);
189                 bzero(sc, sizeof(*sc));
190                 FREE(sc, M_NETGRAPH_H4);
191
192                 return (error);
193         }
194
195         /* Assign node its name */
196         snprintf(name, sizeof(name), "%s%d", typestruct.name, ng_h4_node ++);
197
198         error = ng_name_node(sc->node, name);
199         if (error != 0) {
200                 NG_H4_UNLOCK(sc);
201
202                 printf("%s: %s - node name exists?\n", __func__, name);
203
204                 NG_NODE_UNREF(sc->node);
205                 mtx_destroy(&sc->outq.ifq_mtx);
206                 bzero(sc, sizeof(*sc));
207                 FREE(sc, M_NETGRAPH_H4);
208
209                 return (error);
210         }
211
212         /* Set back pointers */
213         NG_NODE_SET_PRIVATE(sc->node, sc);
214         tp->t_lsc = (caddr_t) sc;
215
216         /* The node has to be a WRITER because data can change node status */
217         NG_NODE_FORCE_WRITER(sc->node);
218
219         /*
220          * Pre-allocate cblocks to the an appropriate amount.
221          * I'm not sure what is appropriate.
222          */
223
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);
229
230         NG_H4_UNLOCK(sc);
231
232         return (error);
233 } /* ng_h4_open */
234
235 /*
236  * Line specific close routine, called from device close routine
237  * and from ttioctl. This causes the node to be destroyed as well.
238  */
239
240 static int
241 ng_h4_close(struct tty *tp, int flag)
242 {
243         ng_h4_info_p    sc = (ng_h4_info_p) tp->t_lsc;
244
245         ttyflush(tp, FREAD | FWRITE);
246         clist_free_cblocks(&tp->t_outq);
247
248         if (sc != NULL) {
249                 NG_H4_LOCK(sc);
250
251                 if (callout_pending(&sc->timo))
252                         ng_uncallout(&sc->timo, sc->node);
253
254                 tp->t_lsc = NULL;
255                 sc->dying = 1;
256
257                 NG_H4_UNLOCK(sc);
258
259                 ng_rmnode_self(sc->node);
260         }
261
262         return (0);
263 } /* ng_h4_close */
264
265 /*
266  * Once the device has been turned into a node, we don't allow reading.
267  */
268
269 static int
270 ng_h4_read(struct tty *tp, struct uio *uio, int flag)
271 {
272         return (EIO);
273 } /* ng_h4_read */
274
275 /*
276  * Once the device has been turned into a node, we don't allow writing.
277  */
278
279 static int
280 ng_h4_write(struct tty *tp, struct uio *uio, int flag)
281 {
282         return (EIO);
283 } /* ng_h4_write */
284
285 /*
286  * We implement the NGIOCGINFO ioctl() defined in ng_message.h.
287  */
288
289 static int
290 ng_h4_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
291                 struct thread *td)
292 {
293         ng_h4_info_p    sc = (ng_h4_info_p) tp->t_lsc;
294         int             error = 0;
295
296         if (sc == NULL)
297                 return (ENXIO);
298
299         NG_H4_LOCK(sc);
300
301         switch (cmd) {
302         case NGIOCGINFO:
303 #undef  NI
304 #define NI(x)   ((struct nodeinfo *)(x))
305
306                 bzero(data, sizeof(*NI(data)));
307
308                 if (NG_NODE_HAS_NAME(sc->node))
309                         strncpy(NI(data)->name, NG_NODE_NAME(sc->node), 
310                                 sizeof(NI(data)->name) - 1);
311
312                 strncpy(NI(data)->type, sc->node->nd_type->name, 
313                         sizeof(NI(data)->type) - 1);
314
315                 NI(data)->id = (u_int32_t) ng_node2ID(sc->node);
316                 NI(data)->hooks = NG_NODE_NUMHOOKS(sc->node);
317                 break;
318
319         default:
320                 error = ENOIOCTL;
321                 break;
322         }
323
324         NG_H4_UNLOCK(sc);
325
326         return (error);
327 } /* ng_h4_ioctl */
328
329 /*
330  * Receive data coming from the device. We get one character at a time, which 
331  * is kindof silly.
332  */
333
334 static int
335 ng_h4_input(int c, struct tty *tp)
336 {
337         ng_h4_info_p    sc = (ng_h4_info_p) tp->t_lsc;
338
339         if (sc == NULL || tp != sc->tp ||
340             sc->node == NULL || NG_NODE_NOT_VALID(sc->node))
341                 return (0);
342
343         NG_H4_LOCK(sc);
344
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));
349
350                 sc->state = NG_H4_W4_PKT_IND;
351                 sc->want = 1;
352                 sc->got = 0;
353
354                 NG_H4_UNLOCK(sc);
355
356                 return (0); /* XXX Loss of synchronization here! */
357         }
358
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);
364
365                 NG_H4_STAT_IERROR(sc->stat);
366
367                 sc->state = NG_H4_W4_PKT_IND;
368                 sc->want = 1;
369                 sc->got = 0;
370
371                 NG_H4_UNLOCK(sc);
372
373                 return (0); /* XXX Loss of synchronization here! */
374         }
375
376         NG_H4_STAT_BYTES_RECV(sc->stat, 1);
377
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);
383
384                 NG_H4_STAT_IERROR(sc->stat);
385
386                 sc->state = NG_H4_W4_PKT_IND;
387                 sc->want = 1;
388                 sc->got = 0;
389
390                 NG_H4_UNLOCK(sc);
391
392                 return (0); /* XXX Loss of synchronization here! */
393         }
394
395         sc->ibuf[sc->got ++] = (c & TTY_CHARMASK);
396
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);
399
400         if (sc->got < sc->want) {
401                 NG_H4_UNLOCK(sc);
402
403                 return (0); /* Wait for more */
404         }
405
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]);
411
412                 sc->state = NG_H4_W4_PKT_HDR;
413
414                 /*
415                  * Since packet indicator included in the packet header
416                  * just set sc->want to sizeof(packet header).
417                  */
418
419                 switch (sc->ibuf[0]) {
420                 case NG_HCI_ACL_DATA_PKT:
421                         sc->want = sizeof(ng_hci_acldata_pkt_t);
422                         break;
423
424                 case NG_HCI_SCO_DATA_PKT:
425                         sc->want = sizeof(ng_hci_scodata_pkt_t);
426                         break;
427
428                 case NG_HCI_EVENT_PKT:
429                         sc->want = sizeof(ng_hci_event_pkt_t);
430                         break;
431
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]);
436
437                         NG_H4_STAT_IERROR(sc->stat);
438
439                         sc->state = NG_H4_W4_PKT_IND;
440                         sc->want = 1;
441                         sc->got = 0;
442                         break;
443                 }
444                 break;
445
446         /* Got packet header */
447         case NG_H4_W4_PKT_HDR:
448                 sc->state = NG_H4_W4_PKT_DATA;
449
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;
455
456                 case NG_HCI_SCO_DATA_PKT:
457                         c = ((ng_hci_scodata_pkt_t *)(sc->ibuf))->length;
458                         break;
459
460                 case NG_HCI_EVENT_PKT:
461                         c = ((ng_hci_event_pkt_t *)(sc->ibuf))->length;
462                         break;
463
464                 default:
465                         KASSERT((0), ("Invalid packet type=%#x\n",
466                                 sc->ibuf[0]));
467                         break;
468                 }
469
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);
473
474                 if (c > 0) {
475                         sc->want += c;
476
477                         /* 
478                          * Try to prevent possible buffer overrun
479                          *
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.
489                          */
490
491                         if (sc->want >= sizeof(sc->ibuf)) {
492                                 int     b;
493
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);
499
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");
504
505                                 /* Reset state */
506                                 NG_H4_STAT_IERROR(sc->stat);
507
508                                 sc->state = NG_H4_W4_PKT_IND;
509                                 sc->want = 1;
510                                 sc->got = 0;
511                         }
512
513                         break;
514                 }
515
516                 /* else FALLTHROUGH and deliver frame */
517                 /* XXX Is this true? Should we deliver empty frame? */
518
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);
524
525                 if (sc->hook != NULL && NG_HOOK_IS_VALID(sc->hook)) {
526                         struct mbuf     *m = NULL;
527
528                         MGETHDR(m, M_DONTWAIT, MT_DATA);
529                         if (m != NULL) {
530                                 m->m_pkthdr.len = 0;
531
532                                 /* XXX m_copyback() is stupid */
533                                 m->m_len = min(MHLEN, sc->got);
534
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));
540
541                                 NG_H4_STAT_IERROR(sc->stat);
542                         }
543                 }
544
545                 sc->state = NG_H4_W4_PKT_IND;
546                 sc->want = 1;
547                 sc->got = 0;
548
549                 NG_H4_STAT_PCKTS_RECV(sc->stat);
550                 break;
551
552         default:
553                 KASSERT((0), ("Invalid H4 node state=%d", sc->state));
554                 break;
555         }
556
557         NG_H4_UNLOCK(sc);
558
559         return (0);
560 } /* ng_h4_input */
561
562 /*
563  * This is called when the device driver is ready for more output. Called from 
564  * tty system. 
565  */
566
567 static int
568 ng_h4_start(struct tty *tp)
569 {
570         ng_h4_info_p     sc = (ng_h4_info_p) tp->t_lsc;
571         struct mbuf     *m = NULL;
572         int              size;
573
574         if (sc == NULL || tp != sc->tp || 
575             sc->node == NULL || NG_NODE_NOT_VALID(sc->node))
576                 return (0);
577
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;
587
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);
592
593                         NG_H4_LOCK(sc);
594                         NG_H4_STAT_BYTES_SENT(sc->stat, size);
595                         NG_H4_UNLOCK(sc);
596
597                         m->m_data += size;
598                         m->m_len -= size;
599                         if (m->m_len > 0)
600                                 break;  /* device can't take no more */
601
602                         m = m_free(m);
603                 }
604
605                 /* Put remainder of mbuf chain (if any) back on queue */
606                 if (m != NULL) {
607                         IF_PREPEND(&sc->outq, m);
608                         break;
609                 }
610
611                 /* Full packet has been sent */
612                 NG_H4_LOCK(sc);
613                 NG_H4_STAT_PCKTS_SENT(sc->stat);
614                 NG_H4_UNLOCK(sc);
615         }
616
617         /* 
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.
620          */
621
622         tt_oproc(sc->tp);
623
624         /*
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.
627          */
628
629         NG_H4_LOCK(sc);
630
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);
634
635         NG_H4_UNLOCK(sc);
636
637         return (0);
638 } /* ng_h4_start */
639
640 /*****************************************************************************
641  *****************************************************************************
642  **                         Netgraph node methods
643  *****************************************************************************
644  *****************************************************************************/
645
646 /*
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.
650  */
651
652 static int
653 ng_h4_constructor(node_p node)
654 {
655         return (EOPNOTSUPP);
656 } /* ng_h4_constructor */
657
658 /*
659  * Add a new hook. There can only be one.
660  */
661
662 static int
663 ng_h4_newhook(node_p node, hook_p hook, const char *name)
664 {
665         ng_h4_info_p    sc = (ng_h4_info_p) NG_NODE_PRIVATE(node);
666
667         if (strcmp(name, NG_H4_HOOK) != 0)
668                 return (EINVAL);
669
670         NG_H4_LOCK(sc);
671
672         if (sc->hook != NULL) {
673                 NG_H4_UNLOCK(sc);
674                 return (EISCONN);
675         }
676         sc->hook = hook;
677
678         NG_H4_UNLOCK(sc);
679
680         return (0);
681 } /* ng_h4_newhook */
682
683 /*
684  * Connect hook. Just say yes.
685  */
686
687 static int
688 ng_h4_connect(hook_p hook)
689 {
690         ng_h4_info_p    sc = (ng_h4_info_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
691
692         if (hook != sc->hook)
693                 panic("%s: hook != sc->hook\n", __func__);
694
695         NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
696         NG_HOOK_FORCE_QUEUE(hook);
697
698         return (0);
699 } /* ng_h4_connect */
700
701 /*
702  * Disconnect the hook
703  */
704
705 static int
706 ng_h4_disconnect(hook_p hook)
707 {
708         ng_h4_info_p    sc = (ng_h4_info_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
709
710         /*
711          * We need to check for sc != NULL because we can be called from
712          * ng_h4_close() via ng_rmnode_self()
713          */
714
715         if (sc != NULL) {
716                 if (hook != sc->hook)
717                         panic("%s: hook != sc->hook\n", __func__);
718
719                 NG_H4_LOCK(sc);
720
721                 /* XXX do we have to untimeout and drain out queue? */
722                 if (callout_pending(&sc->timo))
723                         ng_uncallout(&sc->timo, sc->node);
724
725                 _IF_DRAIN(&sc->outq); 
726
727                 sc->state = NG_H4_W4_PKT_IND;
728                 sc->want = 1;
729                 sc->got = 0;
730
731                 sc->hook = NULL;
732
733                 NG_H4_UNLOCK(sc);
734         }
735
736         return (0);
737 } /* ng_h4_disconnect */
738
739 /*
740  * Remove this node. The does the netgraph portion of the shutdown.
741  * This should only be called indirectly from ng_h4_close().
742  */
743
744 static int
745 ng_h4_shutdown(node_p node)
746 {
747         ng_h4_info_p    sc = (ng_h4_info_p) NG_NODE_PRIVATE(node);
748
749         NG_H4_LOCK(sc);
750
751         if (!sc->dying) {
752                 NG_H4_UNLOCK(sc);
753
754                 NG_NODE_REVIVE(node);   /* we will persist */
755
756                 return (EOPNOTSUPP);
757         }
758
759         NG_H4_UNLOCK(sc);
760
761         NG_NODE_SET_PRIVATE(node, NULL);
762
763         _IF_DRAIN(&sc->outq);
764
765         NG_NODE_UNREF(node);
766         mtx_destroy(&sc->outq.ifq_mtx);
767         bzero(sc, sizeof(*sc));
768         FREE(sc, M_NETGRAPH_H4);
769
770         return (0);
771 } /* ng_h4_shutdown */
772
773 /*
774  * Receive incoming data from Netgraph system. Put it on our
775  * output queue and start output if necessary.
776  */
777
778 static int
779 ng_h4_rcvdata(hook_p hook, item_p item)
780 {
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;
784
785         if (sc == NULL)
786                 return (EHOSTDOWN);
787
788         if (hook != sc->hook)
789                 panic("%s: hook != sc->hook\n", __func__);
790
791         NGI_GET_M(item, m);
792         NG_FREE_ITEM(item);
793
794         NG_H4_LOCK(sc);
795
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);
799
800                 NG_H4_STAT_OERROR(sc->stat);
801                 _IF_DROP(&sc->outq);
802
803                 NG_H4_UNLOCK(sc);
804
805                 NG_FREE_M(m);
806
807                 return (ENOBUFS);
808         }
809
810         NG_H4_INFO("%s: %s - queue mbuf, len=%d\n", __func__,
811                 NG_NODE_NAME(sc->node), m->m_pkthdr.len);
812
813         _IF_ENQUEUE(&sc->outq, m);
814         qlen = _IF_QLEN(&sc->outq);
815
816         NG_H4_UNLOCK(sc);
817
818         /*
819          * If qlen > 1, then we should already have a scheduled callout
820          */
821
822         if (qlen == 1) {
823                 mtx_lock(&Giant);
824                 ng_h4_start(sc->tp);
825                 mtx_unlock(&Giant);
826         }
827
828         return (0);
829 } /* ng_h4_rcvdata */
830
831 /*
832  * Receive control message
833  */
834
835 static int
836 ng_h4_rcvmsg(node_p node, item_p item, hook_p lasthook)
837 {
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;
841
842         if (sc == NULL)
843                 return (EHOSTDOWN);
844
845         NGI_GET_MSG(item, msg);
846         NG_H4_LOCK(sc);
847
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;
870
871                 default:
872                         error = EINVAL;
873                         break;
874                 }
875                 break;
876
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;
885
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;
895
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;
905
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;
913
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;
923
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;
933
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;
943
944                 case NGM_H4_NODE_RESET_STAT:
945                         NG_H4_STAT_RESET(sc->stat);
946                         break;
947
948                 default:
949                         error = EINVAL;
950                         break;
951                 }
952                 break;
953
954         default:
955                 error = EINVAL;
956                 break;
957         }
958
959         NG_H4_UNLOCK(sc);
960
961         NG_RESPOND_MSG(error, node, item, resp);
962         NG_FREE_MSG(msg);
963
964         return (error);
965 } /* ng_h4_rcvmsg */
966
967 /*
968  * Timeout processing function.
969  * We still have data to output to the device, so try sending more.
970  */
971
972 static void
973 ng_h4_process_timeout(node_p node, hook_p hook, void *arg1, int arg2)
974 {
975         ng_h4_info_p    sc = (ng_h4_info_p) NG_NODE_PRIVATE(node);
976
977         mtx_lock(&Giant);
978         ng_h4_start(sc->tp);
979         mtx_unlock(&Giant);
980 } /* ng_h4_process_timeout */
981
982 /*
983  * Handle loading and unloading for this node type
984  */
985
986 static int
987 ng_h4_mod_event(module_t mod, int event, void *data)
988 {
989         static int      ng_h4_ldisc;
990         int             error = 0;
991
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);
998
999                 if (ng_h4_ldisc < 0) {
1000                         printf("%s: can't register H4 line discipline\n",
1001                                 __func__);
1002                         error = EIO;
1003                 }
1004                 break;
1005
1006         case MOD_UNLOAD:
1007                 /* Unregister line discipline */
1008                 mtx_lock(&Giant);
1009                 ldisc_deregister(ng_h4_ldisc);
1010                 mtx_unlock(&Giant);
1011                 break;
1012
1013         default:
1014                 error = EOPNOTSUPP;
1015                 break;
1016         }
1017
1018         return (error);
1019 } /* ng_h4_mod_event */
1020