net: socket: simplify dev_ifconf handling
The dev_ifconf() calling conventions make compat handling more complicated than necessary, simplify this by moving the in_compat_syscall() check into the function. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
b0e99d0377
commit
876f0bf9d0
@@ -31,48 +31,51 @@ static int dev_ifname(struct net *net, struct ifreq *ifr)
|
||||
* size eventually, and there is nothing I can do about it.
|
||||
* Thus we will need a 'compatibility mode'.
|
||||
*/
|
||||
|
||||
int dev_ifconf(struct net *net, struct ifconf *ifc, int size)
|
||||
int dev_ifconf(struct net *net, struct ifconf __user *uifc)
|
||||
{
|
||||
struct net_device *dev;
|
||||
char __user *pos;
|
||||
int len;
|
||||
int total;
|
||||
int i;
|
||||
void __user *pos;
|
||||
size_t size;
|
||||
int len, total = 0, done;
|
||||
|
||||
/*
|
||||
* Fetch the caller's info block.
|
||||
*/
|
||||
/* both the ifconf and the ifreq structures are slightly different */
|
||||
if (in_compat_syscall()) {
|
||||
struct compat_ifconf ifc32;
|
||||
|
||||
pos = ifc->ifc_buf;
|
||||
len = ifc->ifc_len;
|
||||
if (copy_from_user(&ifc32, uifc, sizeof(struct compat_ifconf)))
|
||||
return -EFAULT;
|
||||
|
||||
/*
|
||||
* Loop over the interfaces, and write an info block for each.
|
||||
*/
|
||||
pos = compat_ptr(ifc32.ifcbuf);
|
||||
len = ifc32.ifc_len;
|
||||
size = sizeof(struct compat_ifreq);
|
||||
} else {
|
||||
struct ifconf ifc;
|
||||
|
||||
total = 0;
|
||||
if (copy_from_user(&ifc, uifc, sizeof(struct ifconf)))
|
||||
return -EFAULT;
|
||||
|
||||
pos = ifc.ifc_buf;
|
||||
len = ifc.ifc_len;
|
||||
size = sizeof(struct ifreq);
|
||||
}
|
||||
|
||||
/* Loop over the interfaces, and write an info block for each. */
|
||||
rtnl_lock();
|
||||
for_each_netdev(net, dev) {
|
||||
int done;
|
||||
if (!pos)
|
||||
done = inet_gifconf(dev, NULL, 0, size);
|
||||
else
|
||||
done = inet_gifconf(dev, pos + total,
|
||||
len - total, size);
|
||||
if (done < 0)
|
||||
if (done < 0) {
|
||||
rtnl_unlock();
|
||||
return -EFAULT;
|
||||
}
|
||||
total += done;
|
||||
}
|
||||
rtnl_unlock();
|
||||
|
||||
/*
|
||||
* All done. Write the updated control block back to the caller.
|
||||
*/
|
||||
ifc->ifc_len = total;
|
||||
|
||||
/*
|
||||
* Both BSD and Solaris return 0 here, so we do too.
|
||||
*/
|
||||
return 0;
|
||||
return put_user(total, &uifc->ifc_len);
|
||||
}
|
||||
|
||||
static int dev_getifmap(struct net_device *dev, struct ifreq *ifr)
|
||||
|
Reference in New Issue
Block a user