summaryrefslogtreecommitdiffstats
path: root/sys/netinet
diff options
context:
space:
mode:
authorbrian <brian@FreeBSD.org>2001-11-30 14:00:55 +0000
committerbrian <brian@FreeBSD.org>2001-11-30 14:00:55 +0000
commit0c6aed3bcb2a0f9dce768a346cfbaa6cf749d807 (patch)
tree5fcd1adcd7d56df0034483ab189779b4fb0453cd /sys/netinet
parentc1418d2e44485b5a352aee9e9611866de2383ed8 (diff)
downloadFreeBSD-src-0c6aed3bcb2a0f9dce768a346cfbaa6cf749d807.zip
FreeBSD-src-0c6aed3bcb2a0f9dce768a346cfbaa6cf749d807.tar.gz
During SIOCAIFADDR, if in_ifinit() fails and we've already added an
interface address, blow the address away again before returning the error. In in_ifinit(), if we get an error from rtinit() and we've also got a destination address, return the error rather than masking EEXISTS. Failing to create a host route when configuring an interface should be treated as an error.
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/in.c63
1 files changed, 39 insertions, 24 deletions
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index 12db13e..c582b8f 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -197,7 +197,9 @@ in_control(so, cmd, data, ifp, td)
struct in_ifaddr *oia;
struct in_aliasreq *ifra = (struct in_aliasreq *)data;
struct sockaddr_in oldaddr;
- int error, hostIsNew, maskIsNew, s;
+ int error, hostIsNew, iaIsNew, maskIsNew, s;
+
+ iaIsNew = 0;
switch (cmd) {
case SIOCALIFADDR:
@@ -294,6 +296,7 @@ in_control(so, cmd, data, ifp, td)
if (!(ifp->if_flags & IFF_LOOPBACK))
in_interfaces++;
splx(s);
+ iaIsNew = 1;
}
break;
@@ -314,23 +317,23 @@ in_control(so, cmd, data, ifp, td)
case SIOCGIFADDR:
*((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr;
- break;
+ return (0);
case SIOCGIFBRDADDR:
if ((ifp->if_flags & IFF_BROADCAST) == 0)
return (EINVAL);
*((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr;
- break;
+ return (0);
case SIOCGIFDSTADDR:
if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
return (EINVAL);
*((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr;
- break;
+ return (0);
case SIOCGIFNETMASK:
*((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask;
- break;
+ return (0);
case SIOCSIFDSTADDR:
if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
@@ -349,22 +352,25 @@ in_control(so, cmd, data, ifp, td)
(struct sockaddr *)&ia->ia_dstaddr;
rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
}
- break;
+ return (0);
case SIOCSIFBRDADDR:
if ((ifp->if_flags & IFF_BROADCAST) == 0)
return (EINVAL);
ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr;
- break;
+ return (0);
case SIOCSIFADDR:
- return (in_ifinit(ifp, ia,
- (struct sockaddr_in *) &ifr->ifr_addr, 1));
+ error = in_ifinit(ifp, ia,
+ (struct sockaddr_in *) &ifr->ifr_addr, 1);
+ if (error != 0 && iaIsNew)
+ break;
+ return (0);
case SIOCSIFNETMASK:
ia->ia_sockmask.sin_addr = ifra->ifra_addr.sin_addr;
ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr);
- break;
+ return (0);
case SIOCAIFADDR:
maskIsNew = 0;
@@ -395,6 +401,9 @@ in_control(so, cmd, data, ifp, td)
if (ifra->ifra_addr.sin_family == AF_INET &&
(hostIsNew || maskIsNew))
error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
+ if (error != 0 && iaIsNew)
+ break;
+
if ((ifp->if_flags & IFF_BROADCAST) &&
(ifra->ifra_broadaddr.sin_family == AF_INET))
ia->ia_broadaddr = ifra->ifra_broadaddr;
@@ -420,19 +429,7 @@ in_control(so, cmd, data, ifp, td)
in_pcbpurgeif0(LIST_FIRST(ripcbinfo.listhead), ifp);
in_pcbpurgeif0(LIST_FIRST(udbinfo.listhead), ifp);
}
-
- /*
- * Protect from ipintr() traversing address list
- * while we're modifying it.
- */
- s = splnet();
-
- ifa = &ia->ia_ifa;
- TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
- TAILQ_REMOVE(&in_ifaddrhead, ia, ia_link);
- LIST_REMOVE(ia, ia_hash);
- IFAFREE(&ia->ia_ifa);
- splx(s);
+ error = 0;
break;
default:
@@ -440,7 +437,19 @@ in_control(so, cmd, data, ifp, td)
return (EOPNOTSUPP);
return ((*ifp->if_ioctl)(ifp, cmd, data));
}
- return (0);
+
+ /*
+ * Protect from ipintr() traversing address list while we're modifying
+ * it.
+ */
+ s = splnet();
+ TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
+ TAILQ_REMOVE(&in_ifaddrhead, ia, ia_link);
+ LIST_REMOVE(ia, ia_hash);
+ IFAFREE(&ia->ia_ifa);
+ splx(s);
+
+ return (error);
}
/*
@@ -716,6 +725,12 @@ in_ifinit(ifp, ia, sin, scrub)
}
if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
ia->ia_flags |= IFA_ROUTE;
+
+ if (error != 0 && ia->ia_dstaddr.sin_family == AF_INET) {
+ ia->ia_addr = oldaddr;
+ return (error);
+ }
+
/* XXX check if the subnet route points to the same interface */
if (error == EEXIST)
error = 0;
OpenPOWER on IntegriCloud