The branch main has been updated by melifaro:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=e437991fc9361bce1b7dca999dbe3769321f01da

commit e437991fc9361bce1b7dca999dbe3769321f01da
Author:     Alexander V. Chernikov <melif...@freebsd.org>
AuthorDate: 2022-09-26 13:49:02 +0000
Commit:     Alexander V. Chernikov <melif...@freebsd.org>
CommitDate: 2022-09-27 13:23:34 +0000

    netinet6: factor interface addition code to the dedicated function
    
    Summary:
    Move SIOCAIFADDR_IN6 (current "primary" ioctl to add an IPv6
     interface address) handling code to the dedicated in6_addifaddr()
     function and make it a part of KPI. This allows in-kernel users to
     add/delete interfaces addresses without relying on ioctl interface.
    
    Subscribers: imp, ae, glebius
    
    Differential Revision: https://reviews.freebsd.org/D36713
---
 sys/netinet6/in6.c     | 288 +++++++++++++++++++++++++------------------------
 sys/netinet6/in6_var.h |   1 +
 2 files changed, 151 insertions(+), 138 deletions(-)

diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index ccdf71cfc01c..0a00ea6b8be4 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -252,15 +252,15 @@ in6_control(struct socket *so, u_long cmd, void *data,
        struct  in6_ifaddr *ia = NULL;
        struct  in6_aliasreq *ifra = (struct in6_aliasreq *)data;
        struct sockaddr_in6 *sa6;
-       int carp_attached = 0;
        int error;
-       u_long ocmd = cmd;
 
        /*
         * Compat to make pre-10.x ifconfig(8) operable.
         */
-       if (cmd == OSIOCAIFADDR_IN6)
+       if (cmd == OSIOCAIFADDR_IN6) {
                cmd = SIOCAIFADDR_IN6;
+               ifra->ifra_vhid = 0;
+       }
 
        switch (cmd) {
        case SIOCGETSGCNT_IN6:
@@ -560,142 +560,9 @@ in6_control(struct socket *so, u_long cmd, void *data,
                break;
 
        case SIOCAIFADDR_IN6:
-       {
-               struct nd_prefixctl pr0;
-               struct nd_prefix *pr;
-
-               /*
-                * first, make or update the interface address structure,
-                * and link it to the list.
-                */
-               if ((error = in6_update_ifa(ifp, ifra, ia, 0)) != 0)
-                       goto out;
-               if (ia != NULL) {
-                       if (ia->ia_ifa.ifa_carp)
-                               (*carp_detach_p)(&ia->ia_ifa, true);
-                       ifa_free(&ia->ia_ifa);
-               }
-               if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr))
-                   == NULL) {
-                       /*
-                        * this can happen when the user specify the 0 valid
-                        * lifetime.
-                        */
-                       break;
-               }
-
-               if (cmd == ocmd && ifra->ifra_vhid > 0) {
-                       if (carp_attach_p != NULL)
-                               error = (*carp_attach_p)(&ia->ia_ifa,
-                                   ifra->ifra_vhid);
-                       else
-                               error = EPROTONOSUPPORT;
-                       if (error)
-                               goto out;
-                       else
-                               carp_attached = 1;
-               }
-
-               /*
-                * then, make the prefix on-link on the interface.
-                * XXX: we'd rather create the prefix before the address, but
-                * we need at least one address to install the corresponding
-                * interface route, so we configure the address first.
-                */
-
-               /*
-                * convert mask to prefix length (prefixmask has already
-                * been validated in in6_update_ifa().
-                */
-               bzero(&pr0, sizeof(pr0));
-               pr0.ndpr_ifp = ifp;
-               pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr,
-                   NULL);
-               if (pr0.ndpr_plen == 128) {
-                       /* we don't need to install a host route. */
-                       goto aifaddr_out;
-               }
-               pr0.ndpr_prefix = ifra->ifra_addr;
-               /* apply the mask for safety. */
-               IN6_MASK_ADDR(&pr0.ndpr_prefix.sin6_addr,
-                   &ifra->ifra_prefixmask.sin6_addr);
-
-               /*
-                * XXX: since we don't have an API to set prefix (not address)
-                * lifetimes, we just use the same lifetimes as addresses.
-                * The (temporarily) installed lifetimes can be overridden by
-                * later advertised RAs (when accept_rtadv is non 0), which is
-                * an intended behavior.
-                */
-               pr0.ndpr_raf_onlink = 1; /* should be configurable? */
-               pr0.ndpr_raf_auto =
-                   ((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0);
-               pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime;
-               pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime;
-
-               /* add the prefix if not yet. */
-               if ((pr = nd6_prefix_lookup(&pr0)) == NULL) {
-                       /*
-                        * nd6_prelist_add will install the corresponding
-                        * interface route.
-                        */
-                       if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0) {
-                               if (carp_attached)
-                                       (*carp_detach_p)(&ia->ia_ifa, false);
-                               goto out;
-                       }
-               }
-
-               /* relate the address to the prefix */
-               if (ia->ia6_ndpr == NULL) {
-                       ia->ia6_ndpr = pr;
-                       pr->ndpr_addrcnt++;
-
-                       /*
-                        * If this is the first autoconf address from the
-                        * prefix, create a temporary address as well
-                        * (when required).
-                        */
-                       if ((ia->ia6_flags & IN6_IFF_AUTOCONF) &&
-                           V_ip6_use_tempaddr && pr->ndpr_addrcnt == 1) {
-                               int e;
-                               if ((e = in6_tmpifadd(ia, 1, 0)) != 0) {
-                                       log(LOG_NOTICE, "in6_control: failed "
-                                           "to create a temporary address, "
-                                           "errno=%d\n", e);
-                               }
-                       }
-               }
-               nd6_prefix_rele(pr);
-
-               /*
-                * this might affect the status of autoconfigured addresses,
-                * that is, this address might make other addresses detached.
-                */
-               pfxlist_onlink_check();
-
-aifaddr_out:
-               /*
-                * Try to clear the flag when a new IPv6 address is added
-                * onto an IFDISABLED interface and it succeeds.
-                */
-               if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) {
-                       struct in6_ndireq nd;
-
-                       memset(&nd, 0, sizeof(nd));
-                       nd.ndi.flags = ND_IFINFO(ifp)->flags;
-                       nd.ndi.flags &= ~ND6_IFF_IFDISABLED;
-                       if (nd6_ioctl(SIOCSIFINFO_FLAGS, (caddr_t)&nd, ifp) < 0)
-                               log(LOG_NOTICE, "SIOCAIFADDR_IN6: "
-                                   "SIOCSIFINFO_FLAGS for -ifdisabled "
-                                   "failed.");
-                       /*
-                        * Ignore failure of clearing the flag intentionally.
-                        * The failure means address duplication was detected.
-                        */
-               }
+               error = in6_addifaddr(ifp, ifra, ia);
+               ia = NULL;
                break;
-       }
 
        case SIOCDIFADDR_IN6:
                in6_purgeifaddr(ia);
@@ -1324,6 +1191,151 @@ ifa_is_p2p(struct in6_ifaddr *ia)
        return (false);
 }
 
+int
+in6_addifaddr(struct ifnet *ifp, struct in6_aliasreq *ifra, struct in6_ifaddr 
*ia)
+{
+       struct nd_prefixctl pr0;
+       struct nd_prefix *pr;
+       int carp_attached = 0;
+       int error;
+
+       /*
+        * first, make or update the interface address structure,
+        * and link it to the list.
+        */
+       if ((error = in6_update_ifa(ifp, ifra, ia, 0)) != 0)
+               goto out;
+       if (ia != NULL) {
+               if (ia->ia_ifa.ifa_carp)
+                       (*carp_detach_p)(&ia->ia_ifa, true);
+               ifa_free(&ia->ia_ifa);
+       }
+       if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr)) == NULL) 
{
+               /*
+                * this can happen when the user specify the 0 valid
+                * lifetime.
+                */
+               return (0);
+       }
+
+       if (ifra->ifra_vhid > 0) {
+               if (carp_attach_p != NULL)
+                       error = (*carp_attach_p)(&ia->ia_ifa,
+                           ifra->ifra_vhid);
+               else
+                       error = EPROTONOSUPPORT;
+               if (error)
+                       goto out;
+               else
+                       carp_attached = 1;
+       }
+
+       /*
+        * then, make the prefix on-link on the interface.
+        * XXX: we'd rather create the prefix before the address, but
+        * we need at least one address to install the corresponding
+        * interface route, so we configure the address first.
+        */
+
+       /*
+        * convert mask to prefix length (prefixmask has already
+        * been validated in in6_update_ifa().
+        */
+       bzero(&pr0, sizeof(pr0));
+       pr0.ndpr_ifp = ifp;
+       pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr,
+           NULL);
+       if (pr0.ndpr_plen == 128) {
+               /* we don't need to install a host route. */
+               goto aifaddr_out;
+       }
+       pr0.ndpr_prefix = ifra->ifra_addr;
+       /* apply the mask for safety. */
+       IN6_MASK_ADDR(&pr0.ndpr_prefix.sin6_addr,
+           &ifra->ifra_prefixmask.sin6_addr);
+
+       /*
+        * XXX: since we don't have an API to set prefix (not address)
+        * lifetimes, we just use the same lifetimes as addresses.
+        * The (temporarily) installed lifetimes can be overridden by
+        * later advertised RAs (when accept_rtadv is non 0), which is
+        * an intended behavior.
+        */
+       pr0.ndpr_raf_onlink = 1; /* should be configurable? */
+       pr0.ndpr_raf_auto =
+           ((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0);
+       pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime;
+       pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime;
+
+       /* add the prefix if not yet. */
+       if ((pr = nd6_prefix_lookup(&pr0)) == NULL) {
+               /*
+                * nd6_prelist_add will install the corresponding
+                * interface route.
+                */
+               if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0) {
+                       if (carp_attached)
+                               (*carp_detach_p)(&ia->ia_ifa, false);
+                       goto out;
+               }
+       }
+
+       /* relate the address to the prefix */
+       if (ia->ia6_ndpr == NULL) {
+               ia->ia6_ndpr = pr;
+               pr->ndpr_addrcnt++;
+
+               /*
+                * If this is the first autoconf address from the
+                * prefix, create a temporary address as well
+                * (when required).
+                */
+               if ((ia->ia6_flags & IN6_IFF_AUTOCONF) &&
+                   V_ip6_use_tempaddr && pr->ndpr_addrcnt == 1) {
+                       int e;
+                       if ((e = in6_tmpifadd(ia, 1, 0)) != 0) {
+                               log(LOG_NOTICE, "in6_control: failed "
+                                   "to create a temporary address, "
+                                   "errno=%d\n", e);
+                       }
+               }
+       }
+       nd6_prefix_rele(pr);
+
+       /*
+        * this might affect the status of autoconfigured addresses,
+        * that is, this address might make other addresses detached.
+        */
+       pfxlist_onlink_check();
+
+aifaddr_out:
+       /*
+        * Try to clear the flag when a new IPv6 address is added
+        * onto an IFDISABLED interface and it succeeds.
+        */
+       if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) {
+               struct in6_ndireq nd;
+
+               memset(&nd, 0, sizeof(nd));
+               nd.ndi.flags = ND_IFINFO(ifp)->flags;
+               nd.ndi.flags &= ~ND6_IFF_IFDISABLED;
+               if (nd6_ioctl(SIOCSIFINFO_FLAGS, (caddr_t)&nd, ifp) < 0)
+                       log(LOG_NOTICE, "SIOCAIFADDR_IN6: "
+                           "SIOCSIFINFO_FLAGS for -ifdisabled "
+                           "failed.");
+               /*
+                * Ignore failure of clearing the flag intentionally.
+                * The failure means address duplication was detected.
+                */
+       }
+       error = 0;
+
+out:
+       if (ia != NULL)
+               ifa_free(&ia->ia_ifa);
+       return (error);
+}
+
 void
 in6_purgeaddr(struct ifaddr *ifa)
 {
diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h
index 6af0e54ccb75..b40b426d1332 100644
--- a/sys/netinet6/in6_var.h
+++ b/sys/netinet6/in6_var.h
@@ -889,6 +889,7 @@ int in6_update_ifa(struct ifnet *, struct in6_aliasreq *,
        struct in6_ifaddr *, int);
 void   in6_prepare_ifra(struct in6_aliasreq *, const struct in6_addr *,
        const struct in6_addr *);
+int    in6_addifaddr(struct ifnet *, struct in6_aliasreq *, struct in6_ifaddr 
*);
 void   in6_purgeaddr(struct ifaddr *);
 void   in6_purgeifaddr(struct in6_ifaddr *);
 int    in6if_do_dad(struct ifnet *);

Reply via email to