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