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.10 2006/12/23 00:44:55 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/ioccom.h>
51 #include <sys/syslog.h>
52 #include <sys/malloc.h>
53 #include <sys/thread2.h>
57 #include <netgraph/ng_message.h>
58 #include <netgraph/ng_parse.h>
59 #include <netgraph/netgraph.h>
61 #include <net/i4b/include/machine/i4b_debug.h>
62 #include <net/i4b/include/machine/i4b_ioctl.h>
64 #include "../include/i4b_global.h"
65 #include "../include/i4b_mbuf.h"
66 #include "../include/i4b_l3l4.h"
67 #include "../layer4/i4b_l4.h"
69 #define I4BINGACCT 1 /* enable accounting messages */
70 #define I4BINGACCTINTVL 2 /* accounting msg interval in secs */
72 #define I4BINGMAXQLEN 50 /* max queue length */
74 /* initialized by L4 */
76 static drvr_link_t ing_drvr_linktab
[NI4BING
];
77 static isdn_link_t
*isdn_linktab
[NI4BING
];
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 */
89 struct callout sc_timeout
;
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 */
99 int sc_inpkt
; /* incoming packets */
100 int sc_outpkt
; /* outgoing packets */
102 struct ifqueue xmitq_hipri
; /* hi-priority transmit queue */
103 struct ifqueue xmitq
; /* transmit queue */
105 node_p node
; /* back pointer to node */
106 char nodename
[NG_NODELEN
+ 1]; /* store our node name */
110 u_int packets_in
; /* packets in from downstream */
111 u_int packets_out
; /* packets out towards downstream */
114 } ing_softc
[NI4BING
];
117 ST_IDLE
, /* initialized, ready, idle */
118 ST_DIALING
, /* dialling out to remote */
119 ST_CONNECTED
/* connected to remote */
122 static void i4bingattach(void *);
124 PSEUDO_SET(i4bingattach
, i4b_ing
);
126 static void ing_init_linktab(int unit
);
127 static void ing_tx_queue_empty(int unit
);
129 /* ========= NETGRAPH ============= */
131 #define NG_ING_NODE_TYPE "i4bing" /* node type name */
132 #define NGM_ING_COOKIE 947513046 /* node type cookie */
135 #define NG_ING_HOOK_DEBUG "debug"
136 #define NG_ING_HOOK_RAW "rawdata"
138 /* Netgraph commands understood by this node type */
140 NGM_ING_SET_FLAG
= 1,
144 /* This structure is returned by the NGM_ING_GET_STATUS command */
146 u_int packets_in
; /* packets in from downstream */
147 u_int packets_out
; /* packets out towards downstream */
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.
155 * This needs to be kept in sync with the above structure definition
157 #define NG_ING_STATS_TYPE_INFO { \
158 { "packets_in", &ng_parse_int32_type }, \
159 { "packets_out", &ng_parse_int32_type }, \
164 * This section contains the netgraph method declarations for the
165 * sample node. These methods define the netgraph 'type'.
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
;
176 /* Parse type for struct ngingstat */
178 ng_parse_struct_field ng_ing_stat_type_fields
[] =
179 NG_ING_STATS_TYPE_INFO
;
181 static const struct ng_parse_type ng_ing_stat_type
= {
182 &ng_parse_struct_type
,
183 &ng_ing_stat_type_fields
186 /* List of commands and how to convert arguments to/from ASCII */
188 static const struct ng_cmdlist ng_ing_cmdlist
[] = {
200 &ng_parse_int32_type
,
206 /* Netgraph node type descriptor */
207 static struct ng_type typestruct
= {
223 NETGRAPH_INIT_ORDERED(ing
, &typestruct
, SI_SUB_DRIVERS
, SI_ORDER_ANY
);
225 /*===========================================================================*
226 * DEVICE DRIVER ROUTINES
227 *===========================================================================*/
229 /*---------------------------------------------------------------------------*
230 * interface attach routine at kernel boot time
231 *---------------------------------------------------------------------------*/
233 i4bingattach(void *dummy
)
235 struct ing_softc
*sc
= ing_softc
;
239 kprintf("i4bing: %d i4b NetGraph ISDN B-channel device(s) attached\n", NI4BING
);
241 for(i
=0; i
< NI4BING
; sc
++, i
++)
247 NDBGL4(L4_DIALST
, "setting dial state to ST_IDLE");
249 sc
->sc_state
= ST_IDLE
;
251 sc
->sc_fastq
.ifq_maxlen
= I4BINGMAXQLEN
;
254 callout_init(&sc
->sc_timeout
);
267 sc
->sc_updown
= SOFT_ENA
; /* soft enabled */
269 sc
->sc_dialresp
= DSTAT_NONE
; /* no response */
270 sc
->sc_lastdialresp
= DSTAT_NONE
;
272 /* setup a netgraph node */
274 if ((ret
= ng_make_node_common(&typestruct
, &sc
->node
)))
276 kprintf("ing: ng_make_node_common, ret = %d\n!", ret
);
279 sc
->node
->private = sc
;
281 sc
->xmitq
.ifq_maxlen
= IFQ_MAXLEN
;
282 sc
->xmitq_hipri
.ifq_maxlen
= IFQ_MAXLEN
;
284 /* name the netgraph node */
286 ksprintf(sc
->nodename
, "%s%d", NG_ING_NODE_TYPE
, sc
->sc_unit
);
288 if(ng_name_node(sc
->node
, sc
->nodename
))
297 /*---------------------------------------------------------------------------*
298 * accounting timeout routine
299 *---------------------------------------------------------------------------*/
301 ing_timeout(struct ing_softc
*sc
)
303 bchan_statistics_t bs
;
304 int unit
= sc
->sc_unit
;
306 /* get # of bytes in and out from the HSCX driver */
308 (*isdn_linktab
[unit
]->bch_stat
)
309 (isdn_linktab
[unit
]->unit
, isdn_linktab
[unit
]->channel
, &bs
);
311 sc
->sc_ioutb
+= bs
.outbytes
;
312 sc
->sc_iinb
+= bs
.inbytes
;
314 if((sc
->sc_iinb
!= sc
->sc_linb
) || (sc
->sc_ioutb
!= sc
->sc_loutb
) || sc
->sc_fn
)
316 int ri
= (sc
->sc_iinb
- sc
->sc_linb
)/I4BINGACCTINTVL
;
317 int ro
= (sc
->sc_ioutb
- sc
->sc_loutb
)/I4BINGACCTINTVL
;
319 if((sc
->sc_iinb
== sc
->sc_linb
) && (sc
->sc_ioutb
== sc
->sc_loutb
))
324 sc
->sc_linb
= sc
->sc_iinb
;
325 sc
->sc_loutb
= sc
->sc_ioutb
;
327 i4b_l4_accounting(BDRV_ING
, unit
, ACCT_DURING
,
328 sc
->sc_ioutb
, sc
->sc_iinb
, ro
, ri
, sc
->sc_ioutb
, sc
->sc_iinb
);
331 callout_reset(&sc
->sc_timeout
, I4BINGACCTINTVL
* hz
,
332 (TIMEOUT_FUNC_T
)ing_timeout
, sc
);
334 #endif /* I4BINGACCT */
337 /*---------------------------------------------------------------------------*
338 * clear the interface's send queues
339 *---------------------------------------------------------------------------*/
341 ingclearqueue(struct ifqueue
*iq
)
360 /*===========================================================================*
361 * ISDN INTERFACE ROUTINES
362 *===========================================================================*/
364 /*---------------------------------------------------------------------------*
365 * this routine is called from L4 handler at connect time
366 *---------------------------------------------------------------------------*/
368 ing_connect(int unit
, void *cdp
)
370 struct ing_softc
*sc
= &ing_softc
[unit
];
372 sc
->sc_cdp
= (call_desc_t
*)cdp
;
376 NDBGL4(L4_DIALST
, "ing%d: setting dial state to ST_CONNECTED", unit
);
378 sc
->sc_dialresp
= DSTAT_NONE
;
379 sc
->sc_lastdialresp
= DSTAT_NONE
;
388 callout_reset(&sc
->sc_timeout
, I4BINGACCTINTVL
* hz
,
389 (TIMEOUT_FUNC_T
)ing_timeout
, sc
);
392 sc
->sc_state
= ST_CONNECTED
;
397 /*---------------------------------------------------------------------------*
398 * this routine is called from L4 handler at disconnect time
399 *---------------------------------------------------------------------------*/
401 ing_disconnect(int unit
, void *cdp
)
403 call_desc_t
*cd
= (call_desc_t
*)cdp
;
404 struct ing_softc
*sc
= &ing_softc
[unit
];
406 /* new stuff to check that the active channel is being closed */
408 if (cd
!= sc
->sc_cdp
)
410 NDBGL4(L4_INGDBG
, "ing%d: channel %d not active",
411 cd
->driver_unit
, cd
->channelid
);
416 callout_stop(&sc
->sc_timeout
);
419 i4b_l4_accounting(BDRV_ING
, cd
->driver_unit
, ACCT_FINAL
,
420 sc
->sc_ioutb
, sc
->sc_iinb
, 0, 0, sc
->sc_outb
, sc
->sc_inb
);
422 sc
->sc_cdp
= (call_desc_t
*)0;
424 NDBGL4(L4_DIALST
, "setting dial state to ST_IDLE");
426 sc
->sc_dialresp
= DSTAT_NONE
;
427 sc
->sc_lastdialresp
= DSTAT_NONE
;
429 sc
->sc_state
= ST_IDLE
;
432 /*---------------------------------------------------------------------------*
433 * this routine is used to give a feedback from userland daemon
434 * in case of dial problems
435 *---------------------------------------------------------------------------*/
437 ing_dialresponse(int unit
, int status
, cause_t cause
)
439 struct ing_softc
*sc
= &ing_softc
[unit
];
440 sc
->sc_dialresp
= status
;
442 NDBGL4(L4_INGDBG
, "ing%d: last=%d, this=%d",
443 unit
, sc
->sc_lastdialresp
, sc
->sc_dialresp
);
445 if(status
!= DSTAT_NONE
)
447 NDBGL4(L4_INGDBG
, "ing%d: clearing queues", unit
);
448 /* ingclearqueues(sc); */
452 /*---------------------------------------------------------------------------*
453 * interface soft up/down
454 *---------------------------------------------------------------------------*/
456 ing_updown(int unit
, int updown
)
458 struct ing_softc
*sc
= &ing_softc
[unit
];
459 sc
->sc_updown
= updown
;
462 /*---------------------------------------------------------------------------*
463 * this routine is called from the HSCX interrupt handler
464 * when a new frame (mbuf) has been received and was put on
465 * the rx queue. It is assumed that this routines runs at
466 * pri level splimp() ! Keep it short !
467 *---------------------------------------------------------------------------*/
469 ing_rx_data_rdy(int unit
)
471 struct ing_softc
*sc
= &ing_softc
[unit
];
474 if((m
= *isdn_linktab
[unit
]->rx_mbuf
) == NULL
)
478 sc
->sc_inb
+= m
->m_pkthdr
.len
;
481 m
->m_pkthdr
.rcvif
= NULL
;
485 ng_queue_data(sc
->hook
, m
, NULL
);
488 /*---------------------------------------------------------------------------*
489 * this routine is called from the HSCX interrupt handler
490 * when the last frame has been sent out and there is no
491 * further frame (mbuf) in the tx queue.
492 *---------------------------------------------------------------------------*/
494 ing_tx_queue_empty(int unit
)
496 struct ing_softc
*sc
= &ing_softc
[unit
];
500 if(sc
->sc_state
!= ST_CONNECTED
)
505 IF_DEQUEUE(&sc
->xmitq_hipri
, m
);
509 IF_DEQUEUE(&sc
->xmitq
, m
);
515 sc
->sc_outb
+= m
->m_pkthdr
.len
;
520 if(IF_QFULL(isdn_linktab
[unit
]->tx_queue
))
522 NDBGL4(L4_INGDBG
, "ing%d: tx queue full!", unit
);
527 IF_ENQUEUE(isdn_linktab
[unit
]->tx_queue
, m
);
532 (*isdn_linktab
[unit
]->bch_tx_start
)(isdn_linktab
[unit
]->unit
, isdn_linktab
[unit
]->channel
);
535 /*---------------------------------------------------------------------------*
536 * this routine is called from the HSCX interrupt handler
537 * each time a packet is received or transmitted. It should
538 * be used to implement an activity timeout mechanism.
539 *---------------------------------------------------------------------------*/
541 ing_activity(int unit
, int rxtx
)
543 ing_softc
[unit
].sc_cdp
->last_active_time
= SECOND
;
546 /*---------------------------------------------------------------------------*
547 * return this drivers linktab address
548 *---------------------------------------------------------------------------*/
550 ing_ret_linktab(int unit
)
552 return(&ing_drvr_linktab
[unit
]);
555 /*---------------------------------------------------------------------------*
556 * setup the isdn_linktab for this driver
557 *---------------------------------------------------------------------------*/
559 ing_set_linktab(int unit
, isdn_link_t
*ilt
)
561 isdn_linktab
[unit
] = ilt
;
564 /*---------------------------------------------------------------------------*
565 * initialize this drivers linktab
566 *---------------------------------------------------------------------------*/
568 ing_init_linktab(int unit
)
570 ing_drvr_linktab
[unit
].unit
= unit
;
571 ing_drvr_linktab
[unit
].bch_rx_data_ready
= ing_rx_data_rdy
;
572 ing_drvr_linktab
[unit
].bch_tx_queue_empty
= ing_tx_queue_empty
;
573 ing_drvr_linktab
[unit
].bch_activity
= ing_activity
;
574 ing_drvr_linktab
[unit
].line_connected
= ing_connect
;
575 ing_drvr_linktab
[unit
].line_disconnected
= ing_disconnect
;
576 ing_drvr_linktab
[unit
].dial_response
= ing_dialresponse
;
577 ing_drvr_linktab
[unit
].updown_ind
= ing_updown
;
580 /*===========================================================================*
581 * NETGRAPH INTERFACE ROUTINES
582 *===========================================================================*/
584 /*---------------------------------------------------------------------------*
585 * It is not possible or allowable to create a node of this type.
586 * If the hardware exists, it will already have created it.
587 *---------------------------------------------------------------------------*/
589 ng_ing_constructor(node_p
*nodep
)
594 /*---------------------------------------------------------------------------*
595 * Give our ok for a hook to be added...
596 * Add the hook's private info to the hook structure.
597 *---------------------------------------------------------------------------*/
599 ng_ing_newhook(node_p node
, hook_p hook
, const char *name
)
601 struct ing_softc
*sc
= node
->private;
604 * check if it's our friend the debug hook
606 if(strcmp(name
, NG_ING_HOOK_DEBUG
) == 0)
608 hook
->private = NULL
; /* paranoid */
609 sc
->debughook
= hook
;
613 * Check for raw mode hook.
615 if(strcmp(name
, NG_ING_HOOK_RAW
) == 0)
625 /*---------------------------------------------------------------------------*
626 * Get a netgraph control message.
627 * Check it is one we understand. If needed, send a response.
628 * We could save the address for an async action later, but don't here.
629 * Always free the message.
630 * The response should be in a malloc'd region that the caller can 'free'.
631 * A response is not required.
632 *---------------------------------------------------------------------------*/
634 ng_ing_rcvmsg(node_p node
, struct ng_mesg
*msg
, const char *retaddr
,
635 struct ng_mesg
**rptr
)
637 struct ing_softc
*sc
= node
->private;
639 struct ng_mesg
*resp
= NULL
;
642 if(msg
->header
.typecookie
== NGM_GENERIC_COOKIE
)
644 switch(msg
->header
.cmd
)
646 case NGM_TEXT_STATUS
:
652 NG_MKRESPONSE(resp
, msg
,
653 sizeof(struct ng_mesg
) + NG_TEXTRESPONSE
,
654 M_INTWAIT
| M_NULLOK
);
661 arg
= (char *) resp
->data
;
679 pos
= ksprintf(arg
, "state = %s (%d)\n", p
, sc
->sc_state
);
681 pos
+= ksprintf(arg
+ pos
, "%d bytes in, %d bytes out\n", sc
->sc_inb
, sc
->sc_outb
);
683 pos
+= ksprintf(arg
+ pos
, "%d pkts in, %d pkts out\n", sc
->sc_inpkt
, sc
->sc_outpkt
);
685 resp
->header
.arglen
= pos
+ 1;
694 else if(msg
->header
.typecookie
== NGM_ING_COOKIE
)
696 switch (msg
->header
.cmd
)
698 case NGM_ING_GET_STATUS
:
700 struct ngingstat
*stats
;
702 NG_MKRESPONSE(resp
, msg
, sizeof(*stats
),
703 M_INTWAIT
| M_NULLOK
);
711 stats
= (struct ngingstat
*) resp
->data
;
712 stats
->packets_in
= sc
->packets_in
;
713 stats
->packets_out
= sc
->packets_out
;
717 case NGM_ING_SET_FLAG
:
718 if (msg
->header
.arglen
!= sizeof(u_int32_t
))
723 sc
->flags
= *((u_int32_t
*) msg
->data
);
727 error
= EINVAL
; /* unknown command */
733 error
= EINVAL
; /* unknown cookie type */
736 /* Take care of synchronous response, if any */
741 FREE(resp
, M_NETGRAPH
);
743 /* Free the message and return */
745 FREE(msg
, M_NETGRAPH
);
749 /*---------------------------------------------------------------------------*
750 * get data from another node and transmit it out on a B-channel
751 *---------------------------------------------------------------------------*/
753 ng_ing_rcvdata(hook_p hook
, struct mbuf
*m
, meta_p meta
)
755 struct ing_softc
*sc
= hook
->node
->private;
756 struct ifqueue
*xmitq_p
;
758 if(hook
->private == NULL
)
760 NG_FREE_DATA(m
, meta
);
764 if(sc
->sc_state
== ST_IDLE
|| sc
->sc_state
== ST_DIALING
)
766 i4b_l4_dialout(BDRV_ING
, sc
->sc_unit
);
767 sc
->sc_state
= ST_DIALING
;
773 * Now queue the data for when it can be sent
776 if (meta
&& meta
->priority
> 0)
778 xmitq_p
= (&sc
->xmitq_hipri
);
782 xmitq_p
= (&sc
->xmitq
);
787 if (IF_QFULL(xmitq_p
))
791 NG_FREE_DATA(m
, meta
);
795 IF_ENQUEUE(xmitq_p
, m
);
797 ing_tx_queue_empty(sc
->sc_unit
);
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 *---------------------------------------------------------------------------*/
809 ng_ing_rmnode(node_p node
)
811 struct ing_softc
*sc
= node
->private;
813 node
->flags
|= NG_INVALID
;
816 sc
->packets_in
= 0; /* reset stats */
819 node
->flags
&= ~NG_INVALID
; /* reset invalid flag */
824 /*---------------------------------------------------------------------------*
825 * This is called once we've already connected a new hook to the other node.
826 *---------------------------------------------------------------------------*/
828 ng_ing_connect(hook_p hook
)
836 * For this type, removal of the last link destroys the node
839 ng_ing_disconnect(hook_p hook
)
841 struct ing_softc
*sc
= hook
->node
->private;
843 if(hook
->private == NULL
) {
844 sc
->debughook
= NULL
;
849 /*===========================================================================*/
851 #endif /* NI4BING > 0 */