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:
parent
190bb14e52
commit
9cc3a83e55
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
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)
|
||||
|
@ -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)
|
||||
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,18 +654,51 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
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.
|
||||
* 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];
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
u_char *buf, *r, *p;
|
||||
int rlen;
|
||||
|
||||
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;
|
||||
len -= 4;
|
||||
buf = r = malloc (len, M_TEMP, M_NOWAIT);
|
||||
if (! buf)
|
||||
return (0);
|
||||
|
||||
while (len > 0) {
|
||||
if (*p != LCP_OPT_MAGIC) {
|
||||
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)
|
||||
|
Loading…
Reference in New Issue
Block a user