summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2014-04-16 13:04:39 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2014-04-16 13:04:39 +0000
commit63a71e253aa7f6cbfa4b5307e4e7f08e7cf872c4 (patch)
treed80ee5eca3d44c0fa99cac87ffc0087f4b5358cb /sys
parent7cc17928e3c59d20fe73cd03f931c0048d24ae7b (diff)
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@
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet/in_pcb.c111
-rw-r--r--sys/netinet/in_pcb.h9
-rw-r--r--sys/netinet/udp_usrreq.c30
-rw-r--r--sys/netinet6/in6_pcb.c6
-rw-r--r--sys/netinet6/udp6_output.c20
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;