implement IPV6_V6ONLY socket option from draft-ietf-ipngwg-rfc2553bis-03.txt.

IPV6_BINDV6ONLY (netbsd only) is deprecated, but still work just like before.
This commit is contained in:
itojun 2001-10-15 09:51:15 +00:00
parent d76f074387
commit 91498ffec5
12 changed files with 252 additions and 160 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: ip6.4,v 1.8 2001/09/22 00:57:41 wiz Exp $
.\" $NetBSD: ip6.4,v 1.9 2001/10/15 09:51:16 itojun Exp $
.\" $KAME: ip6.4,v 1.11 2000/05/07 06:21:41 itojun Exp $
.\"
.\" Copyright (C) 1999 WIDE Project.
@ -240,14 +240,14 @@ int range = IPV6_PORTRANGE_LOW; /* see <netinet/in.h> */
setsockopt(s, IPPROTO_IPV6, IPV6_PORTRANGE, &range, sizeof(range));
.Ed
.Pp
.Dv IPV6_BINDV6ONLY
.Dv IPV6_V6ONLY
controls behavior of
.Dv AF_INET6
wildcard listening socket.
The following example sets the option to 1:
.Bd -literal -offset indent
int on = 1;
setsockopt(s, IPPROTO_IPV6, IPV6_BINDV6ONLY, &on, sizeof(on));
setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
.Ed
.Pp
If set to 1,
@ -684,8 +684,7 @@ The ancillary data items were improperly formed, or option name was unknown.
.Sh STANDARDS
Most of the socket options are defined in
RFC2292 and/or RFC2553.
.Dv IPV6_PORTRANGE ,
.Dv IPV6_BINDV6ONLY
.Dv IPV6_PORTRANGE
and
conflict resolution rule
are not defined in the RFCs and should be considered implementation dependent.

View File

@ -1,4 +1,4 @@
/* $NetBSD: udp_usrreq.c,v 1.84 2001/09/17 17:27:01 thorpej Exp $ */
/* $NetBSD: udp_usrreq.c,v 1.85 2001/10/15 09:51:15 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -778,25 +778,21 @@ udp6_realinput(af, src, dst, m, off)
!in6_mcmatch(in6p, &dst6, m->m_pkthdr.rcvif))
continue;
}
#ifndef INET6_BINDV6ONLY
else {
if (IN6_IS_ADDR_V4MAPPED(&dst6) &&
(in6p->in6p_flags & IN6P_BINDV6ONLY))
(in6p->in6p_flags & IN6P_IPV6_V6ONLY))
continue;
}
#endif
if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr,
&src6) || in6p->in6p_fport != sport)
continue;
}
#ifndef INET6_BINDV6ONLY
else {
if (IN6_IS_ADDR_V4MAPPED(&src6) &&
(in6p->in6p_flags & IN6P_BINDV6ONLY))
(in6p->in6p_flags & IN6P_IPV6_V6ONLY))
continue;
}
#endif
last = in6p;
udp6_sendup(m, off, (struct sockaddr *)src,

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6.h,v 1.27 2001/07/24 00:44:36 itojun Exp $ */
/* $NetBSD: in6.h,v 1.28 2001/10/15 09:51:16 itojun Exp $ */
/* $KAME: in6.h,v 1.83 2001/03/29 02:55:07 jinmei Exp $ */
/*
@ -402,7 +402,7 @@ struct route_in6 {
#define IPV6_RTHDR 24 /* bool; routing header */
#define IPV6_PKTOPTIONS 25 /* buf/cmsghdr; set/get IPv6 options */
#define IPV6_CHECKSUM 26 /* int; checksum offset for raw socket */
#define IPV6_BINDV6ONLY 27 /* bool; only bind INET6 at null bind */
#define IPV6_V6ONLY 27 /* bool; only bind INET6 at null bind */
#if 1 /*IPSEC*/
#define IPV6_IPSEC_POLICY 28 /* struct; get/set security policy */
@ -527,7 +527,7 @@ struct in6_pktinfo {
#define IPV6CTL_KAME_VERSION 20
#define IPV6CTL_USE_DEPRECATED 21 /* use deprecated addr (RFC2462 5.5.4) */
#define IPV6CTL_RR_PRUNE 22 /* walk timer for router renumbering */
#define IPV6CTL_BINDV6ONLY 24
#define IPV6CTL_V6ONLY 24
/* 25 to 27: reserved */
#define IPV6CTL_ANONPORTMIN 28 /* minimum ephemeral port */
#define IPV6CTL_ANONPORTMAX 29 /* maximum ephemeral port */

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6_pcb.c,v 1.40 2001/08/06 10:25:01 itojun Exp $ */
/* $NetBSD: in6_pcb.c,v 1.41 2001/10/15 09:51:16 itojun Exp $ */
/* $KAME: in6_pcb.c,v 1.84 2001/02/08 18:02:08 itojun Exp $ */
/*
@ -137,12 +137,8 @@ in6_pcballoc(so, head)
head->in6p_next = in6p;
in6p->in6p_prev = head;
in6p->in6p_next->in6p_prev = in6p;
#ifndef INET6_BINDV6ONLY
if (ip6_bindv6only)
in6p->in6p_flags |= IN6P_BINDV6ONLY;
#else
in6p->in6p_flags |= IN6P_BINDV6ONLY; /*just for safety*/
#endif
if (ip6_v6only)
in6p->in6p_flags |= IN6P_IPV6_V6ONLY;
so->so_pcb = (caddr_t)in6p;
return(0);
}
@ -201,7 +197,8 @@ in6_pcbbind(in6p, nam, p)
*/
if (so->so_options & SO_REUSEADDR)
reuseport = SO_REUSEADDR|SO_REUSEPORT;
} else if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
}
else if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
struct sockaddr_in sin;
bzero(&sin, sizeof(sin));
@ -211,7 +208,8 @@ in6_pcbbind(in6p, nam, p)
sizeof(sin.sin_addr));
if (ifa_ifwithaddr((struct sockaddr *)&sin) == 0)
return EADDRNOTAVAIL;
} else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
}
else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
struct ifaddr *ia = NULL;
sin6->sin6_port = 0; /* yech... */
@ -310,11 +308,14 @@ in6_pcbconnect(in6p, nam)
/* sanity check for mapped address case */
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY) != 0)
return EINVAL;
if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr))
in6p->in6p_laddr.s6_addr16[5] = htons(0xffff);
if (!IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr))
return EINVAL;
} else {
} else
{
if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr))
return EINVAL;
}
@ -352,7 +353,8 @@ in6_pcbconnect(in6p, nam)
#else
return EADDRNOTAVAIL;
#endif
} else {
} else
{
/*
* XXX: in6_selectsrc might replace the bound local address
* with the address specified by setsockopt(IPV6_PKTINFO).
@ -383,7 +385,14 @@ in6_pcbconnect(in6p, nam)
return(EADDRINUSE);
if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)
|| (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr)
&& in6p->in6p_laddr.s6_addr32[3] == 0)) {
&& in6p->in6p_laddr.s6_addr32[3] == 0))
{
/*
* XXX in IPv4 mapped address case, we should grab fresh
* local port number by in_pcbbind, not in6_pcbbind.
* if we are in bad luck, we may assign conflicting port number
* between IPv4 and IPv6 unwillingly.
*/
if (in6p->in6p_lport == 0) {
(void)in6_pcbbind(in6p, (struct mbuf *)0,
(struct proc *)0);
@ -758,14 +767,10 @@ in6_pcblookup(head, faddr6, fport_arg, laddr6, lport_arg, flags)
}
else {
if (IN6_IS_ADDR_V4MAPPED(laddr6)) {
#ifndef INET6_BINDV6ONLY
if (in6p->in6p_flags & IN6P_BINDV6ONLY)
if (in6p->in6p_flags & IN6P_IPV6_V6ONLY)
continue;
else
wildcard++;
#else
continue;
#endif
} else if (!IN6_IS_ADDR_UNSPECIFIED(laddr6))
wildcard++;
}
@ -787,14 +792,10 @@ in6_pcblookup(head, faddr6, fport_arg, laddr6, lport_arg, flags)
}
else {
if (IN6_IS_ADDR_V4MAPPED(faddr6)) {
#ifndef INET6_BINDV6ONLY
if (in6p->in6p_flags & IN6P_BINDV6ONLY)
if (in6p->in6p_flags & IN6P_IPV6_V6ONLY)
continue;
else
wildcard++;
#else
continue;
#endif
} else if (!IN6_IS_ADDR_UNSPECIFIED(faddr6))
wildcard++;
}
@ -860,6 +861,10 @@ in6_pcblookup_connect(head, faddr6, fport_arg, laddr6, lport_arg, faith)
continue;
if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, laddr6))
continue;
if ((IN6_IS_ADDR_V4MAPPED(laddr6) ||
IN6_IS_ADDR_V4MAPPED(faddr6)) &&
(in6p->in6p_flags & IN6P_IPV6_V6ONLY))
continue;
return in6p;
}
return NULL;
@ -889,18 +894,15 @@ in6_pcblookup_bind(head, laddr6, lport_arg, faith)
continue;
if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
if (IN6_IS_ADDR_V4MAPPED(laddr6)) {
#ifndef INET6_BINDV6ONLY
if (in6p->in6p_flags & IN6P_BINDV6ONLY)
if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY))
continue;
else
match = in6p;
#else
continue;
#endif
} else
match = in6p;
}
else if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr) &&
!(in6p->in6p_flags & IN6P_IPV6_V6ONLY) &&
in6p->in6p_laddr.s6_addr32[3] == 0) {
if (IN6_IS_ADDR_V4MAPPED(laddr6) &&
laddr6->s6_addr32[3] != 0)

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6_pcb.h,v 1.17 2001/07/02 15:25:36 itojun Exp $ */
/* $NetBSD: in6_pcb.h,v 1.18 2001/10/15 09:51:16 itojun Exp $ */
/* $KAME: in6_pcb.h,v 1.45 2001/02/09 05:59:46 itojun Exp $ */
/*
@ -122,6 +122,7 @@ struct in6pcb {
#define IN6P_RECVOPTS 0x001000 /* receive incoming IP6 options */
#define IN6P_RECVRETOPTS 0x002000 /* receive IP6 options for reply */
#define IN6P_RECVDSTADDR 0x004000 /* receive IP6 dst address */
#define IN6P_IPV6_V6ONLY 0x008000 /* restrict AF_INET6 socket for v6 */
#define IN6P_PKTINFO 0x010000 /* receive IP6 dst and I/F */
#define IN6P_HOPLIMIT 0x020000 /* receive hoplimit */
#define IN6P_HOPOPTS 0x040000 /* receive hop-by-hop options */
@ -133,7 +134,9 @@ struct in6pcb {
#define IN6P_LOWPORT 0x2000000 /* user wants "low" port binding */
#define IN6P_ANONPORT 0x4000000 /* port chosen for user */
#define IN6P_FAITH 0x8000000 /* accept FAITH'ed connections */
#if 0 /* obsoleted */
#define IN6P_BINDV6ONLY 0x10000000 /* do not grab IPv4 traffic */
#endif
#define IN6P_CONTROLOPTS (IN6P_PKTINFO|IN6P_HOPLIMIT|IN6P_HOPOPTS|\
IN6P_DSTOPTS|IN6P_RTHDR|IN6P_RTHDRDSTOPTS)

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6_proto.c,v 1.29 2001/03/21 19:22:28 thorpej Exp $ */
/* $NetBSD: in6_proto.c,v 1.30 2001/10/15 09:51:17 itojun Exp $ */
/* $KAME: in6_proto.c,v 1.66 2000/10/10 15:35:47 itojun Exp $ */
/*
@ -292,9 +292,7 @@ int ip6_gif_hlim = 0;
int ip6_use_deprecated = 1; /* allow deprecated addr (RFC2462 5.5.4) */
int ip6_rr_prune = 5; /* router renumbering prefix
* walk list every 5 sec. */
#ifndef INET6_BINDV6ONLY
int ip6_bindv6only = 1;
#endif
int ip6_v6only = 1;
u_int32_t ip6_id = 0UL;
int ip6_keepfaith = 0;

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip6_input.c,v 1.42 2001/08/06 10:25:01 itojun Exp $ */
/* $NetBSD: ip6_input.c,v 1.43 2001/10/15 09:51:17 itojun Exp $ */
/* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */
/*
@ -1453,10 +1453,11 @@ ip6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
&ip6_use_deprecated);
case IPV6CTL_RR_PRUNE:
return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_rr_prune);
#ifndef INET6_BINDV6ONLY
case IPV6CTL_BINDV6ONLY:
return sysctl_int(oldp, oldlenp, newp, newlen,
&ip6_bindv6only);
case IPV6CTL_V6ONLY:
#ifdef INET6_BINDV6ONLY
return sysctl_rdint(oldp, oldlenp, newp, ip6_v6only);
#else
return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_v6only);
#endif
case IPV6CTL_ANONPORTMIN:
old = ip6_anonportmin;

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip6_output.c,v 1.36 2001/06/11 13:49:18 itojun Exp $ */
/* $NetBSD: ip6_output.c,v 1.37 2001/10/15 09:51:17 itojun Exp $ */
/* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */
/*
@ -1257,75 +1257,87 @@ ip6_ctloutput(op, so, level, optname, mp)
case IPV6_RTHDR:
case IPV6_CHECKSUM:
case IPV6_FAITH:
#ifndef INET6_BINDV6ONLY
case IPV6_BINDV6ONLY:
#endif
if (!m || m->m_len != sizeof(int))
case IPV6_V6ONLY:
if (!m || m->m_len != sizeof(int)) {
error = EINVAL;
else {
optval = *mtod(m, int *);
switch (optname) {
break;
}
optval = *mtod(m, int *);
switch (optname) {
case IPV6_UNICAST_HOPS:
if (optval < -1 || optval >= 256)
error = EINVAL;
else {
/* -1 = kernel default */
in6p->in6p_hops = optval;
}
break;
#define OPTSET(bit) \
if (optval) \
in6p->in6p_flags |= bit; \
else \
in6p->in6p_flags &= ~bit;
case IPV6_RECVOPTS:
OPTSET(IN6P_RECVOPTS);
break;
case IPV6_RECVRETOPTS:
OPTSET(IN6P_RECVRETOPTS);
break;
case IPV6_RECVDSTADDR:
OPTSET(IN6P_RECVDSTADDR);
break;
case IPV6_PKTINFO:
OPTSET(IN6P_PKTINFO);
break;
case IPV6_HOPLIMIT:
OPTSET(IN6P_HOPLIMIT);
break;
case IPV6_HOPOPTS:
OPTSET(IN6P_HOPOPTS);
break;
case IPV6_DSTOPTS:
OPTSET(IN6P_DSTOPTS);
break;
case IPV6_RTHDR:
OPTSET(IN6P_RTHDR);
break;
case IPV6_CHECKSUM:
in6p->in6p_cksum = optval;
break;
case IPV6_FAITH:
OPTSET(IN6P_FAITH);
break;
#ifndef INET6_BINDV6ONLY
case IPV6_BINDV6ONLY:
OPTSET(IN6P_BINDV6ONLY);
break;
#endif
case IPV6_UNICAST_HOPS:
if (optval < -1 || optval >= 256)
error = EINVAL;
else {
/* -1 = kernel default */
in6p->in6p_hops = optval;
}
break;
#define OPTSET(bit) \
if (optval) \
in6p->in6p_flags |= bit; \
else \
in6p->in6p_flags &= ~bit;
case IPV6_RECVOPTS:
OPTSET(IN6P_RECVOPTS);
break;
case IPV6_RECVRETOPTS:
OPTSET(IN6P_RECVRETOPTS);
break;
case IPV6_RECVDSTADDR:
OPTSET(IN6P_RECVDSTADDR);
break;
case IPV6_PKTINFO:
OPTSET(IN6P_PKTINFO);
break;
case IPV6_HOPLIMIT:
OPTSET(IN6P_HOPLIMIT);
break;
case IPV6_HOPOPTS:
OPTSET(IN6P_HOPOPTS);
break;
case IPV6_DSTOPTS:
OPTSET(IN6P_DSTOPTS);
break;
case IPV6_RTHDR:
OPTSET(IN6P_RTHDR);
break;
case IPV6_CHECKSUM:
in6p->in6p_cksum = optval;
break;
case IPV6_FAITH:
OPTSET(IN6P_FAITH);
break;
case IPV6_V6ONLY:
/*
* make setsockopt(IPV6_V6ONLY)
* available only prior to bind(2).
* see ipng mailing list, Jun 22 2001.
*/
if (in6p->in6p_lport ||
!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr))
{
error = EINVAL;
break;
}
#ifdef INET6_BINDV6ONLY
if (!optval)
error = EINVAL;
#else
OPTSET(IN6P_IPV6_V6ONLY);
#endif
break;
}
break;
#undef OPTSET
@ -1439,9 +1451,7 @@ ip6_ctloutput(op, so, level, optname, mp)
case IPV6_RTHDR:
case IPV6_CHECKSUM:
case IPV6_FAITH:
#ifndef INET6_BINDV6ONLY
case IPV6_BINDV6ONLY:
#endif
case IPV6_V6ONLY:
*mp = m = m_get(M_WAIT, MT_SOOPTS);
m->m_len = sizeof(int);
switch (optname) {
@ -1505,11 +1515,9 @@ ip6_ctloutput(op, so, level, optname, mp)
optval = OPTBIT(IN6P_FAITH);
break;
#ifndef INET6_BINDV6ONLY
case IPV6_BINDV6ONLY:
optval = OPTBIT(IN6P_BINDV6ONLY);
case IPV6_V6ONLY:
optval = OPTBIT(IN6P_IPV6_V6ONLY);
break;
#endif
}
*mtod(m, int *) = optval;
break;

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip6_var.h,v 1.15 2000/08/26 11:03:46 itojun Exp $ */
/* $NetBSD: ip6_var.h,v 1.16 2001/10/15 09:51:17 itojun Exp $ */
/* $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $ */
/*
@ -214,9 +214,7 @@ extern int ip6_gif_hlim; /* Hop limit for gif encap packet */
extern int ip6_use_deprecated; /* allow deprecated addr as source */
extern int ip6_rr_prune; /* router renumbering prefix
* walk list every 5 sec. */
#ifndef INET6_BINDV6ONLY
extern int ip6_bindv6only;
#endif
extern int ip6_v6only;
extern struct socket *ip6_mrouter; /* multicast routing daemon */
extern int ip6_sendredirects; /* send IP redirects when forwarding? */

View File

@ -1,5 +1,5 @@
/* $NetBSD: udp6_output.c,v 1.1 2001/02/08 16:48:02 itojun Exp $ */
/* $KAME: udp6_output.c,v 1.21 2001/02/07 11:51:54 itojun Exp $ */
/* $NetBSD: udp6_output.c,v 1.2 2001/10/15 09:51:17 itojun Exp $ */
/* $KAME: udp6_output.c,v 1.43 2001/10/15 09:19:52 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -123,14 +123,16 @@ udp6_output(in6p, m, addr6, control, p)
u_int32_t plen = sizeof(struct udphdr) + ulen;
struct ip6_hdr *ip6;
struct udphdr *udp6;
struct in6_addr *laddr, *faddr;
struct in6_addr *laddr, *faddr;
struct in6_addr laddr_mapped; /* XXX ugly */
u_short fport;
int error = 0;
struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts;
int priv;
int af, hlen;
int af = AF_INET6, hlen = sizeof(struct ip6_hdr);
#ifdef INET
struct ip *ip;
struct udpiphdr *ui;
#endif
int flags;
struct sockaddr_in6 tmp;
@ -169,6 +171,7 @@ udp6_output(in6p, m, addr6, control, p)
}
if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
/* how about ::ffff:0.0.0.0 case? */
error = EISCONN;
goto release;
}
@ -180,6 +183,37 @@ udp6_output(in6p, m, addr6, control, p)
faddr = &sin6->sin6_addr;
fport = sin6->sin6_port; /* allow 0 port */
if (IN6_IS_ADDR_V4MAPPED(faddr)) {
if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY))
{
/*
* I believe we should explicitly discard the
* packet when mapped addresses are disabled,
* rather than send the packet as an IPv6 one.
* If we chose the latter approach, the packet
* might be sent out on the wire based on the
* default route, the situation which we'd
* probably want to avoid.
* (20010421 jinmei@kame.net)
*/
error = EINVAL;
goto release;
}
if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)
&& !IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr)) {
/*
* when remote addr is an IPv4-mapped address,
* local addr should not be an IPv6 address,
* since you cannot determine how to map IPv6
* source address to IPv4.
*/
error = EINVAL;
goto release;
}
af = AF_INET;
}
/* KAME hack: embed scopeid */
if (in6_embedscope(&sin6->sin6_addr, sin6, in6p, NULL) != 0) {
error = EINVAL;
@ -191,8 +225,41 @@ udp6_output(in6p, m, addr6, control, p)
in6p->in6p_moptions,
&in6p->in6p_route,
&in6p->in6p_laddr, &error);
} else
laddr = &in6p->in6p_laddr; /*XXX*/
} else {
/*
* XXX: freebsd[34] does not have in_selectsrc, but
* we can omit the whole part because freebsd4 calls
* udp_output() directly in this case, and thus we'll
* never see this path.
*/
if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
struct sockaddr_in *sinp, sin_dst;
bzero(&sin_dst, sizeof(sin_dst));
sin_dst.sin_family = AF_INET;
sin_dst.sin_len = sizeof(sin_dst);
bcopy(&faddr->s6_addr[12], &sin_dst.sin_addr,
sizeof(sin_dst.sin_addr));
sinp = in_selectsrc(&sin_dst,
(struct route *)&in6p->in6p_route,
in6p->in6p_socket->so_options,
NULL, &error);
if (sinp == NULL) {
if (error == 0)
error = EADDRNOTAVAIL;
goto release;
}
bzero(&laddr_mapped, sizeof(laddr_mapped));
laddr_mapped.s6_addr16[5] = 0xffff; /* ugly */
bcopy(&sinp->sin_addr,
&laddr_mapped.s6_addr[12],
sizeof(sinp->sin_addr));
laddr = &laddr_mapped;
} else
{
laddr = &in6p->in6p_laddr; /* XXX */
}
}
if (laddr == NULL) {
if (error == 0)
error = EADDRNOTAVAIL;
@ -206,18 +273,30 @@ udp6_output(in6p, m, addr6, control, p)
error = ENOTCONN;
goto release;
}
if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_faddr)) {
if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY))
{
/*
* XXX: this case would happen when the
* application sets the V6ONLY flag after
* connecting the foreign address.
* Such applications should be fixed,
* so we bark here.
*/
log(LOG_INFO, "udp6_output: IPV6_V6ONLY "
"option was set for a connected socket\n");
error = EINVAL;
goto release;
} else
af = AF_INET;
}
laddr = &in6p->in6p_laddr;
faddr = &in6p->in6p_faddr;
fport = in6p->in6p_fport;
}
if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
af = AF_INET6;
hlen = sizeof(struct ip6_hdr);
} else {
af = AF_INET;
if (af == AF_INET)
hlen = sizeof(struct ip);
}
/*
* Calculate data length and get a mbuf
@ -274,7 +353,7 @@ udp6_output(in6p, m, addr6, control, p)
error = ENOBUFS;
goto release;
}
#endif /*IPSEC*/
#endif /* IPSEC */
error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route,
flags, in6p->in6p_moptions, NULL);
break;
@ -287,23 +366,31 @@ udp6_output(in6p, m, addr6, control, p)
}
ip = mtod(m, struct ip *);
ui = (struct udpiphdr *)ip;
bzero(ui->ui_x1, sizeof ui->ui_x1);
ui->ui_pr = IPPROTO_UDP;
ui->ui_len = htons(plen);
bcopy(&faddr->s6_addr[12], &ui->ui_dst, sizeof(ui->ui_dst));
ui->ui_ulen = ui->ui_len;
ip->ip_len = plen;
ip->ip_p = IPPROTO_UDP;
ip->ip_ttl = in6_selecthlim(in6p, NULL); /*XXX*/
ip->ip_tos = 0; /*XXX*/
bcopy(&laddr->s6_addr[12], &ip->ip_src, sizeof(ip->ip_src));
bcopy(&faddr->s6_addr[12], &ip->ip_dst, sizeof(ip->ip_dst));
udp6->uh_sum = 0;
if ((udp6->uh_sum = in_cksum(m, ulen)) == 0)
flags = (in6p->in6p_socket->so_options &
(SO_DONTROUTE | SO_BROADCAST));
bcopy(&laddr->s6_addr[12], &ui->ui_src, sizeof(ui->ui_src));
udp6->uh_sum = in_cksum(m, hlen + plen);
if (udp6->uh_sum == 0)
udp6->uh_sum = 0xffff;
ip->ip_len = hlen + plen;
ip->ip_ttl = in6_selecthlim(in6p, NULL); /* XXX */
ip->ip_tos = 0; /* XXX */
ip->ip_len = hlen + plen; /* XXX */
udpstat.udps_opackets++;
#ifdef IPSEC
(void)ipsec_setsocket(m, NULL); /*XXX*/
#endif /*IPSEC*/
error = ip_output(m, NULL, &in6p->in6p_route, 0 /*XXX*/);
(void)ipsec_setsocket(m, NULL); /* XXX */
#endif /* IPSEC */
error = ip_output(m, NULL, &in6p->in6p_route, flags /* XXX */);
break;
#else
error = EAFNOSUPPORT;

View File

@ -1,4 +1,4 @@
/* $NetBSD: udp6_usrreq.c,v 1.45 2001/07/25 23:28:04 itojun Exp $ */
/* $NetBSD: udp6_usrreq.c,v 1.46 2001/10/15 09:51:17 itojun Exp $ */
/* $KAME: udp6_usrreq.c,v 1.86 2001/05/27 17:33:00 itojun Exp $ */
/*
@ -266,7 +266,7 @@ udp6_input(mp, offp, proto)
m->m_pkthdr.rcvif);
/*
* KAME note: usually we drop udphdr from mbuf here.
* KAME note: traditionally we dropped udpiphdr from mbuf here.
* We need udphdr for IPsec processing so we do that later.
*/
@ -557,7 +557,7 @@ udp6_ctlinput(cmd, sa, d)
/*
* Depending on the value of "valid" and routing table
* size (mtudisc_{hi,lo}wat), we will:
* - recalcurate the new MTU and create the
* - recalculate the new MTU and create the
* corresponding routing entry, or
* - ignore the MTU change notification.
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: udp6_var.h,v 1.9 2000/06/05 06:38:23 itojun Exp $ */
/* $NetBSD: udp6_var.h,v 1.10 2001/10/15 09:51:17 itojun Exp $ */
/* $KAME: udp6_var.h,v 1.11 2000/06/05 00:14:31 itojun Exp $ */
/*
@ -114,4 +114,4 @@ int udp6_usrreq __P((struct socket *,
struct proc *));
#endif /* _KERNEL */
#endif /*_NETINET6_UDP6_VAR_H_*/
#endif /* _NETINET6_UDP6_VAR_H_ */