-/*
- * PPP for Linux
+/* PPP for Linux
+ *
+ * Michael Callahan <callahan@maths.ox.ac.uk>
+ * Al Longyear <longyear@netcom.com>
*
- * ==PPPVERSION 2.1.3==
+ * Dynamic PPP devices by Jim Freeman <jfree@caldera.com>.
+ * ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid <ewerlid@syscon.uu.se>
+ *
+ * ==FILEVERSION 970227==
*
* NOTE TO MAINTAINERS:
- * If you modify this file at all, increment the last number above.
+ * If you modify this file at all, please set the number above to the
+ * date of the modification as YYMMDD (year month day).
* ppp.c is shipped with a PPP distribution as well as with the kernel;
- * if everyone increases the PPPVERSION number above, then scripts
+ * 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.
- *
*/
/*
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
8 data bits, no parity. This adds a small amount of
processing for each received character.
-
- PPP_COMPRESS - Enable the PPP compression protocol. This protocol
- is under contention with Motorolla's patent, so use
- with caution.
-
- NEW_SKBUFF - Use NET3.020 sk_buff's
*/
-/* #define NEW_SKBUFF 1 */
#define OPTIMIZE_FLAG_TIME ((HZ * 3)/2)
+
#define CHECK_CHARACTERS 1
#define PPP_COMPRESS 1
-/* $Id: ppp.c,v 1.5 1995/06/12 11:36:53 paulus Exp $
+#ifndef PPP_MAX_DEV
+#define PPP_MAX_DEV 256
+#endif
+
+/* $Id: ppp.c,v 1.11 1997/04/30 05:42:36 paulus Exp $
* Added dynamic allocation of channels to eliminate
* compiled-in limits on the number of channels.
*
* released under the GNU General Public License Version 2.
*/
+#include <linux/version.h>
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
+
+#undef VERSION
+/* a nice define to generate linux version numbers */
+#define VERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch))
+
+#if LINUX_VERSION_CODE < VERSION(2,1,14)
#include <linux/ioport.h>
+#endif
+
#include <linux/in.h>
#include <linux/malloc.h>
#include <linux/tty.h>
#include <linux/signal.h> /* used in new tty drivers */
#include <asm/system.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.h>
#include <linux/if_ether.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/inet.h>
#include <linux/ioctl.h>
-#ifdef NEW_SKBUFF
-#include <linux/netprotocol.h>
-#else
-#define skb_data(skb) ((unsigned char *) (skb)->data)
-typedef struct sk_buff sk_buff;
-#endif
+typedef struct sk_buff sk_buff;
+#define skb_data(skb) ((__u8 *) (skb)->data)
-#include <ip.h>
-#include <tcp.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
#include <linux/if_arp.h>
-#include "slhc.h"
-#include <net/ppp_defs.h>
-#include <linux/socket.h>
-#include <net/if_ppp.h>
-#include <net/if_pppvar.h>
+#include <net/slhc_vj.h>
-#ifdef MODULE
-#include <linux/module.h>
-#include <linux/version.h>
-#define STATIC static
-#else
-#define MOD_INC_USE_COUNT while(0) { }
-#define MOD_DEC_USE_COUNT while(0) { }
-#endif /* def MODULE */
-
-#ifdef PPP_COMPRESS
-#undef PACKETPTR
-#define PACKETPTR 1
-#include <net/ppp-comp.h>
-#undef PACKETPTR
-
-#define bsd_decompress (*ppp->sc_rcomp->decompress)
-#define bsd_compress (*ppp->sc_xcomp->compress)
-#endif
+#define fcstab ppp_crc16_table /* Name of the table in the kernel */
+#include <linux/ppp_defs.h>
+
+#include <linux/socket.h>
+#include <linux/if_ppp.h>
+#include <linux/if_pppvar.h>
+#include <linux/ppp-comp.h>
#ifndef PPP_IPX
#define PPP_IPX 0x2b /* IPX protocol over PPP */
#endif
#ifndef PPP_LQR
-#define PPP_LQR 0xc025 /* Link Quality Reporting Protocol */
+#define PPP_LQR 0xc025 /* Link Quality Reporting Protocol */
+#endif
+
+#if LINUX_VERSION_CODE >= VERSION(2,1,4)
+#include <asm/segment.h>
+#define GET_USER(error,value,addr) error = get_user(value,addr)
+#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
+#define PUT_USER(error,value,addr) error = put_user(value,addr)
+#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0
+
+#if LINUX_VERSION_CODE >= VERSION(2,1,5)
+#include <asm/uaccess.h>
+#endif
+
+#else /* 2.0.x and 2.1.x before 2.1.4 */
+
+#define GET_USER(error,value,addr) \
+do { \
+ error = verify_area (VERIFY_READ, (void *) addr, sizeof (value)); \
+ if (error == 0) \
+ value = get_user(addr); \
+} while (0)
+
+#define COPY_FROM_USER(error,dest,src,size) \
+do { \
+ error = verify_area (VERIFY_READ, (void *) src, size); \
+ if (error == 0) \
+ memcpy_fromfs (dest, src, size); \
+} while (0)
+
+#define PUT_USER(error,value,addr) \
+do { \
+ error = verify_area (VERIFY_WRITE, (void *) addr, sizeof (value)); \
+ if (error == 0) \
+ put_user (value, addr); \
+} while (0)
+
+#define COPY_TO_USER(error,dest,src,size) \
+do { \
+ error = verify_area (VERIFY_WRITE, (void *) dest, size); \
+ if (error == 0) \
+ memcpy_tofs (dest, src, size); \
+} while (0)
+
#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 struct ppp *ppp_alloc (void);
-static void ppp_print_buffer (const u_char *, u_char *, int);
+static struct ppp *ppp_find (int pid_value);
+static void ppp_print_buffer (const __u8 *, const __u8 *, int);
extern inline void ppp_stuff_char (struct ppp *ppp,
register struct ppp_buffer *buf,
- register u_char chr);
+ register __u8 chr);
extern inline int lock_buffer (register struct ppp_buffer *buf);
-static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd);
-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_ccp (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 *);
+static int rcv_proto_ip (struct ppp *, __u16, __u8 *, int);
+static int rcv_proto_ipx (struct ppp *, __u16, __u8 *, int);
+static int rcv_proto_vjc_comp (struct ppp *, __u16, __u8 *, int);
+static int rcv_proto_vjc_uncomp (struct ppp *, __u16, __u8 *, int);
+static int rcv_proto_unknown (struct ppp *, __u16, __u8 *, int);
+static int rcv_proto_lqr (struct ppp *, __u16, __u8 *, int);
+static void ppp_doframe_lower (struct ppp *, __u8 *, int);
+static int ppp_doframe (struct ppp *);
-/*
- * List of compressors we know about.
- * We leave some space so maybe we can modload compressors.
- */
+static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd);
+static int rcv_proto_ccp (struct ppp *, __u16, __u8 *, int);
-#ifdef PPP_COMPRESS
-extern struct compressor ppp_bsd_compress;
+#define ins_char(pbuf,c) (buf_base(pbuf) [(pbuf)->count++] = (__u8)(c))
-struct compressor *ppp_compressors[8] = {
- &ppp_bsd_compress,
- NULL
-};
-#endif /* PPP_COMPRESS */
+#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.
+ */
-#define ins_char(pbuf,c) (buf_base(pbuf) [(pbuf)->count++] = (u_char)(c))
+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 *);
-#ifdef NEW_SKBUFF
-static int ppp_dev_input (struct protocol *self, struct protocol *lower,
- sk_buff *skb, void *saddr, void *daddr);
-static int ppp_dev_output (struct protocol *self, sk_buff *skb, int type,
- 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 *);
+#if LINUX_VERSION_CODE < VERSION(2,1,15)
+static int ppp_dev_header (sk_buff *, struct device *, __u16,
+ void *, void *, unsigned int);
+static int ppp_dev_rebuild (void *eth, struct device *dev,
+ unsigned long raddr, struct sk_buff *skb);
#endif
/*
* TTY callbacks
*/
-static int ppp_tty_read (struct tty_struct *, struct file *, u_char *,
+static int ppp_tty_read (struct tty_struct *, struct file *, __u8 *,
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 __u8 *,
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 __u8 * cp,
char *fp, int count);
static void ppp_tty_wakeup (struct tty_struct *tty);
-#define PRINTK(p) 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 in_rmap(ppp,c) ((((unsigned int) (__u8) (c)) < 0x20) && \
ppp->recv_async_map & (1 << (c)))
#define bset(p,b) ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
#define ppp2dev(ppp) ((struct device *) ppp->dev)
struct ppp_hdr {
- unsigned char address;
- unsigned char control;
- unsigned char protocol[2];
+ __u8 address;
+ __u8 control;
+ __u8 protocol[2];
};
#define PPP_HARD_HDR_LEN (sizeof (struct ppp_hdr))
-#if 1
-typedef struct ppp_ctrl {
+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 */
+ 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
-
-#else
-
-#define PPP_NRUNIT 4
-static struct ppp ppp_ctrl[PPP_NRUNIT];
-#undef dev2ppp
-#define dev2ppp(dev) ((struct ppp *) &ppp_ctrl[dev->base_addr])
-#endif
+#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_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 */
+/* Define this string only once for all macro invocations */
static char ppp_warning[] = KERN_WARNING "PPP: ALERT! not INUSE! %d\n";
-static char szVersion[] = PPP_VERSION;
-
-#ifdef NEW_SKBUFF
-static struct protocol proto_ppp;
-#endif
+static char szVersion[] = PPP_VERSION;
/*
* Information for the protocol decoder
*/
-typedef int (*pfn_proto) (struct ppp *, u_short, u_char *, int);
+typedef int (*pfn_proto) (struct ppp *, __u16, __u8 *, int);
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_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 },
-#ifdef PPP_COMPRESS
- { PPP_CCP, rcv_proto_ccp },
-#endif
- { 0, rcv_proto_unknown } /* !!! MUST BE LAST !!! */
+ { PPP_LQR, rcv_proto_lqr },
+ { PPP_CCP, rcv_proto_ccp },
+ { 0, rcv_proto_unknown } /* !!! MUST BE LAST !!! */
};
-/* FCS table from RFC1331 */
-
-static unsigned short fcstab[256] =
+__u16 ppp_crc16_table[256] =
{
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
};
#ifdef CHECK_CHARACTERS
-static unsigned paritytab[8] =
+static __u32 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;
+extern inline __u8 * store_long (register __u8 *p, register int value) {
+ *p++ = (__u8) (value >> 24);
+ *p++ = (__u8) (value >> 16);
+ *p++ = (__u8) (value >> 8);
+ *p++ = (__u8) value;
return p;
}
static struct tty_ldisc ppp_ldisc;
int status;
-#ifdef PPP_NRUNIT
-#define PPP_UNITS3(x) #x
-#define PPP_UNITS2(x) PPP_UNITS3(x)
-#define PPP_UNITS1(x) PPP_UNITS2(x)
-#define PPP_UNITS "(" PPP_UNITS1(PPP_NRUNIT) " devices)"
-#else
-#define PPP_UNITS "(dynamic channel allocation)"
-#endif
printk (KERN_INFO
- "PPP: version %s " PPP_UNITS
-#ifdef NEW_SKBUFF
- " NEW_SKBUFF"
-#endif
+ "PPP: version %s (demand dialling)"
"\n", szVersion);
-#undef PPP_UNITS
-#undef PPP_UNITS1
-#undef PPP_UNITS2
-#undef PPP_UNITS3
+#ifndef MODULE /* slhc module logic has its own copyright announcement */
printk (KERN_INFO
"TCP compression code copyright 1989 Regents of the "
"University of California\n");
-
-#ifndef PPP_NRUNIT
+#endif
+
printk (KERN_INFO
"PPP Dynamic channel allocation code copyright 1995 "
"Caldera, Inc.\n");
-#endif
-
/*
- * Register the protocol for the device
+ * Register the tty discipline
*/
-
-#ifdef NEW_SKBUFF
- 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.header_space = 0; /* PPP_HARD_HDR_LEN; */
-
- protocol_register(&proto_ppp);
-#endif
-
-/*
- * 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.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");
ppp_init_dev (struct device *dev)
{
int indx;
-#ifdef NEW_SKBUFF
- dev->default_protocol = &proto_ppp; /* Our protocol layer is PPP */
-#else
+
+#if LINUX_VERSION_CODE < VERSION(2,1,15)
dev->hard_header = ppp_dev_header;
- dev->type_trans = ppp_dev_type;
dev->rebuild_header = ppp_dev_rebuild;
- dev->hard_header_len = 0; /* PPP_HARD_HDR_LEN; */
#endif
+ dev->hard_header_len = PPP_HARD_HDR_LEN;
+
/* device INFO */
- dev->mtu = PPP_MTU;
+ dev->mtu = PPP_MTU;
dev->hard_start_xmit = ppp_dev_xmit;
- dev->open = ppp_dev_open;
- dev->stop = ppp_dev_close;
- dev->get_stats = ppp_dev_stats;
- dev->do_ioctl = ppp_dev_ioctl;
- dev->addr_len = 0;
- dev->type = ARPHRD_PPP;
+ dev->open = ppp_dev_open;
+ dev->stop = ppp_dev_close;
+ dev->get_stats = ppp_dev_stats;
+ dev->do_ioctl = ppp_dev_ioctl;
+ dev->addr_len = 0;
+ dev->tx_queue_len = 10;
+ dev->type = ARPHRD_PPP;
for (indx = 0; indx < DEV_NUMBUFFS; indx++)
skb_queue_head_init (&dev->buffs[indx]);
/* New-style flags */
- dev->flags = IFF_POINTOPOINT;
- dev->family = AF_INET;
- dev->pa_addr = 0;
+ dev->flags = IFF_POINTOPOINT;
+ dev->family = AF_INET;
+ dev->pa_addr = 0;
dev->pa_brdaddr = 0;
- dev->pa_mask = 0;
- dev->pa_alen = sizeof (unsigned long);
+ dev->pa_mask = 0;
+ dev->pa_alen = 4; /* sizeof (__u32) */
return 0;
}
ppp->xmit_async_map[3] = 0x60000000;
ppp->recv_async_map = 0x00000000;
- ppp->rbuf = NULL;
- ppp->wbuf = NULL;
- ppp->ubuf = NULL;
- ppp->cbuf = NULL;
- ppp->slcomp = NULL;
- ppp->read_wait = NULL;
+ ppp->rbuf = NULL;
+ ppp->wbuf = NULL;
+ ppp->ubuf = NULL;
+ ppp->cbuf = NULL;
+ 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->stats, '\0', sizeof (struct pppstat));
+ memset(&ppp->stats, 0, sizeof (struct pppstat));
+ memset(&ppp->estats, 0, sizeof(struct enet_statistics));
/* 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 */
-#ifdef PPP_COMPRESS
+ /* PPP compression data */
ppp->sc_xc_state =
ppp->sc_rc_state = NULL;
-#endif /* PPP_COMPRESS */
}
+#if LINUX_VERSION_CODE < VERSION(2,1,18)
+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>
+};
+#else
+EXPORT_SYMBOL(ppp_register_compressor);
+EXPORT_SYMBOL(ppp_unregister_compressor);
+EXPORT_SYMBOL(ppp_crc16_table);
+#endif
+
/* called at boot/load time for each ppp device defined in the kernel */
#ifndef MODULE
if (first_time) {
first_time = 0;
- answer = ppp_first_time();
- }
-/*
- * Un-register the devices defined at the start of the system. They will
- * be added when they are needed again. The first device just gets us into
- * this code to register the handlers.
- */
-#if 1
- unregister_netdev (dev);
-#else
- ppp_init_dev (dev);
- ppp_init_ctrl_blk (dev2ppp (dev));
- dev2ppp (dev) -> inuse = 0;
- dev2ppp (dev) -> dev = dev;
+ answer = ppp_first_time();
+#if LINUX_VERSION_CODE < VERSION(2,1,18)
+ if (answer == 0)
+ (void) register_symtab (&ppp_syms);
#endif
+ }
+ if (answer == 0)
+ answer = -ENODEV;
return answer;
}
#endif
buf->head = 0;
buf->tail = 0;
buf->fcs = PPP_INITFCS;
+
}
return (buf);
}
lock_buffer (register struct ppp_buffer *buf)
{
register int state;
- int flags;
+ unsigned long flags;
/*
* Save the current state and if free then set it to the "busy" state
*/
state = buf->locked;
if (state == 0)
buf->locked = 2;
-/*
- * Restore the flags and return the previous state. 0 implies success.
- */
+
restore_flags (flags);
return (state);
}
*/
dev = ppp2dev (ppp);
mru = new_mru;
- /* allow for possible escapement of every character */
+ /* allow for possible escaping of every character */
mtu = (new_mtu * 2) + 20;
/* RFC 1331, section 7.2 says the minimum value is 1500 bytes */
mru = PPP_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+PPP_HARD_HDR_LEN, BUFFER_TYPE_DEV_WR);
new_tbuf = ppp_alloc_buf ((PPP_MTU * 2) + 24, BUFFER_TYPE_TTY_WR);
ppp->cbuf = new_cbuf;
ppp->tbuf = new_tbuf;
- ppp->rbuf->size -= 80; /* reserve space for vj header expansion */
+ ppp->rbuf->size -= 80; /* reserve space for vj header expansion */
- dev->mem_start = (unsigned long) buf_base (new_wbuf);
- dev->mem_end = (unsigned long) (dev->mem_start + mtu);
+ dev->mem_start = (unsigned long) buf_base (new_wbuf);
+ dev->mem_end = (unsigned long) (dev->mem_start + mtu);
dev->rmem_start = (unsigned long) buf_base (new_rbuf);
- dev->rmem_end = (unsigned long) (dev->rmem_start + mru);
+ dev->rmem_end = (unsigned long) (dev->rmem_start + mru);
/*
* Update the parameters for the new buffer sizes
*/
ppp->s2buf = NULL;
ppp->xbuf = NULL;
- ppp->tty->flags &= ~TTY_DO_WRITE_WAKEUP;
- ppp->flags &= ~SC_XMIT_BUSY;
+ ppp->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+ ppp->flags &= ~SC_XMIT_BUSY;
sti ();
/*
* CCP is down; free (de)compressor state if necessary.
*/
-#ifdef PPP_COMPRESS
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_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;
- }
+ if (ppp->sc_rc_state) {
+ (*ppp->sc_rcomp->decomp_free) (ppp->sc_rc_state);
+ ppp->sc_rc_state = NULL;
+ }
}
-#endif /* PPP_COMPRESS */
/*
* Called to release all of the information in the current PPP structure.
tty = ppp2tty (ppp);
dev = ppp2dev (ppp);
-#ifdef PPP_COMPRESS
ppp_ccp_closed (ppp);
- ppp->sc_xc_state =
- ppp->sc_rc_state = NULL;
-#endif /* PPP_COMPRESS */
+
+ /* Ensure that the pppd process is not hanging on select() */
+ wake_up_interruptible (&ppp->read_wait);
+ wake_up_interruptible (&ppp->write_wait);
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 */
+ dev->flags = 0; /* prevent recursion */
}
ppp_free_buf (ppp->rbuf);
ppp->inuse = 0;
ppp->tty = NULL;
+ ppp->backup_tty = NULL;
}
/*
- * Device callback.
+ * TTY callback.
*
- * Called when the PPP device goes down in response to an ifconfig request.
+ * Called when the line discipline is changed to something
+ * else, the tty is closed, or the tty detects a hangup.
*/
static void
{
struct ppp *ppp = tty2ppp (tty);
- if (ppp == NULL || ppp->magic != PPP_MAGIC) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_WARNING
- "ppp: trying to close unopened tty!\n");
- } else {
+ if (ppp != NULL) {
+ if (ppp->magic != PPP_MAGIC) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_WARNING
+ "ppp: trying to close unopened tty!\n");
+ return;
+ }
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->disc_data = NULL;
+ if (tty == ppp->backup_tty)
+ ppp->backup_tty = 0;
+ if (tty != ppp->tty)
+ return;
+ if (ppp->backup_tty) {
+ ppp->tty = ppp->backup_tty;
+ } else {
+ ppp->sc_xfer = 0;
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO "ppp: channel %s closing.\n",
+ ppp2dev(ppp)->name);
+ ppp_release (ppp);
+ MOD_DEC_USE_COUNT;
+ }
}
}
ppp_tty_open (struct tty_struct *tty)
{
struct ppp *ppp = tty2ppp (tty);
+ int indx;
/*
* There should not be an existing table for this slot.
*/
/*
* Allocate the structure from the system
*/
- ppp = ppp_alloc ();
- if (ppp == NULL) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_tty_open: couldn't allocate ppp channel\n");
- return -ENFILE;
- }
+ ppp = ppp_find(current->pid);
+ if (ppp != NULL) {
+ /*
+ * If we are taking over a ppp unit which is currently
+ * connected to a loopback pty, there's not much to do.
+ */
+ ppp->tty = tty;
+ tty->disc_data = ppp;
+
+ } else {
+ ppp = ppp_alloc();
+ if (ppp == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR "ppp_alloc failed\n");
+ return -ENFILE;
+ }
/*
* Initialize the control block
*/
- ppp_init_ctrl_blk (ppp);
- ppp->tty = tty;
- tty->disc_data = ppp;
-/*
- * Flush any pending characters in the driver and discipline.
- */
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer (tty);
-
- if (tty->driver.flush_buffer)
- tty->driver.flush_buffer (tty);
+ ppp_init_ctrl_blk (ppp);
+ ppp->tty = tty;
+ tty->disc_data = ppp;
/*
- * 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) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_tty_open: no space for compression buffers!\n");
- ppp_release (ppp);
- return -ENOMEM;
- }
+ ppp->slcomp = slhc_init (16, 16);
+ if (ppp->slcomp == NULL) {
+ 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, ppp2dev(ppp)->mtu, ppp->mru) == 0) {
- ppp_release (ppp);
- return -ENOMEM;
- }
+ if (ppp_changedmtu (ppp, ppp2dev(ppp)->mtu, ppp->mru) == 0) {
+ ppp_release (ppp);
+ return -ENOMEM;
+ }
/*
* Allocate space for a user level buffer
*/
- ppp->ubuf = ppp_alloc_buf (RBUFSIZE, BUFFER_TYPE_TTY_RD);
- if (ppp->ubuf == NULL) {
+ ppp->ubuf = ppp_alloc_buf (RBUFSIZE, BUFFER_TYPE_TTY_RD);
+ if (ppp->ubuf == NULL) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_ERR "ppp_tty_open: "
+ "no space for user receive buffer\n");
+ ppp_release (ppp);
+ return -ENOMEM;
+ }
+
if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_tty_open: no space for user receive buffer\n");
- ppp_release (ppp);
- return -ENOMEM;
- }
+ printk (KERN_INFO "ppp: channel %s open\n",
+ ppp2dev(ppp)->name);
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO "ppp: channel %s open\n",
- ppp2dev(ppp)->name);
+ for (indx = 0; indx < NUM_NP; ++indx)
+ ppp->sc_npmode[indx] = NPMODE_PASS;
+
+ MOD_INC_USE_COUNT;
+ }
+/*
+ * Flush any pending characters in the driver and discipline.
+ */
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer (tty);
- MOD_INC_USE_COUNT;
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer (tty);
return (ppp->line);
}
* This could occur should the carrier drop.
*/
if (actual < 0) {
- ppp->stats.ppp_oerrors++;
+ ppp->stats.ppp_oerrors++;
actual = count;
} else
ppp->bytes_sent += actual;
*/
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;
/*
* transmission block.
*/
if (ppp2dev (ppp) -> flags & IFF_UP) {
- ppp2dev (ppp)->tbusy = 0;
+ if (xbuf->type == BUFFER_TYPE_DEV_WR)
+ ppp2dev (ppp)->tbusy = 0;
mark_bh (NET_BH);
- dev_tint (ppp2dev (ppp));
}
/*
* 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;
}
}
}
struct ppp_buffer *xbuf;
struct ppp *ppp = tty2ppp (tty);
- if (!ppp || ppp->magic != PPP_MAGIC) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG "PPP: write_wakeup called but "
- "couldn't find PPP struct.\n");
+ if (!ppp)
+ return;
+
+ if (ppp->magic != PPP_MAGIC)
+ return;
+
+ if (tty != ppp->tty) {
+ tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
return;
}
/*
static void
ppp_kick_tty (struct ppp *ppp, struct ppp_buffer *xbuf)
{
- register int flags;
+ unsigned long flags;
/*
* Hold interrupts.
*/
/*
* Control the flags which are best performed with the interrupts masked.
*/
- xbuf->locked = 1;
- xbuf->tail = 0;
+ xbuf->locked = 1;
+ xbuf->tail = 0;
/*
* If the transmitter is busy then place the buffer on the appropriate
* priority queue.
/*
* If the transmitter is not busy then this is the highest priority frame
*/
- ppp->flags &= ~SC_XMIT_BUSY;
+ ppp->flags &= ~SC_XMIT_BUSY;
ppp->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
- ppp->xbuf = xbuf;
+ ppp->xbuf = xbuf;
restore_flags (flags);
/*
* Do the "tty wakeup_code" to actually send this buffer.
/*
* Callback function when data is available at the tty driver.
*/
-
static void
-ppp_tty_receive (struct tty_struct *tty, u_char * data, char *flags, int count)
+ppp_tty_receive (struct tty_struct *tty, const __u8 * data,
+ char *flags, int count)
{
register struct ppp *ppp = tty2ppp (tty);
- register struct ppp_buffer *buf = ppp->rbuf;
- u_char chr;
+ register struct ppp_buffer *buf = NULL;
+ __u8 chr;
+
+ /*
+ * This can happen if stuff comes in on the backup tty.
+ */
+ if (tty != ppp->tty)
+ return;
+/*
+ * 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) {
+ if (ppp->magic != PPP_MAGIC) {
if (ppp->flags & SC_DEBUG)
printk (KERN_DEBUG
"PPP: handler called but couldn't find "
ppp->bytes_rcvd++;
chr = *data++;
if (flags) {
- if (*flags && ppp->toss == 0)
+ if (*flags && ppp->toss == 0) {
ppp->toss = *flags;
+ switch (ppp->toss) {
+ case TTY_OVERRUN:
+ ++ppp->estats.rx_fifo_errors;
+ break;
+ case TTY_FRAME:
+ case TTY_BREAK:
+ ++ppp->estats.rx_frame_errors;
+ break;
+ }
+ }
++flags;
}
/*
- * Set the flags for 8 data bits and no parity.
- *
- * Actually, it sets the flags for d7 being 0/1 and parity being even/odd
- * 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.
+ * Set the flags for d7 being 0/1 and parity being even/odd so that
+ * the normal processing would have all flags set at the end of the
+ * session. A missing flag bit indicates an error condition.
*/
#ifdef CHECK_CHARACTERS
ppp->flags |= SC_RCV_EVNP;
#endif
/*
- * Branch on the character. Process the escape character. The sequence ESC ESC
- * is defined to be ESC.
+ * Branch on the character.
*/
switch (chr) {
- case PPP_ESCAPE: /* PPP_ESCAPE: invert bit in next character */
- ppp->escape = PPP_TRANS;
- break;
/*
* FLAG. This is the end of the block. If the block terminated by ESC FLAG,
* then the block is to be ignored. In addition, characters before the very
* first FLAG are also tossed by this procedure.
*/
case PPP_FLAG: /* PPP_FLAG: end of frame */
- ppp->stats.ppp_ibytes = ppp->bytes_rcvd;
+ 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.
*/
- if ((ppp->toss & 0x80) != 0 ||
- ppp_doframe (ppp) == 0) {
+ if (ppp_doframe (ppp) == 0) {
+ ++ppp->stats.ppp_ierrors;
slhc_toss (ppp->slcomp);
}
/*
* receive mask then ignore the character.
*/
default:
+ /* If we're tossing, look no further. */
+ if (ppp->toss != 0)
+ break;
+
+ /* If this is a control char to be ignored, do so */
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)
+ /*
+ * Modify the next character if preceded by escape.
+ * The escape character (0x7d) could be an escaped
+ * 0x5d, if it follows an escape :-)
+ */
+ if (ppp->escape) {
+ chr ^= ppp->escape;
+ ppp->escape = 0;
+ } else if (chr == PPP_ESCAPE) {
+ ppp->escape = PPP_TRANS;
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->stats.ppp_ierrors++;
+ ++ppp->estats.rx_length_errors;
ppp->toss |= 0xC0;
break;
}
*/
static int
-ppp_rcv_rx (struct ppp *ppp, unsigned short proto, u_char * data, int count)
+ppp_rcv_rx (struct ppp *ppp, __u16 proto, __u8 * data, int count)
{
- sk_buff *skb = alloc_skb (count, GFP_ATOMIC);
+ sk_buff *skb = dev_alloc_skb (count);
/*
* Generate a skb buffer for the new frame.
*/
/*
* Move the received data from the input buffer to the skb buffer.
*/
- skb->len = count; /* Store the length */
- skb->dev = ppp2dev (ppp); /* We are the device */
-#ifdef NEW_SKBUF
+ skb->dev = ppp2dev (ppp); /* We are the device */
skb->protocol = proto;
-#endif
- memcpy ((u_char *) skb_data(skb), data, count); /* move data */
+ skb->mac.raw = skb_data(skb);
+ memcpy (skb_put(skb,count), data, count); /* move data */
/*
* Tag the frame and kick it to the proper receive routine
*/
+#if LINUX_VERSION_CODE < VERSION(2,1,15)
skb->free = 1;
- ppp->ddinfo.ip_rjiffies = jiffies;
+#endif
+
+ ppp->ddinfo.recv_idle = jiffies;
netif_rx (skb);
return 1;
}
*/
static int
-rcv_proto_ip (struct ppp *ppp, unsigned short proto, u_char * data, int count)
+rcv_proto_ip (struct ppp *ppp, __u16 proto, __u8 * data, int count)
{
- if (ppp2dev (ppp)->flags & IFF_UP) {
- if (count > 0)
+ if ((ppp2dev (ppp)->flags & IFF_UP) && (count > 0))
+ if (ppp->sc_npmode[NP_IP] == NPMODE_PASS)
return ppp_rcv_rx (ppp, htons (ETH_P_IP), data, count);
- }
return 0;
}
*/
static int
-rcv_proto_ipx (struct ppp *ppp, unsigned short proto, u_char * data, int count)
+rcv_proto_ipx (struct ppp *ppp, __u16 proto, __u8 * data, int count)
{
-#ifdef NEW_SKBUF
- if (ppp2dev (ppp)->flags & IFF_UP) {
- if (count > 0)
- return ppp_rcv_rx (ppp, htons (ETH_P_IPX), data, count);
- } else
-#endif
+ if (((ppp2dev (ppp)->flags & IFF_UP) != 0) && (count > 0))
+ return ppp_rcv_rx (ppp, htons (ETH_P_IPX), data, count);
return 0;
}
*/
static int
-rcv_proto_vjc_comp (struct ppp *ppp, unsigned short proto,
- u_char *data, int count)
+rcv_proto_vjc_comp (struct ppp *ppp, __u16 proto,
+ __u8 *data, int count)
{
if ((ppp->flags & SC_REJ_COMP_TCP) == 0) {
int new_count = slhc_uncompress (ppp->slcomp, data, count);
*/
static int
-rcv_proto_vjc_uncomp (struct ppp *ppp, unsigned short proto,
- u_char *data, int count)
+rcv_proto_vjc_uncomp (struct ppp *ppp, __u16 proto,
+ __u8 *data, int count)
{
if ((ppp->flags & SC_REJ_COMP_TCP) == 0) {
if (slhc_remember (ppp->slcomp, data, count) > 0) {
*/
static int
-rcv_proto_unknown (struct ppp *ppp, unsigned short proto,
- u_char *data, int len)
+rcv_proto_unknown (struct ppp *ppp, __u16 proto,
+ __u8 *data, int len)
{
int totlen;
register int current_idx;
#define PUTC(c) \
{ \
- buf_base (ppp->ubuf) [current_idx++] = (u_char) (c); \
+ buf_base (ppp->ubuf) [current_idx++] = (__u8) (c); \
current_idx &= ppp->ubuf->size; \
if (current_idx == ppp->ubuf->tail) \
goto failure; \
if (ppp->tty->fasync != NULL)
kill_fasync (ppp->tty->fasync, SIGIO);
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp: successfully queued %d bytes\n",
- len + 2);
-
- ppp->ddinfo.nip_rjiffies = jiffies;
return 1;
/*
* The buffer is full. Unlock the header
failure:
clear_bit (0, &ppp->ubuf->locked);
if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
+ printk (KERN_DEBUG
"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
+ printk (KERN_DEBUG
"ppp: dropping packet on the floor.\n");
slhc_toss (ppp->slcomp);
return 0;
* immediate or the compressors will become confused on the peer.
*/
-#ifdef PPP_COMPRESS
-static void ppp_proto_ccp (struct ppp *ppp, u_char *dp, int len, int rcvd)
+static void ppp_proto_ccp (struct ppp *ppp, __u8 *dp, int len, int rcvd)
{
- int slen = CCP_LENGTH(dp);
+ int slen = CCP_LENGTH(dp);
+ __u8 *opt = dp + CCP_HDRLEN;
+ int opt_len = slen - CCP_HDRLEN;
+
+ if (slen > len)
+ return;
- if (slen <= len) {
- switch (CCP_CODE(dp)) {
- case CCP_CONFREQ:
- case CCP_TERMREQ:
- case CCP_TERMACK:
+ 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);
- }
- break;
+ if (ppp->flags & SC_CCP_UP) {
+ ppp->flags &= ~(SC_CCP_UP |
+ SC_COMP_RUN |
+ SC_DECOMP_RUN);
+ }
+ 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 (dp + CCP_HDRLEN) +
- CCP_HDRLEN)
- 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;
/*
* we're agreeing to send compressed packets.
*/
- if (!rcvd) {
- if (ppp->sc_xc_state == NULL)
- break;
-
- if ((*ppp->sc_xcomp->comp_init)
- (ppp->sc_xc_state,
- dp + CCP_HDRLEN,
- slen - CCP_HDRLEN,
- ppp2dev (ppp)->base_addr,
- ppp->flags & SC_DEBUG))
- ppp->flags |= SC_COMP_RUN;
+ 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 & SC_DEBUG))
+ 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,
- dp + CCP_HDRLEN,
- slen - CCP_HDRLEN,
- ppp2dev (ppp)->base_addr,
- ppp->mru,
- ppp->flags & SC_DEBUG)) {
- ppp->flags |= SC_DECOMP_RUN;
- ppp->flags &= ~(SC_DC_ERROR | SC_DC_FERROR);
- }
+ 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 & SC_DEBUG)) {
+ ppp->flags |= SC_DECOMP_RUN;
+ ppp->flags &= ~(SC_DC_ERROR | SC_DC_FERROR);
+ }
+ break;
/*
* The protocol sequence is complete at this end
*/
- 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);
- break;
- }
+ 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->sc_rcomp->decomp_reset)(ppp->sc_rc_state);
ppp->flags &= ~SC_DC_ERROR;
}
- break;
}
+ break;
}
}
static int
-rcv_proto_ccp (struct ppp *ppp, unsigned short proto, u_char *dp, int len)
+rcv_proto_ccp (struct ppp *ppp, __u16 proto, __u8 *dp, int len)
{
ppp_proto_ccp (ppp, dp, len, 1);
return rcv_proto_unknown (ppp, proto, dp, len);
}
-#endif /* PPP_COMPRESS */
/*
* 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.
*/
static int
-rcv_proto_lqr (struct ppp *ppp, unsigned short proto, u_char * data, int len)
+rcv_proto_lqr (struct ppp *ppp, __u16 proto, __u8 * data, int len)
{
- register u_char *p;
-
- if (len > 8) {
- if (len < 48)
- memset (&data [len], '\0', 48 - len);
-/*
- * Fill in the fields from the driver data
- */
- 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;
- }
-/*
- * Pass the frame to the pppd daemon.
- */
return rcv_proto_unknown (ppp, proto, data, len);
}
-/* on entry, a received frame is in ppp->rbuf.bufr
- check it and dispose as appropriate */
-
-static void ppp_doframe_lower (struct ppp *ppp, u_char *data, int len)
+static void ppp_doframe_lower (struct ppp *ppp, __u8 *data, int count)
{
- u_short proto;
- int count = len;
- ppp_proto_type *proto_ptr;
+ __u16 proto = PPP_PROTOCOL (data);
+ ppp_proto_type *proto_ptr;
/*
* Ignore empty frames
*/
- if (count <= 0)
+ if (count <= PPP_HDRLEN)
return;
/*
* Count the frame and print it
++ppp->stats.ppp_ipackets;
if (ppp->flags & SC_LOG_INPKT)
ppp_print_buffer ("receive frame", data, count);
-/*
- * Ignore the leading ADDRESS and CONTROL fields in the frame.
- */
- 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)
- count--;
- else {
- proto = (proto << 8) | (u_short) *data++;
- count -= 2;
- }
/*
* 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.
/*
* Update the appropriate statistic counter.
*/
- if ((*proto_ptr->func) (ppp, proto, data, count))
- ppp->stats.ppp_ioctects += len;
+ 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;
}
static int
ppp_doframe (struct ppp *ppp)
{
- u_char *data = buf_base (ppp->rbuf);
+ __u8 *data = buf_base (ppp->rbuf);
int count = ppp->rbuf->count;
-#ifdef PPP_COMPRESS
- int proto;
+ int addr, ctrl, proto;
int new_count;
- u_char *new_data;
-#endif
+ __u8 *new_data;
/*
* If there is a pending error from the receiver then log it and discard
* the damaged frame.
*/
if (ppp->toss) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_WARNING
- "ppp_toss: tossing frame, reason = %d\n",
+ if ((ppp->flags & SC_DEBUG) && count > 0)
+ printk (KERN_DEBUG
+ "ppp_toss: tossing frame, reason = %x\n",
ppp->toss);
- ppp->stats.ppp_ierrors++;
return 0;
}
/*
*/
if (count < PPP_HARD_HDR_LEN) {
if (ppp->flags & SC_DEBUG)
- printk (KERN_WARNING
+ printk (KERN_DEBUG
"ppp: got runt ppp frame, %d chars\n", count);
- slhc_toss (ppp->slcomp);
- ppp->stats.ppp_ierrors++;
- return 1;
+ ++ppp->estats.rx_length_errors;
+ return 0;
}
/*
* 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++;
+ if (ppp->flags & SC_DEBUG) {
+ printk (KERN_DEBUG
+ "ppp: frame with bad fcs, length = %d\n",
+ count);
+ ppp_print_buffer("bad frame", data, count);
+ }
+ ++ppp->estats.rx_crc_errors;
return 0;
}
count -= 2; /* ignore the fcs characters */
-
-#ifdef PPP_COMPRESS
- proto = PPP_PROTOCOL (data);
/*
- * Process the active decompressor.
+ * Ignore the leading ADDRESS and CONTROL fields in the frame.
+ */
+ addr = PPP_ALLSTATIONS;
+ ctrl = PPP_UI;
+
+ if ((data[0] == PPP_ALLSTATIONS) && (data[1] == PPP_UI)) {
+ data += 2;
+ count -= 2;
+ }
+/*
+ * Obtain the protocol from the frame
+ */
+ proto = (__u16) *data++;
+ if ((proto & 1) == 0) {
+ proto = (proto << 8) | (__u16) *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) == 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.
*/
- if (((ppp->flags & (SC_DC_FERROR | SC_DC_ERROR)) == 0) &&
- (proto == PPP_COMP)) {
- new_data = kmalloc (ppp->mru + 4, GFP_ATOMIC);
+ new_data = kmalloc (ppp->mru + PPP_HDRLEN, 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;
+ new_count = DECOMP_ERROR;
+ } else {
+ new_count = (*ppp->sc_rcomp->decompress)
+ (ppp->sc_rc_state, data, count,
+ new_data, ppp->mru + PPP_HDRLEN);
}
-/*
- * 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;
- case DECOMP_OK:
- break;
-
case DECOMP_ERROR:
ppp->flags |= SC_DC_ERROR;
break;
case DECOMP_FATALERROR:
ppp->flags |= SC_DC_FERROR;
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_ERR "ppp: fatal decomp error\n");
break;
}
/*
* Log the error condition and discard the frame.
*/
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_proto_comp: "
- "decompress err %d\n", new_count);
- kfree (new_data);
+ if (new_data != 0)
+ kfree (new_data);
slhc_toss (ppp->slcomp);
- return 1;
- }
+ ++ppp->stats.ppp_ierrors;
+ } else {
/*
- * The frame is not special. Pass it through the decompressor without
- * actually decompressing the data
+ * 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);
+ (*ppp->sc_rcomp->incomp) (ppp->sc_rc_state,
+ data, count);
+ }
}
-#endif
/*
* Process the uncompressed frame.
*/
*/
static int
-ppp_tty_read (struct tty_struct *tty, struct file *file, u_char * buf,
+ppp_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf,
unsigned int nr)
{
struct ppp *ppp = tty2ppp (tty);
- u_char c;
+ __u8 c;
int len, indx;
+ int error;
#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
+ * Validate the pointers
*/
- if (!ppp || ppp->magic != PPP_MAGIC) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_tty_read: cannot find ppp channel\n");
+ if (!ppp)
return -EIO;
- }
- CHECK_PPP (-ENXIO);
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp_tty_read: called %x num %u\n",
- (unsigned int) buf,
- nr);
+ if (ppp->magic != PPP_MAGIC)
+ return -EIO;
+
+ CHECK_PPP (-ENXIO);
/*
* Acquire the read lock.
*/
for (;;) {
+ ppp = tty2ppp (tty);
+ if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse
+ || tty != ppp->tty)
+ return 0;
+
if (set_bit (0, &ppp->ubuf->locked) != 0) {
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)
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 (len == 0) {
/* no data */
clear_bit (0, &ppp->ubuf->locked);
- if (file->f_flags & O_NONBLOCK) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG
- "ppp_tty_read: no data "
- "(EWOULDBLOCK)\n");
- return -EWOULDBLOCK;
- }
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
current->timeout = 0;
if (ppp->flags & SC_DEBUG)
return -EINTR;
continue;
}
-/*
- * Reset the time of the last read operation.
- */
- ppp->ddinfo.nip_rjiffies = jiffies;
- 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.
+ * discard the frame from the input buffer.
*/
if (len + 2 > nr) {
/* Can't copy it, update us_rbuff_head */
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_USER (error, (u_char) PPP_ALLSTATIONS, buf);
+ ++buf;
+ PUT_USER (error, (u_char) PPP_UI, buf);
+ ++buf;
indx = len;
/*
*/
while (indx-- > 0) {
GETC (c);
- put_fs_byte (c, buf++);
+ PUT_USER (error, 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 */
if (ppp->flags & SC_DEBUG)
extern inline void
ppp_stuff_char (struct ppp *ppp, register struct ppp_buffer *buf,
- register u_char chr)
+ register __u8 chr)
{
/*
* The buffer should not be full.
*/
if (ppp->flags & SC_DEBUG) {
if ((buf->count < 0) || (buf->count > 3000))
- printk (KERN_DEBUG "ppp_stuff_char: %x %d\n",
+ printk (KERN_DEBUG "ppp_stuff_char: %d %x\n",
(unsigned int) buf->count,
- (unsigned int) buf->count);
+ (unsigned int) chr);
}
/*
* Update the FCS and if the character needs to be escaped, do it.
}
/*
- * Procedure to encode the data with the proper escapement and send the
+ * Procedure to encode the data with the proper escaping 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)
+ __u8 *data, int count, int non_ip)
{
- unsigned short int write_fcs;
+ __u16 write_fcs;
+ int address, control;
+ int proto;
+
+ ++ppp->stats.ppp_opackets;
+ ppp->stats.ppp_ooctects += count;
+
/*
* Insert the leading FLAG character
*/
buf->count = 0;
-#ifdef OPTIMIZE_FLAG_TIME
- if (non_ip)
+ if (non_ip || flag_time == 0)
ins_char (buf, PPP_FLAG);
else {
- if (jiffies - ppp->last_xmit > OPTIMIZE_FLAG_TIME)
+ if (jiffies - ppp->last_xmit > flag_time)
ins_char (buf, PPP_FLAG);
}
ppp->last_xmit = jiffies;
-#else
- ins_char (buf, PPP_FLAG);
-#endif
+ buf->fcs = PPP_INITFCS;
+/*
+ * Emit the address/control information if needed
+ */
+ address = PPP_ADDRESS (data);
+ control = PPP_CONTROL (data);
+ proto = PPP_PROTOCOL (data);
- buf->fcs = PPP_INITFCS;
+ 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++);
/*
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
*/
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.
*/
* 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.
+ * 1 if frame must be re-queued for later driver support.
*/
-int
+static int
ppp_dev_xmit_frame (struct ppp *ppp, struct ppp_buffer *buf,
- u_char *data, int count)
+ __u8 *data, int count)
{
- int address, control;
int proto;
- u_char *new_data;
- int new_count;
+ int address, control;
+ __u8 *new_data;
+ int new_count;
/*
* Print the buffer
*/
* 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);
- proto = PPP_PROTOCOL (data);
-#ifdef PPP_COMPRESS
- if ((ppp->flags & SC_COMP_RUN != 0) &&
+ if (((ppp->flags & SC_COMP_RUN) != 0) &&
(ppp->sc_xc_state != (void *) 0) &&
(address == PPP_ALLSTATIONS) &&
(control == PPP_UI) &&
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 += count;
+ new_count = (*ppp->sc_xcomp->compress)
+ (ppp->sc_xc_state, data, new_data, count, count);
- ppp_dev_xmit_lower (ppp, buf, new_data,
- new_count, 0);
+ if (new_count > 0 && (ppp->flags & SC_CCP_UP)) {
+ ppp_dev_xmit_lower (ppp, buf, new_data, new_count, 0);
kfree (new_data);
return 0;
}
/*
- * The frame could not be compressed.
+ * The frame could not be compressed, or it could not be sent in
+ * compressed form because CCP is not yet up.
*/
kfree (new_data);
}
-#endif
-/*
- * 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;
-/*
- * Do not compress the protocol id if not possible
- */
- if (!(ppp->flags & SC_COMP_PROT) || (proto & 0xFF00)) {
- --data;
- ++count;
- }
-
- data += 3;
- count -= 3;
-/*
- * Do not compress the address/control if not possible.
- */
- if (address != PPP_ALLSTATIONS ||
- control != PPP_UI ||
- !(ppp->flags & SC_COMP_AC)) {
- *--data = control;
- *--data = address;
- count += 2;
- }
/*
* Go to the escape encoding
*/
*/
static int
-send_revise_frame (register struct ppp *ppp, u_char *data, int len)
+send_revise_frame (register struct ppp *ppp, __u8 *data, int len)
{
- u_char *p;
+ __u8 *p;
switch (PPP_PROTOCOL (data)) {
/*
*/
case PPP_LQR:
len = 48; /* total size of this frame */
- p = (u_char *) &data [40]; /* Point to last two items. */
+ p = (__u8 *) &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
*/
-#ifdef PPP_COMPRESS
- case PPP_COMP:
- ppp_proto_ccp (ppp, data, len, 0);
+ case PPP_CCP:
+ ppp_proto_ccp (ppp,
+ data + PPP_HARD_HDR_LEN,
+ len - PPP_HARD_HDR_LEN,
+ 0);
break;
-#endif
-/*
- * All other frame types
- */
default:
break;
}
*/
static int
-ppp_tty_write (struct tty_struct *tty, struct file *file, u_char * data,
+ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data,
unsigned int count)
{
struct ppp *ppp = tty2ppp (tty);
- u_char *new_data;
+ __u8 *new_data;
+ int status;
/*
- * Verify the pointer to the PPP data and that the tty is still in PPP mode.
+ * Verify the pointers.
*/
- if (!ppp || ppp->magic != PPP_MAGIC) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_tty_write: cannot find ppp unit\n");
+ if (!ppp)
+ return -EIO;
+
+ if (ppp->magic != PPP_MAGIC)
return -EIO;
- }
CHECK_PPP (-ENXIO);
/*
* Ensure that the caller does not wish to send too much.
*/
- if (count > PPP_MTU) {
+ if (count > PPP_MTU + PPP_HDRLEN) {
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;
+ "from %u to mtu %d\n", count,
+ PPP_MTU + PPP_HDRLEN);
+ count = PPP_MTU + PPP_HDRLEN;
+ }
+/*
+ * Allocate a buffer for the data and fetch it from the user space.
+ */
+ 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;
if (ppp->flags & SC_DEBUG)
printk (KERN_DEBUG "ppp_tty_write: sleeping\n");
interruptible_sleep_on (&ppp->write_wait);
- if (current->signal & ~current->blocked)
+
+ ppp = tty2ppp (tty);
+ if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse
+ || tty != ppp->tty) {
+ kfree (new_data);
+ return 0;
+ }
+
+ if (current->signal & ~current->blocked) {
+ kfree (new_data);
return -EINTR;
+ }
}
/*
- * Allocate a buffer for the data and fetch it from the user space.
+ * Retrieve the user's buffer
*/
- new_data = kmalloc (count, GFP_ATOMIC);
- if (new_data == NULL) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_tty_write: no memory\n");
+ COPY_FROM_USER (status,
+ new_data,
+ data,
+ count);
+
+ if (status != 0) {
+ kfree (new_data);
ppp->tbuf->locked = 0;
- return 0;
+ return status;
}
-
- memcpy_fromfs (new_data, data, count);
/*
* Change the LQR frame
*/
* Process the BSD compression IOCTL event for the tty device.
*/
-#ifdef PPP_COMPRESS
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 ccp_option[CCP_MAX_OPTION_LENGTH];
- struct compressor **cp;
+ __u8 *ptr;
+ __u8 ccp_option[CCP_MAX_OPTION_LENGTH];
/*
- * Validate the range of the ioctl
+ * Fetch the compression parameters
*/
- error = verify_area (VERIFY_READ, odp,
- (unsigned long) (&((struct ppp_option_data *) 0)->length)
- + sizeof (odp->length));
+ COPY_FROM_USER (error,
+ &data,
+ odp,
+ sizeof (data));
- if (error == 0) {
- nb = (int) get_fs_long (odp->length);
- if ((unsigned long) nb-1 >= (unsigned long) CCP_MAX_OPTION_LENGTH)
- nb = CCP_MAX_OPTION_LENGTH;
+ if (error != 0)
+ return error;
- error = verify_area (VERIFY_READ, odp, nb);
- }
+ nb = data.length;
+ ptr = data.ptr;
+ if ((__u32) nb >= (__u32)CCP_MAX_OPTION_LENGTH)
+ nb = CCP_MAX_OPTION_LENGTH;
+
+ COPY_FROM_USER (error,
+ ccp_option,
+ ptr,
+ nb);
if (error != 0)
return error;
- memcpy_fromfs (ccp_option, odp, nb);
if (ccp_option[1] < 2) /* preliminary check on the length byte */
return (-EINVAL);
- for (cp = ppp_compressors; *cp != NULL; ++cp)
- if ((*cp)->compress_proto == ccp_option[0]) {
+ cp = find_compressor ((int) (unsigned int) (__u8) ccp_option[0]);
+ if (cp != (struct compressor *) 0) {
/*
* Found a handler for the protocol - try to allocate
* a compressor or decompressor.
*/
- error = 0;
- if (odp->transmit) {
- if (ppp->sc_xc_state != NULL)
- (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state);
+ 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);
+ 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;
+ 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;
}
- return (error);
+ ppp->flags &= ~SC_DECOMP_RUN;
}
+ return (error);
+ }
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);
+ 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 */
}
-#endif /* PPP_COMPRESS */
/*
* Process the IOCTL event for the tty device.
*/
static int
-ppp_tty_ioctl (struct tty_struct *tty, struct file *file, unsigned int param2,
- unsigned long param3)
+ppp_tty_ioctl (struct tty_struct *tty, struct file * file,
+ unsigned int param2, unsigned long param3)
{
struct ppp *ppp = tty2ppp (tty);
register int temp_i = 0;
- int error;
+ int error = 0;
/*
* Verify the status of the PPP device.
*/
- if (!ppp || ppp->magic != PPP_MAGIC) {
- if (ppp->flags & SC_DEBUG)
- 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.
*/
switch (param2) {
case PPPIOCSMRU:
- error = verify_area (VERIFY_READ, (void *) param3,
- sizeof (temp_i));
+ GET_USER (error, temp_i, (int *) param3);
if (error == 0) {
- temp_i = (int) get_fs_long (param3);
if (ppp->flags & SC_DEBUG)
printk (KERN_INFO
"ppp_tty_ioctl: set mru to %x\n", temp_i);
* Fetch the flags
*/
case PPPIOCGFLAGS:
- error = verify_area (VERIFY_WRITE, (void *) param3,
- sizeof (temp_i));
- if (error == 0) {
- temp_i = (ppp->flags & SC_MASK);
+ temp_i = (ppp->flags & SC_MASK);
#ifndef CHECK_CHARACTERS /* Don't generate errors if we don't check chars. */
- temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 |
- SC_RCV_ODDP | SC_RCV_EVNP;
+ temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 |
+ SC_RCV_ODDP | SC_RCV_EVNP;
#endif
- put_fs_long ((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);
- }
+ PUT_USER (error, temp_i, (int *) param3);
break;
/*
* Set the flags for the various options
*/
case PPPIOCSFLAGS:
- error = verify_area (VERIFY_READ, (void *) param3,
- sizeof (temp_i));
+ GET_USER (error, temp_i, (int *) param3);
if (error == 0) {
- temp_i = (int) get_fs_long (param3) & SC_MASK;
+ temp_i &= SC_MASK;
temp_i |= (ppp->flags & ~SC_MASK);
-#ifdef PPP_COMPRESS
+
if ((ppp->flags & SC_CCP_OPEN) &&
(temp_i & SC_CCP_OPEN) == 0)
ppp_ccp_closed (ppp);
-#else
- temp_i &= ~SC_CCP_OPEN;
-#endif
+
if ((ppp->flags | temp_i) & SC_DEBUG)
printk (KERN_INFO
"ppp_tty_ioctl: set flags to %x\n", temp_i);
/*
* Set the compression mode
*/
-#ifdef PPP_COMPRESS
case PPPIOCSCOMPRESS:
error = ppp_set_compression (ppp,
(struct ppp_option_data *) param3);
break;
-#endif
/*
* Retrieve the transmit async map
*/
case PPPIOCGASYNCMAP:
- error = verify_area (VERIFY_WRITE, (void *) param3,
- sizeof (temp_i));
- if (error == 0) {
- put_fs_long (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, ppp->xmit_async_map[0]);
- }
+ PUT_USER (error, ppp->xmit_async_map[0], (int *) param3);
break;
/*
* Set the transmit async map
*/
case PPPIOCSASYNCMAP:
- error = verify_area (VERIFY_READ, (void *) param3,
- sizeof (temp_i));
+ GET_USER (error, temp_i, (int *) param3);
if (error == 0) {
- ppp->xmit_async_map[0] = get_fs_long (param3);
+ ppp->xmit_async_map[0] = temp_i;
if (ppp->flags & SC_DEBUG)
printk (KERN_INFO
- "ppp_tty_ioctl: set xmit asyncmap %lx\n",
+ "ppp_tty_ioctl: set xmit asyncmap %x\n",
ppp->xmit_async_map[0]);
}
break;
* Set the receive async map
*/
case PPPIOCSRASYNCMAP:
- error = verify_area (VERIFY_READ, (void *) param3,
- sizeof (temp_i));
+ GET_USER (error, temp_i, (int *) param3);
if (error == 0) {
- ppp->recv_async_map = get_fs_long (param3);
+ ppp->recv_async_map = temp_i;
if (ppp->flags & SC_DEBUG)
printk (KERN_INFO
- "ppp_tty_ioctl: set rcv asyncmap %lx\n",
+ "ppp_tty_ioctl: set rcv asyncmap %x\n",
ppp->recv_async_map);
}
break;
* Obtain the unit number for this device.
*/
case PPPIOCGUNIT:
- error = verify_area (VERIFY_WRITE, (void *) param3,
- sizeof (temp_i));
+ PUT_USER (error, ppp2dev (ppp)->base_addr, (int *) param3);
if (error == 0) {
- put_fs_long (ppp2dev (ppp)->base_addr, param3);
if (ppp->flags & SC_DEBUG)
printk (KERN_INFO
- "ppp_tty_ioctl: get unit: %ld",
+ "ppp_tty_ioctl: get unit: %ld\n",
ppp2dev (ppp)->base_addr);
}
break;
* Set the debug level
*/
case PPPIOCSDEBUG:
- error = verify_area (VERIFY_READ, (void *) param3,
- sizeof (temp_i));
+ GET_USER (error, temp_i, (int *) param3);
if (error == 0) {
- temp_i = (int) (get_fs_long (param3) & 0x1F) << 16;
+ temp_i = (temp_i & 0x1F) << 16;
temp_i |= (ppp->flags & ~0x1F0000);
if ((ppp->flags | temp_i) & SC_DEBUG)
* Get the debug level
*/
case PPPIOCGDEBUG:
- error = verify_area (VERIFY_WRITE, (void *) param3,
- sizeof (temp_i));
- if (error == 0) {
- temp_i = (ppp->flags >> 16) & 0x1F;
- put_fs_long ((long) temp_i, param3);
-
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: get debug level %d\n",
- temp_i);
- }
+ temp_i = (ppp->flags >> 16) & 0x1F;
+ PUT_USER (error, temp_i, (int *) param3);
break;
/*
* Get the times since the last send/receive frame operation
*/
- case PPPIOCGTIME:
- error = verify_area (VERIFY_WRITE, (void *) param3,
- sizeof (struct ppp_ddinfo));
- if (error == 0) {
- struct ppp_ddinfo cur_ddinfo;
- unsigned long cur_jiffies = jiffies;
+ case PPPIOCGIDLE:
+ {
+ struct ppp_idle cur_ddinfo;
+ __u32 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;
-
- memcpy_tofs ((void *) param3, &cur_ddinfo,
- sizeof (struct ppp_ddinfo));
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: read demand dial info\n");
+ cur_ddinfo.xmit_idle = (cur_jiffies - ppp->ddinfo.xmit_idle) / HZ;
+ cur_ddinfo.recv_idle = (cur_jiffies - ppp->ddinfo.recv_idle) / HZ;
+ COPY_TO_USER (error,
+ (void *) param3,
+ &cur_ddinfo,
+ sizeof (cur_ddinfo));
}
break;
/*
* Retrieve the extended async map
*/
case PPPIOCGXASYNCMAP:
- error = verify_area (VERIFY_WRITE,
- (void *) param3,
- sizeof (ppp->xmit_async_map));
- if (error == 0) {
- memcpy_tofs ((void *) param3,
- ppp->xmit_async_map,
- sizeof (ppp->xmit_async_map));
-
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: get xasyncmap: addr %lx\n",
- param3);
- }
+ COPY_TO_USER (error,
+ (void *) param3,
+ ppp->xmit_async_map,
+ sizeof (ppp->xmit_async_map));
break;
/*
* Set the async extended map
*/
case PPPIOCSXASYNCMAP:
- error = verify_area (VERIFY_READ, (void *) param3,
- sizeof (ppp->xmit_async_map));
- if (error == 0) {
- unsigned long temp_tbl[8];
-
- memcpy_fromfs (temp_tbl, (void *) param3,
- sizeof (ppp->xmit_async_map));
- temp_tbl[1] = 0x00000000;
- temp_tbl[2] &= ~0x40000000;
- temp_tbl[3] |= 0x60000000;
+ {
+ __u32 temp_tbl[8];
+
+ COPY_FROM_USER (error,
+ temp_tbl,
+ (void *) param3,
+ sizeof (temp_tbl));
+
+ if (error == 0) {
+ temp_tbl[1] = 0x00000000;
+ temp_tbl[2] &= ~0x40000000;
+ 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)
+ error = -EINVAL;
+ else {
+ memcpy (ppp->xmit_async_map,
+ temp_tbl,
+ sizeof (ppp->xmit_async_map));
- if ((temp_tbl[2] & temp_tbl[3]) != 0 ||
- (temp_tbl[4] & temp_tbl[5]) != 0 ||
- (temp_tbl[6] & temp_tbl[7]) != 0)
- error = -EINVAL;
- else {
- memcpy (ppp->xmit_async_map, temp_tbl,
- sizeof (ppp->xmit_async_map));
-
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: set xasyncmap\n");
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_INFO
+ "ppp_tty_ioctl: set xasyncmap\n");
+ }
}
}
break;
* Set the maximum VJ header compression slot number.
*/
case PPPIOCSMAXCID:
- error = verify_area (VERIFY_READ, (void *) param3,
- sizeof (temp_i));
+ GET_USER (error, temp_i, (int *) param3);
if (error == 0) {
- temp_i = (int) get_fs_long (param3) + 1;
+ temp_i = (temp_i & 255) + 1;
if (ppp->flags & SC_DEBUG)
printk (KERN_INFO
"ppp_tty_ioctl: set maxcid to %d\n",
}
}
break;
+
+ case PPPIOCXFERUNIT:
+ ppp->backup_tty = tty;
+ ppp->sc_xfer = current->pid;
+ break;
+
+ case PPPIOCGNPMODE:
+ case PPPIOCSNPMODE:
+ {
+ struct npioctl npi;
+ COPY_FROM_USER (error,
+ &npi,
+ (void *) param3,
+ sizeof (npi));
+
+ if (error != 0)
+ break;
+
+ switch (npi.protocol) {
+ case PPP_IP:
+ npi.protocol = NP_IP;
+ break;
+ default:
+ if (ppp->flags & SC_DEBUG)
+ printk(KERN_DEBUG "pppioc[gs]npmode: "
+ "invalid proto %d\n", npi.protocol);
+ error = -EINVAL;
+ }
+
+ if (error != 0)
+ break;
+
+ if (param2 == PPPIOCGNPMODE) {
+ npi.mode = ppp->sc_npmode[npi.protocol];
+
+ COPY_TO_USER (error,
+ (void *) param3,
+ &npi,
+ sizeof (npi));
+ break;
+ }
+
+ if (npi.mode != ppp->sc_npmode[npi.protocol]) {
+ ppp->sc_npmode[npi.protocol] = npi.mode;
+ if (npi.mode != NPMODE_QUEUE) {
+ /* ppp_requeue(ppp); maybe needed */
+ ppp_tty_wakeup (ppp2tty(ppp));
+ }
+ }
+ }
+ break;
/*
* Allow users to read, but not set, the serial port parameters
*/
case TCGETA:
error = n_tty_ioctl (tty, file, param2, param3);
break;
+
+ case FIONREAD:
+ {
+ int count = ppp->ubuf->tail - ppp->ubuf->head;
+ if (count < 0)
+ count += (ppp->ubuf->size + 1);
+ PUT_USER (error, count, (int *) param3);
+ }
+ break;
/*
* All other ioctl() events will come here.
*/
/*
* Verify the status of the PPP device.
*/
- if (!ppp || ppp->magic != PPP_MAGIC) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_tty_select: can't find PPP block from tty!\n");
+ if (!ppp)
return -EBADF;
- }
+
+ if (ppp->magic != PPP_MAGIC || tty != ppp->tty)
+ return -EBADF;
+
CHECK_PPP (0);
/*
* Branch on the type of select mode. A read request must lock the user
}
clear_bit (0, &ppp->ubuf->locked);
} /* fall through */
- /*
+/*
* Exceptions or read errors.
*/
case SEL_EX:
/* Is this a pty link and the remote disconnected? */
- if (tty->flags & (1 << TTY_SLAVE_CLOSED))
+ if (tty->flags & (1 << TTY_OTHER_CLOSED))
break;
/* Is this a local link and the modem disconnected? */
struct ppp *ppp = dev2ppp (dev);
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;
}
/*
static int
ppp_dev_ioctl_version (struct ppp *ppp, struct ifreq *ifr)
{
- int error;
- int len;
- char *result;
-/*
- * Must have write access to the buffer.
- */
- result = (char *) ifr->ifr_ifru.ifru_data;
- len = strlen (szVersion) + 1;
- error = verify_area (VERIFY_WRITE, result, len);
+ int error;
+ char *result = (char *) ifr->ifr_ifru.ifru_data;
+ int len = strlen (szVersion) + 1;
/*
* Move the version data
*/
- if (error == 0)
- memcpy_tofs (result, szVersion, len);
+ COPY_TO_USER (error,
+ result,
+ szVersion,
+ len);
return error;
}
*/
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;
-/*
- * Must have write access to the buffer.
- */
- result = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
- error = verify_area (VERIFY_WRITE,
- result,
- sizeof (temp));
/*
* 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));
+ memset (&temp, 0, sizeof(temp));
+ if (dev->flags & IFF_UP) {
memcpy (&temp.p, &ppp->stats, sizeof (struct pppstat));
-/*
- * Header Compression statistics
- */
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;
}
+ }
+
+ result = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
+
+ COPY_TO_USER (error,
+ result,
+ &temp,
+ sizeof (temp));
+
+ return error;
+}
+
/*
- * Frame data compression statistics
+ * IOCTL to read the compression statistics for the pppstats program.
*/
-#ifdef PPP_COMPRESS
+
+static int
+ppp_dev_ioctl_comp_stats (struct ppp *ppp, struct ifreq *ifr, struct device *dev)
+{
+ struct ppp_comp_stats *result, temp;
+ int error;
+/*
+ * Supply the information for the caller.
+ */
+ memset (&temp, 0, sizeof(temp));
+ if (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);
-#endif /* PPP_COMPRESS */
-
+ }
/*
* Move the data to the caller's buffer
*/
- memcpy_tofs (result, &temp, sizeof (temp));
- }
+ result = (struct ppp_comp_stats *) ifr->ifr_ifru.ifru_data;
+
+ COPY_TO_USER (error,
+ result,
+ &temp,
+ sizeof (temp));
+
return error;
}
*/
switch (cmd) {
case SIOCGPPPSTATS:
- error = ppp_dev_ioctl_stats (ppp, ifr);
+ error = ppp_dev_ioctl_stats (ppp, ifr, dev);
+ break;
+
+ case SIOCGPPPCSTATS:
+ error = ppp_dev_ioctl_comp_stats (ppp, ifr, dev);
break;
case SIOCGPPPVER:
* 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.
+ * 1 if frame must be re-queued for later driver support.
*/
-int
-ppp_dev_xmit_ip1 (struct device *dev, struct ppp *ppp, u_char *data)
+static int
+ppp_dev_xmit_ip (struct device *dev, struct ppp *ppp, __u8 *data)
{
- int proto = PPP_IP;
- int len;
- struct ppp_hdr *hdr;
+ int proto = PPP_IP;
+ int len;
+ struct ppp_hdr *hdr;
struct tty_struct *tty = ppp2tty (ppp);
/*
* Obtain the length from the IP header.
dev->name);
return 0;
}
+/*
+ * Branch on the type of processing for the IP frame.
+ */
+ switch (ppp->sc_npmode[NP_IP]) {
+ case NPMODE_PASS:
+ break;
+
+ case NPMODE_ERROR:
+ case NPMODE_DROP:
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_DEBUG
+ "ppp_dev_xmit: npmode = %d on %s\n",
+ ppp->sc_npmode[NP_IP], dev->name);
+ return 0;
+
+ case NPMODE_QUEUE:
+ break;
+
+ default:
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_WARNING
+ "ppp_dev_xmit: unknown npmode %d on %s\n",
+ ppp->sc_npmode[NP_IP],
+ dev->name);
+ return 0;
+ }
/*
* Detect a change in the transfer size
*/
}
/*
* 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.
+ * mark the device as busy.
*/
if (lock_buffer (ppp->wbuf) != 0) {
dev->tbusy = 1;
len = slhc_compress (ppp->slcomp, data, len,
buf_base (ppp->cbuf) + PPP_HARD_HDR_LEN,
&data,
- !(ppp->flags & SC_NO_TCP_CCID));
+ (ppp->flags & SC_NO_TCP_CCID) == 0);
if (data[0] & SL_TYPE_COMPRESSED_TCP) {
- proto = PPP_VJC_COMP;
+ proto = PPP_VJC_COMP;
data[0] ^= SL_TYPE_COMPRESSED_TCP;
} else {
if (data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
len += PPP_HARD_HDR_LEN;
hdr = &((struct ppp_hdr *) data)[-1];
- hdr->address = PPP_ALLSTATIONS;
- hdr->control = PPP_UI;
+ 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.
- */
-
-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;
+ return ppp_dev_xmit_frame (ppp, ppp->wbuf, (__u8 *) hdr, len);
}
/*
* 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.
+ * 1 if frame must be re-queued for later driver support.
*/
-
-int
-ppp_dev_xmit_ipx1 (struct device *dev, struct ppp *ppp,
- u_char *data, int len, int proto)
+static int
+ppp_dev_xmit_ipx (struct device *dev, struct ppp *ppp,
+ __u8 *data, int len, int proto)
{
struct tty_struct *tty = ppp2tty (ppp);
- struct ppp_hdr *hdr;
+ struct ppp_hdr *hdr;
/*
* Validate the tty interface
*/
}
/*
* 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.
+ * mark the device as busy.
*/
if (lock_buffer (ppp->wbuf) != 0) {
dev->tbusy = 1;
len += PPP_HARD_HDR_LEN;
hdr = &((struct ppp_hdr *) data)[-1];
- hdr->address = PPP_ALLSTATIONS;
- hdr->control = PPP_UI;
+ 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);
-}
-
-/*
- * 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.
- */
-
-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 = (dev, ppp, (u_char *) &hdr[1], len, proto);
- kfree (hdr);
- }
-
- return answer;
+ return ppp_dev_xmit_frame (ppp, ppp->wbuf, (__u8 *) hdr, len);
}
/*
* Send a frame to the remote.
*/
-int
+static int
ppp_dev_xmit (sk_buff *skb, struct device *dev)
{
- int answer;
- u_char *data;
- struct ppp *ppp = dev2ppp (dev);
+ int answer, len;
+ __u8 *data;
+ struct ppp *ppp = dev2ppp (dev);
struct tty_struct *tty = ppp2tty (ppp);
/*
* just a little sanity check.
dev_close (dev);
return 0;
}
-/*
- * Validate the tty linkage
- */
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG "ppp_dev_xmit [%s]: skb %X\n",
- dev->name, (int) skb);
/*
* Validate the tty interface
*/
/*
* Fetch the pointer to the data
*/
- data = skb_data (skb);
+ len = skb->len;
+ data = skb_data(skb);
+
+ if (data == (__u8 *) 0) {
+ if (ppp->flags & SC_DEBUG)
+ printk (KERN_CRIT "ppp_dev_xmit: %s Null skb data\n",
+ dev->name);
+ dev_kfree_skb (skb, FREE_WRITE);
+ return 0;
+ }
/*
* Look at the protocol in the skb to determine the difference between
* an IP frame and an IPX frame.
*/
-
-#ifdef NEW_SKBUFF
- switch (skb->protocol) {
- case htons (ETH_P_IPX):
- answer = ppp_dev_xmit_ipx (dev, ppp, data, skb->len, PPP_IPX);
+ switch (ntohs (skb->protocol)) {
+ case ETH_P_IPX:
+ answer = ppp_dev_xmit_ipx (dev, ppp, data, len, PPP_IPX);
break;
- case htons (ETH_P_IP):
+ case ETH_P_IP:
answer = ppp_dev_xmit_ip (dev, ppp, data);
break;
dev_kfree_skb (skb, FREE_WRITE);
return 0;
}
-#else
- 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)
+ if (answer == 0) {
dev_kfree_skb (skb, FREE_WRITE);
+ ppp->ddinfo.xmit_idle = jiffies;
+ }
return answer;
}
ppp_dev_stats (struct device *dev)
{
struct ppp *ppp = dev2ppp (dev);
- static struct enet_statistics ppp_stats;
-
- 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->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_carrier_errors = 0;
- ppp_stats.tx_aborted_errors = 0;
- ppp_stats.tx_window_errors = 0;
- ppp_stats.tx_heartbeat_errors = 0;
-
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO "ppp_dev_stats called");
- return &ppp_stats;
-}
-
-#ifdef 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.
- */
-
-static int ppp_dev_input (struct protocol *self, struct protocol *lower,
- sk_buff *skb, void *saddr, void *daddr)
-{
- return protocol_pass_demultiplex(self, NULL, skb, NULL, NULL);
-}
-
-static int ppp_dev_output (struct protocol *self, sk_buff *skb, int type,
- int subid, void *saddr, void *daddr, void *opt)
-{
- if(skb->dev==NULL)
- {
- printk("ppp_dev_output: No device.\n");
- kfree_skb(skb, FREE_WRITE);
- return -1;
- }
- dev_queue_xmit(skb, skb->dev, skb->priority);
- return 0;
-}
-
-static int ppp_dev_getkey(int protocol, int subid, unsigned char *key)
-{
- switch (protocol)
- {
- case htons (ETH_P_IP):
- case htons (ETH_P_IPX):
- return 0;
- default:
- break;
- }
+ ppp->estats.rx_packets = ppp->stats.ppp_ipackets;
+ ppp->estats.rx_errors = ppp->stats.ppp_ierrors;
+ ppp->estats.tx_packets = ppp->stats.ppp_opackets;
+ ppp->estats.tx_errors = ppp->stats.ppp_oerrors;
- return -EAFNOSUPPORT;
+ return &ppp->estats;
}
-#else
-
-/*
- * 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.
- */
-
-static unsigned short
-ppp_dev_type (sk_buff *skb, struct device *dev)
-{
- return (htons (ETH_P_IP));
-}
-
-static int
-ppp_dev_header (u_char * buff, struct device *dev, unsigned short type,
- void *daddr, void *saddr, unsigned len, sk_buff *skb)
+#if LINUX_VERSION_CODE < VERSION(2,1,15)
+static int ppp_dev_header (sk_buff *skb, struct device *dev,
+ __u16 type, void *daddr,
+ void *saddr, unsigned int len)
{
return (0);
}
static int
-ppp_dev_rebuild (void *buff, struct device *dev, unsigned long raddr,
- sk_buff *skb)
+ppp_dev_rebuild (void *eth, struct device *dev,
+ unsigned long raddr, struct sk_buff *skb)
{
return (0);
}
* Miscellany called by various functions above.
*************************************************************/
+/* Locate the previous instance of the PPP channel */
+static struct ppp *
+ppp_find (int pid_value)
+{
+ int if_num;
+ ppp_ctrl_t *ctl;
+ struct ppp *ppp;
+
+ /* try to find the exact same free device which we had before */
+ ctl = ppp_list;
+ if_num = 0;
+
+ while (ctl) {
+ ppp = ctl2ppp (ctl);
+ if (ppp->sc_xfer == pid_value) {
+ set_bit(0, &ppp->inuse);
+ ppp->sc_xfer = 0;
+ return (ppp);
+ }
+ ctl = ctl->next;
+ if (++if_num == max_dev)
+ break;
+ }
+ return NULL;
+}
+
/* allocate or create a PPP channel */
static struct ppp *
ppp_alloc (void)
{
-#if 1
int if_num;
int status;
ppp_ctrl_t *ctl;
struct ppp *ppp;
/* try to find an free device */
- ctl = ppp_list;
- if_num = 0;
-
+ 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 == INT_MAX)
+ if (++if_num == max_dev)
return (NULL);
}
/*
ppp->line = if_num;
ppp->tty = NULL;
+ ppp->backup_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->base_addr = (__u32) 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 */
+ /* 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 ("registered device %s\n", dev->name);
+ printk (KERN_INFO "registered device %s\n", dev->name);
return (ppp);
}
/* This one will forever be busy as it is not initialized */
}
return (NULL);
-#else
- int i;
- for (i = 0; i < PPP_NRUNIT; i++)
- if (!set_bit(0, &ppp_ctrl[i].inuse)) return &ppp_ctrl[i];
-
- return NULL;
-#endif
}
/*
*/
static void
-ppp_print_hex (register u_char * out, u_char * in, int count)
+ppp_print_hex (register __u8 * out, const __u8 * in, int count)
{
- register u_char next_ch;
+ register __u8 next_ch;
static char hex[] = "0123456789ABCDEF";
while (count-- > 0) {
}
static void
-ppp_print_char (register u_char * out, u_char * in, int count)
+ppp_print_char (register __u8 * out, const __u8 * in, int count)
{
- register u_char next_ch;
+ register __u8 next_ch;
while (count-- > 0) {
next_ch = *in++;
}
static void
-ppp_print_buffer (const u_char * name, u_char * buf, int count)
+ppp_print_buffer (const __u8 * name, const __u8 * buf, int count)
{
- u_char line[44];
+ __u8 line[44];
- if (name != (u_char *) NULL)
+ if (name != (__u8 *) NULL)
printk (KERN_DEBUG "ppp: %s, count = %d\n", name, count);
while (count > 8) {
}
}
+/*************************************************************
+ * 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) (__u8) 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
-char kernel_version[] = UTS_RELEASE;
-
int
init_module(void)
{
/* register our line disciplines */
status = ppp_first_time();
- if (status != 0) {
+ if (status != 0)
printk (KERN_INFO
"PPP: ppp_init() failure %d\n", status);
- }
+#if LINUX_VERSION_CODE < VERSION(2,1,18)
+ else
+ (void) register_symtab (&ppp_syms);
+#endif
return (status);
}
ppp_ctrl_t *ctl, *next_ctl;
struct device *dev;
struct ppp *ppp;
- int busy_flag = MOD_IN_USE;
+ int busy_flag = 0;
/*
* Ensure that the devices are not in operation.
*/
- if (!busy_flag) {
- ctl = ppp_list;
- while (ctl) {
- ppp = ctl2ppp (ctl);
- if (ppp->inuse && ppp->tty != NULL) {
- busy_flag = 1;
- break;
- }
+ 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;
+ 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
return;
}
/*
- * Release the tty registration of the line dicipline so that no new entries
+ * Release the tty registration of the line discipline so that no new entries
* may be created.
*/
status = tty_register_ldisc (N_PPP, NULL);
"(err = %d)\n", status);
else
printk (KERN_INFO
- "PPP: ppp line discipline successfully unregistered\n");
+ "PPP: ppp line discipline successfully unregistered\n");
/*
* De-register the devices so that there is no problem with them
- */
- next = ppp_list;
- while (next) {
- ctl = next;
- ppp = ctl2ppp (ctl);
- dev = ctl2dev (ctl);
+ */
+ next_ctl = ppp_list;
+ while (next_ctl) {
+ ctl = next_ctl;
+ next_ctl = ctl->next;
+ ppp = ctl2ppp (ctl);
+ dev = ctl2dev (ctl);
- ppp_release (ppp);
+ ppp_release (ppp);
unregister_netdev (dev);
-/*
- * Release the storage occupied by the control structures
- */
- next = ctl->next;
kfree (ctl);
}
}