]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/raw_ip6.c
xnu-1699.22.73.tar.gz
[apple/xnu.git] / bsd / netinet6 / raw_ip6.c
CommitLineData
b0d623f7 1/*
060df5ea 2 * Copyright (c) 2000-2011 Apple Inc. All rights reserved.
b0d623f7
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
1c79356b
A
28/*
29 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
30 * All rights reserved.
9bccf70c 31 *
1c79356b
A
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. Neither the name of the project nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
9bccf70c 43 *
1c79356b
A
44 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
9bccf70c
A
55 *
56 * $FreeBSD: src/sys/netinet6/raw_ip6.c,v 1.7.2.4 2001/07/29 19:32:40 ume Exp $
1c79356b
A
57 */
58
59/*
60 * Copyright (c) 1982, 1986, 1988, 1993
61 * The Regents of the University of California. All rights reserved.
62 *
63 * Redistribution and use in source and binary forms, with or without
64 * modification, are permitted provided that the following conditions
65 * are met:
66 * 1. Redistributions of source code must retain the above copyright
67 * notice, this list of conditions and the following disclaimer.
68 * 2. Redistributions in binary form must reproduce the above copyright
69 * notice, this list of conditions and the following disclaimer in the
70 * documentation and/or other materials provided with the distribution.
71 * 3. All advertising materials mentioning features or use of this software
72 * must display the following acknowledgement:
73 * This product includes software developed by the University of
74 * California, Berkeley and its contributors.
75 * 4. Neither the name of the University nor the names of its contributors
76 * may be used to endorse or promote products derived from this software
77 * without specific prior written permission.
78 *
79 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
80 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
81 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
82 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
83 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
84 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
85 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
86 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
87 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
88 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
89 * SUCH DAMAGE.
90 *
91 * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94
92 */
1c79356b
A
93#include <sys/param.h>
94#include <sys/malloc.h>
95#include <sys/proc.h>
96#include <sys/mbuf.h>
97#include <sys/socket.h>
98#include <sys/protosw.h>
99#include <sys/socketvar.h>
100#include <sys/errno.h>
101#include <sys/systm.h>
102
103#include <net/if.h>
104#include <net/route.h>
105#include <net/if_types.h>
106
107#include <netinet/in.h>
108#include <netinet/in_var.h>
109#include <netinet/in_systm.h>
110#include <netinet/ip6.h>
111#include <netinet6/ip6_var.h>
112#include <netinet6/ip6_mroute.h>
113#include <netinet/icmp6.h>
1c79356b 114#include <netinet/in_pcb.h>
1c79356b
A
115#include <netinet6/in6_pcb.h>
116#include <netinet6/nd6.h>
117#include <netinet6/ip6protosw.h>
9bccf70c
A
118#if ENABLE_DEFAULT_SCOPE
119#include <netinet6/scope6_var.h>
120#endif
121#include <netinet6/raw_ip6.h>
91447636 122#include <netinet6/ip6_fw.h>
1c79356b
A
123
124#if IPSEC
125#include <netinet6/ipsec.h>
9bccf70c
A
126#include <netinet6/ipsec6.h>
127extern int ipsec_bypass;
1c79356b
A
128#endif /*IPSEC*/
129
9bccf70c
A
130#define satosin6(sa) ((struct sockaddr_in6 *)(sa))
131#define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa))
1c79356b
A
132
133/*
134 * Raw interface to IP6 protocol.
135 */
136
9bccf70c
A
137extern struct inpcbhead ripcb;
138extern struct inpcbinfo ripcbinfo;
b0d623f7
A
139extern u_int32_t rip_sendspace;
140extern u_int32_t rip_recvspace;
6d2010ae 141extern int ip6_raw_ctloutput(struct socket *so, struct sockopt *sopt);
1c79356b 142
9bccf70c
A
143struct rip6stat rip6stat;
144
1c79356b
A
145/*
146 * Setup generic address and protocol structures
147 * for raw_input routine, then pass them along with
148 * mbuf chain.
149 */
150int
91447636
A
151rip6_input(
152 struct mbuf **mp,
6d2010ae
A
153 int *offp,
154 int proto)
1c79356b
A
155{
156 struct mbuf *m = *mp;
157 register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
158 register struct inpcb *in6p;
159 struct inpcb *last = 0;
9bccf70c 160 struct mbuf *opts = NULL;
1c79356b 161 struct sockaddr_in6 rip6src;
6d2010ae 162 int ret;
9bccf70c
A
163
164 rip6stat.rip6s_ipackets++;
1c79356b
A
165
166#if defined(NFAITH) && 0 < NFAITH
9bccf70c
A
167 if (faithprefix(&ip6->ip6_dst)) {
168 /* XXX send icmp6 host/port unreach? */
169 m_freem(m);
170 return IPPROTO_DONE;
1c79356b
A
171 }
172#endif
9bccf70c 173
1c79356b 174 init_sin6(&rip6src, m); /* general init */
1c79356b 175
91447636 176 lck_rw_lock_shared(ripcbinfo.mtx);
1c79356b 177 LIST_FOREACH(in6p, &ripcb, inp_list) {
9bccf70c 178 if ((in6p->in6p_vflag & INP_IPV6) == 0)
1c79356b
A
179 continue;
180 if (in6p->in6p_ip6_nxt &&
181 in6p->in6p_ip6_nxt != proto)
182 continue;
183 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
184 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
185 continue;
186 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
187 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
188 continue;
9bccf70c
A
189 if (in6p->in6p_cksum != -1) {
190 rip6stat.rip6s_isum++;
191 if (in6_cksum(m, ip6->ip6_nxt, *offp,
192 m->m_pkthdr.len - *offp)) {
193 rip6stat.rip6s_badsum++;
194 continue;
195 }
1c79356b
A
196 }
197 if (last) {
198 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
9bccf70c
A
199
200#if IPSEC
201 /*
202 * Check AH/ESP integrity.
203 */
2d21ac55 204 if (ipsec_bypass == 0 && n && ipsec6_in_reject_so(n, last->inp_socket)) {
91447636 205 m_freem(n);
2d21ac55 206 IPSEC_STAT_INCREMENT(ipsec6stat.in_polvio);
91447636 207 /* do not inject data into pcb */
9bccf70c
A
208 } else
209#endif /*IPSEC*/
1c79356b 210 if (n) {
6d2010ae
A
211 if ((last->in6p_flags & IN6P_CONTROLOPTS) != 0 ||
212 (last->in6p_socket->so_options & SO_TIMESTAMP) != 0 ||
213 (last->in6p_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0) {
214 ret = ip6_savecontrol(last, n, &opts);
215 if (ret != 0) {
216 m_freem(n);
217 m_freem(opts);
218 last = in6p;
219 continue;
220 }
221 }
1c79356b
A
222 /* strip intermediate headers */
223 m_adj(n, *offp);
6d2010ae 224 so_recv_data_stat(last->in6p_socket, m, 0);
1c79356b
A
225 if (sbappendaddr(&last->in6p_socket->so_rcv,
226 (struct sockaddr *)&rip6src,
91447636 227 n, opts, NULL) == 0) {
9bccf70c 228 rip6stat.rip6s_fullsock++;
1c79356b
A
229 } else
230 sorwakeup(last->in6p_socket);
9bccf70c 231 opts = NULL;
1c79356b
A
232 }
233 }
234 last = in6p;
235 }
6d2010ae 236
9bccf70c
A
237#if IPSEC
238 /*
239 * Check AH/ESP integrity.
240 */
2d21ac55 241 if (ipsec_bypass == 0 && last && ipsec6_in_reject_so(m, last->inp_socket)) {
91447636 242 m_freem(m);
2d21ac55 243 IPSEC_STAT_INCREMENT(ipsec6stat.in_polvio);
91447636
A
244 ip6stat.ip6s_delivered--;
245 /* do not inject data into pcb */
9bccf70c
A
246 } else
247#endif /*IPSEC*/
1c79356b 248 if (last) {
6d2010ae
A
249 if ((last->in6p_flags & IN6P_CONTROLOPTS) != 0 ||
250 (last->in6p_socket->so_options & SO_TIMESTAMP) != 0 ||
251 (last->in6p_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0) {
252 ret = ip6_savecontrol(last, m, &opts);
253 if (ret != 0) {
254 m_freem(m);
255 m_freem(opts);
256 ip6stat.ip6s_delivered--;
257 goto unlock;
258 }
259
260 }
1c79356b
A
261 /* strip intermediate headers */
262 m_adj(m, *offp);
6d2010ae 263 so_recv_data_stat(last->in6p_socket, m, 0);
1c79356b 264 if (sbappendaddr(&last->in6p_socket->so_rcv,
91447636 265 (struct sockaddr *)&rip6src, m, opts, NULL) == 0) {
9bccf70c 266 rip6stat.rip6s_fullsock++;
1c79356b
A
267 } else
268 sorwakeup(last->in6p_socket);
269 } else {
9bccf70c
A
270 rip6stat.rip6s_nosock++;
271 if (m->m_flags & M_MCAST)
272 rip6stat.rip6s_nosockmcast++;
1c79356b
A
273 if (proto == IPPROTO_NONE)
274 m_freem(m);
275 else {
276 char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
277 icmp6_error(m, ICMP6_PARAM_PROB,
278 ICMP6_PARAMPROB_NEXTHEADER,
279 prvnxtp - mtod(m, char *));
280 }
281 ip6stat.ip6s_delivered--;
282 }
6d2010ae
A
283
284unlock:
285 lck_rw_done(ripcbinfo.mtx);
286
1c79356b
A
287 return IPPROTO_DONE;
288}
289
290void
91447636
A
291rip6_ctlinput(
292 int cmd,
293 struct sockaddr *sa,
294 void *d)
1c79356b 295{
1c79356b
A
296 struct ip6_hdr *ip6;
297 struct mbuf *m;
6d2010ae 298 void *cmdarg = NULL;
1c79356b 299 int off = 0;
9bccf70c
A
300 struct ip6ctlparam *ip6cp = NULL;
301 const struct sockaddr_in6 *sa6_src = NULL;
91447636 302 void (*notify)(struct inpcb *, int) = in6_rtchange;
1c79356b
A
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 = in6_rtchange, d = NULL;
312 else if (cmd == PRC_HOSTDEAD)
313 d = NULL;
314 else if (inet6ctlerrmap[cmd] == 0)
315 return;
316
317 /* if the parameter is from icmp6, decode it. */
318 if (d != NULL) {
9bccf70c 319 ip6cp = (struct ip6ctlparam *)d;
1c79356b
A
320 m = ip6cp->ip6c_m;
321 ip6 = ip6cp->ip6c_ip6;
322 off = ip6cp->ip6c_off;
6d2010ae 323 cmdarg = ip6cp->ip6c_cmdarg;
9bccf70c 324 sa6_src = ip6cp->ip6c_src;
1c79356b
A
325 } else {
326 m = NULL;
327 ip6 = NULL;
9bccf70c 328 sa6_src = &sa6_any;
1c79356b
A
329 }
330
2d21ac55 331 (void) in6_pcbnotify(&ripcbinfo, sa, 0, (const struct sockaddr *)sa6_src,
6d2010ae 332 0, cmd, cmdarg, notify);
1c79356b
A
333}
334
335/*
336 * Generate IPv6 header and pass packet to ip6_output.
337 * Tack on options user may have setup with control call.
338 */
339int
91447636
A
340rip6_output(
341 register struct mbuf *m,
342 struct socket *so,
343 struct sockaddr_in6 *dstsock,
6d2010ae
A
344 struct mbuf *control,
345 int israw)
1c79356b
A
346{
347 struct in6_addr *dst;
348 struct ip6_hdr *ip6;
349 struct inpcb *in6p;
350 u_int plen = m->m_pkthdr.len;
351 int error = 0;
352 struct ip6_pktopts opt, *optp = 0;
6d2010ae 353 struct ip6_moptions *im6o = NULL;
1c79356b
A
354 struct ifnet *oifp = NULL;
355 int type = 0, code = 0; /* for ICMPv6 output statistics only */
6d2010ae
A
356 mbuf_traffic_class_t mtc = MBUF_TC_UNSPEC;
357 struct ip6_out_args ip6oa = { IFSCOPE_NONE, 0 };
358 int flags = IPV6_OUTARGS;
359
360 if (dstsock && IN6_IS_ADDR_V4MAPPED(&dstsock->sin6_addr)) {
361 m_freem(m);
362 return (EINVAL);
363 }
1c79356b
A
364
365 in6p = sotoin6pcb(so);
366
6d2010ae
A
367 ip6oa.ip6oa_boundif = (in6p->inp_flags & INP_BOUND_IF) ?
368 in6p->inp_boundif : IFSCOPE_NONE;
369 ip6oa.ip6oa_nocell = (in6p->inp_flags & INP_NO_IFT_CELLULAR) ? 1 : 0;
370
1c79356b
A
371 dst = &dstsock->sin6_addr;
372 if (control) {
d41d1dae 373 mtc = mbuf_traffic_class_from_control(control);
d41d1dae 374
6d2010ae 375 if ((error = ip6_setpktopts(control, &opt, NULL, so->so_proto->pr_protocol)) != 0)
1c79356b
A
376 goto bad;
377 optp = &opt;
378 } else
379 optp = in6p->in6p_outputopts;
380
381 /*
382 * For an ICMPv6 packet, we should know its type and code
383 * to update statistics.
384 */
385 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
386 struct icmp6_hdr *icmp6;
387 if (m->m_len < sizeof(struct icmp6_hdr) &&
388 (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
389 error = ENOBUFS;
390 goto bad;
391 }
392 icmp6 = mtod(m, struct icmp6_hdr *);
393 type = icmp6->icmp6_type;
394 code = icmp6->icmp6_code;
395 }
396
397 M_PREPEND(m, sizeof(*ip6), M_WAIT);
b0d623f7
A
398 if (m == NULL) {
399 error = ENOBUFS;
400 goto bad;
401 }
1c79356b
A
402 ip6 = mtod(m, struct ip6_hdr *);
403
404 /*
405 * Next header might not be ICMP6 but use its pseudo header anyway.
406 */
407 ip6->ip6_dst = *dst;
408
6d2010ae
A
409 im6o = in6p->in6p_moptions;
410
1c79356b
A
411 /*
412 * If the scope of the destination is link-local, embed the interface
413 * index in the address.
414 *
9bccf70c 415 * XXX advanced-api value overrides sin6_scope_id
1c79356b
A
416 */
417 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
418 struct in6_pktinfo *pi;
6d2010ae 419 struct ifnet *im6o_multicast_ifp = NULL;
1c79356b 420
6d2010ae
A
421 if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && im6o != NULL) {
422 IM6O_LOCK(im6o);
423 im6o_multicast_ifp = im6o->im6o_multicast_ifp;
424 IM6O_UNLOCK(im6o);
425 }
1c79356b
A
426 /*
427 * XXX Boundary check is assumed to be already done in
428 * ip6_setpktoptions().
429 */
b0d623f7 430 ifnet_head_lock_shared();
1c79356b
A
431 if (optp && (pi = optp->ip6po_pktinfo) && pi->ipi6_ifindex) {
432 ip6->ip6_dst.s6_addr16[1] = htons(pi->ipi6_ifindex);
433 oifp = ifindex2ifnet[pi->ipi6_ifindex];
6d2010ae
A
434 if (oifp != NULL)
435 ifnet_reference(oifp);
9bccf70c 436 } else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) &&
6d2010ae
A
437 im6o != NULL && im6o_multicast_ifp != NULL) {
438 oifp = im6o_multicast_ifp;
439 ifnet_reference(oifp);
1c79356b
A
440 ip6->ip6_dst.s6_addr16[1] = htons(oifp->if_index);
441 } else if (dstsock->sin6_scope_id) {
b0d623f7
A
442 /*
443 * boundary check
444 *
445 * Sinced stsock->sin6_scope_id is unsigned, we don't
446 * need to check if it's < 0
447 */
448 if (if_index < dstsock->sin6_scope_id) {
1c79356b 449 error = ENXIO; /* XXX EINVAL? */
b0d623f7 450 ifnet_head_done();
1c79356b
A
451 goto bad;
452 }
453 ip6->ip6_dst.s6_addr16[1]
454 = htons(dstsock->sin6_scope_id & 0xffff);/*XXX*/
455 }
b0d623f7 456 ifnet_head_done();
1c79356b
A
457 }
458
459 /*
460 * Source address selection.
461 */
462 {
463 struct in6_addr *in6a;
91447636 464 struct in6_addr storage;
b0d623f7 465 u_short index = 0;
6d2010ae
A
466
467 if (israw != 0 && optp && optp->ip6po_pktinfo && !IN6_IS_ADDR_UNSPECIFIED(&optp->ip6po_pktinfo->ipi6_addr)) {
468 in6a = &optp->ip6po_pktinfo->ipi6_addr;
469 flags |= IPV6_FLAG_NOSRCIFSEL;
470 } else if ((in6a = in6_selectsrc(dstsock, optp, in6p,
471 &in6p->in6p_route, NULL, &storage, ip6oa.ip6oa_boundif,
472 &error)) == 0) {
1c79356b
A
473 if (error == 0)
474 error = EADDRNOTAVAIL;
475 goto bad;
476 }
477 ip6->ip6_src = *in6a;
b0d623f7
A
478 if (in6p->in6p_route.ro_rt != NULL) {
479 RT_LOCK(in6p->in6p_route.ro_rt);
480 if (in6p->in6p_route.ro_rt->rt_ifp != NULL)
481 index = in6p->in6p_route.ro_rt->rt_ifp->if_index;
482 RT_UNLOCK(in6p->in6p_route.ro_rt);
6d2010ae
A
483 if (oifp != NULL)
484 ifnet_release(oifp);
b0d623f7
A
485 ifnet_head_lock_shared();
486 if (index == 0 || if_index < index) {
487 panic("bad if_index on interface from route");
488 }
489 oifp = ifindex2ifnet[index];
6d2010ae
A
490 if (oifp != NULL)
491 ifnet_reference(oifp);
b0d623f7
A
492 ifnet_head_done();
493 }
1c79356b 494 }
9bccf70c
A
495 ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
496 (in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK);
497 ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |
498 (IPV6_VERSION & IPV6_VERSION_MASK);
499 /* ip6_plen will be filled in ip6_output, so not fill it here. */
1c79356b
A
500 ip6->ip6_nxt = in6p->in6p_ip6_nxt;
501 ip6->ip6_hlim = in6_selecthlim(in6p, oifp);
502
503 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
504 in6p->in6p_cksum != -1) {
505 struct mbuf *n;
506 int off;
507 u_int16_t *p;
508
1c79356b
A
509 /* compute checksum */
510 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
511 off = offsetof(struct icmp6_hdr, icmp6_cksum);
512 else
513 off = in6p->in6p_cksum;
6d2010ae 514 if (plen < (unsigned int)(off + 1)) {
1c79356b
A
515 error = EINVAL;
516 goto bad;
517 }
518 off += sizeof(struct ip6_hdr);
519
520 n = m;
521 while (n && n->m_len <= off) {
522 off -= n->m_len;
523 n = n->m_next;
524 }
525 if (!n)
526 goto bad;
527 p = (u_int16_t *)(mtod(n, caddr_t) + off);
528 *p = 0;
529 *p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
530 }
531
532#if IPSEC
9bccf70c
A
533 if (ipsec_bypass == 0 && ipsec_setsocket(m, so) != 0) {
534 error = ENOBUFS;
535 goto bad;
536 }
1c79356b
A
537#endif /*IPSEC*/
538
b0d623f7
A
539 if (in6p->in6p_route.ro_rt != NULL &&
540 in6p->in6p_route.ro_rt->generation_id != route_generation) {
91447636 541 rtfree(in6p->in6p_route.ro_rt);
b0d623f7 542 in6p->in6p_route.ro_rt = NULL;
91447636
A
543 }
544
6d2010ae
A
545 if (oifp != NULL) {
546 ifnet_release(oifp);
547 oifp = NULL;
548 }
d1ecb069 549
6d2010ae
A
550 set_packet_tclass(m, so, mtc, 1);
551
552 if (im6o != NULL)
553 IM6O_ADDREF(im6o);
d1ecb069 554
6d2010ae
A
555 error = ip6_output(m, optp, &in6p->in6p_route, flags, im6o,
556 &oifp, &ip6oa);
557
558 if (im6o != NULL)
559 IM6O_REMREF(im6o);
560
561 if (in6p->in6p_route.ro_rt != NULL) {
562 struct rtentry *rt = in6p->in6p_route.ro_rt;
563 unsigned int outif;
564
565 if ((rt->rt_flags & RTF_MULTICAST) ||
566 in6p->in6p_socket == NULL ||
567 !(in6p->in6p_socket->so_state & SS_ISCONNECTED)) {
568 rt = NULL; /* unusable */
569 }
570 /*
571 * Always discard the cached route for unconnected
572 * socket or if it is a multicast route.
573 */
574 if (rt == NULL) {
575 rtfree(in6p->in6p_route.ro_rt);
576 in6p->in6p_route.ro_rt = NULL;
577 }
578 /*
579 * If this is a connected socket and the destination
580 * route is not multicast, update outif with that of
581 * the route interface index used by IP.
582 */
583 if (rt != NULL &&
584 (outif = rt->rt_ifp->if_index) != in6p->in6p_last_outif)
585 in6p->in6p_last_outif = outif;
d1ecb069 586 }
d1ecb069 587
1c79356b
A
588 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
589 if (oifp)
590 icmp6_ifoutstat_inc(oifp, type, code);
591 icmp6stat.icp6s_outhist[type]++;
9bccf70c
A
592 } else
593 rip6stat.rip6s_opackets++;
1c79356b
A
594
595 goto freectl;
596
597 bad:
598 if (m)
599 m_freem(m);
600
601 freectl:
2d21ac55 602 if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt) {
9bccf70c 603 rtfree(optp->ip6po_route.ro_rt);
2d21ac55
A
604 optp->ip6po_route.ro_rt = NULL;
605 }
1c79356b
A
606 if (control) {
607 if (optp == &opt)
6d2010ae 608 ip6_clearpktopts(optp, -1);
1c79356b
A
609 m_freem(control);
610 }
6d2010ae
A
611 if (oifp != NULL)
612 ifnet_release(oifp);
1c79356b
A
613 return(error);
614}
615
7e4a7d39 616#if IPFW2
060df5ea 617__private_extern__ void
2d21ac55 618load_ip6fw(void)
91447636
A
619{
620 ip6_fw_init();
621}
7e4a7d39 622#endif
91447636 623
1c79356b
A
624/*
625 * Raw IPv6 socket option processing.
626 */
627int
91447636
A
628rip6_ctloutput(
629 struct socket *so,
630 struct sockopt *sopt)
1c79356b
A
631{
632 int error;
633
634 if (sopt->sopt_level == IPPROTO_ICMPV6)
635 /*
636 * XXX: is it better to call icmp6_ctloutput() directly
637 * from protosw?
638 */
639 return(icmp6_ctloutput(so, sopt));
640 else if (sopt->sopt_level != IPPROTO_IPV6)
641 return (EINVAL);
642
643 error = 0;
644
645 switch (sopt->sopt_dir) {
646 case SOPT_GET:
647 switch (sopt->sopt_name) {
7e4a7d39 648#if IPFW2
91447636
A
649 case IPV6_FW_ADD:
650 case IPV6_FW_GET:
651 if (ip6_fw_ctl_ptr == 0)
652 load_ip6fw();
653 if (ip6_fw_ctl_ptr)
654 error = ip6_fw_ctl_ptr(sopt);
655 else
656 error = ENOPROTOOPT;
657 break;
7e4a7d39 658#endif
91447636 659
1c79356b
A
660 case MRT6_INIT:
661 case MRT6_DONE:
662 case MRT6_ADD_MIF:
663 case MRT6_DEL_MIF:
664 case MRT6_ADD_MFC:
665 case MRT6_DEL_MFC:
666 case MRT6_PIM:
b7266188 667#if MROUTING
1c79356b 668 error = ip6_mrouter_get(so, sopt);
6d2010ae
A
669#else
670 error = ENOPROTOOPT;
671#endif /* MROUTING */
672 break;
673 case IPV6_CHECKSUM:
674 error = ip6_raw_ctloutput(so, sopt);
1c79356b
A
675 break;
676 default:
677 error = ip6_ctloutput(so, sopt);
678 break;
679 }
680 break;
681
682 case SOPT_SET:
683 switch (sopt->sopt_name) {
7e4a7d39 684#if IPFW2
91447636
A
685 case IPV6_FW_ADD:
686 case IPV6_FW_DEL:
687 case IPV6_FW_FLUSH:
688 case IPV6_FW_ZERO:
689 if (ip6_fw_ctl_ptr == 0)
690 load_ip6fw();
691 if (ip6_fw_ctl_ptr)
692 error = ip6_fw_ctl_ptr(sopt);
693 else
694 error = ENOPROTOOPT;
695 break;
7e4a7d39 696#endif
91447636 697
1c79356b
A
698 case MRT6_INIT:
699 case MRT6_DONE:
700 case MRT6_ADD_MIF:
701 case MRT6_DEL_MIF:
702 case MRT6_ADD_MFC:
703 case MRT6_DEL_MFC:
704 case MRT6_PIM:
b7266188 705#if MROUTING
1c79356b 706 error = ip6_mrouter_set(so, sopt);
6d2010ae
A
707#else
708 error = ENOPROTOOPT;
b7266188 709#endif
6d2010ae
A
710 break;
711 case IPV6_CHECKSUM:
712 error = ip6_raw_ctloutput(so, sopt);
713 break;
1c79356b
A
714 default:
715 error = ip6_ctloutput(so, sopt);
716 break;
717 }
718 break;
719 }
720
721 return (error);
722}
723
724static int
b0d623f7 725rip6_attach(struct socket *so, int proto, struct proc *p)
1c79356b
A
726{
727 struct inpcb *inp;
2d21ac55 728 int error;
1c79356b
A
729
730 inp = sotoinpcb(so);
731 if (inp)
732 panic("rip6_attach");
b0d623f7 733 if ((error = proc_suser(p)) != 0)
1c79356b
A
734 return error;
735
9bccf70c
A
736 error = soreserve(so, rip_sendspace, rip_recvspace);
737 if (error)
738 return error;
1c79356b 739 error = in_pcballoc(so, &ripcbinfo, p);
1c79356b
A
740 if (error)
741 return error;
742 inp = (struct inpcb *)so->so_pcb;
743 inp->inp_vflag |= INP_IPV6;
b0d623f7 744 inp->in6p_ip6_nxt = (char)proto;
1c79356b
A
745 inp->in6p_hops = -1; /* use kernel default */
746 inp->in6p_cksum = -1;
1c79356b 747 MALLOC(inp->in6p_icmp6filt, struct icmp6_filter *,
55e303ae
A
748 sizeof(struct icmp6_filter), M_PCB, M_WAITOK);
749 if (inp->in6p_icmp6filt == NULL)
750 return (ENOMEM);
1c79356b
A
751 ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt);
752 return 0;
753}
754
755static int
756rip6_detach(struct socket *so)
757{
758 struct inpcb *inp;
759
760 inp = sotoinpcb(so);
761 if (inp == 0)
762 panic("rip6_detach");
9bccf70c 763 /* xxx: RSVP */
b7266188 764#if MROUTING
1c79356b
A
765 if (so == ip6_mrouter)
766 ip6_mrouter_done();
b7266188 767#endif
1c79356b
A
768 if (inp->in6p_icmp6filt) {
769 FREE(inp->in6p_icmp6filt, M_PCB);
770 inp->in6p_icmp6filt = NULL;
771 }
772 in6_pcbdetach(inp);
773 return 0;
774}
775
776static int
777rip6_abort(struct socket *so)
778{
779 soisdisconnected(so);
780 return rip6_detach(so);
781}
782
783static int
784rip6_disconnect(struct socket *so)
785{
786 struct inpcb *inp = sotoinpcb(so);
787
788 if ((so->so_state & SS_ISCONNECTED) == 0)
789 return ENOTCONN;
790 inp->in6p_faddr = in6addr_any;
791 return rip6_abort(so);
792}
793
794static int
2d21ac55 795rip6_bind(struct socket *so, struct sockaddr *nam, __unused struct proc *p)
1c79356b
A
796{
797 struct inpcb *inp = sotoinpcb(so);
798 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
6d2010ae
A
799 struct ifaddr *ifa = NULL;
800 unsigned int outif = 0;
1c79356b
A
801
802 if (nam->sa_len != sizeof(*addr))
803 return EINVAL;
804
91447636 805 if (TAILQ_EMPTY(&ifnet_head) || addr->sin6_family != AF_INET6)
1c79356b 806 return EADDRNOTAVAIL;
9bccf70c
A
807#if ENABLE_DEFAULT_SCOPE
808 if (addr->sin6_scope_id == 0) { /* not change if specified */
809 addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr);
810 }
811#endif
1c79356b 812 if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
6d2010ae 813 (ifa = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)
1c79356b 814 return EADDRNOTAVAIL;
6d2010ae
A
815 if (ifa != NULL) {
816 IFA_LOCK(ifa);
817 if (((struct in6_ifaddr *)ifa)->ia6_flags &
818 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
819 IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
820 IFA_UNLOCK(ifa);
821 IFA_REMREF(ifa);
822 return(EADDRNOTAVAIL);
823 }
824 outif = ifa->ifa_ifp->if_index;
825 IFA_UNLOCK(ifa);
826 IFA_REMREF(ifa);
1c79356b
A
827 }
828 inp->in6p_laddr = addr->sin6_addr;
6d2010ae 829 inp->in6p_last_outif = outif;
1c79356b
A
830 return 0;
831}
832
833static int
2d21ac55 834rip6_connect(struct socket *so, struct sockaddr *nam, __unused struct proc *p)
1c79356b
A
835{
836 struct inpcb *inp = sotoinpcb(so);
837 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
838 struct in6_addr *in6a = NULL;
91447636 839 struct in6_addr storage;
1c79356b 840 int error = 0;
9bccf70c
A
841#if ENABLE_DEFAULT_SCOPE
842 struct sockaddr_in6 tmp;
843#endif
6d2010ae 844 unsigned int outif = 0, ifscope;
1c79356b
A
845
846 if (nam->sa_len != sizeof(*addr))
847 return EINVAL;
91447636 848 if (TAILQ_EMPTY(&ifnet_head))
1c79356b
A
849 return EADDRNOTAVAIL;
850 if (addr->sin6_family != AF_INET6)
851 return EAFNOSUPPORT;
9bccf70c
A
852#if ENABLE_DEFAULT_SCOPE
853 if (addr->sin6_scope_id == 0) { /* not change if specified */
854 /* avoid overwrites */
855 tmp = *addr;
856 addr = &tmp;
857 addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr);
858 }
859#endif
6d2010ae
A
860
861 ifscope = (inp->inp_flags & INP_BOUND_IF) ?
862 inp->inp_boundif : IFSCOPE_NONE;
863
1c79356b 864 /* Source address selection. XXX: need pcblookup? */
6d2010ae
A
865 in6a = in6_selectsrc(addr, inp->in6p_outputopts, inp, &inp->in6p_route,
866 NULL, &storage, ifscope, &error);
1c79356b
A
867 if (in6a == NULL)
868 return (error ? error : EADDRNOTAVAIL);
869 inp->in6p_laddr = *in6a;
870 inp->in6p_faddr = addr->sin6_addr;
6d2010ae
A
871 if (inp->in6p_route.ro_rt != NULL)
872 outif = inp->in6p_route.ro_rt->rt_ifp->if_index;
873 inp->in6p_last_outif = outif;
1c79356b
A
874 soisconnected(so);
875 return 0;
876}
877
878static int
879rip6_shutdown(struct socket *so)
880{
881 socantsendmore(so);
882 return 0;
883}
884
885static int
6d2010ae
A
886rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
887 struct mbuf *control, struct proc *p)
1c79356b 888{
6d2010ae 889#pragma unused(flags, p)
1c79356b
A
890 struct inpcb *inp = sotoinpcb(so);
891 struct sockaddr_in6 tmp;
6d2010ae 892 struct sockaddr_in6 *dst = (struct sockaddr_in6 *)nam;
1c79356b 893
9bccf70c 894 /* always copy sockaddr to avoid overwrites */
1c79356b
A
895 if (so->so_state & SS_ISCONNECTED) {
896 if (nam) {
897 m_freem(m);
898 return EISCONN;
899 }
900 /* XXX */
901 bzero(&tmp, sizeof(tmp));
902 tmp.sin6_family = AF_INET6;
903 tmp.sin6_len = sizeof(struct sockaddr_in6);
904 bcopy(&inp->in6p_faddr, &tmp.sin6_addr,
905 sizeof(struct in6_addr));
906 dst = &tmp;
907 } else {
908 if (nam == NULL) {
909 m_freem(m);
910 return ENOTCONN;
911 }
9bccf70c
A
912 tmp = *(struct sockaddr_in6 *)nam;
913 dst = &tmp;
1c79356b 914 }
9bccf70c
A
915#if ENABLE_DEFAULT_SCOPE
916 if (dst->sin6_scope_id == 0) { /* not change if specified */
917 dst->sin6_scope_id = scope6_addr2default(&dst->sin6_addr);
918 }
919#endif
6d2010ae 920 return rip6_output(m, so, dst, control, 1);
1c79356b
A
921}
922
923struct pr_usrreqs rip6_usrreqs = {
924 rip6_abort, pru_accept_notsupp, rip6_attach, rip6_bind, rip6_connect,
925 pru_connect2_notsupp, in6_control, rip6_detach, rip6_disconnect,
926 pru_listen_notsupp, in6_setpeeraddr, pru_rcvd_notsupp,
9bccf70c 927 pru_rcvoob_notsupp, rip6_send, pru_sense_null, rip6_shutdown,
91447636 928 in6_setsockaddr, sosend, soreceive, pru_sopoll_notsupp
1c79356b 929};
2d21ac55
A
930
931__private_extern__ struct pr_usrreqs icmp6_dgram_usrreqs = {
932 rip6_abort, pru_accept_notsupp, icmp6_dgram_attach, rip6_bind, rip6_connect,
933 pru_connect2_notsupp, in6_control, rip6_detach, rip6_disconnect,
934 pru_listen_notsupp, in6_setpeeraddr, pru_rcvd_notsupp,
935 pru_rcvoob_notsupp, icmp6_dgram_send, pru_sense_null, rip6_shutdown,
936 in6_setsockaddr, sosend, soreceive, pru_sopoll_notsupp
937};
938
939
940