Line data Source code
1 : /* $OpenBSD: raw_ip6.c,v 1.130 2018/09/13 19:53:58 bluhm Exp $ */
2 : /* $KAME: raw_ip6.c,v 1.69 2001/03/04 15:55:44 itojun Exp $ */
3 :
4 : /*
5 : * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 : * All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : * 1. Redistributions of source code must retain the above copyright
12 : * notice, this list of conditions and the following disclaimer.
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : * 3. Neither the name of the project nor the names of its contributors
17 : * may be used to endorse or promote products derived from this software
18 : * without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 : * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 : * SUCH DAMAGE.
31 : */
32 :
33 : /*
34 : * Copyright (c) 1982, 1986, 1988, 1993
35 : * The Regents of the University of California. All rights reserved.
36 : *
37 : * Redistribution and use in source and binary forms, with or without
38 : * modification, are permitted provided that the following conditions
39 : * are met:
40 : * 1. Redistributions of source code must retain the above copyright
41 : * notice, this list of conditions and the following disclaimer.
42 : * 2. Redistributions in binary form must reproduce the above copyright
43 : * notice, this list of conditions and the following disclaimer in the
44 : * documentation and/or other materials provided with the distribution.
45 : * 3. Neither the name of the University nor the names of its contributors
46 : * may be used to endorse or promote products derived from this software
47 : * without specific prior written permission.
48 : *
49 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 : * SUCH DAMAGE.
60 : *
61 : * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94
62 : */
63 :
64 : #include "pf.h"
65 :
66 : #include <sys/param.h>
67 : #include <sys/malloc.h>
68 : #include <sys/mbuf.h>
69 : #include <sys/socket.h>
70 : #include <sys/protosw.h>
71 : #include <sys/socketvar.h>
72 : #include <sys/errno.h>
73 : #include <sys/systm.h>
74 : #include <sys/sysctl.h>
75 :
76 : #include <net/if.h>
77 : #include <net/if_var.h>
78 : #include <net/route.h>
79 :
80 : #include <netinet/in.h>
81 : #include <netinet6/in6_var.h>
82 : #include <netinet/ip6.h>
83 : #include <netinet6/ip6_var.h>
84 : #ifdef MROUTING
85 : #include <netinet6/ip6_mroute.h>
86 : #endif
87 : #include <netinet/icmp6.h>
88 : #include <netinet/ip.h>
89 : #include <netinet/in_pcb.h>
90 : #include <netinet6/nd6.h>
91 : #include <netinet6/ip6protosw.h>
92 : #include <netinet6/raw_ip6.h>
93 :
94 : #if NPF > 0
95 : #include <net/pfvar.h>
96 : #endif
97 :
98 : #include <sys/stdarg.h>
99 :
100 : /*
101 : * Raw interface to IP6 protocol.
102 : */
103 :
104 : struct inpcbtable rawin6pcbtable;
105 :
106 : struct cpumem *rip6counters;
107 :
108 : /*
109 : * Initialize raw connection block queue.
110 : */
111 : void
112 0 : rip6_init(void)
113 : {
114 0 : in_pcbinit(&rawin6pcbtable, 1);
115 0 : rip6counters = counters_alloc(rip6s_ncounters);
116 0 : }
117 :
118 : int
119 0 : rip6_input(struct mbuf **mp, int *offp, int proto, int af)
120 : {
121 0 : struct mbuf *m = *mp;
122 0 : struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
123 : struct inpcb *in6p;
124 : struct inpcb *last = NULL;
125 : struct in6_addr *key;
126 0 : struct sockaddr_in6 rip6src;
127 0 : struct mbuf *opts = NULL;
128 :
129 0 : KASSERT(af == AF_INET6);
130 :
131 0 : if (proto != IPPROTO_ICMPV6)
132 0 : rip6stat_inc(rip6s_ipackets);
133 :
134 0 : bzero(&rip6src, sizeof(rip6src));
135 0 : rip6src.sin6_len = sizeof(struct sockaddr_in6);
136 0 : rip6src.sin6_family = AF_INET6;
137 : /* KAME hack: recover scopeid */
138 0 : in6_recoverscope(&rip6src, &ip6->ip6_src);
139 :
140 0 : key = &ip6->ip6_dst;
141 : #if NPF > 0
142 0 : if (m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) {
143 : struct pf_divert *divert;
144 :
145 : /* XXX rdomain support */
146 0 : divert = pf_find_divert(m);
147 0 : KASSERT(divert != NULL);
148 0 : switch (divert->type) {
149 : case PF_DIVERT_TO:
150 0 : key = &divert->addr.v6;
151 0 : break;
152 : case PF_DIVERT_REPLY:
153 : break;
154 : default:
155 0 : panic("%s: unknown divert type %d, mbuf %p, divert %p",
156 : __func__, divert->type, m, divert);
157 : }
158 0 : }
159 : #endif
160 0 : NET_ASSERT_LOCKED();
161 0 : TAILQ_FOREACH(in6p, &rawin6pcbtable.inpt_queue, inp_queue) {
162 0 : if (in6p->inp_socket->so_state & SS_CANTRCVMORE)
163 : continue;
164 0 : if (!(in6p->inp_flags & INP_IPV6))
165 : continue;
166 0 : if ((in6p->inp_ipv6.ip6_nxt || proto == IPPROTO_ICMPV6) &&
167 0 : in6p->inp_ipv6.ip6_nxt != proto)
168 : continue;
169 0 : if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->inp_laddr6) &&
170 0 : !IN6_ARE_ADDR_EQUAL(&in6p->inp_laddr6, key))
171 : continue;
172 0 : if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->inp_faddr6) &&
173 0 : !IN6_ARE_ADDR_EQUAL(&in6p->inp_faddr6, &ip6->ip6_src))
174 : continue;
175 0 : if (proto == IPPROTO_ICMPV6 && in6p->inp_icmp6filt) {
176 : struct icmp6_hdr *icmp6;
177 :
178 0 : IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, *offp,
179 : sizeof(*icmp6));
180 0 : if (icmp6 == NULL)
181 0 : return IPPROTO_DONE;
182 0 : if (ICMP6_FILTER_WILLBLOCK(icmp6->icmp6_type,
183 : in6p->inp_icmp6filt))
184 0 : continue;
185 0 : }
186 0 : if (proto != IPPROTO_ICMPV6 && in6p->inp_cksum6 != -1) {
187 0 : rip6stat_inc(rip6s_isum);
188 0 : if (in6_cksum(m, proto, *offp,
189 0 : m->m_pkthdr.len - *offp)) {
190 0 : rip6stat_inc(rip6s_badsum);
191 0 : continue;
192 : }
193 : }
194 0 : if (last) {
195 : struct mbuf *n;
196 0 : if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) != NULL) {
197 0 : if (last->inp_flags & IN6P_CONTROLOPTS)
198 0 : ip6_savecontrol(last, n, &opts);
199 : /* strip intermediate headers */
200 0 : m_adj(n, *offp);
201 0 : if (sbappendaddr(last->inp_socket,
202 0 : &last->inp_socket->so_rcv,
203 0 : sin6tosa(&rip6src), n, opts) == 0) {
204 : /* should notify about lost packet */
205 0 : m_freem(n);
206 0 : m_freem(opts);
207 0 : rip6stat_inc(rip6s_fullsock);
208 0 : } else
209 0 : sorwakeup(last->inp_socket);
210 0 : opts = NULL;
211 0 : }
212 0 : }
213 : last = in6p;
214 0 : }
215 0 : if (last) {
216 0 : if (last->inp_flags & IN6P_CONTROLOPTS)
217 0 : ip6_savecontrol(last, m, &opts);
218 : /* strip intermediate headers */
219 0 : m_adj(m, *offp);
220 0 : if (sbappendaddr(last->inp_socket, &last->inp_socket->so_rcv,
221 0 : sin6tosa(&rip6src), m, opts) == 0) {
222 0 : m_freem(m);
223 0 : m_freem(opts);
224 0 : rip6stat_inc(rip6s_fullsock);
225 0 : } else
226 0 : sorwakeup(last->inp_socket);
227 : } else {
228 0 : struct counters_ref ref;
229 : uint64_t *counters;
230 :
231 0 : if (proto != IPPROTO_ICMPV6) {
232 0 : rip6stat_inc(rip6s_nosock);
233 0 : if (m->m_flags & M_MCAST)
234 0 : rip6stat_inc(rip6s_nosockmcast);
235 : }
236 0 : if (proto == IPPROTO_NONE || proto == IPPROTO_ICMPV6) {
237 0 : m_freem(m);
238 0 : } else {
239 0 : int prvnxt = ip6_get_prevhdr(m, *offp);
240 :
241 0 : icmp6_error(m, ICMP6_PARAM_PROB,
242 : ICMP6_PARAMPROB_NEXTHEADER, prvnxt);
243 : }
244 0 : counters = counters_enter(&ref, ip6counters);
245 0 : counters[ip6s_delivered]--;
246 0 : counters_leave(&ref, ip6counters);
247 0 : }
248 0 : return IPPROTO_DONE;
249 0 : }
250 :
251 : void
252 0 : rip6_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *d)
253 : {
254 : struct ip6_hdr *ip6;
255 : struct ip6ctlparam *ip6cp = NULL;
256 0 : struct sockaddr_in6 *sa6 = satosin6(sa);
257 : const struct sockaddr_in6 *sa6_src = NULL;
258 : void *cmdarg;
259 : void (*notify)(struct inpcb *, int) = in_rtchange;
260 : int nxt;
261 :
262 0 : if (sa->sa_family != AF_INET6 ||
263 0 : sa->sa_len != sizeof(struct sockaddr_in6))
264 0 : return;
265 :
266 0 : if ((unsigned)cmd >= PRC_NCMDS)
267 0 : return;
268 0 : if (PRC_IS_REDIRECT(cmd))
269 0 : notify = in_rtchange, d = NULL;
270 0 : else if (cmd == PRC_HOSTDEAD)
271 0 : d = NULL;
272 0 : else if (cmd == PRC_MSGSIZE)
273 : ; /* special code is present, see below */
274 0 : else if (inet6ctlerrmap[cmd] == 0)
275 0 : return;
276 :
277 : /* if the parameter is from icmp6, decode it. */
278 0 : if (d != NULL) {
279 0 : ip6cp = (struct ip6ctlparam *)d;
280 0 : ip6 = ip6cp->ip6c_ip6;
281 0 : cmdarg = ip6cp->ip6c_cmdarg;
282 0 : sa6_src = ip6cp->ip6c_src;
283 0 : nxt = ip6cp->ip6c_nxt;
284 0 : } else {
285 : ip6 = NULL;
286 : cmdarg = NULL;
287 : sa6_src = &sa6_any;
288 : nxt = -1;
289 : }
290 :
291 0 : if (ip6 && cmd == PRC_MSGSIZE) {
292 : int valid = 0;
293 : struct inpcb *in6p;
294 :
295 : /*
296 : * Check to see if we have a valid raw IPv6 socket
297 : * corresponding to the address in the ICMPv6 message
298 : * payload, and the protocol (ip6_nxt) meets the socket.
299 : * XXX chase extension headers, or pass final nxt value
300 : * from icmp6_notify_error()
301 : */
302 0 : in6p = in6_pcbhashlookup(&rawin6pcbtable, &sa6->sin6_addr, 0,
303 0 : &sa6_src->sin6_addr, 0, rdomain);
304 :
305 0 : if (in6p && in6p->inp_ipv6.ip6_nxt &&
306 0 : in6p->inp_ipv6.ip6_nxt == nxt)
307 0 : valid++;
308 :
309 : /*
310 : * Depending on the value of "valid" and routing table
311 : * size (mtudisc_{hi,lo}wat), we will:
312 : * - recalculate the new MTU and create the
313 : * corresponding routing entry, or
314 : * - ignore the MTU change notification.
315 : */
316 0 : icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
317 :
318 : /*
319 : * regardless of if we called icmp6_mtudisc_update(),
320 : * we need to call in6_pcbnotify(), to notify path
321 : * MTU change to the userland (2292bis-02), because
322 : * some unconnected sockets may share the same
323 : * destination and want to know the path MTU.
324 : */
325 0 : }
326 :
327 0 : (void) in6_pcbnotify(&rawin6pcbtable, sa6, 0,
328 : sa6_src, 0, rdomain, cmd, cmdarg, notify);
329 0 : }
330 :
331 : /*
332 : * Generate IPv6 header and pass packet to ip6_output.
333 : * Tack on options user may have setup with control call.
334 : */
335 : int
336 0 : rip6_output(struct mbuf *m, struct socket *so, struct sockaddr *dstaddr,
337 : struct mbuf *control)
338 : {
339 : struct in6_addr *dst;
340 : struct ip6_hdr *ip6;
341 : struct inpcb *in6p;
342 0 : u_int plen = m->m_pkthdr.len;
343 : int error = 0;
344 0 : struct ip6_pktopts opt, *optp = NULL, *origoptp;
345 : int type; /* for ICMPv6 output statistics only */
346 : int priv = 0;
347 : int flags;
348 :
349 0 : in6p = sotoinpcb(so);
350 :
351 : priv = 0;
352 0 : if ((so->so_state & SS_PRIV) != 0)
353 : priv = 1;
354 0 : if (control) {
355 0 : if ((error = ip6_setpktopts(control, &opt,
356 0 : in6p->inp_outputopts6,
357 0 : priv, so->so_proto->pr_protocol)) != 0)
358 : goto bad;
359 : optp = &opt;
360 0 : } else
361 0 : optp = in6p->inp_outputopts6;
362 :
363 0 : if (dstaddr->sa_family != AF_INET6) {
364 : error = EAFNOSUPPORT;
365 0 : goto bad;
366 : }
367 0 : dst = &satosin6(dstaddr)->sin6_addr;
368 0 : if (IN6_IS_ADDR_V4MAPPED(dst)) {
369 : error = EADDRNOTAVAIL;
370 0 : goto bad;
371 : }
372 :
373 : /*
374 : * For an ICMPv6 packet, we should know its type and code
375 : * to update statistics.
376 : */
377 0 : if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
378 : struct icmp6_hdr *icmp6;
379 0 : if (m->m_len < sizeof(struct icmp6_hdr) &&
380 0 : (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
381 : error = ENOBUFS;
382 0 : goto bad;
383 : }
384 0 : icmp6 = mtod(m, struct icmp6_hdr *);
385 0 : type = icmp6->icmp6_type;
386 0 : }
387 :
388 0 : M_PREPEND(m, sizeof(*ip6), M_DONTWAIT);
389 0 : if (!m) {
390 : error = ENOBUFS;
391 0 : goto bad;
392 : }
393 0 : ip6 = mtod(m, struct ip6_hdr *);
394 :
395 : /*
396 : * Next header might not be ICMP6 but use its pseudo header anyway.
397 : */
398 0 : ip6->ip6_dst = *dst;
399 :
400 : /* KAME hack: embed scopeid */
401 0 : origoptp = in6p->inp_outputopts6;
402 0 : in6p->inp_outputopts6 = optp;
403 0 : if (in6_embedscope(&ip6->ip6_dst, satosin6(dstaddr), in6p) != 0) {
404 : error = EINVAL;
405 0 : goto bad;
406 : }
407 0 : in6p->inp_outputopts6 = origoptp;
408 :
409 : /*
410 : * Source address selection.
411 : */
412 : {
413 0 : struct in6_addr *in6a;
414 :
415 0 : error = in6_pcbselsrc(&in6a, satosin6(dstaddr), in6p, optp);
416 0 : if (error)
417 0 : goto bad;
418 :
419 0 : ip6->ip6_src = *in6a;
420 0 : }
421 :
422 0 : ip6->ip6_flow = in6p->inp_flowinfo & IPV6_FLOWINFO_MASK;
423 0 : ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
424 0 : ip6->ip6_vfc |= IPV6_VERSION;
425 : #if 0 /* ip6_plen will be filled in ip6_output. */
426 : ip6->ip6_plen = htons((u_short)plen);
427 : #endif
428 0 : ip6->ip6_nxt = in6p->inp_ipv6.ip6_nxt;
429 0 : ip6->ip6_hlim = in6_selecthlim(in6p);
430 :
431 0 : if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
432 0 : in6p->inp_cksum6 != -1) {
433 : struct mbuf *n;
434 : int off;
435 : u_int16_t *sump;
436 0 : int sumoff;
437 :
438 : /* compute checksum */
439 0 : if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
440 0 : off = offsetof(struct icmp6_hdr, icmp6_cksum);
441 : else
442 0 : off = in6p->inp_cksum6;
443 0 : if (plen < off + 1) {
444 : error = EINVAL;
445 0 : goto bad;
446 : }
447 0 : off += sizeof(struct ip6_hdr);
448 :
449 0 : n = m_pulldown(m, off, sizeof(*sump), &sumoff);
450 0 : if (n == NULL) {
451 : m = NULL;
452 : error = ENOBUFS;
453 0 : goto bad;
454 : }
455 0 : sump = (u_int16_t *)(mtod(n, caddr_t) + sumoff);
456 0 : *sump = 0;
457 0 : *sump = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
458 0 : }
459 :
460 : flags = 0;
461 0 : if (in6p->inp_flags & IN6P_MINMTU)
462 0 : flags |= IPV6_MINMTU;
463 :
464 : /* force routing table */
465 0 : m->m_pkthdr.ph_rtableid = in6p->inp_rtableid;
466 :
467 : #if NPF > 0
468 0 : if (in6p->inp_socket->so_state & SS_ISCONNECTED &&
469 0 : so->so_proto->pr_protocol != IPPROTO_ICMPV6)
470 0 : pf_mbuf_link_inpcb(m, in6p);
471 : #endif
472 :
473 0 : error = ip6_output(m, optp, &in6p->inp_route6, flags,
474 0 : in6p->inp_moptions6, in6p);
475 0 : if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
476 0 : icmp6stat_inc(icp6s_outhist + type);
477 0 : } else
478 0 : rip6stat_inc(rip6s_opackets);
479 :
480 : goto freectl;
481 :
482 : bad:
483 0 : m_freem(m);
484 :
485 : freectl:
486 0 : if (control) {
487 0 : ip6_clearpktopts(&opt, -1);
488 0 : m_freem(control);
489 0 : }
490 0 : return (error);
491 0 : }
492 :
493 : /*
494 : * Raw IPv6 socket option processing.
495 : */
496 : int
497 0 : rip6_ctloutput(int op, struct socket *so, int level, int optname,
498 : struct mbuf *m)
499 : {
500 : #ifdef MROUTING
501 : int error;
502 : #endif
503 :
504 0 : switch (level) {
505 : case IPPROTO_IPV6:
506 0 : switch (optname) {
507 : #ifdef MROUTING
508 : case MRT6_INIT:
509 : case MRT6_DONE:
510 : case MRT6_ADD_MIF:
511 : case MRT6_DEL_MIF:
512 : case MRT6_ADD_MFC:
513 : case MRT6_DEL_MFC:
514 0 : if (op == PRCO_SETOPT) {
515 0 : error = ip6_mrouter_set(optname, so, m);
516 0 : } else if (op == PRCO_GETOPT)
517 0 : error = ip6_mrouter_get(optname, so, m);
518 : else
519 : error = EINVAL;
520 0 : return (error);
521 : #endif
522 : case IPV6_CHECKSUM:
523 0 : return (ip6_raw_ctloutput(op, so, level, optname, m));
524 : default:
525 0 : return (ip6_ctloutput(op, so, level, optname, m));
526 : }
527 :
528 : case IPPROTO_ICMPV6:
529 : /*
530 : * XXX: is it better to call icmp6_ctloutput() directly
531 : * from protosw?
532 : */
533 0 : return (icmp6_ctloutput(op, so, level, optname, m));
534 :
535 : default:
536 0 : return EINVAL;
537 : }
538 0 : }
539 :
540 : extern u_long rip6_sendspace;
541 : extern u_long rip6_recvspace;
542 :
543 : int
544 0 : rip6_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
545 : struct mbuf *control, struct proc *p)
546 : {
547 : struct inpcb *in6p;
548 : int error = 0;
549 :
550 0 : if (req == PRU_CONTROL)
551 0 : return (in6_control(so, (u_long)m, (caddr_t)nam,
552 0 : (struct ifnet *)control));
553 :
554 0 : soassertlocked(so);
555 :
556 0 : in6p = sotoinpcb(so);
557 0 : if (in6p == NULL) {
558 : error = EINVAL;
559 0 : goto release;
560 : }
561 :
562 0 : switch (req) {
563 : case PRU_DISCONNECT:
564 0 : if ((so->so_state & SS_ISCONNECTED) == 0) {
565 : error = ENOTCONN;
566 0 : break;
567 : }
568 0 : in6p->inp_faddr6 = in6addr_any;
569 0 : so->so_state &= ~SS_ISCONNECTED; /* XXX */
570 0 : break;
571 :
572 : case PRU_ABORT:
573 0 : soisdisconnected(so);
574 0 : if (in6p == NULL)
575 0 : panic("rip6_detach");
576 : #ifdef MROUTING
577 0 : if (so == ip6_mrouter[in6p->inp_rtableid])
578 0 : ip6_mrouter_done(so);
579 : #endif
580 0 : free(in6p->inp_icmp6filt, M_PCB, sizeof(struct icmp6_filter));
581 0 : in6p->inp_icmp6filt = NULL;
582 :
583 0 : in_pcbdetach(in6p);
584 0 : break;
585 :
586 : case PRU_BIND:
587 : {
588 0 : struct sockaddr_in6 *addr;
589 :
590 0 : if ((error = in6_nam2sin6(nam, &addr)))
591 0 : break;
592 : /*
593 : * Make sure to not enter in_pcblookup_local(), local ports
594 : * are non-sensical for raw sockets.
595 : */
596 0 : addr->sin6_port = 0;
597 :
598 0 : if ((error = in6_pcbaddrisavail(in6p, addr, 0, p)))
599 0 : break;
600 :
601 0 : in6p->inp_laddr6 = addr->sin6_addr;
602 0 : break;
603 0 : }
604 :
605 : case PRU_CONNECT:
606 : {
607 0 : struct sockaddr_in6 *addr;
608 0 : struct in6_addr *in6a = NULL;
609 :
610 0 : if ((error = in6_nam2sin6(nam, &addr)))
611 0 : break;
612 : /* Source address selection. XXX: need pcblookup? */
613 0 : error = in6_pcbselsrc(&in6a, addr, in6p, in6p->inp_outputopts6);
614 0 : if (error)
615 0 : break;
616 0 : in6p->inp_laddr6 = *in6a;
617 0 : in6p->inp_faddr6 = addr->sin6_addr;
618 0 : soisconnected(so);
619 0 : break;
620 0 : }
621 :
622 : case PRU_CONNECT2:
623 : error = EOPNOTSUPP;
624 0 : break;
625 :
626 : /*
627 : * Mark the connection as being incapable of futther input.
628 : */
629 : case PRU_SHUTDOWN:
630 0 : socantsendmore(so);
631 0 : break;
632 : /*
633 : * Ship a packet out. The appropriate raw output
634 : * routine handles any messaging necessary.
635 : */
636 : case PRU_SEND:
637 : {
638 0 : struct sockaddr_in6 dst;
639 :
640 : /* always copy sockaddr to avoid overwrites */
641 0 : memset(&dst, 0, sizeof(dst));
642 0 : dst.sin6_family = AF_INET6;
643 0 : dst.sin6_len = sizeof(dst);
644 0 : if (so->so_state & SS_ISCONNECTED) {
645 0 : if (nam) {
646 : error = EISCONN;
647 0 : break;
648 : }
649 0 : dst.sin6_addr = in6p->inp_faddr6;
650 0 : } else {
651 0 : struct sockaddr_in6 *addr6;
652 :
653 0 : if (nam == NULL) {
654 : error = ENOTCONN;
655 0 : break;
656 : }
657 0 : if ((error = in6_nam2sin6(nam, &addr6)))
658 0 : break;
659 0 : dst.sin6_addr = addr6->sin6_addr;
660 0 : dst.sin6_scope_id = addr6->sin6_scope_id;
661 0 : }
662 0 : error = rip6_output(m, so, sin6tosa(&dst), control);
663 : control = NULL;
664 : m = NULL;
665 0 : break;
666 0 : }
667 :
668 : case PRU_SENSE:
669 : /*
670 : * stat: don't bother with a blocksize
671 : */
672 0 : return (0);
673 : /*
674 : * Not supported.
675 : */
676 : case PRU_LISTEN:
677 : case PRU_ACCEPT:
678 : case PRU_SENDOOB:
679 : error = EOPNOTSUPP;
680 0 : break;
681 :
682 : case PRU_RCVD:
683 : case PRU_RCVOOB:
684 0 : return (EOPNOTSUPP); /* do not free mbuf's */
685 :
686 : case PRU_SOCKADDR:
687 0 : in6_setsockaddr(in6p, nam);
688 0 : break;
689 :
690 : case PRU_PEERADDR:
691 0 : in6_setpeeraddr(in6p, nam);
692 0 : break;
693 :
694 : default:
695 0 : panic("rip6_usrreq");
696 : }
697 : release:
698 0 : m_freem(control);
699 0 : m_freem(m);
700 0 : return (error);
701 0 : }
702 :
703 : int
704 0 : rip6_attach(struct socket *so, int proto)
705 : {
706 : struct inpcb *in6p;
707 : int error;
708 :
709 0 : if (so->so_pcb)
710 0 : panic("rip6_attach");
711 0 : if ((so->so_state & SS_PRIV) == 0)
712 0 : return (EACCES);
713 0 : if (proto < 0 || proto >= IPPROTO_MAX)
714 0 : return EPROTONOSUPPORT;
715 :
716 0 : if ((error = soreserve(so, rip6_sendspace, rip6_recvspace)))
717 0 : return error;
718 0 : NET_ASSERT_LOCKED();
719 0 : if ((error = in_pcballoc(so, &rawin6pcbtable)))
720 0 : return error;
721 :
722 0 : in6p = sotoinpcb(so);
723 0 : in6p->inp_ipv6.ip6_nxt = proto;
724 0 : in6p->inp_cksum6 = -1;
725 :
726 0 : in6p->inp_icmp6filt = malloc(sizeof(struct icmp6_filter),
727 : M_PCB, M_NOWAIT);
728 0 : if (in6p->inp_icmp6filt == NULL) {
729 0 : in_pcbdetach(in6p);
730 0 : return ENOMEM;
731 : }
732 0 : ICMP6_FILTER_SETPASSALL(in6p->inp_icmp6filt);
733 0 : return 0;
734 0 : }
735 :
736 : int
737 0 : rip6_detach(struct socket *so)
738 : {
739 0 : struct inpcb *in6p = sotoinpcb(so);
740 :
741 0 : soassertlocked(so);
742 :
743 0 : if (in6p == NULL)
744 0 : panic("rip6_detach");
745 : #ifdef MROUTING
746 0 : if (so == ip6_mrouter[in6p->inp_rtableid])
747 0 : ip6_mrouter_done(so);
748 : #endif
749 0 : free(in6p->inp_icmp6filt, M_PCB, sizeof(struct icmp6_filter));
750 0 : in6p->inp_icmp6filt = NULL;
751 :
752 0 : in_pcbdetach(in6p);
753 :
754 0 : return (0);
755 : }
756 :
757 : int
758 0 : rip6_sysctl_rip6stat(void *oldp, size_t *oldplen, void *newp)
759 : {
760 0 : struct rip6stat rip6stat;
761 :
762 : CTASSERT(sizeof(rip6stat) == rip6s_ncounters * sizeof(uint64_t));
763 0 : counters_read(ip6counters, (uint64_t *)&rip6stat, rip6s_ncounters);
764 :
765 0 : return (sysctl_rdstruct(oldp, oldplen, newp,
766 : &rip6stat, sizeof(rip6stat)));
767 0 : }
768 :
769 : int
770 0 : rip6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
771 : void *newp, size_t newlen)
772 : {
773 : /* All sysctl names at this level are terminal. */
774 0 : if (namelen != 1)
775 0 : return ENOTDIR;
776 :
777 0 : switch (name[0]) {
778 : case RIPV6CTL_STATS:
779 0 : return (rip6_sysctl_rip6stat(oldp, oldlenp, newp));
780 : default:
781 0 : return (EOPNOTSUPP);
782 : }
783 : /* NOTREACHED */
784 0 : }
|