$NetBSD: patch-aa,v 1.3 2005/04/29 11:41:29 cube Exp $ --- ppp_mppe_compress.c.orig 2004-05-31 07:31:51.000000000 +0200 +++ ppp_mppe_compress.c @@ -5,6 +5,8 @@ * By Frank Cusack . * Copyright (c) 2002,2003,2004 Google, Inc. * All rights reserved. + * Copyright (c) 1999 Darrin B. Jewell + * Copyright (c) 2004, 2005 Quentin Garnier * * Permission to use, copy, modify, and distribute this software and its * documentation is hereby granted, provided that the above copyright @@ -18,19 +20,35 @@ * deprecated in 2.6 */ -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include + +#define PACKETPTR struct mbuf * + +#include +#include + +#include +#include + +#if __NetBSD_Version__ < 299001600 +/* MPPE definitions were included into the kernel source */ +#include "ppp-comp-local.h" +#endif -#include -#include +int mppe_in_use; +#define MOD_INC_USE_COUNT mppe_in_use++ +#define MOD_DEC_USE_COUNT mppe_in_use-- -#include "arcfour.h" -#include "sha1.h" +#ifdef MPPE_DEBUG +#define DPRINTF(x) aprint_normal x +#else +#define DPRINTF(x) +#endif /* * State for an MPPE (de)compressor. @@ -38,8 +56,8 @@ typedef struct ppp_mppe_state { unsigned char master_key[MPPE_MAX_KEY_LEN]; unsigned char session_key[MPPE_MAX_KEY_LEN]; - arcfour_context arcfour_context; /* encryption state */ - unsigned keylen; /* key length in bytes */ + void *arcfour_context; /* encryption state */ + unsigned keylen; /* key length in bytes */ /* NB: 128-bit == 16, 40-bit == 8! */ /* If we want to support 56-bit, */ /* the unit has to change to bits */ @@ -84,12 +102,12 @@ static int mppe_comp_init __P((void *sta static int mppe_decomp_init __P((void *state, unsigned char *options, int optlen, int unit, int hdrlen, int mru, int debug)); -static int mppe_compress __P((void *state, unsigned char *ibuf, - unsigned char *obuf, +static int mppe_compress __P((void *state, struct mbuf **opkt, + struct mbuf *ipkt, int isize, int osize)); -static void mppe_incomp __P((void *state, unsigned char *ibuf, int icnt)); -static int mppe_decompress __P((void *state, unsigned char *ibuf, - int isize, unsigned char *obuf,int osize)); +static void mppe_incomp __P((void *state, struct mbuf *mp)); +static int mppe_decompress __P((void *state, struct mbuf *ipkt, + struct mbuf **opkt)); static void mppe_comp_reset __P((void *state)); static void mppe_decomp_reset __P((void *state)); static void mppe_comp_stats __P((void *state, struct compstat *stats)); @@ -104,7 +122,7 @@ GetNewKeyFromSHA(unsigned char *MasterKe unsigned SessionKeyLength, unsigned char *InterimKey) { SHA1_CTX Context; - unsigned char Digest[SHA1_SIGNATURE_SIZE]; + unsigned char Digest[20]; unsigned char SHApad1[40] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -119,12 +137,12 @@ GetNewKeyFromSHA(unsigned char *MasterKe /* assert(SessionKeyLength <= SHA1_SIGNATURE_SIZE); */ - SHA1_Init(&Context); - SHA1_Update(&Context, MasterKey, SessionKeyLength); - SHA1_Update(&Context, SHApad1, sizeof(SHApad1)); - SHA1_Update(&Context, SessionKey, SessionKeyLength); - SHA1_Update(&Context, SHApad2, sizeof(SHApad2)); - SHA1_Final(Digest, &Context); + SHA1Init(&Context); + SHA1Update(&Context, MasterKey, SessionKeyLength); + SHA1Update(&Context, SHApad1, sizeof(SHApad1)); + SHA1Update(&Context, SessionKey, SessionKeyLength); + SHA1Update(&Context, SHApad2, sizeof(SHApad2)); + SHA1Final(Digest, &Context); memcpy(InterimKey, Digest, SessionKeyLength); } @@ -141,9 +159,9 @@ mppe_rekey(ppp_mppe_state *state, int in GetNewKeyFromSHA(state->master_key, state->session_key, state->keylen, InterimKey); if (!initial_key) { - arcfour_setkey(&state->arcfour_context, InterimKey, state->keylen); - arcfour_encrypt(&state->arcfour_context, InterimKey, state->keylen, - state->session_key); + arc4_setkey(state->arcfour_context, InterimKey, state->keylen); + arc4_encrypt(state->arcfour_context, state->session_key, InterimKey, + state->keylen); } else { memcpy(state->session_key, InterimKey, state->keylen); } @@ -153,7 +171,7 @@ mppe_rekey(ppp_mppe_state *state, int in state->session_key[1] = 0x26; state->session_key[2] = 0x9e; } - arcfour_setkey(&state->arcfour_context, state->session_key, state->keylen); + arc4_setkey(state->arcfour_context, state->session_key, state->keylen); } @@ -170,15 +188,12 @@ mppe_alloc(unsigned char *options, int o || options[1] != CILEN_MPPE) return NULL; - state = (ppp_mppe_state *) kmalloc(sizeof(*state), GFP_KERNEL); + state = (ppp_mppe_state *) malloc(sizeof(*state), M_DEVBUF, M_NOWAIT); if (state == NULL) return NULL; + state->arcfour_context = NULL; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) - try_module_get(THIS_MODULE); -#else MOD_INC_USE_COUNT; -#endif memset(state, 0, sizeof(*state)); /* Save keys. */ @@ -201,12 +216,10 @@ mppe_free(void *arg) ppp_mppe_state *state = (ppp_mppe_state *) arg; if (state) { - kfree(state); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) - module_put(THIS_MODULE); -#else + if (state->arcfour_context) + free(state->arcfour_context, M_DEVBUF); + free(state, M_DEVBUF); MOD_DEC_USE_COUNT; -#endif } } @@ -232,12 +245,16 @@ mppe_init(void *arg, unsigned char *opti else if (mppe_opts & MPPE_OPT_40) state->keylen = 8; else { - printk(KERN_WARNING "%s[%d]: unknown key length\n", debugstr, unit); + aprint_error("%s[%d]: unknown key length\n", debugstr, unit); return 0; } if (mppe_opts & MPPE_OPT_STATEFUL) state->stateful = 1; + state->arcfour_context = malloc(arc4_ctxlen(), M_DEVBUF, M_NOWAIT); + if (state->arcfour_context == NULL) + return 0; + /* Generate the initial session key. */ mppe_rekey(state, 1); @@ -246,7 +263,7 @@ mppe_init(void *arg, unsigned char *opti char mkey[sizeof(state->master_key) * 2 + 1]; char skey[sizeof(state->session_key) * 2 + 1]; - printk(KERN_DEBUG "%s[%d]: initialized with %d-bit %s mode\n", debugstr, + aprint_normal("%s[%d]: initialized with %d-bit %s mode\n", debugstr, unit, (state->keylen == 16)? 128: 40, (state->stateful)? "stateful": "stateless"); @@ -254,7 +271,7 @@ mppe_init(void *arg, unsigned char *opti sprintf(mkey + i * 2, "%.2x", state->master_key[i]); for (i = 0; i < sizeof(state->session_key); i++) sprintf(skey + i * 2, "%.2x", state->session_key[i]); - printk(KERN_DEBUG "%s[%d]: keys: master: %s initial session: %s\n", + aprint_normal("%s[%d]: keys: master: %s initial session: %s\n", debugstr, unit, mkey, skey); } @@ -311,30 +328,75 @@ mppe_comp_reset(void *arg) * MPPE_OVHD + 2 bytes larger than the input. */ int -mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf, +mppe_compress(void *arg, struct mbuf **mret, struct mbuf *mp, int isize, int osize) { ppp_mppe_state *state = (ppp_mppe_state *) arg; int proto; + unsigned char *ibuf, *obuf; + *mret = NULL; + ibuf = mtod(mp, unsigned char *); /* * Check that the protocol is in the range we handle. */ proto = PPP_PROTOCOL(ibuf); - if (proto < 0x0021 || proto > 0x00fa) + if (proto < 0x0021 || proto > 0x00fa) { + DPRINTF(("unhandled proto %d\n", proto)); return 0; + } /* Make sure we have enough room to generate an encrypted packet. */ - if (osize < isize + MPPE_OVHD + 2) { + /* XXX */ + if (osize + MPPE_OVHD < isize + MPPE_OVHD) { /* Drop the packet if we should encrypt it, but can't. */ - printk(KERN_DEBUG "mppe_compress[%d]: osize too small! " + aprint_normal("mppe_compress[%d]: osize too small! " "(have: %d need: %d)\n", state->unit, - osize, osize + MPPE_OVHD + 2); - return -1; + osize, isize + MPPE_OVHD + 2); + /* XXX */ + return 0; } osize = isize + MPPE_OVHD + 2; + /* Allocate an mbuf chain to hold the encrypted packet */ + { + struct mbuf *mfirst = NULL; + struct mbuf *mprev; + struct mbuf *m = NULL; + int bleft = isize+MPPE_OVHD+2; + do { + mprev = m; + MGET(m,M_DONTWAIT, MT_DATA); + if (m == NULL) { + m_freem(mfirst); + /* XXX: what should we do here? If we return NULL, the data + * will go out unencrypted. We can't use M_WAITOK, since this + * will be called from splsoftnet() + */ + panic("ppp%d/mppe: unable to allocate mbuf to encrypt packet", + state->unit); + } + m->m_len = 0; + if (mfirst == NULL) { + mfirst = m; + M_COPY_PKTHDR(m,mp); + if (bleft > MHLEN) { + MCLGET(m, M_DONTWAIT); + } + } else { + mprev->m_next = m; + if (bleft > MLEN) { + MCLGET(m, M_DONTWAIT); + } + } + bleft -= M_TRAILINGSPACE(m); + } while (bleft > 0); + *mret = mfirst; + } + + obuf = mtod(*mret, unsigned char *); + /* * Copy over the PPP header and set control bits. */ @@ -346,7 +408,7 @@ mppe_compress(void *arg, unsigned char * state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE; if (state->debug >= 7) - printk(KERN_DEBUG "mppe_compress[%d]: ccount %d\n", state->unit, + aprint_verbose("mppe_compress[%d]: ccount %d\n", state->unit, state->ccount); obuf[0] = state->ccount >> 8; obuf[1] = state->ccount & 0xff; @@ -356,19 +418,62 @@ mppe_compress(void *arg, unsigned char * (state->bits & MPPE_BIT_FLUSHED)) { /* CCP Reset-Request */ /* We must rekey */ if (state->debug && state->stateful) - printk(KERN_DEBUG "mppe_compress[%d]: rekeying\n", state->unit); + aprint_verbose("mppe_compress[%d]: rekeying\n", state->unit); mppe_rekey(state, 0); state->bits |= MPPE_BIT_FLUSHED; } obuf[0] |= state->bits; state->bits &= ~MPPE_BIT_FLUSHED; /* reset for next xmit */ - obuf += MPPE_OVHD; ibuf += 2; /* skip to proto field */ isize -= 2; + (*mret)->m_len += PPP_HDRLEN + MPPE_OVHD; - /* Encrypt packet */ - arcfour_encrypt(&state->arcfour_context, ibuf, isize, obuf); + /* March down input and output mbuf chains, encoding with RC4 */ + { + struct mbuf *mi = mp; /* mbuf in */ + struct mbuf *mo = *mret; /* mbuf out */ + int maxi, maxo; + maxi = mi->m_len-2; + maxo = M_TRAILINGSPACE(mo); + while (mi) { + if (maxi < maxo) { + arc4_encrypt(state->arcfour_context, + mtod(mo,unsigned char *)+mo->m_len, + mtod(mi,unsigned char *)+mi->m_len-maxi, + maxi); + mo->m_len += maxi; + maxo -= maxi; + mi = mi->m_next; + if (mi) { + maxi = mi->m_len; + } + } else if (maxi > maxo) { + arc4_encrypt(state->arcfour_context, + mtod(mo,unsigned char *)+mo->m_len, + mtod(mi,unsigned char *)+mi->m_len-maxi, + maxo); + mo->m_len += maxo; + maxi -= maxo; + mo = mo->m_next; + if (mo) { + maxo = M_TRAILINGSPACE(mo); + } + } else { + arc4_encrypt(state->arcfour_context, + mtod(mo,unsigned char *)+mo->m_len, + mtod(mi,unsigned char *)+mi->m_len-maxi, + maxi); + mo->m_len += maxi; + mi = mi->m_next; + mo = mo->m_next; + if (mi) { + maxi = mi->m_len; + maxo = M_TRAILINGSPACE(mo); + } + } + } + } state->stats.unc_bytes += isize; state->stats.unc_packets++; @@ -413,56 +518,50 @@ mppe_decomp_reset(void *arg) * Decompress (decrypt) an MPPE packet. */ int -mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf, - int osize) +mppe_decompress(void *arg, struct mbuf *mp, struct mbuf **mret) { ppp_mppe_state *state = (ppp_mppe_state *) arg; unsigned ccount; - int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED; - int sanity = 0; + int flushed; + int sanity = 0, isize; + unsigned char *ibuf, *obuf; - if (isize <= PPP_HDRLEN + MPPE_OVHD) { - if (state->debug) - printk(KERN_DEBUG "mppe_decompress[%d]: short pkt (%d)\n", - state->unit, isize); + if (!mp) { + DPRINTF(("ppp%d/mppe: null input packet\n",state->unit)); return DECOMP_ERROR; } - /* - * Make sure we have enough room to decrypt the packet. - * Note that for our test we only subtract 1 byte whereas in - * mppe_compress() we added 2 bytes (+MPPE_OVHD); - * this is to account for possible PFC. - */ - if (osize < isize - MPPE_OVHD - 1) { - printk(KERN_DEBUG "mppe_decompress[%d]: osize too small! " - "(have: %d need: %d)\n", state->unit, - osize, isize - MPPE_OVHD - 1); + if (mp->m_len <= PPP_HDRLEN + MPPE_OVHD) { + if (state->debug) + aprint_error("mppe_decompress[%d]: short pkt (%d)\n", + state->unit, mp->m_len); return DECOMP_ERROR; } - osize = isize - MPPE_OVHD - 2; /* assume no PFC */ + + ibuf = mtod(mp,unsigned char *); + flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED; ccount = MPPE_CCOUNT(ibuf); if (state->debug >= 7) - printk(KERN_DEBUG "mppe_decompress[%d]: ccount %d\n", state->unit, + aprint_error("mppe_decompress[%d]: ccount %d\n", state->unit, ccount); /* sanity checks -- terminate with extreme prejudice */ if (!(MPPE_BITS(ibuf) & MPPE_BIT_ENCRYPTED)) { - printk(KERN_DEBUG "mppe_decompress[%d]: ENCRYPTED bit not set!\n", - state->unit); + DPRINTF(("mppe_decompress[%d]: ENCRYPTED bit not set!\n", + state->unit)); state->sanity_errors += 100; sanity = 1; } if (!state->stateful && !flushed) { - printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set in " - "stateless mode!\n", state->unit); + DPRINTF(("mppe_decompress[%d]: FLUSHED bit not set in " + "stateless mode!\n", state->unit)); state->sanity_errors += 100; sanity = 1; } if (state->stateful && ((ccount & 0xff) == 0xff) && !flushed) { - printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set on " - "flag packet!\n", state->unit); + DPRINTF(("mppe_decompress[%d]: FLUSHED bit not set on " + "flag packet!\n", state->unit)); state->sanity_errors += 100; sanity = 1; } @@ -531,6 +630,46 @@ mppe_decompress(void *arg, unsigned char mppe_rekey(state, 0); } + /* Allocate an mbuf chain to hold the decrypted packet */ + { + struct mbuf *mfirst = 0; + struct mbuf *mprev; + struct mbuf *m = 0; + int bleft; + isize = 0; + for (m=mp; m; m= m->m_next) isize += m->m_len; + bleft = isize-MPPE_OVHD; + do { + mprev = m; + MGET(m,M_DONTWAIT, MT_DATA); + if (m == NULL) { + m_freem(mfirst); +#ifdef DEBUG + aprint_error("ppp%d/mppe: unable to allocate mbuf to decrypt packet\n", + state->unit); +#endif + return DECOMP_ERROR; + } + m->m_len = 0; + if (mfirst == NULL) { + mfirst=m; + M_COPY_PKTHDR(m,mp); + if (bleft > MHLEN) { + MCLGET(m, M_DONTWAIT); + } + } else { + mprev->m_next = m; + if (bleft > MLEN) { + MCLGET(m, M_DONTWAIT); + } + } + bleft -= M_TRAILINGSPACE(m); + } while (bleft > 0); + *mret = mfirst; + } + + obuf = mtod(*mret, unsigned char *); + /* * Fill in the first part of the PPP header. The protocol field * comes from the decrypted data. @@ -538,15 +677,17 @@ mppe_decompress(void *arg, unsigned char obuf[0] = PPP_ADDRESS(ibuf); /* +1 */ obuf[1] = PPP_CONTROL(ibuf); /* +1 */ obuf += 2; + (*mret)->m_len += 2; ibuf += PPP_HDRLEN + MPPE_OVHD; isize -= PPP_HDRLEN + MPPE_OVHD; /* -6 */ /* net osize: isize-4 */ +#ifdef notyet /* * Decrypt the first byte in order to check if it is * a compressed or uncompressed protocol field. */ - arcfour_decrypt(&state->arcfour_context, ibuf, 1, obuf); + arc4_decrypt(state->arcfour_context, obuf, ibuf, 1); /* * Do PFC decompression. @@ -557,13 +698,56 @@ mppe_decompress(void *arg, unsigned char obuf[1] = obuf[0]; obuf[0] = 0; obuf++; - osize++; } +#endif /* And finally, decrypt the rest of the packet. */ - arcfour_decrypt(&state->arcfour_context, ibuf + 1, isize - 1, obuf + 1); - - state->stats.unc_bytes += osize; + /* March down input and output mbuf chains, decoding with RC4 */ + { + struct mbuf *mi = mp; /* mbuf in */ + struct mbuf *mo = *mret; /* mbuf out */ + int maxi, maxo; + maxi = mi->m_len-6; /* adjust for PPP_HDRLEN and MPPE_OVERHEAD */ + maxo = M_TRAILINGSPACE(mo); + while (mi) { + if (maxi < maxo) { + arc4_encrypt(state->arcfour_context, + mtod(mo,unsigned char *)+mo->m_len, + mtod(mi,unsigned char *)+mi->m_len-maxi, + maxi); + mo->m_len += maxi; + maxo -= maxi; + mi = mi->m_next; + if (mi) { + maxi = mi->m_len; + } + } else if (maxi > maxo) { + arc4_encrypt(state->arcfour_context, + mtod(mo,unsigned char *)+mo->m_len, + mtod(mi,unsigned char *)+mi->m_len-maxi, + maxo); + mo->m_len += maxo; + maxi -= maxo; + mo = mo->m_next; + if (mo) { + maxo = M_TRAILINGSPACE(mo); + } + } else { + arc4_encrypt(state->arcfour_context, + mtod(mo,unsigned char *)+mo->m_len, + mtod(mi,unsigned char *)+mi->m_len-maxi, + maxi); + mo->m_len += maxi; + mi = mi->m_next; + mo = mo->m_next; + if (mi) { + maxi = mi->m_len; + maxo = M_TRAILINGSPACE(mo); + } + } + } + } + state->stats.unc_bytes += (*mret)->m_len; state->stats.unc_packets++; state->stats.comp_bytes += isize; state->stats.comp_packets++; @@ -571,7 +755,7 @@ mppe_decompress(void *arg, unsigned char /* good packet credit */ state->sanity_errors >>= 1; - return osize; + return DECOMP_OK; } /* @@ -581,29 +765,23 @@ mppe_decompress(void *arg, unsigned char * packet. (How to do this?) */ static void -mppe_incomp(void *arg, unsigned char *ibuf, int icnt) +mppe_incomp(void *arg, struct mbuf *mp) { ppp_mppe_state *state = (ppp_mppe_state *) arg; + struct mbuf *m; - if (state->debug && - (PPP_PROTOCOL(ibuf) >= 0x0021 && PPP_PROTOCOL(ibuf) <= 0x00fa)) - printk(KERN_DEBUG "mppe_incomp[%d]: incompressible (unencrypted) data! " - "(proto %04x)\n", state->unit, PPP_PROTOCOL(ibuf)); - - state->stats.inc_bytes += icnt; - state->stats.inc_packets++; - state->stats.unc_bytes += icnt; - state->stats.unc_packets++; + for (m=mp;m;m = m->m_next) { + (state->stats).inc_bytes += m->m_len; + (state->stats).unc_bytes += m->m_len; + } + (state->stats).inc_packets++; + (state->stats).unc_packets++; } /************************************************************* * Module interface table *************************************************************/ -/* These are in ppp.c (2.2.x) or ppp_generic.c (2.4.x) */ -extern int ppp_register_compressor (struct compressor *cp); -extern void ppp_unregister_compressor (struct compressor *cp); - /* * Procedures exported to if_ppp.c. */ @@ -623,34 +801,3 @@ struct compressor ppp_mppe = { mppe_incomp, /* incomp */ mppe_comp_stats, /* decomp_stat */ }; - -/* 2.2 compatibility defines */ -#ifndef __init -#define __init -#endif -#ifndef __exit -#define __exit -#endif -#ifndef MODULE_LICENSE -#define MODULE_LICENSE(license) -#endif - -int __init -ppp_mppe_init(void) -{ - int answer = ppp_register_compressor(&ppp_mppe); - - if (answer == 0) - printk(KERN_INFO "PPP MPPE Compression module registered\n"); - return answer; -} - -void __exit -ppp_mppe_cleanup(void) -{ - ppp_unregister_compressor(&ppp_mppe); -} - -module_init(ppp_mppe_init); -module_exit(ppp_mppe_cleanup); -MODULE_LICENSE("BSD without advertisement clause");