2 * Copyright (c) 1997 Joerg Wunsch. All rights reserved.
4 * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 *---------------------------------------------------------------------------
30 * i4b_isppp.c - isdn4bsd kernel SyncPPP driver
31 * --------------------------------------------
33 * Uses Serge Vakulenko's sppp backend (originally contributed with
34 * the "cx" driver for Cronyx's HDLC-in-hardware device). This driver
35 * is only the glue between sppp and i4b.
37 * $Id: i4b_isppp.c,v 1.44 2000/08/31 07:07:26 hm Exp $
39 * $FreeBSD: src/sys/i4b/driver/i4b_isppp.c,v 1.7.2.3 2003/02/06 14:50:53 gj Exp $
40 * $DragonFly: src/sys/net/i4b/driver/i4b_isppp.c,v 1.16 2006/12/22 23:44:55 swildner Exp $
42 * last edit-date: [Thu Aug 31 09:02:27 2000]
44 *---------------------------------------------------------------------------*/
47 #include "use_i4bisppp.h"
50 # error "You need to define `device sppp <N>' with options ISPPP"
53 #include <sys/param.h>
54 #include <sys/systm.h>
56 #include <sys/socket.h>
57 #include <sys/errno.h>
58 #include <sys/ioccom.h>
59 #include <sys/sockio.h>
60 #include <sys/kernel.h>
61 #include <sys/thread2.h>
64 #include <net/if_arp.h>
65 #include <net/if_types.h>
66 #include <net/sppp/if_sppp.h>
73 #include <net/i4b/include/machine/i4b_debug.h>
74 #include <net/i4b/include/machine/i4b_ioctl.h>
76 #include "../include/i4b_global.h"
77 #include "../include/i4b_l3l4.h"
78 #include "../layer4/i4b_l4.h"
80 #define PDEVSTATIC static
82 #define ISPPP_FMT "%s: "
83 #define ISPPP_ARG(sc) ((sc)->sc_if.if_xname)
84 #define IFP2UNIT(ifp) ((struct i4bisppp_softc *)ifp->if_softc)->sc_unit
86 # define IOCTL_CMD_T u_long
88 PDEVSTATIC
void i4bispppattach(void *);
89 PSEUDO_SET(i4bispppattach
, i4b_isppp
);
91 #define I4BISPPPACCT 1 /* enable accounting messages */
92 #define I4BISPPPACCTINTVL 2 /* accounting msg interval in secs */
93 #define I4BISPPPDISCDEBUG 1
95 #define PPP_HDRLEN 4 /* 4 octetts PPP header length */
97 struct i4bisppp_softc
{
99 * struct sppp starts with a struct ifnet, but we gotta allocate
100 * more space for it. NB: do not relocate this union, it must
101 * be first in isppp_softc. The tls and tlf hooks below want to
102 * convert a ``struct sppp *'' into a ``struct isppp_softc *''.
108 #define sc_if sc_if_un.scu_if
110 int sc_state
; /* state of the interface */
111 int sc_unit
; /* unit number */
113 call_desc_t
*sc_cdp
; /* ptr to call descriptor */
116 int sc_iinb
; /* isdn driver # of inbytes */
117 int sc_ioutb
; /* isdn driver # of outbytes */
118 int sc_inb
; /* # of bytes rx'd */
119 int sc_outb
; /* # of bytes tx'd */
120 int sc_linb
; /* last # of bytes rx'd */
121 int sc_loutb
; /* last # of bytes tx'd */
122 int sc_fn
; /* flag, first null acct */
125 struct callout sc_timeout
;
127 } i4bisppp_softc
[NI4BISPPP
];
129 static void i4bisppp_init_linktab(int unit
);
130 static int i4bisppp_ioctl(struct ifnet
*ifp
, IOCTL_CMD_T cmd
, caddr_t data
,
134 static void i4bisppp_send(struct ifnet
*ifp
);
137 static void i4bisppp_start(struct ifnet
*ifp
);
139 #if 0 /* never used ??? */
140 static void i4bisppp_timeout(void *cookie
);
143 static void i4bisppp_tls(struct sppp
*sp
);
144 static void i4bisppp_tlf(struct sppp
*sp
);
145 static void i4bisppp_state_changed(struct sppp
*sp
, int new_state
);
146 static void i4bisppp_negotiation_complete(struct sppp
*sp
);
147 static void i4bisppp_watchdog(struct ifnet
*ifp
);
148 time_t i4bisppp_idletime(int unit
);
150 /* initialized by L4 */
152 static drvr_link_t i4bisppp_drvr_linktab
[NI4BISPPP
];
153 static isdn_link_t
*isdn_linktab
[NI4BISPPP
];
155 enum i4bisppp_states
{
156 ST_IDLE
, /* initialized, ready, idle */
157 ST_DIALING
, /* dialling out to remote */
158 ST_CONNECTED
, /* connected to remote */
161 /*===========================================================================*
162 * DEVICE DRIVER ROUTINES
163 *===========================================================================*/
165 /*---------------------------------------------------------------------------*
166 * interface attach routine at kernel boot time
167 *---------------------------------------------------------------------------*/
169 i4bispppattach(void *dummy
)
171 struct i4bisppp_softc
*sc
= i4bisppp_softc
;
174 #ifndef HACK_NO_PSEUDO_ATTACH_MSG
176 kprintf("i4bisppp: %d ISDN SyncPPP device(s) attached (VJ header compression)\n", NI4BISPPP
);
178 kprintf("i4bisppp: %d ISDN SyncPPP device(s) attached\n", NI4BISPPP
);
182 for(i
= 0; i
< NI4BISPPP
; sc
++, i
++) {
183 i4bisppp_init_linktab(i
);
185 sc
->sc_if
.if_softc
= sc
;
187 if_initname(&(sc
->sc_if
), "isp", i
);
188 sc
->sc_if
.if_mtu
= PP_MTU
;
190 sc
->sc_if
.if_flags
= IFF_SIMPLEX
| IFF_POINTOPOINT
;
192 sc
->sc_if
.if_type
= IFT_ISDNBASIC
;
193 sc
->sc_state
= ST_IDLE
;
195 sc
->sc_if
.if_ioctl
= i4bisppp_ioctl
;
197 /* actually initialized by sppp_attach() */
198 /* sc->sc_if.if_output = sppp_output; */
200 sc
->sc_if
.if_start
= i4bisppp_start
;
202 sc
->sc_if
.if_hdrlen
= 0;
203 sc
->sc_if
.if_addrlen
= 0;
204 sc
->sc_if
.if_snd
.ifq_maxlen
= IFQ_MAXLEN
;
206 sc
->sc_if
.if_ipackets
= 0;
207 sc
->sc_if
.if_ierrors
= 0;
208 sc
->sc_if
.if_opackets
= 0;
209 sc
->sc_if
.if_oerrors
= 0;
210 sc
->sc_if
.if_collisions
= 0;
211 sc
->sc_if
.if_ibytes
= 0;
212 sc
->sc_if
.if_obytes
= 0;
213 sc
->sc_if
.if_imcasts
= 0;
214 sc
->sc_if
.if_omcasts
= 0;
215 sc
->sc_if
.if_iqdrops
= 0;
216 sc
->sc_if
.if_noproto
= 0;
219 sc
->sc_if
.if_timer
= 0;
220 sc
->sc_if
.if_watchdog
= i4bisppp_watchdog
;
230 sc
->sc_if_un
.scu_sp
.pp_tls
= i4bisppp_tls
;
231 sc
->sc_if_un
.scu_sp
.pp_tlf
= i4bisppp_tlf
;
232 sc
->sc_if_un
.scu_sp
.pp_con
= i4bisppp_negotiation_complete
;
233 sc
->sc_if_un
.scu_sp
.pp_chg
= i4bisppp_state_changed
;
235 sppp_attach(&sc
->sc_if
);
236 /* XXX: validate / add proper code */
237 ether_ifattach_bpf(&sc
->sc_if
, ((struct arpcom
*)sc
)->ac_enaddr
,
238 DLT_PPP
, PPP_HDRLEN
, NULL
);
239 callout_init(&sc
->sc_timeout
);
243 /*---------------------------------------------------------------------------*
245 *---------------------------------------------------------------------------*/
247 i4bisppp_ioctl(struct ifnet
*ifp
, IOCTL_CMD_T cmd
, caddr_t data
,
250 struct i4bisppp_softc
*sc
= ifp
->if_softc
;
252 struct sppp
*sp
= (struct sppp
*)sc
;
253 struct ifaddr
*ifa
= (struct ifaddr
*) data
;
254 struct ifreq
*ifr
= (struct ifreq
*) data
;
259 error
= sppp_ioctl(&sc
->sc_if
, cmd
, data
);
265 #if 0 /* never used ??? */
267 if ((ifp
->if_flags
& IFF_UP
) == 0)
268 callout_stop(&sc
->sc_timeout
);
277 /*---------------------------------------------------------------------------*
278 * start output to ISDN B-channel
279 *---------------------------------------------------------------------------*/
281 i4bisppp_start(struct ifnet
*ifp
)
283 struct i4bisppp_softc
*sc
= ifp
->if_softc
;
286 int unit
= IFP2UNIT(ifp
);
288 if (sppp_isempty(ifp
))
291 if(sc
->sc_state
!= ST_CONNECTED
)
296 * ifp->if_flags |= IFF_OACTIVE; // - need to clear this somewhere
300 while ((m
= sppp_dequeue(&sc
->sc_if
)) != NULL
)
304 microtime(&ifp
->if_lastchange
);
306 if(IF_QFULL(isdn_linktab
[unit
]->tx_queue
))
308 NDBGL4(L4_ISPDBG
, "isp%d, tx queue full!", unit
);
314 sc
->sc_if
.if_obytes
+= m
->m_pkthdr
.len
;
316 sc
->sc_outb
+= m
->m_pkthdr
.len
;
317 sc
->sc_if
.if_opackets
++;
319 IF_ENQUEUE(isdn_linktab
[unit
]->tx_queue
, m
);
322 isdn_linktab
[unit
]->bch_tx_start(isdn_linktab
[unit
]->unit
,
323 isdn_linktab
[unit
]->channel
);
327 /*---------------------------------------------------------------------------*
329 *---------------------------------------------------------------------------*/
331 i4bisppp_watchdog(struct ifnet
*ifp
)
333 struct i4bisppp_softc
*sc
= ifp
->if_softc
;
334 int unit
= IFP2UNIT(ifp
);
335 bchan_statistics_t bs
;
337 (*isdn_linktab
[unit
]->bch_stat
)
338 (isdn_linktab
[unit
]->unit
, isdn_linktab
[unit
]->channel
, &bs
);
340 sc
->sc_ioutb
+= bs
.outbytes
;
341 sc
->sc_iinb
+= bs
.inbytes
;
343 if((sc
->sc_iinb
!= sc
->sc_linb
) || (sc
->sc_ioutb
!= sc
->sc_loutb
) || sc
->sc_fn
)
345 int ri
= (sc
->sc_iinb
- sc
->sc_linb
)/I4BISPPPACCTINTVL
;
346 int ro
= (sc
->sc_ioutb
- sc
->sc_loutb
)/I4BISPPPACCTINTVL
;
348 if((sc
->sc_iinb
== sc
->sc_linb
) && (sc
->sc_ioutb
== sc
->sc_loutb
))
353 sc
->sc_linb
= sc
->sc_iinb
;
354 sc
->sc_loutb
= sc
->sc_ioutb
;
356 i4b_l4_accounting(BDRV_ISPPP
, unit
, ACCT_DURING
,
357 sc
->sc_ioutb
, sc
->sc_iinb
, ro
, ri
, sc
->sc_outb
, sc
->sc_inb
);
359 sc
->sc_if
.if_timer
= I4BISPPPACCTINTVL
;
361 #if 0 /* old stuff, keep it around */
362 kprintf(ISPPP_FMT
"transmit timeout\n", ISPPP_ARG(sc
));
366 #endif /* I4BISPPPACCT */
369 *===========================================================================*
370 * SyncPPP layer interface routines
371 *===========================================================================*
374 #if 0 /* never used ??? */
375 /*---------------------------------------------------------------------------*
376 * just an alias for i4bisppp_tls, but of type timeout_t
377 *---------------------------------------------------------------------------*/
379 i4bisppp_timeout(void *cookie
)
381 i4bisppp_tls((struct sppp
*)cookie
);
385 /*---------------------------------------------------------------------------*
386 * PPP this-layer-started action
387 *---------------------------------------------------------------------------*
390 i4bisppp_tls(struct sppp
*sp
)
392 struct i4bisppp_softc
*sc
= (struct i4bisppp_softc
*)sp
;
393 struct ifnet
*ifp
= (struct ifnet
*)sp
;
395 if(sc
->sc_state
== ST_CONNECTED
)
398 i4b_l4_dialout(BDRV_ISPPP
, IFP2UNIT(ifp
));
401 /*---------------------------------------------------------------------------*
402 * PPP this-layer-finished action
403 *---------------------------------------------------------------------------*
406 i4bisppp_tlf(struct sppp
*sp
)
408 struct i4bisppp_softc
*sc
= (struct i4bisppp_softc
*)sp
;
409 /* call_desc_t *cd = sc->sc_cdp; */
410 struct ifnet
*ifp
= (struct ifnet
*)sp
;
412 if(sc
->sc_state
!= ST_CONNECTED
)
415 #if 0 /* never used ??? */
416 callout_stop(&sc
->sc_timeout
);
419 i4b_l4_drvrdisc(BDRV_ISPPP
, IFP2UNIT(ifp
));
421 /*---------------------------------------------------------------------------*
422 * PPP interface phase change
423 *---------------------------------------------------------------------------*
426 i4bisppp_state_changed(struct sppp
*sp
, int new_state
)
428 struct i4bisppp_softc
*sc
= (struct i4bisppp_softc
*)sp
;
430 i4b_l4_ifstate_changed(sc
->sc_cdp
, new_state
);
433 /*---------------------------------------------------------------------------*
434 * PPP control protocol negotiation complete (run ip-up script now)
435 *---------------------------------------------------------------------------*
438 i4bisppp_negotiation_complete(struct sppp
*sp
)
440 struct i4bisppp_softc
*sc
= (struct i4bisppp_softc
*)sp
;
442 i4b_l4_negcomplete(sc
->sc_cdp
);
445 /*===========================================================================*
446 * ISDN INTERFACE ROUTINES
447 *===========================================================================*/
449 /*---------------------------------------------------------------------------*
450 * this routine is called from L4 handler at connect time
451 *---------------------------------------------------------------------------*/
453 i4bisppp_connect(int unit
, void *cdp
)
455 struct i4bisppp_softc
*sc
= &i4bisppp_softc
[unit
];
456 struct sppp
*sp
= &sc
->sc_if_un
.scu_sp
;
460 sc
->sc_cdp
= (call_desc_t
*)cdp
;
461 sc
->sc_state
= ST_CONNECTED
;
470 sc
->sc_if
.if_timer
= I4BISPPPACCTINTVL
;
473 #if 0 /* never used ??? */
474 callout_stop(&sc
->sc_timeout
);
477 sp
->pp_up(sp
); /* tell PPP we are ready */
478 sp
->pp_last_sent
= sp
->pp_last_recv
= SECOND
;
483 /*---------------------------------------------------------------------------*
484 * this routine is called from L4 handler at disconnect time
485 *---------------------------------------------------------------------------*/
487 i4bisppp_disconnect(int unit
, void *cdp
)
489 call_desc_t
*cd
= (call_desc_t
*)cdp
;
490 struct i4bisppp_softc
*sc
= &i4bisppp_softc
[unit
];
491 struct sppp
*sp
= &sc
->sc_if_un
.scu_sp
;
495 /* new stuff to check that the active channel is being closed */
496 if (cd
!= sc
->sc_cdp
)
498 NDBGL4(L4_ISPDBG
, "isp%d, channel%d not active!", unit
, cd
->channelid
);
504 sc
->sc_if
.if_timer
= 0;
507 i4b_l4_accounting(BDRV_ISPPP
, unit
, ACCT_FINAL
,
508 sc
->sc_ioutb
, sc
->sc_iinb
, 0, 0, sc
->sc_outb
, sc
->sc_inb
);
510 if (sc
->sc_state
== ST_CONNECTED
)
512 #if 0 /* never used ??? */
513 callout_stop(&sc
->sc_timeout
);
515 sc
->sc_cdp
= (call_desc_t
*)0;
516 /* do this here because pp_down calls i4bisppp_tlf */
517 sc
->sc_state
= ST_IDLE
;
518 sp
->pp_down(sp
); /* tell PPP we have hung up */
524 /*---------------------------------------------------------------------------*
525 * this routine is used to give a feedback from userland demon
526 * in case of dial problems
527 *---------------------------------------------------------------------------*/
529 i4bisppp_dialresponse(int unit
, int status
, cause_t cause
)
531 struct i4bisppp_softc
*sc
= &i4bisppp_softc
[unit
];
532 struct sppp
*sp
= &sc
->sc_if_un
.scu_sp
;
534 NDBGL4(L4_ISPDBG
, "isp%d: status=%d, cause=%d", unit
, status
, cause
);
536 if(status
!= DSTAT_NONE
)
540 NDBGL4(L4_ISPDBG
, "isp%d: clearing queues", unit
);
542 if(!(sppp_isempty(&sc
->sc_if
)))
544 while((m
= sppp_dequeue(&sc
->sc_if
)) != NULL
)
548 sc
->sc_cdp
= (call_desc_t
*)0;
549 /* do this here because pp_down calls i4bisppp_tlf */
550 sc
->sc_state
= ST_IDLE
;
552 * Ahh, sppp doesn't like to get a down event when
553 * dialing fails. So first tell it that we are up
554 * (doesn't hurt us since sc_state != ST_CONNECTED)
562 /*---------------------------------------------------------------------------*
564 *---------------------------------------------------------------------------*/
566 i4bisppp_updown(int unit
, int updown
)
568 /* could probably do something useful here */
571 /*---------------------------------------------------------------------------*
572 * this routine is called from the HSCX interrupt handler
573 * when a new frame (mbuf) has been received and was put on
575 *---------------------------------------------------------------------------*/
577 i4bisppp_rx_data_rdy(int unit
)
579 struct i4bisppp_softc
*sc
= &i4bisppp_softc
[unit
];
582 if((m
= *isdn_linktab
[unit
]->rx_mbuf
) == NULL
)
585 m
->m_pkthdr
.rcvif
= &sc
->sc_if
;
586 m
->m_pkthdr
.len
= m
->m_len
;
588 microtime(&sc
->sc_if
.if_lastchange
);
590 sc
->sc_if
.if_ipackets
++;
592 sc
->sc_if
.if_ibytes
+= m
->m_pkthdr
.len
;
596 sc
->sc_inb
+= m
->m_pkthdr
.len
;
600 kprintf("i4bisppp_rx_data_ready: received packet!\n");
603 BPF_MTAP(&sc
->sc_if
, m
);
606 sppp_input(&sc
->sc_if
, m
);
610 /*---------------------------------------------------------------------------*
611 * this routine is called from the HSCX interrupt handler
612 * when the last frame has been sent out and there is no
613 * further frame (mbuf) in the tx queue.
614 *---------------------------------------------------------------------------*/
616 i4bisppp_tx_queue_empty(int unit
)
618 i4bisppp_start(&i4bisppp_softc
[unit
].sc_if
);
621 /*---------------------------------------------------------------------------*
622 * THIS should be used instead of last_active_time to implement
623 * an activity timeout mechanism.
625 * Sending back the time difference unneccessarily complicates the
626 * idletime checks in i4b_l4.c. Return the largest time instead.
627 * That way the code in i4b_l4.c needs only minimal changes.
628 *---------------------------------------------------------------------------*/
630 i4bisppp_idletime(int unit
)
633 sp
= (struct sppp
*) &i4bisppp_softc
[unit
];
635 return((sp
->pp_last_recv
< sp
->pp_last_sent
) ?
636 sp
->pp_last_sent
: sp
->pp_last_recv
);
639 /*---------------------------------------------------------------------------*
640 * this routine is called from the HSCX interrupt handler
641 * each time a packet is received or transmitted. It should
642 * be used to implement an activity timeout mechanism.
643 *---------------------------------------------------------------------------*/
645 i4bisppp_activity(int unit
, int rxtx
)
647 i4bisppp_softc
[unit
].sc_cdp
->last_active_time
= SECOND
;
650 /*---------------------------------------------------------------------------*
651 * return this drivers linktab address
652 *---------------------------------------------------------------------------*/
654 i4bisppp_ret_linktab(int unit
)
656 return(&i4bisppp_drvr_linktab
[unit
]);
659 /*---------------------------------------------------------------------------*
660 * setup the isdn_linktab for this driver
661 *---------------------------------------------------------------------------*/
663 i4bisppp_set_linktab(int unit
, isdn_link_t
*ilt
)
665 isdn_linktab
[unit
] = ilt
;
668 /*---------------------------------------------------------------------------*
669 * initialize this drivers linktab
670 *---------------------------------------------------------------------------*/
672 i4bisppp_init_linktab(int unit
)
674 i4bisppp_drvr_linktab
[unit
].unit
= unit
;
675 i4bisppp_drvr_linktab
[unit
].bch_rx_data_ready
= i4bisppp_rx_data_rdy
;
676 i4bisppp_drvr_linktab
[unit
].bch_tx_queue_empty
= i4bisppp_tx_queue_empty
;
677 i4bisppp_drvr_linktab
[unit
].bch_activity
= i4bisppp_activity
;
678 i4bisppp_drvr_linktab
[unit
].line_connected
= i4bisppp_connect
;
679 i4bisppp_drvr_linktab
[unit
].line_disconnected
= i4bisppp_disconnect
;
680 i4bisppp_drvr_linktab
[unit
].dial_response
= i4bisppp_dialresponse
;
681 i4bisppp_drvr_linktab
[unit
].updown_ind
= i4bisppp_updown
;
684 /*===========================================================================*/