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