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