diff options
author | rwatson <rwatson@FreeBSD.org> | 2009-04-23 21:41:37 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2009-04-23 21:41:37 +0000 |
commit | a761d4fb36c74dca2928fcbdbe09f0fb26a86182 (patch) | |
tree | 8f3dfa6d9715d1e876844cf81c2eb4c662573230 /sys/netinet | |
parent | 6335a05791c7c4e8b4da0ea715e1ddc0ffeac4d7 (diff) | |
download | FreeBSD-src-a761d4fb36c74dca2928fcbdbe09f0fb26a86182.zip FreeBSD-src-a761d4fb36c74dca2928fcbdbe09f0fb26a86182.tar.gz |
Reorganize in_control() so that invariants are more obvious, and so
that it is easier to lock:
- Handle the unsupported ioctl case at the beginning of in_control(),
handing off to ifp->if_ioctl, rather than looking up interfaces and
addresses unnecessarily in this case.
- Make it an invariant that ifp is always non-NULL when running
in_control()-implemented ioctls, simplifying the code structure.
MFC after: 3 weeks
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/in.c | 84 |
1 files changed, 51 insertions, 33 deletions
diff --git a/sys/netinet/in.c b/sys/netinet/in.c index bb3973c..e9e9d61 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -202,7 +202,8 @@ in_len2mask(struct in_addr *mask, int len) /* * Generic internet control operations (ioctl's). - * Ifp is 0 if not an interface-specific ioctl. + * + * ifp is NULL if not an interface-specific ioctl. */ /* ARGSUSED */ int @@ -227,7 +228,23 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, iaIsNew = 0; allhosts_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); + /* + * Filter out ioctls we implement directly; forward the rest on to + * in_lifaddr_ioctl() and ifp->if_ioctl(). + */ switch (cmd) { + case SIOCAIFADDR: + case SIOCDIFADDR: + case SIOCGIFADDR: + case SIOCGIFBRDADDR: + case SIOCGIFDSTADDR: + case SIOCGIFNETMASK: + case SIOCSIFADDR: + case SIOCSIFBRDADDR: + case SIOCSIFDSTADDR: + case SIOCSIFNETMASK: + break; + case SIOCALIFADDR: if (td != NULL) { error = priv_check(td, PRIV_NET_ADDIFADDR); @@ -252,46 +269,51 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, if (ifp == NULL) return (EINVAL); return in_lifaddr_ioctl(so, cmd, data, ifp, td); + + default: + if (ifp == NULL || ifp->if_ioctl == NULL) + return (EOPNOTSUPP); + return ((*ifp->if_ioctl)(ifp, cmd, data)); } + if (ifp == NULL) + return (EADDRNOTAVAIL); + /* * Find address for this interface, if it exists. * - * If an alias address was specified, find that one instead of - * the first one on the interface, if possible. + * If an alias address was specified, find that one instead of the + * first one on the interface, if possible. */ - if (ifp != NULL) { - dst = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr; - LIST_FOREACH(iap, INADDR_HASH(dst.s_addr), ia_hash) - if (iap->ia_ifp == ifp && - iap->ia_addr.sin_addr.s_addr == dst.s_addr) { - if (td == NULL || prison_check_ip4( - td->td_ucred, &dst) == 0) - ia = iap; + dst = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr; + LIST_FOREACH(iap, INADDR_HASH(dst.s_addr), ia_hash) { + if (iap->ia_ifp == ifp && + iap->ia_addr.sin_addr.s_addr == dst.s_addr) { + if (td == NULL || prison_check_ip4(td->td_ucred, + &dst) == 0) + ia = iap; + break; + } + } + if (ia == NULL) { + TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + iap = ifatoia(ifa); + if (iap->ia_addr.sin_family == AF_INET) { + if (td != NULL && + prison_check_ip4(td->td_ucred, + &iap->ia_addr.sin_addr) != 0) + continue; + ia = iap; break; } - if (ia == NULL) - TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { - iap = ifatoia(ifa); - if (iap->ia_addr.sin_family == AF_INET) { - if (td != NULL && - prison_check_ip4(td->td_ucred, - &iap->ia_addr.sin_addr) != 0) - continue; - ia = iap; - break; - } - } - if (ia == NULL) - iaIsFirst = 1; + } } + if (ia == NULL) + iaIsFirst = 1; switch (cmd) { - case SIOCAIFADDR: case SIOCDIFADDR: - if (ifp == NULL) - return (EADDRNOTAVAIL); if (ifra->ifra_addr.sin_family == AF_INET) { for (oia = ia; ia; ia = TAILQ_NEXT(ia, ia_link)) { if (ia->ia_ifp == ifp && @@ -319,8 +341,6 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, return (error); } - if (ifp == NULL) - return (EADDRNOTAVAIL); if (ia == NULL) { ia = (struct in_ifaddr *) malloc(sizeof *ia, M_IFADDR, M_WAITOK | M_ZERO); @@ -505,9 +525,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, break; default: - if (ifp == NULL || ifp->if_ioctl == NULL) - return (EOPNOTSUPP); - return ((*ifp->if_ioctl)(ifp, cmd, data)); + panic("in_control: unsupported ioctl"); } /* |