]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/udp6_usrreq.c
xnu-1504.15.3.tar.gz
[apple/xnu.git] / bsd / netinet6 / udp6_usrreq.c
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 $ */
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 */
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>
81 #include <sys/kauth.h>
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>
104 #include <netinet6/ipsec6.h>
105 extern int ipsec_bypass;
106 #endif /*IPSEC*/
107 extern lck_mtx_t *nd6_mutex;
108
109 /*
110 * UDP protocol inplementation.
111 * Per RFC 768, August, 1980.
112 */
113
114 extern struct protosw inetsw[];
115 static int in6_mcmatch(struct inpcb *, struct in6_addr *, struct ifnet *);
116 static int udp6_detach(struct socket *so);
117 static void udp6_append(struct inpcb *, struct ip6_hdr *,
118 struct sockaddr_in6 *, struct mbuf *, int);
119
120 extern void ipfwsyslog( int level, const char *format,...);
121 extern int fw_verbose;
122
123 #if IPFIREWALL
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 }
130 #else
131 #define log_in_vain_log( a ) { log a; }
132 #endif
133
134 static int
135 in6_mcmatch(
136 struct inpcb *in6p,
137 register struct in6_addr *ia6,
138 struct ifnet *ifp)
139 {
140 struct ip6_moptions *im6o = in6p->in6p_moptions;
141 struct in6_multi_mship *imm;
142
143 if (im6o == NULL)
144 return 0;
145
146 lck_mtx_lock(nd6_mutex);
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,
152 ia6)) {
153 lck_mtx_unlock(nd6_mutex);
154 return 1;
155 }
156 }
157 lck_mtx_unlock(nd6_mutex);
158 return 0;
159 }
160
161 /*
162 * subroutine of udp6_input(), mainly for source code readability.
163 */
164 static void
165 udp6_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
188 int
189 udp6_input(
190 struct mbuf **mp,
191 int *offp)
192 {
193 struct mbuf *m = *mp;
194 register struct ip6_hdr *ip6;
195 register struct udphdr *uh;
196 register struct inpcb *in6p;
197 struct mbuf *opts = NULL;
198 int off = *offp;
199 int plen, ulen;
200 struct sockaddr_in6 udp_in6;
201 struct inpcbinfo *pcbinfo = &udbinfo;
202
203 IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), return IPPROTO_DONE);
204
205 ip6 = mtod(m, struct ip6_hdr *);
206
207 #if defined(NFAITH) && 0 < NFAITH
208 if (faithprefix(&ip6->ip6_dst)) {
209 /* XXX send icmp6 host/port unreach? */
210 m_freem(m);
211 return IPPROTO_DONE;
212 }
213 #endif
214
215 udpstat.udps_ipackets++;
216
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 */
229 #ifndef __APPLE__
230 if (uh->uh_sum == 0)
231 udpstat.udps_nosum++;
232 #endif
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)) {
239 int reuse_sock = 0, mcast_delivered = 0;
240 struct mbuf *n = NULL;
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 */
282 lck_rw_lock_shared(pcbinfo->mtx);
283
284 LIST_FOREACH(in6p, &udb, inp_list) {
285
286 if ((in6p->inp_vflag & INP_IPV6) == 0)
287 continue;
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);
300 continue;
301 }
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,
306 m->m_pkthdr.rcvif)) {
307 udp_unlock(in6p->in6p_socket, 1, 0);
308 continue;
309 }
310 }
311 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
312 if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr,
313 &ip6->ip6_src) ||
314 in6p->in6p_fport != uh->uh_sport) {
315 udp_unlock(in6p->in6p_socket, 1, 0);
316 continue;
317 }
318 }
319
320 reuse_sock = in6p->inp_socket->so_options &
321 (SO_REUSEPORT | SO_REUSEADDR);
322
323 {
324 #if IPSEC
325 int skipit = 0;
326 /* Check AH/ESP integrity. */
327 if (ipsec_bypass == 0) {
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 }
333 }
334 if (skipit == 0)
335 #endif /*IPSEC*/
336 {
337 /*
338 * KAME NOTE: do not
339 * m_copy(m, offset, ...) below.
340 * sbappendaddr() expects M_PKTHDR,
341 * and m_copy() will copy M_PKTHDR
342 * only if offset is 0.
343 */
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++;
349 }
350 udp_unlock(in6p->in6p_socket, 1, 0);
351 }
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 */
360 if (reuse_sock == 0 || ((m = n) == NULL))
361 break;
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);
367 }
368 lck_rw_done(pcbinfo->mtx);
369
370 if (mcast_delivered == 0) {
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++;
377 #ifndef __APPLE__
378 udpstat.udps_noportmcast++;
379 #endif
380 goto bad;
381 }
382
383 if (reuse_sock != 0) /* free the extra copy of mbuf */
384 m_freem(m);
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
397 strlcpy(buf, ip6_sprintf(&ip6->ip6_dst), sizeof(buf));
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)));
409 }
410 udpstat.udps_noport++;
411 if (m->m_flags & M_MCAST) {
412 printf("UDP6: M_MCAST is set in a unicast packet.\n");
413 #ifndef __APPLE__
414 udpstat.udps_noportmcast++;
415 #endif
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 */
425 if (ipsec_bypass == 0) {
426 if (ipsec6_in_reject_so(m, in6p->in6p_socket)) {
427 IPSEC_STAT_INCREMENT(ipsec6stat.in_polvio);
428 in_pcb_checkstate(in6p, WNT_RELEASE, 0);
429 goto bad;
430 }
431 }
432 #endif /*IPSEC*/
433
434 /*
435 * Construct sockaddr format source address.
436 * Stuff source address and datagram in user buffer.
437 */
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
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)
449 ip6_savecontrol(in6p, &opts, ip6, m);
450 m_adj(m, off + sizeof(struct udphdr));
451 if (sbappendaddr(&in6p->in6p_socket->so_rcv,
452 (struct sockaddr *)&udp_in6,
453 m, opts, NULL) == 0) {
454 m = NULL;
455 opts = NULL;
456 udpstat.udps_fullsock++;
457 udp_unlock(in6p->in6p_socket, 1, 0);
458 goto bad;
459 }
460 sorwakeup(in6p->in6p_socket);
461 udp_unlock(in6p->in6p_socket, 1, 0);
462 return IPPROTO_DONE;
463 bad:
464 if (m)
465 m_freem(m);
466 if (opts)
467 m_freem(opts);
468 return IPPROTO_DONE;
469 }
470
471 void
472 udp6_ctlinput(
473 int cmd,
474 struct sockaddr *sa,
475 void *d)
476 {
477 struct udphdr uh;
478 struct ip6_hdr *ip6;
479 struct mbuf *m;
480 int off = 0;
481 struct ip6ctlparam *ip6cp = NULL;
482 const struct sockaddr_in6 *sa6_src = NULL;
483 void (*notify)(struct inpcb *, int) = udp_notify;
484 struct udp_portonly {
485 u_int16_t uh_sport;
486 u_int16_t uh_dport;
487 } *uhp;
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) {
504 ip6cp = (struct ip6ctlparam *)d;
505 m = ip6cp->ip6c_m;
506 ip6 = ip6cp->ip6c_ip6;
507 off = ip6cp->ip6c_off;
508 sa6_src = ip6cp->ip6c_src;
509 } else {
510 m = NULL;
511 ip6 = NULL;
512 sa6_src = &sa6_any;
513 }
514
515 if (ip6) {
516 /*
517 * XXX: We assume that when IPV6 is non NULL,
518 * M and OFF are valid.
519 */
520
521 /* check if we can safely examine src and dst ports */
522 if (m->m_pkthdr.len < off + sizeof(*uhp))
523 return;
524
525 bzero(&uh, sizeof(uh));
526 m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh);
527
528 (void) in6_pcbnotify(&udbinfo, sa, uh.uh_dport,
529 (struct sockaddr*)ip6cp->ip6c_src,
530 uh.uh_sport, cmd, notify);
531 } else
532 (void) in6_pcbnotify(&udbinfo, sa, 0, (struct sockaddr *)&sa6_src,
533 0, cmd, notify);
534 }
535
536 #ifndef __APPLE__
537 static int
538 udp6_getcred SYSCTL_HANDLER_ARGS
539 {
540 struct sockaddr_in6 addrs[2];
541 struct inpcb *inp;
542 int error, s;
543
544 error = proc_suser(req->p);
545 if (error)
546 return (error);
547
548 if (req->newlen != sizeof(addrs))
549 return (EINVAL);
550 if (req->oldlen != sizeof(*(kauth_cred_t)0))
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,
565 sizeof(*(kauth_cred_t)0));
566
567 out:
568 splx(s);
569 return (error);
570 }
571
572 SYSCTL_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
576
577 static int
578 udp6_abort(struct socket *so)
579 {
580 struct inpcb *inp;
581
582 inp = sotoinpcb(so);
583 if (inp == 0)
584 return EINVAL; /* ??? possible? panic instead? */
585 soisdisconnected(so);
586 in6_pcbdetach(inp);
587 return 0;
588 }
589
590 static int
591 udp6_attach(struct socket *so, __unused int proto, struct proc *p)
592 {
593 struct inpcb *inp;
594 int error;
595
596 inp = sotoinpcb(so);
597 if (inp != 0)
598 return EINVAL;
599
600 error = in_pcballoc(so, &udbinfo, p);
601 if (error)
602 return error;
603
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 }
609 inp = (struct inpcb *)so->so_pcb;
610 inp->inp_vflag |= INP_IPV6;
611 if (ip6_mapped_addr_on)
612 inp->inp_vflag |= INP_IPV4;
613 inp->in6p_hops = -1; /* use kernel default */
614 inp->in6p_cksum = -1; /* just to be sure */
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;
622 return 0;
623 }
624
625 static int
626 udp6_bind(struct socket *so, struct sockaddr *nam, struct proc *p)
627 {
628 struct inpcb *inp;
629 int error;
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;
637 if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
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;
650 error = in_pcbbind(inp, (struct sockaddr *)&sin, p);
651 return error;
652 }
653 }
654
655 error = in6_pcbbind(inp, nam, p);
656 return error;
657 }
658
659 static int
660 udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p)
661 {
662 struct inpcb *inp;
663 int error;
664
665 inp = sotoinpcb(so);
666 if (inp == 0)
667 return EINVAL;
668
669 if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
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);
679 error = in_pcbconnect(inp, (struct sockaddr *)&sin, p);
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;
691 error = in6_pcbconnect(inp, nam, p);
692 if (error == 0) {
693 if (ip6_mapped_addr_on || (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { /* should be non mapped addr */
694 inp->inp_vflag &= ~INP_IPV4;
695 inp->inp_vflag |= INP_IPV6;
696 }
697 soisconnected(so);
698 }
699 return error;
700 }
701
702 static int
703 udp6_detach(struct socket *so)
704 {
705 struct inpcb *inp;
706
707 inp = sotoinpcb(so);
708 if (inp == 0)
709 return EINVAL;
710 in6_pcbdetach(inp);
711 return 0;
712 }
713
714 static int
715 udp6_disconnect(struct socket *so)
716 {
717 struct inpcb *inp;
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
733 in6_pcbdisconnect(inp);
734 inp->in6p_laddr = in6addr_any;
735 so->so_state &= ~SS_ISCONNECTED; /* XXX */
736 return 0;
737 }
738
739 static int
740 udp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
741 struct mbuf *control, struct proc *p)
742 {
743 struct inpcb *inp;
744 int error = 0;
745
746 inp = sotoinpcb(so);
747 if (inp == 0) {
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 }
761 }
762
763 if (ip6_mapped_addr_on || (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
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;
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);
788
789 bad:
790 m_freem(m);
791 return(error);
792 }
793
794 struct 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,
799 in6_mapped_sockaddr, sosend, soreceive, pru_sopoll_notsupp
800 };