This upgrades the driver for Cronyx-Sigma multiplexor boards

from version 1.2 to version 1.9.
Submitted by:	Serge Vakulenko, <vak@cronyx.ru>
This commit is contained in:
jkh 1995-10-04 22:24:16 +00:00
parent 190bb14e52
commit 9cc3a83e55
8 changed files with 848 additions and 374 deletions

View File

@ -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,10 +619,15 @@ 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) {
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

View File

@ -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,10 +619,15 @@ 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) {
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

View File

@ -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 */

View File

@ -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;
}

View File

@ -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,8 +106,12 @@ 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]));
@ -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);
#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)

View File

@ -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,6 +323,8 @@ 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;
@ -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)
return (0);
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);
if (c->ifp->if_flags & IFF_UP) {
cx_setup_chan (c);
}
/*
* Start the interface. Called on splimp().
*/
void cxup (cx_chan_t *c)
{
unsigned short port = c->chip->port;
/* 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,
@ -577,19 +654,52 @@ void cxstart (struct ifnet *ifp)
outb (IER(port), IER_RXD | IER_TXD);
}
/*
* 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);
}
}
/*
* Handle receive interrupts, including receive errors and
@ -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;
/* Terminate the failed buffer. */
teoir |= TEOI_TERMBUFF;
} else if (tisr & (TIS_EOFR))
++c->ifp->if_opackets;
++c->stat->oerrs;
/* Terminate the failed buffer. */
/* 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)

View File

@ -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

View File

@ -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);
}
/*
@ -461,6 +496,19 @@ void sppp_flush (struct ifnet *ifp)
qflush (&sp->pp_fastq);
}
/*
* 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.
*/
@ -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;
/* Initiate renegotiation. */
sppp_lcp_open (sp);
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_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.
* 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)
{
/* 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];
}
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;
}
void sppp_lcp_conf_rej (struct sppp *sp, struct lcp_header *h)
{
/* 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) {
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;
/* Initiate renegotiation. */
sppp_ipcp_open (sp);
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;
/* 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)