From 83fd84ce1e12e3e2770a68047fc4bc95657a6dc9 Mon Sep 17 00:00:00 2001 From: Kai Germaschewski Date: Wed, 16 Oct 2002 01:06:24 -0500 Subject: ISDN: new xmit handling for ISDN net interfaces Instead of using locking per-channel, just lock the entire ISDN net work interface as an entity, getting rid of weird locking. Basically, ::hard_start_xmit() is already serialized by the network core, so we could just rely on that. However, we want to send keep alive frames, PPP messages from ipppd and such things directly without going through the network stack, so we additionally lock isdn_net_local->xmit_lock in hard_start_xmit(), which is taken in the other paths dealing with transmitting frames as well. --- include/linux/isdn.h | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/linux/isdn.h b/include/linux/isdn.h index 8203314e2cb7..6266234c3644 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -338,10 +338,18 @@ typedef struct isdn_net_local_s { /* phone[0] = Incoming Numbers */ /* phone[1] = Outgoing Numbers */ - struct list_head slaves; /* list of all bundled channels */ - struct list_head online; /* list of all bundled channels, - which are currently online */ - spinlock_t online_lock; /* lock to protect online list */ + struct list_head slaves; /* list of all bundled channels + protected by serializing config + ioctls / no change allowed when + interface is running */ + struct list_head online; /* circular list of all bundled + channels, which are currently + online + protected by xmit_lock */ + + spinlock_t xmit_lock; /* used to protect the xmit path of + a net_device, including all + associated channels's frame_cnt */ struct list_head running_devs; /* member of global running_devs */ atomic_t refcnt; /* references held by ISDN code */ @@ -393,12 +401,9 @@ typedef struct isdn_net_dev_s { int pppbind; /* ippp device for bindings */ int ppp_slot; /* PPPD device slot number */ - spinlock_t xmit_lock; /* used to protect the xmit path of */ - /* a particular channel (including */ - /* the frame_cnt */ struct sk_buff_head super_tx_queue; /* List of supervisory frames to */ /* be transmitted asap */ - atomic_t frame_cnt; /* number of frames currently */ + int frame_cnt; /* number of frames currently */ /* queued in HL driver */ struct tasklet_struct tlet; -- cgit v1.2.3 From 8f7dcd21cdf133ce288b9b62761cb9fa49087a69 Mon Sep 17 00:00:00 2001 From: Kai Germaschewski Date: Wed, 16 Oct 2002 01:10:04 -0500 Subject: ISDN/PPP: Adapt sync-PPP Make sync PPP compile with the latest changes to the ISDN net device layer - PPP negotiations work again after this patch. --- drivers/isdn/i4l/isdn_net.h | 2 + drivers/isdn/i4l/isdn_net_lib.c | 20 +- drivers/isdn/i4l/isdn_ppp.c | 417 ++++++++++++++++++++------------------- drivers/isdn/isdnloop/isdnloop.c | 3 +- include/linux/isdn.h | 6 +- 5 files changed, 234 insertions(+), 214 deletions(-) (limited to 'include') diff --git a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h index 66b8bd092e4c..14f94befc91f 100644 --- a/drivers/isdn/i4l/isdn_net.h +++ b/drivers/isdn/i4l/isdn_net.h @@ -35,6 +35,8 @@ int isdn_net_hangup(isdn_net_dev *); int isdn_net_dial_req(isdn_net_dev *); void isdn_net_writebuf_skb(isdn_net_dev *, struct sk_buff *skb); void isdn_net_write_super(isdn_net_dev *, struct sk_buff *skb); +int isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev); +isdn_net_dev *isdn_net_get_xmit_dev(isdn_net_local *mlp); static inline int put_u8(unsigned char *p, u8 x) diff --git a/drivers/isdn/i4l/isdn_net_lib.c b/drivers/isdn/i4l/isdn_net_lib.c index aeda6e29af2a..e74f7c595f7d 100644 --- a/drivers/isdn/i4l/isdn_net_lib.c +++ b/drivers/isdn/i4l/isdn_net_lib.c @@ -221,7 +221,8 @@ isdn_net_set_encap(isdn_net_local *lp, int encap) if (lp->ops && lp->ops->cleanup) lp->ops->cleanup(lp); - if (encap < 0 || encap >= ISDN_NET_ENCAP_NR) { + if (encap < 0 || encap >= ISDN_NET_ENCAP_NR || + !isdn_netif_ops[encap]) { lp->p_encap = -1; lp->ops = NULL; retval = -EINVAL; @@ -1063,7 +1064,7 @@ isdn_net_open(struct net_device *dev) if (lp->ops->open) retval = lp->ops->open(lp); - if (!retval) + if (retval) return retval; netif_start_queue(dev); @@ -1079,7 +1080,6 @@ isdn_net_open(struct net_device *dev) /* * Shutdown a net-interface. */ -// FIXME share? static int isdn_net_close(struct net_device *dev) { @@ -1093,14 +1093,14 @@ isdn_net_close(struct net_device *dev) netif_stop_queue(dev); - list_for_each_safe(l, n, &lp->online) { - sdev = list_entry(l, isdn_net_dev, online); + list_for_each_safe(l, n, &lp->slaves) { + sdev = list_entry(l, isdn_net_dev, slaves); isdn_net_hangup(sdev); } /* The hangup will make the refcnt drop back to * 1 (referenced by list only) soon. */ spin_lock_irqsave(&running_devs_lock, flags); - while (atomic_read(&dev->refcnt) != 1) { + while (atomic_read(&lp->refcnt) != 1) { spin_unlock_irqrestore(&running_devs_lock, flags); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/10); @@ -1878,7 +1878,6 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) isdn_net_dev *idev = isdn_slot_idev(idx); if (!idev) { - HERE; return 0; } switch (c->command) { @@ -2018,8 +2017,9 @@ isdn_net_local_busy(isdn_net_local *mlp) /* * For the given net device, this will get a non-busy channel out of the * corresponding bundle. + * must hold mlp->xmit_lock */ -static inline isdn_net_dev * +isdn_net_dev * isdn_net_get_xmit_dev(isdn_net_local *mlp) { isdn_net_dev *idev; @@ -2041,7 +2041,7 @@ isdn_net_inc_frame_cnt(isdn_net_dev *idev) { isdn_net_local *mlp = idev->mlp; - if (isdn_net_local_busy(mlp)) + if (isdn_net_dev_busy(idev)) isdn_BUG(); idev->frame_cnt++; @@ -2060,7 +2060,7 @@ isdn_net_dec_frame_cnt(isdn_net_dev *idev) idev->frame_cnt--; - if (isdn_net_local_busy(mlp)) + if (isdn_net_dev_busy(idev)) isdn_BUG(); if (!was_busy) diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 3c59a373459b..030886f28b97 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -22,7 +22,7 @@ /* Prototypes */ 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_closewait(isdn_net_dev *idev); static void isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, struct sk_buff *skb, int proto); static int isdn_ppp_if_get_unit(char *namebuf); @@ -69,7 +69,21 @@ static int isdn_ppp_bundle(struct ippp_struct *, int unit); char *isdn_ppp_revision = "$Revision: 1.85.6.9 $"; -static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; +#define NR_IPPPDS 64 + +static spinlock_t ipppds_lock = SPIN_LOCK_UNLOCKED; +static struct ippp_struct *ipppds[NR_IPPPDS]; + +static inline struct ippp_struct * +ipppd_get(int slot) +{ + return ipppds[slot]; +} + +static inline void +ipppd_put(struct ippp_struct *ipppd) +{ +} static struct isdn_ppp_compressor *ipc_head = NULL; @@ -104,6 +118,8 @@ isdn_ppp_free(isdn_net_dev *idev) { unsigned long flags; struct ippp_struct *is; + + // FIXME much of this wants to rather happen when disconnected() if (idev->ppp_slot < 0 || idev->ppp_slot > ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: ppp_slot(%d) out of range\n", @@ -117,7 +133,6 @@ isdn_ppp_free(isdn_net_dev *idev) #ifdef CONFIG_ISDN_MPP spin_lock(&idev->pb->lock); #endif - isdn_net_rm_from_bundle(idev); #ifdef CONFIG_ISDN_MPP if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */ isdn_ppp_mp_cleanup(lp); @@ -131,9 +146,12 @@ isdn_ppp_free(isdn_net_dev *idev) restore_flags(flags); return; } - is = ippp_table[idev->ppp_slot]; - if ((is->state & IPPP_CONNECT)) - isdn_ppp_closewait(idev->ppp_slot); /* force wakeup on ippp device */ + is = ipppd_get(idev->ppp_slot); + if (!is) + return; + + if (is->state & IPPP_CONNECT) + isdn_ppp_closewait(idev); /* force wakeup on ippp device */ else if (is->state & IPPP_ASSIGNED) is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGNED' state */ @@ -142,6 +160,7 @@ isdn_ppp_free(isdn_net_dev *idev) is->idev = NULL; /* link is down .. set lp to NULL */ idev->ppp_slot = -1; /* is this OK ?? */ + ipppd_put(is); restore_flags(flags); return; @@ -155,12 +174,10 @@ isdn_ppp_bind(isdn_net_dev *idev) { int i; int unit = 0; - long flags; - struct ippp_struct *is; - int retval; + unsigned long flags; + int retval = 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&ipppds_lock, flags); if (idev->pppbind < 0) { /* device bound to ippp device ? */ struct list_head *l; char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */ @@ -174,47 +191,53 @@ isdn_ppp_bind(isdn_net_dev *idev) /* * 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! */ + for (i = 0; i < NR_IPPPDS; i++) { + if (!ipppds[i]) + continue; + if (ipppds[i]->state != IPPP_OPEN) + continue; + if (!exclusive[ipppds[i]->minor]) break; - } + break; } } else { - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (ippp_table[i]->minor == idev->pppbind && - (ippp_table[i]->state & IPPP_OPEN) == IPPP_OPEN) + for (i = 0; i < NR_IPPPDS; i++) { + if (!ipppds[i]) + continue; + if (ipppds[i]->state != IPPP_OPEN) + continue; + if (ipppds[i]->minor == idev->pppbind) break; } } - if (i >= ISDN_MAX_CHANNELS) { - restore_flags(flags); - printk(KERN_WARNING "isdn_ppp_bind: Can't find a (free) connection to the ipppd daemon.\n"); - retval = -1; - goto out; + if (i >= NR_IPPPDS) { + printk(KERN_INFO "isdn_ppp_bind: no ipppd\n"); + retval = -ESRCH; + goto err; } unit = isdn_ppp_if_get_unit(idev->name); /* get unit number from interface name .. ugly! */ if (unit < 0) { - printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", idev->name); - retval = -1; - goto out; + printk(KERN_INFO "isdn_ppp_bind: illegal interface name %s.\n", idev->name); + retval = -ENODEV; + goto err; } idev->ppp_slot = i; - is = ippp_table[i]; - is->idev = idev; - is->unit = unit; - is->state = IPPP_OPEN | IPPP_ASSIGNED; /* assigned to a netdevice but not connected */ + ipppds[i]->idev = idev; + ipppds[i]->unit = unit; + ipppds[i]->state = IPPP_OPEN | IPPP_ASSIGNED; /* assigned to a netdevice but not connected */ + + spin_unlock_irqrestore(&ipppds_lock, flags); + #ifdef CONFIG_ISDN_MPP retval = isdn_ppp_mp_init(lp, NULL); - if (retval < 0) - goto out; + // FIXME unwind? #endif /* CONFIG_ISDN_MPP */ + return retval; - retval = idev->ppp_slot; - - out: - restore_flags(flags); + err: + spin_unlock_irqrestore(&ipppds_lock, flags); return retval; } @@ -226,13 +249,14 @@ isdn_ppp_bind(isdn_net_dev *idev) static void isdn_ppp_wakeup_daemon(isdn_net_dev *idev) { - if (idev->ppp_slot < 0 || idev->ppp_slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: ppp_slot(%d) out of range\n", - __FUNCTION__, idev->ppp_slot); + struct ippp_struct *ipppd = ipppd_get(idev->ppp_slot); + + if (!ipppd) return; - } - ippp_table[idev->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK; - wake_up_interruptible(&ippp_table[idev->ppp_slot]->wq); + + ipppd->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK; + wake_up(&ipppd->wq); + ipppd_put(ipppd); } /* @@ -240,36 +264,38 @@ isdn_ppp_wakeup_daemon(isdn_net_dev *idev) * force wakeup of the ippp device * go into 'device waits for release' state */ -static int -isdn_ppp_closewait(int slot) +static void +isdn_ppp_closewait(isdn_net_dev *idev) { - struct ippp_struct *is; + struct ippp_struct *ipppd = ipppd_get(idev->ppp_slot); - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: slot(%d) out of range\n", - __FUNCTION__ , slot); - return 0; - } - is = ippp_table[slot]; - if (is->state) - wake_up_interruptible(&is->wq); - is->state = IPPP_CLOSEWAIT; - return 1; + if (!ipppd) + return; + + wake_up(&ipppd->wq); + ipppd->state = IPPP_CLOSEWAIT; + ipppd_put(ipppd); } /* - * isdn_ppp_find_slot / isdn_ppp_free_slot + * isdn_ppp_get_slot */ static int isdn_ppp_get_slot(void) { int i; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (!ippp_table[i]->state) - return i; + unsigned long flags; + + spin_lock_irqsave(&ipppds_lock, flags); + for (i = 0; i < NR_IPPPDS; i++) { + if (ipppds[i]->state == 0) { + ipppds[i]->state = IPPP_OPEN; + break; + } } - return -1; + spin_unlock_irqrestore(&ipppds_lock, flags); + return (i < NR_IPPPDS) ? i : -1; } /* @@ -284,10 +310,11 @@ isdn_ppp_open(struct inode *ino, struct file *file) struct ippp_struct *is; slot = isdn_ppp_get_slot(); - if (slot < 0) { + if (slot < 0) return -EBUSY; - } - is = file->private_data = ippp_table[slot]; + + is = ipppds[slot]; + file->private_data = is; printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, minor, is->state); @@ -318,7 +345,6 @@ isdn_ppp_open(struct inode *ino, struct file *file) is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */ #endif - is->state = IPPP_OPEN; isdn_lock_drivers(); return 0; @@ -471,10 +497,9 @@ isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned return r; } if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) { - if (idev) { - /* OK .. we are ready to send buffers */ - isdn_net_dev_wake_queue(idev); - } + if (idev) + /* OK .. we are ready to send buffers */ + isdn_net_online(idev); } is->pppcfg = val; break; @@ -628,25 +653,27 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot) struct sk_buff *skb; unsigned char *p; struct ippp_struct *is; + int retval; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot); - return 0; - } - is = ippp_table[slot]; + is = ipppd_get(slot); + if (!is) + return -ENODEV; if (!(is->state & IPPP_CONNECT)) { printk(KERN_DEBUG "ippp: device not activated.\n"); - return 0; + retval = -ENOTCONN; + goto out; } if (skb_queue_len(&is->rq) > IPPP_MAX_RQ_LEN) { printk(KERN_WARNING "ippp: Queue is full\n"); - return 0; + retval = -EBUSY; + goto out; } skb = dev_alloc_skb(len + 4); if (!skb) { printk(KERN_WARNING "ippp: Can't alloc buf\n"); - return 0; + retval = -ENOMEM; + goto out; } p = skb_put(skb, 4); p += put_u8(p, PPP_ALLSTATIONS); @@ -655,9 +682,12 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot) memcpy(skb_put(skb, len), buf, len); skb_queue_tail(&is->rq, skb); - wake_up_interruptible(&is->wq); + wake_up(&is->wq); - return len; + retval = len; + out: + ipppd_put(is); + return retval; } /* @@ -749,8 +779,7 @@ isdn_ppp_write(struct file *file, const char *buf, size_t count, loff_t *off) retval = 0; goto out; } - if ((dev->drv[isdn_slot_driver(idev->isdn_slot)]->flags & DRV_FLAG_RUNNING) && - isdn_net_online(idev)) { + if ((dev->drv[isdn_slot_driver(idev->isdn_slot)]->flags & DRV_FLAG_RUNNING)) { unsigned short hl; struct sk_buff *skb; /* @@ -808,25 +837,24 @@ struct file_operations isdn_ppp_fops = int isdn_ppp_init(void) { - int i, - j; + int i; #ifdef CONFIG_ISDN_MPP if( isdn_ppp_mp_bundle_array_init() < 0 ) return -ENOMEM; #endif /* CONFIG_ISDN_MPP */ - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (!(ippp_table[i] = (struct ippp_struct *) - kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) { + for (i = 0; i < NR_IPPPDS; i++) { + ipppds[i] = kmalloc(sizeof(struct ippp_struct), GFP_KERNEL); + if (!ipppds[i]) { printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n"); - for (j = 0; j < i; j++) - kfree(ippp_table[j]); - return -1; + for (i--; i >= 0; i++) + kfree(ipppds[i]); + return -ENOMEM; } - memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct)); - ippp_table[i]->state = 0; - skb_queue_head_init(&ippp_table[i]->rq); + memset(ipppds[i], 0, sizeof(struct ippp_struct)); + ipppds[i]->state = 0; + skb_queue_head_init(&ipppds[i]->rq); } return 0; } @@ -836,8 +864,8 @@ isdn_ppp_cleanup(void) { int i; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - kfree(ippp_table[i]); + for (i = 0; i < NR_IPPPDS; i++) + kfree(ipppds[i]); #ifdef CONFIG_ISDN_MPP if (isdn_ppp_bundle_arr) @@ -904,7 +932,6 @@ static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev, struct sk_buff *skb) { struct ippp_struct *is; - int slot; int proto; /* @@ -914,14 +941,9 @@ static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev, if (PPP_PROTOCOL(skb->data) != PPP_LCP) idev->huptimer = 0; - slot = idev->ppp_slot; - if (slot < 0 || slot > ISDN_MAX_CHANNELS) { - printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n", - slot); - kfree_skb(skb); - return; - } - is = ippp_table[slot]; + is = ipppd_get(idev->ppp_slot); + if (!is) + goto err; if (is->debug & 0x4) { printk(KERN_DEBUG "ippp_receive: is:%p lp:%p slot:%d unit:%d len:%d\n", @@ -929,31 +951,38 @@ static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev, isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,idev->ppp_slot); } - if (isdn_ppp_skip_ac(is, skb) < 0) { - kfree_skb(skb); - return; - } + if (isdn_ppp_skip_ac(is, skb) < 0) + goto err_put; + proto = isdn_ppp_strip_proto(skb); - if (proto < 0) { - kfree_skb(skb); - return; - } + if (proto < 0) + goto err_put; #ifdef CONFIG_ISDN_MPP if (is->compflags & SC_LINK_DECOMP_ON) { skb = isdn_ppp_decompress(skb, is, NULL, &proto); if (!skb) // decompression error - return; + goto put; } if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP if (proto == PPP_MP) { isdn_ppp_mp_receive(lp, idev, skb); - return; + goto put; } } -#endif isdn_ppp_push_higher(lp, idev, skb, proto); + put: +#else + isdn_ppp_push_higher(lp, idev, skb, proto); +#endif + ipppd_put(is); + return; + + err_put: + ipppd_put(is); + err: + kfree_skb(skb); } /* @@ -966,27 +995,20 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, struct sk_buff *skb, int proto) { struct net_device *dev = &lp->dev; - struct ippp_struct *is, *mis; - int slot; + struct ippp_struct *is; - slot = idev->ppp_slot; - if (slot < 0 || slot > ISDN_MAX_CHANNELS) { - printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n", - slot); - goto drop_packet; - } - is = ippp_table[slot]; + is = ipppd_get(idev->ppp_slot); + if (!is) + goto drop; - 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,slot); + isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit, idev->ppp_slot); } - if (mis->compflags & SC_DECOMP_ON) { - skb = isdn_ppp_decompress(skb, is, mis, &proto); + if (is->compflags & SC_DECOMP_ON) { + skb = isdn_ppp_decompress(skb, is, is, &proto); if (!skb) // decompression error - return; + goto put; } switch (proto) { case PPP_IPX: /* untested */ @@ -1002,19 +1024,14 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, case PPP_COMP: case PPP_COMPFRAG: printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n"); - goto drop_packet; + goto drop_put; #ifdef CONFIG_ISDN_PPP_VJ case PPP_VJC_UNCOMP: if (is->debug & 0x20) printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n"); - if (idev->ppp_slot < 0) { - printk(KERN_ERR "%s: net_dev->ppp_slot(%d) out of range\n", - __FUNCTION__ , idev->ppp_slot); - goto drop_packet; - } - if (slhc_remember(ippp_table[idev->ppp_slot]->slcomp, skb->data, skb->len) <= 0) { + if (slhc_remember(is->slcomp, skb->data, skb->len) <= 0) { printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n"); - goto drop_packet; + goto drop_put; } skb->protocol = htons(ETH_P_IP); break; @@ -1029,20 +1046,15 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, if (!skb) { printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); skb = skb_old; - goto drop_packet; + goto drop_put; } skb_put(skb, skb_old->len + 128); memcpy(skb->data, skb_old->data, skb_old->len); - if (idev->ppp_slot < 0) { - printk(KERN_ERR "%s: net_dev->ppp_slot(%d) out of range\n", - __FUNCTION__ , idev->ppp_slot); - goto drop_packet; - } - pkt_len = slhc_uncompress(ippp_table[idev->ppp_slot]->slcomp, + pkt_len = slhc_uncompress(is->slcomp, skb->data, skb_old->len); kfree_skb(skb_old); if (pkt_len < 0) - goto drop_packet; + goto drop_put; skb_trim(skb, pkt_len); skb->protocol = htons(ETH_P_IP); @@ -1071,9 +1083,13 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, skb->mac.raw = skb->data; netif_rx(skb); /* net_dev->local->stats.rx_packets++; done in isdn_net.c */ + put: + ipppd_put(is); return; - drop_packet: + drop_put: + ipppd_put(is); + drop: lp->stats.rx_dropped++; kfree_skb(skb); } @@ -1119,27 +1135,21 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) isdn_net_dev *idev = list_entry(mlp->online.next, isdn_net_dev, online); unsigned int proto = PPP_IP; /* 0x21 */ struct ippp_struct *ipt,*ipts; - int slot; ndev->trans_start = jiffies; if (list_empty(&mlp->online)) return isdn_net_autodial(skb, ndev); - slot = idev->ppp_slot; - if (slot < 0 || slot > ISDN_MAX_CHANNELS) { - printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n", - slot); - kfree_skb(skb); - return 0; + ipts = ipppd_get(idev->ppp_slot); + if (!ipts) { + isdn_BUG(); + goto err; } - ipts = ippp_table[slot]; - + if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ - if (ipts->debug & 0x1) - printk(KERN_INFO "%s: IP frame delayed.\n", ndev->name); - netif_stop_queue(ndev); - return 1; + printk(KERN_INFO "%s: IP frame delayed.\n", ndev->name); + goto err_put; } switch (ntohs(skb->protocol)) { @@ -1153,24 +1163,19 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n", skb->protocol); dev_kfree_skb(skb); - return 0; + goto put; } - idev = isdn_net_get_locked_dev(mlp); + idev = isdn_net_get_xmit_dev(mlp); if (!idev) { - printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name); - netif_stop_queue(ndev); - return 1; + isdn_BUG(); + goto err_put; } - /* we have our lp locked from now on */ - slot = idev->ppp_slot; - if (slot < 0 || slot > ISDN_MAX_CHANNELS) { - printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n", - slot); - kfree_skb(skb); - return 0; - } - ipt = ippp_table[slot]; + + ipt = ipppd_get(idev->ppp_slot); + if (!ipt) + goto put; + idev->huptimer = 0; /* @@ -1290,20 +1295,20 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) { unsigned char *data = isdn_ppp_skb_push(&skb,1); if(!data) - goto unlock; + goto put2; data[0] = proto & 0xff; } else { unsigned char *data = isdn_ppp_skb_push(&skb,2); if(!data) - goto unlock; + goto put2; 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) - goto unlock; + goto put2; data[0] = 0xff; /* All Stations */ data[1] = 0x03; /* Unnumbered information */ } @@ -1317,9 +1322,17 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) isdn_net_writebuf_skb(idev, skb); - unlock: - spin_unlock_bh(&idev->xmit_lock); + put2: + ipppd_put(ipt); + put: + ipppd_put(ipts); return 0; + + err_put: + ipppd_put(ipts); + err: + netif_stop_queue(ndev); + return 1; } #ifdef CONFIG_ISDN_MPP @@ -1806,8 +1819,8 @@ out: static int isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev) { - struct ppp_stats *res, - t; + struct ppp_stats *res, t; + struct ippp_struct *is; isdn_net_local *lp = (isdn_net_local *) dev->priv; int err; @@ -1828,16 +1841,20 @@ isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev) t.p.ppp_obytes = lp->stats.tx_bytes; t.p.ppp_oerrors = lp->stats.tx_errors; #ifdef CONFIG_ISDN_PPP_VJ - 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_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_uncompressedin = slcomp->sls_i_uncompressed; - t.vj.vjs_compressedin = slcomp->sls_i_compressed; + is = ipppd_get(slot); + if (is) { + struct slcompress *slcomp = is->slcomp; + if (slcomp) { + 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_uncompressedin = slcomp->sls_i_uncompressed; + t.vj.vjs_compressedin = slcomp->sls_i_compressed; + } + ipppd_put(is); } #endif } @@ -2458,12 +2475,11 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *idev, isdn_net_local *lp, printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n", idev->ppp_slot); - if (idev->ppp_slot < 0 || idev->ppp_slot > ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: ppp_slot(%d) out of range\n", - __FUNCTION__ , idev->ppp_slot); + + is = ipppd_get(idev->ppp_slot); + if (!is) return; - } - is = ippp_table[idev->ppp_slot]; + isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,idev->ppp_slot); mis = is; @@ -2586,6 +2602,7 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *idev, isdn_net_local *lp, } break; } + ipppd_put(is); } @@ -2618,17 +2635,16 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *idev, isdn_net_local *lp, static void isdn_ppp_send_ccp(isdn_net_dev *idev, isdn_net_local *lp, struct sk_buff *skb) { struct ippp_struct *mis,*is; - int proto, slot = idev->ppp_slot; + int proto; unsigned char *data; - if(!skb || skb->len < 3) + if (!skb || skb->len < 3) return; - if (slot < 0 || slot > ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", - __FUNCTION__ , slot); + + is = ipppd_get(idev->ppp_slot); + if (!is) return; - } - is = ippp_table[slot]; + /* Daemon may send with or without address and control field comp */ data = skb->data; if(!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) { @@ -2704,6 +2720,7 @@ static void isdn_ppp_send_ccp(isdn_net_dev *idev, isdn_net_local *lp, struct sk_ printk(KERN_DEBUG "ResetReq from daemon passed by\n"); break; } + ipppd_put(is); } int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc) diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c index e757d5063398..6f7f01cfb75f 100644 --- a/drivers/isdn/isdnloop/isdnloop.c +++ b/drivers/isdn/isdnloop/isdnloop.c @@ -11,11 +11,12 @@ #include #include +#include #include #include "isdnloop.h" static char *revision = "$Revision: 1.11.6.7 $"; -static char *isdnloop_id; +static char *isdnloop_id = "loop0"; MODULE_DESCRIPTION("ISDN4Linux: Pseudo Driver that simulates an ISDN card"); MODULE_AUTHOR("Fritz Elfert"); diff --git a/include/linux/isdn.h b/include/linux/isdn.h index 6266234c3644..95352ab33f37 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -342,9 +342,9 @@ typedef struct isdn_net_local_s { protected by serializing config ioctls / no change allowed when interface is running */ - struct list_head online; /* circular list of all bundled - channels, which are currently - online + struct list_head online; /* list of all bundled channels + which can be used for actual + data (IP) transfer protected by xmit_lock */ spinlock_t xmit_lock; /* used to protect the xmit path of -- cgit v1.2.3 From b449f5b2346efaa7f033dfd3ef8e66909a655794 Mon Sep 17 00:00:00 2001 From: Kai Germaschewski Date: Wed, 16 Oct 2002 01:11:11 -0500 Subject: ISDN/PPP: Rename struct 'ippp_struct' to 'struct ipppd' and move the declaration from include/linux/isdn_ppp.h into drivers/isdn/i4l/isdn_ppp.c --- drivers/isdn/i4l/isdn_ppp.c | 130 +++++++++++++++++++++++++++----------------- include/linux/isdn_ppp.h | 31 +---------- 2 files changed, 80 insertions(+), 81 deletions(-) (limited to 'include') diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 030886f28b97..3e695459f7a6 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -20,37 +20,65 @@ #include "isdn_ppp.h" #include "isdn_net.h" +struct ipppd { + int state; + struct sk_buff_head rq; + wait_queue_head_t wq; + struct task_struct *tk; + unsigned int mpppcfg; + unsigned int pppcfg; + unsigned int mru; + unsigned int mpmru; + unsigned int mpmtu; + unsigned int maxcid; + struct isdn_net_dev_s *idev; + int unit; + int minor; + unsigned int last_link_seqno; + long mp_seqno; +#ifdef CONFIG_ISDN_PPP_VJ + unsigned char *cbuf; + struct slcompress *slcomp; +#endif + unsigned long debug; + struct isdn_ppp_compressor *compressor,*decompressor; + struct isdn_ppp_compressor *link_compressor,*link_decompressor; + void *decomp_stat,*comp_stat,*link_decomp_stat,*link_comp_stat; + struct ippp_ccp_reset *reset; /* Allocated on demand, may never be needed */ + unsigned long compflags; +}; + /* Prototypes */ static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot); static void isdn_ppp_closewait(isdn_net_dev *idev); static void isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, 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,struct isdn_ppp_comp_data *); +static int isdn_ppp_set_compressor(struct ipppd *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 ipppd *,struct ipppd *,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, - struct ippp_struct *is,struct ippp_struct *master,int type); + struct ipppd *is,struct ipppd *master,int type); static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb); /* New CCP stuff */ -static void isdn_ppp_ccp_kickup(struct ippp_struct *is); -static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto, +static void isdn_ppp_ccp_kickup(struct ipppd *is); +static void isdn_ppp_ccp_xmit_reset(struct ipppd *is, int proto, unsigned char code, unsigned char id, unsigned char *data, int len); -static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is); -static void isdn_ppp_ccp_reset_free(struct ippp_struct *is); -static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is, +static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ipppd *is); +static void isdn_ppp_ccp_reset_free(struct ipppd *is); +static void isdn_ppp_ccp_reset_free_state(struct ipppd *is, unsigned char id); static void isdn_ppp_ccp_timer_callback(unsigned long closure); -static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is, +static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ipppd *is, unsigned char id); -static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is, +static void isdn_ppp_ccp_reset_trans(struct ipppd *is, struct isdn_ppp_resetparams *rp); -static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is, +static void isdn_ppp_ccp_reset_ack_rcvd(struct ipppd *is, unsigned char id); @@ -64,7 +92,7 @@ static void isdn_ppp_mp_receive(isdn_net_local *lp, isdn_net_dev *idev, struct sk_buff *skb); static void isdn_ppp_mp_cleanup(isdn_net_local *lp ); -static int isdn_ppp_bundle(struct ippp_struct *, int unit); +static int isdn_ppp_bundle(struct ipppd *, int unit); #endif /* CONFIG_ISDN_MPP */ char *isdn_ppp_revision = "$Revision: 1.85.6.9 $"; @@ -72,16 +100,16 @@ char *isdn_ppp_revision = "$Revision: 1.85.6.9 $"; #define NR_IPPPDS 64 static spinlock_t ipppds_lock = SPIN_LOCK_UNLOCKED; -static struct ippp_struct *ipppds[NR_IPPPDS]; +static struct ipppd *ipppds[NR_IPPPDS]; -static inline struct ippp_struct * +static inline struct ipppd * ipppd_get(int slot) { return ipppds[slot]; } static inline void -ipppd_put(struct ippp_struct *ipppd) +ipppd_put(struct ipppd *ipppd) { } @@ -117,7 +145,7 @@ static void isdn_ppp_free(isdn_net_dev *idev) { unsigned long flags; - struct ippp_struct *is; + struct ipppd *is; // FIXME much of this wants to rather happen when disconnected() @@ -249,7 +277,7 @@ isdn_ppp_bind(isdn_net_dev *idev) static void isdn_ppp_wakeup_daemon(isdn_net_dev *idev) { - struct ippp_struct *ipppd = ipppd_get(idev->ppp_slot); + struct ipppd *ipppd = ipppd_get(idev->ppp_slot); if (!ipppd) return; @@ -267,7 +295,7 @@ isdn_ppp_wakeup_daemon(isdn_net_dev *idev) static void isdn_ppp_closewait(isdn_net_dev *idev) { - struct ippp_struct *ipppd = ipppd_get(idev->ppp_slot); + struct ipppd *ipppd = ipppd_get(idev->ppp_slot); if (!ipppd) return; @@ -307,7 +335,7 @@ isdn_ppp_open(struct inode *ino, struct file *file) { uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP; int slot; - struct ippp_struct *is; + struct ipppd *is; slot = isdn_ppp_get_slot(); if (slot < 0) @@ -357,7 +385,7 @@ static int isdn_ppp_release(struct inode *ino, struct file *file) { uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP; - struct ippp_struct *is; + struct ipppd *is; lock_kernel(); @@ -443,10 +471,10 @@ isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned isdn_net_dev *idev; unsigned long val; int r,i,j; - struct ippp_struct *is; + struct ipppd *is; struct isdn_ppp_comp_data data; - is = (struct ippp_struct *) file->private_data; + is = (struct ipppd *) file->private_data; idev = is->idev; if (is->debug & 0x1) @@ -608,7 +636,7 @@ static unsigned int isdn_ppp_poll(struct file *file, poll_table * wait) { unsigned int mask; - struct ippp_struct *is; + struct ipppd *is; is = file->private_data; @@ -652,7 +680,7 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot) { struct sk_buff *skb; unsigned char *p; - struct ippp_struct *is; + struct ipppd *is; int retval; is = ipppd_get(slot); @@ -698,7 +726,7 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot) static ssize_t isdn_ppp_read(struct file *file, char *buf, size_t count, loff_t *off) { - struct ippp_struct *is; + struct ipppd *is; struct sk_buff *skb; int retval; @@ -740,7 +768,7 @@ static ssize_t isdn_ppp_write(struct file *file, const char *buf, size_t count, loff_t *off) { isdn_net_dev *idev; - struct ippp_struct *is; + struct ipppd *is; int proto; unsigned char protobuf[4]; int retval; @@ -845,14 +873,14 @@ isdn_ppp_init(void) #endif /* CONFIG_ISDN_MPP */ for (i = 0; i < NR_IPPPDS; i++) { - ipppds[i] = kmalloc(sizeof(struct ippp_struct), GFP_KERNEL); + ipppds[i] = kmalloc(sizeof(struct ipppd), GFP_KERNEL); if (!ipppds[i]) { printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n"); for (i--; i >= 0; i++) kfree(ipppds[i]); return -ENOMEM; } - memset(ipppds[i], 0, sizeof(struct ippp_struct)); + memset(ipppds[i], 0, sizeof(struct ipppd)); ipppds[i]->state = 0; skb_queue_head_init(&ipppds[i]->rq); } @@ -878,7 +906,7 @@ isdn_ppp_cleanup(void) * 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) +static int isdn_ppp_skip_ac(struct ipppd *is, struct sk_buff *skb) { if (skb->len < 1) return -1; @@ -931,7 +959,7 @@ static int isdn_ppp_strip_proto(struct sk_buff *skb) static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev, struct sk_buff *skb) { - struct ippp_struct *is; + struct ipppd *is; int proto; /* @@ -995,7 +1023,7 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, struct sk_buff *skb, int proto) { struct net_device *dev = &lp->dev; - struct ippp_struct *is; + struct ipppd *is; is = ipppd_get(idev->ppp_slot); if (!is) @@ -1134,7 +1162,7 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) isdn_net_local *mlp = ndev->priv; isdn_net_dev *idev = list_entry(mlp->online.next, isdn_net_dev, online); unsigned int proto = PPP_IP; /* 0x21 */ - struct ippp_struct *ipt,*ipts; + struct ipppd *ipt,*ipts; ndev->trans_start = jiffies; @@ -1385,7 +1413,7 @@ static ippp_bundle * isdn_ppp_mp_bundle_alloc(void) static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to ) { isdn_net_dev *idev = lp->netdev; - struct ippp_struct * is; + struct ipppd * is; if (idev->ppp_slot < 0) { printk(KERN_ERR "%s: >ppp_slot(%d) out of range\n", @@ -1426,7 +1454,7 @@ static void isdn_ppp_mp_receive(isdn_net_local *lp, isdn_net_dev *dev, struct sk_buff *skb) { isdn_net_dev *idev = lp->netdev; - struct ippp_struct *is; + struct ipppd *is; isdn_net_dev *qdev; ippp_bundle * mp; isdn_mppp_stats * stats; @@ -1767,7 +1795,7 @@ static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb ) } static int -isdn_ppp_bundle(struct ippp_struct *is, int unit) +isdn_ppp_bundle(struct ipppd *is, int unit) { char ifn[IFNAMSIZ + 1]; isdn_net_dev *p; @@ -1820,7 +1848,7 @@ static int isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev) { struct ppp_stats *res, t; - struct ippp_struct *is; + struct ipppd *is; isdn_net_local *lp = (isdn_net_local *) dev->priv; int err; @@ -1979,7 +2007,7 @@ isdn_ppp_hangup_slave(char *name) /* Push an empty CCP Data Frame up to the daemon to wake it up and let it generate a CCP Reset-Request or tear down CCP altogether */ -static void isdn_ppp_ccp_kickup(struct ippp_struct *is) +static void isdn_ppp_ccp_kickup(struct ipppd *is) { isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->idev->ppp_slot); } @@ -2019,7 +2047,7 @@ static void isdn_ppp_ccp_kickup(struct ippp_struct *is) function above but every wrapper does a bit different. Hope I guess correct in this hack... */ -static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto, +static void isdn_ppp_ccp_xmit_reset(struct ipppd *is, int proto, unsigned char code, unsigned char id, unsigned char *data, int len) { @@ -2070,7 +2098,7 @@ static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto, } /* Allocate the reset state vector */ -static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is) +static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ipppd *is) { struct ippp_ccp_reset *r; r = kmalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL); @@ -2086,7 +2114,7 @@ static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is) } /* Destroy the reset state vector. Kill all pending timers first. */ -static void isdn_ppp_ccp_reset_free(struct ippp_struct *is) +static void isdn_ppp_ccp_reset_free(struct ipppd *is) { unsigned int id; @@ -2102,7 +2130,7 @@ static void isdn_ppp_ccp_reset_free(struct ippp_struct *is) } /* Free a given state and clear everything up for later reallocation */ -static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is, +static void isdn_ppp_ccp_reset_free_state(struct ipppd *is, unsigned char id) { struct ippp_ccp_reset_state *rs; @@ -2156,7 +2184,7 @@ static void isdn_ppp_ccp_timer_callback(unsigned long closure) } /* Allocate a new reset transaction state */ -static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is, +static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ipppd *is, unsigned char id) { struct ippp_ccp_reset_state *rs; @@ -2182,7 +2210,7 @@ static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_s /* A decompressor wants a reset with a set of parameters - do what is necessary to fulfill it */ -static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is, +static void isdn_ppp_ccp_reset_trans(struct ipppd *is, struct isdn_ppp_resetparams *rp) { struct ippp_ccp_reset_state *rs; @@ -2285,7 +2313,7 @@ static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is, /* An Ack was received for this id. This means we stop the timer and clean up the state prior to calling the decompressors reset routine. */ -static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is, +static void isdn_ppp_ccp_reset_ack_rcvd(struct ipppd *is, unsigned char id) { struct ippp_ccp_reset_state *rs = is->reset->rs[id]; @@ -2325,14 +2353,14 @@ static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is, * NULL if decompression error */ -static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master, +static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ipppd *is,struct ipppd *master, int *proto) { void *stat = NULL; struct isdn_ppp_compressor *ipc = NULL; struct sk_buff *skb_out; int len; - struct ippp_struct *ri; + struct ipppd *ri; struct isdn_ppp_resetparams rsparm; unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; @@ -2405,7 +2433,7 @@ static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struc * 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) + struct ipppd *is,struct ipppd *master,int type) { int ret; int new_proto; @@ -2467,8 +2495,8 @@ static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto, static void isdn_ppp_receive_ccp(isdn_net_dev *idev, isdn_net_local *lp, struct sk_buff *skb,int proto) { - struct ippp_struct *is; - struct ippp_struct *mis; + struct ipppd *is; + struct ipppd *mis; int len; struct isdn_ppp_resetparams rsparm; unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; @@ -2634,7 +2662,7 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *idev, isdn_net_local *lp, static void isdn_ppp_send_ccp(isdn_net_dev *idev, isdn_net_local *lp, struct sk_buff *skb) { - struct ippp_struct *mis,*is; + struct ipppd *mis,*is; int proto; unsigned char *data; @@ -2746,7 +2774,7 @@ int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc) return 0; } -static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *data) +static int isdn_ppp_set_compressor(struct ipppd *is, struct isdn_ppp_comp_data *data) { struct isdn_ppp_compressor *ipc = ipc_head; int ret; diff --git a/include/linux/isdn_ppp.h b/include/linux/isdn_ppp.h index 68353a39b98c..faf2b2c630b7 100644 --- a/include/linux/isdn_ppp.h +++ b/include/linux/isdn_ppp.h @@ -172,7 +172,7 @@ enum ippp_ccp_reset_states { struct ippp_ccp_reset_state { enum ippp_ccp_reset_states state; /* State of this transaction */ - struct ippp_struct *is; /* Backlink to device stuff */ + struct ipppd *is; /* Backlink to device stuff */ unsigned char id; /* Backlink id index */ unsigned char ta:1; /* The timer is active (flag) */ unsigned char expra:1; /* We expect a ResetAck at all */ @@ -191,34 +191,5 @@ struct ippp_ccp_reset { unsigned char lastid; /* Last id allocated by the engine */ }; -struct ippp_struct { - struct ippp_struct *next_link; - int state; - struct sk_buff_head rq; - wait_queue_head_t wq; - struct task_struct *tk; - unsigned int mpppcfg; - unsigned int pppcfg; - unsigned int mru; - unsigned int mpmru; - unsigned int mpmtu; - unsigned int maxcid; - struct isdn_net_dev_s *idev; - int unit; - int minor; - unsigned int last_link_seqno; - long mp_seqno; -#ifdef CONFIG_ISDN_PPP_VJ - unsigned char *cbuf; - struct slcompress *slcomp; -#endif - unsigned long debug; - struct isdn_ppp_compressor *compressor,*decompressor; - struct isdn_ppp_compressor *link_compressor,*link_decompressor; - void *decomp_stat,*comp_stat,*link_decomp_stat,*link_comp_stat; - struct ippp_ccp_reset *reset; /* Allocated on demand, may never be needed */ - unsigned long compflags; -}; - #endif /* __KERNEL__ */ #endif /* _LINUX_ISDN_PPP_H */ -- cgit v1.2.3 From 43db5879a4247bbbaff555dab2ea2e0a4f44da80 Mon Sep 17 00:00:00 2001 From: Kai Germaschewski Date: Wed, 16 Oct 2002 01:12:48 -0500 Subject: ISDN/PPP: Move state from ipppd to isdn_net_dev/isdn_net_local A lot of the state in struct ipppd actually belongs to isdn_net_dev or isdn_net_local, making it more easily accessible at a most places, and also removing the ambiguity whether it's link- or bundle-specific. --- drivers/isdn/i4l/isdn_net_lib.c | 1 + drivers/isdn/i4l/isdn_ppp.c | 749 +++++++++++++++++++++------------------- include/linux/isdn.h | 30 ++ include/linux/isdn_ppp.h | 6 +- 4 files changed, 435 insertions(+), 351 deletions(-) (limited to 'include') diff --git a/drivers/isdn/i4l/isdn_net_lib.c b/drivers/isdn/i4l/isdn_net_lib.c index e74f7c595f7d..08281c1faa3b 100644 --- a/drivers/isdn/i4l/isdn_net_lib.c +++ b/drivers/isdn/i4l/isdn_net_lib.c @@ -2093,6 +2093,7 @@ isdn_net_tasklet(unsigned long data) void isdn_net_online(isdn_net_dev *idev) { + // FIXME check we're connected isdn_net_local *mlp = idev->mlp; unsigned long flags; diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 3e695459f7a6..b84673e918c6 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -24,28 +24,10 @@ struct ipppd { int state; struct sk_buff_head rq; wait_queue_head_t wq; - struct task_struct *tk; - unsigned int mpppcfg; - unsigned int pppcfg; - unsigned int mru; - unsigned int mpmru; - unsigned int mpmtu; - unsigned int maxcid; struct isdn_net_dev_s *idev; int unit; int minor; - unsigned int last_link_seqno; - long mp_seqno; -#ifdef CONFIG_ISDN_PPP_VJ - unsigned char *cbuf; - struct slcompress *slcomp; -#endif unsigned long debug; - struct isdn_ppp_compressor *compressor,*decompressor; - struct isdn_ppp_compressor *link_compressor,*link_decompressor; - void *decomp_stat,*comp_stat,*link_decomp_stat,*link_comp_stat; - struct ippp_ccp_reset *reset; /* Allocated on demand, may never be needed */ - unsigned long compflags; }; /* Prototypes */ @@ -55,32 +37,44 @@ static void isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, struct sk_buff *skb, int proto); static int isdn_ppp_if_get_unit(char *namebuf); static int isdn_ppp_set_compressor(struct ipppd *is,struct isdn_ppp_comp_data *); -static struct sk_buff *isdn_ppp_decompress(struct sk_buff *, - struct ipppd *,struct ipppd *,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, - struct ipppd *is,struct ipppd *master,int type); -static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *skb); + +static struct sk_buff * +isdn_ppp_decompress(struct sk_buff *skb, isdn_net_dev *idev, + struct isdn_ppp_compressor *ipc, void *stat, + struct ippp_ccp_reset *icr, int cproto, 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, isdn_net_local *lp, + struct ipppd *is, int type); + +static void +isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, + struct sk_buff *skb); /* New CCP stuff */ -static void isdn_ppp_ccp_kickup(struct ipppd *is); -static void isdn_ppp_ccp_xmit_reset(struct ipppd *is, int proto, +static void isdn_ppp_ccp_kick_up(void *priv); +static void isdn_ppp_ccp_xmit_reset(void *priv, int proto, unsigned char code, unsigned char id, unsigned char *data, int len); -static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ipppd *is); -static void isdn_ppp_ccp_reset_free(struct ipppd *is); -static void isdn_ppp_ccp_reset_free_state(struct ipppd *is, +static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(void); +static void isdn_ppp_ccp_reset_free(struct ippp_ccp_reset *); +static void isdn_ppp_ccp_reset_free_state(struct ippp_ccp_reset *r, unsigned char id); static void isdn_ppp_ccp_timer_callback(unsigned long closure); -static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ipppd *is, - unsigned char id); -static void isdn_ppp_ccp_reset_trans(struct ipppd *is, - struct isdn_ppp_resetparams *rp); -static void isdn_ppp_ccp_reset_ack_rcvd(struct ipppd *is, - unsigned char id); +static struct ippp_ccp_reset_state * +isdn_ppp_ccp_reset_alloc_state(struct ippp_ccp_reset *icr, unsigned char id); + +static void +isdn_ppp_ccp_reset_trans(struct ippp_ccp_reset *icr, + struct isdn_ppp_resetparams *rp); + +static void +isdn_ppp_ccp_reset_ack_rcvd(struct ippp_ccp_reset *icr, unsigned char id); #ifdef CONFIG_ISDN_MPP @@ -190,6 +184,17 @@ isdn_ppp_free(isdn_net_dev *idev) idev->ppp_slot = -1; /* is this OK ?? */ ipppd_put(is); + if (idev->comp_stat) + idev->compressor->free(idev->comp_stat); + if (idev->decomp_stat) + idev->decompressor->free(idev->decomp_stat); + idev->compressor = NULL; + idev->decompressor = NULL; + idev->comp_stat = NULL; + idev->decomp_stat = NULL; + if (idev->reset) + isdn_ppp_ccp_reset_free(idev->reset); + restore_flags(flags); return; } @@ -251,17 +256,40 @@ isdn_ppp_bind(isdn_net_dev *idev) goto err; } - idev->ppp_slot = i; - ipppds[i]->idev = idev; - ipppds[i]->unit = unit; ipppds[i]->state = IPPP_OPEN | IPPP_ASSIGNED; /* assigned to a netdevice but not connected */ spin_unlock_irqrestore(&ipppds_lock, flags); + ipppds[i]->idev = idev; + ipppds[i]->unit = unit; + + idev->ppp_slot = i; + idev->pppcfg = 0; /* config flags */ + idev->pppmru = 1524; /* MRU, default 1524 */ + /* seq no last seen, maybe set to bundle min, when joining? */ + idev->pppseq = -1; + + idev->compressor = NULL; + idev->decompressor = NULL; + idev->comp_stat = NULL; + idev->decomp_stat = NULL; + idev->compflags = 0; + idev->reset = isdn_ppp_ccp_reset_alloc(); + if (!idev->reset) { + retval = -ENOMEM; + goto out; + } + idev->reset->priv = idev; + idev->reset->xmit_reset = isdn_ppp_ccp_xmit_reset; + idev->reset->kick_up = isdn_ppp_ccp_kick_up; + #ifdef CONFIG_ISDN_MPP retval = isdn_ppp_mp_init(lp, NULL); - // FIXME unwind? #endif /* CONFIG_ISDN_MPP */ + out: + if (retval) + ipppds[i]->state = IPPP_OPEN; + return retval; err: @@ -327,11 +355,11 @@ isdn_ppp_get_slot(void) } /* - * isdn_ppp_open + * ipppd_open */ static int -isdn_ppp_open(struct inode *ino, struct file *file) +ipppd_open(struct inode *ino, struct file *file) { uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP; int slot; @@ -346,32 +374,10 @@ isdn_ppp_open(struct inode *ino, struct file *file) printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, minor, is->state); - /* compression stuff */ - is->link_compressor = is->compressor = NULL; - is->link_decompressor = is->decompressor = NULL; - is->link_comp_stat = is->comp_stat = NULL; - is->link_decomp_stat = is->decomp_stat = NULL; - is->compflags = 0; - - is->reset = isdn_ppp_ccp_reset_alloc(is); - is->idev = NULL; - is->mp_seqno = 0; /* MP sequence number */ - is->pppcfg = 0; /* ppp configuration */ - is->mpppcfg = 0; /* mppp configuration */ - 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->tk = current; init_waitqueue_head(&is->wq); is->minor = minor; -#ifdef CONFIG_ISDN_PPP_VJ - /* - * VJ header compression init - */ - is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */ -#endif isdn_lock_drivers(); @@ -382,7 +388,7 @@ isdn_ppp_open(struct inode *ino, struct file *file) * release ippp device */ static int -isdn_ppp_release(struct inode *ino, struct file *file) +ipppd_release(struct inode *ino, struct file *file) { uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP; struct ipppd *is; @@ -405,30 +411,6 @@ isdn_ppp_release(struct inode *ino, struct file *file) } skb_queue_purge(&is->rq); -#ifdef CONFIG_ISDN_PPP_VJ -/* TODO: if this was the previous master: link the slcomp to the new master */ - slhc_free(is->slcomp); - is->slcomp = NULL; -#endif - -/* TODO: if this was the previous master: link the the stuff to the new master */ - if(is->comp_stat) - is->compressor->free(is->comp_stat); - if(is->link_comp_stat) - is->link_compressor->free(is->link_comp_stat); - if(is->link_decomp_stat) - is->link_decompressor->free(is->link_decomp_stat); - if(is->decomp_stat) - is->decompressor->free(is->decomp_stat); - is->compressor = is->link_compressor = NULL; - is->decompressor = is->link_decompressor = NULL; - is->comp_stat = is->link_comp_stat = NULL; - is->decomp_stat = is->link_decomp_stat = NULL; - - /* Clean up if necessary */ - if(is->reset) - isdn_ppp_ccp_reset_free(is); - /* this slot is ready for new connections */ is->state = 0; @@ -466,7 +448,7 @@ set_arg(void *b, void *val,int len) * ippp device ioctl */ static int -isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned long arg) +ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned long arg) { isdn_net_dev *idev; unsigned long val; @@ -508,28 +490,35 @@ isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned return r; break; case PPPIOCGMPFLAGS: /* get configuration flags */ - if ((r = set_arg((void *) arg, &is->mpppcfg, sizeof(is->mpppcfg) ))) + if (!idev) + return -ENODEV; + if ((r = set_arg((void *) arg, &idev->mlp->mpppcfg, sizeof(idev->mlp->mpppcfg) ))) return r; break; case PPPIOCSMPFLAGS: /* set configuration flags */ + if (!idev) + return -ENODEV; if ((r = get_arg((void *) arg, &val, sizeof(val) ))) return r; - is->mpppcfg = val; + idev->mlp->mpppcfg = val; break; case PPPIOCGFLAGS: /* get configuration flags */ - if ((r = set_arg((void *) arg, &is->pppcfg,sizeof(is->pppcfg) ))) + if (!idev) + return -ENODEV; + if ((r = set_arg((void *) arg, &idev->pppcfg, sizeof(idev->pppcfg) ))) return r; break; case PPPIOCSFLAGS: /* set configuration flags */ + if (!idev) + return -ENODEV; if ((r = get_arg((void *) arg, &val, sizeof(val) ))) { return r; } - if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) { - if (idev) - /* OK .. we are ready to send buffers */ - isdn_net_online(idev); + if ((val & SC_ENABLE_IP) && !(idev->pppcfg & SC_ENABLE_IP)) { + /* OK .. we are ready to send buffers */ + isdn_net_online(idev); } - is->pppcfg = val; + idev->pppcfg = val; break; case PPPIOCGIDLE: /* get idle time information */ if (idev) { @@ -540,37 +529,39 @@ isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned } break; case PPPIOCSMRU: /* set receive unit size for PPP */ + if (!idev) + return -ENODEV; if ((r = get_arg((void *) arg, &val, sizeof(val) ))) return r; - is->mru = val; + idev->pppmru = val; break; case PPPIOCSMPMRU: break; case PPPIOCSMPMTU: break; +#ifdef CONFIG_ISDN_PPP_VJ case PPPIOCSMAXCID: /* set the maximum compression slot id */ + { + struct slcompress *sltmp; + + if (!idev) + return -ENODEV; if ((r = get_arg((void *) arg, &val, sizeof(val) ))) return r; val++; - if (is->maxcid != val) { -#ifdef CONFIG_ISDN_PPP_VJ - struct slcompress *sltmp; -#endif - 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; -#endif + if (is->debug & 0x1) + printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val); + sltmp = slhc_init(16, val); + if (!sltmp) { + printk(KERN_ERR "ippp, can't realloc slhc struct\n"); + return -ENOMEM; } + if (idev->mlp->slcomp) + slhc_free(idev->mlp->slcomp); + idev->mlp->slcomp = sltmp; break; + } +#endif case PPPIOCGDEBUG: if ((r = set_arg((void *) arg, &is->debug, sizeof(is->debug) ))) return r; @@ -579,6 +570,10 @@ isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned if ((r = get_arg((void *) arg, &val, sizeof(val) ))) return r; is->debug = val; + if (idev) { + idev->debug = val; + idev->mlp->debug = val; + } break; case PPPIOCGCOMPRESSORS: { @@ -633,7 +628,7 @@ isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned } static unsigned int -isdn_ppp_poll(struct file *file, poll_table * wait) +ipppd_poll(struct file *file, poll_table * wait) { unsigned int mask; struct ipppd *is; @@ -724,7 +719,7 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot) */ static ssize_t -isdn_ppp_read(struct file *file, char *buf, size_t count, loff_t *off) +ipppd_read(struct file *file, char *buf, size_t count, loff_t *off) { struct ipppd *is; struct sk_buff *skb; @@ -765,7 +760,7 @@ isdn_ppp_read(struct file *file, char *buf, size_t count, loff_t *off) */ static ssize_t -isdn_ppp_write(struct file *file, const char *buf, size_t count, loff_t *off) +ipppd_write(struct file *file, const char *buf, size_t count, loff_t *off) { isdn_net_dev *idev; struct ipppd *is; @@ -850,12 +845,12 @@ struct file_operations isdn_ppp_fops = { .owner = THIS_MODULE, .llseek = no_llseek, - .read = isdn_ppp_read, - .write = isdn_ppp_write, - .poll = isdn_ppp_poll, - .ioctl = isdn_ppp_ioctl, - .open = isdn_ppp_open, - .release = isdn_ppp_release, + .read = ipppd_read, + .write = ipppd_write, + .poll = ipppd_poll, + .ioctl = ipppd_ioctl, + .open = ipppd_open, + .release = ipppd_release, }; /* @@ -906,7 +901,7 @@ isdn_ppp_cleanup(void) * check for address/control field and skip if allowed * retval != 0 -> discard packet silently */ -static int isdn_ppp_skip_ac(struct ipppd *is, struct sk_buff *skb) +static int isdn_ppp_skip_ac(isdn_net_dev *idev, struct sk_buff *skb) { if (skb->len < 1) return -1; @@ -921,7 +916,7 @@ static int isdn_ppp_skip_ac(struct ipppd *is, struct sk_buff *skb) // skip address/control (AC) field skb_pull(skb, 2); } else { - if (is->pppcfg & SC_REJ_COMP_AC) + if (idev->pppcfg & SC_REJ_COMP_AC) // if AC compression was not negotiated, but used, discard packet return -1; } @@ -979,7 +974,7 @@ static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev, isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,idev->ppp_slot); } - if (isdn_ppp_skip_ac(is, skb) < 0) + if (isdn_ppp_skip_ac(idev, skb) < 0) goto err_put; proto = isdn_ppp_strip_proto(skb); @@ -1033,8 +1028,10 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto); isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit, idev->ppp_slot); } - if (is->compflags & SC_DECOMP_ON) { - skb = isdn_ppp_decompress(skb, is, is, &proto); + if (lp->compflags & SC_DECOMP_ON) { + skb = isdn_ppp_decompress(skb, idev, lp->decompressor, + lp->decomp_stat, lp->reset, + PPP_COMP, &proto); if (!skb) // decompression error goto put; } @@ -1057,7 +1054,7 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, case PPP_VJC_UNCOMP: if (is->debug & 0x20) printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n"); - if (slhc_remember(is->slcomp, skb->data, skb->len) <= 0) { + if (slhc_remember(lp->slcomp, skb->data, skb->len) <= 0) { printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n"); goto drop_put; } @@ -1078,7 +1075,7 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, } skb_put(skb, skb_old->len + 128); memcpy(skb->data, skb_old->data, skb_old->len); - pkt_len = slhc_uncompress(is->slcomp, + pkt_len = slhc_uncompress(lp->slcomp, skb->data, skb_old->len); kfree_skb(skb_old); if (pkt_len < 0) @@ -1175,7 +1172,7 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) goto err; } - if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ + if (!(idev->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ printk(KERN_INFO "%s: IP frame delayed.\n", ndev->name); goto err_put; } @@ -1221,7 +1218,7 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32,ipts->unit,idev->ppp_slot); #ifdef CONFIG_ISDN_PPP_VJ - if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */ + if (proto == PPP_IP && idev->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */ struct sk_buff *new_skb; unsigned short hl; /* @@ -1246,8 +1243,8 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) 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)); + pktlen = slhc_compress(mlp->slcomp, skb->data, skb->len, new_skb->data, + &buf, !(idev->pppcfg & SC_NO_TCP_CCID)); if (buf != skb->data) { if (new_skb->data != buf) @@ -1274,11 +1271,11 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) /* * normal (single link) or bundle compression */ - if(ipts->compflags & SC_COMP_ON) { + if (mlp->compflags & SC_COMP_ON) { /* We send compressed only if both down- und upstream compression is negotiated, that means, CCP is up */ - if(ipts->compflags & SC_DECOMP_ON) { - skb = isdn_ppp_compress(skb,&proto,ipt,ipts,0); + if (mlp->compflags & SC_DECOMP_ON) { + skb = isdn_ppp_compress(skb, &proto, mlp, ipt, 0); } else { printk(KERN_DEBUG "isdn_ppp: CCP not yet up - sending as-is\n"); } @@ -1314,26 +1311,27 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) } #endif +#if 0 /* * 'link in bundle' compression ... */ - if(ipt->compflags & SC_LINK_COMP_ON) + if (ipt->compflags & SC_LINK_COMP_ON) skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1); +#endif - if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) { + if ((idev->pppcfg & SC_COMP_PROT) && (proto <= 0xff)) { unsigned char *data = isdn_ppp_skb_push(&skb,1); if(!data) goto put2; data[0] = proto & 0xff; - } - else { + } else { unsigned char *data = isdn_ppp_skb_push(&skb,2); if(!data) goto put2; data[0] = (proto >> 8) & 0xff; data[1] = proto & 0xff; } - if(!(ipt->pppcfg & SC_COMP_AC)) { + if (!(idev->pppcfg & SC_COMP_AC)) { unsigned char *data = isdn_ppp_skb_push(&skb,2); if(!data) goto put2; @@ -1437,7 +1435,7 @@ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to ) } lp->netdev->pb->ref_ct++; - is->last_link_seqno = 0; + is->pppseq = 0; return 0; } @@ -1483,7 +1481,7 @@ static void isdn_ppp_mp_receive(isdn_net_local *lp, isdn_net_dev *dev, isdn_ppp_mp_print_recv_pkt(slot, skb); newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ, - skb, is->last_link_seqno); + skb, is->pppseq); /* if this packet seq # is less than last already processed one, @@ -1501,14 +1499,14 @@ static void isdn_ppp_mp_receive(isdn_net_local *lp, isdn_net_dev *dev, } /* find the minimum received sequence number over all links */ - is->last_link_seqno = minseq = newseq; + is->pppseq = minseq = newseq; list_for_each_entry(qdev, &lp->online, online) { slot = qdev->ppp_slot; if (slot < 0 || slot > ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n", __FUNCTION__ ,slot); } else { - u32 lls = ippp_table[slot]->last_link_seqno; + u32 lls = ippp_table[slot]->pppseq; if (MP_LT(lls, minseq)) minseq = lls; } @@ -1871,7 +1869,7 @@ isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev) #ifdef CONFIG_ISDN_PPP_VJ is = ipppd_get(slot); if (is) { - struct slcompress *slcomp = is->slcomp; + struct slcompress *slcomp = lp->slcomp; if (slcomp) { t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed; t.vj.vjs_compressed = slcomp->sls_o_compressed; @@ -2007,9 +2005,24 @@ isdn_ppp_hangup_slave(char *name) /* Push an empty CCP Data Frame up to the daemon to wake it up and let it generate a CCP Reset-Request or tear down CCP altogether */ -static void isdn_ppp_ccp_kickup(struct ipppd *is) +static void isdn_ppp_ccp_kick_up(void *priv) +{ + isdn_net_dev *idev = priv; + + isdn_ppp_fill_rq(NULL, 0, PPP_COMP, idev->ppp_slot); +} + +static void isdn_ppp_ccp_lp_kick_up(void *priv) { - isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->idev->ppp_slot); + isdn_net_local *lp = priv; + isdn_net_dev *idev; + + if (list_empty(&lp->online)) { + isdn_BUG(); + return; + } + idev = list_entry(lp->online.next, isdn_net_dev, online); + isdn_ppp_ccp_kick_up(idev); } /* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary, @@ -2047,15 +2060,15 @@ static void isdn_ppp_ccp_kickup(struct ipppd *is) function above but every wrapper does a bit different. Hope I guess correct in this hack... */ -static void isdn_ppp_ccp_xmit_reset(struct ipppd *is, int proto, +static void isdn_ppp_ccp_xmit_reset(void *priv, int proto, unsigned char code, unsigned char id, unsigned char *data, int len) { + isdn_net_dev *idev = priv; struct sk_buff *skb; unsigned char *p; int hl; int cnt = 0; - isdn_net_dev *idev = is->idev; /* Alloc large enough skb */ hl = isdn_slot_hdrlen(idev->isdn_slot); @@ -2068,7 +2081,7 @@ static void isdn_ppp_ccp_xmit_reset(struct ipppd *is, int proto, skb_reserve(skb, hl); /* We may need to stuff an address and control field first */ - if(!(is->pppcfg & SC_COMP_AC)) { + if (!(idev->pppcfg & SC_COMP_AC)) { p = skb_put(skb, 2); *p++ = 0xff; *p++ = 0x03; @@ -2092,16 +2105,31 @@ static void isdn_ppp_ccp_xmit_reset(struct ipppd *is, int proto, /* skb is now ready for xmit */ printk(KERN_DEBUG "Sending CCP Frame:\n"); - isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,idev->ppp_slot); + isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, -1, idev->ppp_slot); isdn_net_write_super(idev, skb); } +static void isdn_ppp_ccp_lp_xmit_reset(void *priv, int proto, + unsigned char code, unsigned char id, + unsigned char *data, int len) +{ + isdn_net_local *lp = priv; + isdn_net_dev *idev; + + if (list_empty(&lp->online)) { + isdn_BUG(); + return; + } + idev = list_entry(lp->online.next, isdn_net_dev, online); + isdn_ppp_ccp_xmit_reset(idev, proto, code, id, data, len); +} + /* Allocate the reset state vector */ -static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ipppd *is) +static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(void) { struct ippp_ccp_reset *r; - r = kmalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL); + r = kmalloc(sizeof(struct ippp_ccp_reset), GFP_ATOMIC); if(!r) { printk(KERN_ERR "ippp_ccp: failed to allocate reset data" " structure - no mem\n"); @@ -2109,39 +2137,36 @@ static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ipppd *is) } memset(r, 0, sizeof(struct ippp_ccp_reset)); printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r); - is->reset = r; + return r; } /* Destroy the reset state vector. Kill all pending timers first. */ -static void isdn_ppp_ccp_reset_free(struct ipppd *is) +static void isdn_ppp_ccp_reset_free(struct ippp_ccp_reset *r) { unsigned int id; - printk(KERN_DEBUG "ippp_ccp: freeing reset data structure %p\n", - is->reset); - for(id = 0; id < 256; id++) { - if(is->reset->rs[id]) { - isdn_ppp_ccp_reset_free_state(is, (unsigned char)id); - } + printk(KERN_DEBUG "ippp_ccp: freeing reset data structure %p\n", r); + for (id = 0; id < 256; id++) { + if (r->rs[id]) + isdn_ppp_ccp_reset_free_state(r, id); } - kfree(is->reset); - is->reset = NULL; + kfree(r); } /* Free a given state and clear everything up for later reallocation */ -static void isdn_ppp_ccp_reset_free_state(struct ipppd *is, +static void isdn_ppp_ccp_reset_free_state(struct ippp_ccp_reset *r, unsigned char id) { struct ippp_ccp_reset_state *rs; - if(is->reset->rs[id]) { + if (r->rs[id]) { printk(KERN_DEBUG "ippp_ccp: freeing state for id %d\n", id); - rs = is->reset->rs[id]; + rs = r->rs[id]; /* Make sure the kernel will not call back later */ - if(rs->ta) - del_timer(&rs->timer); - is->reset->rs[id] = NULL; + if (rs->ta) + del_timer_sync(&rs->timer); + r->rs[id] = NULL; kfree(rs); } else { printk(KERN_WARNING "ippp_ccp: id %d is not allocated\n", id); @@ -2166,14 +2191,14 @@ static void isdn_ppp_ccp_timer_callback(unsigned long closure) up the state now, it will be reallocated if the decompressor insists on another reset */ rs->ta = 0; - isdn_ppp_ccp_reset_free_state(rs->is, rs->id); + isdn_ppp_ccp_reset_free_state(rs->icr, rs->id); return; } printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n", rs->id); /* Push it again */ - isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id, - rs->data, rs->dlen); + rs->icr->xmit_reset(rs->icr->priv, PPP_CCP, CCP_RESETREQ, + rs->id, rs->data, rs->dlen); /* Restart timer */ rs->timer.expires = jiffies + HZ*5; add_timer(&rs->timer); @@ -2184,33 +2209,33 @@ static void isdn_ppp_ccp_timer_callback(unsigned long closure) } /* Allocate a new reset transaction state */ -static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ipppd *is, - unsigned char id) +static struct ippp_ccp_reset_state * +isdn_ppp_ccp_reset_alloc_state(struct ippp_ccp_reset *icr, unsigned char id) { struct ippp_ccp_reset_state *rs; - if(is->reset->rs[id]) { + + if (icr->rs[id]) { printk(KERN_WARNING "ippp_ccp: old state exists for id %d\n", id); return NULL; - } else { - rs = kmalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL); - if(!rs) - return NULL; - memset(rs, 0, sizeof(struct ippp_ccp_reset_state)); - rs->state = CCPResetIdle; - rs->is = is; - rs->id = id; - rs->timer.data = (unsigned long)rs; - rs->timer.function = isdn_ppp_ccp_timer_callback; - is->reset->rs[id] = rs; } + rs = kmalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL); + if(!rs) + return NULL; + memset(rs, 0, sizeof(struct ippp_ccp_reset_state)); + rs->state = CCPResetIdle; + rs->icr = icr; + rs->id = id; + rs->timer.data = (unsigned long)rs; + rs->timer.function = isdn_ppp_ccp_timer_callback; + icr->rs[id] = rs; return rs; } /* A decompressor wants a reset with a set of parameters - do what is necessary to fulfill it */ -static void isdn_ppp_ccp_reset_trans(struct ipppd *is, +static void isdn_ppp_ccp_reset_trans(struct ippp_ccp_reset *icr, struct isdn_ppp_resetparams *rp) { struct ippp_ccp_reset_state *rs; @@ -2224,11 +2249,11 @@ static void isdn_ppp_ccp_reset_trans(struct ipppd *is, " specify reset id\n"); return; } - if(is->reset->rs[rp->id]) { + if(icr->rs[rp->id]) { /* There is already a transaction in existence for this id. May be still waiting for a Ack or may be wrong. */ - rs = is->reset->rs[rp->id]; + rs = icr->rs[rp->id]; if(rs->state == CCPResetSentReq && rs->ta) { printk(KERN_DEBUG "ippp_ccp: reset" " trans still in progress" @@ -2242,7 +2267,7 @@ static void isdn_ppp_ccp_reset_trans(struct ipppd *is, /* Ok, this is a new transaction */ printk(KERN_DEBUG "ippp_ccp: new trans for id" " %d to be started\n", rp->id); - rs = isdn_ppp_ccp_reset_alloc_state(is, rp->id); + rs = isdn_ppp_ccp_reset_alloc_state(icr, rp->id); if(!rs) { printk(KERN_ERR "ippp_ccp: out of mem" " allocing ccp trans\n"); @@ -2254,10 +2279,9 @@ static void isdn_ppp_ccp_reset_trans(struct ipppd *is, rs->dlen = rp->dlen; memcpy(rs->data, rp->data, rp->dlen); } - /* HACK TODO - add link comp here */ - isdn_ppp_ccp_xmit_reset(is, PPP_CCP, - CCP_RESETREQ, rs->id, - rs->data, rs->dlen); + icr->xmit_reset(icr->priv, PPP_CCP, + CCP_RESETREQ, rs->id, + rs->data, rs->dlen); /* Start the timer */ rs->timer.expires = jiffies + 5*HZ; add_timer(&rs->timer); @@ -2271,11 +2295,11 @@ static void isdn_ppp_ccp_reset_trans(struct ipppd *is, care about them, so we just send the minimal requests and increase ids only when an Ack is received for a given id */ - if(is->reset->rs[is->reset->lastid]) { + if(icr->rs[icr->lastid]) { /* There is already a transaction in existence for this id. May be still waiting for a Ack or may be wrong. */ - rs = is->reset->rs[is->reset->lastid]; + rs = icr->rs[icr->lastid]; if(rs->state == CCPResetSentReq && rs->ta) { printk(KERN_DEBUG "ippp_ccp: reset" " trans still in progress" @@ -2287,9 +2311,8 @@ static void isdn_ppp_ccp_reset_trans(struct ipppd *is, } } else { printk(KERN_DEBUG "ippp_ccp: new trans for id" - " %d to be started\n", is->reset->lastid); - rs = isdn_ppp_ccp_reset_alloc_state(is, - is->reset->lastid); + " %d to be started\n", icr->lastid); + rs = isdn_ppp_ccp_reset_alloc_state(icr, icr->lastid); if(!rs) { printk(KERN_ERR "ippp_ccp: out of mem" " allocing ccp trans\n"); @@ -2300,9 +2323,8 @@ static void isdn_ppp_ccp_reset_trans(struct ipppd *is, know better */ rs->expra = 1; rs->dlen = 0; - /* HACK TODO - add link comp here */ - isdn_ppp_ccp_xmit_reset(is, PPP_CCP, CCP_RESETREQ, - rs->id, NULL, 0); + icr->xmit_reset(icr->priv, PPP_CCP, CCP_RESETREQ, + rs->id, NULL, 0); /* Start the timer */ rs->timer.expires = jiffies + 5*HZ; add_timer(&rs->timer); @@ -2313,10 +2335,10 @@ static void isdn_ppp_ccp_reset_trans(struct ipppd *is, /* An Ack was received for this id. This means we stop the timer and clean up the state prior to calling the decompressors reset routine. */ -static void isdn_ppp_ccp_reset_ack_rcvd(struct ipppd *is, +static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_ccp_reset *icr, unsigned char id) { - struct ippp_ccp_reset_state *rs = is->reset->rs[id]; + struct ippp_ccp_reset_state *rs = icr->rs[id]; if(rs) { if(rs->ta && rs->state == CCPResetSentReq) { @@ -2332,13 +2354,13 @@ static void isdn_ppp_ccp_reset_ack_rcvd(struct ipppd *is, rs->ta = 0; del_timer(&rs->timer); } - isdn_ppp_ccp_reset_free_state(is, id); + isdn_ppp_ccp_reset_free_state(icr, id); } else { printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id" " %d\n", id); } /* Make sure the simple reset stuff uses a new id next time */ - is->reset->lastid++; + icr->lastid++; } /* @@ -2353,45 +2375,30 @@ static void isdn_ppp_ccp_reset_ack_rcvd(struct ipppd *is, * NULL if decompression error */ -static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ipppd *is,struct ipppd *master, - int *proto) +static struct sk_buff * +isdn_ppp_decompress(struct sk_buff *skb, isdn_net_dev *idev, + struct isdn_ppp_compressor *ipc, void *stat, + struct ippp_ccp_reset *icr, int cproto, int *proto) { - void *stat = NULL; - struct isdn_ppp_compressor *ipc = NULL; struct sk_buff *skb_out; int len; - struct ipppd *ri; struct isdn_ppp_resetparams rsparm; unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; - if(!master) { - // per-link decompression - stat = is->link_decomp_stat; - ipc = is->link_decompressor; - ri = is; - } else { - stat = master->decomp_stat; - ipc = master->decompressor; - ri = master; - } - 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 + if (!stat) BUG(); - if((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG) ) { - // compressed packets are compressed by their protocol type - + if (*proto == cproto) { // 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); + skb_out = dev_alloc_skb(idev->pppmru + PPP_HDRLEN); len = ipc->decompress(stat, skb, skb_out, &rsparm); kfree_skb(skb); if (len <= 0) { @@ -2400,12 +2407,12 @@ static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ipppd *is, printk(KERN_INFO "ippp: decomp wants reset %s params\n", rsparm.valid ? "with" : "without"); - isdn_ppp_ccp_reset_trans(ri, &rsparm); + isdn_ppp_ccp_reset_trans(icr, &rsparm); break; case DECOMP_FATALERROR: - ri->pppcfg |= SC_DC_FERROR; + idev->pppcfg |= SC_DC_FERROR; /* Kick ipppd to recognize the error */ - isdn_ppp_ccp_kickup(ri); + icr->kick_up(icr->priv); break; } kfree_skb(skb_out); @@ -2433,42 +2440,34 @@ static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ipppd *is, * 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 ipppd *is,struct ipppd *master,int type) + isdn_net_local *lp, struct ipppd *is, + int type) { - int ret; - int new_proto; - struct isdn_ppp_compressor *compressor; - void *stat; - struct sk_buff *skb_out; - + int ret; + int new_proto; + struct isdn_ppp_compressor *compressor; + void *stat; + struct sk_buff *skb_out; + /* we do not compress control protocols */ - if(*proto < 0 || *proto > 0x3fff) { - return skb_in; - } - - if(type) { /* type=1 => Link compression */ + if(*proto < 0 || *proto > 0x3fff) { return skb_in; } - else { - if(!master) { - compressor = is->compressor; - stat = is->comp_stat; - } - else { - compressor = master->compressor; - stat = master->comp_stat; - } + + if (type) { /* type=1 => Link compression */ + return skb_in; + } else { + compressor = lp->compressor; + stat = lp->comp_stat; new_proto = PPP_COMP; } - if(!compressor) { + if (!compressor) { printk(KERN_ERR "isdn_ppp: No compressor set!\n"); return skb_in; } - if(!stat) { - printk(KERN_ERR "isdn_ppp: Compressor not initialized?\n"); - return skb_in; - } + if (!stat) + BUG(); /* Allow for at least 150 % expansion (for now) */ skb_out = alloc_skb(skb_in->len + skb_in->len/2 + 32 + @@ -2514,34 +2513,34 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *idev, isdn_net_local *lp, switch(skb->data[0]) { case CCP_CONFREQ: - if(is->debug & 0x10) + if (is->debug & 0x10) printk(KERN_DEBUG "Disable compression here!\n"); - if(proto == PPP_CCP) - mis->compflags &= ~SC_COMP_ON; + if (proto == PPP_CCP) + lp->compflags &= ~SC_COMP_ON; else - is->compflags &= ~SC_LINK_COMP_ON; + idev->compflags &= ~SC_LINK_COMP_ON; break; case CCP_TERMREQ: case CCP_TERMACK: - if(is->debug & 0x10) + if (is->debug & 0x10) printk(KERN_DEBUG "Disable (de)compression here!\n"); - if(proto == PPP_CCP) - mis->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON); + if (proto == PPP_CCP) + lp->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON); else - is->compflags &= ~(SC_LINK_DECOMP_ON|SC_LINK_COMP_ON); + idev->compflags &= ~(SC_LINK_DECOMP_ON|SC_LINK_COMP_ON); break; case CCP_CONFACK: /* if we RECEIVE an ackowledge we enable the decompressor */ if(is->debug & 0x10) printk(KERN_DEBUG "Enable decompression here!\n"); if(proto == PPP_CCP) { - if (!mis->decompressor) + if (!lp->decomp_stat) break; - mis->compflags |= SC_DECOMP_ON; + lp->compflags |= SC_DECOMP_ON; } else { - if (!is->decompressor) + if (!idev->decomp_stat) break; - is->compflags |= SC_LINK_DECOMP_ON; + lp->compflags |= SC_LINK_DECOMP_ON; } break; @@ -2553,28 +2552,27 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *idev, isdn_net_local *lp, if(proto == PPP_CCP) { /* If a reset Ack was outstanding for this id, then clean up the state engine */ - isdn_ppp_ccp_reset_ack_rcvd(mis, skb->data[1]); - if(mis->decompressor && mis->decomp_stat) - mis->decompressor-> - reset(mis->decomp_stat, + isdn_ppp_ccp_reset_ack_rcvd(lp->reset, skb->data[1]); + if (lp->decomp_stat) + lp->decompressor-> + reset(lp->decomp_stat, skb->data[0], skb->data[1], len ? &skb->data[4] : NULL, len, NULL); /* TODO: This is not easy to decide here */ - mis->compflags &= ~SC_DECOMP_DISCARD; - } - else { - isdn_ppp_ccp_reset_ack_rcvd(is, skb->data[1]); - if(is->link_decompressor && is->link_decomp_stat) - is->link_decompressor-> - reset(is->link_decomp_stat, + lp->compflags &= ~SC_DECOMP_DISCARD; + } else { + isdn_ppp_ccp_reset_ack_rcvd(idev->reset, skb->data[1]); + if(idev->decomp_stat) + idev->decompressor-> + reset(idev->decomp_stat, skb->data[0], skb->data[1], len ? &skb->data[4] : NULL, len, NULL); /* TODO: neither here */ - is->compflags &= ~SC_LINK_DECOMP_DISCARD; + lp->compflags &= ~SC_LINK_DECOMP_DISCARD; } break; @@ -2589,18 +2587,18 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *idev, isdn_net_local *lp, len = (skb->data[2] << 8) | skb->data[3]; len -= 4; if(proto == PPP_CCP) { - if(mis->compressor && mis->comp_stat) - mis->compressor-> - reset(mis->comp_stat, + if (lp->comp_stat) + lp->compressor-> + reset(lp->comp_stat, skb->data[0], skb->data[1], len ? &skb->data[4] : NULL, len, &rsparm); } else { - if(is->link_compressor && is->link_comp_stat) - is->link_compressor-> - reset(is->link_comp_stat, + if (idev->comp_stat) + idev->compressor-> + reset(idev->comp_stat, skb->data[0], skb->data[1], len ? &skb->data[4] : NULL, @@ -2675,7 +2673,7 @@ static void isdn_ppp_send_ccp(isdn_net_dev *idev, isdn_net_local *lp, struct sk_ /* Daemon may send with or without address and control field comp */ data = skb->data; - if(!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) { + if (!(idev->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) { data += 2; if(skb->len < 5) return; @@ -2694,34 +2692,34 @@ static void isdn_ppp_send_ccp(isdn_net_dev *idev, isdn_net_local *lp, struct sk_ switch(data[2]) { case CCP_CONFREQ: - if(is->debug & 0x10) + if (is->debug & 0x10) printk(KERN_DEBUG "Disable decompression here!\n"); - if(proto == PPP_CCP) - is->compflags &= ~SC_DECOMP_ON; + if (proto == PPP_CCP) + lp->compflags &= ~SC_DECOMP_ON; else - is->compflags &= ~SC_LINK_DECOMP_ON; + idev->compflags &= ~SC_LINK_DECOMP_ON; break; case CCP_TERMREQ: case CCP_TERMACK: - if(is->debug & 0x10) + if (is->debug & 0x10) printk(KERN_DEBUG "Disable (de)compression here!\n"); - if(proto == PPP_CCP) - is->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON); + if (proto == PPP_CCP) + lp->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON); else - is->compflags &= ~(SC_LINK_DECOMP_ON|SC_LINK_COMP_ON); + idev->compflags &= ~(SC_LINK_DECOMP_ON|SC_LINK_COMP_ON); break; case CCP_CONFACK: /* if we SEND an ackowledge we can/must enable the compressor */ - if(is->debug & 0x10) + if (is->debug & 0x10) printk(KERN_DEBUG "Enable compression here!\n"); - if(proto == PPP_CCP) { - if (!is->compressor) + if (proto == PPP_CCP) { + if (!lp->compressor) break; - is->compflags |= SC_COMP_ON; + lp->compflags |= SC_COMP_ON; } else { - if (!is->compressor) + if (!idev->compressor) break; - is->compflags |= SC_LINK_COMP_ON; + idev->compflags |= SC_LINK_COMP_ON; } break; case CCP_RESETACK: @@ -2729,18 +2727,17 @@ static void isdn_ppp_send_ccp(isdn_net_dev *idev, isdn_net_local *lp, struct sk_ if(is->debug & 0x10) printk(KERN_DEBUG "Reset decompression state here!\n"); printk(KERN_DEBUG "ResetAck from daemon passed by\n"); - if(proto == PPP_CCP) { + if (proto == PPP_CCP) { /* link to master? */ - if(is->compressor && is->comp_stat) - is->compressor->reset(is->comp_stat, 0, 0, + if (lp->comp_stat) + lp->compressor->reset(lp->comp_stat, 0, 0, NULL, 0, NULL); - is->compflags &= ~SC_COMP_DISCARD; - } - else { - if(is->link_compressor && is->link_comp_stat) - is->link_compressor->reset(is->link_comp_stat, + lp->compflags &= ~SC_COMP_DISCARD; + } else { + if (idev->comp_stat) + idev->compressor->reset(idev->comp_stat, 0, 0, NULL, 0, NULL); - is->compflags &= ~SC_LINK_COMP_DISCARD; + idev->compflags &= ~SC_LINK_COMP_DISCARD; } break; case CCP_RESETREQ: @@ -2780,7 +2777,13 @@ static int isdn_ppp_set_compressor(struct ipppd *is, struct isdn_ppp_comp_data * int ret; void *stat; int num = data->num; + isdn_net_dev *idev = is->idev; + isdn_net_local *lp; + if (!idev) + return -ENODEV; + + lp = idev->mlp; if(is->debug & 0x10) printk(KERN_DEBUG "[%d] Set %s type %d\n",is->unit, (data->flags&IPPP_COMP_FLAG_XMIT)?"compressor":"decompressor",num); @@ -2789,16 +2792,19 @@ static int isdn_ppp_set_compressor(struct ipppd *is, struct isdn_ppp_comp_data * decompressor. The decompressor would cause reset transactions sooner or later, and they need that vector. */ - if(!(data->flags & IPPP_COMP_FLAG_XMIT) && !is->reset) { - printk(KERN_ERR "ippp_ccp: no reset data structure - can't" - " allow decompression.\n"); - return -ENOMEM; + if (!(data->flags & IPPP_COMP_FLAG_XMIT)) { + if ((data->flags & IPPP_COMP_FLAG_LINK && !idev->reset) || + (!(data->flags & IPPP_COMP_FLAG_LINK) && !lp->reset)) { + printk(KERN_ERR "ippp_ccp: no reset data structure - can't" + " allow decompression.\n"); + return -ENOMEM; + } } while(ipc) { - if(ipc->num == num) { + if (ipc->num == num) { stat = ipc->alloc(data); - if(stat) { + if (stat) { ret = ipc->init(stat,data,is->unit,0); if(!ret) { printk(KERN_ERR "Can't init (de)compression!\n"); @@ -2806,38 +2812,34 @@ static int isdn_ppp_set_compressor(struct ipppd *is, struct isdn_ppp_comp_data * stat = NULL; break; } - } - else { + } else { printk(KERN_ERR "Can't alloc (de)compression!\n"); break; } - if(data->flags & IPPP_COMP_FLAG_XMIT) { - if(data->flags & IPPP_COMP_FLAG_LINK) { - if(is->link_comp_stat) - is->link_compressor->free(is->link_comp_stat); - is->link_comp_stat = stat; - is->link_compressor = ipc; - } - else { - if(is->comp_stat) - is->compressor->free(is->comp_stat); - is->comp_stat = stat; - is->compressor = ipc; - } - } - else { - if(data->flags & IPPP_COMP_FLAG_LINK) { - if(is->link_decomp_stat) - is->link_decompressor->free(is->link_decomp_stat); - is->link_decomp_stat = stat; - is->link_decompressor = ipc; + if (data->flags & IPPP_COMP_FLAG_XMIT) { + if (data->flags & IPPP_COMP_FLAG_LINK) { + if (idev->comp_stat) + idev->compressor->free(idev->comp_stat); + idev->comp_stat = stat; + idev->compressor = ipc; + } else { + if (lp->comp_stat) + lp->compressor->free(lp->comp_stat); + lp->comp_stat = stat; + lp->compressor = ipc; } - else { - if(is->decomp_stat) - is->decompressor->free(is->decomp_stat); - is->decomp_stat = stat; - is->decompressor = ipc; + } else { + if (data->flags & IPPP_COMP_FLAG_LINK) { + if (idev->decomp_stat) + idev->decompressor->free(idev->decomp_stat); + idev->decomp_stat = stat; + idev->decompressor = ipc; + } else { + if (lp->decomp_stat) + lp->decompressor->free(lp->decomp_stat); + lp->decomp_stat = stat; + lp->decompressor = ipc; } } return 0; @@ -2850,6 +2852,52 @@ static int isdn_ppp_set_compressor(struct ipppd *is, struct isdn_ppp_comp_data * // ISDN_NET_ENCAP_SYNCPPP // ====================================================================== +static int +isdn_ppp_open(isdn_net_local *lp) +{ + lp->mpppcfg = 0; /* mppp configuration */ + lp->mp_seqno = 0; /* MP sequence number */ + +#ifdef CONFIG_ISDN_PPP_VJ + lp->slcomp = slhc_init(16, 16); +#endif + lp->compressor = NULL; + lp->decompressor = NULL; + lp->comp_stat = NULL; + lp->decomp_stat = NULL; + lp->compflags = 0; + + lp->reset = isdn_ppp_ccp_reset_alloc(); + if (!lp->reset) { + return -ENOMEM; + } + lp->reset->priv = lp; + lp->reset->xmit_reset = isdn_ppp_ccp_lp_xmit_reset; + lp->reset->kick_up = isdn_ppp_ccp_lp_kick_up; + + return 0; +} + +static void +isdn_ppp_close(isdn_net_local *lp) +{ +#ifdef CONFIG_ISDN_PPP_VJ + slhc_free(lp->slcomp); + lp->slcomp = NULL; +#endif + if (lp->comp_stat) + lp->compressor->free(lp->comp_stat); + if (lp->decomp_stat) + lp->decompressor->free(lp->decomp_stat); + + lp->compressor = NULL; + lp->decompressor = NULL; + lp->comp_stat = NULL; + lp->decomp_stat = NULL; + + isdn_ppp_ccp_reset_free(lp->reset); +} + static int isdn_ppp_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, @@ -2870,5 +2918,6 @@ struct isdn_netif_ops isdn_ppp_ops = { .connected = isdn_ppp_wakeup_daemon, .bind = isdn_ppp_bind, .unbind = isdn_ppp_free, - + .open = isdn_ppp_open, + .close = isdn_ppp_close, }; diff --git a/include/linux/isdn.h b/include/linux/isdn.h index 95352ab33f37..fcabee098ab1 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -356,6 +356,24 @@ typedef struct isdn_net_local_s { #ifdef CONFIG_ISDN_X25 struct concap_device_ops *dops; /* callbacks used by encapsulator */ #endif +#ifdef CONFIG_ISDN_PPP + unsigned int mpppcfg; + long mp_seqno; + + struct isdn_ppp_compressor *compressor; + struct isdn_ppp_compressor *decompressor; + void *comp_stat; + void *decomp_stat; + unsigned long compflags; + struct ippp_ccp_reset *reset; + + unsigned long debug; +#ifdef CONFIG_ISDN_PPP_VJ + unsigned char *cbuf; + struct slcompress *slcomp; +#endif +#endif + /* use an own struct for that in later versions */ ulong cisco_myseq; /* Local keepalive seq. for Cisco */ ulong cisco_mineseen; /* returned keepalive seq. from remote */ @@ -415,6 +433,18 @@ typedef struct isdn_net_dev_s { char name[10]; /* Name of device */ struct list_head global_list; /* global list of all isdn_net_devs */ #ifdef CONFIG_ISDN_PPP + unsigned int pppcfg; + unsigned int pppmru; + unsigned int pppseq; /* last seq no seen */ + + struct isdn_ppp_compressor *compressor; + struct isdn_ppp_compressor *decompressor; + void *comp_stat; + void *decomp_stat; + unsigned long compflags; + struct ippp_ccp_reset *reset; + unsigned long debug; + ippp_bundle * pb; /* pointer to the common bundle structure * with the per-bundle data */ #endif diff --git a/include/linux/isdn_ppp.h b/include/linux/isdn_ppp.h index faf2b2c630b7..42418a8aaf08 100644 --- a/include/linux/isdn_ppp.h +++ b/include/linux/isdn_ppp.h @@ -172,7 +172,7 @@ enum ippp_ccp_reset_states { struct ippp_ccp_reset_state { enum ippp_ccp_reset_states state; /* State of this transaction */ - struct ipppd *is; /* Backlink to device stuff */ + struct ippp_ccp_reset *icr; /* Backlink */ unsigned char id; /* Backlink id index */ unsigned char ta:1; /* The timer is active (flag) */ unsigned char expra:1; /* We expect a ResetAck at all */ @@ -189,6 +189,10 @@ struct ippp_ccp_reset_state { struct ippp_ccp_reset { struct ippp_ccp_reset_state *rs[256]; /* One per possible id */ unsigned char lastid; /* Last id allocated by the engine */ + void (*xmit_reset)(void *priv, int proto, unsigned char code, + unsigned char id, unsigned char *data, int len); + void (*kick_up)(void *priv); + void *priv; }; #endif /* __KERNEL__ */ -- cgit v1.2.3 From 1bd35408d15ca4a45ab37a225feea7c47c295c29 Mon Sep 17 00:00:00 2001 From: Kai Germaschewski Date: Wed, 16 Oct 2002 01:14:09 -0500 Subject: ISDN/PPP: Move CCP related stuff into isdn_ppp_ccp.c Create the new files isdn_ppp_ccp.[hc] which deal with PPP CCP (compression control protocol) related stuff. Move most of the CCP related stuff from isdn_ppp.c into isdn_ppp_ccp.c, putting CCP state into a new "struct ippp_ccp". --- drivers/isdn/i4l/Makefile | 2 +- drivers/isdn/i4l/isdn_net_lib.c | 11 +- drivers/isdn/i4l/isdn_ppp.c | 892 ++++------------------------------------ drivers/isdn/i4l/isdn_ppp.h | 14 +- drivers/isdn/i4l/isdn_ppp_ccp.c | 586 ++++++++++++++++++++++++++ drivers/isdn/i4l/isdn_ppp_ccp.h | 53 +++ include/linux/isdn.h | 18 +- include/linux/isdn_ppp.h | 12 +- 8 files changed, 732 insertions(+), 856 deletions(-) create mode 100644 drivers/isdn/i4l/isdn_ppp_ccp.c create mode 100644 drivers/isdn/i4l/isdn_ppp_ccp.h (limited to 'include') diff --git a/drivers/isdn/i4l/Makefile b/drivers/isdn/i4l/Makefile index 407501c0d6b1..58c4e6d3ed35 100644 --- a/drivers/isdn/i4l/Makefile +++ b/drivers/isdn/i4l/Makefile @@ -19,7 +19,7 @@ isdn-objs := isdn_net.o isdn_net_lib.o \ # Optional parts of multipart objects. -isdn-objs-$(CONFIG_ISDN_PPP) += isdn_ppp.o +isdn-objs-$(CONFIG_ISDN_PPP) += isdn_ppp.o isdn_ppp_ccp.o isdn-objs-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o isdn-objs-$(CONFIG_ISDN_AUDIO) += isdn_audio.o isdn-objs-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o diff --git a/drivers/isdn/i4l/isdn_net_lib.c b/drivers/isdn/i4l/isdn_net_lib.c index 08281c1faa3b..681270e68709 100644 --- a/drivers/isdn/i4l/isdn_net_lib.c +++ b/drivers/isdn/i4l/isdn_net_lib.c @@ -2054,18 +2054,12 @@ static inline void isdn_net_dec_frame_cnt(isdn_net_dev *idev) { isdn_net_local *mlp = idev->mlp; - int was_busy; - - was_busy = isdn_net_local_busy(mlp); idev->frame_cnt--; if (isdn_net_dev_busy(idev)) isdn_BUG(); - if (!was_busy) - return; - if (!skb_queue_empty(&idev->super_tx_queue)) tasklet_schedule(&idev->tlet); else @@ -2257,10 +2251,11 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) void isdn_net_write_super(isdn_net_dev *idev, struct sk_buff *skb) { - if (!isdn_net_dev_busy(idev)) + if (!isdn_net_dev_busy(idev)) { isdn_net_writebuf_skb(idev, skb); - else + } else { skb_queue_tail(&idev->super_tx_queue, skb); + } } /* ====================================================================== */ diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index b84673e918c6..2eadf32b1ab7 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -18,6 +18,7 @@ #include "isdn_common.h" #include "isdn_ppp.h" +#include "isdn_ppp_ccp.h" #include "isdn_net.h" struct ipppd { @@ -38,44 +39,21 @@ static void isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, static int isdn_ppp_if_get_unit(char *namebuf); static int isdn_ppp_set_compressor(struct ipppd *is,struct isdn_ppp_comp_data *); -static struct sk_buff * -isdn_ppp_decompress(struct sk_buff *skb, isdn_net_dev *idev, - struct isdn_ppp_compressor *ipc, void *stat, - struct ippp_ccp_reset *icr, int cproto, 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, isdn_net_local *lp, - struct ipppd *is, int type); - static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb); /* New CCP stuff */ -static void isdn_ppp_ccp_kick_up(void *priv); -static void isdn_ppp_ccp_xmit_reset(void *priv, int proto, - unsigned char code, unsigned char id, - unsigned char *data, int len); -static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(void); -static void isdn_ppp_ccp_reset_free(struct ippp_ccp_reset *); -static void isdn_ppp_ccp_reset_free_state(struct ippp_ccp_reset *r, - unsigned char id); -static void isdn_ppp_ccp_timer_callback(unsigned long closure); - -static struct ippp_ccp_reset_state * -isdn_ppp_ccp_reset_alloc_state(struct ippp_ccp_reset *icr, unsigned char id); - static void -isdn_ppp_ccp_reset_trans(struct ippp_ccp_reset *icr, - struct isdn_ppp_resetparams *rp); +isdn_ppp_ccp_kick_up(void *priv, unsigned int flags); static void -isdn_ppp_ccp_reset_ack_rcvd(struct ippp_ccp_reset *icr, unsigned char id); - +isdn_ppp_ccp_xmit_reset(void *priv, int proto, unsigned char code, + unsigned char id, unsigned char *data, int len); #ifdef CONFIG_ISDN_MPP static ippp_bundle * isdn_ppp_bundle_arr = NULL; @@ -107,12 +85,10 @@ ipppd_put(struct ipppd *ipppd) { } -static struct isdn_ppp_compressor *ipc_head = NULL; - /* * frame log (debug) */ -static void +void isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot) { int cnt, @@ -184,16 +160,7 @@ isdn_ppp_free(isdn_net_dev *idev) idev->ppp_slot = -1; /* is this OK ?? */ ipppd_put(is); - if (idev->comp_stat) - idev->compressor->free(idev->comp_stat); - if (idev->decomp_stat) - idev->decompressor->free(idev->decomp_stat); - idev->compressor = NULL; - idev->decompressor = NULL; - idev->comp_stat = NULL; - idev->decomp_stat = NULL; - if (idev->reset) - isdn_ppp_ccp_reset_free(idev->reset); + ippp_ccp_free(idev->ccp); restore_flags(flags); return; @@ -265,23 +232,15 @@ isdn_ppp_bind(isdn_net_dev *idev) idev->ppp_slot = i; idev->pppcfg = 0; /* config flags */ - idev->pppmru = 1524; /* MRU, default 1524 */ /* seq no last seen, maybe set to bundle min, when joining? */ idev->pppseq = -1; - idev->compressor = NULL; - idev->decompressor = NULL; - idev->comp_stat = NULL; - idev->decomp_stat = NULL; - idev->compflags = 0; - idev->reset = isdn_ppp_ccp_reset_alloc(); - if (!idev->reset) { + idev->ccp = ippp_ccp_alloc(PPP_COMPFRAG, idev, isdn_ppp_ccp_xmit_reset, + isdn_ppp_ccp_kick_up); + if (!idev->ccp) { retval = -ENOMEM; goto out; } - idev->reset->priv = idev; - idev->reset->xmit_reset = isdn_ppp_ccp_xmit_reset; - idev->reset->kick_up = isdn_ppp_ccp_kick_up; #ifdef CONFIG_ISDN_MPP retval = isdn_ppp_mp_init(lp, NULL); @@ -452,7 +411,7 @@ ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned lon { isdn_net_dev *idev; unsigned long val; - int r,i,j; + int r; struct ipppd *is; struct isdn_ppp_comp_data data; @@ -533,8 +492,7 @@ ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned lon return -ENODEV; if ((r = get_arg((void *) arg, &val, sizeof(val) ))) return r; - idev->pppmru = val; - break; + return ippp_ccp_set_mru(idev->ccp, val); case PPPIOCSMPMRU: break; case PPPIOCSMPMTU: @@ -577,15 +535,9 @@ ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned lon break; case PPPIOCGCOMPRESSORS: { - unsigned long protos[8] = {0,}; - struct isdn_ppp_compressor *ipc = ipc_head; - while(ipc) { - j = ipc->num / (sizeof(long)*8); - i = ipc->num % (sizeof(long)*8); - if(j < 8) - protos[j] |= (0x1<next; - } + unsigned long protos[8]; + + ippp_ccp_get_compressors(protos); if ((r = set_arg((void *) arg,protos,8*sizeof(long) ))) return r; } @@ -660,6 +612,8 @@ ipppd_poll(struct file *file, poll_table * wait) if (!skb_queue_empty(&is->rq) || is->state & IPPP_NOBLOCK) { is->state &= ~IPPP_NOBLOCK; mask |= POLLIN | POLLRDNORM; + set_current_state(TASK_INTERRUPTIBLE); // FIXME + schedule_timeout(HZ); } out: @@ -927,7 +881,7 @@ static int isdn_ppp_skip_ac(isdn_net_dev *idev, struct sk_buff *skb) * get the PPP protocol header and pull skb * retval < 0 -> discard packet silently */ -static int isdn_ppp_strip_proto(struct sk_buff *skb) +int isdn_ppp_strip_proto(struct sk_buff *skb) { int proto; @@ -1028,13 +982,10 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto); isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit, idev->ppp_slot); } - if (lp->compflags & SC_DECOMP_ON) { - skb = isdn_ppp_decompress(skb, idev, lp->decompressor, - lp->decomp_stat, lp->reset, - PPP_COMP, &proto); - if (!skb) // decompression error - goto put; - } + skb = ippp_ccp_decompress(lp->ccp, skb, &proto); + if (!skb) // decompression error + goto put; + switch (proto) { case PPP_IPX: /* untested */ if (is->debug & 0x20) @@ -1092,20 +1043,21 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, /* Dont pop up ResetReq/Ack stuff to the daemon any longer - the job is done already */ if(skb->data[0] == CCP_RESETREQ || - skb->data[0] == CCP_RESETACK) - break; + skb->data[0] == CCP_RESETACK) { + kfree_skb(skb); + goto put; + } /* fall through */ default: isdn_ppp_fill_rq(skb->data, skb->len, proto, idev->ppp_slot); /* push data to pppd device */ kfree_skb(skb); - return; + goto put; } /* Reset hangup-timer */ idev->huptimer = 0; skb->dev = dev; - skb->mac.raw = skb->data; netif_rx(skb); /* net_dev->local->stats.rx_packets++; done in isdn_net.c */ put: @@ -1271,15 +1223,7 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) /* * normal (single link) or bundle compression */ - if (mlp->compflags & SC_COMP_ON) { - /* We send compressed only if both down- und upstream - compression is negotiated, that means, CCP is up */ - if (mlp->compflags & SC_DECOMP_ON) { - skb = isdn_ppp_compress(skb, &proto, mlp, ipt, 0); - } else { - printk(KERN_DEBUG "isdn_ppp: CCP not yet up - sending as-is\n"); - } - } + skb = ippp_ccp_compress(mlp->ccp, skb, &proto); if (ipt->debug & 0x24) printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto); @@ -2005,14 +1949,15 @@ isdn_ppp_hangup_slave(char *name) /* Push an empty CCP Data Frame up to the daemon to wake it up and let it generate a CCP Reset-Request or tear down CCP altogether */ -static void isdn_ppp_ccp_kick_up(void *priv) +static void isdn_ppp_ccp_kick_up(void *priv, unsigned int flags) { isdn_net_dev *idev = priv; + idev->pppcfg |= flags; isdn_ppp_fill_rq(NULL, 0, PPP_COMP, idev->ppp_slot); } -static void isdn_ppp_ccp_lp_kick_up(void *priv) +static void isdn_ppp_ccp_lp_kick_up(void *priv, unsigned int flags) { isdn_net_local *lp = priv; isdn_net_dev *idev; @@ -2022,39 +1967,10 @@ static void isdn_ppp_ccp_lp_kick_up(void *priv) return; } idev = list_entry(lp->online.next, isdn_net_dev, online); - isdn_ppp_ccp_kick_up(idev); + idev->pppcfg |= flags; + isdn_ppp_fill_rq(NULL, 0, PPP_COMP, idev->ppp_slot); } -/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary, - but absolutely nontrivial. The most abstruse problem we are facing is - that the generation, reception and all the handling of timeouts and - resends including proper request id management should be entirely left - to the (de)compressor, but indeed is not covered by the current API to - the (de)compressor. The API is a prototype version from PPP where only - some (de)compressors have yet been implemented and all of them are - rather simple in their reset handling. Especially, their is only one - outstanding ResetAck at a time with all of them and ResetReq/-Acks do - not have parameters. For this very special case it was sufficient to - just return an error code from the decompressor and have a single - reset() entry to communicate all the necessary information between - the framework and the (de)compressor. Bad enough, LZS is different - (and any other compressor may be different, too). It has multiple - histories (eventually) and needs to Reset each of them independently - and thus uses multiple outstanding Acks and history numbers as an - additional parameter to Reqs/Acks. - All that makes it harder to port the reset state engine into the - kernel because it is not just the same simple one as in (i)pppd but - it must be able to pass additional parameters and have multiple out- - standing Acks. We are trying to achieve the impossible by handling - reset transactions independent by their id. The id MUST change when - the data portion changes, thus any (de)compressor who uses more than - one resettable state must provide and recognize individual ids for - each individual reset transaction. The framework itself does _only_ - differentiate them by id, because it has no other semantics like the - (de)compressor might. - This looks like a major redesign of the interface would be nice, - but I don't have an idea how to do it better. */ - /* Send a CCP Reset-Request or Reset-Ack directly from the kernel. This is getting that lengthy because there is no simple "send-this-frame-out" function above but every wrapper does a bit different. Hope I guess @@ -2078,7 +1994,7 @@ static void isdn_ppp_ccp_xmit_reset(void *priv, int proto, "ippp: CCP cannot send reset - out of memory\n"); return; } - skb_reserve(skb, hl); + skb_reserve(skb, hl+16); /* We may need to stuff an address and control field first */ if (!(idev->pppcfg & SC_COMP_AC)) { @@ -2104,7 +2020,6 @@ static void isdn_ppp_ccp_xmit_reset(void *priv, int proto, } /* skb is now ready for xmit */ - printk(KERN_DEBUG "Sending CCP Frame:\n"); isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, -1, idev->ppp_slot); isdn_net_write_super(idev, skb); @@ -2125,510 +2040,19 @@ static void isdn_ppp_ccp_lp_xmit_reset(void *priv, int proto, isdn_ppp_ccp_xmit_reset(idev, proto, code, id, data, len); } -/* Allocate the reset state vector */ -static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(void) -{ - struct ippp_ccp_reset *r; - r = kmalloc(sizeof(struct ippp_ccp_reset), GFP_ATOMIC); - if(!r) { - printk(KERN_ERR "ippp_ccp: failed to allocate reset data" - " structure - no mem\n"); - return NULL; - } - memset(r, 0, sizeof(struct ippp_ccp_reset)); - printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r); - - return r; -} - -/* Destroy the reset state vector. Kill all pending timers first. */ -static void isdn_ppp_ccp_reset_free(struct ippp_ccp_reset *r) -{ - unsigned int id; - - printk(KERN_DEBUG "ippp_ccp: freeing reset data structure %p\n", r); - for (id = 0; id < 256; id++) { - if (r->rs[id]) - isdn_ppp_ccp_reset_free_state(r, id); - } - kfree(r); -} - -/* Free a given state and clear everything up for later reallocation */ -static void isdn_ppp_ccp_reset_free_state(struct ippp_ccp_reset *r, - unsigned char id) -{ - struct ippp_ccp_reset_state *rs; - - if (r->rs[id]) { - printk(KERN_DEBUG "ippp_ccp: freeing state for id %d\n", id); - rs = r->rs[id]; - /* Make sure the kernel will not call back later */ - if (rs->ta) - del_timer_sync(&rs->timer); - r->rs[id] = NULL; - kfree(rs); - } else { - printk(KERN_WARNING "ippp_ccp: id %d is not allocated\n", id); - } -} - -/* The timer callback function which is called when a ResetReq has timed out, - aka has never been answered by a ResetAck */ -static void isdn_ppp_ccp_timer_callback(unsigned long closure) -{ - struct ippp_ccp_reset_state *rs = - (struct ippp_ccp_reset_state *)closure; - - if(!rs) { - printk(KERN_ERR "ippp_ccp: timer cb with zero closure.\n"); - return; - } - if(rs->ta && rs->state == CCPResetSentReq) { - /* We are correct here */ - if(!rs->expra) { - /* Hmm, there is no Ack really expected. We can clean - up the state now, it will be reallocated if the - decompressor insists on another reset */ - rs->ta = 0; - isdn_ppp_ccp_reset_free_state(rs->icr, rs->id); - return; - } - printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n", - rs->id); - /* Push it again */ - rs->icr->xmit_reset(rs->icr->priv, PPP_CCP, CCP_RESETREQ, - rs->id, rs->data, rs->dlen); - /* Restart timer */ - rs->timer.expires = jiffies + HZ*5; - add_timer(&rs->timer); - } else { - printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n", - rs->state); - } -} - -/* Allocate a new reset transaction state */ -static struct ippp_ccp_reset_state * -isdn_ppp_ccp_reset_alloc_state(struct ippp_ccp_reset *icr, unsigned char id) -{ - struct ippp_ccp_reset_state *rs; - - if (icr->rs[id]) { - printk(KERN_WARNING "ippp_ccp: old state exists for id %d\n", - id); - return NULL; - } - rs = kmalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL); - if(!rs) - return NULL; - memset(rs, 0, sizeof(struct ippp_ccp_reset_state)); - rs->state = CCPResetIdle; - rs->icr = icr; - rs->id = id; - rs->timer.data = (unsigned long)rs; - rs->timer.function = isdn_ppp_ccp_timer_callback; - icr->rs[id] = rs; - return rs; -} - - -/* A decompressor wants a reset with a set of parameters - do what is - necessary to fulfill it */ -static void isdn_ppp_ccp_reset_trans(struct ippp_ccp_reset *icr, - struct isdn_ppp_resetparams *rp) -{ - struct ippp_ccp_reset_state *rs; - - if(rp->valid) { - /* The decompressor defines parameters by itself */ - if(rp->rsend) { - /* And he wants us to send a request */ - if(!(rp->idval)) { - printk(KERN_ERR "ippp_ccp: decompressor must" - " specify reset id\n"); - return; - } - if(icr->rs[rp->id]) { - /* There is already a transaction in existence - for this id. May be still waiting for a - Ack or may be wrong. */ - rs = icr->rs[rp->id]; - if(rs->state == CCPResetSentReq && rs->ta) { - printk(KERN_DEBUG "ippp_ccp: reset" - " trans still in progress" - " for id %d\n", rp->id); - } else { - printk(KERN_WARNING "ippp_ccp: reset" - " trans in wrong state %d for" - " id %d\n", rs->state, rp->id); - } - } else { - /* Ok, this is a new transaction */ - printk(KERN_DEBUG "ippp_ccp: new trans for id" - " %d to be started\n", rp->id); - rs = isdn_ppp_ccp_reset_alloc_state(icr, rp->id); - if(!rs) { - printk(KERN_ERR "ippp_ccp: out of mem" - " allocing ccp trans\n"); - return; - } - rs->state = CCPResetSentReq; - rs->expra = rp->expra; - if(rp->dtval) { - rs->dlen = rp->dlen; - memcpy(rs->data, rp->data, rp->dlen); - } - icr->xmit_reset(icr->priv, PPP_CCP, - CCP_RESETREQ, rs->id, - rs->data, rs->dlen); - /* Start the timer */ - rs->timer.expires = jiffies + 5*HZ; - add_timer(&rs->timer); - rs->ta = 1; - } - } else { - printk(KERN_DEBUG "ippp_ccp: no reset sent\n"); - } - } else { - /* The reset params are invalid. The decompressor does not - care about them, so we just send the minimal requests - and increase ids only when an Ack is received for a - given id */ - if(icr->rs[icr->lastid]) { - /* There is already a transaction in existence - for this id. May be still waiting for a - Ack or may be wrong. */ - rs = icr->rs[icr->lastid]; - if(rs->state == CCPResetSentReq && rs->ta) { - printk(KERN_DEBUG "ippp_ccp: reset" - " trans still in progress" - " for id %d\n", rp->id); - } else { - printk(KERN_WARNING "ippp_ccp: reset" - " trans in wrong state %d for" - " id %d\n", rs->state, rp->id); - } - } else { - printk(KERN_DEBUG "ippp_ccp: new trans for id" - " %d to be started\n", icr->lastid); - rs = isdn_ppp_ccp_reset_alloc_state(icr, icr->lastid); - if(!rs) { - printk(KERN_ERR "ippp_ccp: out of mem" - " allocing ccp trans\n"); - return; - } - rs->state = CCPResetSentReq; - /* We always expect an Ack if the decompressor doesnt - know better */ - rs->expra = 1; - rs->dlen = 0; - icr->xmit_reset(icr->priv, PPP_CCP, CCP_RESETREQ, - rs->id, NULL, 0); - /* Start the timer */ - rs->timer.expires = jiffies + 5*HZ; - add_timer(&rs->timer); - rs->ta = 1; - } - } -} - -/* An Ack was received for this id. This means we stop the timer and clean - up the state prior to calling the decompressors reset routine. */ -static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_ccp_reset *icr, - unsigned char id) -{ - struct ippp_ccp_reset_state *rs = icr->rs[id]; - - if(rs) { - if(rs->ta && rs->state == CCPResetSentReq) { - /* Great, we are correct */ - if(!rs->expra) - printk(KERN_DEBUG "ippp_ccp: ResetAck received" - " for id %d but not expected\n", id); - } else { - printk(KERN_INFO "ippp_ccp: ResetAck received out of" - "sync for id %d\n", id); - } - if(rs->ta) { - rs->ta = 0; - del_timer(&rs->timer); - } - isdn_ppp_ccp_reset_free_state(icr, id); - } else { - printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id" - " %d\n", id); - } - /* Make sure the simple reset stuff uses a new id next time */ - icr->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, isdn_net_dev *idev, - struct isdn_ppp_compressor *ipc, void *stat, - struct ippp_ccp_reset *icr, int cproto, int *proto) -{ - struct sk_buff *skb_out; - int len; - struct isdn_ppp_resetparams rsparm; - unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; - - if (!ipc) { - printk(KERN_DEBUG "ippp: no decompressor defined!\n"); - return skb; - } - if (!stat) - BUG(); - - if (*proto == cproto) { - // 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(idev->pppmru + PPP_HDRLEN); - len = ipc->decompress(stat, skb, skb_out, &rsparm); - kfree_skb(skb); - if (len <= 0) { - switch(len) { - case DECOMP_ERROR: - printk(KERN_INFO "ippp: decomp wants reset %s params\n", - rsparm.valid ? "with" : "without"); - - isdn_ppp_ccp_reset_trans(icr, &rsparm); - break; - case DECOMP_FATALERROR: - idev->pppcfg |= SC_DC_FERROR; - /* Kick ipppd to recognize the error */ - icr->kick_up(icr->priv); - 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 { - // uncompressed packets are fed through the decompressor to - // update the decompressor state - ipc->incomp(stat, skb, *proto); - return skb; - } -} - -/* - * 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, - isdn_net_local *lp, struct ipppd *is, - int type) -{ - int ret; - int new_proto; - struct isdn_ppp_compressor *compressor; - void *stat; - struct sk_buff *skb_out; - - /* we do not compress control protocols */ - if(*proto < 0 || *proto > 0x3fff) { - return skb_in; - } - - if (type) { /* type=1 => Link compression */ - return skb_in; - } else { - compressor = lp->compressor; - stat = lp->comp_stat; - new_proto = PPP_COMP; - } - - if (!compressor) { - printk(KERN_ERR "isdn_ppp: No compressor set!\n"); - return skb_in; - } - if (!stat) - BUG(); - - /* Allow for at least 150 % expansion (for now) */ - skb_out = alloc_skb(skb_in->len + skb_in->len/2 + 32 + - skb_headroom(skb_in), GFP_ATOMIC); - if(!skb_out) - return skb_in; - skb_reserve(skb_out, skb_headroom(skb_in)); - - ret = (compressor->compress)(stat,skb_in,skb_out,*proto); - if(!ret) { - dev_kfree_skb(skb_out); - return skb_in; - } - - dev_kfree_skb(skb_in); - *proto = new_proto; - return skb_out; -} /* * we received a CCP frame .. * not a clean solution, but we MUST handle a few cases in the kernel */ -static void isdn_ppp_receive_ccp(isdn_net_dev *idev, isdn_net_local *lp, - struct sk_buff *skb,int proto) +static void +isdn_ppp_receive_ccp(isdn_net_dev *idev, isdn_net_local *lp, + struct sk_buff *skb,int proto) { - struct ipppd *is; - struct ipppd *mis; - int len; - struct isdn_ppp_resetparams rsparm; - unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; - - printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n", - idev->ppp_slot); - - is = ipppd_get(idev->ppp_slot); - if (!is) - return; - - isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,idev->ppp_slot); - - mis = is; - - switch(skb->data[0]) { - case CCP_CONFREQ: - if (is->debug & 0x10) - printk(KERN_DEBUG "Disable compression here!\n"); - if (proto == PPP_CCP) - lp->compflags &= ~SC_COMP_ON; - else - idev->compflags &= ~SC_LINK_COMP_ON; - break; - case CCP_TERMREQ: - case CCP_TERMACK: - if (is->debug & 0x10) - printk(KERN_DEBUG "Disable (de)compression here!\n"); - if (proto == PPP_CCP) - lp->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON); - else - idev->compflags &= ~(SC_LINK_DECOMP_ON|SC_LINK_COMP_ON); - break; - case CCP_CONFACK: - /* if we RECEIVE an ackowledge we enable the decompressor */ - if(is->debug & 0x10) - printk(KERN_DEBUG "Enable decompression here!\n"); - if(proto == PPP_CCP) { - if (!lp->decomp_stat) - break; - lp->compflags |= SC_DECOMP_ON; - } else { - if (!idev->decomp_stat) - break; - lp->compflags |= SC_LINK_DECOMP_ON; - } - break; - - case CCP_RESETACK: - printk(KERN_DEBUG "Received ResetAck from peer\n"); - len = (skb->data[2] << 8) | skb->data[3]; - len -= 4; - - if(proto == PPP_CCP) { - /* If a reset Ack was outstanding for this id, then - clean up the state engine */ - isdn_ppp_ccp_reset_ack_rcvd(lp->reset, skb->data[1]); - if (lp->decomp_stat) - lp->decompressor-> - reset(lp->decomp_stat, - skb->data[0], - skb->data[1], - len ? &skb->data[4] : NULL, - len, NULL); - /* TODO: This is not easy to decide here */ - lp->compflags &= ~SC_DECOMP_DISCARD; - } else { - isdn_ppp_ccp_reset_ack_rcvd(idev->reset, skb->data[1]); - if(idev->decomp_stat) - idev->decompressor-> - reset(idev->decomp_stat, - skb->data[0], - skb->data[1], - len ? &skb->data[4] : NULL, - len, NULL); - /* TODO: neither here */ - lp->compflags &= ~SC_LINK_DECOMP_DISCARD; - } - break; - - case CCP_RESETREQ: - printk(KERN_DEBUG "Received ResetReq from peer\n"); - /* Receiving a ResetReq means we must reset our compressor */ - /* Set up reset params for the reset entry */ - memset(&rsparm, 0, sizeof(rsparm)); - rsparm.data = rsdata; - rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; - /* Isolate data length */ - len = (skb->data[2] << 8) | skb->data[3]; - len -= 4; - if(proto == PPP_CCP) { - if (lp->comp_stat) - lp->compressor-> - reset(lp->comp_stat, - skb->data[0], - skb->data[1], - len ? &skb->data[4] : NULL, - len, &rsparm); - } - else { - if (idev->comp_stat) - idev->compressor-> - reset(idev->comp_stat, - skb->data[0], - skb->data[1], - len ? &skb->data[4] : NULL, - len, &rsparm); - } - /* Ack the Req as specified by rsparm */ - if(rsparm.valid) { - /* Compressor reset handler decided how to answer */ - if(rsparm.rsend) { - /* We should send a Frame */ - isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK, - rsparm.idval ? rsparm.id - : skb->data[1], - rsparm.dtval ? - rsparm.data : NULL, - rsparm.dtval ? - rsparm.dlen : 0); - } else { - printk(KERN_DEBUG "ResetAck suppressed\n"); - } - } else { - /* We answer with a straight reflected Ack */ - isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK, - skb->data[1], - len ? &skb->data[4] : NULL, - len); - } - break; - } - ipppd_put(is); + if (proto == PPP_CCP) + ippp_ccp_receive_ccp(lp->ccp, skb); + else + ippp_ccp_receive_ccp(idev->ccp, skb); } @@ -2636,217 +2060,58 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *idev, isdn_net_local *lp, * Daemon sends a CCP frame ... */ -/* TODO: Clean this up with new Reset semantics */ - -/* I believe the CCP handling as-is is done wrong. Compressed frames - * should only be sent/received after CCP reaches UP state, which means - * both sides have sent CONF_ACK. Currently, we handle both directions - * independently, which means we may accept compressed frames too early - * (supposedly not a problem), but may also mean we send compressed frames - * too early, which may turn out to be a problem. - * This part of state machine should actually be handled by (i)pppd, but - * that's too big of a change now. --kai - */ - -/* Actually, we might turn this into an advantage: deal with the RFC in - * the old tradition of beeing generous on what we accept, but beeing - * strict on what we send. Thus we should just - * - accept compressed frames as soon as decompression is negotiated - * - send compressed frames only when decomp *and* comp are negotiated - * - drop rx compressed frames if we cannot decomp (instead of pushing them - * up to ipppd) - * and I tried to modify this file according to that. --abp - */ - static void isdn_ppp_send_ccp(isdn_net_dev *idev, isdn_net_local *lp, struct sk_buff *skb) { - struct ipppd *mis,*is; + struct ipppd *is; int proto; unsigned char *data; - if (!skb || skb->len < 3) + if (!skb || skb->len < 3) { + isdn_BUG(); return; - + } is = ipppd_get(idev->ppp_slot); - if (!is) + if (!is) { + isdn_BUG(); return; - + } /* Daemon may send with or without address and control field comp */ data = skb->data; - if (!(idev->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) { + if (data[0] == 0xff && data[1] == 0x03) { data += 2; if(skb->len < 5) return; } - proto = ((int)data[0]<<8)+data[1]; - if(proto != PPP_CCP && proto != PPP_CCPFRAG) - return; - printk(KERN_DEBUG "Received CCP frame from daemon:\n"); - isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,idev->ppp_slot); - - mis = is; - if (mis != is) - printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n"); - - switch(data[2]) { - case CCP_CONFREQ: - if (is->debug & 0x10) - printk(KERN_DEBUG "Disable decompression here!\n"); - if (proto == PPP_CCP) - lp->compflags &= ~SC_DECOMP_ON; - else - idev->compflags &= ~SC_LINK_DECOMP_ON; - break; - case CCP_TERMREQ: - case CCP_TERMACK: - if (is->debug & 0x10) - printk(KERN_DEBUG "Disable (de)compression here!\n"); - if (proto == PPP_CCP) - lp->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON); - else - idev->compflags &= ~(SC_LINK_DECOMP_ON|SC_LINK_COMP_ON); - break; - case CCP_CONFACK: - /* if we SEND an ackowledge we can/must enable the compressor */ - if (is->debug & 0x10) - printk(KERN_DEBUG "Enable compression here!\n"); - if (proto == PPP_CCP) { - if (!lp->compressor) - break; - lp->compflags |= SC_COMP_ON; - } else { - if (!idev->compressor) - break; - idev->compflags |= SC_LINK_COMP_ON; - } - break; - case CCP_RESETACK: - /* If we send a ACK we should reset our compressor */ - if(is->debug & 0x10) - printk(KERN_DEBUG "Reset decompression state here!\n"); - printk(KERN_DEBUG "ResetAck from daemon passed by\n"); - if (proto == PPP_CCP) { - /* link to master? */ - if (lp->comp_stat) - lp->compressor->reset(lp->comp_stat, 0, 0, - NULL, 0, NULL); - lp->compflags &= ~SC_COMP_DISCARD; - } else { - if (idev->comp_stat) - idev->compressor->reset(idev->comp_stat, - 0, 0, NULL, 0, NULL); - idev->compflags &= ~SC_LINK_COMP_DISCARD; - } + switch (proto) { + case PPP_CCP: + ippp_ccp_send_ccp(lp->ccp, skb); break; - case CCP_RESETREQ: - /* Just let it pass by */ - printk(KERN_DEBUG "ResetReq from daemon passed by\n"); + case PPP_CCPFRAG: + ippp_ccp_send_ccp(idev->ccp, skb); break; } - ipppd_put(is); -} - -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 ipppd *is, struct isdn_ppp_comp_data *data) +static int +isdn_ppp_set_compressor(struct ipppd *is, struct isdn_ppp_comp_data *data) { - struct isdn_ppp_compressor *ipc = ipc_head; - int ret; - void *stat; - int num = data->num; isdn_net_dev *idev = is->idev; isdn_net_local *lp; + struct ippp_ccp *ccp; if (!idev) return -ENODEV; lp = idev->mlp; - if(is->debug & 0x10) - printk(KERN_DEBUG "[%d] Set %s type %d\n",is->unit, - (data->flags&IPPP_COMP_FLAG_XMIT)?"compressor":"decompressor",num); - - /* If is has no valid reset state vector, we cannot allocate a - decompressor. The decompressor would cause reset transactions - sooner or later, and they need that vector. */ - - if (!(data->flags & IPPP_COMP_FLAG_XMIT)) { - if ((data->flags & IPPP_COMP_FLAG_LINK && !idev->reset) || - (!(data->flags & IPPP_COMP_FLAG_LINK) && !lp->reset)) { - printk(KERN_ERR "ippp_ccp: no reset data structure - can't" - " allow decompression.\n"); - return -ENOMEM; - } - } - while(ipc) { - if (ipc->num == num) { - stat = ipc->alloc(data); - if (stat) { - ret = ipc->init(stat,data,is->unit,0); - if(!ret) { - printk(KERN_ERR "Can't init (de)compression!\n"); - ipc->free(stat); - stat = NULL; - break; - } - } else { - printk(KERN_ERR "Can't alloc (de)compression!\n"); - break; - } + if (data->flags & IPPP_COMP_FLAG_LINK) + ccp = idev->ccp; + else + ccp = lp->ccp; - if (data->flags & IPPP_COMP_FLAG_XMIT) { - if (data->flags & IPPP_COMP_FLAG_LINK) { - if (idev->comp_stat) - idev->compressor->free(idev->comp_stat); - idev->comp_stat = stat; - idev->compressor = ipc; - } else { - if (lp->comp_stat) - lp->compressor->free(lp->comp_stat); - lp->comp_stat = stat; - lp->compressor = ipc; - } - } else { - if (data->flags & IPPP_COMP_FLAG_LINK) { - if (idev->decomp_stat) - idev->decompressor->free(idev->decomp_stat); - idev->decomp_stat = stat; - idev->decompressor = ipc; - } else { - if (lp->decomp_stat) - lp->decompressor->free(lp->decomp_stat); - lp->decomp_stat = stat; - lp->decompressor = ipc; - } - } - return 0; - } - ipc = ipc->next; - } - return -EINVAL; + return ippp_ccp_set_compressor(ccp, is->unit, data); } // ISDN_NET_ENCAP_SYNCPPP @@ -2861,19 +2126,10 @@ isdn_ppp_open(isdn_net_local *lp) #ifdef CONFIG_ISDN_PPP_VJ lp->slcomp = slhc_init(16, 16); #endif - lp->compressor = NULL; - lp->decompressor = NULL; - lp->comp_stat = NULL; - lp->decomp_stat = NULL; - lp->compflags = 0; - - lp->reset = isdn_ppp_ccp_reset_alloc(); - if (!lp->reset) { + lp->ccp = ippp_ccp_alloc(PPP_COMPFRAG, lp, isdn_ppp_ccp_lp_xmit_reset, + isdn_ppp_ccp_lp_kick_up); + if (!lp->ccp) return -ENOMEM; - } - lp->reset->priv = lp; - lp->reset->xmit_reset = isdn_ppp_ccp_lp_xmit_reset; - lp->reset->kick_up = isdn_ppp_ccp_lp_kick_up; return 0; } @@ -2885,17 +2141,7 @@ isdn_ppp_close(isdn_net_local *lp) slhc_free(lp->slcomp); lp->slcomp = NULL; #endif - if (lp->comp_stat) - lp->compressor->free(lp->comp_stat); - if (lp->decomp_stat) - lp->decompressor->free(lp->decomp_stat); - - lp->compressor = NULL; - lp->decompressor = NULL; - lp->comp_stat = NULL; - lp->decomp_stat = NULL; - - isdn_ppp_ccp_reset_free(lp->reset); + ippp_ccp_free(lp->ccp); } static int @@ -2908,6 +2154,13 @@ isdn_ppp_header(struct sk_buff *skb, struct net_device *dev, return IPPP_MAX_HEADER; } +static void +isdn_ppp_disconnected(isdn_net_dev *idev) +{ + if (idev->pppcfg & SC_ENABLE_IP) + isdn_net_offline(idev); +} + struct isdn_netif_ops isdn_ppp_ops = { .hard_start_xmit = isdn_ppp_start_xmit, .hard_header = isdn_ppp_header, @@ -2916,6 +2169,7 @@ struct isdn_netif_ops isdn_ppp_ops = { .type = ARPHRD_PPP, .receive = isdn_ppp_receive, .connected = isdn_ppp_wakeup_daemon, + .disconnected = isdn_ppp_disconnected, .bind = isdn_ppp_bind, .unbind = isdn_ppp_free, .open = isdn_ppp_open, diff --git a/drivers/isdn/i4l/isdn_ppp.h b/drivers/isdn/i4l/isdn_ppp.h index af6f50fd11db..d96866c70f01 100644 --- a/drivers/isdn/i4l/isdn_ppp.h +++ b/drivers/isdn/i4l/isdn_ppp.h @@ -15,10 +15,16 @@ extern struct file_operations isdn_ppp_fops; extern struct isdn_netif_ops isdn_ppp_ops; -extern int isdn_ppp_init(void); -extern void isdn_ppp_cleanup(void); -extern int isdn_ppp_dial_slave(char *); -extern int isdn_ppp_hangup_slave(char *); +int isdn_ppp_init(void); +void isdn_ppp_cleanup(void); +int isdn_ppp_dial_slave(char *); +int isdn_ppp_hangup_slave(char *); + +void +isdn_ppp_frame_log(char *info, char *data, int len, int maxlen, + int unit, int slot); +int +isdn_ppp_strip_proto(struct sk_buff *skb); #define IPPP_OPEN 0x01 #define IPPP_CONNECT 0x02 diff --git a/drivers/isdn/i4l/isdn_ppp_ccp.c b/drivers/isdn/i4l/isdn_ppp_ccp.c new file mode 100644 index 000000000000..c9fb94cd88cb --- /dev/null +++ b/drivers/isdn/i4l/isdn_ppp_ccp.c @@ -0,0 +1,586 @@ + +#include "isdn_ppp_ccp.h" +#include "isdn_common.h" +#include "isdn_ppp.h" +#include + +/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary, + but absolutely nontrivial. The most abstruse problem we are facing is + that the generation, reception and all the handling of timeouts and + resends including proper request id management should be entirely left + to the (de)compressor, but indeed is not covered by the current API to + the (de)compressor. The API is a prototype version from PPP where only + some (de)compressors have yet been implemented and all of them are + rather simple in their reset handling. Especially, their is only one + outstanding ResetAck at a time with all of them and ResetReq/-Acks do + not have parameters. For this very special case it was sufficient to + just return an error code from the decompressor and have a single + reset() entry to communicate all the necessary information between + the framework and the (de)compressor. Bad enough, LZS is different + (and any other compressor may be different, too). It has multiple + histories (eventually) and needs to Reset each of them independently + and thus uses multiple outstanding Acks and history numbers as an + additional parameter to Reqs/Acks. + All that makes it harder to port the reset state engine into the + kernel because it is not just the same simple one as in (i)pppd but + it must be able to pass additional parameters and have multiple out- + standing Acks. We are trying to achieve the impossible by handling + reset transactions independent by their id. The id MUST change when + the data portion changes, thus any (de)compressor who uses more than + one resettable state must provide and recognize individual ids for + each individual reset transaction. The framework itself does _only_ + differentiate them by id, because it has no other semantics like the + (de)compressor might. + This looks like a major redesign of the interface would be nice, + but I don't have an idea how to do it better. */ + +/* ====================================================================== */ + +/* Free a given state and clear everything up for later reallocation */ +static void +ippp_ccp_reset_free_state(struct ippp_ccp *ccp, unsigned char id) +{ + struct ippp_ccp_reset_state *rs = ccp->reset->rs[id]; + + if (!rs) + return; + + if (rs->ta) // FIXME? + del_timer_sync(&rs->timer); + + kfree(rs); + ccp->reset->rs[id] = NULL; +} + +static inline void +do_xmit_reset(struct ippp_ccp *ccp, unsigned char code, unsigned char id, + unsigned char *data, int len) +{ + ccp->xmit_reset(ccp->priv, + ccp->proto == PPP_COMP ? PPP_CCP : PPP_CCPFRAG, + code, id, data, len); +} + +/* The timer callback function which is called when a ResetReq has timed out, + aka has never been answered by a ResetAck */ +static void +isdn_ppp_ccp_timer_callback(unsigned long data) +{ + struct ippp_ccp_reset_state *rs = (struct ippp_ccp_reset_state *) data; + + if (!rs->ta) { + isdn_BUG(); + return; + } + if (rs->state != CCPResetSentReq) { + printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n", + rs->state); + rs->ta = 0; + return; + } + /* We are correct here */ + if (!rs->expra) { + /* Hmm, there is no Ack really expected. We can clean + up the state now, it will be reallocated if the + decompressor insists on another reset */ + rs->ta = 0; + ippp_ccp_reset_free_state(rs->ccp, rs->id); + return; + } + printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n", + rs->id); + /* Push it again */ + do_xmit_reset(rs->ccp, CCP_RESETREQ, rs->id, rs->data, rs->dlen); + + mod_timer(&rs->timer, jiffies + 5 * HZ); +} + +/* Allocate a new reset transaction state */ +static struct ippp_ccp_reset_state * +ippp_ccp_reset_alloc_state(struct ippp_ccp *ccp, unsigned char id) +{ + struct ippp_ccp_reset_state *rs; + + rs = kmalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL); + if(!rs) + return NULL; + memset(rs, 0, sizeof(struct ippp_ccp_reset_state)); + rs->state = CCPResetIdle; + rs->ccp = ccp; + rs->id = id; + init_timer(&rs->timer); + rs->timer.data = (unsigned long)rs; + rs->timer.function = isdn_ppp_ccp_timer_callback; + + ccp->reset->rs[id] = rs; + return rs; +} + +/* A decompressor wants a reset with a set of parameters - do what is + necessary to fulfill it */ +static void +ippp_ccp_reset_xmit(struct ippp_ccp *ccp, + struct isdn_ppp_resetparams *rp) +{ + struct ippp_ccp_reset_state *rs; + int id; + + if (rp->valid) { + /* The decompressor defines parameters by itself */ + if (!rp->rsend) + return; + + /* And it wants us to send a request */ + if (!rp->idval) { + isdn_BUG(); + return; + } + id = rp->id; + } else { + /* The reset params are invalid. The decompressor does not + care about them, so we just send the minimal requests + and increase ids only when an Ack is received for a + given id */ + id = ccp->reset->lastid++; + /* We always expect an Ack if the decompressor doesnt + know better */ + rp->expra = 1; + rp->dtval = 0; + } + rs = ccp->reset->rs[id]; + if (rs) { + printk(KERN_INFO "ippp_ccp: reset xmit in wrong state %d " + "for id %d (%d)\n", rs->state, id, rs->ta); + return; + } + /* Ok, this is a new transaction */ + printk(KERN_DEBUG "ippp_ccp: new xmit for id %d\n", id); + rs = ippp_ccp_reset_alloc_state(ccp, id); + if(!rs) { + printk(KERN_INFO "ippp_ccp: out of mem allocing ccp trans\n"); + return; + } + rs->expra = rp->expra; + rs->id = id; + if (rp->dtval) { + rs->dlen = rp->dlen; + memcpy(rs->data, rp->data, rp->dlen); + } else { + rs->dlen = 0; + } + + rs->state = CCPResetSentReq; + do_xmit_reset(rs->ccp, CCP_RESETREQ, rs->id, rs->data, rs->dlen); + + /* Start the timer */ + rs->timer.expires = jiffies + 5*HZ; + add_timer(&rs->timer); + rs->ta = 1; +} + +/* ====================================================================== */ + +struct ippp_ccp * +ippp_ccp_alloc(int proto, void *priv, + void (*xmit_reset)(void *priv, int proto, unsigned char code, + unsigned char id, unsigned char *data, + int len), + void (*kick_up)(void *priv, unsigned int flags)) +{ + struct ippp_ccp *ccp; + + ccp = kmalloc(sizeof(*ccp), GFP_ATOMIC); // FIXME + memset(ccp, 0, sizeof(*ccp)); + ccp->proto = proto; + ccp->mru = 1524; /* MRU, default 1524 */ + ccp->reset = kmalloc(sizeof(*ccp->reset), GFP_ATOMIC); // FIXME alloc together? + if (!ccp->reset) { + kfree(ccp); + return NULL; + } + memset(ccp->reset, 0, sizeof(*ccp->reset)); + ccp->priv = priv; + ccp->xmit_reset = xmit_reset; + ccp->kick_up = kick_up; + return ccp; +} + +void +ippp_ccp_free(struct ippp_ccp *ccp) +{ + int id; + + if (ccp->comp_stat) + ccp->compressor->free(ccp->comp_stat); + if (ccp->decomp_stat) + ccp->decompressor->free(ccp->decomp_stat); + + for (id = 0; id < 256; id++) { + if (ccp->reset->rs[id]) + ippp_ccp_reset_free_state(ccp, id); + } + kfree(ccp->reset); + kfree(ccp); +} + +int +ippp_ccp_set_mru(struct ippp_ccp *ccp, unsigned int mru) +{ + ccp->mru = mru; + return 0; +} + +/* + * compress a frame + * returns original skb if we did not compress the frame + * and a new skb otherwise + */ +struct sk_buff * +ippp_ccp_compress(struct ippp_ccp *ccp, struct sk_buff *skb_in, int *proto) +{ + struct sk_buff *skb; + + if (!(ccp->compflags & (SC_COMP_ON|SC_DECOMP_ON))) { + /* We send compressed only if both down- und upstream + compression is negotiated, that means, CCP is up */ + return skb_in; + } + /* we do not compress control protocols */ + if (*proto < 0 || *proto > 0x3fff) { + return skb_in; + } + if (!ccp->compressor || !ccp->comp_stat) { + isdn_BUG(); + return skb_in; + } + /* Allow for at least 150 % expansion (for now) */ + skb = alloc_skb(skb_in->len*2 + skb_headroom(skb_in), GFP_ATOMIC); + if (!skb) + return skb_in; + + skb_reserve(skb, skb_headroom(skb_in)); + if (!ccp->compressor->compress(ccp->comp_stat, skb_in, skb, *proto)) { + dev_kfree_skb(skb); + return skb_in; + } + isdn_ppp_frame_log("comp in:", skb_in->data, skb_in->len, 20, -1, -1); + isdn_ppp_frame_log("comp out:", skb->data, skb->len, 20, -1, -1); + dev_kfree_skb(skb_in); + *proto = ccp->proto; + return skb; +} + +/* + * decompress packet + * + * proto is updated to protocol field of uncompressed packet. + * retval: decompressed packet, + * same packet if uncompressed, + * NULL if decompression error + */ + +struct sk_buff * +ippp_ccp_decompress(struct ippp_ccp *ccp, struct sk_buff *skb_in, int *proto) +{ + struct sk_buff *skb; + struct isdn_ppp_resetparams rsparm; + unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; + int len; + + if (!(ccp->compflags & SC_DECOMP_ON)) { + return skb_in; + } + if (!ccp->decompressor || !ccp->decomp_stat) { + isdn_BUG(); + return skb_in; + } + if (*proto != ccp->proto) { + /* uncompressed packets are fed through the decompressor to + * update the decompressor state */ + ccp->decompressor->incomp(ccp->decomp_stat, skb_in, *proto); + return skb_in; + } + skb = dev_alloc_skb(ccp->mru + PPP_HDRLEN); // FIXME oom? + + // Set up reset params for the decompressor + memset(&rsparm, 0, sizeof(rsparm)); + rsparm.data = rsdata; + rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; + + len = ccp->decompressor->decompress(ccp->decomp_stat, skb_in, skb, + &rsparm); + isdn_ppp_frame_log("deco in:", skb_in->data, skb_in->len, 20, -1, -1); + isdn_ppp_frame_log("deco out:", skb->data, skb->len, 20, -1, -1); + kfree_skb(skb_in); + + if (len <= 0) { + switch(len) { + case DECOMP_ERROR: + printk(KERN_INFO "ippp: decomp wants reset with%s params\n", + rsparm.valid ? "" : "out"); + + ippp_ccp_reset_xmit(ccp, &rsparm); + break; + case DECOMP_FATALERROR: + /* Kick ipppd to recognize the error */ + ccp->kick_up(ccp->priv, SC_DC_FERROR); + break; + } + kfree_skb(skb); + return NULL; + } + *proto = isdn_ppp_strip_proto(skb); + if (*proto < 0) { + kfree_skb(skb); + return NULL; + } + return skb; +} + +/* An Ack was received for this id. This means we stop the timer and clean + up the state prior to calling the decompressors reset routine. */ +static void +isdn_ppp_ccp_reset_ack_rcvd(struct ippp_ccp *ccp, unsigned char id) +{ + struct ippp_ccp_reset_state *rs = ccp->reset->rs[id]; + + if (!rs) { + printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id" + " %d\n", id); + return; + } + + if (rs->ta && rs->state == CCPResetSentReq) { + /* Great, we are correct */ + if(!rs->expra) + printk(KERN_DEBUG "ippp_ccp: ResetAck received" + " for id %d but not expected\n", id); + } else { + printk(KERN_INFO "ippp_ccp: ResetAck received out of" + "sync for id %d\n", id); + } + if(rs->ta) { + rs->ta = 0; + del_timer(&rs->timer); + } + ippp_ccp_reset_free_state(ccp, id); +} + +void +ippp_ccp_receive_ccp(struct ippp_ccp *ccp, struct sk_buff *skb) +{ + int len; + struct isdn_ppp_resetparams rsparm; + unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; + + isdn_ppp_frame_log("ccp-recv", skb->data, skb->len, 32, -1, -1); + + switch(skb->data[0]) { + case CCP_CONFREQ: + if (ccp->debug & 0x10) + printk(KERN_DEBUG "Disable compression here!\n"); + + ccp->compflags &= ~SC_COMP_ON; + break; + case CCP_TERMREQ: + case CCP_TERMACK: + if (ccp->debug & 0x10) + printk(KERN_DEBUG "Disable (de)compression here!\n"); + + ccp->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON); + break; + case CCP_CONFACK: + /* if we RECEIVE an ackowledge we enable the decompressor */ + if (ccp->debug & 0x10) + printk(KERN_DEBUG "Enable decompression here!\n"); + + if (!ccp->decomp_stat) + break; + ccp->compflags |= SC_DECOMP_ON; + break; + case CCP_RESETACK: + printk(KERN_DEBUG "Received ResetAck from peer\n"); + len = (skb->data[2] << 8) | skb->data[3]; + len -= 4; + + /* If a reset Ack was outstanding for this id, then + clean up the state engine */ + isdn_ppp_ccp_reset_ack_rcvd(ccp, skb->data[1]); + if (ccp->decomp_stat) + ccp->decompressor->reset(ccp->decomp_stat, + skb->data[0], skb->data[1], + len ? &skb->data[4] : NULL, + len, NULL); + /* TODO: This is not easy to decide here */ + ccp->compflags &= ~SC_DECOMP_DISCARD; + break; + case CCP_RESETREQ: + printk(KERN_DEBUG "Received ResetReq from peer\n"); + /* Receiving a ResetReq means we must reset our compressor */ + /* Set up reset params for the reset entry */ + memset(&rsparm, 0, sizeof(rsparm)); + rsparm.data = rsdata; + rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; + /* Isolate data length */ + len = (skb->data[2] << 8) | skb->data[3]; + len -= 4; + if (ccp->comp_stat) + ccp->compressor->reset(ccp->comp_stat, + skb->data[0], skb->data[1], + len ? &skb->data[4] : NULL, + len, &rsparm); + /* Ack the Req as specified by rsparm */ + if (rsparm.valid) { + /* Compressor reset handler decided how to answer */ + if (!rsparm.rsend) { + printk(KERN_DEBUG "ResetAck suppressed\n"); + return; + } + /* We should send a Frame */ + do_xmit_reset(ccp, CCP_RESETACK, + rsparm.idval ? rsparm.id : skb->data[1], + rsparm.data, + rsparm.dtval ? rsparm.dlen : 0); + return; + } + /* We answer with a straight reflected Ack */ + do_xmit_reset(ccp, CCP_RESETACK, skb->data[1], + skb->data + 4, len); + } +} + +void +ippp_ccp_send_ccp(struct ippp_ccp *ccp, struct sk_buff *skb) +{ + isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, -1, -1); + + switch (skb->data[2]) { + case CCP_CONFREQ: + if (ccp->debug & 0x10) + printk(KERN_DEBUG "Disable decompression here!\n"); + + ccp->compflags &= ~SC_DECOMP_ON; + break; + case CCP_TERMREQ: + case CCP_TERMACK: + if (ccp->debug & 0x10) + printk(KERN_DEBUG "Disable (de)compression here!\n"); + + ccp->compflags &= ~(SC_DECOMP_ON|SC_COMP_ON); + break; + case CCP_CONFACK: + /* if we SEND an ackowledge we can/must enable the compressor */ + if (ccp->debug & 0x10) + printk(KERN_DEBUG "Enable compression here!\n"); + + if (!ccp->compressor) + break; + + ccp->compflags |= SC_COMP_ON; + break; + case CCP_RESETACK: + /* If we send a ACK we should reset our compressor */ + if (ccp->debug & 0x10) + printk(KERN_DEBUG "Reset decompression state here!\n"); + + printk(KERN_DEBUG "ResetAck from daemon passed by\n"); + + if (!ccp->comp_stat) + break; + + ccp->compressor->reset(ccp->comp_stat, 0, 0, NULL, 0, NULL); + ccp->compflags &= ~SC_COMP_DISCARD; + break; + case CCP_RESETREQ: + /* Just let it pass by */ + printk(KERN_DEBUG "ResetReq from daemon passed by\n"); + break; + } +} + +static struct isdn_ppp_compressor *ipc_head = NULL; + +int +ippp_ccp_set_compressor(struct ippp_ccp *ccp, int unit, + struct isdn_ppp_comp_data *data) +{ + struct isdn_ppp_compressor *ipc = ipc_head; + int ret; + void *stat; + int num = data->num; + + if (ccp->debug & 0x10) + printk(KERN_DEBUG "[%d] Set %scompressor type %d\n", unit, + data->flags & IPPP_COMP_FLAG_XMIT ? "" : "de", num); + + for (ipc = ipc_head; ipc; ipc = ipc->next) { + if (ipc->num != num) + continue; + + stat = ipc->alloc(data); + if (!stat) { + printk(KERN_ERR "Can't alloc (de)compression!\n"); + break; + } + ret = ipc->init(stat, data, unit, 0); + if(!ret) { + printk(KERN_ERR "Can't init (de)compression!\n"); + ipc->free(stat); + break; + } + if (data->flags & IPPP_COMP_FLAG_XMIT) { + if (ccp->comp_stat) + ccp->compressor->free(ccp->comp_stat); + ccp->comp_stat = stat; + ccp->compressor = ipc; + } else { + if (ccp->decomp_stat) + ccp->decompressor->free(ccp->decomp_stat); + ccp->decomp_stat = stat; + ccp->decompressor = ipc; + } + return 0; + } + return -EINVAL; +} + +void +ippp_ccp_get_compressors(unsigned long protos[8]) +{ + struct isdn_ppp_compressor *ipc; + int i, j; + + memset(protos, 0, sizeof(unsigned long) * 8); + for (ipc = ipc_head; ipc; ipc = ipc->next) { + j = ipc->num / (sizeof(long)*8); + i = ipc->num % (sizeof(long)*8); + if (j < 8) + protos[j] |= 1 << i; + } +} + +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; +} + diff --git a/drivers/isdn/i4l/isdn_ppp_ccp.h b/drivers/isdn/i4l/isdn_ppp_ccp.h new file mode 100644 index 000000000000..71d0cfc3bbb3 --- /dev/null +++ b/drivers/isdn/i4l/isdn_ppp_ccp.h @@ -0,0 +1,53 @@ + +#include +#include + +struct ippp_ccp { + int proto; + struct isdn_ppp_compressor *compressor; + struct isdn_ppp_compressor *decompressor; + void *comp_stat; + void *decomp_stat; + unsigned long compflags; + struct ippp_ccp_reset *reset; + int mru; + int debug; + void *priv; + void (*xmit_reset)(void *priv, int proto, unsigned char code, + unsigned char id, unsigned char *data, int len); + void (*kick_up)(void *priv, unsigned int flags); +}; + +struct ippp_ccp * +ippp_ccp_alloc(int proto, void *priv, + void (*xmit_reset)(void *priv, int proto, unsigned char code, + unsigned char id, unsigned char *data, + int len), + void (*kick_up)(void *priv, unsigned int flags)); + +void +ippp_ccp_free(struct ippp_ccp *ccp); + +int +ippp_ccp_set_mru(struct ippp_ccp *ccp, unsigned int mru); + +struct sk_buff * +ippp_ccp_compress(struct ippp_ccp *ccp, struct sk_buff *skb, int *proto); + +struct sk_buff * +ippp_ccp_decompress(struct ippp_ccp *ccp, struct sk_buff *skb, int *proto); + +void +ippp_ccp_send_ccp(struct ippp_ccp *ccp, struct sk_buff *skb); + +void +ippp_ccp_receive_ccp(struct ippp_ccp *ccp, struct sk_buff *skb); + +void +ippp_ccp_get_compressors(unsigned long protos[8]); + +int +ippp_ccp_set_compressor(struct ippp_ccp *ccp, int unit, + struct isdn_ppp_comp_data *data); + + diff --git a/include/linux/isdn.h b/include/linux/isdn.h index fcabee098ab1..64c9c128f46d 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -359,14 +359,7 @@ typedef struct isdn_net_local_s { #ifdef CONFIG_ISDN_PPP unsigned int mpppcfg; long mp_seqno; - - struct isdn_ppp_compressor *compressor; - struct isdn_ppp_compressor *decompressor; - void *comp_stat; - void *decomp_stat; - unsigned long compflags; - struct ippp_ccp_reset *reset; - + struct ippp_ccp *ccp; unsigned long debug; #ifdef CONFIG_ISDN_PPP_VJ unsigned char *cbuf; @@ -434,15 +427,8 @@ typedef struct isdn_net_dev_s { struct list_head global_list; /* global list of all isdn_net_devs */ #ifdef CONFIG_ISDN_PPP unsigned int pppcfg; - unsigned int pppmru; unsigned int pppseq; /* last seq no seen */ - - struct isdn_ppp_compressor *compressor; - struct isdn_ppp_compressor *decompressor; - void *comp_stat; - void *decomp_stat; - unsigned long compflags; - struct ippp_ccp_reset *reset; + struct ippp_ccp *ccp; unsigned long debug; ippp_bundle * pb; /* pointer to the common bundle structure diff --git a/include/linux/isdn_ppp.h b/include/linux/isdn_ppp.h index 42418a8aaf08..2c1fc99849f2 100644 --- a/include/linux/isdn_ppp.h +++ b/include/linux/isdn_ppp.h @@ -8,7 +8,6 @@ #ifndef _LINUX_ISDN_PPP_H #define _LINUX_ISDN_PPP_H - #define CALLTYPE_INCOMING 0x1 #define CALLTYPE_OUTGOING 0x2 #define CALLTYPE_CALLBACK 0x4 @@ -64,7 +63,8 @@ struct isdn_ppp_comp_data { #include - +#include +#include #define DECOMP_ERR_NOMEM (-10) @@ -172,8 +172,8 @@ enum ippp_ccp_reset_states { struct ippp_ccp_reset_state { enum ippp_ccp_reset_states state; /* State of this transaction */ - struct ippp_ccp_reset *icr; /* Backlink */ - unsigned char id; /* Backlink id index */ + struct ippp_ccp *ccp; /* Backlink */ + unsigned char id; /* id index */ unsigned char ta:1; /* The timer is active (flag) */ unsigned char expra:1; /* We expect a ResetAck at all */ int dlen; /* Databytes stored in data */ @@ -189,10 +189,6 @@ struct ippp_ccp_reset_state { struct ippp_ccp_reset { struct ippp_ccp_reset_state *rs[256]; /* One per possible id */ unsigned char lastid; /* Last id allocated by the engine */ - void (*xmit_reset)(void *priv, int proto, unsigned char code, - unsigned char id, unsigned char *data, int len); - void (*kick_up)(void *priv); - void *priv; }; #endif /* __KERNEL__ */ -- cgit v1.2.3 From 949d4e94ce3b9023c165ec9ea2651b56fb0b4847 Mon Sep 17 00:00:00 2001 From: Kai Germaschewski Date: Wed, 16 Oct 2002 01:18:31 -0500 Subject: ISDN/PPP: CCP flags handling Let isdn_ppp_ccp.c take care of keeping state / flags by itself. --- drivers/isdn/i4l/isdn_ppp.c | 14 ++++++++------ drivers/isdn/i4l/isdn_ppp_ccp.c | 11 +++++++++-- drivers/isdn/i4l/isdn_ppp_ccp.h | 20 ++++++++++++++++++-- include/linux/isdn_ppp.h | 9 --------- 4 files changed, 35 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 8595e4e13e70..1de1ca9ef90d 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -49,7 +49,7 @@ isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, /* New CCP stuff */ static void -isdn_ppp_ccp_kick_up(void *priv, unsigned int flags); +isdn_ppp_ccp_kick_up(void *priv); static void isdn_ppp_ccp_xmit_reset(void *priv, int proto, unsigned char code, @@ -438,6 +438,7 @@ ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned lon int r; struct ipppd *is; struct isdn_ppp_comp_data data; + unsigned int cfg; is = (struct ipppd *) file->private_data; idev = is->idev; @@ -488,7 +489,8 @@ ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned lon case PPPIOCGFLAGS: /* get configuration flags */ if (!idev) return -ENODEV; - if ((r = set_arg((void *) arg, &idev->pppcfg, sizeof(idev->pppcfg) ))) + cfg = idev->pppcfg | ippp_ccp_get_flags(idev->ccp); + if ((r = set_arg((void *) arg, &cfg, sizeof(cfg) ))) return r; break; case PPPIOCSFLAGS: /* set configuration flags */ @@ -498,8 +500,10 @@ ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned lon return r; } if ((val & SC_ENABLE_IP) && !(idev->pppcfg & SC_ENABLE_IP)) { + idev->pppcfg = val; /* OK .. we are ready to send buffers */ isdn_net_online(idev); + break; } idev->pppcfg = val; break; @@ -1926,15 +1930,14 @@ isdn_ppp_hangup_slave(char *name) /* Push an empty CCP Data Frame up to the daemon to wake it up and let it generate a CCP Reset-Request or tear down CCP altogether */ -static void isdn_ppp_ccp_kick_up(void *priv, unsigned int flags) +static void isdn_ppp_ccp_kick_up(void *priv) { isdn_net_dev *idev = priv; - idev->pppcfg |= flags; isdn_ppp_fill_rq(NULL, 0, PPP_COMP, idev->ppp_slot); } -static void isdn_ppp_ccp_lp_kick_up(void *priv, unsigned int flags) +static void isdn_ppp_ccp_lp_kick_up(void *priv) { isdn_net_local *lp = priv; isdn_net_dev *idev; @@ -1944,7 +1947,6 @@ static void isdn_ppp_ccp_lp_kick_up(void *priv, unsigned int flags) return; } idev = list_entry(lp->online.next, isdn_net_dev, online); - idev->pppcfg |= flags; isdn_ppp_fill_rq(NULL, 0, PPP_COMP, idev->ppp_slot); } diff --git a/drivers/isdn/i4l/isdn_ppp_ccp.c b/drivers/isdn/i4l/isdn_ppp_ccp.c index c9fb94cd88cb..6e150532958a 100644 --- a/drivers/isdn/i4l/isdn_ppp_ccp.c +++ b/drivers/isdn/i4l/isdn_ppp_ccp.c @@ -185,7 +185,7 @@ ippp_ccp_alloc(int proto, void *priv, void (*xmit_reset)(void *priv, int proto, unsigned char code, unsigned char id, unsigned char *data, int len), - void (*kick_up)(void *priv, unsigned int flags)) + void (*kick_up)(void *priv)) { struct ippp_ccp *ccp; @@ -230,6 +230,12 @@ ippp_ccp_set_mru(struct ippp_ccp *ccp, unsigned int mru) return 0; } +unsigned int +ippp_ccp_get_flags(struct ippp_ccp *ccp); +{ + return idev->ccp->compflags & (SC_DC_ERROR|SC_DC_FERROR); +} + /* * compress a frame * returns original skb if we did not compress the frame @@ -322,8 +328,9 @@ ippp_ccp_decompress(struct ippp_ccp *ccp, struct sk_buff *skb_in, int *proto) ippp_ccp_reset_xmit(ccp, &rsparm); break; case DECOMP_FATALERROR: + ccp->compflags |= SC_DC_FERROR; /* Kick ipppd to recognize the error */ - ccp->kick_up(ccp->priv, SC_DC_FERROR); + ccp->kick_up(ccp->priv); break; } kfree_skb(skb); diff --git a/drivers/isdn/i4l/isdn_ppp_ccp.h b/drivers/isdn/i4l/isdn_ppp_ccp.h index 71d0cfc3bbb3..ddee87c34375 100644 --- a/drivers/isdn/i4l/isdn_ppp_ccp.h +++ b/drivers/isdn/i4l/isdn_ppp_ccp.h @@ -2,6 +2,19 @@ #include #include +/* for ippp_ccp::flags */ + +#define SC_DECOMP_ON 0x01 +#define SC_COMP_ON 0x02 +#define SC_DECOMP_DISCARD 0x04 +#define SC_COMP_DISCARD 0x08 + +/* SC_DC_ERROR/FERROR go in here as well, but are defined elsewhere + + #define SC_DC_FERROR 0x00800000 + #define SC_DC_ERROR 0x00400000 +*/ + struct ippp_ccp { int proto; struct isdn_ppp_compressor *compressor; @@ -15,7 +28,7 @@ struct ippp_ccp { void *priv; void (*xmit_reset)(void *priv, int proto, unsigned char code, unsigned char id, unsigned char *data, int len); - void (*kick_up)(void *priv, unsigned int flags); + void (*kick_up)(void *priv); }; struct ippp_ccp * @@ -23,7 +36,7 @@ ippp_ccp_alloc(int proto, void *priv, void (*xmit_reset)(void *priv, int proto, unsigned char code, unsigned char id, unsigned char *data, int len), - void (*kick_up)(void *priv, unsigned int flags)); + void (*kick_up)(void *priv)); void ippp_ccp_free(struct ippp_ccp *ccp); @@ -31,6 +44,9 @@ ippp_ccp_free(struct ippp_ccp *ccp); int ippp_ccp_set_mru(struct ippp_ccp *ccp, unsigned int mru); +unsigned int +ippp_ccp_get_flags(struct ippp_ccp *ccp); + struct sk_buff * ippp_ccp_compress(struct ippp_ccp *ccp, struct sk_buff *skb, int *proto); diff --git a/include/linux/isdn_ppp.h b/include/linux/isdn_ppp.h index 2c1fc99849f2..ec6016c37421 100644 --- a/include/linux/isdn_ppp.h +++ b/include/linux/isdn_ppp.h @@ -38,15 +38,6 @@ struct pppcallinfo #define SC_OUT_SHORT_SEQ 0x00000800 #define SC_IN_SHORT_SEQ 0x00004000 -#define SC_DECOMP_ON 0x01 -#define SC_COMP_ON 0x02 -#define SC_DECOMP_DISCARD 0x04 -#define SC_COMP_DISCARD 0x08 -#define SC_LINK_DECOMP_ON 0x10 -#define SC_LINK_COMP_ON 0x20 -#define SC_LINK_DECOMP_DISCARD 0x40 -#define SC_LINK_COMP_DISCARD 0x80 - #define ISDN_PPP_COMP_MAX_OPTIONS 16 #define IPPP_COMP_FLAG_XMIT 0x1 -- cgit v1.2.3 From 1f4fa3148bcc7c296ca978456cac92a93276e9e1 Mon Sep 17 00:00:00 2001 From: Kai Germaschewski Date: Wed, 16 Oct 2002 01:21:40 -0500 Subject: ISDN/PPP: Reference struct ipppd directly Instead of just recording the slot number and then retrieving the ipppd via that, we can now just keep a pointer and get a reference which makes sure that it does not go away until we drop the reference. --- drivers/isdn/i4l/isdn_net_lib.c | 2 +- drivers/isdn/i4l/isdn_ppp.c | 209 ++++++++++++++++------------------------ include/linux/isdn.h | 2 +- 3 files changed, 86 insertions(+), 127 deletions(-) (limited to 'include') diff --git a/drivers/isdn/i4l/isdn_net_lib.c b/drivers/isdn/i4l/isdn_net_lib.c index 681270e68709..ba0144200c1f 100644 --- a/drivers/isdn/i4l/isdn_net_lib.c +++ b/drivers/isdn/i4l/isdn_net_lib.c @@ -369,7 +369,7 @@ isdn_net_addif(char *name, isdn_net_local *mlp) idev->pre_channel = -1; idev->exclusive = -1; - idev->ppp_slot = -1; + idev->ipppd = NULL; idev->pppbind = -1; init_timer(&idev->dial_timer); diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index d006767b508d..83e24bc6426d 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -32,15 +32,23 @@ struct ipppd { atomic_t refcnt; }; +/* We use reference counting for struct ipppd. It is alloced on + * open() on /dev/ipppX and saved into file->private, making for one + * reference. release() will release this reference, after all other + * references are gone, the destructor frees it. + * + * Another reference is taken by isdn_ppp_bind() and freed by + * isdn_ppp_unbind(). The callbacks from isdn_net_lib.c happen only + * between isdn_ppp_bind() and isdn_ppp_unbind(), i.e. access to + * idev->ipppd is safe without further locking. + */ + /* Prototypes */ static void isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, struct sk_buff *skb, int proto); static int isdn_ppp_if_get_unit(char *namebuf); static int isdn_ppp_set_compressor(struct ipppd *is,struct isdn_ppp_comp_data *); -static void -ipppd_closewait(struct ipppd *ipppd); - static void isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb,int proto); @@ -183,16 +191,12 @@ isdn_ppp_push_header(isdn_net_dev *idev, struct sk_buff *skb, u16 proto) * in this case we bind another lp to the master device */ static void -isdn_ppp_free(isdn_net_dev *idev) +isdn_ppp_unbind(isdn_net_dev *idev) { - unsigned long flags; struct ipppd *is; // FIXME much of this wants to rather happen when disconnected() - save_flags(flags); - cli(); - #ifdef CONFIG_ISDN_MPP spin_lock(&idev->pb->lock); if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */ @@ -201,32 +205,29 @@ isdn_ppp_free(isdn_net_dev *idev) lp->netdev->pb->ref_ct--; spin_unlock(&lp->netdev->pb->lock); #endif /* CONFIG_ISDN_MPP */ - if (idev->ppp_slot < 0 || idev->ppp_slot > ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n", - __FUNCTION__ , idev->ppp_slot); - restore_flags(flags); + is = idev->ipppd; + if (!is) { + isdn_BUG(); return; } - is = ipppd_get(idev->ppp_slot); - if (!is) - return; - - if (is->state & IPPP_CONNECT) - ipppd_closewait(is); /* force wakeup on ippp device */ - - else if (is->state & IPPP_ASSIGNED) + if (is->state & IPPP_CONNECT) { + is->state = IPPP_CLOSEWAIT; + wake_up(&is->wq); + } else if (is->state & IPPP_ASSIGNED) { is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGNED' state */ - + } else { + isdn_BUG(); + } if (is->debug & 0x1) - printk(KERN_DEBUG "isdn_ppp_free %d %p\n", idev->ppp_slot, is->idev); + printk(KERN_DEBUG "isdn_ppp_unbind %p %p\n", idev, is); - is->idev = NULL; /* link is down .. set lp to NULL */ - idev->ppp_slot = -1; /* is this OK ?? */ - ipppd_put(is); + is->idev = NULL; + /* lose the reference we took on isdn_ppp_bind */ + ipppd_put(is); + idev->ipppd = NULL; ippp_ccp_free(idev->ccp); - restore_flags(flags); return; } @@ -241,15 +242,20 @@ isdn_ppp_bind(isdn_net_dev *idev) unsigned long flags; int retval = 0; + if (idev->ipppd) { + isdn_BUG(); + return 0; + } + spin_lock_irqsave(&ipppds_lock, flags); if (idev->pppbind < 0) { /* device bound to ippp device ? */ struct list_head *l; - char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */ - memset(exclusive, 0, ISDN_MAX_CHANNELS); + char exclusive[NR_IPPPDS]; /* exclusive flags */ + memset(exclusive, 0, NR_IPPPDS); /* step through net devices to find exclusive minors */ list_for_each(l, &isdn_net_devs) { isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list); - if (p->pppbind >= 0) + if (p->pppbind >= 0 && p->pppbind < NR_IPPPDS) exclusive[p->pppbind] = 1; } /* @@ -287,14 +293,13 @@ isdn_ppp_bind(isdn_net_dev *idev) goto err; } - ipppds[i]->state = IPPP_OPEN | IPPP_ASSIGNED; /* assigned to a netdevice but not connected */ - - spin_unlock_irqrestore(&ipppds_lock, flags); - - ipppds[i]->idev = idev; ipppds[i]->unit = unit; + ipppds[i]->state = IPPP_OPEN | IPPP_ASSIGNED; + ipppds[i]->idev = idev; + /* we hold a reference until isdn_ppp_unbind() */ + idev->ipppd = __ipppd_get(ipppds[i]); + spin_unlock_irqrestore(&ipppds_lock, flags); - idev->ppp_slot = i; idev->pppcfg = 0; /* config flags */ /* seq no last seen, maybe set to bundle min, when joining? */ idev->pppseq = -1; @@ -315,8 +320,11 @@ isdn_ppp_bind(isdn_net_dev *idev) retval = isdn_ppp_mp_init(lp, NULL); #endif /* CONFIG_ISDN_MPP */ out: - if (retval) - ipppds[i]->state = IPPP_OPEN; + if (retval) { + idev->ipppd->state = IPPP_OPEN; + ipppd_put(idev->ipppd); + idev->ipppd = NULL; + } return retval; @@ -331,28 +339,12 @@ isdn_ppp_bind(isdn_net_dev *idev) */ static void -isdn_ppp_wakeup_daemon(isdn_net_dev *idev) +isdn_ppp_connected(isdn_net_dev *idev) { - struct ipppd *ipppd = ipppd_get(idev->ppp_slot); + struct ipppd *ipppd = idev->ipppd; - if (!ipppd) - return; - ipppd->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK; wake_up(&ipppd->wq); - ipppd_put(ipppd); -} - -/* - * there was a hangup on the netdevice - * force wakeup of the ippp device - * go into 'device waits for release' state - */ -static void -ipppd_closewait(struct ipppd *ipppd) -{ - wake_up(&ipppd->wq); - ipppd->state = IPPP_CLOSEWAIT; } /* @@ -837,7 +829,7 @@ ipppd_write(struct file *file, const char *buf, size_t count, loff_t *off) } 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,is->unit,idev->ppp_slot); + isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,is->unit,-1); } isdn_ppp_send_ccp(idev,idev->mlp,skb); /* keeps CCP/compression states in sync */ @@ -976,22 +968,22 @@ static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev, struct ipppd *is; int proto; - is = ipppd_get(idev->ppp_slot); + is = idev->ipppd; if (!is) goto err; if (is->debug & 0x4) { - printk(KERN_DEBUG "ippp_receive: is:%p lp:%p slot:%d unit:%d len:%d\n", - is,lp,idev->ppp_slot,is->unit,(int) skb->len); - isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,idev->ppp_slot); + printk(KERN_DEBUG "ippp_receive: is:%p lp:%p unit:%d len:%d\n", + is, lp, is->unit, skb->len); + isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,-1); } if (isdn_ppp_skip_ac(idev, skb) < 0) - goto err_put; + goto err; proto = isdn_ppp_strip_proto(skb); if (proto < 0) - goto err_put; + goto err; /* Don't reset huptimer on LCP packets. */ if (proto != PPP_LCP) @@ -1015,11 +1007,8 @@ static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev, #else isdn_ppp_push_higher(lp, idev, skb, proto); #endif - ipppd_put(is); return; - err_put: - ipppd_put(is); err: kfree_skb(skb); } @@ -1034,19 +1023,15 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, struct sk_buff *skb, int proto) { struct net_device *dev = &lp->dev; - struct ipppd *is; + struct ipppd *is = idev->ipppd; - is = ipppd_get(idev->ppp_slot); - if (!is) - goto drop; - 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, idev->ppp_slot); + isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit, -1); } skb = ippp_ccp_decompress(lp->ccp, skb, &proto); if (!skb) // decompression error - goto put; + goto out; switch (proto) { case PPP_IPX: /* untested */ @@ -1062,14 +1047,14 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, case PPP_COMP: case PPP_COMPFRAG: printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n"); - goto drop_put; + goto drop; #ifdef CONFIG_ISDN_PPP_VJ case PPP_VJC_UNCOMP: if (is->debug & 0x20) printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n"); if (slhc_remember(lp->slcomp, skb->data, skb->len) <= 0) { printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n"); - goto drop_put; + goto drop; } skb->protocol = htons(ETH_P_IP); break; @@ -1084,7 +1069,7 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, if (!skb) { printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); skb = skb_old; - goto drop_put; + goto drop; } skb_put(skb, skb_old->len + 128); memcpy(skb->data, skb_old->data, skb_old->len); @@ -1092,7 +1077,7 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, skb->data, skb_old->len); kfree_skb(skb_old); if (pkt_len < 0) - goto drop_put; + goto drop; skb_trim(skb, pkt_len); skb->protocol = htons(ETH_P_IP); @@ -1107,14 +1092,14 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, if(skb->data[0] == CCP_RESETREQ || skb->data[0] == CCP_RESETACK) { kfree_skb(skb); - goto put; + goto out; } /* fall through */ default: // FIXME use skb directly ipppd_queue_read(is, proto, skb->data, skb->len); kfree_skb(skb); - goto put; + goto out; } /* Reset hangup-timer */ @@ -1123,12 +1108,9 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, skb->dev = dev; netif_rx(skb); /* net_dev->local->stats.rx_packets++; done in isdn_net.c */ - put: - ipppd_put(is); + out: return; - drop_put: - ipppd_put(is); drop: lp->stats.rx_dropped++; kfree_skb(skb); @@ -1148,24 +1130,13 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) isdn_net_local *mlp = ndev->priv; isdn_net_dev *idev = list_entry(mlp->online.next, isdn_net_dev, online); unsigned int proto = PPP_IP; /* 0x21 */ - struct ipppd *ipt,*ipts; + struct ipppd *ipppd; ndev->trans_start = jiffies; if (list_empty(&mlp->online)) return isdn_net_autodial(skb, ndev); - ipts = ipppd_get(idev->ppp_slot); - if (!ipts) { - isdn_BUG(); - goto err; - } - - if (!(idev->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ - printk(KERN_INFO "%s: IP frame delayed.\n", ndev->name); - goto err_put; - } - switch (ntohs(skb->protocol)) { case ETH_P_IP: proto = PPP_IP; @@ -1177,29 +1148,29 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n", skb->protocol); dev_kfree_skb(skb); - goto put; + goto out; } idev = isdn_net_get_xmit_dev(mlp); if (!idev) { + printk(KERN_INFO "%s: IP frame delayed.\n", ndev->name); + goto stop; + } + if (!(idev->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ isdn_BUG(); - goto err_put; + goto stop; } - - ipt = ipppd_get(idev->ppp_slot); - if (!ipt) - goto put; - + ipppd = idev->ipppd; idev->huptimer = 0; /* * after this line .. requeueing in the device queue is no longer allowed!!! */ - if (ipt->debug & 0x4) + if (ipppd->debug & 0x4) printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len); - if (ipts->debug & 0x40) - isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32,ipts->unit,idev->ppp_slot); + if (ipppd->debug & 0x40) + isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32, ipppd->unit, -1); #ifdef CONFIG_ISDN_PPP_VJ if (proto == PPP_IP && idev->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */ @@ -1257,7 +1228,7 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) */ skb = ippp_ccp_compress(mlp->ccp, skb, &proto); - if (ipt->debug & 0x24) + if (ipppd->debug & 0x24) printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto); #ifdef CONFIG_ISDN_MPP @@ -1297,21 +1268,17 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) isdn_ppp_push_header(idev, skb, proto); - if (ipts->debug & 0x40) { + if (ipppd->debug & 0x40) { printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len); - isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,ipt->unit,idev->ppp_slot); + isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, ipppd->unit, -1); } isdn_net_writebuf_skb(idev, skb); - ipppd_put(ipt); - put: - ipppd_put(ipts); + out: return 0; - err_put: - ipppd_put(ipts); - err: + stop: netif_stop_queue(ndev); return 1; } @@ -1963,29 +1930,21 @@ isdn_ppp_hangup_slave(char *name) static void isdn_ppp_dev_kick_up(void *priv) { isdn_net_dev *idev = priv; - struct ipppd *ipppd = ipppd_get(idev->ppp_slot); - if (!ipppd) - return; - - ipppd_queue_read(ipppd, PPP_COMPFRAG, NULL, 0); - ipppd_put(ipppd); + ipppd_queue_read(idev->ipppd, PPP_COMPFRAG, NULL, 0); } static void isdn_ppp_lp_kick_up(void *priv) { isdn_net_local *lp = priv; isdn_net_dev *idev; - struct ipppd *ipppd; if (list_empty(&lp->online)) { isdn_BUG(); return; } idev = list_entry(lp->online.next, isdn_net_dev, online); - ipppd = ipppd_get(idev->ppp_slot); - ipppd_queue_read(ipppd, PPP_COMP, NULL, 0); - ipppd_put(ipppd); + ipppd_queue_read(idev->ipppd, PPP_COMP, NULL, 0); } /* Send a CCP Reset-Request or Reset-Ack directly from the kernel. */ @@ -2186,10 +2145,10 @@ struct isdn_netif_ops isdn_ppp_ops = { .flags = IFF_NOARP | IFF_POINTOPOINT, .type = ARPHRD_PPP, .receive = isdn_ppp_receive, - .connected = isdn_ppp_wakeup_daemon, + .connected = isdn_ppp_connected, .disconnected = isdn_ppp_disconnected, .bind = isdn_ppp_bind, - .unbind = isdn_ppp_free, + .unbind = isdn_ppp_unbind, .open = isdn_ppp_open, .close = isdn_ppp_close, }; diff --git a/include/linux/isdn.h b/include/linux/isdn.h index 64c9c128f46d..0d0ce25b333e 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -410,7 +410,7 @@ typedef struct isdn_net_dev_s { int chargeint; /* Interval between charge-infos */ int pppbind; /* ippp device for bindings */ - int ppp_slot; /* PPPD device slot number */ + struct ipppd *ipppd; /* /dev/ipppX which controls us */ struct sk_buff_head super_tx_queue; /* List of supervisory frames to */ /* be transmitted asap */ -- cgit v1.2.3