sparse and devinet_ioctl

From: Aneesh Kumar
Date: Tue Jun 20 2006 - 07:23:05 EST


How do i make sure i can call devinet_ioctl from kernel without having
a sparse warning.

The call i want to use was SIOCGIFADDR

Right now i am patching it as below

_devinet_ioctl(SIOCGIFADDR, &ifr)

Is this the correct way ? But then I don't want to patch any core
kernel files. In that case how will i achieve the results.


-aneesh diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 54419b2..e8e9eaa 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -532,11 +532,10 @@ static __inline__ int inet_abc_len(u32 a
}


-int devinet_ioctl(unsigned int cmd, void __user *arg)
+int _devinet_ioctl(unsigned int cmd, struct ifreq *ifr)
{
- struct ifreq ifr;
struct sockaddr_in sin_orig;
- struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
+ struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr;
struct in_device *in_dev;
struct in_ifaddr **ifap = NULL;
struct in_ifaddr *ifa = NULL;
@@ -545,23 +544,17 @@ int devinet_ioctl(unsigned int cmd, void
int ret = -EFAULT;
int tryaddrmatch = 0;

- /*
- * Fetch the caller's info block into kernel space
- */
-
- if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
- goto out;
- ifr.ifr_name[IFNAMSIZ - 1] = 0;
+ ifr->ifr_name[IFNAMSIZ - 1] = 0;

/* save original address for comparison */
memcpy(&sin_orig, sin, sizeof(*sin));

- colon = strchr(ifr.ifr_name, ':');
+ colon = strchr(ifr->ifr_name, ':');
if (colon)
*colon = 0;

#ifdef CONFIG_KMOD
- dev_load(ifr.ifr_name);
+ dev_load(ifr->ifr_name);
#endif

switch(cmd) {
@@ -602,7 +595,7 @@ #endif
rtnl_lock();

ret = -ENODEV;
- if ((dev = __dev_get_by_name(ifr.ifr_name)) == NULL)
+ if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)
goto done;

if (colon)
@@ -617,7 +610,7 @@ #endif
This is checked above. */
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
ifap = &ifa->ifa_next) {
- if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
+ if (!strcmp(ifr->ifr_name, ifa->ifa_label) &&
sin_orig.sin_addr.s_addr ==
ifa->ifa_address) {
break; /* found */
@@ -630,7 +623,7 @@ #endif
if (!ifa) {
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
ifap = &ifa->ifa_next)
- if (!strcmp(ifr.ifr_name, ifa->ifa_label))
+ if (!strcmp(ifr->ifr_name, ifa->ifa_label))
break;
}
}
@@ -662,11 +655,11 @@ #endif
if (!ifa)
break;
ret = 0;
- if (!(ifr.ifr_flags & IFF_UP))
+ if (!(ifr->ifr_flags & IFF_UP))
inet_del_ifa(in_dev, ifap, 1);
break;
}
- ret = dev_change_flags(dev, ifr.ifr_flags);
+ ret = dev_change_flags(dev, ifr->ifr_flags);
break;

case SIOCSIFADDR: /* Set interface address (and family) */
@@ -679,7 +672,7 @@ #endif
if ((ifa = inet_alloc_ifa()) == NULL)
break;
if (colon)
- memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
+ memcpy(ifa->ifa_label, ifr->ifr_name, IFNAMSIZ);
else
memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
} else {
@@ -767,9 +760,26 @@ out:
return ret;
rarok:
rtnl_unlock();
- ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
goto out;
}
+int devinet_ioctl(unsigned int cmd, void __user *arg)
+{
+ struct ifreq ifr;
+ int ret;
+
+ /*
+ * Fetch the caller's info block into kernel space
+ */
+
+ if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
+ return -EFAULT;
+
+ if ((ret = _devinet_ioctl(cmd, &ifr)) == 0 ) {
+ ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
+ }
+ return ret;
+
+}

static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
{