Similarly to what we did for ifioctl() a few months back, we can factor
out the handling of reading ioctls into a new function, in_ioctl_get().
Treat these cases before grabbing the NET_LOCK() in in_ioctl().
I only moved and copied a few pieces of code around and did not try to
make any simplifications to keep the idea of the refactoring clearly
visible. This results in a bit of code duplication, but it is not too
bad.
We can think about further simplifications and introducing a helper
function or two in a later step.
Index: sys/netinet/in.c
===================================================================
RCS file: /var/cvs/src/sys/netinet/in.c,v
retrieving revision 1.150
diff -u -p -r1.150 in.c
--- sys/netinet/in.c 30 Apr 2018 19:07:44 -0000 1.150
+++ sys/netinet/in.c 1 May 2018 23:02:04 -0000
@@ -84,6 +84,7 @@
void in_socktrim(struct sockaddr_in *);
+int in_ioctl_get(u_long cmd, caddr_t data, struct ifnet *ifp);
void in_purgeaddr(struct ifaddr *);
int in_addhost(struct in_ifaddr *, struct sockaddr_in *);
int in_scrubhost(struct in_ifaddr *, struct sockaddr_in *);
@@ -220,6 +221,14 @@ in_ioctl(u_long cmd, caddr_t data, struc
if (ifp == NULL)
return (ENXIO);
+ switch (cmd) {
+ case SIOCGIFADDR:
+ case SIOCGIFNETMASK:
+ case SIOCGIFDSTADDR:
+ case SIOCGIFBRDADDR:
+ return in_ioctl_get(cmd, data, ifp);
+ }
+
NET_LOCK();
TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
@@ -230,7 +239,6 @@ in_ioctl(u_long cmd, caddr_t data, struc
}
switch (cmd) {
-
case SIOCAIFADDR:
case SIOCDIFADDR:
if (ifra->ifra_addr.sin_family == AF_INET) {
@@ -279,12 +287,7 @@ in_ioctl(u_long cmd, caddr_t data, struc
error = EPERM;
goto err;
}
- /* FALLTHROUGH */
- case SIOCGIFADDR:
- case SIOCGIFNETMASK:
- case SIOCGIFDSTADDR:
- case SIOCGIFBRDADDR:
if (ia && satosin(&ifr->ifr_addr)->sin_addr.s_addr) {
for (; ifa != NULL; ifa = TAILQ_NEXT(ifa, ifa_list)) {
if ((ifa->ifa_addr->sa_family == AF_INET) &&
@@ -302,31 +305,6 @@ in_ioctl(u_long cmd, caddr_t data, struc
break;
}
switch (cmd) {
-
- case SIOCGIFADDR:
- *satosin(&ifr->ifr_addr) = ia->ia_addr;
- break;
-
- case SIOCGIFBRDADDR:
- if ((ifp->if_flags & IFF_BROADCAST) == 0) {
- error = EINVAL;
- break;
- }
- *satosin(&ifr->ifr_dstaddr) = ia->ia_broadaddr;
- break;
-
- case SIOCGIFDSTADDR:
- if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
- error = EINVAL;
- break;
- }
- *satosin(&ifr->ifr_dstaddr) = ia->ia_dstaddr;
- break;
-
- case SIOCGIFNETMASK:
- *satosin(&ifr->ifr_addr) = ia->ia_sockmask;
- break;
-
case SIOCSIFDSTADDR:
if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
error = EINVAL;
@@ -422,6 +400,73 @@ err:
NET_UNLOCK();
return (error);
}
+
+int
+in_ioctl_get(u_long cmd, caddr_t data, struct ifnet *ifp)
+{
+ struct ifreq *ifr = (struct ifreq *)data;
+ struct ifaddr *ifa;
+ struct in_ifaddr *ia = NULL;
+ int error = 0;
+
+ NET_RLOCK();
+
+ TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
+ if (ifa->ifa_addr->sa_family == AF_INET) {
+ ia = ifatoia(ifa);
+ break;
+ }
+ }
+
+ if (ia && satosin(&ifr->ifr_addr)->sin_addr.s_addr) {
+ for (; ifa != NULL; ifa = TAILQ_NEXT(ifa, ifa_list)) {
+ if ((ifa->ifa_addr->sa_family == AF_INET) &&
+ ifatoia(ifa)->ia_addr.sin_addr.s_addr ==
+ satosin(&ifr->ifr_addr)->sin_addr.s_addr) {
+ ia = ifatoia(ifa);
+ break;
+ }
+ }
+ }
+ if (ia == NULL) {
+ error = EADDRNOTAVAIL;
+ goto err;
+ }
+
+ switch(cmd) {
+ case SIOCGIFADDR:
+ *satosin(&ifr->ifr_addr) = ia->ia_addr;
+ break;
+
+ case SIOCGIFBRDADDR:
+ if ((ifp->if_flags & IFF_BROADCAST) == 0) {
+ error = EINVAL;
+ break;
+ }
+ *satosin(&ifr->ifr_dstaddr) = ia->ia_broadaddr;
+ break;
+
+ case SIOCGIFDSTADDR:
+ if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
+ error = EINVAL;
+ break;
+ }
+ *satosin(&ifr->ifr_dstaddr) = ia->ia_dstaddr;
+ break;
+
+ case SIOCGIFNETMASK:
+ *satosin(&ifr->ifr_addr) = ia->ia_sockmask;
+ break;
+
+ default:
+ panic("invalid ioctl %lu", cmd);
+ }
+
+err:
+ NET_RUNLOCK();
+ return (error);
+}
+
/*
* Delete any existing route for an interface.
*/