a few MP changes and bugfixes

This commit is contained in:
Michael Hipp 1996-10-22 09:39:49 +00:00
parent c71ee2fbf2
commit f7d9078458
1 changed files with 138 additions and 61 deletions

View File

@ -19,9 +19,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log$
* Revision 1.15 1996/09/07 12:50:12 hipp
* bugfixes (unknown device after failed dial attempt, minor bugs)
*
* Revision 1.14 1996/08/12 16:26:47 hipp
* code cleanup
* changed connection management from minors to slots
@ -76,6 +73,8 @@
/* TODO: right tbusy handling when using MP */
#undef ISDN_SYNCPPP_READDRESS
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
@ -87,6 +86,8 @@
#ifndef PPP_IPX
#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);
@ -98,9 +99,10 @@ static int isdn_ppp_if_get_unit(char *namebuf);
#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_queue(isdn_net_dev * dev, long min);
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 int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb,
int BEbyte, int *sqno, int min_sqno);
int BEbyte, long *sqno, int min_sqno);
#endif
char *isdn_ppp_revision = "$Revision$";
@ -109,6 +111,24 @@ struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
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)
{
int cnt,j,i;
char buf[80];
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);
}
}
/*
* unbind isdn_net_local <=> ippp-device
* note: it can happen, that we hangup/free the master before the slaves
@ -135,7 +155,7 @@ int isdn_ppp_free(isdn_net_local *lp)
if(master_lp->netdev->queue == lp) {
master_lp->netdev->queue = lp->next;
if(lp->next == lp) { /* last link in queue? */
master_lp->netdev->ib.bundled = 0;
master_lp->netdev->ib.bundled = 0;
isdn_ppp_free_mpqueue(master_lp->netdev);
isdn_ppp_free_sqqueue(master_lp->netdev);
}
@ -146,13 +166,17 @@ int isdn_ppp_free(isdn_net_local *lp)
if( (is->state & IPPP_CONNECT) )
isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */
else if(is->state & IPPP_ASSIGNED)
is->state = IPPP_OPEN;
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 */
#ifdef ISDN_SYNCPPP_READDRESS
is->old_pa_addr = 0x0;
is->old_pa_dstaddr = 0x0;
#endif
lp->ppp_slot = -1; /* is this OK ?? */
restore_flags(flags);
@ -664,8 +688,6 @@ int isdn_ppp_write(int min, struct file *file, const char *buf, int count)
{
isdn_net_local *lp;
struct ippp_struct *is;
int proto;
unsigned char protobuf[4];
is = file->private_data;
@ -679,33 +701,32 @@ int isdn_ppp_write(int min, struct file *file, const char *buf, int count)
if (!lp)
printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");
else {
/*
* Don't reset huptimer for
* LCP packets. (Echo requests).
*/
memcpy_fromfs(protobuf, buf, 4);
proto = PPP_PROTOCOL(protobuf);
if (proto != PPP_LCP)
lp->huptimer = 0;
lp->huptimer = 0;
if (lp->isdn_device < 0 || lp->isdn_channel < 0)
return 0;
if (dev->drv[lp->isdn_device]->running && lp->dialstate == 0 &&
(lp->flags & ISDN_NET_CONNECTED)) {
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;
memcpy_fromfs(skb_put(skb, count), buf, count);
if (isdn_writebuf_skb_stub(lp->isdn_device,lp->isdn_channel,skb) != 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!\n");
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;
}
}
@ -755,14 +776,15 @@ void isdn_ppp_cleanup(void)
/*
* 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;
is = ippp_table[lp->ppp_slot];
if(is->debug & 0x4)
printk(KERN_DEBUG "recv skb, len: %ld\n",skb->len);
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(net_dev->local.master) {
printk(KERN_WARNING "isdn_ppp_receice: net_dev != master\n");
@ -790,7 +812,7 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
}
if (proto == PPP_MP) {
isdn_net_local *lpq;
int sqno, min_sqno, tseq;
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 ,
@ -807,7 +829,7 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
if ((tseq = is->last_link_seqno) >= sqno) {
int range = is->range;
if (tseq + 1024 < range + sqno) /* redundancy check .. not MP conform */
printk(KERN_WARNING "isdn_ppp_receive, MP, detected overflow with sqno: %d, last: %d !!!\n", sqno, tseq);
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;
@ -815,16 +837,19 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
} else
is->last_link_seqno = sqno;
for (min_sqno = 0, lpq = net_dev->queue;;) {
if (ippp_table[lpq->ppp_slot]->last_link_seqno > min_sqno)
min_sqno = ippp_table[lpq->ppp_slot]->last_link_seqno;
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)
min_sqno = lls;
lpq = lpq->next;
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
isdn_ppp_mask_queue(net_dev, mask);
net_dev->ib.next_num &= mask;
{
@ -844,11 +869,18 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
}
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)
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);
net_dev->ib.modify = 0;
return; /* no packet complete */
}
} else
sqno_end = sqno;
if(is->debug & 0x40)
printk(KERN_DEBUG "min_sqno: %ld sqno_end %ld next: %ld\n",min_sqno,sqno_end,net_dev->ib.next_num );
/*
* MP buffer management .. reorders incoming packets ..
* lotsa mem-copies and not heavily tested.
@ -891,27 +923,14 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
ql->next = q;
}
}
net_dev->ib.modify = 0;
return;
} else {
/*
* packet was 'in order' .. push it higher
*/
struct sqqueue *q;
net_dev->ib.next_num = sqno_end + 1;
isdn_ppp_push_higher(net_dev, lp, skb, -1);
/*
* check queue, whether we have still buffered the next packet(s)
*/
while ((q = net_dev->ib.sq) && q->sqno_start == net_dev->ib.next_num) {
isdn_ppp_push_higher(net_dev, lp, q->skb, -1);
net_dev->ib.sq = q->next;
net_dev->ib.next_num = q->sqno_end + 1;
kfree(q);
}
}
isdn_ppp_cleanup_sqqueue(net_dev,lp,min_sqno);
net_dev->ib.modify = 0;
} else
@ -921,6 +940,27 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
isdn_ppp_push_higher(net_dev, lp, skb , -1);
}
/*
* check sq-queue, whether we have still buffered the next packet(s)
* 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)
{
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);
slhc_toss(ippp_table[net_dev->local.ppp_slot]->slcomp);
}
isdn_ppp_push_higher(net_dev, lp, q->skb, -1);
net_dev->ib.sq = q->next;
net_dev->ib.next_num = q->sqno_end + 1;
kfree(q);
}
}
/*
* push frame to higher layers
@ -941,8 +981,10 @@ static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, stru
}
}
if(is->debug & 0x10)
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);
}
switch (proto) {
case PPP_IPX: /* untested */
@ -1021,10 +1063,8 @@ static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, stru
netif_rx(skb);
/* net_dev->local.stats.rx_packets++; */ /* done in isdn_net.c */
/* Reset hangup-timer */
if (proto != PPP_LCP)
lp->huptimer = 0;
lp->huptimer = 0;
return;
}
@ -1058,24 +1098,55 @@ int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
int proto = PPP_IP; /* 0x21 */
struct ippp_struct *ipt,*ipts;
if(mdev)
mlp = (isdn_net_local *) (mdev->priv);
else
else {
mdev = dev;
mlp = (isdn_net_local *) (dev->priv);
}
nd = mlp->netdev; /* get master lp */
ipts = ippp_table[mlp->ppp_slot];
if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
#ifdef ISDN_SYNCPPP_READDRESS
if(!ipts->old_pa_addr)
ipts->old_pa_addr = mdev->pa_addr;
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;
}
}
skb->destructor = NULL;
switch(ntohs(skb->protocol)) {
case ETH_P_IP:
proto = PPP_IP;
#ifdef ISDN_SYNCPPP_READDRESS
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);
ipfr->saddr = mdev->pa_addr;
}
}
}
/* dstaddr change not so improtant */
#endif
break;
case ETH_P_IPX:
proto = PPP_IPX; /* untested */
break;
}
lp = nd->queue; /* get lp on top of queue */
if(lp->sav_skb) { /* find a non-busy device */
@ -1099,7 +1170,7 @@ int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
printk(KERN_DEBUG "xmit skb, len %ld\n",skb->len);
#ifdef CONFIG_ISDN_PPP_VJ
if (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 this check again */
struct sk_buff *new_skb;
new_skb = dev_alloc_skb(skb->len);
@ -1171,6 +1242,12 @@ int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
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);
@ -1269,7 +1346,7 @@ static void isdn_ppp_mask_queue(isdn_net_dev * dev, long mask)
}
static int isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff ** skb, int BEbyte, int *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;
@ -1281,7 +1358,7 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff ** skb, int
printk(KERN_WARNING "isdn_ppp_fill_mpqueue: Can't alloc struct memory.\n");
save_flags(flags);
cli();
isdn_ppp_cleanup_queue(dev, min_sqno);
isdn_ppp_cleanup_mpqueue(dev, min_sqno);
restore_flags(flags);
return -1;
}
@ -1297,7 +1374,7 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff ** skb, int
dev->mp_last = q1;
q1->next = NULL;
q1->last = NULL;
isdn_ppp_cleanup_queue(dev, min_sqno); /* not necessary */
isdn_ppp_cleanup_mpqueue(dev, min_sqno); /* not necessary */
restore_flags(flags);
return -1;
}
@ -1331,7 +1408,7 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff ** skb, int
while (!(q->BEbyte & MP_END_FRAG)) {
cnt++;
if (!(q->next) || q->next->sqno != cnt) {
isdn_ppp_cleanup_queue(dev, min_sqno);
isdn_ppp_cleanup_mpqueue(dev, min_sqno);
restore_flags(flags);
return -1;
}
@ -1346,7 +1423,7 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff ** skb, int
while (!(q->BEbyte & MP_BEGIN_FRAG)) {
cnt--;
if (!(q->last) || q->last->sqno != cnt) {
isdn_ppp_cleanup_queue(dev, min_sqno);
isdn_ppp_cleanup_mpqueue(dev, min_sqno);
restore_flags(flags);
return -1;
}
@ -1366,7 +1443,7 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff ** skb, int
sqno_end = qe->sqno;
*sqnop = q->sqno;
isdn_ppp_cleanup_queue(dev, min_sqno);
isdn_ppp_cleanup_mpqueue(dev, min_sqno);
restore_flags(flags);
*skb = dev_alloc_skb(pktlen + 40); /* not needed: +40 for VJ compression .. */
@ -1400,7 +1477,7 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev * dev, struct sk_buff ** skb, int
* remove stale packets from list
*/
static void isdn_ppp_cleanup_queue(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;
@ -1457,9 +1534,9 @@ void isdn_ppp_timer_timeout(void)
while (net_dev) {
isdn_net_local *lp = &net_dev->local;
if (net_dev->ib.modify || lp->master) { /* interface locked or slave?*/
net_dev = net_dev->next;
net_dev = net_dev->next;
continue;
}
}
q = net_dev->ib.sq;
while (q) {