Annotation of sys/netinet6/udp6_output.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: udp6_output.c,v 1.14 2007/06/01 00:52:39 henning Exp $ */
! 2: /* $KAME: udp6_output.c,v 1.21 2001/02/07 11:51:54 itojun Exp $ */
! 3:
! 4: /*
! 5: * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. Neither the name of the project nor the names of its contributors
! 17: * may be used to endorse or promote products derived from this software
! 18: * without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
! 21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 23: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
! 24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
! 31: */
! 32:
! 33: /*
! 34: * Copyright (c) 1982, 1986, 1989, 1993
! 35: * The Regents of the University of California. All rights reserved.
! 36: *
! 37: * Redistribution and use in source and binary forms, with or without
! 38: * modification, are permitted provided that the following conditions
! 39: * are met:
! 40: * 1. Redistributions of source code must retain the above copyright
! 41: * notice, this list of conditions and the following disclaimer.
! 42: * 2. Redistributions in binary form must reproduce the above copyright
! 43: * notice, this list of conditions and the following disclaimer in the
! 44: * documentation and/or other materials provided with the distribution.
! 45: * 3. Neither the name of the University nor the names of its contributors
! 46: * may be used to endorse or promote products derived from this software
! 47: * without specific prior written permission.
! 48: *
! 49: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 50: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 51: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 52: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 53: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 54: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 55: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 56: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 57: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 58: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 59: * SUCH DAMAGE.
! 60: *
! 61: * @(#)udp_var.h 8.1 (Berkeley) 6/10/93
! 62: */
! 63:
! 64: #include <sys/param.h>
! 65: #include <sys/malloc.h>
! 66: #include <sys/mbuf.h>
! 67: #include <sys/protosw.h>
! 68: #include <sys/socket.h>
! 69: #include <sys/socketvar.h>
! 70: #include <sys/errno.h>
! 71: #include <sys/stat.h>
! 72: #include <sys/systm.h>
! 73: #include <sys/proc.h>
! 74: #include <sys/syslog.h>
! 75:
! 76: #include <net/if.h>
! 77: #include <net/route.h>
! 78: #include <net/if_types.h>
! 79:
! 80: #include <netinet/in.h>
! 81: #include <netinet/in_var.h>
! 82: #include <netinet/in_systm.h>
! 83: #include <netinet/ip.h>
! 84: #include <netinet/ip_var.h>
! 85: #include <netinet/in_pcb.h>
! 86: #include <netinet/udp.h>
! 87: #include <netinet/udp_var.h>
! 88: #include <netinet/ip6.h>
! 89: #include <netinet6/ip6_var.h>
! 90: #include <netinet/icmp6.h>
! 91: #include <netinet6/ip6protosw.h>
! 92:
! 93: #include "faith.h"
! 94:
! 95: /*
! 96: * UDP protocol inplementation.
! 97: * Per RFC 768, August, 1980.
! 98: */
! 99:
! 100: #define in6pcb inpcb
! 101: #define in6p_outputopts inp_outputopts6
! 102: #define in6p_socket inp_socket
! 103: #define in6p_faddr inp_faddr6
! 104: #define in6p_laddr inp_laddr6
! 105: #define in6p_fport inp_fport
! 106: #define in6p_lport inp_lport
! 107: #define in6p_flags inp_flags
! 108: #define in6p_moptions inp_moptions6
! 109: #define in6p_route inp_route6
! 110: #define in6p_flowinfo inp_flowinfo
! 111: #define udp6stat udpstat
! 112: #define udp6s_opackets udps_opackets
! 113:
! 114: int
! 115: udp6_output(in6p, m, addr6, control)
! 116: struct in6pcb *in6p;
! 117: struct mbuf *m;
! 118: struct mbuf *addr6, *control;
! 119: {
! 120: u_int32_t ulen = m->m_pkthdr.len;
! 121: u_int32_t plen = sizeof(struct udphdr) + ulen;
! 122: struct ip6_hdr *ip6;
! 123: struct udphdr *udp6;
! 124: struct in6_addr *laddr, *faddr;
! 125: u_short fport;
! 126: int error = 0;
! 127: struct ip6_pktopts *optp, opt;
! 128: int priv;
! 129: int af, hlen;
! 130: int flags;
! 131: struct sockaddr_in6 tmp;
! 132: struct proc *p = curproc; /* XXX */
! 133:
! 134: priv = 0;
! 135: if ((in6p->in6p_socket->so_state & SS_PRIV) != 0)
! 136: priv = 1;
! 137: if (control) {
! 138: if ((error = ip6_setpktopts(control, &opt,
! 139: in6p->in6p_outputopts, priv, IPPROTO_UDP)) != 0)
! 140: goto release;
! 141: optp = &opt;
! 142: } else
! 143: optp = in6p->in6p_outputopts;
! 144:
! 145: if (addr6) {
! 146: /*
! 147: * IPv4 version of udp_output calls in_pcbconnect in this case,
! 148: * which needs splnet and affects performance.
! 149: * Since we saw no essential reason for calling in_pcbconnect,
! 150: * we get rid of such kind of logic, and call in6_selectsrc
! 151: * and in6_pcbsetport in order to fill in the local address
! 152: * and the local port.
! 153: */
! 154: struct sockaddr_in6 *sin6 = mtod(addr6, struct sockaddr_in6 *);
! 155:
! 156: if (addr6->m_len != sizeof(*sin6)) {
! 157: error = EINVAL;
! 158: goto release;
! 159: }
! 160: if (sin6->sin6_family != AF_INET6) {
! 161: error = EAFNOSUPPORT;
! 162: goto release;
! 163: }
! 164: if (sin6->sin6_port == 0) {
! 165: error = EADDRNOTAVAIL;
! 166: goto release;
! 167: }
! 168:
! 169: if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
! 170: error = EISCONN;
! 171: goto release;
! 172: }
! 173:
! 174: /* protect *sin6 from overwrites */
! 175: tmp = *sin6;
! 176: sin6 = &tmp;
! 177:
! 178: faddr = &sin6->sin6_addr;
! 179: fport = sin6->sin6_port; /* allow 0 port */
! 180:
! 181: /* KAME hack: embed scopeid */
! 182: if (in6_embedscope(&sin6->sin6_addr, sin6, in6p, NULL) != 0) {
! 183: error = EINVAL;
! 184: goto release;
! 185: }
! 186:
! 187: if (1) /* we don't support IPv4 mapped address */
! 188: {
! 189: laddr = in6_selectsrc(sin6, optp,
! 190: in6p->in6p_moptions,
! 191: &in6p->in6p_route,
! 192: &in6p->in6p_laddr, &error);
! 193: } else
! 194: laddr = &in6p->in6p_laddr; /*XXX*/
! 195: if (laddr == NULL) {
! 196: if (error == 0)
! 197: error = EADDRNOTAVAIL;
! 198: goto release;
! 199: }
! 200: if (in6p->in6p_lport == 0 &&
! 201: (error = in6_pcbsetport(laddr, in6p, p)) != 0)
! 202: goto release;
! 203: } else {
! 204: if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
! 205: error = ENOTCONN;
! 206: goto release;
! 207: }
! 208: laddr = &in6p->in6p_laddr;
! 209: faddr = &in6p->in6p_faddr;
! 210: fport = in6p->in6p_fport;
! 211: }
! 212:
! 213: if (1) /* we don't support IPv4 mapped address */
! 214: {
! 215: af = AF_INET6;
! 216: hlen = sizeof(struct ip6_hdr);
! 217: } else {
! 218: af = AF_INET;
! 219: hlen = sizeof(struct ip);
! 220: }
! 221:
! 222: /*
! 223: * Calculate data length and get a mbuf
! 224: * for UDP and IP6 headers.
! 225: */
! 226: M_PREPEND(m, hlen + sizeof(struct udphdr), M_DONTWAIT);
! 227: if (m == 0) {
! 228: error = ENOBUFS;
! 229: goto release;
! 230: }
! 231:
! 232: /*
! 233: * Stuff checksum and output datagram.
! 234: */
! 235: udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen);
! 236: udp6->uh_sport = in6p->in6p_lport; /* lport is always set in the PCB */
! 237: udp6->uh_dport = fport;
! 238: if (plen <= 0xffff)
! 239: udp6->uh_ulen = htons((u_short)plen);
! 240: else
! 241: udp6->uh_ulen = 0;
! 242: udp6->uh_sum = 0;
! 243:
! 244: switch (af) {
! 245: case AF_INET6:
! 246: ip6 = mtod(m, struct ip6_hdr *);
! 247: ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
! 248: ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
! 249: ip6->ip6_vfc |= IPV6_VERSION;
! 250: #if 0 /* ip6_plen will be filled in ip6_output. */
! 251: ip6->ip6_plen = htons((u_short)plen);
! 252: #endif
! 253: ip6->ip6_nxt = IPPROTO_UDP;
! 254: ip6->ip6_hlim = in6_selecthlim(in6p,
! 255: in6p->in6p_route.ro_rt ?
! 256: in6p->in6p_route.ro_rt->rt_ifp : NULL);
! 257: ip6->ip6_src = *laddr;
! 258: ip6->ip6_dst = *faddr;
! 259:
! 260: if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP,
! 261: sizeof(struct ip6_hdr), plen)) == 0) {
! 262: udp6->uh_sum = 0xffff;
! 263: }
! 264:
! 265: flags = 0;
! 266: if (in6p->in6p_flags & IN6P_MINMTU)
! 267: flags |= IPV6_MINMTU;
! 268:
! 269: udp6stat.udp6s_opackets++;
! 270: error = ip6_output(m, optp, &in6p->in6p_route,
! 271: flags, in6p->in6p_moptions, NULL, in6p);
! 272: break;
! 273: case AF_INET:
! 274: error = EAFNOSUPPORT;
! 275: goto release;
! 276: }
! 277: goto releaseopt;
! 278:
! 279: release:
! 280: m_freem(m);
! 281:
! 282: releaseopt:
! 283: if (control) {
! 284: ip6_clearpktopts(&opt, -1);
! 285: m_freem(control);
! 286: }
! 287: return (error);
! 288: }
CVSweb