Merge in_fixaddr() into in_selectsrc() in order to prepare for
authormpi <mpi@openbsd.org>
Wed, 16 Apr 2014 13:04:38 +0000 (13:04 +0000)
committermpi <mpi@openbsd.org>
Wed, 16 Apr 2014 13:04:38 +0000 (13:04 +0000)
IP_SENDSRCADDR support.  This reduces the differences with the
IPv6 version and kill some comments that are no longer true.

ok jca@, chrisz@, mikeb@

sys/netinet/in_pcb.c
sys/netinet/in_pcb.h
sys/netinet/udp_usrreq.c
sys/netinet6/in6_pcb.c
sys/netinet6/udp6_output.c

index a17d6a2..d9f1a20 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: in_pcb.c,v 1.152 2014/04/07 10:04:17 mpi Exp $        */
+/*     $OpenBSD: in_pcb.c,v 1.153 2014/04/16 13:04:38 mpi Exp $        */
 /*     $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $     */
 
 /*
@@ -370,8 +370,8 @@ in_pcbbind(struct inpcb *inp, struct mbuf *nam, struct proc *p)
 int
 in_pcbconnect(struct inpcb *inp, struct mbuf *nam)
 {
+       struct in_addr *ina = NULL;
        struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
-       struct in_addr laddr;
        int error;
 
 #ifdef INET6
@@ -383,19 +383,30 @@ in_pcbconnect(struct inpcb *inp, struct mbuf *nam)
 
        if (nam->m_len != sizeof (*sin))
                return (EINVAL);
+       if (sin->sin_family != AF_INET)
+               return (EAFNOSUPPORT);
+       if (sin->sin_port == 0)
+               return (EADDRNOTAVAIL);
 
-       if ((error = in_fixaddr(inp, sin, &laddr)))
+       ina = in_selectsrc(sin, inp->inp_moptions, &inp->inp_route,
+           &inp->inp_laddr, &error, inp->inp_rtableid);
+       if (ina == NULL) {
+               if (error == 0)
+                       error = EADDRNOTAVAIL;
                return (error);
+       }
 
        if (in_pcbhashlookup(inp->inp_table, sin->sin_addr, sin->sin_port,
-           laddr, inp->inp_lport, inp->inp_rtableid) != 0)
+           *ina, inp->inp_lport, inp->inp_rtableid) != 0)
                return (EADDRINUSE);
-       KASSERT(inp->inp_laddr.s_addr == INADDR_ANY || inp->inp_lport != 0);
+
+       KASSERT(inp->inp_laddr.s_addr == INADDR_ANY || inp->inp_lport);
+
        if (inp->inp_laddr.s_addr == INADDR_ANY) {
                if (inp->inp_lport == 0 &&
                    in_pcbbind(inp, NULL, curproc) == EADDRNOTAVAIL)
                        return (EADDRNOTAVAIL);
-               inp->inp_laddr = laddr;
+               inp->inp_laddr = *ina;
        }
        inp->inp_faddr = sin->sin_addr;
        inp->inp_fport = sin->sin_port;
@@ -759,13 +770,37 @@ in_pcbrtentry(struct inpcb *inp)
        return (ro->ro_rt);
 }
 
-struct sockaddr_in *
-in_selectsrc(struct sockaddr_in *sin, struct route *ro, int soopts,
-    struct ip_moptions *mopts, int *errorp, u_int rtableid)
+/*
+ * Return an IPv4 address, which is the most appropriate for a given
+ * destination.
+ * If necessary, this function lookups the routing table and returns
+ * an entry to the caller for later use.
+ */
+struct in_addr *
+in_selectsrc(struct sockaddr_in *sin, struct ip_moptions *mopts,
+    struct route *ro, struct in_addr *laddr, int *errorp, u_int rtableid)
 {
        struct sockaddr_in *sin2;
        struct in_ifaddr *ia = NULL;
 
+       if (!TAILQ_EMPTY(&in_ifaddr)) {
+               if (sin->sin_addr.s_addr == INADDR_ANY)
+                       sin->sin_addr =
+                           TAILQ_FIRST(&in_ifaddr)->ia_addr.sin_addr;
+               else if (sin->sin_addr.s_addr == INADDR_BROADCAST &&
+                 (TAILQ_FIRST(&in_ifaddr)->ia_ifp->if_flags & IFF_BROADCAST) &&
+                 TAILQ_FIRST(&in_ifaddr)->ia_broadaddr.sin_addr.s_addr)
+                       sin->sin_addr =
+                           TAILQ_FIRST(&in_ifaddr)->ia_broadaddr.sin_addr;
+       }
+
+       /*
+        * If the source address is not specified but the socket(if any)
+        * is already bound, use the bound address.
+        */
+       if (laddr && laddr->s_addr != INADDR_ANY)
+               return (laddr);
+
        /*
         * If the destination address is multicast and an outgoing
         * interface has been set as a multicast option, use the
@@ -781,9 +816,9 @@ in_selectsrc(struct sockaddr_in *sin, struct route *ro, int soopts,
 
                        if (ia == NULL) {
                                *errorp = EADDRNOTAVAIL;
-                               return NULL;
+                               return (NULL);
                        }
-                       return (&ia->ia_addr);
+                       return (&ia->ia_addr.sin_addr);
                }
        }
        /*
@@ -823,60 +858,8 @@ in_selectsrc(struct sockaddr_in *sin, struct route *ro, int soopts,
                        return (NULL);
                }
        }
-       return (&ia->ia_addr);
-}
-
-/*
- * Fix up source (*laddr) and destination addresses (*sin).
- *
- * If the destination address is INADDR_ANY, use the primary local address.
- * If the supplied address is INADDR_BROADCAST
- * and the primary interface supports broadcast,
- * choose the broadcast address for that interface.
- *
- * If *inp is already bound to a local address, return it in *laddr,
- * otherwise call in_selectsrc() to get a suitable local address.
- */
-int
-in_fixaddr(struct inpcb *inp,
-    struct sockaddr_in *sin, struct in_addr *laddr)
-{
-       if (sin->sin_family != AF_INET)
-               return (EAFNOSUPPORT);
-       if (sin->sin_port == 0)
-               return (EADDRNOTAVAIL);
-       if (!TAILQ_EMPTY(&in_ifaddr)) {
-               if (sin->sin_addr.s_addr == INADDR_ANY)
-                       sin->sin_addr = TAILQ_FIRST(&in_ifaddr)->ia_addr.sin_addr;
-               else if (sin->sin_addr.s_addr == INADDR_BROADCAST &&
-                 (TAILQ_FIRST(&in_ifaddr)->ia_ifp->if_flags & IFF_BROADCAST) &&
-                 TAILQ_FIRST(&in_ifaddr)->ia_broadaddr.sin_addr.s_addr)
-                       sin->sin_addr =
-                           TAILQ_FIRST(&in_ifaddr)->ia_broadaddr.sin_addr;
-       }
-
-       if (laddr != NULL) {
-               if (inp->inp_laddr.s_addr != INADDR_ANY) {
-                       *laddr = inp->inp_laddr;
-               }
-               else {
-                       struct sockaddr_in *ifaddr;
-                       int error;
-
-                       ifaddr = in_selectsrc(sin, &inp->inp_route,
-                                       inp->inp_socket->so_options,
-                                       inp->inp_moptions,
-                                       &error, inp->inp_rtableid);
-                       if (ifaddr == NULL) {
-                               if (error == 0)
-                                       error = EADDRNOTAVAIL;
-                               return (error);
-                       }
-                       *laddr = ifaddr->sin_addr;
-               }
-       }
 
-       return (0);
+       return (&ia->ia_addr.sin_addr);
 }
 
 void
index de1d984..29b9336 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: in_pcb.h,v 1.83 2014/04/06 17:13:23 chrisz Exp $      */
+/*     $OpenBSD: in_pcb.h,v 1.84 2014/04/16 13:04:38 mpi Exp $ */
 /*     $NetBSD: in_pcb.h,v 1.14 1996/02/13 23:42:00 christos Exp $     */
 
 /*
@@ -283,10 +283,9 @@ void        in_rtchange(struct inpcb *, int);
 void    in_setpeeraddr(struct inpcb *, struct mbuf *);
 void    in_setsockaddr(struct inpcb *, struct mbuf *);
 int     in_baddynamic(u_int16_t, u_int16_t);
-int     in_fixaddr(struct inpcb *inp,
-                       struct sockaddr_in *, struct in_addr *laddr);
-extern struct sockaddr_in *in_selectsrc(struct sockaddr_in *,
-       struct route *, int, struct ip_moptions *, int *, u_int);
+struct in_addr *
+       in_selectsrc(struct sockaddr_in *, struct ip_moptions *,
+           struct route *, struct in_addr *, int *, u_int);
 struct rtentry *
        in_pcbrtentry(struct inpcb *);
 
index 6bfe523..4a90f78 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: udp_usrreq.c,v 1.180 2014/04/14 09:06:42 mpi Exp $    */
+/*     $OpenBSD: udp_usrreq.c,v 1.181 2014/04/16 13:04:38 mpi Exp $    */
 /*     $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */
 
 /*
@@ -972,7 +972,7 @@ udp_output(struct mbuf *m, ...)
        struct udpiphdr *ui;
        u_int32_t ipsecflowinfo = 0;
        int len = m->m_pkthdr.len;
-       struct in_addr laddr = { INADDR_ANY };
+       struct in_addr *laddr;
        int error = 0;
        va_list ap;
 
@@ -998,30 +998,46 @@ udp_output(struct mbuf *m, ...)
 
        if (addr) {
                sin = mtod(addr, struct sockaddr_in *);
+
                if (addr->m_len != sizeof(*sin)) {
                        error = EINVAL;
                        goto release;
                }
+               if (sin->sin_family != AF_INET) {
+                       error = EAFNOSUPPORT;
+                       goto release;
+               }
+               if (sin->sin_port == 0) {
+                       error = EADDRNOTAVAIL;
+                       goto release;
+               }
+
                if (inp->inp_faddr.s_addr != INADDR_ANY) {
                        error = EISCONN;
                        goto release;
                }
-               if ((error = in_fixaddr(inp, sin, &laddr)))
+
+               laddr = in_selectsrc(sin, inp->inp_moptions, &inp->inp_route,
+                   &inp->inp_laddr, &error, inp->inp_rtableid);
+               if (laddr == NULL) {
+                       if (error == 0)
+                               error = EADDRNOTAVAIL;
                        goto release;
+               }
 
                if (inp->inp_lport == 0) {
                        int s = splsoftnet();
                        error = in_pcbbind(inp, NULL, curproc);
                        splx(s);
-                       if (error) goto release;
+                       if (error)
+                               goto release;
                }
        } else {
                if (inp->inp_faddr.s_addr == INADDR_ANY) {
                        error = ENOTCONN;
                        goto release;
                }
-               if (laddr.s_addr == INADDR_ANY)
-                       laddr = inp->inp_laddr;
+               laddr = &inp->inp_laddr;
        }
 
 #ifdef IPSEC
@@ -1081,7 +1097,7 @@ udp_output(struct mbuf *m, ...)
        bzero(ui->ui_x1, sizeof ui->ui_x1);
        ui->ui_pr = IPPROTO_UDP;
        ui->ui_len = htons((u_int16_t)len + sizeof (struct udphdr));
-       ui->ui_src = laddr;
+       ui->ui_src = *laddr;
        ui->ui_dst = sin ? sin->sin_addr : inp->inp_faddr;
        ui->ui_sport = inp->inp_lport;
        ui->ui_dport = sin ? sin->sin_port : inp->inp_fport;
index cc06181..28e37dd 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: in6_pcb.c,v 1.60 2014/04/06 16:49:40 chrisz Exp $     */
+/*     $OpenBSD: in6_pcb.c,v 1.61 2014/04/16 13:04:38 mpi Exp $        */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -448,7 +448,9 @@ in6_pcbconnect(struct inpcb *inp, struct mbuf *nam)
            inp->inp_lport, INPLOOKUP_IPV6, inp->inp_rtableid)) {
                return (EADDRINUSE);
        }
-       KASSERT(IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) || inp->inp_lport != 0);
+
+       KASSERT(IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) || inp->inp_lport);
+
        if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) {
                if (inp->inp_lport == 0)
                        (void)in6_pcbbind(inp, NULL, curproc);
index 543f276..be94e2c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: udp6_output.c,v 1.25 2014/04/14 09:06:42 mpi Exp $    */
+/*     $OpenBSD: udp6_output.c,v 1.26 2014/04/16 13:04:38 mpi Exp $    */
 /*     $KAME: udp6_output.c,v 1.21 2001/02/07 11:51:54 itojun Exp $    */
 
 /*
@@ -118,14 +118,6 @@ udp6_output(struct inpcb *in6p, struct mbuf *m, struct mbuf *addr6,
                optp = in6p->inp_outputopts6;
 
        if (addr6) {
-               /*
-                * IPv4 version of udp_output calls in_pcbconnect in this case,
-                * which needs splnet and affects performance.
-                * Since we saw no essential reason for calling in_pcbconnect,
-                * we get rid of such kind of logic, and call in6_selectsrc
-                * and in6_pcbsetport in order to fill in the local address
-                * and the local port.
-                */
                struct sockaddr_in6 *sin6 = mtod(addr6, struct sockaddr_in6 *);
 
                if (addr6->m_len != sizeof(*sin6)) {
@@ -159,12 +151,10 @@ udp6_output(struct inpcb *in6p, struct mbuf *m, struct mbuf *addr6,
                        goto release;
                }
 
-               if (1) {        /* we don't support IPv4 mapped address */
-                       laddr = in6_selectsrc(sin6, optp,
-                           in6p->inp_moptions6, &in6p->inp_route6,
-                           &in6p->inp_laddr6, &error, in6p->inp_rtableid);
-               } else
-                       laddr = &in6p->inp_laddr6;      /*XXX*/
+               /* we don't support IPv4 mapped address */
+               laddr = in6_selectsrc(sin6, optp,
+                   in6p->inp_moptions6, &in6p->inp_route6,
+                   &in6p->inp_laddr6, &error, in6p->inp_rtableid);
                if (laddr == NULL) {
                        if (error == 0)
                                error = EADDRNOTAVAIL;