summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjkh <jkh@FreeBSD.org>1995-10-04 22:24:16 +0000
committerjkh <jkh@FreeBSD.org>1995-10-04 22:24:16 +0000
commit8a1fa70dc0da9908f692ff6de5fe8ca9cad9f310 (patch)
tree2fe87f819c9da98ccb878d0641f4b626f15c348d
parent1c1ef85e1307f05f0ae122e54088a9f8e7425ef7 (diff)
downloadFreeBSD-src-8a1fa70dc0da9908f692ff6de5fe8ca9cad9f310.zip
FreeBSD-src-8a1fa70dc0da9908f692ff6de5fe8ca9cad9f310.tar.gz
This upgrades the driver for Cronyx-Sigma multiplexor boards
from version 1.2 to version 1.9. Submitted by: Serge Vakulenko, <vak@cronyx.ru>
-rw-r--r--sbin/cxconfig/cxconfig.c68
-rw-r--r--sbin/i386/cxconfig/cxconfig.c68
-rw-r--r--sys/i386/include/cronyx.h22
-rw-r--r--sys/i386/isa/cronyx.c49
-rw-r--r--sys/i386/isa/cx.c127
-rw-r--r--sys/i386/isa/if_cx.c304
-rw-r--r--sys/net/if_sppp.h11
-rw-r--r--sys/net/if_spppsubr.c569
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)
OpenPOWER on IntegriCloud