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.
This commit is contained in:
Brian Somers 2001-11-30 14:00:55 +00:00
parent 4a57e677c7
commit 0f02fdac67
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=87124

View File

@ -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;