Make all network interrupt service routines MPSAFE part 1/3.
[dragonfly.git] / sys / net / i4b / driver / i4b_ipr.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1997, 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_ipr.c - isdn4bsd IP over raw HDLC ISDN network driver
28 * ---------------------------------------------------------
29 *
30 * $FreeBSD: src/sys/i4b/driver/i4b_ipr.c,v 1.8.2.3 2001/10/27 15:48:17 hm Exp $
78195a76 31 * $DragonFly: src/sys/net/i4b/driver/i4b_ipr.c,v 1.18 2005/11/28 17:13:45 dillon Exp $
984263bc
MD
32 *
33 * last edit-date: [Fri Oct 26 19:32:38 2001]
34 *
35 *---------------------------------------------------------------------------*
36 *
37 * statistics counter usage (interface lifetime):
38 * ----------------------------------------------
39 * sc->sc_if.if_ipackets # of received packets
40 * sc->sc_if.if_ierrors # of error packets not going to upper layers
41 * sc->sc_if.if_opackets # of transmitted packets
42 * sc->sc_if.if_oerrors # of error packets not being transmitted
43 * sc->sc_if.if_collisions # of invalid ip packets after VJ decompression
44 * sc->sc_if.if_ibytes # of bytes coming in from the line (before VJ)
45 * sc->sc_if.if_obytes # of bytes going out to the line (after VJ)
46 * sc->sc_if.if_imcasts (currently unused)
47 * sc->sc_if.if_omcasts # of frames sent out of the fastqueue
48 * sc->sc_if.if_iqdrops # of frames dropped on input because queue full
49 * sc->sc_if.if_noproto # of frames dropped on output because !AF_INET
50 *
51 * statistics counter usage (connection lifetime):
52 * -----------------------------------------------
53 * sc->sc_iinb # of ISDN incoming bytes from HSCX
54 * sc->sc_ioutb # of ISDN outgoing bytes from HSCX
55 * sc->sc_inb # of incoming bytes after decompression
56 * sc->sc_outb # of outgoing bytes before compression
57 *
58 *---------------------------------------------------------------------------*/
59
1f2de5d4 60#include "use_i4bipr.h"
984263bc
MD
61
62#if NI4BIPR > 0
63
984263bc 64#include "opt_i4b.h"
984263bc
MD
65
66#include <sys/param.h>
67#include <sys/systm.h>
68#include <sys/mbuf.h>
69#include <sys/socket.h>
70#include <sys/errno.h>
71
984263bc
MD
72#include <sys/ioccom.h>
73#include <sys/sockio.h>
74#ifdef IPR_VJ
75#include <sys/malloc.h>
76#endif
984263bc
MD
77
78#include <sys/kernel.h>
817cdab6 79#include <sys/thread2.h>
984263bc
MD
80
81#include <net/if.h>
82#include <net/if_types.h>
83#include <net/netisr.h>
84
85#include <netinet/in.h>
86#include <netinet/in_systm.h>
87#include <netinet/in_var.h>
88#include <netinet/ip.h>
89
90#ifdef IPR_VJ
91#include <net/slcompress.h>
92#define IPR_COMPRESS IFF_LINK0 /* compress TCP traffic */
93#define IPR_AUTOCOMP IFF_LINK1 /* auto-enable TCP compression */
94
95/*---------------------------------------------------------------------------
96 * NOTICE: using NO separate buffer relies on the assumption, that the HSCX
97 * IRQ handler _always_ allocates a single, continuous mbuf cluster large
98 * enough to hold the maximum MTU size if the ipr interface !
99 *
100 * CAUTION: i have re-defined IPR_VJ_USEBUFFER because it makes problems
101 * with 2 i4b's back to back running cvs over ssh, cvs simply
102 * aborts because it gets bad data. Everything else (telnet/ftp?etc)
103 * functions fine.
104 *---------------------------------------------------------------------------*/
105#define IPR_VJ_USEBUFFER /* define to use an allocated separate buffer*/
106 /* undef to uncompress in the mbuf itself */
107#endif /* IPR_VJ */
108
1f2de5d4 109#include "use_bpf.h"
984263bc
MD
110
111#if NBPFILTER > 0 || NBPF > 0
112#include <sys/time.h>
113#include <net/bpf.h>
114#endif
115
1f2de5d4
MD
116#include <net/i4b/include/machine/i4b_debug.h>
117#include <net/i4b/include/machine/i4b_ioctl.h>
984263bc 118
1f2de5d4
MD
119#include "../include/i4b_global.h"
120#include "../include/i4b_l3l4.h"
984263bc 121
1f2de5d4 122#include "../layer4/i4b_l4.h"
984263bc 123
984263bc
MD
124#define IPR_FMT "%s: "
125#define IPR_ARG(sc) ((sc)->sc_if.if_xname)
126#define PDEVSTATIC /* not static */
984263bc
MD
127
128#define I4BIPRMTU 1500 /* regular MTU */
129#define I4BIPRMAXMTU 2000 /* max MTU */
130#define I4BIPRMINMTU 500 /* min MTU */
131
132#define I4BIPRMAXQLEN 50 /* max queue length */
133
134#define I4BIPRACCT 1 /* enable accounting messages */
135#define I4BIPRACCTINTVL 2 /* accounting msg interval in secs */
136#define I4BIPRADJFRXP 1 /* adjust 1st rxd packet */
137
138/* initialized by L4 */
139
140static drvr_link_t ipr_drvr_linktab[NI4BIPR];
141static isdn_link_t *isdn_linktab[NI4BIPR];
142
143struct ipr_softc {
144 struct ifnet sc_if; /* network-visible interface */
145 int sc_state; /* state of the interface */
fe0184c1 146 int sc_unit; /* unit number */
984263bc
MD
147 call_desc_t *sc_cdp; /* ptr to call descriptor */
148 int sc_updown; /* soft state of interface */
149 struct ifqueue sc_fastq; /* interactive traffic */
150 int sc_dialresp; /* dialresponse */
151 int sc_lastdialresp;/* last dialresponse */
152
153#if I4BIPRACCT
154 int sc_iinb; /* isdn driver # of inbytes */
155 int sc_ioutb; /* isdn driver # of outbytes */
156 int sc_inb; /* # of bytes rx'd */
157 int sc_outb; /* # of bytes tx'd */
158 int sc_linb; /* last # of bytes rx'd */
159 int sc_loutb; /* last # of bytes tx'd */
160 int sc_fn; /* flag, first null acct */
161#endif
162
410d1df9 163 struct callout sc_timeout;
984263bc
MD
164
165#ifdef I4BIPRADJFRXP
166 int sc_first_pkt; /* flag, first rxd packet */
167#endif
168#if IPR_LOG
169 int sc_log_first; /* log first n packets */
170#endif
171
172#ifdef IPR_VJ
173 struct slcompress sc_compr; /* tcp compression data */
174#ifdef IPR_VJ_USEBUFFER
175 u_char *sc_cbuf; /* tcp decompression buffer */
176#endif
177#endif
178
179} ipr_softc[NI4BIPR];
180
181enum ipr_states {
182 ST_IDLE, /* initialized, ready, idle */
183 ST_DIALING, /* dialling out to remote */
184 ST_CONNECTED_W, /* connected to remote */
185 ST_CONNECTED_A, /* connected to remote */
186};
187
984263bc 188#define THE_UNIT sc->sc_unit
984263bc 189
984263bc 190# define IOCTL_CMD_T u_long
984263bc 191
984263bc
MD
192PDEVSTATIC void i4biprattach(void *);
193PSEUDO_SET(i4biprattach, i4b_ipr);
9974b71d
JS
194static int i4biprioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data,
195 struct ucred *cr);
984263bc 196static void iprwatchdog(struct ifnet *ifp);
984263bc
MD
197static void ipr_init_linktab(int unit);
198static void ipr_tx_queue_empty(int unit);
199static int i4biproutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rtp);
200static void iprclearqueues(struct ipr_softc *sc);
201
202/*===========================================================================*
203 * DEVICE DRIVER ROUTINES
204 *===========================================================================*/
205
206/*---------------------------------------------------------------------------*
207 * interface attach routine at kernel boot time
208 *---------------------------------------------------------------------------*/
209PDEVSTATIC void
984263bc 210i4biprattach(void *dummy)
984263bc
MD
211{
212 struct ipr_softc *sc = ipr_softc;
213 int i;
214
215#ifdef IPR_VJ
216 printf("i4bipr: %d IP over raw HDLC ISDN device(s) attached (VJ header compression)\n", NI4BIPR);
217#else
218 printf("i4bipr: %d IP over raw HDLC ISDN device(s) attached\n", NI4BIPR);
219#endif
220
221 for(i=0; i < NI4BIPR; sc++, i++)
222 {
223 ipr_init_linktab(i);
224
225 NDBGL4(L4_DIALST, "setting dial state to ST_IDLE");
226
227 sc->sc_state = ST_IDLE;
228
3e4a09e7 229 if_initname(&(sc->sc_if), "ipr", i);
984263bc
MD
230
231#ifdef IPR_VJ
232 sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_SIMPLEX | IPR_AUTOCOMP;
233#else
234 sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_SIMPLEX;
235#endif
236
410d1df9 237 callout_init(&sc->sc_timeout);
984263bc
MD
238
239 sc->sc_if.if_mtu = I4BIPRMTU;
240 sc->sc_if.if_type = IFT_ISDNBASIC;
241 sc->sc_if.if_ioctl = i4biprioctl;
242 sc->sc_if.if_output = i4biproutput;
243
244 sc->sc_if.if_snd.ifq_maxlen = I4BIPRMAXQLEN;
245 sc->sc_fastq.ifq_maxlen = I4BIPRMAXQLEN;
246
984263bc
MD
247 sc->sc_if.if_ipackets = 0;
248 sc->sc_if.if_ierrors = 0;
249 sc->sc_if.if_opackets = 0;
250 sc->sc_if.if_oerrors = 0;
251 sc->sc_if.if_collisions = 0;
252 sc->sc_if.if_ibytes = 0;
253 sc->sc_if.if_obytes = 0;
254 sc->sc_if.if_imcasts = 0;
255 sc->sc_if.if_omcasts = 0;
256 sc->sc_if.if_iqdrops = 0;
257 sc->sc_if.if_noproto = 0;
258
259#if I4BIPRACCT
260 sc->sc_if.if_timer = 0;
261 sc->sc_if.if_watchdog = iprwatchdog;
262 sc->sc_iinb = 0;
263 sc->sc_ioutb = 0;
264 sc->sc_inb = 0;
265 sc->sc_outb = 0;
266 sc->sc_linb = 0;
267 sc->sc_loutb = 0;
268 sc->sc_fn = 1;
269#endif
270#if IPR_LOG
271 sc->sc_log_first = IPR_LOG;
272#endif
273
274#ifdef IPR_VJ
984263bc 275 sl_compress_init(&sc->sc_compr, -1);
984263bc
MD
276
277#ifdef IPR_VJ_USEBUFFER
278 if(!((sc->sc_cbuf =
279 (u_char *)malloc(I4BIPRMAXMTU+128, M_DEVBUF, M_WAITOK))))
280 {
281 panic("if_ipr.c, ipr_attach: VJ malloc failed");
282 }
283#endif
284#endif
285 sc->sc_updown = SOFT_ENA; /* soft enabled */
286 sc->sc_dialresp = DSTAT_NONE; /* no response */
287 sc->sc_lastdialresp = DSTAT_NONE;
288
78195a76 289 if_attach(&sc->sc_if, NULL);
984263bc 290 bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int));
984263bc
MD
291 }
292}
293
294/*---------------------------------------------------------------------------*
295 * output a packet to the ISDN B-channel
296 *---------------------------------------------------------------------------*/
297static int
298i4biproutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
299 struct rtentry *rtp)
300{
301 struct ipr_softc *sc;
302 int unit;
984263bc
MD
303 struct ip *ip;
304
817cdab6 305 crit_enter();
984263bc 306
984263bc
MD
307 sc = ifp->if_softc;
308 unit = sc->sc_unit;
984263bc
MD
309
310 /* check for IP */
311
312 if(dst->sa_family != AF_INET)
313 {
314 printf(IPR_FMT "af%d not supported\n", IPR_ARG(sc), dst->sa_family);
315 m_freem(m);
817cdab6 316 crit_exit();
984263bc
MD
317 sc->sc_if.if_noproto++;
318 sc->sc_if.if_oerrors++;
319 return(EAFNOSUPPORT);
320 }
321
322 /* check interface state = UP */
323
324 if(!(ifp->if_flags & IFF_UP))
325 {
326 NDBGL4(L4_IPRDBG, "ipr%d: interface is DOWN!", unit);
327 m_freem(m);
817cdab6 328 crit_exit();
984263bc
MD
329 sc->sc_if.if_oerrors++;
330 return(ENETDOWN);
331 }
332
333 /* dial if necessary */
334
335 if(sc->sc_state == ST_IDLE || sc->sc_state == ST_DIALING)
336 {
337
338#ifdef NOTDEF
339 switch(sc->sc_dialresp)
340 {
341 case DSTAT_TFAIL: /* transient failure */
342 NDBGL4(L4_IPRDBG, "ipr%d: transient dial failure!", unit);
343 m_freem(m);
344 iprclearqueues(sc);
345 sc->sc_dialresp = DSTAT_NONE;
817cdab6 346 crit_exit();
984263bc
MD
347 sc->sc_if.if_oerrors++;
348 return(ENETUNREACH);
349 break;
350
351 case DSTAT_PFAIL: /* permanent failure */
352 NDBGL4(L4_IPRDBG, "ipr%d: permanent dial failure!", unit);
353 m_freem(m);
354 iprclearqueues(sc);
355 sc->sc_dialresp = DSTAT_NONE;
817cdab6 356 crit_exit();
984263bc
MD
357 sc->sc_if.if_oerrors++;
358 return(EHOSTUNREACH);
359 break;
360
361 case DSTAT_INONLY: /* no dialout allowed*/
362 NDBGL4(L4_IPRDBG, "ipr%d: dialout not allowed failure!", unit);
363 m_freem(m);
364 iprclearqueues(sc);
365 sc->sc_dialresp = DSTAT_NONE;
817cdab6 366 crit_exit();
984263bc
MD
367 sc->sc_if.if_oerrors++;
368 return(EHOSTUNREACH);
369 break;
370 }
371#endif
372
373 NDBGL4(L4_IPRDBG, "ipr%d: send dial request message!", unit);
374 NDBGL4(L4_DIALST, "ipr%d: setting dial state to ST_DIALING", unit);
375 i4b_l4_dialout(BDRV_IPR, unit);
376 sc->sc_state = ST_DIALING;
377 }
378
379#if IPR_LOG
380 if(sc->sc_log_first > 0)
381 {
382 --(sc->sc_log_first);
383 i4b_l4_packet_ind(BDRV_IPR, unit, 1, m );
384 }
385#endif
386
387 /* update access time */
388
389 microtime(&sc->sc_if.if_lastchange);
390
391 /*
392 * check, if type of service indicates interactive, i.e. telnet,
393 * traffic. in case it is interactive, put it into the fast queue,
394 * else (i.e. ftp traffic) put it into the "normal" queue
395 */
396
397 ip = mtod(m, struct ip *); /* get ptr to ip header */
398
984263bc
MD
399 /* check for space in choosen send queue */
400
8bde602d 401 if (netisr_queue(NETISR_IP, m))
984263bc
MD
402 {
403 NDBGL4(L4_IPRDBG, "ipr%d: send queue full!", unit);
817cdab6 404 crit_exit();
984263bc
MD
405 sc->sc_if.if_oerrors++;
406 return(ENOBUFS);
407 }
984263bc
MD
408
409 NDBGL4(L4_IPRDBG, "ipr%d: add packet to send queue!", unit);
410
411 ipr_tx_queue_empty(unit);
412
817cdab6 413 crit_exit();
984263bc
MD
414
415 return (0);
416}
417
418/*---------------------------------------------------------------------------*
419 * process ioctl
420 *---------------------------------------------------------------------------*/
984263bc 421static int
9974b71d 422i4biprioctl(struct ifnet *ifp, IOCTL_CMD_T cmd, caddr_t data, struct ucred *cr)
984263bc 423{
984263bc 424 struct ipr_softc *sc = ifp->if_softc;
984263bc
MD
425
426 struct ifreq *ifr = (struct ifreq *)data;
427 struct ifaddr *ifa = (struct ifaddr *)data;
984263bc
MD
428 int error = 0;
429
817cdab6 430 crit_enter();
984263bc
MD
431
432 switch (cmd)
433 {
434 case SIOCAIFADDR: /* add interface address */
435 case SIOCSIFADDR: /* set interface address */
436 case SIOCSIFDSTADDR: /* set interface destination address */
437 if(ifa->ifa_addr->sa_family != AF_INET)
438 error = EAFNOSUPPORT;
439 else
440 sc->sc_if.if_flags |= IFF_UP;
441 microtime(&sc->sc_if.if_lastchange);
442 break;
443
444 case SIOCSIFFLAGS: /* set interface flags */
445 if(!(ifr->ifr_flags & IFF_UP))
446 {
447 if(sc->sc_if.if_flags & IFF_RUNNING)
448 {
449 /* disconnect ISDN line */
984263bc 450 i4b_l4_drvrdisc(BDRV_IPR, sc->sc_unit);
984263bc
MD
451 sc->sc_if.if_flags &= ~IFF_RUNNING;
452 }
453
454 sc->sc_state = ST_IDLE;
455
456 /* empty queues */
457
458 iprclearqueues(sc);
459 }
460
461 if(ifr->ifr_flags & IFF_DEBUG)
462 {
463 /* enable debug messages */
464 }
465
466 microtime(&sc->sc_if.if_lastchange);
467 break;
468
984263bc
MD
469 case SIOCSIFMTU: /* set interface MTU */
470 if(ifr->ifr_mtu > I4BIPRMAXMTU)
471 error = EINVAL;
472 else if(ifr->ifr_mtu < I4BIPRMINMTU)
473 error = EINVAL;
474 else
475 {
476 ifp->if_mtu = ifr->ifr_mtu;
477 microtime(&sc->sc_if.if_lastchange);
478 }
479 break;
984263bc
MD
480
481#if 0
482 /* not needed for FreeBSD, done in sl_compress_init() (-hm) */
483
484 /* need to add an ioctl: set VJ max slot ID
485 * #define IPRIOCSMAXCID _IOW('I', XXX, int)
486 */
487#ifdef IPR_VJ
488 case IPRIOCSMAXCID:
489 {
dadab5e9 490 struct thread *td = curthread; /* XXX */
984263bc 491
dadab5e9 492 if ((error = suser(td)) != 0)
984263bc
MD
493 return (error);
494 sl_compress_setup(sc->sc_compr, *(int *)data);
495 }
496 break;
497#endif
498#endif
499 default:
500 error = EINVAL;
501 break;
502 }
503
817cdab6 504 crit_exit();
984263bc
MD
505
506 return(error);
507}
508
509/*---------------------------------------------------------------------------*
510 * clear the interface's send queues
511 *---------------------------------------------------------------------------*/
512static void
513iprclearqueues(struct ipr_softc *sc)
514{
984263bc
MD
515 struct mbuf *m;
516
517 for(;;)
518 {
817cdab6 519 crit_enter();
984263bc 520 IF_DEQUEUE(&sc->sc_fastq, m);
817cdab6 521 crit_exit();
984263bc
MD
522 if(m)
523 m_freem(m);
524 else
525 break;
526 }
527
528 for(;;)
529 {
817cdab6 530 crit_enter();
984263bc 531 IF_DEQUEUE(&sc->sc_if.if_snd, m);
817cdab6 532 crit_exit();
984263bc
MD
533 if(m)
534 m_freem(m);
535 else
536 break;
537 }
984263bc
MD
538}
539
540#if I4BIPRACCT
541/*---------------------------------------------------------------------------*
542 * watchdog routine
543 *---------------------------------------------------------------------------*/
984263bc
MD
544static void
545iprwatchdog(struct ifnet *ifp)
546{
984263bc
MD
547 struct ipr_softc *sc = ifp->if_softc;
548 int unit = sc->sc_unit;
984263bc
MD
549 bchan_statistics_t bs;
550
551 /* get # of bytes in and out from the HSCX driver */
552
553 (*isdn_linktab[unit]->bch_stat)
554 (isdn_linktab[unit]->unit, isdn_linktab[unit]->channel, &bs);
555
556 sc->sc_ioutb += bs.outbytes;
557 sc->sc_iinb += bs.inbytes;
558
559 if((sc->sc_iinb != sc->sc_linb) || (sc->sc_ioutb != sc->sc_loutb) || sc->sc_fn)
560 {
561 int ri = (sc->sc_iinb - sc->sc_linb)/I4BIPRACCTINTVL;
562 int ro = (sc->sc_ioutb - sc->sc_loutb)/I4BIPRACCTINTVL;
563
564 if((sc->sc_iinb == sc->sc_linb) && (sc->sc_ioutb == sc->sc_loutb))
565 sc->sc_fn = 0;
566 else
567 sc->sc_fn = 1;
568
569 sc->sc_linb = sc->sc_iinb;
570 sc->sc_loutb = sc->sc_ioutb;
571
572 i4b_l4_accounting(BDRV_IPR, unit, ACCT_DURING,
573 sc->sc_ioutb, sc->sc_iinb, ro, ri, sc->sc_outb, sc->sc_inb);
574 }
575 sc->sc_if.if_timer = I4BIPRACCTINTVL;
984263bc
MD
576}
577#endif /* I4BIPRACCT */
578
579/*===========================================================================*
580 * ISDN INTERFACE ROUTINES
581 *===========================================================================*/
582
583/*---------------------------------------------------------------------------*
584 * start transmitting after connect
585 *---------------------------------------------------------------------------*/
586static void
587i4bipr_connect_startio(struct ipr_softc *sc)
588{
817cdab6 589 crit_enter();
984263bc
MD
590
591 if(sc->sc_state == ST_CONNECTED_W)
592 {
593 sc->sc_state = ST_CONNECTED_A;
594 ipr_tx_queue_empty(THE_UNIT);
595 }
596
817cdab6 597 crit_exit();
984263bc
MD
598}
599
600/*---------------------------------------------------------------------------*
601 * this routine is called from L4 handler at connect time
602 *---------------------------------------------------------------------------*/
603static void
604ipr_connect(int unit, void *cdp)
605{
606 struct ipr_softc *sc = &ipr_softc[unit];
984263bc
MD
607
608 sc->sc_cdp = (call_desc_t *)cdp;
609
817cdab6 610 crit_enter();
984263bc
MD
611
612 NDBGL4(L4_DIALST, "ipr%d: setting dial state to ST_CONNECTED", unit);
613
614 sc->sc_if.if_flags |= IFF_RUNNING;
615 sc->sc_state = ST_CONNECTED_W;
616
617 sc->sc_dialresp = DSTAT_NONE;
618 sc->sc_lastdialresp = DSTAT_NONE;
619
620#if I4BIPRACCT
621 sc->sc_iinb = 0;
622 sc->sc_ioutb = 0;
623 sc->sc_inb = 0;
624 sc->sc_outb = 0;
625 sc->sc_linb = 0;
626 sc->sc_loutb = 0;
627 sc->sc_if.if_timer = I4BIPRACCTINTVL;
628#endif
629
630#ifdef I4BIPRADJFRXP
631 sc->sc_first_pkt = 1;
632#endif
633
634 /*
635 * Sometimes ISDN B-channels are switched thru asymmetic. This
636 * means that under such circumstances B-channel data (the first
637 * three packets of a TCP connection in my case) may get lost,
638 * causing a large delay until the connection is started.
639 * When the sending of the very first packet of a TCP connection
640 * is delayed for a to be empirically determined delay (close
641 * to a second in my case) those packets go thru and the TCP
642 * connection comes up "almost" immediately (-hm).
643 */
644
645 if(sc->sc_cdp->isdntxdelay > 0)
646 {
647 int delay;
648
649 if (hz == 100) {
650 delay = sc->sc_cdp->isdntxdelay; /* avoid any rounding */
651 } else {
652 delay = sc->sc_cdp->isdntxdelay*hz;
653 delay /= 100;
654 }
655
410d1df9
MD
656 callout_reset(&sc->sc_timeout, delay,
657 (TIMEOUT_FUNC_T)i4bipr_connect_startio, sc);
984263bc
MD
658 }
659 else
660 {
661 sc->sc_state = ST_CONNECTED_A;
662 ipr_tx_queue_empty(unit);
663 }
664
817cdab6 665 crit_exit();
984263bc
MD
666
667 /* we don't need any negotiation - pass event back right now */
668 i4b_l4_negcomplete(sc->sc_cdp);
669}
670
671/*---------------------------------------------------------------------------*
672 * this routine is called from L4 handler at disconnect time
673 *---------------------------------------------------------------------------*/
674static void
675ipr_disconnect(int unit, void *cdp)
676{
677 call_desc_t *cd = (call_desc_t *)cdp;
678 struct ipr_softc *sc = &ipr_softc[unit];
679
680 /* new stuff to check that the active channel is being closed */
681
682 if (cd != sc->sc_cdp)
683 {
684 NDBGL4(L4_IPRDBG, "ipr%d: channel %d not active",
685 cd->driver_unit, cd->channelid);
686 return;
687 }
688
689#if I4BIPRACCT
690 sc->sc_if.if_timer = 0;
691#endif
692#if IPR_LOG
693 /* show next IPR_LOG packets again */
694 sc->sc_log_first = IPR_LOG;
695#endif
696
697 i4b_l4_accounting(BDRV_IPR, cd->driver_unit, ACCT_FINAL,
698 sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_outb, sc->sc_inb);
699
700 sc->sc_cdp = (call_desc_t *)0;
701
702 NDBGL4(L4_DIALST, "setting dial state to ST_IDLE");
703
704 sc->sc_dialresp = DSTAT_NONE;
705 sc->sc_lastdialresp = DSTAT_NONE;
706
707 sc->sc_if.if_flags &= ~IFF_RUNNING;
708 sc->sc_state = ST_IDLE;
709}
710
711/*---------------------------------------------------------------------------*
712 * this routine is used to give a feedback from userland daemon
713 * in case of dial problems
714 *---------------------------------------------------------------------------*/
715static void
716ipr_dialresponse(int unit, int status, cause_t cause)
717{
718 struct ipr_softc *sc = &ipr_softc[unit];
719 sc->sc_dialresp = status;
720
721 NDBGL4(L4_IPRDBG, "ipr%d: last=%d, this=%d",
722 unit, sc->sc_lastdialresp, sc->sc_dialresp);
723
724 if(status != DSTAT_NONE)
725 {
726 NDBGL4(L4_IPRDBG, "ipr%d: clearing queues", unit);
727 iprclearqueues(sc);
728 }
729}
730
731/*---------------------------------------------------------------------------*
732 * interface soft up/down
733 *---------------------------------------------------------------------------*/
734static void
735ipr_updown(int unit, int updown)
736{
737 struct ipr_softc *sc = &ipr_softc[unit];
738 sc->sc_updown = updown;
739}
740
741/*---------------------------------------------------------------------------*
742 * this routine is called from the HSCX interrupt handler
743 * when a new frame (mbuf) has been received and was put on
817cdab6
MD
744 * the rx queue. It is assumed that this routines runs in
745 * a critical section ! Keep it short !
984263bc
MD
746 *---------------------------------------------------------------------------*/
747static void
748ipr_rx_data_rdy(int unit)
749{
94332c29
RG
750 struct ipr_softc *sc = &ipr_softc[unit];
751 struct mbuf *m;
984263bc
MD
752#ifdef IPR_VJ
753#ifdef IPR_VJ_USEBUFFER
754 u_char *cp = sc->sc_cbuf;
755#endif
756 int len, c;
757#endif
1f8e62c9 758 static const uint32_t af = AF_INET;
984263bc
MD
759
760 if((m = *isdn_linktab[unit]->rx_mbuf) == NULL)
761 return;
762
763 m->m_pkthdr.rcvif = &sc->sc_if;
764
765 m->m_pkthdr.len = m->m_len;
766
767 microtime(&sc->sc_if.if_lastchange);
768
769#ifdef I4BIPRADJFRXP
770
771 /*
772 * The very first packet after the B channel is switched thru
773 * has very often several bytes of random data prepended. This
774 * routine looks where the IP header starts and removes the
775 * the bad data.
776 */
777
778 if(sc->sc_first_pkt)
779 {
780 unsigned char *mp = m->m_data;
781 int i;
782
783 sc->sc_first_pkt = 0;
784
785 for(i = 0; i < m->m_len; i++, mp++)
786 {
787 if( ((*mp & 0xf0) == 0x40) &&
788 ((*mp & 0x0f) >= 0x05) )
789 {
790 m->m_data = mp;
791 m->m_pkthdr.len -= i;
792 break;
793 }
794 }
795 }
796#endif
797
798 sc->sc_if.if_ipackets++;
799 sc->sc_if.if_ibytes += m->m_pkthdr.len;
800
801#ifdef IPR_VJ
802 if((c = (*(mtod(m, u_char *)) & 0xf0)) != (IPVERSION << 4))
803 {
804 /* copy data to buffer */
805
806 len = m->m_len;
807
808#ifdef IPR_VJ_USEBUFFER
809/* XXX */ m_copydata(m, 0, len, cp);
810#endif
811
812 if(c & 0x80)
813 {
814 c = TYPE_COMPRESSED_TCP;
815 }
816 else if(c == TYPE_UNCOMPRESSED_TCP)
817 {
818#ifdef IPR_VJ_USEBUFFER
819 *cp &= 0x4f; /* XXX */
820#else
821 *(mtod(m, u_char *)) &= 0x4f;
822#endif
823 }
824
825 /*
826 * We've got something that's not an IP packet.
827 * If compression is enabled, try to decompress it.
828 * Otherwise, if `auto-enable' compression is on and
829 * it's a reasonable packet, decompress it and then
830 * enable compression. Otherwise, drop it.
831 */
832 if(sc->sc_if.if_flags & IPR_COMPRESS)
833 {
834#ifdef IPR_VJ_USEBUFFER
835 len = sl_uncompress_tcp(&cp,len,(u_int)c,&sc->sc_compr);
836#else
837 len = sl_uncompress_tcp((u_char **)&m->m_data, len,
838 (u_int)c, &sc->sc_compr);
839#endif
840
841 if(len <= 0)
842 {
843#ifdef DEBUG_IPR_VJ
844 printf("i4b_ipr, ipr_rx_data_rdy: len <= 0 IPR_COMPRESS!\n");
845#endif
846 goto error;
847 }
848 }
849 else if((sc->sc_if.if_flags & IPR_AUTOCOMP) &&
850 (c == TYPE_UNCOMPRESSED_TCP) && (len >= 40))
851 {
852#ifdef IPR_VJ_USEBUFFER
853 len = sl_uncompress_tcp(&cp,len,(u_int)c,&sc->sc_compr);
854#else
855 len = sl_uncompress_tcp((u_char **)&m->m_data, len,
856 (u_int)c, &sc->sc_compr);
857#endif
858
859 if(len <= 0)
860 {
861#ifdef DEBUG_IPR_VJ
862 printf("i4b_ipr, ipr_rx_data_rdy: len <= 0 IPR_AUTOCOMP!\n");
863#endif
864 goto error;
865 }
866
867 sc->sc_if.if_flags |= IPR_COMPRESS;
868 }
869 else
870 {
871#ifdef DEBUG_IPR_VJ
872 printf("i4b_ipr, ipr_input: invalid ip packet!\n");
873#endif
874
875error:
876 sc->sc_if.if_ierrors++;
877 sc->sc_if.if_collisions++;
878 m_freem(m);
879 return;
880 }
881#ifdef IPR_VJ_USEBUFFER
882/* XXX */ m_copyback(m, 0, len, cp);
883#else
884 m->m_len = m->m_pkthdr.len = len;
885#endif
886 }
887#endif
888
889#if I4BIPRACCT
890 /* NB. do the accounting after decompression! */
891 sc->sc_inb += m->m_pkthdr.len;
892#endif
893#if IPR_LOG
894 if(sc->sc_log_first > 0)
895 {
896 --(sc->sc_log_first);
897 i4b_l4_packet_ind(BDRV_IPR, unit, 0, m );
898 }
899#endif
900
1f8e62c9
JS
901 if (sc->sc_if.if_bpf)
902 bpf_ptap(sc->sc_if.if_bpf, m, &af, sizeof(af));
984263bc 903
8bde602d 904 if (netisr_queue(NETISR_IP, m)) {
984263bc
MD
905 NDBGL4(L4_IPRDBG, "ipr%d: ipintrq full!", unit);
906 sc->sc_if.if_ierrors++;
907 sc->sc_if.if_iqdrops++;
908 }
984263bc
MD
909}
910
911/*---------------------------------------------------------------------------*
912 * this routine is called from the HSCX interrupt handler
913 * when the last frame has been sent out and there is no
914 * further frame (mbuf) in the tx queue.
915 *---------------------------------------------------------------------------*/
916static void
917ipr_tx_queue_empty(int unit)
918{
1f8e62c9 919 static const uint32_t af = AF_INET;
94332c29
RG
920 struct ipr_softc *sc = &ipr_softc[unit];
921 struct mbuf *m;
984263bc
MD
922#ifdef IPR_VJ
923 struct ip *ip;
924#endif
925 int x = 0;
926
927 if(sc->sc_state != ST_CONNECTED_A)
928 return;
929
930 for(;;)
931 {
932 IF_DEQUEUE(&sc->sc_fastq, m);
933 if(m)
934 {
935 sc->sc_if.if_omcasts++;
936 }
937 else
938 {
939 IF_DEQUEUE(&sc->sc_if.if_snd, m);
940 if(m == NULL)
941 break;
942 }
943
944 microtime(&sc->sc_if.if_lastchange);
1f8e62c9
JS
945
946 if (sc->sc_if.if_bpf)
947 bpf_ptap(sc->sc_if.if_bpf, m, &af, sizeof(af));
984263bc
MD
948
949#if I4BIPRACCT
950 sc->sc_outb += m->m_pkthdr.len; /* size before compression */
951#endif
952
953#ifdef IPR_VJ
954 if((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP)
955 {
956 if(sc->sc_if.if_flags & IPR_COMPRESS)
957 {
958 *mtod(m, u_char *) |= sl_compress_tcp(m, ip,
959 &sc->sc_compr, 1);
960 }
961 }
962#endif
963 x = 1;
964
fd81ccf9 965 if(IF_QFULL(isdn_linktab[unit]->tx_queue))
984263bc
MD
966 {
967 NDBGL4(L4_IPRDBG, "ipr%d: tx queue full!", unit);
968 m_freem(m);
969 }
970 else
971 {
972 sc->sc_if.if_obytes += m->m_pkthdr.len;
973
974 sc->sc_if.if_opackets++;
975
fd81ccf9 976 IF_ENQUEUE(isdn_linktab[unit]->tx_queue, m);
984263bc
MD
977
978 }
984263bc
MD
979 }
980
981 if(x)
982 (*isdn_linktab[unit]->bch_tx_start)(isdn_linktab[unit]->unit, isdn_linktab[unit]->channel);
983}
984
985/*---------------------------------------------------------------------------*
986 * this routine is called from the HSCX interrupt handler
987 * each time a packet is received or transmitted. It should
988 * be used to implement an activity timeout mechanism.
989 *---------------------------------------------------------------------------*/
990static void
991ipr_activity(int unit, int rxtx)
992{
993 ipr_softc[unit].sc_cdp->last_active_time = SECOND;
994}
995
996/*---------------------------------------------------------------------------*
997 * return this drivers linktab address
998 *---------------------------------------------------------------------------*/
999drvr_link_t *
1000ipr_ret_linktab(int unit)
1001{
1002 return(&ipr_drvr_linktab[unit]);
1003}
1004
1005/*---------------------------------------------------------------------------*
1006 * setup the isdn_linktab for this driver
1007 *---------------------------------------------------------------------------*/
1008void
1009ipr_set_linktab(int unit, isdn_link_t *ilt)
1010{
1011 isdn_linktab[unit] = ilt;
1012}
1013
1014/*---------------------------------------------------------------------------*
1015 * initialize this drivers linktab
1016 *---------------------------------------------------------------------------*/
1017static void
1018ipr_init_linktab(int unit)
1019{
1020 ipr_drvr_linktab[unit].unit = unit;
1021 ipr_drvr_linktab[unit].bch_rx_data_ready = ipr_rx_data_rdy;
1022 ipr_drvr_linktab[unit].bch_tx_queue_empty = ipr_tx_queue_empty;
1023 ipr_drvr_linktab[unit].bch_activity = ipr_activity;
1024 ipr_drvr_linktab[unit].line_connected = ipr_connect;
1025 ipr_drvr_linktab[unit].line_disconnected = ipr_disconnect;
1026 ipr_drvr_linktab[unit].dial_response = ipr_dialresponse;
1027 ipr_drvr_linktab[unit].updown_ind = ipr_updown;
1028}
1029
1030/*===========================================================================*/
1031
1032#endif /* NI4BIPR > 0 */