]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/raw_ip6.c
xnu-1504.9.37.tar.gz
[apple/xnu.git] / bsd / netinet6 / raw_ip6.c
CommitLineData
b0d623f7 1/*
d41d1dae 2 * Copyright (c) 2000-2010 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;
1c79356b 141
9bccf70c
A
142struct rip6stat rip6stat;
143
1c79356b
A
144/*
145 * Setup generic address and protocol structures
146 * for raw_input routine, then pass them along with
147 * mbuf chain.
148 */
149int
91447636
A
150rip6_input(
151 struct mbuf **mp,
152 int *offp)
1c79356b
A
153{
154 struct mbuf *m = *mp;
155 register struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
156 register struct inpcb *in6p;
157 struct inpcb *last = 0;
9bccf70c 158 struct mbuf *opts = NULL;
1c79356b 159 struct sockaddr_in6 rip6src;
9bccf70c
A
160 int proto = ip6->ip6_nxt;
161
162 rip6stat.rip6s_ipackets++;
1c79356b
A
163
164#if defined(NFAITH) && 0 < NFAITH
9bccf70c
A
165 if (faithprefix(&ip6->ip6_dst)) {
166 /* XXX send icmp6 host/port unreach? */
167 m_freem(m);
168 return IPPROTO_DONE;
1c79356b
A
169 }
170#endif
9bccf70c 171
1c79356b 172 init_sin6(&rip6src, m); /* general init */
1c79356b 173
91447636 174 lck_rw_lock_shared(ripcbinfo.mtx);
1c79356b 175 LIST_FOREACH(in6p, &ripcb, inp_list) {
9bccf70c 176 if ((in6p->in6p_vflag & INP_IPV6) == 0)
1c79356b
A
177 continue;
178 if (in6p->in6p_ip6_nxt &&
179 in6p->in6p_ip6_nxt != proto)
180 continue;
181 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
182 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
183 continue;
184 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
185 !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
186 continue;
9bccf70c
A
187 if (in6p->in6p_cksum != -1) {
188 rip6stat.rip6s_isum++;
189 if (in6_cksum(m, ip6->ip6_nxt, *offp,
190 m->m_pkthdr.len - *offp)) {
191 rip6stat.rip6s_badsum++;
192 continue;
193 }
1c79356b
A
194 }
195 if (last) {
196 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
9bccf70c
A
197
198#if IPSEC
199 /*
200 * Check AH/ESP integrity.
201 */
2d21ac55 202 if (ipsec_bypass == 0 && n && ipsec6_in_reject_so(n, last->inp_socket)) {
91447636 203 m_freem(n);
2d21ac55 204 IPSEC_STAT_INCREMENT(ipsec6stat.in_polvio);
91447636 205 /* do not inject data into pcb */
9bccf70c
A
206 } else
207#endif /*IPSEC*/
1c79356b
A
208 if (n) {
209 if (last->in6p_flags & IN6P_CONTROLOPTS ||
210 last->in6p_socket->so_options & SO_TIMESTAMP)
9bccf70c 211 ip6_savecontrol(last, &opts, ip6, n);
1c79356b
A
212 /* strip intermediate headers */
213 m_adj(n, *offp);
214 if (sbappendaddr(&last->in6p_socket->so_rcv,
215 (struct sockaddr *)&rip6src,
91447636 216 n, opts, NULL) == 0) {
9bccf70c 217 rip6stat.rip6s_fullsock++;
1c79356b
A
218 } else
219 sorwakeup(last->in6p_socket);
9bccf70c 220 opts = NULL;
1c79356b
A
221 }
222 }
223 last = in6p;
224 }
91447636 225 lck_rw_done(ripcbinfo.mtx);
9bccf70c
A
226#if IPSEC
227 /*
228 * Check AH/ESP integrity.
229 */
2d21ac55 230 if (ipsec_bypass == 0 && last && ipsec6_in_reject_so(m, last->inp_socket)) {
91447636 231 m_freem(m);
2d21ac55 232 IPSEC_STAT_INCREMENT(ipsec6stat.in_polvio);
91447636
A
233 ip6stat.ip6s_delivered--;
234 /* do not inject data into pcb */
9bccf70c
A
235 } else
236#endif /*IPSEC*/
1c79356b
A
237 if (last) {
238 if (last->in6p_flags & IN6P_CONTROLOPTS ||
239 last->in6p_socket->so_options & SO_TIMESTAMP)
9bccf70c 240 ip6_savecontrol(last, &opts, ip6, m);
1c79356b
A
241 /* strip intermediate headers */
242 m_adj(m, *offp);
243 if (sbappendaddr(&last->in6p_socket->so_rcv,
91447636 244 (struct sockaddr *)&rip6src, m, opts, NULL) == 0) {
9bccf70c 245 rip6stat.rip6s_fullsock++;
1c79356b
A
246 } else
247 sorwakeup(last->in6p_socket);
248 } else {
9bccf70c
A
249 rip6stat.rip6s_nosock++;
250 if (m->m_flags & M_MCAST)
251 rip6stat.rip6s_nosockmcast++;
1c79356b
A
252 if (proto == IPPROTO_NONE)
253 m_freem(m);
254 else {
255 char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
256 icmp6_error(m, ICMP6_PARAM_PROB,
257 ICMP6_PARAMPROB_NEXTHEADER,
258 prvnxtp - mtod(m, char *));
259 }
260 ip6stat.ip6s_delivered--;
261 }
262 return IPPROTO_DONE;
263}
264
265void
91447636
A
266rip6_ctlinput(
267 int cmd,
268 struct sockaddr *sa,
269 void *d)
1c79356b 270{
1c79356b
A
271 struct ip6_hdr *ip6;
272 struct mbuf *m;
273 int off = 0;
9bccf70c
A
274 struct ip6ctlparam *ip6cp = NULL;
275 const struct sockaddr_in6 *sa6_src = NULL;
91447636 276 void (*notify)(struct inpcb *, int) = in6_rtchange;
1c79356b
A
277
278 if (sa->sa_family != AF_INET6 ||
279 sa->sa_len != sizeof(struct sockaddr_in6))
280 return;
281
282 if ((unsigned)cmd >= PRC_NCMDS)
283 return;
284 if (PRC_IS_REDIRECT(cmd))
285 notify = in6_rtchange, d = NULL;
286 else if (cmd == PRC_HOSTDEAD)
287 d = NULL;
288 else if (inet6ctlerrmap[cmd] == 0)
289 return;
290
291 /* if the parameter is from icmp6, decode it. */
292 if (d != NULL) {
9bccf70c 293 ip6cp = (struct ip6ctlparam *)d;
1c79356b
A
294 m = ip6cp->ip6c_m;
295 ip6 = ip6cp->ip6c_ip6;
296 off = ip6cp->ip6c_off;
9bccf70c 297 sa6_src = ip6cp->ip6c_src;
1c79356b
A
298 } else {
299 m = NULL;
300 ip6 = NULL;
9bccf70c 301 sa6_src = &sa6_any;
1c79356b
A
302 }
303
2d21ac55 304 (void) in6_pcbnotify(&ripcbinfo, sa, 0, (const struct sockaddr *)sa6_src,
9bccf70c 305 0, cmd, notify);
1c79356b
A
306}
307
308/*
309 * Generate IPv6 header and pass packet to ip6_output.
310 * Tack on options user may have setup with control call.
311 */
312int
91447636
A
313rip6_output(
314 register struct mbuf *m,
315 struct socket *so,
316 struct sockaddr_in6 *dstsock,
317 struct mbuf *control)
1c79356b
A
318{
319 struct in6_addr *dst;
320 struct ip6_hdr *ip6;
321 struct inpcb *in6p;
322 u_int plen = m->m_pkthdr.len;
323 int error = 0;
324 struct ip6_pktopts opt, *optp = 0;
325 struct ifnet *oifp = NULL;
326 int type = 0, code = 0; /* for ICMPv6 output statistics only */
327 int priv = 0;
d41d1dae
A
328#if PKT_PRIORITY
329 mbuf_traffic_class_t mtc = MBUF_TC_NONE;
330#endif /* PKT_PRIORITY */
1c79356b
A
331
332 in6p = sotoin6pcb(so);
333
334 priv = 0;
9bccf70c 335 if (so->so_uid == 0)
1c79356b 336 priv = 1;
1c79356b
A
337 dst = &dstsock->sin6_addr;
338 if (control) {
d41d1dae
A
339#if PKT_PRIORITY
340 mtc = mbuf_traffic_class_from_control(control);
341#endif /* PKT_PRIORITY */
342
1c79356b
A
343 if ((error = ip6_setpktoptions(control, &opt, priv, 0)) != 0)
344 goto bad;
345 optp = &opt;
346 } else
347 optp = in6p->in6p_outputopts;
348
349 /*
350 * For an ICMPv6 packet, we should know its type and code
351 * to update statistics.
352 */
353 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
354 struct icmp6_hdr *icmp6;
355 if (m->m_len < sizeof(struct icmp6_hdr) &&
356 (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
357 error = ENOBUFS;
358 goto bad;
359 }
360 icmp6 = mtod(m, struct icmp6_hdr *);
361 type = icmp6->icmp6_type;
362 code = icmp6->icmp6_code;
363 }
364
365 M_PREPEND(m, sizeof(*ip6), M_WAIT);
b0d623f7
A
366 if (m == NULL) {
367 error = ENOBUFS;
368 goto bad;
369 }
1c79356b
A
370 ip6 = mtod(m, struct ip6_hdr *);
371
372 /*
373 * Next header might not be ICMP6 but use its pseudo header anyway.
374 */
375 ip6->ip6_dst = *dst;
376
377 /*
378 * If the scope of the destination is link-local, embed the interface
379 * index in the address.
380 *
9bccf70c 381 * XXX advanced-api value overrides sin6_scope_id
1c79356b
A
382 */
383 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
384 struct in6_pktinfo *pi;
385
386 /*
387 * XXX Boundary check is assumed to be already done in
388 * ip6_setpktoptions().
389 */
b0d623f7 390 ifnet_head_lock_shared();
1c79356b
A
391 if (optp && (pi = optp->ip6po_pktinfo) && pi->ipi6_ifindex) {
392 ip6->ip6_dst.s6_addr16[1] = htons(pi->ipi6_ifindex);
393 oifp = ifindex2ifnet[pi->ipi6_ifindex];
9bccf70c 394 } else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) &&
1c79356b
A
395 in6p->in6p_moptions &&
396 in6p->in6p_moptions->im6o_multicast_ifp) {
397 oifp = in6p->in6p_moptions->im6o_multicast_ifp;
398 ip6->ip6_dst.s6_addr16[1] = htons(oifp->if_index);
399 } else if (dstsock->sin6_scope_id) {
b0d623f7
A
400 /*
401 * boundary check
402 *
403 * Sinced stsock->sin6_scope_id is unsigned, we don't
404 * need to check if it's < 0
405 */
406 if (if_index < dstsock->sin6_scope_id) {
1c79356b 407 error = ENXIO; /* XXX EINVAL? */
b0d623f7 408 ifnet_head_done();
1c79356b
A
409 goto bad;
410 }
411 ip6->ip6_dst.s6_addr16[1]
412 = htons(dstsock->sin6_scope_id & 0xffff);/*XXX*/
413 }
b0d623f7 414 ifnet_head_done();
1c79356b
A
415 }
416
417 /*
418 * Source address selection.
419 */
420 {
421 struct in6_addr *in6a;
91447636 422 struct in6_addr storage;
b0d623f7 423 u_short index = 0;
1c79356b
A
424 if ((in6a = in6_selectsrc(dstsock, optp,
425 in6p->in6p_moptions,
426 &in6p->in6p_route,
427 &in6p->in6p_laddr,
91447636 428 &storage, &error)) == 0) {
1c79356b
A
429 if (error == 0)
430 error = EADDRNOTAVAIL;
431 goto bad;
432 }
433 ip6->ip6_src = *in6a;
b0d623f7
A
434 if (in6p->in6p_route.ro_rt != NULL) {
435 RT_LOCK(in6p->in6p_route.ro_rt);
436 if (in6p->in6p_route.ro_rt->rt_ifp != NULL)
437 index = in6p->in6p_route.ro_rt->rt_ifp->if_index;
438 RT_UNLOCK(in6p->in6p_route.ro_rt);
439 ifnet_head_lock_shared();
440 if (index == 0 || if_index < index) {
441 panic("bad if_index on interface from route");
442 }
443 oifp = ifindex2ifnet[index];
444 ifnet_head_done();
445 }
1c79356b 446 }
9bccf70c
A
447 ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
448 (in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK);
449 ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |
450 (IPV6_VERSION & IPV6_VERSION_MASK);
451 /* ip6_plen will be filled in ip6_output, so not fill it here. */
1c79356b
A
452 ip6->ip6_nxt = in6p->in6p_ip6_nxt;
453 ip6->ip6_hlim = in6_selecthlim(in6p, oifp);
454
455 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
456 in6p->in6p_cksum != -1) {
457 struct mbuf *n;
458 int off;
459 u_int16_t *p;
460
1c79356b
A
461 /* compute checksum */
462 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
463 off = offsetof(struct icmp6_hdr, icmp6_cksum);
464 else
465 off = in6p->in6p_cksum;
466 if (plen < off + 1) {
467 error = EINVAL;
468 goto bad;
469 }
470 off += sizeof(struct ip6_hdr);
471
472 n = m;
473 while (n && n->m_len <= off) {
474 off -= n->m_len;
475 n = n->m_next;
476 }
477 if (!n)
478 goto bad;
479 p = (u_int16_t *)(mtod(n, caddr_t) + off);
480 *p = 0;
481 *p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
482 }
483
484#if IPSEC
9bccf70c
A
485 if (ipsec_bypass == 0 && ipsec_setsocket(m, so) != 0) {
486 error = ENOBUFS;
487 goto bad;
488 }
1c79356b
A
489#endif /*IPSEC*/
490
b0d623f7
A
491 if (in6p->in6p_route.ro_rt != NULL &&
492 in6p->in6p_route.ro_rt->generation_id != route_generation) {
91447636 493 rtfree(in6p->in6p_route.ro_rt);
b0d623f7 494 in6p->in6p_route.ro_rt = NULL;
91447636
A
495 }
496
d1ecb069 497#if PKT_PRIORITY
d41d1dae 498 set_traffic_class(m, so, mtc);
d1ecb069
A
499#endif /* PKT_PRIORITY */
500
9bccf70c 501 error = ip6_output(m, optp, &in6p->in6p_route, 0,
91447636 502 in6p->in6p_moptions, &oifp, 0);
d1ecb069
A
503
504#if IFNET_ROUTE_REFCNT
505 /*
506 * Always discard the cached route for unconnected socket
507 * or if it is a multicast route.
508 */
509 if (in6p->in6p_route.ro_rt != NULL &&
510 ((in6p->in6p_route.ro_rt->rt_flags & RTF_MULTICAST) ||
511 in6p->in6p_socket == NULL ||
512 in6p->in6p_socket->so_state != SS_ISCONNECTED)) {
513 rtfree(in6p->in6p_route.ro_rt);
514 in6p->in6p_route.ro_rt = NULL;
515 }
516#endif /* IFNET_ROUTE_REFCNT */
517
1c79356b
A
518 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
519 if (oifp)
520 icmp6_ifoutstat_inc(oifp, type, code);
521 icmp6stat.icp6s_outhist[type]++;
9bccf70c
A
522 } else
523 rip6stat.rip6s_opackets++;
1c79356b
A
524
525 goto freectl;
526
527 bad:
528 if (m)
529 m_freem(m);
530
531 freectl:
2d21ac55 532 if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt) {
9bccf70c 533 rtfree(optp->ip6po_route.ro_rt);
2d21ac55
A
534 optp->ip6po_route.ro_rt = NULL;
535 }
1c79356b
A
536 if (control) {
537 if (optp == &opt)
538 ip6_clearpktopts(optp, 0, -1);
539 m_freem(control);
540 }
541 return(error);
542}
543
7e4a7d39 544#if IPFW2
91447636 545static void
2d21ac55 546load_ip6fw(void)
91447636
A
547{
548 ip6_fw_init();
549}
7e4a7d39 550#endif
91447636 551
1c79356b
A
552/*
553 * Raw IPv6 socket option processing.
554 */
555int
91447636
A
556rip6_ctloutput(
557 struct socket *so,
558 struct sockopt *sopt)
1c79356b
A
559{
560 int error;
561
562 if (sopt->sopt_level == IPPROTO_ICMPV6)
563 /*
564 * XXX: is it better to call icmp6_ctloutput() directly
565 * from protosw?
566 */
567 return(icmp6_ctloutput(so, sopt));
568 else if (sopt->sopt_level != IPPROTO_IPV6)
569 return (EINVAL);
570
571 error = 0;
572
573 switch (sopt->sopt_dir) {
574 case SOPT_GET:
575 switch (sopt->sopt_name) {
7e4a7d39 576#if IPFW2
91447636
A
577 case IPV6_FW_ADD:
578 case IPV6_FW_GET:
579 if (ip6_fw_ctl_ptr == 0)
580 load_ip6fw();
581 if (ip6_fw_ctl_ptr)
582 error = ip6_fw_ctl_ptr(sopt);
583 else
584 error = ENOPROTOOPT;
585 break;
7e4a7d39 586#endif
91447636 587
1c79356b
A
588 case MRT6_INIT:
589 case MRT6_DONE:
590 case MRT6_ADD_MIF:
591 case MRT6_DEL_MIF:
592 case MRT6_ADD_MFC:
593 case MRT6_DEL_MFC:
594 case MRT6_PIM:
b7266188 595#if MROUTING
1c79356b
A
596 error = ip6_mrouter_get(so, sopt);
597 break;
b7266188 598#endif
1c79356b
A
599 default:
600 error = ip6_ctloutput(so, sopt);
601 break;
602 }
603 break;
604
605 case SOPT_SET:
606 switch (sopt->sopt_name) {
7e4a7d39 607#if IPFW2
91447636
A
608 case IPV6_FW_ADD:
609 case IPV6_FW_DEL:
610 case IPV6_FW_FLUSH:
611 case IPV6_FW_ZERO:
612 if (ip6_fw_ctl_ptr == 0)
613 load_ip6fw();
614 if (ip6_fw_ctl_ptr)
615 error = ip6_fw_ctl_ptr(sopt);
616 else
617 error = ENOPROTOOPT;
618 break;
7e4a7d39 619#endif
91447636 620
1c79356b
A
621 case MRT6_INIT:
622 case MRT6_DONE:
623 case MRT6_ADD_MIF:
624 case MRT6_DEL_MIF:
625 case MRT6_ADD_MFC:
626 case MRT6_DEL_MFC:
627 case MRT6_PIM:
b7266188 628#if MROUTING
1c79356b
A
629 error = ip6_mrouter_set(so, sopt);
630 break;
b7266188 631#endif
1c79356b
A
632 default:
633 error = ip6_ctloutput(so, sopt);
634 break;
635 }
636 break;
637 }
638
639 return (error);
640}
641
642static int
b0d623f7 643rip6_attach(struct socket *so, int proto, struct proc *p)
1c79356b
A
644{
645 struct inpcb *inp;
2d21ac55 646 int error;
1c79356b
A
647
648 inp = sotoinpcb(so);
649 if (inp)
650 panic("rip6_attach");
b0d623f7 651 if ((error = proc_suser(p)) != 0)
1c79356b
A
652 return error;
653
9bccf70c
A
654 error = soreserve(so, rip_sendspace, rip_recvspace);
655 if (error)
656 return error;
1c79356b 657 error = in_pcballoc(so, &ripcbinfo, p);
1c79356b
A
658 if (error)
659 return error;
660 inp = (struct inpcb *)so->so_pcb;
661 inp->inp_vflag |= INP_IPV6;
b0d623f7 662 inp->in6p_ip6_nxt = (char)proto;
1c79356b
A
663 inp->in6p_hops = -1; /* use kernel default */
664 inp->in6p_cksum = -1;
1c79356b 665 MALLOC(inp->in6p_icmp6filt, struct icmp6_filter *,
55e303ae
A
666 sizeof(struct icmp6_filter), M_PCB, M_WAITOK);
667 if (inp->in6p_icmp6filt == NULL)
668 return (ENOMEM);
1c79356b
A
669 ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt);
670 return 0;
671}
672
673static int
674rip6_detach(struct socket *so)
675{
676 struct inpcb *inp;
677
678 inp = sotoinpcb(so);
679 if (inp == 0)
680 panic("rip6_detach");
9bccf70c 681 /* xxx: RSVP */
b7266188 682#if MROUTING
1c79356b
A
683 if (so == ip6_mrouter)
684 ip6_mrouter_done();
b7266188 685#endif
1c79356b
A
686 if (inp->in6p_icmp6filt) {
687 FREE(inp->in6p_icmp6filt, M_PCB);
688 inp->in6p_icmp6filt = NULL;
689 }
690 in6_pcbdetach(inp);
691 return 0;
692}
693
694static int
695rip6_abort(struct socket *so)
696{
697 soisdisconnected(so);
698 return rip6_detach(so);
699}
700
701static int
702rip6_disconnect(struct socket *so)
703{
704 struct inpcb *inp = sotoinpcb(so);
705
706 if ((so->so_state & SS_ISCONNECTED) == 0)
707 return ENOTCONN;
708 inp->in6p_faddr = in6addr_any;
709 return rip6_abort(so);
710}
711
712static int
2d21ac55 713rip6_bind(struct socket *so, struct sockaddr *nam, __unused struct proc *p)
1c79356b
A
714{
715 struct inpcb *inp = sotoinpcb(so);
716 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
717 struct ifaddr *ia = NULL;
718
719 if (nam->sa_len != sizeof(*addr))
720 return EINVAL;
721
91447636 722 if (TAILQ_EMPTY(&ifnet_head) || addr->sin6_family != AF_INET6)
1c79356b 723 return EADDRNOTAVAIL;
9bccf70c
A
724#if ENABLE_DEFAULT_SCOPE
725 if (addr->sin6_scope_id == 0) { /* not change if specified */
726 addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr);
727 }
728#endif
1c79356b
A
729 if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
730 (ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)
731 return EADDRNOTAVAIL;
732 if (ia &&
733 ((struct in6_ifaddr *)ia)->ia6_flags &
734 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
735 IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
91447636 736 if (ia) ifafree(ia);
1c79356b
A
737 return(EADDRNOTAVAIL);
738 }
2d21ac55
A
739 if (ia != NULL)
740 ifafree(ia);
1c79356b
A
741 inp->in6p_laddr = addr->sin6_addr;
742 return 0;
743}
744
745static int
2d21ac55 746rip6_connect(struct socket *so, struct sockaddr *nam, __unused struct proc *p)
1c79356b
A
747{
748 struct inpcb *inp = sotoinpcb(so);
749 struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
750 struct in6_addr *in6a = NULL;
91447636 751 struct in6_addr storage;
1c79356b 752 int error = 0;
9bccf70c
A
753#if ENABLE_DEFAULT_SCOPE
754 struct sockaddr_in6 tmp;
755#endif
1c79356b
A
756
757 if (nam->sa_len != sizeof(*addr))
758 return EINVAL;
91447636 759 if (TAILQ_EMPTY(&ifnet_head))
1c79356b
A
760 return EADDRNOTAVAIL;
761 if (addr->sin6_family != AF_INET6)
762 return EAFNOSUPPORT;
9bccf70c
A
763#if ENABLE_DEFAULT_SCOPE
764 if (addr->sin6_scope_id == 0) { /* not change if specified */
765 /* avoid overwrites */
766 tmp = *addr;
767 addr = &tmp;
768 addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr);
769 }
770#endif
1c79356b
A
771 /* Source address selection. XXX: need pcblookup? */
772 in6a = in6_selectsrc(addr, inp->in6p_outputopts,
773 inp->in6p_moptions, &inp->in6p_route,
91447636 774 &inp->in6p_laddr, &storage, &error);
1c79356b
A
775 if (in6a == NULL)
776 return (error ? error : EADDRNOTAVAIL);
777 inp->in6p_laddr = *in6a;
778 inp->in6p_faddr = addr->sin6_addr;
779 soisconnected(so);
780 return 0;
781}
782
783static int
784rip6_shutdown(struct socket *so)
785{
786 socantsendmore(so);
787 return 0;
788}
789
790static int
2d21ac55
A
791rip6_send(struct socket *so, __unused int flags, struct mbuf *m, struct sockaddr *nam,
792 struct mbuf *control, __unused struct proc *p)
1c79356b
A
793{
794 struct inpcb *inp = sotoinpcb(so);
795 struct sockaddr_in6 tmp;
796 struct sockaddr_in6 *dst;
797
9bccf70c 798 /* always copy sockaddr to avoid overwrites */
1c79356b
A
799 if (so->so_state & SS_ISCONNECTED) {
800 if (nam) {
801 m_freem(m);
802 return EISCONN;
803 }
804 /* XXX */
805 bzero(&tmp, sizeof(tmp));
806 tmp.sin6_family = AF_INET6;
807 tmp.sin6_len = sizeof(struct sockaddr_in6);
808 bcopy(&inp->in6p_faddr, &tmp.sin6_addr,
809 sizeof(struct in6_addr));
810 dst = &tmp;
811 } else {
812 if (nam == NULL) {
813 m_freem(m);
814 return ENOTCONN;
815 }
9bccf70c
A
816 tmp = *(struct sockaddr_in6 *)nam;
817 dst = &tmp;
1c79356b 818 }
9bccf70c
A
819#if ENABLE_DEFAULT_SCOPE
820 if (dst->sin6_scope_id == 0) { /* not change if specified */
821 dst->sin6_scope_id = scope6_addr2default(&dst->sin6_addr);
822 }
823#endif
1c79356b
A
824 return rip6_output(m, so, dst, control);
825}
826
827struct pr_usrreqs rip6_usrreqs = {
828 rip6_abort, pru_accept_notsupp, rip6_attach, rip6_bind, rip6_connect,
829 pru_connect2_notsupp, in6_control, rip6_detach, rip6_disconnect,
830 pru_listen_notsupp, in6_setpeeraddr, pru_rcvd_notsupp,
9bccf70c 831 pru_rcvoob_notsupp, rip6_send, pru_sense_null, rip6_shutdown,
91447636 832 in6_setsockaddr, sosend, soreceive, pru_sopoll_notsupp
1c79356b 833};
2d21ac55
A
834
835__private_extern__ struct pr_usrreqs icmp6_dgram_usrreqs = {
836 rip6_abort, pru_accept_notsupp, icmp6_dgram_attach, rip6_bind, rip6_connect,
837 pru_connect2_notsupp, in6_control, rip6_detach, rip6_disconnect,
838 pru_listen_notsupp, in6_setpeeraddr, pru_rcvd_notsupp,
839 pru_rcvoob_notsupp, icmp6_dgram_send, pru_sense_null, rip6_shutdown,
840 in6_setsockaddr, sosend, soreceive, pru_sopoll_notsupp
841};
842
843
844