diff options
-rw-r--r-- | sbin/cxconfig/cxconfig.c | 68 | ||||
-rw-r--r-- | sbin/i386/cxconfig/cxconfig.c | 68 | ||||
-rw-r--r-- | sys/i386/include/cronyx.h | 22 | ||||
-rw-r--r-- | sys/i386/isa/cronyx.c | 49 | ||||
-rw-r--r-- | sys/i386/isa/cx.c | 127 | ||||
-rw-r--r-- | sys/i386/isa/if_cx.c | 304 | ||||
-rw-r--r-- | sys/net/if_sppp.h | 11 | ||||
-rw-r--r-- | sys/net/if_spppsubr.c | 569 |
8 files changed, 846 insertions, 372 deletions
diff --git a/sbin/cxconfig/cxconfig.c b/sbin/cxconfig/cxconfig.c index 0a2391f..4e2400e 100644 --- a/sbin/cxconfig/cxconfig.c +++ b/sbin/cxconfig/cxconfig.c @@ -11,7 +11,7 @@ * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * - * Version 1.1, Wed Oct 26 16:08:09 MSK 1994 + * Version 1.9, Wed Oct 4 18:58:15 MSK 1995 * * Usage: * cxconfig [-a] @@ -24,15 +24,18 @@ #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> -#include <sys/cronyx.h> +#include <machine/cronyx.h> #include <net/if.h> #include <stdio.h> +#define NBRD 3 #define CXDEV "/dev/cronyx" #define atoi(a) strtol((a), (char**)0, 0) cx_options_t o; +cx_stat_t st; int aflag; +int sflag; char *symbol (unsigned char sym) { @@ -121,6 +124,40 @@ void getchan (int channel) } } +int printstats (int channel, int hflag) +{ + int s, res; + + s = open (CXDEV, 0); + if (s < 0) { + perror (CXDEV); + exit (1); + } + st.board = channel/NCHAN; + st.channel = channel%NCHAN; + res = ioctl (s, CXIOCGETSTAT, (caddr_t)&st); + close (s); + if (res < 0) + return (-1); + + if (hflag) + printf ("Chan Rintr Tintr Mintr Ibytes Ipkts Ierrs Obytes Opkts Oerrs\n"); + printf ("cx%-2d %7ld %7ld %7ld %8ld %7ld %7ld %8ld %7ld %7ld\n", + channel, st.rintr, st.tintr, st.mintr, st.ibytes, st.ipkts, + st.ierrs, st.obytes, st.opkts, st.oerrs); + return (0); +} + +void printallstats () +{ + int b, c; + + printf ("Chan Rintr Tintr Mintr Ibytes Ipkts Ierrs Obytes Opkts Oerrs\n"); + for (b=0; b<NBRD; ++b) + for (c=0; c<NCHAN; ++c) + printstats (b*NCHAN + c, 0); +} + void setchan (int channel) { int s = open (CXDEV, 0); @@ -362,6 +399,8 @@ void printchan (int channel) printf (o.sopt.ext ? " ext" : o.sopt.cisco ? " cisco" : " ppp"); printf (" %ckeepalive", o.sopt.keepalive ? '+' : '-'); printf (" %cautorts", o.sopt.norts ? '-' : '+'); + if (*o.master) + printf (" master=%s", o.master); printf ("\n"); if (aflag) printopt (); @@ -429,6 +468,15 @@ void set_interface_type (char *type) o.iftype = 1; } +void set_master (char *ifname) +{ + if (o.type == T_ASYNC) { + printf ("master option is not applicable for async channels\n"); + exit (1); + } + strcpy (o.master, ifname); +} + void set_async_opt (char *opt) { /* channel option register 1 */ @@ -571,11 +619,16 @@ int main (int argc, char **argv) for (--argc, ++argv; argc>0 && **argv=='-'; --argc, ++argv) if (! strcasecmp (*argv, "-a")) ++aflag; + else if (! strcasecmp (*argv, "-s")) + ++sflag; else usage (); if (argc <= 0) { - printall (); + if (sflag) + printallstats (); + else + printall (); return (0); } @@ -585,6 +638,13 @@ int main (int argc, char **argv) usage (); channel = atoi (*argv); --argc, ++argv; + + if (sflag) { + if (printstats (channel, 1) < 0) + printf ("channel cx%d not available\n", channel); + return (0); + } + getchan (channel); if (argc <= 0) { @@ -631,6 +691,8 @@ int main (int argc, char **argv) ! strcasecmp (*argv, "port=rs449") || ! strcasecmp (*argv, "port=v35")) set_interface_type (*argv); + else if (! strncasecmp (*argv, "master=",7)) + set_master (*argv+7); /* * Common channel options diff --git a/sbin/i386/cxconfig/cxconfig.c b/sbin/i386/cxconfig/cxconfig.c index 0a2391f..4e2400e 100644 --- a/sbin/i386/cxconfig/cxconfig.c +++ b/sbin/i386/cxconfig/cxconfig.c @@ -11,7 +11,7 @@ * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * - * Version 1.1, Wed Oct 26 16:08:09 MSK 1994 + * Version 1.9, Wed Oct 4 18:58:15 MSK 1995 * * Usage: * cxconfig [-a] @@ -24,15 +24,18 @@ #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> -#include <sys/cronyx.h> +#include <machine/cronyx.h> #include <net/if.h> #include <stdio.h> +#define NBRD 3 #define CXDEV "/dev/cronyx" #define atoi(a) strtol((a), (char**)0, 0) cx_options_t o; +cx_stat_t st; int aflag; +int sflag; char *symbol (unsigned char sym) { @@ -121,6 +124,40 @@ void getchan (int channel) } } +int printstats (int channel, int hflag) +{ + int s, res; + + s = open (CXDEV, 0); + if (s < 0) { + perror (CXDEV); + exit (1); + } + st.board = channel/NCHAN; + st.channel = channel%NCHAN; + res = ioctl (s, CXIOCGETSTAT, (caddr_t)&st); + close (s); + if (res < 0) + return (-1); + + if (hflag) + printf ("Chan Rintr Tintr Mintr Ibytes Ipkts Ierrs Obytes Opkts Oerrs\n"); + printf ("cx%-2d %7ld %7ld %7ld %8ld %7ld %7ld %8ld %7ld %7ld\n", + channel, st.rintr, st.tintr, st.mintr, st.ibytes, st.ipkts, + st.ierrs, st.obytes, st.opkts, st.oerrs); + return (0); +} + +void printallstats () +{ + int b, c; + + printf ("Chan Rintr Tintr Mintr Ibytes Ipkts Ierrs Obytes Opkts Oerrs\n"); + for (b=0; b<NBRD; ++b) + for (c=0; c<NCHAN; ++c) + printstats (b*NCHAN + c, 0); +} + void setchan (int channel) { int s = open (CXDEV, 0); @@ -362,6 +399,8 @@ void printchan (int channel) printf (o.sopt.ext ? " ext" : o.sopt.cisco ? " cisco" : " ppp"); printf (" %ckeepalive", o.sopt.keepalive ? '+' : '-'); printf (" %cautorts", o.sopt.norts ? '-' : '+'); + if (*o.master) + printf (" master=%s", o.master); printf ("\n"); if (aflag) printopt (); @@ -429,6 +468,15 @@ void set_interface_type (char *type) o.iftype = 1; } +void set_master (char *ifname) +{ + if (o.type == T_ASYNC) { + printf ("master option is not applicable for async channels\n"); + exit (1); + } + strcpy (o.master, ifname); +} + void set_async_opt (char *opt) { /* channel option register 1 */ @@ -571,11 +619,16 @@ int main (int argc, char **argv) for (--argc, ++argv; argc>0 && **argv=='-'; --argc, ++argv) if (! strcasecmp (*argv, "-a")) ++aflag; + else if (! strcasecmp (*argv, "-s")) + ++sflag; else usage (); if (argc <= 0) { - printall (); + if (sflag) + printallstats (); + else + printall (); return (0); } @@ -585,6 +638,13 @@ int main (int argc, char **argv) usage (); channel = atoi (*argv); --argc, ++argv; + + if (sflag) { + if (printstats (channel, 1) < 0) + printf ("channel cx%d not available\n", channel); + return (0); + } + getchan (channel); if (argc <= 0) { @@ -631,6 +691,8 @@ int main (int argc, char **argv) ! strcasecmp (*argv, "port=rs449") || ! strcasecmp (*argv, "port=v35")) set_interface_type (*argv); + else if (! strncasecmp (*argv, "master=",7)) + set_master (*argv+7); /* * Common channel options diff --git a/sys/i386/include/cronyx.h b/sys/i386/include/cronyx.h index 9421cbc..0ea0e65 100644 --- a/sys/i386/include/cronyx.h +++ b/sys/i386/include/cronyx.h @@ -11,7 +11,7 @@ * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * - * Version 1.1, Wed Oct 26 16:09:46 MSK 1994 + * Version 1.9, Wed Oct 4 18:58:15 MSK 1995 */ /* * Asynchronous channel mode ------------------------------------------------- @@ -382,6 +382,7 @@ typedef struct { cx_opt_bisync_t bopt; /* bisync mode options */ cx_opt_x21_t xopt; /* x.21 mode options */ cx_soft_opt_t sopt; /* software options and state flags */ + char master[16]; /* master interface name or \0 */ } cx_options_t; /* user settable options */ typedef struct _chan_t { @@ -389,6 +390,7 @@ typedef struct _chan_t { unsigned char num; /* channel number, 0..15 */ struct _board_t *board; /* board pointer */ struct _chip_t *chip; /* controller pointer */ + struct _stat_t *stat; /* statistics */ unsigned long rxbaud; /* receiver speed */ unsigned long txbaud; /* transmitter speed */ cx_chan_mode_t mode; /* channel mode */ @@ -410,6 +412,8 @@ typedef struct _chan_t { #ifdef KERNEL struct tty *ttyp; /* tty structure pointer */ struct ifnet *ifp; /* network interface data */ + struct ifnet *master; /* master interface, or ==ifp */ + struct _chan_t *slaveq; /* slave queue pointer, or NULL */ caddr_t bpf; /* packet filter data */ cx_soft_opt_t sopt; /* software options and state flags */ cx_break_t brk; /* line break mode */ @@ -426,6 +430,20 @@ typedef struct _chip_t { unsigned long oscfreq; /* oscillator frequency in Hz */ } cx_chip_t; +typedef struct _stat_t { + unsigned char board; /* adapter number, 0..2 */ + unsigned char channel; /* channel number, 0..15 */ + unsigned long rintr; /* receive interrupts */ + unsigned long tintr; /* transmit interrupts */ + unsigned long mintr; /* modem interrupts */ + unsigned long ibytes; /* input bytes */ + unsigned long ipkts; /* input packets */ + unsigned long ierrs; /* input errors */ + unsigned long obytes; /* output bytes */ + unsigned long opkts; /* output packets */ + unsigned long oerrs; /* output errors */ +} cx_stat_t; + typedef struct _board_t { unsigned short port; /* base board port, 0..3f0 */ unsigned short num; /* board number, 0..2 */ @@ -439,6 +457,7 @@ typedef struct _board_t { unsigned short bcr1b; /* BCR1b image */ cx_chip_t chip[NCHIP]; /* controller structures */ cx_chan_t chan[NCHAN]; /* channel structures */ + cx_stat_t stat[NCHAN]; /* channel statistics */ char name[16]; /* board version name */ unsigned char nuniv; /* number of universal channels */ unsigned char nsync; /* number of sync. channels */ @@ -473,3 +492,4 @@ void cx_clock (long hz, long ba, int *clk, int *div); #define CXIOCGETMODE _IOWR('x', 1, cx_options_t) /* get channel options */ #define CXIOCSETMODE _IOW('x', 2, cx_options_t) /* set channel options */ +#define CXIOCGETSTAT _IOWR('x', 3, cx_stat_t) /* get channel stats */ diff --git a/sys/i386/isa/cronyx.c b/sys/i386/isa/cronyx.c index 31eeef3..c312100 100644 --- a/sys/i386/isa/cronyx.c +++ b/sys/i386/isa/cronyx.c @@ -1,8 +1,8 @@ /* * Low-level subroutines for Cronyx-Sigma adapter. * - * Copyright (C) 1994 Cronyx Ltd. - * Author: Serge Vakulenko, <vak@zebub.msk.su> + * Copyright (C) 1994-95 Cronyx Ltd. + * Author: Serge Vakulenko, <vak@cronyx.ru> * * This software is distributed with NO WARRANTIES, not even the implied * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. @@ -11,7 +11,7 @@ * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * - * Version 1.2, Mon Nov 28 16:12:18 MSK 1994 + * Version 1.6, Wed May 31 16:03:20 MSD 1995 */ #if defined (MSDOS) || defined (__MSDOS__) # include <string.h> @@ -26,13 +26,15 @@ # include "cxreg.h" #else # include <sys/param.h> -# include <sys/systm.h> # include <sys/socket.h> # include <net/if.h> # include <vm/vm.h> # ifdef __FreeBSD__ # if __FreeBSD__ < 2 # include <machine/pio.h> +# else +# include <machine/cpufunc.h> +# include <sys/libkern.h> # endif # else # include <machine/inline.h> @@ -368,6 +370,7 @@ void cx_init_board (cx_board_t *b, int num, int port, int irq, int dma, c->num = i; c->board = b; c->chip = b->chip + i*NCHIP/NCHAN; + c->stat = b->stat + i; c->type = T_NONE; } @@ -772,20 +775,26 @@ void cx_chan_dtr (cx_chan_t *c, int on) /* Channels 4..7 and 12..15 in syncronous mode * have no DTR signal. */ break; - case 0: case 1: case 2: case 3: + + case 1: case 2: case 3: + if (c->type == T_UNIV_RS232) + break; + case 0: if (on) c->board->bcr1 |= 0x100 << c->num; else c->board->bcr1 &= ~(0x100 << c->num); - outb (CAR(c->chip->port), c->num); outw (BCR1(c->board->port), c->board->bcr1); break; - case 8: case 9: case 10: case 11: + + case 9: case 10: case 11: + if (c->type == T_UNIV_RS232) + break; + case 8: if (on) c->board->bcr1b |= 0x100 << (c->num & 3); else c->board->bcr1b &= ~(0x100 << (c->num & 3)); - outb (CAR(c->chip->port), c->num & 3); outw (BCR1(c->board->port+0x10), c->board->bcr1b); break; } @@ -820,10 +829,18 @@ int cx_chan_dsr (cx_chan_t *c) switch (c->num) { default: return (1); - case 0: case 1: case 2: case 3: + + case 1: case 2: case 3: + if (c->type == T_UNIV_RS232) + return (1); + case 0: sigval = inw (BSR(c->board->port)) >> 8; break; - case 8: case 9: case 10: case 11: + + case 9: case 10: case 11: + if (c->type == T_UNIV_RS232) + return (1); + case 8: sigval = inw (BSR(c->board->port+0x10)) >> 8; break; } @@ -848,10 +865,18 @@ int cx_chan_cd (cx_chan_t *c) switch (c->num) { default: return (1); - case 0: case 1: case 2: case 3: + + case 1: case 2: case 3: + if (c->type == T_UNIV_RS232) + return (1); + case 0: sigval = inw (BSR(c->board->port)) >> 8; break; - case 8: case 9: case 10: case 11: + + case 9: case 10: case 11: + if (c->type == T_UNIV_RS232) + return (1); + case 8: sigval = inw (BSR(c->board->port+0x10)) >> 8; break; } diff --git a/sys/i386/isa/cx.c b/sys/i386/isa/cx.c index 6c236f5..c01c157 100644 --- a/sys/i386/isa/cx.c +++ b/sys/i386/isa/cx.c @@ -13,7 +13,7 @@ * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * - * Version 1.2, Tue Nov 22 18:57:27 MSK 1994 + * Version 1.9, Wed Oct 4 18:58:15 MSK 1995 */ #undef DEBUG @@ -39,6 +39,7 @@ # include <machine/pio.h> # define RB_GETC(q) getc(q) # else /* BSD 4.4 Lite */ +# include <machine/cpufunc.h> # include <sys/devconf.h> # endif # define oproc_func_t void(*)(struct tty*) @@ -55,11 +56,9 @@ # define t_out t_outq # define RB_LEN(q) ((q).c_cc) # define RB_GETC(q) getc(&q) -#ifndef TSA_CARR_ON /* FreeBSD 2.x before not long after 2.0.5 */ # define TSA_CARR_ON(tp) tp # define TSA_OLOWAT(q) ((caddr_t)&(q)->t_out) #endif -#endif #include <machine/cronyx.h> #include <i386/isa/cxreg.h> @@ -67,7 +66,7 @@ #ifdef DEBUG # define print(s) printf s #else -# define print(s) /*void*/ +# define print(s) {/*void*/} #endif #define DMABUFSZ (6*256) /* buffer size */ @@ -107,9 +106,13 @@ int cxopen (dev_t dev, int flag, int mode, struct proc *p) if (c->mode != M_ASYNC) return (EBUSY); if (! c->ttyp) { +#ifdef __FreeBSD__ #if __FreeBSD__ >= 2 c->ttyp = &cx_tty[unit]; #else + c->ttyp = cx_tty[unit] = ttymalloc (cx_tty[unit]); +#endif +#else MALLOC (cx_tty[unit], struct tty*, sizeof (struct tty), M_DEVBUF, M_WAITOK); bzero (cx_tty[unit], sizeof (*cx_tty[unit])); c->ttyp = cx_tty[unit]; @@ -194,7 +197,7 @@ int cxopen (dev_t dev, int flag, int mode, struct proc *p) cx_chan_rts (c, 1); } if (cx_chan_cd (c)) - (*linesw[tp->t_line].l_modem)(tp, 1); + tp->t_state |= TS_CARR_ON; if (! (flag & O_NONBLOCK)) { /* Lock the channel against cxconfig while we are * waiting for carrier. */ @@ -283,10 +286,12 @@ int cxwrite (dev_t dev, struct uio *uio, int flag) int cxioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) { int unit = UNIT (dev); - cx_chan_t *c; + cx_chan_t *c, *m; + cx_stat_t *st; struct tty *tp; int error, s; unsigned char msv; + struct ifnet *master; if (unit == UNIT_CTL) { /* Process an ioctl request on /dev/cronyx */ @@ -324,6 +329,32 @@ int cxioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) /* Network interface is up? */ if (c->mode != M_ASYNC && (c->ifp->if_flags & IFF_UP)) return (EBUSY); + + /* Find the master interface. */ + master = *o->master ? ifunit (o->master) : c->ifp; + if (! master) + return (EINVAL); + m = cxchan[master->if_unit]; + + /* Leave the previous master queue. */ + if (c->master != c->ifp) { + cx_chan_t *p = cxchan[c->master->if_unit]; + + for (; p; p=p->slaveq) + if (p->slaveq == c) + p->slaveq = c->slaveq; + } + + /* Set up new master. */ + c->master = master; + c->slaveq = 0; + + /* Join the new master queue. */ + if (c->master != c->ifp) { + c->slaveq = m->slaveq; + m->slaveq = c; + } + c->mode = o->mode; c->rxbaud = o->rxbaud; c->txbaud = o->txbaud; @@ -336,13 +367,26 @@ int cxioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) case 0: c->board->if0type = o->iftype; break; case 8: c->board->if8type = o->iftype; break; } - cxswitch (c, o->sopt); s = spltty (); + cxswitch (c, o->sopt); cx_setup_chan (c); outb (IER(c->chip->port), 0); splx (s); break; + case CXIOCGETSTAT: + st = (cx_stat_t*) data; + st->rintr = c->stat->rintr; + st->tintr = c->stat->tintr; + st->mintr = c->stat->mintr; + st->ibytes = c->stat->ibytes; + st->ipkts = c->stat->ipkts; + st->ierrs = c->stat->ierrs; + st->obytes = c->stat->obytes; + st->opkts = c->stat->opkts; + st->oerrs = c->stat->oerrs; + break; + case CXIOCGETMODE: print (("cx%d.%d: CXIOCGETMODE\n", o->board, o->channel)); o->type = c->type; @@ -359,6 +403,11 @@ int cxioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p) case 0: o->iftype = c->board->if0type; break; case 8: o->iftype = c->board->if8type; break; } + if (c->master != c->ifp) + sprintf (o->master, "%s%d", c->master->if_name, + c->master->if_unit); + else + *o->master = 0; break; } return (0); @@ -476,9 +525,9 @@ void cxout (cx_chan_t *c, char b) c->brk = BRK_IDLE; break; case BRK_IDLE: - len = RB_LEN (tp->t_out); + p = buf; if (tp->t_iflag & IXOFF) - for (i=0, p=buf; i<len && p<buf+DMABUFSZ-1; ++i) { + while (RB_LEN (tp->t_out) && p<buf+DMABUFSZ-1) { sym = RB_GETC (tp->t_out); /* Send XON/XOFF out of band. */ if (sym == tp->t_cc[VSTOP]) { @@ -495,7 +544,7 @@ void cxout (cx_chan_t *c, char b) *p++ = sym; } else - for (i=0, p=buf; i<len && p<buf+DMABUFSZ-1; ++i) { + while (RB_LEN (tp->t_out) && p<buf+DMABUFSZ-1) { sym = RB_GETC (tp->t_out); /* Duplicate NULLs in ETC mode. */ if (! sym) @@ -510,6 +559,7 @@ void cxout (cx_chan_t *c, char b) if (len) { outw (cnt_port, len); outb (sts_port, BSTS_INTR | BSTS_OWN24); + c->stat->obytes += len; tp->t_state |= TS_BUSY; print (("cx%d.%d: out %d bytes to %c\n", c->board->num, c->num, len, b)); @@ -544,9 +594,6 @@ void cxoproc (struct tty *tp) if (tp->t_state & (TS_SO_OCOMPLETE | TS_SO_OLOWAT) || tp->t_wsel) ttwwakeup (tp); #else /* FreeBSD 2.x and BSDI */ -#ifndef TS_ASLEEP /* FreeBSD some time after 2.0.5 */ - ttwwakeup(tp); -#else if (RB_LEN (tp->t_out) <= tp->t_lowat) { if (tp->t_state & TS_ASLEEP) { tp->t_state &= ~TS_ASLEEP; @@ -555,16 +602,6 @@ void cxoproc (struct tty *tp) selwakeup(&tp->t_wsel); } #endif -#endif - /* - * Enable TXMPTY interrupt, - * to catch the case when the second buffer is empty. - */ - if ((inb (ATBSTS(port)) & BSTS_OWN24) && - (inb (BTBSTS(port)) & BSTS_OWN24)) { - outb (IER(port), IER_RXD|IER_RET|IER_TXD|IER_TXMPTY|IER_MDM); - } else - outb (IER(port), IER_RXD|IER_RET|IER_TXD|IER_MDM); splx (s); } @@ -682,12 +719,8 @@ struct tty *cxdevtotty (dev_t dev) { int unit = UNIT(dev); - if (unit == UNIT_CTL) - return (NULL); - - if (unit > NCX*NCHAN) - return (NULL); - + if (unit == UNIT_CTL || unit >= NCX*NCHAN) + return (0); return (cxchan[unit]->ttyp); } @@ -695,13 +728,13 @@ int cxselect (dev_t dev, int flag, struct proc *p) { int unit = UNIT (dev); - if (unit == UNIT_CTL) + if (unit == UNIT_CTL || unit >= NCX*NCHAN) return (0); - - if (unit > NCX*NCHAN) - return (ENXIO); - - return (ttyselect(cxchan[unit]->ttyp, flag, p)); +#if defined (__FreeBSD__) && __FreeBSD__ < 2 + return (ttselect (dev, flag, p)); +#else /* FreeBSD 2.x and BSDI */ + return (ttyselect (cxchan[unit]->ttyp, flag, p)); +#endif } /* @@ -765,6 +798,7 @@ int cxrinta (cx_chan_t *c) print (("cx%d.%d: async receive timeout (%d bytes), risr=%b, arbsts=%b, brbsts=%b\n", c->board->num, c->num, len, risr, RISA_BITS, inb (ARBSTS(port)), BSTS_BITS, inb (BRBSTS(port)), BSTS_BITS)); + c->stat->ibytes += len; if (tp && (tp->t_state & TS_ISOPEN)) { int i; void (*rint)() = (void(*)()) @@ -785,23 +819,29 @@ int cxrinta (cx_chan_t *c) c->board->num, c->num, risr, RISA_BITS, inb (ARBSTS(port)), BSTS_BITS, inb (BRBSTS(port)), BSTS_BITS)); - if (risr & RIS_BUSERR) + if (risr & RIS_BUSERR) { printf ("cx%d.%d: receive bus error\n", c->board->num, c->num); - + ++c->stat->ierrs; + } if (risr & (RIS_OVERRUN | RISA_PARERR | RISA_FRERR | RISA_BREAK)) { int err = 0; - if (risr & RIS_OVERRUN) - err |= TTY_OE; if (risr & RISA_PARERR) err |= TTY_PE; if (risr & RISA_FRERR) err |= TTY_FE; +#ifdef TTY_OE + if (risr & RIS_OVERRUN) + err |= TTY_OE; +#endif +#ifdef TTY_BI if (risr & RISA_BREAK) err |= TTY_BI; +#endif print (("cx%d.%d: receive error %x\n", c->board->num, c->num, err)); if (tp && (tp->t_state & TS_ISOPEN)) (*linesw[tp->t_line].l_rint) (err, tp); + ++c->stat->ierrs; } /* Discard exception characters. */ @@ -818,6 +858,7 @@ int cxrinta (cx_chan_t *c) print (("cx%d.%d: async: %d bytes received\n", c->board->num, c->num, len)); + c->stat->ibytes += len; buf = (risr & RIS_BB) ? c->brbuf : c->arbuf; for (i=0; i<len; ++i) @@ -849,13 +890,15 @@ void cxtinta (cx_chan_t *c) c->board->num, c->num, tisr, TIS_BITS, inb (ATBSTS(port)), BSTS_BITS, inb (BTBSTS(port)), BSTS_BITS)); - if (tisr & TIS_BUSERR) + if (tisr & TIS_BUSERR) { printf ("cx%d.%d: transmit bus error\n", c->board->num, c->num); - else if (tisr & TIS_UNDERRUN) + ++c->stat->oerrs; + } else if (tisr & TIS_UNDERRUN) { printf ("cx%d.%d: transmit underrun error\n", c->board->num, c->num); - + ++c->stat->oerrs; + } if (tp) { tp->t_state &= ~(TS_BUSY | TS_FLUSH); if (tp->t_line) diff --git a/sys/i386/isa/if_cx.c b/sys/i386/isa/if_cx.c index f4adf10..6292e74 100644 --- a/sys/i386/isa/if_cx.c +++ b/sys/i386/isa/if_cx.c @@ -14,13 +14,13 @@ * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * - * Version 1.2, Tue Nov 22 18:57:27 MSK 1994 + * Version 1.9, Wed Oct 4 18:58:15 MSK 1995 */ #undef DEBUG #include "cx.h" #if NCX > 0 -#include "bpfilter.h" +#include <bpfilter.h> #include <sys/param.h> #include <sys/systm.h> @@ -44,6 +44,7 @@ # if __FreeBSD__ < 2 # include <machine/pio.h> # else +# include <machine/cpufunc.h> # include <sys/devconf.h> # endif # define init_func_t void(*)(int) @@ -81,10 +82,10 @@ struct cxsoftc { #ifdef DEBUG # define print(s) printf s #else -# define print(s) /*void*/ +# define print(s) {/*void*/} #endif -#define TXTIMEOUT 2 /* transmit timeout in seconds */ +#define TXTIMEOUT 10 /* transmit timeout in seconds */ #define DMABUFSZ (6*256) /* buffer size */ #define PPP_HEADER_LEN 4 /* size of PPP header */ @@ -103,7 +104,6 @@ struct cxsoftc { #endif #define IFNETSZ (sizeof (struct ifnet)) -int cxoutput (struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt); int cxsioctl (struct ifnet *ifp, int cmd, caddr_t data); void cxinit (int unit); void cxstart (struct ifnet *ifp); @@ -113,6 +113,8 @@ int cxrinta (cx_chan_t *c); void cxtinta (cx_chan_t *c); void cxmint (cx_chan_t *c); void cxtimeout (caddr_t a); +void cxdown (cx_chan_t *c); +void cxup (cx_chan_t *c); cx_board_t cxboard [NCX]; /* adapter state structures */ cx_chan_t *cxchan [NCX*NCHAN]; /* unit to channel struct pointer */ @@ -321,10 +323,12 @@ void cxattach (struct device *parent, struct device *self, void *aux) c->type = T_NONE; continue; } + bzero (c->ifp, IFSTRUCTSZ); + c->master = c->ifp; c->ifp->if_unit = u; c->ifp->if_name = "cx"; c->ifp->if_mtu = PP_MTU; - c->ifp->if_flags = IFF_POINTOPOINT|IFF_MULTICAST; + c->ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST; c->ifp->if_ioctl = cxsioctl; c->ifp->if_start = (start_func_t) cxstart; c->ifp->if_watchdog = (watchdog_func_t) cxwatchdog; @@ -380,62 +384,106 @@ struct cfdriver cxcd = { 0, "cx", cxprobe, cxattach, sizeof (struct cxsoftc) }; */ int cxsioctl (struct ifnet *ifp, int cmd, caddr_t data) { - cx_chan_t *c = cxchan[ifp->if_unit]; - int error, s; + cx_chan_t *q, *c = cxchan[ifp->if_unit]; + int error, s, was_up, should_be_up; + /* + * No socket ioctls while the channel is in async mode. + */ if (c->type==T_NONE || c->mode==M_ASYNC) return (EINVAL); + + /* + * Socket ioctls on slave subchannels are not allowed. + */ + if (c->master != c->ifp) + return (EBUSY); + + was_up = (ifp->if_flags & IFF_RUNNING) != 0; #ifdef __bsdi__ - if (c->sopt.ext) { - /* Save RUNNING flag. */ - int running = (ifp->if_flags & IFF_RUNNING); + if (c->sopt.ext) error = p2p_ioctl (ifp, cmd, data); - ifp->if_flags &= ~IFF_RUNNING; - ifp->if_flags |= running; - } else + else #endif error = sppp_ioctl (ifp, cmd, data); if (error) return (error); - if (cmd != SIOCSIFFLAGS) + + print (("cxioctl (%d.%d, ", c->board->num, c->num)); + switch (cmd) { + default: + print (("0x%x)\n", cmd)); + return (0); + case SIOCADDMULTI: + print (("SIOCADDMULTI)\n")); + return (0); + case SIOCDELMULTI: + print (("SIOCDELMULTI)\n")); return (0); + case SIOCSIFFLAGS: + print (("SIOCSIFFLAGS)\n")); + break; + case SIOCSIFADDR: + print (("SIOCSIFADDR)\n")); + break; + } + /* We get here only in case of SIFFLAGS or SIFADDR. */ s = splimp (); - if (! (ifp->if_flags & IFF_UP) && (ifp->if_flags & IFF_RUNNING)) - /* Interface is down and running -- stop it. */ - cxinit (ifp->if_unit); - else if ((ifp->if_flags & IFF_UP) && ! (ifp->if_flags & IFF_RUNNING)) - /* Interface is up and not running -- start it. */ - cxinit (ifp->if_unit); + should_be_up = (ifp->if_flags & IFF_RUNNING) != 0; + if (!was_up && should_be_up) { + /* Interface goes up -- start it. */ + cxup (c); + + /* Start all slave subchannels. */ + for (q=c->slaveq; q; q=q->slaveq) + cxup (q); + + cxstart (c->ifp); + } else if (was_up && !should_be_up) { + /* Interface is going down -- stop it. */ + cxdown (c); + + /* Stop all slave subchannels. */ + for (q=c->slaveq; q; q=q->slaveq) + cxdown (q); + + /* Flush the interface output queue */ + if (! c->sopt.ext) + sppp_flush (c->ifp); + } splx (s); return (0); } /* - * Initialization of interface. + * Stop the interface. Called on splimp(). */ -void cxinit (int unit) +void cxdown (cx_chan_t *c) { - cx_chan_t *c = cxchan[unit]; unsigned short port = c->chip->port; - int s; - print (("cx%d.%d: cxinit\n", c->board->num, c->num)); + print (("cx%d.%d: cxdown\n", c->board->num, c->num)); - /* Disable interrupts */ - s = splimp(); + /* The interface is down, stop it */ + c->ifp->if_flags &= ~IFF_OACTIVE; /* Reset the channel (for sync modes only) */ - if (c->ifp->if_flags & IFF_OACTIVE) { outb (CAR(port), c->num & 3); outb (STCR(port), STC_ABORTTX | STC_SNDSPC); - } + cx_setup_chan (c); - c->ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); +} + +/* + * Start the interface. Called on splimp(). + */ +void cxup (cx_chan_t *c) +{ + unsigned short port = c->chip->port; - if (c->ifp->if_flags & IFF_UP) { /* The interface is up, start it */ - c->ifp->if_flags |= IFF_RUNNING; + print (("cx%d.%d: cxup\n", c->board->num, c->num)); #if __FreeBSD__ >= 2 /* Mark the board busy on the first startup. @@ -459,13 +507,31 @@ void cxinit (int unit) /* Enable interrupts */ outb (IER(port), IER_RXD | IER_TXD); +} - cxstart (c->ifp); +/* + * Initialization of interface. + */ +void cxinit (int unit) +{ + cx_chan_t *q, *c = cxchan[unit]; + int s = splimp(); - } else if (! c->sopt.ext) - /* Flush the interface output queue, if it is down */ - sppp_flush (c->ifp); + print (("cx%d.%d: cxinit\n", c->board->num, c->num)); + + cxdown (c); + + /* Stop all slave subchannels. */ + for (q=c->slaveq; q; q=q->slaveq) + cxdown (q); + if (c->ifp->if_flags & IFF_RUNNING) { + cxup (c); + + /* Start all slave subchannels. */ + for (q=c->slaveq; q; q=q->slaveq) + cxup (q); + } splx (s); } @@ -491,28 +557,37 @@ void cxput (cx_chan_t *c, char b) /* Is it busy? */ if (inb (sts_port) & BSTS_OWN24) { - c->ifp->if_flags |= IFF_OACTIVE; - return; + if (c->ifp->if_flags & IFF_DEBUG) + print (("cx%d.%d: tbuf %c already busy, bsts=%b\n", + c->board->num, c->num, b, + inb (sts_port), BSTS_BITS)); + goto ret; } /* Get the packet to send. */ #ifdef __bsdi__ if (c->sopt.ext) { - struct p2pcom *p = (struct p2pcom*) c->ifp; + struct p2pcom *p = (struct p2pcom*) c->master; int s = splimp (); IF_DEQUEUE (&p->p2p_isnd, m) if (! m) - IF_DEQUEUE (&c->ifp->if_snd, m) + IF_DEQUEUE (&c->master->if_snd, m) splx (s); } else #endif - m = sppp_dequeue (c->ifp); + m = sppp_dequeue (c->master); if (! m) return; len = m->m_pkthdr.len; + + /* Count the transmitted bytes to the subchannel, not the master. */ + c->master->if_obytes -= len + 3; + c->ifp->if_obytes += len + 3; + c->stat->obytes += len + 3; + if (len >= DMABUFSZ) { - printf ("cx%d.%d: too long packet: %d bytes\n", + printf ("cx%d.%d: too long packet: %d bytes: ", c->board->num, c->num, len); printmbuf (m); m_freem (m); @@ -528,26 +603,28 @@ void cxput (cx_chan_t *c, char b) /* Start transmitter. */ outw (cnt_port, len); outb (sts_port, BSTS_EOFR | BSTS_INTR | BSTS_OWN24); -#ifdef DEBUG + if (c->ifp->if_flags & IFF_DEBUG) - printf ("cx%d.%d: enqueue %d bytes to %c\n", - c->board->num, c->num, len, buf==c->atbuf ? 'A' : 'B'); -#endif + print (("cx%d.%d: enqueue %d bytes to %c\n", + c->board->num, c->num, len, buf==c->atbuf ? 'A' : 'B')); +ret: c->ifp->if_flags |= IFF_OACTIVE; } /* - * Start output on interface. Get another datagram to send + * Start output on the (slave) interface. Get another datagram to send * off of the interface queue, and copy it to the interface * before starting the output. */ -void cxstart (struct ifnet *ifp) +void cxsend (cx_chan_t *c) { - cx_chan_t *c = cxchan[ifp->if_unit]; unsigned short port = c->chip->port; + if (c->ifp->if_flags & IFF_DEBUG) + print (("cx%d.%d: cxsend\n", c->board->num, c->num)); + /* No output if the interface is down. */ - if (! (ifp->if_flags & IFF_RUNNING)) + if (! (c->ifp->if_flags & IFF_RUNNING)) return; /* Set the current channel number. */ @@ -563,8 +640,8 @@ void cxstart (struct ifnet *ifp) } /* Set up transmit timeout. */ - if (c->ifp->if_flags & IFF_OACTIVE) - c->ifp->if_timer = TXTIMEOUT; + if (c->master->if_flags & IFF_OACTIVE) + c->master->if_timer = TXTIMEOUT; /* * Enable TXMPTY interrupt, @@ -578,17 +655,50 @@ void cxstart (struct ifnet *ifp) } /* + * Start output on the (master) interface and all slave interfaces. + * Always called on splimp(). + */ +void cxstart (struct ifnet *ifp) +{ + cx_chan_t *q, *c = cxchan[ifp->if_unit]; + + if (c->ifp->if_flags & IFF_DEBUG) + print (("cx%d.%d: cxstart\n", c->board->num, c->num)); + + /* Start the master subchannel. */ + cxsend (c); + + /* Start all slave subchannels. */ + if (c->slaveq && ! sppp_isempty (c->master)) + for (q=c->slaveq; q; q=q->slaveq) + if ((q->ifp->if_flags & IFF_RUNNING) && + ! (q->ifp->if_flags & IFF_OACTIVE)) + cxsend (q); +} + +/* * Handle transmit timeouts. * Recover after lost transmit interrupts. + * Always called on splimp(). */ void cxwatchdog (int unit) { - cx_chan_t *c = cxchan[unit]; + cx_chan_t *q, *c = cxchan[unit]; + + if (! (c->ifp->if_flags & IFF_RUNNING)) + return; + if (c->ifp->if_flags & IFF_DEBUG) + printf ("cx%d.%d: device timeout\n", c->board->num, c->num); + + cxdown (c); + for (q=c->slaveq; q; q=q->slaveq) + cxdown (q); + + cxup (c); + for (q=c->slaveq; q; q=q->slaveq) + cxup (q); - if (c->ifp->if_flags & IFF_OACTIVE) { - c->ifp->if_flags &= ~IFF_OACTIVE; cxstart (c->ifp); - } } /* @@ -600,21 +710,26 @@ void cxrinth (cx_chan_t *c) unsigned short port = c->chip->port; unsigned short len, risr = inw (RISR(port)); - print (("cx%d.%d: hdlc receive interrupt, risr=%b, arbsts=%b, brbsts=%b\n", - c->board->num, c->num, risr, RISH_BITS, - inb (ARBSTS(port)), BSTS_BITS, inb (BRBSTS(port)), BSTS_BITS)); - /* Receive errors. */ if (risr & (RIS_BUSERR | RIS_OVERRUN | RISH_CRCERR | RISH_RXABORT)) { if (c->ifp->if_flags & IFF_DEBUG) printf ("cx%d.%d: receive error, risr=%b\n", c->board->num, c->num, risr, RISH_BITS); ++c->ifp->if_ierrors; + ++c->stat->ierrs; if (risr & RIS_OVERRUN) ++c->ifp->if_collisions; } else if (risr & RIS_EOBUF) { + if (c->ifp->if_flags & IFF_DEBUG) + print (("cx%d.%d: hdlc receive interrupt, risr=%b, arbsts=%b, brbsts=%b\n", + c->board->num, c->num, risr, RISH_BITS, + inb (ARBSTS(port)), BSTS_BITS, + inb (BRBSTS(port)), BSTS_BITS)); + ++c->stat->ipkts; + /* Handle received data. */ len = (risr & RIS_BB) ? inw(BRBCNT(port)) : inw(ARBCNT(port)); + c->stat->ibytes += len; if (len > DMABUFSZ) { /* Fatal error: actual DMA transfer size * exceeds our buffer size. It could be caused @@ -633,11 +748,16 @@ void cxrinth (cx_chan_t *c) ++c->ifp->if_ierrors; } else { /* Valid frame received. */ - print (("cx%d.%d: HDLC: %d bytes received\n", + if (c->ifp->if_flags & IFF_DEBUG) + print (("cx%d.%d: hdlc received %d bytes\n", c->board->num, c->num, len)); cxinput (c, (risr & RIS_BB) ? c->brbuf : c->arbuf, len); ++c->ifp->if_ipackets; } + } else if (c->ifp->if_flags & IFF_DEBUG) { + print (("cx%d.%d: unknown hdlc receive interrupt, risr=%b\n", + c->board->num, c->num, risr, RISH_BITS)); + ++c->stat->ierrs; } /* Restart receiver. */ @@ -660,22 +780,35 @@ int cxtinth (cx_chan_t *c) unsigned char tisr = inb (TISR(port)); unsigned char teoir = 0; - print (("cx%d.%d: hdlc transmit interrupt, tisr=%b, atbsts=%b, btbsts=%b\n", - c->board->num, c->num, tisr, TIS_BITS, - inb (ATBSTS(port)), BSTS_BITS, inb (BTBSTS(port)), BSTS_BITS)); + c->ifp->if_flags &= ~IFF_OACTIVE; + if (c->ifp == c->master) + c->ifp->if_timer = 0; if (tisr & (TIS_BUSERR | TIS_UNDERRUN)) { - if (c->ifp->if_flags & IFF_DEBUG) - printf ("cx%d.%d: transmit error, tisr=%b\n", - c->board->num, c->num, tisr, TIS_BITS); + /* if (c->ifp->if_flags & IFF_DEBUG) */ + print (("cx%d.%d: transmit error, tisr=%b, atbsts=%b, btbsts=%b\n", + c->board->num, c->num, tisr, TIS_BITS, + inb (ATBSTS(port)), BSTS_BITS, + inb (BTBSTS(port)), BSTS_BITS)); ++c->ifp->if_oerrors; + ++c->stat->oerrs; + /* Terminate the failed buffer. */ - teoir |= TEOI_TERMBUFF; - } else if (tisr & (TIS_EOFR)) + /* teoir = TEOI_TERMBUFF; */ + } else if (c->ifp->if_flags & IFF_DEBUG) + print (("cx%d.%d: hdlc transmit interrupt, tisr=%b, atbsts=%b, btbsts=%b\n", + c->board->num, c->num, tisr, TIS_BITS, + inb (ATBSTS(port)), BSTS_BITS, + inb (BTBSTS(port)), BSTS_BITS)); + + if (tisr & TIS_EOFR) { ++c->ifp->if_opackets; + ++c->stat->opkts; + } + + /* Start output on the (sub-) channel. */ + cxsend (c); - c->ifp->if_flags &= ~IFF_OACTIVE; - cxstart (c->ifp); return (teoir); } @@ -715,6 +848,7 @@ void cxintr (cx_board_t *b) switch (livr & 3) { case LIV_EXCEP: /* receive exception */ case LIV_RXDATA: /* receive interrupt */ + ++c->stat->rintr; switch (c->mode) { case M_ASYNC: eoi = cxrinta (c); break; case M_HDLC: cxrinth (c); break; @@ -722,6 +856,7 @@ void cxintr (cx_board_t *b) } break; case LIV_TXDATA: /* transmit interrupt */ + ++c->stat->tintr; eoiport = TEOIR(port); switch (c->mode) { case M_ASYNC: cxtinta (c); break; @@ -730,6 +865,7 @@ void cxintr (cx_board_t *b) } break; case LIV_MODEM: /* modem/timer interrupt */ + ++c->stat->mintr; eoiport = MEOIR(port); cxmint (c); break; @@ -746,6 +882,18 @@ void cxintr (cx_board_t *b) /* Exit from interrupt context. */ outb (eoiport, eoi); + + /* Master channel - start output on all idle subchannels. */ + if (c->master == c->ifp && c->slaveq && + (livr & 3) == LIV_TXDATA && c->mode == M_HDLC && + ! sppp_isempty (c->ifp)) { + cx_chan_t *q; + + for (q=c->slaveq; q; q=q->slaveq) + if ((q->ifp->if_flags & IFF_RUNNING) && + ! (q->ifp->if_flags & IFF_OACTIVE)) + cxsend (q); + } } } @@ -763,8 +911,9 @@ void cxinput (cx_chan_t *c, void *buf, unsigned len) ++c->ifp->if_iqdrops; return; } - m->m_pkthdr.rcvif = c->ifp; + m->m_pkthdr.rcvif = c->master; #ifdef DEBUG + if (c->ifp->if_flags & IFF_DEBUG) printmbuf (m); #endif @@ -776,13 +925,18 @@ void cxinput (cx_chan_t *c, void *buf, unsigned len) if (c->bpf) bpf_tap (c->bpf, buf, len); #endif + + /* Count the received bytes to the subchannel, not the master. */ + c->master->if_ibytes -= len + 3; + c->ifp->if_ibytes += len + 3; + #ifdef __bsdi__ if (c->sopt.ext) { - struct p2pcom *p = (struct p2pcom*) c->ifp; + struct p2pcom *p = (struct p2pcom*) c->master; (*p->p2p_input) (p, m); } else #endif - sppp_input (c->ifp, m); + sppp_input (c->master, m); } void cxswitch (cx_chan_t *c, cx_soft_opt_t new) diff --git a/sys/net/if_sppp.h b/sys/net/if_sppp.h index c915977..5a4d173 100644 --- a/sys/net/if_sppp.h +++ b/sys/net/if_sppp.h @@ -11,7 +11,7 @@ * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * - * Version 1.1, Thu Oct 27 21:15:02 MSK 1994 + * Version 1.7, Wed Jun 7 22:12:02 MSD 1995 */ #ifndef _NET_IF_HDLC_H_ @@ -20,12 +20,13 @@ struct slcp { u_short state; /* state machine */ u_long magic; /* local magic number */ - u_long rmagic; /* remote magic number */ - u_char lastid; /* id of last keepalive echo request */ + u_char echoid; /* id of last keepalive echo request */ + u_char confid; /* id of last configuration request */ }; struct sipcp { u_short state; /* state machine */ + u_char confid; /* id of last configuration request */ }; struct sppp { @@ -43,6 +44,7 @@ struct sppp { #define PP_KEEPALIVE 0x01 /* use keepalive protocol */ #define PP_CISCO 0x02 /* use Cisco protocol instead of PPP */ +#define PP_TIMO 0x04 /* cp_timeout routine active */ #define PP_MTU 1500 /* max. transmit unit */ @@ -62,8 +64,9 @@ void sppp_detach (struct ifnet *ifp); void sppp_input (struct ifnet *ifp, struct mbuf *m); int sppp_output (struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt); -int sppp_ioctl (struct ifnet *ifp, int cmd, caddr_t data); +int sppp_ioctl (struct ifnet *ifp, int cmd, void *data); struct mbuf *sppp_dequeue (struct ifnet *ifp); +int sppp_isempty (struct ifnet *ifp); void sppp_flush (struct ifnet *ifp); #endif diff --git a/sys/net/if_spppsubr.c b/sys/net/if_spppsubr.c index 38b60ca..e8a9576 100644 --- a/sys/net/if_spppsubr.c +++ b/sys/net/if_spppsubr.c @@ -12,7 +12,7 @@ * or modify this software as long as this message is kept with the software, * all derivative works or modified versions. * - * Version 1.1, Thu Oct 27 21:13:59 MSK 1994 + * Version 1.9, Wed Oct 4 18:58:15 MSK 1995 */ #undef DEBUG @@ -53,7 +53,7 @@ #ifdef DEBUG #define print(s) printf s #else -#define print(s) /*void*/ +#define print(s) {/*void*/} #endif #define MAXALIVECNT 3 /* max. alive packets */ @@ -103,26 +103,26 @@ #define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ struct ppp_header { - unsigned char address; - unsigned char control; - unsigned short protocol; + u_char address; + u_char control; + u_short protocol; }; #define PPP_HEADER_LEN sizeof (struct ppp_header) struct lcp_header { - unsigned char type; - unsigned char ident; - unsigned short len; + u_char type; + u_char ident; + u_short len; }; #define LCP_HEADER_LEN sizeof (struct lcp_header) struct cisco_packet { - unsigned long type; - unsigned long par1; - unsigned long par2; - unsigned short rel; - unsigned short time0; - unsigned short time1; + u_long type; + u_long par1; + u_long par2; + u_short rel; + u_short time0; + u_short time1; }; #define CISCO_PACKET_LEN 18 @@ -134,27 +134,37 @@ struct sppp *spppq; * priority queue. To decide if traffic is interactive, we check that * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control. */ -static unsigned short interactive_ports[8] = { +static u_short interactive_ports[8] = { 0, 513, 0, 0, 0, 21, 0, 23, }; #define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p)) -void sppp_keepalive (void *dummy1); -void sppp_cp_send (struct sppp *sp, unsigned short proto, unsigned char type, - unsigned char ident, unsigned short len, void *data); +/* + * Timeout routine activation macros. + */ +#define TIMO(p,s) if (! ((p)->pp_flags & PP_TIMO)) { \ + timeout (sppp_cp_timeout, (void*) (p), (s)*hz); \ + (p)->pp_flags |= PP_TIMO; } +#define UNTIMO(p) if ((p)->pp_flags & PP_TIMO) { \ + untimeout (sppp_cp_timeout, (void*) (p)); \ + (p)->pp_flags &= ~PP_TIMO; } + +void sppp_keepalive (void *dummy); +void sppp_cp_send (struct sppp *sp, u_short proto, u_char type, + u_char ident, u_short len, void *data); void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2); void sppp_lcp_input (struct sppp *sp, struct mbuf *m); void sppp_cisco_input (struct sppp *sp, struct mbuf *m); -void sppp_lcp_conf_rej (struct sppp *sp, struct lcp_header *h); void sppp_ipcp_input (struct sppp *sp, struct mbuf *m); void sppp_lcp_open (struct sppp *sp); void sppp_ipcp_open (struct sppp *sp); -int sppp_lcp_conf_unknown_options (int len, unsigned char *p); +int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, + int len, u_long *magic); void sppp_cp_timeout (void *arg); -char *sppp_lcp_type_name (unsigned char type); -char *sppp_ipcp_type_name (unsigned char type); -void sppp_print_bytes (unsigned char *p, unsigned short len); +char *sppp_lcp_type_name (u_char type); +char *sppp_ipcp_type_name (u_char type); +void sppp_print_bytes (u_char *p, u_short len); /* * Flush interface queue. @@ -179,8 +189,9 @@ static void qflush (struct ifqueue *ifq) void sppp_input (struct ifnet *ifp, struct mbuf *m) { struct ppp_header *h; - struct sppp *sp; + struct sppp *sp = (struct sppp*) ifp; struct ifqueue *inq = 0; + int s; ifp->if_lastchange = time; if (ifp->if_flags & IFF_UP) @@ -211,12 +222,18 @@ invalid: if (ifp->if_flags & IFF_DEBUG) case PPP_ALLSTATIONS: if (h->control != PPP_UI) goto invalid; - sp = (struct sppp*) ifp; + if (sp->pp_flags & PP_CISCO) { + if (ifp->if_flags & IFF_DEBUG) + printf ("%s%d: PPP packet in Cisco mode <0x%x 0x%x 0x%x>\n", + ifp->if_name, ifp->if_unit, + h->address, h->control, ntohs (h->protocol)); + goto drop; + } switch (ntohs (h->protocol)) { default: if (sp->lcp.state == LCP_STATE_OPENED) sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ, - ++sp->pp_seq, m->m_pkthdr.len - 2, + ++sp->pp_seq, m->m_pkthdr.len + 2, &h->protocol); if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: invalid input protocol <0x%x 0x%x 0x%x>\n", @@ -264,6 +281,13 @@ invalid: if (ifp->if_flags & IFF_DEBUG) case CISCO_MULTICAST: case CISCO_UNICAST: /* Don't check the control field here (RFC 1547). */ + if (! (sp->pp_flags & PP_CISCO)) { + if (ifp->if_flags & IFF_DEBUG) + printf ("%s%d: Cisco packet in PPP mode <0x%x 0x%x 0x%x>\n", + ifp->if_name, ifp->if_unit, + h->address, h->control, ntohs (h->protocol)); + goto drop; + } switch (ntohs (h->protocol)) { default: ++ifp->if_noproto; @@ -292,15 +316,18 @@ invalid: if (ifp->if_flags & IFF_DEBUG) goto drop; /* Check queue. */ + s = splimp (); if (IF_QFULL (inq)) { /* Queue overflow. */ + IF_DROP (inq); + splx (s); if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: protocol queue overflow\n", ifp->if_name, ifp->if_unit); - IF_DROP (inq); goto drop; } IF_ENQUEUE (inq, m); + splx (s); } /* @@ -361,8 +388,15 @@ int sppp_output (struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct switch (dst->sa_family) { #ifdef INET case AF_INET: /* Internet Protocol */ - h->protocol = htons ((sp->pp_flags & PP_CISCO) ? - ETHERTYPE_IP : PPP_IP); + if (sp->pp_flags & PP_CISCO) + h->protocol = htons (ETHERTYPE_IP); + else if (sp->ipcp.state == IPCP_STATE_OPENED) + h->protocol = htons (PPP_IP); + else { + m_freem (m); + splx (s); + return (ENETDOWN); + } break; #endif #ifdef NS @@ -416,7 +450,7 @@ void sppp_attach (struct ifnet *ifp) /* Initialize keepalive handler. */ if (! spppq) - timeout (sppp_keepalive, (void *)0, hz * 10); + timeout (sppp_keepalive, 0, hz * 10); /* Insert new entry into the keepalive list. */ sp->pp_next = spppq; @@ -427,10 +461,11 @@ void sppp_attach (struct ifnet *ifp) sp->pp_fastq.ifq_maxlen = 32; sp->pp_loopcnt = 0; sp->pp_alivecnt = 0; - sp->lcp.magic = time.tv_sec + time.tv_usec; - sp->lcp.rmagic = 0; - sp->pp_seq = sp->lcp.magic; + sp->pp_seq = 0; sp->pp_rseq = 0; + sp->lcp.magic = 0; + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; } void sppp_detach (struct ifnet *ifp) @@ -446,8 +481,8 @@ void sppp_detach (struct ifnet *ifp) /* Stop keepalive handler. */ if (! spppq) - untimeout (sppp_keepalive, (void *)0); - untimeout (sppp_cp_timeout, (void *)sp); + untimeout (sppp_keepalive, 0); + UNTIMO (sp); } /* @@ -462,6 +497,19 @@ void sppp_flush (struct ifnet *ifp) } /* + * Check if the output queue is empty. + */ +int sppp_isempty (struct ifnet *ifp) +{ + struct sppp *sp = (struct sppp*) ifp; + int empty, s = splimp (); + + empty = !sp->pp_fastq.ifq_head && !sp->pp_if.if_snd.ifq_head; + splx (s); + return (empty); +} + +/* * Get next packet to send. */ struct mbuf *sppp_dequeue (struct ifnet *ifp) @@ -480,8 +528,7 @@ struct mbuf *sppp_dequeue (struct ifnet *ifp) /* * Send keepalive packets, every 10 seconds. */ -void -sppp_keepalive (void *dummy1) +void sppp_keepalive (void *dummy) { struct sppp *sp; int s = splimp (); @@ -489,8 +536,13 @@ sppp_keepalive (void *dummy1) for (sp=spppq; sp; sp=sp->pp_next) { struct ifnet *ifp = &sp->pp_if; + /* Keepalive mode disabled or channel down? */ if (! (sp->pp_flags & PP_KEEPALIVE) || - ! (ifp->if_flags & IFF_RUNNING) || + ! (ifp->if_flags & IFF_RUNNING)) + continue; + + /* No keepalive in PPP mode if LCP not opened yet. */ + if (! (sp->pp_flags & PP_CISCO) && sp->lcp.state != LCP_STATE_OPENED) continue; @@ -499,10 +551,15 @@ sppp_keepalive (void *dummy1) printf ("%s%d: down\n", ifp->if_name, ifp->if_unit); if_down (ifp); qflush (&sp->pp_fastq); + if (! (sp->pp_flags & PP_CISCO)) { + /* Shut down the PPP link. */ + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + UNTIMO (sp); + /* Initiate negotiation. */ + sppp_lcp_open (sp); + } } - if (sp->pp_loopcnt >= MAXALIVECNT) - printf ("%s%d: loopback\n", ifp->if_name, ifp->if_unit); - if (sp->pp_alivecnt <= MAXALIVECNT) ++sp->pp_alivecnt; if (sp->pp_flags & PP_CISCO) @@ -510,13 +567,13 @@ sppp_keepalive (void *dummy1) sp->pp_rseq); else if (sp->lcp.state == LCP_STATE_OPENED) { long nmagic = htonl (sp->lcp.magic); - sp->lcp.lastid = ++sp->pp_seq; + sp->lcp.echoid = ++sp->pp_seq; sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ, - sp->lcp.lastid, 4, &nmagic); + sp->lcp.echoid, 4, &nmagic); } } splx (s); - timeout (sppp_keepalive, (void *)0, hz * 10); + timeout (sppp_keepalive, 0, hz * 10); } /* @@ -527,7 +584,8 @@ void sppp_lcp_input (struct sppp *sp, struct mbuf *m) struct lcp_header *h; struct ifnet *ifp = &sp->pp_if; int len = m->m_pkthdr.len; - unsigned char *p; + u_char *p, opt[6]; + u_long rmagic; if (len < 4) { if (ifp->if_flags & IFF_DEBUG) @@ -537,11 +595,18 @@ void sppp_lcp_input (struct sppp *sp, struct mbuf *m) } h = mtod (m, struct lcp_header*); if (ifp->if_flags & IFF_DEBUG) { - printf ("%s%d: lcp input: %d bytes <%s id=%xh len=%xh", - ifp->if_name, ifp->if_unit, len, + char state = '?'; + switch (sp->lcp.state) { + case LCP_STATE_CLOSED: state = 'C'; break; + case LCP_STATE_ACK_RCVD: state = 'R'; break; + case LCP_STATE_ACK_SENT: state = 'S'; break; + case LCP_STATE_OPENED: state = 'O'; break; + } + printf ("%s%d: lcp input(%c): %d bytes <%s id=%xh len=%xh", + ifp->if_name, ifp->if_unit, state, len, sppp_lcp_type_name (h->type), h->ident, ntohs (h->len)); if (len > 4) - sppp_print_bytes ((unsigned char*) (h+1), len-4); + sppp_print_bytes ((u_char*) (h+1), len-4); printf (">\n"); } if (len > ntohs (h->len)) @@ -549,107 +614,128 @@ void sppp_lcp_input (struct sppp *sp, struct mbuf *m) switch (h->type) { default: /* Unknown packet type -- send Code-Reject packet. */ - sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq, len, h); + sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq, + m->m_pkthdr.len, h); break; case LCP_CONF_REQ: if (len < 4) { if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: invalid lcp configure request packet length: %d bytes\n", ifp->if_name, ifp->if_unit, len); - return; + break; } - if (len>4 && sppp_lcp_conf_unknown_options (len-4, (unsigned char*) (h+1))) { - sppp_lcp_conf_rej (sp, h); - if (sp->lcp.state == LCP_STATE_OPENED) + if (len>4 && !sppp_lcp_conf_parse_options (sp, h, len, &rmagic)) + goto badreq; + if (rmagic == sp->lcp.magic) { + /* Local and remote magics equal -- loopback? */ + if (sp->pp_loopcnt >= MAXALIVECNT*5) { + printf ("%s%d: loopback\n", + ifp->if_name, ifp->if_unit); + sp->pp_loopcnt = 0; + if (ifp->if_flags & IFF_UP) { + if_down (ifp); + qflush (&sp->pp_fastq); + } + } else if (ifp->if_flags & IFF_DEBUG) + printf ("%s%d: conf req: magic glitch\n", + ifp->if_name, ifp->if_unit); + ++sp->pp_loopcnt; + + /* MUST send Conf-Nack packet. */ + rmagic = ~sp->lcp.magic; + opt[0] = LCP_OPT_MAGIC; + opt[1] = sizeof (opt); + opt[2] = rmagic >> 24; + opt[3] = rmagic >> 16; + opt[4] = rmagic >> 8; + opt[5] = rmagic; + sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK, + h->ident, sizeof (opt), &opt); +badreq: + switch (sp->lcp.state) { + case LCP_STATE_OPENED: /* Initiate renegotiation. */ sppp_lcp_open (sp); - if (sp->lcp.state != LCP_STATE_ACK_RCVD) { + /* fall through... */ + case LCP_STATE_ACK_SENT: /* Go to closed state. */ sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; } - } else { - /* Extract remote magic number. */ - p = (unsigned char*) (h+1); - if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) - sp->lcp.rmagic = (unsigned long)p[2] << 24 | - (unsigned long)p[3] << 16 | - p[4] << 8 | p[5]; - if (sp->lcp.rmagic == sp->lcp.magic) { - /* Local and remote magics are equal -- loop? */ - sp->lcp.rmagic = ~sp->lcp.magic; - /* Send Configure-Nack packet. */ - p[2] = sp->lcp.rmagic >> 24; - p[3] = sp->lcp.rmagic >> 16; - p[4] = sp->lcp.rmagic >> 8; - p[5] = sp->lcp.rmagic; - sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK, - h->ident, len-4, h+1); - if (sp->lcp.state != LCP_STATE_ACK_RCVD) { - /* Go to closed state. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; + break; } - } else { /* Send Configure-Ack packet. */ sp->pp_loopcnt = 0; sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK, h->ident, len-4, h+1); - if (sp->lcp.state == LCP_STATE_OPENED) - /* Initiate renegotiation. */ - sppp_lcp_open (sp); /* Change the state. */ - if (sp->lcp.state == LCP_STATE_ACK_RCVD) { + switch (sp->lcp.state) { + case LCP_STATE_CLOSED: + sp->lcp.state = LCP_STATE_ACK_SENT; + break; + case LCP_STATE_ACK_RCVD: sp->lcp.state = LCP_STATE_OPENED; sppp_ipcp_open (sp); - } else - sp->lcp.state = LCP_STATE_ACK_SENT; - } + break; + case LCP_STATE_OPENED: + /* Remote magic changed -- close session. */ + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + /* Initiate renegotiation. */ + sppp_lcp_open (sp); + break; } break; case LCP_CONF_ACK: - if (h->ident != sp->pp_seq) - return; - untimeout (sppp_cp_timeout, (void *)sp); + if (h->ident != sp->lcp.confid) + break; + UNTIMO (sp); + if (! (ifp->if_flags & IFF_UP) && + (ifp->if_flags & IFF_RUNNING)) { + /* Coming out of loopback mode. */ + ifp->if_flags |= IFF_UP; + printf ("%s%d: up\n", ifp->if_name, ifp->if_unit); + } switch (sp->lcp.state) { case LCP_STATE_CLOSED: sp->lcp.state = LCP_STATE_ACK_RCVD; + TIMO (sp, 5); break; case LCP_STATE_ACK_SENT: sp->lcp.state = LCP_STATE_OPENED; sppp_ipcp_open (sp); break; - case LCP_STATE_ACK_RCVD: - case LCP_STATE_OPENED: - /* Initiate renegotiation. */ - sppp_lcp_open (sp); - /* Go to closed state. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - break; } break; case LCP_CONF_NAK: - if (h->ident != sp->pp_seq) - return; - p = (unsigned char*) (h+1); + if (h->ident != sp->lcp.confid) + break; + p = (u_char*) (h+1); if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) { - sp->lcp.rmagic = (unsigned long)p[2] << 24 | - (unsigned long)p[3] << 16 | - p[4] << 8 | p[5]; - if (sp->lcp.rmagic == ~sp->lcp.magic) { + rmagic = (u_long)p[2] << 24 | + (u_long)p[3] << 16 | p[4] << 8 | p[5]; + if (rmagic == ~sp->lcp.magic) { if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: conf nak: magic glitch\n", ifp->if_name, ifp->if_unit); - ++sp->pp_loopcnt; - sp->lcp.magic = time.tv_sec + time.tv_usec; + sp->lcp.magic += time.tv_sec + time.tv_usec; + } else + sp->lcp.magic = rmagic; } + if (sp->lcp.state != LCP_STATE_ACK_SENT) { + /* Go to closed state. */ + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; } - /* Fall through. */ + /* The link will be renegotiated after timeout, + * to avoid endless req-nack loop. */ + UNTIMO (sp); + TIMO (sp, 2); + break; case LCP_CONF_REJ: - if (h->ident != sp->pp_seq) - return; - untimeout (sppp_cp_timeout, (void *)sp); + if (h->ident != sp->lcp.confid) + break; + UNTIMO (sp); /* Initiate renegotiation. */ sppp_lcp_open (sp); if (sp->lcp.state != LCP_STATE_ACK_SENT) { @@ -659,27 +745,16 @@ void sppp_lcp_input (struct sppp *sp, struct mbuf *m) } break; case LCP_TERM_REQ: + UNTIMO (sp); /* Send Terminate-Ack packet. */ sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, 0); - if (sp->lcp.state == LCP_STATE_OPENED) - /* Initiate renegotiation. */ - sppp_lcp_open (sp); /* Go to closed state. */ sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; - break; - case LCP_TERM_ACK: - if (h->ident != sp->pp_seq) - return; - if (sp->lcp.state == LCP_STATE_OPENED) /* Initiate renegotiation. */ sppp_lcp_open (sp); - if (sp->lcp.state != LCP_STATE_ACK_SENT) { - /* Go to closed state. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - } break; + case LCP_TERM_ACK: case LCP_CODE_REJ: case LCP_PROTO_REJ: /* Ignore for now. */ @@ -692,33 +767,35 @@ void sppp_lcp_input (struct sppp *sp, struct mbuf *m) if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: invalid lcp echo request packet length: %d bytes\n", ifp->if_name, ifp->if_unit, len); - return; + break; } if (ntohl (*(long*)(h+1)) == sp->lcp.magic) { - if (ifp->if_flags & IFF_DEBUG) - printf ("%s%d: echo reply: magic glitch\n", - ifp->if_name, ifp->if_unit); - ++sp->pp_loopcnt; + /* Line loopback mode detected. */ + printf ("%s%d: loopback\n", ifp->if_name, ifp->if_unit); + if_down (ifp); + qflush (&sp->pp_fastq); + + /* Shut down the PPP link. */ + sp->lcp.state = LCP_STATE_CLOSED; + sp->ipcp.state = IPCP_STATE_CLOSED; + UNTIMO (sp); + /* Initiate negotiation. */ + sppp_lcp_open (sp); + break; } *(long*)(h+1) = htonl (sp->lcp.magic); sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1); break; case LCP_ECHO_REPLY: - if (h->ident != sp->lcp.lastid) - return; + if (h->ident != sp->lcp.echoid) + break; if (len < 8) { if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: invalid lcp echo reply packet length: %d bytes\n", ifp->if_name, ifp->if_unit, len); - return; - } - if (ntohl (*(long*)(h+1)) == sp->lcp.magic) - return; - if (! (ifp->if_flags & IFF_UP) && - (ifp->if_flags & IFF_RUNNING)) { - ifp->if_flags |= IFF_UP; - printf ("%s%d: up\n", ifp->if_name, ifp->if_unit); + break; } + if (ntohl (*(long*)(h+1)) != sp->lcp.magic) sp->pp_alivecnt = 0; break; } @@ -741,8 +818,7 @@ void sppp_cisco_input (struct sppp *sp, struct mbuf *m) } h = mtod (m, struct cisco_packet*); if (ifp->if_flags & IFF_DEBUG) - printf ("%s%d: cisco input: %d bytes " - "<%lxh %lxh %lxh %xh %xh-%xh>\n", + printf ("%s%d: cisco input: %d bytes <%lxh %lxh %lxh %xh %xh-%xh>\n", ifp->if_name, ifp->if_unit, m->m_pkthdr.len, ntohl (h->type), h->par1, h->par2, h->rel, h->time0, h->time1); @@ -756,22 +832,32 @@ void sppp_cisco_input (struct sppp *sp, struct mbuf *m) /* Reply on address request, ignore */ break; case CISCO_KEEPALIVE_REQ: - if (! (ifp->if_flags & IFF_UP) && - (ifp->if_flags & IFF_RUNNING)) { - ifp->if_flags |= IFF_UP; - printf ("%s%d: up\n", ifp->if_name, ifp->if_unit); - } sp->pp_alivecnt = 0; sp->pp_rseq = ntohl (h->par1); if (sp->pp_seq == sp->pp_rseq) { /* Local and remote sequence numbers are equal. * Probably, the line is in loopback mode. */ + if (sp->pp_loopcnt >= MAXALIVECNT) { + printf ("%s%d: loopback\n", + ifp->if_name, ifp->if_unit); + sp->pp_loopcnt = 0; + if (ifp->if_flags & IFF_UP) { + if_down (ifp); + qflush (&sp->pp_fastq); + } + } ++sp->pp_loopcnt; /* Generate new local sequence number */ sp->pp_seq ^= time.tv_sec ^ time.tv_usec; - } else + break; + } sp->pp_loopcnt = 0; + if (! (ifp->if_flags & IFF_UP) && + (ifp->if_flags & IFF_RUNNING)) { + ifp->if_flags |= IFF_UP; + printf ("%s%d: up\n", ifp->if_name, ifp->if_unit); + } break; case CISCO_ADDR_REQ: for (ifa=ifp->if_addrlist; ifa; ifa=ifa->ifa_next) @@ -793,8 +879,8 @@ void sppp_cisco_input (struct sppp *sp, struct mbuf *m) /* * Send PPP LCP packet. */ -void sppp_cp_send (struct sppp *sp, unsigned short proto, unsigned char type, - unsigned char ident, unsigned short len, void *data) +void sppp_cp_send (struct sppp *sp, u_short proto, u_char type, + u_char ident, u_short len, void *data) { struct ppp_header *h; struct lcp_header *lh; @@ -829,7 +915,7 @@ void sppp_cp_send (struct sppp *sp, unsigned short proto, unsigned char type, sppp_ipcp_type_name (lh->type), lh->ident, ntohs (lh->len)); if (len) - sppp_print_bytes ((unsigned char*) (lh+1), len); + sppp_print_bytes ((u_char*) (lh+1), len); printf (">\n"); } if (IF_QFULL (&sp->pp_fastq)) { @@ -851,7 +937,7 @@ void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2) struct cisco_packet *ch; struct mbuf *m; struct ifnet *ifp = &sp->pp_if; - unsigned long t = (time.tv_sec - boottime.tv_sec) * 1000; + u_long t = (time.tv_sec - boottime.tv_sec) * 1000; MGETHDR (m, M_DONTWAIT, MT_DATA); if (! m) @@ -869,8 +955,8 @@ void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2) ch->par1 = htonl (par1); ch->par2 = htonl (par2); ch->rel = -1; - ch->time0 = htons ((unsigned short) (t >> 16)); - ch->time1 = htons ((unsigned short) t); + ch->time0 = htons ((u_short) (t >> 16)); + ch->time1 = htons ((u_short) t); if (ifp->if_flags & IFF_DEBUG) printf ("%s%d: cisco output: <%lxh %lxh %lxh %xh %xh-%xh>\n", @@ -890,35 +976,42 @@ void sppp_cisco_send (struct sppp *sp, int type, long par1, long par2) /* * Process an ioctl request. Called on low priority level. */ -int sppp_ioctl (struct ifnet *ifp, int cmd, caddr_t data) +int sppp_ioctl (struct ifnet *ifp, int cmd, void *data) { struct ifreq *ifr = (struct ifreq*) data; - struct sppp *sp; - int s; + struct sppp *sp = (struct sppp*) ifp; + int s, going_up, going_down; switch (cmd) { default: return (EINVAL); - case SIOCSIFADDR: case SIOCAIFADDR: case SIOCSIFDSTADDR: break; + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + /* fall through... */ + case SIOCSIFFLAGS: + if (sp->pp_flags & PP_CISCO) + break; s = splimp (); - if (! (ifp->if_flags & IFF_UP) && (ifp->if_flags & IFF_RUNNING)) { - /* Interface is stopping. */ - sp = (struct sppp*) ifp; - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - sppp_cp_send (sp, PPP_LCP, LCP_TERM_REQ, ++sp->pp_seq, - 0, 0); - } else if ((ifp->if_flags & IFF_UP) && ! (ifp->if_flags & IFF_RUNNING)) { - /* Interface is starting. */ - sp = (struct sppp*) ifp; + going_up = (ifp->if_flags & IFF_UP) && + ! (ifp->if_flags & IFF_RUNNING); + going_down = ! (ifp->if_flags & IFF_UP) && + (ifp->if_flags & IFF_RUNNING); + if (going_up || going_down) { + /* Shut down the PPP link. */ + ifp->if_flags &= ~IFF_RUNNING; sp->lcp.state = LCP_STATE_CLOSED; sp->ipcp.state = IPCP_STATE_CLOSED; + UNTIMO (sp); + } + if (going_up) { + /* Interface is starting -- initiate negotiation. */ + ifp->if_flags |= IFF_RUNNING; sppp_lcp_open (sp); } splx (s); @@ -960,35 +1053,56 @@ int sppp_ioctl (struct ifnet *ifp, int cmd, caddr_t data) return (0); } -int sppp_lcp_conf_unknown_options (int len, unsigned char *p) -{ - /* Analyze the LCP Configure-Request options list - * for the presence of unknown options. */ - while (len > 0) { - if (*p != LCP_OPT_MAGIC) - return (1); - len -= p[1]; - p += p[1]; - } - return (0); -} - -void sppp_lcp_conf_rej (struct sppp *sp, struct lcp_header *h) +/* + * Analyze the LCP Configure-Request options list + * for the presence of unknown options. + * If the request contains unknown options, build and + * send Configure-reject packet, containing only unknown options. + */ +int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, + int len, u_long *magic) { - /* The LCP Configure-Request contains unknown options. - * Send Configure-reject packet, containing only unknown options. */ - unsigned char buf [PP_MTU], *r = buf, *p = (void*) (h+1); - unsigned rlen = 0, len = h->len - 4; - - while (len > 0) { - if (*p != LCP_OPT_MAGIC) { + u_char *buf, *r, *p; + int rlen; + + len -= 4; + buf = r = malloc (len, M_TEMP, M_NOWAIT); + if (! buf) + return (0); + + p = (void*) (h+1); + for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { + switch (*p) { + case LCP_OPT_MAGIC: + /* Magic number -- extract. */ + if (len >= 6 && p[1] == 6) { + *magic = (u_long)p[2] << 24 | + (u_long)p[3] << 16 | p[4] << 8 | p[5]; + continue; + } + break; + case LCP_OPT_ASYNC_MAP: + /* Async control character map -- check to be zero. */ + if (len >= 6 && p[1] == 6 && ! p[2] && ! p[3] && + ! p[4] && ! p[5]) + continue; + break; + case LCP_OPT_MRU: + /* Maximum receive unit -- always OK. */ + continue; + default: + /* Others not supported. */ + break; + } + /* Add the option to rejected list. */ bcopy (p, r, p[1]); r += p[1]; + rlen += p[1]; } - len -= p[1]; - p += p[1]; - } + if (rlen) sppp_cp_send (sp, PPP_LCP, LCP_CONF_REJ, h->ident, rlen, buf); + free (buf, M_TEMP); + return (rlen == 0); } void sppp_ipcp_input (struct sppp *sp, struct mbuf *m) @@ -1009,7 +1123,7 @@ void sppp_ipcp_input (struct sppp *sp, struct mbuf *m) ifp->if_name, ifp->if_unit, len, sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len)); if (len > 4) - sppp_print_bytes ((unsigned char*) (h+1), len-4); + sppp_print_bytes ((u_char*) (h+1), len-4); printf (">\n"); } if (len > ntohs (h->len)) @@ -1029,51 +1143,46 @@ void sppp_ipcp_input (struct sppp *sp, struct mbuf *m) if (len > 4) { sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident, len-4, h+1); - if (sp->lcp.state == LCP_STATE_OPENED && - sp->ipcp.state == IPCP_STATE_OPENED) + + switch (sp->ipcp.state) { + case IPCP_STATE_OPENED: /* Initiate renegotiation. */ sppp_ipcp_open (sp); - if (sp->ipcp.state != IPCP_STATE_ACK_RCVD) + /* fall through... */ + case IPCP_STATE_ACK_SENT: /* Go to closed state. */ sp->ipcp.state = IPCP_STATE_CLOSED; + } } else { /* Send Configure-Ack packet. */ sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident, 0, 0); - if (sp->lcp.state == LCP_STATE_OPENED && - sp->ipcp.state == IPCP_STATE_OPENED) - /* Initiate renegotiation. */ - sppp_ipcp_open (sp); /* Change the state. */ - sp->ipcp.state = (sp->ipcp.state == IPCP_STATE_ACK_RCVD) ? - IPCP_STATE_OPENED : IPCP_STATE_ACK_SENT; + if (sp->ipcp.state == IPCP_STATE_ACK_RCVD) + sp->ipcp.state = IPCP_STATE_OPENED; + else + sp->ipcp.state = IPCP_STATE_ACK_SENT; } break; case IPCP_CONF_ACK: - untimeout (sppp_cp_timeout, (void *)sp); + if (h->ident != sp->ipcp.confid) + break; + UNTIMO (sp); switch (sp->ipcp.state) { case IPCP_STATE_CLOSED: sp->ipcp.state = IPCP_STATE_ACK_RCVD; + TIMO (sp, 5); break; case IPCP_STATE_ACK_SENT: sp->ipcp.state = IPCP_STATE_OPENED; break; - case IPCP_STATE_ACK_RCVD: - case IPCP_STATE_OPENED: - if (sp->lcp.state == LCP_STATE_OPENED) - /* Initiate renegotiation. */ - sppp_ipcp_open (sp); - /* Go to closed state. */ - sp->ipcp.state = IPCP_STATE_CLOSED; - break; } break; case IPCP_CONF_NAK: case IPCP_CONF_REJ: - untimeout (sppp_cp_timeout, (void *)sp); - /* Initiate renegotiation. */ - sppp_ipcp_open (sp); - if (sp->lcp.state == LCP_STATE_OPENED) + if (h->ident != sp->ipcp.confid) + break; + UNTIMO (sp); /* Initiate renegotiation. */ sppp_ipcp_open (sp); if (sp->ipcp.state != IPCP_STATE_ACK_SENT) @@ -1083,22 +1192,13 @@ void sppp_ipcp_input (struct sppp *sp, struct mbuf *m) case IPCP_TERM_REQ: /* Send Terminate-Ack packet. */ sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, 0); - if (sp->lcp.state == LCP_STATE_OPENED && - sp->ipcp.state == IPCP_STATE_OPENED) - /* Initiate renegotiation. */ - sppp_ipcp_open (sp); /* Go to closed state. */ sp->ipcp.state = IPCP_STATE_CLOSED; - break; - case IPCP_TERM_ACK: - if (sp->lcp.state == LCP_STATE_OPENED && - sp->ipcp.state == IPCP_STATE_OPENED) /* Initiate renegotiation. */ sppp_ipcp_open (sp); - if (sp->ipcp.state != IPCP_STATE_ACK_SENT) - /* Go to closed state. */ - sp->ipcp.state = IPCP_STATE_CLOSED; break; + case IPCP_TERM_ACK: + /* Ignore for now. */ case IPCP_CODE_REJ: /* Ignore for now. */ break; @@ -1109,7 +1209,7 @@ void sppp_lcp_open (struct sppp *sp) { char opt[6]; - /* Make new magic number. */ + if (! sp->lcp.magic) sp->lcp.magic = time.tv_sec + time.tv_usec; opt[0] = LCP_OPT_MAGIC; opt[1] = sizeof (opt); @@ -1117,27 +1217,32 @@ void sppp_lcp_open (struct sppp *sp) opt[3] = sp->lcp.magic >> 16; opt[4] = sp->lcp.magic >> 8; opt[5] = sp->lcp.magic; - sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, ++sp->pp_seq, + sp->lcp.confid = ++sp->pp_seq; + sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, sp->lcp.confid, sizeof (opt), &opt); - timeout (sppp_cp_timeout, (void *)sp, hz * 5); + TIMO (sp, 2); } void sppp_ipcp_open (struct sppp *sp) { - sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, ++sp->pp_seq, 0, 0); - timeout (sppp_cp_timeout, (void *)sp, hz * 5); + sp->ipcp.confid = ++sp->pp_seq; + sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, 0); + TIMO (sp, 2); } /* * Process PPP control protocol timeouts. */ -void -sppp_cp_timeout (void * arg) +void sppp_cp_timeout (void *arg) { struct sppp *sp = (struct sppp*) arg; - struct ifnet *ifp = &sp->pp_if; int s = splimp (); + sp->pp_flags &= ~PP_TIMO; + if (! (sp->pp_if.if_flags & IFF_RUNNING) || (sp->pp_flags & PP_CISCO)) { + splx (s); + return; + } switch (sp->lcp.state) { case LCP_STATE_CLOSED: /* No ACK for Configure-Request, retry. */ @@ -1177,7 +1282,7 @@ sppp_cp_timeout (void * arg) splx (s); } -char *sppp_lcp_type_name (unsigned char type) +char *sppp_lcp_type_name (u_char type) { static char buf [8]; switch (type) { @@ -1197,7 +1302,7 @@ char *sppp_lcp_type_name (unsigned char type) return (buf); } -char *sppp_ipcp_type_name (unsigned char type) +char *sppp_ipcp_type_name (u_char type) { static char buf [8]; switch (type) { @@ -1213,7 +1318,7 @@ char *sppp_ipcp_type_name (unsigned char type) return (buf); } -void sppp_print_bytes (unsigned char *p, unsigned short len) +void sppp_print_bytes (u_char *p, u_short len) { printf (" %x", *p++); while (--len > 0) |