Commit cb35e72a authored by Kai Germaschewski's avatar Kai Germaschewski

ISDN/PPP: clean up ipppd_write() and ipppd_ioctl()

plus other small cleanups, in particular getting rid of
isdn_ppp_{receive,send}_ccp() and calling into the CCP code directly.
parent d6b03063
...@@ -21,12 +21,11 @@ ...@@ -21,12 +21,11 @@
#include "isdn_ppp_ccp.h" #include "isdn_ppp_ccp.h"
#include "isdn_net.h" #include "isdn_net.h"
static void static struct sk_buff *
isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, isdn_ppp_dev_alloc_skb(void *priv, int len, int gfp_mask);
struct sk_buff *skb);
static int static int
isdn_ppp_set_compressor(struct ipppd *is,struct isdn_ppp_comp_data *); isdn_ppp_set_compressor(isdn_net_dev *idev, struct isdn_ppp_comp_data *);
/* ====================================================================== */ /* ====================================================================== */
/* IPPPD handling */ /* IPPPD handling */
...@@ -212,86 +211,66 @@ static ssize_t ...@@ -212,86 +211,66 @@ static ssize_t
ipppd_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; isdn_net_dev *idev;
struct ipppd *is; struct ipppd *ipppd;
int proto; struct sk_buff *skb;
unsigned char protobuf[4]; char *p;
int retval; int retval;
u16 proto;
if (off != &file->f_pos) if (off != &file->f_pos)
return -ESPIPE; return -ESPIPE;
lock_kernel(); ipppd = file->private_data;
ipppd_debug(ipppd, "count = %d", count);
is = file->private_data;
ipppd_debug(is, "");
if (is->state != IPPPD_ST_CONNECTED) { if (ipppd->state != IPPPD_ST_CONNECTED) {
retval = -ENOTCONN; retval = -ENOTCONN;
goto out; goto out;
} }
/* -> push it directly to the lowlevel interface */ idev = ipppd->idev;
if (!idev) {
idev = is->idev; isdn_BUG();
if (!idev) retval = -ENODEV;
printk(KERN_DEBUG "isdn_ppp_write: idev == NULL\n"); goto out;
else { }
/* /* Daemon needs to send at least full header, AC + proto */
* Don't reset huptimer for if (count < 4) {
* LCP packets. (Echo requests). retval = -EMSGSIZE;
*/ goto out;
if (copy_from_user(protobuf, buf, 4)) { }
retval = -EFAULT; skb = isdn_ppp_dev_alloc_skb(idev, count, GFP_KERNEL);
goto out; if (!skb) {
} retval = -ENOMEM;
proto = PPP_PROTOCOL(protobuf); goto out;
if (proto != PPP_LCP) }
idev->huptimer = 0; p = skb_put(skb, count);
if (copy_from_user(p, buf, count)) {
if (idev->isdn_slot < 0) { kfree_skb(skb);
retval = 0; retval = -EFAULT;
goto out; 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;
}
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);
}
/* keeps CCP/compression states in sync */
isdn_ppp_send_ccp(idev,idev->mlp,skb);
/* FIXME: Somewhere we need protection against the
* queue growing too large */
isdn_net_write_super(idev, skb);
}
} }
/* Don't reset huptimer for LCP packets. (Echo requests). */
proto = PPP_PROTOCOL(p);
if (proto != PPP_LCP)
idev->huptimer = 0;
/* Keeps CCP/compression states in sync */
switch (proto) {
case PPP_CCP:
ippp_ccp_send_ccp(idev->mlp->ccp, skb);
break;
case PPP_CCPFRAG:
ippp_ccp_send_ccp(idev->ccp, skb);
break;
}
/* FIXME: Somewhere we need protection against the
* queue growing too large */
isdn_net_write_super(idev, skb);
retval = count; retval = count;
out: out:
unlock_kernel();
return retval; return retval;
} }
...@@ -335,20 +314,18 @@ ipppd_poll(struct file *file, poll_table * wait) ...@@ -335,20 +314,18 @@ ipppd_poll(struct file *file, poll_table * wait)
/* get_arg .. ioctl helper */ /* get_arg .. ioctl helper */
static int static int
get_arg(void *b, void *val, int len) get_arg(unsigned long arg, void *val, int len)
{ {
if (len <= 0) if (copy_from_user((void *) val, (void *) arg, len))
len = sizeof(void *);
if (copy_from_user((void *) val, b, len))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
/* set arg .. ioctl helper */ /* set arg .. ioctl helper */
static int static int
set_arg(void *b, void *val,int len) set_arg(unsigned long arg, void *val,int len)
{ {
if (copy_to_user(b, (void *) val, len)) if (copy_to_user((void *) arg, (void *) val, len))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
...@@ -372,53 +349,78 @@ ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd, ...@@ -372,53 +349,78 @@ ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd,
switch (cmd) { switch (cmd) {
case PPPIOCBUNDLE: case PPPIOCBUNDLE:
#ifdef CONFIG_ISDN_MPP #ifdef CONFIG_ISDN_MPP
if (!(is->state & IPPP_CONNECT)) if (is->state != IPPPD_ST_CONNECTED) {
return -EINVAL; r = -EINVAL;
if ((r = get_arg((void *) arg, &val, sizeof(val) ))) break;
return r; }
r = get_arg(arg, &val, sizeof(val));
if (r)
break;
printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n", printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
(int) is->minor, (int) is->unit, (int) val); is->minor, is->unit, val);
return isdn_ppp_bundle(is, val); r = isdn_ppp_bundle(is, val);
#else #else
return -1; r = -EINVAL;
#endif #endif
break; break;
case PPPIOCGUNIT: /* get ppp/isdn unit number */ case PPPIOCGUNIT: /* get ppp/isdn unit number */
if ((r = set_arg((void *) arg, &is->unit, sizeof(is->unit) ))) r = set_arg(arg, &is->unit, sizeof(is->unit));
return r;
break; break;
case PPPIOCGDEBUG:
r = set_arg(arg, &is->debug, sizeof(is->debug));
break;
case PPPIOCSDEBUG:
r = get_arg(arg, &val, sizeof(val));
if (r)
break;
is->debug = val;
if (idev) {
idev->debug = val;
idev->mlp->debug = val;
}
break;
case PPPIOCGCOMPRESSORS:
{
unsigned long protos[8];
ippp_ccp_get_compressors(protos);
r = set_arg(arg, protos, sizeof(protos));
break;
}
default:
r = -ENOTTY;
break;
}
if (r != -ENOTTY)
goto out;
if (!idev) {
r = -ENODEV;
goto out;
}
switch (cmd) {
case PPPIOCGIFNAME: case PPPIOCGIFNAME:
if(!idev) r = set_arg(arg, idev->name, strlen(idev->name)+1);
return -EINVAL;
if ((r = set_arg((void *) arg, idev->name, strlen(idev->name))))
return r;
break; break;
case PPPIOCGMPFLAGS: /* get configuration flags */ case PPPIOCGMPFLAGS: /* get configuration flags */
if (!idev) r = set_arg(arg, &idev->mlp->mpppcfg, sizeof(idev->mlp->mpppcfg));
return -ENODEV;
if ((r = set_arg((void *) arg, &idev->mlp->mpppcfg, sizeof(idev->mlp->mpppcfg) )))
return r;
break; break;
case PPPIOCSMPFLAGS: /* set configuration flags */ case PPPIOCSMPFLAGS: /* set configuration flags */
if (!idev) r = get_arg(arg, &val, sizeof(val));
return -ENODEV; if (r)
if ((r = get_arg((void *) arg, &val, sizeof(val) ))) break;
return r;
idev->mlp->mpppcfg = val; idev->mlp->mpppcfg = val;
break; break;
case PPPIOCGFLAGS: /* get configuration flags */ case PPPIOCGFLAGS: /* get configuration flags */
if (!idev)
return -ENODEV;
cfg = idev->pppcfg | ippp_ccp_get_flags(idev->ccp); cfg = idev->pppcfg | ippp_ccp_get_flags(idev->ccp);
if ((r = set_arg((void *) arg, &cfg, sizeof(cfg) ))) r = set_arg(arg, &cfg, sizeof(cfg));
return r;
break; break;
case PPPIOCSFLAGS: /* set configuration flags */ case PPPIOCSFLAGS: /* set configuration flags */
if (!idev) r = get_arg(arg, &val, sizeof(val));
return -ENODEV; if (r)
if ((r = get_arg((void *) arg, &val, sizeof(val) ))) { break;
return r;
}
if ((val & SC_ENABLE_IP) && !(idev->pppcfg & SC_ENABLE_IP)) { if ((val & SC_ENABLE_IP) && !(idev->pppcfg & SC_ENABLE_IP)) {
idev->pppcfg = val; idev->pppcfg = val;
/* OK .. we are ready to send buffers */ /* OK .. we are ready to send buffers */
...@@ -428,19 +430,18 @@ ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd, ...@@ -428,19 +430,18 @@ ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd,
idev->pppcfg = val; idev->pppcfg = val;
break; break;
case PPPIOCGIDLE: /* get idle time information */ case PPPIOCGIDLE: /* get idle time information */
if (idev) { {
struct ppp_idle pidle; struct ppp_idle pidle;
pidle.xmit_idle = pidle.recv_idle = idev->huptimer; pidle.xmit_idle = pidle.recv_idle = idev->huptimer;
if ((r = set_arg((void *) arg, &pidle,sizeof(struct ppp_idle)))) r = set_arg(arg, &pidle,sizeof(pidle));
return r;
}
break; break;
}
case PPPIOCSMRU: /* set receive unit size for PPP */ case PPPIOCSMRU: /* set receive unit size for PPP */
if (!idev) r = get_arg(arg, &val, sizeof(val));
return -ENODEV; if (r)
if ((r = get_arg((void *) arg, &val, sizeof(val) ))) break;
return r; r = ippp_ccp_set_mru(idev->ccp, val);
return ippp_ccp_set_mru(idev->ccp, val); break;
case PPPIOCSMPMRU: case PPPIOCSMPMRU:
break; break;
case PPPIOCSMPMTU: case PPPIOCSMPMTU:
...@@ -449,82 +450,61 @@ ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd, ...@@ -449,82 +450,61 @@ ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd,
case PPPIOCSMAXCID: /* set the maximum compression slot id */ case PPPIOCSMAXCID: /* set the maximum compression slot id */
{ {
struct slcompress *sltmp; struct slcompress *sltmp;
r = get_arg(arg, &val, sizeof(val));
if (!idev) if (r)
return -ENODEV; break;
if ((r = get_arg((void *) arg, &val, sizeof(val) )))
return r;
val++; val++;
if (is->debug & 0x1)
printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val);
sltmp = slhc_init(16, val); sltmp = slhc_init(16, val);
if (!sltmp) { if (!sltmp) {
printk(KERN_ERR "ippp, can't realloc slhc struct\n"); r = -ENOMEM;
return -ENOMEM; break;
} }
if (idev->mlp->slcomp) if (idev->mlp->slcomp)
slhc_free(idev->mlp->slcomp); slhc_free(idev->mlp->slcomp);
idev->mlp->slcomp = sltmp; idev->mlp->slcomp = sltmp;
r = 0;
break; break;
} }
#endif #endif
case PPPIOCGDEBUG:
if ((r = set_arg((void *) arg, &is->debug, sizeof(is->debug) )))
return r;
break;
case PPPIOCSDEBUG:
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:
{
unsigned long protos[8];
ippp_ccp_get_compressors(protos);
if ((r = set_arg((void *) arg,protos,8*sizeof(long) )))
return r;
}
break;
case PPPIOCSCOMPRESSOR: case PPPIOCSCOMPRESSOR:
if ((r = get_arg((void *) arg, &data, sizeof(struct isdn_ppp_comp_data)))) r = get_arg(arg, &data, sizeof(data));
return r; if (r)
return isdn_ppp_set_compressor(is, &data); break;
r = isdn_ppp_set_compressor(idev, &data);
break;
case PPPIOCGCALLINFO: case PPPIOCGCALLINFO:
{ {
isdn_net_local *mlp; isdn_net_local *mlp;
struct isdn_net_phone *phone; struct isdn_net_phone *phone;
struct pppcallinfo pci; struct pppcallinfo pci;
int i; int i;
memset((char *) &pci,0,sizeof(struct pppcallinfo)); memset(&pci, 0, sizeof(pci));
if(idev) {
mlp = idev->mlp; mlp = idev->mlp;
strncpy(pci.local_num, mlp->msn, 63); strncpy(pci.local_num, mlp->msn, 63);
i = 0; i = 0;
list_for_each_entry(phone, &mlp->phone[1], list) { list_for_each_entry(phone, &mlp->phone[1], list) {
if (i++ == idev->dial) { if (i++ == idev->dial) {
strncpy(pci.remote_num,phone->num,63); strncpy(pci.remote_num,phone->num,63);
break; break;
}
} }
pci.charge_units = idev->charge;
if(idev->outgoing)
pci.calltype = CALLTYPE_OUTGOING;
else
pci.calltype = CALLTYPE_INCOMING;
if(mlp->flags & ISDN_NET_CALLBACK)
pci.calltype |= CALLTYPE_CALLBACK;
} }
return set_arg((void *)arg,&pci,sizeof(struct pppcallinfo)); pci.charge_units = idev->charge;
if (idev->outgoing)
pci.calltype = CALLTYPE_OUTGOING;
else
pci.calltype = CALLTYPE_INCOMING;
if (mlp->flags & ISDN_NET_CALLBACK)
pci.calltype |= CALLTYPE_CALLBACK;
r = set_arg(arg, &pci, sizeof(pci));
break;
} }
default: default:
r = -ENOTTY;
break; break;
} }
return 0; out:
return r;
} }
/* --- fops ------------------------------------------------------------- */ /* --- fops ------------------------------------------------------------- */
...@@ -589,13 +569,6 @@ static void isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, ...@@ -589,13 +569,6 @@ 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);
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 static void
isdn_ppp_dev_push_header(void *priv, struct sk_buff *skb, u16 proto); isdn_ppp_dev_push_header(void *priv, struct sk_buff *skb, u16 proto);
...@@ -934,7 +907,6 @@ int isdn_ppp_strip_proto(struct sk_buff *skb) ...@@ -934,7 +907,6 @@ int isdn_ppp_strip_proto(struct sk_buff *skb)
return proto; return proto;
} }
/* /*
* handler for incoming packets on a syncPPP interface * handler for incoming packets on a syncPPP interface
*/ */
...@@ -1060,22 +1032,22 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, ...@@ -1060,22 +1032,22 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
} }
break; break;
#endif #endif
case PPP_CCP:
case PPP_CCPFRAG: case PPP_CCPFRAG:
isdn_ppp_receive_ccp(idev,lp,skb,proto); ippp_ccp_receive_ccp(idev->ccp, skb);
goto ccp;
case PPP_CCP:
ippp_ccp_receive_ccp(lp->ccp, skb);
ccp:
/* Dont pop up ResetReq/Ack stuff to the daemon any /* Dont pop up ResetReq/Ack stuff to the daemon any
longer - the job is done already */ longer - the job is done already */
if(skb->data[0] == CCP_RESETREQ || if(skb->data[0] == CCP_RESETREQ ||
skb->data[0] == CCP_RESETACK) { skb->data[0] == CCP_RESETACK)
kfree_skb(skb); goto free;
goto out;
}
/* fall through */ /* fall through */
default: default:
// FIXME use skb directly // FIXME use skb directly
ipppd_queue_read(is, proto, skb->data, skb->len); ipppd_queue_read(is, proto, skb->data, skb->len);
kfree_skb(skb); goto free;
goto out;
} }
/* Reset hangup-timer */ /* Reset hangup-timer */
...@@ -1089,6 +1061,7 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev, ...@@ -1089,6 +1061,7 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
drop: drop:
lp->stats.rx_dropped++; lp->stats.rx_dropped++;
free:
kfree_skb(skb); kfree_skb(skb);
} }
...@@ -1795,17 +1768,18 @@ isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -1795,17 +1768,18 @@ isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return -EINVAL; return -EINVAL;
switch (cmd) { switch (cmd) {
case SIOCGPPPVER: case SIOCGPPPVER:
r = (char *) ifr->ifr_ifru.ifru_data; r = (char *) ifr->ifr_ifru.ifru_data;
len = strlen(PPP_VERSION) + 1; len = strlen(PPP_VERSION) + 1;
if(copy_to_user(r, PPP_VERSION, len)) error = -EFAULT; if (copy_to_user(r, PPP_VERSION, len))
break; error = -EFAULT;
case SIOCGPPPSTATS: break;
error = isdn_ppp_dev_ioctl_stats(ifr, dev); case SIOCGPPPSTATS:
break; error = isdn_ppp_dev_ioctl_stats(ifr, dev);
default: break;
error = -EINVAL; default:
break; error = -EINVAL;
break;
} }
return error; return error;
} }
...@@ -2001,72 +1975,17 @@ isdn_ppp_lp_xmit(void *priv, struct sk_buff *skb) ...@@ -2001,72 +1975,17 @@ isdn_ppp_lp_xmit(void *priv, struct sk_buff *skb)
isdn_net_write_super(idev, skb); isdn_net_write_super(idev, skb);
} }
/*
* 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)
{
if (proto == PPP_CCP)
ippp_ccp_receive_ccp(lp->ccp, skb);
else
ippp_ccp_receive_ccp(idev->ccp, skb);
}
/*
* Daemon sends a CCP frame ...
*/
static void isdn_ppp_send_ccp(isdn_net_dev *idev, isdn_net_local *lp, struct sk_buff *skb)
{
int proto;
unsigned char *data;
if (!skb || skb->len < 3) {
isdn_BUG();
return;
}
/* Daemon may send with or without address and control field comp */
data = skb->data;
if (data[0] == 0xff && data[1] == 0x03) {
data += 2;
if(skb->len < 5)
return;
}
proto = ((int)data[0]<<8)+data[1];
switch (proto) {
case PPP_CCP:
ippp_ccp_send_ccp(lp->ccp, skb);
break;
case PPP_CCPFRAG:
ippp_ccp_send_ccp(idev->ccp, skb);
break;
}
}
static int static int
isdn_ppp_set_compressor(struct ipppd *is, struct isdn_ppp_comp_data *data) isdn_ppp_set_compressor(isdn_net_dev *idev, struct isdn_ppp_comp_data *data)
{ {
isdn_net_dev *idev = is->idev;
isdn_net_local *lp;
struct ippp_ccp *ccp; struct ippp_ccp *ccp;
if (!idev)
return -ENODEV;
lp = idev->mlp;
if (data->flags & IPPP_COMP_FLAG_LINK) if (data->flags & IPPP_COMP_FLAG_LINK)
ccp = idev->ccp; ccp = idev->ccp;
else else
ccp = lp->ccp; ccp = idev->mlp->ccp;
return ippp_ccp_set_compressor(ccp, is->unit, data); return ippp_ccp_set_compressor(ccp, idev->ipppd->unit, data);
} }
// ISDN_NET_ENCAP_SYNCPPP // ISDN_NET_ENCAP_SYNCPPP
...@@ -2102,6 +2021,7 @@ isdn_ppp_close(isdn_net_local *lp) ...@@ -2102,6 +2021,7 @@ isdn_ppp_close(isdn_net_local *lp)
lp->slcomp = NULL; lp->slcomp = NULL;
#endif #endif
ippp_ccp_free(lp->ccp); ippp_ccp_free(lp->ccp);
lp->ccp = NULL;
} }
struct isdn_netif_ops isdn_ppp_ops = { struct isdn_netif_ops isdn_ppp_ops = {
......
...@@ -27,5 +27,3 @@ int ...@@ -27,5 +27,3 @@ int
isdn_ppp_strip_proto(struct sk_buff *skb); isdn_ppp_strip_proto(struct sk_buff *skb);
#define IPPP_MAX_HEADER 10 #define IPPP_MAX_HEADER 10
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