ipv6 sit: Avoid extra need for compat layer in PRL management.

We've introduced extra need of compat layer for ip_tunnel_prl{}
for PRL (Potential Router List) management.  Though compat_ioctl
is still missing in ipv4/ipv6, let's make the interface more
straight-forward and eliminate extra need for nasty compat layer
anyway since the interface is new for 2.6.26.

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
YOSHIFUJI Hideaki 2008-06-16 16:48:20 -07:00 committed by David S. Miller
parent 47083fc073
commit 2b4743bd6b
2 changed files with 25 additions and 21 deletions

View file

@ -41,7 +41,7 @@ struct ip_tunnel_prl {
__u16 __reserved; __u16 __reserved;
__u32 datalen; __u32 datalen;
__u32 __reserved2; __u32 __reserved2;
void __user *data; /* data follows */
}; };
/* PRL flags */ /* PRL flags */

View file

@ -222,15 +222,18 @@ __ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr)
} }
static int ipip6_tunnel_get_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) static int ipip6_tunnel_get_prl(struct ip_tunnel *t,
struct ip_tunnel_prl __user *a)
{ {
struct ip_tunnel_prl *kp; struct ip_tunnel_prl kprl, *kp;
struct ip_tunnel_prl_entry *prl; struct ip_tunnel_prl_entry *prl;
unsigned int cmax, c = 0, ca, len; unsigned int cmax, c = 0, ca, len;
int ret = 0; int ret = 0;
cmax = a->datalen / sizeof(*a); if (copy_from_user(&kprl, a, sizeof(kprl)))
if (cmax > 1 && a->addr != htonl(INADDR_ANY)) return -EFAULT;
cmax = kprl.datalen / sizeof(kprl);
if (cmax > 1 && kprl.addr != htonl(INADDR_ANY))
cmax = 1; cmax = 1;
/* For simple GET or for root users, /* For simple GET or for root users,
@ -261,26 +264,25 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
for (prl = t->prl; prl; prl = prl->next) { for (prl = t->prl; prl; prl = prl->next) {
if (c > cmax) if (c > cmax)
break; break;
if (a->addr != htonl(INADDR_ANY) && prl->addr != a->addr) if (kprl.addr != htonl(INADDR_ANY) && prl->addr != kprl.addr)
continue; continue;
kp[c].addr = prl->addr; kp[c].addr = prl->addr;
kp[c].flags = prl->flags; kp[c].flags = prl->flags;
c++; c++;
if (a->addr != htonl(INADDR_ANY)) if (kprl.addr != htonl(INADDR_ANY))
break; break;
} }
out: out:
read_unlock(&ipip6_lock); read_unlock(&ipip6_lock);
len = sizeof(*kp) * c; len = sizeof(*kp) * c;
ret = len ? copy_to_user(a->data, kp, len) : 0; ret = 0;
if ((len && copy_to_user(a + 1, kp, len)) || put_user(len, &a->datalen))
ret = -EFAULT;
kfree(kp); kfree(kp);
if (ret)
return -EFAULT;
a->datalen = len; return ret;
return 0;
} }
static int static int
@ -873,11 +875,20 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
break; break;
case SIOCGETPRL: case SIOCGETPRL:
err = -EINVAL;
if (dev == sitn->fb_tunnel_dev)
goto done;
err = -ENOENT;
if (!(t = netdev_priv(dev)))
goto done;
err = ipip6_tunnel_get_prl(t, ifr->ifr_ifru.ifru_data);
break;
case SIOCADDPRL: case SIOCADDPRL:
case SIOCDELPRL: case SIOCDELPRL:
case SIOCCHGPRL: case SIOCCHGPRL:
err = -EPERM; err = -EPERM;
if (cmd != SIOCGETPRL && !capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
goto done; goto done;
err = -EINVAL; err = -EINVAL;
if (dev == sitn->fb_tunnel_dev) if (dev == sitn->fb_tunnel_dev)
@ -890,12 +901,6 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
goto done; goto done;
switch (cmd) { switch (cmd) {
case SIOCGETPRL:
err = ipip6_tunnel_get_prl(t, &prl);
if (!err && copy_to_user(ifr->ifr_ifru.ifru_data,
&prl, sizeof(prl)))
err = -EFAULT;
break;
case SIOCDELPRL: case SIOCDELPRL:
err = ipip6_tunnel_del_prl(t, &prl); err = ipip6_tunnel_del_prl(t, &prl);
break; break;
@ -904,8 +909,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL); err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL);
break; break;
} }
if (cmd != SIOCGETPRL) netdev_state_change(dev);
netdev_state_change(dev);
break; break;
default: default: