kernel: Replace all usage of MALLOC()/FREE() with kmalloc()/kfree().
[dragonfly.git] / sys / net / i4b / driver / i4b_ing.c
1 /*
2  * Copyright (c) 1999, 2001 Hellmuth Michaelis. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  *---------------------------------------------------------------------------
26  *
27  *      i4b_ing.c - isdn4bsd B-channel to netgraph driver
28  *      -------------------------------------------------
29  *
30  * $FreeBSD: src/sys/i4b/driver/i4b_ing.c,v 1.10.2.4 2002/07/02 23:44:02 archie Exp $
31  *
32  *      last edit-date: [Tue Jan  1 10:43:58 2002]
33  *
34  *---------------------------------------------------------------------------*/
35
36 #include "use_i4bing.h"
37
38 #if NI4BING > 0
39
40 #include "opt_i4b.h"
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/mbuf.h>
46 #include <sys/socket.h>
47 #include <sys/errno.h>
48 #include <sys/ctype.h>
49 #include <sys/syslog.h>
50 #include <sys/malloc.h>
51 #include <sys/thread2.h>
52
53 #include <net/if.h>
54
55 #include <netgraph/ng_message.h>
56 #include <netgraph/ng_parse.h>
57 #include <netgraph/netgraph.h>
58
59 #include <net/i4b/include/machine/i4b_debug.h>
60 #include <net/i4b/include/machine/i4b_ioctl.h>
61
62 #include "../include/i4b_global.h"
63 #include "../include/i4b_mbuf.h"
64 #include "../include/i4b_l3l4.h"
65 #include "../layer4/i4b_l4.h"
66
67 #define I4BINGACCT      1               /* enable accounting messages */
68 #define I4BINGACCTINTVL 2               /* accounting msg interval in secs */
69
70 #define I4BINGMAXQLEN   50              /* max queue length */
71
72 /* initialized by L4 */
73
74 static drvr_link_t ing_drvr_linktab[NI4BING];
75 static isdn_link_t *isdn_linktab[NI4BING];
76
77 struct ing_softc {
78         int             sc_unit;        /* unit number                  */
79         int             sc_state;       /* state of the interface       */
80         call_desc_t     *sc_cdp;        /* ptr to call descriptor       */
81         int             sc_updown;      /* soft state of interface      */
82         struct ifqueue  sc_fastq;       /* interactive traffic          */
83         int             sc_dialresp;    /* dialresponse                 */
84         int             sc_lastdialresp;/* last dialresponse            */
85
86 #if I4BINGACCT
87         struct callout  sc_timeout;
88         int             sc_iinb;        /* isdn driver # of inbytes     */
89         int             sc_ioutb;       /* isdn driver # of outbytes    */
90         int             sc_inb;         /* # of bytes rx'd              */
91         int             sc_outb;        /* # of bytes tx'd              */
92         int             sc_linb;        /* last # of bytes rx'd         */
93         int             sc_loutb;       /* last # of bytes tx'd         */
94         int             sc_fn;          /* flag, first null acct        */
95 #endif
96
97         int             sc_inpkt;       /* incoming packets             */
98         int             sc_outpkt;      /* outgoing packets             */
99
100         struct ifqueue  xmitq_hipri;    /* hi-priority transmit queue */
101         struct ifqueue  xmitq;    /* transmit queue */
102
103         node_p          node;           /* back pointer to node */
104         char            nodename[NG_NODESIZ]; /* store our node name */
105         hook_p          debughook;
106         hook_p          hook;
107
108         u_int           packets_in;     /* packets in from downstream */
109         u_int           packets_out;    /* packets out towards downstream */
110         u_int32_t       flags;
111
112 } ing_softc[NI4BING];
113
114 enum ing_states {
115         ST_IDLE,                        /* initialized, ready, idle     */
116         ST_DIALING,                     /* dialling out to remote       */
117         ST_CONNECTED                    /* connected to remote          */
118 };
119
120 static void i4bingattach(void *);
121
122 PSEUDO_SET(i4bingattach, i4b_ing);
123
124 static void ing_init_linktab(int unit);
125 static void ing_tx_queue_empty(int unit);
126
127 /* ========= NETGRAPH ============= */
128
129 #define NG_ING_NODE_TYPE        "i4bing"        /* node type name */
130 #define NGM_ING_COOKIE          947513046       /* node type cookie */
131
132 /* Hook names */
133 #define NG_ING_HOOK_DEBUG       "debug"
134 #define NG_ING_HOOK_RAW         "rawdata"
135
136 /* Netgraph commands understood by this node type */
137 enum {
138         NGM_ING_SET_FLAG = 1,
139         NGM_ING_GET_STATUS,
140 };
141
142 /* This structure is returned by the NGM_ING_GET_STATUS command */
143 struct ngingstat {
144         u_int   packets_in;     /* packets in from downstream */
145         u_int   packets_out;    /* packets out towards downstream */
146 };
147
148 /*
149  * This is used to define the 'parse type' for a struct ngingstat, which
150  * is bascially a description of how to convert a binary struct ngingstat
151  * to an ASCII string and back.  See ng_parse.h for more info.
152  *
153  * This needs to be kept in sync with the above structure definition
154  */
155 #define NG_ING_STATS_TYPE_INFO  {                               \
156           { "packets_in",       &ng_parse_int32_type    },      \
157           { "packets_out",      &ng_parse_int32_type    },      \
158           { NULL },                                             \
159 }
160
161 /*
162  * This section contains the netgraph method declarations for the
163  * sample node. These methods define the netgraph 'type'.
164  */
165
166 static ng_constructor_t ng_ing_constructor;
167 static ng_rcvmsg_t      ng_ing_rcvmsg;
168 static ng_shutdown_t    ng_ing_rmnode;
169 static ng_newhook_t     ng_ing_newhook;
170 static ng_connect_t     ng_ing_connect;
171 static ng_rcvdata_t     ng_ing_rcvdata;
172 static ng_disconnect_t  ng_ing_disconnect;
173
174 /* Parse type for struct ngingstat */
175 static const struct
176         ng_parse_struct_field ng_ing_stat_type_fields[] =
177         NG_ING_STATS_TYPE_INFO;
178
179 static const struct ng_parse_type ng_ing_stat_type = {
180         &ng_parse_struct_type,
181         &ng_ing_stat_type_fields
182 };
183
184 /* List of commands and how to convert arguments to/from ASCII */
185
186 static const struct ng_cmdlist ng_ing_cmdlist[] = {
187         {
188                 NGM_ING_COOKIE,
189                 NGM_ING_GET_STATUS,
190                 "getstatus",
191                 NULL,
192                 &ng_ing_stat_type,
193         },
194         {
195                 NGM_ING_COOKIE,
196                 NGM_ING_SET_FLAG,
197                 "setflag",
198                 &ng_parse_int32_type,
199                 NULL
200         },
201         { 0 }
202 };
203
204 /* Netgraph node type descriptor */
205 static struct ng_type typestruct = {
206         NG_VERSION,
207         NG_ING_NODE_TYPE,
208         NULL,
209         ng_ing_constructor,
210         ng_ing_rcvmsg,
211         ng_ing_rmnode,
212         ng_ing_newhook,
213         NULL,
214         ng_ing_connect,
215         ng_ing_rcvdata,
216         ng_ing_rcvdata,
217         ng_ing_disconnect,
218         ng_ing_cmdlist
219 };
220
221 NETGRAPH_INIT_ORDERED(ing, &typestruct, SI_SUB_DRIVERS, SI_ORDER_ANY);
222
223 /*===========================================================================*
224  *                      DEVICE DRIVER ROUTINES
225  *===========================================================================*/
226
227 /*---------------------------------------------------------------------------*
228  *      interface attach routine at kernel boot time
229  *---------------------------------------------------------------------------*/
230 static void
231 i4bingattach(void *dummy)
232 {
233         struct ing_softc *sc = ing_softc;
234         int i;
235         int ret;
236
237         kprintf("i4bing: %d i4b NetGraph ISDN B-channel device(s) attached\n", NI4BING);
238
239         for(i=0; i < NI4BING; sc++, i++)
240         {
241                 sc->sc_unit = i;
242
243                 ing_init_linktab(i);
244
245                 NDBGL4(L4_DIALST, "setting dial state to ST_IDLE");
246
247                 sc->sc_state = ST_IDLE;
248
249                 sc->sc_fastq.ifq_maxlen = I4BINGMAXQLEN;
250
251 #if I4BINGACCT
252                 callout_init(&sc->sc_timeout);
253                 sc->sc_iinb = 0;
254                 sc->sc_ioutb = 0;
255                 sc->sc_inb = 0;
256                 sc->sc_outb = 0;
257                 sc->sc_linb = 0;
258                 sc->sc_loutb = 0;
259                 sc->sc_fn = 1;
260 #endif
261
262                 sc->sc_inpkt = 0;
263                 sc->sc_outpkt = 0;
264
265                 sc->sc_updown = SOFT_ENA;       /* soft enabled */
266
267                 sc->sc_dialresp = DSTAT_NONE;   /* no response */
268                 sc->sc_lastdialresp = DSTAT_NONE;
269
270                 /* setup a netgraph node */
271
272                 if ((ret = ng_make_node_common(&typestruct, &sc->node)))
273                 {
274                         kprintf("ing: ng_make_node_common, ret = %d\n!", ret);
275                 }
276
277                 sc->node->private = sc;
278
279                 sc->xmitq.ifq_maxlen = IFQ_MAXLEN;
280                 sc->xmitq_hipri.ifq_maxlen = IFQ_MAXLEN;
281
282                 /* name the netgraph node */
283
284                 ksprintf(sc->nodename, "%s%d", NG_ING_NODE_TYPE, sc->sc_unit);
285
286                 if(ng_name_node(sc->node, sc->nodename))
287                 {
288                         ng_rmnode(sc->node);
289                         ng_unref(sc->node);
290                 }
291         }
292 }
293
294 #ifdef I4BINGACCT
295 /*---------------------------------------------------------------------------*
296  *      accounting timeout routine
297  *---------------------------------------------------------------------------*/
298 static void
299 ing_timeout(struct ing_softc *sc)
300 {
301         bchan_statistics_t bs;
302         int unit = sc->sc_unit;
303
304         /* get # of bytes in and out from the HSCX driver */
305
306         (*isdn_linktab[unit]->bch_stat)
307                 (isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs);
308
309         sc->sc_ioutb += bs.outbytes;
310         sc->sc_iinb += bs.inbytes;
311
312         if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn)
313         {
314                 int ri = (sc->sc_iinb - sc->sc_linb)/I4BINGACCTINTVL;
315                 int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BINGACCTINTVL;
316
317                 if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
318                         sc->sc_fn = 0;
319                 else
320                         sc->sc_fn = 1;
321
322                 sc->sc_linb = sc->sc_iinb;
323                 sc->sc_loutb = sc->sc_ioutb;
324
325                 i4b_l4_accounting(BDRV_ING, unit, ACCT_DURING,
326                          sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_ioutb, sc->sc_iinb);
327         }
328
329         callout_reset(&sc->sc_timeout, I4BINGACCTINTVL * hz,
330                         (TIMEOUT_FUNC_T)ing_timeout, sc);
331 }
332 #endif /* I4BINGACCT */
333
334 #if 0
335 /*---------------------------------------------------------------------------*
336  *      clear the interface's send queues
337  *---------------------------------------------------------------------------*/
338 static void
339 ingclearqueue(struct ifqueue *iq)
340 {
341         int x;
342         struct mbuf *m;
343
344         for(;;)
345         {
346                 crit_enter();
347                 IF_DEQUEUE(iq, m);
348                 crit_exit();
349
350                 if(m)
351                         m_freem(m);
352                 else
353                         break;
354         }
355 }
356 #endif
357
358 /*===========================================================================*
359  *                      ISDN INTERFACE ROUTINES
360  *===========================================================================*/
361
362 /*---------------------------------------------------------------------------*
363  *      this routine is called from L4 handler at connect time
364  *---------------------------------------------------------------------------*/
365 static void
366 ing_connect(int unit, void *cdp)
367 {
368         struct ing_softc *sc = &ing_softc[unit];
369
370         sc->sc_cdp = (call_desc_t *)cdp;
371
372         crit_enter();
373
374         NDBGL4(L4_DIALST, "ing%d: setting dial state to ST_CONNECTED", unit);
375
376         sc->sc_dialresp = DSTAT_NONE;
377         sc->sc_lastdialresp = DSTAT_NONE;
378
379 #if I4BINGACCT
380         sc->sc_iinb = 0;
381         sc->sc_ioutb = 0;
382         sc->sc_inb = 0;
383         sc->sc_outb = 0;
384         sc->sc_linb = 0;
385         sc->sc_loutb = 0;
386         callout_reset(&sc->sc_timeout, I4BINGACCTINTVL * hz,
387                         (TIMEOUT_FUNC_T)ing_timeout, sc);
388 #endif
389
390         sc->sc_state = ST_CONNECTED;
391
392         crit_exit();
393 }
394
395 /*---------------------------------------------------------------------------*
396  *      this routine is called from L4 handler at disconnect time
397  *---------------------------------------------------------------------------*/
398 static void
399 ing_disconnect(int unit, void *cdp)
400 {
401         call_desc_t *cd = (call_desc_t *)cdp;
402         struct ing_softc *sc = &ing_softc[unit];
403
404         /* new stuff to check that the active channel is being closed */
405
406         if (cd != sc->sc_cdp)
407         {
408                 NDBGL4(L4_INGDBG, "ing%d: channel %d not active",
409                                 cd->driver_unit, cd->channelid);
410                 return;
411         }
412
413 #if I4BINGACCT
414         callout_stop(&sc->sc_timeout);
415 #endif
416
417         i4b_l4_accounting(BDRV_ING, cd->driver_unit, ACCT_FINAL,
418                  sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_outb, sc->sc_inb);
419
420         sc->sc_cdp = NULL;
421
422         NDBGL4(L4_DIALST, "setting dial state to ST_IDLE");
423
424         sc->sc_dialresp = DSTAT_NONE;
425         sc->sc_lastdialresp = DSTAT_NONE;
426
427         sc->sc_state = ST_IDLE;
428 }
429
430 /*---------------------------------------------------------------------------*
431  *      this routine is used to give a feedback from userland daemon
432  *      in case of dial problems
433  *---------------------------------------------------------------------------*/
434 static void
435 ing_dialresponse(int unit, int status, cause_t cause)
436 {
437         struct ing_softc *sc = &ing_softc[unit];
438         sc->sc_dialresp = status;
439
440         NDBGL4(L4_INGDBG, "ing%d: last=%d, this=%d",
441                 unit, sc->sc_lastdialresp, sc->sc_dialresp);
442
443         if(status != DSTAT_NONE)
444         {
445                 NDBGL4(L4_INGDBG, "ing%d: clearing queues", unit);
446 /*              ingclearqueues(sc); */
447         }
448 }
449
450 /*---------------------------------------------------------------------------*
451  *      interface soft up/down
452  *---------------------------------------------------------------------------*/
453 static void
454 ing_updown(int unit, int updown)
455 {
456         struct ing_softc *sc = &ing_softc[unit];
457         sc->sc_updown = updown;
458 }
459
460 /*---------------------------------------------------------------------------*
461  *      this routine is called from the HSCX interrupt handler
462  *      when a new frame (mbuf) has been received and was put on
463  *      the rx queue. It is assumed that this routines runs at
464  *      pri level splimp() ! Keep it short !
465  *---------------------------------------------------------------------------*/
466 static void
467 ing_rx_data_rdy(int unit)
468 {
469         struct ing_softc *sc = &ing_softc[unit];
470         struct mbuf *m;
471
472         if((m = *isdn_linktab[unit]->rx_mbuf) == NULL)
473                 return;
474
475 #if I4BINGACCT
476         sc->sc_inb += m->m_pkthdr.len;
477 #endif
478
479         m->m_pkthdr.rcvif = NULL;
480
481         sc->sc_inpkt++;
482
483         ng_queue_data(sc->hook, m, NULL);
484 }
485
486 /*---------------------------------------------------------------------------*
487  *      this routine is called from the HSCX interrupt handler
488  *      when the last frame has been sent out and there is no
489  *      further frame (mbuf) in the tx queue.
490  *---------------------------------------------------------------------------*/
491 static void
492 ing_tx_queue_empty(int unit)
493 {
494         struct ing_softc *sc = &ing_softc[unit];
495         struct mbuf *m;
496         int x = 0;
497
498         if(sc->sc_state != ST_CONNECTED)
499                 return;
500
501         for(;;)
502         {
503                 IF_DEQUEUE(&sc->xmitq_hipri, m);
504
505                 if(m == NULL)
506                 {
507                         IF_DEQUEUE(&sc->xmitq, m);
508                         if(m == NULL)
509                                 break;
510                 }
511
512 #if I4BINGACCT
513                 sc->sc_outb += m->m_pkthdr.len;
514 #endif
515
516                 x = 1;
517
518                 if(IF_QFULL(isdn_linktab[unit]->tx_queue))
519                 {
520                         NDBGL4(L4_INGDBG, "ing%d: tx queue full!", unit);
521                         m_freem(m);
522                 }
523                 else
524                 {
525                         IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m);
526                 }
527         }
528
529         if(x)
530                 (*isdn_linktab[unit]->bch_tx_start)(isdn_linktab[unit]->unit, isdn_linktab[unit]->channel);
531 }
532
533 /*---------------------------------------------------------------------------*
534  *      this routine is called from the HSCX interrupt handler
535  *      each time a packet is received or transmitted. It should
536  *      be used to implement an activity timeout mechanism.
537  *---------------------------------------------------------------------------*/
538 static void
539 ing_activity(int unit, int rxtx)
540 {
541         ing_softc[unit].sc_cdp->last_active_time = SECOND;
542 }
543
544 /*---------------------------------------------------------------------------*
545  *      return this drivers linktab address
546  *---------------------------------------------------------------------------*/
547 drvr_link_t *
548 ing_ret_linktab(int unit)
549 {
550         return(&ing_drvr_linktab[unit]);
551 }
552
553 /*---------------------------------------------------------------------------*
554  *      setup the isdn_linktab for this driver
555  *---------------------------------------------------------------------------*/
556 void
557 ing_set_linktab(int unit, isdn_link_t *ilt)
558 {
559         isdn_linktab[unit] = ilt;
560 }
561
562 /*---------------------------------------------------------------------------*
563  *      initialize this drivers linktab
564  *---------------------------------------------------------------------------*/
565 static void
566 ing_init_linktab(int unit)
567 {
568         ing_drvr_linktab[unit].unit = unit;
569         ing_drvr_linktab[unit].bch_rx_data_ready = ing_rx_data_rdy;
570         ing_drvr_linktab[unit].bch_tx_queue_empty = ing_tx_queue_empty;
571         ing_drvr_linktab[unit].bch_activity = ing_activity;
572         ing_drvr_linktab[unit].line_connected = ing_connect;
573         ing_drvr_linktab[unit].line_disconnected = ing_disconnect;
574         ing_drvr_linktab[unit].dial_response = ing_dialresponse;
575         ing_drvr_linktab[unit].updown_ind = ing_updown;
576 }
577
578 /*===========================================================================*
579  *                      NETGRAPH INTERFACE ROUTINES
580  *===========================================================================*/
581
582 /*---------------------------------------------------------------------------*
583  * It is not possible or allowable to create a node of this type.
584  * If the hardware exists, it will already have created it.
585  *---------------------------------------------------------------------------*/
586 static int
587 ng_ing_constructor(node_p *nodep)
588 {
589         return(EINVAL);
590 }
591
592 /*---------------------------------------------------------------------------*
593  * Give our ok for a hook to be added...
594  * Add the hook's private info to the hook structure.
595  *---------------------------------------------------------------------------*/
596 static int
597 ng_ing_newhook(node_p node, hook_p hook, const char *name)
598 {
599         struct ing_softc *sc = node->private;
600
601         /*
602          * check if it's our friend the debug hook
603          */
604         if(strcmp(name, NG_ING_HOOK_DEBUG) == 0)
605         {
606                 hook->private = NULL; /* paranoid */
607                 sc->debughook = hook;
608                 return (0);
609         }
610         /*
611          * Check for raw mode hook.
612          */
613         if(strcmp(name, NG_ING_HOOK_RAW) == 0)
614         {
615                 hook->private = sc;
616                 sc->hook = hook;
617                 return (0);
618         }
619
620         return (EINVAL);
621 }
622
623 /*---------------------------------------------------------------------------*
624  * Get a netgraph control message.
625  * Check it is one we understand. If needed, send a response.
626  * We could save the address for an async action later, but don't here.
627  * Always free the message.
628  * The response should be in a malloc'd region that the caller can 'free'.
629  * A response is not required.
630  *---------------------------------------------------------------------------*/
631 static int
632 ng_ing_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr,
633                                                         struct ng_mesg **rptr)
634 {
635         struct ing_softc *sc = node->private;
636
637         struct ng_mesg *resp = NULL;
638         int error = 0;
639
640         if(msg->header.typecookie == NGM_GENERIC_COOKIE)
641         {
642                 switch(msg->header.cmd)
643                 {
644                         case NGM_TEXT_STATUS:
645                         {
646                                 char *arg;
647                                 char *p;
648                                 int pos = 0;
649
650                                 NG_MKRESPONSE(resp, msg,
651                                     sizeof(struct ng_mesg) + NG_TEXTRESPONSE,
652                                     M_INTWAIT | M_NULLOK);
653
654                                 if (resp == NULL)
655                                 {
656                                         error = ENOMEM;
657                                         break;
658                                 }
659                                 arg = (char *) resp->data;
660
661                                 switch(sc->sc_state)
662                                 {
663                                         case ST_IDLE:
664                                                 p = "idle";
665                                                 break;
666                                         case ST_DIALING:
667                                                 p = "dialing";
668                                                 break;
669                                         case ST_CONNECTED:
670                                                 p = "connected";
671                                                 break;
672                                         default:
673                                                 p = "???";
674                                                 break;
675                                 }
676
677                                 pos = ksprintf(arg, "state = %s (%d)\n", p, sc->sc_state);
678 #if I4BINGACCT
679                                 pos += ksprintf(arg + pos, "%d bytes in, %d bytes out\n", sc->sc_inb, sc->sc_outb);
680 #endif
681                                 pos += ksprintf(arg + pos, "%d pkts in, %d pkts out\n", sc->sc_inpkt, sc->sc_outpkt);
682
683                                 resp->header.arglen = pos + 1;
684                                 break;
685                         }
686
687                         default:
688                                 error = EINVAL;
689                                 break;
690                 }
691         }
692         else if(msg->header.typecookie == NGM_ING_COOKIE)
693         {
694                 switch (msg->header.cmd)
695                 {
696                         case NGM_ING_GET_STATUS:
697                         {
698                                 struct ngingstat *stats;
699
700                                 NG_MKRESPONSE(resp, msg, sizeof(*stats),
701                                     M_INTWAIT | M_NULLOK);
702
703                                 if (!resp)
704                                 {
705                                         error = ENOMEM;
706                                         break;
707                                 }
708
709                                 stats = (struct ngingstat *) resp->data;
710                                 stats->packets_in = sc->packets_in;
711                                 stats->packets_out = sc->packets_out;
712                                 break;
713                         }
714
715                         case NGM_ING_SET_FLAG:
716                                 if (msg->header.arglen != sizeof(u_int32_t))
717                                 {
718                                         error = EINVAL;
719                                         break;
720                                 }
721                                 sc->flags = *((u_int32_t *) msg->data);
722                                 break;
723
724                         default:
725                                 error = EINVAL;         /* unknown command */
726                                 break;
727                 }
728         }
729         else
730         {
731                 error = EINVAL;                 /* unknown cookie type */
732         }
733
734         /* Take care of synchronous response, if any */
735
736         if (rptr)
737                 *rptr = resp;
738         else if (resp)
739                 kfree(resp, M_NETGRAPH);
740
741         /* Free the message and return */
742
743         kfree(msg, M_NETGRAPH);
744         return(error);
745 }
746
747 /*---------------------------------------------------------------------------*
748  * get data from another node and transmit it out on a B-channel
749  *---------------------------------------------------------------------------*/
750 static int
751 ng_ing_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
752 {
753         struct ing_softc *sc = hook->node->private;
754         struct ifqueue  *xmitq_p;
755
756         if(hook->private == NULL)
757         {
758                 NG_FREE_DATA(m, meta);
759                 return(ENETDOWN);
760         }
761
762         if(sc->sc_state == ST_IDLE || sc->sc_state == ST_DIALING)
763         {
764                 i4b_l4_dialout(BDRV_ING, sc->sc_unit);
765                 sc->sc_state = ST_DIALING;
766         }
767
768         sc->sc_outpkt++;
769
770        /*
771         * Now queue the data for when it can be sent
772         */
773
774         if (meta && meta->priority > 0)
775         {
776                 xmitq_p = (&sc->xmitq_hipri);
777         }
778         else
779         {
780                 xmitq_p = (&sc->xmitq);
781         }
782
783         crit_enter();
784
785         if (IF_QFULL(xmitq_p))
786         {
787                 IF_DROP(xmitq_p);
788                 crit_exit();
789                 NG_FREE_DATA(m, meta);
790                 return(ENOBUFS);
791         }
792
793         IF_ENQUEUE(xmitq_p, m);
794
795         ing_tx_queue_empty(sc->sc_unit);
796
797         crit_exit();
798         return (0);
799 }
800
801 /*---------------------------------------------------------------------------*
802  * Do local shutdown processing..
803  * If we are a persistant device, we might refuse to go away, and
804  * we'd only remove our links and reset ourself.
805  *---------------------------------------------------------------------------*/
806 static int
807 ng_ing_rmnode(node_p node)
808 {
809         struct ing_softc *sc = node->private;
810
811         node->flags |= NG_INVALID;
812         ng_cutlinks(node);
813
814         sc->packets_in = 0;             /* reset stats */
815         sc->packets_out = 0;
816
817         node->flags &= ~NG_INVALID;     /* reset invalid flag */
818
819         return (0);
820 }
821
822 /*---------------------------------------------------------------------------*
823  * This is called once we've already connected a new hook to the other node.
824  *---------------------------------------------------------------------------*/
825 static int
826 ng_ing_connect(hook_p hook)
827 {
828         return (0);
829 }
830
831 /*
832  * Dook disconnection
833  *
834  * For this type, removal of the last link destroys the node
835  */
836 static int
837 ng_ing_disconnect(hook_p hook)
838 {
839         struct ing_softc *sc = hook->node->private;
840
841         if(hook->private == NULL) {
842                 sc->debughook = NULL;
843         }
844         return (0);
845 }
846
847 /*===========================================================================*/
848
849 #endif /* NI4BING > 0 */