xref: /xnu-11215.61.5/bsd/netinet6/ah_output.c (revision 4f1223e81cd707a65cc109d0b8ad6653699da3c4)
1*4f1223e8SApple OSS Distributions /*
2*4f1223e8SApple OSS Distributions  * Copyright (c) 2008-2023 Apple Inc. All rights reserved.
3*4f1223e8SApple OSS Distributions  *
4*4f1223e8SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*4f1223e8SApple OSS Distributions  *
6*4f1223e8SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*4f1223e8SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*4f1223e8SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*4f1223e8SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*4f1223e8SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*4f1223e8SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*4f1223e8SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*4f1223e8SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*4f1223e8SApple OSS Distributions  *
15*4f1223e8SApple OSS Distributions  * Please obtain a copy of the License at
16*4f1223e8SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*4f1223e8SApple OSS Distributions  *
18*4f1223e8SApple OSS Distributions  * The Original Code and all software distributed under the License are
19*4f1223e8SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*4f1223e8SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*4f1223e8SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*4f1223e8SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*4f1223e8SApple OSS Distributions  * Please see the License for the specific language governing rights and
24*4f1223e8SApple OSS Distributions  * limitations under the License.
25*4f1223e8SApple OSS Distributions  *
26*4f1223e8SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*4f1223e8SApple OSS Distributions  */
28*4f1223e8SApple OSS Distributions 
29*4f1223e8SApple OSS Distributions /*	$FreeBSD: src/sys/netinet6/ah_output.c,v 1.1.2.3 2001/07/03 11:01:49 ume Exp $	*/
30*4f1223e8SApple OSS Distributions /*	$KAME: ah_output.c,v 1.30 2001/02/21 00:50:53 itojun Exp $	*/
31*4f1223e8SApple OSS Distributions 
32*4f1223e8SApple OSS Distributions /*
33*4f1223e8SApple OSS Distributions  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
34*4f1223e8SApple OSS Distributions  * All rights reserved.
35*4f1223e8SApple OSS Distributions  *
36*4f1223e8SApple OSS Distributions  * Redistribution and use in source and binary forms, with or without
37*4f1223e8SApple OSS Distributions  * modification, are permitted provided that the following conditions
38*4f1223e8SApple OSS Distributions  * are met:
39*4f1223e8SApple OSS Distributions  * 1. Redistributions of source code must retain the above copyright
40*4f1223e8SApple OSS Distributions  *    notice, this list of conditions and the following disclaimer.
41*4f1223e8SApple OSS Distributions  * 2. Redistributions in binary form must reproduce the above copyright
42*4f1223e8SApple OSS Distributions  *    notice, this list of conditions and the following disclaimer in the
43*4f1223e8SApple OSS Distributions  *    documentation and/or other materials provided with the distribution.
44*4f1223e8SApple OSS Distributions  * 3. Neither the name of the project nor the names of its contributors
45*4f1223e8SApple OSS Distributions  *    may be used to endorse or promote products derived from this software
46*4f1223e8SApple OSS Distributions  *    without specific prior written permission.
47*4f1223e8SApple OSS Distributions  *
48*4f1223e8SApple OSS Distributions  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
49*4f1223e8SApple OSS Distributions  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50*4f1223e8SApple OSS Distributions  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51*4f1223e8SApple OSS Distributions  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
52*4f1223e8SApple OSS Distributions  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53*4f1223e8SApple OSS Distributions  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54*4f1223e8SApple OSS Distributions  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55*4f1223e8SApple OSS Distributions  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56*4f1223e8SApple OSS Distributions  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57*4f1223e8SApple OSS Distributions  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58*4f1223e8SApple OSS Distributions  * SUCH DAMAGE.
59*4f1223e8SApple OSS Distributions  */
60*4f1223e8SApple OSS Distributions 
61*4f1223e8SApple OSS Distributions /*
62*4f1223e8SApple OSS Distributions  * RFC1826/2402 authentication header.
63*4f1223e8SApple OSS Distributions  */
64*4f1223e8SApple OSS Distributions 
65*4f1223e8SApple OSS Distributions #define _IP_VHL
66*4f1223e8SApple OSS Distributions 
67*4f1223e8SApple OSS Distributions #include <sys/param.h>
68*4f1223e8SApple OSS Distributions #include <sys/systm.h>
69*4f1223e8SApple OSS Distributions #include <sys/malloc.h>
70*4f1223e8SApple OSS Distributions #include <sys/mbuf.h>
71*4f1223e8SApple OSS Distributions #include <sys/domain.h>
72*4f1223e8SApple OSS Distributions #include <sys/protosw.h>
73*4f1223e8SApple OSS Distributions #include <sys/socket.h>
74*4f1223e8SApple OSS Distributions #include <sys/socketvar.h>
75*4f1223e8SApple OSS Distributions #include <sys/errno.h>
76*4f1223e8SApple OSS Distributions #include <sys/time.h>
77*4f1223e8SApple OSS Distributions #include <sys/kernel.h>
78*4f1223e8SApple OSS Distributions #include <sys/syslog.h>
79*4f1223e8SApple OSS Distributions 
80*4f1223e8SApple OSS Distributions #include <net/if.h>
81*4f1223e8SApple OSS Distributions #include <net/route.h>
82*4f1223e8SApple OSS Distributions 
83*4f1223e8SApple OSS Distributions #include <netinet/in.h>
84*4f1223e8SApple OSS Distributions 
85*4f1223e8SApple OSS Distributions #include <netinet/in_systm.h>
86*4f1223e8SApple OSS Distributions #include <netinet/ip.h>
87*4f1223e8SApple OSS Distributions #include <netinet/in_var.h>
88*4f1223e8SApple OSS Distributions 
89*4f1223e8SApple OSS Distributions #include <netinet/ip6.h>
90*4f1223e8SApple OSS Distributions #include <netinet6/ip6_var.h>
91*4f1223e8SApple OSS Distributions #include <netinet/icmp6.h>
92*4f1223e8SApple OSS Distributions 
93*4f1223e8SApple OSS Distributions #include <netinet6/ipsec.h>
94*4f1223e8SApple OSS Distributions #include <netinet6/ipsec6.h>
95*4f1223e8SApple OSS Distributions #include <netinet6/ah.h>
96*4f1223e8SApple OSS Distributions #include <netinet6/ah6.h>
97*4f1223e8SApple OSS Distributions #include <netkey/key.h>
98*4f1223e8SApple OSS Distributions #include <netkey/keydb.h>
99*4f1223e8SApple OSS Distributions 
100*4f1223e8SApple OSS Distributions #include <net/net_osdep.h>
101*4f1223e8SApple OSS Distributions 
102*4f1223e8SApple OSS Distributions #if INET
103*4f1223e8SApple OSS Distributions static struct in_addr *ah4_finaldst(struct mbuf *);
104*4f1223e8SApple OSS Distributions 
105*4f1223e8SApple OSS Distributions static LCK_GRP_DECLARE(sadb_stat_mutex_grp, "sadb_stat");
106*4f1223e8SApple OSS Distributions static LCK_MTX_DECLARE(sadb_stat_mutex, &sadb_stat_mutex_grp);
107*4f1223e8SApple OSS Distributions #endif
108*4f1223e8SApple OSS Distributions 
109*4f1223e8SApple OSS Distributions /*
110*4f1223e8SApple OSS Distributions  * compute AH header size.
111*4f1223e8SApple OSS Distributions  * transport mode only.  for tunnel mode, we should implement
112*4f1223e8SApple OSS Distributions  * virtual interface, and control MTU/MSS by the interface MTU.
113*4f1223e8SApple OSS Distributions  */
114*4f1223e8SApple OSS Distributions size_t
ah_hdrsiz(struct ipsecrequest * isr)115*4f1223e8SApple OSS Distributions ah_hdrsiz(struct ipsecrequest *isr)
116*4f1223e8SApple OSS Distributions {
117*4f1223e8SApple OSS Distributions 	/* sanity check */
118*4f1223e8SApple OSS Distributions 	if (isr == NULL) {
119*4f1223e8SApple OSS Distributions 		panic("ah_hdrsiz: NULL was passed.");
120*4f1223e8SApple OSS Distributions 	}
121*4f1223e8SApple OSS Distributions 
122*4f1223e8SApple OSS Distributions 	if (isr->saidx.proto != IPPROTO_AH) {
123*4f1223e8SApple OSS Distributions 		panic("unsupported mode passed to ah_hdrsiz");
124*4f1223e8SApple OSS Distributions 	}
125*4f1223e8SApple OSS Distributions 
126*4f1223e8SApple OSS Distributions #if 0
127*4f1223e8SApple OSS Distributions 	{
128*4f1223e8SApple OSS Distributions 		lck_mtx_lock(sadb_mutex);
129*4f1223e8SApple OSS Distributions 		const struct ah_algorithm *algo;
130*4f1223e8SApple OSS Distributions 		size_t hdrsiz;
131*4f1223e8SApple OSS Distributions 
132*4f1223e8SApple OSS Distributions 		/*%%%%% this needs to change - no sav in ipsecrequest any more */
133*4f1223e8SApple OSS Distributions 		if (isr->sav == NULL) {
134*4f1223e8SApple OSS Distributions 			goto estimate;
135*4f1223e8SApple OSS Distributions 		}
136*4f1223e8SApple OSS Distributions 		if (isr->sav->state != SADB_SASTATE_MATURE
137*4f1223e8SApple OSS Distributions 		    && isr->sav->state != SADB_SASTATE_DYING) {
138*4f1223e8SApple OSS Distributions 			goto estimate;
139*4f1223e8SApple OSS Distributions 		}
140*4f1223e8SApple OSS Distributions 
141*4f1223e8SApple OSS Distributions 		/* we need transport mode AH. */
142*4f1223e8SApple OSS Distributions 		algo = ah_algorithm_lookup(isr->sav->alg_auth);
143*4f1223e8SApple OSS Distributions 		if (!algo) {
144*4f1223e8SApple OSS Distributions 			goto estimate;
145*4f1223e8SApple OSS Distributions 		}
146*4f1223e8SApple OSS Distributions 
147*4f1223e8SApple OSS Distributions 		/*
148*4f1223e8SApple OSS Distributions 		 * XXX
149*4f1223e8SApple OSS Distributions 		 * right now we don't calcurate the padding size.  simply
150*4f1223e8SApple OSS Distributions 		 * treat the padding size as constant, for simplicity.
151*4f1223e8SApple OSS Distributions 		 *
152*4f1223e8SApple OSS Distributions 		 * XXX variable size padding support
153*4f1223e8SApple OSS Distributions 		 */
154*4f1223e8SApple OSS Distributions 		hdrsiz = (((*algo->sumsiz)(isr->sav) + 3) & ~(4 - 1));
155*4f1223e8SApple OSS Distributions 		if (isr->sav->flags & SADB_X_EXT_OLD) {
156*4f1223e8SApple OSS Distributions 			hdrsiz += sizeof(struct ah);
157*4f1223e8SApple OSS Distributions 		} else {
158*4f1223e8SApple OSS Distributions 			hdrsiz += sizeof(struct newah);
159*4f1223e8SApple OSS Distributions 		}
160*4f1223e8SApple OSS Distributions 
161*4f1223e8SApple OSS Distributions 		lck_mtx_unlock(sadb_mutex);
162*4f1223e8SApple OSS Distributions 		return hdrsiz;
163*4f1223e8SApple OSS Distributions 	}
164*4f1223e8SApple OSS Distributions 
165*4f1223e8SApple OSS Distributions estimate:
166*4f1223e8SApple OSS Distributions #endif
167*4f1223e8SApple OSS Distributions 
168*4f1223e8SApple OSS Distributions 	//lck_mtx_unlock(sadb_mutex);
169*4f1223e8SApple OSS Distributions 	/* ASSUMING:
170*4f1223e8SApple OSS Distributions 	 *	sizeof(struct newah) > sizeof(struct ah).
171*4f1223e8SApple OSS Distributions 	 *	16 = (16 + 3) & ~(4 - 1).
172*4f1223e8SApple OSS Distributions 	 */
173*4f1223e8SApple OSS Distributions 	return sizeof(struct newah) + 16;
174*4f1223e8SApple OSS Distributions }
175*4f1223e8SApple OSS Distributions 
176*4f1223e8SApple OSS Distributions #if INET
177*4f1223e8SApple OSS Distributions /*
178*4f1223e8SApple OSS Distributions  * Modify the packet so that it includes the authentication data.
179*4f1223e8SApple OSS Distributions  * The mbuf passed must start with IPv4 header.
180*4f1223e8SApple OSS Distributions  *
181*4f1223e8SApple OSS Distributions  * assumes that the first mbuf contains IPv4 header + option only.
182*4f1223e8SApple OSS Distributions  * the function does not modify m.
183*4f1223e8SApple OSS Distributions  */
184*4f1223e8SApple OSS Distributions int
ah4_output(struct mbuf * m,struct secasvar * sav)185*4f1223e8SApple OSS Distributions ah4_output(struct mbuf *m, struct secasvar *sav)
186*4f1223e8SApple OSS Distributions {
187*4f1223e8SApple OSS Distributions 	const struct ah_algorithm *algo;
188*4f1223e8SApple OSS Distributions 	u_int32_t spi;
189*4f1223e8SApple OSS Distributions 	u_char *ahdrpos;
190*4f1223e8SApple OSS Distributions 	u_char *ahsumpos = NULL;
191*4f1223e8SApple OSS Distributions 	size_t hlen = 0;        /*IP header+option in bytes*/
192*4f1223e8SApple OSS Distributions 	size_t plen = 0;        /*AH payload size in bytes*/
193*4f1223e8SApple OSS Distributions 	size_t ahlen = 0;       /*plen + sizeof(ah)*/
194*4f1223e8SApple OSS Distributions 	struct ip *ip;
195*4f1223e8SApple OSS Distributions 	struct in_addr dst = { .s_addr = 0 };
196*4f1223e8SApple OSS Distributions 	struct in_addr *finaldst;
197*4f1223e8SApple OSS Distributions 	int error;
198*4f1223e8SApple OSS Distributions 
199*4f1223e8SApple OSS Distributions 	/* sanity checks */
200*4f1223e8SApple OSS Distributions 	if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay[0] == NULL) {
201*4f1223e8SApple OSS Distributions 		ip = mtod(m, struct ip *);
202*4f1223e8SApple OSS Distributions 		ipseclog((LOG_DEBUG, "ah4_output: internal error: "
203*4f1223e8SApple OSS Distributions 		    "sav->replay is null: %x->%x, SPI=%u\n",
204*4f1223e8SApple OSS Distributions 		    (u_int32_t)ntohl(ip->ip_src.s_addr),
205*4f1223e8SApple OSS Distributions 		    (u_int32_t)ntohl(ip->ip_dst.s_addr),
206*4f1223e8SApple OSS Distributions 		    (u_int32_t)ntohl(sav->spi)));
207*4f1223e8SApple OSS Distributions 		IPSEC_STAT_INCREMENT(ipsecstat.out_inval);
208*4f1223e8SApple OSS Distributions 		m_freem(m);
209*4f1223e8SApple OSS Distributions 		return EINVAL;
210*4f1223e8SApple OSS Distributions 	}
211*4f1223e8SApple OSS Distributions 
212*4f1223e8SApple OSS Distributions 	algo = ah_algorithm_lookup(sav->alg_auth);
213*4f1223e8SApple OSS Distributions 	if (!algo) {
214*4f1223e8SApple OSS Distributions 		ipseclog((LOG_ERR, "ah4_output: unsupported algorithm: "
215*4f1223e8SApple OSS Distributions 		    "SPI=%u\n", (u_int32_t)ntohl(sav->spi)));
216*4f1223e8SApple OSS Distributions 		IPSEC_STAT_INCREMENT(ipsecstat.out_inval);
217*4f1223e8SApple OSS Distributions 		m_freem(m);
218*4f1223e8SApple OSS Distributions 		return EINVAL;
219*4f1223e8SApple OSS Distributions 	}
220*4f1223e8SApple OSS Distributions 	spi = sav->spi;
221*4f1223e8SApple OSS Distributions 
222*4f1223e8SApple OSS Distributions 	/*
223*4f1223e8SApple OSS Distributions 	 * determine the size to grow.
224*4f1223e8SApple OSS Distributions 	 */
225*4f1223e8SApple OSS Distributions 	if (sav->flags & SADB_X_EXT_OLD) {
226*4f1223e8SApple OSS Distributions 		/* RFC 1826 */
227*4f1223e8SApple OSS Distributions 		plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /*XXX pad to 8byte?*/
228*4f1223e8SApple OSS Distributions 		ahlen = plen + sizeof(struct ah);
229*4f1223e8SApple OSS Distributions 	} else {
230*4f1223e8SApple OSS Distributions 		/* RFC 2402 */
231*4f1223e8SApple OSS Distributions 		plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1); /*XXX pad to 8byte?*/
232*4f1223e8SApple OSS Distributions 		ahlen = plen + sizeof(struct newah);
233*4f1223e8SApple OSS Distributions 	}
234*4f1223e8SApple OSS Distributions 
235*4f1223e8SApple OSS Distributions 	VERIFY(ahlen <= UINT16_MAX);
236*4f1223e8SApple OSS Distributions 
237*4f1223e8SApple OSS Distributions 	/*
238*4f1223e8SApple OSS Distributions 	 * grow the mbuf to accomodate AH.
239*4f1223e8SApple OSS Distributions 	 */
240*4f1223e8SApple OSS Distributions 	ip = mtod(m, struct ip *);
241*4f1223e8SApple OSS Distributions #ifdef _IP_VHL
242*4f1223e8SApple OSS Distributions 	hlen = IP_VHL_HL(ip->ip_vhl) << 2;
243*4f1223e8SApple OSS Distributions #else
244*4f1223e8SApple OSS Distributions 	hlen = ip->ip_hl << 2;
245*4f1223e8SApple OSS Distributions #endif
246*4f1223e8SApple OSS Distributions 
247*4f1223e8SApple OSS Distributions 	if (m->m_len != hlen) {
248*4f1223e8SApple OSS Distributions 		panic("ah4_output: assumption failed (first mbuf length)");
249*4f1223e8SApple OSS Distributions 	}
250*4f1223e8SApple OSS Distributions 	if (M_LEADINGSPACE(m->m_next) < ahlen) {
251*4f1223e8SApple OSS Distributions 		struct mbuf *n;
252*4f1223e8SApple OSS Distributions 		MGET(n, M_DONTWAIT, MT_DATA);
253*4f1223e8SApple OSS Distributions 		if (!n) {
254*4f1223e8SApple OSS Distributions 			ipseclog((LOG_DEBUG, "ENOBUFS in ah4_output %d\n",
255*4f1223e8SApple OSS Distributions 			    __LINE__));
256*4f1223e8SApple OSS Distributions 			m_freem(m);
257*4f1223e8SApple OSS Distributions 			return ENOBUFS;
258*4f1223e8SApple OSS Distributions 		}
259*4f1223e8SApple OSS Distributions 		n->m_len = (int32_t)ahlen;
260*4f1223e8SApple OSS Distributions 		n->m_next = m->m_next;
261*4f1223e8SApple OSS Distributions 		m->m_next = n;
262*4f1223e8SApple OSS Distributions 		m->m_pkthdr.len += ahlen;
263*4f1223e8SApple OSS Distributions 		ahdrpos = mtod(n, u_char *);
264*4f1223e8SApple OSS Distributions 	} else {
265*4f1223e8SApple OSS Distributions 		m->m_next->m_len += ahlen;
266*4f1223e8SApple OSS Distributions 		m->m_next->m_data -= ahlen;
267*4f1223e8SApple OSS Distributions 		m->m_pkthdr.len += ahlen;
268*4f1223e8SApple OSS Distributions 		ahdrpos = mtod(m->m_next, u_char *);
269*4f1223e8SApple OSS Distributions 	}
270*4f1223e8SApple OSS Distributions 
271*4f1223e8SApple OSS Distributions 	ip = mtod(m, struct ip *);      /*just to be sure*/
272*4f1223e8SApple OSS Distributions 
273*4f1223e8SApple OSS Distributions 	/*
274*4f1223e8SApple OSS Distributions 	 * initialize AH.
275*4f1223e8SApple OSS Distributions 	 */
276*4f1223e8SApple OSS Distributions 	if (sav->flags & SADB_X_EXT_OLD) {
277*4f1223e8SApple OSS Distributions 		struct ah *ahdr;
278*4f1223e8SApple OSS Distributions 
279*4f1223e8SApple OSS Distributions 		VERIFY((plen >> 2) <= UINT8_MAX);
280*4f1223e8SApple OSS Distributions 		ahdr = (struct ah *)(void *)ahdrpos;
281*4f1223e8SApple OSS Distributions 		ahsumpos = (u_char *)(ahdr + 1);
282*4f1223e8SApple OSS Distributions 		ahdr->ah_len = (u_int8_t)(plen >> 2);
283*4f1223e8SApple OSS Distributions 		ahdr->ah_nxt = ip->ip_p;
284*4f1223e8SApple OSS Distributions 		ahdr->ah_reserve = htons(0);
285*4f1223e8SApple OSS Distributions 		ahdr->ah_spi = spi;
286*4f1223e8SApple OSS Distributions 		bzero(ahdr + 1, plen);
287*4f1223e8SApple OSS Distributions 	} else {
288*4f1223e8SApple OSS Distributions 		struct newah *ahdr;
289*4f1223e8SApple OSS Distributions 
290*4f1223e8SApple OSS Distributions 		VERIFY(((plen >> 2) + 1) <= UINT8_MAX);
291*4f1223e8SApple OSS Distributions 		ahdr = (struct newah *)(void *)ahdrpos;
292*4f1223e8SApple OSS Distributions 		ahsumpos = (u_char *)(ahdr + 1);
293*4f1223e8SApple OSS Distributions 		ahdr->ah_len = (u_int8_t)((plen >> 2) + 1); /* plus one for seq# */
294*4f1223e8SApple OSS Distributions 		ahdr->ah_nxt = ip->ip_p;
295*4f1223e8SApple OSS Distributions 		ahdr->ah_reserve = htons(0);
296*4f1223e8SApple OSS Distributions 		ahdr->ah_spi = spi;
297*4f1223e8SApple OSS Distributions 		if (sav->replay[0]->count == ~0) {
298*4f1223e8SApple OSS Distributions 			if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) {
299*4f1223e8SApple OSS Distributions 				/* XXX Is it noisy ? */
300*4f1223e8SApple OSS Distributions 				ipseclog((LOG_WARNING,
301*4f1223e8SApple OSS Distributions 				    "replay counter overflowed. %s\n",
302*4f1223e8SApple OSS Distributions 				    ipsec_logsastr(sav)));
303*4f1223e8SApple OSS Distributions 				IPSEC_STAT_INCREMENT(ipsecstat.out_inval);
304*4f1223e8SApple OSS Distributions 				m_freem(m);
305*4f1223e8SApple OSS Distributions 				return EINVAL;
306*4f1223e8SApple OSS Distributions 			}
307*4f1223e8SApple OSS Distributions 		}
308*4f1223e8SApple OSS Distributions 		lck_mtx_lock(sadb_mutex);
309*4f1223e8SApple OSS Distributions 		sav->replay[0]->count++;
310*4f1223e8SApple OSS Distributions 		lck_mtx_unlock(sadb_mutex);
311*4f1223e8SApple OSS Distributions 		/*
312*4f1223e8SApple OSS Distributions 		 * XXX sequence number must not be cycled, if the SA is
313*4f1223e8SApple OSS Distributions 		 * installed by IKE daemon.
314*4f1223e8SApple OSS Distributions 		 */
315*4f1223e8SApple OSS Distributions 		ahdr->ah_seq = htonl(sav->replay[0]->count);
316*4f1223e8SApple OSS Distributions 		bzero(ahdr + 1, plen);
317*4f1223e8SApple OSS Distributions 	}
318*4f1223e8SApple OSS Distributions 
319*4f1223e8SApple OSS Distributions 	/*
320*4f1223e8SApple OSS Distributions 	 * modify IPv4 header.
321*4f1223e8SApple OSS Distributions 	 */
322*4f1223e8SApple OSS Distributions 	ip->ip_p = IPPROTO_AH;
323*4f1223e8SApple OSS Distributions 	if (ahlen < (IP_MAXPACKET - ntohs(ip->ip_len))) {
324*4f1223e8SApple OSS Distributions 		ip->ip_len = htons(ntohs(ip->ip_len) + (u_int16_t)ahlen);
325*4f1223e8SApple OSS Distributions 	} else {
326*4f1223e8SApple OSS Distributions 		ipseclog((LOG_ERR, "IPv4 AH output: size exceeds limit\n"));
327*4f1223e8SApple OSS Distributions 		IPSEC_STAT_INCREMENT(ipsecstat.out_inval);
328*4f1223e8SApple OSS Distributions 		m_freem(m);
329*4f1223e8SApple OSS Distributions 		return EMSGSIZE;
330*4f1223e8SApple OSS Distributions 	}
331*4f1223e8SApple OSS Distributions 
332*4f1223e8SApple OSS Distributions 	/*
333*4f1223e8SApple OSS Distributions 	 * If there is source routing option, update destination field in
334*4f1223e8SApple OSS Distributions 	 * the IPv4 header to the final destination.
335*4f1223e8SApple OSS Distributions 	 * Note that we do not need to update source routing option itself
336*4f1223e8SApple OSS Distributions 	 * (as done in IPv4 AH processing -- see ip6_output()), since
337*4f1223e8SApple OSS Distributions 	 * source routing option is not part of the ICV computation.
338*4f1223e8SApple OSS Distributions 	 */
339*4f1223e8SApple OSS Distributions 	finaldst = ah4_finaldst(m);
340*4f1223e8SApple OSS Distributions 	if (finaldst) {
341*4f1223e8SApple OSS Distributions 		dst.s_addr = ip->ip_dst.s_addr;
342*4f1223e8SApple OSS Distributions 		ip->ip_dst.s_addr = finaldst->s_addr;
343*4f1223e8SApple OSS Distributions 	}
344*4f1223e8SApple OSS Distributions 
345*4f1223e8SApple OSS Distributions 	/*
346*4f1223e8SApple OSS Distributions 	 * calcurate the checksum, based on security association
347*4f1223e8SApple OSS Distributions 	 * and the algorithm specified.
348*4f1223e8SApple OSS Distributions 	 */
349*4f1223e8SApple OSS Distributions 	error = ah4_calccksum(m, (caddr_t)ahsumpos, plen, algo, sav);
350*4f1223e8SApple OSS Distributions 	if (error) {
351*4f1223e8SApple OSS Distributions 		ipseclog((LOG_ERR,
352*4f1223e8SApple OSS Distributions 		    "error after ah4_calccksum, called from ah4_output"));
353*4f1223e8SApple OSS Distributions 		m_freem(m);
354*4f1223e8SApple OSS Distributions 		m = NULL;
355*4f1223e8SApple OSS Distributions 		IPSEC_STAT_INCREMENT(ipsecstat.out_inval);
356*4f1223e8SApple OSS Distributions 		return error;
357*4f1223e8SApple OSS Distributions 	}
358*4f1223e8SApple OSS Distributions 
359*4f1223e8SApple OSS Distributions 	if (finaldst) {
360*4f1223e8SApple OSS Distributions 		ip = mtod(m, struct ip *);      /*just to make sure*/
361*4f1223e8SApple OSS Distributions 		ip->ip_dst.s_addr = dst.s_addr;
362*4f1223e8SApple OSS Distributions 	}
363*4f1223e8SApple OSS Distributions 	lck_mtx_lock(&sadb_stat_mutex);
364*4f1223e8SApple OSS Distributions 	ipsecstat.out_success++;
365*4f1223e8SApple OSS Distributions 	ipsecstat.out_ahhist[sav->alg_auth]++;
366*4f1223e8SApple OSS Distributions 	lck_mtx_unlock(&sadb_stat_mutex);
367*4f1223e8SApple OSS Distributions 	key_sa_recordxfer(sav, m->m_pkthdr.len);
368*4f1223e8SApple OSS Distributions 
369*4f1223e8SApple OSS Distributions 	return 0;
370*4f1223e8SApple OSS Distributions }
371*4f1223e8SApple OSS Distributions #endif
372*4f1223e8SApple OSS Distributions 
373*4f1223e8SApple OSS Distributions /* Calculate AH length */
374*4f1223e8SApple OSS Distributions size_t
ah_hdrlen(struct secasvar * sav)375*4f1223e8SApple OSS Distributions ah_hdrlen(struct secasvar *sav)
376*4f1223e8SApple OSS Distributions {
377*4f1223e8SApple OSS Distributions 	const struct ah_algorithm *algo;
378*4f1223e8SApple OSS Distributions 	size_t plen, ahlen;
379*4f1223e8SApple OSS Distributions 
380*4f1223e8SApple OSS Distributions 	algo = ah_algorithm_lookup(sav->alg_auth);
381*4f1223e8SApple OSS Distributions 	if (!algo) {
382*4f1223e8SApple OSS Distributions 		return 0;
383*4f1223e8SApple OSS Distributions 	}
384*4f1223e8SApple OSS Distributions 	if (sav->flags & SADB_X_EXT_OLD) {
385*4f1223e8SApple OSS Distributions 		/* RFC 1826 */
386*4f1223e8SApple OSS Distributions 		plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1);   /*XXX pad to 8byte?*/
387*4f1223e8SApple OSS Distributions 		ahlen = plen + sizeof(struct ah);
388*4f1223e8SApple OSS Distributions 	} else {
389*4f1223e8SApple OSS Distributions 		/* RFC 2402 */
390*4f1223e8SApple OSS Distributions 		plen = ((*algo->sumsiz)(sav) + 3) & ~(4 - 1);   /*XXX pad to 8byte?*/
391*4f1223e8SApple OSS Distributions 		ahlen = plen + sizeof(struct newah);
392*4f1223e8SApple OSS Distributions 	}
393*4f1223e8SApple OSS Distributions 
394*4f1223e8SApple OSS Distributions 	return ahlen;
395*4f1223e8SApple OSS Distributions }
396*4f1223e8SApple OSS Distributions 
397*4f1223e8SApple OSS Distributions /*
398*4f1223e8SApple OSS Distributions  * Fill in the Authentication Header and calculate checksum.
399*4f1223e8SApple OSS Distributions  */
400*4f1223e8SApple OSS Distributions int
ah6_output(struct mbuf * m,u_char * nexthdrp,struct mbuf * md,struct secasvar * sav)401*4f1223e8SApple OSS Distributions ah6_output(struct mbuf *m, u_char *nexthdrp, struct mbuf *md,
402*4f1223e8SApple OSS Distributions     struct secasvar *sav)
403*4f1223e8SApple OSS Distributions {
404*4f1223e8SApple OSS Distributions 	struct mbuf *mprev;
405*4f1223e8SApple OSS Distributions 	struct mbuf *mah;
406*4f1223e8SApple OSS Distributions 	const struct ah_algorithm *algo;
407*4f1223e8SApple OSS Distributions 	u_int32_t spi;
408*4f1223e8SApple OSS Distributions 	u_char *ahsumpos = NULL;
409*4f1223e8SApple OSS Distributions 	size_t plen;    /*AH payload size in bytes*/
410*4f1223e8SApple OSS Distributions 	int error = 0;
411*4f1223e8SApple OSS Distributions 	size_t ahlen;
412*4f1223e8SApple OSS Distributions 	struct ip6_hdr *ip6;
413*4f1223e8SApple OSS Distributions 
414*4f1223e8SApple OSS Distributions 	if (m->m_len < sizeof(struct ip6_hdr)) {
415*4f1223e8SApple OSS Distributions 		ipseclog((LOG_DEBUG, "ah6_output: first mbuf too short\n"));
416*4f1223e8SApple OSS Distributions 		m_freem(m);
417*4f1223e8SApple OSS Distributions 		return EINVAL;
418*4f1223e8SApple OSS Distributions 	}
419*4f1223e8SApple OSS Distributions 
420*4f1223e8SApple OSS Distributions 	ahlen = ah_hdrlen(sav);
421*4f1223e8SApple OSS Distributions 	if (ahlen == 0) {
422*4f1223e8SApple OSS Distributions 		return 0;
423*4f1223e8SApple OSS Distributions 	}
424*4f1223e8SApple OSS Distributions 
425*4f1223e8SApple OSS Distributions 	VERIFY(ahlen <= UINT16_MAX);
426*4f1223e8SApple OSS Distributions 
427*4f1223e8SApple OSS Distributions 	for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next) {
428*4f1223e8SApple OSS Distributions 		;
429*4f1223e8SApple OSS Distributions 	}
430*4f1223e8SApple OSS Distributions 	if (!mprev || mprev->m_next != md) {
431*4f1223e8SApple OSS Distributions 		ipseclog((LOG_DEBUG, "ah6_output: md is not in chain\n"));
432*4f1223e8SApple OSS Distributions 		m_freem(m);
433*4f1223e8SApple OSS Distributions 		return EINVAL;
434*4f1223e8SApple OSS Distributions 	}
435*4f1223e8SApple OSS Distributions 
436*4f1223e8SApple OSS Distributions 	MGET(mah, M_DONTWAIT, MT_DATA);
437*4f1223e8SApple OSS Distributions 	if (!mah) {
438*4f1223e8SApple OSS Distributions 		m_freem(m);
439*4f1223e8SApple OSS Distributions 		return ENOBUFS;
440*4f1223e8SApple OSS Distributions 	}
441*4f1223e8SApple OSS Distributions 	if (ahlen > MLEN) {
442*4f1223e8SApple OSS Distributions 		MCLGET(mah, M_DONTWAIT);
443*4f1223e8SApple OSS Distributions 		if ((mah->m_flags & M_EXT) == 0) {
444*4f1223e8SApple OSS Distributions 			m_free(mah);
445*4f1223e8SApple OSS Distributions 			m_freem(m);
446*4f1223e8SApple OSS Distributions 			return ENOBUFS;
447*4f1223e8SApple OSS Distributions 		}
448*4f1223e8SApple OSS Distributions 	}
449*4f1223e8SApple OSS Distributions 	mah->m_len = (int32_t)ahlen;
450*4f1223e8SApple OSS Distributions 	mah->m_next = md;
451*4f1223e8SApple OSS Distributions 	mprev->m_next = mah;
452*4f1223e8SApple OSS Distributions 	m->m_pkthdr.len += ahlen;
453*4f1223e8SApple OSS Distributions 
454*4f1223e8SApple OSS Distributions 	/* fix plen */
455*4f1223e8SApple OSS Distributions 	if (m->m_pkthdr.len - sizeof(struct ip6_hdr) > IPV6_MAXPACKET) {
456*4f1223e8SApple OSS Distributions 		ipseclog((LOG_ERR,
457*4f1223e8SApple OSS Distributions 		    "ip6_output: AH with IPv6 jumbogram is not supported\n"));
458*4f1223e8SApple OSS Distributions 		m_freem(m);
459*4f1223e8SApple OSS Distributions 		return EINVAL;
460*4f1223e8SApple OSS Distributions 	}
461*4f1223e8SApple OSS Distributions 
462*4f1223e8SApple OSS Distributions 	ip6 = mtod(m, struct ip6_hdr *);
463*4f1223e8SApple OSS Distributions 	ip6->ip6_plen = htons((u_int16_t)(m->m_pkthdr.len - sizeof(struct ip6_hdr)));
464*4f1223e8SApple OSS Distributions 
465*4f1223e8SApple OSS Distributions 	if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay[0] == NULL) {
466*4f1223e8SApple OSS Distributions 		ipseclog((LOG_DEBUG, "ah6_output: internal error: "
467*4f1223e8SApple OSS Distributions 		    "sav->replay is null: SPI=%u\n",
468*4f1223e8SApple OSS Distributions 		    (u_int32_t)ntohl(sav->spi)));
469*4f1223e8SApple OSS Distributions 		IPSEC_STAT_INCREMENT(ipsec6stat.out_inval);
470*4f1223e8SApple OSS Distributions 		m_freem(m);
471*4f1223e8SApple OSS Distributions 		return EINVAL;
472*4f1223e8SApple OSS Distributions 	}
473*4f1223e8SApple OSS Distributions 
474*4f1223e8SApple OSS Distributions 	algo = ah_algorithm_lookup(sav->alg_auth);
475*4f1223e8SApple OSS Distributions 	if (!algo) {
476*4f1223e8SApple OSS Distributions 		ipseclog((LOG_ERR, "ah6_output: unsupported algorithm: "
477*4f1223e8SApple OSS Distributions 		    "SPI=%u\n", (u_int32_t)ntohl(sav->spi)));
478*4f1223e8SApple OSS Distributions 		IPSEC_STAT_INCREMENT(ipsec6stat.out_inval);
479*4f1223e8SApple OSS Distributions 		m_freem(m);
480*4f1223e8SApple OSS Distributions 		return EINVAL;
481*4f1223e8SApple OSS Distributions 	}
482*4f1223e8SApple OSS Distributions 	spi = sav->spi;
483*4f1223e8SApple OSS Distributions 
484*4f1223e8SApple OSS Distributions 	/*
485*4f1223e8SApple OSS Distributions 	 * initialize AH.
486*4f1223e8SApple OSS Distributions 	 */
487*4f1223e8SApple OSS Distributions 	if (sav->flags & SADB_X_EXT_OLD) {
488*4f1223e8SApple OSS Distributions 		struct ah *ahdr = mtod(mah, struct ah *);
489*4f1223e8SApple OSS Distributions 
490*4f1223e8SApple OSS Distributions 		plen = mah->m_len - sizeof(struct ah);
491*4f1223e8SApple OSS Distributions 		VERIFY((plen >> 2) <= UINT8_MAX);
492*4f1223e8SApple OSS Distributions 		ahsumpos = (u_char *)(ahdr + 1);
493*4f1223e8SApple OSS Distributions 		ahdr->ah_nxt = *nexthdrp;
494*4f1223e8SApple OSS Distributions 		*nexthdrp = IPPROTO_AH;
495*4f1223e8SApple OSS Distributions 		ahdr->ah_len = (u_int8_t)(plen >> 2);
496*4f1223e8SApple OSS Distributions 		ahdr->ah_reserve = htons(0);
497*4f1223e8SApple OSS Distributions 		ahdr->ah_spi = spi;
498*4f1223e8SApple OSS Distributions 		bzero(ahdr + 1, plen);
499*4f1223e8SApple OSS Distributions 	} else {
500*4f1223e8SApple OSS Distributions 		struct newah *ahdr = mtod(mah, struct newah *);
501*4f1223e8SApple OSS Distributions 
502*4f1223e8SApple OSS Distributions 		plen = mah->m_len - sizeof(struct newah);
503*4f1223e8SApple OSS Distributions 		VERIFY(((plen >> 2) + 1) <= UINT8_MAX);
504*4f1223e8SApple OSS Distributions 		ahsumpos = (u_char *)(ahdr + 1);
505*4f1223e8SApple OSS Distributions 		ahdr->ah_nxt = *nexthdrp;
506*4f1223e8SApple OSS Distributions 		*nexthdrp = IPPROTO_AH;
507*4f1223e8SApple OSS Distributions 		ahdr->ah_len = (u_int8_t)((plen >> 2) + 1); /* plus one for seq# */
508*4f1223e8SApple OSS Distributions 		ahdr->ah_reserve = htons(0);
509*4f1223e8SApple OSS Distributions 		ahdr->ah_spi = spi;
510*4f1223e8SApple OSS Distributions 		if (sav->replay[0]->count == ~0) {
511*4f1223e8SApple OSS Distributions 			if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) {
512*4f1223e8SApple OSS Distributions 				/* XXX Is it noisy ? */
513*4f1223e8SApple OSS Distributions 				ipseclog((LOG_WARNING,
514*4f1223e8SApple OSS Distributions 				    "replay counter overflowed. %s\n",
515*4f1223e8SApple OSS Distributions 				    ipsec_logsastr(sav)));
516*4f1223e8SApple OSS Distributions 				IPSEC_STAT_INCREMENT(ipsec6stat.out_inval);
517*4f1223e8SApple OSS Distributions 				m_freem(m);
518*4f1223e8SApple OSS Distributions 				return EINVAL;
519*4f1223e8SApple OSS Distributions 			}
520*4f1223e8SApple OSS Distributions 		}
521*4f1223e8SApple OSS Distributions 		lck_mtx_lock(sadb_mutex);
522*4f1223e8SApple OSS Distributions 		sav->replay[0]->count++;
523*4f1223e8SApple OSS Distributions 		lck_mtx_unlock(sadb_mutex);
524*4f1223e8SApple OSS Distributions 		/*
525*4f1223e8SApple OSS Distributions 		 * XXX sequence number must not be cycled, if the SA is
526*4f1223e8SApple OSS Distributions 		 * installed by IKE daemon.
527*4f1223e8SApple OSS Distributions 		 */
528*4f1223e8SApple OSS Distributions 		ahdr->ah_seq = htonl(sav->replay[0]->count);
529*4f1223e8SApple OSS Distributions 		bzero(ahdr + 1, plen);
530*4f1223e8SApple OSS Distributions 	}
531*4f1223e8SApple OSS Distributions 
532*4f1223e8SApple OSS Distributions 	/*
533*4f1223e8SApple OSS Distributions 	 * calcurate the checksum, based on security association
534*4f1223e8SApple OSS Distributions 	 * and the algorithm specified.
535*4f1223e8SApple OSS Distributions 	 */
536*4f1223e8SApple OSS Distributions 	error = ah6_calccksum(m, (caddr_t)ahsumpos, plen, algo, sav);
537*4f1223e8SApple OSS Distributions 	if (error) {
538*4f1223e8SApple OSS Distributions 		IPSEC_STAT_INCREMENT(ipsec6stat.out_inval);
539*4f1223e8SApple OSS Distributions 		m_freem(m);
540*4f1223e8SApple OSS Distributions 	} else {
541*4f1223e8SApple OSS Distributions 		IPSEC_STAT_INCREMENT(ipsec6stat.out_success);
542*4f1223e8SApple OSS Distributions 		key_sa_recordxfer(sav, m->m_pkthdr.len);
543*4f1223e8SApple OSS Distributions 	}
544*4f1223e8SApple OSS Distributions 	IPSEC_STAT_INCREMENT(ipsec6stat.out_ahhist[sav->alg_auth]);
545*4f1223e8SApple OSS Distributions 
546*4f1223e8SApple OSS Distributions 	return error;
547*4f1223e8SApple OSS Distributions }
548*4f1223e8SApple OSS Distributions 
549*4f1223e8SApple OSS Distributions /*
550*4f1223e8SApple OSS Distributions  * Find the final destination if there is loose/strict source routing option.
551*4f1223e8SApple OSS Distributions  * Returns NULL if there's no source routing options.
552*4f1223e8SApple OSS Distributions  * Returns NULL on errors too.
553*4f1223e8SApple OSS Distributions  * Note that this function will return a pointer INTO the given parameter,
554*4f1223e8SApple OSS Distributions  * struct mbuf *m.
555*4f1223e8SApple OSS Distributions  * The mbuf must be pulled up toward, at least, ip option part.
556*4f1223e8SApple OSS Distributions  */
557*4f1223e8SApple OSS Distributions static struct in_addr *
ah4_finaldst(struct mbuf * m)558*4f1223e8SApple OSS Distributions ah4_finaldst(struct mbuf *m)
559*4f1223e8SApple OSS Distributions {
560*4f1223e8SApple OSS Distributions 	struct ip *ip;
561*4f1223e8SApple OSS Distributions 	int optlen;
562*4f1223e8SApple OSS Distributions 	u_char *q;
563*4f1223e8SApple OSS Distributions 	int i;
564*4f1223e8SApple OSS Distributions 	int hlen;
565*4f1223e8SApple OSS Distributions 
566*4f1223e8SApple OSS Distributions 	if (!m) {
567*4f1223e8SApple OSS Distributions 		panic("ah4_finaldst: m == NULL");
568*4f1223e8SApple OSS Distributions 	}
569*4f1223e8SApple OSS Distributions 	ip = mtod(m, struct ip *);
570*4f1223e8SApple OSS Distributions #ifdef _IP_VHL
571*4f1223e8SApple OSS Distributions 	hlen = IP_VHL_HL(ip->ip_vhl) << 2;
572*4f1223e8SApple OSS Distributions #else
573*4f1223e8SApple OSS Distributions 	hlen = ip->ip_hl << 2;
574*4f1223e8SApple OSS Distributions #endif
575*4f1223e8SApple OSS Distributions 
576*4f1223e8SApple OSS Distributions 	if (m->m_len < hlen) {
577*4f1223e8SApple OSS Distributions 		ipseclog((LOG_DEBUG,
578*4f1223e8SApple OSS Distributions 		    "ah4_finaldst: parameter mbuf wrong (not pulled up)\n"));
579*4f1223e8SApple OSS Distributions 		return NULL;
580*4f1223e8SApple OSS Distributions 	}
581*4f1223e8SApple OSS Distributions 
582*4f1223e8SApple OSS Distributions 	if (hlen == sizeof(struct ip)) {
583*4f1223e8SApple OSS Distributions 		return NULL;
584*4f1223e8SApple OSS Distributions 	}
585*4f1223e8SApple OSS Distributions 
586*4f1223e8SApple OSS Distributions 	optlen = hlen - sizeof(struct ip);
587*4f1223e8SApple OSS Distributions 	if (optlen < 0) {
588*4f1223e8SApple OSS Distributions 		ipseclog((LOG_DEBUG, "ah4_finaldst: wrong optlen %d\n",
589*4f1223e8SApple OSS Distributions 		    optlen));
590*4f1223e8SApple OSS Distributions 		return NULL;
591*4f1223e8SApple OSS Distributions 	}
592*4f1223e8SApple OSS Distributions 
593*4f1223e8SApple OSS Distributions 	q = (u_char *)(ip + 1);
594*4f1223e8SApple OSS Distributions 	i = 0;
595*4f1223e8SApple OSS Distributions 	while (i < optlen) {
596*4f1223e8SApple OSS Distributions 		if (i + IPOPT_OPTVAL >= optlen) {
597*4f1223e8SApple OSS Distributions 			return NULL;
598*4f1223e8SApple OSS Distributions 		}
599*4f1223e8SApple OSS Distributions 		if (q[i + IPOPT_OPTVAL] == IPOPT_EOL ||
600*4f1223e8SApple OSS Distributions 		    q[i + IPOPT_OPTVAL] == IPOPT_NOP ||
601*4f1223e8SApple OSS Distributions 		    i + IPOPT_OLEN < optlen) {
602*4f1223e8SApple OSS Distributions 			;
603*4f1223e8SApple OSS Distributions 		} else {
604*4f1223e8SApple OSS Distributions 			return NULL;
605*4f1223e8SApple OSS Distributions 		}
606*4f1223e8SApple OSS Distributions 
607*4f1223e8SApple OSS Distributions 		switch (q[i + IPOPT_OPTVAL]) {
608*4f1223e8SApple OSS Distributions 		case IPOPT_EOL:
609*4f1223e8SApple OSS Distributions 			i = optlen;     /* bye */
610*4f1223e8SApple OSS Distributions 			break;
611*4f1223e8SApple OSS Distributions 		case IPOPT_NOP:
612*4f1223e8SApple OSS Distributions 			i++;
613*4f1223e8SApple OSS Distributions 			break;
614*4f1223e8SApple OSS Distributions 		case IPOPT_LSRR:
615*4f1223e8SApple OSS Distributions 		case IPOPT_SSRR:
616*4f1223e8SApple OSS Distributions 			if (q[i + IPOPT_OLEN] < 2 + sizeof(struct in_addr) ||
617*4f1223e8SApple OSS Distributions 			    optlen - i < q[i + IPOPT_OLEN]) {
618*4f1223e8SApple OSS Distributions 				ipseclog((LOG_ERR,
619*4f1223e8SApple OSS Distributions 				    "ip_finaldst: invalid IP option "
620*4f1223e8SApple OSS Distributions 				    "(code=%02x len=%02x)\n",
621*4f1223e8SApple OSS Distributions 				    q[i + IPOPT_OPTVAL], q[i + IPOPT_OLEN]));
622*4f1223e8SApple OSS Distributions 				return NULL;
623*4f1223e8SApple OSS Distributions 			}
624*4f1223e8SApple OSS Distributions 			i += q[i + IPOPT_OLEN] - sizeof(struct in_addr);
625*4f1223e8SApple OSS Distributions 			return (struct in_addr *)(void *)(q + i);
626*4f1223e8SApple OSS Distributions 		default:
627*4f1223e8SApple OSS Distributions 			if (q[i + IPOPT_OLEN] < 2 ||
628*4f1223e8SApple OSS Distributions 			    optlen - i < q[i + IPOPT_OLEN]) {
629*4f1223e8SApple OSS Distributions 				ipseclog((LOG_ERR,
630*4f1223e8SApple OSS Distributions 				    "ip_finaldst: invalid IP option "
631*4f1223e8SApple OSS Distributions 				    "(code=%02x len=%02x)\n",
632*4f1223e8SApple OSS Distributions 				    q[i + IPOPT_OPTVAL], q[i + IPOPT_OLEN]));
633*4f1223e8SApple OSS Distributions 				return NULL;
634*4f1223e8SApple OSS Distributions 			}
635*4f1223e8SApple OSS Distributions 			i += q[i + IPOPT_OLEN];
636*4f1223e8SApple OSS Distributions 			break;
637*4f1223e8SApple OSS Distributions 		}
638*4f1223e8SApple OSS Distributions 	}
639*4f1223e8SApple OSS Distributions 	return NULL;
640*4f1223e8SApple OSS Distributions }
641