diff options
author | rwatson <rwatson@FreeBSD.org> | 2007-07-23 07:58:58 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2007-07-23 07:58:58 +0000 |
commit | 9f42d6219fe8097ea3b6faf2beb93af539c11208 (patch) | |
tree | e9ddacff2fe82669b4c4c98bd691013a9988dda2 /sys/netinet6 | |
parent | 3a5cb59d83f3e960b56b9c5348a183a78c676655 (diff) | |
download | FreeBSD-src-9f42d6219fe8097ea3b6faf2beb93af539c11208.zip FreeBSD-src-9f42d6219fe8097ea3b6faf2beb93af539c11208.tar.gz |
Continue effort to align UDPv4 and UDPv6 implementations by merging
udp6_output() from udp6_output.c to udp6_usrreq.c, matching the UDPv4
structure, and allowing us to remove udp6_output.c.
Reviewed by: bz, gnn
Approved by: re (bmah)
Diffstat (limited to 'sys/netinet6')
-rw-r--r-- | sys/netinet6/udp6_output.c | 330 | ||||
-rw-r--r-- | sys/netinet6/udp6_usrreq.c | 226 | ||||
-rw-r--r-- | sys/netinet6/udp6_var.h | 2 |
3 files changed, 226 insertions, 332 deletions
diff --git a/sys/netinet6/udp6_output.c b/sys/netinet6/udp6_output.c deleted file mode 100644 index d068791..0000000 --- a/sys/netinet6/udp6_output.c +++ /dev/null @@ -1,330 +0,0 @@ -/* $FreeBSD$ */ -/* $KAME: udp6_output.c,v 1.31 2001/05/21 16:39:15 jinmei Exp $ */ - -/*- - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/*- - * Copyright (c) 1982, 1986, 1989, 1993 - * The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)udp_var.h 8.1 (Berkeley) 6/10/93 - */ - -#include "opt_ipsec.h" -#include "opt_inet.h" -#include "opt_inet6.h" - -#include <sys/param.h> -#include <sys/proc.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/priv.h> -#include <sys/protosw.h> -#include <sys/socket.h> -#include <sys/socketvar.h> -#include <sys/sysctl.h> -#include <sys/errno.h> -#include <sys/stat.h> -#include <sys/syslog.h> - -#include <net/if.h> -#include <net/route.h> -#include <net/if_types.h> - -#include <netinet/in.h> -#include <netinet/in_var.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/ip_var.h> -#include <netinet/in_pcb.h> -#include <netinet/udp.h> -#include <netinet/udp_var.h> -#include <netinet/ip6.h> -#include <netinet6/ip6_var.h> -#include <netinet6/in6_pcb.h> -#include <netinet6/udp6_var.h> -#include <netinet/icmp6.h> -#include <netinet6/ip6protosw.h> -#include <netinet6/scope6_var.h> - -/* - * UDP protocol inplementation. - * Per RFC 768, August, 1980. - */ - -#define in6pcb inpcb -#define udp6stat udpstat -#define udp6s_opackets udps_opackets - -int -udp6_output(struct in6pcb *in6p, struct mbuf *m, struct sockaddr *addr6, - struct mbuf *control, struct thread *td) -{ - u_int32_t ulen = m->m_pkthdr.len; - u_int32_t plen = sizeof(struct udphdr) + ulen; - struct ip6_hdr *ip6; - struct udphdr *udp6; - struct in6_addr *laddr, *faddr; - struct sockaddr_in6 *sin6 = NULL; - struct ifnet *oifp = NULL; - int scope_ambiguous = 0; - u_short fport; - int error = 0; - struct ip6_pktopts *optp, opt; - int priv; - int af = AF_INET6, hlen = sizeof(struct ip6_hdr); - int flags; - struct sockaddr_in6 tmp; - - INP_LOCK_ASSERT(in6p); - - priv = 0; - if (td && !suser(td)) - priv = 1; - - if (addr6) { - /* addr6 has been validated in udp6_send(). */ - sin6 = (struct sockaddr_in6 *)addr6; - - /* protect *sin6 from overwrites */ - tmp = *sin6; - sin6 = &tmp; - - /* - * Application should provide a proper zone ID or the use of - * default zone IDs should be enabled. Unfortunately, some - * applications do not behave as it should, so we need a - * workaround. Even if an appropriate ID is not determined, - * we'll see if we can determine the outgoing interface. If we - * can, determine the zone ID based on the interface below. - */ - if (sin6->sin6_scope_id == 0 && !ip6_use_defzone) - scope_ambiguous = 1; - if ((error = sa6_embedscope(sin6, ip6_use_defzone)) != 0) - return (error); - } - - if (control) { - if ((error = ip6_setpktopts(control, &opt, - in6p->in6p_outputopts, priv, IPPROTO_UDP)) != 0) - goto release; - optp = &opt; - } else - optp = in6p->in6p_outputopts; - - if (sin6) { - faddr = &sin6->sin6_addr; - - /* - * 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. - */ - if (sin6->sin6_port == 0) { - error = EADDRNOTAVAIL; - goto release; - } - - if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { - /* how about ::ffff:0.0.0.0 case? */ - error = EISCONN; - goto release; - } - - 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; - } - - if (!IN6_IS_ADDR_V4MAPPED(faddr)) { - laddr = in6_selectsrc(sin6, optp, in6p->in6p_moptions, - NULL, &in6p->in6p_laddr, &oifp, &error); - if (oifp && scope_ambiguous && - (error = in6_setscope(&sin6->sin6_addr, - oifp, NULL))) { - goto release; - } - } else - laddr = &in6p->in6p_laddr; /* XXX */ - if (laddr == NULL) { - if (error == 0) - error = EADDRNOTAVAIL; - goto release; - } - if (in6p->in6p_lport == 0 && - (error = in6_pcbsetport(laddr, in6p, td->td_ucred)) != 0) - goto release; - } else { - if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { - 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 (af == AF_INET) - hlen = sizeof(struct ip); - - /* - * Calculate data length and get a mbuf - * for UDP and IP6 headers. - */ - M_PREPEND(m, hlen + sizeof(struct udphdr), M_DONTWAIT); - if (m == 0) { - error = ENOBUFS; - goto release; - } - - /* - * Stuff checksum and output datagram. - */ - udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen); - udp6->uh_sport = in6p->in6p_lport; /* lport is always set in the PCB */ - udp6->uh_dport = fport; - if (plen <= 0xffff) - udp6->uh_ulen = htons((u_short)plen); - else - udp6->uh_ulen = 0; - udp6->uh_sum = 0; - - switch (af) { - case AF_INET6: - ip6 = mtod(m, struct ip6_hdr *); - ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK; - ip6->ip6_vfc &= ~IPV6_VERSION_MASK; - ip6->ip6_vfc |= IPV6_VERSION; -#if 0 /* ip6_plen will be filled in ip6_output. */ - ip6->ip6_plen = htons((u_short)plen); -#endif - ip6->ip6_nxt = IPPROTO_UDP; - ip6->ip6_hlim = in6_selecthlim(in6p, NULL); - ip6->ip6_src = *laddr; - ip6->ip6_dst = *faddr; - - if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP, - sizeof(struct ip6_hdr), plen)) == 0) { - udp6->uh_sum = 0xffff; - } - - flags = 0; - - udp6stat.udp6s_opackets++; - error = ip6_output(m, optp, NULL, flags, in6p->in6p_moptions, - NULL, in6p); - break; - case AF_INET: - error = EAFNOSUPPORT; - goto release; - } - goto releaseopt; - -release: - m_freem(m); - -releaseopt: - if (control) { - ip6_clearpktopts(&opt, -1); - m_freem(control); - } - return (error); -} diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index b57448b..585b2b4 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -1,5 +1,6 @@ /* $FreeBSD$ */ /* $KAME: udp6_usrreq.c,v 1.27 2001/05/21 05:45:10 jinmei Exp $ */ +/* $KAME: udp6_output.c,v 1.31 2001/05/21 16:39:15 jinmei Exp $ */ /*- * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -468,6 +469,231 @@ udp6_getcred(SYSCTL_HANDLER_ARGS) SYSCTL_PROC(_net_inet6_udp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW, 0, 0, udp6_getcred, "S,xucred", "Get the xucred of a UDP6 connection"); +#define in6pcb inpcb +#define udp6stat udpstat +#define udp6s_opackets udps_opackets + +static int +udp6_output(struct in6pcb *in6p, struct mbuf *m, struct sockaddr *addr6, + struct mbuf *control, struct thread *td) +{ + u_int32_t ulen = m->m_pkthdr.len; + u_int32_t plen = sizeof(struct udphdr) + ulen; + struct ip6_hdr *ip6; + struct udphdr *udp6; + struct in6_addr *laddr, *faddr; + struct sockaddr_in6 *sin6 = NULL; + struct ifnet *oifp = NULL; + int scope_ambiguous = 0; + u_short fport; + int error = 0; + struct ip6_pktopts *optp, opt; + int priv; + int af = AF_INET6, hlen = sizeof(struct ip6_hdr); + int flags; + struct sockaddr_in6 tmp; + + INP_LOCK_ASSERT(in6p); + + priv = 0; + if (td && !suser(td)) + priv = 1; + + if (addr6) { + /* addr6 has been validated in udp6_send(). */ + sin6 = (struct sockaddr_in6 *)addr6; + + /* protect *sin6 from overwrites */ + tmp = *sin6; + sin6 = &tmp; + + /* + * Application should provide a proper zone ID or the use of + * default zone IDs should be enabled. Unfortunately, some + * applications do not behave as it should, so we need a + * workaround. Even if an appropriate ID is not determined, + * we'll see if we can determine the outgoing interface. If we + * can, determine the zone ID based on the interface below. + */ + if (sin6->sin6_scope_id == 0 && !ip6_use_defzone) + scope_ambiguous = 1; + if ((error = sa6_embedscope(sin6, ip6_use_defzone)) != 0) + return (error); + } + + if (control) { + if ((error = ip6_setpktopts(control, &opt, + in6p->in6p_outputopts, priv, IPPROTO_UDP)) != 0) + goto release; + optp = &opt; + } else + optp = in6p->in6p_outputopts; + + if (sin6) { + faddr = &sin6->sin6_addr; + + /* + * 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. + */ + if (sin6->sin6_port == 0) { + error = EADDRNOTAVAIL; + goto release; + } + + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { + /* how about ::ffff:0.0.0.0 case? */ + error = EISCONN; + goto release; + } + + 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; + } + + if (!IN6_IS_ADDR_V4MAPPED(faddr)) { + laddr = in6_selectsrc(sin6, optp, in6p->in6p_moptions, + NULL, &in6p->in6p_laddr, &oifp, &error); + if (oifp && scope_ambiguous && + (error = in6_setscope(&sin6->sin6_addr, + oifp, NULL))) { + goto release; + } + } else + laddr = &in6p->in6p_laddr; /* XXX */ + if (laddr == NULL) { + if (error == 0) + error = EADDRNOTAVAIL; + goto release; + } + if (in6p->in6p_lport == 0 && + (error = in6_pcbsetport(laddr, in6p, td->td_ucred)) != 0) + goto release; + } else { + if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { + 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 (af == AF_INET) + hlen = sizeof(struct ip); + + /* + * Calculate data length and get a mbuf + * for UDP and IP6 headers. + */ + M_PREPEND(m, hlen + sizeof(struct udphdr), M_DONTWAIT); + if (m == 0) { + error = ENOBUFS; + goto release; + } + + /* + * Stuff checksum and output datagram. + */ + udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen); + udp6->uh_sport = in6p->in6p_lport; /* lport is always set in the PCB */ + udp6->uh_dport = fport; + if (plen <= 0xffff) + udp6->uh_ulen = htons((u_short)plen); + else + udp6->uh_ulen = 0; + udp6->uh_sum = 0; + + switch (af) { + case AF_INET6: + ip6 = mtod(m, struct ip6_hdr *); + ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK; + ip6->ip6_vfc &= ~IPV6_VERSION_MASK; + ip6->ip6_vfc |= IPV6_VERSION; +#if 0 /* ip6_plen will be filled in ip6_output. */ + ip6->ip6_plen = htons((u_short)plen); +#endif + ip6->ip6_nxt = IPPROTO_UDP; + ip6->ip6_hlim = in6_selecthlim(in6p, NULL); + ip6->ip6_src = *laddr; + ip6->ip6_dst = *faddr; + + if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP, + sizeof(struct ip6_hdr), plen)) == 0) { + udp6->uh_sum = 0xffff; + } + + flags = 0; + + udp6stat.udp6s_opackets++; + error = ip6_output(m, optp, NULL, flags, in6p->in6p_moptions, + NULL, in6p); + break; + case AF_INET: + error = EAFNOSUPPORT; + goto release; + } + goto releaseopt; + +release: + m_freem(m); + +releaseopt: + if (control) { + ip6_clearpktopts(&opt, -1); + m_freem(control); + } + return (error); +} + static void udp6_abort(struct socket *so) { diff --git a/sys/netinet6/udp6_var.h b/sys/netinet6/udp6_var.h index e8f624c..feee95e 100644 --- a/sys/netinet6/udp6_var.h +++ b/sys/netinet6/udp6_var.h @@ -71,8 +71,6 @@ extern struct pr_usrreqs udp6_usrreqs; void udp6_ctlinput(int, struct sockaddr *, void *); int udp6_input(struct mbuf **, int *, int); -int udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr, - struct mbuf *control, struct thread *td); #endif #endif /*_NETINET6_UDP6_VAR_H_*/ |