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