Commit d6b03063 authored by Kai Germaschewski's avatar Kai Germaschewski

ISDN/PPP: cosmetics

No (well, hardly any ;) code changes, only moving all /dev/ipppX related
code next to each other and some indenting changes.
parent a0097af3
......@@ -21,6 +21,38 @@
#include "isdn_ppp_ccp.h"
#include "isdn_net.h"
static void
isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
struct sk_buff *skb);
static int
isdn_ppp_set_compressor(struct ipppd *is,struct isdn_ppp_comp_data *);
/* ====================================================================== */
/* IPPPD handling */
/* ====================================================================== */
/* 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.
*/
#define IPPPD_DEBUG
#ifdef IPPPD_DEBUG
#define ipppd_debug(i, fmt, arg...) \
printk(KERN_DEBUG "ipppd %p minor %d state %#x %s: " fmt "\n", (i), \
(i)->minor, (i)->state, __FUNCTION__ , ## arg)
#else
#define ipppd_debug(...) do { } while (0)
#endif
/* ipppd::flags */
enum {
IPPPD_FL_HUP = 0x01,
......@@ -47,73 +79,7 @@ struct ipppd {
atomic_t refcnt;
};
#define IPPPD_DEBUG
#ifdef IPPPD_DEBUG
#define ipppd_debug(i, fmt, arg...) \
printk(KERN_DEBUG "ipppd %p state %#x %s:" fmt "\n", (i), (i)->state, \
__FUNCTION__ , ## arg)
#else
#define ipppd_debug(...) do { } while (0)
#endif
/* 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
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_dev_alloc_skb(void *priv, int len, int gfp_mask);
static void
isdn_ppp_dev_push_header(void *priv, struct sk_buff *skb, u16 proto);
static void
isdn_ppp_dev_xmit(void *priv, struct sk_buff *skb);
static struct sk_buff *
isdn_ppp_lp_alloc_skb(void *priv, int len, int gfp_mask);
static void
isdn_ppp_lp_push_header(void *priv, struct sk_buff *skb, u16 proto);
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_dev_kick_up(void *priv);
#ifdef CONFIG_ISDN_MPP
static ippp_bundle * isdn_ppp_bundle_arr = NULL;
static int isdn_ppp_mp_bundle_array_init(void);
static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to);
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 ipppd *, int unit);
#endif /* CONFIG_ISDN_MPP */
char *isdn_ppp_revision = "$Revision: 1.85.6.9 $";
/* ====================================================================== */
static spinlock_t ipppds_lock = SPIN_LOCK_UNLOCKED;
static LIST_HEAD(ipppds);
......@@ -128,7 +94,7 @@ ipppd_destroy(struct ipppd *ipppd)
}
static inline struct ipppd *
__ipppd_get(struct ipppd *ipppd)
ipppd_get(struct ipppd *ipppd)
{
atomic_inc(&ipppd->refcnt);
printk("%s: %d\n", __FUNCTION__, atomic_read(&ipppd->refcnt));
......@@ -144,293 +110,230 @@ ipppd_put(struct ipppd *ipppd)
ipppd_destroy(ipppd);
}
/*
* frame log (debug)
*/
void
isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot)
/* ====================================================================== */
/* char dev ops */
/* --- open ------------------------------------------------------------- */
static int
ipppd_open(struct inode *ino, struct file *file)
{
int cnt,
j,
i;
char buf[80];
unsigned long flags;
unsigned int minor = minor(ino->i_rdev) - ISDN_MINOR_PPP;
struct ipppd *ipppd;
if (len < maxlen)
maxlen = len;
ipppd = kmalloc(sizeof(*ipppd), GFP_KERNEL);
if (!ipppd)
return -ENOMEM;
for (i = 0, cnt = 0; cnt < maxlen; i++) {
for (j = 0; j < 16 && cnt < maxlen; j++, cnt++)
sprintf(buf + j * 3, "%02x ", (unsigned char) data[cnt]);
printk(KERN_DEBUG "[%d/%d].%s[%d]: %s\n",unit,slot, info, i, buf);
}
memset(ipppd, 0, sizeof(*ipppd));
atomic_set(&ipppd->refcnt, 0);
/* file->private_data holds a reference */
file->private_data = ipppd_get(ipppd);
ipppd->unit = -1; /* set by isdn_ppp_bind */
ipppd->minor = minor;
ipppd->state = IPPPD_ST_OPEN;
init_waitqueue_head(&ipppd->wq);
skb_queue_head_init(&ipppd->rq);
spin_lock_irqsave(&ipppds, flags);
list_add(&ipppd->ipppds, &ipppds);
spin_unlock_irqrestore(&ipppds, flags);
ipppd_debug(ipppd, "minor %d", minor);
return 0;
}
/* --- release --------------------------------------------------------- */
static void
isdn_ppp_push_header(isdn_net_dev *idev, struct sk_buff *skb, u16 proto)
static int
ipppd_release(struct inode *ino, struct file *file)
{
unsigned char *p;
unsigned long flags;
struct ipppd *ipppd = file->private_data;
if (skb_headroom(skb) < 4) {
isdn_BUG();
return;
}
ipppd_debug(ipppd, "");
if ((idev->pppcfg & SC_COMP_PROT) && proto <= 0xff)
put_u8(skb_push(skb, 1), proto);
else
put_u16(skb_push(skb, 2), proto);
if (ipppd->state == IPPPD_ST_CONNECTED)
isdn_net_hangup(ipppd->idev);
if (idev->pppcfg & SC_COMP_AC)
return;
spin_lock_irqsave(&ipppds, flags);
list_del(&ipppd->ipppds);
spin_unlock_irqrestore(&ipppds, flags);
p = skb_push(skb, 2);
p += put_u8(p, PPP_ALLSTATIONS);
p += put_u8(p, PPP_UI);
ipppd_put(ipppd);
return 0;
}
/*
* unbind isdn_net_local <=> ippp-device
* note: it can happen, that we hangup/free the master before the slaves
* in this case we bind another lp to the master device
*/
static void
isdn_ppp_unbind(isdn_net_dev *idev)
/* --- read ------------------------------------------------------------- */
/* read() is always non blocking */
static ssize_t
ipppd_read(struct file *file, char *buf, size_t count, loff_t *off)
{
struct ipppd *is = idev->ipppd;
struct ipppd *is;
struct sk_buff *skb;
int retval;
if (!is) {
isdn_BUG();
return;
if (off != &file->f_pos)
return -ESPIPE;
is = file->private_data;
skb = skb_dequeue(&is->rq);
if (!skb) {
retval = -EAGAIN;
goto out;
}
if (skb->len > count) {
retval = -EMSGSIZE;
goto out_free;
}
if (copy_to_user(buf, skb->data, skb->len)) {
retval = -EFAULT;
goto out_free;
}
retval = skb->len;
ipppd_debug(is, "");
out_free:
dev_kfree_skb(skb);
out:
return retval;
}
if (is->state != IPPPD_ST_ASSIGNED)
isdn_BUG();
/* --- write ------------------------------------------------------------ */
is->state = IPPPD_ST_OPEN;
/* write() is always non blocking */
static ssize_t
ipppd_write(struct file *file, const char *buf, size_t count, loff_t *off)
{
isdn_net_dev *idev;
struct ipppd *is;
int proto;
unsigned char protobuf[4];
int retval;
/* is->idev will be invalid shortly */
ippp_ccp_free(idev->ccp);
if (off != &file->f_pos)
return -ESPIPE;
is->idev = NULL;
/* lose the reference we took on isdn_ppp_bind */
ipppd_put(is);
idev->ipppd = NULL;
lock_kernel();
return;
}
is = file->private_data;
/*
* bind isdn_net_local <=> ippp-device
*/
int
isdn_ppp_bind(isdn_net_dev *idev)
{
int unit = 0;
unsigned long flags;
int retval = 0;
struct ipppd *ipppd;
ipppd_debug(is, "");
if (idev->ipppd) {
isdn_BUG();
return 0;
if (is->state != IPPPD_ST_CONNECTED) {
retval = -ENOTCONN;
goto out;
}
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);
/* 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 && p->pppbind < ISDN_MAX_CHANNELS)
exclusive[p->pppbind] = 1;
}
/*
* search a free device / slot
/* -> push it directly to the lowlevel interface */
idev = is->idev;
if (!idev)
printk(KERN_DEBUG "isdn_ppp_write: idev == NULL\n");
else {
/*
* Don't reset huptimer for
* LCP packets. (Echo requests).
*/
list_for_each_entry(ipppd, &ipppds, ipppds) {
if (!ipppd)
continue;
if (ipppd->state != IPPPD_ST_OPEN)
continue;
if (!exclusive[ipppd->minor])
break;
goto found;
if (copy_from_user(protobuf, buf, 4)) {
retval = -EFAULT;
goto out;
}
} else {
list_for_each_entry(ipppd, &ipppds, ipppds) {
if (!ipppd)
continue;
if (ipppd->state != IPPPD_ST_OPEN)
continue;
if (ipppd->minor == idev->pppbind)
goto found;
proto = PPP_PROTOCOL(protobuf);
if (proto != PPP_LCP)
idev->huptimer = 0;
if (idev->isdn_slot < 0) {
retval = 0;
goto out;
}
if ((dev->drv[isdn_slot_driver(idev->isdn_slot)]->flags & DRV_FLAG_RUNNING)) {
unsigned short hl;
struct sk_buff *skb;
/*
* we need to reserve enought space in front of
* sk_buff. old call to dev_alloc_skb only reserved
* 16 bytes, now we are looking what the driver want
*/
hl = isdn_slot_hdrlen(idev->isdn_slot);
skb = alloc_skb(hl+count, GFP_ATOMIC);
if (!skb) {
printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
retval = count;
goto out;
}
printk(KERN_INFO "isdn_ppp_bind: no ipppd\n");
retval = -ESRCH;
goto err;
found:
unit = isdn_ppp_if_get_unit(idev->name); /* get unit number from interface name .. ugly! */
if (unit < 0) {
printk(KERN_INFO "isdn_ppp_bind: illegal interface name %s.\n", idev->name);
retval = -ENODEV;
goto err;
skb_reserve(skb, hl);
if (copy_from_user(skb_put(skb, count), buf, count))
{
kfree_skb(skb);
retval = -EFAULT;
goto out;
}
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,-1);
}
ipppd->unit = unit;
ipppd->state = IPPPD_ST_ASSIGNED;
ipppd->idev = idev;
/* we hold a reference until isdn_ppp_unbind() */
idev->ipppd = __ipppd_get(ipppd);
spin_unlock_irqrestore(&ipppds_lock, flags);
idev->pppcfg = 0; /* config flags */
/* seq no last seen, maybe set to bundle min, when joining? */
idev->pppseq = -1;
/* keeps CCP/compression states in sync */
isdn_ppp_send_ccp(idev,idev->mlp,skb);
idev->ccp = ippp_ccp_alloc();
if (!idev->ccp) {
retval = -ENOMEM;
goto out;
/* FIXME: Somewhere we need protection against the
* queue growing too large */
isdn_net_write_super(idev, skb);
}
idev->ccp->proto = PPP_COMPFRAG;
idev->ccp->priv = idev;
idev->ccp->alloc_skb = isdn_ppp_dev_alloc_skb;
idev->ccp->push_header = isdn_ppp_dev_push_header;
idev->ccp->xmit = isdn_ppp_dev_xmit;
idev->ccp->kick_up = isdn_ppp_dev_kick_up;
#ifdef CONFIG_ISDN_MPP
retval = isdn_ppp_mp_init(lp, NULL);
#endif /* CONFIG_ISDN_MPP */
out:
if (retval) {
idev->ipppd->state = IPPPD_ST_OPEN;
ipppd_put(idev->ipppd);
idev->ipppd = NULL;
}
retval = count;
return retval;
err:
spin_unlock_irqrestore(&ipppds_lock, flags);
out:
unlock_kernel();
return retval;
}
/*
* kick the ipppd on the device
* (wakes up daemon after B-channel connect)
*/
static void
isdn_ppp_connected(isdn_net_dev *idev)
{
struct ipppd *ipppd = idev->ipppd;
ipppd_debug(ipppd, "");
ipppd->state = IPPPD_ST_CONNECTED;
ipppd->flags |= IPPPD_FL_WAKEUP;
wake_up(&ipppd->wq);
}
/* --- poll ------------------------------------------------------------- */
static void
isdn_ppp_disconnected(isdn_net_dev *idev)
static unsigned int
ipppd_poll(struct file *file, poll_table * wait)
{
struct ipppd *ipppd = idev->ipppd;
ipppd_debug(ipppd, "");
if (idev->pppcfg & SC_ENABLE_IP)
isdn_net_offline(idev);
if (ipppd->state != IPPPD_ST_CONNECTED)
isdn_BUG();
unsigned int mask;
struct ipppd *is;
ipppd->state = IPPPD_ST_ASSIGNED;
ipppd->flags |= IPPPD_FL_HUP;
wake_up(&ipppd->wq);
is = file->private_data;
#ifdef CONFIG_ISDN_MPP
spin_lock(&idev->pb->lock);
if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */
isdn_ppp_mp_cleanup(lp);
ipppd_debug(is, "");
lp->netdev->pb->ref_ct--;
spin_unlock(&lp->netdev->pb->lock);
#endif /* CONFIG_ISDN_MPP */
/* just registers wait_queue hook. This doesn't really wait. */
poll_wait(file, &is->wq, wait);
}
if (is->flags & IPPPD_FL_HUP) {
mask = POLLHUP;
goto out;
}
/* we're always ready to send .. */
mask = POLLOUT | POLLWRNORM;
/*
* ipppd_open
/*
* if IPPP_FL_WAKEUP is set we return even if we have nothing to read
*/
if (!skb_queue_empty(&is->rq) || is->flags & IPPPD_FL_WAKEUP) {
is->flags &= ~IPPPD_FL_WAKEUP;
mask |= POLLIN | POLLRDNORM;
set_current_state(TASK_INTERRUPTIBLE); // FIXME
schedule_timeout(HZ);
}
static int
ipppd_open(struct inode *ino, struct file *file)
{
unsigned long flags;
unsigned int minor = minor(ino->i_rdev) - ISDN_MINOR_PPP;
struct ipppd *ipppd;
ipppd = kmalloc(sizeof(*ipppd), GFP_KERNEL);
if (!ipppd)
return -ENOMEM;
memset(ipppd, 0, sizeof(*ipppd));
atomic_set(&ipppd->refcnt, 0);
/* file->private_data holds a reference */
file->private_data = __ipppd_get(ipppd);
ipppd->unit = -1; /* set by isdn_ppp_bind */
ipppd->minor = minor;
ipppd->state = IPPPD_ST_OPEN;
init_waitqueue_head(&ipppd->wq);
skb_queue_head_init(&ipppd->rq);
spin_lock_irqsave(&ipppds, flags);
list_add(&ipppd->ipppds, &ipppds);
spin_unlock_irqrestore(&ipppds, flags);
ipppd_debug(ipppd, "minor %d", minor);
return 0;
out:
return mask;
}
/*
* release ippp device
*/
static int
ipppd_release(struct inode *ino, struct file *file)
{
unsigned long flags;
struct ipppd *ipppd = file->private_data;
ipppd_debug(ipppd, "");
if (ipppd->state == IPPPD_ST_CONNECTED)
isdn_net_hangup(ipppd->idev);
spin_lock_irqsave(&ipppds, flags);
list_del(&ipppd->ipppds);
spin_unlock_irqrestore(&ipppds, flags);
ipppd_put(ipppd);
return 0;
}
/* --- ioctl ------------------------------------------------------------ */
/*
* get_arg .. ioctl helper
*/
/* get_arg .. ioctl helper */
static int
get_arg(void *b, void *val, int len)
{
......@@ -441,9 +344,7 @@ get_arg(void *b, void *val, int len)
return 0;
}
/*
* set arg .. ioctl helper
*/
/* set arg .. ioctl helper */
static int
set_arg(void *b, void *val,int len)
{
......@@ -452,11 +353,9 @@ set_arg(void *b, void *val,int len)
return 0;
}
/*
* ippp device ioctl
*/
static int
ipppd_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;
......@@ -465,11 +364,10 @@ ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned lon
struct isdn_ppp_comp_data data;
unsigned int cfg;
is = (struct ipppd *) file->private_data;
is = file->private_data;
idev = is->idev;
if (is->debug & 0x1)
printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", is->minor, cmd, is->state);
ipppd_debug(is, "cmd %#x", cmd);
switch (cmd) {
case PPPIOCBUNDLE:
......@@ -629,50 +527,30 @@ ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned lon
return 0;
}
static unsigned int
ipppd_poll(struct file *file, poll_table * wait)
/* --- fops ------------------------------------------------------------- */
struct file_operations isdn_ppp_fops =
{
unsigned int mask;
struct ipppd *is;
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = ipppd_read,
.write = ipppd_write,
.poll = ipppd_poll,
.ioctl = ipppd_ioctl,
.open = ipppd_open,
.release = ipppd_release,
};
is = file->private_data;
/* --- ipppd_queue_read ------------------------------------------------- */
ipppd_debug(is, "");
/* Queue packets for ipppd to read(). */
/* just registers wait_queue hook. This doesn't really wait. */
poll_wait(file, &is->wq, wait);
if (is->flags & IPPPD_FL_HUP) {
mask = POLLHUP;
goto out;
}
/* we're always ready to send .. */
mask = POLLOUT | POLLWRNORM;
/*
* if IPPP_FL_WAKEUP is set we return even if we have nothing to read
*/
if (!skb_queue_empty(&is->rq) || is->flags & IPPPD_FL_WAKEUP) {
is->flags &= ~IPPPD_FL_WAKEUP;
mask |= POLLIN | POLLRDNORM;
set_current_state(TASK_INTERRUPTIBLE); // FIXME
schedule_timeout(HZ);
}
out:
return mask;
}
/*
* Queue packets for ipppd to read().
*/
static int
ipppd_queue_read(struct ipppd *is, u16 proto, unsigned char *buf, int len)
{
struct sk_buff *skb;
unsigned char *p;
int retval;
static int
ipppd_queue_read(struct ipppd *is, u16 proto, unsigned char *buf, int len)
{
struct sk_buff *skb;
unsigned char *p;
int retval;
if (is->state != IPPPD_ST_CONNECTED) {
printk(KERN_DEBUG "ippp: device not connected.\n");
......@@ -704,144 +582,274 @@ ipppd_queue_read(struct ipppd *is, u16 proto, unsigned char *buf, int len)
return retval;
}
/* ====================================================================== */
/* 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 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_dev_alloc_skb(void *priv, int len, int gfp_mask);
static void
isdn_ppp_dev_push_header(void *priv, struct sk_buff *skb, u16 proto);
static void
isdn_ppp_dev_xmit(void *priv, struct sk_buff *skb);
static struct sk_buff *
isdn_ppp_lp_alloc_skb(void *priv, int len, int gfp_mask);
static void
isdn_ppp_lp_push_header(void *priv, struct sk_buff *skb, u16 proto);
/* New CCP stuff */
static void
isdn_ppp_dev_kick_up(void *priv);
#ifdef CONFIG_ISDN_MPP
static ippp_bundle * isdn_ppp_bundle_arr = NULL;
static int isdn_ppp_mp_bundle_array_init(void);
static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to);
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 ipppd *, int unit);
#endif /* CONFIG_ISDN_MPP */
char *isdn_ppp_revision = "$Revision: 1.85.6.9 $";
/*
* read() .. non-blocking: ipppd calls it only after select()
* reports, that there is data
* frame log (debug)
*/
static ssize_t
ipppd_read(struct file *file, char *buf, size_t count, loff_t *off)
void
isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot)
{
struct ipppd *is;
struct sk_buff *skb;
int retval;
if (off != &file->f_pos)
return -ESPIPE;
int cnt,
j,
i;
char buf[80];
is = file->private_data;
if (len < maxlen)
maxlen = len;
skb = skb_dequeue(&is->rq);
if (!skb) {
retval = -EAGAIN;
goto out;
}
if (skb->len > count) {
retval = -EMSGSIZE;
goto out_free;
for (i = 0, cnt = 0; cnt < maxlen; i++) {
for (j = 0; j < 16 && cnt < maxlen; j++, cnt++)
sprintf(buf + j * 3, "%02x ", (unsigned char) data[cnt]);
printk(KERN_DEBUG "[%d/%d].%s[%d]: %s\n",unit,slot, info, i, buf);
}
if (copy_to_user(buf, skb->data, skb->len)) {
retval = -EFAULT;
goto out_free;
}
static void
isdn_ppp_push_header(isdn_net_dev *idev, struct sk_buff *skb, u16 proto)
{
unsigned char *p;
if (skb_headroom(skb) < 4) {
isdn_BUG();
return;
}
retval = skb->len;
out_free:
dev_kfree_skb(skb);
out:
return retval;
if ((idev->pppcfg & SC_COMP_PROT) && proto <= 0xff)
put_u8(skb_push(skb, 1), proto);
else
put_u16(skb_push(skb, 2), proto);
if (idev->pppcfg & SC_COMP_AC)
return;
p = skb_push(skb, 2);
p += put_u8(p, PPP_ALLSTATIONS);
p += put_u8(p, PPP_UI);
}
/*
* ipppd wanna write a packet to the card .. non-blocking
* unbind isdn_net_local <=> ippp-device
* note: it can happen, that we hangup/free the master before the slaves
* in this case we bind another lp to the master device
*/
static ssize_t
ipppd_write(struct file *file, const char *buf, size_t count, loff_t *off)
static void
isdn_ppp_unbind(isdn_net_dev *idev)
{
isdn_net_dev *idev;
struct ipppd *is;
int proto;
unsigned char protobuf[4];
int retval;
struct ipppd *is = idev->ipppd;
if (off != &file->f_pos)
return -ESPIPE;
if (!is) {
isdn_BUG();
return;
}
lock_kernel();
ipppd_debug(is, "");
is = file->private_data;
if (is->state != IPPPD_ST_ASSIGNED)
isdn_BUG();
ipppd_debug(is, "");
is->state = IPPPD_ST_OPEN;
if (is->state != IPPPD_ST_CONNECTED) {
HERE;
retval = -ENOTCONN;
goto out;
}
/* is->idev will be invalid shortly */
ippp_ccp_free(idev->ccp);
/* -> push it directly to the lowlevel interface */
is->idev = NULL;
/* lose the reference we took on isdn_ppp_bind */
ipppd_put(is);
idev->ipppd = NULL;
idev = is->idev;
if (!idev)
printk(KERN_DEBUG "isdn_ppp_write: idev == NULL\n");
else {
/*
* Don't reset huptimer for
* LCP packets. (Echo requests).
return;
}
/*
* bind isdn_net_local <=> ippp-device
*/
if (copy_from_user(protobuf, buf, 4)) {
retval = -EFAULT;
goto out;
int
isdn_ppp_bind(isdn_net_dev *idev)
{
int unit = 0;
unsigned long flags;
int retval = 0;
struct ipppd *ipppd;
if (idev->ipppd) {
isdn_BUG();
return 0;
}
proto = PPP_PROTOCOL(protobuf);
if (proto != PPP_LCP)
idev->huptimer = 0;
if (idev->isdn_slot < 0) {
retval = 0;
goto out;
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);
/* 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 && p->pppbind < ISDN_MAX_CHANNELS)
exclusive[p->pppbind] = 1;
}
if ((dev->drv[isdn_slot_driver(idev->isdn_slot)]->flags & DRV_FLAG_RUNNING)) {
unsigned short hl;
struct sk_buff *skb;
/*
* we need to reserve enought space in front of
* sk_buff. old call to dev_alloc_skb only reserved
* 16 bytes, now we are looking what the driver want
* search a free device / slot
*/
hl = isdn_slot_hdrlen(idev->isdn_slot);
skb = alloc_skb(hl+count, GFP_ATOMIC);
if (!skb) {
printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
retval = count;
goto out;
list_for_each_entry(ipppd, &ipppds, ipppds) {
if (!ipppd)
continue;
if (ipppd->state != IPPPD_ST_OPEN)
continue;
if (!exclusive[ipppd->minor])
break;
goto found;
}
skb_reserve(skb, hl);
if (copy_from_user(skb_put(skb, count), buf, count))
{
kfree_skb(skb);
retval = -EFAULT;
goto out;
} else {
list_for_each_entry(ipppd, &ipppds, ipppds) {
if (!ipppd)
continue;
if (ipppd->state != IPPPD_ST_OPEN)
continue;
if (ipppd->minor == idev->pppbind)
goto found;
}
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,-1);
}
isdn_ppp_send_ccp(idev,idev->mlp,skb); /* keeps CCP/compression states in sync */
printk(KERN_INFO "isdn_ppp_bind: no ipppd\n");
retval = -ESRCH;
goto err;
isdn_net_write_super(idev, skb);
found:
unit = isdn_ppp_if_get_unit(idev->name); /* get unit number from interface name .. ugly! */
if (unit < 0) {
printk(KERN_INFO "isdn_ppp_bind: illegal interface name %s.\n", idev->name);
retval = -ENODEV;
goto err;
}
ipppd->unit = unit;
ipppd->state = IPPPD_ST_ASSIGNED;
ipppd->idev = idev;
/* we hold a reference until isdn_ppp_unbind() */
idev->ipppd = ipppd_get(ipppd);
spin_unlock_irqrestore(&ipppds_lock, flags);
idev->pppcfg = 0; /* config flags */
/* seq no last seen, maybe set to bundle min, when joining? */
idev->pppseq = -1;
idev->ccp = ippp_ccp_alloc();
if (!idev->ccp) {
retval = -ENOMEM;
goto out;
}
retval = count;
idev->ccp->proto = PPP_COMPFRAG;
idev->ccp->priv = idev;
idev->ccp->alloc_skb = isdn_ppp_dev_alloc_skb;
idev->ccp->push_header = isdn_ppp_dev_push_header;
idev->ccp->xmit = isdn_ppp_dev_xmit;
idev->ccp->kick_up = isdn_ppp_dev_kick_up;
#ifdef CONFIG_ISDN_MPP
retval = isdn_ppp_mp_init(lp, NULL);
#endif /* CONFIG_ISDN_MPP */
out:
unlock_kernel();
if (retval) {
idev->ipppd->state = IPPPD_ST_OPEN;
ipppd_put(idev->ipppd);
idev->ipppd = NULL;
}
return retval;
err:
spin_unlock_irqrestore(&ipppds_lock, flags);
return retval;
}
struct file_operations isdn_ppp_fops =
/*
* kick the ipppd on the device
* (wakes up daemon after B-channel connect)
*/
static void
isdn_ppp_connected(isdn_net_dev *idev)
{
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = ipppd_read,
.write = ipppd_write,
.poll = ipppd_poll,
.ioctl = ipppd_ioctl,
.open = ipppd_open,
.release = ipppd_release,
};
struct ipppd *ipppd = idev->ipppd;
ipppd_debug(ipppd, "");
ipppd->state = IPPPD_ST_CONNECTED;
ipppd->flags |= IPPPD_FL_WAKEUP;
wake_up(&ipppd->wq);
}
static void
isdn_ppp_disconnected(isdn_net_dev *idev)
{
struct ipppd *ipppd = idev->ipppd;
ipppd_debug(ipppd, "");
if (idev->pppcfg & SC_ENABLE_IP)
isdn_net_offline(idev);
if (ipppd->state != IPPPD_ST_CONNECTED)
isdn_BUG();
ipppd->state = IPPPD_ST_ASSIGNED;
ipppd->flags |= IPPPD_FL_HUP;
wake_up(&ipppd->wq);
#ifdef CONFIG_ISDN_MPP
spin_lock(&idev->pb->lock);
if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */
isdn_ppp_mp_cleanup(lp);
lp->netdev->pb->ref_ct--;
spin_unlock(&lp->netdev->pb->lock);
#endif /* CONFIG_ISDN_MPP */
}
/*
* init memory, structures etc.
......
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