X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..5eebf7385fedb1517b66b53c28e5aa6bb0a2be50:/bsd/netinet6/udp6_usrreq.c diff --git a/bsd/netinet6/udp6_usrreq.c b/bsd/netinet6/udp6_usrreq.c index c6bfcc685..9bab08c72 100644 --- a/bsd/netinet6/udp6_usrreq.c +++ b/bsd/netinet6/udp6_usrreq.c @@ -1,4 +1,5 @@ -/* $KAME: udp6_usrreq.c,v 1.25 2000/04/04 11:18:10 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/udp6_usrreq.c,v 1.6.2.6 2001/07/29 19:32:40 ume Exp $ */ +/* $KAME: udp6_usrreq.c,v 1.27 2001/05/21 05:45:10 jinmei Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -63,9 +64,6 @@ * * @(#)udp_var.h 8.1 (Berkeley) 6/10/93 */ -#if BSD310 -#include "opt_inet.h" -#endif #include #include @@ -102,9 +100,14 @@ #if IPSEC #include +#include +extern int ipsec_bypass; #endif /*IPSEC*/ #include "faith.h" +#if defined(NFAITH) && NFAITH > 0 +#include +#endif /* * UDP protocol inplementation. @@ -139,34 +142,33 @@ in6_mcmatch(in6p, ia6, ifp) } int -udp6_input(mp, offp, proto) +udp6_input(mp, offp) struct mbuf **mp; - int *offp, proto; + int *offp; { struct mbuf *m = *mp; register struct ip6_hdr *ip6; register struct udphdr *uh; register struct inpcb *in6p; - struct ip6_recvpktopts opts; + struct mbuf *opts = NULL; int off = *offp; int plen, ulen; struct sockaddr_in6 udp_in6; + IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); + + ip6 = mtod(m, struct ip6_hdr *); + #if defined(NFAITH) && 0 < NFAITH - if (m->m_pkthdr.rcvif) { - if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) { - /* XXX send icmp6 host/port unreach? */ - m_freem(m); - return IPPROTO_DONE; - } + if (faithprefix(&ip6->ip6_dst)) { + /* XXX send icmp6 host/port unreach? */ + m_freem(m); + return IPPROTO_DONE; } #endif - udpstat.udps_ipackets++; - bzero(&opts, sizeof(opts)); - IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); + udpstat.udps_ipackets++; - ip6 = mtod(m, struct ip6_hdr *); plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6); uh = (struct udphdr *)((caddr_t)ip6 + off); ulen = ntohs((u_short)uh->uh_ulen); @@ -179,8 +181,10 @@ udp6_input(mp, offp, proto) /* * Checksum extended UDP header and data. */ -// if (uh->uh_sum == 0) -// udpstat.udps_nosum++; +#ifndef __APPLE__ + if (uh->uh_sum == 0) + udpstat.udps_nosum++; +#endif else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) { udpstat.udps_badsum++; goto bad; @@ -256,7 +260,7 @@ udp6_input(mp, offp, proto) /* * Check AH/ESP integrity. */ - if (ipsec6_in_reject_so(m, last->inp_socket)) + if (ipsec_bypass == 0 && ipsec6_in_reject_so(m, last->inp_socket)) ipsec6stat.in_polvio++; /* do not inject data into pcb */ else @@ -271,20 +275,20 @@ udp6_input(mp, offp, proto) */ if (last->in6p_flags & IN6P_CONTROLOPTS || last->in6p_socket->so_options & SO_TIMESTAMP) - ip6_savecontrol(last, ip6, n, - &opts, NULL); + ip6_savecontrol(last, &opts, + ip6, n); m_adj(n, off + sizeof(struct udphdr)); if (sbappendaddr(&last->in6p_socket->so_rcv, (struct sockaddr *)&udp_in6, - n, opts.head) == 0) { + n, opts) == 0) { m_freem(n); - if (opts.head) - m_freem(opts.head); + if (opts) + m_freem(opts); udpstat.udps_fullsock++; } else sorwakeup(last->in6p_socket); - bzero(&opts, sizeof(opts)); + opts = NULL; } } last = in6p; @@ -308,26 +312,28 @@ udp6_input(mp, offp, proto) * for a broadcast or multicast datgram.) */ udpstat.udps_noport++; -// udpstat.udps_noportmcast++; +#ifndef __APPLE__ + udpstat.udps_noportmcast++; +#endif goto bad; } #if IPSEC /* * Check AH/ESP integrity. */ - if (ipsec6_in_reject_so(m, last->inp_socket)) { + if (ipsec_bypass == 0 && ipsec6_in_reject_so(m, last->inp_socket)) { ipsec6stat.in_polvio++; goto bad; } #endif /*IPSEC*/ if (last->in6p_flags & IN6P_CONTROLOPTS || last->in6p_socket->so_options & SO_TIMESTAMP) - ip6_savecontrol(last, ip6, m, &opts, NULL); + ip6_savecontrol(last, &opts, ip6, m); m_adj(m, off + sizeof(struct udphdr)); if (sbappendaddr(&last->in6p_socket->so_rcv, (struct sockaddr *)&udp_in6, - m, opts.head) == 0) { + m, opts) == 0) { udpstat.udps_fullsock++; goto bad; } @@ -353,7 +359,9 @@ udp6_input(mp, offp, proto) udpstat.udps_noport++; if (m->m_flags & M_MCAST) { printf("UDP6: M_MCAST is set in a unicast packet.\n"); -// udpstat.udps_noportmcast++; +#ifndef __APPLE__ + udpstat.udps_noportmcast++; +#endif goto bad; } icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0); @@ -363,7 +371,7 @@ udp6_input(mp, offp, proto) /* * Check AH/ESP integrity. */ - if (ipsec6_in_reject_so(m, in6p->in6p_socket)) { + if (ipsec_bypass == 0 && ipsec6_in_reject_so(m, in6p->in6p_socket)) { ipsec6stat.in_polvio++; goto bad; } @@ -377,11 +385,11 @@ udp6_input(mp, offp, proto) udp_in6.sin6_port = uh->uh_sport; if (in6p->in6p_flags & IN6P_CONTROLOPTS || in6p->in6p_socket->so_options & SO_TIMESTAMP) - ip6_savecontrol(in6p, ip6, m, &opts, NULL); + ip6_savecontrol(in6p, &opts, ip6, m); m_adj(m, off + sizeof(struct udphdr)); if (sbappendaddr(&in6p->in6p_socket->so_rcv, (struct sockaddr *)&udp_in6, - m, opts.head) == 0) { + m, opts) == 0) { udpstat.udps_fullsock++; goto bad; } @@ -390,8 +398,8 @@ udp6_input(mp, offp, proto) bad: if (m) m_freem(m); - if (opts.head) - m_freem(opts.head); + if (opts) + m_freem(opts); return IPPROTO_DONE; } @@ -401,13 +409,17 @@ udp6_ctlinput(cmd, sa, d) struct sockaddr *sa; void *d; { - register struct udphdr *uhp; struct udphdr uh; - struct sockaddr_in6 sa6; struct ip6_hdr *ip6; struct mbuf *m; int off = 0; + struct ip6ctlparam *ip6cp = NULL; + const struct sockaddr_in6 *sa6_src = NULL; void (*notify) __P((struct inpcb *, int)) = udp_notify; + struct udp_portonly { + u_int16_t uh_sport; + u_int16_t uh_dport; + } *uhp; if (sa->sa_family != AF_INET6 || sa->sa_len != sizeof(struct sockaddr_in6)) @@ -424,49 +436,39 @@ udp6_ctlinput(cmd, sa, d) /* if the parameter is from icmp6, decode it. */ if (d != NULL) { - struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; + ip6cp = (struct ip6ctlparam *)d; m = ip6cp->ip6c_m; ip6 = ip6cp->ip6c_ip6; off = ip6cp->ip6c_off; + sa6_src = ip6cp->ip6c_src; } else { m = NULL; ip6 = NULL; + sa6_src = &sa6_any; } - /* translate addresses into internal form */ - sa6 = *(struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif) - sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); - if (ip6) { /* * XXX: We assume that when IPV6 is non NULL, * M and OFF are valid. */ - struct in6_addr s; - /* translate addresses into internal form */ - memcpy(&s, &ip6->ip6_src, sizeof(s)); - if (IN6_IS_ADDR_LINKLOCAL(&s)) - s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); + /* check if we can safely examine src and dst ports */ + if (m->m_pkthdr.len < off + sizeof(*uhp)) + return; - if (m->m_len < off + sizeof(uh)) { - /* - * this should be rare case, - * so we compromise on this copy... - */ - m_copydata(m, off, sizeof(uh), (caddr_t)&uh); - uhp = &uh; - } else - uhp = (struct udphdr *)(mtod(m, caddr_t) + off); - (void) in6_pcbnotify(&udb, (struct sockaddr *)&sa6, - uhp->uh_dport, &s, - uhp->uh_sport, cmd, notify); + bzero(&uh, sizeof(uh)); + m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh); + + (void) in6_pcbnotify(&udb, sa, uh.uh_dport, + (struct sockaddr*)ip6cp->ip6c_src, + uh.uh_sport, cmd, notify); } else - (void) in6_pcbnotify(&udb, (struct sockaddr *)&sa6, 0, - &zeroin6_addr, 0, cmd, notify); + (void) in6_pcbnotify(&udb, sa, 0, (struct sockaddr *)&sa6_src, + 0, cmd, notify); } -#if 0 + +#ifndef __APPLE__ static int udp6_getcred SYSCTL_HANDLER_ARGS { @@ -506,128 +508,6 @@ SYSCTL_PROC(_net_inet6_udp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW, 0, 0, udp6_getcred, "S,ucred", "Get the ucred of a UDP6 connection"); #endif -int -udp6_output(in6p, m, addr6, control, p) - register struct inpcb *in6p; - register struct mbuf *m; - struct sockaddr *addr6; - struct mbuf *control; - struct proc *p; -{ - register int ulen = m->m_pkthdr.len; - int plen = sizeof(struct udphdr) + ulen; - struct ip6_hdr *ip6; - struct udphdr *udp6; - struct in6_addr laddr6; - int s = 0, error = 0; - struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts; - int flags; - - if (control) { - if (error = ip6_setpktoptions(control, &opt, - p && - suser(p->p_ucred, &p->p_acflag), 0)) - goto release; - in6p->in6p_outputopts = &opt; - } - - if (addr6) { - laddr6 = in6p->in6p_laddr; - if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { - error = EISCONN; - goto release; - } - /* - * Must block input while temporarily connected. - */ - s = splnet(); - /* - * XXX: the user might want to overwrite the local address - * via an ancillary data. - */ - bzero(&in6p->in6p_laddr, sizeof(struct in6_addr)); - error = in6_pcbconnect(in6p, addr6, p); - if (error) { - splx(s); - goto release; - } - } else { - if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { - error = ENOTCONN; - goto release; - } - } - /* - * Calculate data length and get a mbuf - * for UDP and IP6 headers. - */ - M_PREPEND(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr), - M_DONTWAIT); - if (m == 0) { - error = ENOBUFS; - if (addr6) - splx(s); - goto release; - } - - /* - * Stuff checksum and output datagram. - */ - ip6 = mtod(m, struct ip6_hdr *); - ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_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, - in6p->in6p_route.ro_rt ? - in6p->in6p_route.ro_rt->rt_ifp : - NULL); - ip6->ip6_src = in6p->in6p_laddr; - ip6->ip6_dst = in6p->in6p_faddr; - - udp6 = (struct udphdr *)(ip6 + 1); - udp6->uh_sport = in6p->in6p_lport; - udp6->uh_dport = in6p->in6p_fport; - udp6->uh_ulen = htons((u_short)plen); - udp6->uh_sum = 0; - - if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP, - sizeof(struct ip6_hdr), plen)) == 0) { - udp6->uh_sum = 0xffff; - } - - flags = 0; - if (in6p->in6p_flags & IN6P_MINMTU) - flags |= IPV6_MINMTU; - - udpstat.udps_opackets++; - -#if IPSEC - ipsec_setsocket(m, in6p->in6p_socket); -#endif /*IPSEC*/ - error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route, - flags, in6p->in6p_moptions, NULL); - - if (addr6) { - in6_pcbdisconnect(in6p); - in6p->in6p_laddr = laddr6; - splx(s); - } - goto releaseopt; - -release: - m_freem(m); - -releaseopt: - if (control) { - ip6_clearpktopts(in6p->in6p_outputopts, 0, -1); - in6p->in6p_outputopts = stickyopt; - m_freem(control); - } - return(error); -} static int udp6_abort(struct socket *so) @@ -667,15 +547,17 @@ udp6_attach(struct socket *so, int proto, struct proc *p) return error; inp = (struct inpcb *)so->so_pcb; inp->inp_vflag |= INP_IPV6; + if (ip6_mapped_addr_on) + inp->inp_vflag |= INP_IPV4; inp->in6p_hops = -1; /* use kernel default */ inp->in6p_cksum = -1; /* just to be sure */ -#if IPSEC - error = ipsec_init_policy(so, &inp->in6p_sp); - if (error != 0) { - in6_pcbdetach(inp); - return (error); - } -#endif /*IPSEC*/ + /* + * XXX: ugly!! + * IPv4 TTL initialization is necessary for an IPv6 socket as well, + * because the socket may be bound to an IPv6 wildcard address, + * which may match an IPv4-mapped IPv6 address. + */ + inp->inp_ip_ttl = ip_defttl; return 0; } @@ -691,7 +573,7 @@ udp6_bind(struct socket *so, struct sockaddr *nam, struct proc *p) inp->inp_vflag &= ~INP_IPV4; inp->inp_vflag |= INP_IPV6; - if (ip6_mapped_addr_on && (inp->inp_flags & IN6P_BINDV6ONLY) == 0) { + if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { struct sockaddr_in6 *sin6_p; sin6_p = (struct sockaddr_in6 *)nam; @@ -727,7 +609,7 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p) if (inp == 0) return EINVAL; - if (ip6_mapped_addr_on) { + if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { struct sockaddr_in6 *sin6_p; sin6_p = (struct sockaddr_in6 *)nam; @@ -753,14 +635,9 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p) return EISCONN; s = splnet(); error = in6_pcbconnect(inp, nam, p); - if (ip6_auto_flowlabel) { - inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK; - inp->in6p_flowinfo |= - (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK); - } splx(s); if (error == 0) { - if (ip6_mapped_addr_on) { /* should be non mapped addr */ + if (ip6_mapped_addr_on || (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { /* should be non mapped addr */ inp->inp_vflag &= ~INP_IPV4; inp->inp_vflag |= INP_IPV6; } @@ -817,14 +694,26 @@ udp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, struct mbuf *control, struct proc *p) { struct inpcb *inp; + int error = 0; inp = sotoinpcb(so); if (inp == 0) { - m_freem(m); - return EINVAL; + error = EINVAL; + goto bad; } - if (ip6_mapped_addr_on) { + if (addr) { + if (addr->sa_len != sizeof(struct sockaddr_in6)) { + error = EINVAL; + goto bad; + } + if (addr->sa_family != AF_INET6) { + error = EAFNOSUPPORT; + goto bad; + } + } + + if (ip6_mapped_addr_on || (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { int hasv4addr; struct sockaddr_in6 *sin6 = 0; @@ -837,7 +726,6 @@ udp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, } if (hasv4addr) { struct pr_usrreqs *pru; - int error; if (sin6) in6_sin6_2_sin_in_sock(addr); @@ -850,6 +738,10 @@ udp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, } return udp6_output(inp, m, addr, control, p); + + bad: + m_freem(m); + return(error); } struct pr_usrreqs udp6_usrreqs = {