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