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