1/*
2 * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
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 */
28/*
29 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
30 * All rights reserved.
31 *
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.
43 *
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.
55 *
56 * $FreeBSD: src/sys/netinet6/raw_ip6.c,v 1.7.2.4 2001/07/29 19:32:40 ume Exp $
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 */
93#include <sys/param.h>
94#include <sys/malloc.h>
95#include <sys/proc.h>
96#include <sys/mcache.h>
97#include <sys/mbuf.h>
98#include <sys/socket.h>
99#include <sys/protosw.h>
100#include <sys/socketvar.h>
101#include <sys/errno.h>
102#include <sys/systm.h>
103
104#include <net/if.h>
105#include <net/route.h>
106#include <net/if_types.h>
107
108#include <netinet/in.h>
109#include <netinet/in_var.h>
110#include <netinet/in_systm.h>
111#include <netinet/ip6.h>
112#include <netinet6/ip6_var.h>
113#include <netinet6/ip6_mroute.h>
114#include <netinet/icmp6.h>
115#include <netinet/in_pcb.h>
116#include <netinet6/in6_pcb.h>
117#include <netinet6/nd6.h>
118#include <netinet6/ip6protosw.h>
119#if ENABLE_DEFAULT_SCOPE
120#include <netinet6/scope6_var.h>
121#endif
122#include <netinet6/raw_ip6.h>
123#include <netinet6/ip6_fw.h>
124
125#if IPSEC
126#include <netinet6/ipsec.h>
127#include <netinet6/ipsec6.h>
128extern int ipsec_bypass;
129#endif /*IPSEC*/
130
131/*
132 * Raw interface to IP6 protocol.
133 */
134
135extern struct	inpcbhead ripcb;
136extern struct	inpcbinfo ripcbinfo;
137extern u_int32_t	rip_sendspace;
138extern u_int32_t	rip_recvspace;
139extern int ip6_raw_ctloutput(struct socket *so, struct sockopt *sopt);
140
141struct rip6stat rip6stat;
142
143/*
144 * Setup generic address and protocol structures
145 * for raw_input routine, then pass them along with
146 * mbuf chain.
147 */
148int
149rip6_input(
150	struct	mbuf **mp,
151	int	*offp,
152	int	proto)
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;
158	struct mbuf *opts = NULL;
159	struct sockaddr_in6 rip6src;
160	int ret;
161
162	/* Expect 32-bit aligned data pointer on strict-align platforms */
163	MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m);
164
165	rip6stat.rip6s_ipackets++;
166
167	init_sin6(&rip6src, m); /* general init */
168
169	lck_rw_lock_shared(ripcbinfo.mtx);
170	LIST_FOREACH(in6p, &ripcb, inp_list) {
171		if ((in6p->in6p_vflag & INP_IPV6) == 0)
172			continue;
173		if (in6p->in6p_ip6_nxt &&
174		    in6p->in6p_ip6_nxt != proto)
175			continue;
176		if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) &&
177		    !IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst))
178			continue;
179		if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) &&
180		    !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
181			continue;
182		if (proto == IPPROTO_ICMPV6 || in6p->in6p_cksum != -1) {
183			rip6stat.rip6s_isum++;
184			if (in6_cksum(m, ip6->ip6_nxt, *offp,
185			    m->m_pkthdr.len - *offp)) {
186				rip6stat.rip6s_badsum++;
187				continue;
188			}
189		}
190		if (last) {
191			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
192
193#if IPSEC
194			/*
195			 * Check AH/ESP integrity.
196			 */
197			if (ipsec_bypass == 0 && n && ipsec6_in_reject_so(n, last->inp_socket)) {
198					m_freem(n);
199					IPSEC_STAT_INCREMENT(ipsec6stat.in_polvio);
200					/* do not inject data into pcb */
201			} else
202#endif /*IPSEC*/
203			if (n) {
204				if ((last->in6p_flags & IN6P_CONTROLOPTS) != 0 ||
205				    (last->in6p_socket->so_options & SO_TIMESTAMP) != 0 ||
206				    (last->in6p_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0) {
207					ret = ip6_savecontrol(last, n, &opts);
208					if (ret != 0) {
209						m_freem(n);
210						m_freem(opts);
211						last = in6p;
212						continue;
213					}
214				}
215				/* strip intermediate headers */
216				m_adj(n, *offp);
217				so_recv_data_stat(last->in6p_socket, m, 0);
218				if (sbappendaddr(&last->in6p_socket->so_rcv,
219						(struct sockaddr *)&rip6src,
220						 n, opts, NULL) == 0) {
221					rip6stat.rip6s_fullsock++;
222				} else
223					sorwakeup(last->in6p_socket);
224				opts = NULL;
225			}
226		}
227		last = in6p;
228	}
229
230#if IPSEC
231	/*
232	 * Check AH/ESP integrity.
233	 */
234	if (ipsec_bypass == 0 && last && ipsec6_in_reject_so(m, last->inp_socket)) {
235			m_freem(m);
236			IPSEC_STAT_INCREMENT(ipsec6stat.in_polvio);
237			ip6stat.ip6s_delivered--;
238			/* do not inject data into pcb */
239	} else
240#endif /*IPSEC*/
241	if (last) {
242		if ((last->in6p_flags & IN6P_CONTROLOPTS) != 0 ||
243		    (last->in6p_socket->so_options & SO_TIMESTAMP) != 0 ||
244		    (last->in6p_socket->so_options & SO_TIMESTAMP_MONOTONIC) != 0) {
245			ret = ip6_savecontrol(last, m, &opts);
246			if (ret != 0) {
247				m_freem(m);
248				m_freem(opts);
249				ip6stat.ip6s_delivered--;
250				goto unlock;
251			}
252
253		}
254		/* strip intermediate headers */
255		m_adj(m, *offp);
256		so_recv_data_stat(last->in6p_socket, m, 0);
257		if (sbappendaddr(&last->in6p_socket->so_rcv,
258				(struct sockaddr *)&rip6src, m, opts, NULL) == 0) {
259			rip6stat.rip6s_fullsock++;
260		} else
261			sorwakeup(last->in6p_socket);
262	} else {
263		rip6stat.rip6s_nosock++;
264		if (m->m_flags & M_MCAST)
265			rip6stat.rip6s_nosockmcast++;
266		if (proto == IPPROTO_NONE)
267			m_freem(m);
268		else {
269			char *prvnxtp = ip6_get_prevhdr(m, *offp); /* XXX */
270			icmp6_error(m, ICMP6_PARAM_PROB,
271				    ICMP6_PARAMPROB_NEXTHEADER,
272				    prvnxtp - mtod(m, char *));
273		}
274		ip6stat.ip6s_delivered--;
275	}
276
277unlock:
278	lck_rw_done(ripcbinfo.mtx);
279
280	return IPPROTO_DONE;
281}
282
283void
284rip6_ctlinput(
285	int cmd,
286	struct sockaddr *sa,
287	void *d)
288{
289	struct ip6_hdr *ip6;
290	struct mbuf *m;
291	void *cmdarg = NULL;
292	int off = 0;
293	struct ip6ctlparam *ip6cp = NULL;
294	const struct sockaddr_in6 *sa6_src = NULL;
295	void (*notify)(struct inpcb *, int) = in6_rtchange;
296
297	if (sa->sa_family != AF_INET6 ||
298	    sa->sa_len != sizeof(struct sockaddr_in6))
299		return;
300
301	if ((unsigned)cmd >= PRC_NCMDS)
302		return;
303	if (PRC_IS_REDIRECT(cmd))
304		notify = in6_rtchange, d = NULL;
305	else if (cmd == PRC_HOSTDEAD)
306		d = NULL;
307	else if (inet6ctlerrmap[cmd] == 0)
308		return;
309
310	/* if the parameter is from icmp6, decode it. */
311	if (d != NULL) {
312		ip6cp = (struct ip6ctlparam *)d;
313		m = ip6cp->ip6c_m;
314		ip6 = ip6cp->ip6c_ip6;
315		off = ip6cp->ip6c_off;
316		cmdarg = ip6cp->ip6c_cmdarg;
317		sa6_src = ip6cp->ip6c_src;
318	} else {
319		m = NULL;
320		ip6 = NULL;
321		sa6_src = &sa6_any;
322	}
323
324	(void) in6_pcbnotify(&ripcbinfo, sa, 0, (const struct sockaddr *)sa6_src,
325			     0, cmd, cmdarg, notify);
326}
327
328/*
329 * Generate IPv6 header and pass packet to ip6_output.
330 * Tack on options user may have setup with control call.
331 */
332int
333rip6_output(
334	register struct mbuf *m,
335	struct socket *so,
336	struct sockaddr_in6 *dstsock,
337	struct mbuf *control,
338	int israw)
339{
340	struct in6_addr *dst;
341	struct ip6_hdr *ip6;
342	struct inpcb *in6p;
343	u_int	plen = m->m_pkthdr.len;
344	int error = 0;
345	struct ip6_pktopts opt, *optp = 0;
346	struct ip6_moptions *im6o = NULL;
347	struct ifnet *oifp = NULL;
348	int type = 0, code = 0;		/* for ICMPv6 output statistics only */
349	mbuf_svc_class_t msc = MBUF_SC_UNSPEC;
350	struct ip6_out_args ip6oa =
351	    { IFSCOPE_NONE, { 0 }, IP6OAF_SELECT_SRCIF };
352	int flags = IPV6_OUTARGS;
353
354	if (dstsock && IN6_IS_ADDR_V4MAPPED(&dstsock->sin6_addr)) {
355		m_freem(m);
356		return (EINVAL);
357	}
358
359	in6p = sotoin6pcb(so);
360
361	if (in6p->inp_flags & INP_BOUND_IF) {
362		ip6oa.ip6oa_boundif = in6p->inp_boundifp->if_index;
363		ip6oa.ip6oa_flags |= IP6OAF_BOUND_IF;
364	}
365	if (in6p->inp_flags & INP_NO_IFT_CELLULAR)
366		ip6oa.ip6oa_flags |= IP6OAF_NO_CELLULAR;
367
368	dst = &dstsock->sin6_addr;
369	if (control) {
370		msc = mbuf_service_class_from_control(control);
371
372		if ((error = ip6_setpktopts(control, &opt, NULL, so->so_proto->pr_protocol)) != 0)
373			goto bad;
374		optp = &opt;
375	} else
376		optp = in6p->in6p_outputopts;
377
378	/*
379	 * For an ICMPv6 packet, we should know its type and code
380	 * to update statistics.
381	 */
382	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
383		struct icmp6_hdr *icmp6;
384		if (m->m_len < sizeof(struct icmp6_hdr) &&
385		    (m = m_pullup(m, sizeof(struct icmp6_hdr))) == NULL) {
386			error = ENOBUFS;
387			goto bad;
388		}
389		icmp6 = mtod(m, struct icmp6_hdr *);
390		type = icmp6->icmp6_type;
391		code = icmp6->icmp6_code;
392	}
393
394	if (in6p->inp_flowhash == 0)
395		in6p->inp_flowhash = inp_calc_flowhash(in6p);
396
397	M_PREPEND(m, sizeof(*ip6), M_WAIT);
398	if (m == NULL) {
399		error = ENOBUFS;
400		goto bad;
401	}
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
409	im6o = in6p->in6p_moptions;
410
411	/*
412	 * If the scope of the destination is link-local, embed the interface
413	 * index in the address.
414	 *
415	 * XXX advanced-api value overrides sin6_scope_id
416	 */
417	if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
418		struct in6_pktinfo *pi;
419		struct ifnet *im6o_multicast_ifp = NULL;
420
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		}
426		/*
427		 * XXX Boundary check is assumed to be already done in
428		 * ip6_setpktoptions().
429		 */
430		ifnet_head_lock_shared();
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];
434			if (oifp != NULL)
435				ifnet_reference(oifp);
436		} else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) &&
437		    im6o != NULL && im6o_multicast_ifp != NULL) {
438			oifp = im6o_multicast_ifp;
439			ifnet_reference(oifp);
440			ip6->ip6_dst.s6_addr16[1] = htons(oifp->if_index);
441		} else if (dstsock->sin6_scope_id) {
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) {
449				error = ENXIO;  /* XXX EINVAL? */
450				ifnet_head_done();
451				goto bad;
452			}
453			ip6->ip6_dst.s6_addr16[1]
454				= htons(dstsock->sin6_scope_id & 0xffff);/*XXX*/
455		}
456		ifnet_head_done();
457	}
458
459	/*
460	 * Source address selection.
461	 */
462	{
463		struct in6_addr *in6a;
464		struct in6_addr	storage;
465		u_short index = 0;
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) {
473			if (error == 0)
474				error = EADDRNOTAVAIL;
475			goto bad;
476		} else {
477			ip6oa.ip6oa_flags |= IP6OAF_BOUND_SRCADDR;
478		}
479		ip6->ip6_src = *in6a;
480		if (in6p->in6p_route.ro_rt != NULL) {
481			RT_LOCK(in6p->in6p_route.ro_rt);
482			if (in6p->in6p_route.ro_rt->rt_ifp != NULL)
483				index = in6p->in6p_route.ro_rt->rt_ifp->if_index;
484			RT_UNLOCK(in6p->in6p_route.ro_rt);
485			if (oifp != NULL)
486				ifnet_release(oifp);
487			ifnet_head_lock_shared();
488			if (index == 0 || if_index < index) {
489				panic("bad if_index on interface from route");
490			}
491			oifp = ifindex2ifnet[index];
492			if (oifp != NULL)
493				ifnet_reference(oifp);
494			ifnet_head_done();
495		}
496	}
497	ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) |
498		(in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK);
499	ip6->ip6_vfc = (ip6->ip6_vfc & ~IPV6_VERSION_MASK) |
500		(IPV6_VERSION & IPV6_VERSION_MASK);
501	/* ip6_plen will be filled in ip6_output, so not fill it here. */
502	ip6->ip6_nxt = in6p->in6p_ip6_nxt;
503	ip6->ip6_hlim = in6_selecthlim(in6p, oifp);
504
505	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6 ||
506	    in6p->in6p_cksum != -1) {
507		struct mbuf *n;
508		int off;
509		u_int16_t *p;
510
511		/* compute checksum */
512		if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
513			off = offsetof(struct icmp6_hdr, icmp6_cksum);
514		else
515			off = in6p->in6p_cksum;
516		if (plen < (unsigned int)(off + 1)) {
517			error = EINVAL;
518			goto bad;
519		}
520		off += sizeof(struct ip6_hdr);
521
522		n = m;
523		while (n && n->m_len <= off) {
524			off -= n->m_len;
525			n = n->m_next;
526		}
527		if (!n)
528			goto bad;
529		p = (u_int16_t *)(void *)(mtod(n, caddr_t) + off);
530		*p = 0;
531		*p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
532	}
533
534#if IPSEC
535	if (ipsec_bypass == 0 && ipsec_setsocket(m, so) != 0) {
536		error = ENOBUFS;
537		goto bad;
538	}
539#endif /*IPSEC*/
540
541	if (in6p->in6p_route.ro_rt != NULL &&
542	    in6p->in6p_route.ro_rt->generation_id != route_generation) {
543		rtfree(in6p->in6p_route.ro_rt);
544		in6p->in6p_route.ro_rt = NULL;
545	}
546
547	if (oifp != NULL) {
548		ifnet_release(oifp);
549		oifp = NULL;
550	}
551
552	set_packet_service_class(m, so, msc, PKT_SCF_IPV6);
553	m->m_pkthdr.m_flowhash = in6p->inp_flowhash;
554	m->m_pkthdr.m_fhflags |= PF_TAG_FLOWHASH;
555
556	if (im6o != NULL)
557		IM6O_ADDREF(im6o);
558
559	error = ip6_output(m, optp, &in6p->in6p_route, flags, im6o,
560	    &oifp, &ip6oa);
561
562	if (im6o != NULL)
563		IM6O_REMREF(im6o);
564
565	if (in6p->in6p_route.ro_rt != NULL) {
566		struct rtentry *rt = in6p->in6p_route.ro_rt;
567		struct ifnet *outif;
568
569		if ((rt->rt_flags & RTF_MULTICAST) ||
570		    in6p->in6p_socket == NULL ||
571		    !(in6p->in6p_socket->so_state & SS_ISCONNECTED)) {
572			rt = NULL;	/* unusable */
573		}
574		/*
575		 * Always discard the cached route for unconnected
576		 * socket or if it is a multicast route.
577		 */
578		if (rt == NULL) {
579			rtfree(in6p->in6p_route.ro_rt);
580			in6p->in6p_route.ro_rt = NULL;
581		}
582		/*
583		 * If this is a connected socket and the destination
584		 * route is not multicast, update outif with that of
585		 * the route interface index used by IP.
586		 */
587		if (rt != NULL &&
588		    (outif = rt->rt_ifp) != in6p->in6p_last_outifp)
589			in6p->in6p_last_outifp = outif;
590	}
591
592	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
593		if (oifp)
594			icmp6_ifoutstat_inc(oifp, type, code);
595		icmp6stat.icp6s_outhist[type]++;
596	} else
597		rip6stat.rip6s_opackets++;
598
599	goto freectl;
600
601 bad:
602	if (m)
603		m_freem(m);
604
605 freectl:
606	if (optp == &opt && optp->ip6po_rthdr && optp->ip6po_route.ro_rt) {
607		rtfree(optp->ip6po_route.ro_rt);
608		optp->ip6po_route.ro_rt = NULL;
609	}
610	if (control) {
611		if (optp == &opt)
612			ip6_clearpktopts(optp, -1);
613		m_freem(control);
614	}
615	if (oifp != NULL)
616		ifnet_release(oifp);
617	return(error);
618}
619
620#if IPFW2
621__private_extern__ void
622load_ip6fw(void)
623{
624	ip6_fw_init();
625}
626#endif
627
628/*
629 * Raw IPv6 socket option processing.
630 */
631int
632rip6_ctloutput(
633	struct socket *so,
634	struct sockopt *sopt)
635{
636	int error, optval;
637
638	/* Allow <SOL_SOCKET,SO_FLUSH> at this level */
639	if (sopt->sopt_level == IPPROTO_ICMPV6)
640		/*
641		 * XXX: is it better to call icmp6_ctloutput() directly
642		 * from protosw?
643		 */
644		return(icmp6_ctloutput(so, sopt));
645	else if (sopt->sopt_level != IPPROTO_IPV6 &&
646	    !(sopt->sopt_level == SOL_SOCKET && sopt->sopt_name == SO_FLUSH))
647		return (EINVAL);
648
649	error = 0;
650
651	switch (sopt->sopt_dir) {
652	case SOPT_GET:
653		switch (sopt->sopt_name) {
654#if IPFW2
655		case IPV6_FW_ADD:
656		case IPV6_FW_GET:
657			if (ip6_fw_ctl_ptr == 0)
658				load_ip6fw();
659			if (ip6_fw_ctl_ptr)
660				error = ip6_fw_ctl_ptr(sopt);
661			else
662				error = ENOPROTOOPT;
663			break;
664#endif
665
666		case MRT6_INIT:
667		case MRT6_DONE:
668		case MRT6_ADD_MIF:
669		case MRT6_DEL_MIF:
670		case MRT6_ADD_MFC:
671		case MRT6_DEL_MFC:
672		case MRT6_PIM:
673#if MROUTING
674			error = ip6_mrouter_get(so, sopt);
675#else
676			error = ENOPROTOOPT;
677#endif /* MROUTING */
678			break;
679		case IPV6_CHECKSUM:
680			error = ip6_raw_ctloutput(so, sopt);
681			break;
682		default:
683			error = ip6_ctloutput(so, sopt);
684			break;
685		}
686		break;
687
688	case SOPT_SET:
689		switch (sopt->sopt_name) {
690#if IPFW2
691		case IPV6_FW_ADD:
692		case IPV6_FW_DEL:
693		case IPV6_FW_FLUSH:
694		case IPV6_FW_ZERO:
695			if (ip6_fw_ctl_ptr == 0)
696				load_ip6fw();
697			if (ip6_fw_ctl_ptr)
698				error = ip6_fw_ctl_ptr(sopt);
699			else
700				error = ENOPROTOOPT;
701			break;
702#endif
703
704		case MRT6_INIT:
705		case MRT6_DONE:
706		case MRT6_ADD_MIF:
707		case MRT6_DEL_MIF:
708		case MRT6_ADD_MFC:
709		case MRT6_DEL_MFC:
710		case MRT6_PIM:
711#if MROUTING
712			error = ip6_mrouter_set(so, sopt);
713#else
714			error = ENOPROTOOPT;
715#endif
716			break;
717		case IPV6_CHECKSUM:
718			error = ip6_raw_ctloutput(so, sopt);
719			break;
720
721		case SO_FLUSH:
722			if ((error = sooptcopyin(sopt, &optval, sizeof (optval),
723			    sizeof (optval))) != 0)
724				break;
725
726			error = inp_flush(sotoinpcb(so), optval);
727			break;
728
729		default:
730			error = ip6_ctloutput(so, sopt);
731			break;
732		}
733		break;
734	}
735
736	return (error);
737}
738
739static int
740rip6_attach(struct socket *so, int proto, struct proc *p)
741{
742	struct inpcb *inp;
743	int error;
744
745	inp = sotoinpcb(so);
746	if (inp)
747		panic("rip6_attach");
748	if ((error = proc_suser(p)) != 0)
749		return error;
750
751	error = soreserve(so, rip_sendspace, rip_recvspace);
752	if (error)
753		return error;
754	error = in_pcballoc(so, &ripcbinfo, p);
755	if (error)
756		return error;
757	inp = (struct inpcb *)so->so_pcb;
758	inp->inp_vflag |= INP_IPV6;
759	inp->in6p_ip6_nxt = (char)proto;
760	inp->in6p_hops = -1;	/* use kernel default */
761	inp->in6p_cksum = -1;
762	MALLOC(inp->in6p_icmp6filt, struct icmp6_filter *,
763	       sizeof(struct icmp6_filter), M_PCB, M_WAITOK);
764	if (inp->in6p_icmp6filt == NULL)
765		return (ENOMEM);
766	ICMP6_FILTER_SETPASSALL(inp->in6p_icmp6filt);
767	return 0;
768}
769
770static int
771rip6_detach(struct socket *so)
772{
773	struct inpcb *inp;
774
775	inp = sotoinpcb(so);
776	if (inp == 0)
777		panic("rip6_detach");
778	/* xxx: RSVP */
779#if MROUTING
780	if (so == ip6_mrouter)
781		ip6_mrouter_done();
782#endif
783	if (inp->in6p_icmp6filt) {
784		FREE(inp->in6p_icmp6filt, M_PCB);
785		inp->in6p_icmp6filt = NULL;
786	}
787	in6_pcbdetach(inp);
788	return 0;
789}
790
791static int
792rip6_abort(struct socket *so)
793{
794	soisdisconnected(so);
795	return rip6_detach(so);
796}
797
798static int
799rip6_disconnect(struct socket *so)
800{
801	struct inpcb *inp = sotoinpcb(so);
802
803	if ((so->so_state & SS_ISCONNECTED) == 0)
804		return ENOTCONN;
805	inp->in6p_faddr = in6addr_any;
806	return rip6_abort(so);
807}
808
809static int
810rip6_bind(struct socket *so, struct sockaddr *nam, __unused struct proc *p)
811{
812	struct inpcb *inp = sotoinpcb(so);
813	struct sockaddr_in6 *addr = (struct sockaddr_in6 *)(void *)nam;
814	struct ifaddr *ifa = NULL;
815	struct ifnet *outif = NULL;
816
817	if (nam->sa_len != sizeof(*addr))
818		return EINVAL;
819
820	if (TAILQ_EMPTY(&ifnet_head) || addr->sin6_family != AF_INET6)
821		return EADDRNOTAVAIL;
822#if ENABLE_DEFAULT_SCOPE
823	if (addr->sin6_scope_id == 0) {	/* not change if specified  */
824		addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr);
825	}
826#endif
827	if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
828	    (ifa = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)
829		return EADDRNOTAVAIL;
830	if (ifa != NULL) {
831		IFA_LOCK(ifa);
832		if (((struct in6_ifaddr *)ifa)->ia6_flags &
833		    (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
834		     IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
835			IFA_UNLOCK(ifa);
836			IFA_REMREF(ifa);
837			return(EADDRNOTAVAIL);
838		}
839		outif = ifa->ifa_ifp;
840		IFA_UNLOCK(ifa);
841		IFA_REMREF(ifa);
842	}
843	inp->in6p_laddr = addr->sin6_addr;
844	inp->in6p_last_outifp = outif;
845	return 0;
846}
847
848static int
849rip6_connect(struct socket *so, struct sockaddr *nam, __unused struct proc *p)
850{
851	struct inpcb *inp = sotoinpcb(so);
852	struct sockaddr_in6 *addr = (struct sockaddr_in6 *)(void *)nam;
853	struct in6_addr *in6a = NULL;
854	struct in6_addr storage;
855	int error = 0;
856#if ENABLE_DEFAULT_SCOPE
857	struct sockaddr_in6 tmp;
858#endif
859	unsigned int ifscope;
860	struct ifnet *outif = NULL;
861
862	if (nam->sa_len != sizeof(*addr))
863		return EINVAL;
864	if (TAILQ_EMPTY(&ifnet_head))
865		return EADDRNOTAVAIL;
866	if (addr->sin6_family != AF_INET6)
867		return EAFNOSUPPORT;
868#if ENABLE_DEFAULT_SCOPE
869	if (addr->sin6_scope_id == 0) {	/* not change if specified  */
870		/* avoid overwrites */
871		tmp = *addr;
872		addr = &tmp;
873		addr->sin6_scope_id = scope6_addr2default(&addr->sin6_addr);
874	}
875#endif
876
877	ifscope = (inp->inp_flags & INP_BOUND_IF) ?
878	    inp->inp_boundifp->if_index : IFSCOPE_NONE;
879
880	/* Source address selection. XXX: need pcblookup? */
881	in6a = in6_selectsrc(addr, inp->in6p_outputopts, inp, &inp->in6p_route,
882	    NULL, &storage, ifscope, &error);
883	if (in6a == NULL)
884		return (error ? error : EADDRNOTAVAIL);
885	inp->in6p_laddr = *in6a;
886	inp->in6p_faddr = addr->sin6_addr;
887	if (inp->in6p_route.ro_rt != NULL)
888		outif = inp->in6p_route.ro_rt->rt_ifp;
889	inp->in6p_last_outifp = outif;
890	soisconnected(so);
891	return 0;
892}
893
894static int
895rip6_shutdown(struct socket *so)
896{
897	socantsendmore(so);
898	return 0;
899}
900
901static int
902rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
903	 struct mbuf *control, struct proc *p)
904{
905#pragma unused(flags, p)
906	struct inpcb *inp = sotoinpcb(so);
907	struct sockaddr_in6 tmp;
908	struct sockaddr_in6 *dst = (struct sockaddr_in6 *)(void *)nam;
909
910	/* always copy sockaddr to avoid overwrites */
911	if (so->so_state & SS_ISCONNECTED) {
912		if (nam) {
913			m_freem(m);
914			return EISCONN;
915		}
916		/* XXX */
917		bzero(&tmp, sizeof(tmp));
918		tmp.sin6_family = AF_INET6;
919		tmp.sin6_len = sizeof(struct sockaddr_in6);
920		bcopy(&inp->in6p_faddr, &tmp.sin6_addr,
921		      sizeof(struct in6_addr));
922		dst = &tmp;
923	} else {
924		if (nam == NULL) {
925			m_freem(m);
926			return ENOTCONN;
927		}
928		tmp = *(struct sockaddr_in6 *)(void *)nam;
929		dst = &tmp;
930	}
931#if ENABLE_DEFAULT_SCOPE
932	if (dst->sin6_scope_id == 0) {	/* not change if specified  */
933		dst->sin6_scope_id = scope6_addr2default(&dst->sin6_addr);
934	}
935#endif
936	return rip6_output(m, so, dst, control, 1);
937}
938
939struct pr_usrreqs rip6_usrreqs = {
940	rip6_abort, pru_accept_notsupp, rip6_attach, rip6_bind, rip6_connect,
941	pru_connect2_notsupp, in6_control, rip6_detach, rip6_disconnect,
942	pru_listen_notsupp, in6_setpeeraddr, pru_rcvd_notsupp,
943	pru_rcvoob_notsupp, rip6_send, pru_sense_null, rip6_shutdown,
944	in6_setsockaddr, sosend, soreceive, pru_sopoll_notsupp
945};
946
947__private_extern__ struct pr_usrreqs icmp6_dgram_usrreqs = {
948        rip6_abort, pru_accept_notsupp, icmp6_dgram_attach, rip6_bind, rip6_connect,
949        pru_connect2_notsupp, in6_control, rip6_detach, rip6_disconnect,
950        pru_listen_notsupp, in6_setpeeraddr, pru_rcvd_notsupp,
951        pru_rcvoob_notsupp, icmp6_dgram_send, pru_sense_null, rip6_shutdown,
952        in6_setsockaddr, sosend, soreceive, pru_sopoll_notsupp
953};
954
955
956
957