X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..eee3565979933af707c711411001ba11fe406a3c:/bsd/netinet6/ipcomp_input.c diff --git a/bsd/netinet6/ipcomp_input.c b/bsd/netinet6/ipcomp_input.c index 43039d9c7..c3b330305 100644 --- a/bsd/netinet6/ipcomp_input.c +++ b/bsd/netinet6/ipcomp_input.c @@ -1,4 +1,5 @@ -/* $KAME: ipcomp_input.c,v 1.11 2000/02/22 14:04:23 itojun Exp $ */ +/* $FreeBSD: src/sys/netinet6/ipcomp_input.c,v 1.1.2.2 2001/07/03 11:01:54 ume Exp $ */ +/* $KAME: ipcomp_input.c,v 1.25 2001/03/01 09:12:09 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. @@ -33,15 +34,12 @@ * RFC2393 IP payload compression protocol (IPComp). */ -#define _IP_VHL -#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) -#include "opt_inet.h" -#endif #include #include #include #include +#include #include #include #include @@ -52,9 +50,9 @@ #include #include -#include -#include +#include #include +#include #include #include @@ -62,35 +60,36 @@ #include #include #include +#include #if INET6 #include #include #endif #include +#if INET6 +#include +#endif #include +#if INET6 +#include +#endif #include #include -#include #include +#include #define IPLEN_FLIPPED - -#if INET -extern struct protosw * ip_protox[]; -#if defined(__bsdi__) || defined(__NetBSD__) -extern u_char ip_protox[]; -#endif - void ipcomp4_input(struct mbuf *m, int off) { + struct mbuf *md; struct ip *ip; struct ipcomp *ipcomp; - struct ipcomp_algorithm *algo; + const struct ipcomp_algorithm *algo; u_int16_t cpi; /* host order */ u_int16_t nxt; size_t hlen; @@ -98,43 +97,27 @@ ipcomp4_input(struct mbuf *m, int off) size_t newlen, olen; struct secasvar *sav = NULL; - - if (off + sizeof(struct ipcomp) > MHLEN) { - /*XXX the restriction should be relaxed*/ + if (m->m_pkthdr.len < off + sizeof(struct ipcomp)) { ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed " - "(header too long)\n")); - ipsecstat.in_inval++; + "(packet too short)\n")); + IPSEC_STAT_INCREMENT(ipsecstat.in_inval); goto fail; } - if (m->m_len < off + sizeof(struct ipcomp)) { - m = m_pullup(m, off + sizeof(struct ipcomp)); - if (!m) { - ipseclog((LOG_DEBUG, "IPv4 IPComp input: can't pullup;" - "dropping the packet for simplicity\n")); - ipsecstat.in_nomem++; - goto fail; - } - } else if (m->m_len > off + sizeof(struct ipcomp)) { - /* chop header part from the packet header chain */ - struct mbuf *n; - MGETHDR(n, M_DONTWAIT, MT_HEADER); - if (!n) { - ipsecstat.in_nomem++; - goto fail; - } - M_COPY_PKTHDR(n, m); - MH_ALIGN(n, off + sizeof(struct ipcomp)); - n->m_len = off + sizeof(struct ipcomp); - bcopy(mtod(m, caddr_t), mtod(n, caddr_t), - off + sizeof(struct ipcomp)); - m_adj(m, off + sizeof(struct ipcomp)); - m->m_flags &= ~M_PKTHDR; - n->m_next = m; - m = n; + + md = m_pulldown(m, off, sizeof(*ipcomp), NULL); + if (!md) { + m = NULL; /*already freed*/ + ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed " + "(pulldown failure)\n")); + IPSEC_STAT_INCREMENT(ipsecstat.in_inval); + goto fail; } + ipcomp = mtod(md, struct ipcomp *); + + /* Expect 32-bit aligned data pointer on strict-align platforms */ + MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m); ip = mtod(m, struct ip *); - ipcomp = (struct ipcomp *)(((caddr_t)ip) + off); nxt = ipcomp->comp_nxt; #ifdef _IP_VHL hlen = IP_VHL_HL(ip->ip_vhl) << 2; @@ -154,20 +137,18 @@ ipcomp4_input(struct mbuf *m, int off) /* other parameters to look at? */ } } - if (cpi < IPCOMP_MAX && ipcomp_algorithms[cpi].decompress != NULL) - algo = &ipcomp_algorithms[cpi]; - else - algo = NULL; + algo = ipcomp_algorithm_lookup(cpi); if (!algo) { ipseclog((LOG_WARNING, "IPv4 IPComp input: unknown cpi %u\n", cpi)); - ipsecstat.in_nosa++; + IPSEC_STAT_INCREMENT(ipsecstat.in_nosa); goto fail; } /* chop ipcomp header */ ipcomp = NULL; - m->m_len -= sizeof(struct ipcomp); + md->m_data += sizeof(struct ipcomp); + md->m_len -= sizeof(struct ipcomp); m->m_pkthdr.len -= sizeof(struct ipcomp); #ifdef IPLEN_FLIPPED ip->ip_len -= sizeof(struct ipcomp); @@ -179,14 +160,14 @@ ipcomp4_input(struct mbuf *m, int off) newlen = m->m_pkthdr.len - off; error = (*algo->decompress)(m, m->m_next, &newlen); if (error != 0) { - if (error == EINVAL) - ipsecstat.in_inval++; - else if (error == ENOBUFS) - ipsecstat.in_nomem++; + if (error == EINVAL) { + IPSEC_STAT_INCREMENT(ipsecstat.in_inval); + } else if (error == ENOBUFS) + IPSEC_STAT_INCREMENT(ipsecstat.in_nomem); m = NULL; goto fail; } - ipsecstat.in_comphist[cpi]++; + IPSEC_STAT_INCREMENT(ipsecstat.in_comphist[cpi]); /* * returning decompressed packet onto icmp is meaningless. @@ -211,7 +192,7 @@ ipcomp4_input(struct mbuf *m, int off) len -= olen; if (len & ~0xffff) { /* packet too big after decompress */ - ipsecstat.in_inval++; + IPSEC_STAT_INCREMENT(ipsecstat.in_inval); goto fail; } #ifdef IPLEN_FLIPPED @@ -224,97 +205,78 @@ ipcomp4_input(struct mbuf *m, int off) if (sav) { key_sa_recordxfer(sav, m); - key_freesav(sav); + if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) { + IPSEC_STAT_INCREMENT(ipsecstat.in_nomem); + goto fail; + } + key_freesav(sav, KEY_SADB_UNLOCKED); sav = NULL; } - if (nxt != IPPROTO_DONE) - (*ip_protox[nxt]->pr_input)(m, off); - else + if (nxt != IPPROTO_DONE) { + if ((ip_protox[nxt]->pr_flags & PR_LASTHDR) != 0 && + ipsec4_in_reject(m, NULL)) { + IPSEC_STAT_INCREMENT(ipsecstat.in_polvio); + goto fail; + } + + DTRACE_IP6(receive, struct mbuf *, m, struct inpcb *, NULL, + struct ip *, ip, struct ifnet *, m->m_pkthdr.rcvif, + struct ip *, ip, struct ip6_hdr *, NULL); + + ip_proto_dispatch_in(m, off, nxt, 0); + } else m_freem(m); m = NULL; - ipsecstat.in_success++; + IPSEC_STAT_INCREMENT(ipsecstat.in_success); return; fail: if (sav) - key_freesav(sav); + key_freesav(sav, KEY_SADB_UNLOCKED); + if (m) m_freem(m); return; } -#endif /* INET */ #if INET6 int -ipcomp6_input(mp, offp) - struct mbuf **mp; - int *offp; +ipcomp6_input(struct mbuf **mp, int *offp, int proto) { +#pragma unused(proto) struct mbuf *m, *md; int off; struct ip6_hdr *ip6; - struct mbuf *ipcompm; struct ipcomp *ipcomp; - struct ipcomp_algorithm *algo; + const struct ipcomp_algorithm *algo; u_int16_t cpi; /* host order */ u_int16_t nxt; int error; size_t newlen; struct secasvar *sav = NULL; + char *prvnxtp; m = *mp; off = *offp; - IP6_EXTHDR_CHECK(m, off, sizeof(struct ipcomp), IPPROTO_DONE); - - { - int skip; - struct mbuf *n; - struct mbuf *p, *q; - size_t l; - - skip = off; - for (n = m; n && skip > 0; n = n->m_next) { - if (n->m_len <= skip) { - skip -= n->m_len; - continue; - } - break; - } - if (!n) { - ipseclog((LOG_DEBUG, "IPv6 IPComp input: wrong mbuf chain\n")); - ipsecstat.in_inval++; - goto fail; - } - if (n->m_len < skip + sizeof(struct ipcomp)) { - ipseclog((LOG_DEBUG, "IPv6 IPComp input: wrong mbuf chain\n")); - ipsecstat.in_inval++; + md = m_pulldown(m, off, sizeof(*ipcomp), NULL); + if (!md) { + m = NULL; /*already freed*/ + ipseclog((LOG_DEBUG, "IPv6 IPComp input: assumption failed " + "(pulldown failure)\n")); + IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); goto fail; } - ip6 = mtod(m, struct ip6_hdr *); - ipcompm = n; - ipcomp = (struct ipcomp *)(mtod(n, caddr_t) + skip); - if (n->m_len > skip + sizeof(struct ipcomp)) { - /* split mbuf to ease the following steps*/ - l = n->m_len - (skip + sizeof(struct ipcomp)); - p = m_copym(n, skip + sizeof(struct ipcomp), l , M_DONTWAIT); - if (!p) { - ipsecstat.in_nomem++; - goto fail; - } - for (q = p; q && q->m_next; q = q->m_next) - ; - q->m_next = n->m_next; - n->m_next = p; - n->m_len -= l; - md = p; - } else - md = n->m_next; - } + ipcomp = mtod(md, struct ipcomp *); + /* Expect 32-bit aligned data pointer on strict-align platforms */ + MBUF_STRICT_DATA_ALIGNMENT_CHECK_32(m); + + ip6 = mtod(m, struct ip6_hdr *); nxt = ipcomp->comp_nxt; + cpi = ntohs(ipcomp->comp_cpi); if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) { @@ -327,29 +289,32 @@ ipcomp6_input(mp, offp) /* other parameters to look at? */ } } - if (cpi < IPCOMP_MAX && ipcomp_algorithms[cpi].decompress != NULL) - algo = &ipcomp_algorithms[cpi]; - else - algo = NULL; + algo = ipcomp_algorithm_lookup(cpi); if (!algo) { ipseclog((LOG_WARNING, "IPv6 IPComp input: unknown cpi %u; " "dropping the packet for simplicity\n", cpi)); - ipsec6stat.in_nosa++; + IPSEC_STAT_INCREMENT(ipsec6stat.in_nosa); goto fail; } - newlen = m->m_pkthdr.len - off - sizeof(struct ipcomp); + /* chop ipcomp header */ + ipcomp = NULL; + md->m_data += sizeof(struct ipcomp); + md->m_len -= sizeof(struct ipcomp); + m->m_pkthdr.len -= sizeof(struct ipcomp); + + newlen = m->m_pkthdr.len - off; error = (*algo->decompress)(m, md, &newlen); if (error != 0) { - if (error == EINVAL) - ipsec6stat.in_inval++; - else if (error == ENOBUFS) - ipsec6stat.in_nomem++; + if (error == EINVAL) { + IPSEC_STAT_INCREMENT(ipsec6stat.in_inval); + } else if (error == ENOBUFS) + IPSEC_STAT_INCREMENT(ipsec6stat.in_nomem); m = NULL; goto fail; } - ipsec6stat.in_comphist[cpi]++; - m->m_pkthdr.len = off + sizeof(struct ipcomp) + newlen; + IPSEC_STAT_INCREMENT(ipsec6stat.in_comphist[cpi]); + m->m_pkthdr.len = off + newlen; /* * returning decompressed packet onto icmp is meaningless. @@ -357,38 +322,34 @@ ipcomp6_input(mp, offp) */ m->m_flags |= M_DECRYPTED; - { - char *prvnxtp; - - /* chop IPComp header */ + /* update next header field */ prvnxtp = ip6_get_prevhdr(m, off); *prvnxtp = nxt; - ipcompm->m_len -= sizeof(struct ipcomp); - ipcompm->m_pkthdr.len -= sizeof(struct ipcomp); - /* adjust payload length */ - ip6 = mtod(m, struct ip6_hdr *); - if (((m->m_pkthdr.len - sizeof(struct ip6_hdr)) & ~0xffff) != 0) - ip6->ip6_plen = 0; /*now a jumbogram*/ - else - ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); - } + /* + * no need to adjust payload length, as all the IPv6 protocols + * look at m->m_pkthdr.len + */ if (sav) { key_sa_recordxfer(sav, m); - key_freesav(sav); + if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) { + IPSEC_STAT_INCREMENT(ipsec6stat.in_nomem); + goto fail; + } + key_freesav(sav, KEY_SADB_UNLOCKED); sav = NULL; } *offp = off; *mp = m; - ipsec6stat.in_success++; + IPSEC_STAT_INCREMENT(ipsec6stat.in_success); return nxt; fail: if (m) m_freem(m); if (sav) - key_freesav(sav); + key_freesav(sav, KEY_SADB_UNLOCKED); return IPPROTO_DONE; } #endif /* INET6 */