-/* $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 $ */
/*
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
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;
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
if (ia == NULL) {
*errorp = EADDRNOTAVAIL;
- return NULL;
+ return (NULL);
}
- return (&ia->ia_addr);
+ return (&ia->ia_addr.sin_addr);
}
}
/*
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
-/* $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 $ */
/*
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 *);
-/* $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 $ */
/*
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;
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
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;
-/* $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 $ */
/*
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)) {
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;