patch-2.0.31 linux/drivers/isdn/isdn_ppp.c
Next file: linux/drivers/isdn/isdn_ppp.h
Previous file: linux/drivers/isdn/isdn_net.h
Back to the patch index
Back to the overall index
- Lines: 2444
- Date:
Mon Aug 4 17:34:00 1997
- Orig file:
v2.0.30/linux/drivers/isdn/isdn_ppp.c
- Orig date:
Tue Nov 12 22:36:19 1996
diff -u --recursive --new-file v2.0.30/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c
@@ -1,9 +1,9 @@
-/* $Id: isdn_ppp.c,v 1.20 1996/10/30 12:21:58 fritz Exp $
+/* $Id: isdn_ppp.c,v 1.28 1997/06/17 13:05:57 hipp Exp $
*
* Linux ISDN subsystem, functions for synchronous PPP (linklevel).
*
* Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
- *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
@@ -16,9 +16,42 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_ppp.c,v $
+ * Revision 1.28 1997/06/17 13:05:57 hipp
+ * Applied Eric's underflow-patches (slightly modified)
+ * more compression changes (but disabled at the moment)
+ * changed one copy_to_user() to run with enabled IRQs
+ * a few MP changes
+ * changed 'proto' handling in the isdn_ppp receive code
+ *
+ * Revision 1.27 1997/03/30 16:51:17 calle
+ * changed calls to copy_from_user/copy_to_user and removed verify_area
+ * were possible.
+ *
+ * Revision 1.26 1997/02/23 16:53:44 hipp
+ * minor cleanup
+ * some initial changes for future PPP compresion
+ * added AC,PC compression for outgoing frames
+ *
+ * Revision 1.25 1997/02/12 20:37:35 hipp
+ * New ioctl() PPPIOCGCALLINFO, minor cleanup
+ *
+ * Revision 1.24 1997/02/11 18:32:56 fritz
+ * Bugfix in isdn_ppp_free_mpqueue().
+ *
+ * Revision 1.23 1997/02/10 11:12:19 fritz
+ * More changes for Kernel 2.1.X compatibility.
+ *
+ * Revision 1.22 1997/02/06 15:03:51 hipp
+ * changed GFP_KERNEL kmalloc to GFP_ATOMIC in isdn_ppp_fill_mpqueue()
+ *
+ * Revision 1.21 1997/02/03 23:29:38 fritz
+ * Reformatted according CodingStyle
+ * Bugfix: removed isdn_ppp_skb_destructor, used by upper layers.
+ * Misc changes for Kernel 2.1.X compatibility.
+ *
* Revision 1.20 1996/10/30 12:21:58 fritz
* Cosmetic fix: Compiler warning when compiling without MPP.
*
@@ -92,70 +125,91 @@
/* TODO: right tbusy handling when using MP */
+/*
+ * experimental for dynamic addressing: readdress IP frames
+ */
#undef ISDN_SYNCPPP_READDRESS
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
+#include <linux/version.h>
#include <linux/isdn.h>
+#if (LINUX_VERSION_CODE >= 0x020117)
+#include <asm/poll.h>
+#endif
#include "isdn_common.h"
#include "isdn_ppp.h"
#include "isdn_net.h"
#ifndef PPP_IPX
-#define PPP_IPX 0x002b
+#define PPP_IPX 0x002b
#endif
/* set this if you use dynamic addressing */
-
+
/* Prototypes */
-static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int slot);
+static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot);
static int isdn_ppp_closewait(int slot);
static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp,
- struct sk_buff *skb, int proto);
+ struct sk_buff *skb, int proto);
static int isdn_ppp_if_get_unit(char *namebuf);
+static int isdn_ppp_set_compressor(struct ippp_struct *is,int num);
+static struct sk_buff *isdn_ppp_decompress(struct sk_buff *,
+ struct ippp_struct *,struct ippp_struct *);
+static void isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp,
+ struct sk_buff *skb);
+static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
+ struct ippp_struct *is,struct ippp_struct *master,int type);
#ifdef CONFIG_ISDN_MPP
static int isdn_ppp_bundle(struct ippp_struct *, int unit);
static void isdn_ppp_mask_queue(isdn_net_dev * dev, long mask);
static void isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min);
-static void isdn_ppp_cleanup_sqqueue(isdn_net_dev * dev,isdn_net_local *, long min);
+static void isdn_ppp_cleanup_sqqueue(isdn_net_dev * dev, isdn_net_local *, long min);
+static void isdn_ppp_free_sqqueue(isdn_net_dev *);
static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb,
- int BEbyte, long *sqno, int min_sqno);
+ int BEbyte, long *sqno, int min_sqno);
+static void isdn_ppp_free_mpqueue(isdn_net_dev *);
#endif
-char *isdn_ppp_revision = "$Revision: 1.20 $";
+char *isdn_ppp_revision = "$Revision: 1.28 $";
-struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
+static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
+static struct isdn_ppp_compressor *ipc_head = NULL;
extern int isdn_net_force_dial_lp(isdn_net_local *);
/*
* frame log (debug)
*/
-static void isdn_ppp_frame_log(char *info,char *data,int len,int maxlen)
+static void
+isdn_ppp_frame_log(char *info, char *data, int len, int maxlen)
{
- int cnt,j,i;
+ int cnt,
+ j,
+ i;
char buf[80];
- if(len < maxlen)
+ if (len < maxlen)
maxlen = len;
-
- for(i=0,cnt=0;cnt<maxlen;i++) {
- for(j=0;j<16 && cnt<maxlen;j++,cnt++)
- sprintf(buf+j*3,"%02x ",(unsigned char) data[cnt]);
- printk(KERN_DEBUG "%s[%d]: %s\n",info,i,buf);
+
+ for (i = 0, cnt = 0; cnt < maxlen; i++) {
+ for (j = 0; j < 16 && cnt < maxlen; j++, cnt++)
+ sprintf(buf + j * 3, "%02x ", (unsigned char) data[cnt]);
+ printk(KERN_DEBUG "%s[%d]: %s\n", info, i, buf);
}
}
/*
- * unbind isdn_net_local <=> ippp-device
+ * unbind isdn_net_local <=> ippp-device
* note: it can happen, that we hangup/free the master before the slaves
*/
-int isdn_ppp_free(isdn_net_local *lp)
+int
+isdn_ppp_free(isdn_net_local * lp)
{
#ifdef CONFIG_ISDN_MPP
- isdn_net_local *master_lp=lp;
+ isdn_net_local *master_lp = lp;
#endif
unsigned long flags;
struct ippp_struct *is;
@@ -168,14 +222,14 @@
save_flags(flags);
cli();
#ifdef CONFIG_ISDN_MPP
- if(lp->master)
+ if (lp->master)
master_lp = (isdn_net_local *) lp->master->priv;
lp->last->next = lp->next;
lp->next->last = lp->last;
- if(master_lp->netdev->queue == lp) {
+ if (master_lp->netdev->queue == lp) {
master_lp->netdev->queue = lp->next;
- if(lp->next == lp) { /* last link in queue? */
+ if (lp->next == lp) { /* last link in queue? */
master_lp->netdev->ib.bundled = 0;
isdn_ppp_free_mpqueue(master_lp->netdev);
isdn_ppp_free_sqqueue(master_lp->netdev);
@@ -184,21 +238,21 @@
lp->next = lp->last = lp; /* (re)set own pointers */
#endif
- if( (is->state & IPPP_CONNECT) )
+ if ((is->state & IPPP_CONNECT))
isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */
- else if(is->state & IPPP_ASSIGNED)
+ else if (is->state & IPPP_ASSIGNED)
is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGEND' staet */
-
- if(is->debug & 0x1)
- printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp,(long) is->lp);
- is->lp = NULL; /* link is down .. set lp to NULL */
+ if (is->debug & 0x1)
+ printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp);
+
+ is->lp = NULL; /* link is down .. set lp to NULL */
#ifdef ISDN_SYNCPPP_READDRESS
is->old_pa_addr = 0x0;
is->old_pa_dstaddr = 0x0;
#endif
- lp->ppp_slot = -1; /* is this OK ?? */
+ lp->ppp_slot = -1; /* is this OK ?? */
restore_flags(flags);
return 0;
@@ -207,7 +261,8 @@
/*
* bind isdn_net_local <=> ippp-device
*/
-int isdn_ppp_bind(isdn_net_local * lp)
+int
+isdn_ppp_bind(isdn_net_local * lp)
{
int i;
int unit = 0;
@@ -220,14 +275,13 @@
save_flags(flags);
cli();
- if(lp->pppbind < 0) /* device bounded to ippp device ? */
- {
- isdn_net_dev *net_dev = dev->netdev;
+ if (lp->pppbind < 0) { /* device bounded to ippp device ? */
+ isdn_net_dev *net_dev = dev->netdev;
char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */
- memset(exclusive,0,ISDN_MAX_CHANNELS);
+ memset(exclusive, 0, ISDN_MAX_CHANNELS);
while (net_dev) { /* step through net devices to find exclusive minors */
isdn_net_local *lp = &net_dev->local;
- if(lp->pppbind >= 0)
+ if (lp->pppbind >= 0)
exclusive[lp->pppbind] = 1;
net_dev = net_dev->next;
}
@@ -235,14 +289,13 @@
* search a free device / slot
*/
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) { /* OPEN, but not connected! */
+ if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) { /* OPEN, but not connected! */
break;
}
}
- }
- else {
- for(i=0;i<ISDN_MAX_CHANNELS;i++)
- if(ippp_table[i]->minor == lp->pppbind && ippp_table[i]->state == IPPP_OPEN)
+ } else {
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+ if (ippp_table[i]->minor == lp->pppbind && ippp_table[i]->state == IPPP_OPEN)
break;
}
@@ -251,13 +304,11 @@
printk(KERN_WARNING "isdn_ppp_bind: Can't find usable ippp device.\n");
return -1;
}
-
- unit = isdn_ppp_if_get_unit(lp->name); /* get unit number from interface name .. ugly! */
- if(unit < 0) {
- printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n",lp->name);
+ unit = isdn_ppp_if_get_unit(lp->name); /* get unit number from interface name .. ugly! */
+ if (unit < 0) {
+ printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", lp->name);
return -1;
}
-
lp->ppp_slot = i;
is = ippp_table[i];
is->lp = lp;
@@ -274,9 +325,10 @@
* (wakes up daemon after B-channel connect)
*/
-void isdn_ppp_wakeup_daemon(isdn_net_local *lp)
+void
+isdn_ppp_wakeup_daemon(isdn_net_local * lp)
{
- if(lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS)
+ if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS)
return;
ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
@@ -287,10 +339,11 @@
/*
* there was a hangup on the netdevice
- * force wakeup of the ippp device
+ * force wakeup of the ippp device
* go into 'device waits for release' state
*/
-static int isdn_ppp_closewait(int slot)
+static int
+isdn_ppp_closewait(int slot)
{
struct ippp_struct *is;
@@ -309,56 +362,64 @@
* isdn_ppp_find_slot / isdn_ppp_free_slot
*/
-static int isdn_ppp_get_slot(void)
+static int
+isdn_ppp_get_slot(void)
{
int i;
- for(i=0;i<ISDN_MAX_CHANNELS;i++) {
- if(!ippp_table[i]->state)
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ if (!ippp_table[i]->state)
return i;
}
return -1;
}
/*
- * isdn_ppp_open
+ * isdn_ppp_open
*/
-int isdn_ppp_open(int min, struct file *file)
+int
+isdn_ppp_open(int min, struct file *file)
{
int slot;
struct ippp_struct *is;
- if(min < 0 || min > ISDN_MAX_CHANNELS)
+ if (min < 0 || min > ISDN_MAX_CHANNELS)
return -ENODEV;
slot = isdn_ppp_get_slot();
- if(slot < 0) {
+ if (slot < 0) {
return -EBUSY;
}
is = file->private_data = ippp_table[slot];
- if(is->debug & 0x1)
- printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n",slot, min,is->state);
+ if (is->debug & 0x1)
+ printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, min, is->state);
- is->lp = 0;
- is->mp_seqno = 0; /* MP sequence number */
- is->pppcfg = 0; /* ppp configuration */
- is->mpppcfg = 0; /* mppp configuration */
- is->range = 0x1000000; /* MP: 24 bit range */
+ /* compression stuff */
+ is->compressor = NULL;
+ is->decomp_stat = is->comp_stat = NULL;
+ is->link_compressor = NULL;
+ is->link_decomp_stat = is->link_comp_stat = NULL;
+
+ is->lp = NULL;
+ is->mp_seqno = 0; /* MP sequence number */
+ is->pppcfg = 0; /* ppp configuration */
+ is->mpppcfg = 0; /* mppp configuration */
+ is->range = 0x1000000; /* MP: 24 bit range */
is->last_link_seqno = -1; /* MP: maybe set to Bundle-MIN, when joining a bundle ?? */
- is->unit = -1; /* set, when we have our interface */
- is->mru = 1524; /* MRU, default 1524 */
- is->maxcid = 16; /* VJ: maxcid */
+ is->unit = -1; /* set, when we have our interface */
+ is->mru = 1524; /* MRU, default 1524 */
+ is->maxcid = 16; /* VJ: maxcid */
is->tk = current;
- is->wq = NULL; /* read() wait queue */
- is->wq1 = NULL; /* select() wait queue */
- is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
+ is->wq = NULL; /* read() wait queue */
+ is->wq1 = NULL; /* select() wait queue */
+ is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
is->last = is->rq;
is->minor = min;
#ifdef CONFIG_ISDN_PPP_VJ
- /*
- * VJ header compression init
- */
+ /*
+ * VJ header compression init
+ */
is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */
#endif
@@ -370,7 +431,8 @@
/*
* release ippp device
*/
-void isdn_ppp_release(int min, struct file *file)
+void
+isdn_ppp_release(int min, struct file *file)
{
int i;
struct ippp_struct *is;
@@ -379,14 +441,14 @@
return;
is = file->private_data;
- if(is->debug & 0x1)
+ if (is->debug & 0x1)
printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);
- if (is->lp) { /* a lp address says: this link is still up */
+ if (is->lp) { /* a lp address says: this link is still up */
isdn_net_dev *p = is->lp->netdev;
-
- is->state &= ~IPPP_CONNECT; /* -> effect: no call of wakeup */
- /*
+
+ is->state &= ~IPPP_CONNECT; /* -> effect: no call of wakeup */
+ /*
* isdn_net_hangup() calls isdn_ppp_free()
* isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1
* removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon()
@@ -399,8 +461,8 @@
is->rq[i].buf = NULL;
}
}
- is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
- is->last = is->rq;
+ is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
+ is->last = is->rq;
#ifdef CONFIG_ISDN_PPP_VJ
slhc_free(is->slcomp);
@@ -413,216 +475,286 @@
/*
* get_arg .. ioctl helper
*/
-static int get_arg(void *b,void *val,int len)
+static int
+get_arg(void *b, void *val, int len)
{
int r;
- if(len <= 0)
- len = sizeof(unsigned long);
- if ((r = verify_area(VERIFY_READ, (void *) b, len )))
- return r;
- copy_from_user((void *) val, b, len );
+ if (len <= 0)
+ len = sizeof(unsigned long);
+ if ((r = copy_from_user((void *) val, b, len)))
+ return r;
return 0;
}
/*
* set arg .. ioctl helper
*/
-static int set_arg(void *b, unsigned long val,void *str)
+static int
+set_arg(void *b, unsigned long val, void *str)
{
int r;
- if(!str) {
- if ((r = verify_area(VERIFY_WRITE, b, 4 )))
- return r;
- copy_to_user(b, (void *) &val, 4 );
- }
- else {
- if ((r = verify_area(VERIFY_WRITE, b,val)))
+ if (!str) {
+ if ((r = copy_to_user(b, (void *) &val, 4)))
+ return r;
+ } else {
+ if ((r = copy_to_user(b, str, val)))
return r;
- copy_to_user(b,str,val);
}
return 0;
}
/*
- * ippp device ioctl
+ * ippp device ioctl
*/
-int isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
+int
+isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
{
unsigned long val;
- int r;
+ int num,r;
struct ippp_struct *is;
+ isdn_net_local *lp;
- is = file->private_data;
+ is = (struct ippp_struct *) file->private_data;
+ lp = is->lp;
- if(is->debug & 0x1)
- printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n",min,cmd,is->state);
+ if (is->debug & 0x1)
+ printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state);
if (!(is->state & IPPP_OPEN))
return -EINVAL;
switch (cmd) {
- case PPPIOCBUNDLE:
+ case PPPIOCBUNDLE:
#ifdef CONFIG_ISDN_MPP
- if( !(is->state & IPPP_CONNECT) )
- return -EINVAL;
- if ((r = get_arg((void *) arg, &val,0)))
- return r;
- printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
- (int) min, (int) is->unit, (int) val);
- return isdn_ppp_bundle(is, val);
+ if (!(is->state & IPPP_CONNECT))
+ return -EINVAL;
+ if ((r = get_arg((void *) arg, &val, 0)))
+ return r;
+ printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
+ (int) min, (int) is->unit, (int) val);
+ return isdn_ppp_bundle(is, val);
#else
- return -1;
+ return -1;
#endif
- break;
- case PPPIOCGUNIT: /* get ppp/isdn unit number */
- if ((r = set_arg((void *) arg, is->unit,NULL)))
- return r;
- break;
- case PPPIOCGMPFLAGS: /* get configuration flags */
- if ((r = set_arg((void *) arg, is->mpppcfg,NULL)))
- return r;
- break;
- case PPPIOCSMPFLAGS: /* set configuration flags */
- if ((r = get_arg((void *) arg, &val,0)))
- return r;
- is->mpppcfg = val;
- break;
- case PPPIOCGFLAGS: /* get configuration flags */
- if ((r = set_arg((void *) arg, is->pppcfg,NULL)))
- return r;
- break;
- case PPPIOCSFLAGS: /* set configuration flags */
- if ((r = get_arg((void *) arg, &val,0))) {
- return r;
- }
- if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT) ) {
- isdn_net_local *lp = is->lp;
- if(lp) {
- lp->netdev->dev.tbusy = 0;
- mark_bh(NET_BH); /* OK .. we are ready to send buffers */
+ break;
+ case PPPIOCGUNIT: /* get ppp/isdn unit number */
+ if ((r = set_arg((void *) arg, is->unit, NULL)))
+ return r;
+ break;
+ case PPPIOCGMPFLAGS: /* get configuration flags */
+ if ((r = set_arg((void *) arg, is->mpppcfg, NULL)))
+ return r;
+ break;
+ case PPPIOCSMPFLAGS: /* set configuration flags */
+ if ((r = get_arg((void *) arg, &val, 0)))
+ return r;
+ is->mpppcfg = val;
+ break;
+ case PPPIOCGFLAGS: /* get configuration flags */
+ if ((r = set_arg((void *) arg, is->pppcfg, NULL)))
+ return r;
+ break;
+ case PPPIOCSFLAGS: /* set configuration flags */
+ if ((r = get_arg((void *) arg, &val, 0))) {
+ return r;
}
- }
- is->pppcfg = val;
- break;
+ if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
+ if (lp) {
+ lp->netdev->dev.tbusy = 0;
+ mark_bh(NET_BH); /* OK .. we are ready to send buffers */
+ }
+ }
+ is->pppcfg = val;
+ break;
#if 0
- case PPPIOCGSTAT: /* read PPP statistic information */
- break;
+ case PPPIOCGSTAT: /* read PPP statistic information */
+ break;
#endif
- case PPPIOCGIDLE: /* get idle time information */
- if(is->lp)
- {
- struct ppp_idle pidle;
- pidle.xmit_idle = pidle.recv_idle = is->lp->huptimer;
- if((r = set_arg((void *) arg,sizeof(struct ppp_idle),&pidle)))
- return r;
- }
- break;
- case PPPIOCSMRU: /* set receive unit size for PPP */
- if ((r = get_arg((void *) arg, &val,0)))
- return r;
- is->mru = val;
- break;
- case PPPIOCSMPMRU:
- break;
- case PPPIOCSMPMTU:
- break;
- case PPPIOCSMAXCID: /* set the maximum compression slot id */
- if ((r = get_arg((void *) arg, &val,0)))
- return r;
- val++;
- if(is->maxcid != val) {
+ case PPPIOCGIDLE: /* get idle time information */
+ if (lp) {
+ struct ppp_idle pidle;
+ pidle.xmit_idle = pidle.recv_idle = lp->huptimer;
+ if ((r = set_arg((void *) arg, sizeof(struct ppp_idle), &pidle)))
+ return r;
+ }
+ break;
+ case PPPIOCSMRU: /* set receive unit size for PPP */
+ if ((r = get_arg((void *) arg, &val, 0)))
+ return r;
+ is->mru = val;
+ break;
+ case PPPIOCSMPMRU:
+ break;
+ case PPPIOCSMPMTU:
+ break;
+ case PPPIOCSMAXCID: /* set the maximum compression slot id */
+ if ((r = get_arg((void *) arg, &val, 0)))
+ return r;
+ val++;
+ if (is->maxcid != val) {
#ifdef CONFIG_ISDN_PPP_VJ
- struct slcompress *sltmp;
+ struct slcompress *sltmp;
#endif
- if(is->debug & 0x1)
- printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n",val);
- is->maxcid = val;
+ if (is->debug & 0x1)
+ printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val);
+ is->maxcid = val;
#ifdef CONFIG_ISDN_PPP_VJ
- sltmp = slhc_init(16,val);
- if(!sltmp) {
- printk(KERN_ERR "ippp, can't realloc slhc struct\n");
- return -ENOMEM;
- }
- if(is->slcomp)
- slhc_free(is->slcomp);
- is->slcomp = sltmp;
+ sltmp = slhc_init(16, val);
+ if (!sltmp) {
+ printk(KERN_ERR "ippp, can't realloc slhc struct\n");
+ return -ENOMEM;
+ }
+ if (is->slcomp)
+ slhc_free(is->slcomp);
+ is->slcomp = sltmp;
#endif
- }
- break;
- case PPPIOCGDEBUG:
- if ((r = set_arg((void *) arg, is->debug,0)))
- return r;
- break;
- case PPPIOCSDEBUG:
- if ((r = get_arg((void *) arg, &val,0)))
- return r;
- is->debug = val;
- break;
- case PPPIOCSCOMPRESS:
-#if 0
- {
- struct ppp_option_data pod;
- r = get_arg((void *) arg,&pod,sizeof(struct ppp_option_data));
- if(r)
+ }
+ break;
+ case PPPIOCGDEBUG:
+ if ((r = set_arg((void *) arg, is->debug, 0)))
return r;
- ippp_set_compression(is,&pod);
- }
-#endif
- break;
- default:
- break;
+ break;
+ case PPPIOCSDEBUG:
+ if ((r = get_arg((void *) arg, &val, 0)))
+ return r;
+ is->debug = val;
+ break;
+ case PPPIOCGCOMPRESSORS:
+ {
+ unsigned long protos = 0;
+ struct isdn_ppp_compressor *ipc = ipc_head;
+ while(ipc) {
+ protos |= (0x1<<ipc->num);
+ ipc = ipc->next;
+ }
+ if ((r = set_arg((void *) arg, protos, 0)))
+ return r;
+ }
+ break;
+ case PPPIOCSCOMPRESSOR:
+ if ((r = get_arg((void *) arg, &num, sizeof(int))))
+ return r;
+ return isdn_ppp_set_compressor(is, num);
+ break;
+ case PPPIOCGCALLINFO:
+ {
+ struct pppcallinfo pci;
+ memset((char *) &pci,0,sizeof(struct pppcallinfo));
+ if(lp)
+ {
+ strncpy(pci.local_num,lp->msn,63);
+ if(lp->dial) {
+ strncpy(pci.remote_num,lp->dial->num,63);
+ }
+ pci.charge_units = lp->charge;
+ if(lp->outgoing)
+ pci.calltype = CALLTYPE_OUTGOING;
+ else
+ pci.calltype = CALLTYPE_INCOMING;
+ if(lp->flags & ISDN_NET_CALLBACK)
+ pci.calltype |= CALLTYPE_CALLBACK;
+ }
+ return set_arg((void *)arg,sizeof(struct pppcallinfo),&pci);
+ }
+ default:
+ break;
}
return 0;
}
-int isdn_ppp_select(int min, struct file *file, int type, select_table * st)
+#if (LINUX_VERSION_CODE < 0x020117)
+int
+isdn_ppp_select(int min, struct file *file, int type, select_table * st)
{
- struct ippp_buf_queue *bf, *bl;
+ struct ippp_buf_queue *bf,
+ *bl;
unsigned long flags;
struct ippp_struct *is;
is = file->private_data;
- if(is->debug & 0x2)
- printk(KERN_DEBUG "isdn_ppp_select: minor: %d, type: %d \n",min,type);
+ if (is->debug & 0x2)
+ printk(KERN_DEBUG "isdn_ppp_select: minor: %d, type: %d \n", min, type);
if (!(is->state & IPPP_OPEN))
return -EINVAL;
switch (type) {
- case SEL_IN:
- save_flags(flags);
- cli();
- bl = is->last;
- bf = is->first;
- /*
- * if IPPP_NOBLOCK is set we return even if we have nothing to read
- */
- if (bf->next == bl && !(is->state & IPPP_NOBLOCK)) {
- select_wait(&is->wq, st);
+ case SEL_IN:
+ save_flags(flags);
+ cli();
+ bl = is->last;
+ bf = is->first;
+ /*
+ * if IPPP_NOBLOCK is set we return even if we have nothing to read
+ */
+ if (bf->next == bl && !(is->state & IPPP_NOBLOCK)) {
+ select_wait(&is->wq, st);
+ restore_flags(flags);
+ return 0;
+ }
+ is->state &= ~IPPP_NOBLOCK;
restore_flags(flags);
+ return 1;
+ case SEL_OUT:
+ /* we're always ready to send .. */
+ return 1;
+ case SEL_EX:
+ select_wait(&is->wq1, st);
return 0;
- }
- is->state &= ~IPPP_NOBLOCK;
- restore_flags(flags);
- return 1;
- case SEL_OUT:
- /* we're always ready to send .. */
- return 1;
- case SEL_EX:
- select_wait(&is->wq1, st);
- return 0;
}
return 1;
}
+#else
+unsigned int
+isdn_ppp_poll(struct file *file, poll_table * wait)
+{
+ unsigned int mask;
+ struct ippp_buf_queue *bf;
+ struct ippp_buf_queue *bl;
+ unsigned long flags;
+ struct ippp_struct *is;
+
+ is = file->private_data;
+
+ if (is->debug & 0x2)
+ printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n", MINOR(file->f_inode->i_rdev));
+
+ poll_wait(&is->wq, wait);
+
+ if (!(is->state & IPPP_OPEN)) {
+ printk(KERN_DEBUG "isdn_ppp: device not open\n");
+ return POLLERR;
+ }
+ /* we're always ready to send .. */
+ mask = POLLOUT | POLLWRNORM;
+
+ save_flags(flags);
+ cli();
+ bl = is->last;
+ bf = is->first;
+ /*
+ * if IPPP_NOBLOCK is set we return even if we have nothing to read
+ */
+ if (bf->next != bl || (is->state & IPPP_NOBLOCK)) {
+ is->state &= ~IPPP_NOBLOCK;
+ mask |= POLLIN | POLLRDNORM;
+ }
+ restore_flags(flags);
+ return mask;
+}
+#endif
+
/*
* fill up isdn_ppp_read() queue ..
*/
-static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int slot)
+static int
+isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
{
- struct ippp_buf_queue *bf, *bl;
+ struct ippp_buf_queue *bf,
+ *bl;
unsigned long flags;
unsigned char *nbuf;
struct ippp_struct *is;
@@ -637,9 +769,8 @@
printk(KERN_DEBUG "ippp: device not activated.\n");
return 0;
}
-
- nbuf = (unsigned char *) kmalloc(len+4, GFP_ATOMIC);
- if(!nbuf) {
+ nbuf = (unsigned char *) kmalloc(len + 4, GFP_ATOMIC);
+ if (!nbuf) {
printk(KERN_WARNING "ippp: Can't alloc buf\n");
return 0;
}
@@ -647,7 +778,7 @@
nbuf[1] = PPP_UI;
nbuf[2] = proto >> 8;
nbuf[3] = proto & 0xff;
- memcpy(nbuf+4, buf, len);
+ memcpy(nbuf + 4, buf, len);
save_flags(flags);
cli();
@@ -662,7 +793,7 @@
is->first = bf;
}
bl->buf = (char *) nbuf;
- bl->len = len+4;
+ bl->len = len + 4;
is->last = bl->next;
restore_flags(flags);
@@ -678,12 +809,14 @@
* reports, that there is data
*/
-int isdn_ppp_read(int min, struct file *file, char *buf, int count)
+int
+isdn_ppp_read(int min, struct file *file, char *buf, int count)
{
struct ippp_struct *is;
struct ippp_buf_queue *b;
int r;
unsigned long flags;
+ unsigned char *save_buf;
is = file->private_data;
@@ -697,26 +830,30 @@
cli();
b = is->first->next;
- if (!b->buf) {
+ save_buf = b->buf;
+ if (!save_buf) {
restore_flags(flags);
return -EAGAIN;
}
if (b->len < count)
count = b->len;
- copy_to_user(buf, b->buf, count);
- kfree(b->buf);
b->buf = NULL;
is->first = b;
+
restore_flags(flags);
+ copy_to_user(buf, save_buf, count);
+ kfree(save_buf);
+
return count;
}
/*
* ipppd wanna write a packet to the card .. non-blocking
*/
-
-int isdn_ppp_write(int min, struct file *file, const char *buf, int count)
+
+int
+isdn_ppp_write(int min, struct file *file, const char *buf, int count)
{
isdn_net_local *lp;
struct ippp_struct *is;
@@ -735,15 +872,16 @@
if (!lp)
printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");
else {
- /*
- * Don't reset huptimer for
- * LCP packets. (Echo requests).
- */
- copy_from_user(protobuf, buf, 4);
- proto = PPP_PROTOCOL(protobuf);
- if (proto != PPP_LCP)
+ /*
+ * Don't reset huptimer for
+ * LCP packets. (Echo requests).
+ */
+ if (copy_from_user(protobuf, buf, 4))
+ return -EFAULT;
+ proto = PPP_PROTOCOL(protobuf);
+ if (proto != PPP_LCP)
lp->huptimer = 0;
-
+
if (lp->isdn_device < 0 || lp->isdn_channel < 0)
return 0;
@@ -752,23 +890,23 @@
int cnt;
struct sk_buff *skb;
skb = dev_alloc_skb(count);
- if(!skb) {
+ if (!skb) {
printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
return count;
}
- skb->free = 1;
- copy_from_user(skb_put(skb, count), buf, count);
- if(is->debug & 0x40) {
- printk(KERN_DEBUG "ppp xmit: len %ld\n",skb->len);
- isdn_ppp_frame_log("xmit",skb->data,skb->len,32);
- }
- if( (cnt=isdn_writebuf_skb_stub(lp->isdn_device,lp->isdn_channel,skb)) != count) {
- if(lp->sav_skb) {
- dev_kfree_skb(lp->sav_skb,FREE_WRITE);
- printk(KERN_INFO "isdn_ppp_write: freeing sav_skb (%d,%d)!\n",cnt,count);
- }
- else
- printk(KERN_INFO "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n",cnt,count);
+ SET_SKB_FREE(skb);
+ if (copy_from_user(skb_put(skb, count), buf, count))
+ return -EFAULT;
+ if (is->debug & 0x40) {
+ printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
+ isdn_ppp_frame_log("xmit", skb->data, skb->len, 32);
+ }
+ if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb)) != count) {
+ if (lp->sav_skb) {
+ dev_kfree_skb(lp->sav_skb, FREE_WRITE);
+ printk(KERN_INFO "isdn_ppp_write: freeing sav_skb (%d,%d)!\n", cnt, count);
+ } else
+ printk(KERN_INFO "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n", cnt, count);
lp->sav_skb = skb;
}
}
@@ -777,21 +915,23 @@
}
/*
- * init memory, structures etc.
+ * init memory, structures etc.
*/
-int isdn_ppp_init(void)
+int
+isdn_ppp_init(void)
{
- int i, j;
+ int i,
+ j;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (!(ippp_table[i] = (struct ippp_struct *)
- kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
- printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");
+ if (!(ippp_table[i] = (struct ippp_struct *)
+ kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
+ printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");
for (j = 0; j < i; j++)
kfree(ippp_table[i]);
- return -1;
- }
+ return -1;
+ }
memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct));
ippp_table[i]->state = 0;
ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
@@ -807,78 +947,109 @@
return 0;
}
-void isdn_ppp_cleanup(void)
+void
+isdn_ppp_cleanup(void)
{
- int i;
+ int i;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- kfree(ippp_table[i]);
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+ kfree(ippp_table[i]);
}
/*
+ * get the PPP protocol header and pull skb
+ */
+static int isdn_ppp_strip_proto(struct sk_buff *skb)
+{
+ int proto;
+ if (skb->data[0] & 0x1) {
+ proto = skb->data[0];
+ skb_pull(skb, 1); /* protocol ID is only 8 bit */
+ } else {
+ proto = ((int) skb->data[0] << 8) + skb->data[1];
+ skb_pull(skb, 2);
+ }
+ return proto;
+}
+
+
+/*
* handler for incoming packets on a syncPPP interface
*/
void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb)
{
struct ippp_struct *is;
+ int proto;
+
is = ippp_table[lp->ppp_slot];
- if(is->debug & 0x4) {
- printk(KERN_DEBUG "ippp_receive: len: %ld\n",skb->len);
- isdn_ppp_frame_log("receive",skb->data,skb->len,32);
+ if (is->debug & 0x4) {
+ printk(KERN_DEBUG "ippp_receive: len: %d\n", (int) skb->len);
+ isdn_ppp_frame_log("receive", skb->data, skb->len, 32);
}
-
- if(net_dev->local.master) {
+ if (net_dev->local.master) {
printk(KERN_WARNING "isdn_ppp_receice: net_dev != master\n");
- net_dev = ((isdn_net_local*) net_dev->local.master->priv)->netdev;
+ net_dev = ((isdn_net_local *) net_dev->local.master->priv)->netdev;
}
-
- if(skb->data[0] == 0xff && skb->data[1] == 0x03)
- skb_pull(skb,2);
+ if (skb->data[0] == 0xff && skb->data[1] == 0x03)
+ skb_pull(skb, 2);
else if (is->pppcfg & SC_REJ_COMP_AC) {
- skb->free = 1;
- dev_kfree_skb(skb,0 /* FREE_READ */ );
- return; /* discard it silently */
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, 0 /* FREE_READ */ );
+ return; /* discard it silently */
}
+ proto = isdn_ppp_strip_proto(skb);
+
#ifdef CONFIG_ISDN_MPP
if (!(is->mpppcfg & SC_REJ_MP_PROT)) {
- int proto;
int sqno_end;
- if (skb->data[0] & 0x1) {
- proto = skb->data[0];
- skb_pull(skb,1); /* protocol ID is only 8 bit */
- } else {
- proto = ((int) skb->data[0] << 8) + skb->data[1];
- skb_pull(skb,2);
+
+ if(proto == PPP_LINK_COMP) {
+ printk(KERN_DEBUG "received single link compressed frame\n");
+ skb = isdn_ppp_decompress(skb,is,NULL);
+ if(!skb)
+ return;
+ proto = isdn_ppp_strip_proto(skb);
}
+
if (proto == PPP_MP) {
isdn_net_local *lpq;
long sqno, min_sqno, tseq;
+
u_char BEbyte = skb->data[0];
- if(is->debug & 0x8)
- printk(KERN_DEBUG "recv: %d/%04x/%d -> %02x %02x %02x %02x %02x %02x\n", lp->ppp_slot, proto ,
- (int) skb->len, (int) skb->data[0], (int) skb->data[1], (int) skb->data[2],
- (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
+ if (is->debug & 0x8)
+ printk(KERN_DEBUG "recv: %d/%04x/%d -> %02x %02x %02x %02x %02x %02x\n", lp->ppp_slot, proto,
+ (int) skb->len, (int) skb->data[0], (int) skb->data[1], (int) skb->data[2],
+ (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
if (!(is->mpppcfg & SC_IN_SHORT_SEQ)) {
sqno = ((int) skb->data[1] << 16) + ((int) skb->data[2] << 8) + (int) skb->data[3];
- skb_pull(skb,4);
+ skb_pull(skb, 4);
} else {
sqno = (((int) skb->data[0] & 0xf) << 8) + (int) skb->data[1];
- skb_pull(skb,2);
+ skb_pull(skb, 2);
}
+ /*
+ * new sequence number lower than last number? (this is only allowed
+ * for overflow case)
+ */
if ((tseq = is->last_link_seqno) >= sqno) {
int range = is->range;
- if (tseq + 1024 < range + sqno) /* redundancy check .. not MP conform */
+ if (tseq + 1024 < range + sqno) /* redundancy check .. not MP conform */
printk(KERN_WARNING "isdn_ppp_receive, MP, detected overflow with sqno: %ld, last: %ld !!!\n", sqno, tseq);
else {
sqno += range;
is->last_link_seqno = sqno;
}
- } else
+ } else {
+ /* here, we should also add an redundancy check */
is->last_link_seqno = sqno;
+ }
+ /*
+ * step over all links to find lowest link number
+ */
for (min_sqno = LONG_MAX, lpq = net_dev->queue;;) {
long lls = ippp_table[lpq->ppp_slot]->last_link_seqno;
if (lls >= 0 && lls < min_sqno)
@@ -887,11 +1058,14 @@
if (lpq == net_dev->queue)
break;
}
- if (min_sqno >= ippp_table[lpq->ppp_slot]->range) { /* OK, every link overflowed */
- int mask = ippp_table[lpq->ppp_slot]->range - 1; /* range is a power of 2 */
-#if 0
- isdn_ppp_cleanup_queue(net_dev, min_sqno);
-#endif
+
+ /*
+ * for the case, that the last frame numbers of all
+ * links are overflowed: mask/reduce the sequenece number to
+ * 'normal' numbering.
+ */
+ if (min_sqno >= ippp_table[lpq->ppp_slot]->range) {
+ int mask = ippp_table[lpq->ppp_slot]->range-1; /* range is power of two, so a mask will do the job */
isdn_ppp_mask_queue(net_dev, mask);
net_dev->ib.next_num &= mask;
{
@@ -910,18 +1084,22 @@
}
}
if ((BEbyte & (MP_BEGIN_FRAG | MP_END_FRAG)) != (MP_BEGIN_FRAG | MP_END_FRAG)) {
- printk(KERN_DEBUG "ippp: trying ;) to fill mp_queue %d .. UNTESTED!!\n", lp->ppp_slot);
- if ((sqno_end = isdn_ppp_fill_mpqueue(net_dev, &skb , BEbyte, &sqno, min_sqno)) < 0) {
+ static int dmes = 0;
+ if( !dmes ) {
+ printk(KERN_DEBUG "ippp: trying ;) to fill mp_queue %d .. UNTESTED!!\n", lp->ppp_slot);
+ dmes = 1;
+ }
+ if ((sqno_end = isdn_ppp_fill_mpqueue(net_dev, &skb, BEbyte, &sqno, min_sqno)) < 0) {
net_dev->ib.modify = 1; /* block timeout-timer */
- isdn_ppp_cleanup_sqqueue(net_dev,lp,min_sqno);
+ isdn_ppp_cleanup_sqqueue(net_dev, lp, min_sqno);
net_dev->ib.modify = 0;
- return; /* no packet complete */
+ return; /* no packet complete */
}
} else
sqno_end = sqno;
- if(is->debug & 0x40)
- printk(KERN_DEBUG "min_sqno: %ld sqno_end %d next: %ld\n",min_sqno,sqno_end,net_dev->ib.next_num );
+ if (is->debug & 0x40)
+ printk(KERN_DEBUG "min_sqno: %ld sqno_end %d next: %ld\n", min_sqno, sqno_end, net_dev->ib.next_num);
/*
* MP buffer management .. reorders incoming packets ..
@@ -930,7 +1108,7 @@
* first check whether there is more than one link in the bundle
* then check whether the number is in order
*/
- net_dev->ib.modify = 1; /* block timeout-timer */
+ net_dev->ib.modify = 1; /* block timeout-timer */
if (net_dev->ib.bundled && net_dev->ib.next_num != sqno) {
/*
* packet is not 'in order'
@@ -941,9 +1119,9 @@
if (!q) {
net_dev->ib.modify = 0;
printk(KERN_WARNING "ippp/MPPP: Bad! Can't alloc sq node!\n");
- skb->free = 1;
+ SET_SKB_FREE(skb);
dev_kfree_skb(skb, 0 /* FREE_READ */ );
- return; /* discard */
+ return; /* discard */
}
q->skb = skb;
q->sqno_end = sqno_end;
@@ -966,123 +1144,128 @@
}
}
} else {
- /*
- * packet was 'in order' .. push it higher
+ /*
+ * packet was 'in order' .. push it higher
*/
net_dev->ib.next_num = sqno_end + 1;
- isdn_ppp_push_higher(net_dev, lp, skb, -1);
+ proto = isdn_ppp_strip_proto(skb);
+ isdn_ppp_push_higher(net_dev, lp, skb, proto);
}
- isdn_ppp_cleanup_sqqueue(net_dev,lp,min_sqno);
+ isdn_ppp_cleanup_sqqueue(net_dev, lp, min_sqno);
net_dev->ib.modify = 0;
} else
- isdn_ppp_push_higher(net_dev, lp, skb , proto);
+ isdn_ppp_push_higher(net_dev, lp, skb, proto);
} else
#endif
- isdn_ppp_push_higher(net_dev, lp, skb , -1);
+ isdn_ppp_push_higher(net_dev, lp, skb, proto);
}
/*
* push frame to higher layers
* note: net_dev has to be master net_dev
*/
-static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb,int proto)
+static void
+isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto)
{
struct device *dev = &net_dev->dev;
struct ippp_struct *is = ippp_table[lp->ppp_slot];
- if (proto < 0) { /* MP, oder normales Paket bei REJ_MP, MP Pakete gehen bei REJ zum pppd */
- if (skb->data[0] & 0x01) { /* is it odd? */
- proto = (unsigned char) skb->data[0];
- skb_pull(skb,1); /* protocol ID is only 8 bit */
- } else {
- proto = ((int) (unsigned char) skb->data[0] << 8) + (unsigned char) skb->data[1];
- skb_pull(skb,2);
- }
+ if (is->debug & 0x10) {
+ printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
+ isdn_ppp_frame_log("rpush", skb->data, skb->len, 32);
}
- if(is->debug & 0x10) {
- printk(KERN_DEBUG "push, skb %ld %04x\n",skb->len,proto);
- isdn_ppp_frame_log("rpush",skb->data,skb->len,32);
+ if(proto == PPP_COMP) {
+ if(!lp->master)
+ skb = isdn_ppp_decompress(skb,is,is);
+ else
+ skb = isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot]);
+ if(!skb)
+ return;
+ proto = isdn_ppp_strip_proto(skb);
}
switch (proto) {
- case PPP_IPX: /* untested */
- if(is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: IPX\n");
- skb->dev = dev;
- skb->mac.raw = skb->data;
- skb->protocol = htons(ETH_P_IPX);
- break;
-#ifdef CONFIG_ISDN_PPP_VJ
- case PPP_VJC_UNCOMP:
- if(is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
- if(slhc_remember(ippp_table[net_dev->local.ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
- printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
- net_dev->local.stats.rx_dropped++;
- skb->free = 1;
- dev_kfree_skb(skb,0 /* FREE_READ */ );
- return;
- }
-#endif
- case PPP_IP:
- if(is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: IP\n");
- skb->dev = dev;
- skb->mac.raw = skb->data;
- skb->protocol = htons(ETH_P_IP);
- break;
- case PPP_VJC_COMP:
- if(is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
+ case PPP_IPX: /* untested */
+ if (is->debug & 0x20)
+ printk(KERN_DEBUG "isdn_ppp: IPX\n");
+ skb->dev = dev;
+ skb->mac.raw = skb->data;
+ skb->protocol = htons(ETH_P_IPX);
+ break;
#ifdef CONFIG_ISDN_PPP_VJ
- {
- struct sk_buff *skb_old = skb;
- int pkt_len;
- skb = dev_alloc_skb(skb_old->len + 40);
-
- skb_old->free = 1;
-
- if (!skb) {
- printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
+ case PPP_VJC_UNCOMP:
+ if (is->debug & 0x20)
+ printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
+ if (slhc_remember(ippp_table[net_dev->local.ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
+ printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
net_dev->local.stats.rx_dropped++;
- dev_kfree_skb(skb_old,0 /* FREE_READ */ );
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, 0 /* FREE_READ */ );
return;
}
+#endif
+ case PPP_IP:
+ if (is->debug & 0x20)
+ printk(KERN_DEBUG "isdn_ppp: IP\n");
skb->dev = dev;
- skb_put(skb,skb_old->len + 40);
- memcpy(skb->data, skb_old->data, skb_old->len);
skb->mac.raw = skb->data;
- pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_slot]->slcomp,
- skb->data, skb_old->len);
- dev_kfree_skb(skb_old,0 /* FREE_READ */ );
- if(pkt_len < 0) {
- skb->free = 1;
- dev_kfree_skb(skb, 0 /* FREE_READ */ );
- lp->stats.rx_dropped++;
- return;
- }
- skb_trim(skb, pkt_len);
skb->protocol = htons(ETH_P_IP);
- }
+ break;
+ case PPP_VJC_COMP:
+ if (is->debug & 0x20)
+ printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
+#ifdef CONFIG_ISDN_PPP_VJ
+ {
+ struct sk_buff *skb_old = skb;
+ int pkt_len;
+ skb = dev_alloc_skb(skb_old->len + 40);
+
+ SET_SKB_FREE(skb_old);
+
+ if (!skb) {
+ printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
+ net_dev->local.stats.rx_dropped++;
+ dev_kfree_skb(skb_old, 0 /* FREE_READ */ );
+ return;
+ }
+ skb->dev = dev;
+ skb_put(skb, skb_old->len + 40);
+ memcpy(skb->data, skb_old->data, skb_old->len);
+ skb->mac.raw = skb->data;
+ pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_slot]->slcomp,
+ skb->data, skb_old->len);
+ dev_kfree_skb(skb_old, 0 /* FREE_READ */ );
+ if (pkt_len < 0) {
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, 0 /* FREE_READ */ );
+ lp->stats.rx_dropped++;
+ return;
+ }
+ skb_trim(skb, pkt_len);
+ skb->protocol = htons(ETH_P_IP);
+ }
#else
- printk(KERN_INFO "isdn: Ooopsa .. VJ-Compression support not compiled into isdn driver.\n");
- lp->stats.rx_dropped++;
- skb->free = 1;
- dev_kfree_skb(skb,0 /* FREE_READ */ );
- return;
+ printk(KERN_INFO "isdn: Ooopsa .. VJ-Compression support not compiled into isdn driver.\n");
+ lp->stats.rx_dropped++;
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, 0 /* FREE_READ */ );
+ return;
#endif
- break;
- default:
- isdn_ppp_fill_rq(skb->data, skb->len,proto, lp->ppp_slot); /* push data to pppd device */
- skb->free = 1;
- dev_kfree_skb(skb,0 /* FREE_READ */ );
- return;
+ break;
+ case PPP_CCP:
+ isdn_ppp_receive_ccp(net_dev,lp,skb);
+ /* fall through */
+ default:
+ isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, 0 /* FREE_READ */ );
+ return;
}
netif_rx(skb);
-/* net_dev->local.stats.rx_packets++; */ /* done in isdn_net.c */
+ /* net_dev->local.stats.rx_packets++; *//* done in isdn_net.c */
/* Reset hangup-timer */
lp->huptimer = 0;
@@ -1090,89 +1273,95 @@
}
/*
- * send ppp frame .. we expect a PIDCOMPressable proto --
- * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
- *
- * VJ compression may change skb pointer!!! .. requeue with old
- * skb isn't allowed!!
+ * isdn_ppp_skb_push ..
+ * checks whether we have enough space at the beginning of the SKB
+ * and allocs a new SKB if necessary
*/
-
-static void isdn_ppp_skb_destructor(struct sk_buff *skb) /* debug function */
+static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len)
{
- char outstr[80],*outpnt=outstr;
- int i;
+ struct sk_buff *skb = *skb_p;
- *outpnt = 0;
- for(i=0;i<24 && i<skb->len;i++) {
- sprintf(outpnt,"%02x ",skb->data[i]);
- outpnt += 3;
+ if(skb_headroom(skb) < len) {
+ printk(KERN_ERR "isdn_ppp_skb_push:under %d %d\n",skb_headroom(skb),len);
+ dev_kfree_skb(skb,FREE_WRITE);
+ return NULL;
}
- printk(KERN_DEBUG "ippp_dstrct: %s\n",outstr);
+ return skb_push(skb,len);
}
-int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
+
+/*
+ * send ppp frame .. we expect a PIDCOMPressable proto --
+ * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
+ *
+ * VJ compression may change skb pointer!!! .. requeue with old
+ * skb isn't allowed!!
+ */
+
+int
+isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
{
- struct device *mdev = ((isdn_net_local *) (dev->priv) )->master; /* get master (for redundancy) */
+ struct device *mdev = ((isdn_net_local *) (dev->priv))->master; /* get master (for redundancy) */
isdn_net_local *lp,*mlp;
isdn_net_dev *nd;
- int proto = PPP_IP; /* 0x21 */
+ unsigned int proto = PPP_IP; /* 0x21 */
struct ippp_struct *ipt,*ipts;
- if(mdev)
- mlp = (isdn_net_local *) (mdev->priv);
+ if (mdev)
+ mlp = (isdn_net_local *) (mdev->priv);
else {
mdev = dev;
mlp = (isdn_net_local *) (dev->priv);
}
- nd = mlp->netdev; /* get master lp */
+ nd = mlp->netdev; /* get master lp */
ipts = ippp_table[mlp->ppp_slot];
- if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
+ if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
#ifdef ISDN_SYNCPPP_READDRESS
- if(!ipts->old_pa_addr)
+ if (!ipts->old_pa_addr)
ipts->old_pa_addr = mdev->pa_addr;
- if(!ipts->old_pa_dstaddr)
+ if (!ipts->old_pa_dstaddr)
ipts->old_pa_dstaddr = mdev->pa_dstaddr;
#endif
- if(ipts->debug & 0x1) {
- printk(KERN_INFO "%s: IP frame delayed.\n",dev->name);
- skb->destructor = isdn_ppp_skb_destructor;
- }
- return 1;
+ if (ipts->debug & 0x1)
+ printk(KERN_INFO "%s: IP frame delayed.\n", dev->name);
+ return 1;
}
- skb->destructor = NULL;
-
- switch(ntohs(skb->protocol)) {
+ switch (ntohs(skb->protocol)) {
case ETH_P_IP:
proto = PPP_IP;
#ifdef ISDN_SYNCPPP_READDRESS
- if(ipts->old_pa_addr != mdev->pa_addr)
- {
+ if (ipts->old_pa_addr != mdev->pa_addr) {
struct iphdr *ipfr;
ipfr = (struct iphdr *) skb->data;
-printk(KERN_DEBUG "IF-address changed from %lx to %lx\n",ipts->old_pa_addr,mdev->pa_addr);
- if(ipfr->version == 4) {
- if(ipfr->saddr == ipts->old_pa_addr) {
-printk(KERN_DEBUG "readdressing %lx to %lx\n",ipfr->saddr,mdev->pa_addr);
+ if(ipts->debug & 0x4)
+ printk(KERN_DEBUG "IF-address changed from %lx to %lx\n", ipts->old_pa_addr, mdev->pa_addr);
+ if (ipfr->version == 4) {
+ if (ipfr->saddr == ipts->old_pa_addr) {
+ printk(KERN_DEBUG "readdressing %lx to %lx\n", ipfr->saddr, mdev->pa_addr);
ipfr->saddr = mdev->pa_addr;
}
}
}
- /* dstaddr change not so improtant */
+ /* dstaddr change not so important */
#endif
break;
case ETH_P_IPX:
proto = PPP_IPX; /* untested */
break;
+ default:
+ dev_kfree_skb(skb, FREE_WRITE);
+ printk(KERN_ERR "isdn_ppp: skipped frame with unsupported protocoll: %#x.\n", skb->protocol);
+ return 0;
}
- lp = nd->queue; /* get lp on top of queue */
+ lp = nd->queue; /* get lp on top of queue */
- if(lp->sav_skb) { /* find a non-busy device */
+ if (lp->sav_skb) { /* find a non-busy device */
isdn_net_local *nlp = lp->next;
- while(lp->sav_skb) {
- if(lp == nlp)
+ while (lp->sav_skb) {
+ if (lp == nlp)
return 1;
nlp = nd->queue = nd->queue->next;
}
@@ -1180,43 +1369,49 @@
}
ipt = ippp_table[lp->ppp_slot];
- lp->huptimer = 0;
+ lp->huptimer = 0;
/*
- * after this line .. requeueing in the device queue is no longer allowed!!!
+ * after this line .. requeueing in the device queue is no longer allowed!!!
*/
- if(ipt->debug & 0x4)
- printk(KERN_DEBUG "xmit skb, len %ld\n",skb->len);
+ /* Pull off the fake header we stuck on earlier to keep
+ * the fragemntation code happy.
+ * this will break the ISDN_SYNCPPP_READDRESS hack a few lines
+ * above. So, enabling this is no longer allowed
+ */
+ skb_pull(skb,IPPP_MAX_HEADER);
+
+ if (ipt->debug & 0x4)
+ printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len);
#ifdef CONFIG_ISDN_PPP_VJ
- if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes .. but this check again */
+ if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */
struct sk_buff *new_skb;
new_skb = dev_alloc_skb(skb->len);
- if(new_skb) {
+ if (new_skb) {
u_char *buf;
int pktlen;
new_skb->dev = skb->dev;
- new_skb->free = 1;
- skb_put(new_skb,skb->len);
+ SET_SKB_FREE(new_skb);
+ skb_put(new_skb, skb->len);
buf = skb->data;
pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data,
- &buf, !(ipts->pppcfg & SC_NO_TCP_CCID));
+ &buf, !(ipts->pppcfg & SC_NO_TCP_CCID));
- if(buf != skb->data) { /* copied to new buffer ??? (btw: WHY must slhc copy it?? *sigh*) */
- if(new_skb->data != buf)
+ if (buf != skb->data) {
+ if (new_skb->data != buf)
printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n");
- dev_kfree_skb(skb,FREE_WRITE);
+ dev_kfree_skb(skb, FREE_WRITE);
skb = new_skb;
- }
- else {
- dev_kfree_skb(new_skb,0 /* FREE_WRITE */ );
+ } else {
+ dev_kfree_skb(new_skb, 0 /* FREE_WRITE */ );
}
- skb_trim(skb,pktlen);
+ skb_trim(skb, pktlen);
if (skb->data[0] & SL_TYPE_COMPRESSED_TCP) { /* cslip? style -> PPP */
proto = PPP_VJC_COMP;
skb->data[0] ^= SL_TYPE_COMPRESSED_TCP;
@@ -1229,8 +1424,13 @@
}
#endif
- if(ipt->debug & 0x24)
- printk(KERN_DEBUG "xmit2 skb, len %ld, proto %04x\n",skb->len,proto);
+ /*
+ * normal or bundle compression
+ */
+ skb = isdn_ppp_compress(skb,&proto,ipt,ipts,0);
+
+ if (ipt->debug & 0x24)
+ printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto);
#ifdef CONFIG_ISDN_MPP
if (ipt->mpppcfg & SC_MP_PROT) {
@@ -1239,41 +1439,64 @@
ipts->mp_seqno++;
nd->queue = nd->queue->next;
if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
- skb_push(skb, 3);
+ unsigned char *data = isdn_ppp_skb_push(&skb, 3);
+ if(!data)
+ return 0;
mp_seqno &= 0xfff;
- skb->data[0] = MP_BEGIN_FRAG | MP_END_FRAG | (mp_seqno >> 8); /* (B)egin & (E)ndbit .. */
- skb->data[1] = mp_seqno & 0xff;
- skb->data[2] = proto; /* PID compression */
+ data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf); /* (B)egin & (E)ndbit .. */
+ data[1] = mp_seqno & 0xff;
+ data[2] = proto; /* PID compression */
} else {
- skb_push(skb, 5);
- skb->data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */
- skb->data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */
- skb->data[2] = (mp_seqno >> 8) & 0xff;
- skb->data[3] = (mp_seqno >> 0) & 0xff;
- skb->data[4] = proto; /* PID compression */
+ unsigned char *data = isdn_ppp_skb_push(&skb, 5);
+ if(!data)
+ return 0;
+ data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */
+ data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */
+ data[2] = (mp_seqno >> 8) & 0xff;
+ data[3] = (mp_seqno >> 0) & 0xff;
+ data[4] = proto; /* PID compression */
}
proto = PPP_MP; /* MP Protocol, 0x003d */
}
#endif
- skb_push(skb,4);
- skb->data[0] = 0xff; /* All Stations */
- skb->data[1] = 0x03; /* Unnumbered information */
- skb->data[2] = proto >> 8;
- skb->data[3] = proto & 0xff;
-
- /* tx-stats are now updated via BSENT-callback */
-
- if(ipts->debug & 0x40) {
- printk(KERN_DEBUG "skb xmit: len: %ld\n",skb->len);
- isdn_ppp_frame_log("xmit",skb->data,skb->len,32);
- }
-
- if(isdn_net_send_skb(dev , lp , skb)) {
- if(lp->sav_skb) { /* whole sav_skb processing with disabled IRQs ?? */
- printk(KERN_ERR "%s: whoops .. there is another stored skb!\n",dev->name);
- dev_kfree_skb(skb,FREE_WRITE);
- }
- else
+
+ /*
+ * 'link' compression
+ */
+ skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1);
+
+ if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) {
+ unsigned char *data = isdn_ppp_skb_push(&skb,1);
+ if(!data)
+ return 0;
+ data[0] = proto & 0xff;
+ }
+ else {
+ unsigned char *data = isdn_ppp_skb_push(&skb,2);
+ if(!data)
+ return 0;
+ data[0] = (proto >> 8) & 0xff;
+ data[1] = proto & 0xff;
+ }
+ if(!(ipt->pppcfg & SC_COMP_AC)) {
+ unsigned char *data = isdn_ppp_skb_push(&skb,2);
+ if(!data)
+ return 0;
+ data[0] = 0xff; /* All Stations */
+ data[1] = 0x03; /* Unnumbered information */
+ }
+
+ /* tx-stats are now updated via BSENT-callback */
+
+ if (ipts->debug & 0x40) {
+ printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
+ isdn_ppp_frame_log("xmit", skb->data, skb->len, 32);
+ }
+ if (isdn_net_send_skb(dev, lp, skb)) {
+ if (lp->sav_skb) { /* whole sav_skb processing with disabled IRQs ?? */
+ printk(KERN_ERR "%s: whoops .. there is another stored skb!\n", dev->name);
+ dev_kfree_skb(skb, FREE_WRITE);
+ } else
lp->sav_skb = skb;
}
return 0;
@@ -1281,16 +1504,17 @@
#ifdef CONFIG_ISDN_MPP
-void isdn_ppp_free_sqqueue(isdn_net_dev * p)
+static void
+isdn_ppp_free_sqqueue(isdn_net_dev * p)
{
struct sqqueue *q = p->ib.sq;
p->ib.sq = NULL;
- while(q) {
+ while (q) {
struct sqqueue *qn = q->next;
- if(q->skb) {
- q->skb->free = 1;
- dev_kfree_skb(q->skb,0 /* FREE_READ */ );
+ if (q->skb) {
+ SET_SKB_FREE(q->skb);
+ dev_kfree_skb(q->skb, 0 /* FREE_READ */ );
}
kfree(q);
q = qn;
@@ -1298,24 +1522,29 @@
}
-void isdn_ppp_free_mpqueue(isdn_net_dev * p)
+static void
+isdn_ppp_free_mpqueue(isdn_net_dev * p)
{
- struct mpqueue *ql, *q = p->mp_last;
+ struct mpqueue *q = p->mp_last;
+ p->mp_last = NULL;
+
while (q) {
- ql = q->next;
- q->skb->free = 1;
- dev_kfree_skb(q->skb,0 /* FREE_READ */ );
+ struct mpqueue *ql = q->next;
+ SET_SKB_FREE(q->skb);
+ dev_kfree_skb(q->skb, 0 /* FREE_READ */ );
kfree(q);
q = ql;
}
}
-static int isdn_ppp_bundle(struct ippp_struct *is, int unit)
+static int
+isdn_ppp_bundle(struct ippp_struct *is, int unit)
{
char ifn[IFNAMSIZ + 1];
long flags;
isdn_net_dev *p;
- isdn_net_local *lp,*nlp;
+ isdn_net_local *lp,
+ *nlp;
sprintf(ifn, "ippp%d", unit);
p = isdn_net_findif(ifn);
@@ -1356,7 +1585,8 @@
}
-static void isdn_ppp_mask_queue(isdn_net_dev * dev, long mask)
+static void
+isdn_ppp_mask_queue(isdn_net_dev * dev, long mask)
{
struct mpqueue *q = dev->mp_last;
while (q) {
@@ -1365,14 +1595,19 @@
}
}
-static int isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff ** skb, int BEbyte, long *sqnop, int min_sqno)
+static int
+isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff **skb, int BEbyte, long *sqnop, int min_sqno)
{
- struct mpqueue *qe, *q1, *q;
- long cnt, flags;
- int pktlen, sqno_end;
+ struct mpqueue *qe,
+ *q1,
+ *q;
+ long cnt,
+ flags;
+ int pktlen,
+ sqno_end;
int sqno = *sqnop;
- q1 = (struct mpqueue *) kmalloc(sizeof(struct mpqueue), GFP_KERNEL);
+ q1 = (struct mpqueue *) kmalloc(sizeof(struct mpqueue), GFP_ATOMIC);
if (!q1) {
printk(KERN_WARNING "isdn_ppp_fill_mpqueue: Can't alloc struct memory.\n");
save_flags(flags);
@@ -1395,9 +1630,9 @@
q1->last = NULL;
isdn_ppp_cleanup_mpqueue(dev, min_sqno); /* not necessary */
restore_flags(flags);
- return -1;
+ return -1; /* -1 is not an error. Just says, that this fragment hasn't complete a full frame */
}
- for (;;) { /* the faster way would be to step from the queue-end to the start */
+ for (;;) { /* the faster way would be to step from the queue-end to the start */
if (sqno > q->sqno) {
if (q->next) {
q = q->next;
@@ -1465,26 +1700,26 @@
isdn_ppp_cleanup_mpqueue(dev, min_sqno);
restore_flags(flags);
- *skb = dev_alloc_skb(pktlen + 40); /* not needed: +40 for VJ compression .. */
+ *skb = dev_alloc_skb(pktlen + 40); /* not needed: +40 for VJ compression .. */
if (!(*skb)) {
while (q) {
struct mpqueue *ql = q->next;
- q->skb->free = 1;
- dev_kfree_skb(q->skb,0 /* FREE_READ */ );
+ SET_SKB_FREE(q->skb);
+ dev_kfree_skb(q->skb, 0 /* FREE_READ */ );
kfree(q);
q = ql;
}
return -2;
}
cnt = 0;
- skb_put(*skb,pktlen);
+ skb_put(*skb, pktlen);
while (q) {
struct mpqueue *ql = q->next;
memcpy((*skb)->data + cnt, q->skb->data, q->skb->len);
cnt += q->skb->len;
- q->skb->free = 1;
- dev_kfree_skb(q->skb,0 /* FREE_READ */ );
+ SET_SKB_FREE(q->skb);
+ dev_kfree_skb(q->skb, 0 /* FREE_READ */ );
kfree(q);
q = ql;
}
@@ -1497,28 +1732,32 @@
* or packets with a sqno less or equal to min_sqno
* net_dev: master netdevice , lp: 'real' local connection
*/
-static void isdn_ppp_cleanup_sqqueue(isdn_net_dev *net_dev, isdn_net_local *lp,long min_sqno)
+static void
+isdn_ppp_cleanup_sqqueue(isdn_net_dev * net_dev, isdn_net_local * lp, long min_sqno)
{
struct sqqueue *q;
- while ((q = net_dev->ib.sq) && (q->sqno_start == net_dev->ib.next_num || q->sqno_end <= min_sqno) ) {
- if(q->sqno_start != net_dev->ib.next_num) {
- printk(KERN_DEBUG "ippp: MP, stepping over missing frame: %ld\n",net_dev->ib.next_num);
+ while ((q = net_dev->ib.sq) && (q->sqno_start == net_dev->ib.next_num || q->sqno_end <= min_sqno)) {
+ int proto;
+ if (q->sqno_start != net_dev->ib.next_num) {
+ printk(KERN_DEBUG "ippp: MP, stepping over missing frame: %ld\n", net_dev->ib.next_num);
#ifdef CONFIG_ISDN_PPP_VJ
slhc_toss(ippp_table[net_dev->local.ppp_slot]->slcomp);
#endif
}
- isdn_ppp_push_higher(net_dev, lp, q->skb, -1);
+ proto = isdn_ppp_strip_proto(q->skb);
+ isdn_ppp_push_higher(net_dev, lp, q->skb, proto);
net_dev->ib.sq = q->next;
net_dev->ib.next_num = q->sqno_end + 1;
kfree(q);
- }
+ }
}
/*
* remove stale packets from list
*/
-static void isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min_sqno)
+static void
+isdn_ppp_cleanup_mpqueue(isdn_net_dev * dev, long min_sqno)
{
#ifdef CONFIG_ISDN_PPP_VJ
int toss = 0;
@@ -1526,36 +1765,36 @@
/* z.z einfaches aussortieren gammeliger pakete. Fuer die Zukunft:
eventuell, solange vorne kein B-paket ist und sqno<=min_sqno: auch rauswerfen
wenn sqno<min_sqno und Luecken vorhanden sind: auch weg (die koennen nicht mehr gefuellt werden)
- bei paketen groesser min_sqno: ueber mp_mrru: wenn summe ueber pktlen der rumhaengenden Pakete
+ bei paketen groesser min_sqno: ueber mp_mrru: wenn summe ueber pktlen der rumhaengenden Pakete
groesser als mrru ist: raus damit , Pakete muessen allerdings zusammenhaengen sonst koennte
ja ein Paket mit B und eins mit E dazwischenpassen */
- struct mpqueue *ql, *q = dev->mp_last;
- while (q) {
- if (q->sqno < min_sqno) {
- if (q->BEbyte & MP_END_FRAG) {
- printk(KERN_DEBUG "ippp: freeing stale packet!\n");
- if ((dev->mp_last = q->next))
- q->next->last = NULL;
- while (q) {
- ql = q->last;
- q->skb->free = 1;
- dev_kfree_skb(q->skb,0 /* FREE_READ */ );
- kfree(q);
+ struct mpqueue *ql,
+ *q = dev->mp_last;
+ while(q && (q->sqno < min_sqno) ) {
+ if ( (q->BEbyte & MP_END_FRAG) ||
+ (q->next && (q->next->sqno <= min_sqno) && (q->next->BEbyte & MP_BEGIN_FRAG)) ) {
+ printk(KERN_DEBUG "ippp: freeing stale packet(s), min_sq: %ld!\n",min_sqno);
+ if ((dev->mp_last = q->next))
+ q->next->last = NULL;
+ while (q) {
+ ql = q->last;
+ SET_SKB_FREE(q->skb);
+ printk(KERN_DEBUG "ippp, freeing packet with sqno: %ld\n",q->sqno);
+ dev_kfree_skb(q->skb, 0 /* FREE_READ */ );
+ kfree(q);
#ifdef CONFIG_ISDN_PPP_VJ
- toss = 1;
+ toss = 1;
#endif
- q = ql;
- }
- q = dev->mp_last;
- } else
- q = q->next;
+ q = ql;
+ }
+ q = dev->mp_last;
} else
- break;
+ q = q->next;
}
#ifdef CONFIG_ISDN_PPP_VJ
/* did we free a stale frame ? */
- if(toss)
+ if (toss)
slhc_toss(ippp_table[dev->local.ppp_slot]->slcomp);
#endif
}
@@ -1566,26 +1805,28 @@
#endif
-void isdn_ppp_timer_timeout(void)
+void
+isdn_ppp_timer_timeout(void)
{
#ifdef CONFIG_ISDN_MPP
isdn_net_dev *net_dev = dev->netdev;
- struct sqqueue *q, *ql = NULL, *qn;
+ struct sqqueue *q,
+ *ql = NULL,
+ *qn;
while (net_dev) {
isdn_net_local *lp = &net_dev->local;
- if (net_dev->ib.modify || lp->master) { /* interface locked or slave?*/
+ if (net_dev->ib.modify || lp->master) { /* interface locked or slave? */
net_dev = net_dev->next;
continue;
}
-
q = net_dev->ib.sq;
while (q) {
if (q->sqno_start == net_dev->ib.next_num || q->timer < jiffies) {
#ifdef CONFIG_ISDN_PPP_VJ
/* did we step over a missing frame ? */
- if(q->sqno_start != net_dev->ib.next_num)
+ if (q->sqno_start != net_dev->ib.next_num)
slhc_toss(ippp_table[lp->ppp_slot]->slcomp);
#endif
@@ -1594,7 +1835,8 @@
net_dev->ib.next_num = q->sqno_end + 1;
q->next = NULL;
for (; ql;) {
- isdn_ppp_push_higher(net_dev, lp, ql->skb, -1);
+ int proto = isdn_ppp_strip_proto(ql->skb);
+ isdn_ppp_push_higher(net_dev, lp, ql->skb, proto);
qn = ql->next;
kfree(ql);
ql = qn;
@@ -1612,46 +1854,47 @@
* network device ioctl handlers
*/
-static int isdn_ppp_dev_ioctl_stats(int slot,struct ifreq *ifr,struct device *dev)
+static int
+isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct device *dev)
{
- struct ppp_stats *res, t;
+ struct ppp_stats *res,
+ t;
isdn_net_local *lp = (isdn_net_local *) dev->priv;
int err;
- res = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
- err = verify_area (VERIFY_WRITE, res,sizeof(struct ppp_stats));
+ res = (struct ppp_stats *) ifr->ifr_ifru.ifru_data;
+ err = verify_area(VERIFY_WRITE, res, sizeof(struct ppp_stats));
- if(err)
+ if (err)
return err;
/* build a temporary stat struct and copy it to user space */
- memset (&t, 0, sizeof(struct ppp_stats));
- if(dev->flags & IFF_UP) {
+ memset(&t, 0, sizeof(struct ppp_stats));
+ if (dev->flags & IFF_UP) {
t.p.ppp_ipackets = lp->stats.rx_packets;
t.p.ppp_ierrors = lp->stats.rx_errors;
t.p.ppp_opackets = lp->stats.tx_packets;
t.p.ppp_oerrors = lp->stats.tx_errors;
#ifdef CONFIG_ISDN_PPP_VJ
- if(slot >= 0 && ippp_table[slot]->slcomp) {
+ if (slot >= 0 && ippp_table[slot]->slcomp) {
struct slcompress *slcomp = ippp_table[slot]->slcomp;
- t.vj.vjs_packets = slcomp->sls_o_compressed+slcomp->sls_o_uncompressed;
+ t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed;
t.vj.vjs_compressed = slcomp->sls_o_compressed;
t.vj.vjs_searches = slcomp->sls_o_searches;
- t.vj.vjs_misses = slcomp->sls_o_misses;
- t.vj.vjs_errorin = slcomp->sls_i_error;
- t.vj.vjs_tossed = slcomp->sls_i_tossed;
+ t.vj.vjs_misses = slcomp->sls_o_misses;
+ t.vj.vjs_errorin = slcomp->sls_i_error;
+ t.vj.vjs_tossed = slcomp->sls_i_tossed;
t.vj.vjs_uncompressedin = slcomp->sls_i_uncompressed;
t.vj.vjs_compressedin = slcomp->sls_i_compressed;
}
#endif
}
- copy_to_user (res, &t, sizeof (struct ppp_stats));
- return 0;
-
+ return copy_to_user(res, &t, sizeof(struct ppp_stats));
}
-int isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+int
+isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
{
int error;
char *r;
@@ -1659,7 +1902,7 @@
isdn_net_local *lp = (isdn_net_local *) dev->priv;
#if 0
- printk(KERN_DEBUG "ippp, dev_ioctl: cmd %#08x , %d \n",cmd,lp->ppp_slot);
+ printk(KERN_DEBUG "ippp, dev_ioctl: cmd %#08x , %d \n", cmd, lp->ppp_slot);
#endif
if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
@@ -1669,12 +1912,10 @@
case SIOCGPPPVER:
r = (char *) ifr->ifr_ifru.ifru_data;
len = strlen(PPP_VERSION) + 1;
- error = verify_area(VERIFY_WRITE, r, len);
- if (!error)
- copy_to_user(r, PPP_VERSION, len);
+ error = copy_to_user(r, PPP_VERSION, len);
break;
case SIOCGPPPSTATS:
- error = isdn_ppp_dev_ioctl_stats (lp->ppp_slot, ifr, dev);
+ error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev);
break;
default:
error = -EINVAL;
@@ -1683,51 +1924,55 @@
return error;
}
-static int isdn_ppp_if_get_unit(char *name)
+static int
+isdn_ppp_if_get_unit(char *name)
{
- int len, i, unit = 0, deci;
+ int len,
+ i,
+ unit = 0,
+ deci;
len = strlen(name);
- if(strncmp("ippp",name,4) || len > 8)
+ if (strncmp("ippp", name, 4) || len > 8)
return -1;
for (i = 0, deci = 1; i < len; i++, deci *= 10) {
- char a = name[len-i-1];
+ char a = name[len - i - 1];
if (a >= '0' && a <= '9')
unit += (a - '0') * deci;
else
break;
}
- if (!i || len-i != 4)
+ if (!i || len - i != 4)
unit = -1;
return unit;
}
-int isdn_ppp_dial_slave(char *name)
+int
+isdn_ppp_dial_slave(char *name)
{
#ifdef CONFIG_ISDN_MPP
isdn_net_dev *ndev;
isdn_net_local *lp;
struct device *sdev;
- if(!(ndev = isdn_net_findif(name)))
+ if (!(ndev = isdn_net_findif(name)))
return 1;
lp = &ndev->local;
- if(!(lp->flags & ISDN_NET_CONNECTED))
+ if (!(lp->flags & ISDN_NET_CONNECTED))
return 5;
sdev = lp->slave;
- while(sdev)
- {
+ while (sdev) {
isdn_net_local *mlp = (isdn_net_local *) sdev->priv;
- if(!(mlp->flags & ISDN_NET_CONNECTED))
+ if (!(mlp->flags & ISDN_NET_CONNECTED))
break;
sdev = mlp->slave;
}
- if(!sdev)
+ if (!sdev)
return 2;
isdn_net_force_dial_lp((isdn_net_local *) sdev->priv);
@@ -1737,28 +1982,28 @@
#endif
}
-int isdn_ppp_hangup_slave(char *name)
+int
+isdn_ppp_hangup_slave(char *name)
{
#ifdef CONFIG_ISDN_MPP
- isdn_net_dev *ndev;
- isdn_net_local *lp;
- struct device *sdev;
+ isdn_net_dev *ndev;
+ isdn_net_local *lp;
+ struct device *sdev;
- if(!(ndev = isdn_net_findif(name)))
+ if (!(ndev = isdn_net_findif(name)))
return 1;
lp = &ndev->local;
- if(!(lp->flags & ISDN_NET_CONNECTED))
+ if (!(lp->flags & ISDN_NET_CONNECTED))
return 5;
sdev = lp->slave;
- while(sdev)
- {
+ while (sdev) {
isdn_net_local *mlp = (isdn_net_local *) sdev->priv;
- if((mlp->flags & ISDN_NET_CONNECTED))
+ if ((mlp->flags & ISDN_NET_CONNECTED))
break;
sdev = mlp->slave;
}
- if(!sdev)
+ if (!sdev)
return 2;
isdn_net_hangup(sdev);
@@ -1768,13 +2013,182 @@
#endif
}
+/*
+ * PPP compression stuff
+ */
+static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master)
+{
+#if 1
+ printk(KERN_ERR "compression not included!\n");
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb,FREE_WRITE);
+ return NULL;
+#else
+ if(!master) {
+ /*
+ * single link compression
+ */
+ if(!is->link_compressor) {
+ printk(KERN_ERR "ippp: no (link) compressor defined!\n");
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb,FREE_WRITE);
+ return NULL;
+ }
+ if(!is->link_decomp_stat) {
+ printk(KERN_DEBUG "ippp: initialize link compressor\n");
+ }
+/*
+ -> decompress link
+*/
+ }
+ else {
+ /*
+ * 'normal' or bundle-compression
+ */
+ if(!master->compressor) {
+ printk(KERN_ERR "ippp: no (link) compressor defined!\n");
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb,FREE_WRITE);
+ return NULL;
+ }
+ if(!master->decomp_stat) {
+#if 0
+ master->decomp_stat = (master->compressor->decomp_alloc)( .. );
+#endif
+ printk(KERN_DEBUG "ippp: initialize compressor\n");
+ }
+ }
+
+ return skb;
+#endif
+}
+
+/*
+ * compress a frame
+ * type=0: normal/bundle compression
+ * =1: link compression
+ * returns original skb if we haven't compressed the frame
+ * and a new skb pointer if we've done it
+ */
+static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
+ struct ippp_struct *is,struct ippp_struct *master,int type)
+{
+#if 1
+ return skb_in;
+#else
+ int ret;
+ int new_proto;
+ struct isdn_ppp_compressor *compressor;
+ void *stat;
+ struct sk_buff *skb_out;
+
+ if(type) { /* type=1 => Link compression */
+ compressor = is->link_compressor;
+ stat = is->link_comp_stat;
+ new_proto = PPP_LINK_COMP;
+ }
+ else {
+ if(!master) {
+ compressor = is->compressor;
+ stat = is->comp_stat;
+ }
+ else {
+ compressor = master->compressor;
+ stat = master->comp_stat;
+ }
+ new_proto = PPP_COMP;
+ }
+
+ if(!compressor) {
+ printk(KERN_ERR "No compressor set!\n");
+ return skb_in;
+ }
+ if(!stat) {
+ /* init here ? */
+ return skb_in;
+ }
+
+ skb_out = dev_alloc_skb(skb_in->len);
+ if(!skb_out)
+ return skb_in;
+
+ ret = (compressor->compress)(stat,skb_in,skb_out,*proto);
+ if(!ret) {
+ SET_SKB_FREE(skb_out);
+ dev_kfree_skb(skb_out,0);
+ return skb_in;
+ }
+
+ dev_kfree_skb(skb_in,FREE_WRITE);
+ *proto = new_proto;
+ return skb_out;
+#endif
+
+}
+
+/*
+ * we received a CCP frame ..
+ * not a clean solution, but we SHOULD handle a few cased in the kernel
+ */
+static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
+ struct sk_buff *skb)
+{
+#if 0
+ printk(KERN_DEBUG "isdn_ppp_receive_cpp: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ skb->data[0],skb->data[1],skb->data[2],skb->data[3],
+ skb->data[4],skb->data[5],skb->data[6],skb->data[7] );
+#endif
+}
+
+int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
+{
+ ipc->next = ipc_head;
+ ipc->prev = NULL;
+ if(ipc_head) {
+ ipc_head->prev = ipc;
+ }
+ ipc_head = ipc;
+ return 0;
+}
+
+int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc)
+{
+ if(ipc->prev)
+ ipc->prev->next = ipc->next;
+ else
+ ipc_head = ipc->next;
+ if(ipc->next)
+ ipc->next->prev = ipc->prev;
+ ipc->prev = ipc->next = NULL;
+ return 0;
+}
+
+static int isdn_ppp_set_compressor(struct ippp_struct *is,int num)
+{
+ struct isdn_ppp_compressor *ipc = ipc_head;
+
+ while(ipc) {
+ if(ipc->num == num) {
+ return 0;
+ is->compressor = ipc;
+ is->link_compressor = ipc;
+ }
+ ipc = ipc->next;
+ }
+ return -EINVAL;
+}
+
+
#if 0
-static struct symbol_table isdn_ppp_syms = {
+static struct symbol_table isdn_ppp_syms =
+{
#include <linux/symtab_begin.h>
- X(isdn_ppp_register_compressor),
- X(isdn_ppp_unregister_compressor),
+ X(isdn_ppp_register_compressor),
+ X(isdn_ppp_unregister_compressor),
#include <linux/symtab_end.h>
};
#endif
+
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov