diff --exclude CVS -C 3 /usr/src/sys/netinet6/ipcomp.h ./ipcomp.h *** /usr/src/sys/netinet6/ipcomp.h Sun Apr 28 01:40:27 2002 --- ./ipcomp.h Sat May 1 17:33:11 2004 *************** *** 56,61 **** --- 56,63 ---- #define IPCOMP_CPI_NEGOTIATE_MIN 256 #ifdef _KERNEL + #include + struct ipcomp_algorithm { int (*compress) __P((struct mbuf *, struct mbuf *, size_t *)); int (*decompress) __P((struct mbuf *, struct mbuf *, size_t *)); *************** *** 65,71 **** struct ipsecrequest; extern const struct ipcomp_algorithm *ipcomp_algorithm_lookup __P((int)); extern void ipcomp4_input __P((struct mbuf *, ...)); ! extern int ipcomp4_output __P((struct mbuf *, struct ipsecrequest *)); #endif /* KERNEL */ #endif /* _NETINET6_IPCOMP_H_ */ --- 67,73 ---- struct ipsecrequest; extern const struct ipcomp_algorithm *ipcomp_algorithm_lookup __P((int)); extern void ipcomp4_input __P((struct mbuf *, ...)); ! extern int ipcomp4_output __P((struct ipsec_output_state *, struct ipsecrequest *)); #endif /* KERNEL */ #endif /* _NETINET6_IPCOMP_H_ */ Only in .: ipcomp.patch diff --exclude CVS -C 3 /usr/src/sys/netinet6/ipcomp6.h ./ipcomp6.h *** /usr/src/sys/netinet6/ipcomp6.h Tue Jul 3 07:01:54 2001 --- ./ipcomp6.h Sat May 1 17:32:36 2004 *************** *** 36,45 **** #ifndef _NETINET6_IPCOMP6_H_ #define _NETINET6_IPCOMP6_H_ - #ifdef _KERNEL extern int ipcomp6_input __P((struct mbuf **, int *, int)); ! extern int ipcomp6_output __P((struct mbuf *, u_char *, struct mbuf *, struct ipsecrequest *)); #endif /*KERNEL*/ --- 36,47 ---- #ifndef _NETINET6_IPCOMP6_H_ #define _NETINET6_IPCOMP6_H_ #ifdef _KERNEL + + #include + extern int ipcomp6_input __P((struct mbuf **, int *, int)); ! extern int ipcomp6_output __P((struct ipsec_output_state *, u_char *, struct mbuf *, struct ipsecrequest *)); #endif /*KERNEL*/ diff --exclude CVS -C 3 /usr/src/sys/netinet6/ipcomp_input.c ./ipcomp_input.c *** /usr/src/sys/netinet6/ipcomp_input.c Sun Apr 28 01:40:27 2002 --- ./ipcomp_input.c Sun May 2 21:00:08 2004 *************** *** 107,112 **** --- 107,113 ---- struct secasvar *sav = NULL; int off, proto; va_list ap; + int s; va_start(ap, m); off = va_arg(ap, int); *************** *** 120,125 **** --- 121,162 ---- goto fail; } + /* kfl: + * If we are dealing with a mbuf chain + * (happens when doing ESP over IPComp over a tunnel) we try to pullup + * all in one mbuf before pulling down. Since each protocol + * pulls up we end up here with a mbuf chain made of multiple + * small mbufs (about 20 to 60 bytes each). Although there is + * nothing wrong with it, m_pulldown return a chain where + * m_pkthdr.len is not equal to the sum of all m_len. By doing this + * pullup and the other hack (valid for 2 mbufs only) we get things + * working. + * + * XXX Its probably a good idea to rewrite this kludge into something + * more general. Turn the #if 0 to #if 1 and see that m_pulldown does + * something funky with the chain. + */ + if (m->m_next) { + m = m_pullup(m, m->m_pkthdr.len); + if (!m) { + ipseclog((LOG_DEBUG, "IPv4 IPComp input: too ambitious " + "(pullup failure)\n")); + goto fail; + } + } + #if 0 + { + struct mbuf *n; + int total_len = 0; + for (n=m; n; n=n->m_next) + total_len += n->m_len; + if (m->m_pkthdr.len != total_len) + /* Should never happen */ + printf("before pulldown, len mismatch! m_pkthdr.len:%d total_len:%d\n", + m->m_pkthdr.len, total_len); + } + #endif + md = m_pulldown(m, off, sizeof(*ipcomp), NULL); if (!m) { m = NULL; /* already freed */ *************** *** 128,133 **** --- 165,192 ---- ipsecstat.in_inval++; goto fail; } + #if 0 + { + struct mbuf *n; + int total_len = 0; + for (n=m; n; n=n->m_next) + total_len += n->m_len; + if (m->m_pkthdr.len != total_len) + /* Should never happen */ + printf("after pulldown, len mismatch! m_pkthdr.len:%d total_len:%d\n", + m->m_pkthdr.len, total_len); + } + #endif + /* + * kfl: I think m_pulldown has some problems with m_len, I should look + * into it but this hack (along with the previous one) does the trick for me now. + * XXX WARNING this assumes there is only two mbufs in the + * chain (which is ok for most packets because of the m_pullup and m_pulldown + * being carefull not to split mbufs easily). + */ + if (m->m_next->m_next == 0 && (m->m_pkthdr.len > m->m_len + md->m_len)) + md->m_len = m->m_pkthdr.len - m->m_len; + ipcomp = mtod(md, struct ipcomp *); ip = mtod(m, struct ip *); nxt = ipcomp->comp_nxt; *************** *** 167,173 **** #else ip->ip_len = htons(ntohs(ip->ip_len) - sizeof(struct ipcomp)); #endif - olen = m->m_pkthdr.len; newlen = m->m_pkthdr.len - off; error = (*algo->decompress)(m, m->m_next, &newlen); --- 226,231 ---- *************** *** 181,186 **** --- 239,249 ---- } ipsecstat.in_comphist[cpi]++; + if (newlen < olen) { + ipseclog((LOG_DEBUG, "IPv4 IPComp input: olen > newlen something may be wrong" + " with the mbuf chain\n")); + goto fail; + } /* * returning decompressed packet onto icmp is meaningless. * mark it decrypted to prevent icmp from attaching original packet. *************** *** 215,240 **** ip->ip_p = nxt; } ! if (sav) { ! key_sa_recordxfer(sav, m); ! if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) { ! ipsecstat.in_nomem++; ! goto fail; ! } ! key_freesav(sav); ! sav = NULL; } ! if (nxt != IPPROTO_DONE) { ! if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 && ! ipsec4_in_reject(m, NULL)) { ! ipsecstat.in_polvio++; ! goto fail; ! } ! (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt); ! } else ! m_freem(m); ! m = NULL; ipsecstat.in_success++; return; --- 278,356 ---- ip->ip_p = nxt; } ! /* was it transmitted over the IPsec tunnel */ ! if (ipsec4_tunnel_validate(m, off, nxt, sav)) { ! u_int8_t tos; ! ! tos = ip->ip_tos; ! ! m_adj(m, off); ! if (m->m_len < sizeof(*ip)) { ! m = m_pullup(m, sizeof(*ip)); ! if (!m) { ! ipsecstat.in_inval++; ! goto fail; } + } ! ip = mtod(m, struct ip *); ! /* ! * ECN consideration. ! * XXX Should we do this here? ! */ ! ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos); ! if (!key_checktunnelsanity(sav, AF_INET, ! (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) { ! ipseclog((LOG_ERR, "ipsec tunnel address mismatch " ! "in IPv4 IPComp input: %u %s\n", ! cpi, ipsec_logsastr(sav))); ! ipsecstat.in_inval++; ! goto fail; ! } ! ! key_sa_recordxfer(sav, m); ! if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0 || ! ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) { ! ipsecstat.in_nomem++; ! goto fail; ! } ! s = splimp(); ! if (IF_QFULL(&ipintrq)) { ! ipsecstat.in_inval++; ! splx(s); ! goto fail; ! } ! IF_ENQUEUE(&ipintrq, m); ! m = NULL; ! schednetisr(NETISR_IP); /* can be skipped but to make sure */ ! splx(s); ! nxt = IPPROTO_DONE; ! } else { ! if (sav) { ! key_sa_recordxfer(sav, m); ! if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) { ! ipsecstat.in_nomem++; ! goto fail; ! } ! key_freesav(sav); ! sav = NULL; ! } ! ! if (nxt != IPPROTO_DONE) { ! if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 && ! ipsec4_in_reject(m, NULL)) { ! ipsecstat.in_polvio++; ! goto fail; ! } ! printf("nxt :%d\n", nxt); ! (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt); ! } else ! m_freem(m); ! m = NULL; ! } ! ! if (sav) ! key_freesav(sav); ipsecstat.in_success++; return; diff --exclude CVS -C 3 /usr/src/sys/netinet6/ipcomp_output.c ./ipcomp_output.c *** /usr/src/sys/netinet6/ipcomp_output.c Sun Apr 28 01:40:27 2002 --- ./ipcomp_output.c Sun May 2 17:40:45 2004 *************** *** 81,87 **** #include ! static int ipcomp_output __P((struct mbuf *, u_char *, struct mbuf *, struct ipsecrequest *, int)); /* --- 81,87 ---- #include ! static int ipcomp_output __P((struct ipsec_output_state *, u_char *, struct mbuf *, struct ipsecrequest *, int)); /* *************** *** 103,118 **** * <-----------------> compoff */ static int ! ipcomp_output(m, nexthdrp, md, isr, af) ! struct mbuf *m; u_char *nexthdrp; struct mbuf *md; struct ipsecrequest *isr; int af; { struct mbuf *n; ! struct mbuf *md0; ! struct mbuf *mcopy; struct mbuf *mprev; struct ipcomp *ipcomp; struct secasvar *sav = isr->sav; --- 103,119 ---- * <-----------------> compoff */ static int ! ipcomp_output(state, nexthdrp, md, isr, af) ! struct ipsec_output_state *state; u_char *nexthdrp; struct mbuf *md; struct ipsecrequest *isr; int af; { struct mbuf *n; ! struct mbuf *m = state->m; ! struct mbuf *md0 = 0; ! struct mbuf *mcopy = 0; struct mbuf *mprev; struct ipcomp *ipcomp; struct secasvar *sav = isr->sav; *************** *** 171,186 **** * compromise two m_copym(). we will be going through every byte of * the payload during compression process anyways. */ ! mcopy = m_copym(m, 0, M_COPYALL, M_NOWAIT); ! if (mcopy == NULL) { ! error = ENOBUFS; ! return 0; ! } ! md0 = m_copym(md, 0, M_COPYALL, M_NOWAIT); ! if (md0 == NULL) { ! m_freem(mcopy); ! error = ENOBUFS; ! return 0; } plen0 = plen; --- 172,194 ---- * compromise two m_copym(). we will be going through every byte of * the payload during compression process anyways. */ ! /* kfl: ! * In tunnel mode, we already have a copy. ! * XXX We save one m_copym in tunnel mode and I ! * beleive we should be able in transport mode as well. ! */ ! if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) { ! mcopy = m_copym(m, 0, M_COPYALL, M_NOWAIT); ! if (mcopy == NULL) { ! error = ENOBUFS; ! return 0; ! } ! md0 = m_copym(md, 0, M_COPYALL, M_NOWAIT); ! if (md0 == NULL) { ! m_freem(mcopy); ! error = ENOBUFS; ! return 0; ! } } plen0 = plen; *************** *** 296,302 **** m->m_pkthdr.len += complen; ipcomp = mtod(md, struct ipcomp *); } - bzero(ipcomp, sizeof(*ipcomp)); ipcomp->comp_nxt = *nexthdrp; *nexthdrp = IPPROTO_IPCOMP; --- 304,309 ---- *************** *** 304,310 **** switch (af) { #ifdef INET case AF_INET: ! if (compoff + complen + plen < IP_MAXPACKET) ip->ip_len = htons(compoff + complen + plen); else { ipseclog((LOG_ERR, --- 311,317 ---- switch (af) { #ifdef INET case AF_INET: ! if (compoff + complen + plen < IP_MAXPACKET) ip->ip_len = htons(compoff + complen + plen); else { ipseclog((LOG_ERR, *************** *** 333,341 **** stat->out_success++; /* compute byte lifetime against original packet */ ! key_sa_recordxfer(sav, mcopy); ! m_freem(mcopy); ! return 0; fail: --- 340,354 ---- stat->out_success++; /* compute byte lifetime against original packet */ ! if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { ! key_sa_recordxfer(sav, state->mcopy); ! m_freem(state->mcopy); ! state->mcopy = NULL; ! } ! else { ! key_sa_recordxfer(sav, mcopy); ! m_freem(mcopy); ! } return 0; fail: *************** *** 348,357 **** #ifdef INET int ! ipcomp4_output(m, isr) ! struct mbuf *m; struct ipsecrequest *isr; { struct ip *ip; if (m->m_len < sizeof(struct ip)) { ipseclog((LOG_DEBUG, "ipcomp4_output: first mbuf too short\n")); --- 361,371 ---- #ifdef INET int ! ipcomp4_output(state, isr) ! struct ipsec_output_state *state; struct ipsecrequest *isr; { + struct mbuf *m = state->m; struct ip *ip; if (m->m_len < sizeof(struct ip)) { ipseclog((LOG_DEBUG, "ipcomp4_output: first mbuf too short\n")); *************** *** 361,384 **** } ip = mtod(m, struct ip *); /* XXX assumes that m->m_next points to payload */ ! return ipcomp_output(m, &ip->ip_p, m->m_next, isr, AF_INET); } #endif /* INET */ #ifdef INET6 int ! ipcomp6_output(m, nexthdrp, md, isr) ! struct mbuf *m; u_char *nexthdrp; struct mbuf *md; struct ipsecrequest *isr; { if (m->m_len < sizeof(struct ip6_hdr)) { ipseclog((LOG_DEBUG, "ipcomp6_output: first mbuf too short\n")); ipsec6stat.out_inval++; m_freem(m); return 0; } ! return ipcomp_output(m, nexthdrp, md, isr, AF_INET6); } #endif /* INET6 */ --- 375,399 ---- } ip = mtod(m, struct ip *); /* XXX assumes that m->m_next points to payload */ ! return ipcomp_output(state, &ip->ip_p, m->m_next, isr, AF_INET); } #endif /* INET */ #ifdef INET6 int ! ipcomp6_output(state, nexthdrp, md, isr) ! struct ipsec_output_state *state; u_char *nexthdrp; struct mbuf *md; struct ipsecrequest *isr; { + struct mbuf *m = state->m; if (m->m_len < sizeof(struct ip6_hdr)) { ipseclog((LOG_DEBUG, "ipcomp6_output: first mbuf too short\n")); ipsec6stat.out_inval++; m_freem(m); return 0; } ! return ipcomp_output(state, nexthdrp, md, isr, AF_INET6); } #endif /* INET6 */ diff --exclude CVS -C 3 /usr/src/sys/netinet6/ipsec.c ./ipsec.c *** /usr/src/sys/netinet6/ipsec.c Thu Jan 23 16:06:47 2003 --- ./ipsec.c Sat May 1 17:30:28 2004 *************** *** 2575,2580 **** --- 2575,2590 ---- s = splnet(); if (isr->saidx.mode == IPSEC_MODE_TUNNEL) { + /* + * Make a copy in case we cannot compress the packet in IPComp. + */ + if (isr->saidx.proto == IPPROTO_IPCOMP) { + state->mcopy = m_copym(state->m, 0, M_COPYALL, M_NOWAIT); + if (state->mcopy == NULL) { + error = ENOBUFS; + goto bad; + } + } /* * build IPsec tunnel. */ *************** *** 2657,2665 **** } break; case IPPROTO_IPCOMP: ! if ((error = ipcomp4_output(state->m, isr)) != 0) { state->m = NULL; ! goto bad; } break; default: --- 2667,2681 ---- } break; case IPPROTO_IPCOMP: ! if ((error = ipcomp4_output(state, isr)) != 0) { ! m_freem(state->mcopy); state->m = NULL; ! goto bad; ! } ! /* If we still have a copy, use it. */ ! else if (state->mcopy) { ! m_freem(state->m); ! state->m = state->mcopy; } break; default: *************** *** 2824,2830 **** error = ah6_output(state->m, nexthdrp, mprev->m_next, isr); break; case IPPROTO_IPCOMP: ! error = ipcomp6_output(state->m, nexthdrp, mprev->m_next, isr); break; default: ipseclog((LOG_ERR, "ipsec6_output_trans: " --- 2840,2846 ---- error = ah6_output(state->m, nexthdrp, mprev->m_next, isr); break; case IPPROTO_IPCOMP: ! error = ipcomp6_output(state, nexthdrp, mprev->m_next, isr); break; default: ipseclog((LOG_ERR, "ipsec6_output_trans: " *************** *** 2986,2991 **** --- 3002,3017 ---- /* * build IPsec tunnel. */ + /* + * Make a copy in case we cannot compress the packet in IPComp. + */ + if (isr->saidx.proto == IPPROTO_IPCOMP) { + state->mcopy = m_copym(state->m, 0, M_COPYALL, M_NOWAIT); + if (state->mcopy == NULL) { + error = ENOBUFS; + goto bad; + } + } /* XXX should be processed with other familiy */ if (((struct sockaddr *)&isr->sav->sah->saidx.src)->sa_family != AF_INET6) { ipseclog((LOG_ERR, "ipsec6_output_tunnel: " diff --exclude CVS -C 3 /usr/src/sys/netinet6/ipsec.h ./ipsec.h *** /usr/src/sys/netinet6/ipsec.h Thu Jan 23 16:06:47 2003 --- ./ipsec.h Sat May 1 17:19:12 2004 *************** *** 272,277 **** --- 272,278 ---- #ifdef _KERNEL struct ipsec_output_state { struct mbuf *m; + struct mbuf *mcopy; struct route *ro; struct sockaddr *dst; };