]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/udp6_usrreq.c
xnu-1504.15.3.tar.gz
[apple/xnu.git] / bsd / netinet6 / udp6_usrreq.c
CommitLineData
9bccf70c
A
1/* $FreeBSD: src/sys/netinet6/udp6_usrreq.c,v 1.6.2.6 2001/07/29 19:32:40 ume Exp $ */
2/* $KAME: udp6_usrreq.c,v 1.27 2001/05/21 05:45:10 jinmei Exp $ */
1c79356b
A
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. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the University of
48 * California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 *
65 * @(#)udp_var.h 8.1 (Berkeley) 6/10/93
66 */
1c79356b
A
67
68#include <sys/param.h>
69#include <sys/kernel.h>
70#include <sys/malloc.h>
71#include <sys/mbuf.h>
72#include <sys/protosw.h>
73#include <sys/socket.h>
74#include <sys/socketvar.h>
75#include <sys/sysctl.h>
76#include <sys/errno.h>
77#include <sys/stat.h>
78#include <sys/systm.h>
79#include <sys/syslog.h>
80#include <sys/proc.h>
91447636 81#include <sys/kauth.h>
1c79356b
A
82
83#include <net/if.h>
84#include <net/route.h>
85#include <net/if_types.h>
86
87#include <netinet/in.h>
88#include <netinet/in_systm.h>
89#include <netinet/ip.h>
90#include <netinet/in_pcb.h>
91#include <netinet/in_var.h>
92#include <netinet/ip_var.h>
93#include <netinet/udp.h>
94#include <netinet/udp_var.h>
95#include <netinet/ip6.h>
96#include <netinet6/ip6_var.h>
97#include <netinet6/in6_pcb.h>
98#include <netinet/icmp6.h>
99#include <netinet6/udp6_var.h>
100#include <netinet6/ip6protosw.h>
101
102#if IPSEC
103#include <netinet6/ipsec.h>
9bccf70c
A
104#include <netinet6/ipsec6.h>
105extern int ipsec_bypass;
1c79356b 106#endif /*IPSEC*/
2d21ac55 107extern lck_mtx_t *nd6_mutex;
1c79356b
A
108
109/*
110 * UDP protocol inplementation.
111 * Per RFC 768, August, 1980.
112 */
113
114extern struct protosw inetsw[];
91447636
A
115static int in6_mcmatch(struct inpcb *, struct in6_addr *, struct ifnet *);
116static int udp6_detach(struct socket *so);
2d21ac55
A
117static void udp6_append(struct inpcb *, struct ip6_hdr *,
118 struct sockaddr_in6 *, struct mbuf *, int);
91447636 119
2d21ac55 120extern void ipfwsyslog( int level, const char *format,...);
91447636
A
121extern int fw_verbose;
122
2d21ac55 123#if IPFIREWALL
91447636
A
124#define log_in_vain_log( a ) { \
125 if ( (log_in_vain == 3 ) && (fw_verbose == 2)) { /* Apple logging, log to ipfw.log */ \
126 ipfwsyslog a ; \
127 } \
128 else log a ; \
129}
2d21ac55
A
130#else
131#define log_in_vain_log( a ) { log a; }
132#endif
1c79356b
A
133
134static int
91447636
A
135in6_mcmatch(
136 struct inpcb *in6p,
137 register struct in6_addr *ia6,
138 struct ifnet *ifp)
1c79356b
A
139{
140 struct ip6_moptions *im6o = in6p->in6p_moptions;
141 struct in6_multi_mship *imm;
142
143 if (im6o == NULL)
144 return 0;
145
91447636 146 lck_mtx_lock(nd6_mutex);
1c79356b
A
147 for (imm = im6o->im6o_memberships.lh_first; imm != NULL;
148 imm = imm->i6mm_chain.le_next) {
149 if ((ifp == NULL ||
150 imm->i6mm_maddr->in6m_ifp == ifp) &&
151 IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
91447636
A
152 ia6)) {
153 lck_mtx_unlock(nd6_mutex);
1c79356b 154 return 1;
91447636 155 }
1c79356b 156 }
91447636 157 lck_mtx_unlock(nd6_mutex);
1c79356b
A
158 return 0;
159}
160
2d21ac55
A
161/*
162 * subroutine of udp6_input(), mainly for source code readability.
163 */
164static void
165udp6_append(struct inpcb *last, struct ip6_hdr *ip6,
166 struct sockaddr_in6 *udp_in6, struct mbuf *n, int off)
167{
168 struct mbuf *opts = NULL;
169
170#if CONFIG_MACF_NET
171 if (mac_inpcb_check_deliver(last, n, AF_INET6, SOCK_DGRAM) != 0) {
172 m_freem(n);
173 return;
174 }
175#endif
176 if (last->in6p_flags & IN6P_CONTROLOPTS ||
177 last->in6p_socket->so_options & SO_TIMESTAMP)
178 ip6_savecontrol(last, &opts, ip6, n);
179
180 m_adj(n, off);
181 if (sbappendaddr(&last->in6p_socket->so_rcv,
182 (struct sockaddr *)udp_in6, n, opts, NULL) == 0)
183 udpstat.udps_fullsock++;
184 else
185 sorwakeup(last->in6p_socket);
186}
187
1c79356b 188int
91447636
A
189udp6_input(
190 struct mbuf **mp,
191 int *offp)
1c79356b
A
192{
193 struct mbuf *m = *mp;
194 register struct ip6_hdr *ip6;
195 register struct udphdr *uh;
196 register struct inpcb *in6p;
9bccf70c 197 struct mbuf *opts = NULL;
1c79356b
A
198 int off = *offp;
199 int plen, ulen;
200 struct sockaddr_in6 udp_in6;
91447636 201 struct inpcbinfo *pcbinfo = &udbinfo;
1c79356b 202
91447636 203 IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), return IPPROTO_DONE);
9bccf70c
A
204
205 ip6 = mtod(m, struct ip6_hdr *);
206
1c79356b 207#if defined(NFAITH) && 0 < NFAITH
9bccf70c
A
208 if (faithprefix(&ip6->ip6_dst)) {
209 /* XXX send icmp6 host/port unreach? */
210 m_freem(m);
211 return IPPROTO_DONE;
1c79356b
A
212 }
213#endif
1c79356b 214
9bccf70c 215 udpstat.udps_ipackets++;
1c79356b 216
1c79356b
A
217 plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6);
218 uh = (struct udphdr *)((caddr_t)ip6 + off);
219 ulen = ntohs((u_short)uh->uh_ulen);
220
221 if (plen != ulen) {
222 udpstat.udps_badlen++;
223 goto bad;
224 }
225
226 /*
227 * Checksum extended UDP header and data.
228 */
9bccf70c
A
229#ifndef __APPLE__
230 if (uh->uh_sum == 0)
231 udpstat.udps_nosum++;
232#endif
1c79356b
A
233 else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) {
234 udpstat.udps_badsum++;
235 goto bad;
236 }
237
238 if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
2d21ac55
A
239 int reuse_sock = 0, mcast_delivered = 0;
240 struct mbuf *n = NULL;
1c79356b
A
241
242 /*
243 * Deliver a multicast datagram to all sockets
244 * for which the local and remote addresses and ports match
245 * those of the incoming datagram. This allows more than
246 * one process to receive multicasts on the same port.
247 * (This really ought to be done for unicast datagrams as
248 * well, but that would cause problems with existing
249 * applications that open both address-specific sockets and
250 * a wildcard socket listening to the same port -- they would
251 * end up receiving duplicates of every unicast datagram.
252 * Those applications open the multiple sockets to overcome an
253 * inadequacy of the UDP socket interface, but for backwards
254 * compatibility we avoid the problem here rather than
255 * fixing the interface. Maybe 4.5BSD will remedy this?)
256 */
257
258 /*
259 * In a case that laddr should be set to the link-local
260 * address (this happens in RIPng), the multicast address
261 * specified in the received packet does not match with
262 * laddr. To cure this situation, the matching is relaxed
263 * if the receiving interface is the same as one specified
264 * in the socket and if the destination multicast address
265 * matches one of the multicast groups specified in the socket.
266 */
267
268 /*
269 * Construct sockaddr format source address.
270 */
271 init_sin6(&udp_in6, m); /* general init */
272 udp_in6.sin6_port = uh->uh_sport;
273 /*
274 * KAME note: usually we drop udphdr from mbuf here.
275 * We need udphdr for IPsec processing so we do that later.
276 */
277
278 /*
279 * Locate pcb(s) for datagram.
280 * (Algorithm copied from raw_intr().)
281 */
91447636
A
282 lck_rw_lock_shared(pcbinfo->mtx);
283
1c79356b 284 LIST_FOREACH(in6p, &udb, inp_list) {
91447636 285
1c79356b
A
286 if ((in6p->inp_vflag & INP_IPV6) == 0)
287 continue;
91447636
A
288
289 if (in_pcb_checkstate(in6p, WNT_ACQUIRE, 0) == WNT_STOPUSING)
290 continue;
291
292 udp_lock(in6p->in6p_socket, 1, 0);
293
294 if (in_pcb_checkstate(in6p, WNT_RELEASE, 1) == WNT_STOPUSING) {
295 udp_unlock(in6p->in6p_socket, 1, 0);
296 continue;
297 }
298 if (in6p->in6p_lport != uh->uh_dport) {
299 udp_unlock(in6p->in6p_socket, 1, 0);
1c79356b 300 continue;
91447636 301 }
1c79356b
A
302 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
303 if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr,
304 &ip6->ip6_dst) &&
305 !in6_mcmatch(in6p, &ip6->ip6_dst,
91447636
A
306 m->m_pkthdr.rcvif)) {
307 udp_unlock(in6p->in6p_socket, 1, 0);
1c79356b 308 continue;
91447636 309 }
1c79356b
A
310 }
311 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
312 if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr,
313 &ip6->ip6_src) ||
91447636
A
314 in6p->in6p_fport != uh->uh_sport) {
315 udp_unlock(in6p->in6p_socket, 1, 0);
1c79356b 316 continue;
91447636 317 }
1c79356b
A
318 }
319
2d21ac55
A
320 reuse_sock = in6p->inp_socket->so_options &
321 (SO_REUSEPORT | SO_REUSEADDR);
1c79356b 322
2d21ac55 323 {
1c79356b 324#if IPSEC
2d21ac55
A
325 int skipit = 0;
326 /* Check AH/ESP integrity. */
91447636 327 if (ipsec_bypass == 0) {
2d21ac55
A
328 if (ipsec6_in_reject_so(m, in6p->inp_socket)) {
329 IPSEC_STAT_INCREMENT(ipsec6stat.in_polvio);
330 /* do not inject data to pcb */
331 skipit = 1;
332 }
91447636 333 }
2d21ac55 334 if (skipit == 0)
1c79356b 335#endif /*IPSEC*/
2d21ac55 336 {
1c79356b
A
337 /*
338 * KAME NOTE: do not
2d21ac55 339 * m_copy(m, offset, ...) below.
1c79356b
A
340 * sbappendaddr() expects M_PKTHDR,
341 * and m_copy() will copy M_PKTHDR
342 * only if offset is 0.
343 */
2d21ac55
A
344 if (reuse_sock)
345 n = m_copy(m, 0, M_COPYALL);
346 udp6_append(in6p, ip6, &udp_in6, m,
347 off + sizeof (struct udphdr));
348 mcast_delivered++;
1c79356b 349 }
2d21ac55 350 udp_unlock(in6p->in6p_socket, 1, 0);
1c79356b 351 }
1c79356b
A
352 /*
353 * Don't look for additional matches if this one does
354 * not have either the SO_REUSEPORT or SO_REUSEADDR
355 * socket options set. This heuristic avoids searching
356 * through all pcbs in the common case of a non-shared
357 * port. It assumes that an application will never
358 * clear these options after setting them.
359 */
2d21ac55 360 if (reuse_sock == 0 || ((m = n) == NULL))
1c79356b 361 break;
b0d623f7
A
362 /*
363 * Recompute IP and UDP header pointers for new mbuf
364 */
365 ip6 = mtod(m, struct ip6_hdr *);
366 uh = (struct udphdr *)((caddr_t)ip6 + off);
1c79356b 367 }
91447636 368 lck_rw_done(pcbinfo->mtx);
1c79356b 369
2d21ac55 370 if (mcast_delivered == 0) {
1c79356b
A
371 /*
372 * No matching pcb found; discard datagram.
373 * (No need to send an ICMP Port Unreachable
374 * for a broadcast or multicast datgram.)
375 */
376 udpstat.udps_noport++;
9bccf70c
A
377#ifndef __APPLE__
378 udpstat.udps_noportmcast++;
379#endif
1c79356b
A
380 goto bad;
381 }
2d21ac55
A
382
383 if (reuse_sock != 0) /* free the extra copy of mbuf */
384 m_freem(m);
1c79356b
A
385 return IPPROTO_DONE;
386 }
387 /*
388 * Locate pcb for datagram.
389 */
390 in6p = in6_pcblookup_hash(&udbinfo, &ip6->ip6_src, uh->uh_sport,
391 &ip6->ip6_dst, uh->uh_dport, 1,
392 m->m_pkthdr.rcvif);
393 if (in6p == 0) {
394 if (log_in_vain) {
395 char buf[INET6_ADDRSTRLEN];
396
2d21ac55 397 strlcpy(buf, ip6_sprintf(&ip6->ip6_dst), sizeof(buf));
91447636
A
398 if (log_in_vain != 3)
399 log(LOG_INFO,
400 "Connection attempt to UDP %s:%d from %s:%d\n",
401 buf, ntohs(uh->uh_dport),
402 ip6_sprintf(&ip6->ip6_src), ntohs(uh->uh_sport));
403 else if (!(m->m_flags & (M_BCAST | M_MCAST)) &&
404 !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &ip6->ip6_src))
405 log_in_vain_log((LOG_INFO,
406 "Connection attempt to UDP %s:%d from %s:%d\n",
407 buf, ntohs(uh->uh_dport),
408 ip6_sprintf(&ip6->ip6_src), ntohs(uh->uh_sport)));
1c79356b
A
409 }
410 udpstat.udps_noport++;
411 if (m->m_flags & M_MCAST) {
412 printf("UDP6: M_MCAST is set in a unicast packet.\n");
9bccf70c
A
413#ifndef __APPLE__
414 udpstat.udps_noportmcast++;
415#endif
1c79356b
A
416 goto bad;
417 }
418 icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
419 return IPPROTO_DONE;
420 }
421#if IPSEC
422 /*
423 * Check AH/ESP integrity.
424 */
91447636 425 if (ipsec_bypass == 0) {
91447636 426 if (ipsec6_in_reject_so(m, in6p->in6p_socket)) {
2d21ac55 427 IPSEC_STAT_INCREMENT(ipsec6stat.in_polvio);
91447636
A
428 in_pcb_checkstate(in6p, WNT_RELEASE, 0);
429 goto bad;
430 }
1c79356b
A
431 }
432#endif /*IPSEC*/
433
434 /*
435 * Construct sockaddr format source address.
436 * Stuff source address and datagram in user buffer.
437 */
91447636
A
438 udp_lock(in6p->in6p_socket, 1, 0);
439
440 if (in_pcb_checkstate(in6p, WNT_RELEASE, 1) == WNT_STOPUSING) {
441 udp_unlock(in6p->in6p_socket, 1, 0);
442 goto bad;
443 }
444
1c79356b
A
445 init_sin6(&udp_in6, m); /* general init */
446 udp_in6.sin6_port = uh->uh_sport;
447 if (in6p->in6p_flags & IN6P_CONTROLOPTS
448 || in6p->in6p_socket->so_options & SO_TIMESTAMP)
9bccf70c 449 ip6_savecontrol(in6p, &opts, ip6, m);
1c79356b
A
450 m_adj(m, off + sizeof(struct udphdr));
451 if (sbappendaddr(&in6p->in6p_socket->so_rcv,
452 (struct sockaddr *)&udp_in6,
91447636
A
453 m, opts, NULL) == 0) {
454 m = NULL;
455 opts = NULL;
1c79356b 456 udpstat.udps_fullsock++;
91447636 457 udp_unlock(in6p->in6p_socket, 1, 0);
1c79356b
A
458 goto bad;
459 }
460 sorwakeup(in6p->in6p_socket);
91447636 461 udp_unlock(in6p->in6p_socket, 1, 0);
1c79356b
A
462 return IPPROTO_DONE;
463bad:
464 if (m)
465 m_freem(m);
9bccf70c
A
466 if (opts)
467 m_freem(opts);
1c79356b
A
468 return IPPROTO_DONE;
469}
470
471void
91447636
A
472udp6_ctlinput(
473 int cmd,
474 struct sockaddr *sa,
475 void *d)
1c79356b 476{
1c79356b 477 struct udphdr uh;
1c79356b
A
478 struct ip6_hdr *ip6;
479 struct mbuf *m;
480 int off = 0;
9bccf70c
A
481 struct ip6ctlparam *ip6cp = NULL;
482 const struct sockaddr_in6 *sa6_src = NULL;
91447636 483 void (*notify)(struct inpcb *, int) = udp_notify;
9bccf70c
A
484 struct udp_portonly {
485 u_int16_t uh_sport;
486 u_int16_t uh_dport;
487 } *uhp;
1c79356b
A
488
489 if (sa->sa_family != AF_INET6 ||
490 sa->sa_len != sizeof(struct sockaddr_in6))
491 return;
492
493 if ((unsigned)cmd >= PRC_NCMDS)
494 return;
495 if (PRC_IS_REDIRECT(cmd))
496 notify = in6_rtchange, d = NULL;
497 else if (cmd == PRC_HOSTDEAD)
498 d = NULL;
499 else if (inet6ctlerrmap[cmd] == 0)
500 return;
501
502 /* if the parameter is from icmp6, decode it. */
503 if (d != NULL) {
9bccf70c 504 ip6cp = (struct ip6ctlparam *)d;
1c79356b
A
505 m = ip6cp->ip6c_m;
506 ip6 = ip6cp->ip6c_ip6;
507 off = ip6cp->ip6c_off;
9bccf70c 508 sa6_src = ip6cp->ip6c_src;
1c79356b
A
509 } else {
510 m = NULL;
511 ip6 = NULL;
9bccf70c 512 sa6_src = &sa6_any;
1c79356b
A
513 }
514
1c79356b
A
515 if (ip6) {
516 /*
517 * XXX: We assume that when IPV6 is non NULL,
518 * M and OFF are valid.
519 */
1c79356b 520
9bccf70c
A
521 /* check if we can safely examine src and dst ports */
522 if (m->m_pkthdr.len < off + sizeof(*uhp))
523 return;
1c79356b 524
9bccf70c
A
525 bzero(&uh, sizeof(uh));
526 m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh);
527
91447636 528 (void) in6_pcbnotify(&udbinfo, sa, uh.uh_dport,
9bccf70c
A
529 (struct sockaddr*)ip6cp->ip6c_src,
530 uh.uh_sport, cmd, notify);
1c79356b 531 } else
91447636 532 (void) in6_pcbnotify(&udbinfo, sa, 0, (struct sockaddr *)&sa6_src,
9bccf70c 533 0, cmd, notify);
1c79356b 534}
9bccf70c
A
535
536#ifndef __APPLE__
1c79356b
A
537static int
538udp6_getcred SYSCTL_HANDLER_ARGS
539{
540 struct sockaddr_in6 addrs[2];
541 struct inpcb *inp;
542 int error, s;
543
2d21ac55 544 error = proc_suser(req->p);
1c79356b
A
545 if (error)
546 return (error);
547
548 if (req->newlen != sizeof(addrs))
549 return (EINVAL);
91447636 550 if (req->oldlen != sizeof(*(kauth_cred_t)0))
1c79356b
A
551 return (EINVAL);
552 error = SYSCTL_IN(req, addrs, sizeof(addrs));
553 if (error)
554 return (error);
555 s = splnet();
556 inp = in6_pcblookup_hash(&udbinfo, &addrs[1].sin6_addr,
557 addrs[1].sin6_port,
558 &addrs[0].sin6_addr, addrs[0].sin6_port,
559 1, NULL);
560 if (!inp || !inp->inp_socket || !inp->inp_socket->so_cred) {
561 error = ENOENT;
562 goto out;
563 }
564 error = SYSCTL_OUT(req, inp->inp_socket->so_cred->pc_ucred,
91447636 565 sizeof(*(kauth_cred_t)0));
1c79356b
A
566
567out:
568 splx(s);
569 return (error);
570}
571
572SYSCTL_PROC(_net_inet6_udp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW,
573 0, 0,
574 udp6_getcred, "S,ucred", "Get the ucred of a UDP6 connection");
575#endif
1c79356b
A
576
577static int
578udp6_abort(struct socket *so)
579{
580 struct inpcb *inp;
1c79356b
A
581
582 inp = sotoinpcb(so);
583 if (inp == 0)
584 return EINVAL; /* ??? possible? panic instead? */
585 soisdisconnected(so);
1c79356b 586 in6_pcbdetach(inp);
1c79356b
A
587 return 0;
588}
589
590static int
2d21ac55 591udp6_attach(struct socket *so, __unused int proto, struct proc *p)
1c79356b
A
592{
593 struct inpcb *inp;
91447636 594 int error;
1c79356b
A
595
596 inp = sotoinpcb(so);
597 if (inp != 0)
598 return EINVAL;
599
91447636
A
600 error = in_pcballoc(so, &udbinfo, p);
601 if (error)
602 return error;
603
1c79356b
A
604 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
605 error = soreserve(so, udp_sendspace, udp_recvspace);
606 if (error)
607 return error;
608 }
1c79356b
A
609 inp = (struct inpcb *)so->so_pcb;
610 inp->inp_vflag |= INP_IPV6;
55e303ae
A
611 if (ip6_mapped_addr_on)
612 inp->inp_vflag |= INP_IPV4;
1c79356b
A
613 inp->in6p_hops = -1; /* use kernel default */
614 inp->in6p_cksum = -1; /* just to be sure */
9bccf70c
A
615 /*
616 * XXX: ugly!!
617 * IPv4 TTL initialization is necessary for an IPv6 socket as well,
618 * because the socket may be bound to an IPv6 wildcard address,
619 * which may match an IPv4-mapped IPv6 address.
620 */
621 inp->inp_ip_ttl = ip_defttl;
1c79356b
A
622 return 0;
623}
624
625static int
626udp6_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
627{
628 struct inpcb *inp;
91447636 629 int error;
1c79356b
A
630
631 inp = sotoinpcb(so);
632 if (inp == 0)
633 return EINVAL;
634
635 inp->inp_vflag &= ~INP_IPV4;
636 inp->inp_vflag |= INP_IPV6;
9bccf70c 637 if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
1c79356b
A
638 struct sockaddr_in6 *sin6_p;
639
640 sin6_p = (struct sockaddr_in6 *)nam;
641
642 if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr))
643 inp->inp_vflag |= INP_IPV4;
644 else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
645 struct sockaddr_in sin;
646
647 in6_sin6_2_sin(&sin, sin6_p);
648 inp->inp_vflag |= INP_IPV4;
649 inp->inp_vflag &= ~INP_IPV6;
1c79356b 650 error = in_pcbbind(inp, (struct sockaddr *)&sin, p);
1c79356b
A
651 return error;
652 }
653 }
654
1c79356b 655 error = in6_pcbbind(inp, nam, p);
1c79356b
A
656 return error;
657}
658
659static int
660udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
661{
662 struct inpcb *inp;
91447636 663 int error;
1c79356b
A
664
665 inp = sotoinpcb(so);
666 if (inp == 0)
667 return EINVAL;
668
9bccf70c 669 if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
1c79356b
A
670 struct sockaddr_in6 *sin6_p;
671
672 sin6_p = (struct sockaddr_in6 *)nam;
673 if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
674 struct sockaddr_in sin;
675
676 if (inp->inp_faddr.s_addr != INADDR_ANY)
677 return EISCONN;
678 in6_sin6_2_sin(&sin, sin6_p);
1c79356b 679 error = in_pcbconnect(inp, (struct sockaddr *)&sin, p);
1c79356b
A
680 if (error == 0) {
681 inp->inp_vflag |= INP_IPV4;
682 inp->inp_vflag &= ~INP_IPV6;
683 soisconnected(so);
684 }
685 return error;
686 }
687 }
688
689 if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr))
690 return EISCONN;
1c79356b 691 error = in6_pcbconnect(inp, nam, p);
1c79356b 692 if (error == 0) {
55e303ae 693 if (ip6_mapped_addr_on || (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { /* should be non mapped addr */
1c79356b
A
694 inp->inp_vflag &= ~INP_IPV4;
695 inp->inp_vflag |= INP_IPV6;
696 }
697 soisconnected(so);
698 }
699 return error;
700}
701
702static int
703udp6_detach(struct socket *so)
704{
705 struct inpcb *inp;
1c79356b
A
706
707 inp = sotoinpcb(so);
708 if (inp == 0)
709 return EINVAL;
1c79356b 710 in6_pcbdetach(inp);
1c79356b
A
711 return 0;
712}
713
714static int
715udp6_disconnect(struct socket *so)
716{
717 struct inpcb *inp;
1c79356b
A
718
719 inp = sotoinpcb(so);
720 if (inp == 0)
721 return EINVAL;
722
723 if (inp->inp_vflag & INP_IPV4) {
724 struct pr_usrreqs *pru;
725
726 pru = ip_protox[IPPROTO_UDP]->pr_usrreqs;
727 return ((*pru->pru_disconnect)(so));
728 }
729
730 if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr))
731 return ENOTCONN;
732
1c79356b
A
733 in6_pcbdisconnect(inp);
734 inp->in6p_laddr = in6addr_any;
1c79356b
A
735 so->so_state &= ~SS_ISCONNECTED; /* XXX */
736 return 0;
737}
738
739static int
740udp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
741 struct mbuf *control, struct proc *p)
742{
743 struct inpcb *inp;
9bccf70c 744 int error = 0;
1c79356b
A
745
746 inp = sotoinpcb(so);
747 if (inp == 0) {
9bccf70c
A
748 error = EINVAL;
749 goto bad;
750 }
751
752 if (addr) {
753 if (addr->sa_len != sizeof(struct sockaddr_in6)) {
754 error = EINVAL;
755 goto bad;
756 }
757 if (addr->sa_family != AF_INET6) {
758 error = EAFNOSUPPORT;
759 goto bad;
760 }
1c79356b
A
761 }
762
55e303ae 763 if (ip6_mapped_addr_on || (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
1c79356b
A
764 int hasv4addr;
765 struct sockaddr_in6 *sin6 = 0;
766
767 if (addr == 0)
768 hasv4addr = (inp->inp_vflag & INP_IPV4);
769 else {
770 sin6 = (struct sockaddr_in6 *)addr;
771 hasv4addr = IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)
772 ? 1 : 0;
773 }
774 if (hasv4addr) {
775 struct pr_usrreqs *pru;
1c79356b
A
776
777 if (sin6)
778 in6_sin6_2_sin_in_sock(addr);
779 pru = ip_protox[IPPROTO_UDP]->pr_usrreqs;
780 error = ((*pru->pru_send)(so, flags, m, addr, control,
781 p));
782 /* addr will just be freed in sendit(). */
783 return error;
784 }
785 }
786
787 return udp6_output(inp, m, addr, control, p);
9bccf70c
A
788
789 bad:
790 m_freem(m);
791 return(error);
1c79356b
A
792}
793
794struct pr_usrreqs udp6_usrreqs = {
795 udp6_abort, pru_accept_notsupp, udp6_attach, udp6_bind, udp6_connect,
796 pru_connect2_notsupp, in6_control, udp6_detach, udp6_disconnect,
797 pru_listen_notsupp, in6_mapped_peeraddr, pru_rcvd_notsupp,
798 pru_rcvoob_notsupp, udp6_send, pru_sense_null, udp_shutdown,
91447636 799 in6_mapped_sockaddr, sosend, soreceive, pru_sopoll_notsupp
1c79356b 800};