1 /* $OpenBSD: raw_ip6.c,v 1.184 2024/04/17 20:48:51 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 const struct pr_usrreqs rip6_usrreqs = {
109 .pru_attach = rip6_attach,
110 .pru_detach = rip6_detach,
111 .pru_lock = rip6_lock,
112 .pru_unlock = rip6_unlock,
113 .pru_locked = rip6_locked,
114 .pru_bind = rip6_bind,
115 .pru_connect = rip6_connect,
116 .pru_disconnect = rip6_disconnect,
117 .pru_shutdown = rip6_shutdown,
118 .pru_send = rip6_send,
119 .pru_control = in6_control,
120 .pru_sockaddr = in6_sockaddr,
121 .pru_peeraddr = in6_peeraddr,
122 };
123
124 /*
125 * Initialize raw connection block queue.
126 */
127 void
rip6_init(void)128 rip6_init(void)
129 {
130 in_pcbinit(&rawin6pcbtable, 1);
131 rip6counters = counters_alloc(rip6s_ncounters);
132 }
133
134 int
rip6_input(struct mbuf ** mp,int * offp,int proto,int af)135 rip6_input(struct mbuf **mp, int *offp, int proto, int af)
136 {
137 struct mbuf *m = *mp;
138 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
139 struct inpcb *inp;
140 SIMPLEQ_HEAD(, inpcb) inpcblist;
141 struct in6_addr *key;
142 struct sockaddr_in6 rip6src;
143 uint8_t type;
144
145 KASSERT(af == AF_INET6);
146
147 if (proto == IPPROTO_ICMPV6) {
148 struct icmp6_hdr *icmp6;
149
150 IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, *offp,
151 sizeof(*icmp6));
152 if (icmp6 == NULL)
153 return IPPROTO_DONE;
154 type = icmp6->icmp6_type;
155 } else
156 rip6stat_inc(rip6s_ipackets);
157
158 memset(&rip6src, 0, sizeof(rip6src));
159 rip6src.sin6_family = AF_INET6;
160 rip6src.sin6_len = sizeof(rip6src);
161 /* KAME hack: recover scopeid */
162 in6_recoverscope(&rip6src, &ip6->ip6_src);
163
164 key = &ip6->ip6_dst;
165 #if NPF > 0
166 if (m->m_pkthdr.pf.flags & PF_TAG_DIVERTED) {
167 struct pf_divert *divert;
168
169 divert = pf_find_divert(m);
170 KASSERT(divert != NULL);
171 switch (divert->type) {
172 case PF_DIVERT_TO:
173 key = &divert->addr.v6;
174 break;
175 case PF_DIVERT_REPLY:
176 break;
177 default:
178 panic("%s: unknown divert type %d, mbuf %p, divert %p",
179 __func__, divert->type, m, divert);
180 }
181 }
182 #endif
183 SIMPLEQ_INIT(&inpcblist);
184 rw_enter_write(&rawin6pcbtable.inpt_notify);
185 mtx_enter(&rawin6pcbtable.inpt_mtx);
186 TAILQ_FOREACH(inp, &rawin6pcbtable.inpt_queue, inp_queue) {
187 KASSERT(ISSET(inp->inp_flags, INP_IPV6));
188
189 /*
190 * Packet must not be inserted after disconnected wakeup
191 * call. To avoid race, check again when holding receive
192 * buffer mutex.
193 */
194 if (ISSET(READ_ONCE(inp->inp_socket->so_rcv.sb_state),
195 SS_CANTRCVMORE))
196 continue;
197 if (rtable_l2(inp->inp_rtableid) !=
198 rtable_l2(m->m_pkthdr.ph_rtableid))
199 continue;
200
201 if ((inp->inp_ipv6.ip6_nxt || proto == IPPROTO_ICMPV6) &&
202 inp->inp_ipv6.ip6_nxt != proto)
203 continue;
204 if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6) &&
205 !IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, key))
206 continue;
207 if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6) &&
208 !IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, &ip6->ip6_src))
209 continue;
210 if (proto == IPPROTO_ICMPV6 && inp->inp_icmp6filt) {
211 if (ICMP6_FILTER_WILLBLOCK(type, inp->inp_icmp6filt))
212 continue;
213 }
214 if (proto != IPPROTO_ICMPV6 && inp->inp_cksum6 != -1) {
215 rip6stat_inc(rip6s_isum);
216 /*
217 * Although in6_cksum() does not need the position of
218 * the checksum field for verification, enforce that it
219 * is located within the packet. Userland has given
220 * a checksum offset, a packet too short for that is
221 * invalid. Avoid overflow with user supplied offset.
222 */
223 if (m->m_pkthdr.len < *offp + 2 ||
224 m->m_pkthdr.len - *offp - 2 < inp->inp_cksum6 ||
225 in6_cksum(m, proto, *offp,
226 m->m_pkthdr.len - *offp)) {
227 rip6stat_inc(rip6s_badsum);
228 continue;
229 }
230 }
231
232 in_pcbref(inp);
233 SIMPLEQ_INSERT_TAIL(&inpcblist, inp, inp_notify);
234 }
235 mtx_leave(&rawin6pcbtable.inpt_mtx);
236
237 if (SIMPLEQ_EMPTY(&inpcblist)) {
238 struct counters_ref ref;
239 uint64_t *counters;
240
241 rw_exit_write(&rawin6pcbtable.inpt_notify);
242
243 if (proto != IPPROTO_ICMPV6) {
244 rip6stat_inc(rip6s_nosock);
245 if (m->m_flags & M_MCAST)
246 rip6stat_inc(rip6s_nosockmcast);
247 }
248 if (proto == IPPROTO_NONE || proto == IPPROTO_ICMPV6) {
249 m_freem(m);
250 } else {
251 int prvnxt = ip6_get_prevhdr(m, *offp);
252
253 icmp6_error(m, ICMP6_PARAM_PROB,
254 ICMP6_PARAMPROB_NEXTHEADER, prvnxt);
255 }
256 counters = counters_enter(&ref, ip6counters);
257 counters[ip6s_delivered]--;
258 counters_leave(&ref, ip6counters);
259
260 return IPPROTO_DONE;
261 }
262
263 while ((inp = SIMPLEQ_FIRST(&inpcblist)) != NULL) {
264 struct mbuf *n, *opts = NULL;
265
266 SIMPLEQ_REMOVE_HEAD(&inpcblist, inp_notify);
267 if (SIMPLEQ_EMPTY(&inpcblist))
268 n = m;
269 else
270 n = m_copym(m, 0, M_COPYALL, M_NOWAIT);
271 if (n != NULL) {
272 struct socket *so = inp->inp_socket;
273 int ret = 0;
274
275 if (inp->inp_flags & IN6P_CONTROLOPTS)
276 ip6_savecontrol(inp, n, &opts);
277 /* strip intermediate headers */
278 m_adj(n, *offp);
279
280 mtx_enter(&so->so_rcv.sb_mtx);
281 if (!ISSET(inp->inp_socket->so_rcv.sb_state,
282 SS_CANTRCVMORE)) {
283 ret = sbappendaddr(so, &so->so_rcv,
284 sin6tosa(&rip6src), n, opts);
285 }
286 mtx_leave(&so->so_rcv.sb_mtx);
287
288 if (ret == 0) {
289 m_freem(n);
290 m_freem(opts);
291 rip6stat_inc(rip6s_fullsock);
292 } else
293 sorwakeup(so);
294 }
295 in_pcbunref(inp);
296 }
297 rw_exit_write(&rawin6pcbtable.inpt_notify);
298
299 return IPPROTO_DONE;
300 }
301
302 void
rip6_ctlinput(int cmd,struct sockaddr * sa,u_int rdomain,void * d)303 rip6_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *d)
304 {
305 struct ip6_hdr *ip6;
306 struct ip6ctlparam *ip6cp = NULL;
307 struct sockaddr_in6 *sa6 = satosin6(sa);
308 const struct sockaddr_in6 *sa6_src = NULL;
309 void *cmdarg;
310 void (*notify)(struct inpcb *, int) = in_rtchange;
311 int nxt;
312
313 if (sa->sa_family != AF_INET6 ||
314 sa->sa_len != sizeof(struct sockaddr_in6))
315 return;
316
317 if ((unsigned)cmd >= PRC_NCMDS)
318 return;
319 if (PRC_IS_REDIRECT(cmd))
320 notify = in_rtchange, d = NULL;
321 else if (cmd == PRC_HOSTDEAD)
322 d = NULL;
323 else if (cmd == PRC_MSGSIZE)
324 ; /* special code is present, see below */
325 else if (inet6ctlerrmap[cmd] == 0)
326 return;
327
328 /* if the parameter is from icmp6, decode it. */
329 if (d != NULL) {
330 ip6cp = (struct ip6ctlparam *)d;
331 ip6 = ip6cp->ip6c_ip6;
332 cmdarg = ip6cp->ip6c_cmdarg;
333 sa6_src = ip6cp->ip6c_src;
334 nxt = ip6cp->ip6c_nxt;
335 } else {
336 ip6 = NULL;
337 cmdarg = NULL;
338 sa6_src = &sa6_any;
339 nxt = -1;
340 }
341
342 if (ip6 && cmd == PRC_MSGSIZE) {
343 int valid = 0;
344 struct inpcb *inp;
345
346 /*
347 * Check to see if we have a valid raw IPv6 socket
348 * corresponding to the address in the ICMPv6 message
349 * payload, and the protocol (ip6_nxt) meets the socket.
350 * XXX chase extension headers, or pass final nxt value
351 * from icmp6_notify_error()
352 */
353 inp = in6_pcblookup(&rawin6pcbtable, &sa6->sin6_addr, 0,
354 &sa6_src->sin6_addr, 0, rdomain);
355
356 if (inp && inp->inp_ipv6.ip6_nxt &&
357 inp->inp_ipv6.ip6_nxt == nxt)
358 valid = 1;
359
360 /*
361 * Depending on the value of "valid" and routing table
362 * size (mtudisc_{hi,lo}wat), we will:
363 * - recalculate the new MTU and create the
364 * corresponding routing entry, or
365 * - ignore the MTU change notification.
366 */
367 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
368 in_pcbunref(inp);
369
370 /*
371 * regardless of if we called icmp6_mtudisc_update(),
372 * we need to call in6_pcbnotify(), to notify path
373 * MTU change to the userland (2292bis-02), because
374 * some unconnected sockets may share the same
375 * destination and want to know the path MTU.
376 */
377 }
378
379 in6_pcbnotify(&rawin6pcbtable, sa6, 0,
380 sa6_src, 0, rdomain, cmd, cmdarg, notify);
381 }
382
383 /*
384 * Generate IPv6 header and pass packet to ip6_output.
385 * Tack on options user may have setup with control call.
386 */
387 int
rip6_output(struct mbuf * m,struct socket * so,struct sockaddr * dstaddr,struct mbuf * control)388 rip6_output(struct mbuf *m, struct socket *so, struct sockaddr *dstaddr,
389 struct mbuf *control)
390 {
391 struct in6_addr *dst;
392 struct ip6_hdr *ip6;
393 struct inpcb *inp;
394 u_int plen = m->m_pkthdr.len;
395 int error = 0;
396 struct ip6_pktopts opt, *optp = NULL;
397 int type; /* for ICMPv6 output statistics only */
398 int priv = 0;
399 int flags;
400
401 inp = sotoinpcb(so);
402
403 priv = 0;
404 if ((so->so_state & SS_PRIV) != 0)
405 priv = 1;
406 if (control) {
407 if ((error = ip6_setpktopts(control, &opt,
408 inp->inp_outputopts6,
409 priv, so->so_proto->pr_protocol)) != 0)
410 goto bad;
411 optp = &opt;
412 } else
413 optp = inp->inp_outputopts6;
414
415 if (dstaddr->sa_family != AF_INET6) {
416 error = EAFNOSUPPORT;
417 goto bad;
418 }
419 dst = &satosin6(dstaddr)->sin6_addr;
420 if (IN6_IS_ADDR_V4MAPPED(dst)) {
421 error = EADDRNOTAVAIL;
422 goto bad;
423 }
424
425 /*
426 * For an ICMPv6 packet, we should know its type and code
427 * to update statistics.
428 */
429 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
430 struct icmp6_hdr *icmp6;
431 if (m->m_len < sizeof(struct icmp6_hdr) &&
432 (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
433 error = ENOBUFS;
434 goto bad;
435 }
436 icmp6 = mtod(m, struct icmp6_hdr *);
437 type = icmp6->icmp6_type;
438 }
439
440 M_PREPEND(m, sizeof(*ip6), M_DONTWAIT);
441 if (!m) {
442 error = ENOBUFS;
443 goto bad;
444 }
445 ip6 = mtod(m, struct ip6_hdr *);
446
447 /*
448 * Next header might not be ICMP6 but use its pseudo header anyway.
449 */
450 ip6->ip6_dst = *dst;
451
452 /* KAME hack: embed scopeid */
453 if (in6_embedscope(&ip6->ip6_dst, satosin6(dstaddr),
454 optp, inp->inp_moptions6) != 0) {
455 error = EINVAL;
456 goto bad;
457 }
458
459 /*
460 * Source address selection.
461 */
462 {
463 const struct in6_addr *in6a;
464
465 error = in6_pcbselsrc(&in6a, satosin6(dstaddr), inp, optp);
466 if (error)
467 goto bad;
468
469 ip6->ip6_src = *in6a;
470 }
471
472 ip6->ip6_flow = inp->inp_flowinfo & IPV6_FLOWINFO_MASK;
473 ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
474 ip6->ip6_vfc |= IPV6_VERSION;
475 #if 0 /* ip6_plen will be filled in ip6_output. */
476 ip6->ip6_plen = htons((u_short)plen);
477 #endif
478 ip6->ip6_nxt = inp->inp_ipv6.ip6_nxt;
479 ip6->ip6_hlim = in6_selecthlim(inp);
480
481 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
482 inp->inp_cksum6 != -1) {
483 struct mbuf *n;
484 int off;
485 u_int16_t *sump;
486 int sumoff;
487
488 /* compute checksum */
489 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
490 off = offsetof(struct icmp6_hdr, icmp6_cksum);
491 else
492 off = inp->inp_cksum6;
493 if (plen < 2 || plen - 2 < off) {
494 error = EINVAL;
495 goto bad;
496 }
497 off += sizeof(struct ip6_hdr);
498
499 n = m_pulldown(m, off, sizeof(*sump), &sumoff);
500 if (n == NULL) {
501 m = NULL;
502 error = ENOBUFS;
503 goto bad;
504 }
505 sump = (u_int16_t *)(mtod(n, caddr_t) + sumoff);
506 *sump = 0;
507 *sump = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
508 }
509
510 flags = 0;
511 if (inp->inp_flags & IN6P_MINMTU)
512 flags |= IPV6_MINMTU;
513
514 /* force routing table */
515 m->m_pkthdr.ph_rtableid = inp->inp_rtableid;
516
517 #if NPF > 0
518 if (inp->inp_socket->so_state & SS_ISCONNECTED &&
519 so->so_proto->pr_protocol != IPPROTO_ICMPV6)
520 pf_mbuf_link_inpcb(m, inp);
521 #endif
522
523 error = ip6_output(m, optp, &inp->inp_route, flags,
524 inp->inp_moptions6, &inp->inp_seclevel);
525 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
526 icmp6stat_inc(icp6s_outhist + type);
527 } else
528 rip6stat_inc(rip6s_opackets);
529
530 goto freectl;
531
532 bad:
533 m_freem(m);
534
535 freectl:
536 if (control) {
537 ip6_clearpktopts(&opt, -1);
538 m_freem(control);
539 }
540 return (error);
541 }
542
543 /*
544 * Raw IPv6 socket option processing.
545 */
546 int
rip6_ctloutput(int op,struct socket * so,int level,int optname,struct mbuf * m)547 rip6_ctloutput(int op, struct socket *so, int level, int optname,
548 struct mbuf *m)
549 {
550 #ifdef MROUTING
551 int error;
552 #endif
553
554 switch (level) {
555 case IPPROTO_IPV6:
556 switch (optname) {
557 #ifdef MROUTING
558 case MRT6_INIT:
559 case MRT6_DONE:
560 case MRT6_ADD_MIF:
561 case MRT6_DEL_MIF:
562 case MRT6_ADD_MFC:
563 case MRT6_DEL_MFC:
564 if (op == PRCO_SETOPT) {
565 error = ip6_mrouter_set(optname, so, m);
566 } else if (op == PRCO_GETOPT)
567 error = ip6_mrouter_get(optname, so, m);
568 else
569 error = EINVAL;
570 return (error);
571 #endif
572 case IPV6_CHECKSUM:
573 return (ip6_raw_ctloutput(op, so, level, optname, m));
574 default:
575 return (ip6_ctloutput(op, so, level, optname, m));
576 }
577
578 case IPPROTO_ICMPV6:
579 /*
580 * XXX: is it better to call icmp6_ctloutput() directly
581 * from protosw?
582 */
583 return (icmp6_ctloutput(op, so, level, optname, m));
584
585 default:
586 return EINVAL;
587 }
588 }
589
590 extern u_long rip6_sendspace;
591 extern u_long rip6_recvspace;
592
593 int
rip6_attach(struct socket * so,int proto,int wait)594 rip6_attach(struct socket *so, int proto, int wait)
595 {
596 struct inpcb *inp;
597 int error;
598
599 if (so->so_pcb)
600 panic("%s", __func__);
601 if ((so->so_state & SS_PRIV) == 0)
602 return (EACCES);
603 if (proto < 0 || proto >= IPPROTO_MAX)
604 return EPROTONOSUPPORT;
605
606 if ((error = soreserve(so, rip6_sendspace, rip6_recvspace)))
607 return error;
608 NET_ASSERT_LOCKED();
609 if ((error = in_pcballoc(so, &rawin6pcbtable, wait)))
610 return error;
611
612 inp = sotoinpcb(so);
613 inp->inp_ipv6.ip6_nxt = proto;
614 inp->inp_cksum6 = -1;
615
616 inp->inp_icmp6filt = malloc(sizeof(struct icmp6_filter), M_PCB,
617 wait == M_WAIT ? M_WAITOK : M_NOWAIT);
618 if (inp->inp_icmp6filt == NULL) {
619 in_pcbdetach(inp);
620 return ENOMEM;
621 }
622 ICMP6_FILTER_SETPASSALL(inp->inp_icmp6filt);
623 return 0;
624 }
625
626 int
rip6_detach(struct socket * so)627 rip6_detach(struct socket *so)
628 {
629 struct inpcb *inp = sotoinpcb(so);
630
631 soassertlocked(so);
632
633 if (inp == NULL)
634 panic("%s", __func__);
635 #ifdef MROUTING
636 if (so == ip6_mrouter[inp->inp_rtableid])
637 ip6_mrouter_done(so);
638 #endif
639 free(inp->inp_icmp6filt, M_PCB, sizeof(struct icmp6_filter));
640 inp->inp_icmp6filt = NULL;
641
642 in_pcbdetach(inp);
643
644 return (0);
645 }
646
647 void
rip6_lock(struct socket * so)648 rip6_lock(struct socket *so)
649 {
650 struct inpcb *inp = sotoinpcb(so);
651
652 NET_ASSERT_LOCKED();
653 mtx_enter(&inp->inp_mtx);
654 }
655
656 void
rip6_unlock(struct socket * so)657 rip6_unlock(struct socket *so)
658 {
659 struct inpcb *inp = sotoinpcb(so);
660
661 NET_ASSERT_LOCKED();
662 mtx_leave(&inp->inp_mtx);
663 }
664
665 int
rip6_locked(struct socket * so)666 rip6_locked(struct socket *so)
667 {
668 struct inpcb *inp = sotoinpcb(so);
669
670 return mtx_owned(&inp->inp_mtx);
671 }
672
673 int
rip6_bind(struct socket * so,struct mbuf * nam,struct proc * p)674 rip6_bind(struct socket *so, struct mbuf *nam, struct proc *p)
675 {
676 struct inpcb *inp = sotoinpcb(so);
677 struct sockaddr_in6 *addr;
678 int error;
679
680 soassertlocked(so);
681
682 if ((error = in6_nam2sin6(nam, &addr)))
683 return (error);
684
685 /*
686 * Make sure to not enter in_pcblookup_local(), local ports
687 * are non-sensical for raw sockets.
688 */
689 addr->sin6_port = 0;
690
691 if ((error = in6_pcbaddrisavail(inp, addr, 0, p)))
692 return (error);
693
694 mtx_enter(&rawin6pcbtable.inpt_mtx);
695 inp->inp_laddr6 = addr->sin6_addr;
696 mtx_leave(&rawin6pcbtable.inpt_mtx);
697
698 return (0);
699 }
700
701 int
rip6_connect(struct socket * so,struct mbuf * nam)702 rip6_connect(struct socket *so, struct mbuf *nam)
703 {
704 struct inpcb *inp = sotoinpcb(so);
705 struct sockaddr_in6 *addr;
706 const struct in6_addr *in6a;
707 int error;
708
709 soassertlocked(so);
710
711 if ((error = in6_nam2sin6(nam, &addr)))
712 return (error);
713
714 /* Source address selection. XXX: need pcblookup? */
715 error = in6_pcbselsrc(&in6a, addr, inp, inp->inp_outputopts6);
716 if (error)
717 return (error);
718
719 mtx_enter(&rawin6pcbtable.inpt_mtx);
720 inp->inp_laddr6 = *in6a;
721 inp->inp_faddr6 = addr->sin6_addr;
722 mtx_leave(&rawin6pcbtable.inpt_mtx);
723 soisconnected(so);
724
725 return (0);
726 }
727
728 int
rip6_disconnect(struct socket * so)729 rip6_disconnect(struct socket *so)
730 {
731 struct inpcb *inp = sotoinpcb(so);
732
733 soassertlocked(so);
734
735 if ((so->so_state & SS_ISCONNECTED) == 0)
736 return (ENOTCONN);
737
738 soisdisconnected(so);
739 mtx_enter(&rawin6pcbtable.inpt_mtx);
740 inp->inp_faddr6 = in6addr_any;
741 mtx_leave(&rawin6pcbtable.inpt_mtx);
742
743 return (0);
744 }
745
746 int
rip6_shutdown(struct socket * so)747 rip6_shutdown(struct socket *so)
748 {
749 /*
750 * Mark the connection as being incapable of further input.
751 */
752 soassertlocked(so);
753 socantsendmore(so);
754 return (0);
755 }
756
757 int
rip6_send(struct socket * so,struct mbuf * m,struct mbuf * nam,struct mbuf * control)758 rip6_send(struct socket *so, struct mbuf *m, struct mbuf *nam,
759 struct mbuf *control)
760 {
761 struct inpcb *inp = sotoinpcb(so);
762 struct sockaddr_in6 dst;
763 int error;
764
765 soassertlocked(so);
766
767 /*
768 * Ship a packet out. The appropriate raw output
769 * routine handles any messaging necessary.
770 */
771
772 /* always copy sockaddr to avoid overwrites */
773 memset(&dst, 0, sizeof(dst));
774 dst.sin6_family = AF_INET6;
775 dst.sin6_len = sizeof(dst);
776 if (so->so_state & SS_ISCONNECTED) {
777 if (nam) {
778 error = EISCONN;
779 goto out;
780 }
781 dst.sin6_addr = inp->inp_faddr6;
782 } else {
783 struct sockaddr_in6 *addr6;
784
785 if (nam == NULL) {
786 error = ENOTCONN;
787 goto out;
788 }
789 if ((error = in6_nam2sin6(nam, &addr6)))
790 goto out;
791 dst.sin6_addr = addr6->sin6_addr;
792 dst.sin6_scope_id = addr6->sin6_scope_id;
793 }
794 error = rip6_output(m, so, sin6tosa(&dst), control);
795 control = NULL;
796 m = NULL;
797
798 out:
799 m_freem(control);
800 m_freem(m);
801
802 return (error);
803 }
804
805 int
rip6_sysctl_rip6stat(void * oldp,size_t * oldplen,void * newp)806 rip6_sysctl_rip6stat(void *oldp, size_t *oldplen, void *newp)
807 {
808 struct rip6stat rip6stat;
809
810 CTASSERT(sizeof(rip6stat) == rip6s_ncounters * sizeof(uint64_t));
811 counters_read(rip6counters, (uint64_t *)&rip6stat, rip6s_ncounters,
812 NULL);
813
814 return (sysctl_rdstruct(oldp, oldplen, newp,
815 &rip6stat, sizeof(rip6stat)));
816 }
817
818 int
rip6_sysctl(int * name,u_int namelen,void * oldp,size_t * oldlenp,void * newp,size_t newlen)819 rip6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
820 void *newp, size_t newlen)
821 {
822 /* All sysctl names at this level are terminal. */
823 if (namelen != 1)
824 return ENOTDIR;
825
826 switch (name[0]) {
827 case RIPV6CTL_STATS:
828 return (rip6_sysctl_rip6stat(oldp, oldlenp, newp));
829 default:
830 return (EOPNOTSUPP);
831 }
832 /* NOTREACHED */
833 }
834