159109Sarchie/* 259109Sarchie * ng_mppc.c 3139823Simp */ 4139823Simp 5139823Simp/*- 659109Sarchie * Copyright (c) 1996-2000 Whistle Communications, Inc. 759109Sarchie * All rights reserved. 859109Sarchie * 959109Sarchie * Subject to the following obligations and disclaimer of warranty, use and 1059109Sarchie * redistribution of this software, in source or object code forms, with or 1159109Sarchie * without modifications are expressly permitted by Whistle Communications; 1259109Sarchie * provided, however, that: 1359109Sarchie * 1. Any and all reproductions of the source or object code must include the 1459109Sarchie * copyright notice above and the following disclaimer of warranties; and 1559109Sarchie * 2. No rights are granted, in any manner or form, to use Whistle 1659109Sarchie * Communications, Inc. trademarks, including the mark "WHISTLE 1759109Sarchie * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1859109Sarchie * such appears in the above copyright notice or in the software. 1959109Sarchie * 2059109Sarchie * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2159109Sarchie * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2259109Sarchie * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2359109Sarchie * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2459109Sarchie * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2559109Sarchie * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 2659109Sarchie * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2759109Sarchie * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2859109Sarchie * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2959109Sarchie * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 3059109Sarchie * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3159109Sarchie * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3259109Sarchie * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3359109Sarchie * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3459109Sarchie * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3559109Sarchie * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3659109Sarchie * OF SUCH DAMAGE. 3759109Sarchie * 3867506Sjulian * Author: Archie Cobbs <archie@freebsd.org> 3959109Sarchie * 4059109Sarchie * $Whistle: ng_mppc.c,v 1.4 1999/11/25 00:10:12 archie Exp $ 4159109Sarchie * $FreeBSD$ 4259109Sarchie */ 4359109Sarchie 4459109Sarchie/* 4559109Sarchie * Microsoft PPP compression (MPPC) and encryption (MPPE) netgraph node type. 4659109Sarchie * 4759109Sarchie * You must define one or both of the NETGRAPH_MPPC_COMPRESSION and/or 4859109Sarchie * NETGRAPH_MPPC_ENCRYPTION options for this node type to be useful. 4959109Sarchie */ 5059109Sarchie 5159109Sarchie#include <sys/param.h> 5259109Sarchie#include <sys/systm.h> 5359109Sarchie#include <sys/kernel.h> 5459109Sarchie#include <sys/mbuf.h> 5559109Sarchie#include <sys/malloc.h> 56206021Smav#include <sys/endian.h> 5759109Sarchie#include <sys/errno.h> 58267094Smav#include <sys/sysctl.h> 5959109Sarchie#include <sys/syslog.h> 6059109Sarchie 6159109Sarchie#include <netgraph/ng_message.h> 6259109Sarchie#include <netgraph/netgraph.h> 6359109Sarchie#include <netgraph/ng_mppc.h> 6459109Sarchie 6559109Sarchie#include "opt_netgraph.h" 6659109Sarchie 6759109Sarchie#if !defined(NETGRAPH_MPPC_COMPRESSION) && !defined(NETGRAPH_MPPC_ENCRYPTION) 68151349Syar#ifdef KLD_MODULE 69151349Syar/* XXX NETGRAPH_MPPC_COMPRESSION isn't functional yet */ 70151349Syar#define NETGRAPH_MPPC_ENCRYPTION 71151349Syar#else 72151349Syar/* This case is indicative of an error in sys/conf files */ 7359109Sarchie#error Need either NETGRAPH_MPPC_COMPRESSION or NETGRAPH_MPPC_ENCRYPTION 7459109Sarchie#endif 75151349Syar#endif 7659109Sarchie 7770870Sjulian#ifdef NG_SEPARATE_MALLOC 78249132Smavstatic MALLOC_DEFINE(M_NETGRAPH_MPPC, "netgraph_mppc", "netgraph mppc node"); 7970870Sjulian#else 8070870Sjulian#define M_NETGRAPH_MPPC M_NETGRAPH 8170870Sjulian#endif 8270870Sjulian 8359109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION 8459109Sarchie/* XXX this file doesn't exist yet, but hopefully someday it will... */ 8559109Sarchie#include <net/mppc.h> 8659109Sarchie#endif 8759109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION 8859109Sarchie#include <crypto/rc4/rc4.h> 8959109Sarchie#endif 9059109Sarchie#include <crypto/sha1.h> 9159109Sarchie 9259109Sarchie/* Decompression blowup */ 9359109Sarchie#define MPPC_DECOMP_BUFSIZE 8092 /* allocate buffer this big */ 9459109Sarchie#define MPPC_DECOMP_SAFETY 100 /* plus this much margin */ 9559109Sarchie 9659109Sarchie/* MPPC/MPPE header length */ 9759109Sarchie#define MPPC_HDRLEN 2 9859109Sarchie 9959109Sarchie/* Key length */ 10059109Sarchie#define KEYLEN(b) (((b) & MPPE_128) ? 16 : 8) 10159109Sarchie 102107845Sarchie/* 103107845Sarchie * When packets are lost with MPPE, we may have to re-key arbitrarily 104107845Sarchie * many times to 'catch up' to the new jumped-ahead sequence number. 105107845Sarchie * Since this can be expensive, we pose a limit on how many re-keyings 106107845Sarchie * we will do at one time to avoid a possible D.O.S. vulnerability. 107107845Sarchie * This should instead be a configurable parameter. 108107845Sarchie */ 109107845Sarchie#define MPPE_MAX_REKEY 1000 11059109Sarchie 111267094SmavSYSCTL_NODE(_net_graph, OID_AUTO, mppe, CTLFLAG_RW, 0, "MPPE"); 112267094Smav 113267094Smavstatic int mppe_block_on_max_rekey = 0; 114267094SmavTUNABLE_INT("net.graph.mppe.block_on_max_rekey", &mppe_block_on_max_rekey); 115267094SmavSYSCTL_INT(_net_graph_mppe, OID_AUTO, block_on_max_rekey, CTLFLAG_RW, 116267094Smav &mppe_block_on_max_rekey, 0, "Block node on max MPPE key re-calculations"); 117267094Smav 118267094Smavstatic int mppe_log_max_rekey = 1; 119267094SmavTUNABLE_INT("net.graph.mppe.log_max_rekey", &mppe_log_max_rekey); 120267094SmavSYSCTL_INT(_net_graph_mppe, OID_AUTO, log_max_rekey, CTLFLAG_RW, 121267094Smav &mppe_log_max_rekey, 0, "Log max MPPE key re-calculations event"); 122267094Smav 123267094Smavstatic int mppe_max_rekey = MPPE_MAX_REKEY; 124267094SmavTUNABLE_INT("net.graph.mppe.max_rekey", &mppe_max_rekey); 125267094SmavSYSCTL_INT(_net_graph_mppe, OID_AUTO, max_rekey, CTLFLAG_RW, 126267094Smav &mppe_max_rekey, 0, "Maximum number of MPPE key re-calculations"); 127267094Smav 12859109Sarchie/* MPPC packet header bits */ 12959109Sarchie#define MPPC_FLAG_FLUSHED 0x8000 /* xmitter reset state */ 13059109Sarchie#define MPPC_FLAG_RESTART 0x4000 /* compress history restart */ 13159109Sarchie#define MPPC_FLAG_COMPRESSED 0x2000 /* packet is compresed */ 13259109Sarchie#define MPPC_FLAG_ENCRYPTED 0x1000 /* packet is encrypted */ 13359109Sarchie#define MPPC_CCOUNT_MASK 0x0fff /* sequence number mask */ 13459109Sarchie 135169261Smav#define MPPC_CCOUNT_INC(d) ((d) = (((d) + 1) & MPPC_CCOUNT_MASK)) 136169261Smav 13759109Sarchie#define MPPE_UPDATE_MASK 0xff /* coherency count when we're */ 13859109Sarchie#define MPPE_UPDATE_FLAG 0xff /* supposed to update key */ 13959109Sarchie 14059109Sarchie#define MPPC_COMP_OK 0x05 14159109Sarchie#define MPPC_DECOMP_OK 0x05 14259109Sarchie 14359109Sarchie/* Per direction info */ 14459109Sarchiestruct ng_mppc_dir { 14559109Sarchie struct ng_mppc_config cfg; /* configuration */ 14659109Sarchie hook_p hook; /* netgraph hook */ 14759109Sarchie u_int16_t cc:12; /* coherency count */ 14859109Sarchie u_char flushed; /* clean history (xmit only) */ 14959109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION 15059109Sarchie u_char *history; /* compression history */ 15159109Sarchie#endif 15259109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION 15359109Sarchie u_char key[MPPE_KEY_LEN]; /* session key */ 15459109Sarchie struct rc4_state rc4; /* rc4 state */ 15559109Sarchie#endif 15659109Sarchie}; 15759109Sarchie 15859109Sarchie/* Node private data */ 15959109Sarchiestruct ng_mppc_private { 16059109Sarchie struct ng_mppc_dir xmit; /* compress/encrypt config */ 16159109Sarchie struct ng_mppc_dir recv; /* decompress/decrypt config */ 16270700Sjulian ng_ID_t ctrlnode; /* path to controlling node */ 16359109Sarchie}; 16459109Sarchietypedef struct ng_mppc_private *priv_p; 16559109Sarchie 16659109Sarchie/* Netgraph node methods */ 16759109Sarchiestatic ng_constructor_t ng_mppc_constructor; 16859109Sarchiestatic ng_rcvmsg_t ng_mppc_rcvmsg; 16970700Sjulianstatic ng_shutdown_t ng_mppc_shutdown; 17059109Sarchiestatic ng_newhook_t ng_mppc_newhook; 17159109Sarchiestatic ng_rcvdata_t ng_mppc_rcvdata; 17259109Sarchiestatic ng_disconnect_t ng_mppc_disconnect; 17359109Sarchie 17459109Sarchie/* Helper functions */ 17559109Sarchiestatic int ng_mppc_compress(node_p node, 176169474Smav struct mbuf **datap); 17759109Sarchiestatic int ng_mppc_decompress(node_p node, 178169474Smav struct mbuf **datap); 179169678Smav#ifdef NETGRAPH_MPPC_ENCRYPTION 18059109Sarchiestatic void ng_mppc_getkey(const u_char *h, u_char *h2, int len); 18159109Sarchiestatic void ng_mppc_updatekey(u_int32_t bits, 18259109Sarchie u_char *key0, u_char *key, struct rc4_state *rc4); 183169678Smav#endif 18459109Sarchiestatic void ng_mppc_reset_req(node_p node); 18559109Sarchie 18659109Sarchie/* Node type descriptor */ 18759109Sarchiestatic struct ng_type ng_mppc_typestruct = { 188129823Sjulian .version = NG_ABI_VERSION, 189129823Sjulian .name = NG_MPPC_NODE_TYPE, 190129823Sjulian .constructor = ng_mppc_constructor, 191129823Sjulian .rcvmsg = ng_mppc_rcvmsg, 192129823Sjulian .shutdown = ng_mppc_shutdown, 193129823Sjulian .newhook = ng_mppc_newhook, 194129823Sjulian .rcvdata = ng_mppc_rcvdata, 195129823Sjulian .disconnect = ng_mppc_disconnect, 19659109Sarchie}; 19759109SarchieNETGRAPH_INIT(mppc, &ng_mppc_typestruct); 19859109Sarchie 199110409Sambrisko#ifdef NETGRAPH_MPPC_ENCRYPTION 200110409Sambrisko/* Depend on separate rc4 module */ 201110409SambriskoMODULE_DEPEND(ng_mppc, rc4, 1, 1, 1); 202110409Sambrisko#endif 203110409Sambrisko 20487971Sarchie/* Fixed bit pattern to weaken keysize down to 40 or 56 bits */ 20559109Sarchiestatic const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e }; 20659109Sarchie 20759109Sarchie#define ERROUT(x) do { error = (x); goto done; } while (0) 20859109Sarchie 20959109Sarchie/************************************************************************ 21059109Sarchie NETGRAPH NODE STUFF 21159109Sarchie ************************************************************************/ 21259109Sarchie 21359109Sarchie/* 21459109Sarchie * Node type constructor 21559109Sarchie */ 21659109Sarchiestatic int 21770700Sjulianng_mppc_constructor(node_p node) 21859109Sarchie{ 21959109Sarchie priv_p priv; 22059109Sarchie 22159109Sarchie /* Allocate private structure */ 222220768Sglebius priv = malloc(sizeof(*priv), M_NETGRAPH_MPPC, M_WAITOK | M_ZERO); 22359109Sarchie 22470784Sjulian NG_NODE_SET_PRIVATE(node, priv); 22559109Sarchie 226146919Sglebius /* This node is not thread safe. */ 227146919Sglebius NG_NODE_FORCE_WRITER(node); 228146919Sglebius 22959109Sarchie /* Done */ 23059109Sarchie return (0); 23159109Sarchie} 23259109Sarchie 23359109Sarchie/* 23459109Sarchie * Give our OK for a hook to be added 23559109Sarchie */ 23659109Sarchiestatic int 23759109Sarchieng_mppc_newhook(node_p node, hook_p hook, const char *name) 23859109Sarchie{ 23970784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 24059109Sarchie hook_p *hookPtr; 24159109Sarchie 24259109Sarchie /* Check hook name */ 24359109Sarchie if (strcmp(name, NG_MPPC_HOOK_COMP) == 0) 24459109Sarchie hookPtr = &priv->xmit.hook; 24559109Sarchie else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0) 24659109Sarchie hookPtr = &priv->recv.hook; 24759109Sarchie else 24859109Sarchie return (EINVAL); 24959109Sarchie 25059109Sarchie /* See if already connected */ 25159109Sarchie if (*hookPtr != NULL) 25259109Sarchie return (EISCONN); 25359109Sarchie 25459109Sarchie /* OK */ 25559109Sarchie *hookPtr = hook; 25659109Sarchie return (0); 25759109Sarchie} 25859109Sarchie 25959109Sarchie/* 26059109Sarchie * Receive a control message 26159109Sarchie */ 26259109Sarchiestatic int 26370700Sjulianng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook) 26459109Sarchie{ 26570784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 26659109Sarchie struct ng_mesg *resp = NULL; 26759109Sarchie int error = 0; 26870700Sjulian struct ng_mesg *msg; 26959109Sarchie 27070700Sjulian NGI_GET_MSG(item, msg); 27159109Sarchie switch (msg->header.typecookie) { 27259109Sarchie case NGM_MPPC_COOKIE: 27359109Sarchie switch (msg->header.cmd) { 27459109Sarchie case NGM_MPPC_CONFIG_COMP: 27559109Sarchie case NGM_MPPC_CONFIG_DECOMP: 27659109Sarchie { 27759109Sarchie struct ng_mppc_config *const cfg 27859109Sarchie = (struct ng_mppc_config *)msg->data; 27959109Sarchie const int isComp = 28059109Sarchie msg->header.cmd == NGM_MPPC_CONFIG_COMP; 28159109Sarchie struct ng_mppc_dir *const d = isComp ? 28259109Sarchie &priv->xmit : &priv->recv; 28359109Sarchie 28459109Sarchie /* Check configuration */ 28559109Sarchie if (msg->header.arglen != sizeof(*cfg)) 28659109Sarchie ERROUT(EINVAL); 28759109Sarchie if (cfg->enable) { 28859109Sarchie if ((cfg->bits & ~MPPC_VALID_BITS) != 0) 28959109Sarchie ERROUT(EINVAL); 29059109Sarchie#ifndef NETGRAPH_MPPC_COMPRESSION 29159109Sarchie if ((cfg->bits & MPPC_BIT) != 0) 29259109Sarchie ERROUT(EPROTONOSUPPORT); 29359109Sarchie#endif 29459109Sarchie#ifndef NETGRAPH_MPPC_ENCRYPTION 29559109Sarchie if ((cfg->bits & MPPE_BITS) != 0) 29659109Sarchie ERROUT(EPROTONOSUPPORT); 29759109Sarchie#endif 29859109Sarchie } else 29959109Sarchie cfg->bits = 0; 30059109Sarchie 30159109Sarchie /* Save return address so we can send reset-req's */ 302107845Sarchie if (!isComp) 303107845Sarchie priv->ctrlnode = NGI_RETADDR(item); 30459109Sarchie 30559109Sarchie /* Configuration is OK, reset to it */ 30659109Sarchie d->cfg = *cfg; 30759109Sarchie 30859109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION 30959109Sarchie /* Initialize state buffers for compression */ 31059109Sarchie if (d->history != NULL) { 311184205Sdes free(d->history, M_NETGRAPH_MPPC); 31259109Sarchie d->history = NULL; 31359109Sarchie } 31459109Sarchie if ((cfg->bits & MPPC_BIT) != 0) { 315184214Sdes d->history = malloc(isComp ? 316184214Sdes MPPC_SizeOfCompressionHistory() : 31759109Sarchie MPPC_SizeOfDecompressionHistory(), 31870870Sjulian M_NETGRAPH_MPPC, M_NOWAIT); 31959109Sarchie if (d->history == NULL) 32059109Sarchie ERROUT(ENOMEM); 32159109Sarchie if (isComp) 32259109Sarchie MPPC_InitCompressionHistory(d->history); 32359109Sarchie else { 32459109Sarchie MPPC_InitDecompressionHistory( 32559109Sarchie d->history); 32659109Sarchie } 32759109Sarchie } 32859109Sarchie#endif 32959109Sarchie 33059109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION 33159109Sarchie /* Generate initial session keys for encryption */ 33259109Sarchie if ((cfg->bits & MPPE_BITS) != 0) { 33359109Sarchie const int keylen = KEYLEN(cfg->bits); 33459109Sarchie 33559109Sarchie bcopy(cfg->startkey, d->key, keylen); 33659109Sarchie ng_mppc_getkey(cfg->startkey, d->key, keylen); 33787971Sarchie if ((cfg->bits & MPPE_40) != 0) 33887971Sarchie bcopy(&ng_mppe_weakenkey, d->key, 3); 33987971Sarchie else if ((cfg->bits & MPPE_56) != 0) 34087971Sarchie bcopy(&ng_mppe_weakenkey, d->key, 1); 34159109Sarchie rc4_init(&d->rc4, d->key, keylen); 34259109Sarchie } 34359109Sarchie#endif 34459109Sarchie 34559109Sarchie /* Initialize other state */ 34659109Sarchie d->cc = 0; 34759109Sarchie d->flushed = 0; 34859109Sarchie break; 34959109Sarchie } 35059109Sarchie 35159109Sarchie case NGM_MPPC_RESETREQ: 35259109Sarchie ng_mppc_reset_req(node); 35359109Sarchie break; 35459109Sarchie 35559109Sarchie default: 35659109Sarchie error = EINVAL; 35759109Sarchie break; 35859109Sarchie } 35959109Sarchie break; 36059109Sarchie default: 36159109Sarchie error = EINVAL; 36259109Sarchie break; 36359109Sarchie } 36459109Sarchiedone: 36570700Sjulian NG_RESPOND_MSG(error, node, item, resp); 36670700Sjulian NG_FREE_MSG(msg); 36759109Sarchie return (error); 36859109Sarchie} 36959109Sarchie 37059109Sarchie/* 37159109Sarchie * Receive incoming data on our hook. 37259109Sarchie */ 37359109Sarchiestatic int 37470700Sjulianng_mppc_rcvdata(hook_p hook, item_p item) 37559109Sarchie{ 37670784Sjulian const node_p node = NG_HOOK_NODE(hook); 37770784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 37859109Sarchie int error; 37970700Sjulian struct mbuf *m; 38059109Sarchie 38170700Sjulian NGI_GET_M(item, m); 38259109Sarchie /* Compress and/or encrypt */ 38359109Sarchie if (hook == priv->xmit.hook) { 38459109Sarchie if (!priv->xmit.cfg.enable) { 38570700Sjulian NG_FREE_M(m); 38670700Sjulian NG_FREE_ITEM(item); 38759109Sarchie return (ENXIO); 38859109Sarchie } 389169474Smav if ((error = ng_mppc_compress(node, &m)) != 0) { 39070700Sjulian NG_FREE_ITEM(item); 39159109Sarchie return(error); 39259109Sarchie } 393169474Smav NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m); 39459109Sarchie return (error); 39559109Sarchie } 39659109Sarchie 39759109Sarchie /* Decompress and/or decrypt */ 39859109Sarchie if (hook == priv->recv.hook) { 39959109Sarchie if (!priv->recv.cfg.enable) { 40070700Sjulian NG_FREE_M(m); 40170700Sjulian NG_FREE_ITEM(item); 40259109Sarchie return (ENXIO); 40359109Sarchie } 404169474Smav if ((error = ng_mppc_decompress(node, &m)) != 0) { 40570700Sjulian NG_FREE_ITEM(item); 406102244Sarchie if (error == EINVAL && priv->ctrlnode != 0) { 40759109Sarchie struct ng_mesg *msg; 40859109Sarchie 40959109Sarchie /* Need to send a reset-request */ 41059109Sarchie NG_MKMESSAGE(msg, NGM_MPPC_COOKIE, 41159109Sarchie NGM_MPPC_RESETREQ, 0, M_NOWAIT); 41259109Sarchie if (msg == NULL) 41359109Sarchie return (error); 41470700Sjulian NG_SEND_MSG_ID(error, node, msg, 415102244Sarchie priv->ctrlnode, 0); 41659109Sarchie } 41759109Sarchie return (error); 41859109Sarchie } 419169474Smav NG_FWD_NEW_DATA(error, item, priv->recv.hook, m); 42059109Sarchie return (error); 42159109Sarchie } 42259109Sarchie 42359109Sarchie /* Oops */ 42487599Sobrien panic("%s: unknown hook", __func__); 42559109Sarchie} 42659109Sarchie 42759109Sarchie/* 42859109Sarchie * Destroy node 42959109Sarchie */ 43059109Sarchiestatic int 43170700Sjulianng_mppc_shutdown(node_p node) 43259109Sarchie{ 43370784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 43459109Sarchie 43559109Sarchie /* Take down netgraph node */ 43659109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION 43759109Sarchie if (priv->xmit.history != NULL) 438184205Sdes free(priv->xmit.history, M_NETGRAPH_MPPC); 43959109Sarchie if (priv->recv.history != NULL) 440184205Sdes free(priv->recv.history, M_NETGRAPH_MPPC); 44159109Sarchie#endif 44259109Sarchie bzero(priv, sizeof(*priv)); 443184205Sdes free(priv, M_NETGRAPH_MPPC); 44470784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 44570784Sjulian NG_NODE_UNREF(node); /* let the node escape */ 44659109Sarchie return (0); 44759109Sarchie} 44859109Sarchie 44959109Sarchie/* 45059109Sarchie * Hook disconnection 45159109Sarchie */ 45259109Sarchiestatic int 45359109Sarchieng_mppc_disconnect(hook_p hook) 45459109Sarchie{ 45570784Sjulian const node_p node = NG_HOOK_NODE(hook); 45670784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 45759109Sarchie 45859109Sarchie /* Zero out hook pointer */ 45959109Sarchie if (hook == priv->xmit.hook) 46059109Sarchie priv->xmit.hook = NULL; 46159109Sarchie if (hook == priv->recv.hook) 46259109Sarchie priv->recv.hook = NULL; 46359109Sarchie 46459109Sarchie /* Go away if no longer connected */ 46570784Sjulian if ((NG_NODE_NUMHOOKS(node) == 0) 46670784Sjulian && NG_NODE_IS_VALID(node)) 46770700Sjulian ng_rmnode_self(node); 46859109Sarchie return (0); 46959109Sarchie} 47059109Sarchie 47159109Sarchie/************************************************************************ 47259109Sarchie HELPER STUFF 47359109Sarchie ************************************************************************/ 47459109Sarchie 47559109Sarchie/* 47659109Sarchie * Compress/encrypt a packet and put the result in a new mbuf at *resultp. 47759109Sarchie * The original mbuf is not free'd. 47859109Sarchie */ 47959109Sarchiestatic int 480169474Smavng_mppc_compress(node_p node, struct mbuf **datap) 48159109Sarchie{ 48270784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 48359109Sarchie struct ng_mppc_dir *const d = &priv->xmit; 48459109Sarchie u_int16_t header; 485169474Smav struct mbuf *m = *datap; 48659109Sarchie 487187405Smav /* We must own the mbuf chain exclusively to modify it. */ 488187405Smav m = m_unshare(m, M_DONTWAIT); 489187405Smav if (m == NULL) 490187405Smav return (ENOMEM); 491187405Smav 49259109Sarchie /* Initialize */ 49359109Sarchie header = d->cc; 494169262Smav 495169262Smav /* Always set the flushed bit in stateless mode */ 496169262Smav if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) { 49759109Sarchie header |= MPPC_FLAG_FLUSHED; 49859109Sarchie d->flushed = 0; 49959109Sarchie } 50059109Sarchie 501169474Smav /* Compress packet (if compression enabled) */ 50259109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION 50359109Sarchie if ((d->cfg.bits & MPPC_BIT) != 0) { 50459109Sarchie u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS; 505169474Smav u_char *inbuf, *outbuf; 506187410Smav int outlen, inlen, ina; 50759109Sarchie u_char *source, *dest; 50859109Sarchie u_long sourceCnt, destCnt; 50959109Sarchie int rtn; 51059109Sarchie 511169474Smav /* Work with contiguous regions of memory. */ 512169474Smav inlen = m->m_pkthdr.len; 513187410Smav if (m->m_next == NULL) { 514187410Smav inbuf = mtod(m, u_char *); 515187410Smav ina = 0; 516187410Smav } else { 517187410Smav inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT); 518187410Smav if (inbuf == NULL) 519187410Smav goto err1; 520187410Smav m_copydata(m, 0, inlen, (caddr_t)inbuf); 521187410Smav ina = 1; 522187410Smav } 523169474Smav 524169474Smav outlen = MPPC_MAX_BLOWUP(inlen); 525169474Smav outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT); 526169474Smav if (outbuf == NULL) { 527187410Smav if (ina) 528187410Smav free(inbuf, M_NETGRAPH_MPPC); 529185723Smaverr1: 530169474Smav m_freem(m); 531185723Smav MPPC_InitCompressionHistory(d->history); 532185723Smav d->flushed = 1; 533169474Smav return (ENOMEM); 534169474Smav } 535169474Smav 53659109Sarchie /* Prepare to compress */ 53759109Sarchie source = inbuf; 53859109Sarchie sourceCnt = inlen; 539169474Smav dest = outbuf; 540169474Smav destCnt = outlen; 54159109Sarchie if ((d->cfg.bits & MPPE_STATELESS) == 0) 54259109Sarchie flags |= MPPC_SAVE_HISTORY; 54359109Sarchie 54459109Sarchie /* Compress */ 54559109Sarchie rtn = MPPC_Compress(&source, &dest, &sourceCnt, 54659109Sarchie &destCnt, d->history, flags, 0); 54759109Sarchie 54859109Sarchie /* Check return value */ 54987599Sobrien KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); 55059109Sarchie if ((rtn & MPPC_EXPANDED) == 0 55159109Sarchie && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) { 55259109Sarchie outlen -= destCnt; 55359109Sarchie header |= MPPC_FLAG_COMPRESSED; 55459109Sarchie if ((rtn & MPPC_RESTART_HISTORY) != 0) 55559109Sarchie header |= MPPC_FLAG_RESTART; 556169474Smav 557169474Smav /* Replace m by the compresed one. */ 558187405Smav m_copyback(m, 0, outlen, (caddr_t)outbuf); 559187405Smav if (m->m_pkthdr.len < outlen) { 560187405Smav m_freem(m); 561187405Smav m = NULL; 562187405Smav } else if (outlen < m->m_pkthdr.len) 563187405Smav m_adj(m, outlen - m->m_pkthdr.len); 56459109Sarchie } 56559109Sarchie d->flushed = (rtn & MPPC_EXPANDED) != 0 56659109Sarchie || (flags & MPPC_SAVE_HISTORY) == 0; 567169474Smav 568187410Smav if (ina) 569187410Smav free(inbuf, M_NETGRAPH_MPPC); 570169474Smav free(outbuf, M_NETGRAPH_MPPC); 571169474Smav 572187405Smav /* Check mbuf chain reload result. */ 573185723Smav if (m == NULL) { 574185723Smav if (!d->flushed) { 575185723Smav MPPC_InitCompressionHistory(d->history); 576185723Smav d->flushed = 1; 577185723Smav } 578169474Smav return (ENOMEM); 579185723Smav } 58059109Sarchie } 58159109Sarchie#endif 58259109Sarchie 58359109Sarchie /* Now encrypt packet (if encryption enabled) */ 58459109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION 58559109Sarchie if ((d->cfg.bits & MPPE_BITS) != 0) { 586169474Smav struct mbuf *m1; 58759109Sarchie 588169263Smav /* Set header bits */ 58959109Sarchie header |= MPPC_FLAG_ENCRYPTED; 59059109Sarchie 59159109Sarchie /* Update key if it's time */ 59259109Sarchie if ((d->cfg.bits & MPPE_STATELESS) != 0 59359109Sarchie || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) { 594169263Smav ng_mppc_updatekey(d->cfg.bits, 595169263Smav d->cfg.startkey, d->key, &d->rc4); 596169263Smav } else if ((header & MPPC_FLAG_FLUSHED) != 0) { 597169263Smav /* Need to reset key if we say we did 598169263Smav and ng_mppc_updatekey wasn't called to do it also. */ 599169263Smav rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 60059109Sarchie } 60159109Sarchie 60259109Sarchie /* Encrypt packet */ 603169474Smav m1 = m; 604169474Smav while (m1) { 605169474Smav rc4_crypt(&d->rc4, mtod(m1, u_char *), 606169474Smav mtod(m1, u_char *), m1->m_len); 607169474Smav m1 = m1->m_next; 608169474Smav } 60959109Sarchie } 61059109Sarchie#endif 61159109Sarchie 612169261Smav /* Update coherency count for next time (12 bit arithmetic) */ 613169261Smav MPPC_CCOUNT_INC(d->cc); 61459109Sarchie 61559109Sarchie /* Install header */ 616169474Smav M_PREPEND(m, MPPC_HDRLEN, M_DONTWAIT); 617169474Smav if (m != NULL) 618206021Smav be16enc(mtod(m, void *), header); 61959109Sarchie 620169474Smav *datap = m; 621169474Smav return (*datap == NULL ? ENOBUFS : 0); 62259109Sarchie} 62359109Sarchie 62459109Sarchie/* 62559109Sarchie * Decompress/decrypt packet and put the result in a new mbuf at *resultp. 62659109Sarchie * The original mbuf is not free'd. 62759109Sarchie */ 62859109Sarchiestatic int 629169474Smavng_mppc_decompress(node_p node, struct mbuf **datap) 63059109Sarchie{ 63170784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 63259109Sarchie struct ng_mppc_dir *const d = &priv->recv; 633107845Sarchie u_int16_t header, cc; 634107845Sarchie u_int numLost; 635169474Smav struct mbuf *m = *datap; 63659109Sarchie 637187405Smav /* We must own the mbuf chain exclusively to modify it. */ 638187405Smav m = m_unshare(m, M_DONTWAIT); 639187405Smav if (m == NULL) 640187405Smav return (ENOMEM); 641187405Smav 64259109Sarchie /* Pull off header */ 643169474Smav if (m->m_pkthdr.len < MPPC_HDRLEN) { 644169474Smav m_freem(m); 64559109Sarchie return (EINVAL); 646169474Smav } 647206021Smav header = be16dec(mtod(m, void *)); 64859109Sarchie cc = (header & MPPC_CCOUNT_MASK); 649169474Smav m_adj(m, MPPC_HDRLEN); 65059109Sarchie 651107845Sarchie /* Check for an unexpected jump in the sequence number */ 65259109Sarchie numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK); 65359109Sarchie 65459109Sarchie /* If flushed bit set, we can always handle packet */ 65559109Sarchie if ((header & MPPC_FLAG_FLUSHED) != 0) { 65659109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION 65759109Sarchie if (d->history != NULL) 65859109Sarchie MPPC_InitDecompressionHistory(d->history); 65959109Sarchie#endif 66059109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION 66159109Sarchie if ((d->cfg.bits & MPPE_BITS) != 0) { 662107845Sarchie u_int rekey; 66359109Sarchie 664107845Sarchie /* How many times are we going to have to re-key? */ 665107845Sarchie rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ? 666107845Sarchie numLost : (numLost / (MPPE_UPDATE_MASK + 1)); 667267094Smav if (rekey > mppe_max_rekey) { 668267094Smav if (mppe_block_on_max_rekey) { 669267094Smav if (mppe_log_max_rekey) { 670267094Smav log(LOG_ERR, "%s: too many (%d) packets" 671267094Smav " dropped, disabling node %p!\n", 672267094Smav __func__, numLost, node); 673267094Smav } 674107845Sarchie priv->recv.cfg.enable = 0; 675107845Sarchie goto failed; 676267094Smav } else { 677267094Smav if (mppe_log_max_rekey) { 678267094Smav log(LOG_ERR, "%s: %d packets" 679267094Smav " dropped, node %p\n", 680267094Smav __func__, numLost, node); 681267094Smav } 682267094Smav goto failed; 683267094Smav } 684107845Sarchie } 685107845Sarchie 686107845Sarchie /* Re-key as necessary to catch up to peer */ 68759109Sarchie while (d->cc != cc) { 688107845Sarchie if ((d->cfg.bits & MPPE_STATELESS) != 0 68959109Sarchie || (d->cc & MPPE_UPDATE_MASK) 69059109Sarchie == MPPE_UPDATE_FLAG) { 69159109Sarchie ng_mppc_updatekey(d->cfg.bits, 69259109Sarchie d->cfg.startkey, d->key, &d->rc4); 69359109Sarchie } 694169261Smav MPPC_CCOUNT_INC(d->cc); 69559109Sarchie } 69659109Sarchie 69759109Sarchie /* Reset key (except in stateless mode, see below) */ 69859109Sarchie if ((d->cfg.bits & MPPE_STATELESS) == 0) 69959109Sarchie rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 70059109Sarchie } 70159109Sarchie#endif 70259109Sarchie d->cc = cc; /* skip over lost seq numbers */ 70359109Sarchie numLost = 0; /* act like no packets were lost */ 70459109Sarchie } 70559109Sarchie 70659109Sarchie /* Can't decode non-sequential packets without a flushed bit */ 70759109Sarchie if (numLost != 0) 70859109Sarchie goto failed; 70959109Sarchie 71059109Sarchie /* Decrypt packet */ 71159109Sarchie if ((header & MPPC_FLAG_ENCRYPTED) != 0) { 712169474Smav#ifdef NETGRAPH_MPPC_ENCRYPTION 713169474Smav struct mbuf *m1; 714169474Smav#endif 71559109Sarchie 71659109Sarchie /* Are we not expecting encryption? */ 71759109Sarchie if ((d->cfg.bits & MPPE_BITS) == 0) { 71859109Sarchie log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 71987599Sobrien __func__, "encrypted"); 72059109Sarchie goto failed; 72159109Sarchie } 72259109Sarchie 72359109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION 72459109Sarchie /* Update key if it's time (always in stateless mode) */ 72559109Sarchie if ((d->cfg.bits & MPPE_STATELESS) != 0 72659109Sarchie || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) { 72759109Sarchie ng_mppc_updatekey(d->cfg.bits, 72859109Sarchie d->cfg.startkey, d->key, &d->rc4); 72959109Sarchie } 73059109Sarchie 73159109Sarchie /* Decrypt packet */ 732169474Smav m1 = m; 733169474Smav while (m1 != NULL) { 734169474Smav rc4_crypt(&d->rc4, mtod(m1, u_char *), 735169474Smav mtod(m1, u_char *), m1->m_len); 736169474Smav m1 = m1->m_next; 737169474Smav } 73859109Sarchie#endif 73959109Sarchie } else { 74059109Sarchie 74159109Sarchie /* Are we expecting encryption? */ 74259109Sarchie if ((d->cfg.bits & MPPE_BITS) != 0) { 74359109Sarchie log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 74487599Sobrien __func__, "unencrypted"); 74559109Sarchie goto failed; 74659109Sarchie } 74759109Sarchie } 74859109Sarchie 74959109Sarchie /* Update coherency count for next time (12 bit arithmetic) */ 750169261Smav MPPC_CCOUNT_INC(d->cc); 75159109Sarchie 75259109Sarchie /* Check for unexpected compressed packet */ 75359109Sarchie if ((header & MPPC_FLAG_COMPRESSED) != 0 75459109Sarchie && (d->cfg.bits & MPPC_BIT) == 0) { 75559109Sarchie log(LOG_ERR, "%s: rec'd unexpectedly %s packet", 75687599Sobrien __func__, "compressed"); 75759109Sarchiefailed: 758169474Smav m_freem(m); 75959109Sarchie return (EINVAL); 76059109Sarchie } 76159109Sarchie 76259109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION 76359109Sarchie /* Decompress packet */ 76459109Sarchie if ((header & MPPC_FLAG_COMPRESSED) != 0) { 76559109Sarchie int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS; 766187410Smav u_char *inbuf, *outbuf; 767187410Smav int inlen, outlen, ina; 768187410Smav u_char *source, *dest; 76959109Sarchie u_long sourceCnt, destCnt; 770187410Smav int rtn; 77159109Sarchie 772169474Smav /* Copy payload into a contiguous region of memory. */ 773187410Smav inlen = m->m_pkthdr.len; 774187410Smav if (m->m_next == NULL) { 775187410Smav inbuf = mtod(m, u_char *); 776187410Smav ina = 0; 777187410Smav } else { 778187410Smav inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT); 779187410Smav if (inbuf == NULL) { 780187410Smav m_freem(m); 781187410Smav return (ENOMEM); 782187410Smav } 783187410Smav m_copydata(m, 0, inlen, (caddr_t)inbuf); 784187410Smav ina = 1; 785169474Smav } 786169474Smav 78759109Sarchie /* Allocate a buffer for decompressed data */ 788187410Smav outbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY, 789169474Smav M_NETGRAPH_MPPC, M_NOWAIT); 790187410Smav if (outbuf == NULL) { 791169474Smav m_freem(m); 792187410Smav if (ina) 793187410Smav free(inbuf, M_NETGRAPH_MPPC); 79459109Sarchie return (ENOMEM); 79559109Sarchie } 796187410Smav outlen = MPPC_DECOMP_BUFSIZE; 79759109Sarchie 79859109Sarchie /* Prepare to decompress */ 799187410Smav source = inbuf; 800187410Smav sourceCnt = inlen; 801187410Smav dest = outbuf; 802187410Smav destCnt = outlen; 80359109Sarchie if ((header & MPPC_FLAG_RESTART) != 0) 80459109Sarchie flags |= MPPC_RESTART_HISTORY; 80559109Sarchie 80659109Sarchie /* Decompress */ 80759109Sarchie rtn = MPPC_Decompress(&source, &dest, 80859109Sarchie &sourceCnt, &destCnt, d->history, flags); 80959109Sarchie 81059109Sarchie /* Check return value */ 81187599Sobrien KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); 81259109Sarchie if ((rtn & MPPC_DEST_EXHAUSTED) != 0 81359109Sarchie || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) { 81459109Sarchie log(LOG_ERR, "%s: decomp returned 0x%x", 81587599Sobrien __func__, rtn); 816187410Smav if (ina) 817187410Smav free(inbuf, M_NETGRAPH_MPPC); 818187410Smav free(outbuf, M_NETGRAPH_MPPC); 81959109Sarchie goto failed; 82059109Sarchie } 82159109Sarchie 82259109Sarchie /* Replace compressed data with decompressed data */ 823187410Smav if (ina) 824187410Smav free(inbuf, M_NETGRAPH_MPPC); 825187410Smav outlen -= destCnt; 826169474Smav 827187410Smav m_copyback(m, 0, outlen, (caddr_t)outbuf); 828187410Smav if (m->m_pkthdr.len < outlen) { 829187405Smav m_freem(m); 830187405Smav m = NULL; 831187410Smav } else if (outlen < m->m_pkthdr.len) 832187410Smav m_adj(m, outlen - m->m_pkthdr.len); 833187410Smav free(outbuf, M_NETGRAPH_MPPC); 83459109Sarchie } 83559109Sarchie#endif 83659109Sarchie 83759109Sarchie /* Return result in an mbuf */ 838169474Smav *datap = m; 839169474Smav return (*datap == NULL ? ENOBUFS : 0); 84059109Sarchie} 84159109Sarchie 84259109Sarchie/* 84359109Sarchie * The peer has sent us a CCP ResetRequest, so reset our transmit state. 84459109Sarchie */ 84559109Sarchiestatic void 84659109Sarchieng_mppc_reset_req(node_p node) 84759109Sarchie{ 84870784Sjulian const priv_p priv = NG_NODE_PRIVATE(node); 84959109Sarchie struct ng_mppc_dir *const d = &priv->xmit; 85059109Sarchie 85159109Sarchie#ifdef NETGRAPH_MPPC_COMPRESSION 85259109Sarchie if (d->history != NULL) 85359109Sarchie MPPC_InitCompressionHistory(d->history); 85459109Sarchie#endif 85559109Sarchie#ifdef NETGRAPH_MPPC_ENCRYPTION 85659109Sarchie if ((d->cfg.bits & MPPE_STATELESS) == 0) 85759109Sarchie rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits)); 85859109Sarchie#endif 85959109Sarchie d->flushed = 1; 86059109Sarchie} 86159109Sarchie 862169678Smav#ifdef NETGRAPH_MPPC_ENCRYPTION 86359109Sarchie/* 86459109Sarchie * Generate a new encryption key 86559109Sarchie */ 86659109Sarchiestatic void 86759109Sarchieng_mppc_getkey(const u_char *h, u_char *h2, int len) 86859109Sarchie{ 869186189Smav static const u_char pad1[40] = 870186189Smav { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 871186189Smav 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 872186189Smav 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 873186189Smav 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 874186189Smav static const u_char pad2[40] = 875186189Smav { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 876186189Smav 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 877186189Smav 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 878186189Smav 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 }; 87959109Sarchie u_char hash[20]; 88059109Sarchie SHA1_CTX c; 88159109Sarchie 88259109Sarchie SHA1Init(&c); 88359109Sarchie SHA1Update(&c, h, len); 884186189Smav SHA1Update(&c, pad1, sizeof(pad1)); 88559109Sarchie SHA1Update(&c, h2, len); 886186189Smav SHA1Update(&c, pad2, sizeof(pad2)); 88759109Sarchie SHA1Final(hash, &c); 88859109Sarchie bcopy(hash, h2, len); 88959109Sarchie} 89059109Sarchie 89159109Sarchie/* 89259109Sarchie * Update the encryption key 89359109Sarchie */ 89459109Sarchiestatic void 89559109Sarchieng_mppc_updatekey(u_int32_t bits, 89659109Sarchie u_char *key0, u_char *key, struct rc4_state *rc4) 89759109Sarchie{ 89859109Sarchie const int keylen = KEYLEN(bits); 89959109Sarchie 90059109Sarchie ng_mppc_getkey(key0, key, keylen); 90159109Sarchie rc4_init(rc4, key, keylen); 90259109Sarchie rc4_crypt(rc4, key, key, keylen); 90387971Sarchie if ((bits & MPPE_40) != 0) 90487971Sarchie bcopy(&ng_mppe_weakenkey, key, 3); 90587971Sarchie else if ((bits & MPPE_56) != 0) 90687971Sarchie bcopy(&ng_mppe_weakenkey, key, 1); 90759109Sarchie rc4_init(rc4, key, keylen); 90859109Sarchie} 909169678Smav#endif 91059109Sarchie 911