From 5bf9318f6ab6d870f7133fe4beb83c6cb40b0c17 Mon Sep 17 00:00:00 2001 From: mpi Date: Wed, 16 Apr 2014 13:04:38 +0000 Subject: [PATCH] Merge in_fixaddr() into in_selectsrc() in order to prepare for 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 | 111 ++++++++++++++++--------------------- sys/netinet/in_pcb.h | 9 ++- sys/netinet/udp_usrreq.c | 30 +++++++--- sys/netinet6/in6_pcb.c | 6 +- sys/netinet6/udp6_output.c | 20 ++----- 5 files changed, 83 insertions(+), 93 deletions(-) diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index a17d6a24030..d9f1a20d391 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -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 diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index de1d984c5b9..29b933648d3 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -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 *); diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 6bfe5238e4b..4a90f786784 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -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; diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index cc06181a166..28e37dd3d0e 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -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); diff --git a/sys/netinet6/udp6_output.c b/sys/netinet6/udp6_output.c index 543f276f2f1..be94e2c500c 100644 --- a/sys/netinet6/udp6_output.c +++ b/sys/netinet6/udp6_output.c @@ -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; -- 2.20.1