udp6_usrreq.c revision 1.1.2.1 1 /*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 /*
31 * Copyright (c) 1982, 1986, 1989, 1993
32 * The Regents of the University of California. All rights reserved.
33 *
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
36 * are met:
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 * 3. All advertising materials mentioning features or use of this software
43 * must display the following acknowledgement:
44 * This product includes software developed by the University of
45 * California, Berkeley and its contributors.
46 * 4. Neither the name of the University nor the names of its contributors
47 * may be used to endorse or promote products derived from this software
48 * without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * SUCH DAMAGE.
61 *
62 * @(#)udp_var.h 8.1 (Berkeley) 6/10/93
63 */
64
65 #include <sys/param.h>
66 #include <sys/malloc.h>
67 #include <sys/mbuf.h>
68 #include <sys/protosw.h>
69 #include <sys/socket.h>
70 #include <sys/socketvar.h>
71 #include <sys/errno.h>
72 #include <sys/stat.h>
73 #include <sys/systm.h>
74 #ifdef __NetBSD__
75 #include <sys/proc.h>
76 #endif
77
78 #include <net/if.h>
79 #include <net/route.h>
80 #include <net/if_types.h>
81
82 #include <netinet/in.h>
83 #include <netinet/in_var.h>
84 #include <netinet6/in6_systm.h>
85 #include <netinet6/ip6.h>
86 #ifdef MAPPED_ADDR_ENABLED
87 #include <netinet/in_pcb.h>
88 #endif /* MAPPED_ADDR_ENABLED */
89 #include <netinet6/in6_pcb.h>
90 #include <netinet6/ip6_var.h>
91 #include <netinet6/icmp6.h>
92 #include <netinet6/udp6.h>
93 #include <netinet6/udp6_var.h>
94
95 #ifdef IPSEC
96 #include <netinet6/ipsec.h>
97 #endif /*IPSEC*/
98
99 #include "faith.h"
100
101 /*
102 * UDP protocol inplementation.
103 * Per RFC 768, August, 1980.
104 */
105
106 struct in6pcb *udp6_last_in6pcb = &udb6;
107
108 static int in6_mcmatch __P((struct in6pcb *, struct in6_addr *, struct ifnet *));
109 static void udp6_detach __P((struct in6pcb *));
110 static void udp6_notify __P((struct in6pcb *, int));
111
112 void
113 udp6_init()
114 {
115 udb6.in6p_next = udb6.in6p_prev = &udb6;
116 }
117
118 static int
119 in6_mcmatch(in6p, ia6, ifp)
120 struct in6pcb *in6p;
121 register struct in6_addr *ia6;
122 struct ifnet *ifp;
123 {
124 struct ip6_moptions *im6o = in6p->in6p_moptions;
125 struct in6_multi_mship *imm;
126
127 if (im6o == NULL)
128 return 0;
129
130 for (imm = im6o->im6o_memberships.lh_first; imm != NULL;
131 imm = imm->i6mm_chain.le_next) {
132 if ((ifp == NULL ||
133 imm->i6mm_maddr->in6m_ifp == ifp) &&
134 IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
135 ia6))
136 return 1;
137 }
138 return 0;
139 }
140
141 int
142 udp6_input(mp, offp, proto)
143 struct mbuf **mp;
144 int *offp, proto;
145 {
146 struct mbuf *m = *mp;
147 register struct ip6_hdr *ip6;
148 register struct udphdr *uh;
149 register struct in6pcb *in6p;
150 struct mbuf *opts = 0;
151 int off = *offp;
152 int plen, ulen;
153 struct sockaddr_in6 udp_in6;
154
155 #if defined(NFAITH) && 0 < NFAITH
156 if (m->m_pkthdr.rcvif) {
157 if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
158 /* send icmp6 host unreach? */
159 m_freem(m);
160 return IPPROTO_DONE;
161 }
162 }
163 #endif
164 udp6stat.udp6s_ipackets++;
165
166 IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE);
167
168 ip6 = mtod(m, struct ip6_hdr *);
169 plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6);
170 uh = (struct udphdr *)((caddr_t)ip6 + off);
171 ulen = ntohs((u_short)uh->uh_ulen);
172
173 if (plen != ulen) {
174 udp6stat.udp6s_badlen++;
175 goto bad;
176 }
177
178 /*
179 * Checksum extended UDP header and data.
180 */
181 if (uh->uh_sum == 0)
182 udp6stat.udp6s_nosum++;
183 else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) {
184 udp6stat.udp6s_badsum++;
185 goto bad;
186 }
187
188 if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
189 struct in6pcb *last;
190
191 /*
192 * Deliver a multicast datagram to all sockets
193 * for which the local and remote addresses and ports match
194 * those of the incoming datagram. This allows more than
195 * one process to receive multicasts on the same port.
196 * (This really ought to be done for unicast datagrams as
197 * well, but that would cause problems with existing
198 * applications that open both address-specific sockets and
199 * a wildcard socket listening to the same port -- they would
200 * end up receiving duplicates of every unicast datagram.
201 * Those applications open the multiple sockets to overcome an
202 * inadequacy of the UDP socket interface, but for backwards
203 * compatibility we avoid the problem here rather than
204 * fixing the interface. Maybe 4.5BSD will remedy this?)
205 */
206
207 /*
208 * In a case that laddr should be set to the link-local
209 * address (this happens in RIPng), the multicast address
210 * specified in the received packet does not match with
211 * laddr. To cure this situation, the matching is relaxed
212 * if the receiving interface is the same as one specified
213 * in the socket and if the destination multicast address
214 * matches one of the multicast groups specified in the socket.
215 */
216
217 /*
218 * Construct sockaddr format source address.
219 */
220 bzero(&udp_in6, sizeof(udp_in6));
221 udp_in6.sin6_len = sizeof(struct sockaddr_in6);
222 udp_in6.sin6_family = AF_INET6;
223 udp_in6.sin6_port = uh->uh_sport;
224 udp_in6.sin6_addr = ip6->ip6_src;
225 if (IN6_IS_SCOPE_LINKLOCAL(&udp_in6.sin6_addr))
226 udp_in6.sin6_addr.s6_addr16[1] = 0;
227 if (m->m_pkthdr.rcvif) {
228 if (IN6_IS_SCOPE_LINKLOCAL(&udp_in6.sin6_addr)) {
229 udp_in6.sin6_scope_id =
230 m->m_pkthdr.rcvif->if_index;
231 } else
232 udp_in6.sin6_scope_id = 0;
233 } else
234 udp_in6.sin6_scope_id = 0;
235 /*
236 * KAME note: usually we drop udphdr from mbuf here.
237 * We need udphdr for IPsec processing so we do that later.
238 */
239
240 /*
241 * Locate pcb(s) for datagram.
242 * (Algorithm copied from raw_intr().)
243 */
244 last = NULL;
245 for (in6p = udb6.in6p_next;
246 in6p != &udb6;
247 in6p = in6p->in6p_next) {
248 if (in6p->in6p_lport != uh->uh_dport)
249 continue;
250 if (!IN6_IS_ADDR_ANY(&in6p->in6p_laddr)) {
251 if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr,
252 &ip6->ip6_dst) &&
253 !in6_mcmatch(in6p, &ip6->ip6_dst,
254 m->m_pkthdr.rcvif))
255 continue;
256 }
257 if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) {
258 if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr,
259 &ip6->ip6_src) ||
260 in6p->in6p_fport != uh->uh_sport)
261 continue;
262 }
263
264 if (last != NULL) {
265 struct mbuf *n;
266
267 #ifdef IPSEC
268 /*
269 * Check AH/ESP integrity.
270 */
271 if (last != NULL && ipsec6_in_reject(m, last)) {
272 ipsec6stat.in_polvio++;
273 /* do not inject data into pcb */
274 } else
275 #endif /*IPSEC*/
276 if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
277 /*
278 * KAME NOTE: do not
279 * m_copy(m, offset, ...) above.
280 * sbappendaddr() expects M_PKTHDR,
281 * and m_copy() will copy M_PKTHDR
282 * only if offset is 0.
283 */
284 if (last->in6p_flags & IN6P_CONTROLOPTS) {
285 ip6_savecontrol(last, &opts,
286 ip6, n);
287 }
288
289 m_adj(m, off + sizeof(struct udphdr));
290 if (sbappendaddr(&last->in6p_socket->so_rcv,
291 (struct sockaddr *)&udp_in6,
292 n, opts) == 0) {
293 m_freem(n);
294 if (opts)
295 m_freem(opts);
296 udp6stat.udp6s_fullsock++;
297 } else
298 sorwakeup(last->in6p_socket);
299 opts = 0;
300 }
301 }
302 last = in6p;
303 /*
304 * Don't look for additional matches if this one does
305 * not have either the SO_REUSEPORT or SO_REUSEADDR
306 * socket options set. This heuristic avoids searching
307 * through all pcbs in the common case of a non-shared
308 * port. It assumes that an application will never
309 * clear these options after setting them.
310 */
311 if ((last->in6p_socket->so_options &
312 (SO_REUSEPORT|SO_REUSEADDR)) == 0)
313 break;
314 }
315
316 if (last == NULL) {
317 /*
318 * No matching pcb found; discard datagram.
319 * (No need to send an ICMP Port Unreachable
320 * for a broadcast or multicast datgram.)
321 */
322 udp6stat.udp6s_noport++;
323 udp6stat.udp6s_noportmcast++;
324 goto bad;
325 }
326 #ifdef IPSEC
327 /*
328 * Check AH/ESP integrity.
329 */
330 if (last != NULL && ipsec6_in_reject(m, last)) {
331 ipsec6stat.in_polvio++;
332 goto bad;
333 }
334 #endif /*IPSEC*/
335 if (last->in6p_flags & IN6P_CONTROLOPTS)
336 ip6_savecontrol(last, &opts, ip6, m);
337
338 m_adj(m, off + sizeof(struct udphdr));
339 if (sbappendaddr(&last->in6p_socket->so_rcv,
340 (struct sockaddr *)&udp_in6,
341 m, opts) == 0) {
342 udp6stat.udp6s_fullsock++;
343 goto bad;
344 }
345 sorwakeup(last->in6p_socket);
346 return IPPROTO_DONE;
347 }
348 /*
349 * Locate pcb for datagram.
350 */
351 in6p = udp6_last_in6pcb;
352 if (in6p->in6p_lport != uh->uh_dport ||
353 in6p->in6p_fport != uh->uh_sport ||
354 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src) ||
355 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst)) {
356 in6p = in6_pcblookup(&udb6,
357 &ip6->ip6_src, uh->uh_sport,
358 &ip6->ip6_dst, uh->uh_dport,
359 IN6PLOOKUP_WILDCARD);
360 if (in6p)
361 udp6_last_in6pcb = in6p;
362 udp6stat.udp6ps_pcbcachemiss++;
363 }
364 if (in6p == 0) {
365 udp6stat.udp6s_noport++;
366 if (m->m_flags & M_MCAST) {
367 printf("UDP6: M_MCAST is set in a unicast packet.\n");
368 udp6stat.udp6s_noportmcast++;
369 goto bad;
370 }
371 icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0);
372 return IPPROTO_DONE;
373 }
374 #ifdef IPSEC
375 /*
376 * Check AH/ESP integrity.
377 */
378 if (in6p != NULL && ipsec6_in_reject(m, in6p)) {
379 ipsec6stat.in_polvio++;
380 goto bad;
381 }
382 #endif /*IPSEC*/
383
384 /*
385 * Construct sockaddr format source address.
386 * Stuff source address and datagram in user buffer.
387 */
388 bzero(&udp_in6, sizeof(udp_in6));
389 udp_in6.sin6_len = sizeof(struct sockaddr_in6);
390 udp_in6.sin6_family = AF_INET6;
391 udp_in6.sin6_port = uh->uh_sport;
392 udp_in6.sin6_addr = ip6->ip6_src;
393 if (IN6_IS_SCOPE_LINKLOCAL(&udp_in6.sin6_addr))
394 udp_in6.sin6_addr.s6_addr16[1] = 0;
395 if (m->m_pkthdr.rcvif) {
396 if (IN6_IS_SCOPE_LINKLOCAL(&udp_in6.sin6_addr))
397 udp_in6.sin6_scope_id = m->m_pkthdr.rcvif->if_index;
398 else
399 udp_in6.sin6_scope_id = 0;
400 } else
401 udp_in6.sin6_scope_id = 0;
402 if (in6p->in6p_flags & IN6P_CONTROLOPTS)
403 ip6_savecontrol(in6p, &opts, ip6, m);
404
405 m_adj(m, off + sizeof(struct udphdr));
406 if (sbappendaddr(&in6p->in6p_socket->so_rcv,
407 (struct sockaddr *)&udp_in6,
408 m, opts) == 0) {
409 udp6stat.udp6s_fullsock++;
410 goto bad;
411 }
412 sorwakeup(in6p->in6p_socket);
413 return IPPROTO_DONE;
414 bad:
415 if (m)
416 m_freem(m);
417 if (opts)
418 m_freem(opts);
419 return IPPROTO_DONE;
420 }
421
422 /*
423 * Notify a udp user of an asynchronous error;
424 * just wake up so tat he can collect error status.
425 */
426 static void
427 udp6_notify(in6p, errno)
428 register struct in6pcb *in6p;
429 int errno;
430 {
431 in6p->in6p_socket->so_error = errno;
432 sorwakeup(in6p->in6p_socket);
433 sowwakeup(in6p->in6p_socket);
434 }
435
436 void
437 udp6_ctlinput(cmd, sa, ip6, m, off)
438 int cmd;
439 struct sockaddr *sa;
440 register struct ip6_hdr *ip6;
441 struct mbuf *m;
442 int off;
443 {
444 register struct udphdr *uhp;
445 struct udphdr uh;
446
447 #if 0
448 if (cmd == PRC_IFNEWADDR)
449 in6_mrejoin(&udb6);
450 else
451 #endif
452 if (!PRC_IS_REDIRECT(cmd) &&
453 ((unsigned)cmd >= PRC_NCMDS || inet6ctlerrmap[cmd] == 0))
454 return;
455 if (ip6) {
456 /*
457 * XXX: We assume that when IPV6 is non NULL,
458 * M and OFF are valid.
459 */
460 if (m->m_len < off + sizeof(uh)) {
461 /*
462 * this should be rare case,
463 * so we compromise on this copy...
464 */
465 m_copydata(m, off, sizeof(uh), (caddr_t)&uh);
466 uhp = &uh;
467 } else
468 uhp = (struct udphdr *)(mtod(m, caddr_t) + off);
469 (void) in6_pcbnotify(&udb6, sa, uhp->uh_dport, &ip6->ip6_src,
470 uhp->uh_sport, cmd, udp6_notify);
471 } else {
472 (void) in6_pcbnotify(&udb6, sa, 0, &zeroin6_addr, 0, cmd,
473 udp6_notify);
474 }
475 }
476
477 int
478 udp6_output(in6p, m, addr6, control)
479 register struct in6pcb *in6p;
480 register struct mbuf *m;
481 struct mbuf *addr6, *control;
482 {
483 register int ulen = m->m_pkthdr.len;
484 int plen = sizeof(struct udphdr) + ulen;
485 struct ip6_hdr *ip6;
486 struct udphdr *udp6;
487 struct in6_addr laddr6;
488 int s = 0, error = 0;
489 struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts;
490 int priv = 0;
491 struct proc *p = curproc; /* XXX */
492
493 if (p && !suser(p->p_ucred, &p->p_acflag))
494 priv = 1;
495 if (control) {
496 if ((error = ip6_setpktoptions(control, &opt, priv)) != 0)
497 goto release;
498 in6p->in6p_outputopts = &opt;
499 }
500
501 if (addr6) {
502 laddr6 = in6p->in6p_laddr;
503 if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) {
504 error = EISCONN;
505 goto release;
506 }
507 /*
508 * Must block input while temporarily connected.
509 */
510 s = splnet();
511 error = in6_pcbconnect(in6p, addr6);
512 if (error) {
513 splx(s);
514 goto release;
515 }
516 } else {
517 if (IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) {
518 error = ENOTCONN;
519 goto release;
520 }
521 }
522 /*
523 * Calculate data length and get a mbuf
524 * for UDP and IP6 headers.
525 */
526 M_PREPEND(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr), M_DONTWAIT);
527 if (m == 0) {
528 error = ENOBUFS;
529 goto release;
530 }
531
532 /*
533 * Stuff checksum and output datagram.
534 */
535 ip6 = mtod(m, struct ip6_hdr *);
536 ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
537 ip6->ip6_vfc = IPV6_VERSION;
538 #if 0 /* ip6_plen will be filled in ip6_output. */
539 ip6->ip6_plen = htons((u_short)plen);
540 #endif
541 ip6->ip6_nxt = IPPROTO_UDP;
542 ip6->ip6_hlim = in6p->in6p_ip6.ip6_hlim; /* XXX */
543 ip6->ip6_src = in6p->in6p_laddr;
544 ip6->ip6_dst = in6p->in6p_faddr;
545
546 udp6 = (struct udphdr *)(ip6 + 1);
547 udp6->uh_sport = in6p->in6p_lport;
548 udp6->uh_dport = in6p->in6p_fport;
549 udp6->uh_ulen = htons((u_short)plen);
550 udp6->uh_sum = 0;
551
552 if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP,
553 sizeof(struct ip6_hdr), plen)) == 0) {
554 udp6->uh_sum = 0xffff;
555 }
556
557 udp6stat.udp6s_opackets++;
558
559 #ifdef IPSEC
560 m->m_pkthdr.rcvif = (struct ifnet *)in6p->in6p_socket;
561 #endif /*IPSEC*/
562 error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route,
563 0, in6p->in6p_moptions);
564
565 if (addr6) {
566 in6_pcbdisconnect(in6p);
567 in6p->in6p_laddr = laddr6;
568 splx(s);
569 }
570 goto releaseopt;
571
572 release:
573 m_freem(m);
574
575 releaseopt:
576 if (control) {
577 in6p->in6p_outputopts = stickyopt;
578 m_freem(control);
579 }
580 return(error);
581 }
582
583 #ifdef MAPPED_ADDR_ENABLED
584 void udp_detach __P((struct inpcb *inp));
585 int udp_usrreq __P((struct socket *so, int req, struct mbuf *m,
586 struct mbuf *addr, struct mbuf *control));
587 int udp_output __P((struct inpcb *, struct mbuf *, struct mbuf *,
588 struct mbuf *));
589
590 /*
591 * Do V4 mapped addr related binding work.
592 * Return 1 when V6 bind is not necessary.
593 * Return 0 when V6 bind may be necessary.
594 */
595 static int
596 udp6_mapped_bind(struct socket *so, struct mbuf *addr6, int *error_p)
597 {
598 struct inpcb *inp = sotoinpcb(so);
599 struct sockaddr_in6 *sin6_p;
600 int s, unspec;
601
602 sin6_p = mtod(addr6, struct sockaddr_in6 *);
603 unspec = (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) ? 1 : 0;
604 if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr) || unspec) {
605
606 /* Attach v4 if notyet */
607 if (inp == 0) {
608 *error_p = udp_usrreq(so, PRU_ATTACH, 0, 0, 0);
609 if (*error_p)
610 return 1;
611 inp = sotoinpcb(so);
612 }
613 in6_sin6_2_sin_in_m(addr6);
614 s = splnet();
615 *error_p = in_pcbbind(inp, addr6);
616 splx(s);
617 if (*error_p)
618 return 1;
619 in6_sin_2_v4mapsin6_in_m(addr6);
620 if (unspec) {
621 sin6_p = mtod(addr6, struct sockaddr_in6 *);
622 sin6_p->sin6_addr.s6_addr32[2] = 0;
623 return 0;
624 } else
625 return 1;
626 }
627 return 0;
628 }
629
630 /*
631 * Do V4 mapped addr related connect work.
632 * Return 1 when V6 connect is not necessary.
633 * Return 0 when V6 connect is necessary.
634 */
635 static int
636 udp6_mapped_connect(struct socket *so, struct mbuf *addr6, int *error_p)
637 {
638 struct inpcb *inp = sotoinpcb(so);
639 struct sockaddr_in6 *sin6_p;
640 int s;
641
642 sin6_p = mtod(addr6, struct sockaddr_in6 *);
643 if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
644
645 /* Attach v4 if notyet */
646 if (inp == 0) {
647 *error_p = udp_usrreq(so, PRU_ATTACH, 0, 0, 0);
648 if (*error_p)
649 return 1;
650 inp = sotoinpcb(so);
651 }
652 if (inp->inp_faddr.s_addr != INADDR_ANY) {
653 *error_p = EISCONN;
654 return 1;
655 }
656 in6_sin6_2_sin_in_m(addr6);
657 s = splnet();
658 *error_p = in_pcbconnect(inp, addr6);
659 splx(s);
660 if (*error_p)
661 return 1;
662 else
663 soisconnected(so);
664 in6_sin_2_v4mapsin6_in_m(addr6);
665 return 1;
666 }
667 return 0;
668 }
669
670 /*
671 * Do V4 mapped addr related disconnect work.
672 * Return 1 when v4 is connected.
673 * Return 0 when V4 is not connected.
674 */
675 static int
676 udp6_mapped_disconnect(struct socket *so, struct mbuf *addr6, int *error_p)
677 {
678 struct inpcb *inp = sotoinpcb(so);
679 int s;
680
681 if (inp) {
682 if (inp->inp_faddr.s_addr == INADDR_ANY)
683 return 0;
684 else {
685 s = splnet();
686 in_pcbdisconnect(inp);
687 inp->inp_laddr.s_addr = INADDR_ANY;
688 splx(s);
689 return 1;
690 }
691 } else
692 return 0;
693 }
694
695 /*
696 * Do V4 mapped addr related sending work.
697 * Return 2 when v4 attach is failed.
698 * Return 1 when v6 send is not necessary.
699 * Return 0 when v6 send is necessary.
700 */
701 static int
702 udp6_mapped_send(struct socket *so,
703 struct mbuf *m,
704 struct mbuf *addr6,
705 struct mbuf *control,
706 int *error_p)
707 {
708 struct inpcb *inp = sotoinpcb(so);
709 struct in6pcb *in6p = sotoin6pcb(so);
710 struct sockaddr_in6 *sin6_p = 0;
711 int hasv4addr;
712
713 if (addr6 == 0) {
714 if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr))
715 hasv4addr = 0;
716 else
717 hasv4addr = (inp &&
718 inp->inp_faddr.s_addr != INADDR_ANY) ? 1 : 0;
719 } else {
720 sin6_p = mtod(addr6, struct sockaddr_in6 *);
721 hasv4addr = IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr) ? 1 : 0;
722 }
723 if (hasv4addr) {
724
725 /* Attach v4 if notyet */
726 if (inp == 0) {
727 *error_p = udp_usrreq(so, PRU_ATTACH, 0, 0, 0);
728 if (*error_p)
729 return 2;
730 inp = sotoinpcb(so);
731 }
732 if (sin6_p)
733 in6_sin6_2_sin_in_m(addr6);
734 *error_p = udp_output(inp, m, addr6, control);
735 if (sin6_p)
736 in6_sin_2_v4mapsin6_in_m(addr6);
737 return 1;
738 }
739 return 0;
740 }
741
742 /*
743 * Do V4 mapped addr related get sockaddr work.
744 * Return 1 when v6 get sockaddr is not necessary.
745 * Return 0 when v6 get sockaddr is necessary.
746 */
747 int
748 udp6_mapped_sockaddr(struct socket *so, struct mbuf *addr6, int *error_p)
749 {
750 struct inpcb *inp = sotoinpcb(so);
751 struct in6pcb *in6p = sotoin6pcb(so);
752 int hasv4addr;
753
754 if (inp == 0)
755 return 0;
756 hasv4addr = (inp->inp_laddr.s_addr == INADDR_ANY) ? 0 : 1;
757 if (hasv4addr && IN6_IS_ADDR_ANY(&in6p->in6p_laddr)) {
758
759 in_setsockaddr(inp, addr6);
760 in6_sin_2_v4mapsin6_in_m(addr6);
761 return 1;
762 }
763 return 0;
764 }
765
766 /*
767 * Do V4 mapped addr related get peeraddr work.
768 * Return 1 when v6 get peeraddr is not necessary.
769 * Return 0 when v6 get peeraddr is necessary.
770 */
771 int
772 udp6_mapped_peeraddr(struct socket *so, struct mbuf *addr6, int *error_p)
773 {
774 struct inpcb *inp = sotoinpcb(so);
775 struct in6pcb *in6p = sotoin6pcb(so);
776 int hasv4addr;
777
778 if (inp == 0)
779 return 0;
780 hasv4addr = (inp->inp_faddr.s_addr == INADDR_ANY) ? 0 : 1;
781 if (hasv4addr && IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) {
782
783 in_setpeeraddr(inp, addr6);
784 in6_sin_2_v4mapsin6_in_m(addr6);
785 return 1;
786 }
787 return 0;
788 }
789 #endif /* MAPPED_ADDR_ENABLED */
790
791 extern int udp6_sendspace;
792 extern int udp6_recvspace;
793
794 int
795 udp6_usrreq(so, req, m, addr6, control, p)
796 struct socket *so;
797 int req;
798 struct mbuf *m, *addr6, *control;
799 struct proc *p;
800 {
801 struct in6pcb *in6p = sotoin6pcb(so);
802 int error = 0;
803 int s;
804 #ifdef MAPPED_ADDR_ENABLED
805 struct inpcb *inp = sotoinpcb(so);
806 int hasv4addr;
807 #endif /* MAPPED_ADDR_ENABLED */
808
809 /*
810 * MAPPED_ADDR implementation info:
811 * Mapped addr support for PRU_CONTROL is not necessary.
812 * Because typical user of PRU_CONTROL is such as ifconfig,
813 * and they don't associate any addr to their socket. Then
814 * socket family is only hint about the PRU_CONTROL'ed address
815 * family, especially when getting addrs from kernel.
816 * So AF_INET socket need to be used to control AF_INET addrs,
817 * and AF_INET6 socket for AF_INET6 addrs.
818 */
819 if (req == PRU_CONTROL)
820 return(in6_control(so, (u_long)m, (caddr_t)addr6,
821 (struct ifnet *)control, p));
822
823 if (in6p == NULL && req != PRU_ATTACH) {
824 error = EINVAL;
825 goto release;
826 }
827
828 switch (req) {
829 case PRU_ATTACH:
830 /*
831 * MAPPED_ADDR implementation spec:
832 * Always attach for IPv6,
833 * and only when necessary for IPv4.
834 */
835 if (in6p != NULL
836 #ifdef MAPPED_ADDR_ENABLED
837 /*
838 * MAPPED_ADDR implementation spec:
839 * When PRU_ATTACH, each of in6p and inp must be NULL.
840 */
841 || inp != NULL
842 #endif /* MAPPED_ADDR_ENABLED */
843 ) {
844 error = EINVAL;
845 break;
846 }
847 s = splnet();
848 error = in6_pcballoc(so, &udb6);
849 splx(s);
850 if (error)
851 break;
852 error = soreserve(so, udp6_sendspace, udp6_recvspace);
853 if (error)
854 break;
855 in6p = sotoin6pcb(so);
856 in6p->in6p_ip6.ip6_hlim = ip6_defhlim;
857 in6p->in6p_cksum = -1; /* just to be sure */
858 #ifdef IPSEC
859 error = ipsec_init_policy(&in6p->in6p_sp);
860 #endif /*IPSEC*/
861 break;
862
863 case PRU_DETACH:
864 udp6_detach(in6p);
865 #ifdef MAPPED_ADDR_ENABLED
866 if (inp)
867 udp_detach(inp);
868 #endif /* MAPPED_ADDR_ENABLED */
869 break;
870
871 case PRU_BIND:
872 #ifdef MAPPED_ADDR_ENABLED
873 if (ip6_mapped_addr_on)
874 if (udp6_mapped_bind(so, addr6, &error))
875 break;
876 #endif /* MAPPED_ADDR_ENABLED */
877 s = splnet();
878 error = in6_pcbbind(in6p, addr6);
879 splx(s);
880 break;
881
882 case PRU_LISTEN:
883 error = EOPNOTSUPP;
884 break;
885
886 case PRU_CONNECT:
887 #ifdef MAPPED_ADDR_ENABLED
888 if (ip6_mapped_addr_on)
889 if (udp6_mapped_connect(so, addr6, &error))
890 break;
891 #endif /* MAPPED_ADDR_ENABLED */
892 if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) {
893 error = EISCONN;
894 break;
895 }
896 s = splnet();
897 error = in6_pcbconnect(in6p, addr6);
898 if (ip6_auto_flowlabel) {
899 in6p->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK;
900 in6p->in6p_flowinfo |=
901 (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK);
902 }
903 splx(s);
904 if (error == 0)
905 soisconnected(so);
906 break;
907
908 case PRU_CONNECT2:
909 error = EOPNOTSUPP;
910 break;
911
912 case PRU_ACCEPT:
913 error = EOPNOTSUPP;
914 break;
915
916 case PRU_DISCONNECT:
917 #ifdef MAPPED_ADDR_ENABLED
918 /*
919 * Should only one of IPv4 or IPv6 is connected at most,
920 * but we check either and (if connected)disconnect them.
921 */
922 hasv4addr = udp6_mapped_disconnect(so, addr6, &error);
923 #endif /* MAPPED_ADDR_ENABLED */
924 if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
925 #ifdef MAPPED_ADDR_ENABLED
926 if (hasv4addr == 0)
927 error = ENOTCONN;
928 else
929 so->so_state &= ~SS_ISCONNECTED; /* XXX */
930 #else /* MAPPED_ADDR_ENABLED */
931 error = ENOTCONN;
932 #endif /* MAPPED_ADDR_ENABLED */
933 break;
934 }
935 s = splnet();
936 in6_pcbdisconnect(in6p);
937 bzero((caddr_t)&in6p->in6p_laddr, sizeof(in6p->in6p_laddr));
938 splx(s);
939 so->so_state &= ~SS_ISCONNECTED; /* XXX */
940 break;
941
942 case PRU_SHUTDOWN:
943 socantsendmore(so);
944 break;
945
946 case PRU_SEND:
947 #ifdef MAPPED_ADDR_ENABLED
948 if (ip6_mapped_addr_on) {
949 int ret_val;
950
951 ret_val = udp6_mapped_send(so, m, addr6, control,
952 &error);
953 if (ret_val != 0) {
954 if (ret_val == 1)
955 return (error);
956 else /* ret_val shoud be 2. v4 attach failed */
957 break;
958 }
959 /* else proceed to udp6_output() */
960 }
961 #endif /* MAPPED_ADDR_ENABLED */
962 return(udp6_output(in6p, m, addr6, control));
963
964 case PRU_ABORT:
965 soisdisconnected(so);
966 #ifdef MAPPED_ADDR_ENABLED
967 if (inp)
968 udp_detach(inp);
969 #endif /* MAPPED_ADDR_ENABLED */
970 udp6_detach(in6p);
971 break;
972
973 case PRU_SOCKADDR:
974 #ifdef MAPPED_ADDR_ENABLED
975 if (ip6_mapped_addr_on)
976 if (udp6_mapped_sockaddr(so, addr6, &error))
977 break;
978 #endif /* MAPPED_ADDR_ENABLED */
979 in6_setsockaddr(in6p, addr6);
980 break;
981
982 case PRU_PEERADDR:
983 #ifdef MAPPED_ADDR_ENABLED
984 if (ip6_mapped_addr_on)
985 if (udp6_mapped_peeraddr(so, addr6, &error))
986 break;
987 #endif /* MAPPED_ADDR_ENABLED */
988 in6_setpeeraddr(in6p, addr6);
989 break;
990
991 case PRU_SENSE:
992 /*
993 * stat: don't bother with a blocksize
994 */
995 return(0);
996
997 case PRU_SENDOOB:
998 case PRU_FASTTIMO:
999 case PRU_SLOWTIMO:
1000 case PRU_PROTORCV:
1001 case PRU_PROTOSEND:
1002 error = EOPNOTSUPP;
1003 break;
1004
1005 case PRU_RCVD:
1006 case PRU_RCVOOB:
1007 return(EOPNOTSUPP); /* do not free mbuf's */
1008
1009 default:
1010 panic("udp6_usrreq");
1011 }
1012
1013 release:
1014 if (control) {
1015 printf("udp control data unexpectedly retained\n");
1016 m_freem(control);
1017 }
1018 if (m)
1019 m_freem(m);
1020 return(error);
1021 }
1022
1023 static void
1024 udp6_detach(in6p)
1025 struct in6pcb *in6p;
1026 {
1027 int s = splnet();
1028
1029 if (in6p == udp6_last_in6pcb)
1030 udp6_last_in6pcb = &udb6;
1031 in6_pcbdetach(in6p);
1032 splx(s);
1033 }
1034
1035 #ifdef __bsdi__
1036 int *udp6_sysvars[] = UDP6CTL_VARS;
1037
1038 int
1039 udp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
1040 int *name;
1041 u_int namelen;
1042 void *oldp;
1043 size_t *oldlenp;
1044 void *newp;
1045 size_t newlen;
1046 {
1047 if (name[0] >= UDP6CTL_MAXID)
1048 return (EOPNOTSUPP);
1049 switch (name[0]) {
1050 case UDP6CTL_STATS:
1051 return sysctl_rdtrunc(oldp, oldlenp, newp, &udp6stat,
1052 sizeof(udp6stat));
1053
1054 default:
1055 return (sysctl_int_arr(udp6_sysvars, name, namelen,
1056 oldp, oldlenp, newp, newlen));
1057 }
1058 }
1059 #endif /*__bsdi__*/
1060
1061 #ifdef __NetBSD__
1062 #include <vm/vm.h>
1063 #include <sys/sysctl.h>
1064
1065 int
1066 udp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
1067 int *name;
1068 u_int namelen;
1069 void *oldp;
1070 size_t *oldlenp;
1071 void *newp;
1072 size_t newlen;
1073 {
1074 /* All sysctl names at this level are terminal. */
1075 if (namelen != 1)
1076 return ENOTDIR;
1077
1078 switch (name[0]) {
1079
1080 case UDP6CTL_SENDMAX:
1081 return sysctl_int(oldp, oldlenp, newp, newlen,
1082 &udp6_sendspace);
1083 case UDP6CTL_RECVSPACE:
1084 return sysctl_int(oldp, oldlenp, newp, newlen,
1085 &udp6_recvspace);
1086 default:
1087 return ENOPROTOOPT;
1088 }
1089 /* NOTREACHED */
1090 }
1091 #endif
1092