udp6_usrreq.c revision 1.13 1 /* $NetBSD: udp6_usrreq.c,v 1.13 1999/09/13 12:15:56 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(n, 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 (sa->sa_family != AF_INET6 ||
457 sa->sa_len != sizeof(struct sockaddr_in6))
458 return;
459 #if 0
460 if (cmd == PRC_IFNEWADDR)
461 in6_mrejoin(&udb6);
462 else
463 #endif
464 if (!PRC_IS_REDIRECT(cmd) &&
465 ((unsigned)cmd >= PRC_NCMDS || inet6ctlerrmap[cmd] == 0))
466 return;
467
468 /* translate addresses into internal form */
469 sa6 = *(struct sockaddr_in6 *)sa;
470 if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr))
471 sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
472
473 if (ip6) {
474 /*
475 * XXX: We assume that when IPV6 is non NULL,
476 * M and OFF are valid.
477 */
478 struct in6_addr s;
479
480 /* translate addresses into internal form */
481 memcpy(&s, &ip6->ip6_src, sizeof(s));
482 if (IN6_IS_ADDR_LINKLOCAL(&s))
483 s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
484
485 if (m->m_len < off + sizeof(uh)) {
486 /*
487 * this should be rare case,
488 * so we compromise on this copy...
489 */
490 m_copydata(m, off, sizeof(uh), (caddr_t)&uh);
491 uhp = &uh;
492 } else
493 uhp = (struct udphdr *)(mtod(m, caddr_t) + off);
494 (void) in6_pcbnotify(&udb6, (struct sockaddr *)&sa6,
495 uhp->uh_dport, &s,
496 uhp->uh_sport, cmd, udp6_notify);
497 } else {
498 (void) in6_pcbnotify(&udb6, (struct sockaddr *)&sa6, 0,
499 &zeroin6_addr, 0, cmd, udp6_notify);
500 }
501 }
502
503 int
504 udp6_output(in6p, m, addr6, control)
505 register struct in6pcb *in6p;
506 register struct mbuf *m;
507 struct mbuf *addr6, *control;
508 {
509 register int ulen = m->m_pkthdr.len;
510 int plen = sizeof(struct udphdr) + ulen;
511 struct ip6_hdr *ip6;
512 struct udphdr *udp6;
513 struct in6_addr laddr6;
514 int s = 0, error = 0;
515 struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts;
516 int priv = 0;
517 struct proc *p = curproc; /* XXX */
518
519 if (p && !suser(p->p_ucred, &p->p_acflag))
520 priv = 1;
521 if (control) {
522 if ((error = ip6_setpktoptions(control, &opt, priv)) != 0)
523 goto release;
524 in6p->in6p_outputopts = &opt;
525 }
526
527 if (addr6) {
528 laddr6 = in6p->in6p_laddr;
529 if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) {
530 error = EISCONN;
531 goto release;
532 }
533 /*
534 * Must block input while temporarily connected.
535 */
536 s = splsoftnet();
537 error = in6_pcbconnect(in6p, addr6);
538 if (error) {
539 splx(s);
540 goto release;
541 }
542 } else {
543 if (IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) {
544 error = ENOTCONN;
545 goto release;
546 }
547 }
548 /*
549 * Calculate data length and get a mbuf
550 * for UDP and IP6 headers.
551 */
552 M_PREPEND(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr), M_DONTWAIT);
553 if (m == 0) {
554 error = ENOBUFS;
555 if (addr6)
556 splx(s);
557 goto release;
558 }
559
560 /*
561 * Stuff checksum and output datagram.
562 */
563 ip6 = mtod(m, struct ip6_hdr *);
564 ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
565 ip6->ip6_vfc = IPV6_VERSION;
566 #if 0 /* ip6_plen will be filled in ip6_output. */
567 ip6->ip6_plen = htons((u_short)plen);
568 #endif
569 ip6->ip6_nxt = IPPROTO_UDP;
570 ip6->ip6_hlim = in6p->in6p_ip6.ip6_hlim; /* XXX */
571 ip6->ip6_src = in6p->in6p_laddr;
572 ip6->ip6_dst = in6p->in6p_faddr;
573
574 udp6 = (struct udphdr *)(ip6 + 1);
575 udp6->uh_sport = in6p->in6p_lport;
576 udp6->uh_dport = in6p->in6p_fport;
577 udp6->uh_ulen = htons((u_short)plen);
578 udp6->uh_sum = 0;
579
580 if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP,
581 sizeof(struct ip6_hdr), plen)) == 0) {
582 udp6->uh_sum = 0xffff;
583 }
584
585 udp6stat.udp6s_opackets++;
586
587 #ifdef IPSEC
588 m->m_pkthdr.rcvif = (struct ifnet *)in6p->in6p_socket;
589 #endif /*IPSEC*/
590 error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route,
591 0, in6p->in6p_moptions);
592
593 if (addr6) {
594 in6_pcbdisconnect(in6p);
595 in6p->in6p_laddr = laddr6;
596 splx(s);
597 }
598 goto releaseopt;
599
600 release:
601 m_freem(m);
602
603 releaseopt:
604 if (control) {
605 in6p->in6p_outputopts = stickyopt;
606 m_freem(control);
607 }
608 return(error);
609 }
610
611 extern int udp6_sendspace;
612 extern int udp6_recvspace;
613
614 int
615 udp6_usrreq(so, req, m, addr6, control, p)
616 struct socket *so;
617 int req;
618 struct mbuf *m, *addr6, *control;
619 struct proc *p;
620 {
621 struct in6pcb *in6p = sotoin6pcb(so);
622 int error = 0;
623 int s;
624
625 /*
626 * MAPPED_ADDR implementation info:
627 * Mapped addr support for PRU_CONTROL is not necessary.
628 * Because typical user of PRU_CONTROL is such as ifconfig,
629 * and they don't associate any addr to their socket. Then
630 * socket family is only hint about the PRU_CONTROL'ed address
631 * family, especially when getting addrs from kernel.
632 * So AF_INET socket need to be used to control AF_INET addrs,
633 * and AF_INET6 socket for AF_INET6 addrs.
634 */
635 if (req == PRU_CONTROL)
636 return(in6_control(so, (u_long)m, (caddr_t)addr6,
637 (struct ifnet *)control, p));
638
639 if (in6p == NULL && req != PRU_ATTACH) {
640 error = EINVAL;
641 goto release;
642 }
643
644 switch (req) {
645 case PRU_ATTACH:
646 /*
647 * MAPPED_ADDR implementation spec:
648 * Always attach for IPv6,
649 * and only when necessary for IPv4.
650 */
651 if (in6p != NULL) {
652 error = EINVAL;
653 break;
654 }
655 s = splsoftnet();
656 error = in6_pcballoc(so, &udb6);
657 splx(s);
658 if (error)
659 break;
660 error = soreserve(so, udp6_sendspace, udp6_recvspace);
661 if (error)
662 break;
663 in6p = sotoin6pcb(so);
664 in6p->in6p_ip6.ip6_hlim = ip6_defhlim;
665 in6p->in6p_cksum = -1; /* just to be sure */
666 #ifdef IPSEC
667 if ((error = ipsec_init_policy(&in6p->in6p_sp)) != 0)
668 in6_pcbdetach(in6p);
669 #endif /*IPSEC*/
670 break;
671
672 case PRU_DETACH:
673 udp6_detach(in6p);
674 break;
675
676 case PRU_BIND:
677 s = splsoftnet();
678 error = in6_pcbbind(in6p, addr6);
679 splx(s);
680 break;
681
682 case PRU_LISTEN:
683 error = EOPNOTSUPP;
684 break;
685
686 case PRU_CONNECT:
687 if (!IN6_IS_ADDR_ANY(&in6p->in6p_faddr)) {
688 error = EISCONN;
689 break;
690 }
691 s = splsoftnet();
692 error = in6_pcbconnect(in6p, addr6);
693 if (ip6_auto_flowlabel) {
694 in6p->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK;
695 in6p->in6p_flowinfo |=
696 (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK);
697 }
698 splx(s);
699 if (error == 0)
700 soisconnected(so);
701 break;
702
703 case PRU_CONNECT2:
704 error = EOPNOTSUPP;
705 break;
706
707 case PRU_ACCEPT:
708 error = EOPNOTSUPP;
709 break;
710
711 case PRU_DISCONNECT:
712 if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
713 error = ENOTCONN;
714 break;
715 }
716 s = splsoftnet();
717 in6_pcbdisconnect(in6p);
718 bzero((caddr_t)&in6p->in6p_laddr, sizeof(in6p->in6p_laddr));
719 splx(s);
720 so->so_state &= ~SS_ISCONNECTED; /* XXX */
721 break;
722
723 case PRU_SHUTDOWN:
724 socantsendmore(so);
725 break;
726
727 case PRU_SEND:
728 return(udp6_output(in6p, m, addr6, control));
729
730 case PRU_ABORT:
731 soisdisconnected(so);
732 udp6_detach(in6p);
733 break;
734
735 case PRU_SOCKADDR:
736 in6_setsockaddr(in6p, addr6);
737 break;
738
739 case PRU_PEERADDR:
740 in6_setpeeraddr(in6p, addr6);
741 break;
742
743 case PRU_SENSE:
744 /*
745 * stat: don't bother with a blocksize
746 */
747 return(0);
748
749 case PRU_SENDOOB:
750 case PRU_FASTTIMO:
751 case PRU_SLOWTIMO:
752 case PRU_PROTORCV:
753 case PRU_PROTOSEND:
754 error = EOPNOTSUPP;
755 break;
756
757 case PRU_RCVD:
758 case PRU_RCVOOB:
759 return(EOPNOTSUPP); /* do not free mbuf's */
760
761 default:
762 panic("udp6_usrreq");
763 }
764
765 release:
766 if (control) {
767 printf("udp control data unexpectedly retained\n");
768 m_freem(control);
769 }
770 if (m)
771 m_freem(m);
772 return(error);
773 }
774
775 static void
776 udp6_detach(in6p)
777 struct in6pcb *in6p;
778 {
779 int s = splsoftnet();
780
781 if (in6p == udp6_last_in6pcb)
782 udp6_last_in6pcb = &udb6;
783 in6_pcbdetach(in6p);
784 splx(s);
785 }
786
787 #ifdef __bsdi__
788 int *udp6_sysvars[] = UDP6CTL_VARS;
789
790 int
791 udp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
792 int *name;
793 u_int namelen;
794 void *oldp;
795 size_t *oldlenp;
796 void *newp;
797 size_t newlen;
798 {
799 if (name[0] >= UDP6CTL_MAXID)
800 return (EOPNOTSUPP);
801 switch (name[0]) {
802 case UDP6CTL_STATS:
803 return sysctl_rdtrunc(oldp, oldlenp, newp, &udp6stat,
804 sizeof(udp6stat));
805
806 default:
807 return (sysctl_int_arr(udp6_sysvars, name, namelen,
808 oldp, oldlenp, newp, newlen));
809 }
810 }
811 #endif /*__bsdi__*/
812
813 #ifdef __NetBSD__
814 #include <vm/vm.h>
815 #include <sys/sysctl.h>
816
817 int
818 udp6_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
819 int *name;
820 u_int namelen;
821 void *oldp;
822 size_t *oldlenp;
823 void *newp;
824 size_t newlen;
825 {
826 /* All sysctl names at this level are terminal. */
827 if (namelen != 1)
828 return ENOTDIR;
829
830 switch (name[0]) {
831
832 case UDP6CTL_SENDMAX:
833 return sysctl_int(oldp, oldlenp, newp, newlen,
834 &udp6_sendspace);
835 case UDP6CTL_RECVSPACE:
836 return sysctl_int(oldp, oldlenp, newp, newlen,
837 &udp6_recvspace);
838 default:
839 return ENOPROTOOPT;
840 }
841 /* NOTREACHED */
842 }
843 #endif
844