2 * Copyright (c) 1999, 2001 Hellmuth Michaelis. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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
25 *---------------------------------------------------------------------------
27 * i4b_ing.c - isdn4bsd B-channel to netgraph driver
28 * -------------------------------------------------
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.11 2007/06/04 00:40:31 swildner Exp $
33 * last edit-date: [Tue Jan 1 10:43:58 2002]
35 *---------------------------------------------------------------------------*/
37 #include "use_i4bing.h"
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
47 #include <sys/socket.h>
48 #include <sys/errno.h>
49 #include <sys/ctype.h>
50 #include <sys/syslog.h>
51 #include <sys/malloc.h>
52 #include <sys/thread2.h>
56 #include <netgraph/ng_message.h>
57 #include <netgraph/ng_parse.h>
58 #include <netgraph/netgraph.h>
60 #include <net/i4b/include/machine/i4b_debug.h>
61 #include <net/i4b/include/machine/i4b_ioctl.h>
63 #include "../include/i4b_global.h"
64 #include "../include/i4b_mbuf.h"
65 #include "../include/i4b_l3l4.h"
66 #include "../layer4/i4b_l4.h"
68 #define I4BINGACCT 1 /* enable accounting messages */
69 #define I4BINGACCTINTVL 2 /* accounting msg interval in secs */
71 #define I4BINGMAXQLEN 50 /* max queue length */
73 /* initialized by L4 */
75 static drvr_link_t ing_drvr_linktab
[NI4BING
];
76 static isdn_link_t
*isdn_linktab
[NI4BING
];
79 int sc_unit
; /* unit number */
80 int sc_state
; /* state of the interface */
81 call_desc_t
*sc_cdp
; /* ptr to call descriptor */
82 int sc_updown
; /* soft state of interface */
83 struct ifqueue sc_fastq
; /* interactive traffic */
84 int sc_dialresp
; /* dialresponse */
85 int sc_lastdialresp
;/* last dialresponse */
88 struct callout sc_timeout
;
89 int sc_iinb
; /* isdn driver # of inbytes */
90 int sc_ioutb
; /* isdn driver # of outbytes */
91 int sc_inb
; /* # of bytes rx'd */
92 int sc_outb
; /* # of bytes tx'd */
93 int sc_linb
; /* last # of bytes rx'd */
94 int sc_loutb
; /* last # of bytes tx'd */
95 int sc_fn
; /* flag, first null acct */
98 int sc_inpkt
; /* incoming packets */
99 int sc_outpkt
; /* outgoing packets */
101 struct ifqueue xmitq_hipri
; /* hi-priority transmit queue */
102 struct ifqueue xmitq
; /* transmit queue */
104 node_p node
; /* back pointer to node */
105 char nodename
[NG_NODESIZ
]; /* store our node name */
109 u_int packets_in
; /* packets in from downstream */
110 u_int packets_out
; /* packets out towards downstream */
113 } ing_softc
[NI4BING
];
116 ST_IDLE
, /* initialized, ready, idle */
117 ST_DIALING
, /* dialling out to remote */
118 ST_CONNECTED
/* connected to remote */
121 static void i4bingattach(void *);
123 PSEUDO_SET(i4bingattach
, i4b_ing
);
125 static void ing_init_linktab(int unit
);
126 static void ing_tx_queue_empty(int unit
);
128 /* ========= NETGRAPH ============= */
130 #define NG_ING_NODE_TYPE "i4bing" /* node type name */
131 #define NGM_ING_COOKIE 947513046 /* node type cookie */
134 #define NG_ING_HOOK_DEBUG "debug"
135 #define NG_ING_HOOK_RAW "rawdata"
137 /* Netgraph commands understood by this node type */
139 NGM_ING_SET_FLAG
= 1,
143 /* This structure is returned by the NGM_ING_GET_STATUS command */
145 u_int packets_in
; /* packets in from downstream */
146 u_int packets_out
; /* packets out towards downstream */
150 * This is used to define the 'parse type' for a struct ngingstat, which
151 * is bascially a description of how to convert a binary struct ngingstat
152 * to an ASCII string and back. See ng_parse.h for more info.
154 * This needs to be kept in sync with the above structure definition
156 #define NG_ING_STATS_TYPE_INFO { \
157 { "packets_in", &ng_parse_int32_type }, \
158 { "packets_out", &ng_parse_int32_type }, \
163 * This section contains the netgraph method declarations for the
164 * sample node. These methods define the netgraph 'type'.
167 static ng_constructor_t ng_ing_constructor
;
168 static ng_rcvmsg_t ng_ing_rcvmsg
;
169 static ng_shutdown_t ng_ing_rmnode
;
170 static ng_newhook_t ng_ing_newhook
;
171 static ng_connect_t ng_ing_connect
;
172 static ng_rcvdata_t ng_ing_rcvdata
;
173 static ng_disconnect_t ng_ing_disconnect
;
175 /* Parse type for struct ngingstat */
177 ng_parse_struct_field ng_ing_stat_type_fields
[] =
178 NG_ING_STATS_TYPE_INFO
;
180 static const struct ng_parse_type ng_ing_stat_type
= {
181 &ng_parse_struct_type
,
182 &ng_ing_stat_type_fields
185 /* List of commands and how to convert arguments to/from ASCII */
187 static const struct ng_cmdlist ng_ing_cmdlist
[] = {
199 &ng_parse_int32_type
,
205 /* Netgraph node type descriptor */
206 static struct ng_type typestruct
= {
222 NETGRAPH_INIT_ORDERED(ing
, &typestruct
, SI_SUB_DRIVERS
, SI_ORDER_ANY
);
224 /*===========================================================================*
225 * DEVICE DRIVER ROUTINES
226 *===========================================================================*/
228 /*---------------------------------------------------------------------------*
229 * interface attach routine at kernel boot time
230 *---------------------------------------------------------------------------*/
232 i4bingattach(void *dummy
)
234 struct ing_softc
*sc
= ing_softc
;
238 kprintf("i4bing: %d i4b NetGraph ISDN B-channel device(s) attached\n", NI4BING
);
240 for(i
=0; i
< NI4BING
; sc
++, i
++)
246 NDBGL4(L4_DIALST
, "setting dial state to ST_IDLE");
248 sc
->sc_state
= ST_IDLE
;
250 sc
->sc_fastq
.ifq_maxlen
= I4BINGMAXQLEN
;
253 callout_init(&sc
->sc_timeout
);
266 sc
->sc_updown
= SOFT_ENA
; /* soft enabled */
268 sc
->sc_dialresp
= DSTAT_NONE
; /* no response */
269 sc
->sc_lastdialresp
= DSTAT_NONE
;
271 /* setup a netgraph node */
273 if ((ret
= ng_make_node_common(&typestruct
, &sc
->node
)))
275 kprintf("ing: ng_make_node_common, ret = %d\n!", ret
);
278 sc
->node
->private = sc
;
280 sc
->xmitq
.ifq_maxlen
= IFQ_MAXLEN
;
281 sc
->xmitq_hipri
.ifq_maxlen
= IFQ_MAXLEN
;
283 /* name the netgraph node */
285 ksprintf(sc
->nodename
, "%s%d", NG_ING_NODE_TYPE
, sc
->sc_unit
);
287 if(ng_name_node(sc
->node
, sc
->nodename
))
296 /*---------------------------------------------------------------------------*
297 * accounting timeout routine
298 *---------------------------------------------------------------------------*/
300 ing_timeout(struct ing_softc
*sc
)
302 bchan_statistics_t bs
;
303 int unit
= sc
->sc_unit
;
305 /* get # of bytes in and out from the HSCX driver */
307 (*isdn_linktab
[unit
]->bch_stat
)
308 (isdn_linktab
[unit
]->unit
, isdn_linktab
[unit
]->channel
, &bs
);
310 sc
->sc_ioutb
+= bs
.outbytes
;
311 sc
->sc_iinb
+= bs
.inbytes
;
313 if((sc
->sc_iinb
!= sc
->sc_linb
) || (sc
->sc_ioutb
!= sc
->sc_loutb
) || sc
->sc_fn
)
315 int ri
= (sc
->sc_iinb
- sc
->sc_linb
)/I4BINGACCTINTVL
;
316 int ro
= (sc
->sc_ioutb
- sc
->sc_loutb
)/I4BINGACCTINTVL
;
318 if((sc
->sc_iinb
== sc
->sc_linb
) && (sc
->sc_ioutb
== sc
->sc_loutb
))
323 sc
->sc_linb
= sc
->sc_iinb
;
324 sc
->sc_loutb
= sc
->sc_ioutb
;
326 i4b_l4_accounting(BDRV_ING
, unit
, ACCT_DURING
,
327 sc
->sc_ioutb
, sc
->sc_iinb
, ro
, ri
, sc
->sc_ioutb
, sc
->sc_iinb
);
330 callout_reset(&sc
->sc_timeout
, I4BINGACCTINTVL
* hz
,
331 (TIMEOUT_FUNC_T
)ing_timeout
, sc
);
333 #endif /* I4BINGACCT */
336 /*---------------------------------------------------------------------------*
337 * clear the interface's send queues
338 *---------------------------------------------------------------------------*/
340 ingclearqueue(struct ifqueue
*iq
)
359 /*===========================================================================*
360 * ISDN INTERFACE ROUTINES
361 *===========================================================================*/
363 /*---------------------------------------------------------------------------*
364 * this routine is called from L4 handler at connect time
365 *---------------------------------------------------------------------------*/
367 ing_connect(int unit
, void *cdp
)
369 struct ing_softc
*sc
= &ing_softc
[unit
];
371 sc
->sc_cdp
= (call_desc_t
*)cdp
;
375 NDBGL4(L4_DIALST
, "ing%d: setting dial state to ST_CONNECTED", unit
);
377 sc
->sc_dialresp
= DSTAT_NONE
;
378 sc
->sc_lastdialresp
= DSTAT_NONE
;
387 callout_reset(&sc
->sc_timeout
, I4BINGACCTINTVL
* hz
,
388 (TIMEOUT_FUNC_T
)ing_timeout
, sc
);
391 sc
->sc_state
= ST_CONNECTED
;
396 /*---------------------------------------------------------------------------*
397 * this routine is called from L4 handler at disconnect time
398 *---------------------------------------------------------------------------*/
400 ing_disconnect(int unit
, void *cdp
)
402 call_desc_t
*cd
= (call_desc_t
*)cdp
;
403 struct ing_softc
*sc
= &ing_softc
[unit
];
405 /* new stuff to check that the active channel is being closed */
407 if (cd
!= sc
->sc_cdp
)
409 NDBGL4(L4_INGDBG
, "ing%d: channel %d not active",
410 cd
->driver_unit
, cd
->channelid
);
415 callout_stop(&sc
->sc_timeout
);
418 i4b_l4_accounting(BDRV_ING
, cd
->driver_unit
, ACCT_FINAL
,
419 sc
->sc_ioutb
, sc
->sc_iinb
, 0, 0, sc
->sc_outb
, sc
->sc_inb
);
423 NDBGL4(L4_DIALST
, "setting dial state to ST_IDLE");
425 sc
->sc_dialresp
= DSTAT_NONE
;
426 sc
->sc_lastdialresp
= DSTAT_NONE
;
428 sc
->sc_state
= ST_IDLE
;
431 /*---------------------------------------------------------------------------*
432 * this routine is used to give a feedback from userland daemon
433 * in case of dial problems
434 *---------------------------------------------------------------------------*/
436 ing_dialresponse(int unit
, int status
, cause_t cause
)
438 struct ing_softc
*sc
= &ing_softc
[unit
];
439 sc
->sc_dialresp
= status
;
441 NDBGL4(L4_INGDBG
, "ing%d: last=%d, this=%d",
442 unit
, sc
->sc_lastdialresp
, sc
->sc_dialresp
);
444 if(status
!= DSTAT_NONE
)
446 NDBGL4(L4_INGDBG
, "ing%d: clearing queues", unit
);
447 /* ingclearqueues(sc); */
451 /*---------------------------------------------------------------------------*
452 * interface soft up/down
453 *---------------------------------------------------------------------------*/
455 ing_updown(int unit
, int updown
)
457 struct ing_softc
*sc
= &ing_softc
[unit
];
458 sc
->sc_updown
= updown
;
461 /*---------------------------------------------------------------------------*
462 * this routine is called from the HSCX interrupt handler
463 * when a new frame (mbuf) has been received and was put on
464 * the rx queue. It is assumed that this routines runs at
465 * pri level splimp() ! Keep it short !
466 *---------------------------------------------------------------------------*/
468 ing_rx_data_rdy(int unit
)
470 struct ing_softc
*sc
= &ing_softc
[unit
];
473 if((m
= *isdn_linktab
[unit
]->rx_mbuf
) == NULL
)
477 sc
->sc_inb
+= m
->m_pkthdr
.len
;
480 m
->m_pkthdr
.rcvif
= NULL
;
484 ng_queue_data(sc
->hook
, m
, NULL
);
487 /*---------------------------------------------------------------------------*
488 * this routine is called from the HSCX interrupt handler
489 * when the last frame has been sent out and there is no
490 * further frame (mbuf) in the tx queue.
491 *---------------------------------------------------------------------------*/
493 ing_tx_queue_empty(int unit
)
495 struct ing_softc
*sc
= &ing_softc
[unit
];
499 if(sc
->sc_state
!= ST_CONNECTED
)
504 IF_DEQUEUE(&sc
->xmitq_hipri
, m
);
508 IF_DEQUEUE(&sc
->xmitq
, m
);
514 sc
->sc_outb
+= m
->m_pkthdr
.len
;
519 if(IF_QFULL(isdn_linktab
[unit
]->tx_queue
))
521 NDBGL4(L4_INGDBG
, "ing%d: tx queue full!", unit
);
526 IF_ENQUEUE(isdn_linktab
[unit
]->tx_queue
, m
);
531 (*isdn_linktab
[unit
]->bch_tx_start
)(isdn_linktab
[unit
]->unit
, isdn_linktab
[unit
]->channel
);
534 /*---------------------------------------------------------------------------*
535 * this routine is called from the HSCX interrupt handler
536 * each time a packet is received or transmitted. It should
537 * be used to implement an activity timeout mechanism.
538 *---------------------------------------------------------------------------*/
540 ing_activity(int unit
, int rxtx
)
542 ing_softc
[unit
].sc_cdp
->last_active_time
= SECOND
;
545 /*---------------------------------------------------------------------------*
546 * return this drivers linktab address
547 *---------------------------------------------------------------------------*/
549 ing_ret_linktab(int unit
)
551 return(&ing_drvr_linktab
[unit
]);
554 /*---------------------------------------------------------------------------*
555 * setup the isdn_linktab for this driver
556 *---------------------------------------------------------------------------*/
558 ing_set_linktab(int unit
, isdn_link_t
*ilt
)
560 isdn_linktab
[unit
] = ilt
;
563 /*---------------------------------------------------------------------------*
564 * initialize this drivers linktab
565 *---------------------------------------------------------------------------*/
567 ing_init_linktab(int unit
)
569 ing_drvr_linktab
[unit
].unit
= unit
;
570 ing_drvr_linktab
[unit
].bch_rx_data_ready
= ing_rx_data_rdy
;
571 ing_drvr_linktab
[unit
].bch_tx_queue_empty
= ing_tx_queue_empty
;
572 ing_drvr_linktab
[unit
].bch_activity
= ing_activity
;
573 ing_drvr_linktab
[unit
].line_connected
= ing_connect
;
574 ing_drvr_linktab
[unit
].line_disconnected
= ing_disconnect
;
575 ing_drvr_linktab
[unit
].dial_response
= ing_dialresponse
;
576 ing_drvr_linktab
[unit
].updown_ind
= ing_updown
;
579 /*===========================================================================*
580 * NETGRAPH INTERFACE ROUTINES
581 *===========================================================================*/
583 /*---------------------------------------------------------------------------*
584 * It is not possible or allowable to create a node of this type.
585 * If the hardware exists, it will already have created it.
586 *---------------------------------------------------------------------------*/
588 ng_ing_constructor(node_p
*nodep
)
593 /*---------------------------------------------------------------------------*
594 * Give our ok for a hook to be added...
595 * Add the hook's private info to the hook structure.
596 *---------------------------------------------------------------------------*/
598 ng_ing_newhook(node_p node
, hook_p hook
, const char *name
)
600 struct ing_softc
*sc
= node
->private;
603 * check if it's our friend the debug hook
605 if(strcmp(name
, NG_ING_HOOK_DEBUG
) == 0)
607 hook
->private = NULL
; /* paranoid */
608 sc
->debughook
= hook
;
612 * Check for raw mode hook.
614 if(strcmp(name
, NG_ING_HOOK_RAW
) == 0)
624 /*---------------------------------------------------------------------------*
625 * Get a netgraph control message.
626 * Check it is one we understand. If needed, send a response.
627 * We could save the address for an async action later, but don't here.
628 * Always free the message.
629 * The response should be in a malloc'd region that the caller can 'free'.
630 * A response is not required.
631 *---------------------------------------------------------------------------*/
633 ng_ing_rcvmsg(node_p node
, struct ng_mesg
*msg
, const char *retaddr
,
634 struct ng_mesg
**rptr
)
636 struct ing_softc
*sc
= node
->private;
638 struct ng_mesg
*resp
= NULL
;
641 if(msg
->header
.typecookie
== NGM_GENERIC_COOKIE
)
643 switch(msg
->header
.cmd
)
645 case NGM_TEXT_STATUS
:
651 NG_MKRESPONSE(resp
, msg
,
652 sizeof(struct ng_mesg
) + NG_TEXTRESPONSE
,
653 M_INTWAIT
| M_NULLOK
);
660 arg
= (char *) resp
->data
;
678 pos
= ksprintf(arg
, "state = %s (%d)\n", p
, sc
->sc_state
);
680 pos
+= ksprintf(arg
+ pos
, "%d bytes in, %d bytes out\n", sc
->sc_inb
, sc
->sc_outb
);
682 pos
+= ksprintf(arg
+ pos
, "%d pkts in, %d pkts out\n", sc
->sc_inpkt
, sc
->sc_outpkt
);
684 resp
->header
.arglen
= pos
+ 1;
693 else if(msg
->header
.typecookie
== NGM_ING_COOKIE
)
695 switch (msg
->header
.cmd
)
697 case NGM_ING_GET_STATUS
:
699 struct ngingstat
*stats
;
701 NG_MKRESPONSE(resp
, msg
, sizeof(*stats
),
702 M_INTWAIT
| M_NULLOK
);
710 stats
= (struct ngingstat
*) resp
->data
;
711 stats
->packets_in
= sc
->packets_in
;
712 stats
->packets_out
= sc
->packets_out
;
716 case NGM_ING_SET_FLAG
:
717 if (msg
->header
.arglen
!= sizeof(u_int32_t
))
722 sc
->flags
= *((u_int32_t
*) msg
->data
);
726 error
= EINVAL
; /* unknown command */
732 error
= EINVAL
; /* unknown cookie type */
735 /* Take care of synchronous response, if any */
740 FREE(resp
, M_NETGRAPH
);
742 /* Free the message and return */
744 FREE(msg
, M_NETGRAPH
);
748 /*---------------------------------------------------------------------------*
749 * get data from another node and transmit it out on a B-channel
750 *---------------------------------------------------------------------------*/
752 ng_ing_rcvdata(hook_p hook
, struct mbuf
*m
, meta_p meta
)
754 struct ing_softc
*sc
= hook
->node
->private;
755 struct ifqueue
*xmitq_p
;
757 if(hook
->private == NULL
)
759 NG_FREE_DATA(m
, meta
);
763 if(sc
->sc_state
== ST_IDLE
|| sc
->sc_state
== ST_DIALING
)
765 i4b_l4_dialout(BDRV_ING
, sc
->sc_unit
);
766 sc
->sc_state
= ST_DIALING
;
772 * Now queue the data for when it can be sent
775 if (meta
&& meta
->priority
> 0)
777 xmitq_p
= (&sc
->xmitq_hipri
);
781 xmitq_p
= (&sc
->xmitq
);
786 if (IF_QFULL(xmitq_p
))
790 NG_FREE_DATA(m
, meta
);
794 IF_ENQUEUE(xmitq_p
, m
);
796 ing_tx_queue_empty(sc
->sc_unit
);
802 /*---------------------------------------------------------------------------*
803 * Do local shutdown processing..
804 * If we are a persistant device, we might refuse to go away, and
805 * we'd only remove our links and reset ourself.
806 *---------------------------------------------------------------------------*/
808 ng_ing_rmnode(node_p node
)
810 struct ing_softc
*sc
= node
->private;
812 node
->flags
|= NG_INVALID
;
815 sc
->packets_in
= 0; /* reset stats */
818 node
->flags
&= ~NG_INVALID
; /* reset invalid flag */
823 /*---------------------------------------------------------------------------*
824 * This is called once we've already connected a new hook to the other node.
825 *---------------------------------------------------------------------------*/
827 ng_ing_connect(hook_p hook
)
835 * For this type, removal of the last link destroys the node
838 ng_ing_disconnect(hook_p hook
)
840 struct ing_softc
*sc
= hook
->node
->private;
842 if(hook
->private == NULL
) {
843 sc
->debughook
= NULL
;
848 /*===========================================================================*/
850 #endif /* NI4BING > 0 */