2 /* $KAME: ah_input.c,v 1.59 2001/05/16 04:01:27 jinmei Exp $ */
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
34 * RFC1826/2402 authentication header.
38 #include "opt_inet6.h"
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/malloc.h>
44 #include <sys/domain.h>
45 #include <sys/protosw.h>
46 #include <sys/socket.h>
47 #include <sys/errno.h>
49 #include <sys/syslog.h>
52 #include <net/route.h>
53 #include <net/netisr.h>
54 #include <machine/cpu.h>
56 #include <netinet/in.h>
57 #include <netinet/in_systm.h>
58 #include <netinet/in_var.h>
59 #include <netinet/ip.h>
60 #include <netinet/ip_var.h>
61 #include <netinet/ip_ecn.h>
63 #include <netinet6/ip6_ecn.h>
67 #include <netinet/ip6.h>
68 #include <netinet6/ip6_var.h>
69 #include <netinet6/in6_pcb.h>
70 #include <netinet/icmp6.h>
71 #include <netinet6/ip6protosw.h>
74 #include <netinet6/ipsec.h>
76 #include <netinet6/ipsec6.h>
78 #include <netinet6/ah.h>
80 #include <netinet6/ah6.h>
82 #include <netkey/key.h>
83 #include <netkey/keydb.h>
85 #include <netkey/key_debug.h>
87 #define KEYDEBUG(lev,arg)
90 #include <machine/stdarg.h>
92 #include <net/net_osdep.h>
97 #include <netinet/ipprotosw.h>
98 extern struct ipprotosw inetsw[];
102 ah4_input(struct mbuf *m, ...)
104 ah4_input(m, va_alist)
112 const struct ah_algorithm *algo;
116 struct secasvar *sav = NULL;
124 off = va_arg(ap, int);
125 proto = va_arg(ap, int);
128 #ifndef PULLDOWN_TEST
129 if (m->m_len < off + sizeof(struct newah)) {
130 m = m_pullup(m, off + sizeof(struct newah));
132 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
133 "dropping the packet for simplicity\n"));
134 ipsecstat.in_inval++;
139 ip = mtod(m, struct ip *);
140 ah = (struct ah *)(((caddr_t)ip) + off);
142 ip = mtod(m, struct ip *);
143 IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah));
145 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
146 "dropping the packet for simplicity\n"));
147 ipsecstat.in_inval++;
153 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
155 hlen = ip->ip_hl << 2;
158 /* find the sassoc. */
161 if ((sav = key_allocsa(AF_INET,
162 (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst,
163 IPPROTO_AH, spi)) == 0) {
164 ipseclog((LOG_WARNING,
165 "IPv4 AH input: no key association found for spi %u\n",
166 (u_int32_t)ntohl(spi)));
170 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
171 printf("DP ah4_input called to allocate SA:%p\n", sav));
172 if (sav->state != SADB_SASTATE_MATURE
173 && sav->state != SADB_SASTATE_DYING) {
175 "IPv4 AH input: non-mature/dying SA found for spi %u\n",
176 (u_int32_t)ntohl(spi)));
177 ipsecstat.in_badspi++;
181 algo = ah_algorithm_lookup(sav->alg_auth);
183 ipseclog((LOG_DEBUG, "IPv4 AH input: "
184 "unsupported authentication algorithm for spi %u\n",
185 (u_int32_t)ntohl(spi)));
186 ipsecstat.in_badspi++;
190 siz = (*algo->sumsiz)(sav);
191 siz1 = ((siz + 3) & ~(4 - 1));
194 * sanity checks for header, 1.
199 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
202 * Here, we do not do "siz1 == siz". This is because the way
203 * RFC240[34] section 2 is written. They do not require truncation
205 * For example, Microsoft IPsec stack attaches 160 bits of
206 * authentication data for both hmac-md5 and hmac-sha1. For hmac-sha1,
207 * 32 bits of padding is attached.
209 * There are two downsides to this specification.
210 * They have no real harm, however, they leave us fuzzy feeling.
211 * - if we attach more than 96 bits of authentication data onto AH,
212 * we will never notice about possible modification by rogue
213 * intermediate nodes.
214 * Since extra bits in AH checksum is never used, this constitutes
215 * no real issue, however, it is wacky.
216 * - even if the peer attaches big authentication data, we will never
217 * notice the difference, since longer authentication data will just
220 * We may need some clarification in the spec.
223 ipseclog((LOG_NOTICE, "sum length too short in IPv4 AH input "
224 "(%lu, should be at least %lu): %s\n",
225 (u_long)siz1, (u_long)siz,
226 ipsec4_logpacketstr(ip, spi)));
227 ipsecstat.in_inval++;
230 if ((ah->ah_len << 2) - sizoff != siz1) {
231 ipseclog((LOG_NOTICE, "sum length mismatch in IPv4 AH input "
232 "(%d should be %lu): %s\n",
233 (ah->ah_len << 2) - sizoff, (u_long)siz1,
234 ipsec4_logpacketstr(ip, spi)));
235 ipsecstat.in_inval++;
239 #ifndef PULLDOWN_TEST
240 if (m->m_len < off + sizeof(struct ah) + sizoff + siz1) {
241 m = m_pullup(m, off + sizeof(struct ah) + sizoff + siz1);
243 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
244 ipsecstat.in_inval++;
248 ip = mtod(m, struct ip *);
249 ah = (struct ah *)(((caddr_t)ip) + off);
252 IP6_EXTHDR_GET(ah, struct ah *, m, off,
253 sizeof(struct ah) + sizoff + siz1);
255 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
256 ipsecstat.in_inval++;
263 * check for sequence number.
265 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
266 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav))
269 ipsecstat.in_ahreplay++;
270 ipseclog((LOG_WARNING,
271 "replay packet in IPv4 AH input: %s %s\n",
272 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
278 * alright, it seems sane. now we are going to check the
279 * cryptographic checksum.
281 cksum = malloc(siz1, M_TEMP, M_NOWAIT);
283 ipseclog((LOG_DEBUG, "IPv4 AH input: "
284 "couldn't alloc temporary region for cksum\n"));
285 ipsecstat.in_inval++;
290 * some of IP header fields are flipped to the host endian.
291 * convert them back to network endian. VERY stupid.
293 ip->ip_len = htons(ip->ip_len + hlen);
294 ip->ip_off = htons(ip->ip_off);
295 if (ah4_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
297 ipsecstat.in_inval++;
300 ipsecstat.in_ahhist[sav->alg_auth]++;
304 ip->ip_len = ntohs(ip->ip_len) - hlen;
305 ip->ip_off = ntohs(ip->ip_off);
308 caddr_t sumpos = NULL;
310 if (sav->flags & SADB_X_EXT_OLD) {
312 sumpos = (caddr_t)(ah + 1);
315 sumpos = (caddr_t)(((struct newah *)ah) + 1);
318 if (bcmp(sumpos, cksum, siz) != 0) {
319 ipseclog((LOG_WARNING,
320 "checksum mismatch in IPv4 AH input: %s %s\n",
321 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
323 ipsecstat.in_ahauthfail++;
330 m->m_flags |= M_AUTHIPHDR;
331 m->m_flags |= M_AUTHIPDGM;
335 * looks okey, but we need more sanity check.
336 * XXX should elaborate.
338 if (ah->ah_nxt == IPPROTO_IPIP || ah->ah_nxt == IPPROTO_IP) {
342 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
344 if (m->m_len < off + sizeof(struct ah) + sizoff + siz1 + hlen) {
345 m = m_pullup(m, off + sizeof(struct ah)
346 + sizoff + siz1 + hlen);
349 "IPv4 AH input: can't pullup\n"));
350 ipsecstat.in_inval++;
355 nip = (struct ip *)((u_char *)(ah + 1) + sizoff + siz1);
356 if (nip->ip_src.s_addr != ip->ip_src.s_addr
357 || nip->ip_dst.s_addr != ip->ip_dst.s_addr) {
358 m->m_flags &= ~M_AUTHIPHDR;
359 m->m_flags &= ~M_AUTHIPDGM;
363 else if (ah->ah_nxt == IPPROTO_IPV6) {
364 m->m_flags &= ~M_AUTHIPHDR;
365 m->m_flags &= ~M_AUTHIPDGM;
370 if (m->m_flags & M_AUTHIPHDR
371 && m->m_flags & M_AUTHIPDGM) {
374 "IPv4 AH input: authentication succeess\n"));
376 ipsecstat.in_ahauthsucc++;
378 ipseclog((LOG_WARNING,
379 "authentication failed in IPv4 AH input: %s %s\n",
380 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
381 ipsecstat.in_ahauthfail++;
386 * update sequence number.
388 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
389 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) {
390 ipsecstat.in_ahreplay++;
395 /* was it transmitted over the IPsec tunnel SA? */
396 if (sav->flags & SADB_X_EXT_OLD) {
398 stripsiz = sizeof(struct ah) + siz1;
401 stripsiz = sizeof(struct newah) + siz1;
403 if (ipsec4_tunnel_validate(m, off + stripsiz, nxt, sav)) {
405 * strip off all the headers that precedes AH.
406 * IP xx AH IP' payload -> IP' payload
408 * XXX more sanity checks
409 * XXX relationship with gif?
414 m_adj(m, off + stripsiz);
415 if (m->m_len < sizeof(*ip)) {
416 m = m_pullup(m, sizeof(*ip));
418 ipsecstat.in_inval++;
422 ip = mtod(m, struct ip *);
423 /* ECN consideration. */
424 ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos);
425 if (!key_checktunnelsanity(sav, AF_INET,
426 (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) {
427 ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
428 "in IPv4 AH input: %s %s\n",
429 ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
430 ipsecstat.in_inval++;
434 #if 0 /* XXX should we call ipfw rather than ipsec_in_reject? */
435 /* drop it if it does not match the default policy */
436 if (ipsec4_in_reject(m, NULL)) {
437 ipsecstat.in_polvio++;
444 * Should the inner packet be considered authentic?
445 * My current answer is: NO.
447 * host1 -- gw1 === gw2 -- host2
448 * In this case, gw2 can trust the authenticity of the
449 * outer packet, but NOT inner. Packet may be altered
450 * between host1 and gw1.
452 * host1 -- gw1 === host2
453 * This case falls into the same scenario as above.
456 * This case is the only case when we may be able to leave
457 * M_AUTHIPHDR and M_AUTHIPDGM set.
458 * However, if host1 is wrongly configured, and allows
459 * attacker to inject some packet with src=host1 and
460 * dst=host2, you are in risk.
462 m->m_flags &= ~M_AUTHIPHDR;
463 m->m_flags &= ~M_AUTHIPDGM;
466 key_sa_recordxfer(sav, m);
467 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
468 ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) {
469 ipsecstat.in_nomem++;
473 if (! IF_HANDOFF(&ipintrq, m, NULL)) {
474 ipsecstat.in_inval++;
479 schednetisr(NETISR_IP); /*can be skipped but to make sure*/
486 ip = mtod(m, struct ip *);
487 #ifndef PULLDOWN_TEST
489 * We do deep-copy since KAME requires that
490 * the packet is placed in a single external mbuf.
492 ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off);
493 m->m_data += stripsiz;
494 m->m_len -= stripsiz;
495 m->m_pkthdr.len -= stripsiz;
498 * even in m_pulldown case, we need to strip off AH so that
499 * we can compute checksum for multiple AH correctly.
501 if (m->m_len >= stripsiz + off) {
502 ovbcopy((caddr_t)ip, ((caddr_t)ip) + stripsiz, off);
503 m->m_data += stripsiz;
504 m->m_len -= stripsiz;
505 m->m_pkthdr.len -= stripsiz;
508 * this comes with no copy if the boundary is on
513 n = m_split(m, off, M_DONTWAIT);
515 /* m is retained by m_split */
520 /* m_cat does not update m_pkthdr.len */
521 m->m_pkthdr.len += n->m_pkthdr.len;
525 if (m->m_len < sizeof(*ip)) {
526 m = m_pullup(m, sizeof(*ip));
528 ipsecstat.in_inval++;
532 ip = mtod(m, struct ip *);
534 ip->ip_len = ip->ip_len - stripsiz;
536 ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz);
539 /* forget about IP hdr checksum, the check has already been passed */
541 key_sa_recordxfer(sav, m);
542 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
543 ipsecstat.in_nomem++;
547 if (nxt != IPPROTO_DONE) {
548 if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
549 ipsec4_in_reject(m, NULL)) {
550 ipsecstat.in_polvio++;
553 (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
560 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
561 printf("DP ah4_input call free SA:%p\n", sav));
564 ipsecstat.in_success++;
569 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
570 printf("DP ah4_input call free SA:%p\n", sav));
581 ah6_input(mp, offp, proto)
585 struct mbuf *m = *mp;
590 const struct ah_algorithm *algo;
594 struct secasvar *sav = NULL;
598 #ifndef PULLDOWN_TEST
599 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), IPPROTO_DONE);
600 ah = (struct ah *)(mtod(m, caddr_t) + off);
602 IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah));
604 ipseclog((LOG_DEBUG, "IPv6 AH input: can't pullup\n"));
605 ipsec6stat.in_inval++;
609 ip6 = mtod(m, struct ip6_hdr *);
612 /* find the sassoc. */
615 if (ntohs(ip6->ip6_plen) == 0) {
616 ipseclog((LOG_ERR, "IPv6 AH input: "
617 "AH with IPv6 jumbogram is not supported.\n"));
618 ipsec6stat.in_inval++;
622 if ((sav = key_allocsa(AF_INET6,
623 (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst,
624 IPPROTO_AH, spi)) == 0) {
625 ipseclog((LOG_WARNING,
626 "IPv6 AH input: no key association found for spi %u\n",
627 (u_int32_t)ntohl(spi)));
628 ipsec6stat.in_nosa++;
631 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
632 printf("DP ah6_input called to allocate SA:%p\n", sav));
633 if (sav->state != SADB_SASTATE_MATURE
634 && sav->state != SADB_SASTATE_DYING) {
636 "IPv6 AH input: non-mature/dying SA found for spi %u; ",
637 (u_int32_t)ntohl(spi)));
638 ipsec6stat.in_badspi++;
642 algo = ah_algorithm_lookup(sav->alg_auth);
644 ipseclog((LOG_DEBUG, "IPv6 AH input: "
645 "unsupported authentication algorithm for spi %u\n",
646 (u_int32_t)ntohl(spi)));
647 ipsec6stat.in_badspi++;
651 siz = (*algo->sumsiz)(sav);
652 siz1 = ((siz + 3) & ~(4 - 1));
655 * sanity checks for header, 1.
660 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
663 * Here, we do not do "siz1 == siz". See ah4_input() for complete
667 ipseclog((LOG_NOTICE, "sum length too short in IPv6 AH input "
668 "(%lu, should be at least %lu): %s\n",
669 (u_long)siz1, (u_long)siz,
670 ipsec6_logpacketstr(ip6, spi)));
671 ipsec6stat.in_inval++;
674 if ((ah->ah_len << 2) - sizoff != siz1) {
675 ipseclog((LOG_NOTICE, "sum length mismatch in IPv6 AH input "
676 "(%d should be %lu): %s\n",
677 (ah->ah_len << 2) - sizoff, (u_long)siz1,
678 ipsec6_logpacketstr(ip6, spi)));
679 ipsec6stat.in_inval++;
682 #ifndef PULLDOWN_TEST
683 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1, IPPROTO_DONE);
685 IP6_EXTHDR_GET(ah, struct ah *, m, off,
686 sizeof(struct ah) + sizoff + siz1);
688 ipseclog((LOG_NOTICE, "couldn't pullup gather IPv6 AH checksum part"));
689 ipsec6stat.in_inval++;
697 * check for sequence number.
699 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
700 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav))
703 ipsec6stat.in_ahreplay++;
704 ipseclog((LOG_WARNING,
705 "replay packet in IPv6 AH input: %s %s\n",
706 ipsec6_logpacketstr(ip6, spi),
707 ipsec_logsastr(sav)));
713 * alright, it seems sane. now we are going to check the
714 * cryptographic checksum.
716 cksum = malloc(siz1, M_TEMP, M_NOWAIT);
718 ipseclog((LOG_DEBUG, "IPv6 AH input: "
719 "couldn't alloc temporary region for cksum\n"));
720 ipsec6stat.in_inval++;
724 if (ah6_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
726 ipsec6stat.in_inval++;
729 ipsec6stat.in_ahhist[sav->alg_auth]++;
732 caddr_t sumpos = NULL;
734 if (sav->flags & SADB_X_EXT_OLD) {
736 sumpos = (caddr_t)(ah + 1);
739 sumpos = (caddr_t)(((struct newah *)ah) + 1);
742 if (bcmp(sumpos, cksum, siz) != 0) {
743 ipseclog((LOG_WARNING,
744 "checksum mismatch in IPv6 AH input: %s %s\n",
745 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
747 ipsec6stat.in_ahauthfail++;
754 m->m_flags |= M_AUTHIPHDR;
755 m->m_flags |= M_AUTHIPDGM;
759 * looks okey, but we need more sanity check.
760 * XXX should elaborate.
762 if (ah->ah_nxt == IPPROTO_IPV6) {
763 struct ip6_hdr *nip6;
766 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
768 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1
769 + sizeof(struct ip6_hdr), IPPROTO_DONE);
771 nip6 = (struct ip6_hdr *)((u_char *)(ah + 1) + sizoff + siz1);
772 if (!IN6_ARE_ADDR_EQUAL(&nip6->ip6_src, &ip6->ip6_src)
773 || !IN6_ARE_ADDR_EQUAL(&nip6->ip6_dst, &ip6->ip6_dst)) {
774 m->m_flags &= ~M_AUTHIPHDR;
775 m->m_flags &= ~M_AUTHIPDGM;
777 } else if (ah->ah_nxt == IPPROTO_IPIP) {
778 m->m_flags &= ~M_AUTHIPHDR;
779 m->m_flags &= ~M_AUTHIPDGM;
780 } else if (ah->ah_nxt == IPPROTO_IP) {
781 m->m_flags &= ~M_AUTHIPHDR;
782 m->m_flags &= ~M_AUTHIPDGM;
786 if (m->m_flags & M_AUTHIPHDR
787 && m->m_flags & M_AUTHIPDGM) {
790 "IPv6 AH input: authentication succeess\n"));
792 ipsec6stat.in_ahauthsucc++;
794 ipseclog((LOG_WARNING,
795 "authentication failed in IPv6 AH input: %s %s\n",
796 ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
797 ipsec6stat.in_ahauthfail++;
802 * update sequence number.
804 if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
805 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) {
806 ipsec6stat.in_ahreplay++;
811 /* was it transmitted over the IPsec tunnel SA? */
812 if (sav->flags & SADB_X_EXT_OLD) {
814 stripsiz = sizeof(struct ah) + siz1;
817 stripsiz = sizeof(struct newah) + siz1;
819 if (ipsec6_tunnel_validate(m, off + stripsiz, nxt, sav)) {
821 * strip off all the headers that precedes AH.
822 * IP6 xx AH IP6' payload -> IP6' payload
824 * XXX more sanity checks
825 * XXX relationship with gif?
827 u_int32_t flowinfo; /*net endian*/
829 flowinfo = ip6->ip6_flow;
830 m_adj(m, off + stripsiz);
831 if (m->m_len < sizeof(*ip6)) {
833 * m_pullup is prohibited in KAME IPv6 input processing
834 * but there's no other way!
836 m = m_pullup(m, sizeof(*ip6));
838 ipsec6stat.in_inval++;
842 ip6 = mtod(m, struct ip6_hdr *);
843 /* ECN consideration. */
844 ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow);
845 if (!key_checktunnelsanity(sav, AF_INET6,
846 (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) {
847 ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
848 "in IPv6 AH input: %s %s\n",
849 ipsec6_logpacketstr(ip6, spi),
850 ipsec_logsastr(sav)));
851 ipsec6stat.in_inval++;
855 #if 0 /* XXX should we call ipfw rather than ipsec_in_reject? */
856 /* drop it if it does not match the default policy */
857 if (ipsec6_in_reject(m, NULL)) {
858 ipsec6stat.in_polvio++;
865 * should the inner packet be considered authentic?
866 * see comment in ah4_input().
868 m->m_flags &= ~M_AUTHIPHDR;
869 m->m_flags &= ~M_AUTHIPDGM;
872 key_sa_recordxfer(sav, m);
873 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
874 ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) {
875 ipsec6stat.in_nomem++;
879 if (! IF_HANDOFF(&ip6intrq, m, NULL)) {
880 ipsec6stat.in_inval++;
885 schednetisr(NETISR_IPV6); /*can be skipped but to make sure*/
894 * Copy the value of the next header field of AH to the
895 * next header field of the previous header.
896 * This is necessary because AH will be stripped off below.
898 prvnxtp = ip6_get_prevhdr(m, off); /* XXX */
901 ip6 = mtod(m, struct ip6_hdr *);
902 #ifndef PULLDOWN_TEST
904 * We do deep-copy since KAME requires that
905 * the packet is placed in a single mbuf.
907 ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
908 m->m_data += stripsiz;
909 m->m_len -= stripsiz;
910 m->m_pkthdr.len -= stripsiz;
913 * even in m_pulldown case, we need to strip off AH so that
914 * we can compute checksum for multiple AH correctly.
916 if (m->m_len >= stripsiz + off) {
917 ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
918 m->m_data += stripsiz;
919 m->m_len -= stripsiz;
920 m->m_pkthdr.len -= stripsiz;
923 * this comes with no copy if the boundary is on
928 n = m_split(m, off, M_DONTWAIT);
930 /* m is retained by m_split */
935 /* m_cat does not update m_pkthdr.len */
936 m->m_pkthdr.len += n->m_pkthdr.len;
939 ip6 = mtod(m, struct ip6_hdr *);
941 ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
943 key_sa_recordxfer(sav, m);
944 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
945 ipsec6stat.in_nomem++;
954 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
955 printf("DP ah6_input call free SA:%p\n", sav));
958 ipsec6stat.in_success++;
963 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
964 printf("DP ah6_input call free SA:%p\n", sav));
973 ah6_ctlinput(cmd, sa, d)
978 const struct newah *ahp;
980 struct secasvar *sav;
983 struct ip6ctlparam *ip6cp = NULL;
985 struct sockaddr_in6 sa6_src, sa6_dst;
987 if (sa->sa_family != AF_INET6 ||
988 sa->sa_len != sizeof(struct sockaddr_in6))
990 if ((unsigned)cmd >= PRC_NCMDS)
993 /* if the parameter is from icmp6, decode it. */
995 ip6cp = (struct ip6ctlparam *)d;
997 ip6 = ip6cp->ip6c_ip6;
998 off = ip6cp->ip6c_off;
1006 * XXX: We assume that when ip6 is non NULL,
1007 * M and OFF are valid.
1010 /* check if we can safely examine src and dst ports */
1011 if (m->m_pkthdr.len < off + sizeof(ah))
1014 if (m->m_len < off + sizeof(ah)) {
1016 * this should be rare case,
1017 * so we compromise on this copy...
1019 m_copydata(m, off, sizeof(ah), (caddr_t)&ah);
1022 ahp = (struct newah *)(mtod(m, caddr_t) + off);
1024 if (cmd == PRC_MSGSIZE) {
1028 * Check to see if we have a valid SA corresponding to
1029 * the address in the ICMP message payload.
1031 sav = key_allocsa(AF_INET6,
1032 (caddr_t)&sa6_src.sin6_addr,
1033 (caddr_t)&sa6_dst.sin6_addr,
1034 IPPROTO_AH, ahp->ah_spi);
1036 if (sav->state == SADB_SASTATE_MATURE ||
1037 sav->state == SADB_SASTATE_DYING)
1042 /* XXX Further validation? */
1045 * Depending on the value of "valid" and routing table
1046 * size (mtudisc_{hi,lo}wat), we will:
1047 * - recalcurate the new MTU and create the
1048 * corresponding routing entry, or
1049 * - ignore the MTU change notification.
1051 icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
1054 /* we normally notify single pcb here */
1056 /* we normally notify any pcb here */