]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/esp_input.c
2052493abeba91c5253c09a2b3a1a512f1fc1b04
[apple/xnu.git] / bsd / netinet6 / esp_input.c
1 /*
2 * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /* $FreeBSD: src/sys/netinet6/esp_input.c,v 1.1.2.3 2001/07/03 11:01:50 ume Exp $ */
30 /* $KAME: esp_input.c,v 1.55 2001/03/23 08:08:47 itojun Exp $ */
31
32 /*
33 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the project nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 */
60
61 /*
62 * RFC1827/2406 Encapsulated Security Payload.
63 */
64
65 #include <sys/param.h>
66 #include <sys/systm.h>
67 #include <sys/malloc.h>
68 #include <sys/mbuf.h>
69 #include <sys/domain.h>
70 #include <sys/protosw.h>
71 #include <sys/socket.h>
72 #include <sys/errno.h>
73 #include <sys/time.h>
74 #include <sys/kernel.h>
75 #include <sys/syslog.h>
76
77 #include <net/if.h>
78 #include <net/route.h>
79 #include <kern/cpu_number.h>
80 #include <kern/locks.h>
81
82 #include <netinet/in.h>
83 #include <netinet/in_systm.h>
84 #include <netinet/ip.h>
85 #include <netinet/ip_var.h>
86 #include <netinet/in_var.h>
87 #include <netinet/ip_ecn.h>
88 #include <netinet/in_pcb.h>
89 #include <netinet/udp.h>
90 #if INET6
91 #include <netinet6/ip6_ecn.h>
92 #endif
93
94 #if INET6
95 #include <netinet/ip6.h>
96 #include <netinet6/in6_pcb.h>
97 #include <netinet6/ip6_var.h>
98 #include <netinet/icmp6.h>
99 #include <netinet6/ip6protosw.h>
100 #endif
101
102 #include <netinet6/ipsec.h>
103 #if INET6
104 #include <netinet6/ipsec6.h>
105 #endif
106 #include <netinet6/ah.h>
107 #if INET6
108 #include <netinet6/ah6.h>
109 #endif
110 #include <netinet6/esp.h>
111 #if INET6
112 #include <netinet6/esp6.h>
113 #endif
114 #include <netkey/key.h>
115 #include <netkey/keydb.h>
116 #include <netkey/key_debug.h>
117
118 #include <net/kpi_protocol.h>
119 #include <netinet/kpi_ipfilter_var.h>
120
121 #include <net/net_osdep.h>
122 #include <mach/sdt.h>
123
124 #include <sys/kdebug.h>
125 #define DBG_LAYER_BEG NETDBG_CODE(DBG_NETIPSEC, 1)
126 #define DBG_LAYER_END NETDBG_CODE(DBG_NETIPSEC, 3)
127 #define DBG_FNC_ESPIN NETDBG_CODE(DBG_NETIPSEC, (6 << 8))
128 #define DBG_FNC_DECRYPT NETDBG_CODE(DBG_NETIPSEC, (7 << 8))
129 #define IPLEN_FLIPPED
130
131 extern lck_mtx_t *sadb_mutex;
132
133 #if INET
134 extern struct protosw inetsw[];
135
136 #define ESPMAXLEN \
137 (sizeof(struct esp) < sizeof(struct newesp) \
138 ? sizeof(struct newesp) : sizeof(struct esp))
139
140 static struct ip *
141 esp4_input_strip_UDP_encap (struct mbuf *m, int iphlen)
142 {
143 // strip the udp header that's encapsulating ESP
144 struct ip *ip;
145 size_t stripsiz = sizeof(struct udphdr);
146
147 ip = mtod(m, __typeof__(ip));
148 ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), iphlen);
149 m->m_data += stripsiz;
150 m->m_len -= stripsiz;
151 m->m_pkthdr.len -= stripsiz;
152 ip = mtod(m, __typeof__(ip));
153 ip->ip_len = ip->ip_len - stripsiz;
154 ip->ip_p = IPPROTO_ESP;
155 return ip;
156 }
157
158 void
159 esp4_input(m, off)
160 struct mbuf *m;
161 int off;
162 {
163 struct ip *ip;
164 #if INET6
165 struct ip6_hdr *ip6;
166 #endif /* INET6 */
167 struct esp *esp;
168 struct esptail esptail;
169 u_int32_t spi;
170 u_int32_t seq;
171 struct secasvar *sav = NULL;
172 size_t taillen;
173 u_int16_t nxt;
174 const struct esp_algorithm *algo;
175 int ivlen;
176 size_t hlen;
177 size_t esplen;
178 sa_family_t ifamily;
179
180 KERNEL_DEBUG(DBG_FNC_ESPIN | DBG_FUNC_START, 0,0,0,0,0);
181 /* sanity check for alignment. */
182 if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) {
183 ipseclog((LOG_ERR, "IPv4 ESP input: packet alignment problem "
184 "(off=%d, pktlen=%d)\n", off, m->m_pkthdr.len));
185 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
186 goto bad;
187 }
188
189 if (m->m_len < off + ESPMAXLEN) {
190 m = m_pullup(m, off + ESPMAXLEN);
191 if (!m) {
192 ipseclog((LOG_DEBUG,
193 "IPv4 ESP input: can't pullup in esp4_input\n"));
194 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
195 goto bad;
196 }
197 }
198
199 ip = mtod(m, struct ip *);
200 // expect udp-encap and esp packets only
201 if (ip->ip_p != IPPROTO_ESP &&
202 !(ip->ip_p == IPPROTO_UDP && off >= sizeof(struct udphdr))) {
203 ipseclog((LOG_DEBUG,
204 "IPv4 ESP input: invalid protocol type\n"));
205 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
206 goto bad;
207 }
208 esp = (struct esp *)(((u_int8_t *)ip) + off);
209 #ifdef _IP_VHL
210 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
211 #else
212 hlen = ip->ip_hl << 2;
213 #endif
214
215 /* find the sassoc. */
216 spi = esp->esp_spi;
217
218 if ((sav = key_allocsa(AF_INET,
219 (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst,
220 IPPROTO_ESP, spi)) == 0) {
221 ipseclog((LOG_WARNING,
222 "IPv4 ESP input: no key association found for spi %u\n",
223 (u_int32_t)ntohl(spi)));
224 IPSEC_STAT_INCREMENT(ipsecstat.in_nosa);
225 goto bad;
226 }
227 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
228 printf("DP esp4_input called to allocate SA:%p\n", sav));
229 if (sav->state != SADB_SASTATE_MATURE
230 && sav->state != SADB_SASTATE_DYING) {
231 ipseclog((LOG_DEBUG,
232 "IPv4 ESP input: non-mature/dying SA found for spi %u\n",
233 (u_int32_t)ntohl(spi)));
234 IPSEC_STAT_INCREMENT(ipsecstat.in_badspi);
235 goto bad;
236 }
237 algo = esp_algorithm_lookup(sav->alg_enc);
238 if (!algo) {
239 ipseclog((LOG_DEBUG, "IPv4 ESP input: "
240 "unsupported encryption algorithm for spi %u\n",
241 (u_int32_t)ntohl(spi)));
242 IPSEC_STAT_INCREMENT(ipsecstat.in_badspi);
243 goto bad;
244 }
245
246 /* check if we have proper ivlen information */
247 ivlen = sav->ivlen;
248 if (ivlen < 0) {
249 ipseclog((LOG_ERR, "inproper ivlen in IPv4 ESP input: %s %s\n",
250 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
251 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
252 goto bad;
253 }
254
255 seq = ntohl(((struct newesp *)esp)->esp_seq);
256 if (!((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay
257 && (sav->alg_auth && sav->key_auth)))
258 goto noreplaycheck;
259
260 if (sav->alg_auth == SADB_X_AALG_NULL ||
261 sav->alg_auth == SADB_AALG_NONE)
262 goto noreplaycheck;
263
264 /*
265 * check for sequence number.
266 */
267 if (ipsec_chkreplay(seq, sav))
268 ; /*okey*/
269 else {
270 IPSEC_STAT_INCREMENT(ipsecstat.in_espreplay);
271 ipseclog((LOG_WARNING,
272 "replay packet in IPv4 ESP input: %s %s\n",
273 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
274 goto bad;
275 }
276
277 /* check ICV */
278 {
279 u_char sum0[AH_MAXSUMSIZE];
280 u_char sum[AH_MAXSUMSIZE];
281 const struct ah_algorithm *sumalgo;
282 size_t siz;
283
284 sumalgo = ah_algorithm_lookup(sav->alg_auth);
285 if (!sumalgo)
286 goto noreplaycheck;
287 siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1));
288 if (m->m_pkthdr.len < off + ESPMAXLEN + siz) {
289 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
290 goto bad;
291 }
292 if (AH_MAXSUMSIZE < siz) {
293 ipseclog((LOG_DEBUG,
294 "internal error: AH_MAXSUMSIZE must be larger than %lu\n",
295 (u_int32_t)siz));
296 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
297 goto bad;
298 }
299
300 m_copydata(m, m->m_pkthdr.len - siz, siz, (caddr_t) &sum0[0]);
301
302 if (esp_auth(m, off, m->m_pkthdr.len - off - siz, sav, sum)) {
303 ipseclog((LOG_WARNING, "auth fail in IPv4 ESP input: %s %s\n",
304 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
305 IPSEC_STAT_INCREMENT(ipsecstat.in_espauthfail);
306 goto bad;
307 }
308
309 if (bcmp(sum0, sum, siz) != 0) {
310 ipseclog((LOG_WARNING, "auth fail in IPv4 ESP input: %s %s\n",
311 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
312 IPSEC_STAT_INCREMENT(ipsecstat.in_espauthfail);
313 goto bad;
314 }
315
316 /* strip off the authentication data */
317 m_adj(m, -siz);
318 ip = mtod(m, struct ip *);
319 #ifdef IPLEN_FLIPPED
320 ip->ip_len = ip->ip_len - siz;
321 #else
322 ip->ip_len = htons(ntohs(ip->ip_len) - siz);
323 #endif
324 m->m_flags |= M_AUTHIPDGM;
325 IPSEC_STAT_INCREMENT(ipsecstat.in_espauthsucc);
326 }
327
328 /*
329 * update sequence number.
330 */
331 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
332 if (ipsec_updatereplay(seq, sav)) {
333 IPSEC_STAT_INCREMENT(ipsecstat.in_espreplay);
334 goto bad;
335 }
336 }
337
338 noreplaycheck:
339
340 /* process main esp header. */
341 if (sav->flags & SADB_X_EXT_OLD) {
342 /* RFC 1827 */
343 esplen = sizeof(struct esp);
344 } else {
345 /* RFC 2406 */
346 if (sav->flags & SADB_X_EXT_DERIV)
347 esplen = sizeof(struct esp);
348 else
349 esplen = sizeof(struct newesp);
350 }
351
352 if (m->m_pkthdr.len < off + esplen + ivlen + sizeof(esptail)) {
353 ipseclog((LOG_WARNING,
354 "IPv4 ESP input: packet too short\n"));
355 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
356 goto bad;
357 }
358
359 if (m->m_len < off + esplen + ivlen) {
360 m = m_pullup(m, off + esplen + ivlen);
361 if (!m) {
362 ipseclog((LOG_DEBUG,
363 "IPv4 ESP input: can't pullup in esp4_input\n"));
364 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
365 goto bad;
366 }
367 }
368
369 /*
370 * pre-compute and cache intermediate key
371 */
372 if (esp_schedule(algo, sav) != 0) {
373 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
374 goto bad;
375 }
376
377 /*
378 * decrypt the packet.
379 */
380 if (!algo->decrypt)
381 panic("internal error: no decrypt function");
382 KERNEL_DEBUG(DBG_FNC_DECRYPT | DBG_FUNC_START, 0,0,0,0,0);
383 if ((*algo->decrypt)(m, off, sav, algo, ivlen)) {
384 /* m is already freed */
385 m = NULL;
386 ipseclog((LOG_ERR, "decrypt fail in IPv4 ESP input: %s\n",
387 ipsec_logsastr(sav)));
388 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
389 KERNEL_DEBUG(DBG_FNC_DECRYPT | DBG_FUNC_END, 1,0,0,0,0);
390 goto bad;
391 }
392 KERNEL_DEBUG(DBG_FNC_DECRYPT | DBG_FUNC_END, 2,0,0,0,0);
393 IPSEC_STAT_INCREMENT(ipsecstat.in_esphist[sav->alg_enc]);
394
395 m->m_flags |= M_DECRYPTED;
396
397 /*
398 * find the trailer of the ESP.
399 */
400 m_copydata(m, m->m_pkthdr.len - sizeof(esptail), sizeof(esptail),
401 (caddr_t)&esptail);
402 nxt = esptail.esp_nxt;
403 taillen = esptail.esp_padlen + sizeof(esptail);
404
405 if (m->m_pkthdr.len < taillen
406 || m->m_pkthdr.len - taillen < hlen) { /*?*/
407 ipseclog((LOG_WARNING,
408 "bad pad length in IPv4 ESP input: %s %s\n",
409 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
410 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
411 goto bad;
412 }
413
414 /* strip off the trailing pad area. */
415 m_adj(m, -taillen);
416 ip = mtod(m, struct ip *);
417 #ifdef IPLEN_FLIPPED
418 ip->ip_len = ip->ip_len - taillen;
419 #else
420 ip->ip_len = htons(ntohs(ip->ip_len) - taillen);
421 #endif
422 if (ip->ip_p == IPPROTO_UDP) {
423 // offset includes the outer ip and udp header lengths.
424 if (m->m_len < off) {
425 m = m_pullup(m, off);
426 if (!m) {
427 ipseclog((LOG_DEBUG,
428 "IPv4 ESP input: invalid udp encapsulated ESP packet length \n"));
429 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
430 goto bad;
431 }
432 }
433
434 // check the UDP encap header to detect changes in the source port, and then strip the header
435 off -= sizeof(struct udphdr); // off no longer includes the udphdr's size
436 // if peer is behind nat and this is the latest esp packet
437 if ((sav->flags & SADB_X_EXT_NATT_DETECTED_PEER) != 0 &&
438 (sav->flags & SADB_X_EXT_OLD) == 0 &&
439 seq && sav->replay &&
440 seq >= sav->replay->lastseq) {
441 struct udphdr *encap_uh = (__typeof__(encap_uh))((caddr_t)ip + off);
442 if (encap_uh->uh_sport &&
443 ntohs(encap_uh->uh_sport) != sav->remote_ike_port) {
444 sav->remote_ike_port = ntohs(encap_uh->uh_sport);
445 }
446 }
447 ip = esp4_input_strip_UDP_encap(m, off);
448 esp = (struct esp *)(((u_int8_t *)ip) + off);
449 }
450
451 /* was it transmitted over the IPsec tunnel SA? */
452 if (ipsec4_tunnel_validate(m, off + esplen + ivlen, nxt, sav, &ifamily)) {
453 ifaddr_t ifa;
454 struct sockaddr_storage addr;
455
456 /*
457 * strip off all the headers that precedes ESP header.
458 * IP4 xx ESP IP4' payload -> IP4' payload
459 *
460 * XXX more sanity checks
461 * XXX relationship with gif?
462 */
463 u_int8_t tos;
464
465 tos = ip->ip_tos;
466 m_adj(m, off + esplen + ivlen);
467 if (ifamily == AF_INET) {
468 struct sockaddr_in *ipaddr;
469
470 if (m->m_len < sizeof(*ip)) {
471 m = m_pullup(m, sizeof(*ip));
472 if (!m) {
473 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
474 goto bad;
475 }
476 }
477 ip = mtod(m, struct ip *);
478 /* ECN consideration. */
479 ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos);
480 if (!key_checktunnelsanity(sav, AF_INET,
481 (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) {
482 ipseclog((LOG_ERR, "ipsec tunnel address mismatch "
483 "in ESP input: %s %s\n",
484 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
485 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
486 goto bad;
487 }
488
489 if (ip_doscopedroute) {
490 bzero(&addr, sizeof(addr));
491 ipaddr = (__typeof__(ipaddr))&addr;
492 ipaddr->sin_family = AF_INET;
493 ipaddr->sin_len = sizeof(*ipaddr);
494 ipaddr->sin_addr = ip->ip_dst;
495 }
496 #if INET6
497 } else if (ifamily == AF_INET6) {
498 struct sockaddr_in6 *ip6addr;
499
500 #ifndef PULLDOWN_TEST
501 /*
502 * m_pullup is prohibited in KAME IPv6 input processing
503 * but there's no other way!
504 */
505 #else
506 /* okay to pullup in m_pulldown style */
507 #endif
508 if (m->m_len < sizeof(*ip6)) {
509 m = m_pullup(m, sizeof(*ip6));
510 if (!m) {
511 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
512 goto bad;
513 }
514 }
515
516 ip6 = mtod(m, struct ip6_hdr *);
517
518 /* ECN consideration. */
519 /* XXX To be fixed later if needed */
520 // ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos);
521
522 if (!key_checktunnelsanity(sav, AF_INET6,
523 (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) {
524 ipseclog((LOG_ERR, "ipsec tunnel address mismatch "
525 "in ESP input: %s %s\n",
526 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
527 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
528 goto bad;
529 }
530
531 if (ip6_doscopedroute) {
532 bzero(&addr, sizeof(addr));
533 ip6addr = (__typeof__(ip6addr))&addr;
534 ip6addr->sin6_family = AF_INET6;
535 ip6addr->sin6_len = sizeof(*ip6addr);
536 ip6addr->sin6_addr = ip6->ip6_dst;
537 }
538 #endif /* INET6 */
539 } else {
540 ipseclog((LOG_ERR, "ipsec tunnel unsupported address family "
541 "in ESP input\n"));
542 goto bad;
543 }
544
545 key_sa_recordxfer(sav, m);
546 if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 ||
547 ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) {
548 IPSEC_STAT_INCREMENT(ipsecstat.in_nomem);
549 goto bad;
550 }
551
552 if (ip_doscopedroute || ip6_doscopedroute) {
553 // update the receiving interface address based on the inner address
554 ifa = ifa_ifwithaddr((struct sockaddr *)&addr);
555 if (ifa) {
556 m->m_pkthdr.rcvif = ifa->ifa_ifp;
557 IFA_REMREF(ifa);
558 }
559 }
560
561 /* Clear the csum flags, they can't be valid for the inner headers */
562 m->m_pkthdr.csum_flags = 0;
563 if (proto_input(ifamily == AF_INET ? PF_INET : PF_INET6, m) != 0)
564 goto bad;
565
566 nxt = IPPROTO_DONE;
567 KERNEL_DEBUG(DBG_FNC_ESPIN | DBG_FUNC_END, 2,0,0,0,0);
568 } else {
569 /*
570 * strip off ESP header and IV.
571 * even in m_pulldown case, we need to strip off ESP so that
572 * we can always compute checksum for AH correctly.
573 */
574 size_t stripsiz;
575
576 stripsiz = esplen + ivlen;
577
578 ip = mtod(m, struct ip *);
579 ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off);
580 m->m_data += stripsiz;
581 m->m_len -= stripsiz;
582 m->m_pkthdr.len -= stripsiz;
583
584 ip = mtod(m, struct ip *);
585 #ifdef IPLEN_FLIPPED
586 ip->ip_len = ip->ip_len - stripsiz;
587 #else
588 ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz);
589 #endif
590 ip->ip_p = nxt;
591
592 key_sa_recordxfer(sav, m);
593 if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0) {
594 IPSEC_STAT_INCREMENT(ipsecstat.in_nomem);
595 goto bad;
596 }
597
598 /*
599 * Set the csum valid flag, if we authenticated the
600 * packet, the payload shouldn't be corrupt unless
601 * it was corrupted before being signed on the other
602 * side.
603 */
604 if (nxt == IPPROTO_TCP || nxt == IPPROTO_UDP) {
605 m->m_pkthdr.csum_flags = CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
606 m->m_pkthdr.csum_data = 0xFFFF;
607 }
608
609 if (nxt != IPPROTO_DONE) {
610 if ((ip_protox[nxt]->pr_flags & PR_LASTHDR) != 0 &&
611 ipsec4_in_reject(m, NULL)) {
612 IPSEC_STAT_INCREMENT(ipsecstat.in_polvio);
613 goto bad;
614 }
615 KERNEL_DEBUG(DBG_FNC_ESPIN | DBG_FUNC_END, 3,0,0,0,0);
616
617 /* translate encapsulated UDP port ? */
618 if ((sav->flags & SADB_X_EXT_NATT_MULTIPLEUSERS) != 0) {
619 struct udphdr *udp;
620
621 if (nxt != IPPROTO_UDP) { /* not UPD packet - drop it */
622 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
623 goto bad;
624 }
625
626 if (m->m_len < off + sizeof(struct udphdr)) {
627 m = m_pullup(m, off + sizeof(struct udphdr));
628 if (!m) {
629 ipseclog((LOG_DEBUG,
630 "IPv4 ESP input: can't pullup UDP header in esp4_input\n"));
631 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
632 goto bad;
633 }
634 ip = mtod(m, struct ip *);
635 }
636 udp = (struct udphdr *)(((u_int8_t *)ip) + off);
637
638 lck_mtx_lock(sadb_mutex);
639 if (sav->natt_encapsulated_src_port == 0) {
640 sav->natt_encapsulated_src_port = udp->uh_sport;
641 } else if (sav->natt_encapsulated_src_port != udp->uh_sport) { /* something wrong */
642 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
643 lck_mtx_unlock(sadb_mutex);
644 goto bad;
645 }
646 lck_mtx_unlock(sadb_mutex);
647 udp->uh_sport = htons(sav->remote_ike_port);
648 udp->uh_sum = 0;
649 }
650
651 DTRACE_IP6(receive, struct mbuf *, m, struct inpcb *, NULL,
652 struct ip *, ip, struct ifnet *, m->m_pkthdr.rcvif,
653 struct ip *, ip, struct ip6_hdr *, NULL);
654
655 ip_proto_dispatch_in(m, off, nxt, 0);
656 } else
657 m_freem(m);
658 m = NULL;
659 }
660
661 if (sav) {
662 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
663 printf("DP esp4_input call free SA:%p\n", sav));
664 key_freesav(sav, KEY_SADB_UNLOCKED);
665 }
666 IPSEC_STAT_INCREMENT(ipsecstat.in_success);
667 return;
668
669 bad:
670 if (sav) {
671 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
672 printf("DP esp4_input call free SA:%p\n", sav));
673 key_freesav(sav, KEY_SADB_UNLOCKED);
674 }
675 if (m)
676 m_freem(m);
677 KERNEL_DEBUG(DBG_FNC_ESPIN | DBG_FUNC_END, 4,0,0,0,0);
678 return;
679 }
680 #endif /* INET */
681
682 #if INET6
683 int
684 esp6_input(struct mbuf **mp, int *offp, int proto)
685 {
686 #pragma unused(proto)
687 struct mbuf *m = *mp;
688 int off = *offp;
689 struct ip6_hdr *ip6;
690 struct esp *esp;
691 struct esptail esptail;
692 u_int32_t spi;
693 u_int32_t seq;
694 struct secasvar *sav = NULL;
695 size_t taillen;
696 u_int16_t nxt;
697 const struct esp_algorithm *algo;
698 int ivlen;
699 size_t esplen;
700
701 /* sanity check for alignment. */
702 if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) {
703 ipseclog((LOG_ERR, "IPv6 ESP input: packet alignment problem "
704 "(off=%d, pktlen=%d)\n", off, m->m_pkthdr.len));
705 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
706 goto bad;
707 }
708
709 #ifndef PULLDOWN_TEST
710 IP6_EXTHDR_CHECK(m, off, ESPMAXLEN, {return IPPROTO_DONE;});
711 esp = (struct esp *)(mtod(m, caddr_t) + off);
712 #else
713 IP6_EXTHDR_GET(esp, struct esp *, m, off, ESPMAXLEN);
714 if (esp == NULL) {
715 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
716 return IPPROTO_DONE;
717 }
718 #endif
719 ip6 = mtod(m, struct ip6_hdr *);
720
721 if (ntohs(ip6->ip6_plen) == 0) {
722 ipseclog((LOG_ERR, "IPv6 ESP input: "
723 "ESP with IPv6 jumbogram is not supported.\n"));
724 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
725 goto bad;
726 }
727
728 /* find the sassoc. */
729 spi = esp->esp_spi;
730
731 if ((sav = key_allocsa(AF_INET6,
732 (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst,
733 IPPROTO_ESP, spi)) == 0) {
734 ipseclog((LOG_WARNING,
735 "IPv6 ESP input: no key association found for spi %u\n",
736 (u_int32_t)ntohl(spi)));
737 IPSEC_STAT_INCREMENT(ipsec6stat.in_nosa);
738 goto bad;
739 }
740 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
741 printf("DP esp6_input called to allocate SA:%p\n", sav));
742 if (sav->state != SADB_SASTATE_MATURE
743 && sav->state != SADB_SASTATE_DYING) {
744 ipseclog((LOG_DEBUG,
745 "IPv6 ESP input: non-mature/dying SA found for spi %u\n",
746 (u_int32_t)ntohl(spi)));
747 IPSEC_STAT_INCREMENT(ipsec6stat.in_badspi);
748 goto bad;
749 }
750 algo = esp_algorithm_lookup(sav->alg_enc);
751 if (!algo) {
752 ipseclog((LOG_DEBUG, "IPv6 ESP input: "
753 "unsupported encryption algorithm for spi %u\n",
754 (u_int32_t)ntohl(spi)));
755 IPSEC_STAT_INCREMENT(ipsec6stat.in_badspi);
756 goto bad;
757 }
758
759 /* check if we have proper ivlen information */
760 ivlen = sav->ivlen;
761 if (ivlen < 0) {
762 ipseclog((LOG_ERR, "inproper ivlen in IPv6 ESP input: %s %s\n",
763 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
764 IPSEC_STAT_INCREMENT(ipsec6stat.in_badspi);
765 goto bad;
766 }
767
768 seq = ntohl(((struct newesp *)esp)->esp_seq);
769
770 if (!((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay
771 && (sav->alg_auth && sav->key_auth)))
772 goto noreplaycheck;
773
774 if (sav->alg_auth == SADB_X_AALG_NULL ||
775 sav->alg_auth == SADB_AALG_NONE)
776 goto noreplaycheck;
777
778 /*
779 * check for sequence number.
780 */
781 if (ipsec_chkreplay(seq, sav))
782 ; /*okey*/
783 else {
784 IPSEC_STAT_INCREMENT(ipsec6stat.in_espreplay);
785 ipseclog((LOG_WARNING,
786 "replay packet in IPv6 ESP input: %s %s\n",
787 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
788 goto bad;
789 }
790
791 /* check ICV */
792 {
793 u_char sum0[AH_MAXSUMSIZE];
794 u_char sum[AH_MAXSUMSIZE];
795 const struct ah_algorithm *sumalgo;
796 size_t siz;
797
798 sumalgo = ah_algorithm_lookup(sav->alg_auth);
799 if (!sumalgo)
800 goto noreplaycheck;
801 siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1));
802 if (m->m_pkthdr.len < off + ESPMAXLEN + siz) {
803 IPSEC_STAT_INCREMENT(ipsecstat.in_inval);
804 goto bad;
805 }
806 if (AH_MAXSUMSIZE < siz) {
807 ipseclog((LOG_DEBUG,
808 "internal error: AH_MAXSUMSIZE must be larger than %lu\n",
809 (u_int32_t)siz));
810 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
811 goto bad;
812 }
813
814 m_copydata(m, m->m_pkthdr.len - siz, siz, (caddr_t) &sum0[0]);
815
816 if (esp_auth(m, off, m->m_pkthdr.len - off - siz, sav, sum)) {
817 ipseclog((LOG_WARNING, "auth fail in IPv6 ESP input: %s %s\n",
818 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
819 IPSEC_STAT_INCREMENT(ipsec6stat.in_espauthfail);
820 goto bad;
821 }
822
823 if (bcmp(sum0, sum, siz) != 0) {
824 ipseclog((LOG_WARNING, "auth fail in IPv6 ESP input: %s %s\n",
825 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
826 IPSEC_STAT_INCREMENT(ipsec6stat.in_espauthfail);
827 goto bad;
828 }
829
830 /* strip off the authentication data */
831 m_adj(m, -siz);
832 ip6 = mtod(m, struct ip6_hdr *);
833 ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - siz);
834
835 m->m_flags |= M_AUTHIPDGM;
836 IPSEC_STAT_INCREMENT(ipsec6stat.in_espauthsucc);
837 }
838
839 /*
840 * update sequence number.
841 */
842 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
843 if (ipsec_updatereplay(seq, sav)) {
844 IPSEC_STAT_INCREMENT(ipsec6stat.in_espreplay);
845 goto bad;
846 }
847 }
848
849 noreplaycheck:
850
851 /* process main esp header. */
852 if (sav->flags & SADB_X_EXT_OLD) {
853 /* RFC 1827 */
854 esplen = sizeof(struct esp);
855 } else {
856 /* RFC 2406 */
857 if (sav->flags & SADB_X_EXT_DERIV)
858 esplen = sizeof(struct esp);
859 else
860 esplen = sizeof(struct newesp);
861 }
862
863 if (m->m_pkthdr.len < off + esplen + ivlen + sizeof(esptail)) {
864 ipseclog((LOG_WARNING,
865 "IPv6 ESP input: packet too short\n"));
866 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
867 goto bad;
868 }
869
870 #ifndef PULLDOWN_TEST
871 IP6_EXTHDR_CHECK(m, off, esplen + ivlen, return IPPROTO_DONE); /*XXX*/
872 #else
873 IP6_EXTHDR_GET(esp, struct esp *, m, off, esplen + ivlen);
874 if (esp == NULL) {
875 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
876 m = NULL;
877 goto bad;
878 }
879 #endif
880 ip6 = mtod(m, struct ip6_hdr *); /*set it again just in case*/
881
882 /*
883 * pre-compute and cache intermediate key
884 */
885 if (esp_schedule(algo, sav) != 0) {
886 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
887 goto bad;
888 }
889
890 /*
891 * decrypt the packet.
892 */
893 if (!algo->decrypt)
894 panic("internal error: no decrypt function");
895 if ((*algo->decrypt)(m, off, sav, algo, ivlen)) {
896 /* m is already freed */
897 m = NULL;
898 ipseclog((LOG_ERR, "decrypt fail in IPv6 ESP input: %s\n",
899 ipsec_logsastr(sav)));
900 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
901 goto bad;
902 }
903 IPSEC_STAT_INCREMENT(ipsec6stat.in_esphist[sav->alg_enc]);
904
905 m->m_flags |= M_DECRYPTED;
906
907 /*
908 * find the trailer of the ESP.
909 */
910 m_copydata(m, m->m_pkthdr.len - sizeof(esptail), sizeof(esptail),
911 (caddr_t)&esptail);
912 nxt = esptail.esp_nxt;
913 taillen = esptail.esp_padlen + sizeof(esptail);
914
915 if (m->m_pkthdr.len < taillen
916 || m->m_pkthdr.len - taillen < sizeof(struct ip6_hdr)) { /*?*/
917 ipseclog((LOG_WARNING,
918 "bad pad length in IPv6 ESP input: %s %s\n",
919 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
920 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
921 goto bad;
922 }
923
924 /* strip off the trailing pad area. */
925 m_adj(m, -taillen);
926 ip6 = mtod(m, struct ip6_hdr *);
927 ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - taillen);
928
929 /* was it transmitted over the IPsec tunnel SA? */
930 if (ipsec6_tunnel_validate(m, off + esplen + ivlen, nxt, sav)) {
931 ifaddr_t ifa;
932 struct sockaddr_storage addr;
933
934 /*
935 * strip off all the headers that precedes ESP header.
936 * IP6 xx ESP IP6' payload -> IP6' payload
937 *
938 * XXX more sanity checks
939 * XXX relationship with gif?
940 */
941 u_int32_t flowinfo; /*net endian*/
942 flowinfo = ip6->ip6_flow;
943 m_adj(m, off + esplen + ivlen);
944 if (m->m_len < sizeof(*ip6)) {
945 #ifndef PULLDOWN_TEST
946 /*
947 * m_pullup is prohibited in KAME IPv6 input processing
948 * but there's no other way!
949 */
950 #else
951 /* okay to pullup in m_pulldown style */
952 #endif
953 m = m_pullup(m, sizeof(*ip6));
954 if (!m) {
955 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
956 goto bad;
957 }
958 }
959 ip6 = mtod(m, struct ip6_hdr *);
960 /* ECN consideration. */
961 ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow);
962 if (!key_checktunnelsanity(sav, AF_INET6,
963 (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) {
964 ipseclog((LOG_ERR, "ipsec tunnel address mismatch "
965 "in IPv6 ESP input: %s %s\n",
966 ipsec6_logpacketstr(ip6, spi),
967 ipsec_logsastr(sav)));
968 IPSEC_STAT_INCREMENT(ipsec6stat.in_inval);
969 goto bad;
970 }
971
972 key_sa_recordxfer(sav, m);
973 if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 ||
974 ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) {
975 IPSEC_STAT_INCREMENT(ipsec6stat.in_nomem);
976 goto bad;
977 }
978
979 if (ip6_doscopedroute) {
980 struct sockaddr_in6 *ip6addr;
981
982 bzero(&addr, sizeof(addr));
983 ip6addr = (__typeof__(ip6addr))&addr;
984 ip6addr->sin6_family = AF_INET6;
985 ip6addr->sin6_len = sizeof(*ip6addr);
986 ip6addr->sin6_addr = ip6->ip6_dst;
987
988 // update the receiving interface address based on the inner address
989 ifa = ifa_ifwithaddr((struct sockaddr *)&addr);
990 if (ifa) {
991 m->m_pkthdr.rcvif = ifa->ifa_ifp;
992 IFA_REMREF(ifa);
993 }
994 }
995
996 if (proto_input(PF_INET6, m) != 0)
997 goto bad;
998 nxt = IPPROTO_DONE;
999 } else {
1000 /*
1001 * strip off ESP header and IV.
1002 * even in m_pulldown case, we need to strip off ESP so that
1003 * we can always compute checksum for AH correctly.
1004 */
1005 size_t stripsiz;
1006 char *prvnxtp;
1007
1008 /*
1009 * Set the next header field of the previous header correctly.
1010 */
1011 prvnxtp = ip6_get_prevhdr(m, off); /* XXX */
1012 *prvnxtp = nxt;
1013
1014 stripsiz = esplen + ivlen;
1015
1016 ip6 = mtod(m, struct ip6_hdr *);
1017 if (m->m_len >= stripsiz + off) {
1018 ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
1019 m->m_data += stripsiz;
1020 m->m_len -= stripsiz;
1021 m->m_pkthdr.len -= stripsiz;
1022 } else {
1023 /*
1024 * this comes with no copy if the boundary is on
1025 * cluster
1026 */
1027 struct mbuf *n;
1028
1029 n = m_split(m, off, M_DONTWAIT);
1030 if (n == NULL) {
1031 /* m is retained by m_split */
1032 goto bad;
1033 }
1034 m_adj(n, stripsiz);
1035 /* m_cat does not update m_pkthdr.len */
1036 m->m_pkthdr.len += n->m_pkthdr.len;
1037 m_cat(m, n);
1038 }
1039
1040 #ifndef PULLDOWN_TEST
1041 /*
1042 * KAME requires that the packet to be contiguous on the
1043 * mbuf. We need to make that sure.
1044 * this kind of code should be avoided.
1045 * XXX other conditions to avoid running this part?
1046 */
1047 if (m->m_len != m->m_pkthdr.len) {
1048 struct mbuf *n = NULL;
1049 int maxlen;
1050
1051 MGETHDR(n, M_DONTWAIT, MT_HEADER); /* MAC-OK */
1052 maxlen = MHLEN;
1053 if (n)
1054 M_COPY_PKTHDR(n, m);
1055 if (n && m->m_pkthdr.len > maxlen) {
1056 MCLGET(n, M_DONTWAIT);
1057 maxlen = MCLBYTES;
1058 if ((n->m_flags & M_EXT) == 0) {
1059 m_free(n);
1060 n = NULL;
1061 }
1062 }
1063 if (!n) {
1064 printf("esp6_input: mbuf allocation failed\n");
1065 goto bad;
1066 }
1067
1068 if (m->m_pkthdr.len <= maxlen) {
1069 m_copydata(m, 0, m->m_pkthdr.len, mtod(n, caddr_t));
1070 n->m_len = m->m_pkthdr.len;
1071 n->m_pkthdr.len = m->m_pkthdr.len;
1072 n->m_next = NULL;
1073 m_freem(m);
1074 } else {
1075 m_copydata(m, 0, maxlen, mtod(n, caddr_t));
1076 n->m_len = maxlen;
1077 n->m_pkthdr.len = m->m_pkthdr.len;
1078 n->m_next = m;
1079 m_adj(m, maxlen);
1080 m->m_flags &= ~M_PKTHDR;
1081 }
1082 m = n;
1083 }
1084 #endif
1085
1086 ip6 = mtod(m, struct ip6_hdr *);
1087 ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
1088
1089 key_sa_recordxfer(sav, m);
1090 if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0) {
1091 IPSEC_STAT_INCREMENT(ipsec6stat.in_nomem);
1092 goto bad;
1093 }
1094 }
1095
1096 *offp = off;
1097 *mp = m;
1098
1099 if (sav) {
1100 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
1101 printf("DP esp6_input call free SA:%p\n", sav));
1102 key_freesav(sav, KEY_SADB_UNLOCKED);
1103 }
1104 IPSEC_STAT_INCREMENT(ipsec6stat.in_success);
1105 return nxt;
1106
1107 bad:
1108 if (sav) {
1109 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
1110 printf("DP esp6_input call free SA:%p\n", sav));
1111 key_freesav(sav, KEY_SADB_UNLOCKED);
1112 }
1113 if (m)
1114 m_freem(m);
1115 return IPPROTO_DONE;
1116 }
1117
1118 void
1119 esp6_ctlinput(cmd, sa, d)
1120 int cmd;
1121 struct sockaddr *sa;
1122 void *d;
1123 {
1124 const struct newesp *espp;
1125 struct newesp esp;
1126 struct ip6ctlparam *ip6cp = NULL, ip6cp1;
1127 struct secasvar *sav;
1128 struct ip6_hdr *ip6;
1129 struct mbuf *m;
1130 int off;
1131 struct sockaddr_in6 *sa6_src, *sa6_dst;
1132
1133 if (sa->sa_family != AF_INET6 ||
1134 sa->sa_len != sizeof(struct sockaddr_in6))
1135 return;
1136 if ((unsigned)cmd >= PRC_NCMDS)
1137 return;
1138
1139 /* if the parameter is from icmp6, decode it. */
1140 if (d != NULL) {
1141 ip6cp = (struct ip6ctlparam *)d;
1142 m = ip6cp->ip6c_m;
1143 ip6 = ip6cp->ip6c_ip6;
1144 off = ip6cp->ip6c_off;
1145 } else {
1146 m = NULL;
1147 ip6 = NULL;
1148 }
1149
1150 if (ip6) {
1151 /*
1152 * Notify the error to all possible sockets via pfctlinput2.
1153 * Since the upper layer information (such as protocol type,
1154 * source and destination ports) is embedded in the encrypted
1155 * data and might have been cut, we can't directly call
1156 * an upper layer ctlinput function. However, the pcbnotify
1157 * function will consider source and destination addresses
1158 * as well as the flow info value, and may be able to find
1159 * some PCB that should be notified.
1160 * Although pfctlinput2 will call esp6_ctlinput(), there is
1161 * no possibility of an infinite loop of function calls,
1162 * because we don't pass the inner IPv6 header.
1163 */
1164 bzero(&ip6cp1, sizeof(ip6cp1));
1165 ip6cp1.ip6c_src = ip6cp->ip6c_src;
1166 pfctlinput2(cmd, sa, (void *)&ip6cp1);
1167
1168 /*
1169 * Then go to special cases that need ESP header information.
1170 * XXX: We assume that when ip6 is non NULL,
1171 * M and OFF are valid.
1172 */
1173
1174 /* check if we can safely examine src and dst ports */
1175 if (m->m_pkthdr.len < off + sizeof(esp))
1176 return;
1177
1178 if (m->m_len < off + sizeof(esp)) {
1179 /*
1180 * this should be rare case,
1181 * so we compromise on this copy...
1182 */
1183 m_copydata(m, off, sizeof(esp), (caddr_t)&esp);
1184 espp = &esp;
1185 } else
1186 espp = (struct newesp*)(mtod(m, caddr_t) + off);
1187
1188 if (cmd == PRC_MSGSIZE) {
1189 int valid = 0;
1190
1191 /*
1192 * Check to see if we have a valid SA corresponding to
1193 * the address in the ICMP message payload.
1194 */
1195 sa6_src = ip6cp->ip6c_src;
1196 sa6_dst = (struct sockaddr_in6 *)sa;
1197 sav = key_allocsa(AF_INET6,
1198 (caddr_t)&sa6_src->sin6_addr,
1199 (caddr_t)&sa6_dst->sin6_addr,
1200 IPPROTO_ESP, espp->esp_spi);
1201 if (sav) {
1202 if (sav->state == SADB_SASTATE_MATURE ||
1203 sav->state == SADB_SASTATE_DYING)
1204 valid++;
1205 key_freesav(sav, KEY_SADB_LOCKED);
1206 }
1207
1208 /* XXX Further validation? */
1209
1210 /*
1211 * Depending on the value of "valid" and routing table
1212 * size (mtudisc_{hi,lo}wat), we will:
1213 * - recalcurate the new MTU and create the
1214 * corresponding routing entry, or
1215 * - ignore the MTU change notification.
1216 */
1217 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
1218 }
1219 } else {
1220 /* we normally notify any pcb here */
1221 }
1222 }
1223 #endif /* INET6 */