svn commit: r227791 - head/sys/netinet

Qing Li qingli at freebsd.org
Mon Nov 21 16:48:33 UTC 2011


Logically speaking the prefix route should not be removed until all of the
address related housing keeping tasks have been completed successfully.

Putting "in_scrubprefix()" at the top does not gain you anything at
all, but can
potentially be problematic if additional tasks are in fact performed
in "if_ioctl()"
that may in fact affect the logic in "in_ifinit()".

Case in point, I had to perform additional routing related tasks so I
re-introduced "nd6_rtrequest()" in r227460.

You are not simplifying much logic by removing the error recovery code from
the return of "if_ioctl()". So why removing the flexibility of what
"if_ioctl()" is
intended for as part of the address configuration logic ?

--Qing

On Mon, Nov 21, 2011 at 6:10 AM, Gleb Smirnoff <glebius at freebsd.org> wrote:
> Author: glebius
> Date: Mon Nov 21 14:10:13 2011
> New Revision: 227791
> URL: http://svn.freebsd.org/changeset/base/227791
>
> Log:
>  Historically in_control() did not check sockaddrs supplied with
>  structs ifreq/in_aliasreq and there've been several panics due
>  to that problem. All these panics were fixed just a couple of
>  lines above the panicing code.
>
>  Take a more general approach: sanity check sockaddrs supplied
>  with SIOCAIFADDR and SIOCSIF*ADDR at the beggining of the
>  function and drop all checks below.
>
>  One check is now disabled due to strange code in ifconfig(8)
>  that I've removed recently. I'm going to enable it with next
>  __FreeBSD_version bump.
>
>  Historically in_ifinit() was able to recover from an error
>  and restore old address. Nowadays this feature isn't working
>  for all error cases, but for some of them. I suppose no software
>  relies on this behavior, so I'd like to remove it, since this
>  simplifies code a lot.
>
>  Also, move if_scrub() earlier in the in_ifinit(). It is more
>  correct to wipe routes before removing address from local
>  address list, and interface address list.
>
>  Silence from: bz, brooks, andre, rwatson, 3 weeks
>
> Modified:
>  head/sys/netinet/in.c
>
> Modified: head/sys/netinet/in.c
> ==============================================================================
> --- head/sys/netinet/in.c       Mon Nov 21 13:40:35 2011        (r227790)
> +++ head/sys/netinet/in.c       Mon Nov 21 14:10:13 2011        (r227791)
> @@ -234,16 +234,42 @@ in_control(struct socket *so, u_long cmd
>         * in_lifaddr_ioctl() and ifp->if_ioctl().
>         */
>        switch (cmd) {
> -       case SIOCAIFADDR:
> -       case SIOCDIFADDR:
>        case SIOCGIFADDR:
>        case SIOCGIFBRDADDR:
>        case SIOCGIFDSTADDR:
>        case SIOCGIFNETMASK:
> +       case SIOCDIFADDR:
> +               break;
> +       case SIOCAIFADDR:
> +               /*
> +                * ifra_addr must be present and be of INET family.
> +                * ifra_broadaddr and ifra_mask are optional.
> +                */
> +               if (ifra->ifra_addr.sin_len != sizeof(struct sockaddr_in) ||
> +                   ifra->ifra_addr.sin_family != AF_INET)
> +                       return (EINVAL);
> +               if (ifra->ifra_broadaddr.sin_len != 0 &&
> +                   (ifra->ifra_broadaddr.sin_len != sizeof(struct sockaddr_in) ||
> +                   ifra->ifra_broadaddr.sin_family != AF_INET))
> +                       return (EINVAL);
> +#if 0
> +               /*
> +                * ifconfig(8) historically doesn't set af_family for mask
> +                * for unknown reason.
> +                */
> +               if (ifra->ifra_mask.sin_len != 0 &&
> +                   (ifra->ifra_mask.sin_len != sizeof(struct sockaddr_in) ||
> +                   ifra->ifra_mask.sin_family != AF_INET))
> +                       return (EINVAL);
> +#endif
> +               break;
>        case SIOCSIFADDR:
>        case SIOCSIFBRDADDR:
>        case SIOCSIFDSTADDR:
>        case SIOCSIFNETMASK:
> +               if (ifr->ifr_addr.sa_family != AF_INET ||
> +                   ifr->ifr_addr.sa_len != sizeof(struct sockaddr_in))
> +                       return (EINVAL);
>                break;
>
>        case SIOCALIFADDR:
> @@ -349,7 +375,7 @@ in_control(struct socket *so, u_long cmd
>        switch (cmd) {
>        case SIOCAIFADDR:
>        case SIOCDIFADDR:
> -               if (ifra->ifra_addr.sin_family == AF_INET) {
> +               {
>                        struct in_ifaddr *oia;
>
>                        IN_IFADDR_RLOCK();
> @@ -506,7 +532,7 @@ in_control(struct socket *so, u_long cmd
>                goto out;
>
>        case SIOCSIFNETMASK:
> -               ia->ia_sockmask.sin_addr = ifra->ifra_addr.sin_addr;
> +               ia->ia_sockmask = *(struct sockaddr_in *)&ifr->ifr_addr;
>                ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr);
>                goto out;
>
> @@ -514,14 +540,12 @@ in_control(struct socket *so, u_long cmd
>                maskIsNew = 0;
>                hostIsNew = 1;
>                error = 0;
> -               if (ia->ia_addr.sin_family == AF_INET) {
> -                       if (ifra->ifra_addr.sin_len == 0) {
> -                               ifra->ifra_addr = ia->ia_addr;
> -                               hostIsNew = 0;
> -                       } else if (ifra->ifra_addr.sin_addr.s_addr ==
> -                                              ia->ia_addr.sin_addr.s_addr)
> -                               hostIsNew = 0;
> -               }
> +               if (ifra->ifra_addr.sin_len == 0) {
> +                       ifra->ifra_addr = ia->ia_addr;
> +                       hostIsNew = 0;
> +               } else if (ifra->ifra_addr.sin_addr.s_addr ==
> +                           ia->ia_addr.sin_addr.s_addr)
> +                       hostIsNew = 0;
>                if (ifra->ifra_mask.sin_len) {
>                        /*
>                         * QL: XXX
> @@ -552,7 +576,7 @@ in_control(struct socket *so, u_long cmd
>                        break;
>
>                if ((ifp->if_flags & IFF_BROADCAST) &&
> -                   (ifra->ifra_broadaddr.sin_family == AF_INET))
> +                   ifra->ifra_broadaddr.sin_len)
>                        ia->ia_broadaddr = ifra->ifra_broadaddr;
>                if (error == 0) {
>                        ii = ((struct in_ifinfo *)ifp->if_afdata[AF_INET]);
> @@ -608,31 +632,26 @@ in_control(struct socket *so, u_long cmd
>
>        IN_IFADDR_WLOCK();
>        TAILQ_REMOVE(&V_in_ifaddrhead, ia, ia_link);
> -       if (ia->ia_addr.sin_family == AF_INET) {
> -               struct in_ifaddr *if_ia;
>
> -               LIST_REMOVE(ia, ia_hash);
> -               IN_IFADDR_WUNLOCK();
> -               /*
> -                * If this is the last IPv4 address configured on this
> -                * interface, leave the all-hosts group.
> -                * No state-change report need be transmitted.
> -                */
> -               if_ia = NULL;
> -               IFP_TO_IA(ifp, if_ia);
> -               if (if_ia == NULL) {
> -                       ii = ((struct in_ifinfo *)ifp->if_afdata[AF_INET]);
> -                       IN_MULTI_LOCK();
> -                       if (ii->ii_allhosts) {
> -                               (void)in_leavegroup_locked(ii->ii_allhosts,
> -                                   NULL);
> -                               ii->ii_allhosts = NULL;
> -                       }
> -                       IN_MULTI_UNLOCK();
> -               } else
> -                       ifa_free(&if_ia->ia_ifa);
> +       LIST_REMOVE(ia, ia_hash);
> +       IN_IFADDR_WUNLOCK();
> +       /*
> +        * If this is the last IPv4 address configured on this
> +        * interface, leave the all-hosts group.
> +        * No state-change report need be transmitted.
> +        */
> +       IFP_TO_IA(ifp, iap);
> +       if (iap == NULL) {
> +               ii = ((struct in_ifinfo *)ifp->if_afdata[AF_INET]);
> +               IN_MULTI_LOCK();
> +               if (ii->ii_allhosts) {
> +                       (void)in_leavegroup_locked(ii->ii_allhosts, NULL);
> +                       ii->ii_allhosts = NULL;
> +               }
> +               IN_MULTI_UNLOCK();
>        } else
> -               IN_IFADDR_WUNLOCK();
> +               ifa_free(&iap->ia_ifa);
> +
>        ifa_free(&ia->ia_ifa);                          /* in_ifaddrhead */
>  out:
>        if (ia != NULL)
> @@ -828,50 +847,29 @@ in_ifinit(struct ifnet *ifp, struct in_i
>     int scrub)
>  {
>        register u_long i = ntohl(sin->sin_addr.s_addr);
> -       struct sockaddr_in oldaddr;
>        int flags = RTF_UP, error = 0;
>
> -       oldaddr = ia->ia_addr;
> -       if (oldaddr.sin_family == AF_INET)
> +       if (scrub)
> +               in_scrubprefix(ia, LLE_STATIC);
> +
> +       IN_IFADDR_WLOCK();
> +       if (ia->ia_addr.sin_family == AF_INET)
>                LIST_REMOVE(ia, ia_hash);
>        ia->ia_addr = *sin;
> -       if (ia->ia_addr.sin_family == AF_INET) {
> -               IN_IFADDR_WLOCK();
> -               LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr),
> -                   ia, ia_hash);
> -               IN_IFADDR_WUNLOCK();
> -       }
> +       LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr),
> +           ia, ia_hash);
> +       IN_IFADDR_WUNLOCK();
> +
>        /*
>         * Give the interface a chance to initialize
>         * if this is its first address,
>         * and to validate the address if necessary.
>         */
> -       if (ifp->if_ioctl != NULL) {
> -               error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
> -               if (error) {
> +       if (ifp->if_ioctl != NULL &&
> +           (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia)) != 0)
>                        /* LIST_REMOVE(ia, ia_hash) is done in in_control */
> -                       ia->ia_addr = oldaddr;
> -                       IN_IFADDR_WLOCK();
> -                       if (ia->ia_addr.sin_family == AF_INET)
> -                               LIST_INSERT_HEAD(INADDR_HASH(
> -                                   ia->ia_addr.sin_addr.s_addr), ia, ia_hash);
> -                       else
> -                               /*
> -                                * If oldaddr family is not AF_INET (e.g.
> -                                * interface has been just created) in_control
> -                                * does not call LIST_REMOVE, and we end up
> -                                * with bogus ia entries in hash
> -                                */
> -                               LIST_REMOVE(ia, ia_hash);
> -                       IN_IFADDR_WUNLOCK();
>                        return (error);
> -               }
> -       }
> -       if (scrub) {
> -               ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
> -               in_ifscrub(ifp, ia, LLE_STATIC);
> -               ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
> -       }
> +
>        /*
>         * Be compatible with network classes, if netmask isn't supplied,
>         * guess it based on classes.
> @@ -916,11 +914,9 @@ in_ifinit(struct ifnet *ifp, struct in_i
>        if (ia->ia_addr.sin_addr.s_addr == INADDR_ANY)
>                return (0);
>
> -       if (ifp->if_flags & IFF_POINTOPOINT) {
> -               if (ia->ia_dstaddr.sin_addr.s_addr == ia->ia_addr.sin_addr.s_addr)
> +       if (ifp->if_flags & IFF_POINTOPOINT &&
> +           ia->ia_dstaddr.sin_addr.s_addr == ia->ia_addr.sin_addr.s_addr)
>                        return (0);
> -       }
> -
>
>        /*
>         * add a loopback route to self
>


More information about the svn-src-all mailing list