2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * Copyright (c) 1982, 1986, 1988, 1993
32 * The Regents of the University of California. All rights reserved.
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 * 3. All advertising materials mentioning features or use of this software
43 * must display the following acknowledgement:
44 * This product includes software developed by the University of
45 * California, Berkeley and its contributors.
46 * 4. Neither the name of the University nor the names of its contributors
47 * may be used to endorse or promote products derived from this software
48 * without specific prior written permission.
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94
70 #include <sys/param.h>
71 #include <sys/malloc.h>
74 #include <sys/socket.h>
75 #include <sys/protosw.h>
76 #include <sys/socketvar.h>
77 #include <sys/errno.h>
78 #include <sys/systm.h>
81 #include <net/route.h>
82 #include <net/if_types.h>
84 #include <netinet/in.h>
85 #include <netinet/in_var.h>
86 #include <netinet/in_systm.h>
87 #include <netinet/ip6.h>
88 #include <netinet6/ip6_var.h>
89 #include <netinet6/ip6_mroute.h>
90 #include <netinet/icmp6.h>
91 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
92 #include <netinet/in_pcb.h>
94 #include <netinet6/in6_pcb.h>
95 #include <netinet6/nd6.h>
96 #include <netinet6/ip6protosw.h>
99 #include <netinet6/ipsec.h>
105 #define satosin6(sa) ((struct sockaddr_in6 *)(sa))
106 #define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa))
109 * Raw interface to IP6 protocol.
112 extern struct inpcbhead ripcb
;
113 extern struct inpcbinfo ripcbinfo
;
114 extern u_long rip_sendspace
;
115 extern u_long rip_recvspace
;
118 * Setup generic address and protocol structures
119 * for raw_input routine, then pass them along with
123 rip6_input(mp
, offp
, proto
)
127 struct mbuf
*m
= *mp
;
128 register struct ip6_hdr
*ip6
= mtod(m
, struct ip6_hdr
*);
129 register struct inpcb
*in6p
;
130 struct inpcb
*last
= 0;
131 struct ip6_recvpktopts opts
;
132 struct sockaddr_in6 rip6src
;
134 #if defined(NFAITH) && 0 < NFAITH
135 if (m
->m_pkthdr
.rcvif
) {
136 if (m
->m_pkthdr
.rcvif
->if_type
== IFT_FAITH
) {
137 /* XXX send icmp6 host/port unreach? */
143 init_sin6(&rip6src
, m
); /* general init */
144 bzero(&opts
, sizeof(opts
));
146 LIST_FOREACH(in6p
, &ripcb
, inp_list
) {
147 if ((in6p
->in6p_vflag
& INP_IPV6
) == NULL
)
149 if (in6p
->in6p_ip6_nxt
&&
150 in6p
->in6p_ip6_nxt
!= proto
)
152 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p
->in6p_laddr
) &&
153 !IN6_ARE_ADDR_EQUAL(&in6p
->in6p_laddr
, &ip6
->ip6_dst
))
155 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p
->in6p_faddr
) &&
156 !IN6_ARE_ADDR_EQUAL(&in6p
->in6p_faddr
, &ip6
->ip6_src
))
158 if (in6p
->in6p_cksum
!= -1
159 && in6_cksum(m
, ip6
->ip6_nxt
, *offp
,
160 m
->m_pkthdr
.len
- *offp
)) {
161 /* XXX bark something */
165 struct mbuf
*n
= m_copy(m
, 0, (int)M_COPYALL
);
167 if (last
->in6p_flags
& IN6P_CONTROLOPTS
||
168 last
->in6p_socket
->so_options
& SO_TIMESTAMP
)
169 ip6_savecontrol(last
, ip6
, n
, &opts
,
171 /* strip intermediate headers */
173 if (sbappendaddr(&last
->in6p_socket
->so_rcv
,
174 (struct sockaddr
*)&rip6src
,
175 n
, opts
.head
) == 0) {
176 /* should notify about lost packet */
181 sorwakeup(last
->in6p_socket
);
182 bzero(&opts
, sizeof(opts
));
188 if (last
->in6p_flags
& IN6P_CONTROLOPTS
||
189 last
->in6p_socket
->so_options
& SO_TIMESTAMP
)
190 ip6_savecontrol(last
, ip6
, m
, &opts
, NULL
);
191 /* strip intermediate headers */
193 if (sbappendaddr(&last
->in6p_socket
->so_rcv
,
194 (struct sockaddr
*)&rip6src
, m
, opts
.head
) == 0) {
199 sorwakeup(last
->in6p_socket
);
201 if (proto
== IPPROTO_NONE
)
204 char *prvnxtp
= ip6_get_prevhdr(m
, *offp
); /* XXX */
205 icmp6_error(m
, ICMP6_PARAM_PROB
,
206 ICMP6_PARAMPROB_NEXTHEADER
,
207 prvnxtp
- mtod(m
, char *));
209 ip6stat
.ip6s_delivered
--;
215 rip6_ctlinput(cmd
, sa
, d
)
220 struct sockaddr_in6 sa6
;
224 void (*notify
) __P((struct inpcb
*, int)) = in6_rtchange
;
226 if (sa
->sa_family
!= AF_INET6
||
227 sa
->sa_len
!= sizeof(struct sockaddr_in6
))
230 if ((unsigned)cmd
>= PRC_NCMDS
)
232 if (PRC_IS_REDIRECT(cmd
))
233 notify
= in6_rtchange
, d
= NULL
;
234 else if (cmd
== PRC_HOSTDEAD
)
236 else if (inet6ctlerrmap
[cmd
] == 0)
239 /* if the parameter is from icmp6, decode it. */
241 struct ip6ctlparam
*ip6cp
= (struct ip6ctlparam
*)d
;
243 ip6
= ip6cp
->ip6c_ip6
;
244 off
= ip6cp
->ip6c_off
;
250 /* translate addresses into internal form */
251 sa6
= *(struct sockaddr_in6
*)sa
;
252 if (IN6_IS_ADDR_LINKLOCAL(&sa6
.sin6_addr
) && m
&& m
->m_pkthdr
.rcvif
)
253 sa6
.sin6_addr
.s6_addr16
[1] = htons(m
->m_pkthdr
.rcvif
->if_index
);
257 * XXX: We assume that when IPV6 is non NULL,
258 * M and OFF are valid.
262 /* translate addresses into internal form */
263 memcpy(&s
, &ip6
->ip6_src
, sizeof(s
));
264 if (IN6_IS_ADDR_LINKLOCAL(&s
))
265 s
.s6_addr16
[1] = htons(m
->m_pkthdr
.rcvif
->if_index
);
267 (void) in6_pcbnotify(&ripcb
, (struct sockaddr
*)&sa6
,
268 0, &s
, 0, cmd
, notify
);
270 (void) in6_pcbnotify(&ripcb
, (struct sockaddr
*)&sa6
, 0,
271 &zeroin6_addr
, 0, cmd
, notify
);
275 * Generate IPv6 header and pass packet to ip6_output.
276 * Tack on options user may have setup with control call.
279 rip6_output(m
, so
, dstsock
, control
)
280 register struct mbuf
*m
;
282 struct sockaddr_in6
*dstsock
;
283 struct mbuf
*control
;
285 struct in6_addr
*dst
;
288 u_int plen
= m
->m_pkthdr
.len
;
290 struct ip6_pktopts opt
, *optp
= 0;
291 struct ifnet
*oifp
= NULL
;
292 int type
= 0, code
= 0; /* for ICMPv6 output statistics only */
295 in6p
= sotoin6pcb(so
);
298 #if !defined(__APPLE__)
300 struct proc
*p
= current_proc(); /* XXX */
302 if (p
&& !suser(p
->p_ucred
, &p
->p_acflag
))
306 if ((so
->so_state
& SS_PRIV
) != 0)
309 dst
= &dstsock
->sin6_addr
;
311 if ((error
= ip6_setpktoptions(control
, &opt
, priv
, 0)) != 0)
315 optp
= in6p
->in6p_outputopts
;
318 * For an ICMPv6 packet, we should know its type and code
319 * to update statistics.
321 if (so
->so_proto
->pr_protocol
== IPPROTO_ICMPV6
) {
322 struct icmp6_hdr
*icmp6
;
323 if (m
->m_len
< sizeof(struct icmp6_hdr
) &&
324 (m
= m_pullup(m
, sizeof(struct icmp6_hdr
))) == NULL
) {
328 icmp6
= mtod(m
, struct icmp6_hdr
*);
329 type
= icmp6
->icmp6_type
;
330 code
= icmp6
->icmp6_code
;
333 M_PREPEND(m
, sizeof(*ip6
), M_WAIT
);
334 ip6
= mtod(m
, struct ip6_hdr
*);
337 * Next header might not be ICMP6 but use its pseudo header anyway.
342 * If the scope of the destination is link-local, embed the interface
343 * index in the address.
345 * XXX advanced-api value overrides sin6_scope_id
347 if (IN6_IS_SCOPE_LINKLOCAL(&ip6
->ip6_dst
)) {
348 struct in6_pktinfo
*pi
;
351 * XXX Boundary check is assumed to be already done in
352 * ip6_setpktoptions().
354 if (optp
&& (pi
= optp
->ip6po_pktinfo
) && pi
->ipi6_ifindex
) {
355 ip6
->ip6_dst
.s6_addr16
[1] = htons(pi
->ipi6_ifindex
);
356 oifp
= ifindex2ifnet
[pi
->ipi6_ifindex
];
358 else if (IN6_IS_ADDR_MULTICAST(&ip6
->ip6_dst
) &&
359 in6p
->in6p_moptions
&&
360 in6p
->in6p_moptions
->im6o_multicast_ifp
) {
361 oifp
= in6p
->in6p_moptions
->im6o_multicast_ifp
;
362 ip6
->ip6_dst
.s6_addr16
[1] = htons(oifp
->if_index
);
363 } else if (dstsock
->sin6_scope_id
) {
365 if (dstsock
->sin6_scope_id
< 0
366 || if_index
< dstsock
->sin6_scope_id
) {
367 error
= ENXIO
; /* XXX EINVAL? */
370 ip6
->ip6_dst
.s6_addr16
[1]
371 = htons(dstsock
->sin6_scope_id
& 0xffff);/*XXX*/
376 * Source address selection.
379 struct in6_addr
*in6a
;
381 if ((in6a
= in6_selectsrc(dstsock
, optp
,
387 error
= EADDRNOTAVAIL
;
390 ip6
->ip6_src
= *in6a
;
391 if (in6p
->in6p_route
.ro_rt
)
392 oifp
= ifindex2ifnet
[in6p
->in6p_route
.ro_rt
->rt_ifp
->if_index
];
395 ip6
->ip6_flow
= in6p
->in6p_flowinfo
& IPV6_FLOWINFO_MASK
;
396 ip6
->ip6_vfc
|= IPV6_VERSION
;
397 #if 0 /* ip6_plen will be filled in ip6_output. */
398 ip6
->ip6_plen
= htons((u_short
)plen
);
400 ip6
->ip6_nxt
= in6p
->in6p_ip6_nxt
;
401 ip6
->ip6_hlim
= in6_selecthlim(in6p
, oifp
);
403 if (so
->so_proto
->pr_protocol
== IPPROTO_ICMPV6
||
404 in6p
->in6p_cksum
!= -1) {
409 #define offsetof(type, member) ((size_t)(&((type *)0)->member)) /* XXX */
411 /* compute checksum */
412 if (so
->so_proto
->pr_protocol
== IPPROTO_ICMPV6
)
413 off
= offsetof(struct icmp6_hdr
, icmp6_cksum
);
415 off
= in6p
->in6p_cksum
;
416 if (plen
< off
+ 1) {
420 off
+= sizeof(struct ip6_hdr
);
423 while (n
&& n
->m_len
<= off
) {
429 p
= (u_int16_t
*)(mtod(n
, caddr_t
) + off
);
431 *p
= in6_cksum(m
, ip6
->ip6_nxt
, sizeof(*ip6
), plen
);
435 ipsec_setsocket(m
, so
);
438 error
= ip6_output(m
, optp
, &in6p
->in6p_route
, 0, in6p
->in6p_moptions
,
440 if (so
->so_proto
->pr_protocol
== IPPROTO_ICMPV6
) {
442 icmp6_ifoutstat_inc(oifp
, type
, code
);
443 icmp6stat
.icp6s_outhist
[type
]++;
453 if (optp
== &opt
&& optp
->ip6po_rthdr
&& optp
->ip6po_route
.ro_rt
)
454 RTFREE(optp
->ip6po_route
.ro_rt
);
457 ip6_clearpktopts(optp
, 0, -1);
464 * Raw IPv6 socket option processing.
467 rip6_ctloutput(so
, sopt
)
469 struct sockopt
*sopt
;
473 if (sopt
->sopt_level
== IPPROTO_ICMPV6
)
475 * XXX: is it better to call icmp6_ctloutput() directly
478 return(icmp6_ctloutput(so
, sopt
));
479 else if (sopt
->sopt_level
!= IPPROTO_IPV6
)
484 switch (sopt
->sopt_dir
) {
486 switch (sopt
->sopt_name
) {
494 error
= ip6_mrouter_get(so
, sopt
);
497 error
= ip6_ctloutput(so
, sopt
);
503 switch (sopt
->sopt_name
) {
511 error
= ip6_mrouter_set(so
, sopt
);
514 error
= ip6_ctloutput(so
, sopt
);
524 rip6_attach(struct socket
*so
, int proto
, struct proc
*p
)
531 panic("rip6_attach");
532 if (p
&& (error
= suser(p
->p_ucred
, &p
->p_acflag
)) != 0)
535 if (so
->so_snd
.sb_hiwat
== 0 || so
->so_rcv
.sb_hiwat
== 0) {
536 error
= soreserve(so
, rip_sendspace
, rip_recvspace
);
541 error
= in_pcballoc(so
, &ripcbinfo
, p
);
545 inp
= (struct inpcb
*)so
->so_pcb
;
546 inp
->inp_vflag
|= INP_IPV6
;
547 inp
->in6p_ip6_nxt
= (long)proto
;
548 inp
->in6p_hops
= -1; /* use kernel default */
549 inp
->in6p_cksum
= -1;
551 error
= ipsec_init_policy(so
, &inp
->in6p_sp
);
557 MALLOC(inp
->in6p_icmp6filt
, struct icmp6_filter
*,
558 sizeof(struct icmp6_filter
), M_PCB
, M_NOWAIT
);
559 ICMP6_FILTER_SETPASSALL(inp
->in6p_icmp6filt
);
564 rip6_detach(struct socket
*so
)
570 panic("rip6_detach");
571 if (so
== ip6_mrouter
)
574 if (inp
->in6p_icmp6filt
) {
575 FREE(inp
->in6p_icmp6filt
, M_PCB
);
576 inp
->in6p_icmp6filt
= NULL
;
583 rip6_abort(struct socket
*so
)
585 soisdisconnected(so
);
586 return rip6_detach(so
);
590 rip6_disconnect(struct socket
*so
)
592 struct inpcb
*inp
= sotoinpcb(so
);
594 if ((so
->so_state
& SS_ISCONNECTED
) == 0)
596 inp
->in6p_faddr
= in6addr_any
;
597 return rip6_abort(so
);
601 rip6_bind(struct socket
*so
, struct sockaddr
*nam
, struct proc
*p
)
603 struct inpcb
*inp
= sotoinpcb(so
);
604 struct sockaddr_in6
*addr
= (struct sockaddr_in6
*)nam
;
605 struct ifaddr
*ia
= NULL
;
607 if (nam
->sa_len
!= sizeof(*addr
))
610 if (TAILQ_EMPTY(&ifnet
) || addr
->sin6_family
!= AF_INET6
)
611 return EADDRNOTAVAIL
;
612 if (!IN6_IS_ADDR_UNSPECIFIED(&addr
->sin6_addr
) &&
613 (ia
= ifa_ifwithaddr((struct sockaddr
*)addr
)) == 0)
614 return EADDRNOTAVAIL
;
616 ((struct in6_ifaddr
*)ia
)->ia6_flags
&
617 (IN6_IFF_ANYCAST
|IN6_IFF_NOTREADY
|
618 IN6_IFF_DETACHED
|IN6_IFF_DEPRECATED
)) {
619 return(EADDRNOTAVAIL
);
621 inp
->in6p_laddr
= addr
->sin6_addr
;
626 rip6_connect(struct socket
*so
, struct sockaddr
*nam
, struct proc
*p
)
628 struct inpcb
*inp
= sotoinpcb(so
);
629 struct sockaddr_in6
*addr
= (struct sockaddr_in6
*)nam
;
630 struct in6_addr
*in6a
= NULL
;
633 if (nam
->sa_len
!= sizeof(*addr
))
635 if (TAILQ_EMPTY(&ifnet
))
636 return EADDRNOTAVAIL
;
637 if (addr
->sin6_family
!= AF_INET6
)
640 /* Source address selection. XXX: need pcblookup? */
641 in6a
= in6_selectsrc(addr
, inp
->in6p_outputopts
,
642 inp
->in6p_moptions
, &inp
->in6p_route
,
643 &inp
->in6p_laddr
, &error
);
645 return (error
? error
: EADDRNOTAVAIL
);
646 inp
->in6p_laddr
= *in6a
;
647 inp
->in6p_faddr
= addr
->sin6_addr
;
653 rip6_shutdown(struct socket
*so
)
660 rip6_send(struct socket
*so
, int flags
, struct mbuf
*m
, struct sockaddr
*nam
,
661 struct mbuf
*control
, struct proc
*p
)
663 struct inpcb
*inp
= sotoinpcb(so
);
664 struct sockaddr_in6 tmp
;
665 struct sockaddr_in6
*dst
;
667 if (so
->so_state
& SS_ISCONNECTED
) {
673 bzero(&tmp
, sizeof(tmp
));
674 tmp
.sin6_family
= AF_INET6
;
675 tmp
.sin6_len
= sizeof(struct sockaddr_in6
);
676 bcopy(&inp
->in6p_faddr
, &tmp
.sin6_addr
,
677 sizeof(struct in6_addr
));
684 dst
= (struct sockaddr_in6
*)nam
;
686 return rip6_output(m
, so
, dst
, control
);
689 struct pr_usrreqs rip6_usrreqs
= {
690 rip6_abort
, pru_accept_notsupp
, rip6_attach
, rip6_bind
, rip6_connect
,
691 pru_connect2_notsupp
, in6_control
, rip6_detach
, rip6_disconnect
,
692 pru_listen_notsupp
, in6_setpeeraddr
, pru_rcvd_notsupp
,
693 pru_rcvoob_notsupp
, rip6_send
, pru_sense_null
, rip6_shutdown
,
694 in6_setsockaddr
, sosend
, soreceive
, sopoll