patch-2.2.19 linux/drivers/isdn/isdn_ppp.c
Next file: linux/drivers/isdn/isdn_tty.c
Previous file: linux/drivers/isdn/isdn_net.h
Back to the patch index
Back to the overall index
- Lines: 1151
- Date:
Sun Mar 25 11:37:33 2001
- Orig file:
v2.2.18/drivers/isdn/isdn_ppp.c
- Orig date:
Sun Mar 25 11:28:24 2001
diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.63 2000/03/16 15:46:37 kai Exp $
+/* $Id: isdn_ppp.c,v 1.85.6.2 2001/01/23 17:45:02 kai Exp $
*
* Linux ISDN subsystem, functions for synchronous PPP (linklevel).
*
@@ -20,8 +20,6 @@
*
*/
-#define CONFIG_ISDN_CCP 1
-
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
@@ -29,6 +27,7 @@
#include <linux/poll.h>
#include <linux/isdn.h>
#include <linux/ppp-comp.h>
+#include <linux/isdn_compat.h>
#include "isdn_common.h"
#include "isdn_ppp.h"
@@ -38,8 +37,6 @@
#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_closewait(int slot);
@@ -48,7 +45,7 @@
static int isdn_ppp_if_get_unit(char *namebuf);
static int isdn_ppp_set_compressor(struct ippp_struct *is,struct isdn_ppp_comp_data *);
static struct sk_buff *isdn_ppp_decompress(struct sk_buff *,
- struct ippp_struct *,struct ippp_struct *,int proto);
+ struct ippp_struct *,struct ippp_struct *,int *proto);
static void isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp,
struct sk_buff *skb,int proto);
static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
@@ -85,11 +82,9 @@
static void isdn_ppp_mp_cleanup( isdn_net_local * lp );
static int isdn_ppp_bundle(struct ippp_struct *, int unit);
-
-#define MP_UNLOCK(b) up(&(b)->lock)
#endif /* CONFIG_ISDN_MPP */
-char *isdn_ppp_revision = "$Revision: 1.63 $";
+char *isdn_ppp_revision = "$Revision: 1.85.6.2 $";
static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
@@ -124,55 +119,28 @@
int
isdn_ppp_free(isdn_net_local * lp)
{
-#ifdef CONFIG_ISDN_MPP
- isdn_net_local *master_lp = NULL;
-#endif
unsigned long flags;
struct ippp_struct *is;
- isdn_net_local * nlp;
if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS)
return 0;
- is = ippp_table[lp->ppp_slot];
-
save_flags(flags);
cli();
-#ifdef CONFIG_ISDN_MPP
- spin_lock(&lp->netdev->pb->lock); // irq_save not necessary
-
- if (lp->master)
- master_lp = (isdn_net_local *) lp->master->priv;
-
-
- /* make sure none of the queue pointers will point to the
- * interface being removed */
- for (nlp=lp->next; nlp != lp; nlp=nlp->next)
- if (nlp->netdev->queue == lp )
- nlp->netdev->queue = lp->next;
- lp->last->next = lp->next;
- lp->next->last = lp->last;
-
- if (master_lp && master_lp->netdev->queue == lp)
- master_lp->netdev->queue = lp->next;
-/*
- if (lp->next->netdev->queue == lp)
- lp->next->netdev->queue = lp->next;
- if (lp->last->netdev->queue == lp)
- lp->last->netdev->queue = lp->last;
-*/
+#ifdef CONFIG_ISDN_MPP
+ spin_lock(&lp->netdev->pb->lock);
+#endif
+ isdn_net_rm_from_bundle(lp);
+#ifdef CONFIG_ISDN_MPP
if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */
- isdn_ppp_mp_cleanup(lp);
-
- lp->next = lp->last = lp; /* (re)set own pointers */
- lp->netdev->queue = lp;
-
- spin_unlock(&lp->netdev->pb->lock);
+ isdn_ppp_mp_cleanup(lp);
+
lp->netdev->pb->ref_ct--;
-
+ spin_unlock(&lp->netdev->pb->lock);
#endif /* CONFIG_ISDN_MPP */
+ is = ippp_table[lp->ppp_slot];
if ((is->state & IPPP_CONNECT))
isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */
else if (is->state & IPPP_ASSIGNED)
@@ -183,8 +151,8 @@
is->lp = NULL; /* link is down .. set lp to NULL */
lp->ppp_slot = -1; /* is this OK ?? */
- restore_flags(flags);
+ restore_flags(flags);
return 0;
}
@@ -199,12 +167,8 @@
long flags;
struct ippp_struct *is;
- if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
- return -1;
-
save_flags(flags);
cli();
-
if (lp->pppbind < 0) { /* device bounded to ippp device ? */
isdn_net_dev *net_dev = dev->netdev;
char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */
@@ -243,7 +207,6 @@
}
lp->ppp_slot = i;
-
is = ippp_table[i];
is->lp = lp;
is->unit = unit;
@@ -270,8 +233,7 @@
return;
ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
-
- if (ippp_table[lp->ppp_slot]->wq)
+
wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
}
@@ -289,7 +251,7 @@
return 0;
is = ippp_table[slot];
- if (is->state && is->wq)
+ if (is->state)
wake_up_interruptible(&is->wq);
is->state = IPPP_CLOSEWAIT;
@@ -350,7 +312,7 @@
is->mru = 1524; /* MRU, default 1524 */
is->maxcid = 16; /* VJ: maxcid */
is->tk = current;
- is->wq = NULL; /* read() wait queue */
+ init_waitqueue_head(&is->wq);
is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
is->last = is->rq;
is->minor = min;
@@ -714,7 +676,6 @@
is->last = bl->next;
restore_flags(flags);
- if (is->wq)
wake_up_interruptible(&is->wq);
return len;
@@ -805,8 +766,6 @@
lp->dialstate == 0 &&
(lp->flags & ISDN_NET_CONNECTED)) {
unsigned short hl;
- unsigned long flags;
- int cnt;
struct sk_buff *skb;
/*
* we need to reserve enought space in front of
@@ -829,17 +788,7 @@
isdn_ppp_send_ccp(lp->netdev,lp,skb); /* keeps CCP/compression states in sync */
- save_flags(flags);
- cli();
- if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb)) != count) {
- if (lp->sav_skb) {
- dev_kfree_skb(lp->sav_skb);
- 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;
- }
- restore_flags(flags);
+ isdn_net_write_super(lp, skb);
}
}
return count;
@@ -899,15 +848,49 @@
}
/*
+ * check for address/control field and skip if allowed
+ * retval != 0 -> discard packet silently
+ */
+static int isdn_ppp_skip_ac(struct ippp_struct *is, struct sk_buff *skb)
+{
+ if (skb->len < 1)
+ return -1;
+
+ if (skb->data[0] == 0xff) {
+ if (skb->len < 2)
+ return -1;
+
+ if (skb->data[1] != 0x03)
+ return -1;
+
+ // skip address/control (AC) field
+ skb_pull(skb, 2);
+ } else {
+ if (is->pppcfg & SC_REJ_COMP_AC)
+ // if AC compression was not negotiated, but used, discard packet
+ return -1;
+ }
+ return 0;
+}
+
+/*
* get the PPP protocol header and pull skb
+ * retval < 0 -> discard packet silently
*/
static int isdn_ppp_strip_proto(struct sk_buff *skb)
{
int proto;
+
+ if (skb->len < 1)
+ return -1;
+
if (skb->data[0] & 0x1) {
+ // protocol field is compressed
proto = skb->data[0];
- skb_pull(skb, 1); /* protocol ID is only 8 bit */
+ skb_pull(skb, 1);
} else {
+ if (skb->len < 2)
+ return -1;
proto = ((int) skb->data[0] << 8) + skb->data[1];
skb_pull(skb, 2);
}
@@ -924,6 +907,9 @@
int slot;
int proto;
+ if (net_dev->local->master)
+ BUG(); // we're called with the master device always
+
slot = lp->ppp_slot;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot %d\n", lp->ppp_slot);
@@ -937,135 +923,95 @@
(long)is,(long)lp,lp->ppp_slot,is->unit,(int) skb->len);
isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
}
- if (net_dev->local->master) {
- printk(KERN_WARNING "isdn_ppp_receive: net_dev != master\n");
- net_dev = ((isdn_net_local *) net_dev->local->master->priv)->netdev;
- }
- if (skb->data[0] == 0xff && skb->data[1] == 0x03)
- skb_pull(skb, 2);
- else if (is->pppcfg & SC_REJ_COMP_AC) {
- dev_kfree_skb(skb);
- return; /* discard it silently */
- }
-
- proto = isdn_ppp_strip_proto(skb);
+ if (isdn_ppp_skip_ac(is, skb) < 0) {
+ kfree_skb(skb);
+ return;
+ }
+ proto = isdn_ppp_strip_proto(skb);
+ if (proto < 0) {
+ kfree_skb(skb);
+ return;
+ }
+
#ifdef CONFIG_ISDN_MPP
- if (!(is->mpppcfg & SC_REJ_MP_PROT)) {
-
- if(is->compflags & SC_LINK_DECOMP_ON) {
- if(proto == PPP_LINK_COMP) {
- if(is->debug & 0x10)
- printk(KERN_DEBUG "received single link compressed frame\n");
- skb = isdn_ppp_decompress(skb,is,NULL,proto);
- if(!skb) {
- printk(KERN_DEBUG "ippp: dropping LINK_COMP frame!\n");
- return;
- }
- proto = isdn_ppp_strip_proto(skb);
- } else {
- skb = isdn_ppp_decompress(skb,is,NULL,proto);
- if(!skb) {
- printk(KERN_DEBUG "ippp: dropping uncompressed frame!\n");
- return;
- }
- }
- }
-
- if (proto == PPP_MP) {
- isdn_ppp_mp_receive(net_dev, lp, skb);
- }
- else
- isdn_ppp_push_higher(net_dev, lp, skb, proto);
- } else
-#endif /* CONFIG_ISDN_MPP */
- isdn_ppp_push_higher(net_dev, lp, skb, proto);
+ if (is->compflags & SC_LINK_DECOMP_ON) {
+ skb = isdn_ppp_decompress(skb, is, NULL, &proto);
+ if (!skb) // decompression error
+ return;
+ }
+
+ if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP
+ if (proto == PPP_MP) {
+ isdn_ppp_mp_receive(net_dev, lp, skb);
+ return;
+ }
+ }
+#endif
+ isdn_ppp_push_higher(net_dev, lp, skb, proto);
}
/*
- * push frame to higher layers
+ * we receive a reassembled frame, MPPP has been taken care of before.
+ * address/control and protocol have been stripped from the skb
* 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)
{
struct device *dev = &net_dev->dev;
- struct ippp_struct *is;
+ struct ippp_struct *is, *mis;
int slot;
slot = lp->ppp_slot;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot %d\n", lp->ppp_slot);
- kfree_skb(skb);
- return;
+ goto drop_packet;
}
is = ippp_table[slot];
+
+ if (lp->master) { // FIXME?
+ slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
+ if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+ printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot %d\n", lp->ppp_slot);
+ goto drop_packet;
+ }
+ }
+ mis = ippp_table[slot];
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,is->unit,lp->ppp_slot);
}
-
- if(proto == PPP_COMP) {
- if(!lp->master) {
- skb = isdn_ppp_decompress(skb,is,is,proto);
- } else {
- skb = isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot],proto);
- }
- if(!skb) {
- printk(KERN_DEBUG "ippp: compressed frame discarded!\n");
- return;
- }
-
- proto = isdn_ppp_strip_proto(skb);
- if (is->debug & 0x10) {
- printk(KERN_DEBUG "RPostDecomp, skb %d %04x\n", (int) skb->len, proto);
- isdn_ppp_frame_log("R-Decomp", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
- }
- }
- else if (is->compflags & SC_DECOMP_ON) { /* If decomp is ON */
- if(!lp->master) {
- skb = isdn_ppp_decompress(skb,is,is,proto);
- } else {
- skb = isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot],proto);
- }
-
- if(!skb) {
- printk(KERN_DEBUG "ippp: compressed frame discarded!\n");
- return;
- }
- }
-
+ if (is->compflags & SC_DECOMP_ON) {
+ skb = isdn_ppp_decompress(skb, is, mis, &proto);
+ if (!skb) // decompression error
+ return;
+ }
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;
+ case PPP_IP:
+ if (is->debug & 0x20)
+ printk(KERN_DEBUG "isdn_ppp: IP\n");
+ skb->protocol = htons(ETH_P_IP);
+ 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++;
- dev_kfree_skb(skb);
- return;
+ goto drop_packet;
}
-#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");
-#ifdef CONFIG_ISDN_PPP_VJ
{
struct sk_buff *skb_old = skb;
int pkt_len;
@@ -1073,34 +1019,24 @@
if (!skb) {
printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
- net_dev->local->stats.rx_dropped++;
- dev_kfree_skb(skb_old);
- return;
+ skb = skb_old;
+ goto drop_packet;
}
- skb->dev = dev;
skb_put(skb, skb_old->len + 128);
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);
- if (pkt_len < 0) {
- dev_kfree_skb(skb);
- lp->stats.rx_dropped++;
- return;
- }
+ kfree_skb(skb_old);
+ if (pkt_len < 0)
+ goto drop_packet;
+
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++;
- dev_kfree_skb(skb);
- return;
-#endif
break;
+#endif
case PPP_CCP:
- case PPP_LINK_CCP:
+ case PPP_CCPFRAG:
isdn_ppp_receive_ccp(net_dev,lp,skb,proto);
/* Dont pop up ResetReq/Ack stuff to the daemon any
longer - the job is done already */
@@ -1110,21 +1046,27 @@
/* fall through */
default:
isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */
- dev_kfree_skb(skb);
+ kfree_skb(skb);
return;
}
/* Reset hangup-timer */
lp->huptimer = 0;
- netif_rx(skb);
- /* net_dev->local->stats.rx_packets++; *//* done in isdn_net.c */
+ skb->dev = dev;
+ skb->mac.raw = skb->data;
+ netif_rx(skb);
+ /* net_dev->local->stats.rx_packets++; done in isdn_net.c */
return;
+
+ drop_packet:
+ net_dev->local->stats.rx_dropped++;
+ kfree_skb(skb);
}
/*
* isdn_ppp_skb_push ..
- * checks whether we have enough space at the beginning of the SKB
+ * checks whether we have enough space at the beginning of the skb
* and allocs a new SKB if necessary
*/
static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len)
@@ -1159,20 +1101,13 @@
int
isdn_ppp_xmit(struct sk_buff *skb, struct device *netdev)
{
- struct device *mdev = ((isdn_net_local *) (netdev->priv))->master; /* get master (for redundancy) */
isdn_net_local *lp,*mlp;
isdn_net_dev *nd;
unsigned int proto = PPP_IP; /* 0x21 */
struct ippp_struct *ipt,*ipts;
- unsigned long flags;
int slot;
- if (mdev)
- mlp = (isdn_net_local *) (mdev->priv);
- else {
- mdev = netdev;
- mlp = (isdn_net_local *) (netdev->priv);
- }
+ mlp = (isdn_net_local *) (netdev->priv);
nd = mlp->netdev; /* get master lp */
slot = mlp->ppp_slot;
@@ -1197,22 +1132,19 @@
proto = PPP_IPX; /* untested */
break;
default:
+ printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n",
+ skb->protocol);
dev_kfree_skb(skb);
- printk(KERN_ERR "isdn_ppp: skipped frame with unsupported protocol: %#x.\n", skb->protocol);
return 0;
}
- lp = nd->queue; /* get lp on top of queue */
-
- if (lp->sav_skb) { /* find a non-busy device */
- isdn_net_local *nlp = lp->next;
- while (nlp->sav_skb) {
- if (lp == nlp)
- return 1;
- nlp = nd->queue = nd->queue->next;
- }
- lp = nlp;
+ lp = isdn_net_get_locked_lp(nd);
+ if (!lp) {
+ printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name);
+ return 1;
}
+ /* we have our lp locked from now on */
+
slot = lp->ppp_slot;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot %d\n", lp->ppp_slot);
@@ -1227,8 +1159,8 @@
*/
/* Pull off the fake header we stuck on earlier to keep
- * the fragemntation code happy.
- */
+ * the fragmentation code happy.
+ */
skb_pull(skb,IPPP_MAX_HEADER);
if (ipt->debug & 0x4)
@@ -1301,11 +1233,10 @@
/* we get mp_seqno from static isdn_net_local */
long mp_seqno = ipts->mp_seqno;
ipts->mp_seqno++;
- nd->queue = nd->queue->next;
if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
unsigned char *data = isdn_ppp_skb_push(&skb, 3);
if(!data)
- return 0;
+ goto unlock;
mp_seqno &= 0xfff;
data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf); /* (B)egin & (E)ndbit .. */
data[1] = mp_seqno & 0xff;
@@ -1313,7 +1244,7 @@
} else {
unsigned char *data = isdn_ppp_skb_push(&skb, 5);
if(!data)
- return 0;
+ goto unlock;
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;
@@ -1333,20 +1264,20 @@
if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) {
unsigned char *data = isdn_ppp_skb_push(&skb,1);
if(!data)
- return 0;
+ goto unlock;
data[0] = proto & 0xff;
}
else {
unsigned char *data = isdn_ppp_skb_push(&skb,2);
if(!data)
- return 0;
+ goto unlock;
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;
+ goto unlock;
data[0] = 0xff; /* All Stations */
data[1] = 0x03; /* Unnumbered information */
}
@@ -1357,16 +1288,10 @@
printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,ipt->unit,lp->ppp_slot);
}
- save_flags(flags);
- cli();
- if (isdn_net_send_skb(netdev, lp, skb)) {
- if (lp->sav_skb) { /* should never happen as sav_skb are sent with disabled IRQs) */
- printk(KERN_ERR "%s: whoops .. there is another stored skb!\n", netdev->name);
- dev_kfree_skb(skb);
- } else
- lp->sav_skb = skb;
- }
- restore_flags(flags);
+
+ isdn_net_writebuf_skb(lp, skb);
+
+ unlock:
return 0;
}
@@ -1397,8 +1322,8 @@
static int isdn_ppp_mp_bundle_array_init(void)
{
- int i;
- int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle);
+ int i;
+ int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle);
if( (isdn_ppp_bundle_arr = (ippp_bundle*)kmalloc(sz,
GFP_KERNEL)) == NULL )
return -ENOMEM;
@@ -1410,7 +1335,7 @@
static ippp_bundle * isdn_ppp_mp_bundle_alloc(void)
{
- int i;
+ int i;
for( i = 0; i < ISDN_MAX_CHANNELS; i++ )
if (isdn_ppp_bundle_arr[i].ref_ct <= 0)
return (isdn_ppp_bundle_arr + i);
@@ -1419,7 +1344,7 @@
static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to )
{
- struct ippp_struct * is = ippp_table[lp->ppp_slot];
+ struct ippp_struct * is = ippp_table[lp->ppp_slot];
if (add_to) {
if( lp->netdev->pb )
@@ -1442,9 +1367,9 @@
static u32 isdn_ppp_mp_get_seq( int short_seq,
struct sk_buff * skb, u32 last_seq );
-struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,
+static struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,
struct sk_buff * from, struct sk_buff * to );
-void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
+static void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
struct sk_buff * from, struct sk_buff * to );
static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb );
static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb );
@@ -1452,18 +1377,27 @@
static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp,
struct sk_buff *skb)
{
- struct ippp_struct *is = ippp_table[lp->ppp_slot];
+ struct ippp_struct *is;
isdn_net_local * lpq;
ippp_bundle * mp;
isdn_mppp_stats * stats;
struct sk_buff * newfrag, * frag, * start, *nextf;
u32 newseq, minseq, thisseq;
unsigned long flags;
-
- spin_lock_irqsave(&net_dev->pb->lock, flags);
+ int slot;
+
+ spin_lock_irqsave(&net_dev->pb->lock, flags);
mp = net_dev->pb;
stats = &mp->stats;
-
+ slot = lp->ppp_slot;
+ if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+ printk(KERN_ERR "isdn_ppp_mp_receive: lp->ppp_slot %d\n", lp->ppp_slot);
+ stats->frame_drops++;
+ dev_kfree_skb(skb);
+ spin_unlock_irqrestore(&mp->lock, flags);
+ return;
+ }
+ is = ippp_table[slot];
if( ++mp->frames > stats->max_queue_len )
stats->max_queue_len = mp->frames;
@@ -1491,9 +1425,14 @@
/* find the minimum received sequence number over all links */
is->last_link_seqno = minseq = newseq;
for (lpq = net_dev->queue;;) {
- u32 lls = ippp_table[lpq->ppp_slot]->last_link_seqno;
- if (MP_LT(lls, minseq))
- minseq = lls;
+ slot = lpq->ppp_slot;
+ if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+ printk(KERN_ERR "isdn_ppp_mp_receive: lpq->ppp_slot %d\n", lpq->ppp_slot);
+ } else {
+ u32 lls = ippp_table[slot]->last_link_seqno;
+ if (MP_LT(lls, minseq))
+ minseq = lls;
+ }
if ((lpq = lpq->next) == net_dev->queue)
break;
}
@@ -1645,20 +1584,19 @@
* queue overflow */
if (mp->frames > MP_MAX_QUEUE_LEN) {
stats->overflows++;
- while (mp->frames < MP_MAX_QUEUE_LEN) {
+ while (mp->frames > MP_MAX_QUEUE_LEN) {
frag = mp->frags->next;
isdn_ppp_mp_free_skb(mp, mp->frags);
mp->frags = frag;
}
}
-
spin_unlock_irqrestore(&mp->lock, flags);
}
static void isdn_ppp_mp_cleanup( isdn_net_local * lp )
{
- struct sk_buff * frag = lp->netdev->pb->frags;
- struct sk_buff * nextfrag;
+ struct sk_buff * frag = lp->netdev->pb->frags;
+ struct sk_buff * nextfrag;
while( frag ) {
nextfrag = frag->next;
isdn_ppp_mp_free_skb(lp->netdev->pb, frag);
@@ -1670,8 +1608,8 @@
static u32 isdn_ppp_mp_get_seq( int short_seq,
struct sk_buff * skb, u32 last_seq )
{
- u32 seq;
- int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG);
+ u32 seq;
+ int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG);
if( !short_seq )
{
@@ -1716,46 +1654,40 @@
void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
struct sk_buff * from, struct sk_buff * to )
{
- ippp_bundle * mp = net_dev->pb;
- int proto;
- struct sk_buff * skb;
- unsigned int tot_len;
-
- if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) )
- {
+ ippp_bundle * mp = net_dev->pb;
+ int proto;
+ struct sk_buff * skb;
+ unsigned int tot_len;
+
+ if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) {
if( ippp_table[lp->ppp_slot]->debug & 0x40 )
printk(KERN_DEBUG"isdn_mppp: reassembly: frame %d, "
"len %d\n", MP_SEQ(from), from->len );
skb = from;
skb_pull(skb, MP_HEADER_LEN);
mp->frames--;
- }
- else
- {
- struct sk_buff * frag;
- int n;
-
- for( tot_len=0, frag=from, n = 0; frag != to;
- frag=frag->next, n++ )
+ } else {
+ struct sk_buff * frag;
+ int n;
+
+ for(tot_len=n=0, frag=from; frag != to; frag=frag->next, n++)
tot_len += frag->len - MP_HEADER_LEN;
-
+
if( ippp_table[lp->ppp_slot]->debug & 0x40 )
printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "
"to %d, len %d\n", MP_SEQ(from),
(MP_SEQ(from)+n-1) & MP_LONGSEQ_MASK, tot_len );
-
- if( (skb = dev_alloc_skb(tot_len)) == NULL )
- {
- printk(KERN_ERR"isdn_mppp: cannot allocate sk buff "
+ if( (skb = dev_alloc_skb(tot_len)) == NULL ) {
+ printk(KERN_ERR "isdn_mppp: cannot allocate sk buff "
"of size %d\n", tot_len);
isdn_ppp_mp_discard(mp, from, to);
return;
}
-
- while( from != to )
- {
- unsigned int len = from->len - MP_HEADER_LEN;
- memcpy(skb_put(skb,len), from->data+MP_HEADER_LEN, len);
+
+ while( from != to ) {
+ unsigned int len = from->len - MP_HEADER_LEN;
+
+ memcpy(skb_put(skb,len), from->data+MP_HEADER_LEN, len);
frag = from->next;
isdn_ppp_mp_free_skb(mp, from);
from = frag;
@@ -1784,15 +1716,13 @@
{
char ifn[IFNAMSIZ + 1];
isdn_net_dev *p;
- isdn_net_local *lp,
- *nlp;
+ isdn_net_local *lp, *nlp;
int rc;
unsigned long flags;
sprintf(ifn, "ippp%d", unit);
p = isdn_net_findif(ifn);
- if (!p)
- {
+ if (!p) {
printk(KERN_ERR "ippp_bundle: cannot find %s\n", ifn);
return -EINVAL;
}
@@ -1800,38 +1730,29 @@
spin_lock_irqsave(&p->pb->lock, flags);
nlp = is->lp;
-
lp = p->queue;
-
if( nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ||
- lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS )
- {
- spin_unlock_irqrestore(&p->pb->lock, flags);
+ lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS ) {
printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n",
- nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ?
- nlp->ppp_slot : lp->ppp_slot );
- return -EINVAL;
- }
-
- nlp->last = lp->last;
- lp->last->next = nlp;
- lp->last = nlp;
- nlp->next = lp;
- p->queue = nlp;
+ nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ?
+ nlp->ppp_slot : lp->ppp_slot );
+ rc = -EINVAL;
+ goto out;
+ }
+
+ isdn_net_add_to_bundle(p, nlp);
ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit;
-/* maybe also SC_CCP stuff */
- ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg &
- (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
+ /* maybe also SC_CCP stuff */
+ ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg &
+ (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg &
- (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
-
- rc = isdn_ppp_mp_init(nlp, p->pb);
-
+ (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
+ rc = isdn_ppp_mp_init(nlp, p->pb);
+out:
spin_unlock_irqrestore(&p->pb->lock, flags);
-
- return rc;
+ return rc;
}
#endif /* CONFIG_ISDN_MPP */
@@ -2051,8 +1972,7 @@
{
struct sk_buff *skb;
unsigned char *p;
- int count, hl;
- unsigned long flags;
+ int hl;
int cnt = 0;
isdn_net_local *lp = is->lp;
@@ -2093,26 +2013,7 @@
printk(KERN_DEBUG "Sending CCP Frame:\n");
isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
- /* Just ripped from isdn_ppp_write. Dunno whether it makes sense,
- especially dunno what the sav_skb stuff is good for. */
-
- count = skb->len;
- save_flags(flags);
- cli();
- if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel,
- 1, skb)) != count) {
- if (lp->sav_skb) {
- dev_kfree_skb(lp->sav_skb);
- 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;
- }
- restore_flags(flags);
+ isdn_net_write_super(lp, skb);
}
/* Allocate the reset state vector */
@@ -2359,17 +2260,21 @@
is->reset->lastid++;
}
+/*
+ * decompress packet
+ *
+ * if master = 0, we're trying to uncompress an per-link compressed packet,
+ * as opposed to an compressed reconstructed-from-MPPP packet.
+ * proto is updated to protocol field of uncompressed packet.
+ *
+ * retval: decompressed packet,
+ * same packet if uncompressed,
+ * NULL if decompression error
+ */
+
static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master,
- int proto)
+ int *proto)
{
-#ifndef CONFIG_ISDN_CCP
- if(proto == PPP_COMP || proto == PPP_LINK_COMP) {
- printk(KERN_ERR "isdn_ppp: Ouch! Compression not included!\n");
- dev_kfree_skb(skb);
- return NULL;
- }
- return skb;
-#else
void *stat = NULL;
struct isdn_ppp_compressor *ipc = NULL;
struct sk_buff *skb_out;
@@ -2379,83 +2284,65 @@
unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
if(!master) {
- /*
- * single link decompression
- */
- if(!is->link_decompressor) {
- printk(KERN_DEBUG "ippp: no link decompressor defined!\n");
- return skb;
- }
- if(!is->link_decomp_stat) {
- printk(KERN_DEBUG "ippp: no link decompressor data allocated\n");
- return skb;
- }
+ // per-link decompression
stat = is->link_decomp_stat;
ipc = is->link_decompressor;
ri = is;
- }
- else {
- /*
- * 'normal' or bundle-compression
- */
- if(!master->decompressor) {
- printk(KERN_DEBUG "ippp: no decompressor defined!\n");
- return skb;
- }
- if(!master->decomp_stat) {
- printk(KERN_DEBUG "ippp: no decompressor data allocated\n");
- return skb;
- }
+ } else {
stat = master->decomp_stat;
ipc = master->decompressor;
ri = master;
}
- /*
- printk(KERN_DEBUG "ippp: Decompress valid!\n");
- */
+ if (!ipc) {
+ // no decompressor -> we can't decompress.
+ printk(KERN_DEBUG "ippp: no decompressor defined!\n");
+ return skb;
+ }
+ if (!stat) // if we have a compressor, stat has been set as well
+ BUG();
- if((master && proto == PPP_COMP) || (!master && proto == PPP_LINK_COMP) ) {
- /* Set up reset params for the decompressor */
- memset(&rsparm, 0, sizeof(rsparm));
- rsparm.data = rsdata;
- rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
+ if((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG) ) {
+ // compressed packets are compressed by their protocol type
-/* !!!HACK,HACK,HACK!!! 2048 is only assumed */
- skb_out = dev_alloc_skb(2048);
- len = ipc->decompress(stat,skb,skb_out, &rsparm);
- dev_kfree_skb(skb);
- if(len <= 0) {
- /* Ok, some error */
- switch(len) {
- case DECOMP_ERROR:
- ri->pppcfg |= SC_DC_ERROR;
- printk(KERN_INFO "ippp: decomp wants reset %s params\n",
- rsparm.valid ? "with" : "without");
-
- isdn_ppp_ccp_reset_trans(ri, &rsparm);
-
- break;
- case DECOMP_FATALERROR:
- ri->pppcfg |= SC_DC_FERROR;
- /* Kick ipppd to recognize the error */
- isdn_ppp_ccp_kickup(ri);
- break;
- }
- /* Did I see a leak here ? */
- dev_kfree_skb(skb_out);
- return NULL;
+ // Set up reset params for the decompressor
+ memset(&rsparm, 0, sizeof(rsparm));
+ rsparm.data = rsdata;
+ rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
+
+ skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN);
+ len = ipc->decompress(stat, skb, skb_out, &rsparm);
+ kfree_skb(skb);
+ if (len <= 0) {
+ switch(len) {
+ case DECOMP_ERROR:
+ ri->pppcfg |= SC_DC_ERROR;
+ printk(KERN_INFO "ippp: decomp wants reset %s params\n",
+ rsparm.valid ? "with" : "without");
+
+ isdn_ppp_ccp_reset_trans(ri, &rsparm);
+ break;
+ case DECOMP_FATALERROR:
+ ri->pppcfg |= SC_DC_FERROR;
+ /* Kick ipppd to recognize the error */
+ isdn_ppp_ccp_kickup(ri);
+ break;
+ }
+ kfree_skb(skb_out);
+ return NULL;
+ }
+ *proto = isdn_ppp_strip_proto(skb_out);
+ if (*proto < 0) {
+ kfree_skb(skb_out);
+ return NULL;
}
return skb_out;
- }
- else {
- /*
- printk(KERN_DEBUG "isdn_ppp: [%d] Calling incomp with this frame!\n",is->unit);
- */
- ipc->incomp(stat,skb,proto);
+ } else {
+ // uncompressed packets are fed through the decompressor to
+ // update the decompressor state
+ ipc->incomp(stat, skb, *proto);
return skb;
}
-#endif
}
/*
@@ -2474,13 +2361,9 @@
void *stat;
struct sk_buff *skb_out;
-#ifdef CONFIG_ISDN_CCP
/* we do not compress control protocols */
if(*proto < 0 || *proto > 0x3fff) {
-#else
- {
-#endif
- return skb_in;
+ return skb_in;
}
if(type) { /* type=1 => Link compression */
@@ -2681,7 +2564,7 @@
}
proto = ((int)data[0]<<8)+data[1];
- if(proto != PPP_CCP && proto != PPP_LINK_CCP)
+ if(proto != PPP_CCP && proto != PPP_CCPFRAG)
return;
printk(KERN_DEBUG "Received CCP frame from daemon:\n");
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)