1af7ab184SArchie Cobbs /*
2af7ab184SArchie Cobbs * ng_mppc.c
3c398230bSWarner Losh */
4c398230bSWarner Losh
5c398230bSWarner Losh /*-
6af7ab184SArchie Cobbs * Copyright (c) 1996-2000 Whistle Communications, Inc.
7af7ab184SArchie Cobbs * All rights reserved.
8af7ab184SArchie Cobbs *
9af7ab184SArchie Cobbs * Subject to the following obligations and disclaimer of warranty, use and
10af7ab184SArchie Cobbs * redistribution of this software, in source or object code forms, with or
11af7ab184SArchie Cobbs * without modifications are expressly permitted by Whistle Communications;
12af7ab184SArchie Cobbs * provided, however, that:
13af7ab184SArchie Cobbs * 1. Any and all reproductions of the source or object code must include the
14af7ab184SArchie Cobbs * copyright notice above and the following disclaimer of warranties; and
15af7ab184SArchie Cobbs * 2. No rights are granted, in any manner or form, to use Whistle
16af7ab184SArchie Cobbs * Communications, Inc. trademarks, including the mark "WHISTLE
17af7ab184SArchie Cobbs * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
18af7ab184SArchie Cobbs * such appears in the above copyright notice or in the software.
19af7ab184SArchie Cobbs *
20af7ab184SArchie Cobbs * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
21af7ab184SArchie Cobbs * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
22af7ab184SArchie Cobbs * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
23af7ab184SArchie Cobbs * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
24af7ab184SArchie Cobbs * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
25af7ab184SArchie Cobbs * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
26af7ab184SArchie Cobbs * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
27af7ab184SArchie Cobbs * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
28af7ab184SArchie Cobbs * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
29af7ab184SArchie Cobbs * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
30af7ab184SArchie Cobbs * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31af7ab184SArchie Cobbs * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
32af7ab184SArchie Cobbs * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
33af7ab184SArchie Cobbs * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34af7ab184SArchie Cobbs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35af7ab184SArchie Cobbs * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
36af7ab184SArchie Cobbs * OF SUCH DAMAGE.
37af7ab184SArchie Cobbs *
38cc3bbd68SJulian Elischer * Author: Archie Cobbs <archie@freebsd.org>
39af7ab184SArchie Cobbs *
40af7ab184SArchie Cobbs * $Whistle: ng_mppc.c,v 1.4 1999/11/25 00:10:12 archie Exp $
41af7ab184SArchie Cobbs */
42af7ab184SArchie Cobbs
43af7ab184SArchie Cobbs /*
44af7ab184SArchie Cobbs * Microsoft PPP compression (MPPC) and encryption (MPPE) netgraph node type.
45af7ab184SArchie Cobbs *
46af7ab184SArchie Cobbs * You must define one or both of the NETGRAPH_MPPC_COMPRESSION and/or
47af7ab184SArchie Cobbs * NETGRAPH_MPPC_ENCRYPTION options for this node type to be useful.
48af7ab184SArchie Cobbs */
49af7ab184SArchie Cobbs
50af7ab184SArchie Cobbs #include <sys/param.h>
51af7ab184SArchie Cobbs #include <sys/systm.h>
52af7ab184SArchie Cobbs #include <sys/kernel.h>
53af7ab184SArchie Cobbs #include <sys/mbuf.h>
54af7ab184SArchie Cobbs #include <sys/malloc.h>
5539228864SAlexander Motin #include <sys/endian.h>
56af7ab184SArchie Cobbs #include <sys/errno.h>
57ee652839SAlexander Motin #include <sys/sysctl.h>
58af7ab184SArchie Cobbs #include <sys/syslog.h>
59af7ab184SArchie Cobbs
60af7ab184SArchie Cobbs #include <netgraph/ng_message.h>
61af7ab184SArchie Cobbs #include <netgraph/netgraph.h>
62af7ab184SArchie Cobbs #include <netgraph/ng_mppc.h>
63af7ab184SArchie Cobbs
64af7ab184SArchie Cobbs #include "opt_netgraph.h"
65af7ab184SArchie Cobbs
66af7ab184SArchie Cobbs #if !defined(NETGRAPH_MPPC_COMPRESSION) && !defined(NETGRAPH_MPPC_ENCRYPTION)
6710d645b7SYaroslav Tykhiy #ifdef KLD_MODULE
68ec5753e0SPedro F. Giffuni #define NETGRAPH_MPPC_COMPRESSION
6910d645b7SYaroslav Tykhiy #define NETGRAPH_MPPC_ENCRYPTION
7010d645b7SYaroslav Tykhiy #else
7110d645b7SYaroslav Tykhiy /* This case is indicative of an error in sys/conf files */
72af7ab184SArchie Cobbs #error Need either NETGRAPH_MPPC_COMPRESSION or NETGRAPH_MPPC_ENCRYPTION
73af7ab184SArchie Cobbs #endif
7410d645b7SYaroslav Tykhiy #endif
75af7ab184SArchie Cobbs
769c8c302fSJulian Elischer #ifdef NG_SEPARATE_MALLOC
77d745c852SEd Schouten static MALLOC_DEFINE(M_NETGRAPH_MPPC, "netgraph_mppc", "netgraph mppc node");
789c8c302fSJulian Elischer #else
799c8c302fSJulian Elischer #define M_NETGRAPH_MPPC M_NETGRAPH
809c8c302fSJulian Elischer #endif
819c8c302fSJulian Elischer
82af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION
83af7ab184SArchie Cobbs #include <net/mppc.h>
84af7ab184SArchie Cobbs #endif
85af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION
86af7ab184SArchie Cobbs #include <crypto/rc4/rc4.h>
87af7ab184SArchie Cobbs #endif
88af7ab184SArchie Cobbs #include <crypto/sha1.h>
89af7ab184SArchie Cobbs
90af7ab184SArchie Cobbs /* Decompression blowup */
91af7ab184SArchie Cobbs #define MPPC_DECOMP_BUFSIZE 8092 /* allocate buffer this big */
92af7ab184SArchie Cobbs #define MPPC_DECOMP_SAFETY 100 /* plus this much margin */
93af7ab184SArchie Cobbs
94af7ab184SArchie Cobbs /* MPPC/MPPE header length */
95af7ab184SArchie Cobbs #define MPPC_HDRLEN 2
96af7ab184SArchie Cobbs
97af7ab184SArchie Cobbs /* Key length */
98af7ab184SArchie Cobbs #define KEYLEN(b) (((b) & MPPE_128) ? 16 : 8)
99af7ab184SArchie Cobbs
1005372c30bSGleb Smirnoff /*
1015372c30bSGleb Smirnoff * When packets are lost with MPPE, we may have to re-key arbitrarily
1025372c30bSGleb Smirnoff * many times to 'catch up' to the new jumped-ahead sequence number.
1035372c30bSGleb Smirnoff * Since this can be expensive, we pose a limit on how many re-keyings
1045372c30bSGleb Smirnoff * we will do at one time to avoid a possible D.O.S. vulnerability.
1055372c30bSGleb Smirnoff * This should instead be a configurable parameter.
1065372c30bSGleb Smirnoff */
1075372c30bSGleb Smirnoff #define MPPE_MAX_REKEY 1000
1085372c30bSGleb Smirnoff
109*7029da5cSPawel Biernacki SYSCTL_NODE(_net_graph, OID_AUTO, mppe, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
110*7029da5cSPawel Biernacki "MPPE");
111ee652839SAlexander Motin
112ee652839SAlexander Motin static int mppe_block_on_max_rekey = 0;
113af3b2549SHans Petter Selasky SYSCTL_INT(_net_graph_mppe, OID_AUTO, block_on_max_rekey, CTLFLAG_RWTUN,
114ee652839SAlexander Motin &mppe_block_on_max_rekey, 0, "Block node on max MPPE key re-calculations");
115ee652839SAlexander Motin
116ee652839SAlexander Motin static int mppe_log_max_rekey = 1;
117af3b2549SHans Petter Selasky SYSCTL_INT(_net_graph_mppe, OID_AUTO, log_max_rekey, CTLFLAG_RWTUN,
118ee652839SAlexander Motin &mppe_log_max_rekey, 0, "Log max MPPE key re-calculations event");
119ee652839SAlexander Motin
120ee652839SAlexander Motin static int mppe_max_rekey = MPPE_MAX_REKEY;
121af3b2549SHans Petter Selasky SYSCTL_INT(_net_graph_mppe, OID_AUTO, max_rekey, CTLFLAG_RWTUN,
122ee652839SAlexander Motin &mppe_max_rekey, 0, "Maximum number of MPPE key re-calculations");
123ee652839SAlexander Motin
124af7ab184SArchie Cobbs /* MPPC packet header bits */
125af7ab184SArchie Cobbs #define MPPC_FLAG_FLUSHED 0x8000 /* xmitter reset state */
126af7ab184SArchie Cobbs #define MPPC_FLAG_RESTART 0x4000 /* compress history restart */
127af7ab184SArchie Cobbs #define MPPC_FLAG_COMPRESSED 0x2000 /* packet is compresed */
128af7ab184SArchie Cobbs #define MPPC_FLAG_ENCRYPTED 0x1000 /* packet is encrypted */
129af7ab184SArchie Cobbs #define MPPC_CCOUNT_MASK 0x0fff /* sequence number mask */
130af7ab184SArchie Cobbs
131755bc287SAlexander Motin #define MPPC_CCOUNT_INC(d) ((d) = (((d) + 1) & MPPC_CCOUNT_MASK))
132755bc287SAlexander Motin
133af7ab184SArchie Cobbs #define MPPE_UPDATE_MASK 0xff /* coherency count when we're */
134af7ab184SArchie Cobbs #define MPPE_UPDATE_FLAG 0xff /* supposed to update key */
135af7ab184SArchie Cobbs
136af7ab184SArchie Cobbs #define MPPC_COMP_OK 0x05
137af7ab184SArchie Cobbs #define MPPC_DECOMP_OK 0x05
138af7ab184SArchie Cobbs
139af7ab184SArchie Cobbs /* Per direction info */
140af7ab184SArchie Cobbs struct ng_mppc_dir {
141af7ab184SArchie Cobbs struct ng_mppc_config cfg; /* configuration */
142af7ab184SArchie Cobbs hook_p hook; /* netgraph hook */
143af7ab184SArchie Cobbs u_int16_t cc:12; /* coherency count */
144af7ab184SArchie Cobbs u_char flushed; /* clean history (xmit only) */
145af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION
146af7ab184SArchie Cobbs u_char *history; /* compression history */
147af7ab184SArchie Cobbs #endif
148af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION
149af7ab184SArchie Cobbs u_char key[MPPE_KEY_LEN]; /* session key */
150af7ab184SArchie Cobbs struct rc4_state rc4; /* rc4 state */
151af7ab184SArchie Cobbs #endif
152af7ab184SArchie Cobbs };
153af7ab184SArchie Cobbs
154af7ab184SArchie Cobbs /* Node private data */
155af7ab184SArchie Cobbs struct ng_mppc_private {
156af7ab184SArchie Cobbs struct ng_mppc_dir xmit; /* compress/encrypt config */
157af7ab184SArchie Cobbs struct ng_mppc_dir recv; /* decompress/decrypt config */
158069154d5SJulian Elischer ng_ID_t ctrlnode; /* path to controlling node */
159af7ab184SArchie Cobbs };
160af7ab184SArchie Cobbs typedef struct ng_mppc_private *priv_p;
161af7ab184SArchie Cobbs
162af7ab184SArchie Cobbs /* Netgraph node methods */
163af7ab184SArchie Cobbs static ng_constructor_t ng_mppc_constructor;
164af7ab184SArchie Cobbs static ng_rcvmsg_t ng_mppc_rcvmsg;
165069154d5SJulian Elischer static ng_shutdown_t ng_mppc_shutdown;
166af7ab184SArchie Cobbs static ng_newhook_t ng_mppc_newhook;
167af7ab184SArchie Cobbs static ng_rcvdata_t ng_mppc_rcvdata;
168af7ab184SArchie Cobbs static ng_disconnect_t ng_mppc_disconnect;
169af7ab184SArchie Cobbs
170af7ab184SArchie Cobbs /* Helper functions */
171af7ab184SArchie Cobbs static int ng_mppc_compress(node_p node,
172ce52e8f4SAlexander Motin struct mbuf **datap);
173af7ab184SArchie Cobbs static int ng_mppc_decompress(node_p node,
174ce52e8f4SAlexander Motin struct mbuf **datap);
17506c51e6eSAlexander Motin #ifdef NETGRAPH_MPPC_ENCRYPTION
176af7ab184SArchie Cobbs static void ng_mppc_getkey(const u_char *h, u_char *h2, int len);
177af7ab184SArchie Cobbs static void ng_mppc_updatekey(u_int32_t bits,
178af7ab184SArchie Cobbs u_char *key0, u_char *key, struct rc4_state *rc4);
17906c51e6eSAlexander Motin #endif
180af7ab184SArchie Cobbs static void ng_mppc_reset_req(node_p node);
181af7ab184SArchie Cobbs
182af7ab184SArchie Cobbs /* Node type descriptor */
183af7ab184SArchie Cobbs static struct ng_type ng_mppc_typestruct = {
184f8aae777SJulian Elischer .version = NG_ABI_VERSION,
185f8aae777SJulian Elischer .name = NG_MPPC_NODE_TYPE,
186f8aae777SJulian Elischer .constructor = ng_mppc_constructor,
187f8aae777SJulian Elischer .rcvmsg = ng_mppc_rcvmsg,
188f8aae777SJulian Elischer .shutdown = ng_mppc_shutdown,
189f8aae777SJulian Elischer .newhook = ng_mppc_newhook,
190f8aae777SJulian Elischer .rcvdata = ng_mppc_rcvdata,
191f8aae777SJulian Elischer .disconnect = ng_mppc_disconnect,
192af7ab184SArchie Cobbs };
193af7ab184SArchie Cobbs NETGRAPH_INIT(mppc, &ng_mppc_typestruct);
194af7ab184SArchie Cobbs
195233896e9SDoug Ambrisko #ifdef NETGRAPH_MPPC_ENCRYPTION
196233896e9SDoug Ambrisko /* Depend on separate rc4 module */
197233896e9SDoug Ambrisko MODULE_DEPEND(ng_mppc, rc4, 1, 1, 1);
198233896e9SDoug Ambrisko #endif
199233896e9SDoug Ambrisko
20034fd2381SArchie Cobbs /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
201af7ab184SArchie Cobbs static const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e };
202af7ab184SArchie Cobbs
203af7ab184SArchie Cobbs #define ERROUT(x) do { error = (x); goto done; } while (0)
204af7ab184SArchie Cobbs
205af7ab184SArchie Cobbs /************************************************************************
206af7ab184SArchie Cobbs NETGRAPH NODE STUFF
207af7ab184SArchie Cobbs ************************************************************************/
208af7ab184SArchie Cobbs
209af7ab184SArchie Cobbs /*
210af7ab184SArchie Cobbs * Node type constructor
211af7ab184SArchie Cobbs */
212af7ab184SArchie Cobbs static int
ng_mppc_constructor(node_p node)213069154d5SJulian Elischer ng_mppc_constructor(node_p node)
214af7ab184SArchie Cobbs {
215af7ab184SArchie Cobbs priv_p priv;
216af7ab184SArchie Cobbs
217af7ab184SArchie Cobbs /* Allocate private structure */
218674d86bfSGleb Smirnoff priv = malloc(sizeof(*priv), M_NETGRAPH_MPPC, M_WAITOK | M_ZERO);
219af7ab184SArchie Cobbs
22030400f03SJulian Elischer NG_NODE_SET_PRIVATE(node, priv);
221af7ab184SArchie Cobbs
2222f07580bSGleb Smirnoff /* This node is not thread safe. */
2232f07580bSGleb Smirnoff NG_NODE_FORCE_WRITER(node);
2242f07580bSGleb Smirnoff
225af7ab184SArchie Cobbs /* Done */
226af7ab184SArchie Cobbs return (0);
227af7ab184SArchie Cobbs }
228af7ab184SArchie Cobbs
229af7ab184SArchie Cobbs /*
230af7ab184SArchie Cobbs * Give our OK for a hook to be added
231af7ab184SArchie Cobbs */
232af7ab184SArchie Cobbs static int
ng_mppc_newhook(node_p node,hook_p hook,const char * name)233af7ab184SArchie Cobbs ng_mppc_newhook(node_p node, hook_p hook, const char *name)
234af7ab184SArchie Cobbs {
23530400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node);
236af7ab184SArchie Cobbs hook_p *hookPtr;
237af7ab184SArchie Cobbs
238af7ab184SArchie Cobbs /* Check hook name */
239af7ab184SArchie Cobbs if (strcmp(name, NG_MPPC_HOOK_COMP) == 0)
240af7ab184SArchie Cobbs hookPtr = &priv->xmit.hook;
241af7ab184SArchie Cobbs else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0)
242af7ab184SArchie Cobbs hookPtr = &priv->recv.hook;
243af7ab184SArchie Cobbs else
244af7ab184SArchie Cobbs return (EINVAL);
245af7ab184SArchie Cobbs
246af7ab184SArchie Cobbs /* See if already connected */
247af7ab184SArchie Cobbs if (*hookPtr != NULL)
248af7ab184SArchie Cobbs return (EISCONN);
249af7ab184SArchie Cobbs
250af7ab184SArchie Cobbs /* OK */
251af7ab184SArchie Cobbs *hookPtr = hook;
252af7ab184SArchie Cobbs return (0);
253af7ab184SArchie Cobbs }
254af7ab184SArchie Cobbs
255af7ab184SArchie Cobbs /*
256af7ab184SArchie Cobbs * Receive a control message
257af7ab184SArchie Cobbs */
258af7ab184SArchie Cobbs static int
ng_mppc_rcvmsg(node_p node,item_p item,hook_p lasthook)259069154d5SJulian Elischer ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook)
260af7ab184SArchie Cobbs {
26130400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node);
262af7ab184SArchie Cobbs struct ng_mesg *resp = NULL;
263af7ab184SArchie Cobbs int error = 0;
264069154d5SJulian Elischer struct ng_mesg *msg;
265af7ab184SArchie Cobbs
266069154d5SJulian Elischer NGI_GET_MSG(item, msg);
267af7ab184SArchie Cobbs switch (msg->header.typecookie) {
268af7ab184SArchie Cobbs case NGM_MPPC_COOKIE:
269af7ab184SArchie Cobbs switch (msg->header.cmd) {
270af7ab184SArchie Cobbs case NGM_MPPC_CONFIG_COMP:
271af7ab184SArchie Cobbs case NGM_MPPC_CONFIG_DECOMP:
272af7ab184SArchie Cobbs {
273af7ab184SArchie Cobbs struct ng_mppc_config *const cfg
274af7ab184SArchie Cobbs = (struct ng_mppc_config *)msg->data;
275af7ab184SArchie Cobbs const int isComp =
276af7ab184SArchie Cobbs msg->header.cmd == NGM_MPPC_CONFIG_COMP;
277af7ab184SArchie Cobbs struct ng_mppc_dir *const d = isComp ?
278af7ab184SArchie Cobbs &priv->xmit : &priv->recv;
279af7ab184SArchie Cobbs
280af7ab184SArchie Cobbs /* Check configuration */
281af7ab184SArchie Cobbs if (msg->header.arglen != sizeof(*cfg))
282af7ab184SArchie Cobbs ERROUT(EINVAL);
283af7ab184SArchie Cobbs if (cfg->enable) {
284af7ab184SArchie Cobbs if ((cfg->bits & ~MPPC_VALID_BITS) != 0)
285af7ab184SArchie Cobbs ERROUT(EINVAL);
286af7ab184SArchie Cobbs #ifndef NETGRAPH_MPPC_COMPRESSION
287af7ab184SArchie Cobbs if ((cfg->bits & MPPC_BIT) != 0)
288af7ab184SArchie Cobbs ERROUT(EPROTONOSUPPORT);
289af7ab184SArchie Cobbs #endif
290af7ab184SArchie Cobbs #ifndef NETGRAPH_MPPC_ENCRYPTION
291af7ab184SArchie Cobbs if ((cfg->bits & MPPE_BITS) != 0)
292af7ab184SArchie Cobbs ERROUT(EPROTONOSUPPORT);
293af7ab184SArchie Cobbs #endif
294af7ab184SArchie Cobbs } else
295af7ab184SArchie Cobbs cfg->bits = 0;
296af7ab184SArchie Cobbs
297af7ab184SArchie Cobbs /* Save return address so we can send reset-req's */
298f3059f39SArchie Cobbs if (!isComp)
299069154d5SJulian Elischer priv->ctrlnode = NGI_RETADDR(item);
300af7ab184SArchie Cobbs
301af7ab184SArchie Cobbs /* Configuration is OK, reset to it */
302af7ab184SArchie Cobbs d->cfg = *cfg;
303af7ab184SArchie Cobbs
304af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION
305af7ab184SArchie Cobbs /* Initialize state buffers for compression */
306af7ab184SArchie Cobbs if (d->history != NULL) {
3071ede983cSDag-Erling Smørgrav free(d->history, M_NETGRAPH_MPPC);
308af7ab184SArchie Cobbs d->history = NULL;
309af7ab184SArchie Cobbs }
310af7ab184SArchie Cobbs if ((cfg->bits & MPPC_BIT) != 0) {
311e11e3f18SDag-Erling Smørgrav d->history = malloc(isComp ?
312e11e3f18SDag-Erling Smørgrav MPPC_SizeOfCompressionHistory() :
313af7ab184SArchie Cobbs MPPC_SizeOfDecompressionHistory(),
3149c8c302fSJulian Elischer M_NETGRAPH_MPPC, M_NOWAIT);
315af7ab184SArchie Cobbs if (d->history == NULL)
316af7ab184SArchie Cobbs ERROUT(ENOMEM);
317af7ab184SArchie Cobbs if (isComp)
318af7ab184SArchie Cobbs MPPC_InitCompressionHistory(d->history);
319af7ab184SArchie Cobbs else {
320af7ab184SArchie Cobbs MPPC_InitDecompressionHistory(
321af7ab184SArchie Cobbs d->history);
322af7ab184SArchie Cobbs }
323af7ab184SArchie Cobbs }
324af7ab184SArchie Cobbs #endif
325af7ab184SArchie Cobbs
326af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION
327af7ab184SArchie Cobbs /* Generate initial session keys for encryption */
328af7ab184SArchie Cobbs if ((cfg->bits & MPPE_BITS) != 0) {
329af7ab184SArchie Cobbs const int keylen = KEYLEN(cfg->bits);
330af7ab184SArchie Cobbs
331af7ab184SArchie Cobbs bcopy(cfg->startkey, d->key, keylen);
332af7ab184SArchie Cobbs ng_mppc_getkey(cfg->startkey, d->key, keylen);
33334fd2381SArchie Cobbs if ((cfg->bits & MPPE_40) != 0)
33434fd2381SArchie Cobbs bcopy(&ng_mppe_weakenkey, d->key, 3);
33534fd2381SArchie Cobbs else if ((cfg->bits & MPPE_56) != 0)
33634fd2381SArchie Cobbs bcopy(&ng_mppe_weakenkey, d->key, 1);
337af7ab184SArchie Cobbs rc4_init(&d->rc4, d->key, keylen);
338af7ab184SArchie Cobbs }
339af7ab184SArchie Cobbs #endif
340af7ab184SArchie Cobbs
341af7ab184SArchie Cobbs /* Initialize other state */
342af7ab184SArchie Cobbs d->cc = 0;
343af7ab184SArchie Cobbs d->flushed = 0;
344af7ab184SArchie Cobbs break;
345af7ab184SArchie Cobbs }
346af7ab184SArchie Cobbs
347af7ab184SArchie Cobbs case NGM_MPPC_RESETREQ:
348af7ab184SArchie Cobbs ng_mppc_reset_req(node);
349af7ab184SArchie Cobbs break;
350af7ab184SArchie Cobbs
351af7ab184SArchie Cobbs default:
352af7ab184SArchie Cobbs error = EINVAL;
353af7ab184SArchie Cobbs break;
354af7ab184SArchie Cobbs }
355af7ab184SArchie Cobbs break;
356af7ab184SArchie Cobbs default:
357af7ab184SArchie Cobbs error = EINVAL;
358af7ab184SArchie Cobbs break;
359af7ab184SArchie Cobbs }
360af7ab184SArchie Cobbs done:
361069154d5SJulian Elischer NG_RESPOND_MSG(error, node, item, resp);
362069154d5SJulian Elischer NG_FREE_MSG(msg);
363af7ab184SArchie Cobbs return (error);
364af7ab184SArchie Cobbs }
365af7ab184SArchie Cobbs
366af7ab184SArchie Cobbs /*
367af7ab184SArchie Cobbs * Receive incoming data on our hook.
368af7ab184SArchie Cobbs */
369af7ab184SArchie Cobbs static int
ng_mppc_rcvdata(hook_p hook,item_p item)370069154d5SJulian Elischer ng_mppc_rcvdata(hook_p hook, item_p item)
371af7ab184SArchie Cobbs {
37230400f03SJulian Elischer const node_p node = NG_HOOK_NODE(hook);
37330400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node);
374af7ab184SArchie Cobbs int error;
375069154d5SJulian Elischer struct mbuf *m;
376af7ab184SArchie Cobbs
377069154d5SJulian Elischer NGI_GET_M(item, m);
378af7ab184SArchie Cobbs /* Compress and/or encrypt */
379af7ab184SArchie Cobbs if (hook == priv->xmit.hook) {
380af7ab184SArchie Cobbs if (!priv->xmit.cfg.enable) {
381069154d5SJulian Elischer NG_FREE_M(m);
382069154d5SJulian Elischer NG_FREE_ITEM(item);
383af7ab184SArchie Cobbs return (ENXIO);
384af7ab184SArchie Cobbs }
385ce52e8f4SAlexander Motin if ((error = ng_mppc_compress(node, &m)) != 0) {
386069154d5SJulian Elischer NG_FREE_ITEM(item);
387af7ab184SArchie Cobbs return(error);
388af7ab184SArchie Cobbs }
389ce52e8f4SAlexander Motin NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m);
390af7ab184SArchie Cobbs return (error);
391af7ab184SArchie Cobbs }
392af7ab184SArchie Cobbs
393af7ab184SArchie Cobbs /* Decompress and/or decrypt */
394af7ab184SArchie Cobbs if (hook == priv->recv.hook) {
395af7ab184SArchie Cobbs if (!priv->recv.cfg.enable) {
396069154d5SJulian Elischer NG_FREE_M(m);
397069154d5SJulian Elischer NG_FREE_ITEM(item);
398af7ab184SArchie Cobbs return (ENXIO);
399af7ab184SArchie Cobbs }
400ce52e8f4SAlexander Motin if ((error = ng_mppc_decompress(node, &m)) != 0) {
401069154d5SJulian Elischer NG_FREE_ITEM(item);
402facfd889SArchie Cobbs if (error == EINVAL && priv->ctrlnode != 0) {
403af7ab184SArchie Cobbs struct ng_mesg *msg;
404af7ab184SArchie Cobbs
405af7ab184SArchie Cobbs /* Need to send a reset-request */
406af7ab184SArchie Cobbs NG_MKMESSAGE(msg, NGM_MPPC_COOKIE,
407af7ab184SArchie Cobbs NGM_MPPC_RESETREQ, 0, M_NOWAIT);
408af7ab184SArchie Cobbs if (msg == NULL)
409af7ab184SArchie Cobbs return (error);
410069154d5SJulian Elischer NG_SEND_MSG_ID(error, node, msg,
411facfd889SArchie Cobbs priv->ctrlnode, 0);
412af7ab184SArchie Cobbs }
413af7ab184SArchie Cobbs return (error);
414af7ab184SArchie Cobbs }
415ce52e8f4SAlexander Motin NG_FWD_NEW_DATA(error, item, priv->recv.hook, m);
416af7ab184SArchie Cobbs return (error);
417af7ab184SArchie Cobbs }
418af7ab184SArchie Cobbs
419af7ab184SArchie Cobbs /* Oops */
4206e551fb6SDavid E. O'Brien panic("%s: unknown hook", __func__);
421af7ab184SArchie Cobbs }
422af7ab184SArchie Cobbs
423af7ab184SArchie Cobbs /*
424af7ab184SArchie Cobbs * Destroy node
425af7ab184SArchie Cobbs */
426af7ab184SArchie Cobbs static int
ng_mppc_shutdown(node_p node)427069154d5SJulian Elischer ng_mppc_shutdown(node_p node)
428af7ab184SArchie Cobbs {
42930400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node);
430af7ab184SArchie Cobbs
431af7ab184SArchie Cobbs /* Take down netgraph node */
432af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION
433af7ab184SArchie Cobbs if (priv->xmit.history != NULL)
4341ede983cSDag-Erling Smørgrav free(priv->xmit.history, M_NETGRAPH_MPPC);
435af7ab184SArchie Cobbs if (priv->recv.history != NULL)
4361ede983cSDag-Erling Smørgrav free(priv->recv.history, M_NETGRAPH_MPPC);
437af7ab184SArchie Cobbs #endif
438af7ab184SArchie Cobbs bzero(priv, sizeof(*priv));
4391ede983cSDag-Erling Smørgrav free(priv, M_NETGRAPH_MPPC);
44030400f03SJulian Elischer NG_NODE_SET_PRIVATE(node, NULL);
44130400f03SJulian Elischer NG_NODE_UNREF(node); /* let the node escape */
442af7ab184SArchie Cobbs return (0);
443af7ab184SArchie Cobbs }
444af7ab184SArchie Cobbs
445af7ab184SArchie Cobbs /*
446af7ab184SArchie Cobbs * Hook disconnection
447af7ab184SArchie Cobbs */
448af7ab184SArchie Cobbs static int
ng_mppc_disconnect(hook_p hook)449af7ab184SArchie Cobbs ng_mppc_disconnect(hook_p hook)
450af7ab184SArchie Cobbs {
45130400f03SJulian Elischer const node_p node = NG_HOOK_NODE(hook);
45230400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node);
453af7ab184SArchie Cobbs
454af7ab184SArchie Cobbs /* Zero out hook pointer */
455af7ab184SArchie Cobbs if (hook == priv->xmit.hook)
456af7ab184SArchie Cobbs priv->xmit.hook = NULL;
457af7ab184SArchie Cobbs if (hook == priv->recv.hook)
458af7ab184SArchie Cobbs priv->recv.hook = NULL;
459af7ab184SArchie Cobbs
460af7ab184SArchie Cobbs /* Go away if no longer connected */
46130400f03SJulian Elischer if ((NG_NODE_NUMHOOKS(node) == 0)
46230400f03SJulian Elischer && NG_NODE_IS_VALID(node))
463069154d5SJulian Elischer ng_rmnode_self(node);
464af7ab184SArchie Cobbs return (0);
465af7ab184SArchie Cobbs }
466af7ab184SArchie Cobbs
467af7ab184SArchie Cobbs /************************************************************************
468af7ab184SArchie Cobbs HELPER STUFF
469af7ab184SArchie Cobbs ************************************************************************/
470af7ab184SArchie Cobbs
471af7ab184SArchie Cobbs /*
472af7ab184SArchie Cobbs * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
473af7ab184SArchie Cobbs * The original mbuf is not free'd.
474af7ab184SArchie Cobbs */
475af7ab184SArchie Cobbs static int
ng_mppc_compress(node_p node,struct mbuf ** datap)476ce52e8f4SAlexander Motin ng_mppc_compress(node_p node, struct mbuf **datap)
477af7ab184SArchie Cobbs {
47830400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node);
479af7ab184SArchie Cobbs struct ng_mppc_dir *const d = &priv->xmit;
480af7ab184SArchie Cobbs u_int16_t header;
481ce52e8f4SAlexander Motin struct mbuf *m = *datap;
482af7ab184SArchie Cobbs
483e4651e05SAlexander Motin /* We must own the mbuf chain exclusively to modify it. */
484eb1b1807SGleb Smirnoff m = m_unshare(m, M_NOWAIT);
485e4651e05SAlexander Motin if (m == NULL)
486e4651e05SAlexander Motin return (ENOMEM);
487e4651e05SAlexander Motin
488af7ab184SArchie Cobbs /* Initialize */
489af7ab184SArchie Cobbs header = d->cc;
490adecf751SAlexander Motin
491adecf751SAlexander Motin /* Always set the flushed bit in stateless mode */
492adecf751SAlexander Motin if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) {
493af7ab184SArchie Cobbs header |= MPPC_FLAG_FLUSHED;
494af7ab184SArchie Cobbs d->flushed = 0;
495af7ab184SArchie Cobbs }
496af7ab184SArchie Cobbs
497ce52e8f4SAlexander Motin /* Compress packet (if compression enabled) */
498af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION
499af7ab184SArchie Cobbs if ((d->cfg.bits & MPPC_BIT) != 0) {
500af7ab184SArchie Cobbs u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS;
501ce52e8f4SAlexander Motin u_char *inbuf, *outbuf;
50267898a23SAlexander Motin int outlen, inlen, ina;
503af7ab184SArchie Cobbs u_char *source, *dest;
504af7ab184SArchie Cobbs u_long sourceCnt, destCnt;
505af7ab184SArchie Cobbs int rtn;
506af7ab184SArchie Cobbs
507ce52e8f4SAlexander Motin /* Work with contiguous regions of memory. */
508ce52e8f4SAlexander Motin inlen = m->m_pkthdr.len;
50967898a23SAlexander Motin if (m->m_next == NULL) {
51067898a23SAlexander Motin inbuf = mtod(m, u_char *);
51167898a23SAlexander Motin ina = 0;
51267898a23SAlexander Motin } else {
513ce52e8f4SAlexander Motin inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
51411d1cadeSAlexander Motin if (inbuf == NULL)
51511d1cadeSAlexander Motin goto err1;
516ce52e8f4SAlexander Motin m_copydata(m, 0, inlen, (caddr_t)inbuf);
51767898a23SAlexander Motin ina = 1;
51867898a23SAlexander Motin }
519ce52e8f4SAlexander Motin
520ce52e8f4SAlexander Motin outlen = MPPC_MAX_BLOWUP(inlen);
521ce52e8f4SAlexander Motin outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT);
522ce52e8f4SAlexander Motin if (outbuf == NULL) {
52367898a23SAlexander Motin if (ina)
524ce52e8f4SAlexander Motin free(inbuf, M_NETGRAPH_MPPC);
52511d1cadeSAlexander Motin err1:
52611d1cadeSAlexander Motin m_freem(m);
52711d1cadeSAlexander Motin MPPC_InitCompressionHistory(d->history);
52811d1cadeSAlexander Motin d->flushed = 1;
529ce52e8f4SAlexander Motin return (ENOMEM);
530ce52e8f4SAlexander Motin }
531ce52e8f4SAlexander Motin
532af7ab184SArchie Cobbs /* Prepare to compress */
533af7ab184SArchie Cobbs source = inbuf;
534af7ab184SArchie Cobbs sourceCnt = inlen;
535ce52e8f4SAlexander Motin dest = outbuf;
536ce52e8f4SAlexander Motin destCnt = outlen;
537af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_STATELESS) == 0)
538af7ab184SArchie Cobbs flags |= MPPC_SAVE_HISTORY;
539af7ab184SArchie Cobbs
540af7ab184SArchie Cobbs /* Compress */
541af7ab184SArchie Cobbs rtn = MPPC_Compress(&source, &dest, &sourceCnt,
542af7ab184SArchie Cobbs &destCnt, d->history, flags, 0);
543af7ab184SArchie Cobbs
544af7ab184SArchie Cobbs /* Check return value */
545ec5753e0SPedro F. Giffuni /* KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); */
546af7ab184SArchie Cobbs if ((rtn & MPPC_EXPANDED) == 0
547af7ab184SArchie Cobbs && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) {
548af7ab184SArchie Cobbs outlen -= destCnt;
549af7ab184SArchie Cobbs header |= MPPC_FLAG_COMPRESSED;
550af7ab184SArchie Cobbs if ((rtn & MPPC_RESTART_HISTORY) != 0)
551af7ab184SArchie Cobbs header |= MPPC_FLAG_RESTART;
552ce52e8f4SAlexander Motin
553ce52e8f4SAlexander Motin /* Replace m by the compresed one. */
554e4651e05SAlexander Motin m_copyback(m, 0, outlen, (caddr_t)outbuf);
555e4651e05SAlexander Motin if (m->m_pkthdr.len < outlen) {
556ce52e8f4SAlexander Motin m_freem(m);
557e4651e05SAlexander Motin m = NULL;
558e4651e05SAlexander Motin } else if (outlen < m->m_pkthdr.len)
559e4651e05SAlexander Motin m_adj(m, outlen - m->m_pkthdr.len);
560af7ab184SArchie Cobbs }
561af7ab184SArchie Cobbs d->flushed = (rtn & MPPC_EXPANDED) != 0
562af7ab184SArchie Cobbs || (flags & MPPC_SAVE_HISTORY) == 0;
563ce52e8f4SAlexander Motin
56467898a23SAlexander Motin if (ina)
565ce52e8f4SAlexander Motin free(inbuf, M_NETGRAPH_MPPC);
566ce52e8f4SAlexander Motin free(outbuf, M_NETGRAPH_MPPC);
567ce52e8f4SAlexander Motin
568e4651e05SAlexander Motin /* Check mbuf chain reload result. */
56911d1cadeSAlexander Motin if (m == NULL) {
57011d1cadeSAlexander Motin if (!d->flushed) {
57111d1cadeSAlexander Motin MPPC_InitCompressionHistory(d->history);
57211d1cadeSAlexander Motin d->flushed = 1;
57311d1cadeSAlexander Motin }
574ce52e8f4SAlexander Motin return (ENOMEM);
575af7ab184SArchie Cobbs }
57611d1cadeSAlexander Motin }
577af7ab184SArchie Cobbs #endif
578af7ab184SArchie Cobbs
579af7ab184SArchie Cobbs /* Now encrypt packet (if encryption enabled) */
580af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION
581af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_BITS) != 0) {
582ce52e8f4SAlexander Motin struct mbuf *m1;
583af7ab184SArchie Cobbs
5846370fd6bSAlexander Motin /* Set header bits */
585af7ab184SArchie Cobbs header |= MPPC_FLAG_ENCRYPTED;
586af7ab184SArchie Cobbs
587af7ab184SArchie Cobbs /* Update key if it's time */
588af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_STATELESS) != 0
589af7ab184SArchie Cobbs || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
590af7ab184SArchie Cobbs ng_mppc_updatekey(d->cfg.bits,
591af7ab184SArchie Cobbs d->cfg.startkey, d->key, &d->rc4);
5926370fd6bSAlexander Motin } else if ((header & MPPC_FLAG_FLUSHED) != 0) {
5936370fd6bSAlexander Motin /* Need to reset key if we say we did
5946370fd6bSAlexander Motin and ng_mppc_updatekey wasn't called to do it also. */
5956370fd6bSAlexander Motin rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
596af7ab184SArchie Cobbs }
597af7ab184SArchie Cobbs
598af7ab184SArchie Cobbs /* Encrypt packet */
599ce52e8f4SAlexander Motin m1 = m;
600ce52e8f4SAlexander Motin while (m1) {
601ce52e8f4SAlexander Motin rc4_crypt(&d->rc4, mtod(m1, u_char *),
602ce52e8f4SAlexander Motin mtod(m1, u_char *), m1->m_len);
603ce52e8f4SAlexander Motin m1 = m1->m_next;
604ce52e8f4SAlexander Motin }
605af7ab184SArchie Cobbs }
606af7ab184SArchie Cobbs #endif
607af7ab184SArchie Cobbs
608755bc287SAlexander Motin /* Update coherency count for next time (12 bit arithmetic) */
609755bc287SAlexander Motin MPPC_CCOUNT_INC(d->cc);
610af7ab184SArchie Cobbs
611af7ab184SArchie Cobbs /* Install header */
612eb1b1807SGleb Smirnoff M_PREPEND(m, MPPC_HDRLEN, M_NOWAIT);
613ce52e8f4SAlexander Motin if (m != NULL)
61439228864SAlexander Motin be16enc(mtod(m, void *), header);
615af7ab184SArchie Cobbs
616ce52e8f4SAlexander Motin *datap = m;
617ce52e8f4SAlexander Motin return (*datap == NULL ? ENOBUFS : 0);
618af7ab184SArchie Cobbs }
619af7ab184SArchie Cobbs
620af7ab184SArchie Cobbs /*
621af7ab184SArchie Cobbs * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
622af7ab184SArchie Cobbs * The original mbuf is not free'd.
623af7ab184SArchie Cobbs */
624af7ab184SArchie Cobbs static int
ng_mppc_decompress(node_p node,struct mbuf ** datap)625ce52e8f4SAlexander Motin ng_mppc_decompress(node_p node, struct mbuf **datap)
626af7ab184SArchie Cobbs {
62730400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node);
628af7ab184SArchie Cobbs struct ng_mppc_dir *const d = &priv->recv;
629f3059f39SArchie Cobbs u_int16_t header, cc;
630f3059f39SArchie Cobbs u_int numLost;
631ce52e8f4SAlexander Motin struct mbuf *m = *datap;
632af7ab184SArchie Cobbs
633e4651e05SAlexander Motin /* We must own the mbuf chain exclusively to modify it. */
634eb1b1807SGleb Smirnoff m = m_unshare(m, M_NOWAIT);
635e4651e05SAlexander Motin if (m == NULL)
636e4651e05SAlexander Motin return (ENOMEM);
637e4651e05SAlexander Motin
638af7ab184SArchie Cobbs /* Pull off header */
639ce52e8f4SAlexander Motin if (m->m_pkthdr.len < MPPC_HDRLEN) {
640ce52e8f4SAlexander Motin m_freem(m);
641af7ab184SArchie Cobbs return (EINVAL);
642ce52e8f4SAlexander Motin }
64339228864SAlexander Motin header = be16dec(mtod(m, void *));
644af7ab184SArchie Cobbs cc = (header & MPPC_CCOUNT_MASK);
645ce52e8f4SAlexander Motin m_adj(m, MPPC_HDRLEN);
646af7ab184SArchie Cobbs
647f3059f39SArchie Cobbs /* Check for an unexpected jump in the sequence number */
648af7ab184SArchie Cobbs numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK);
649af7ab184SArchie Cobbs
650af7ab184SArchie Cobbs /* If flushed bit set, we can always handle packet */
651af7ab184SArchie Cobbs if ((header & MPPC_FLAG_FLUSHED) != 0) {
652af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION
653af7ab184SArchie Cobbs if (d->history != NULL)
654af7ab184SArchie Cobbs MPPC_InitDecompressionHistory(d->history);
655af7ab184SArchie Cobbs #endif
656af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION
657af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_BITS) != 0) {
658f3059f39SArchie Cobbs u_int rekey;
659af7ab184SArchie Cobbs
660f3059f39SArchie Cobbs /* How many times are we going to have to re-key? */
661f3059f39SArchie Cobbs rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ?
662f3059f39SArchie Cobbs numLost : (numLost / (MPPE_UPDATE_MASK + 1));
663ee652839SAlexander Motin if (rekey > mppe_max_rekey) {
664ee652839SAlexander Motin if (mppe_block_on_max_rekey) {
665ee652839SAlexander Motin if (mppe_log_max_rekey) {
6665372c30bSGleb Smirnoff log(LOG_ERR, "%s: too many (%d) packets"
667ee652839SAlexander Motin " dropped, disabling node %p!\n",
6685372c30bSGleb Smirnoff __func__, numLost, node);
669ee652839SAlexander Motin }
6705372c30bSGleb Smirnoff priv->recv.cfg.enable = 0;
6715372c30bSGleb Smirnoff goto failed;
672ee652839SAlexander Motin } else {
673ee652839SAlexander Motin if (mppe_log_max_rekey) {
674ee652839SAlexander Motin log(LOG_ERR, "%s: %d packets"
675ee652839SAlexander Motin " dropped, node %p\n",
676ee652839SAlexander Motin __func__, numLost, node);
677ee652839SAlexander Motin }
678ee652839SAlexander Motin goto failed;
679ee652839SAlexander Motin }
6805372c30bSGleb Smirnoff }
681f3059f39SArchie Cobbs
6825372c30bSGleb Smirnoff /* Re-key as necessary to catch up to peer */
683af7ab184SArchie Cobbs while (d->cc != cc) {
684f3059f39SArchie Cobbs if ((d->cfg.bits & MPPE_STATELESS) != 0
685af7ab184SArchie Cobbs || (d->cc & MPPE_UPDATE_MASK)
686af7ab184SArchie Cobbs == MPPE_UPDATE_FLAG) {
687af7ab184SArchie Cobbs ng_mppc_updatekey(d->cfg.bits,
688af7ab184SArchie Cobbs d->cfg.startkey, d->key, &d->rc4);
689af7ab184SArchie Cobbs }
690755bc287SAlexander Motin MPPC_CCOUNT_INC(d->cc);
691af7ab184SArchie Cobbs }
692af7ab184SArchie Cobbs
693af7ab184SArchie Cobbs /* Reset key (except in stateless mode, see below) */
694af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_STATELESS) == 0)
695af7ab184SArchie Cobbs rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
696af7ab184SArchie Cobbs }
697af7ab184SArchie Cobbs #endif
698af7ab184SArchie Cobbs d->cc = cc; /* skip over lost seq numbers */
699af7ab184SArchie Cobbs numLost = 0; /* act like no packets were lost */
700af7ab184SArchie Cobbs }
701af7ab184SArchie Cobbs
702af7ab184SArchie Cobbs /* Can't decode non-sequential packets without a flushed bit */
703af7ab184SArchie Cobbs if (numLost != 0)
704af7ab184SArchie Cobbs goto failed;
705af7ab184SArchie Cobbs
706af7ab184SArchie Cobbs /* Decrypt packet */
707af7ab184SArchie Cobbs if ((header & MPPC_FLAG_ENCRYPTED) != 0) {
708ce52e8f4SAlexander Motin #ifdef NETGRAPH_MPPC_ENCRYPTION
709ce52e8f4SAlexander Motin struct mbuf *m1;
710ce52e8f4SAlexander Motin #endif
711af7ab184SArchie Cobbs
712af7ab184SArchie Cobbs /* Are we not expecting encryption? */
713af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_BITS) == 0) {
714af7ab184SArchie Cobbs log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
7156e551fb6SDavid E. O'Brien __func__, "encrypted");
716af7ab184SArchie Cobbs goto failed;
717af7ab184SArchie Cobbs }
718af7ab184SArchie Cobbs
719af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION
720af7ab184SArchie Cobbs /* Update key if it's time (always in stateless mode) */
721af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_STATELESS) != 0
722af7ab184SArchie Cobbs || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
723af7ab184SArchie Cobbs ng_mppc_updatekey(d->cfg.bits,
724af7ab184SArchie Cobbs d->cfg.startkey, d->key, &d->rc4);
725af7ab184SArchie Cobbs }
726af7ab184SArchie Cobbs
727af7ab184SArchie Cobbs /* Decrypt packet */
728ce52e8f4SAlexander Motin m1 = m;
729ce52e8f4SAlexander Motin while (m1 != NULL) {
730ce52e8f4SAlexander Motin rc4_crypt(&d->rc4, mtod(m1, u_char *),
731ce52e8f4SAlexander Motin mtod(m1, u_char *), m1->m_len);
732ce52e8f4SAlexander Motin m1 = m1->m_next;
733ce52e8f4SAlexander Motin }
734af7ab184SArchie Cobbs #endif
735af7ab184SArchie Cobbs } else {
736af7ab184SArchie Cobbs /* Are we expecting encryption? */
737af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_BITS) != 0) {
738af7ab184SArchie Cobbs log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
7396e551fb6SDavid E. O'Brien __func__, "unencrypted");
740af7ab184SArchie Cobbs goto failed;
741af7ab184SArchie Cobbs }
742af7ab184SArchie Cobbs }
743af7ab184SArchie Cobbs
744af7ab184SArchie Cobbs /* Update coherency count for next time (12 bit arithmetic) */
745755bc287SAlexander Motin MPPC_CCOUNT_INC(d->cc);
746af7ab184SArchie Cobbs
747af7ab184SArchie Cobbs /* Check for unexpected compressed packet */
748af7ab184SArchie Cobbs if ((header & MPPC_FLAG_COMPRESSED) != 0
749af7ab184SArchie Cobbs && (d->cfg.bits & MPPC_BIT) == 0) {
750af7ab184SArchie Cobbs log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
7516e551fb6SDavid E. O'Brien __func__, "compressed");
752af7ab184SArchie Cobbs failed:
753ce52e8f4SAlexander Motin m_freem(m);
754af7ab184SArchie Cobbs return (EINVAL);
755af7ab184SArchie Cobbs }
756af7ab184SArchie Cobbs
757af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION
758af7ab184SArchie Cobbs /* Decompress packet */
759af7ab184SArchie Cobbs if ((header & MPPC_FLAG_COMPRESSED) != 0) {
760af7ab184SArchie Cobbs int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS;
76167898a23SAlexander Motin u_char *inbuf, *outbuf;
76267898a23SAlexander Motin int inlen, outlen, ina;
76367898a23SAlexander Motin u_char *source, *dest;
764af7ab184SArchie Cobbs u_long sourceCnt, destCnt;
76567898a23SAlexander Motin int rtn;
766ce52e8f4SAlexander Motin
767ce52e8f4SAlexander Motin /* Copy payload into a contiguous region of memory. */
76867898a23SAlexander Motin inlen = m->m_pkthdr.len;
76967898a23SAlexander Motin if (m->m_next == NULL) {
77067898a23SAlexander Motin inbuf = mtod(m, u_char *);
77167898a23SAlexander Motin ina = 0;
77267898a23SAlexander Motin } else {
77367898a23SAlexander Motin inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
77467898a23SAlexander Motin if (inbuf == NULL) {
775ce52e8f4SAlexander Motin m_freem(m);
776ce52e8f4SAlexander Motin return (ENOMEM);
777ce52e8f4SAlexander Motin }
77867898a23SAlexander Motin m_copydata(m, 0, inlen, (caddr_t)inbuf);
77967898a23SAlexander Motin ina = 1;
78067898a23SAlexander Motin }
781af7ab184SArchie Cobbs
782af7ab184SArchie Cobbs /* Allocate a buffer for decompressed data */
78367898a23SAlexander Motin outbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY,
784ce52e8f4SAlexander Motin M_NETGRAPH_MPPC, M_NOWAIT);
78567898a23SAlexander Motin if (outbuf == NULL) {
786ce52e8f4SAlexander Motin m_freem(m);
78767898a23SAlexander Motin if (ina)
78867898a23SAlexander Motin free(inbuf, M_NETGRAPH_MPPC);
789af7ab184SArchie Cobbs return (ENOMEM);
790af7ab184SArchie Cobbs }
79167898a23SAlexander Motin outlen = MPPC_DECOMP_BUFSIZE;
792af7ab184SArchie Cobbs
793af7ab184SArchie Cobbs /* Prepare to decompress */
79467898a23SAlexander Motin source = inbuf;
79567898a23SAlexander Motin sourceCnt = inlen;
79667898a23SAlexander Motin dest = outbuf;
79767898a23SAlexander Motin destCnt = outlen;
798af7ab184SArchie Cobbs if ((header & MPPC_FLAG_RESTART) != 0)
799af7ab184SArchie Cobbs flags |= MPPC_RESTART_HISTORY;
800af7ab184SArchie Cobbs
801af7ab184SArchie Cobbs /* Decompress */
802af7ab184SArchie Cobbs rtn = MPPC_Decompress(&source, &dest,
803af7ab184SArchie Cobbs &sourceCnt, &destCnt, d->history, flags);
804af7ab184SArchie Cobbs
805af7ab184SArchie Cobbs /* Check return value */
806ec5753e0SPedro F. Giffuni /* KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); */
807af7ab184SArchie Cobbs if ((rtn & MPPC_DEST_EXHAUSTED) != 0
808af7ab184SArchie Cobbs || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) {
809af7ab184SArchie Cobbs log(LOG_ERR, "%s: decomp returned 0x%x",
8106e551fb6SDavid E. O'Brien __func__, rtn);
81167898a23SAlexander Motin if (ina)
81267898a23SAlexander Motin free(inbuf, M_NETGRAPH_MPPC);
81367898a23SAlexander Motin free(outbuf, M_NETGRAPH_MPPC);
814af7ab184SArchie Cobbs goto failed;
815af7ab184SArchie Cobbs }
816af7ab184SArchie Cobbs
817af7ab184SArchie Cobbs /* Replace compressed data with decompressed data */
81867898a23SAlexander Motin if (ina)
81967898a23SAlexander Motin free(inbuf, M_NETGRAPH_MPPC);
82067898a23SAlexander Motin outlen -= destCnt;
821ce52e8f4SAlexander Motin
82267898a23SAlexander Motin m_copyback(m, 0, outlen, (caddr_t)outbuf);
82367898a23SAlexander Motin if (m->m_pkthdr.len < outlen) {
824ce52e8f4SAlexander Motin m_freem(m);
825e4651e05SAlexander Motin m = NULL;
82667898a23SAlexander Motin } else if (outlen < m->m_pkthdr.len)
82767898a23SAlexander Motin m_adj(m, outlen - m->m_pkthdr.len);
82867898a23SAlexander Motin free(outbuf, M_NETGRAPH_MPPC);
829af7ab184SArchie Cobbs }
830af7ab184SArchie Cobbs #endif
831af7ab184SArchie Cobbs
832af7ab184SArchie Cobbs /* Return result in an mbuf */
833ce52e8f4SAlexander Motin *datap = m;
834ce52e8f4SAlexander Motin return (*datap == NULL ? ENOBUFS : 0);
835af7ab184SArchie Cobbs }
836af7ab184SArchie Cobbs
837af7ab184SArchie Cobbs /*
838af7ab184SArchie Cobbs * The peer has sent us a CCP ResetRequest, so reset our transmit state.
839af7ab184SArchie Cobbs */
840af7ab184SArchie Cobbs static void
ng_mppc_reset_req(node_p node)841af7ab184SArchie Cobbs ng_mppc_reset_req(node_p node)
842af7ab184SArchie Cobbs {
84330400f03SJulian Elischer const priv_p priv = NG_NODE_PRIVATE(node);
844af7ab184SArchie Cobbs struct ng_mppc_dir *const d = &priv->xmit;
845af7ab184SArchie Cobbs
846af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION
847af7ab184SArchie Cobbs if (d->history != NULL)
848af7ab184SArchie Cobbs MPPC_InitCompressionHistory(d->history);
849af7ab184SArchie Cobbs #endif
850af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION
851af7ab184SArchie Cobbs if ((d->cfg.bits & MPPE_STATELESS) == 0)
852af7ab184SArchie Cobbs rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
853af7ab184SArchie Cobbs #endif
854af7ab184SArchie Cobbs d->flushed = 1;
855af7ab184SArchie Cobbs }
856af7ab184SArchie Cobbs
85706c51e6eSAlexander Motin #ifdef NETGRAPH_MPPC_ENCRYPTION
858af7ab184SArchie Cobbs /*
859af7ab184SArchie Cobbs * Generate a new encryption key
860af7ab184SArchie Cobbs */
861af7ab184SArchie Cobbs static void
ng_mppc_getkey(const u_char * h,u_char * h2,int len)862af7ab184SArchie Cobbs ng_mppc_getkey(const u_char *h, u_char *h2, int len)
863af7ab184SArchie Cobbs {
864b3d298b9SAlexander Motin static const u_char pad1[40] =
865b3d298b9SAlexander Motin { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
866b3d298b9SAlexander Motin 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
867b3d298b9SAlexander Motin 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
868b3d298b9SAlexander Motin 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
869b3d298b9SAlexander Motin static const u_char pad2[40] =
870b3d298b9SAlexander Motin { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
871b3d298b9SAlexander Motin 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
872b3d298b9SAlexander Motin 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
873b3d298b9SAlexander Motin 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 };
874af7ab184SArchie Cobbs u_char hash[20];
875af7ab184SArchie Cobbs SHA1_CTX c;
876af7ab184SArchie Cobbs
877af7ab184SArchie Cobbs SHA1Init(&c);
878af7ab184SArchie Cobbs SHA1Update(&c, h, len);
879592009a3SAlexander Motin SHA1Update(&c, pad1, sizeof(pad1));
880af7ab184SArchie Cobbs SHA1Update(&c, h2, len);
881af7ab184SArchie Cobbs SHA1Update(&c, pad2, sizeof(pad2));
882af7ab184SArchie Cobbs SHA1Final(hash, &c);
883af7ab184SArchie Cobbs bcopy(hash, h2, len);
884af7ab184SArchie Cobbs }
885af7ab184SArchie Cobbs
886af7ab184SArchie Cobbs /*
887af7ab184SArchie Cobbs * Update the encryption key
888af7ab184SArchie Cobbs */
889af7ab184SArchie Cobbs static void
ng_mppc_updatekey(u_int32_t bits,u_char * key0,u_char * key,struct rc4_state * rc4)890af7ab184SArchie Cobbs ng_mppc_updatekey(u_int32_t bits,
891af7ab184SArchie Cobbs u_char *key0, u_char *key, struct rc4_state *rc4)
892af7ab184SArchie Cobbs {
893af7ab184SArchie Cobbs const int keylen = KEYLEN(bits);
894af7ab184SArchie Cobbs
895af7ab184SArchie Cobbs ng_mppc_getkey(key0, key, keylen);
896af7ab184SArchie Cobbs rc4_init(rc4, key, keylen);
897af7ab184SArchie Cobbs rc4_crypt(rc4, key, key, keylen);
89834fd2381SArchie Cobbs if ((bits & MPPE_40) != 0)
89934fd2381SArchie Cobbs bcopy(&ng_mppe_weakenkey, key, 3);
90034fd2381SArchie Cobbs else if ((bits & MPPE_56) != 0)
90134fd2381SArchie Cobbs bcopy(&ng_mppe_weakenkey, key, 1);
902af7ab184SArchie Cobbs rc4_init(rc4, key, keylen);
903af7ab184SArchie Cobbs }
90406c51e6eSAlexander Motin #endif
905