Eliminate use of curthread in if_ioctl functions by passing down the
[dragonfly.git] / sys / netinet6 / ah_input.c
1 /*      $FreeBSD: src/sys/netinet6/ah_input.c,v 1.1.2.6 2002/04/28 05:40:26 suz Exp $   */
2 /*      $DragonFly: src/sys/netinet6/ah_input.c,v 1.5 2003/09/15 23:38:14 hsu Exp $     */
3 /*      $KAME: ah_input.c,v 1.67 2002/01/07 11:39:56 kjc Exp $  */
4
5 /*
6  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the project nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 /*
35  * RFC1826/2402 authentication header.
36  */
37
38 #include "opt_inet.h"
39 #include "opt_inet6.h"
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/malloc.h>
44 #include <sys/mbuf.h>
45 #include <sys/domain.h>
46 #include <sys/protosw.h>
47 #include <sys/socket.h>
48 #include <sys/errno.h>
49 #include <sys/time.h>
50 #include <sys/syslog.h>
51
52 #include <net/if.h>
53 #include <net/route.h>
54 #include <net/netisr.h>
55 #include <machine/cpu.h>
56
57 #include <netinet/in.h>
58 #include <netinet/in_systm.h>
59 #include <netinet/in_var.h>
60 #include <netinet/ip.h>
61 #include <netinet/ip_var.h>
62 #include <netinet/ip_ecn.h>
63 #ifdef INET6
64 #include <netinet6/ip6_ecn.h>
65 #endif
66
67 #ifdef INET6
68 #include <netinet/ip6.h>
69 #include <netinet6/ip6_var.h>
70 #include <netinet6/in6_pcb.h>
71 #include <netinet/icmp6.h>
72 #include <netinet6/ip6protosw.h>
73 #endif
74
75 #include <netinet6/ipsec.h>
76 #ifdef INET6
77 #include <netinet6/ipsec6.h>
78 #endif
79 #include <netinet6/ah.h>
80 #ifdef INET6
81 #include <netinet6/ah6.h>
82 #endif
83 #include <netproto/key/key.h>
84 #include <netproto/key/keydb.h>
85 #ifdef IPSEC_DEBUG
86 #include <netproto/key/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 void
102 ah4_input(struct mbuf *m, int off, int proto)
103 {
104         struct ip *ip;
105         struct ah *ah;
106         u_int32_t spi;
107         const struct ah_algorithm *algo;
108         size_t siz;
109         size_t siz1;
110         u_char *cksum;
111         struct secasvar *sav = NULL;
112         u_int16_t nxt;
113         size_t hlen;
114         size_t stripsiz = 0;
115
116 #ifndef PULLDOWN_TEST
117         if (m->m_len < off + sizeof(struct newah)) {
118                 m = m_pullup(m, off + sizeof(struct newah));
119                 if (!m) {
120                         ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
121                                 "dropping the packet for simplicity\n"));
122                         ipsecstat.in_inval++;
123                         goto fail;
124                 }
125         }
126
127         ip = mtod(m, struct ip *);
128         ah = (struct ah *)(((caddr_t)ip) + off);
129 #else
130         ip = mtod(m, struct ip *);
131         IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah));
132         if (ah == NULL) {
133                 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
134                         "dropping the packet for simplicity\n"));
135                 ipsecstat.in_inval++;
136                 goto fail;
137         }
138 #endif
139         nxt = ah->ah_nxt;
140 #ifdef _IP_VHL
141         hlen = IP_VHL_HL(ip->ip_vhl) << 2;
142 #else
143         hlen = ip->ip_hl << 2;
144 #endif
145
146         /* find the sassoc. */
147         spi = ah->ah_spi;
148
149         if ((sav = key_allocsa(AF_INET,
150                               (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst,
151                               IPPROTO_AH, spi)) == 0) {
152                 ipseclog((LOG_WARNING,
153                     "IPv4 AH input: no key association found for spi %u\n",
154                     (u_int32_t)ntohl(spi)));
155                 ipsecstat.in_nosa++;
156                 goto fail;
157         }
158         KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
159                 printf("DP ah4_input called to allocate SA:%p\n", sav));
160         if (sav->state != SADB_SASTATE_MATURE
161          && sav->state != SADB_SASTATE_DYING) {
162                 ipseclog((LOG_DEBUG,
163                     "IPv4 AH input: non-mature/dying SA found for spi %u\n",
164                     (u_int32_t)ntohl(spi)));
165                 ipsecstat.in_badspi++;
166                 goto fail;
167         }
168
169         algo = ah_algorithm_lookup(sav->alg_auth);
170         if (!algo) {
171                 ipseclog((LOG_DEBUG, "IPv4 AH input: "
172                     "unsupported authentication algorithm for spi %u\n",
173                     (u_int32_t)ntohl(spi)));
174                 ipsecstat.in_badspi++;
175                 goto fail;
176         }
177
178         siz = (*algo->sumsiz)(sav);
179         siz1 = ((siz + 3) & ~(4 - 1));
180
181         /*
182          * sanity checks for header, 1.
183          */
184     {
185         int sizoff;
186
187         sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
188
189         /*
190          * Here, we do not do "siz1 == siz".  This is because the way
191          * RFC240[34] section 2 is written.  They do not require truncation
192          * to 96 bits.
193          * For example, Microsoft IPsec stack attaches 160 bits of
194          * authentication data for both hmac-md5 and hmac-sha1.  For hmac-sha1,
195          * 32 bits of padding is attached.
196          *
197          * There are two downsides to this specification.
198          * They have no real harm, however, they leave us fuzzy feeling.
199          * - if we attach more than 96 bits of authentication data onto AH,
200          *   we will never notice about possible modification by rogue
201          *   intermediate nodes.
202          *   Since extra bits in AH checksum is never used, this constitutes
203          *   no real issue, however, it is wacky.
204          * - even if the peer attaches big authentication data, we will never
205          *   notice the difference, since longer authentication data will just
206          *   work.
207          *
208          * We may need some clarification in the spec.
209          */
210         if (siz1 < siz) {
211                 ipseclog((LOG_NOTICE, "sum length too short in IPv4 AH input "
212                     "(%lu, should be at least %lu): %s\n",
213                     (u_long)siz1, (u_long)siz,
214                     ipsec4_logpacketstr(ip, spi)));
215                 ipsecstat.in_inval++;
216                 goto fail;
217         }
218         if ((ah->ah_len << 2) - sizoff != siz1) {
219                 ipseclog((LOG_NOTICE, "sum length mismatch in IPv4 AH input "
220                     "(%d should be %lu): %s\n",
221                     (ah->ah_len << 2) - sizoff, (u_long)siz1,
222                     ipsec4_logpacketstr(ip, spi)));
223                 ipsecstat.in_inval++;
224                 goto fail;
225         }
226
227 #ifndef PULLDOWN_TEST
228         if (m->m_len < off + sizeof(struct ah) + sizoff + siz1) {
229                 m = m_pullup(m, off + sizeof(struct ah) + sizoff + siz1);
230                 if (!m) {
231                         ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
232                         ipsecstat.in_inval++;
233                         goto fail;
234                 }
235
236                 ip = mtod(m, struct ip *);
237                 ah = (struct ah *)(((caddr_t)ip) + off);
238         }
239 #else
240         IP6_EXTHDR_GET(ah, struct ah *, m, off,
241                 sizeof(struct ah) + sizoff + siz1);
242         if (ah == NULL) {
243                 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
244                 ipsecstat.in_inval++;
245                 goto fail;
246         }
247 #endif
248     }
249
250         /*
251          * check for sequence number.
252          */
253         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
254                 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav))
255                         ; /* okey */
256                 else {
257                         ipsecstat.in_ahreplay++;
258                         ipseclog((LOG_WARNING,
259                             "replay packet in IPv4 AH input: %s %s\n",
260                             ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
261                         goto fail;
262                 }
263         }
264
265         /*
266          * alright, it seems sane.  now we are going to check the
267          * cryptographic checksum.
268          */
269         cksum = malloc(siz1, M_TEMP, M_NOWAIT);
270         if (!cksum) {
271                 ipseclog((LOG_DEBUG, "IPv4 AH input: "
272                     "couldn't alloc temporary region for cksum\n"));
273                 ipsecstat.in_inval++;
274                 goto fail;
275         }
276         
277         /*
278          * some of IP header fields are flipped to the host endian.
279          * convert them back to network endian.  VERY stupid.
280          */
281         ip->ip_len = htons(ip->ip_len + hlen);
282         ip->ip_off = htons(ip->ip_off);
283         if (ah4_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
284                 free(cksum, M_TEMP);
285                 ipsecstat.in_inval++;
286                 goto fail;
287         }
288         ipsecstat.in_ahhist[sav->alg_auth]++;
289         /*
290          * flip them back.
291          */
292         ip->ip_len = ntohs(ip->ip_len) - hlen;
293         ip->ip_off = ntohs(ip->ip_off);
294
295     {
296         caddr_t sumpos = NULL;
297
298         if (sav->flags & SADB_X_EXT_OLD) {
299                 /* RFC 1826 */
300                 sumpos = (caddr_t)(ah + 1);
301         } else {
302                 /* RFC 2402 */
303                 sumpos = (caddr_t)(((struct newah *)ah) + 1);
304         }
305
306         if (bcmp(sumpos, cksum, siz) != 0) {
307                 ipseclog((LOG_WARNING,
308                     "checksum mismatch in IPv4 AH input: %s %s\n",
309                     ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
310                 free(cksum, M_TEMP);
311                 ipsecstat.in_ahauthfail++;
312                 goto fail;
313         }
314     }
315
316         free(cksum, M_TEMP);
317
318         m->m_flags |= M_AUTHIPHDR;
319         m->m_flags |= M_AUTHIPDGM;
320
321 #if 0
322         /*
323          * looks okey, but we need more sanity check.
324          * XXX should elaborate.
325          */
326         if (ah->ah_nxt == IPPROTO_IPIP || ah->ah_nxt == IPPROTO_IP) {
327                 struct ip *nip;
328                 size_t sizoff;
329
330                 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
331
332                 if (m->m_len < off + sizeof(struct ah) + sizoff + siz1 + hlen) {
333                         m = m_pullup(m, off + sizeof(struct ah)
334                                         + sizoff + siz1 + hlen);
335                         if (!m) {
336                                 ipseclog((LOG_DEBUG,
337                                     "IPv4 AH input: can't pullup\n"));
338                                 ipsecstat.in_inval++;
339                                 goto fail;
340                         }
341                 }
342
343                 nip = (struct ip *)((u_char *)(ah + 1) + sizoff + siz1);
344                 if (nip->ip_src.s_addr != ip->ip_src.s_addr
345                  || nip->ip_dst.s_addr != ip->ip_dst.s_addr) {
346                         m->m_flags &= ~M_AUTHIPHDR;
347                         m->m_flags &= ~M_AUTHIPDGM;
348                 }
349         }
350 #ifdef INET6
351         else if (ah->ah_nxt == IPPROTO_IPV6) {
352                 m->m_flags &= ~M_AUTHIPHDR;
353                 m->m_flags &= ~M_AUTHIPDGM;
354         }
355 #endif /* INET6 */
356 #endif /* 0 */
357
358         if (m->m_flags & M_AUTHIPHDR
359          && m->m_flags & M_AUTHIPDGM) {
360 #if 0
361                 ipseclog((LOG_DEBUG,
362                     "IPv4 AH input: authentication succeess\n"));
363 #endif
364                 ipsecstat.in_ahauthsucc++;
365         } else {
366                 ipseclog((LOG_WARNING,
367                     "authentication failed in IPv4 AH input: %s %s\n",
368                     ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
369                 ipsecstat.in_ahauthfail++;
370                 goto fail;
371         }
372
373         /*
374          * update sequence number.
375          */
376         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
377                 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) {
378                         ipsecstat.in_ahreplay++;
379                         goto fail;
380                 }
381         }
382
383         /* was it transmitted over the IPsec tunnel SA? */
384         if (sav->flags & SADB_X_EXT_OLD) {
385                 /* RFC 1826 */
386                 stripsiz = sizeof(struct ah) + siz1;
387         } else {
388                 /* RFC 2402 */
389                 stripsiz = sizeof(struct newah) + siz1;
390         }
391         if (ipsec4_tunnel_validate(m, off + stripsiz, nxt, sav)) {
392                 /*
393                  * strip off all the headers that precedes AH.
394                  *      IP xx AH IP' payload -> IP' payload
395                  *
396                  * XXX more sanity checks
397                  * XXX relationship with gif?
398                  */
399                 u_int8_t tos;
400
401                 tos = ip->ip_tos;
402                 m_adj(m, off + stripsiz);
403                 if (m->m_len < sizeof(*ip)) {
404                         m = m_pullup(m, sizeof(*ip));
405                         if (!m) {
406                                 ipsecstat.in_inval++;
407                                 goto fail;
408                         }
409                 }
410                 ip = mtod(m, struct ip *);
411                 /* ECN consideration. */
412                 ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos);
413                 if (!key_checktunnelsanity(sav, AF_INET,
414                             (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) {
415                         ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
416                             "in IPv4 AH input: %s %s\n",
417                             ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
418                         ipsecstat.in_inval++;
419                         goto fail;
420                 }
421
422 #if 1
423                 /*
424                  * Should the inner packet be considered authentic?
425                  * My current answer is: NO.
426                  *
427                  * host1 -- gw1 === gw2 -- host2
428                  *      In this case, gw2 can trust the authenticity of the
429                  *      outer packet, but NOT inner.  Packet may be altered
430                  *      between host1 and gw1.
431                  *
432                  * host1 -- gw1 === host2
433                  *      This case falls into the same scenario as above.
434                  *
435                  * host1 === host2
436                  *      This case is the only case when we may be able to leave
437                  *      M_AUTHIPHDR and M_AUTHIPDGM set.
438                  *      However, if host1 is wrongly configured, and allows
439                  *      attacker to inject some packet with src=host1 and
440                  *      dst=host2, you are in risk.
441                  */
442                 m->m_flags &= ~M_AUTHIPHDR;
443                 m->m_flags &= ~M_AUTHIPDGM;
444 #endif
445
446                 key_sa_recordxfer(sav, m);
447                 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
448                     ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) {
449                         ipsecstat.in_nomem++;
450                         goto fail;
451                 }
452
453                 if (netisr_queue(NETISR_IP, m)) {
454                         ipsecstat.in_inval++;
455                         m = NULL;
456                         goto fail;
457                 }
458
459                 nxt = IPPROTO_DONE;
460         } else {
461                 /*
462                  * strip off AH.
463                  */
464
465                 ip = mtod(m, struct ip *);
466 #ifndef PULLDOWN_TEST
467                 /*
468                  * We do deep-copy since KAME requires that
469                  * the packet is placed in a single external mbuf.
470                  */
471                 ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off);
472                 m->m_data += stripsiz;
473                 m->m_len -= stripsiz;
474                 m->m_pkthdr.len -= stripsiz;
475 #else
476                 /*
477                  * even in m_pulldown case, we need to strip off AH so that
478                  * we can compute checksum for multiple AH correctly.
479                  */
480                 if (m->m_len >= stripsiz + off) {
481                         ovbcopy((caddr_t)ip, ((caddr_t)ip) + stripsiz, off);
482                         m->m_data += stripsiz;
483                         m->m_len -= stripsiz;
484                         m->m_pkthdr.len -= stripsiz;
485                 } else {
486                         /*
487                          * this comes with no copy if the boundary is on
488                          * cluster
489                          */
490                         struct mbuf *n;
491
492                         n = m_split(m, off, M_DONTWAIT);
493                         if (n == NULL) {
494                                 /* m is retained by m_split */
495                                 goto fail;
496                         }
497                         m_adj(n, stripsiz);
498                         m_cat(m, n);
499                         /* m_cat does not update m_pkthdr.len */
500                         m->m_pkthdr.len += n->m_pkthdr.len;
501                 }
502 #endif
503
504                 if (m->m_len < sizeof(*ip)) {
505                         m = m_pullup(m, sizeof(*ip));
506                         if (m == NULL) {
507                                 ipsecstat.in_inval++;
508                                 goto fail;
509                         }
510                 }
511                 ip = mtod(m, struct ip *);
512 #ifdef IPLEN_FLIPPED
513                 ip->ip_len = ip->ip_len - stripsiz;
514 #else
515                 ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz);
516 #endif
517                 ip->ip_p = nxt;
518                 /* forget about IP hdr checksum, the check has already been passed */
519
520                 key_sa_recordxfer(sav, m);
521                 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
522                         ipsecstat.in_nomem++;
523                         goto fail;
524                 }
525
526                 if (nxt != IPPROTO_DONE) {
527                         if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
528                             ipsec4_in_reject(m, NULL)) {
529                                 ipsecstat.in_polvio++;
530                                 goto fail;
531                         }
532                         (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
533                 } else
534                         m_freem(m);
535                 m = NULL;
536         }
537
538         if (sav) {
539                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
540                         printf("DP ah4_input call free SA:%p\n", sav));
541                 key_freesav(sav);
542         }
543         ipsecstat.in_success++;
544         return;
545
546 fail:
547         if (sav) {
548                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
549                         printf("DP ah4_input call free SA:%p\n", sav));
550                 key_freesav(sav);
551         }
552         if (m)
553                 m_freem(m);
554         return;
555 }
556 #endif /* INET */
557
558 #ifdef INET6
559 int
560 ah6_input(mp, offp, proto)
561         struct mbuf **mp;
562         int *offp, proto;
563 {
564         struct mbuf *m = *mp;
565         int off = *offp;
566         struct ip6_hdr *ip6;
567         struct ah *ah;
568         u_int32_t spi;
569         const struct ah_algorithm *algo;
570         size_t siz;
571         size_t siz1;
572         u_char *cksum;
573         struct secasvar *sav = NULL;
574         u_int16_t nxt;
575         size_t stripsiz = 0;
576
577 #ifndef PULLDOWN_TEST
578         IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), IPPROTO_DONE);
579         ah = (struct ah *)(mtod(m, caddr_t) + off);
580 #else
581         IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah));
582         if (ah == NULL) {
583                 ipseclog((LOG_DEBUG, "IPv6 AH input: can't pullup\n"));
584                 ipsec6stat.in_inval++;
585                 return IPPROTO_DONE;
586         }
587 #endif
588         ip6 = mtod(m, struct ip6_hdr *);
589         nxt = ah->ah_nxt;
590
591         /* find the sassoc. */
592         spi = ah->ah_spi;
593
594         if (ntohs(ip6->ip6_plen) == 0) {
595                 ipseclog((LOG_ERR, "IPv6 AH input: "
596                     "AH with IPv6 jumbogram is not supported.\n"));
597                 ipsec6stat.in_inval++;
598                 goto fail;
599         }
600
601         if ((sav = key_allocsa(AF_INET6,
602                               (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst,
603                               IPPROTO_AH, spi)) == 0) {
604                 ipseclog((LOG_WARNING,
605                     "IPv6 AH input: no key association found for spi %u\n",
606                     (u_int32_t)ntohl(spi)));
607                 ipsec6stat.in_nosa++;
608                 goto fail;
609         }
610         KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
611                 printf("DP ah6_input called to allocate SA:%p\n", sav));
612         if (sav->state != SADB_SASTATE_MATURE
613          && sav->state != SADB_SASTATE_DYING) {
614                 ipseclog((LOG_DEBUG,
615                     "IPv6 AH input: non-mature/dying SA found for spi %u; ",
616                     (u_int32_t)ntohl(spi)));
617                 ipsec6stat.in_badspi++;
618                 goto fail;
619         }
620
621         algo = ah_algorithm_lookup(sav->alg_auth);
622         if (!algo) {
623                 ipseclog((LOG_DEBUG, "IPv6 AH input: "
624                     "unsupported authentication algorithm for spi %u\n",
625                     (u_int32_t)ntohl(spi)));
626                 ipsec6stat.in_badspi++;
627                 goto fail;
628         }
629
630         siz = (*algo->sumsiz)(sav);
631         siz1 = ((siz + 3) & ~(4 - 1));
632
633         /*
634          * sanity checks for header, 1.
635          */
636     {
637         int sizoff;
638
639         sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
640
641         /*
642          * Here, we do not do "siz1 == siz".  See ah4_input() for complete
643          * description.
644          */
645         if (siz1 < siz) {
646                 ipseclog((LOG_NOTICE, "sum length too short in IPv6 AH input "
647                     "(%lu, should be at least %lu): %s\n",
648                     (u_long)siz1, (u_long)siz,
649                     ipsec6_logpacketstr(ip6, spi)));
650                 ipsec6stat.in_inval++;
651                 goto fail;
652         }
653         if ((ah->ah_len << 2) - sizoff != siz1) {
654                 ipseclog((LOG_NOTICE, "sum length mismatch in IPv6 AH input "
655                     "(%d should be %lu): %s\n",
656                     (ah->ah_len << 2) - sizoff, (u_long)siz1,
657                     ipsec6_logpacketstr(ip6, spi)));
658                 ipsec6stat.in_inval++;
659                 goto fail;
660         }
661 #ifndef PULLDOWN_TEST
662         IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1, IPPROTO_DONE);
663 #else
664         IP6_EXTHDR_GET(ah, struct ah *, m, off,
665                 sizeof(struct ah) + sizoff + siz1);
666         if (ah == NULL) {
667                 ipseclog((LOG_NOTICE, "couldn't pullup gather IPv6 AH checksum part"));
668                 ipsec6stat.in_inval++;
669                 m = NULL;
670                 goto fail;
671         }
672 #endif
673     }
674
675         /*
676          * check for sequence number.
677          */
678         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
679                 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav))
680                         ; /* okey */
681                 else {
682                         ipsec6stat.in_ahreplay++;
683                         ipseclog((LOG_WARNING,
684                             "replay packet in IPv6 AH input: %s %s\n",
685                             ipsec6_logpacketstr(ip6, spi),
686                             ipsec_logsastr(sav)));
687                         goto fail;
688                 }
689         }
690
691         /*
692          * alright, it seems sane.  now we are going to check the
693          * cryptographic checksum.
694          */
695         cksum = malloc(siz1, M_TEMP, M_NOWAIT);
696         if (!cksum) {
697                 ipseclog((LOG_DEBUG, "IPv6 AH input: "
698                     "couldn't alloc temporary region for cksum\n"));
699                 ipsec6stat.in_inval++;
700                 goto fail;
701         }
702         
703         if (ah6_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
704                 free(cksum, M_TEMP);
705                 ipsec6stat.in_inval++;
706                 goto fail;
707         }
708         ipsec6stat.in_ahhist[sav->alg_auth]++;
709
710     {
711         caddr_t sumpos = NULL;
712
713         if (sav->flags & SADB_X_EXT_OLD) {
714                 /* RFC 1826 */
715                 sumpos = (caddr_t)(ah + 1);
716         } else {
717                 /* RFC 2402 */
718                 sumpos = (caddr_t)(((struct newah *)ah) + 1);
719         }
720
721         if (bcmp(sumpos, cksum, siz) != 0) {
722                 ipseclog((LOG_WARNING,
723                     "checksum mismatch in IPv6 AH input: %s %s\n",
724                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
725                 free(cksum, M_TEMP);
726                 ipsec6stat.in_ahauthfail++;
727                 goto fail;
728         }
729     }
730
731         free(cksum, M_TEMP);
732
733         m->m_flags |= M_AUTHIPHDR;
734         m->m_flags |= M_AUTHIPDGM;
735
736 #if 0
737         /*
738          * looks okey, but we need more sanity check.
739          * XXX should elaborate.
740          */
741         if (ah->ah_nxt == IPPROTO_IPV6) {
742                 struct ip6_hdr *nip6;
743                 size_t sizoff;
744
745                 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
746
747                 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1
748                                 + sizeof(struct ip6_hdr), IPPROTO_DONE);
749
750                 nip6 = (struct ip6_hdr *)((u_char *)(ah + 1) + sizoff + siz1);
751                 if (!IN6_ARE_ADDR_EQUAL(&nip6->ip6_src, &ip6->ip6_src)
752                  || !IN6_ARE_ADDR_EQUAL(&nip6->ip6_dst, &ip6->ip6_dst)) {
753                         m->m_flags &= ~M_AUTHIPHDR;
754                         m->m_flags &= ~M_AUTHIPDGM;
755                 }
756         } else if (ah->ah_nxt == IPPROTO_IPIP) {
757                 m->m_flags &= ~M_AUTHIPHDR;
758                 m->m_flags &= ~M_AUTHIPDGM;
759         } else if (ah->ah_nxt == IPPROTO_IP) {
760                 m->m_flags &= ~M_AUTHIPHDR;
761                 m->m_flags &= ~M_AUTHIPDGM;
762         }
763 #endif
764
765         if (m->m_flags & M_AUTHIPHDR
766          && m->m_flags & M_AUTHIPDGM) {
767 #if 0
768                 ipseclog((LOG_DEBUG,
769                     "IPv6 AH input: authentication succeess\n"));
770 #endif
771                 ipsec6stat.in_ahauthsucc++;
772         } else {
773                 ipseclog((LOG_WARNING,
774                     "authentication failed in IPv6 AH input: %s %s\n",
775                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
776                 ipsec6stat.in_ahauthfail++;
777                 goto fail;
778         }
779
780         /*
781          * update sequence number.
782          */
783         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
784                 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) {
785                         ipsec6stat.in_ahreplay++;
786                         goto fail;
787                 }
788         }
789
790         /* was it transmitted over the IPsec tunnel SA? */
791         if (sav->flags & SADB_X_EXT_OLD) {
792                 /* RFC 1826 */
793                 stripsiz = sizeof(struct ah) + siz1;
794         } else {
795                 /* RFC 2402 */
796                 stripsiz = sizeof(struct newah) + siz1;
797         }
798         if (ipsec6_tunnel_validate(m, off + stripsiz, nxt, sav)) {
799                 /*
800                  * strip off all the headers that precedes AH.
801                  *      IP6 xx AH IP6' payload -> IP6' payload
802                  *
803                  * XXX more sanity checks
804                  * XXX relationship with gif?
805                  */
806                 u_int32_t flowinfo;     /* net endian */
807
808                 flowinfo = ip6->ip6_flow;
809                 m_adj(m, off + stripsiz);
810                 if (m->m_len < sizeof(*ip6)) {
811                         /*
812                          * m_pullup is prohibited in KAME IPv6 input processing
813                          * but there's no other way!
814                          */
815                         m = m_pullup(m, sizeof(*ip6));
816                         if (!m) {
817                                 ipsec6stat.in_inval++;
818                                 goto fail;
819                         }
820                 }
821                 ip6 = mtod(m, struct ip6_hdr *);
822                 /* ECN consideration. */
823                 ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow);
824                 if (!key_checktunnelsanity(sav, AF_INET6,
825                             (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) {
826                         ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
827                             "in IPv6 AH input: %s %s\n",
828                             ipsec6_logpacketstr(ip6, spi),
829                             ipsec_logsastr(sav)));
830                         ipsec6stat.in_inval++;
831                         goto fail;
832                 }
833
834 #if 1
835                 /*
836                  * should the inner packet be considered authentic?
837                  * see comment in ah4_input().
838                  */
839                 m->m_flags &= ~M_AUTHIPHDR;
840                 m->m_flags &= ~M_AUTHIPDGM;
841 #endif
842
843                 key_sa_recordxfer(sav, m);
844                 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
845                     ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) {
846                         ipsec6stat.in_nomem++;
847                         goto fail;
848                 }
849
850                 if (netisr_queue(NETISR_IPV6, m)) {
851                         ipsecstat.in_inval++;
852                         m = NULL;
853                         goto fail;
854                 }
855
856                 nxt = IPPROTO_DONE;
857         } else {
858                 /*
859                  * strip off AH.
860                  */
861                 char *prvnxtp;
862
863                 /*
864                  * Copy the value of the next header field of AH to the
865                  * next header field of the previous header.
866                  * This is necessary because AH will be stripped off below.
867                  */
868                 prvnxtp = ip6_get_prevhdr(m, off); /* XXX */
869                 *prvnxtp = nxt;
870
871                 ip6 = mtod(m, struct ip6_hdr *);
872 #ifndef PULLDOWN_TEST
873                 /*
874                  * We do deep-copy since KAME requires that
875                  * the packet is placed in a single mbuf.
876                  */
877                 ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
878                 m->m_data += stripsiz;
879                 m->m_len -= stripsiz;
880                 m->m_pkthdr.len -= stripsiz;
881 #else
882                 /*
883                  * even in m_pulldown case, we need to strip off AH so that
884                  * we can compute checksum for multiple AH correctly.
885                  */
886                 if (m->m_len >= stripsiz + off) {
887                         ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
888                         m->m_data += stripsiz;
889                         m->m_len -= stripsiz;
890                         m->m_pkthdr.len -= stripsiz;
891                 } else {
892                         /*
893                          * this comes with no copy if the boundary is on
894                          * cluster
895                          */
896                         struct mbuf *n;
897
898                         n = m_split(m, off, M_DONTWAIT);
899                         if (n == NULL) {
900                                 /* m is retained by m_split */
901                                 goto fail;
902                         }
903                         m_adj(n, stripsiz);
904                         m_cat(m, n);
905                         /* m_cat does not update m_pkthdr.len */
906                         m->m_pkthdr.len += n->m_pkthdr.len;
907                 }
908 #endif
909                 ip6 = mtod(m, struct ip6_hdr *);
910                 /* XXX jumbogram */
911                 ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
912
913                 key_sa_recordxfer(sav, m);
914                 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
915                         ipsec6stat.in_nomem++;
916                         goto fail;
917                 }
918         }
919
920         *offp = off;
921         *mp = m;
922
923         if (sav) {
924                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
925                         printf("DP ah6_input call free SA:%p\n", sav));
926                 key_freesav(sav);
927         }
928         ipsec6stat.in_success++;
929         return nxt;
930
931 fail:
932         if (sav) {
933                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
934                         printf("DP ah6_input call free SA:%p\n", sav));
935                 key_freesav(sav);
936         }
937         if (m)
938                 m_freem(m);
939         return IPPROTO_DONE;
940 }
941
942 void
943 ah6_ctlinput(cmd, sa, d)
944         int cmd;
945         struct sockaddr *sa;
946         void *d;
947 {
948         const struct newah *ahp;
949         struct newah ah;
950         struct secasvar *sav;
951         struct ip6_hdr *ip6;
952         struct mbuf *m;
953         struct ip6ctlparam *ip6cp = NULL;
954         int off;
955         struct sockaddr_in6 *sa6_src, *sa6_dst;
956
957         if (sa->sa_family != AF_INET6 ||
958             sa->sa_len != sizeof(struct sockaddr_in6))
959                 return;
960         if ((unsigned)cmd >= PRC_NCMDS)
961                 return;
962
963         /* if the parameter is from icmp6, decode it. */
964         if (d != NULL) {
965                 ip6cp = (struct ip6ctlparam *)d;
966                 m = ip6cp->ip6c_m;
967                 ip6 = ip6cp->ip6c_ip6;
968                 off = ip6cp->ip6c_off;
969         } else {
970                 m = NULL;
971                 ip6 = NULL;
972                 off = 0; /* fix warning */
973         }
974
975         if (ip6) {
976                 /*
977                  * XXX: We assume that when ip6 is non NULL,
978                  * M and OFF are valid.
979                  */
980
981                 /* check if we can safely examine src and dst ports */
982                 if (m->m_pkthdr.len < off + sizeof(ah))
983                         return;
984
985                 if (m->m_len < off + sizeof(ah)) {
986                         /*
987                          * this should be rare case,
988                          * so we compromise on this copy...
989                          */
990                         m_copydata(m, off, sizeof(ah), (caddr_t)&ah);
991                         ahp = &ah;
992                 } else
993                         ahp = (struct newah *)(mtod(m, caddr_t) + off);
994
995                 if (cmd == PRC_MSGSIZE) {
996                         int valid = 0;
997
998                         /*
999                          * Check to see if we have a valid SA corresponding to
1000                          * the address in the ICMP message payload.
1001                          */
1002                         sa6_src = ip6cp->ip6c_src;
1003                         sa6_dst = (struct sockaddr_in6 *)sa;
1004                         sav = key_allocsa(AF_INET6,
1005                                           (caddr_t)&sa6_src->sin6_addr,
1006                                           (caddr_t)&sa6_dst->sin6_addr,
1007                                           IPPROTO_AH, ahp->ah_spi);
1008                         if (sav) {
1009                                 if (sav->state == SADB_SASTATE_MATURE ||
1010                                     sav->state == SADB_SASTATE_DYING)
1011                                         valid++;
1012                                 key_freesav(sav);
1013                         }
1014
1015                         /* XXX Further validation? */
1016
1017                         /*
1018                          * Depending on the value of "valid" and routing table
1019                          * size (mtudisc_{hi,lo}wat), we will:
1020                          * - recalcurate the new MTU and create the
1021                          *   corresponding routing entry, or
1022                          * - ignore the MTU change notification.
1023                          */
1024                         icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
1025                 }
1026
1027                 /* we normally notify single pcb here */
1028         } else {
1029                 /* we normally notify any pcb here */
1030         }
1031 }
1032 #endif /* INET6 */