kernel/netgraph7: Use kprintf etc. directly instead of defining printf.
[dragonfly.git] / sys / netgraph7 / bluetooth / drivers / h4 / ng_h4.c
1 /*-
2  * (MPSAFE)
3  *
4  * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5  * All rights reserved.
6  *
7  * ng_h4.c
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/malloc.h>
49 #include <sys/mbuf.h>
50 #include <sys/priv.h>
51 #include <sys/socket.h>
52 #include <sys/tty.h>
53 #include <sys/ttycom.h>
54 #include <net/if.h>
55 #include <net/if_var.h>
56 #include "ng_message.h"
57 #include "netgraph.h"
58 #include "ng_parse.h"
59 #include "bluetooth/include/ng_bluetooth.h"
60 #include "bluetooth/include/ng_hci.h"
61 #include "bluetooth/include/ng_h4.h"
62 #include "bluetooth/drivers/h4/ng_h4_var.h"
63 #include "bluetooth/drivers/h4/ng_h4_prse.h"
64
65 /*****************************************************************************
66  *****************************************************************************
67  ** This node implements a Bluetooth HCI UART transport layer as per chapter
68  ** H4 of the Bluetooth Specification Book v1.1. It is a terminal line 
69  ** discipline that is also a netgraph node. Installing this line discipline 
70  ** on a terminal device instantiates a new netgraph node of this type, which 
71  ** allows access to the device via the "hook" hook of the node.
72  **
73  ** Once the line discipline is installed, you can find out the name of the 
74  ** corresponding netgraph node via a NGIOCGINFO ioctl().
75  *****************************************************************************
76  *****************************************************************************/
77
78 /* MALLOC define */
79 #ifndef NG_SEPARATE_MALLOC
80 MALLOC_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 */
86 static int      ng_h4_open      (struct cdev *, struct tty *);
87 static int      ng_h4_close     (struct tty *, int);
88 static int      ng_h4_read      (struct tty *, struct uio *, int);
89 static int      ng_h4_write     (struct tty *, struct uio *, int);
90 static int      ng_h4_input     (int, struct tty *);
91 static int      ng_h4_start     (struct tty *);
92 static int      ng_h4_ioctl     (struct tty *, u_long, caddr_t, 
93                                         int, struct thread *);
94
95 /* Line discipline descriptor */
96 static struct linesw            ng_h4_disc = {
97         ng_h4_open,             /* open */
98         ng_h4_close,            /* close */
99         ng_h4_read,             /* read */
100         ng_h4_write,            /* write */
101         ng_h4_ioctl,            /* ioctl */
102         ng_h4_input,            /* input */
103         ng_h4_start,            /* start */
104         ttymodem                /* modem */
105 };
106
107 /* Netgraph methods */
108 static ng_constructor_t         ng_h4_constructor;
109 static ng_rcvmsg_t              ng_h4_rcvmsg;
110 static ng_shutdown_t            ng_h4_shutdown;
111 static ng_newhook_t             ng_h4_newhook;
112 static ng_connect_t             ng_h4_connect;
113 static ng_rcvdata_t             ng_h4_rcvdata;
114 static ng_disconnect_t          ng_h4_disconnect;
115
116 /* Other stuff */
117 static void     ng_h4_process_timeout   (node_p, hook_p, void *, int);
118 static int      ng_h4_mod_event         (module_t, int, void *);
119
120 /* Netgraph node type descriptor */
121 static struct ng_type           typestruct = {
122         .version =      NG_ABI_VERSION,
123         .name =         NG_H4_NODE_TYPE,
124         .mod_event =    ng_h4_mod_event,
125         .constructor =  ng_h4_constructor,
126         .rcvmsg =       ng_h4_rcvmsg,
127         .shutdown =     ng_h4_shutdown,
128         .newhook =      ng_h4_newhook,
129         .connect =      ng_h4_connect,
130         .rcvdata =      ng_h4_rcvdata,
131         .disconnect =   ng_h4_disconnect,
132         .cmdlist =      ng_h4_cmdlist
133 };
134 NETGRAPH_INIT(h4, &typestruct);
135 MODULE_VERSION(ng_h4, NG_BLUETOOTH_VERSION);
136
137 static int      ng_h4_node = 0;
138
139 /*****************************************************************************
140  *****************************************************************************
141  **                         Line discipline methods
142  *****************************************************************************
143  *****************************************************************************/
144
145 /*
146  * Set our line discipline on the tty.
147  */
148
149 static int
150 ng_h4_open(struct cdev *dev, struct tty *tp)
151 {
152         struct thread   *td = curthread;
153         char             name[NG_NODESIZ];
154         ng_h4_info_p     sc = NULL;
155         int              error;
156
157         /* Super-user only */
158         error = priv_check(td, PRIV_NETGRAPH_TTY); /* XXX */
159         if (error != 0)
160                 return (error);
161
162         /* Initialize private struct */
163         sc = kmalloc(sizeof(*sc), M_NETGRAPH_H4, M_WAITOK | M_NULLOK | M_ZERO);
164         if (sc == NULL)
165                 return (ENOMEM);
166
167         lwkt_gettoken(&tty_token);
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                 kprintf("%s: Unable to create new node!\n", __func__);
187
188                 mtx_destroy(&sc->outq.ifq_mtx);
189                 bzero(sc, sizeof(*sc));
190                 kfree(sc, M_NETGRAPH_H4);
191
192                 lwkt_reltoken(&tty_token);
193                 return (error);
194         }
195
196         /* Assign node its name */
197         ksnprintf(name, sizeof(name), "%s%d", typestruct.name, ng_h4_node ++);
198
199         error = ng_name_node(sc->node, name);
200         if (error != 0) {
201                 NG_H4_UNLOCK(sc);
202
203                 kprintf("%s: %s - node name exists?\n", __func__, name);
204
205                 NG_NODE_UNREF(sc->node);
206                 mtx_destroy(&sc->outq.ifq_mtx);
207                 bzero(sc, sizeof(*sc));
208                 kfree(sc, M_NETGRAPH_H4);
209
210                 lwkt_reltoken(&tty_token);
211                 return (error);
212         }
213
214         /* Set back pointers */
215         NG_NODE_SET_PRIVATE(sc->node, sc);
216         tp->t_lsc = (caddr_t) sc;
217
218         /* The node has to be a WRITER because data can change node status */
219         NG_NODE_FORCE_WRITER(sc->node);
220
221         /*
222          * Pre-allocate cblocks to the an appropriate amount.
223          * I'm not sure what is appropriate.
224          */
225
226         ttyflush(tp, FREAD | FWRITE);
227         clist_alloc_cblocks(&tp->t_canq, 0, 0);
228         clist_alloc_cblocks(&tp->t_rawq, 0, 0);
229         clist_alloc_cblocks(&tp->t_outq,
230                 MLEN + NG_H4_HIWATER, MLEN + NG_H4_HIWATER);
231
232         NG_H4_UNLOCK(sc);
233
234         lwkt_reltoken(&tty_token);
235         return (error);
236 } /* ng_h4_open */
237
238 /*
239  * Line specific close routine, called from device close routine
240  * and from ttioctl. This causes the node to be destroyed as well.
241  */
242
243 static int
244 ng_h4_close(struct tty *tp, int flag)
245 {
246         ng_h4_info_p    sc = (ng_h4_info_p) tp->t_lsc;
247
248         lwkt_gettoken(&tty_token);
249         ttyflush(tp, FREAD | FWRITE);
250         clist_free_cblocks(&tp->t_outq);
251
252         if (sc != NULL) {
253                 NG_H4_LOCK(sc);
254
255                 if (callout_pending(&sc->timo))
256                         ng_uncallout(&sc->timo, sc->node);
257
258                 tp->t_lsc = NULL;
259                 sc->dying = 1;
260
261                 NG_H4_UNLOCK(sc);
262
263                 ng_rmnode_self(sc->node);
264         }
265
266         lwkt_reltoken(&tty_token);
267         return (0);
268 } /* ng_h4_close */
269
270 /*
271  * Once the device has been turned into a node, we don't allow reading.
272  */
273
274 static int
275 ng_h4_read(struct tty *tp, struct uio *uio, int flag)
276 {
277         return (EIO);
278 } /* ng_h4_read */
279
280 /*
281  * Once the device has been turned into a node, we don't allow writing.
282  */
283
284 static int
285 ng_h4_write(struct tty *tp, struct uio *uio, int flag)
286 {
287         return (EIO);
288 } /* ng_h4_write */
289
290 /*
291  * We implement the NGIOCGINFO ioctl() defined in ng_message.h.
292  */
293
294 static int
295 ng_h4_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
296                 struct thread *td)
297 {
298         ng_h4_info_p    sc = (ng_h4_info_p) tp->t_lsc;
299         int             error = 0;
300
301         if (sc == NULL)
302                 return (ENXIO);
303
304         lwkt_gettoken(&tty_token);
305         NG_H4_LOCK(sc);
306
307         switch (cmd) {
308         case NGIOCGINFO:
309 #undef  NI
310 #define NI(x)   ((struct nodeinfo *)(x))
311
312                 bzero(data, sizeof(*NI(data)));
313
314                 if (NG_NODE_HAS_NAME(sc->node))
315                         strncpy(NI(data)->name, NG_NODE_NAME(sc->node), 
316                                 sizeof(NI(data)->name) - 1);
317
318                 strncpy(NI(data)->type, sc->node->nd_type->name, 
319                         sizeof(NI(data)->type) - 1);
320
321                 NI(data)->id = (u_int32_t) ng_node2ID(sc->node);
322                 NI(data)->hooks = NG_NODE_NUMHOOKS(sc->node);
323                 break;
324
325         default:
326                 error = ENOIOCTL;
327                 break;
328         }
329
330         NG_H4_UNLOCK(sc);
331
332         lwkt_reltoken(&tty_token);
333         return (error);
334 } /* ng_h4_ioctl */
335
336 /*
337  * Receive data coming from the device. We get one character at a time, which 
338  * is kindof silly.
339  */
340
341 static int
342 ng_h4_input(int c, struct tty *tp)
343 {
344         ng_h4_info_p    sc = (ng_h4_info_p) tp->t_lsc;
345
346         lwkt_gettoken(&tty_token);
347         if (sc == NULL || tp != sc->tp ||
348             sc->node == NULL || NG_NODE_NOT_VALID(sc->node)) {
349                 lwkt_reltoken(&tty_token);
350                 return (0);
351         }
352
353         NG_H4_LOCK(sc);
354
355         /* Check for error conditions */
356         if ((tp->t_state & TS_CONNECTED) == 0) {
357                 NG_H4_INFO("%s: %s - no carrier\n", __func__,
358                         NG_NODE_NAME(sc->node));
359
360                 sc->state = NG_H4_W4_PKT_IND;
361                 sc->want = 1;
362                 sc->got = 0;
363
364                 NG_H4_UNLOCK(sc);
365
366                 lwkt_reltoken(&tty_token);
367                 return (0); /* XXX Loss of synchronization here! */
368         }
369
370         /* Check for framing error or overrun on this char */
371         if (c & TTY_ERRORMASK) {
372                 NG_H4_ERR("%s: %s - line error %#x, c=%#x\n", __func__, 
373                         NG_NODE_NAME(sc->node), c & TTY_ERRORMASK,
374                         c & TTY_CHARMASK);
375
376                 NG_H4_STAT_IERROR(sc->stat);
377
378                 sc->state = NG_H4_W4_PKT_IND;
379                 sc->want = 1;
380                 sc->got = 0;
381
382                 NG_H4_UNLOCK(sc);
383
384                 lwkt_reltoken(&tty_token);
385                 return (0); /* XXX Loss of synchronization here! */
386         }
387
388         NG_H4_STAT_BYTES_RECV(sc->stat, 1);
389
390         /* Append char to mbuf */
391         if (sc->got >= sizeof(sc->ibuf)) {
392                 NG_H4_ALERT("%s: %s - input buffer overflow, c=%#x, got=%d\n",
393                         __func__, NG_NODE_NAME(sc->node), c & TTY_CHARMASK,
394                         sc->got);
395
396                 NG_H4_STAT_IERROR(sc->stat);
397
398                 sc->state = NG_H4_W4_PKT_IND;
399                 sc->want = 1;
400                 sc->got = 0;
401
402                 NG_H4_UNLOCK(sc);
403
404                 lwkt_reltoken(&tty_token);
405                 return (0); /* XXX Loss of synchronization here! */
406         }
407
408         sc->ibuf[sc->got ++] = (c & TTY_CHARMASK);
409
410         NG_H4_INFO("%s: %s - got char %#x, want=%d, got=%d\n", __func__,
411                 NG_NODE_NAME(sc->node), c, sc->want, sc->got);
412
413         if (sc->got < sc->want) {
414                 NG_H4_UNLOCK(sc);
415
416                 lwkt_reltoken(&tty_token);
417                 return (0); /* Wait for more */
418         }
419
420         switch (sc->state) {
421         /* Got packet indicator */
422         case NG_H4_W4_PKT_IND:
423                 NG_H4_INFO("%s: %s - got packet indicator %#x\n", __func__,
424                         NG_NODE_NAME(sc->node), sc->ibuf[0]);
425
426                 sc->state = NG_H4_W4_PKT_HDR;
427
428                 /*
429                  * Since packet indicator included in the packet header
430                  * just set sc->want to sizeof(packet header).
431                  */
432
433                 switch (sc->ibuf[0]) {
434                 case NG_HCI_ACL_DATA_PKT:
435                         sc->want = sizeof(ng_hci_acldata_pkt_t);
436                         break;
437
438                 case NG_HCI_SCO_DATA_PKT:
439                         sc->want = sizeof(ng_hci_scodata_pkt_t);
440                         break;
441
442                 case NG_HCI_EVENT_PKT:
443                         sc->want = sizeof(ng_hci_event_pkt_t);
444                         break;
445
446                 default:
447                         NG_H4_WARN("%s: %s - ignoring unknown packet " \
448                                 "type=%#x\n", __func__, NG_NODE_NAME(sc->node),
449                                 sc->ibuf[0]);
450
451                         NG_H4_STAT_IERROR(sc->stat);
452
453                         sc->state = NG_H4_W4_PKT_IND;
454                         sc->want = 1;
455                         sc->got = 0;
456                         break;
457                 }
458                 break;
459
460         /* Got packet header */
461         case NG_H4_W4_PKT_HDR:
462                 sc->state = NG_H4_W4_PKT_DATA;
463
464                 switch (sc->ibuf[0]) {
465                 case NG_HCI_ACL_DATA_PKT:
466                         c = le16toh(((ng_hci_acldata_pkt_t *)
467                                 (sc->ibuf))->length);
468                         break;
469
470                 case NG_HCI_SCO_DATA_PKT:
471                         c = ((ng_hci_scodata_pkt_t *)(sc->ibuf))->length;
472                         break;
473
474                 case NG_HCI_EVENT_PKT:
475                         c = ((ng_hci_event_pkt_t *)(sc->ibuf))->length;
476                         break;
477
478                 default:
479                         KASSERT((0), ("Invalid packet type=%#x",
480                                 sc->ibuf[0]));
481                         break;
482                 }
483
484                 NG_H4_INFO("%s: %s - got packet header, packet type=%#x, " \
485                         "packet size=%d, payload size=%d\n", __func__, 
486                         NG_NODE_NAME(sc->node), sc->ibuf[0], sc->got, c);
487
488                 if (c > 0) {
489                         sc->want += c;
490
491                         /* 
492                          * Try to prevent possible buffer overrun
493                          *
494                          * XXX I'm *really* confused here. It turns out
495                          * that Xircom card sends us packets with length
496                          * greater then 512 bytes! This is greater then
497                          * our old receive buffer (ibuf) size. In the same
498                          * time the card demands from us *not* to send 
499                          * packets greater then 192 bytes. Weird! How the 
500                          * hell i should know how big *receive* buffer 
501                          * should be? For now increase receiving buffer 
502                          * size to 1K and add the following check.
503                          */
504
505                         if (sc->want >= sizeof(sc->ibuf)) {
506                                 int     b;
507
508                                 NG_H4_ALERT("%s: %s - packet too big for " \
509                                         "buffer, type=%#x, got=%d, want=%d, " \
510                                         "length=%d\n", __func__, 
511                                         NG_NODE_NAME(sc->node), sc->ibuf[0],
512                                         sc->got, sc->want, c);
513
514                                 NG_H4_ALERT("Packet header:\n");
515                                 for (b = 0; b < sc->got; b++)
516                                         NG_H4_ALERT("%#x ", sc->ibuf[b]);
517                                 NG_H4_ALERT("\n");
518
519                                 /* Reset state */
520                                 NG_H4_STAT_IERROR(sc->stat);
521
522                                 sc->state = NG_H4_W4_PKT_IND;
523                                 sc->want = 1;
524                                 sc->got = 0;
525                         }
526
527                         break;
528                 }
529
530                 /* else FALLTHROUGH and deliver frame */
531                 /* XXX Is this true? Should we deliver empty frame? */
532
533         /* Got packet data */
534         case NG_H4_W4_PKT_DATA:
535                 NG_H4_INFO("%s: %s - got full packet, packet type=%#x, " \
536                         "packet size=%d\n", __func__,
537                         NG_NODE_NAME(sc->node), sc->ibuf[0], sc->got);
538
539                 if (sc->hook != NULL && NG_HOOK_IS_VALID(sc->hook)) {
540                         struct mbuf     *m = NULL;
541
542                         MGETHDR(m, MB_DONTWAIT, MT_DATA);
543                         if (m != NULL) {
544                                 m->m_pkthdr.len = 0;
545
546                                 /* XXX m_copyback() is stupid */
547                                 m->m_len = min(MHLEN, sc->got);
548
549                                 m_copyback(m, 0, sc->got, sc->ibuf);
550                                 NG_SEND_DATA_ONLY(c, sc->hook, m);
551                         } else {
552                                 NG_H4_ERR("%s: %s - could not get mbuf\n",
553                                         __func__, NG_NODE_NAME(sc->node));
554
555                                 NG_H4_STAT_IERROR(sc->stat);
556                         }
557                 }
558
559                 sc->state = NG_H4_W4_PKT_IND;
560                 sc->want = 1;
561                 sc->got = 0;
562
563                 NG_H4_STAT_PCKTS_RECV(sc->stat);
564                 break;
565
566         default:
567                 KASSERT((0), ("Invalid H4 node state=%d", sc->state));
568                 break;
569         }
570
571         NG_H4_UNLOCK(sc);
572
573         lwkt_reltoken(&tty_token);
574         return (0);
575 } /* ng_h4_input */
576
577 /*
578  * This is called when the device driver is ready for more output. Called from 
579  * tty system. 
580  */
581
582 static int
583 ng_h4_start(struct tty *tp)
584 {
585         ng_h4_info_p     sc = (ng_h4_info_p) tp->t_lsc;
586         struct mbuf     *m = NULL;
587         int              size;
588
589         lwkt_gettoken(&tty_token);
590         if (sc == NULL || tp != sc->tp || 
591             sc->node == NULL || NG_NODE_NOT_VALID(sc->node)) {
592                 lwkt_reltoken(&tty_token);
593                 return (0);
594         }
595
596 #if 0
597         while (tp->t_outq.c_cc < NG_H4_HIWATER) { /* XXX 2.2 specific ? */
598 #else
599         while (1) {
600 #endif
601                 /* Remove first mbuf from queue */
602                 IF_DEQUEUE(&sc->outq, m);
603                 if (m == NULL)
604                         break;
605
606                 /* Send as much of it as possible */
607                 while (m != NULL) {
608                         size = m->m_len - b_to_q(mtod(m, u_char *),
609                                         m->m_len, &tp->t_outq);
610
611                         NG_H4_LOCK(sc);
612                         NG_H4_STAT_BYTES_SENT(sc->stat, size);
613                         NG_H4_UNLOCK(sc);
614
615                         m->m_data += size;
616                         m->m_len -= size;
617                         if (m->m_len > 0)
618                                 break;  /* device can't take no more */
619
620                         m = m_free(m);
621                 }
622
623                 /* Put remainder of mbuf chain (if any) back on queue */
624                 if (m != NULL) {
625                         IF_PREPEND(&sc->outq, m);
626                         break;
627                 }
628
629                 /* Full packet has been sent */
630                 NG_H4_LOCK(sc);
631                 NG_H4_STAT_PCKTS_SENT(sc->stat);
632                 NG_H4_UNLOCK(sc);
633         }
634
635         /* 
636          * Call output process whether or not there is any output. We are
637          * being called in lieu of ttstart and must do what it would.
638          */
639
640         tt_oproc(sc->tp);
641
642         /*
643          * This timeout is needed for operation on a pseudo-tty, because the
644          * pty code doesn't call pppstart after it has drained the t_outq.
645          */
646
647         NG_H4_LOCK(sc);
648
649         if (!IFQ_IS_EMPTY(&sc->outq) && !callout_pending(&sc->timo))
650                 ng_callout(&sc->timo, sc->node, NULL, 1,
651                         ng_h4_process_timeout, NULL, 0);
652
653         NG_H4_UNLOCK(sc);
654
655         lwkt_reltoken(&tty_token);
656         return (0);
657 } /* ng_h4_start */
658
659 /*****************************************************************************
660  *****************************************************************************
661  **                         Netgraph node methods
662  *****************************************************************************
663  *****************************************************************************/
664
665 /*
666  * Initialize a new node of this type. We only allow nodes to be created as 
667  * a result of setting the line discipline on a tty, so always return an error
668  * if not.
669  */
670
671 static int
672 ng_h4_constructor(node_p node)
673 {
674         return (EOPNOTSUPP);
675 } /* ng_h4_constructor */
676
677 /*
678  * Add a new hook. There can only be one.
679  */
680
681 static int
682 ng_h4_newhook(node_p node, hook_p hook, const char *name)
683 {
684         ng_h4_info_p    sc = (ng_h4_info_p) NG_NODE_PRIVATE(node);
685
686         if (strcmp(name, NG_H4_HOOK) != 0)
687                 return (EINVAL);
688
689         NG_H4_LOCK(sc);
690
691         if (sc->hook != NULL) {
692                 NG_H4_UNLOCK(sc);
693                 return (EISCONN);
694         }
695         sc->hook = hook;
696
697         NG_H4_UNLOCK(sc);
698
699         return (0);
700 } /* ng_h4_newhook */
701
702 /*
703  * Connect hook. Just say yes.
704  */
705
706 static int
707 ng_h4_connect(hook_p hook)
708 {
709         ng_h4_info_p    sc = (ng_h4_info_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
710
711         if (hook != sc->hook)
712                 panic("%s: hook != sc->hook", __func__);
713
714         NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
715         NG_HOOK_FORCE_QUEUE(hook);
716
717         return (0);
718 } /* ng_h4_connect */
719
720 /*
721  * Disconnect the hook
722  */
723
724 static int
725 ng_h4_disconnect(hook_p hook)
726 {
727         ng_h4_info_p    sc = (ng_h4_info_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
728
729         /*
730          * We need to check for sc != NULL because we can be called from
731          * ng_h4_close() via ng_rmnode_self()
732          */
733
734         if (sc != NULL) {
735                 if (hook != sc->hook)
736                         panic("%s: hook != sc->hook", __func__);
737
738                 NG_H4_LOCK(sc);
739
740                 /* XXX do we have to untimeout and drain out queue? */
741                 if (callout_pending(&sc->timo))
742                         ng_uncallout(&sc->timo, sc->node);
743
744                 _IF_DRAIN(&sc->outq); 
745
746                 sc->state = NG_H4_W4_PKT_IND;
747                 sc->want = 1;
748                 sc->got = 0;
749
750                 sc->hook = NULL;
751
752                 NG_H4_UNLOCK(sc);
753         }
754
755         return (0);
756 } /* ng_h4_disconnect */
757
758 /*
759  * Remove this node. The does the netgraph portion of the shutdown.
760  * This should only be called indirectly from ng_h4_close().
761  */
762
763 static int
764 ng_h4_shutdown(node_p node)
765 {
766         ng_h4_info_p    sc = (ng_h4_info_p) NG_NODE_PRIVATE(node);
767
768         NG_H4_LOCK(sc);
769
770         if (!sc->dying) {
771                 NG_H4_UNLOCK(sc);
772
773                 NG_NODE_REVIVE(node);   /* we will persist */
774
775                 return (EOPNOTSUPP);
776         }
777
778         NG_H4_UNLOCK(sc);
779
780         NG_NODE_SET_PRIVATE(node, NULL);
781
782         _IF_DRAIN(&sc->outq);
783
784         NG_NODE_UNREF(node);
785         mtx_destroy(&sc->outq.ifq_mtx);
786         bzero(sc, sizeof(*sc));
787         kfree(sc, M_NETGRAPH_H4);
788
789         return (0);
790 } /* ng_h4_shutdown */
791
792 /*
793  * Receive incoming data from Netgraph system. Put it on our
794  * output queue and start output if necessary.
795  */
796
797 static int
798 ng_h4_rcvdata(hook_p hook, item_p item)
799 {
800         ng_h4_info_p     sc = (ng_h4_info_p)NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
801         struct mbuf     *m = NULL;
802         int              qlen;
803
804         if (sc == NULL)
805                 return (EHOSTDOWN);
806
807         if (hook != sc->hook)
808                 panic("%s: hook != sc->hook", __func__);
809
810         NGI_GET_M(item, m);
811         NG_FREE_ITEM(item);
812
813         NG_H4_LOCK(sc);
814
815         if (_IF_QFULL(&sc->outq)) {
816                 NG_H4_ERR("%s: %s - dropping mbuf, len=%d\n", __func__,
817                         NG_NODE_NAME(sc->node), m->m_pkthdr.len);
818
819                 NG_H4_STAT_OERROR(sc->stat);
820                 _IF_DROP(&sc->outq);
821
822                 NG_H4_UNLOCK(sc);
823
824                 NG_FREE_M(m);
825
826                 return (ENOBUFS);
827         }
828
829         NG_H4_INFO("%s: %s - queue mbuf, len=%d\n", __func__,
830                 NG_NODE_NAME(sc->node), m->m_pkthdr.len);
831
832         _IF_ENQUEUE(&sc->outq, m);
833         qlen = _IF_QLEN(&sc->outq);
834
835         NG_H4_UNLOCK(sc);
836
837         /*
838          * If qlen > 1, then we should already have a scheduled callout
839          */
840
841         if (qlen == 1) {
842                 mtx_lock(&Giant);
843                 ng_h4_start(sc->tp);
844                 mtx_unlock(&Giant);
845         }
846
847         return (0);
848 } /* ng_h4_rcvdata */
849
850 /*
851  * Receive control message
852  */
853
854 static int
855 ng_h4_rcvmsg(node_p node, item_p item, hook_p lasthook)
856 {
857         ng_h4_info_p     sc = (ng_h4_info_p) NG_NODE_PRIVATE(node);
858         struct ng_mesg  *msg = NULL, *resp = NULL;
859         int              error = 0;
860
861         if (sc == NULL)
862                 return (EHOSTDOWN);
863
864         NGI_GET_MSG(item, msg);
865         NG_H4_LOCK(sc);
866
867         switch (msg->header.typecookie) {
868         case NGM_GENERIC_COOKIE:
869                 switch (msg->header.cmd) {
870                 case NGM_TEXT_STATUS:
871                         NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_WAITOK | M_NULLOK);
872                         if (resp == NULL)
873                                 error = ENOMEM;
874                         else
875                                 ksnprintf(resp->data, NG_TEXTRESPONSE,
876                                         "Hook: %s\n"   \
877                                         "Debug: %d\n"  \
878                                         "State: %d\n"  \
879                                         "Queue: [have:%d,max:%d]\n" \
880                                         "Input: [got:%d,want:%d]",
881                                         (sc->hook != NULL)? NG_H4_HOOK : "",
882                                         sc->debug,
883                                         sc->state,
884                                         _IF_QLEN(&sc->outq),
885                                         sc->outq.ifq_maxlen,
886                                         sc->got,
887                                         sc->want);
888                         break;
889
890                 default:
891                         error = EINVAL;
892                         break;
893                 }
894                 break;
895
896         case NGM_H4_COOKIE:
897                 switch (msg->header.cmd) {
898                 case NGM_H4_NODE_RESET:
899                         _IF_DRAIN(&sc->outq); 
900                         sc->state = NG_H4_W4_PKT_IND;
901                         sc->want = 1;
902                         sc->got = 0;
903                         break;
904
905                 case NGM_H4_NODE_GET_STATE:
906                         NG_MKRESPONSE(resp, msg, sizeof(ng_h4_node_state_ep),
907                                 M_WAITOK | M_NULLOK);
908                         if (resp == NULL)
909                                 error = ENOMEM;
910                         else
911                                 *((ng_h4_node_state_ep *)(resp->data)) = 
912                                         sc->state;
913                         break;
914
915                 case NGM_H4_NODE_GET_DEBUG:
916                         NG_MKRESPONSE(resp, msg, sizeof(ng_h4_node_debug_ep),
917                                 M_WAITOK | M_NULLOK);
918                         if (resp == NULL)
919                                 error = ENOMEM;
920                         else
921                                 *((ng_h4_node_debug_ep *)(resp->data)) = 
922                                         sc->debug;
923                         break;
924
925                 case NGM_H4_NODE_SET_DEBUG:
926                         if (msg->header.arglen != sizeof(ng_h4_node_debug_ep))
927                                 error = EMSGSIZE;
928                         else
929                                 sc->debug =
930                                         *((ng_h4_node_debug_ep *)(msg->data));
931                         break;
932
933                 case NGM_H4_NODE_GET_QLEN:
934                         NG_MKRESPONSE(resp, msg, sizeof(ng_h4_node_qlen_ep),
935                                 M_WAITOK | M_NULLOK);
936                         if (resp == NULL)
937                                 error = ENOMEM;
938                         else
939                                 *((ng_h4_node_qlen_ep *)(resp->data)) = 
940                                         sc->outq.ifq_maxlen;
941                         break;
942
943                 case NGM_H4_NODE_SET_QLEN:
944                         if (msg->header.arglen != sizeof(ng_h4_node_qlen_ep))
945                                 error = EMSGSIZE;
946                         else if (*((ng_h4_node_qlen_ep *)(msg->data)) <= 0)
947                                 error = EINVAL;
948                         else
949                                 IFQ_SET_MAXLEN(&sc->outq,
950                                         *((ng_h4_node_qlen_ep *)(msg->data)));
951                         break;
952
953                 case NGM_H4_NODE_GET_STAT:
954                         NG_MKRESPONSE(resp, msg, sizeof(ng_h4_node_stat_ep),
955                                 M_WAITOK | M_NULLOK);
956                         if (resp == NULL)
957                                 error = ENOMEM;
958                         else
959                                 bcopy(&sc->stat, resp->data,
960                                         sizeof(ng_h4_node_stat_ep));
961                         break;
962
963                 case NGM_H4_NODE_RESET_STAT:
964                         NG_H4_STAT_RESET(sc->stat);
965                         break;
966
967                 default:
968                         error = EINVAL;
969                         break;
970                 }
971                 break;
972
973         default:
974                 error = EINVAL;
975                 break;
976         }
977
978         NG_H4_UNLOCK(sc);
979
980         NG_RESPOND_MSG(error, node, item, resp);
981         NG_FREE_MSG(msg);
982
983         return (error);
984 } /* ng_h4_rcvmsg */
985
986 /*
987  * Timeout processing function.
988  * We still have data to output to the device, so try sending more.
989  */
990
991 static void
992 ng_h4_process_timeout(node_p node, hook_p hook, void *arg1, int arg2)
993 {
994         ng_h4_info_p    sc = (ng_h4_info_p) NG_NODE_PRIVATE(node);
995
996         mtx_lock(&Giant);
997         ng_h4_start(sc->tp);
998         mtx_unlock(&Giant);
999 } /* ng_h4_process_timeout */
1000
1001 /*
1002  * Handle loading and unloading for this node type
1003  */
1004
1005 static int
1006 ng_h4_mod_event(module_t mod, int event, void *data)
1007 {
1008         static int      ng_h4_ldisc;
1009         int             error = 0;
1010
1011         switch (event) {
1012         case MOD_LOAD:
1013                 /* Register line discipline */
1014                 mtx_lock(&Giant);
1015                 ng_h4_ldisc = ldisc_register(H4DISC, &ng_h4_disc);
1016                 mtx_unlock(&Giant);
1017
1018                 if (ng_h4_ldisc < 0) {
1019                         kprintf("%s: can't register H4 line discipline\n",
1020                                 __func__);
1021                         error = EIO;
1022                 }
1023                 break;
1024
1025         case MOD_UNLOAD:
1026                 /* Unregister line discipline */
1027                 mtx_lock(&Giant);
1028                 ldisc_deregister(ng_h4_ldisc);
1029                 mtx_unlock(&Giant);
1030                 break;
1031
1032         default:
1033                 error = EOPNOTSUPP;
1034                 break;
1035         }
1036
1037         return (error);
1038 } /* ng_h4_mod_event */
1039