xref: /freebsd/sys/netgraph/ng_mppc.c (revision d0b2dbfa0ecf2bbc9709efc5e20baf8e4b44bbbf)
1 /*
2  * ng_mppc.c
3  */
4 
5 /*-
6  * Copyright (c) 1996-2000 Whistle Communications, Inc.
7  * All rights reserved.
8  *
9  * Subject to the following obligations and disclaimer of warranty, use and
10  * redistribution of this software, in source or object code forms, with or
11  * without modifications are expressly permitted by Whistle Communications;
12  * provided, however, that:
13  * 1. Any and all reproductions of the source or object code must include the
14  *    copyright notice above and the following disclaimer of warranties; and
15  * 2. No rights are granted, in any manner or form, to use Whistle
16  *    Communications, Inc. trademarks, including the mark "WHISTLE
17  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
18  *    such appears in the above copyright notice or in the software.
19  *
20  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
21  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
22  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
23  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
25  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
26  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
27  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
28  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
29  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
30  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
32  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
36  * OF SUCH DAMAGE.
37  *
38  * Author: Archie Cobbs <archie@freebsd.org>
39  *
40  * $Whistle: ng_mppc.c,v 1.4 1999/11/25 00:10:12 archie Exp $
41  */
42 
43 /*
44  * Microsoft PPP compression (MPPC) and encryption (MPPE) netgraph node type.
45  *
46  * You must define one or both of the NETGRAPH_MPPC_COMPRESSION and/or
47  * NETGRAPH_MPPC_ENCRYPTION options for this node type to be useful.
48  */
49 
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/kernel.h>
53 #include <sys/mbuf.h>
54 #include <sys/malloc.h>
55 #include <sys/endian.h>
56 #include <sys/errno.h>
57 #include <sys/sysctl.h>
58 #include <sys/syslog.h>
59 
60 #include <netgraph/ng_message.h>
61 #include <netgraph/netgraph.h>
62 #include <netgraph/ng_mppc.h>
63 
64 #include "opt_netgraph.h"
65 
66 #if !defined(NETGRAPH_MPPC_COMPRESSION) && !defined(NETGRAPH_MPPC_ENCRYPTION)
67 #ifdef KLD_MODULE
68 #define NETGRAPH_MPPC_COMPRESSION
69 #define NETGRAPH_MPPC_ENCRYPTION
70 #else
71 /* This case is indicative of an error in sys/conf files */
72 #error Need either NETGRAPH_MPPC_COMPRESSION or NETGRAPH_MPPC_ENCRYPTION
73 #endif
74 #endif
75 
76 #ifdef NG_SEPARATE_MALLOC
77 static MALLOC_DEFINE(M_NETGRAPH_MPPC, "netgraph_mppc", "netgraph mppc node");
78 #else
79 #define M_NETGRAPH_MPPC M_NETGRAPH
80 #endif
81 
82 #ifdef NETGRAPH_MPPC_COMPRESSION
83 #include <net/mppc.h>
84 #endif
85 #ifdef NETGRAPH_MPPC_ENCRYPTION
86 #include <crypto/rc4/rc4.h>
87 #endif
88 #include <crypto/sha1.h>
89 
90 /* Decompression blowup */
91 #define MPPC_DECOMP_BUFSIZE	8092            /* allocate buffer this big */
92 #define MPPC_DECOMP_SAFETY	100             /*   plus this much margin */
93 
94 /* MPPC/MPPE header length */
95 #define MPPC_HDRLEN		2
96 
97 /* Key length */
98 #define KEYLEN(b)		(((b) & MPPE_128) ? 16 : 8)
99 
100 /*
101  * When packets are lost with MPPE, we may have to re-key arbitrarily
102  * many times to 'catch up' to the new jumped-ahead sequence number.
103  * Since this can be expensive, we pose a limit on how many re-keyings
104  * we will do at one time to avoid a possible D.O.S. vulnerability.
105  * This should instead be a configurable parameter.
106  */
107 #define MPPE_MAX_REKEY		1000
108 
109 SYSCTL_NODE(_net_graph, OID_AUTO, mppe, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
110     "MPPE");
111 
112 static int mppe_block_on_max_rekey = 0;
113 SYSCTL_INT(_net_graph_mppe, OID_AUTO, block_on_max_rekey, CTLFLAG_RWTUN,
114     &mppe_block_on_max_rekey, 0, "Block node on max MPPE key re-calculations");
115 
116 static int mppe_log_max_rekey = 1;
117 SYSCTL_INT(_net_graph_mppe, OID_AUTO, log_max_rekey, CTLFLAG_RWTUN,
118     &mppe_log_max_rekey, 0, "Log max MPPE key re-calculations event");
119 
120 static int mppe_max_rekey = MPPE_MAX_REKEY;
121 SYSCTL_INT(_net_graph_mppe, OID_AUTO, max_rekey, CTLFLAG_RWTUN,
122     &mppe_max_rekey, 0, "Maximum number of MPPE key re-calculations");
123 
124 /* MPPC packet header bits */
125 #define MPPC_FLAG_FLUSHED	0x8000		/* xmitter reset state */
126 #define MPPC_FLAG_RESTART	0x4000		/* compress history restart */
127 #define MPPC_FLAG_COMPRESSED	0x2000		/* packet is compresed */
128 #define MPPC_FLAG_ENCRYPTED	0x1000		/* packet is encrypted */
129 #define MPPC_CCOUNT_MASK	0x0fff		/* sequence number mask */
130 
131 #define MPPC_CCOUNT_INC(d)	((d) = (((d) + 1) & MPPC_CCOUNT_MASK))
132 
133 #define MPPE_UPDATE_MASK	0xff		/* coherency count when we're */
134 #define MPPE_UPDATE_FLAG	0xff		/*   supposed to update key */
135 
136 #define MPPC_COMP_OK		0x05
137 #define MPPC_DECOMP_OK		0x05
138 
139 /* Per direction info */
140 struct ng_mppc_dir {
141 	struct ng_mppc_config	cfg;		/* configuration */
142 	hook_p			hook;		/* netgraph hook */
143 	u_int16_t		cc:12;		/* coherency count */
144 	u_char			flushed;	/* clean history (xmit only) */
145 #ifdef NETGRAPH_MPPC_COMPRESSION
146 	u_char			*history;	/* compression history */
147 #endif
148 #ifdef NETGRAPH_MPPC_ENCRYPTION
149 	u_char			key[MPPE_KEY_LEN];	/* session key */
150 	struct rc4_state	rc4;			/* rc4 state */
151 #endif
152 };
153 
154 /* Node private data */
155 struct ng_mppc_private {
156 	struct ng_mppc_dir	xmit;		/* compress/encrypt config */
157 	struct ng_mppc_dir	recv;		/* decompress/decrypt config */
158 	ng_ID_t			ctrlnode;	/* path to controlling node */
159 };
160 typedef struct ng_mppc_private *priv_p;
161 
162 /* Netgraph node methods */
163 static ng_constructor_t	ng_mppc_constructor;
164 static ng_rcvmsg_t	ng_mppc_rcvmsg;
165 static ng_shutdown_t	ng_mppc_shutdown;
166 static ng_newhook_t	ng_mppc_newhook;
167 static ng_rcvdata_t	ng_mppc_rcvdata;
168 static ng_disconnect_t	ng_mppc_disconnect;
169 
170 /* Helper functions */
171 static int	ng_mppc_compress(node_p node,
172 			struct mbuf **datap);
173 static int	ng_mppc_decompress(node_p node,
174 			struct mbuf **datap);
175 #ifdef NETGRAPH_MPPC_ENCRYPTION
176 static void	ng_mppc_getkey(const u_char *h, u_char *h2, int len);
177 static void	ng_mppc_updatekey(u_int32_t bits,
178 			u_char *key0, u_char *key, struct rc4_state *rc4);
179 #endif
180 static void	ng_mppc_reset_req(node_p node);
181 
182 /* Node type descriptor */
183 static struct ng_type ng_mppc_typestruct = {
184 	.version =	NG_ABI_VERSION,
185 	.name =		NG_MPPC_NODE_TYPE,
186 	.constructor =	ng_mppc_constructor,
187 	.rcvmsg =	ng_mppc_rcvmsg,
188 	.shutdown =	ng_mppc_shutdown,
189 	.newhook =	ng_mppc_newhook,
190 	.rcvdata =	ng_mppc_rcvdata,
191 	.disconnect =	ng_mppc_disconnect,
192 };
193 NETGRAPH_INIT(mppc, &ng_mppc_typestruct);
194 
195 #ifdef NETGRAPH_MPPC_ENCRYPTION
196 /* Depend on separate rc4 module */
197 MODULE_DEPEND(ng_mppc, rc4, 1, 1, 1);
198 #endif
199 
200 /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
201 static const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e };
202 
203 #define ERROUT(x)	do { error = (x); goto done; } while (0)
204 
205 /************************************************************************
206 			NETGRAPH NODE STUFF
207  ************************************************************************/
208 
209 /*
210  * Node type constructor
211  */
212 static int
213 ng_mppc_constructor(node_p node)
214 {
215 	priv_p priv;
216 
217 	/* Allocate private structure */
218 	priv = malloc(sizeof(*priv), M_NETGRAPH_MPPC, M_WAITOK | M_ZERO);
219 
220 	NG_NODE_SET_PRIVATE(node, priv);
221 
222 	/* This node is not thread safe. */
223 	NG_NODE_FORCE_WRITER(node);
224 
225 	/* Done */
226 	return (0);
227 }
228 
229 /*
230  * Give our OK for a hook to be added
231  */
232 static int
233 ng_mppc_newhook(node_p node, hook_p hook, const char *name)
234 {
235 	const priv_p priv = NG_NODE_PRIVATE(node);
236 	hook_p *hookPtr;
237 
238 	/* Check hook name */
239 	if (strcmp(name, NG_MPPC_HOOK_COMP) == 0)
240 		hookPtr = &priv->xmit.hook;
241 	else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0)
242 		hookPtr = &priv->recv.hook;
243 	else
244 		return (EINVAL);
245 
246 	/* See if already connected */
247 	if (*hookPtr != NULL)
248 		return (EISCONN);
249 
250 	/* OK */
251 	*hookPtr = hook;
252 	return (0);
253 }
254 
255 /*
256  * Receive a control message
257  */
258 static int
259 ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook)
260 {
261 	const priv_p priv = NG_NODE_PRIVATE(node);
262 	struct ng_mesg *resp = NULL;
263 	int error = 0;
264 	struct ng_mesg *msg;
265 
266 	NGI_GET_MSG(item, msg);
267 	switch (msg->header.typecookie) {
268 	case NGM_MPPC_COOKIE:
269 		switch (msg->header.cmd) {
270 		case NGM_MPPC_CONFIG_COMP:
271 		case NGM_MPPC_CONFIG_DECOMP:
272 		    {
273 			struct ng_mppc_config *const cfg
274 			    = (struct ng_mppc_config *)msg->data;
275 			const int isComp =
276 			    msg->header.cmd == NGM_MPPC_CONFIG_COMP;
277 			struct ng_mppc_dir *const d = isComp ?
278 			    &priv->xmit : &priv->recv;
279 
280 			/* Check configuration */
281 			if (msg->header.arglen != sizeof(*cfg))
282 				ERROUT(EINVAL);
283 			if (cfg->enable) {
284 				if ((cfg->bits & ~MPPC_VALID_BITS) != 0)
285 					ERROUT(EINVAL);
286 #ifndef NETGRAPH_MPPC_COMPRESSION
287 				if ((cfg->bits & MPPC_BIT) != 0)
288 					ERROUT(EPROTONOSUPPORT);
289 #endif
290 #ifndef NETGRAPH_MPPC_ENCRYPTION
291 				if ((cfg->bits & MPPE_BITS) != 0)
292 					ERROUT(EPROTONOSUPPORT);
293 #endif
294 			} else
295 				cfg->bits = 0;
296 
297 			/* Save return address so we can send reset-req's */
298 			if (!isComp)
299 				priv->ctrlnode = NGI_RETADDR(item);
300 
301 			/* Configuration is OK, reset to it */
302 			d->cfg = *cfg;
303 
304 #ifdef NETGRAPH_MPPC_COMPRESSION
305 			/* Initialize state buffers for compression */
306 			if (d->history != NULL) {
307 				free(d->history, M_NETGRAPH_MPPC);
308 				d->history = NULL;
309 			}
310 			if ((cfg->bits & MPPC_BIT) != 0) {
311 				d->history = malloc(isComp ?
312 				    MPPC_SizeOfCompressionHistory() :
313 				    MPPC_SizeOfDecompressionHistory(),
314 				    M_NETGRAPH_MPPC, M_NOWAIT);
315 				if (d->history == NULL)
316 					ERROUT(ENOMEM);
317 				if (isComp)
318 					MPPC_InitCompressionHistory(d->history);
319 				else {
320 					MPPC_InitDecompressionHistory(
321 					    d->history);
322 				}
323 			}
324 #endif
325 
326 #ifdef NETGRAPH_MPPC_ENCRYPTION
327 			/* Generate initial session keys for encryption */
328 			if ((cfg->bits & MPPE_BITS) != 0) {
329 				const int keylen = KEYLEN(cfg->bits);
330 
331 				bcopy(cfg->startkey, d->key, keylen);
332 				ng_mppc_getkey(cfg->startkey, d->key, keylen);
333 				if ((cfg->bits & MPPE_40) != 0)
334 					bcopy(&ng_mppe_weakenkey, d->key, 3);
335 				else if ((cfg->bits & MPPE_56) != 0)
336 					bcopy(&ng_mppe_weakenkey, d->key, 1);
337 				rc4_init(&d->rc4, d->key, keylen);
338 			}
339 #endif
340 
341 			/* Initialize other state */
342 			d->cc = 0;
343 			d->flushed = 0;
344 			break;
345 		    }
346 
347 		case NGM_MPPC_RESETREQ:
348 			ng_mppc_reset_req(node);
349 			break;
350 
351 		default:
352 			error = EINVAL;
353 			break;
354 		}
355 		break;
356 	default:
357 		error = EINVAL;
358 		break;
359 	}
360 done:
361 	NG_RESPOND_MSG(error, node, item, resp);
362 	NG_FREE_MSG(msg);
363 	return (error);
364 }
365 
366 /*
367  * Receive incoming data on our hook.
368  */
369 static int
370 ng_mppc_rcvdata(hook_p hook, item_p item)
371 {
372 	const node_p node = NG_HOOK_NODE(hook);
373 	const priv_p priv = NG_NODE_PRIVATE(node);
374 	int error;
375 	struct mbuf *m;
376 
377 	NGI_GET_M(item, m);
378 	/* Compress and/or encrypt */
379 	if (hook == priv->xmit.hook) {
380 		if (!priv->xmit.cfg.enable) {
381 			NG_FREE_M(m);
382 			NG_FREE_ITEM(item);
383 			return (ENXIO);
384 		}
385 		if ((error = ng_mppc_compress(node, &m)) != 0) {
386 			NG_FREE_ITEM(item);
387 			return(error);
388 		}
389 		NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m);
390 		return (error);
391 	}
392 
393 	/* Decompress and/or decrypt */
394 	if (hook == priv->recv.hook) {
395 		if (!priv->recv.cfg.enable) {
396 			NG_FREE_M(m);
397 			NG_FREE_ITEM(item);
398 			return (ENXIO);
399 		}
400 		if ((error = ng_mppc_decompress(node, &m)) != 0) {
401 			NG_FREE_ITEM(item);
402 			if (error == EINVAL && priv->ctrlnode != 0) {
403 				struct ng_mesg *msg;
404 
405 				/* Need to send a reset-request */
406 				NG_MKMESSAGE(msg, NGM_MPPC_COOKIE,
407 				    NGM_MPPC_RESETREQ, 0, M_NOWAIT);
408 				if (msg == NULL)
409 					return (error);
410 				NG_SEND_MSG_ID(error, node, msg,
411 					priv->ctrlnode, 0);
412 			}
413 			return (error);
414 		}
415 		NG_FWD_NEW_DATA(error, item, priv->recv.hook, m);
416 		return (error);
417 	}
418 
419 	/* Oops */
420 	panic("%s: unknown hook", __func__);
421 }
422 
423 /*
424  * Destroy node
425  */
426 static int
427 ng_mppc_shutdown(node_p node)
428 {
429 	const priv_p priv = NG_NODE_PRIVATE(node);
430 
431 	/* Take down netgraph node */
432 #ifdef NETGRAPH_MPPC_COMPRESSION
433 	if (priv->xmit.history != NULL)
434 		free(priv->xmit.history, M_NETGRAPH_MPPC);
435 	if (priv->recv.history != NULL)
436 		free(priv->recv.history, M_NETGRAPH_MPPC);
437 #endif
438 	bzero(priv, sizeof(*priv));
439 	free(priv, M_NETGRAPH_MPPC);
440 	NG_NODE_SET_PRIVATE(node, NULL);
441 	NG_NODE_UNREF(node);		/* let the node escape */
442 	return (0);
443 }
444 
445 /*
446  * Hook disconnection
447  */
448 static int
449 ng_mppc_disconnect(hook_p hook)
450 {
451 	const node_p node = NG_HOOK_NODE(hook);
452 	const priv_p priv = NG_NODE_PRIVATE(node);
453 
454 	/* Zero out hook pointer */
455 	if (hook == priv->xmit.hook)
456 		priv->xmit.hook = NULL;
457 	if (hook == priv->recv.hook)
458 		priv->recv.hook = NULL;
459 
460 	/* Go away if no longer connected */
461 	if ((NG_NODE_NUMHOOKS(node) == 0)
462 	&& NG_NODE_IS_VALID(node))
463 		ng_rmnode_self(node);
464 	return (0);
465 }
466 
467 /************************************************************************
468 			HELPER STUFF
469  ************************************************************************/
470 
471 /*
472  * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
473  * The original mbuf is not free'd.
474  */
475 static int
476 ng_mppc_compress(node_p node, struct mbuf **datap)
477 {
478 	const priv_p priv = NG_NODE_PRIVATE(node);
479 	struct ng_mppc_dir *const d = &priv->xmit;
480 	u_int16_t header;
481 	struct mbuf *m = *datap;
482 
483 	/* We must own the mbuf chain exclusively to modify it. */
484 	m = m_unshare(m, M_NOWAIT);
485 	if (m == NULL)
486 		return (ENOMEM);
487 
488 	/* Initialize */
489 	header = d->cc;
490 
491 	/* Always set the flushed bit in stateless mode */
492 	if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) {
493 		header |= MPPC_FLAG_FLUSHED;
494 		d->flushed = 0;
495 	}
496 
497 	/* Compress packet (if compression enabled) */
498 #ifdef NETGRAPH_MPPC_COMPRESSION
499 	if ((d->cfg.bits & MPPC_BIT) != 0) {
500 		u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS;
501 		u_char *inbuf, *outbuf;
502 		int outlen, inlen, ina;
503 		u_char *source, *dest;
504 		u_long sourceCnt, destCnt;
505 		int rtn;
506 
507 		/* Work with contiguous regions of memory. */
508 		inlen = m->m_pkthdr.len;
509 		if (m->m_next == NULL) {
510 			inbuf = mtod(m, u_char *);
511 			ina = 0;
512 		} else {
513 			inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
514 			if (inbuf == NULL)
515 				goto err1;
516 			m_copydata(m, 0, inlen, (caddr_t)inbuf);
517 			ina = 1;
518 		}
519 
520 		outlen = MPPC_MAX_BLOWUP(inlen);
521 		outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT);
522 		if (outbuf == NULL) {
523 			if (ina)
524 				free(inbuf, M_NETGRAPH_MPPC);
525 err1:
526 			m_freem(m);
527 			MPPC_InitCompressionHistory(d->history);
528 			d->flushed = 1;
529 			return (ENOMEM);
530 		}
531 
532 		/* Prepare to compress */
533 		source = inbuf;
534 		sourceCnt = inlen;
535 		dest = outbuf;
536 		destCnt = outlen;
537 		if ((d->cfg.bits & MPPE_STATELESS) == 0)
538 			flags |= MPPC_SAVE_HISTORY;
539 
540 		/* Compress */
541 		rtn = MPPC_Compress(&source, &dest, &sourceCnt,
542 			&destCnt, d->history, flags, 0);
543 
544 		/* Check return value */
545 		/* KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); */
546 		if ((rtn & MPPC_EXPANDED) == 0
547 		    && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) {
548 			outlen -= destCnt;
549 			header |= MPPC_FLAG_COMPRESSED;
550 			if ((rtn & MPPC_RESTART_HISTORY) != 0)
551 				header |= MPPC_FLAG_RESTART;
552 
553 			/* Replace m by the compresed one. */
554 			m_copyback(m, 0, outlen, (caddr_t)outbuf);
555 			if (m->m_pkthdr.len < outlen) {
556 				m_freem(m);
557 				m = NULL;
558 			} else if (outlen < m->m_pkthdr.len)
559 				m_adj(m, outlen - m->m_pkthdr.len);
560 		}
561 		d->flushed = (rtn & MPPC_EXPANDED) != 0
562 		    || (flags & MPPC_SAVE_HISTORY) == 0;
563 
564 		if (ina)
565 			free(inbuf, M_NETGRAPH_MPPC);
566 		free(outbuf, M_NETGRAPH_MPPC);
567 
568 		/* Check mbuf chain reload result. */
569 		if (m == NULL) {
570 			if (!d->flushed) {
571 				MPPC_InitCompressionHistory(d->history);
572 				d->flushed = 1;
573 			}
574 			return (ENOMEM);
575 		}
576 	}
577 #endif
578 
579 	/* Now encrypt packet (if encryption enabled) */
580 #ifdef NETGRAPH_MPPC_ENCRYPTION
581 	if ((d->cfg.bits & MPPE_BITS) != 0) {
582 		struct mbuf *m1;
583 
584 		/* Set header bits */
585 		header |= MPPC_FLAG_ENCRYPTED;
586 
587 		/* Update key if it's time */
588 		if ((d->cfg.bits & MPPE_STATELESS) != 0
589 		    || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
590 			ng_mppc_updatekey(d->cfg.bits,
591 			    d->cfg.startkey, d->key, &d->rc4);
592 		} else if ((header & MPPC_FLAG_FLUSHED) != 0) {
593 			/* Need to reset key if we say we did
594 			   and ng_mppc_updatekey wasn't called to do it also. */
595 			rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
596 		}
597 
598 		/* Encrypt packet */
599 		m1 = m;
600 		while (m1) {
601 			rc4_crypt(&d->rc4, mtod(m1, u_char *),
602 			    mtod(m1, u_char *), m1->m_len);
603 			m1 = m1->m_next;
604 		}
605 	}
606 #endif
607 
608 	/* Update coherency count for next time (12 bit arithmetic) */
609 	MPPC_CCOUNT_INC(d->cc);
610 
611 	/* Install header */
612 	M_PREPEND(m, MPPC_HDRLEN, M_NOWAIT);
613 	if (m != NULL)
614 		be16enc(mtod(m, void *), header);
615 
616 	*datap = m;
617 	return (*datap == NULL ? ENOBUFS : 0);
618 }
619 
620 /*
621  * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
622  * The original mbuf is not free'd.
623  */
624 static int
625 ng_mppc_decompress(node_p node, struct mbuf **datap)
626 {
627 	const priv_p priv = NG_NODE_PRIVATE(node);
628 	struct ng_mppc_dir *const d = &priv->recv;
629 	u_int16_t header, cc;
630 	u_int numLost;
631 	struct mbuf *m = *datap;
632 
633 	/* We must own the mbuf chain exclusively to modify it. */
634 	m = m_unshare(m, M_NOWAIT);
635 	if (m == NULL)
636 		return (ENOMEM);
637 
638 	/* Pull off header */
639 	if (m->m_pkthdr.len < MPPC_HDRLEN) {
640 		m_freem(m);
641 		return (EINVAL);
642 	}
643 	header = be16dec(mtod(m, void *));
644 	cc = (header & MPPC_CCOUNT_MASK);
645 	m_adj(m, MPPC_HDRLEN);
646 
647 	/* Check for an unexpected jump in the sequence number */
648 	numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK);
649 
650 	/* If flushed bit set, we can always handle packet */
651 	if ((header & MPPC_FLAG_FLUSHED) != 0) {
652 #ifdef NETGRAPH_MPPC_COMPRESSION
653 		if (d->history != NULL)
654 			MPPC_InitDecompressionHistory(d->history);
655 #endif
656 #ifdef NETGRAPH_MPPC_ENCRYPTION
657 		if ((d->cfg.bits & MPPE_BITS) != 0) {
658 			u_int rekey;
659 
660 			/* How many times are we going to have to re-key? */
661 			rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ?
662 			    numLost : (numLost / (MPPE_UPDATE_MASK + 1));
663 			if (rekey > mppe_max_rekey) {
664 			    if (mppe_block_on_max_rekey) {
665 				if (mppe_log_max_rekey) {
666 				    log(LOG_ERR, "%s: too many (%d) packets"
667 					" dropped, disabling node %p!\n",
668 					__func__, numLost, node);
669 				}
670 				priv->recv.cfg.enable = 0;
671 				goto failed;
672 			    } else {
673 				if (mppe_log_max_rekey) {
674 				    log(LOG_ERR, "%s: %d packets"
675 					" dropped, node %p\n",
676 					__func__, numLost, node);
677 				}
678 				goto failed;
679 			    }
680 			}
681 
682 			/* Re-key as necessary to catch up to peer */
683 			while (d->cc != cc) {
684 				if ((d->cfg.bits & MPPE_STATELESS) != 0
685 				    || (d->cc & MPPE_UPDATE_MASK)
686 				      == MPPE_UPDATE_FLAG) {
687 					ng_mppc_updatekey(d->cfg.bits,
688 					    d->cfg.startkey, d->key, &d->rc4);
689 				}
690 				MPPC_CCOUNT_INC(d->cc);
691 			}
692 
693 			/* Reset key (except in stateless mode, see below) */
694 			if ((d->cfg.bits & MPPE_STATELESS) == 0)
695 				rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
696 		}
697 #endif
698 		d->cc = cc;		/* skip over lost seq numbers */
699 		numLost = 0;		/* act like no packets were lost */
700 	}
701 
702 	/* Can't decode non-sequential packets without a flushed bit */
703 	if (numLost != 0)
704 		goto failed;
705 
706 	/* Decrypt packet */
707 	if ((header & MPPC_FLAG_ENCRYPTED) != 0) {
708 #ifdef NETGRAPH_MPPC_ENCRYPTION
709 		struct mbuf *m1;
710 #endif
711 
712 		/* Are we not expecting encryption? */
713 		if ((d->cfg.bits & MPPE_BITS) == 0) {
714 			log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
715 				__func__, "encrypted");
716 			goto failed;
717 		}
718 
719 #ifdef NETGRAPH_MPPC_ENCRYPTION
720 		/* Update key if it's time (always in stateless mode) */
721 		if ((d->cfg.bits & MPPE_STATELESS) != 0
722 		    || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
723 			ng_mppc_updatekey(d->cfg.bits,
724 			    d->cfg.startkey, d->key, &d->rc4);
725 		}
726 
727 		/* Decrypt packet */
728 		m1 = m;
729 		while (m1 != NULL) {
730 			rc4_crypt(&d->rc4, mtod(m1, u_char *),
731 			    mtod(m1, u_char *), m1->m_len);
732 			m1 = m1->m_next;
733 		}
734 #endif
735 	} else {
736 		/* Are we expecting encryption? */
737 		if ((d->cfg.bits & MPPE_BITS) != 0) {
738 			log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
739 				__func__, "unencrypted");
740 			goto failed;
741 		}
742 	}
743 
744 	/* Update coherency count for next time (12 bit arithmetic) */
745 	MPPC_CCOUNT_INC(d->cc);
746 
747 	/* Check for unexpected compressed packet */
748 	if ((header & MPPC_FLAG_COMPRESSED) != 0
749 	    && (d->cfg.bits & MPPC_BIT) == 0) {
750 		log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
751 			__func__, "compressed");
752 failed:
753 		m_freem(m);
754 		return (EINVAL);
755 	}
756 
757 #ifdef NETGRAPH_MPPC_COMPRESSION
758 	/* Decompress packet */
759 	if ((header & MPPC_FLAG_COMPRESSED) != 0) {
760 		int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS;
761 		u_char *inbuf, *outbuf;
762 		int inlen, outlen, ina;
763 		u_char *source, *dest;
764 		u_long sourceCnt, destCnt;
765 		int rtn;
766 
767 		/* Copy payload into a contiguous region of memory. */
768 		inlen = m->m_pkthdr.len;
769 		if (m->m_next == NULL) {
770                 	inbuf = mtod(m, u_char *);
771 			ina = 0;
772 		} else {
773 		        inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
774 			if (inbuf == NULL) {
775 				m_freem(m);
776 				return (ENOMEM);
777 			}
778 			m_copydata(m, 0, inlen, (caddr_t)inbuf);
779 			ina = 1;
780 		}
781 
782 		/* Allocate a buffer for decompressed data */
783 		outbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY,
784 		    M_NETGRAPH_MPPC, M_NOWAIT);
785 		if (outbuf == NULL) {
786 			m_freem(m);
787 			if (ina)
788 				free(inbuf, M_NETGRAPH_MPPC);
789 			return (ENOMEM);
790 		}
791 		outlen = MPPC_DECOMP_BUFSIZE;
792 
793 		/* Prepare to decompress */
794 		source = inbuf;
795 		sourceCnt = inlen;
796 		dest = outbuf;
797 		destCnt = outlen;
798 		if ((header & MPPC_FLAG_RESTART) != 0)
799 			flags |= MPPC_RESTART_HISTORY;
800 
801 		/* Decompress */
802 		rtn = MPPC_Decompress(&source, &dest,
803 			&sourceCnt, &destCnt, d->history, flags);
804 
805 		/* Check return value */
806 		/* KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); */
807 		if ((rtn & MPPC_DEST_EXHAUSTED) != 0
808 		    || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) {
809 			log(LOG_ERR, "%s: decomp returned 0x%x",
810 			    __func__, rtn);
811 			if (ina)
812 				free(inbuf, M_NETGRAPH_MPPC);
813 			free(outbuf, M_NETGRAPH_MPPC);
814 			goto failed;
815 		}
816 
817 		/* Replace compressed data with decompressed data */
818 		if (ina)
819 			free(inbuf, M_NETGRAPH_MPPC);
820 		outlen -= destCnt;
821 
822 		m_copyback(m, 0, outlen, (caddr_t)outbuf);
823 		if (m->m_pkthdr.len < outlen) {
824 			m_freem(m);
825 			m = NULL;
826 		} else if (outlen < m->m_pkthdr.len)
827 			m_adj(m, outlen - m->m_pkthdr.len);
828 		free(outbuf, M_NETGRAPH_MPPC);
829 	}
830 #endif
831 
832 	/* Return result in an mbuf */
833 	*datap = m;
834 	return (*datap == NULL ? ENOBUFS : 0);
835 }
836 
837 /*
838  * The peer has sent us a CCP ResetRequest, so reset our transmit state.
839  */
840 static void
841 ng_mppc_reset_req(node_p node)
842 {
843 	const priv_p priv = NG_NODE_PRIVATE(node);
844 	struct ng_mppc_dir *const d = &priv->xmit;
845 
846 #ifdef NETGRAPH_MPPC_COMPRESSION
847 	if (d->history != NULL)
848 		MPPC_InitCompressionHistory(d->history);
849 #endif
850 #ifdef NETGRAPH_MPPC_ENCRYPTION
851 	if ((d->cfg.bits & MPPE_STATELESS) == 0)
852 		rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
853 #endif
854 	d->flushed = 1;
855 }
856 
857 #ifdef NETGRAPH_MPPC_ENCRYPTION
858 /*
859  * Generate a new encryption key
860  */
861 static void
862 ng_mppc_getkey(const u_char *h, u_char *h2, int len)
863 {
864 	static const u_char pad1[40] =
865 	    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
866 	      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
867 	      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
868 	      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
869 	static const u_char pad2[40] =
870 	    { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
871 	      0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
872 	      0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
873 	      0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 };
874 	u_char hash[20];
875 	SHA1_CTX c;
876 
877 	SHA1Init(&c);
878 	SHA1Update(&c, h, len);
879 	SHA1Update(&c, pad1, sizeof(pad1));
880 	SHA1Update(&c, h2, len);
881 	SHA1Update(&c, pad2, sizeof(pad2));
882 	SHA1Final(hash, &c);
883 	bcopy(hash, h2, len);
884 }
885 
886 /*
887  * Update the encryption key
888  */
889 static void
890 ng_mppc_updatekey(u_int32_t bits,
891 	u_char *key0, u_char *key, struct rc4_state *rc4)
892 {
893 	const int keylen = KEYLEN(bits);
894 
895 	ng_mppc_getkey(key0, key, keylen);
896 	rc4_init(rc4, key, keylen);
897 	rc4_crypt(rc4, key, key, keylen);
898 	if ((bits & MPPE_40) != 0)
899 		bcopy(&ng_mppe_weakenkey, key, 3);
900 	else if ((bits & MPPE_56) != 0)
901 		bcopy(&ng_mppe_weakenkey, key, 1);
902 	rc4_init(rc4, key, keylen);
903 }
904 #endif
905