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