Commit 8f7dcd21 authored by Kai Germaschewski's avatar Kai Germaschewski

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.
parent 9a36fb68
...@@ -35,6 +35,8 @@ int isdn_net_hangup(isdn_net_dev *); ...@@ -35,6 +35,8 @@ int isdn_net_hangup(isdn_net_dev *);
int isdn_net_dial_req(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_writebuf_skb(isdn_net_dev *, struct sk_buff *skb);
void isdn_net_write_super(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 static inline int
put_u8(unsigned char *p, u8 x) put_u8(unsigned char *p, u8 x)
......
...@@ -221,7 +221,8 @@ isdn_net_set_encap(isdn_net_local *lp, int encap) ...@@ -221,7 +221,8 @@ isdn_net_set_encap(isdn_net_local *lp, int encap)
if (lp->ops && lp->ops->cleanup) if (lp->ops && lp->ops->cleanup)
lp->ops->cleanup(lp); 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->p_encap = -1;
lp->ops = NULL; lp->ops = NULL;
retval = -EINVAL; retval = -EINVAL;
...@@ -1063,7 +1064,7 @@ isdn_net_open(struct net_device *dev) ...@@ -1063,7 +1064,7 @@ isdn_net_open(struct net_device *dev)
if (lp->ops->open) if (lp->ops->open)
retval = lp->ops->open(lp); retval = lp->ops->open(lp);
if (!retval) if (retval)
return retval; return retval;
netif_start_queue(dev); netif_start_queue(dev);
...@@ -1079,7 +1080,6 @@ isdn_net_open(struct net_device *dev) ...@@ -1079,7 +1080,6 @@ isdn_net_open(struct net_device *dev)
/* /*
* Shutdown a net-interface. * Shutdown a net-interface.
*/ */
// FIXME share?
static int static int
isdn_net_close(struct net_device *dev) isdn_net_close(struct net_device *dev)
{ {
...@@ -1093,14 +1093,14 @@ isdn_net_close(struct net_device *dev) ...@@ -1093,14 +1093,14 @@ isdn_net_close(struct net_device *dev)
netif_stop_queue(dev); netif_stop_queue(dev);
list_for_each_safe(l, n, &lp->online) { list_for_each_safe(l, n, &lp->slaves) {
sdev = list_entry(l, isdn_net_dev, online); sdev = list_entry(l, isdn_net_dev, slaves);
isdn_net_hangup(sdev); isdn_net_hangup(sdev);
} }
/* The hangup will make the refcnt drop back to /* The hangup will make the refcnt drop back to
* 1 (referenced by list only) soon. */ * 1 (referenced by list only) soon. */
spin_lock_irqsave(&running_devs_lock, flags); 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); spin_unlock_irqrestore(&running_devs_lock, flags);
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/10); schedule_timeout(HZ/10);
...@@ -1878,7 +1878,6 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) ...@@ -1878,7 +1878,6 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
isdn_net_dev *idev = isdn_slot_idev(idx); isdn_net_dev *idev = isdn_slot_idev(idx);
if (!idev) { if (!idev) {
HERE;
return 0; return 0;
} }
switch (c->command) { switch (c->command) {
...@@ -2018,8 +2017,9 @@ isdn_net_local_busy(isdn_net_local *mlp) ...@@ -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 * For the given net device, this will get a non-busy channel out of the
* corresponding bundle. * 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_get_xmit_dev(isdn_net_local *mlp)
{ {
isdn_net_dev *idev; isdn_net_dev *idev;
...@@ -2041,7 +2041,7 @@ isdn_net_inc_frame_cnt(isdn_net_dev *idev) ...@@ -2041,7 +2041,7 @@ isdn_net_inc_frame_cnt(isdn_net_dev *idev)
{ {
isdn_net_local *mlp = idev->mlp; isdn_net_local *mlp = idev->mlp;
if (isdn_net_local_busy(mlp)) if (isdn_net_dev_busy(idev))
isdn_BUG(); isdn_BUG();
idev->frame_cnt++; idev->frame_cnt++;
...@@ -2060,7 +2060,7 @@ isdn_net_dec_frame_cnt(isdn_net_dev *idev) ...@@ -2060,7 +2060,7 @@ isdn_net_dec_frame_cnt(isdn_net_dev *idev)
idev->frame_cnt--; idev->frame_cnt--;
if (isdn_net_local_busy(mlp)) if (isdn_net_dev_busy(idev))
isdn_BUG(); isdn_BUG();
if (!was_busy) if (!was_busy)
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
/* Prototypes */ /* Prototypes */
static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot); static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot);
static int isdn_ppp_closewait(int slot); static void isdn_ppp_closewait(isdn_net_dev *idev);
static void isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, static void isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb, int proto); struct sk_buff *skb, int proto);
static int isdn_ppp_if_get_unit(char *namebuf); static int isdn_ppp_if_get_unit(char *namebuf);
...@@ -69,7 +69,21 @@ static int isdn_ppp_bundle(struct ippp_struct *, int unit); ...@@ -69,7 +69,21 @@ static int isdn_ppp_bundle(struct ippp_struct *, int unit);
char *isdn_ppp_revision = "$Revision: 1.85.6.9 $"; 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; static struct isdn_ppp_compressor *ipc_head = NULL;
...@@ -104,6 +118,8 @@ isdn_ppp_free(isdn_net_dev *idev) ...@@ -104,6 +118,8 @@ isdn_ppp_free(isdn_net_dev *idev)
{ {
unsigned long flags; unsigned long flags;
struct ippp_struct *is; 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) { if (idev->ppp_slot < 0 || idev->ppp_slot > ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: ppp_slot(%d) out of range\n", printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
...@@ -117,7 +133,6 @@ isdn_ppp_free(isdn_net_dev *idev) ...@@ -117,7 +133,6 @@ isdn_ppp_free(isdn_net_dev *idev)
#ifdef CONFIG_ISDN_MPP #ifdef CONFIG_ISDN_MPP
spin_lock(&idev->pb->lock); spin_lock(&idev->pb->lock);
#endif #endif
isdn_net_rm_from_bundle(idev);
#ifdef CONFIG_ISDN_MPP #ifdef CONFIG_ISDN_MPP
if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */ if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */
isdn_ppp_mp_cleanup(lp); isdn_ppp_mp_cleanup(lp);
...@@ -131,9 +146,12 @@ isdn_ppp_free(isdn_net_dev *idev) ...@@ -131,9 +146,12 @@ isdn_ppp_free(isdn_net_dev *idev)
restore_flags(flags); restore_flags(flags);
return; return;
} }
is = ippp_table[idev->ppp_slot]; is = ipppd_get(idev->ppp_slot);
if ((is->state & IPPP_CONNECT)) if (!is)
isdn_ppp_closewait(idev->ppp_slot); /* force wakeup on ippp device */ return;
if (is->state & IPPP_CONNECT)
isdn_ppp_closewait(idev); /* force wakeup on ippp device */
else if (is->state & IPPP_ASSIGNED) else if (is->state & IPPP_ASSIGNED)
is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGNED' state */ is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGNED' state */
...@@ -142,6 +160,7 @@ isdn_ppp_free(isdn_net_dev *idev) ...@@ -142,6 +160,7 @@ isdn_ppp_free(isdn_net_dev *idev)
is->idev = NULL; /* link is down .. set lp to NULL */ is->idev = NULL; /* link is down .. set lp to NULL */
idev->ppp_slot = -1; /* is this OK ?? */ idev->ppp_slot = -1; /* is this OK ?? */
ipppd_put(is);
restore_flags(flags); restore_flags(flags);
return; return;
...@@ -155,12 +174,10 @@ isdn_ppp_bind(isdn_net_dev *idev) ...@@ -155,12 +174,10 @@ isdn_ppp_bind(isdn_net_dev *idev)
{ {
int i; int i;
int unit = 0; int unit = 0;
long flags; unsigned long flags;
struct ippp_struct *is; int retval = 0;
int retval;
save_flags(flags); spin_lock_irqsave(&ipppds_lock, flags);
cli();
if (idev->pppbind < 0) { /* device bound to ippp device ? */ if (idev->pppbind < 0) { /* device bound to ippp device ? */
struct list_head *l; struct list_head *l;
char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */ char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */
...@@ -174,47 +191,53 @@ isdn_ppp_bind(isdn_net_dev *idev) ...@@ -174,47 +191,53 @@ isdn_ppp_bind(isdn_net_dev *idev)
/* /*
* search a free device / slot * search a free device / slot
*/ */
for (i = 0; i < ISDN_MAX_CHANNELS; i++) { for (i = 0; i < NR_IPPPDS; i++) {
if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) { /* OPEN, but not connected! */ if (!ipppds[i])
continue;
if (ipppds[i]->state != IPPP_OPEN)
continue;
if (!exclusive[ipppds[i]->minor])
break; break;
} break;
} }
} else { } else {
for (i = 0; i < ISDN_MAX_CHANNELS; i++) { for (i = 0; i < NR_IPPPDS; i++) {
if (ippp_table[i]->minor == idev->pppbind && if (!ipppds[i])
(ippp_table[i]->state & IPPP_OPEN) == IPPP_OPEN) continue;
if (ipppds[i]->state != IPPP_OPEN)
continue;
if (ipppds[i]->minor == idev->pppbind)
break; break;
} }
} }
if (i >= ISDN_MAX_CHANNELS) { if (i >= NR_IPPPDS) {
restore_flags(flags); printk(KERN_INFO "isdn_ppp_bind: no ipppd\n");
printk(KERN_WARNING "isdn_ppp_bind: Can't find a (free) connection to the ipppd daemon.\n"); retval = -ESRCH;
retval = -1; goto err;
goto out;
} }
unit = isdn_ppp_if_get_unit(idev->name); /* get unit number from interface name .. ugly! */ unit = isdn_ppp_if_get_unit(idev->name); /* get unit number from interface name .. ugly! */
if (unit < 0) { if (unit < 0) {
printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", idev->name); printk(KERN_INFO "isdn_ppp_bind: illegal interface name %s.\n", idev->name);
retval = -1; retval = -ENODEV;
goto out; goto err;
} }
idev->ppp_slot = i; idev->ppp_slot = i;
is = ippp_table[i]; ipppds[i]->idev = idev;
is->idev = idev; ipppds[i]->unit = unit;
is->unit = unit; ipppds[i]->state = IPPP_OPEN | IPPP_ASSIGNED; /* assigned to a netdevice but not connected */
is->state = IPPP_OPEN | IPPP_ASSIGNED; /* assigned to a netdevice but not connected */
spin_unlock_irqrestore(&ipppds_lock, flags);
#ifdef CONFIG_ISDN_MPP #ifdef CONFIG_ISDN_MPP
retval = isdn_ppp_mp_init(lp, NULL); retval = isdn_ppp_mp_init(lp, NULL);
if (retval < 0) // FIXME unwind?
goto out;
#endif /* CONFIG_ISDN_MPP */ #endif /* CONFIG_ISDN_MPP */
return retval;
retval = idev->ppp_slot; err:
spin_unlock_irqrestore(&ipppds_lock, flags);
out:
restore_flags(flags);
return retval; return retval;
} }
...@@ -226,13 +249,14 @@ isdn_ppp_bind(isdn_net_dev *idev) ...@@ -226,13 +249,14 @@ isdn_ppp_bind(isdn_net_dev *idev)
static void static void
isdn_ppp_wakeup_daemon(isdn_net_dev *idev) isdn_ppp_wakeup_daemon(isdn_net_dev *idev)
{ {
if (idev->ppp_slot < 0 || idev->ppp_slot >= ISDN_MAX_CHANNELS) { struct ippp_struct *ipppd = ipppd_get(idev->ppp_slot);
printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
__FUNCTION__, idev->ppp_slot); if (!ipppd)
return; return;
}
ippp_table[idev->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK; ipppd->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
wake_up_interruptible(&ippp_table[idev->ppp_slot]->wq); wake_up(&ipppd->wq);
ipppd_put(ipppd);
} }
/* /*
...@@ -240,36 +264,38 @@ isdn_ppp_wakeup_daemon(isdn_net_dev *idev) ...@@ -240,36 +264,38 @@ isdn_ppp_wakeup_daemon(isdn_net_dev *idev)
* force wakeup of the ippp device * force wakeup of the ippp device
* go into 'device waits for release' state * go into 'device waits for release' state
*/ */
static int static void
isdn_ppp_closewait(int slot) 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) { if (!ipppd)
printk(KERN_ERR "%s: slot(%d) out of range\n", return;
__FUNCTION__ , slot);
return 0; wake_up(&ipppd->wq);
} ipppd->state = IPPP_CLOSEWAIT;
is = ippp_table[slot]; ipppd_put(ipppd);
if (is->state)
wake_up_interruptible(&is->wq);
is->state = IPPP_CLOSEWAIT;
return 1;
} }
/* /*
* isdn_ppp_find_slot / isdn_ppp_free_slot * isdn_ppp_get_slot
*/ */
static int static int
isdn_ppp_get_slot(void) isdn_ppp_get_slot(void)
{ {
int i; int i;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) { unsigned long flags;
if (!ippp_table[i]->state)
return i; 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) ...@@ -284,10 +310,11 @@ isdn_ppp_open(struct inode *ino, struct file *file)
struct ippp_struct *is; struct ippp_struct *is;
slot = isdn_ppp_get_slot(); slot = isdn_ppp_get_slot();
if (slot < 0) { if (slot < 0)
return -EBUSY; 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); 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) ...@@ -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 */ is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */
#endif #endif
is->state = IPPP_OPEN;
isdn_lock_drivers(); isdn_lock_drivers();
return 0; return 0;
...@@ -471,10 +497,9 @@ isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned ...@@ -471,10 +497,9 @@ isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned
return r; return r;
} }
if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) { if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
if (idev) { if (idev)
/* OK .. we are ready to send buffers */ /* OK .. we are ready to send buffers */
isdn_net_dev_wake_queue(idev); isdn_net_online(idev);
}
} }
is->pppcfg = val; is->pppcfg = val;
break; break;
...@@ -628,25 +653,27 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot) ...@@ -628,25 +653,27 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
struct sk_buff *skb; struct sk_buff *skb;
unsigned char *p; unsigned char *p;
struct ippp_struct *is; struct ippp_struct *is;
int retval;
if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { is = ipppd_get(slot);
printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot); if (!is)
return 0; return -ENODEV;
}
is = ippp_table[slot];
if (!(is->state & IPPP_CONNECT)) { if (!(is->state & IPPP_CONNECT)) {
printk(KERN_DEBUG "ippp: device not activated.\n"); printk(KERN_DEBUG "ippp: device not activated.\n");
return 0; retval = -ENOTCONN;
goto out;
} }
if (skb_queue_len(&is->rq) > IPPP_MAX_RQ_LEN) { if (skb_queue_len(&is->rq) > IPPP_MAX_RQ_LEN) {
printk(KERN_WARNING "ippp: Queue is full\n"); printk(KERN_WARNING "ippp: Queue is full\n");
return 0; retval = -EBUSY;
goto out;
} }
skb = dev_alloc_skb(len + 4); skb = dev_alloc_skb(len + 4);
if (!skb) { if (!skb) {
printk(KERN_WARNING "ippp: Can't alloc buf\n"); printk(KERN_WARNING "ippp: Can't alloc buf\n");
return 0; retval = -ENOMEM;
goto out;
} }
p = skb_put(skb, 4); p = skb_put(skb, 4);
p += put_u8(p, PPP_ALLSTATIONS); p += put_u8(p, PPP_ALLSTATIONS);
...@@ -655,9 +682,12 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot) ...@@ -655,9 +682,12 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
memcpy(skb_put(skb, len), buf, len); memcpy(skb_put(skb, len), buf, len);
skb_queue_tail(&is->rq, skb); 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) ...@@ -749,8 +779,7 @@ isdn_ppp_write(struct file *file, const char *buf, size_t count, loff_t *off)
retval = 0; retval = 0;
goto out; goto out;
} }
if ((dev->drv[isdn_slot_driver(idev->isdn_slot)]->flags & DRV_FLAG_RUNNING) && if ((dev->drv[isdn_slot_driver(idev->isdn_slot)]->flags & DRV_FLAG_RUNNING)) {
isdn_net_online(idev)) {
unsigned short hl; unsigned short hl;
struct sk_buff *skb; struct sk_buff *skb;
/* /*
...@@ -808,25 +837,24 @@ struct file_operations isdn_ppp_fops = ...@@ -808,25 +837,24 @@ struct file_operations isdn_ppp_fops =
int int
isdn_ppp_init(void) isdn_ppp_init(void)
{ {
int i, int i;
j;
#ifdef CONFIG_ISDN_MPP #ifdef CONFIG_ISDN_MPP
if( isdn_ppp_mp_bundle_array_init() < 0 ) if( isdn_ppp_mp_bundle_array_init() < 0 )
return -ENOMEM; return -ENOMEM;
#endif /* CONFIG_ISDN_MPP */ #endif /* CONFIG_ISDN_MPP */
for (i = 0; i < ISDN_MAX_CHANNELS; i++) { for (i = 0; i < NR_IPPPDS; i++) {
if (!(ippp_table[i] = (struct ippp_struct *) ipppds[i] = kmalloc(sizeof(struct ippp_struct), GFP_KERNEL);
kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) { if (!ipppds[i]) {
printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n"); printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");
for (j = 0; j < i; j++) for (i--; i >= 0; i++)
kfree(ippp_table[j]); kfree(ipppds[i]);
return -1; return -ENOMEM;
} }
memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct)); memset(ipppds[i], 0, sizeof(struct ippp_struct));
ippp_table[i]->state = 0; ipppds[i]->state = 0;
skb_queue_head_init(&ippp_table[i]->rq); skb_queue_head_init(&ipppds[i]->rq);
} }
return 0; return 0;
} }
...@@ -836,8 +864,8 @@ isdn_ppp_cleanup(void) ...@@ -836,8 +864,8 @@ isdn_ppp_cleanup(void)
{ {
int i; int i;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) for (i = 0; i < NR_IPPPDS; i++)
kfree(ippp_table[i]); kfree(ipppds[i]);
#ifdef CONFIG_ISDN_MPP #ifdef CONFIG_ISDN_MPP
if (isdn_ppp_bundle_arr) if (isdn_ppp_bundle_arr)
...@@ -904,7 +932,6 @@ static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev, ...@@ -904,7 +932,6 @@ static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct ippp_struct *is; struct ippp_struct *is;
int slot;
int proto; int proto;
/* /*
...@@ -914,14 +941,9 @@ static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev, ...@@ -914,14 +941,9 @@ static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev,
if (PPP_PROTOCOL(skb->data) != PPP_LCP) if (PPP_PROTOCOL(skb->data) != PPP_LCP)
idev->huptimer = 0; idev->huptimer = 0;
slot = idev->ppp_slot; is = ipppd_get(idev->ppp_slot);
if (slot < 0 || slot > ISDN_MAX_CHANNELS) { if (!is)
printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n", goto err;
slot);
kfree_skb(skb);
return;
}
is = ippp_table[slot];
if (is->debug & 0x4) { if (is->debug & 0x4) {
printk(KERN_DEBUG "ippp_receive: is:%p lp:%p slot:%d unit:%d len:%d\n", 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, ...@@ -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); 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(is, skb) < 0)
kfree_skb(skb); goto err_put;
return;
}
proto = isdn_ppp_strip_proto(skb); proto = isdn_ppp_strip_proto(skb);
if (proto < 0) { if (proto < 0)
kfree_skb(skb); goto err_put;
return;
}
#ifdef CONFIG_ISDN_MPP #ifdef CONFIG_ISDN_MPP
if (is->compflags & SC_LINK_DECOMP_ON) { if (is->compflags & SC_LINK_DECOMP_ON) {
skb = isdn_ppp_decompress(skb, is, NULL, &proto); skb = isdn_ppp_decompress(skb, is, NULL, &proto);
if (!skb) // decompression error if (!skb) // decompression error
return; goto put;
} }
if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP
if (proto == PPP_MP) { if (proto == PPP_MP) {
isdn_ppp_mp_receive(lp, idev, skb); isdn_ppp_mp_receive(lp, idev, skb);
return; goto put;
} }
} }
#endif
isdn_ppp_push_higher(lp, idev, skb, proto); 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, ...@@ -966,27 +995,20 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb, int proto) struct sk_buff *skb, int proto)
{ {
struct net_device *dev = &lp->dev; struct net_device *dev = &lp->dev;
struct ippp_struct *is, *mis; struct ippp_struct *is;
int slot;
slot = idev->ppp_slot; is = ipppd_get(idev->ppp_slot);
if (slot < 0 || slot > ISDN_MAX_CHANNELS) { if (!is)
printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n", goto drop;
slot);
goto drop_packet;
}
is = ippp_table[slot];
mis = ippp_table[slot];
if (is->debug & 0x10) { if (is->debug & 0x10) {
printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto); 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) { if (is->compflags & SC_DECOMP_ON) {
skb = isdn_ppp_decompress(skb, is, mis, &proto); skb = isdn_ppp_decompress(skb, is, is, &proto);
if (!skb) // decompression error if (!skb) // decompression error
return; goto put;
} }
switch (proto) { switch (proto) {
case PPP_IPX: /* untested */ case PPP_IPX: /* untested */
...@@ -1002,19 +1024,14 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, ...@@ -1002,19 +1024,14 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
case PPP_COMP: case PPP_COMP:
case PPP_COMPFRAG: case PPP_COMPFRAG:
printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n"); printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n");
goto drop_packet; goto drop_put;
#ifdef CONFIG_ISDN_PPP_VJ #ifdef CONFIG_ISDN_PPP_VJ
case PPP_VJC_UNCOMP: case PPP_VJC_UNCOMP:
if (is->debug & 0x20) if (is->debug & 0x20)
printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n"); printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
if (idev->ppp_slot < 0) { if (slhc_remember(is->slcomp, skb->data, skb->len) <= 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) {
printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n"); printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
goto drop_packet; goto drop_put;
} }
skb->protocol = htons(ETH_P_IP); skb->protocol = htons(ETH_P_IP);
break; break;
...@@ -1029,20 +1046,15 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, ...@@ -1029,20 +1046,15 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
if (!skb) { if (!skb) {
printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
skb = skb_old; skb = skb_old;
goto drop_packet; goto drop_put;
} }
skb_put(skb, skb_old->len + 128); skb_put(skb, skb_old->len + 128);
memcpy(skb->data, skb_old->data, skb_old->len); memcpy(skb->data, skb_old->data, skb_old->len);
if (idev->ppp_slot < 0) { pkt_len = slhc_uncompress(is->slcomp,
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,
skb->data, skb_old->len); skb->data, skb_old->len);
kfree_skb(skb_old); kfree_skb(skb_old);
if (pkt_len < 0) if (pkt_len < 0)
goto drop_packet; goto drop_put;
skb_trim(skb, pkt_len); skb_trim(skb, pkt_len);
skb->protocol = htons(ETH_P_IP); skb->protocol = htons(ETH_P_IP);
...@@ -1071,9 +1083,13 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, ...@@ -1071,9 +1083,13 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
skb->mac.raw = skb->data; skb->mac.raw = skb->data;
netif_rx(skb); netif_rx(skb);
/* net_dev->local->stats.rx_packets++; done in isdn_net.c */ /* net_dev->local->stats.rx_packets++; done in isdn_net.c */
put:
ipppd_put(is);
return; return;
drop_packet: drop_put:
ipppd_put(is);
drop:
lp->stats.rx_dropped++; lp->stats.rx_dropped++;
kfree_skb(skb); kfree_skb(skb);
} }
...@@ -1119,27 +1135,21 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) ...@@ -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); isdn_net_dev *idev = list_entry(mlp->online.next, isdn_net_dev, online);
unsigned int proto = PPP_IP; /* 0x21 */ unsigned int proto = PPP_IP; /* 0x21 */
struct ippp_struct *ipt,*ipts; struct ippp_struct *ipt,*ipts;
int slot;
ndev->trans_start = jiffies; ndev->trans_start = jiffies;
if (list_empty(&mlp->online)) if (list_empty(&mlp->online))
return isdn_net_autodial(skb, ndev); return isdn_net_autodial(skb, ndev);
slot = idev->ppp_slot; ipts = ipppd_get(idev->ppp_slot);
if (slot < 0 || slot > ISDN_MAX_CHANNELS) { if (!ipts) {
printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n", isdn_BUG();
slot); goto err;
kfree_skb(skb);
return 0;
} }
ipts = ippp_table[slot];
if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
if (ipts->debug & 0x1) printk(KERN_INFO "%s: IP frame delayed.\n", ndev->name);
printk(KERN_INFO "%s: IP frame delayed.\n", ndev->name); goto err_put;
netif_stop_queue(ndev);
return 1;
} }
switch (ntohs(skb->protocol)) { switch (ntohs(skb->protocol)) {
...@@ -1153,24 +1163,19 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) ...@@ -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", printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n",
skb->protocol); skb->protocol);
dev_kfree_skb(skb); dev_kfree_skb(skb);
return 0; goto put;
} }
idev = isdn_net_get_locked_dev(mlp); idev = isdn_net_get_xmit_dev(mlp);
if (!idev) { if (!idev) {
printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name); isdn_BUG();
netif_stop_queue(ndev); goto err_put;
return 1;
} }
/* we have our lp locked from now on */
slot = idev->ppp_slot; ipt = ipppd_get(idev->ppp_slot);
if (slot < 0 || slot > ISDN_MAX_CHANNELS) { if (!ipt)
printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n", goto put;
slot);
kfree_skb(skb);
return 0;
}
ipt = ippp_table[slot];
idev->huptimer = 0; idev->huptimer = 0;
/* /*
...@@ -1290,20 +1295,20 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) ...@@ -1290,20 +1295,20 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev)
if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) { if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) {
unsigned char *data = isdn_ppp_skb_push(&skb,1); unsigned char *data = isdn_ppp_skb_push(&skb,1);
if(!data) if(!data)
goto unlock; goto put2;
data[0] = proto & 0xff; data[0] = proto & 0xff;
} }
else { else {
unsigned char *data = isdn_ppp_skb_push(&skb,2); unsigned char *data = isdn_ppp_skb_push(&skb,2);
if(!data) if(!data)
goto unlock; goto put2;
data[0] = (proto >> 8) & 0xff; data[0] = (proto >> 8) & 0xff;
data[1] = proto & 0xff; data[1] = proto & 0xff;
} }
if(!(ipt->pppcfg & SC_COMP_AC)) { if(!(ipt->pppcfg & SC_COMP_AC)) {
unsigned char *data = isdn_ppp_skb_push(&skb,2); unsigned char *data = isdn_ppp_skb_push(&skb,2);
if(!data) if(!data)
goto unlock; goto put2;
data[0] = 0xff; /* All Stations */ data[0] = 0xff; /* All Stations */
data[1] = 0x03; /* Unnumbered information */ data[1] = 0x03; /* Unnumbered information */
} }
...@@ -1317,9 +1322,17 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev) ...@@ -1317,9 +1322,17 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev)
isdn_net_writebuf_skb(idev, skb); isdn_net_writebuf_skb(idev, skb);
unlock: put2:
spin_unlock_bh(&idev->xmit_lock); ipppd_put(ipt);
put:
ipppd_put(ipts);
return 0; return 0;
err_put:
ipppd_put(ipts);
err:
netif_stop_queue(ndev);
return 1;
} }
#ifdef CONFIG_ISDN_MPP #ifdef CONFIG_ISDN_MPP
...@@ -1806,8 +1819,8 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit) ...@@ -1806,8 +1819,8 @@ isdn_ppp_bundle(struct ippp_struct *is, int unit)
static int static int
isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev) isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev)
{ {
struct ppp_stats *res, struct ppp_stats *res, t;
t; struct ippp_struct *is;
isdn_net_local *lp = (isdn_net_local *) dev->priv; isdn_net_local *lp = (isdn_net_local *) dev->priv;
int err; int err;
...@@ -1828,16 +1841,20 @@ isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev) ...@@ -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_obytes = lp->stats.tx_bytes;
t.p.ppp_oerrors = lp->stats.tx_errors; t.p.ppp_oerrors = lp->stats.tx_errors;
#ifdef CONFIG_ISDN_PPP_VJ #ifdef CONFIG_ISDN_PPP_VJ
if (slot >= 0 && ippp_table[slot]->slcomp) { is = ipppd_get(slot);
struct slcompress *slcomp = ippp_table[slot]->slcomp; if (is) {
t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed; struct slcompress *slcomp = is->slcomp;
t.vj.vjs_compressed = slcomp->sls_o_compressed; if (slcomp) {
t.vj.vjs_searches = slcomp->sls_o_searches; t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed;
t.vj.vjs_misses = slcomp->sls_o_misses; t.vj.vjs_compressed = slcomp->sls_o_compressed;
t.vj.vjs_errorin = slcomp->sls_i_error; t.vj.vjs_searches = slcomp->sls_o_searches;
t.vj.vjs_tossed = slcomp->sls_i_tossed; t.vj.vjs_misses = slcomp->sls_o_misses;
t.vj.vjs_uncompressedin = slcomp->sls_i_uncompressed; t.vj.vjs_errorin = slcomp->sls_i_error;
t.vj.vjs_compressedin = slcomp->sls_i_compressed; 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 #endif
} }
...@@ -2458,12 +2475,11 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *idev, isdn_net_local *lp, ...@@ -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", printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n",
idev->ppp_slot); 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", is = ipppd_get(idev->ppp_slot);
__FUNCTION__ , idev->ppp_slot); if (!is)
return; return;
}
is = ippp_table[idev->ppp_slot];
isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,idev->ppp_slot); isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,idev->ppp_slot);
mis = is; mis = is;
...@@ -2586,6 +2602,7 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *idev, isdn_net_local *lp, ...@@ -2586,6 +2602,7 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *idev, isdn_net_local *lp,
} }
break; break;
} }
ipppd_put(is);
} }
...@@ -2618,17 +2635,16 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *idev, isdn_net_local *lp, ...@@ -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) static void isdn_ppp_send_ccp(isdn_net_dev *idev, isdn_net_local *lp, struct sk_buff *skb)
{ {
struct ippp_struct *mis,*is; struct ippp_struct *mis,*is;
int proto, slot = idev->ppp_slot; int proto;
unsigned char *data; unsigned char *data;
if(!skb || skb->len < 3) if (!skb || skb->len < 3)
return; return;
if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", is = ipppd_get(idev->ppp_slot);
__FUNCTION__ , slot); if (!is)
return; return;
}
is = ippp_table[slot];
/* Daemon may send with or without address and control field comp */ /* Daemon may send with or without address and control field comp */
data = skb->data; data = skb->data;
if(!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) { 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_ ...@@ -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"); printk(KERN_DEBUG "ResetReq from daemon passed by\n");
break; break;
} }
ipppd_put(is);
} }
int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc) int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
......
...@@ -11,11 +11,12 @@ ...@@ -11,11 +11,12 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/init.h> #include <linux/init.h>
#include "isdnloop.h" #include "isdnloop.h"
static char *revision = "$Revision: 1.11.6.7 $"; 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_DESCRIPTION("ISDN4Linux: Pseudo Driver that simulates an ISDN card");
MODULE_AUTHOR("Fritz Elfert"); MODULE_AUTHOR("Fritz Elfert");
......
...@@ -342,9 +342,9 @@ typedef struct isdn_net_local_s { ...@@ -342,9 +342,9 @@ typedef struct isdn_net_local_s {
protected by serializing config protected by serializing config
ioctls / no change allowed when ioctls / no change allowed when
interface is running */ interface is running */
struct list_head online; /* circular list of all bundled struct list_head online; /* list of all bundled channels
channels, which are currently which can be used for actual
online data (IP) transfer
protected by xmit_lock */ protected by xmit_lock */
spinlock_t xmit_lock; /* used to protect the xmit path of spinlock_t xmit_lock; /* used to protect the xmit path of
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment