Line data Source code
1 : /* $OpenBSD: udp6_output.c,v 1.56 2018/09/13 19:53:58 bluhm 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 :
62 : #include "pf.h"
63 :
64 : #include <sys/param.h>
65 : #include <sys/mbuf.h>
66 : #include <sys/protosw.h>
67 : #include <sys/socket.h>
68 : #include <sys/socketvar.h>
69 : #include <sys/errno.h>
70 : #include <sys/stat.h>
71 : #include <sys/systm.h>
72 : #include <sys/syslog.h>
73 :
74 : #include <net/if.h>
75 : #include <net/if_var.h>
76 : #include <net/route.h>
77 : #if NPF > 0
78 : #include <net/pfvar.h>
79 : #endif
80 :
81 : #include <netinet/in.h>
82 : #include <netinet6/in6_var.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 : /*
94 : * UDP protocol inplementation.
95 : * Per RFC 768, August, 1980.
96 : */
97 : int
98 0 : udp6_output(struct inpcb *in6p, struct mbuf *m, struct mbuf *addr6,
99 : struct mbuf *control)
100 : {
101 0 : u_int32_t ulen = m->m_pkthdr.len;
102 0 : u_int32_t plen = sizeof(struct udphdr) + ulen;
103 : int error = 0, priv = 0, hlen, flags;
104 : struct ip6_hdr *ip6;
105 : struct udphdr *udp6;
106 0 : struct in6_addr *laddr, *faddr;
107 0 : struct ip6_pktopts *optp, opt;
108 0 : struct sockaddr_in6 tmp, valid;
109 0 : struct proc *p = curproc; /* XXX */
110 : u_short fport;
111 :
112 0 : if ((in6p->inp_socket->so_state & SS_PRIV) != 0)
113 0 : priv = 1;
114 0 : if (control) {
115 0 : if ((error = ip6_setpktopts(control, &opt,
116 0 : in6p->inp_outputopts6, priv, IPPROTO_UDP)) != 0)
117 : goto release;
118 : optp = &opt;
119 0 : } else
120 0 : optp = in6p->inp_outputopts6;
121 :
122 0 : if (addr6) {
123 0 : struct sockaddr_in6 *sin6;
124 :
125 0 : if ((error = in6_nam2sin6(addr6, &sin6)))
126 0 : goto release;
127 0 : if (sin6->sin6_port == 0) {
128 : error = EADDRNOTAVAIL;
129 0 : goto release;
130 : }
131 0 : if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
132 : error = EADDRNOTAVAIL;
133 0 : goto release;
134 : }
135 0 : if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->inp_faddr6)) {
136 : error = EISCONN;
137 0 : goto release;
138 : }
139 :
140 : /* protect *sin6 from overwrites */
141 0 : tmp = *sin6;
142 0 : sin6 = &tmp;
143 :
144 0 : faddr = &sin6->sin6_addr;
145 0 : fport = sin6->sin6_port; /* allow 0 port */
146 :
147 : /* KAME hack: embed scopeid */
148 0 : if (in6_embedscope(&sin6->sin6_addr, sin6, in6p) != 0) {
149 : error = EINVAL;
150 0 : goto release;
151 : }
152 :
153 0 : error = in6_pcbselsrc(&laddr, sin6, in6p, optp);
154 0 : if (error)
155 0 : goto release;
156 :
157 0 : if (in6p->inp_lport == 0){
158 0 : error = in_pcbbind(in6p, NULL, p);
159 0 : if (error)
160 0 : goto release;
161 : }
162 :
163 0 : if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->inp_laddr6) &&
164 0 : !IN6_ARE_ADDR_EQUAL(&in6p->inp_laddr6, laddr)) {
165 0 : valid.sin6_addr = *laddr;
166 0 : valid.sin6_port = in6p->inp_lport;
167 0 : valid.sin6_scope_id = 0;
168 0 : valid.sin6_family = AF_INET6;
169 0 : valid.sin6_len = sizeof(valid);
170 0 : error = in6_pcbaddrisavail(in6p, &valid, 0, p);
171 0 : if (error)
172 0 : goto release;
173 : }
174 0 : } else {
175 0 : if (IN6_IS_ADDR_UNSPECIFIED(&in6p->inp_faddr6)) {
176 : error = ENOTCONN;
177 0 : goto release;
178 : }
179 0 : laddr = &in6p->inp_laddr6;
180 : faddr = &in6p->inp_faddr6;
181 0 : fport = in6p->inp_fport;
182 : }
183 :
184 : hlen = sizeof(struct ip6_hdr);
185 :
186 : /*
187 : * Calculate data length and get a mbuf
188 : * for UDP and IP6 headers.
189 : */
190 0 : M_PREPEND(m, hlen + sizeof(struct udphdr), M_DONTWAIT);
191 0 : if (m == NULL) {
192 : error = ENOBUFS;
193 0 : goto releaseopt;
194 : }
195 :
196 : /*
197 : * Stuff checksum and output datagram.
198 : */
199 0 : udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen);
200 0 : udp6->uh_sport = in6p->inp_lport; /* lport is always set in the PCB */
201 0 : udp6->uh_dport = fport;
202 0 : if (plen <= 0xffff)
203 0 : udp6->uh_ulen = htons((u_short)plen);
204 : else
205 0 : udp6->uh_ulen = 0;
206 0 : udp6->uh_sum = 0;
207 :
208 0 : ip6 = mtod(m, struct ip6_hdr *);
209 0 : ip6->ip6_flow = in6p->inp_flowinfo & IPV6_FLOWINFO_MASK;
210 0 : ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
211 0 : ip6->ip6_vfc |= IPV6_VERSION;
212 : #if 0 /* ip6_plen will be filled in ip6_output. */
213 : ip6->ip6_plen = htons((u_short)plen);
214 : #endif
215 0 : ip6->ip6_nxt = IPPROTO_UDP;
216 0 : ip6->ip6_hlim = in6_selecthlim(in6p);
217 0 : ip6->ip6_src = *laddr;
218 0 : ip6->ip6_dst = *faddr;
219 :
220 0 : m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT;
221 :
222 : flags = 0;
223 0 : if (in6p->inp_flags & IN6P_MINMTU)
224 0 : flags |= IPV6_MINMTU;
225 :
226 0 : udpstat_inc(udps_opackets);
227 :
228 : /* force routing table */
229 0 : m->m_pkthdr.ph_rtableid = in6p->inp_rtableid;
230 :
231 : #if NPF > 0
232 0 : if (in6p->inp_socket->so_state & SS_ISCONNECTED)
233 0 : pf_mbuf_link_inpcb(m, in6p);
234 : #endif
235 :
236 0 : error = ip6_output(m, optp, &in6p->inp_route6,
237 0 : flags, in6p->inp_moptions6, in6p);
238 0 : goto releaseopt;
239 :
240 : release:
241 0 : m_freem(m);
242 :
243 : releaseopt:
244 0 : if (control) {
245 0 : ip6_clearpktopts(&opt, -1);
246 0 : m_freem(control);
247 0 : }
248 0 : return (error);
249 0 : }
|