-/*
- PPP for Linux
-
- $Id: ppp.c,v 1.4 1995/04/28 06:28:22 paulus Exp $
-*/
+/* PPP for Linux
+ *
+ * Michael Callahan <callahan@maths.ox.ac.uk>
+ * Al Longyear <longyear@netcom.com>
+ *
+ * Dynamic PPP devices by Jim Freeman <jfree@caldera.com>.
+ * ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid <ewerlid@syscon.uu.se>
+ *
+ * ==FILEVERSION 8==
+ *
+ * NOTE TO MAINTAINERS:
+ * If you modify this file at all, increment the number above.
+ * ppp.c is shipped with a PPP distribution as well as with the kernel;
+ * if everyone increases the FILEVERSION number above, then scripts
+ * can do the right thing when deciding whether to install a new ppp.c
+ * file. Don't change the format of that line otherwise, so the
+ * installation script can recognize it.
+ */
/*
Sources:
OPTIMIZE_FLAG_TIME - Number of jiffies to force sending of leading flag
character. This is normally set to ((HZ * 3) / 2).
- This is 1.5 seconds. If not defined then the leading
+ This is 1.5 seconds. If zero then the leading
flag is always sent.
CHECK_CHARACTERS - Enable the checking on all received characters for
processing for each received character.
NEW_SKBUFF - Use NET3.020 sk_buff's
+
+ IPX_CHANGE - Force the use of IPX support into the driver.
+ THIS IS **VERY** ALPHA LEVEL CODE!!!!
*/
-/* #define NEW_SKBUFF */
-#define OPTIMIZE_FLAG_TIME ((HZ * 3)/2) /* */
+/* #define NEW_SKBUFF 1 */
+#define OPTIMIZE_FLAG_TIME ((HZ * 3)/2)
+
+#define CHECK_CHARACTERS 1
+#define PPP_COMPRESS 1
+#define USE_SKB_PROTOCOL 1 /* Set by the installation program! */
+
+#ifdef NEW_SKBUFF
+#undef USE_SKB_PROTOCOL
+#define USE_SKB_PROTOCOL 2
+#endif
+
+#ifndef PPP_MAX_DEV
+#define PPP_MAX_DEV 256
+#endif
+
+#undef IPX_CHANGE
+
+#if defined(IPX_CHANGE) || defined(NEW_SKBUFF)
+#define PPP_REQUESTED_HDR_LEN PPP_HARD_HDR_LEN
+#else
+#define PPP_REQUESTED_HDR_LEN 0
+#endif
+
+/* $Id: ppp.c,v 1.6 1995/12/18 03:38:12 paulus Exp $
+ * Added dynamic allocation of channels to eliminate
+ * compiled-in limits on the number of channels.
+ *
+ * Dynamic channel allocation code Copyright 1995 Caldera, Inc.,
+ * released under the GNU General Public License Version 2.
+ */
+
+#if USE_SKB_PROTOCOL == 0
+#include <linux/config.h> /* still needed for 1.2 */
+#endif
+#include <linux/module.h>
+
+#ifndef MOD_INC_USE_COUNT /* for those 1.2 kernels still out there */
+#undef MOD_DEC_USE_COUNT
+#define MOD_DEC_USE_COUNT do {} while (0)
+#define MOD_INC_USE_COUNT do {} while (0)
+#endif
+#include <endian.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <asm/bitops.h>
#include <asm/segment.h>
#include <net/if.h>
-#include <net/if_arp.h>
-#include <net/if_route.h>
#include <linux/if_ether.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#ifdef NEW_SKBUFF
#include <linux/netprotocol.h>
#else
-#define skb_data(skb) ((skb)->data)
-typedef struct sk_buff sk_buff;
+typedef struct sk_buff sk_buff;
+#define skb_data(skb) ((unsigned char *) (skb)->data)
#endif
-#include <ip.h>
-#include <tcp.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
#include <linux/if_arp.h>
#include "slhc.h"
-#include <net/ppp_defs.h>
+#include <linux/ppp_defs.h>
#include <linux/socket.h>
-#include <net/if_ppp.h>
-#include <net/if_pppvar.h>
+#include <linux/if_ppp.h>
+#include <linux/if_pppvar.h>
+
+#undef PACKETPTR
+#define PACKETPTR 1
+#include <linux/ppp-comp.h>
+#undef PACKETPTR
+
+#define bsd_decompress (*ppp->sc_rcomp->decompress)
+#define bsd_compress (*ppp->sc_xcomp->compress)
#ifndef PPP_IPX
#define PPP_IPX 0x2b /* IPX protocol over PPP */
#endif
+#ifndef PPP_LQR
+#define PPP_LQR 0xc025 /* Link Quality Reporting Protocol */
+#endif
+
+static int ppp_register_compressor (struct compressor *cp);
+static void ppp_unregister_compressor (struct compressor *cp);
+
/*
* Local functions
*/
+static struct compressor *find_compressor (int type);
static void ppp_init_ctrl_blk (register struct ppp *);
static void ppp_kick_tty (struct ppp *, struct ppp_buffer *bfr);
static int ppp_doframe (struct ppp *);
-static int ppp_do_ip (struct ppp *, unsigned short, u_char *, int);
-static int ppp_us_queue (struct ppp *, unsigned short, u_char *, int);
static struct ppp *ppp_alloc (void);
-static void ppp_print_buffer (const u_char *, u_char *, int, int);
+static void ppp_print_buffer (const u_char *, const u_char *, int);
extern inline void ppp_stuff_char (struct ppp *ppp,
register struct ppp_buffer *buf,
register u_char chr);
extern inline int lock_buffer (register struct ppp_buffer *buf);
+static int rcv_proto_ip (struct ppp *, u_short, u_char *, int);
+static int rcv_proto_ipx (struct ppp *, u_short, u_char *, int);
+static int rcv_proto_vjc_comp (struct ppp *, u_short, u_char *, int);
+static int rcv_proto_vjc_uncomp (struct ppp *, u_short, u_char *, int);
+static int rcv_proto_unknown (struct ppp *, u_short, u_char *, int);
+static int rcv_proto_lqr (struct ppp *, u_short, u_char *, int);
+static void ppp_doframe_lower (struct ppp *, u_char *, int);
+static int ppp_doframe (struct ppp *);
+
+extern int ppp_bsd_compressor_init(void);
+static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd);
+static int rcv_proto_ccp (struct ppp *, u_short, u_char *, int);
+
#define ins_char(pbuf,c) (buf_base(pbuf) [(pbuf)->count++] = (u_char)(c))
+#ifndef OPTIMIZE_FLAG_TIME
+#define OPTIMIZE_FLAG_TIME 0
+#endif
+
+#ifndef PPP_MAX_DEV
+#define PPP_MAX_DEV 256
+#endif
+
+/*
+ * Parameters which may be changed via insmod.
+ */
+
+static int flag_time = OPTIMIZE_FLAG_TIME;
+static int max_dev = PPP_MAX_DEV;
+
/*
* The "main" procedure to the ppp device
*/
static int ppp_dev_xmit (sk_buff *, struct device *);
static struct enet_statistics *ppp_dev_stats (struct device *);
+#if USE_SKB_PROTOCOL == 0 /* The 1.2.x kernel is here */
+#define dev_alloc_skb(count) alloc_skb(count, GFP_ATOMIC)
+#define skb_put(skb,count) skb_data(skb)
+#define get_long_user(addr) get_user_long((void *) addr)
+#define get_int_user(addr) ((int) get_user_long((void *) addr))
+#define put_byte_user(val,addr) put_fs_byte(val,((u_char *) (addr)))
+#define put_long_user(val,addr) put_fs_long((val),((void *) (addr)))
+
+static unsigned short ppp_dev_type (sk_buff *, struct device *);
+static int ppp_dev_header (unsigned char *buff, struct device *dev,
+ unsigned short type, void *daddr, void *saddr,
+ unsigned len, struct sk_buff *skb);
+
+#else /* The 1.3.x kernel is here */
+#define get_long_user(addr) get_user(((int *) addr))
+#define get_int_user(addr) ((int) get_user(((int *) addr)))
+#define put_byte_user(val,addr) put_user((val),((u_char *) (addr)))
+#define put_long_user(val,addr) put_user((val),((int *) (addr)))
+
+static int ppp_dev_header (sk_buff *, struct device *, unsigned short,
+ void *, void *, unsigned);
+#endif
+
#ifdef NEW_SKBUFF
static int ppp_dev_input (struct protocol *self, struct protocol *lower,
sk_buff *skb, void *saddr, void *daddr);
int subid, void *saddr, void *daddr, void *opt);
static int ppp_dev_getkey(int protocol, int subid, unsigned char *key);
#else
-static int ppp_dev_header (u_char *, struct device *, unsigned short,
- void *, void *, unsigned, sk_buff *);
static int ppp_dev_rebuild (void *, struct device *, unsigned long,
sk_buff *);
-static unsigned short ppp_dev_type (sk_buff *, struct device *);
#endif
/*
static int ppp_tty_read (struct tty_struct *, struct file *, u_char *,
unsigned int);
-static int ppp_tty_write (struct tty_struct *, struct file *, u_char *,
+static int ppp_tty_write (struct tty_struct *, struct file *, const u_char *,
unsigned int);
static int ppp_tty_ioctl (struct tty_struct *, struct file *, unsigned int,
unsigned long);
static int ppp_tty_open (struct tty_struct *);
static void ppp_tty_close (struct tty_struct *);
static int ppp_tty_room (struct tty_struct *tty);
-static void ppp_tty_receive (struct tty_struct *tty, u_char * cp,
+static void ppp_tty_receive (struct tty_struct *tty, const u_char * cp,
char *fp, int count);
static void ppp_tty_wakeup (struct tty_struct *tty);
-
-#define PRINTK(p) printk p ;
-#define ASSERT(p) if (!p) PRINTK ((KERN_CRIT "assertion failed: " # p))
-#define PRINTKN(n,p) {if (ppp_debug >= n) PRINTK (p)}
-#define CHECK_PPP(a) if (!ppp->inuse) { PRINTK ((ppp_warning, __LINE__)) return a;}
-#define CHECK_PPP_VOID() if (!ppp->inuse) { PRINTK ((ppp_warning, __LINE__)) return;}
+#define CHECK_PPP(a) if (!ppp->inuse) { printk (ppp_warning, __LINE__); return a;}
+#define CHECK_PPP_VOID() if (!ppp->inuse) { printk (ppp_warning, __LINE__); return;}
#define in_xmap(ppp,c) (ppp->xmit_async_map[(c) >> 5] & (1 << ((c) & 0x1f)))
#define in_rmap(ppp,c) ((((unsigned int) (u_char) (c)) < 0x20) && \
#define bset(p,b) ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
+#define tty2ppp(tty) ((struct ppp *) (tty->disc_data))
+#define dev2ppp(dev) ((struct ppp *) (dev->priv))
+#define ppp2tty(ppp) ((struct tty_struct *) ppp->tty)
+#define ppp2dev(ppp) ((struct device *) ppp->dev)
+
+struct ppp_hdr {
+ unsigned char address;
+ unsigned char control;
+ unsigned char protocol[2];
+};
+
+#define PPP_HARD_HDR_LEN (sizeof (struct ppp_hdr))
+
+typedef struct ppp_ctrl {
+ struct ppp_ctrl *next; /* Next structure in the list */
+ char name [8]; /* Name of the device */
+ struct ppp ppp; /* PPP control table */
+ struct device dev; /* Device information table */
+} ppp_ctrl_t;
+
+static ppp_ctrl_t *ppp_list = NULL;
+
+#define ctl2ppp(ctl) (struct ppp *) &ctl->ppp
+#define ctl2dev(ctl) (struct device *) &ctl->dev
+#undef PPP_NRUNIT
+
/* Buffer types */
-#define BUFFER_TYPE_DEV_RD 0 /* ppp? read buffer */
-#define BUFFER_TYPE_TTY_WR 1 /* tty? write buffer */
-#define BUFFER_TYPE_DEV_WR 2 /* ppp? write buffer */
-#define BUFFER_TYPE_TTY_RD 3 /* tty? read buffer */
-#define BUFFER_TYPE_VJ 4 /* vj compression buffer */
+#define BUFFER_TYPE_DEV_RD 0 /* ppp read buffer */
+#define BUFFER_TYPE_TTY_WR 1 /* tty write buffer */
+#define BUFFER_TYPE_DEV_WR 2 /* ppp write buffer */
+#define BUFFER_TYPE_TTY_RD 3 /* tty read buffer */
+#define BUFFER_TYPE_VJ 4 /* vj compression buffer */
/* Define this string only once for all macro envocations */
static char ppp_warning[] = KERN_WARNING "PPP: ALERT! not INUSE! %d\n";
-static int first_time = 1;
static char szVersion[] = PPP_VERSION;
-static int ppp_debug = 5;
-static int ppp_debug_netpackets = 0;
-static struct tty_ldisc ppp_ldisc;
-static struct ppp ppp_ctrl [PPP_NRUNIT];
#ifdef NEW_SKBUFF
-struct protocol proto_ppp;
+static struct protocol proto_ppp;
#endif
-/* FCS table from RFC1331 */
+/*
+ * Information for the protocol decoder
+ */
+
+typedef int (*pfn_proto) (struct ppp *, u_short, u_char *, int);
-static unsigned short fcstab[256] =
+typedef struct ppp_proto_struct {
+ int proto;
+ pfn_proto func;
+} ppp_proto_type;
+
+static
+ppp_proto_type proto_list[] = {
+ { PPP_IP, rcv_proto_ip },
+ { PPP_IPX, rcv_proto_ipx },
+ { PPP_VJC_COMP, rcv_proto_vjc_comp },
+ { PPP_VJC_UNCOMP, rcv_proto_vjc_uncomp },
+ { PPP_LQR, rcv_proto_lqr },
+ { PPP_CCP, rcv_proto_ccp },
+ { 0, rcv_proto_unknown } /* !!! MUST BE LAST !!! */
+};
+
+/*
+ * Values for FCS calculations.
+ */
+
+#define PPP_INITFCS 0xffff /* Initial FCS value */
+#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */
+#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ ppp_crc16_table[((fcs) ^ (c)) & 0xff])
+
+unsigned short ppp_crc16_table[256] =
{
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
+#ifdef CHECK_CHARACTERS
+static unsigned paritytab[8] =
+{
+ 0x96696996, 0x69969669, 0x69969669, 0x96696996,
+ 0x69969669, 0x96696996, 0x96696996, 0x69969669
+};
+#endif
+
+/* local function to store a value into the LQR frame */
+extern inline u_char * store_long (register u_char *p, register int value) {
+ *p++ = (u_char) (value >> 24);
+ *p++ = (u_char) (value >> 16);
+ *p++ = (u_char) (value >> 8);
+ *p++ = (u_char) value;
+ return p;
+}
+
/*************************************************************
* INITIALIZATION
*************************************************************/
-/* called at boot time for each ppp device */
+/* This procedure is called once and once only to define who we are to
+ * the operating system and the various procedures that it may use in
+ * accessing the ppp protocol.
+ */
-int
-ppp_init (struct device *dev)
+static int
+ppp_first_time (void)
{
- struct ppp *ppp;
- int i;
-
- ppp = &ppp_ctrl[dev->base_addr];
-
- if (first_time) {
- first_time = 0;
+ static struct tty_ldisc ppp_ldisc;
+ int status;
- printk (KERN_INFO "PPP: version %s (%d channels)"
+ printk (KERN_INFO
+ "PPP: version %s (dynamic channel allocation)"
#ifdef NEW_SKBUFF
- " NEW_SKBUFF"
+ " NEW_SKBUFF"
#endif
- "\n", szVersion, PPP_NRUNIT);
+ "\n", szVersion);
- printk (KERN_INFO
- "TCP compression code copyright 1989 Regents of the "
- "University of California\n");
-
- (void) memset (&ppp_ldisc, 0, sizeof (ppp_ldisc));
- ppp_ldisc.magic = TTY_LDISC_MAGIC;
- ppp_ldisc.open = ppp_tty_open;
- ppp_ldisc.close = ppp_tty_close;
- ppp_ldisc.read = ppp_tty_read;
- ppp_ldisc.write = ppp_tty_write;
- ppp_ldisc.ioctl = ppp_tty_ioctl;
- ppp_ldisc.select = ppp_tty_select;
- ppp_ldisc.receive_room = ppp_tty_room;
- ppp_ldisc.receive_buf = ppp_tty_receive;
- ppp_ldisc.write_wakeup = ppp_tty_wakeup;
-
- i = tty_register_ldisc (N_PPP, &ppp_ldisc);
- if (i == 0) {
- printk (KERN_INFO "PPP line discipline registered.\n");
- } else {
- printk (KERN_ERR "error registering line discipline: %d\n", i);
- }
+#ifndef MODULE /* slhc module logic has its own copyright announcment */
+ printk (KERN_INFO
+ "TCP compression code copyright 1989 Regents of the "
+ "University of California\n");
+#endif
+
+ printk (KERN_INFO
+ "PPP Dynamic channel allocation code copyright 1995 "
+ "Caldera, Inc.\n");
+/*
+ * Register the protocol for the device
+ */
#ifdef NEW_SKBUFF
- memset (&proto_ppp, 0, sizeof (proto_ppp));
+ memset (&proto_ppp, 0, sizeof (proto_ppp));
- proto_ppp.name = "PPP";
- proto_ppp.output = ppp_dev_output;
- proto_ppp.input = ppp_dev_input;
- proto_ppp.bh_input = ppp_dev_input;
- proto_ppp.control_event = default_protocol_control;
- proto_ppp.get_binding = ppp_dev_getkey;
+ proto_ppp.name = "PPP";
+ proto_ppp.output = ppp_dev_output;
+ proto_ppp.input = ppp_dev_input;
+ proto_ppp.bh_input = ppp_dev_input;
+ proto_ppp.control_event = default_protocol_control;
+ proto_ppp.get_binding = ppp_dev_getkey;
+ proto_ppp.header_space = PPP_REQUESTED_HDR_LEN;
- protocol_register(&proto_ppp);
+ protocol_register(&proto_ppp);
#endif
- }
- /* initialize PPP control block */
- ppp_init_ctrl_blk (ppp);
- ppp->inuse = 0;
- ppp->line = dev->base_addr;
- ppp->tty = NULL;
- ppp->dev = dev;
+/*
+ * Register the tty dicipline
+ */
+ (void) memset (&ppp_ldisc, 0, sizeof (ppp_ldisc));
+ ppp_ldisc.magic = TTY_LDISC_MAGIC;
+ ppp_ldisc.open = ppp_tty_open;
+ ppp_ldisc.close = ppp_tty_close;
+ ppp_ldisc.read = ppp_tty_read;
+ ppp_ldisc.write = ppp_tty_write;
+ ppp_ldisc.ioctl = ppp_tty_ioctl;
+ ppp_ldisc.select = ppp_tty_select;
+ ppp_ldisc.receive_room = ppp_tty_room;
+ ppp_ldisc.receive_buf = ppp_tty_receive;
+ ppp_ldisc.write_wakeup = ppp_tty_wakeup;
+
+ status = tty_register_ldisc (N_PPP, &ppp_ldisc);
+ if (status == 0)
+ printk (KERN_INFO "PPP line discipline registered.\n");
+ else
+ printk (KERN_ERR "error registering line discipline: %d\n",
+ status);
+ return status;
+}
- /* clear statistics */
- memset (&ppp->p, '\0', sizeof (struct ppp_stats));
+/*************************************************************
+ * INITIALIZATION
+ *************************************************************/
+/* called when the device is actually created */
+
+static int
+ppp_init_dev (struct device *dev)
+{
+ int indx;
#ifdef NEW_SKBUFF
dev->default_protocol = &proto_ppp; /* Our protocol layer is PPP */
#else
dev->hard_header = ppp_dev_header;
+#if USE_SKB_PROTOCOL == 0
dev->type_trans = ppp_dev_type;
+#endif
dev->rebuild_header = ppp_dev_rebuild;
- dev->hard_header_len = 0;
+ dev->hard_header_len = PPP_REQUESTED_HDR_LEN;
#endif
/* device INFO */
dev->addr_len = 0;
dev->type = ARPHRD_PPP;
- for (i = 0; i < DEV_NUMBUFFS; i++) {
- skb_queue_head_init (&dev->buffs[i]);
- }
+ for (indx = 0; indx < DEV_NUMBUFFS; indx++)
+ skb_queue_head_init (&dev->buffs[indx]);
/* New-style flags */
dev->flags = IFF_POINTOPOINT;
dev->pa_addr = 0;
dev->pa_brdaddr = 0;
dev->pa_mask = 0;
- dev->pa_alen = sizeof (unsigned long);
+ dev->pa_alen = 4; /* sizeof (unsigned long) */
return 0;
}
ppp->slcomp = NULL;
ppp->read_wait = NULL;
ppp->write_wait = NULL;
-
-#ifdef OPTIMIZE_FLAG_TIME /* ensure flag will always be sent first time */
- ppp->last_xmit = jiffies - OPTIMIZE_FLAG_TIME;
-#else
- ppp->last_xmit = 0;
-#endif
+ ppp->last_xmit = jiffies - flag_time;
/* clear statistics */
- memset (&ppp->p, '\0', sizeof (struct ppp_stats));
+ memset (&ppp->stats, '\0', sizeof (struct pppstat));
/* Reset the demand dial information */
- ppp->ddinfo.ip_sjiffies =
- ppp->ddinfo.ip_rjiffies =
- ppp->ddinfo.nip_sjiffies =
- ppp->ddinfo.nip_rjiffies = jiffies;
+ ppp->ddinfo.xmit_idle= /* time since last NP packet sent */
+ ppp->ddinfo.recv_idle=jiffies; /* time since last NP packet received */
+
+ /* PPP compression data */
+ ppp->sc_xc_state =
+ ppp->sc_rc_state = NULL;
+}
+
+static struct symbol_table ppp_syms = {
+#include <linux/symtab_begin.h>
+ X(ppp_register_compressor),
+ X(ppp_unregister_compressor),
+ X(ppp_crc16_table),
+#include <linux/symtab_end.h>
+};
+
+/* called at boot/load time for each ppp device defined in the kernel */
+
+#ifndef MODULE
+int
+ppp_init (struct device *dev)
+{
+ static int first_time = 1;
+ int answer = 0;
+
+ if (first_time) {
+ first_time = 0;
+ answer = ppp_first_time();
+ if (answer == 0)
+ (void) register_symtab (&ppp_syms);
+ }
+ if (answer == 0)
+ answer = -ENODEV;
+ return answer;
}
+#endif
/*
* Routine to allocate a buffer for later use by the driver.
static void
ppp_free_buf (struct ppp_buffer *ptr)
{
- if (ptr != NULL) {
+ if (ptr != NULL)
kfree (ptr);
- }
}
/*
save_flags (flags);
cli ();
state = buf->locked;
- if (state == 0) {
+ if (state == 0)
buf->locked = 2;
- }
/*
* Restore the flags and return the previous state. 0 implies success.
*/
/*
* Allocate the buffer from the kernel for the data
*/
- dev = ppp->dev;
+ dev = ppp2dev (ppp);
mru = new_mru;
+ /* allow for possible escapement of every character */
mtu = (new_mtu * 2) + 20;
/* RFC 1331, section 7.2 says the minimum value is 1500 bytes */
- if (mru < PPP_MRU) {
+ if (mru < PPP_MRU)
mru = PPP_MRU;
- }
- mru += 10;
- PRINTKN (2, (KERN_INFO "ppp: channel %s mtu = %d, mru = %d\n",
- dev->name, new_mtu, new_mru));
+ mru += 10;
+
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO "ppp: channel %s mtu = %d, mru = %d\n",
+ dev->name, new_mtu, new_mru);
- new_wbuf = ppp_alloc_buf (mtu + 4, BUFFER_TYPE_DEV_WR);
- new_tbuf = ppp_alloc_buf ((PPP_MTU * 2) + 24, BUFFER_TYPE_TTY_WR);
- new_rbuf = ppp_alloc_buf (mru + 84, BUFFER_TYPE_DEV_RD);
- new_cbuf = ppp_alloc_buf (mru + 4, BUFFER_TYPE_VJ);
+ new_wbuf = ppp_alloc_buf (mtu+PPP_HARD_HDR_LEN, BUFFER_TYPE_DEV_WR);
+ new_tbuf = ppp_alloc_buf ((PPP_MTU * 2) + 24, BUFFER_TYPE_TTY_WR);
+ new_rbuf = ppp_alloc_buf (mru + 84, BUFFER_TYPE_DEV_RD);
+ new_cbuf = ppp_alloc_buf (mru+PPP_HARD_HDR_LEN, BUFFER_TYPE_VJ);
/*
* If the buffers failed to allocate then complain and release the partial
* allocations.
*/
if (new_wbuf == NULL || new_tbuf == NULL ||
new_rbuf == NULL || new_cbuf == NULL) {
- PRINTKN (2,(KERN_ERR "ppp: failed to allocate new buffers\n"));
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp: failed to allocate new buffers\n");
+
ppp_free_buf (new_wbuf);
ppp_free_buf (new_tbuf);
ppp_free_buf (new_rbuf);
/*
* Update the parameters for the new buffer sizes
*/
- ppp->toss = 0xE0; /* To ignore characters until new FLAG */
+ ppp->toss = 0xE0; /* To ignore characters until new FLAG */
ppp->escape = 0; /* No pending escape character */
- dev->mtu =
- ppp->mtu = new_mtu;
- ppp->mru = new_mru;
+ dev->mtu =
+ ppp->mtu = new_mtu;
+ ppp->mru = new_mru;
- ppp->s1buf = NULL;
- ppp->s2buf = NULL;
- ppp->xbuf = NULL;
+ ppp->s1buf = NULL;
+ ppp->s2buf = NULL;
+ ppp->xbuf = NULL;
- ppp->tty->flags &= ~TTY_DO_WRITE_WAKEUP;
+ ppp->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
ppp->flags &= ~SC_XMIT_BUSY;
sti ();
return 1;
}
+/*
+ * CCP is down; free (de)compressor state if necessary.
+ */
+
+static void
+ppp_ccp_closed (struct ppp *ppp)
+{
+ if (ppp->sc_xc_state) {
+ (*ppp->sc_xcomp->comp_free) (ppp->sc_xc_state);
+ ppp->sc_xc_state = NULL;
+ }
+
+ if (ppp->sc_rc_state) {
+ (*ppp->sc_rcomp->decomp_free) (ppp->sc_rc_state);
+ ppp->sc_rc_state = NULL;
+ }
+}
+
/*
* Called to release all of the information in the current PPP structure.
*
static void
ppp_release (struct ppp *ppp)
{
- if (ppp->tty != NULL && ppp->tty->disc_data == ppp) {
- ppp->tty->disc_data = NULL; /* Break the tty->ppp link */
- }
- if (ppp->dev) {
- ppp->dev->flags &= ~IFF_UP; /* down the device */
- ppp->dev->flags |= IFF_POINTOPOINT;
+ struct tty_struct *tty;
+ struct device *dev;
+
+ tty = ppp2tty (ppp);
+ dev = ppp2dev (ppp);
+
+ ppp_ccp_closed (ppp);
+
+ if (tty != NULL && tty->disc_data == ppp)
+ tty->disc_data = NULL; /* Break the tty->ppp link */
+
+ if (dev && dev->flags & IFF_UP) {
+ dev_close (dev); /* close the device properly */
+ dev->flags = 0; /* prevent recursion */
}
+
ppp_free_buf (ppp->rbuf);
ppp_free_buf (ppp->wbuf);
ppp_free_buf (ppp->cbuf);
slhc_free (ppp->slcomp);
ppp->slcomp = NULL;
}
+
ppp->inuse = 0;
- ppp->tty = NULL;
+ ppp->tty = NULL;
}
/*
static void
ppp_tty_close (struct tty_struct *tty)
{
- struct ppp *ppp = (struct ppp *) tty->disc_data;
+ struct ppp *ppp = tty2ppp (tty);
- if (ppp == NULL || ppp->magic != PPP_MAGIC) {
- PRINTKN (1,
- (KERN_WARNING "ppp: trying to close unopened tty!\n"));
- } else {
- CHECK_PPP_VOID ();
- PRINTKN (2,
- (KERN_INFO "ppp: channel %s closing.\n", ppp->dev->name));
- ppp_release (ppp);
+ if (ppp != NULL) {
+ if (ppp->magic != PPP_MAGIC) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_WARNING
+ "ppp: trying to close unopened tty!\n");
+ } else {
+ CHECK_PPP_VOID();
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO "ppp: channel %s closing.\n",
+ ppp2dev(ppp) -> name);
+ ppp_release (ppp);
+ MOD_DEC_USE_COUNT;
+ }
}
}
/*
* TTY callback.
*
- * Called when the tty dicipline is switched to PPP.
+ * Called when the tty discipline is switched to PPP.
*/
static int
ppp_tty_open (struct tty_struct *tty)
{
- struct ppp *ppp = (struct ppp *) tty->disc_data;
+ struct ppp *ppp = tty2ppp (tty);
/*
* There should not be an existing table for this slot.
*/
if (ppp) {
- PRINTKN (1, (KERN_ERR
- "ppp_tty_open: gack! tty already associated to %s!\n",
- ppp->magic == PPP_MAGIC ? ppp->dev->name
- : "unknown"));
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_tty_open: gack! tty already associated to %s!\n",
+ ppp->magic == PPP_MAGIC ? ppp2dev(ppp)->name
+ : "unknown");
return -EEXIST;
}
/*
* Allocate the structure from the system
*/
- ppp = ppp_alloc ();
+ ppp = ppp_alloc();
if (ppp == NULL) {
- PRINTKN (1, (KERN_ERR
- "ppp_tty_open: couldn't allocate ppp channel\n"));
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_tty_open: couldn't allocate ppp channel\n");
return -ENFILE;
}
/*
ppp->tty = tty;
tty->disc_data = ppp;
/*
- * Flush any pending characters in the driver and dicipline.
+ * Flush any pending characters in the driver and discipline.
*/
- if (tty->ldisc.flush_buffer) {
+ if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer (tty);
- }
- if (tty->driver.flush_buffer) {
+ if (tty->driver.flush_buffer)
tty->driver.flush_buffer (tty);
- }
/*
- * Allocate space for the default VJ header compression slots (16)
+ * Allocate space for the default VJ header compression slots
*/
ppp->slcomp = slhc_init (16, 16);
if (ppp->slcomp == NULL) {
- PRINTKN (1, (KERN_ERR
- "ppp_tty_open: no space for compression buffers!\n"));
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_tty_open: no space for compression buffers!\n");
ppp_release (ppp);
return -ENOMEM;
}
/*
* Allocate space for the MTU and MRU buffers
*/
- if (ppp_changedmtu (ppp, ppp->dev->mtu, ppp->mru) == 0) {
+ if (ppp_changedmtu (ppp, ppp2dev(ppp)->mtu, ppp->mru) == 0) {
ppp_release (ppp);
return -ENOMEM;
}
*/
ppp->ubuf = ppp_alloc_buf (RBUFSIZE, BUFFER_TYPE_TTY_RD);
if (ppp->ubuf == NULL) {
- PRINTKN (1, (KERN_ERR
- "ppp_tty_open: no space for user receive buffer\n"));
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_tty_open: no space for user receive buffer\n");
ppp_release (ppp);
return -ENOMEM;
}
- PRINTKN (2, (KERN_INFO "ppp: channel %s open\n", ppp->dev->name));
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO "ppp: channel %s open\n",
+ ppp2dev(ppp)->name);
+
+ MOD_INC_USE_COUNT;
return (ppp->line);
}
* This could occur should the carrier drop.
*/
if (actual < 0) {
- ppp->p.ppp_oerrors++;
+ ppp->stats.ppp_oerrors++;
actual = count;
- } else {
+ } else
ppp->bytes_sent += actual;
- }
/*
* If the buffer has been transmitted then clear the indicators.
*/
xbuf = NULL;
ppp->flags &= ~SC_XMIT_BUSY;
/*
- * Complete the transmisson on the current buffer.
+ * Complete the transmission on the current buffer.
*/
xbuf = ppp->xbuf;
if (xbuf != NULL) {
- tty->flags &= ~TTY_DO_WRITE_WAKEUP;
+ tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
xbuf->locked = 0;
ppp->xbuf = NULL;
/*
* If the completed buffer came from the device write, then complete the
* transmission block.
*/
- if (ppp->dev->flags & IFF_UP) {
- ppp->dev->tbusy = 0;
+ if (ppp2dev (ppp) -> flags & IFF_UP) {
+ if (xbuf->type == BUFFER_TYPE_DEV_WR)
+ ppp2dev (ppp)->tbusy = 0;
mark_bh (NET_BH);
- dev_tint (ppp->dev);
}
/*
* Wake up the transmission queue for all completion events.
/*
* Look at the priorities. Choose a daemon write over the device driver.
*/
+ cli();
xbuf = ppp->s1buf;
ppp->s1buf = NULL;
if (xbuf == NULL) {
xbuf = ppp->s2buf;
ppp->s2buf = NULL;
}
+ sti();
/*
* If there is a pending buffer then transmit it now.
*/
if (xbuf != NULL) {
ppp->flags &= ~SC_XMIT_BUSY;
ppp_kick_tty (ppp, xbuf);
+ return;
}
}
}
ppp_tty_wakeup (struct tty_struct *tty)
{
struct ppp_buffer *xbuf;
- struct ppp *ppp = (struct ppp *) tty->disc_data;
+ struct ppp *ppp = tty2ppp (tty);
- if (!ppp || ppp->magic != PPP_MAGIC) {
- PRINTKN (1, (KERN_ERR "PPP: write_wakeup called but couldn't "
- "find PPP struct.\n"));
+ if (!ppp)
+ return;
+
+ if (ppp->magic != PPP_MAGIC)
return;
- }
/*
* Ensure that there is a transmission pending. Clear the re-entry flag if
* there is no pending buffer. Otherwise, send the buffer.
*/
xbuf = ppp->xbuf;
- if (xbuf == NULL) {
+ if (xbuf == NULL)
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
- } else {
+ else
ppp_tty_wakeup_code (ppp, tty, xbuf);
- }
}
/*
- * This function is called to transmit a buffer to the rmeote. The buffer
+ * This function is called to transmit a buffer to the remote. The buffer
* is placed on the pending queue if there is presently a buffer being
* sent or it is transmitted with the aid of ppp_tty_wakeup.
*/
* priority queue.
*/
if (ppp->xbuf != NULL) {
- if (xbuf->type == BUFFER_TYPE_TTY_WR) {
+ if (xbuf->type == BUFFER_TYPE_TTY_WR)
ppp->s1buf = xbuf;
- } else {
+ else
ppp->s2buf = xbuf;
- }
restore_flags (flags);
return;
}
/*
* Do the "tty wakeup_code" to actually send this buffer.
*/
- ppp_tty_wakeup_code (ppp, ppp->tty, xbuf);
+ ppp_tty_wakeup_code (ppp, ppp2tty (ppp), xbuf);
}
/*************************************************************
* user process reading this TTY.
*************************************************************/
-#ifdef CHECK_CHARACTERS
-static unsigned paritytab[8] =
-{
- 0x96696996, 0x69969669, 0x69969669, 0x96696996,
- 0x69969669, 0x96696996, 0x96696996, 0x69969669
-};
-#endif
-
/*
* Callback function from tty driver. Return the amount of space left
* in the receiver's buffer to decide if remote transmitter is to be
*/
static void
-ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count)
+ppp_tty_receive (struct tty_struct *tty, const u_char * data,
+ char *flags, int count)
{
- register struct ppp *ppp = (struct ppp *) tty->disc_data;
- register struct ppp_buffer *buf = ppp->rbuf;
+ register struct ppp *ppp = tty2ppp (tty);
+ register struct ppp_buffer *buf = NULL;
u_char chr;
/*
- * Verify the table pointer and ensure that the line is still in PPP dicipline.
+ * Fetch the pointer to the buffer. Be careful about race conditions.
+ */
+ if (ppp != NULL)
+ buf = ppp->rbuf;
+
+ if (buf == NULL)
+ return;
+/*
+ * Verify the table pointer and ensure that the line is
+ * still in PPP discipline.
*/
- if (!ppp || ppp->magic != PPP_MAGIC) {
- PRINTKN (1, ("PPP: handler called but couldn't find "
- "PPP struct.\n"));
+ if (ppp->magic != PPP_MAGIC) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "PPP: handler called but couldn't find "
+ "PPP struct.\n");
return;
}
CHECK_PPP_VOID ();
/*
* Print the buffer if desired
*/
- if (ppp_debug >= 5) {
- ppp_print_buffer ("receive buffer", data, count, KERNEL_DS);
- }
+ if (ppp->flags & SC_LOG_RAWIN)
+ ppp_print_buffer ("receive buffer", data, count);
/*
* Collect the character and error condition for the character. Set the toss
* flag for the first character error.
ppp->bytes_rcvd++;
chr = *data++;
if (flags) {
- if (*flags && ppp->toss == 0) {
+ if (*flags && ppp->toss == 0)
ppp->toss = *flags;
- }
++flags;
}
/*
* so that the normal processing would have all flags set at the end of the
* session. A missing flag bit would denote an error condition.
*/
+
#ifdef CHECK_CHARACTERS
- if (chr & 0x80) {
+ if (chr & 0x80)
ppp->flags |= SC_RCV_B7_1;
- } else {
+ else
ppp->flags |= SC_RCV_B7_0;
- }
- if (paritytab[chr >> 5] & (1 << (chr & 0x1F))) {
+ if (paritytab[chr >> 5] & (1 << (chr & 0x1F)))
ppp->flags |= SC_RCV_ODDP;
- } else {
+ else
ppp->flags |= SC_RCV_EVNP;
- }
#endif
/*
* Branch on the character. Process the escape character. The sequence ESC ESC
* first FLAG are also tossed by this procedure.
*/
case PPP_FLAG: /* PPP_FLAG: end of frame */
- ppp->p.ppp_ibytes = ppp->bytes_rcvd;
- if (ppp->escape) {
+ ppp->stats.ppp_ibytes += ppp->rbuf->count;
+ if (ppp->escape)
ppp->toss |= 0x80;
- }
/*
* Process frames which are not to be ignored. If the processing failed,
* then clean up the VJ tables.
break;
/*
* All other characters in the data come here. If the character is in the
- * recieve mask then ignore the character.
+ * receive mask then ignore the character.
*/
default:
- if (in_rmap (ppp, chr)) {
+ if (in_rmap (ppp, chr))
break;
- }
/*
* Adjust the character and if the frame is to be discarded then simply
* ignore the character until the ending FLAG is received.
chr ^= ppp->escape;
ppp->escape = 0;
- if (ppp->toss != 0) {
+ if (ppp->toss != 0)
break;
- }
/*
* If the count sent is within reason then store the character, bump the
* count, and update the FCS for the character.
* The peer sent too much data. Set the flags to discard the current frame
* and wait for the re-synchronization FLAG to be sent.
*/
- ppp->p.ppp_ierrors++;
+ ppp->stats.ppp_ierrors++;
ppp->toss |= 0xC0;
break;
}
}
}
-/* on entry, a received frame is in ppp->rbuf.bufr
- check it and dispose as appropriate */
+/*
+ * Put the input frame into the networking system for the indicated protocol
+ */
static int
-ppp_doframe (struct ppp *ppp)
+ppp_rcv_rx (struct ppp *ppp, unsigned short proto, u_char * data, int count)
{
- u_short proto;
- u_char *data = buf_base (ppp->rbuf);
- int count = ppp->rbuf->count;
+ sk_buff *skb = dev_alloc_skb (count);
/*
- * If there is a pending error from the receiver then log it and discard
- * the damaged frame.
+ * Generate a skb buffer for the new frame.
*/
- if (ppp->toss) {
- PRINTKN (1, (KERN_WARNING
- "ppp_toss: tossing frame, reason = %d\n",
- ppp->toss));
- ppp->p.ppp_ierrors++;
+ if (skb == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_do_ip: packet dropped on %s (no memory)!\n",
+ ppp2dev (ppp)->name);
return 0;
}
/*
- * An empty frame is ignored. This occurs if the FLAG sequence precedes and
- * follows each frame.
+ * Move the received data from the input buffer to the skb buffer.
*/
- if (count == 0) {
- return 1;
- }
+ skb->dev = ppp2dev (ppp); /* We are the device */
+#if USE_SKB_PROTOCOL == 0
+ skb->len = count;
+#else
+ skb->protocol = proto;
+ skb->mac.raw = skb_data(skb);
+#endif
+ memcpy (skb_put(skb,count), data, count); /* move data */
/*
- * Print the received data.
+ * Tag the frame and kick it to the proper receive routine
*/
- if (ppp_debug >= 3) {
- ppp_print_buffer ("receive frame", data, count, KERNEL_DS);
- }
+ skb->free = 1;
+ ppp->ddinfo.recv_idle = jiffies;
+ netif_rx (skb);
+ return 1;
+}
+
/*
- * Generate an error if the frame is too small.
+ * Process the receipt of an IP frame
*/
- if (count < 4) {
- PRINTKN (1, (KERN_WARNING
- "ppp: got runt ppp frame, %d chars\n", count));
- ppp->p.ppp_ierrors++;
- return 1;
- }
+
+static int
+rcv_proto_ip (struct ppp *ppp, unsigned short proto, u_char * data, int count)
+{
+ if ((ppp2dev (ppp)->flags & IFF_UP) && (count > 0))
+ return ppp_rcv_rx (ppp, htons (ETH_P_IP), data, count);
+ return 0;
+}
+
/*
- * Verify the CRC of the frame and discard the CRC characters from the
- * end of the buffer.
+ * Process the receipt of an IPX frame
*/
- if (ppp->rbuf->fcs != PPP_GOODFCS) {
- PRINTKN (1, (KERN_WARNING
- "ppp: frame with bad fcs, excess = %x\n",
- ppp->rbuf->fcs ^ PPP_GOODFCS));
- ppp->p.ppp_ierrors++;
- return 0;
- }
- count -= 2; /* ignore the fcs characters */
+
+static int
+rcv_proto_ipx (struct ppp *ppp, unsigned short proto, u_char * data, int count)
+{
+#if defined(NEW_SKBUFF) || defined(IPX_CHANGE)
+ if (((ppp2dev (ppp)->flags & IFF_UP) != 0) && (count > 0))
+ return ppp_rcv_rx (ppp, htons (ETH_P_IPX), data, count);
+#endif
+ return 0;
+}
+
/*
- * Ignore the leading ADDRESS and CONTROL fields in the frame.
+ * Process the receipt of an VJ Compressed frame
*/
- if ((data[0] == PPP_ALLSTATIONS) && (data[1] == PPP_UI)) {
- data += 2;
- count -= 2;
- }
-
- proto = (u_short) * data++; /* PROTO compressed */
- if (proto & 1) {
- count--;
- } else {
- proto = (proto << 8) | (u_short) * data++;
- count -= 2;
- }
- /* Send the frame to the network if the ppp device is up */
- if (ppp->dev->flags & IFF_UP) {
- if (ppp_do_ip (ppp, proto, data, count)) {
- ppp->ddinfo.ip_rjiffies = jiffies;
- return 1;
+static int
+rcv_proto_vjc_comp (struct ppp *ppp, unsigned short proto,
+ u_char *data, int count)
+{
+ if ((ppp->flags & SC_REJ_COMP_TCP) == 0) {
+ int new_count = slhc_uncompress (ppp->slcomp, data, count);
+ if (new_count >= 0) {
+ return rcv_proto_ip (ppp, PPP_IP, data, new_count);
}
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_NOTICE
+ "ppp: error in VJ decompression\n");
}
-
- /* If we got here, it has to go to a user process doing a read,
- so queue it. */
- if (ppp_us_queue (ppp, proto, data, count)) {
- ppp->ddinfo.nip_rjiffies = jiffies;
- return 1;
- }
-
- /* couldn't cope. */
- PRINTKN (1, (KERN_WARNING
- "ppp: dropping packet on the floor: nobody could take it.\n"));
- ppp->p.ppp_ierrors++;
- return 1;
+ return 0;
}
-/* Examine packet at C, attempt to pass up to net layer.
- PROTO is the protocol field from the PPP frame.
- Return 1 if could handle it, 0 otherwise. */
-
-static int
-ppp_do_ip (struct ppp *ppp, unsigned short proto, u_char * data, int count)
-{
- sk_buff *skb;
/*
- * Log the IP information
+ * Process the receipt of an VJ Un-compressed frame
*/
- PRINTKN (4, (KERN_DEBUG "ppp_do_ip: proto %x len %d first byte %x\n",
- (int) proto, count, data[0]));
- if (ppp_debug_netpackets) {
- PRINTK ((KERN_DEBUG "%s <-- proto %x len %d\n", ppp->dev->name,
- (int) proto, count));
+static int
+rcv_proto_vjc_uncomp (struct ppp *ppp, unsigned short proto,
+ u_char *data, int count)
+{
+ if ((ppp->flags & SC_REJ_COMP_TCP) == 0) {
+ if (slhc_remember (ppp->slcomp, data, count) > 0) {
+ return rcv_proto_ip (ppp, PPP_IP, data, count);
+ }
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_NOTICE
+ "ppp: error in VJ memorizing\n");
}
+ return 0;
+}
+
/*
- * If this is uncompressed IP data then receive the data
+ * Receive all unclassified protocols.
*/
- switch (proto) {
- case PPP_IP:
- break;
+
+static int
+rcv_proto_unknown (struct ppp *ppp, unsigned short proto,
+ u_char *data, int len)
+{
+ int totlen;
+ register int current_idx;
+
+#define PUTC(c) \
+{ \
+ buf_base (ppp->ubuf) [current_idx++] = (u_char) (c); \
+ current_idx &= ppp->ubuf->size; \
+ if (current_idx == ppp->ubuf->tail) \
+ goto failure; \
+}
+
/*
- * For now, reject the IPX frames. Return 1 to indicate that it has been
- * processed so that it is simply discarded.
+ * The total length includes the protocol data.
+ * Lock the user information buffer.
*/
- case PPP_IPX:
- return 1;
+ if (set_bit (0, &ppp->ubuf->locked)) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "ppp_us_queue: can't get lock\n");
+ } else {
+ current_idx = ppp->ubuf->head;
/*
- * Process compressed IP frame. If the remote told us to reject frames then
- * do so now. Otherwise ensure that there is space in the buffer.
+ * Insert the buffer length (not counted), the protocol, and the data
*/
- case PPP_VJC_COMP:
- if (ppp->flags & SC_REJ_COMP_TCP) {
- return 1;
+ totlen = len + 2;
+ PUTC (totlen >> 8);
+ PUTC (totlen);
+
+ PUTC (proto >> 8);
+ PUTC (proto);
+
+ totlen -= 2;
+ while (totlen-- > 0) {
+ PUTC (*data++);
}
+#undef PUTC
/*
- * Uncompress the header. We now can _guarantee_ that there is room.
+ * The frame is complete. Update the head pointer and wakeup the pppd
+ * process.
*/
- count = slhc_uncompress (ppp->slcomp, data, count);
- if (count <= 0) {
- ppp->p.ppp_ierrors++;
- PRINTKN (1, (KERN_NOTICE
- "ppp: error in VJ decompression\n"));
- return 1;
+ ppp->ubuf->head = current_idx;
+
+ clear_bit (0, &ppp->ubuf->locked);
+ wake_up_interruptible (&ppp->read_wait);
+ if (ppp->tty->fasync != NULL)
+ kill_fasync (ppp->tty->fasync, SIGIO);
+
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp: successfully queued %d bytes, flags = %x\n",
+ len + 2, ppp->flags);
+
+ return 1;
+/*
+ * The buffer is full. Unlock the header
+ */
+failure:
+ clear_bit (0, &ppp->ubuf->locked);
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_us_queue: ran out of buffer space.\n");
+ }
+/*
+ * Discard the frame. There are no takers for this protocol.
+ */
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_WARNING
+ "ppp: dropping packet on the floor.\n");
+ slhc_toss (ppp->slcomp);
+ return 0;
+}
+
+/*
+ * Handle a CCP packet.
+ *
+ * The CCP packet is passed along to the pppd process just like any
+ * other PPP frame. The difference is that some processing needs to be
+ * immediate or the compressors will become confused on the peer.
+ */
+
+static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd)
+{
+ int slen = CCP_LENGTH(dp);
+ u_char *opt = dp + CCP_HDRLEN;
+ int opt_len = slen - CCP_HDRLEN;
+
+ if (slen > len)
+ return;
+
+ switch (CCP_CODE(dp)) {
+ case CCP_CONFREQ:
+ case CCP_TERMREQ:
+ case CCP_TERMACK:
+/*
+ * CCP must be going down - disable compression
+ */
+ if (ppp->flags & SC_CCP_UP) {
+ ppp->flags &= ~(SC_CCP_UP |
+ SC_COMP_RUN |
+ SC_DECOMP_RUN);
}
- proto = PPP_IP;
break;
+
+ case CCP_CONFACK:
+ if ((ppp->flags & SC_CCP_OPEN) == 0)
+ break;
+ if (ppp->flags & SC_CCP_UP)
+ break;
+ if (slen < (CCP_HDRLEN + CCP_OPT_MINLEN))
+ break;
+ if (slen < (CCP_OPT_LENGTH (opt) + CCP_HDRLEN))
+ break;
/*
- * Process uncompressed IP frame
+ * we're agreeing to send compressed packets.
*/
- case PPP_VJC_UNCOMP:
- if ((ppp->flags & SC_REJ_COMP_TCP) == 0) {
- if (slhc_remember (ppp->slcomp,
- data, count) <= 0) {
- ppp->p.ppp_ierrors++;
- PRINTKN (1, (KERN_NOTICE
- "ppp: error in VJ memorizing\n"));
- return 1;
- }
+ if (!rcvd) {
+ if (ppp->sc_xc_state == NULL)
+ break;
+
+ if ((*ppp->sc_xcomp->comp_init)
+ (ppp->sc_xc_state,
+ opt,
+ opt_len,
+ ppp2dev (ppp)->base_addr,
+ 0,
+ ppp->flags))
+ ppp->flags |= SC_COMP_RUN;
+ break;
+ }
+/*
+ * peer is agreeing to send compressed packets.
+ */
+ if (ppp->sc_rc_state == NULL)
+ break;
+
+ if ((*ppp->sc_rcomp->decomp_init)
+ (ppp->sc_rc_state,
+ opt,
+ opt_len,
+ ppp2dev (ppp)->base_addr,
+ 0,
+ ppp->mru,
+ ppp->flags)) {
+ ppp->flags |= SC_DECOMP_RUN;
+ ppp->flags &= ~(SC_DC_ERROR | SC_DC_FERROR);
}
- proto = PPP_IP;
break;
/*
- * The frame is not a valid IP frame. Ignore it.
+ * The protocol sequence is complete at this end
*/
- default:
- return 0;
+ case CCP_RESETACK:
+ if ((ppp->flags & SC_CCP_UP) == 0)
+ break;
+
+ if (!rcvd) {
+ if (ppp->sc_xc_state && (ppp->flags & SC_COMP_RUN))
+ (*ppp->sc_xcomp->comp_reset)(ppp->sc_xc_state);
+ } else {
+ if (ppp->sc_rc_state && (ppp->flags & SC_DECOMP_RUN)) {
+ (*ppp->sc_rcomp->decomp_reset)(ppp->sc_rc_state);
+ ppp->flags &= ~SC_DC_ERROR;
+ }
+ }
+ break;
}
+}
+
+static int
+rcv_proto_ccp (struct ppp *ppp, unsigned short proto, u_char *dp, int len)
+{
+ ppp_proto_ccp (ppp, dp, len, 1);
+ return rcv_proto_unknown (ppp, proto, dp, len);
+}
+
/*
- * If debugging net packets then print the information. Process the IP
- * frames first.
+ * Handle a LQR packet.
+ *
+ * The LQR packet is passed along to the pppd process just like any
+ * other PPP frame. The difference is that some processing needs to be
+ * performed to append the current data to the end of the frame.
*/
- if (ppp_debug_netpackets && proto == PPP_IP) {
- struct iphdr *iph = (struct iphdr *) data;
- PRINTK ((KERN_INFO
- "%s <-- src %lx dst %lx len %d\n",
- ppp->dev->name,
- iph->saddr,
- iph->daddr,
- count));
- }
+
+static int
+rcv_proto_lqr (struct ppp *ppp, unsigned short proto, u_char * data, int len)
+{
+#if 0 /* until support is in the pppd process don't corrupt the reject. */
+ register u_char *p;
+ if (len > 8) {
+ if (len < 48)
+ memset (&data [len], '\0', 48 - len);
/*
- * Generate a skb buffer for the new frame.
+ * Fill in the fields from the driver data
*/
- skb = alloc_skb (count, GFP_ATOMIC);
- if (skb == NULL) {
- PRINTK ((KERN_ERR
- "ppp_do_ip: packet dropped on %s (no memory)!\n",
- ppp->dev->name));
+ p = &data [48];
+ p = store_long (p, ++ppp->stats.ppp_ilqrs);
+ p = store_long (p, ppp->stats.ppp_ipackets);
+ p = store_long (p, ppp->stats.ppp_discards);
+ p = store_long (p, ppp->stats.ppp_ierrors);
+ p = store_long (p, ppp->stats.ppp_ioctects + len);
+
+ len = 68;
}
+#endif
/*
- * Move the received data from the input buffer to the skb buffer.
+ * Pass the frame to the pppd daemon.
*/
- else {
+ return rcv_proto_unknown (ppp, proto, data, len);
+}
+
+/* on entry, a received frame is in ppp->rbuf.bufr
+ check it and dispose as appropriate */
- skb->len = count; /* Store the length */
- skb->dev = ppp->dev; /* We are the device */
- memcpy ((u_char *) skb_data(skb), data, count); /* move data */
+static void ppp_doframe_lower (struct ppp *ppp, u_char *data, int count)
+{
+ u_short proto = PPP_PROTOCOL (data);
+ ppp_proto_type *proto_ptr;
/*
- * Tag the frame and kick it to the proper receive routine
+ * Ignore empty frames
*/
- skb->free = 1;
- netif_rx (skb); /* Receive the buffer */
- }
- return 1;
+ if (count <= 4)
+ return;
+/*
+ * Count the frame and print it
+ */
+ ++ppp->stats.ppp_ipackets;
+ if (ppp->flags & SC_LOG_INPKT)
+ ppp_print_buffer ("receive frame", data, count);
+/*
+ * Find the procedure to handle this protocol. The last one is marked
+ * as a protocol 0 which is the 'catch-all' to feed it to the pppd daemon.
+ */
+ proto_ptr = proto_list;
+ while (proto_ptr->proto != 0 && proto_ptr->proto != proto)
+ ++proto_ptr;
+/*
+ * Update the appropriate statistic counter.
+ */
+ if ((*proto_ptr->func) (ppp, proto,
+ &data[PPP_HARD_HDR_LEN],
+ count - PPP_HARD_HDR_LEN))
+ ppp->stats.ppp_ioctects += count;
+ else
+ ++ppp->stats.ppp_discards;
}
-/* stuff packet at BUF, length LEN, into the us_rbuff buffer
- prepend PROTO information */
+/* on entry, a received frame is in ppp->rbuf.bufr
+ check it and dispose as appropriate */
static int
-ppp_us_queue (struct ppp *ppp, unsigned short proto, u_char * data, int len)
+ppp_doframe (struct ppp *ppp)
{
- int totlen;
- register int current_idx;
+ u_char *data = buf_base (ppp->rbuf);
+ int count = ppp->rbuf->count;
+ int addr, ctrl, proto;
+ int new_count;
+ u_char *new_data;
/*
- * The total length includes the protocol data.
- * Lock the user information buffer.
+ * If there is a pending error from the receiver then log it and discard
+ * the damaged frame.
*/
- if (set_bit (0, &ppp->ubuf->locked)) {
- PRINTKN (1, (KERN_NOTICE "ppp_us_queue: can't get lock\n"));
+ if (ppp->toss) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_WARNING
+ "ppp_toss: tossing frame, reason = %d\n",
+ ppp->toss);
+ ppp->stats.ppp_ierrors++;
return 0;
}
- current_idx = ppp->ubuf->head;
-
-#define PUTC(c) \
-{ \
- buf_base (ppp->ubuf) [current_idx++] = (u_char) (c);\
- current_idx &= ppp->ubuf->size; \
- if (current_idx == ppp->ubuf->tail) { \
- goto failure; \
- } \
-}
-
/*
- * Insert the buffer length (not counted), the protocol, and the data
+ * An empty frame is ignored. This occurs if the FLAG sequence precedes and
+ * follows each frame.
*/
- totlen = len + 2;
- PUTC (totlen >> 8);
- PUTC (totlen);
-
- PUTC (proto >> 8);
- PUTC (proto);
-
- while (len-- > 0) {
- PUTC (*data++);
+ if (count == 0)
+ return 1;
+/*
+ * Generate an error if the frame is too small.
+ */
+ if (count < PPP_HARD_HDR_LEN) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_WARNING
+ "ppp: got runt ppp frame, %d chars\n", count);
+ slhc_toss (ppp->slcomp);
+ ppp->stats.ppp_ierrors++;
+ return 1;
}
-#undef PUTC
/*
- * The frame is complete. Update the head pointer and wakeup the pppd
- * process.
+ * Verify the CRC of the frame and discard the CRC characters from the
+ * end of the buffer.
+ */
+ if (ppp->rbuf->fcs != PPP_GOODFCS) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_WARNING
+ "ppp: frame with bad fcs, excess = %x\n",
+ ppp->rbuf->fcs ^ PPP_GOODFCS);
+ ppp->stats.ppp_ierrors++;
+ return 0;
+ }
+ count -= 2; /* ignore the fcs characters */
+/*
+ * Ignore the leading ADDRESS and CONTROL fields in the frame.
*/
- ppp->ubuf->head = current_idx;
+ addr = PPP_ALLSTATIONS;
+ ctrl = PPP_UI;
- clear_bit (0, &ppp->ubuf->locked); /* Unlock the buffer header */
- wake_up_interruptible (&ppp->read_wait); /* select() processing */
- if (ppp->tty->fasync != NULL) {
- kill_fasync (ppp->tty->fasync, SIGIO); /* SIGIO processing */
+ if ((data[0] == PPP_ALLSTATIONS) && (data[1] == PPP_UI)) {
+ data += 2;
+ count -= 2;
+ }
+/*
+ * Obtain the protocol from the frame
+ */
+ proto = (u_short) *data++;
+ if ((proto & 1) == 0) {
+ proto = (proto << 8) | (u_short) *data++;
+ --count;
}
+/*
+ * Rewrite the header with the full information. This may encroach upon
+ * the 'filler' area in the buffer header. This is the purpose for the
+ * filler.
+ */
+ *(--data) = proto;
+ *(--data) = proto >> 8;
+ *(--data) = ctrl;
+ *(--data) = addr;
+ count += 3;
+/*
+ * Process the active decompressor.
+ */
+ if ((ppp->sc_rc_state != (void *) 0) &&
+ (ppp->flags & SC_DECOMP_RUN) &&
+ ((ppp->flags & (SC_DC_FERROR | SC_DC_ERROR)) == 0)) {
+ if (proto == PPP_COMP) {
+/*
+ * If the frame is compressed then decompress it.
+ */
+ new_data = kmalloc (ppp->mru + 4, GFP_ATOMIC);
+ if (new_data == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_doframe: no memory\n");
+ slhc_toss (ppp->slcomp);
+ (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
+ data,
+ count);
+ return 1;
+ }
+/*
+ * Decompress the frame
+ */
+ new_count = bsd_decompress (ppp->sc_rc_state,
+ data,
+ count,
+ new_data,
+ ppp->mru + 4);
+ switch (new_count) {
+ default:
+ ppp_doframe_lower (ppp, new_data, new_count);
+ kfree (new_data);
+ return 1;
- PRINTKN (3, (KERN_INFO "ppp: successfully queued %d bytes\n", totlen));
- return 1;
+ case DECOMP_OK:
+ break;
+
+ case DECOMP_ERROR:
+ ppp->flags |= SC_DC_ERROR;
+ break;
+
+ case DECOMP_FATALERROR:
+ ppp->flags |= SC_DC_FERROR;
+ break;
+ }
/*
- * The buffer is full. Unlock the header and return the failure condition.
+ * Log the error condition and discard the frame.
*/
- failure:
- clear_bit (0, &ppp->ubuf->locked);
- PRINTKN (1, (KERN_NOTICE "ppp_us_queue: ran out of buffer space.\n"));
- return 0;
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_proto_comp: "
+ "decompress err %d\n", new_count);
+ kfree (new_data);
+ slhc_toss (ppp->slcomp);
+ return 1;
+ }
+/*
+ * The frame is not special. Pass it through the compressor without
+ * actually compressing the data
+ */
+ (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
+ data,
+ count);
+ }
+/*
+ * Process the uncompressed frame.
+ */
+ ppp_doframe_lower (ppp, data, count);
+ return 1;
}
/*************************************************************
ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf,
unsigned int nr)
{
- struct ppp *ppp = (struct ppp *) tty->disc_data;
+ struct ppp *ppp = tty2ppp (tty);
u_char c;
int len, indx;
#define GETC(c) \
{ \
- c = buf_base (ppp->ubuf) [ppp->ubuf->tail++]; \
- ppp->ubuf->tail &= ppp->ubuf->size; \
+ c = buf_base (ppp->ubuf) [ppp->ubuf->tail++]; \
+ ppp->ubuf->tail &= ppp->ubuf->size; \
}
/*
* Validate the pointer to the PPP structure
*/
- if (!ppp || ppp->magic != PPP_MAGIC) {
- PRINTKN (1, (KERN_ERR
- "ppp_tty_read: cannnot find ppp channel\n"));
+ if (!ppp)
return -EIO;
- }
+
+ if (ppp->magic != PPP_MAGIC)
+ return -EIO;
+
CHECK_PPP (-ENXIO);
- PRINTKN (4, (KERN_DEBUG "ppp_tty_read: called %x num %u\n",
- (unsigned int) buf,
- nr));
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "ppp_tty_read: called buf=%p nr=%u\n",
+ buf, nr);
/*
* Acquire the read lock.
*/
for (;;) {
+ ppp = tty2ppp (tty);
+ if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse)
+ return 0;
+
if (set_bit (0, &ppp->ubuf->locked) != 0) {
- PRINTKN (3, (KERN_DEBUG
- "ppp_tty_read: sleeping(ubuf)\n"));
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "ppp_tty_read: sleeping(ubuf)\n");
current->timeout = 0;
- current->state = TASK_INTERRUPTIBLE;
+ current->state = TASK_INTERRUPTIBLE;
schedule ();
- if (current->signal & ~current->blocked) {
+ if (current->signal & ~current->blocked)
return -EINTR;
- }
continue;
}
+/*
+ * Before we attempt to write the frame to the user, ensure that the
+ * user has access to the pages for the total buffer length.
+ */
+ indx = verify_area (VERIFY_WRITE, buf, nr);
+ if (indx != 0)
+ return (indx);
/*
* Fetch the length of the buffer from the first two bytes.
*/
- if (ppp->ubuf->head == ppp->ubuf->tail) {
+ if (ppp->ubuf->head == ppp->ubuf->tail)
len = 0;
- } else {
+ else {
GETC (c);
len = c << 8;
GETC (c);
/* no data */
clear_bit (0, &ppp->ubuf->locked);
if (file->f_flags & O_NONBLOCK) {
- PRINTKN (4, (KERN_DEBUG
- "ppp_tty_read: no data (EWOULDBLOCK)\n"));
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "ppp_tty_read: no data "
+ "(EWOULDBLOCK)\n");
return -EWOULDBLOCK;
}
current->timeout = 0;
- PRINTKN (3, (KERN_DEBUG
- "ppp_tty_read: sleeping(read_wait)\n"));
+
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "ppp_tty_read: sleeping(read_wait)\n");
+
interruptible_sleep_on (&ppp->read_wait);
- if (current->signal & ~current->blocked) {
+ if (current->signal & ~current->blocked)
return -EINTR;
- }
continue;
}
/*
* Reset the time of the last read operation.
*/
- ppp->ddinfo.nip_rjiffies = jiffies;
- PRINTKN (4, (KERN_DEBUG "ppp_tty_read: len = %d\n", len));
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG "ppp_tty_read: len = %d\n", len);
/*
* Ensure that the frame will fit within the caller's buffer. If not, then
* discard the frame from the input buffer and return an error to the caller.
*/
if (len + 2 > nr) {
/* Can't copy it, update us_rbuff_head */
- PRINTKN (1, (KERN_DEBUG
- "ppp: read of %u bytes too small for %d frame\n",
- nr, len + 2));
+
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "ppp: read of %u bytes too small for %d "
+ "frame\n", nr, len + 2);
ppp->ubuf->tail += len;
ppp->ubuf->tail &= ppp->ubuf->size;
clear_bit (0, &ppp->ubuf->locked);
- ppp->p.ppp_ierrors++;
+ ppp->stats.ppp_ierrors++;
return -EOVERFLOW;
}
+/*
+ * Before we attempt to write the frame to the user, ensure that the
+ * page tables are proper.
+ */
+ indx = verify_area (VERIFY_WRITE, buf, len + 2);
+ if (indx != 0) {
+ ppp->ubuf->tail += len;
+ ppp->ubuf->tail &= ppp->ubuf->size;
+ clear_bit (0, &ppp->ubuf->locked);
+ return (indx);
+ }
/*
* Fake the insertion of the ADDRESS and CONTROL information because these
* were not saved in the buffer.
*/
- put_fs_byte (PPP_ALLSTATIONS, buf++);
- put_fs_byte (PPP_UI, buf++);
+ put_byte_user (PPP_ALLSTATIONS, buf++);
+ put_byte_user (PPP_UI, buf++);
+
indx = len;
/*
* Copy the received data from the buffer to the caller's area.
*/
while (indx-- > 0) {
GETC (c);
- put_fs_byte (c, buf++);
+ put_byte_user (c, buf);
+ ++buf;
}
/*
* Release the lock and return the character count in the buffer area.
*/
clear_bit (0, &ppp->ubuf->locked);
len += 2; /* Account for ADDRESS and CONTROL bytes */
- PRINTKN (3,
- (KERN_DEBUG "ppp_tty_read: passing %d bytes up\n", len));
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "ppp_tty_read: passing %d bytes up\n", len);
return len;
}
#undef GETC
/*
* The buffer should not be full.
*/
- if ((buf->count < 0) || (buf->count > 3000)) {
- PRINTK ((KERN_DEBUG "ppp_stuff_char: %x %d\n",
- (unsigned int) buf->count,
- (unsigned int) buf->count))
+ if (ppp->flags & SC_DEBUG) {
+ if ((buf->count < 0) || (buf->count > 3000))
+ printk (KERN_DEBUG "ppp_stuff_char: %x %d\n",
+ (unsigned int) buf->count,
+ (unsigned int) chr);
}
/*
* Update the FCS and if the character needs to be escaped, do it.
ins_char (buf, chr);
}
+/*
+ * Procedure to encode the data with the proper escapement and send the
+ * data to the remote system.
+ */
+
+static void
+ppp_dev_xmit_lower (struct ppp *ppp, struct ppp_buffer *buf,
+ u_char *data, int count, int non_ip)
+{
+ unsigned short int write_fcs;
+ int address, control;
+ int proto;
+/*
+ * Insert the leading FLAG character
+ */
+ buf->count = 0;
+
+ if (non_ip || flag_time == 0)
+ ins_char (buf, PPP_FLAG);
+ else {
+ if (jiffies - ppp->last_xmit > flag_time)
+ ins_char (buf, PPP_FLAG);
+ }
+ ppp->last_xmit = jiffies;
+ buf->fcs = PPP_INITFCS;
+/*
+ * Emit the address/control information if needed
+ */
+ address = PPP_ADDRESS (data);
+ control = PPP_CONTROL (data);
+ proto = PPP_PROTOCOL (data);
+
+ if (address != PPP_ALLSTATIONS ||
+ control != PPP_UI ||
+ (ppp->flags & SC_COMP_AC) == 0) {
+ ppp_stuff_char (ppp, buf, address);
+ ppp_stuff_char (ppp, buf, control);
+ }
+/*
+ * Emit the protocol (compressed if possible)
+ */
+ if ((ppp->flags & SC_COMP_PROT) == 0 || (proto & 0xFF00))
+ ppp_stuff_char (ppp, buf, proto >> 8);
+
+ ppp_stuff_char (ppp, buf, proto);
+/*
+ * Insert the data
+ */
+ data += 4;
+ count -= 4;
+
+ while (count-- > 0)
+ ppp_stuff_char (ppp, buf, *data++);
+/*
+ * Add the trailing CRC and the final flag character
+ */
+ write_fcs = buf->fcs ^ 0xFFFF;
+ ppp_stuff_char (ppp, buf, write_fcs);
+ ppp_stuff_char (ppp, buf, write_fcs >> 8);
+
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG "ppp_dev_xmit_lower: fcs is %hx\n",
+ write_fcs);
+/*
+ * Add the trailing flag character
+ */
+ ins_char (buf, PPP_FLAG);
+/*
+ * Print the buffer
+ */
+ if (ppp->flags & SC_LOG_FLUSH)
+ ppp_print_buffer ("ppp flush", buf_base (buf),
+ buf->count);
+ else {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "ppp_dev_xmit: writing %d chars\n",
+ buf->count);
+ }
+/*
+ * Send the block to the tty driver.
+ */
+ ppp->stats.ppp_obytes += buf->count;
+ ppp_kick_tty (ppp, buf);
+}
+
+/*
+ * Send an frame to the remote with the proper bsd compression.
+ *
+ * Return 0 if frame was queued for transmission.
+ * 1 if frame must be re-queued for later driver support.
+ */
+
+static int
+ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
+ u_char *data, int count)
+{
+ int proto;
+ int address, control;
+ u_char *new_data;
+ int new_count;
+/*
+ * Print the buffer
+ */
+ if (ppp->flags & SC_LOG_OUTPKT)
+ ppp_print_buffer ("write frame", data, count);
+/*
+ * Determine if the frame may be compressed. Attempt to compress the
+ * frame if possible.
+ */
+ proto = PPP_PROTOCOL (data);
+ address = PPP_ADDRESS (data);
+ control = PPP_CONTROL (data);
+
+ if (((ppp->flags & SC_COMP_RUN) != 0) &&
+ (ppp->sc_xc_state != (void *) 0) &&
+ (address == PPP_ALLSTATIONS) &&
+ (control == PPP_UI) &&
+ (proto != PPP_LCP) &&
+ (proto != PPP_CCP)) {
+ new_data = kmalloc (count, GFP_ATOMIC);
+ if (new_data == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_dev_xmit_frame: no memory\n");
+ return 1;
+ }
+
+ new_count = bsd_compress (ppp->sc_xc_state,
+ data,
+ new_data,
+ count,
+ count);
+
+ if (new_count > 0) {
+ ++ppp->stats.ppp_opackets;
+ ppp->stats.ppp_ooctects += new_count;
+
+ ppp_dev_xmit_lower (ppp, buf, new_data,
+ new_count, 0);
+ kfree (new_data);
+ return 0;
+ }
+/*
+ * The frame could not be compressed.
+ */
+ kfree (new_data);
+ }
+/*
+ * The frame may not be compressed. Update the statistics before the
+ * count field is destroyed. The frame will be transmitted.
+ */
+ ++ppp->stats.ppp_opackets;
+ ppp->stats.ppp_ooctects += count;
+/*
+ * Go to the escape encoding
+ */
+ ppp_dev_xmit_lower (ppp, buf, data, count, !!(proto & 0xFF00));
+ return 0;
+}
+
+/*
+ * Revise the tty frame for specific protocols.
+ */
+
+static int
+send_revise_frame (register struct ppp *ppp, u_char *data, int len)
+{
+ u_char *p;
+
+ switch (PPP_PROTOCOL (data)) {
+/*
+ * Update the LQR frame with the current MIB information. This saves having
+ * the daemon read old MIB data from the driver.
+ */
+ case PPP_LQR:
+ len = 48; /* total size of this frame */
+ p = (u_char *) &data [40]; /* Point to last two items. */
+ p = store_long (p, ppp->stats.ppp_opackets + 1);
+ p = store_long (p, ppp->stats.ppp_ooctects + len);
+ break;
+/*
+ * Outbound compression frames
+ */
+ case PPP_CCP:
+ ppp_proto_ccp (ppp,
+ data + PPP_HARD_HDR_LEN,
+ len - PPP_HARD_HDR_LEN,
+ 0);
+ break;
+/*
+ * All other frame types
+ */
+ default:
+ break;
+ }
+
+ return len;
+}
+
/*
* write a frame with NR chars from BUF to TTY
* we have to put the FCS field on ourselves
*/
static int
-ppp_tty_write (struct tty_struct *tty, struct file *file, u_char * buf,
+ppp_tty_write (struct tty_struct *tty, struct file *file, const u_char * data,
unsigned int count)
{
- struct ppp *ppp = (struct ppp *) tty->disc_data;
- int indx;
- unsigned short write_fcs;
+ struct ppp *ppp = tty2ppp (tty);
+ u_char *new_data;
+ int status;
/*
* Verify the pointer to the PPP data and that the tty is still in PPP mode.
*/
- if (!ppp || ppp->magic != PPP_MAGIC) {
- PRINTKN (1,(KERN_ERR "ppp_tty_write: cannot find ppp unit\n"));
+ if (!ppp)
return -EIO;
- }
+
+ if (ppp->magic != PPP_MAGIC)
+ return -EIO;
+
CHECK_PPP (-ENXIO);
-/*
- * Detech a change in the transfer size
- */
- if (ppp->mtu != ppp->dev->mtu) { /* Someone has been ifconfigging */
- ppp_changedmtu (ppp,
- ppp->dev->mtu,
- ppp->mru);
- }
/*
* Ensure that the caller does not wish to send too much.
*/
if (count > PPP_MTU) {
- PRINTKN (1, (KERN_WARNING
- "ppp_tty_write: truncating user packet from %u to mtu %d\n",
- count, PPP_MTU));
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_WARNING
+ "ppp_tty_write: truncating user packet "
+ "from %u to mtu %d\n", count, PPP_MTU);
count = PPP_MTU;
}
/*
- * Print the buffer
+ * Allocate a buffer for the data and fetch it from the user space.
*/
- if (ppp_debug >= 3) {
- ppp_print_buffer ("write frame", buf, count, USER_DS);
+ new_data = kmalloc (count, GFP_KERNEL);
+ if (new_data == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_tty_write: no memory\n");
+ return 0;
}
/*
* lock this PPP unit so we will be the only writer;
*/
while (lock_buffer (ppp->tbuf) != 0) {
current->timeout = 0;
- PRINTKN (3, (KERN_DEBUG "ppp_tty_write: sleeping\n"));
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG "ppp_tty_write: sleeping\n");
interruptible_sleep_on (&ppp->write_wait);
+
+ ppp = tty2ppp (tty);
+ if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse) {
+ kfree (new_data);
+ return 0;
+ }
+
if (current->signal & ~current->blocked) {
+ kfree (new_data);
return -EINTR;
}
}
/*
- * OK, locked. Add the leading FLAG character to the buffer.
+ * Ensure that the caller's buffer is valid.
*/
- PRINTKN (4, (KERN_DEBUG "ppp_tty_write: acquired write lock\n"));
- ppp->tbuf->count = 0;
-
-#ifdef OPTIMIZE_FLAG_TIME
- if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME) {
- ins_char (ppp->tbuf, PPP_FLAG);
+ status = verify_area (VERIFY_READ, data, count);
+ if (status != 0) {
+ kfree (new_data);
+ ppp->tbuf->locked = 0;
+ return status;
}
- ppp->last_xmit = jiffies;
-#else
- ins_char (ppp->tbuf, PPP_FLAG);
-#endif
+
+ memcpy_fromfs (new_data, data, count);
/*
- * Add the data for the frame to the buffer.
+ * Change the LQR frame
*/
- ppp->tbuf->fcs = PPP_INITFCS;
- indx = count;
- while (indx-- > 0) {
- register char chr = get_fs_byte (buf++);
- ppp_stuff_char (ppp, ppp->tbuf, chr);
- }
+ count = send_revise_frame (ppp, new_data, count);
/*
- * Add the trailing CRC and the final flag character
+ * Send the data
*/
- write_fcs = ppp->tbuf->fcs ^ 0xFFFF;
- ppp_stuff_char (ppp, ppp->tbuf, write_fcs);
- ppp_stuff_char (ppp, ppp->tbuf, write_fcs >> 8);
+ ppp_dev_xmit_frame (ppp, ppp->tbuf, new_data, count);
+ kfree (new_data);
+ return (int) count;
+}
- PRINTKN (4, (KERN_DEBUG "ppp_tty_write: fcs is %hx\n", write_fcs));
/*
- * Add the trailing FLAG character
+ * Process the BSD compression IOCTL event for the tty device.
*/
- ins_char (ppp->tbuf, PPP_FLAG);
+
+static int
+ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp)
+{
+ struct compressor *cp;
+ struct ppp_option_data data;
+ int error;
+ int nb;
+ u_char *ptr;
+ u_char ccp_option[CCP_MAX_OPTION_LENGTH];
/*
- * Update the time and print the data to the debug log.
+ * Fetch the compression parameters
*/
- ppp->ddinfo.nip_sjiffies = jiffies;
+ error = verify_area (VERIFY_READ, odp, sizeof (data));
+ if (error == 0) {
+ memcpy_fromfs (&data, odp, sizeof (data));
+ nb = data.length;
+ ptr = data.ptr;
+ if ((unsigned long) nb >= (unsigned long)CCP_MAX_OPTION_LENGTH)
+ nb = CCP_MAX_OPTION_LENGTH;
+
+ error = verify_area (VERIFY_READ, ptr, nb);
+ }
- if (ppp_debug >= 6) {
- ppp_print_buffer ("xmit buffer",
- buf_base (ppp->tbuf),
- ppp->tbuf->count,
- KERNEL_DS);
- } else {
- PRINTKN (4, (KERN_DEBUG
- "ppp_tty_write: writing %d chars\n", ppp->tbuf->count));
+ if (error != 0)
+ return error;
+
+ memcpy_fromfs (ccp_option, ptr, nb);
+
+ if (ccp_option[1] < 2) /* preliminary check on the length byte */
+ return (-EINVAL);
+
+ cp = find_compressor ((int) (unsigned) (unsigned char) ccp_option[0]);
+ if (cp != (struct compressor *) 0) {
+ /*
+ * Found a handler for the protocol - try to allocate
+ * a compressor or decompressor.
+ */
+ error = 0;
+ if (data.transmit) {
+ if (ppp->sc_xc_state != NULL)
+ (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state);
+
+ ppp->sc_xcomp = cp;
+ ppp->sc_xc_state = cp->comp_alloc(ccp_option, nb);
+
+ if (ppp->sc_xc_state == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk("ppp%ld: comp_alloc failed\n",
+ ppp2dev (ppp)->base_addr);
+ error = -ENOBUFS;
+ }
+ ppp->flags &= ~SC_COMP_RUN;
+ } else {
+ if (ppp->sc_rc_state != NULL)
+ (*ppp->sc_rcomp->decomp_free)(ppp->sc_rc_state);
+ ppp->sc_rcomp = cp;
+ ppp->sc_rc_state = cp->decomp_alloc(ccp_option, nb);
+ if (ppp->sc_rc_state == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk("ppp%ld: decomp_alloc failed\n",
+ ppp2dev (ppp)->base_addr);
+ error = ENOBUFS;
+ }
+ ppp->flags &= ~SC_DECOMP_RUN;
+ }
+ return (error);
}
-/*
- * Start the transmitter and the request is complete.
- */
- ppp->p.ppp_obytes += ppp->tbuf->count;
- ++ppp->p.ppp_opackets;
- ppp_kick_tty (ppp, ppp->tbuf);
- return ((int) count);
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "ppp%ld: no compressor for [%x %x %x], %x\n",
+ ppp2dev (ppp)->base_addr, ccp_option[0], ccp_option[1],
+ ccp_option[2], nb);
+ return (-EINVAL); /* no handler found */
}
/*
ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
unsigned long param3)
{
- struct ppp *ppp = (struct ppp *) tty->disc_data;
+ struct ppp *ppp = tty2ppp (tty);
register int temp_i = 0;
int error;
/*
* Verify the status of the PPP device.
*/
- if (!ppp || ppp->magic != PPP_MAGIC) {
- PRINTK ((KERN_ERR
- "ppp_tty_ioctl: can't find PPP block from tty!\n"));
+ if (!ppp)
return -EBADF;
- }
+
+ if (ppp->magic != PPP_MAGIC)
+ return -EBADF;
+
CHECK_PPP (-ENXIO);
/*
* The user must have an euid of root to do these requests.
*/
- if (!suser ()) {
+ if (!suser ())
return -EPERM;
- }
/*
* Set the MRU value
*/
error = verify_area (VERIFY_READ, (void *) param3,
sizeof (temp_i));
if (error == 0) {
- PRINTKN (3, (KERN_INFO
- "ppp_tty_ioctl: set mru to %x\n", temp_i));
- temp_i = (int) get_fs_long (param3);
- if (ppp->mru != temp_i) {
- ppp_changedmtu (ppp, ppp->dev->mtu, temp_i);
- }
+ temp_i = get_int_user ((int *) param3);
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: set mru to %x\n", temp_i);
+
+ if (ppp->mru != temp_i)
+ ppp_changedmtu (ppp, ppp2dev (ppp)->mtu, temp_i);
}
break;
/*
temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 |
SC_RCV_ODDP | SC_RCV_EVNP;
#endif
- put_fs_long ((long) temp_i, param3);
- PRINTKN (3, (KERN_DEBUG
- "ppp_tty_ioctl: get flags: addr %lx flags %x\n",
- param3, temp_i));
+ put_long_user ((long) temp_i, param3);
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "ppp_tty_ioctl: get flags: addr %lx flags "
+ "%x\n", param3, temp_i);
}
break;
/*
error = verify_area (VERIFY_READ, (void *) param3,
sizeof (temp_i));
if (error == 0) {
- temp_i = (int) get_fs_long (param3);
- ppp->flags ^= ((ppp->flags ^ temp_i) & SC_MASK);
- PRINTKN (3, (KERN_INFO
- "ppp_tty_ioctl: set flags to %x\n", temp_i));
+ temp_i = get_int_user (param3) & SC_MASK;
+ temp_i |= (ppp->flags & ~SC_MASK);
+
+ if ((ppp->flags & SC_CCP_OPEN) &&
+ (temp_i & SC_CCP_OPEN) == 0)
+ ppp_ccp_closed (ppp);
+
+ if ((ppp->flags | temp_i) & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: set flags to %x\n", temp_i);
+ ppp->flags = temp_i;
}
break;
+/*
+ * Set the compression mode
+ */
+ case PPPIOCSCOMPRESS:
+ error = ppp_set_compression (ppp,
+ (struct ppp_option_data *) param3);
+ break;
/*
* Retrieve the transmit async map
*/
error = verify_area (VERIFY_WRITE, (void *) param3,
sizeof (temp_i));
if (error == 0) {
- put_fs_long (ppp->xmit_async_map[0], param3);
- PRINTKN (3, (KERN_INFO
- "ppp_tty_ioctl: get asyncmap: addr %lx asyncmap %lx\n",
- param3, ppp->xmit_async_map[0]));
+ put_long_user (ppp->xmit_async_map[0], param3);
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: get asyncmap: addr "
+ "%lx asyncmap %lx\n",
+ param3,
+ (unsigned long) ppp->xmit_async_map[0]);
}
break;
/*
error = verify_area (VERIFY_READ, (void *) param3,
sizeof (temp_i));
if (error == 0) {
- ppp->xmit_async_map[0] = get_fs_long (param3);
- PRINTKN (3, (KERN_INFO
+ ppp->xmit_async_map[0] = get_long_user (param3);
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
"ppp_tty_ioctl: set xmit asyncmap %lx\n",
- ppp->xmit_async_map[0]));
+ (unsigned long) ppp->xmit_async_map[0]);
}
break;
/*
error = verify_area (VERIFY_READ, (void *) param3,
sizeof (temp_i));
if (error == 0) {
- ppp->recv_async_map = get_fs_long (param3);
- PRINTKN (3, (KERN_INFO
+ ppp->recv_async_map = get_long_user (param3);
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
"ppp_tty_ioctl: set rcv asyncmap %lx\n",
- ppp->recv_async_map));
+ (unsigned long) ppp->recv_async_map);
}
break;
/*
error = verify_area (VERIFY_WRITE, (void *) param3,
sizeof (temp_i));
if (error == 0) {
- put_fs_long (ppp->dev->base_addr, param3);
- PRINTKN (3,
- (KERN_INFO "ppp_tty_ioctl: get unit: %d",
- ppp->dev->base_addr));
+ put_long_user (ppp2dev (ppp)->base_addr, param3);
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: get unit: %ld",
+ ppp2dev (ppp)->base_addr);
}
break;
/*
error = verify_area (VERIFY_READ, (void *) param3,
sizeof (temp_i));
if (error == 0) {
- ppp_debug = (int) get_fs_long (param3);
- ppp_debug_netpackets = (ppp_debug & 0xff00) >> 8;
- ppp_debug &= 0xff;
- PRINTKN (1, (KERN_INFO
- "ppp_tty_ioctl: set debug level %d, netpacket %d\n",
- ppp_debug, ppp_debug_netpackets));
+ temp_i = (get_int_user (param3) & 0x1F) << 16;
+ temp_i |= (ppp->flags & ~0x1F0000);
+
+ if ((ppp->flags | temp_i) & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: set flags to %x\n", temp_i);
+ ppp->flags = temp_i;
}
break;
/*
error = verify_area (VERIFY_WRITE, (void *) param3,
sizeof (temp_i));
if (error == 0) {
- put_fs_long ((long) (ppp_debug |
- (ppp_debug_netpackets << 8)),
- param3);
-
- PRINTKN (3, (KERN_INFO
- "ppp_tty_ioctl: get debug level %d\n",
- ppp_debug | (ppp_debug_netpackets << 8)));
- }
+ temp_i = (ppp->flags >> 16) & 0x1F;
+ put_long_user ((long) temp_i, param3);
+
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: get debug level %d\n",
+ temp_i);
+ }
break;
/*
* Get the times since the last send/receive frame operation
*/
- case PPPIOCGTIME:
+ case PPPIOCGIDLE:
error = verify_area (VERIFY_WRITE, (void *) param3,
- sizeof (struct ppp_ddinfo));
+ sizeof (struct ppp_idle));
if (error == 0) {
- struct ppp_ddinfo cur_ddinfo;
+ struct ppp_idle cur_ddinfo;
unsigned long cur_jiffies = jiffies;
/* change absolute times to relative times. */
- cur_ddinfo.ip_sjiffies = cur_jiffies - ppp->ddinfo.ip_sjiffies;
- cur_ddinfo.ip_rjiffies = cur_jiffies - ppp->ddinfo.ip_rjiffies;
- cur_ddinfo.nip_sjiffies = cur_jiffies - ppp->ddinfo.nip_sjiffies;
- cur_ddinfo.nip_rjiffies = cur_jiffies - ppp->ddinfo.nip_rjiffies;
-
+ cur_ddinfo.xmit_idle = (cur_jiffies - ppp->ddinfo.xmit_idle) / HZ;
+ cur_ddinfo.recv_idle = (cur_jiffies - ppp->ddinfo.recv_idle) / HZ;
memcpy_tofs ((void *) param3, &cur_ddinfo,
- sizeof (struct ppp_ddinfo));
- PRINTKN (3, (KERN_INFO
- "ppp_tty_ioctl: read demand dial info\n"));
+ sizeof (cur_ddinfo));
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: read demand dial info\n");
}
break;
/*
memcpy_tofs ((void *) param3,
ppp->xmit_async_map,
sizeof (ppp->xmit_async_map));
- PRINTKN (3, (KERN_INFO
- "ppp_tty_ioctl: get xasyncmap: addr %lx\n",
- param3));
+
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: get xasyncmap: addr %lx\n",
+ param3);
}
break;
/*
error = verify_area (VERIFY_READ, (void *) param3,
sizeof (ppp->xmit_async_map));
if (error == 0) {
- unsigned long temp_tbl[8];
+ __u32 temp_tbl[8];
memcpy_fromfs (temp_tbl, (void *) param3,
sizeof (ppp->xmit_async_map));
- temp_tbl[1] = 0x00000000;
+ temp_tbl[1] = 0x00000000;
temp_tbl[2] &= ~0x40000000;
- temp_tbl[3] |= 0x60000000;
+ temp_tbl[3] |= 0x60000000;
if ((temp_tbl[2] & temp_tbl[3]) != 0 ||
(temp_tbl[4] & temp_tbl[5]) != 0 ||
- (temp_tbl[6] & temp_tbl[7]) != 0) {
+ (temp_tbl[6] & temp_tbl[7]) != 0)
error = -EINVAL;
- } else {
+ else {
memcpy (ppp->xmit_async_map, temp_tbl,
sizeof (ppp->xmit_async_map));
- PRINTKN (3, (KERN_INFO
- "ppp_tty_ioctl: set xasyncmap\n"));
+
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: set xasyncmap\n");
}
}
break;
error = verify_area (VERIFY_READ, (void *) param3,
sizeof (temp_i));
if (error == 0) {
- temp_i = (int) get_fs_long (param3) + 1;
- PRINTKN (3, (KERN_INFO
+ temp_i = get_int_user (param3) + 1;
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
"ppp_tty_ioctl: set maxcid to %d\n",
- temp_i));
- if (ppp->slcomp != NULL) {
+ temp_i);
+ if (ppp->slcomp != NULL)
slhc_free (ppp->slcomp);
- }
- ppp->slcomp = slhc_init (temp_i, temp_i);
+ ppp->slcomp = slhc_init (16, temp_i);
if (ppp->slcomp == NULL) {
- PRINTKN (1, (KERN_ERR
- "ppp: no space for compression buffers!\n"));
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp: no space for compression buffers!\n");
ppp_release (ppp);
error = -ENOMEM;
}
* All other ioctl() events will come here.
*/
default:
- PRINTKN (1, (KERN_ERR
- "ppp_tty_ioctl: invalid ioctl: %x, addr %lx\n",
- param2,
- param3));
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_tty_ioctl: invalid ioctl: %x, addr %lx\n",
+ param2,
+ param3);
error = -ENOIOCTLCMD;
break;
ppp_tty_select (struct tty_struct *tty, struct inode *inode,
struct file *filp, int sel_type, select_table * wait)
{
- struct ppp *ppp = (struct ppp *) tty->disc_data;
+ struct ppp *ppp = tty2ppp (tty);
int result = 1;
/*
* Verify the status of the PPP device.
*/
- if (!ppp || ppp->magic != PPP_MAGIC) {
- PRINTK ((KERN_ERR
- "ppp_tty_select: can't find PPP block from tty!\n"));
+ if (!ppp)
return -EBADF;
- }
+
+ if (ppp->magic != PPP_MAGIC)
+ return -EBADF;
+
CHECK_PPP (0);
/*
* Branch on the type of select mode. A read request must lock the user
*/
case SEL_EX:
/* Is this a pty link and the remote disconnected? */
- if (tty->flags & (1 << TTY_SLAVE_CLOSED)) {
+ if (tty->flags & (1 << TTY_SLAVE_CLOSED))
break;
- }
+
/* Is this a local link and the modem disconnected? */
- if (tty_hung_up_p (filp)) {
+ if (tty_hung_up_p (filp))
break;
- }
+
select_wait (&ppp->read_wait, wait);
result = 0;
break;
}
break;
}
-
return result;
}
static int
ppp_dev_open (struct device *dev)
{
- struct ppp *ppp = &ppp_ctrl[dev->base_addr];
+ struct ppp *ppp = dev2ppp (dev);
/* reset POINTOPOINT every time, since dev_close zaps it! */
dev->flags |= IFF_POINTOPOINT;
- if (ppp->tty == NULL) {
- PRINTKN (1,
- (KERN_ERR "ppp: %s not connected to a TTY! can't go open!\n",
- dev->name));
+ if (ppp2tty (ppp) == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp: %s not connected to a TTY! can't go open!\n",
+ dev->name);
return -ENXIO;
}
- PRINTKN (2, (KERN_INFO "ppp: channel %s going up for IP packets!\n",
- dev->name));
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp: channel %s going up for IP packets!\n",
+ dev->name);
CHECK_PPP (-ENXIO);
return 0;
static int
ppp_dev_close (struct device *dev)
{
- struct ppp *ppp = &ppp_ctrl[dev->base_addr];
+ struct ppp *ppp = dev2ppp (dev);
- if (ppp->tty == NULL) {
- PRINTKN (1,
- (KERN_ERR "ppp: %s not connected to a TTY! can't go down!\n",
- dev->name));
+ if (ppp2tty (ppp) == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp: %s not connected to a TTY! can't go down!\n",
+ dev->name);
return -ENXIO;
}
/*
* We don't do anything about the device going down. It is not important
* for us.
*/
- PRINTKN (2, (KERN_INFO "ppp: channel %s going down for IP packets!\n",
- dev->name));
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp: channel %s going down for IP packets!\n",
+ dev->name);
CHECK_PPP (-ENXIO);
return 0;
}
*/
static int
-ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr)
+ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev)
{
struct ppp_stats *result, temp;
int error;
* Supply the information for the caller. First move the version data
* then move the ppp stats; and finally the vj stats.
*/
- if (error == 0) {
- memset (&temp, 0, sizeof(temp));
- memcpy (&temp.p, &ppp->p, sizeof (struct pppstat));
-/*
- * Header Compression statistics
- */
+ memset (&temp, 0, sizeof(temp));
+ if (error == 0 && dev->flags & IFF_UP) {
+ memcpy (&temp.p, &ppp->stats, sizeof (struct pppstat));
if (ppp->slcomp != NULL) {
- temp.vj.vjs_packets = ppp->slcomp->sls_o_nontcp +
- ppp->slcomp->sls_o_tcp;
+ temp.vj.vjs_packets = ppp->slcomp->sls_o_compressed+
+ ppp->slcomp->sls_o_uncompressed;
temp.vj.vjs_compressed = ppp->slcomp->sls_o_compressed;
temp.vj.vjs_searches = ppp->slcomp->sls_o_searches;
temp.vj.vjs_misses = ppp->slcomp->sls_o_misses;
temp.vj.vjs_uncompressedin = ppp->slcomp->sls_i_uncompressed;
temp.vj.vjs_compressedin = ppp->slcomp->sls_i_compressed;
}
-
+ }
/*
* Move the data to the caller's buffer
*/
+ if (error == 0)
memcpy_tofs (result, &temp, sizeof (temp));
- }
return error;
}
-#ifdef PPP_COMPRESS
+/*
+ * IOCTL to read the compression statistics for the pppstats program.
+ */
static int
-ppp_dev_ioctl_stats (struct ppp *ppp, struct ifreq *ifr)
+ppp_dev_ioctl_comp_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev)
{
struct ppp_comp_stats *result, temp;
int error;
result,
sizeof (temp));
/*
- * Supply the information for the caller. Get the frame data compression
- * statistics and move them out to the caller.
+ * Supply the information for the caller.
*/
- if (error == 0) {
- memset (&temp, 0, sizeof(temp));
-
+ memset (&temp, 0, sizeof(temp));
+ if (error == 0 && dev->flags & IFF_UP) {
if (ppp->sc_xc_state != NULL)
(*ppp->sc_xcomp->comp_stat) (ppp->sc_xc_state,
&temp.c);
if (ppp->sc_rc_state != NULL)
(*ppp->sc_rcomp->decomp_stat) (ppp->sc_rc_state,
&temp.d);
-
+ }
/*
* Move the data to the caller's buffer
*/
+ if (error == 0)
memcpy_tofs (result, &temp, sizeof (temp));
- }
return error;
}
-#endif /* PPP_COMPRESS */
-
/*
* Callback from the network layer to process the sockioctl functions.
*/
static int
ppp_dev_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
{
- struct ppp *ppp = &ppp_ctrl[dev->base_addr];
+ struct ppp *ppp = dev2ppp (dev);
int error;
/*
* Process the requests
*/
switch (cmd) {
case SIOCGPPPSTATS:
- error = ppp_dev_ioctl_stats (ppp, ifr);
+ error = ppp_dev_ioctl_stats (ppp, ifr, dev);
break;
-#ifdef PPP_COMPRESS
case SIOCGPPPCSTATS:
- error = ppp_dev_ioctl_cstats (ppp, ifr);
+ error = ppp_dev_ioctl_comp_stats (ppp, ifr, dev);
break;
-#endif /* PPP_COMPRESS */
case SIOCGPPPVER:
error = ppp_dev_ioctl_version (ppp, ifr);
}
/*
- * Send a frame to the remote.
+ * Send an IP frame to the remote with vj header compression.
+ *
+ * Return 0 if frame was queued for transmission.
+ * 1 if frame must be re-queued for later driver support.
*/
-int
-ppp_dev_xmit (sk_buff *skb, struct device *dev)
+#if defined(IPX_CHANGE)
+#define ppp_dev_xmit_ip1 ppp_dev_xmit_ip
+#endif
+
+static int
+ppp_dev_xmit_ip1 (struct device *dev, struct ppp *ppp, u_char *data)
{
- struct tty_struct *tty;
- struct ppp *ppp;
- u_char *data;
- unsigned short proto;
- int len;
- unsigned short write_fcs;
-/*
- * just a little sanity check.
- */
- if (skb == NULL) {
- PRINTKN (3, (KERN_WARNING "ppp_dev_xmit: null packet!\n"));
- return 0;
- }
+ int proto = PPP_IP;
+ int len;
+ struct ppp_hdr *hdr;
+ struct tty_struct *tty = ppp2tty (ppp);
/*
- * Fetch the poitners to the data
+ * Obtain the length from the IP header.
*/
- ppp = &ppp_ctrl[dev->base_addr];
- tty = ppp->tty;
- data = (u_char *) (&skb[1]);
- len = skb->len;
- proto = PPP_IP;
-
- PRINTKN (4, (KERN_DEBUG "ppp_dev_xmit [%s]: skb %lX busy %d\n",
- dev->name,
- (unsigned long int) skb, ppp->wbuf->locked));
-
- CHECK_PPP (0);
+ len = ((struct iphdr *)data) -> tot_len;
+ len = ntohs (len);
/*
* Validate the tty interface
*/
- do {
- if (tty == NULL) {
- PRINTKN (1,
- (KERN_ERR "ppp_dev_xmit: %s not connected to a TTY!\n",
- dev->name));
- break;
- }
+ if (tty == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_dev_xmit: %s not connected to a TTY!\n",
+ dev->name);
+ return 0;
+ }
/*
* Ensure that the PPP device is still up
*/
- if (!(dev->flags & IFF_UP)) {
- PRINTKN (1, (KERN_WARNING
+ if (!(dev->flags & IFF_UP)) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_WARNING
"ppp_dev_xmit: packet sent on interface %s,"
" which is down for IP\n",
- dev->name));
- break;
- }
+ dev->name);
+ return 0;
+ }
/*
* Detect a change in the transfer size
*/
- if (ppp->mtu != ppp->dev->mtu) {
- ppp_changedmtu (ppp,
- ppp->dev->mtu,
- ppp->mru);
- }
-/*
- * Fetch the length from the IP header.
- */
- if (len < sizeof (struct iphdr)) {
- PRINTKN (0, (KERN_ERR
- "ppp_dev_xmit: given runt packet, ignoring\n"));
- break;
- }
- len = ntohs (((struct iphdr *) skb_data(skb))->tot_len);
+ if (ppp->mtu != ppp2dev (ppp)->mtu) {
+ ppp_changedmtu (ppp,
+ ppp2dev (ppp)->mtu,
+ ppp->mru);
+ }
/*
* Acquire the lock on the transmission buffer. If the buffer was busy then
* mark the device as busy and return "failure to send, try back later" error.
*/
- if (lock_buffer (ppp->wbuf) != 0) {
- dev->tbusy = 1;
- return 1;
- }
+ if (lock_buffer (ppp->wbuf) != 0) {
+ dev->tbusy = 1;
+ return 1;
+ }
+/*
+ * Print the frame being sent
+ */
+ if (ppp->flags & SC_LOG_OUTPKT)
+ ppp_print_buffer ("ppp outpkt", data, len);
/*
* At this point, the buffer will be transmitted. There is no other exit.
*
* Try to compress the header.
*/
- if (ppp->flags & SC_COMP_TCP) {
- /* last 0 argument says don't compress connection ID */
- len = slhc_compress (ppp->slcomp, data, len,
- buf_base (ppp->cbuf),
- &data, 0);
-
- if (data[0] & SL_TYPE_COMPRESSED_TCP) {
- proto = PPP_VJC_COMP;
- } else {
- if (data[0] >= SL_TYPE_UNCOMPRESSED_TCP) {
- proto = PPP_VJC_UNCOMP;
- data[0] = (data[0] & 0x0f) | 0x40;
- }
- }
- }
+ if (ppp->flags & SC_COMP_TCP) {
+ len = slhc_compress (ppp->slcomp, data, len,
+ buf_base (ppp->cbuf) + PPP_HARD_HDR_LEN,
+ &data,
+ (ppp->flags & SC_NO_TCP_CCID) == 0);
- if (ppp_debug_netpackets) {
- struct iphdr *iph = (struct iphdr *) skb_data(skb);
- PRINTK ((KERN_DEBUG "%s ==> proto %x len %d src %x "
- "dst %x proto %d\n",
- dev->name, (int) proto, (int) len, (int) iph->saddr,
- (int) iph->daddr, (int) iph->protocol))
+ if (data[0] & SL_TYPE_COMPRESSED_TCP) {
+ proto = PPP_VJC_COMP;
+ data[0] ^= SL_TYPE_COMPRESSED_TCP;
+ } else {
+ if (data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
+ proto = PPP_VJC_UNCOMP;
+ data[0] = (data[0] & 0x0f) | 0x40;
}
+ }
/*
- * Insert the leading FLAG character
+ * Send the frame
*/
- ppp->wbuf->count = 0;
+ len += PPP_HARD_HDR_LEN;
+ hdr = &((struct ppp_hdr *) data)[-1];
-#ifdef OPTIMIZE_FLAG_TIME
- if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME) {
- ins_char (ppp->wbuf, PPP_FLAG);
- }
- ppp->last_xmit = jiffies;
-#else
- ins_char (ppp->wbuf, PPP_FLAG);
+ hdr->address = PPP_ALLSTATIONS;
+ hdr->control = PPP_UI;
+ hdr->protocol[0] = 0;
+ hdr->protocol[1] = proto;
+
+ return ppp_dev_xmit_frame (ppp, ppp->wbuf, (u_char *) hdr, len);
+}
+
+/*
+ * This is just an interum solution until the 1.3 kernel's networking is
+ * available. The 1.2 kernel has problems with device headers before the
+ * buffers.
+ *
+ * This routine should be deleted, and the ppp_dev_xmit_ip1 routine called
+ * by this name.
+ */
+
+#if !defined(IPX_CHANGE)
+static int
+ppp_dev_xmit_ip (struct device *dev, struct ppp *ppp, u_char *data)
+{
+ struct ppp_hdr *hdr;
+ int len;
+ int answer;
+
+ len = ((struct iphdr *)data) -> tot_len;
+ len = ntohs (len);
+
+ hdr = (struct ppp_hdr *) kmalloc (len + sizeof (struct ppp_hdr),
+ GFP_ATOMIC);
+
+ if (hdr == NULL)
+ answer = 1;
+ else {
+ memcpy (&hdr[1], data, len);
+ answer = ppp_dev_xmit_ip1 (dev, ppp, (u_char *) &hdr[1]);
+ kfree (hdr);
+ }
+
+ return answer;
+}
+#endif /* !defined(IPX_CHANGE) */
+
+/*
+ * Send an IPX (or any other non-IP) frame to the remote.
+ *
+ * Return 0 if frame was queued for transmission.
+ * 1 if frame must be re-queued for later driver support.
+ */
+
+#if defined(IPX_CHANGE)
+#define ppp_dev_xmit_ipx1 ppp_dev_xmit_ipx
#endif
- ppp->wbuf->fcs = PPP_INITFCS;
+#if defined(NEW_SKBUFF) || defined(IPX_CHANGE)
+static int
+ppp_dev_xmit_ipx1 (struct device *dev, struct ppp *ppp,
+ u_char *data, int len, int proto)
+{
+ struct tty_struct *tty = ppp2tty (ppp);
+ struct ppp_hdr *hdr;
/*
- * Insert the address and control data
+ * Validate the tty interface
*/
- if (!(ppp->flags & SC_COMP_AC)) {
- ppp_stuff_char (ppp, ppp->wbuf, PPP_ALLSTATIONS);
- ppp_stuff_char (ppp, ppp->wbuf, PPP_UI);
- }
+ if (tty == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_dev_xmit: %s not connected to a TTY!\n",
+ dev->name);
+ return 0;
+ }
/*
- * Insert the protocol.
+ * Ensure that the PPP device is still up
*/
- if (!(ppp->flags & SC_COMP_PROT) || (proto & 0xff00)) {
- ppp_stuff_char (ppp, ppp->wbuf, proto >> 8);
- }
- ppp_stuff_char (ppp, ppp->wbuf, proto);
+ if (!(dev->flags & IFF_UP)) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_WARNING
+ "ppp_dev_xmit: packet sent on interface %s,"
+ " which is down\n",
+ dev->name);
+ return 0;
+ }
/*
- * Insert the data
+ * Detect a change in the transfer size
*/
- while (len-- > 0) {
- ppp_stuff_char (ppp, ppp->wbuf, *data++);
- }
+ if (ppp->mtu != ppp2dev (ppp)->mtu) {
+ ppp_changedmtu (ppp,
+ ppp2dev (ppp)->mtu,
+ ppp->mru);
+ }
/*
- * Add the trailing CRC and the final flag character
+ * Acquire the lock on the transmission buffer. If the buffer was busy then
+ * mark the device as busy and return "failure to send, try back later" error.
+ */
+ if (lock_buffer (ppp->wbuf) != 0) {
+ dev->tbusy = 1;
+ return 1;
+ }
+/*
+ * Print the frame being sent
+ */
+ if (ppp->flags & SC_LOG_OUTPKT)
+ ppp_print_buffer ("ppp outpkt", data, len);
+/*
+ * Send the frame
*/
- write_fcs = ppp->wbuf->fcs ^ 0xFFFF;
- ppp_stuff_char (ppp, ppp->wbuf, write_fcs);
- ppp_stuff_char (ppp, ppp->wbuf, write_fcs >> 8);
+ len += PPP_HARD_HDR_LEN;
+ hdr = &((struct ppp_hdr *) data)[-1];
+
+ hdr->address = PPP_ALLSTATIONS;
+ hdr->control = PPP_UI;
+ hdr->protocol[0] = proto >> 8;
+ hdr->protocol[1] = proto;
+
+ return ppp_dev_xmit_frame (ppp, ppp->wbuf, (u_char *) hdr, len);
+}
- PRINTKN (4,
- (KERN_DEBUG "ppp_dev_xmit: fcs is %hx\n", write_fcs));
/*
- * Add the trailing flag character
+ * This is just an interum solution until the 1.3 kernel's networking is
+ * available. The 1.2 kernel has problems with device headers before the
+ * buffers.
+ *
+ * This routine should be deleted, and the ppp_dev_xmit_ipx1 routine called
+ * by this name.
+ */
+
+#if !defined(IPX_CHANGE)
+static int
+ppp_dev_xmit_ipx (struct device *dev, struct ppp *ppp,
+ u_char *data, int len, int proto)
+{
+ struct ppp_hdr *hdr;
+ int answer;
+
+ hdr = (struct ppp_hdr *) kmalloc (len + sizeof (struct ppp_hdr),
+ GFP_ATOMIC);
+ if (hdr == NULL)
+ answer = 1;
+ else {
+ memcpy (&hdr[1], data, len);
+ answer = ppp_dev_xmit_ipx1 (dev, ppp, (u_char *) &hdr[1],
+ len, proto);
+ kfree (hdr);
+ }
+
+ return answer;
+}
+#endif /* !defined(IPX_CHANGE) */
+#endif /* defined(NEW_SKBUFF) || defined(IPX_CHANGE) */
+
+/*
+ * Send a frame to the remote.
+ */
+
+static int
+ppp_dev_xmit (sk_buff *skb, struct device *dev)
+{
+ int answer, len;
+ u_char *data;
+ struct ppp *ppp = dev2ppp (dev);
+ struct tty_struct *tty = ppp2tty (ppp);
+/*
+ * just a little sanity check.
*/
- ins_char (ppp->wbuf, PPP_FLAG);
+ if (skb == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_WARNING "ppp_dev_xmit: null packet!\n");
+ return 0;
+ }
/*
- * Update the times for the transmission.
+ * Avoid timing problem should tty hangup while data is queued to be sent
*/
- ppp->ddinfo.ip_sjiffies = jiffies;
+ if (!ppp->inuse) {
+ dev_kfree_skb (skb, FREE_WRITE);
+ dev_close (dev);
+ return 0;
+ }
/*
- * Print the buffer
+ * Validate the tty linkage
*/
- if (ppp_debug >= 6) {
- ppp_print_buffer ("xmit buffer", buf_base (ppp->wbuf),
- ppp->wbuf->count, KERNEL_DS);
- } else {
- PRINTKN (4, (KERN_DEBUG
- "ppp_dev_xmit: writing %d chars\n",
- ppp->wbuf->count));
- }
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG "ppp_dev_xmit [%s]: skb %p\n",
+ dev->name, skb);
/*
- * Send the block to the tty driver.
+ * Validate the tty interface
*/
- ppp->p.ppp_obytes += ppp->wbuf->count;
- ++ppp->p.ppp_opackets;
- ppp_kick_tty (ppp, ppp->wbuf);
+ if (tty == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR
+ "ppp_dev_xmit: %s not connected to a TTY!\n",
+ dev->name);
+ dev_kfree_skb (skb, FREE_WRITE);
+ return 0;
}
- while (0);
/*
- * This is the end of the transmission. Release the buffer.
+ * Fetch the pointer to the data
*/
- dev_kfree_skb (skb, FREE_WRITE);
- return 0;
+ len = skb->len;
+ data = skb_data(skb);
+/*
+ * Look at the protocol in the skb to determine the difference between
+ * an IP frame and an IPX frame.
+ */
+
+#if defined(NEW_SKBUFF) || defined(IPX_CHANGE)
+ switch (ntohs (skb->protocol)) {
+ case ETH_P_IPX:
+ answer = ppp_dev_xmit_ipx (dev, ppp, data, len, PPP_IPX);
+ break;
+
+ case ETH_P_IP:
+ answer = ppp_dev_xmit_ip (dev, ppp, data);
+ break;
+
+ default: /* All others have no support at this time. */
+#if 1 /* I **REALLY** want to toss this. For the time being, I'll assume
+ that this is IP. However, if you start to see the message below
+ then you should fix the skb->protocol to have the proper values. */
+
+ printk (KERN_ERR
+ "ppp: strange protocol type %x in ppp_dev_xmit\n",
+ skb->protocol);
+ answer = ppp_dev_xmit_ip (dev, ppp, data);
+ break;
+#else /* Shortly, this is what it will be! */
+ dev_kfree_skb (skb, FREE_WRITE);
+ return 0;
+#endif /* if 1 */
+ }
+#else /* defined(NEW_SKBUFF) || defined(IPX_CHANGE) */
+ answer = ppp_dev_xmit_ip (dev, ppp, data);
+#endif
+
+/*
+ * This is the end of the transmission. Release the buffer if it was sent.
+ */
+ if (answer == 0) {
+ dev_kfree_skb (skb, FREE_WRITE);
+ ppp->ddinfo.xmit_idle = jiffies;
+ }
+ return answer;
}
+/*
+ * Generate the statistic information for the /proc/net/dev listing.
+ */
+
static struct enet_statistics *
ppp_dev_stats (struct device *dev)
{
- struct ppp *ppp = &ppp_ctrl[dev->base_addr];
+ struct ppp *ppp = dev2ppp (dev);
static struct enet_statistics ppp_stats;
- ppp_stats.rx_packets = ppp->p.ppp_ipackets;
- ppp_stats.rx_errors = ppp->p.ppp_ierrors;
- ppp_stats.rx_dropped = ppp->p.ppp_ierrors;
+ ppp_stats.rx_packets = ppp->stats.ppp_ipackets;
+ ppp_stats.rx_errors = ppp->stats.ppp_ierrors;
+ ppp_stats.rx_dropped = ppp->stats.ppp_ierrors;
ppp_stats.rx_fifo_errors = 0;
ppp_stats.rx_length_errors = 0;
ppp_stats.rx_over_errors = 0;
ppp_stats.rx_crc_errors = 0;
ppp_stats.rx_frame_errors = 0;
- ppp_stats.tx_packets = ppp->p.ppp_opackets;
- ppp_stats.tx_errors = ppp->p.ppp_oerrors;
+ ppp_stats.tx_packets = ppp->stats.ppp_opackets;
+ ppp_stats.tx_errors = ppp->stats.ppp_oerrors;
ppp_stats.tx_dropped = 0;
ppp_stats.tx_fifo_errors = 0;
ppp_stats.collisions = 0;
ppp_stats.tx_window_errors = 0;
ppp_stats.tx_heartbeat_errors = 0;
- PRINTKN (3, (KERN_INFO "ppp_dev_stats called"));
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO "ppp_dev_stats called");
return &ppp_stats;
}
-#ifdef NEW_SKBUFF
+#if defined(NEW_SKBUFF)
/*
- * The PPP protocol is currently pure IP (no IPX yet). This defines
- * the protocol layer which is blank since the driver does all the
- * cooking.
+ * This defines the protocol layer which is blank since the
+ * driver does all the cooking.
*/
static int ppp_dev_input (struct protocol *self, struct protocol *lower,
{
switch (protocol)
{
- case ETH_P_IP:
+ case htons (ETH_P_IP):
+ case htons (ETH_P_IPX):
return 0;
default:
#else
+#if USE_SKB_PROTOCOL == 0
/*
* Called to enquire about the type of the frame in the buffer. Return
* ETH_P_IP for an IP frame, ETH_P_IPX for an IPX frame.
{
return (htons (ETH_P_IP));
}
+#endif
-static int
-ppp_dev_header (u_char * buff, struct device *dev, unsigned short type,
- void *daddr, void *saddr, unsigned len, sk_buff *skb)
+#if USE_SKB_PROTOCOL == 0
+static int ppp_dev_header (unsigned char *buff, struct device *dev,
+ unsigned short type, void *daddr, void *saddr,
+ unsigned len, struct sk_buff *skb)
+#else
+static int ppp_dev_header (sk_buff *skb, struct device *dev,
+ unsigned short type, void *daddr,
+ void *saddr, unsigned len)
+#endif
{
return (0);
}
* Miscellany called by various functions above.
*************************************************************/
-/* allocate a PPP channel */
+/* allocate or create a PPP channel */
static struct ppp *
ppp_alloc (void)
{
- int i;
- for (i = 0; i < PPP_NRUNIT; i++) {
- if (!set_bit (0, &ppp_ctrl[i].inuse)) {
- return &ppp_ctrl[i];
+ int if_num;
+ int status;
+ ppp_ctrl_t *ctl;
+ struct device *dev;
+ struct ppp *ppp;
+
+ /* try to find an free device */
+ ctl = ppp_list;
+ if_num = 0;
+
+ while (ctl) {
+ ppp = ctl2ppp (ctl);
+ if (!set_bit(0, &ppp->inuse))
+ return (ppp);
+ ctl = ctl->next;
+ if (++if_num == max_dev)
+ return (NULL);
+ }
+/*
+ * There are no available items. Allocate a device from the system pool
+ */
+ ctl = (ppp_ctrl_t *) kmalloc (sizeof(ppp_ctrl_t), GFP_KERNEL);
+ if (ctl) {
+ (void) memset(ctl, 0, sizeof(ppp_ctrl_t));
+ ppp = ctl2ppp (ctl);
+ dev = ctl2dev (ctl);
+
+ /* initialize channel control data */
+ set_bit(0, &ppp->inuse);
+
+ ppp->line = if_num;
+ ppp->tty = NULL;
+ ppp->dev = dev;
+
+ dev->next = NULL;
+ dev->init = ppp_init_dev;
+ dev->name = ctl->name;
+ dev->base_addr = (unsigned long) if_num;
+ dev->priv = (void *) ppp;
+
+ sprintf (dev->name, "ppp%d", if_num);
+
+ /* link in the new channel */
+ ctl->next = ppp_list;
+ ppp_list = ctl;
+
+/* register device so that we can be ifconfig'd */
+/* ppp_init_dev() will be called as a side-effect */
+
+ status = register_netdev (dev);
+ if (status == 0) {
+ printk (KERN_INFO "registered device %s\n", dev->name);
+ return (ppp);
}
+
+ printk (KERN_ERR
+ "ppp_alloc - register_netdev(%s) = %d failure.\n",
+ dev->name, status);
+ /* This one will forever be busy as it is not initialized */
}
- return NULL;
+ return (NULL);
}
/*
*/
static void
-ppp_print_hex (register u_char * out, u_char * in, int count)
+ppp_print_hex (register u_char * out, const u_char * in, int count)
{
register u_char next_ch;
static char hex[] = "0123456789ABCDEF";
while (count-- > 0) {
- next_ch = (u_char) get_fs_byte (in);
+ next_ch = *in++;
*out++ = hex[(next_ch >> 4) & 0x0F];
*out++ = hex[next_ch & 0x0F];
++out;
- ++in;
}
}
static void
-ppp_print_char (register u_char * out, u_char * in, int count)
+ppp_print_char (register u_char * out, const u_char * in, int count)
{
register u_char next_ch;
while (count-- > 0) {
- next_ch = (u_char) get_fs_byte (in);
+ next_ch = *in++;
- if (next_ch < 0x20 || next_ch > 0x7e) {
+ if (next_ch < 0x20 || next_ch > 0x7e)
*out++ = '.';
- } else {
+ else {
*out++ = next_ch;
- if (next_ch == '%') { /* printk/syslogd has a bug !! */
+ if (next_ch == '%') /* printk/syslogd has a bug !! */
*out++ = '%';
- }
}
- ++in;
}
*out = '\0';
}
static void
-ppp_print_buffer (const u_char * name, u_char * buf, int count, int seg)
+ppp_print_buffer (const u_char * name, const u_char * buf, int count)
{
u_char line[44];
- int old_fs = get_fs ();
- set_fs (seg);
+ if (name != (u_char *) NULL)
+ printk (KERN_DEBUG "ppp: %s, count = %d\n", name, count);
- if (name != (u_char *) NULL) {
- PRINTK ((KERN_DEBUG "ppp: %s, count = %d\n", name, count));
- }
while (count > 8) {
- memset (line, ' ', sizeof (line));
+ memset (line, 32, 44);
ppp_print_hex (line, buf, 8);
ppp_print_char (&line[8 * 3], buf, 8);
- PRINTK ((KERN_DEBUG "%s\n", line));
+ printk (KERN_DEBUG "%s\n", line);
count -= 8;
buf += 8;
}
if (count > 0) {
- memset (line, ' ', sizeof (line));
+ memset (line, 32, 44);
ppp_print_hex (line, buf, count);
ppp_print_char (&line[8 * 3], buf, count);
- PRINTK ((KERN_DEBUG "%s\n", line));
+ printk (KERN_DEBUG "%s\n", line);
+ }
+}
+
+/*************************************************************
+ * Compressor module interface
+ *************************************************************/
+
+struct compressor_link {
+ struct compressor_link *next;
+ struct compressor *comp;
+};
+
+static struct compressor_link *ppp_compressors = (struct compressor_link *) 0;
+
+static struct compressor *find_compressor (int type)
+{
+ struct compressor_link *lnk;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ lnk = ppp_compressors;
+ while (lnk != (struct compressor_link *) 0) {
+ if ((int) (unsigned char) lnk->comp->compress_proto == type) {
+ restore_flags(flags);
+ return lnk->comp;
+ }
+ lnk = lnk->next;
+ }
+
+ restore_flags(flags);
+ return (struct compressor *) 0;
+}
+
+static int ppp_register_compressor (struct compressor *cp)
+{
+ struct compressor_link *new;
+ unsigned long flags;
+
+ new = (struct compressor_link *) kmalloc (sizeof (struct compressor_link), GFP_KERNEL);
+
+ if (new == (struct compressor_link *) 0)
+ return 1;
+
+ save_flags(flags);
+ cli();
+
+ if (find_compressor (cp->compress_proto)) {
+ restore_flags(flags);
+ kfree (new);
+ return 0;
+ }
+
+ new->next = ppp_compressors;
+ new->comp = cp;
+ ppp_compressors = new;
+
+ restore_flags(flags);
+ return 0;
+}
+
+static void ppp_unregister_compressor (struct compressor *cp)
+{
+ struct compressor_link *prev = (struct compressor_link *) 0;
+ struct compressor_link *lnk;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+
+ lnk = ppp_compressors;
+ while (lnk != (struct compressor_link *) 0) {
+ if (lnk->comp == cp) {
+ if (prev)
+ prev->next = lnk->next;
+ else
+ ppp_compressors = lnk->next;
+ kfree (lnk);
+ break;
+ }
+ prev = lnk;
+ lnk = lnk->next;
+ }
+ restore_flags(flags);
+}
+
+/*************************************************************
+ * Module support routines
+ *************************************************************/
+
+#ifdef MODULE
+int
+init_module(void)
+{
+ int status;
+
+ /* register our line disciplines */
+ status = ppp_first_time();
+ if (status != 0)
+ printk (KERN_INFO
+ "PPP: ppp_init() failure %d\n", status);
+ else
+ (void) register_symtab (&ppp_syms);
+ return (status);
+}
+
+void
+cleanup_module(void)
+{
+ int status;
+ ppp_ctrl_t *ctl, *next_ctl;
+ struct device *dev;
+ struct ppp *ppp;
+ int busy_flag = 0;
+/*
+ * Ensure that the devices are not in operation.
+ */
+ ctl = ppp_list;
+ while (ctl) {
+ ppp = ctl2ppp (ctl);
+ if (ppp->inuse && ppp->tty != NULL) {
+ busy_flag = 1;
+ break;
+ }
+
+ dev = ctl2dev (ctl);
+ if (dev->start || dev->flags & IFF_UP) {
+ busy_flag = 1;
+ break;
+ }
+ ctl = ctl->next;
+ }
+/*
+ * Ensure that there are no compressor modules registered
+ */
+ if (ppp_compressors != NULL)
+ busy_flag = 1;
+
+ if (busy_flag) {
+ printk (KERN_INFO
+ "PPP: device busy, remove delayed\n");
+ return;
+ }
+/*
+ * Release the tty registration of the line dicipline so that no new entries
+ * may be created.
+ */
+ status = tty_register_ldisc (N_PPP, NULL);
+ if (status != 0)
+ printk (KERN_INFO
+ "PPP: Unable to unregister ppp line discipline "
+ "(err = %d)\n", status);
+ else
+ printk (KERN_INFO
+ "PPP: ppp line discipline successfully unregistered\n");
+/*
+ * De-register the devices so that there is no problem with them
+ */
+ next_ctl = ppp_list;
+ while (next_ctl) {
+ ctl = next_ctl;
+ next_ctl = ctl->next;
+ ppp = ctl2ppp (ctl);
+ dev = ctl2dev (ctl);
+
+ ppp_release (ppp);
+ unregister_netdev (dev);
+ kfree (ctl);
}
- set_fs (old_fs);
}
+#endif