]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet6/esp_input.c
This commit was generated by cvs2svn to compensate for changes in r77349,
[FreeBSD/FreeBSD.git] / sys / netinet6 / esp_input.c
1 /*      $FreeBSD$       */
2 /*      $KAME: esp_input.c,v 1.25 2000/05/08 08:04:30 itojun Exp $      */
3
4 /*
5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the project nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 /*
34  * RFC1827/2406 Encapsulated Security Payload.
35  */
36
37 #include "opt_inet.h"
38 #include "opt_inet6.h"
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/mbuf.h>
43 #include <sys/domain.h>
44 #include <sys/protosw.h>
45 #include <sys/socket.h>
46 #include <sys/errno.h>
47 #include <sys/time.h>
48 #include <sys/syslog.h>
49
50 #include <net/if.h>
51 #include <net/route.h>
52 #include <net/netisr.h>
53 #include <machine/cpu.h>
54
55 #include <netinet/in.h>
56 #include <netinet/in_systm.h>
57 #include <netinet/ip.h>
58 #include <netinet/ip_var.h>
59 #include <netinet/in_var.h>
60 #include <netinet/ip_ecn.h>
61 #ifdef INET6
62 #include <netinet6/ip6_ecn.h>
63 #endif
64
65 #ifdef INET6
66 #include <netinet/ip6.h>
67 #include <netinet6/ip6_var.h>
68 #include <netinet/icmp6.h>
69 #endif
70
71 #include <netinet6/ipsec.h>
72 #ifdef INET6
73 #include <netinet6/ipsec6.h>
74 #endif
75 #include <netinet6/ah.h>
76 #ifdef INET6
77 #include <netinet6/ah6.h>
78 #endif
79 #include <netinet6/esp.h>
80 #ifdef INET6
81 #include <netinet6/esp6.h>
82 #endif
83 #include <netkey/key.h>
84 #include <netkey/keydb.h>
85 #ifdef IPSEC_DEBUG
86 #include <netkey/key_debug.h>
87 #else
88 #define KEYDEBUG(lev,arg)
89 #endif
90
91 #include <machine/stdarg.h>
92
93 #include <net/net_osdep.h>
94
95 #define IPLEN_FLIPPED
96
97 #ifdef INET
98 #include <netinet/ipprotosw.h>
99 extern struct ipprotosw inetsw[];
100
101 #define ESPMAXLEN \
102         (sizeof(struct esp) < sizeof(struct newesp) \
103                 ? sizeof(struct newesp) : sizeof(struct esp))
104
105 void
106 #if __STDC__
107 esp4_input(struct mbuf *m, ...)
108 #else
109 esp4_input(m, va_alist)
110         struct mbuf *m;
111         va_dcl
112 #endif
113 {
114         struct ip *ip;
115         struct esp *esp;
116         struct esptail esptail;
117         u_int32_t spi;
118         struct secasvar *sav = NULL;
119         size_t taillen;
120         u_int16_t nxt;
121         struct esp_algorithm *algo;
122         int ivlen;
123         size_t hlen;
124         size_t esplen;
125         va_list ap;
126         int off, proto;
127
128         va_start(ap, m);
129         off = va_arg(ap, int);
130         proto = va_arg(ap, int);
131         va_end(ap);
132
133         /* sanity check for alignment. */
134         if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) {
135                 ipseclog((LOG_ERR, "IPv4 ESP input: packet alignment problem "
136                         "(off=%d, pktlen=%d)\n", off, m->m_pkthdr.len));
137                 ipsecstat.in_inval++;
138                 goto bad;
139         }
140
141         if (m->m_len < off + ESPMAXLEN) {
142                 m = m_pullup(m, off + ESPMAXLEN);
143                 if (!m) {
144                         ipseclog((LOG_DEBUG,
145                             "IPv4 ESP input: can't pullup in esp4_input\n"));
146                         ipsecstat.in_inval++;
147                         goto bad;
148                 }
149         }
150
151         ip = mtod(m, struct ip *);
152         esp = (struct esp *)(((u_int8_t *)ip) + off);
153 #ifdef _IP_VHL
154         hlen = IP_VHL_HL(ip->ip_vhl) << 2;
155 #else
156         hlen = ip->ip_hl << 2;
157 #endif
158
159         /* find the sassoc. */
160         spi = esp->esp_spi;
161
162         if ((sav = key_allocsa(AF_INET,
163                               (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst,
164                               IPPROTO_ESP, spi)) == 0) {
165                 ipseclog((LOG_WARNING,
166                     "IPv4 ESP input: no key association found for spi %u\n",
167                     (u_int32_t)ntohl(spi)));
168                 ipsecstat.in_nosa++;
169                 goto bad;
170         }
171         KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
172                 printf("DP esp4_input called to allocate SA:%p\n", sav));
173         if (sav->state != SADB_SASTATE_MATURE
174          && sav->state != SADB_SASTATE_DYING) {
175                 ipseclog((LOG_DEBUG,
176                     "IPv4 ESP input: non-mature/dying SA found for spi %u\n",
177                     (u_int32_t)ntohl(spi)));
178                 ipsecstat.in_badspi++;
179                 goto bad;
180         }
181         if (sav->alg_enc == SADB_EALG_NONE) {
182                 ipseclog((LOG_DEBUG, "IPv4 ESP input: "
183                     "unspecified encryption algorithm for spi %u\n",
184                     (u_int32_t)ntohl(spi)));
185                 ipsecstat.in_badspi++;
186                 goto bad;
187         }
188
189         algo = &esp_algorithms[sav->alg_enc];   /*XXX*/
190
191         /* check if we have proper ivlen information */
192         ivlen = sav->ivlen;
193         if (ivlen < 0) {
194                 ipseclog((LOG_ERR, "inproper ivlen in IPv4 ESP input: %s %s\n",
195                     ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
196                 ipsecstat.in_inval++;
197                 goto bad;
198         }
199
200         if (!((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay
201          && (sav->alg_auth && sav->key_auth)))
202                 goto noreplaycheck;
203
204         if (sav->alg_auth == SADB_AALG_NULL)
205                 goto noreplaycheck;
206
207         /*
208          * check for sequence number.
209          */
210         if (ipsec_chkreplay(ntohl(((struct newesp *)esp)->esp_seq), sav))
211                 ; /*okey*/
212         else {
213                 ipsecstat.in_espreplay++;
214                 ipseclog((LOG_WARNING,
215                     "replay packet in IPv4 ESP input: %s %s\n",
216                     ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
217                 goto bad;
218         }
219
220         /* check ICV */
221     {
222         u_char sum0[AH_MAXSUMSIZE];
223         u_char sum[AH_MAXSUMSIZE];
224         struct ah_algorithm *sumalgo;
225         size_t siz;
226
227         sumalgo = &ah_algorithms[sav->alg_auth];
228         siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1));
229         if (AH_MAXSUMSIZE < siz) {
230                 ipseclog((LOG_DEBUG,
231                     "internal error: AH_MAXSUMSIZE must be larger than %lu\n",
232                     (u_long)siz));
233                 ipsecstat.in_inval++;
234                 goto bad;
235         }
236
237         m_copydata(m, m->m_pkthdr.len - siz, siz, &sum0[0]);
238
239         if (esp_auth(m, off, m->m_pkthdr.len - off - siz, sav, sum)) {
240                 ipseclog((LOG_WARNING, "auth fail in IPv4 ESP input: %s %s\n",
241                     ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
242                 ipsecstat.in_espauthfail++;
243                 goto bad;
244         }
245
246         if (bcmp(sum0, sum, siz) != 0) {
247                 ipseclog((LOG_WARNING, "auth fail in IPv4 ESP input: %s %s\n",
248                     ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
249                 ipsecstat.in_espauthfail++;
250                 goto bad;
251         }
252
253         /* strip off the authentication data */
254         m_adj(m, -siz);
255         ip = mtod(m, struct ip *);
256 #ifdef IPLEN_FLIPPED
257         ip->ip_len = ip->ip_len - siz;
258 #else
259         ip->ip_len = htons(ntohs(ip->ip_len) - siz);
260 #endif
261         m->m_flags |= M_AUTHIPDGM;
262         ipsecstat.in_espauthsucc++;
263     }
264
265         /*
266          * update sequence number.
267          */
268         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
269                 if (ipsec_updatereplay(ntohl(((struct newesp *)esp)->esp_seq), sav)) {
270                         ipsecstat.in_espreplay++;
271                         goto bad;
272                 }
273         }
274
275 noreplaycheck:
276
277         /* process main esp header. */
278         if (sav->flags & SADB_X_EXT_OLD) {
279                 /* RFC 1827 */
280                 esplen = sizeof(struct esp);
281         } else {
282                 /* RFC 2406 */
283                 if (sav->flags & SADB_X_EXT_DERIV)
284                         esplen = sizeof(struct esp);
285                 else
286                         esplen = sizeof(struct newesp);
287         }
288
289         if (m->m_pkthdr.len < off + esplen + ivlen + sizeof(esptail)) {
290                 ipseclog((LOG_WARNING,
291                     "IPv4 ESP input: packet too short\n"));
292                 ipsecstat.in_inval++;
293                 goto bad;
294         }
295
296         if (m->m_len < off + esplen + ivlen) {
297                 m = m_pullup(m, off + esplen + ivlen);
298                 if (!m) {
299                         ipseclog((LOG_DEBUG,
300                             "IPv4 ESP input: can't pullup in esp4_input\n"));
301                         ipsecstat.in_inval++;
302                         goto bad;
303                 }
304         }
305
306     {
307         /*
308          * decrypt the packet.
309          */
310         if (!algo->decrypt)
311                 panic("internal error: no decrypt function");
312         if ((*algo->decrypt)(m, off, sav, algo, ivlen)) {
313                 ipseclog((LOG_ERR, "decrypt fail in IPv4 ESP input: %s %s\n",
314                     ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
315                 ipsecstat.in_inval++;
316                 goto bad;
317         }
318         ipsecstat.in_esphist[sav->alg_enc]++;
319
320         m->m_flags |= M_DECRYPTED;
321     }
322
323         /*
324          * find the trailer of the ESP.
325          */
326         m_copydata(m, m->m_pkthdr.len - sizeof(esptail), sizeof(esptail),
327              (caddr_t)&esptail);
328         nxt = esptail.esp_nxt;
329         taillen = esptail.esp_padlen + sizeof(esptail);
330
331         if (m->m_pkthdr.len < taillen
332          || m->m_pkthdr.len - taillen < hlen) { /*?*/
333                 ipseclog((LOG_WARNING,
334                     "bad pad length in IPv4 ESP input: %s %s\n",
335                     ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
336                 ipsecstat.in_inval++;
337                 goto bad;
338         }
339
340         /* strip off the trailing pad area. */
341         m_adj(m, -taillen);
342
343 #ifdef IPLEN_FLIPPED
344         ip->ip_len = ip->ip_len - taillen;
345 #else
346         ip->ip_len = htons(ntohs(ip->ip_len) - taillen);
347 #endif
348
349         /* was it transmitted over the IPsec tunnel SA? */
350         if (ipsec4_tunnel_validate(ip, nxt, sav)) {
351                 /*
352                  * strip off all the headers that precedes ESP header.
353                  *      IP4 xx ESP IP4' payload -> IP4' payload
354                  *
355                  * XXX more sanity checks
356                  * XXX relationship with gif?
357                  */
358                 u_int8_t tos;
359
360                 tos = ip->ip_tos;
361                 m_adj(m, off + esplen + ivlen);
362                 if (m->m_len < sizeof(*ip)) {
363                         m = m_pullup(m, sizeof(*ip));
364                         if (!m) {
365                                 ipsecstat.in_inval++;
366                                 goto bad;
367                         }
368                 }
369                 ip = mtod(m, struct ip *);
370                 /* ECN consideration. */
371                 ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos);
372                 if (!key_checktunnelsanity(sav, AF_INET,
373                             (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) {
374                         ipseclog((LOG_ERR, "ipsec tunnel address mismatch "
375                             "in IPv4 ESP input: %s %s\n",
376                             ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
377                         ipsecstat.in_inval++;
378                         goto bad;
379                 }
380
381 #if 0 /* XXX should call ipfw rather than ipsec_in_reject, shouldn't it ? */
382                 /* drop it if it does not match the default policy */
383                 if (ipsec4_in_reject(m, NULL)) {
384                         ipsecstat.in_polvio++;
385                         goto bad;
386                 }
387 #endif
388
389                 key_sa_recordxfer(sav, m);
390
391                 if (! IF_HANDOFF(&ipintrq, m, NULL)) {
392                         ipsecstat.in_inval++;
393                         m = NULL;
394                         goto bad;
395                 }
396                 m = NULL;
397                 schednetisr(NETISR_IP); /*can be skipped but to make sure*/
398                 nxt = IPPROTO_DONE;
399         } else {
400                 /*
401                  * strip off ESP header and IV.
402                  * even in m_pulldown case, we need to strip off ESP so that
403                  * we can always compute checksum for AH correctly.
404                  */
405                 size_t stripsiz;
406
407                 stripsiz = esplen + ivlen;
408
409                 ip = mtod(m, struct ip *);
410                 ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off);
411                 m->m_data += stripsiz;
412                 m->m_len -= stripsiz;
413                 m->m_pkthdr.len -= stripsiz;
414
415                 ip = mtod(m, struct ip *);
416 #ifdef IPLEN_FLIPPED
417                 ip->ip_len = ip->ip_len - stripsiz;
418 #else
419                 ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz);
420 #endif
421                 ip->ip_p = nxt;
422
423                 key_sa_recordxfer(sav, m);
424
425                 if (nxt != IPPROTO_DONE)
426                         (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
427                 else
428                         m_freem(m);
429                 m = NULL;
430         }
431
432         if (sav) {
433                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
434                         printf("DP esp4_input call free SA:%p\n", sav));
435                 key_freesav(sav);
436         }
437         ipsecstat.in_success++;
438         return;
439
440 bad:
441         if (sav) {
442                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
443                         printf("DP esp4_input call free SA:%p\n", sav));
444                 key_freesav(sav);
445         }
446         if (m)
447                 m_freem(m);
448         return;
449 }
450 #endif /* INET */
451
452 #ifdef INET6
453 int
454 esp6_input(mp, offp, proto)
455         struct mbuf **mp;
456         int *offp, proto;
457 {
458         struct mbuf *m = *mp;
459         int off = *offp;
460         struct ip6_hdr *ip6;
461         struct esp *esp;
462         struct esptail esptail;
463         u_int32_t spi;
464         struct secasvar *sav = NULL;
465         size_t taillen;
466         u_int16_t nxt;
467         struct esp_algorithm *algo;
468         int ivlen;
469         size_t esplen;
470         int s;
471
472         /* sanity check for alignment. */
473         if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) {
474                 ipseclog((LOG_ERR, "IPv6 ESP input: packet alignment problem "
475                         "(off=%d, pktlen=%d)\n", off, m->m_pkthdr.len));
476                 ipsec6stat.in_inval++;
477                 goto bad;
478         }
479
480 #ifndef PULLDOWN_TEST
481         IP6_EXTHDR_CHECK(m, off, ESPMAXLEN, IPPROTO_DONE);
482         esp = (struct esp *)(mtod(m, caddr_t) + off);
483 #else
484         IP6_EXTHDR_GET(esp, struct esp *, m, off, ESPMAXLEN);
485         if (esp == NULL) {
486                 ipsec6stat.in_inval++;
487                 return IPPROTO_DONE;
488         }
489 #endif
490         ip6 = mtod(m, struct ip6_hdr *);
491
492         if (ntohs(ip6->ip6_plen) == 0) {
493                 ipseclog((LOG_ERR, "IPv6 ESP input: "
494                     "ESP with IPv6 jumbogram is not supported.\n"));
495                 ipsec6stat.in_inval++;
496                 goto bad;
497         }
498
499         /* find the sassoc. */
500         spi = esp->esp_spi;
501
502         if ((sav = key_allocsa(AF_INET6,
503                               (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst,
504                               IPPROTO_ESP, spi)) == 0) {
505                 ipseclog((LOG_WARNING,
506                     "IPv6 ESP input: no key association found for spi %u\n",
507                     (u_int32_t)ntohl(spi)));
508                 ipsec6stat.in_nosa++;
509                 goto bad;
510         }
511         KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
512                 printf("DP esp6_input called to allocate SA:%p\n", sav));
513         if (sav->state != SADB_SASTATE_MATURE
514          && sav->state != SADB_SASTATE_DYING) {
515                 ipseclog((LOG_DEBUG,
516                     "IPv6 ESP input: non-mature/dying SA found for spi %u\n",
517                     (u_int32_t)ntohl(spi)));
518                 ipsec6stat.in_badspi++;
519                 goto bad;
520         }
521         if (sav->alg_enc == SADB_EALG_NONE) {
522                 ipseclog((LOG_DEBUG, "IPv6 ESP input: "
523                     "unspecified encryption algorithm for spi %u\n",
524                     (u_int32_t)ntohl(spi)));
525                 ipsec6stat.in_badspi++;
526                 goto bad;
527         }
528
529         algo = &esp_algorithms[sav->alg_enc];   /*XXX*/
530
531         /* check if we have proper ivlen information */
532         ivlen = sav->ivlen;
533         if (ivlen < 0) {
534                 ipseclog((LOG_ERR, "inproper ivlen in IPv6 ESP input: %s %s\n",
535                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
536                 ipsec6stat.in_badspi++;
537                 goto bad;
538         }
539
540         if (!((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay
541          && (sav->alg_auth && sav->key_auth)))
542                 goto noreplaycheck;
543
544         if (sav->alg_auth == SADB_AALG_NULL)
545                 goto noreplaycheck;
546
547         /*
548          * check for sequence number.
549          */
550         if (ipsec_chkreplay(ntohl(((struct newesp *)esp)->esp_seq), sav))
551                 ; /*okey*/
552         else {
553                 ipsec6stat.in_espreplay++;
554                 ipseclog((LOG_WARNING,
555                     "replay packet in IPv6 ESP input: %s %s\n",
556                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
557                 goto bad;
558         }
559
560         /* check ICV */
561     {
562         u_char sum0[AH_MAXSUMSIZE];
563         u_char sum[AH_MAXSUMSIZE];
564         struct ah_algorithm *sumalgo;
565         size_t siz;
566
567         sumalgo = &ah_algorithms[sav->alg_auth];
568         siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1));
569         if (AH_MAXSUMSIZE < siz) {
570                 ipseclog((LOG_DEBUG,
571                     "internal error: AH_MAXSUMSIZE must be larger than %lu\n",
572                     (u_long)siz));
573                 ipsec6stat.in_inval++;
574                 goto bad;
575         }
576
577         m_copydata(m, m->m_pkthdr.len - siz, siz, &sum0[0]);
578
579         if (esp_auth(m, off, m->m_pkthdr.len - off - siz, sav, sum)) {
580                 ipseclog((LOG_WARNING, "auth fail in IPv6 ESP input: %s %s\n",
581                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
582                 ipsec6stat.in_espauthfail++;
583                 goto bad;
584         }
585
586         if (bcmp(sum0, sum, siz) != 0) {
587                 ipseclog((LOG_WARNING, "auth fail in IPv6 ESP input: %s %s\n",
588                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
589                 ipsec6stat.in_espauthfail++;
590                 goto bad;
591         }
592
593         /* strip off the authentication data */
594         m_adj(m, -siz);
595         ip6 = mtod(m, struct ip6_hdr *);
596         ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - siz);
597
598         m->m_flags |= M_AUTHIPDGM;
599         ipsec6stat.in_espauthsucc++;
600     }
601
602         /*
603          * update sequence number.
604          */
605         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
606                 if (ipsec_updatereplay(ntohl(((struct newesp *)esp)->esp_seq), sav)) {
607                         ipsec6stat.in_espreplay++;
608                         goto bad;
609                 }
610         }
611
612 noreplaycheck:
613
614         /* process main esp header. */
615         if (sav->flags & SADB_X_EXT_OLD) {
616                 /* RFC 1827 */
617                 esplen = sizeof(struct esp);
618         } else {
619                 /* RFC 2406 */
620                 if (sav->flags & SADB_X_EXT_DERIV)
621                         esplen = sizeof(struct esp);
622                 else
623                         esplen = sizeof(struct newesp);
624         }
625
626         if (m->m_pkthdr.len < off + esplen + ivlen + sizeof(esptail)) {
627                 ipseclog((LOG_WARNING,
628                     "IPv6 ESP input: packet too short\n"));
629                 ipsec6stat.in_inval++;
630                 goto bad;
631         }
632
633 #ifndef PULLDOWN_TEST
634         IP6_EXTHDR_CHECK(m, off, esplen + ivlen, IPPROTO_DONE); /*XXX*/
635 #else
636         IP6_EXTHDR_GET(esp, struct esp *, m, off, esplen + ivlen);
637         if (esp == NULL) {
638                 ipsec6stat.in_inval++;
639                 m = NULL;
640                 goto bad;
641         }
642 #endif
643         ip6 = mtod(m, struct ip6_hdr *);        /*set it again just in case*/
644
645         /*
646          * decrypt the packet.
647          */
648         if (!algo->decrypt)
649                 panic("internal error: no decrypt function");
650         if ((*algo->decrypt)(m, off, sav, algo, ivlen)) {
651                 ipseclog((LOG_ERR, "decrypt fail in IPv6 ESP input: %s %s\n",
652                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
653                 ipsec6stat.in_inval++;
654                 goto bad;
655         }
656         ipsec6stat.in_esphist[sav->alg_enc]++;
657
658         m->m_flags |= M_DECRYPTED;
659
660         /*
661          * find the trailer of the ESP.
662          */
663         m_copydata(m, m->m_pkthdr.len - sizeof(esptail), sizeof(esptail),
664              (caddr_t)&esptail);
665         nxt = esptail.esp_nxt;
666         taillen = esptail.esp_padlen + sizeof(esptail);
667
668         if (m->m_pkthdr.len < taillen
669          || m->m_pkthdr.len - taillen < sizeof(struct ip6_hdr)) {       /*?*/
670                 ipseclog((LOG_WARNING,
671                     "bad pad length in IPv6 ESP input: %s %s\n",
672                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
673                 ipsec6stat.in_inval++;
674                 goto bad;
675         }
676
677         /* strip off the trailing pad area. */
678         m_adj(m, -taillen);
679
680         ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - taillen);
681
682         /* was it transmitted over the IPsec tunnel SA? */
683         if (ipsec6_tunnel_validate(ip6, nxt, sav)) {
684                 /*
685                  * strip off all the headers that precedes ESP header.
686                  *      IP6 xx ESP IP6' payload -> IP6' payload
687                  *
688                  * XXX more sanity checks
689                  * XXX relationship with gif?
690                  */
691                 u_int32_t flowinfo;     /*net endian*/
692                 flowinfo = ip6->ip6_flow;
693                 m_adj(m, off + esplen + ivlen);
694                 if (m->m_len < sizeof(*ip6)) {
695 #ifndef PULLDOWN_TEST
696                         /*
697                          * m_pullup is prohibited in KAME IPv6 input processing
698                          * but there's no other way!
699                          */
700 #else
701                         /* okay to pullup in m_pulldown style */
702 #endif
703                         m = m_pullup(m, sizeof(*ip6));
704                         if (!m) {
705                                 ipsec6stat.in_inval++;
706                                 goto bad;
707                         }
708                 }
709                 ip6 = mtod(m, struct ip6_hdr *);
710                 /* ECN consideration. */
711                 ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow);
712                 if (!key_checktunnelsanity(sav, AF_INET6,
713                             (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) {
714                         ipseclog((LOG_ERR, "ipsec tunnel address mismatch "
715                             "in IPv6 ESP input: %s %s\n",
716                             ipsec6_logpacketstr(ip6, spi),
717                             ipsec_logsastr(sav)));
718                         ipsec6stat.in_inval++;
719                         goto bad;
720                 }
721
722 #if 0 /* XXX should call ipfw rather than ipsec_in_reject, shouldn't it ? */
723                 /* drop it if it does not match the default policy */
724                 if (ipsec6_in_reject(m, NULL)) {
725                         ipsec6stat.in_polvio++;
726                         goto bad;
727                 }
728 #endif
729
730                 key_sa_recordxfer(sav, m);
731
732                 if (! IF_HANDOFF(&ip6intrq, m, NULL)) {
733                         ipsec6stat.in_inval++;
734                         m = NULL;
735                         goto bad;
736                 }
737                 m = NULL;
738                 schednetisr(NETISR_IPV6); /*can be skipped but to make sure*/
739                 nxt = IPPROTO_DONE;
740         } else {
741                 /*
742                  * strip off ESP header and IV.
743                  * even in m_pulldown case, we need to strip off ESP so that
744                  * we can always compute checksum for AH correctly.
745                  */
746                 size_t stripsiz;
747                 char *prvnxtp;
748
749                 /*
750                  * Set the next header field of the previous header correctly.
751                  */
752                 prvnxtp = ip6_get_prevhdr(m, off); /* XXX */
753                 *prvnxtp = nxt;
754
755                 stripsiz = esplen + ivlen;
756
757                 ip6 = mtod(m, struct ip6_hdr *);
758                 if (m->m_len >= stripsiz + off) {
759                         ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
760                         m->m_data += stripsiz;
761                         m->m_len -= stripsiz;
762                         m->m_pkthdr.len -= stripsiz;
763                 } else {
764                         /*
765                          * this comes with no copy if the boundary is on
766                          * cluster
767                          */
768                         struct mbuf *n;
769
770                         n = m_split(m, off, M_DONTWAIT);
771                         if (n == NULL) {
772                                 /* m is retained by m_split */
773                                 goto bad;
774                         }
775                         m_adj(n, stripsiz);
776                         m_cat(m, n);
777                         /* m_cat does not update m_pkthdr.len */
778                         m->m_pkthdr.len += n->m_pkthdr.len;
779                 }
780
781                 ip6 = mtod(m, struct ip6_hdr *);
782                 ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
783
784                 key_sa_recordxfer(sav, m);
785         }
786
787         *offp = off;
788         *mp = m;
789
790         if (sav) {
791                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
792                         printf("DP esp6_input call free SA:%p\n", sav));
793                 key_freesav(sav);
794         }
795         ipsec6stat.in_success++;
796         return nxt;
797
798 bad:
799         if (sav) {
800                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
801                         printf("DP esp6_input call free SA:%p\n", sav));
802                 key_freesav(sav);
803         }
804         if (m)
805                 m_freem(m);
806         return IPPROTO_DONE;
807 }
808 #endif /* INET6 */