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