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