xref: /freebsd/sys/netgraph/ng_mppc.c (revision af3b2549c4ba2ef00a7cbb4cb6836598bf0aefbe)
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  * $FreeBSD$
42af7ab184SArchie Cobbs  */
43af7ab184SArchie Cobbs 
44af7ab184SArchie Cobbs /*
45af7ab184SArchie Cobbs  * Microsoft PPP compression (MPPC) and encryption (MPPE) netgraph node type.
46af7ab184SArchie Cobbs  *
47af7ab184SArchie Cobbs  * You must define one or both of the NETGRAPH_MPPC_COMPRESSION and/or
48af7ab184SArchie Cobbs  * NETGRAPH_MPPC_ENCRYPTION options for this node type to be useful.
49af7ab184SArchie Cobbs  */
50af7ab184SArchie Cobbs 
51af7ab184SArchie Cobbs #include <sys/param.h>
52af7ab184SArchie Cobbs #include <sys/systm.h>
53af7ab184SArchie Cobbs #include <sys/kernel.h>
54af7ab184SArchie Cobbs #include <sys/mbuf.h>
55af7ab184SArchie Cobbs #include <sys/malloc.h>
5639228864SAlexander Motin #include <sys/endian.h>
57af7ab184SArchie Cobbs #include <sys/errno.h>
58ee652839SAlexander Motin #include <sys/sysctl.h>
59af7ab184SArchie Cobbs #include <sys/syslog.h>
60af7ab184SArchie Cobbs 
61af7ab184SArchie Cobbs #include <netgraph/ng_message.h>
62af7ab184SArchie Cobbs #include <netgraph/netgraph.h>
63af7ab184SArchie Cobbs #include <netgraph/ng_mppc.h>
64af7ab184SArchie Cobbs 
65af7ab184SArchie Cobbs #include "opt_netgraph.h"
66af7ab184SArchie Cobbs 
67af7ab184SArchie Cobbs #if !defined(NETGRAPH_MPPC_COMPRESSION) && !defined(NETGRAPH_MPPC_ENCRYPTION)
6810d645b7SYaroslav Tykhiy #ifdef KLD_MODULE
6910d645b7SYaroslav Tykhiy /* XXX NETGRAPH_MPPC_COMPRESSION isn't functional yet */
7010d645b7SYaroslav Tykhiy #define NETGRAPH_MPPC_ENCRYPTION
7110d645b7SYaroslav Tykhiy #else
7210d645b7SYaroslav Tykhiy /* This case is indicative of an error in sys/conf files */
73af7ab184SArchie Cobbs #error Need either NETGRAPH_MPPC_COMPRESSION or NETGRAPH_MPPC_ENCRYPTION
74af7ab184SArchie Cobbs #endif
7510d645b7SYaroslav Tykhiy #endif
76af7ab184SArchie Cobbs 
779c8c302fSJulian Elischer #ifdef NG_SEPARATE_MALLOC
78d745c852SEd Schouten static MALLOC_DEFINE(M_NETGRAPH_MPPC, "netgraph_mppc", "netgraph mppc node");
799c8c302fSJulian Elischer #else
809c8c302fSJulian Elischer #define M_NETGRAPH_MPPC M_NETGRAPH
819c8c302fSJulian Elischer #endif
829c8c302fSJulian Elischer 
83af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION
84af7ab184SArchie Cobbs /* XXX this file doesn't exist yet, but hopefully someday it will... */
85af7ab184SArchie Cobbs #include <net/mppc.h>
86af7ab184SArchie Cobbs #endif
87af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION
88af7ab184SArchie Cobbs #include <crypto/rc4/rc4.h>
89af7ab184SArchie Cobbs #endif
90af7ab184SArchie Cobbs #include <crypto/sha1.h>
91af7ab184SArchie Cobbs 
92af7ab184SArchie Cobbs /* Decompression blowup */
93af7ab184SArchie Cobbs #define MPPC_DECOMP_BUFSIZE	8092            /* allocate buffer this big */
94af7ab184SArchie Cobbs #define MPPC_DECOMP_SAFETY	100             /*   plus this much margin */
95af7ab184SArchie Cobbs 
96af7ab184SArchie Cobbs /* MPPC/MPPE header length */
97af7ab184SArchie Cobbs #define MPPC_HDRLEN		2
98af7ab184SArchie Cobbs 
99af7ab184SArchie Cobbs /* Key length */
100af7ab184SArchie Cobbs #define KEYLEN(b)		(((b) & MPPE_128) ? 16 : 8)
101af7ab184SArchie Cobbs 
1025372c30bSGleb Smirnoff /*
1035372c30bSGleb Smirnoff  * When packets are lost with MPPE, we may have to re-key arbitrarily
1045372c30bSGleb Smirnoff  * many times to 'catch up' to the new jumped-ahead sequence number.
1055372c30bSGleb Smirnoff  * Since this can be expensive, we pose a limit on how many re-keyings
1065372c30bSGleb Smirnoff  * we will do at one time to avoid a possible D.O.S. vulnerability.
1075372c30bSGleb Smirnoff  * This should instead be a configurable parameter.
1085372c30bSGleb Smirnoff  */
1095372c30bSGleb Smirnoff #define MPPE_MAX_REKEY		1000
1105372c30bSGleb Smirnoff 
111ee652839SAlexander Motin SYSCTL_NODE(_net_graph, OID_AUTO, mppe, CTLFLAG_RW, 0, "MPPE");
112ee652839SAlexander Motin 
113ee652839SAlexander Motin static int mppe_block_on_max_rekey = 0;
114*af3b2549SHans Petter Selasky SYSCTL_INT(_net_graph_mppe, OID_AUTO, block_on_max_rekey, CTLFLAG_RWTUN,
115ee652839SAlexander Motin     &mppe_block_on_max_rekey, 0, "Block node on max MPPE key re-calculations");
116ee652839SAlexander Motin 
117ee652839SAlexander Motin static int mppe_log_max_rekey = 1;
118*af3b2549SHans Petter Selasky SYSCTL_INT(_net_graph_mppe, OID_AUTO, log_max_rekey, CTLFLAG_RWTUN,
119ee652839SAlexander Motin     &mppe_log_max_rekey, 0, "Log max MPPE key re-calculations event");
120ee652839SAlexander Motin 
121ee652839SAlexander Motin static int mppe_max_rekey = MPPE_MAX_REKEY;
122*af3b2549SHans Petter Selasky SYSCTL_INT(_net_graph_mppe, OID_AUTO, max_rekey, CTLFLAG_RWTUN,
123ee652839SAlexander Motin     &mppe_max_rekey, 0, "Maximum number of MPPE key re-calculations");
124ee652839SAlexander Motin 
125af7ab184SArchie Cobbs /* MPPC packet header bits */
126af7ab184SArchie Cobbs #define MPPC_FLAG_FLUSHED	0x8000		/* xmitter reset state */
127af7ab184SArchie Cobbs #define MPPC_FLAG_RESTART	0x4000		/* compress history restart */
128af7ab184SArchie Cobbs #define MPPC_FLAG_COMPRESSED	0x2000		/* packet is compresed */
129af7ab184SArchie Cobbs #define MPPC_FLAG_ENCRYPTED	0x1000		/* packet is encrypted */
130af7ab184SArchie Cobbs #define MPPC_CCOUNT_MASK	0x0fff		/* sequence number mask */
131af7ab184SArchie Cobbs 
132755bc287SAlexander Motin #define MPPC_CCOUNT_INC(d)	((d) = (((d) + 1) & MPPC_CCOUNT_MASK))
133755bc287SAlexander Motin 
134af7ab184SArchie Cobbs #define MPPE_UPDATE_MASK	0xff		/* coherency count when we're */
135af7ab184SArchie Cobbs #define MPPE_UPDATE_FLAG	0xff		/*   supposed to update key */
136af7ab184SArchie Cobbs 
137af7ab184SArchie Cobbs #define MPPC_COMP_OK		0x05
138af7ab184SArchie Cobbs #define MPPC_DECOMP_OK		0x05
139af7ab184SArchie Cobbs 
140af7ab184SArchie Cobbs /* Per direction info */
141af7ab184SArchie Cobbs struct ng_mppc_dir {
142af7ab184SArchie Cobbs 	struct ng_mppc_config	cfg;		/* configuration */
143af7ab184SArchie Cobbs 	hook_p			hook;		/* netgraph hook */
144af7ab184SArchie Cobbs 	u_int16_t		cc:12;		/* coherency count */
145af7ab184SArchie Cobbs 	u_char			flushed;	/* clean history (xmit only) */
146af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION
147af7ab184SArchie Cobbs 	u_char			*history;	/* compression history */
148af7ab184SArchie Cobbs #endif
149af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION
150af7ab184SArchie Cobbs 	u_char			key[MPPE_KEY_LEN];	/* session key */
151af7ab184SArchie Cobbs 	struct rc4_state	rc4;			/* rc4 state */
152af7ab184SArchie Cobbs #endif
153af7ab184SArchie Cobbs };
154af7ab184SArchie Cobbs 
155af7ab184SArchie Cobbs /* Node private data */
156af7ab184SArchie Cobbs struct ng_mppc_private {
157af7ab184SArchie Cobbs 	struct ng_mppc_dir	xmit;		/* compress/encrypt config */
158af7ab184SArchie Cobbs 	struct ng_mppc_dir	recv;		/* decompress/decrypt config */
159069154d5SJulian Elischer 	ng_ID_t			ctrlnode;	/* path to controlling node */
160af7ab184SArchie Cobbs };
161af7ab184SArchie Cobbs typedef struct ng_mppc_private *priv_p;
162af7ab184SArchie Cobbs 
163af7ab184SArchie Cobbs /* Netgraph node methods */
164af7ab184SArchie Cobbs static ng_constructor_t	ng_mppc_constructor;
165af7ab184SArchie Cobbs static ng_rcvmsg_t	ng_mppc_rcvmsg;
166069154d5SJulian Elischer static ng_shutdown_t	ng_mppc_shutdown;
167af7ab184SArchie Cobbs static ng_newhook_t	ng_mppc_newhook;
168af7ab184SArchie Cobbs static ng_rcvdata_t	ng_mppc_rcvdata;
169af7ab184SArchie Cobbs static ng_disconnect_t	ng_mppc_disconnect;
170af7ab184SArchie Cobbs 
171af7ab184SArchie Cobbs /* Helper functions */
172af7ab184SArchie Cobbs static int	ng_mppc_compress(node_p node,
173ce52e8f4SAlexander Motin 			struct mbuf **datap);
174af7ab184SArchie Cobbs static int	ng_mppc_decompress(node_p node,
175ce52e8f4SAlexander Motin 			struct mbuf **datap);
17606c51e6eSAlexander Motin #ifdef NETGRAPH_MPPC_ENCRYPTION
177af7ab184SArchie Cobbs static void	ng_mppc_getkey(const u_char *h, u_char *h2, int len);
178af7ab184SArchie Cobbs static void	ng_mppc_updatekey(u_int32_t bits,
179af7ab184SArchie Cobbs 			u_char *key0, u_char *key, struct rc4_state *rc4);
18006c51e6eSAlexander Motin #endif
181af7ab184SArchie Cobbs static void	ng_mppc_reset_req(node_p node);
182af7ab184SArchie Cobbs 
183af7ab184SArchie Cobbs /* Node type descriptor */
184af7ab184SArchie Cobbs static struct ng_type ng_mppc_typestruct = {
185f8aae777SJulian Elischer 	.version =	NG_ABI_VERSION,
186f8aae777SJulian Elischer 	.name =		NG_MPPC_NODE_TYPE,
187f8aae777SJulian Elischer 	.constructor =	ng_mppc_constructor,
188f8aae777SJulian Elischer 	.rcvmsg =	ng_mppc_rcvmsg,
189f8aae777SJulian Elischer 	.shutdown =	ng_mppc_shutdown,
190f8aae777SJulian Elischer 	.newhook =	ng_mppc_newhook,
191f8aae777SJulian Elischer 	.rcvdata =	ng_mppc_rcvdata,
192f8aae777SJulian Elischer 	.disconnect =	ng_mppc_disconnect,
193af7ab184SArchie Cobbs };
194af7ab184SArchie Cobbs NETGRAPH_INIT(mppc, &ng_mppc_typestruct);
195af7ab184SArchie Cobbs 
196233896e9SDoug Ambrisko #ifdef NETGRAPH_MPPC_ENCRYPTION
197233896e9SDoug Ambrisko /* Depend on separate rc4 module */
198233896e9SDoug Ambrisko MODULE_DEPEND(ng_mppc, rc4, 1, 1, 1);
199233896e9SDoug Ambrisko #endif
200233896e9SDoug Ambrisko 
20134fd2381SArchie Cobbs /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
202af7ab184SArchie Cobbs static const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e };
203af7ab184SArchie Cobbs 
204af7ab184SArchie Cobbs #define ERROUT(x)	do { error = (x); goto done; } while (0)
205af7ab184SArchie Cobbs 
206af7ab184SArchie Cobbs /************************************************************************
207af7ab184SArchie Cobbs 			NETGRAPH NODE STUFF
208af7ab184SArchie Cobbs  ************************************************************************/
209af7ab184SArchie Cobbs 
210af7ab184SArchie Cobbs /*
211af7ab184SArchie Cobbs  * Node type constructor
212af7ab184SArchie Cobbs  */
213af7ab184SArchie Cobbs static int
214069154d5SJulian Elischer ng_mppc_constructor(node_p node)
215af7ab184SArchie Cobbs {
216af7ab184SArchie Cobbs 	priv_p priv;
217af7ab184SArchie Cobbs 
218af7ab184SArchie Cobbs 	/* Allocate private structure */
219674d86bfSGleb Smirnoff 	priv = malloc(sizeof(*priv), M_NETGRAPH_MPPC, M_WAITOK | M_ZERO);
220af7ab184SArchie Cobbs 
22130400f03SJulian Elischer 	NG_NODE_SET_PRIVATE(node, priv);
222af7ab184SArchie Cobbs 
2232f07580bSGleb Smirnoff 	/* This node is not thread safe. */
2242f07580bSGleb Smirnoff 	NG_NODE_FORCE_WRITER(node);
2252f07580bSGleb Smirnoff 
226af7ab184SArchie Cobbs 	/* Done */
227af7ab184SArchie Cobbs 	return (0);
228af7ab184SArchie Cobbs }
229af7ab184SArchie Cobbs 
230af7ab184SArchie Cobbs /*
231af7ab184SArchie Cobbs  * Give our OK for a hook to be added
232af7ab184SArchie Cobbs  */
233af7ab184SArchie Cobbs static int
234af7ab184SArchie Cobbs ng_mppc_newhook(node_p node, hook_p hook, const char *name)
235af7ab184SArchie Cobbs {
23630400f03SJulian Elischer 	const priv_p priv = NG_NODE_PRIVATE(node);
237af7ab184SArchie Cobbs 	hook_p *hookPtr;
238af7ab184SArchie Cobbs 
239af7ab184SArchie Cobbs 	/* Check hook name */
240af7ab184SArchie Cobbs 	if (strcmp(name, NG_MPPC_HOOK_COMP) == 0)
241af7ab184SArchie Cobbs 		hookPtr = &priv->xmit.hook;
242af7ab184SArchie Cobbs 	else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0)
243af7ab184SArchie Cobbs 		hookPtr = &priv->recv.hook;
244af7ab184SArchie Cobbs 	else
245af7ab184SArchie Cobbs 		return (EINVAL);
246af7ab184SArchie Cobbs 
247af7ab184SArchie Cobbs 	/* See if already connected */
248af7ab184SArchie Cobbs 	if (*hookPtr != NULL)
249af7ab184SArchie Cobbs 		return (EISCONN);
250af7ab184SArchie Cobbs 
251af7ab184SArchie Cobbs 	/* OK */
252af7ab184SArchie Cobbs 	*hookPtr = hook;
253af7ab184SArchie Cobbs 	return (0);
254af7ab184SArchie Cobbs }
255af7ab184SArchie Cobbs 
256af7ab184SArchie Cobbs /*
257af7ab184SArchie Cobbs  * Receive a control message
258af7ab184SArchie Cobbs  */
259af7ab184SArchie Cobbs static int
260069154d5SJulian Elischer ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook)
261af7ab184SArchie Cobbs {
26230400f03SJulian Elischer 	const priv_p priv = NG_NODE_PRIVATE(node);
263af7ab184SArchie Cobbs 	struct ng_mesg *resp = NULL;
264af7ab184SArchie Cobbs 	int error = 0;
265069154d5SJulian Elischer 	struct ng_mesg *msg;
266af7ab184SArchie Cobbs 
267069154d5SJulian Elischer 	NGI_GET_MSG(item, msg);
268af7ab184SArchie Cobbs 	switch (msg->header.typecookie) {
269af7ab184SArchie Cobbs 	case NGM_MPPC_COOKIE:
270af7ab184SArchie Cobbs 		switch (msg->header.cmd) {
271af7ab184SArchie Cobbs 		case NGM_MPPC_CONFIG_COMP:
272af7ab184SArchie Cobbs 		case NGM_MPPC_CONFIG_DECOMP:
273af7ab184SArchie Cobbs 		    {
274af7ab184SArchie Cobbs 			struct ng_mppc_config *const cfg
275af7ab184SArchie Cobbs 			    = (struct ng_mppc_config *)msg->data;
276af7ab184SArchie Cobbs 			const int isComp =
277af7ab184SArchie Cobbs 			    msg->header.cmd == NGM_MPPC_CONFIG_COMP;
278af7ab184SArchie Cobbs 			struct ng_mppc_dir *const d = isComp ?
279af7ab184SArchie Cobbs 			    &priv->xmit : &priv->recv;
280af7ab184SArchie Cobbs 
281af7ab184SArchie Cobbs 			/* Check configuration */
282af7ab184SArchie Cobbs 			if (msg->header.arglen != sizeof(*cfg))
283af7ab184SArchie Cobbs 				ERROUT(EINVAL);
284af7ab184SArchie Cobbs 			if (cfg->enable) {
285af7ab184SArchie Cobbs 				if ((cfg->bits & ~MPPC_VALID_BITS) != 0)
286af7ab184SArchie Cobbs 					ERROUT(EINVAL);
287af7ab184SArchie Cobbs #ifndef NETGRAPH_MPPC_COMPRESSION
288af7ab184SArchie Cobbs 				if ((cfg->bits & MPPC_BIT) != 0)
289af7ab184SArchie Cobbs 					ERROUT(EPROTONOSUPPORT);
290af7ab184SArchie Cobbs #endif
291af7ab184SArchie Cobbs #ifndef NETGRAPH_MPPC_ENCRYPTION
292af7ab184SArchie Cobbs 				if ((cfg->bits & MPPE_BITS) != 0)
293af7ab184SArchie Cobbs 					ERROUT(EPROTONOSUPPORT);
294af7ab184SArchie Cobbs #endif
295af7ab184SArchie Cobbs 			} else
296af7ab184SArchie Cobbs 				cfg->bits = 0;
297af7ab184SArchie Cobbs 
298af7ab184SArchie Cobbs 			/* Save return address so we can send reset-req's */
299f3059f39SArchie Cobbs 			if (!isComp)
300069154d5SJulian Elischer 				priv->ctrlnode = NGI_RETADDR(item);
301af7ab184SArchie Cobbs 
302af7ab184SArchie Cobbs 			/* Configuration is OK, reset to it */
303af7ab184SArchie Cobbs 			d->cfg = *cfg;
304af7ab184SArchie Cobbs 
305af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION
306af7ab184SArchie Cobbs 			/* Initialize state buffers for compression */
307af7ab184SArchie Cobbs 			if (d->history != NULL) {
3081ede983cSDag-Erling Smørgrav 				free(d->history, M_NETGRAPH_MPPC);
309af7ab184SArchie Cobbs 				d->history = NULL;
310af7ab184SArchie Cobbs 			}
311af7ab184SArchie Cobbs 			if ((cfg->bits & MPPC_BIT) != 0) {
312e11e3f18SDag-Erling Smørgrav 				d->history = malloc(isComp ?
313e11e3f18SDag-Erling Smørgrav 				    MPPC_SizeOfCompressionHistory() :
314af7ab184SArchie Cobbs 				    MPPC_SizeOfDecompressionHistory(),
3159c8c302fSJulian Elischer 				    M_NETGRAPH_MPPC, M_NOWAIT);
316af7ab184SArchie Cobbs 				if (d->history == NULL)
317af7ab184SArchie Cobbs 					ERROUT(ENOMEM);
318af7ab184SArchie Cobbs 				if (isComp)
319af7ab184SArchie Cobbs 					MPPC_InitCompressionHistory(d->history);
320af7ab184SArchie Cobbs 				else {
321af7ab184SArchie Cobbs 					MPPC_InitDecompressionHistory(
322af7ab184SArchie Cobbs 					    d->history);
323af7ab184SArchie Cobbs 				}
324af7ab184SArchie Cobbs 			}
325af7ab184SArchie Cobbs #endif
326af7ab184SArchie Cobbs 
327af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION
328af7ab184SArchie Cobbs 			/* Generate initial session keys for encryption */
329af7ab184SArchie Cobbs 			if ((cfg->bits & MPPE_BITS) != 0) {
330af7ab184SArchie Cobbs 				const int keylen = KEYLEN(cfg->bits);
331af7ab184SArchie Cobbs 
332af7ab184SArchie Cobbs 				bcopy(cfg->startkey, d->key, keylen);
333af7ab184SArchie Cobbs 				ng_mppc_getkey(cfg->startkey, d->key, keylen);
33434fd2381SArchie Cobbs 				if ((cfg->bits & MPPE_40) != 0)
33534fd2381SArchie Cobbs 					bcopy(&ng_mppe_weakenkey, d->key, 3);
33634fd2381SArchie Cobbs 				else if ((cfg->bits & MPPE_56) != 0)
33734fd2381SArchie Cobbs 					bcopy(&ng_mppe_weakenkey, d->key, 1);
338af7ab184SArchie Cobbs 				rc4_init(&d->rc4, d->key, keylen);
339af7ab184SArchie Cobbs 			}
340af7ab184SArchie Cobbs #endif
341af7ab184SArchie Cobbs 
342af7ab184SArchie Cobbs 			/* Initialize other state */
343af7ab184SArchie Cobbs 			d->cc = 0;
344af7ab184SArchie Cobbs 			d->flushed = 0;
345af7ab184SArchie Cobbs 			break;
346af7ab184SArchie Cobbs 		    }
347af7ab184SArchie Cobbs 
348af7ab184SArchie Cobbs 		case NGM_MPPC_RESETREQ:
349af7ab184SArchie Cobbs 			ng_mppc_reset_req(node);
350af7ab184SArchie Cobbs 			break;
351af7ab184SArchie Cobbs 
352af7ab184SArchie Cobbs 		default:
353af7ab184SArchie Cobbs 			error = EINVAL;
354af7ab184SArchie Cobbs 			break;
355af7ab184SArchie Cobbs 		}
356af7ab184SArchie Cobbs 		break;
357af7ab184SArchie Cobbs 	default:
358af7ab184SArchie Cobbs 		error = EINVAL;
359af7ab184SArchie Cobbs 		break;
360af7ab184SArchie Cobbs 	}
361af7ab184SArchie Cobbs done:
362069154d5SJulian Elischer 	NG_RESPOND_MSG(error, node, item, resp);
363069154d5SJulian Elischer 	NG_FREE_MSG(msg);
364af7ab184SArchie Cobbs 	return (error);
365af7ab184SArchie Cobbs }
366af7ab184SArchie Cobbs 
367af7ab184SArchie Cobbs /*
368af7ab184SArchie Cobbs  * Receive incoming data on our hook.
369af7ab184SArchie Cobbs  */
370af7ab184SArchie Cobbs static int
371069154d5SJulian Elischer ng_mppc_rcvdata(hook_p hook, item_p item)
372af7ab184SArchie Cobbs {
37330400f03SJulian Elischer 	const node_p node = NG_HOOK_NODE(hook);
37430400f03SJulian Elischer 	const priv_p priv = NG_NODE_PRIVATE(node);
375af7ab184SArchie Cobbs 	int error;
376069154d5SJulian Elischer 	struct mbuf *m;
377af7ab184SArchie Cobbs 
378069154d5SJulian Elischer 	NGI_GET_M(item, m);
379af7ab184SArchie Cobbs 	/* Compress and/or encrypt */
380af7ab184SArchie Cobbs 	if (hook == priv->xmit.hook) {
381af7ab184SArchie Cobbs 		if (!priv->xmit.cfg.enable) {
382069154d5SJulian Elischer 			NG_FREE_M(m);
383069154d5SJulian Elischer 			NG_FREE_ITEM(item);
384af7ab184SArchie Cobbs 			return (ENXIO);
385af7ab184SArchie Cobbs 		}
386ce52e8f4SAlexander Motin 		if ((error = ng_mppc_compress(node, &m)) != 0) {
387069154d5SJulian Elischer 			NG_FREE_ITEM(item);
388af7ab184SArchie Cobbs 			return(error);
389af7ab184SArchie Cobbs 		}
390ce52e8f4SAlexander Motin 		NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m);
391af7ab184SArchie Cobbs 		return (error);
392af7ab184SArchie Cobbs 	}
393af7ab184SArchie Cobbs 
394af7ab184SArchie Cobbs 	/* Decompress and/or decrypt */
395af7ab184SArchie Cobbs 	if (hook == priv->recv.hook) {
396af7ab184SArchie Cobbs 		if (!priv->recv.cfg.enable) {
397069154d5SJulian Elischer 			NG_FREE_M(m);
398069154d5SJulian Elischer 			NG_FREE_ITEM(item);
399af7ab184SArchie Cobbs 			return (ENXIO);
400af7ab184SArchie Cobbs 		}
401ce52e8f4SAlexander Motin 		if ((error = ng_mppc_decompress(node, &m)) != 0) {
402069154d5SJulian Elischer 			NG_FREE_ITEM(item);
403facfd889SArchie Cobbs 			if (error == EINVAL && priv->ctrlnode != 0) {
404af7ab184SArchie Cobbs 				struct ng_mesg *msg;
405af7ab184SArchie Cobbs 
406af7ab184SArchie Cobbs 				/* Need to send a reset-request */
407af7ab184SArchie Cobbs 				NG_MKMESSAGE(msg, NGM_MPPC_COOKIE,
408af7ab184SArchie Cobbs 				    NGM_MPPC_RESETREQ, 0, M_NOWAIT);
409af7ab184SArchie Cobbs 				if (msg == NULL)
410af7ab184SArchie Cobbs 					return (error);
411069154d5SJulian Elischer 				NG_SEND_MSG_ID(error, node, msg,
412facfd889SArchie Cobbs 					priv->ctrlnode, 0);
413af7ab184SArchie Cobbs 			}
414af7ab184SArchie Cobbs 			return (error);
415af7ab184SArchie Cobbs 		}
416ce52e8f4SAlexander Motin 		NG_FWD_NEW_DATA(error, item, priv->recv.hook, m);
417af7ab184SArchie Cobbs 		return (error);
418af7ab184SArchie Cobbs 	}
419af7ab184SArchie Cobbs 
420af7ab184SArchie Cobbs 	/* Oops */
4216e551fb6SDavid E. O'Brien 	panic("%s: unknown hook", __func__);
422af7ab184SArchie Cobbs }
423af7ab184SArchie Cobbs 
424af7ab184SArchie Cobbs /*
425af7ab184SArchie Cobbs  * Destroy node
426af7ab184SArchie Cobbs  */
427af7ab184SArchie Cobbs static int
428069154d5SJulian Elischer ng_mppc_shutdown(node_p node)
429af7ab184SArchie Cobbs {
43030400f03SJulian Elischer 	const priv_p priv = NG_NODE_PRIVATE(node);
431af7ab184SArchie Cobbs 
432af7ab184SArchie Cobbs 	/* Take down netgraph node */
433af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION
434af7ab184SArchie Cobbs 	if (priv->xmit.history != NULL)
4351ede983cSDag-Erling Smørgrav 		free(priv->xmit.history, M_NETGRAPH_MPPC);
436af7ab184SArchie Cobbs 	if (priv->recv.history != NULL)
4371ede983cSDag-Erling Smørgrav 		free(priv->recv.history, M_NETGRAPH_MPPC);
438af7ab184SArchie Cobbs #endif
439af7ab184SArchie Cobbs 	bzero(priv, sizeof(*priv));
4401ede983cSDag-Erling Smørgrav 	free(priv, M_NETGRAPH_MPPC);
44130400f03SJulian Elischer 	NG_NODE_SET_PRIVATE(node, NULL);
44230400f03SJulian Elischer 	NG_NODE_UNREF(node);		/* let the node escape */
443af7ab184SArchie Cobbs 	return (0);
444af7ab184SArchie Cobbs }
445af7ab184SArchie Cobbs 
446af7ab184SArchie Cobbs /*
447af7ab184SArchie Cobbs  * Hook disconnection
448af7ab184SArchie Cobbs  */
449af7ab184SArchie Cobbs static int
450af7ab184SArchie Cobbs ng_mppc_disconnect(hook_p hook)
451af7ab184SArchie Cobbs {
45230400f03SJulian Elischer 	const node_p node = NG_HOOK_NODE(hook);
45330400f03SJulian Elischer 	const priv_p priv = NG_NODE_PRIVATE(node);
454af7ab184SArchie Cobbs 
455af7ab184SArchie Cobbs 	/* Zero out hook pointer */
456af7ab184SArchie Cobbs 	if (hook == priv->xmit.hook)
457af7ab184SArchie Cobbs 		priv->xmit.hook = NULL;
458af7ab184SArchie Cobbs 	if (hook == priv->recv.hook)
459af7ab184SArchie Cobbs 		priv->recv.hook = NULL;
460af7ab184SArchie Cobbs 
461af7ab184SArchie Cobbs 	/* Go away if no longer connected */
46230400f03SJulian Elischer 	if ((NG_NODE_NUMHOOKS(node) == 0)
46330400f03SJulian Elischer 	&& NG_NODE_IS_VALID(node))
464069154d5SJulian Elischer 		ng_rmnode_self(node);
465af7ab184SArchie Cobbs 	return (0);
466af7ab184SArchie Cobbs }
467af7ab184SArchie Cobbs 
468af7ab184SArchie Cobbs /************************************************************************
469af7ab184SArchie Cobbs 			HELPER STUFF
470af7ab184SArchie Cobbs  ************************************************************************/
471af7ab184SArchie Cobbs 
472af7ab184SArchie Cobbs /*
473af7ab184SArchie Cobbs  * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
474af7ab184SArchie Cobbs  * The original mbuf is not free'd.
475af7ab184SArchie Cobbs  */
476af7ab184SArchie Cobbs static int
477ce52e8f4SAlexander Motin ng_mppc_compress(node_p node, struct mbuf **datap)
478af7ab184SArchie Cobbs {
47930400f03SJulian Elischer 	const priv_p priv = NG_NODE_PRIVATE(node);
480af7ab184SArchie Cobbs 	struct ng_mppc_dir *const d = &priv->xmit;
481af7ab184SArchie Cobbs 	u_int16_t header;
482ce52e8f4SAlexander Motin 	struct mbuf *m = *datap;
483af7ab184SArchie Cobbs 
484e4651e05SAlexander Motin 	/* We must own the mbuf chain exclusively to modify it. */
485eb1b1807SGleb Smirnoff 	m = m_unshare(m, M_NOWAIT);
486e4651e05SAlexander Motin 	if (m == NULL)
487e4651e05SAlexander Motin 		return (ENOMEM);
488e4651e05SAlexander Motin 
489af7ab184SArchie Cobbs 	/* Initialize */
490af7ab184SArchie Cobbs 	header = d->cc;
491adecf751SAlexander Motin 
492adecf751SAlexander Motin 	/* Always set the flushed bit in stateless mode */
493adecf751SAlexander Motin 	if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) {
494af7ab184SArchie Cobbs 		header |= MPPC_FLAG_FLUSHED;
495af7ab184SArchie Cobbs 		d->flushed = 0;
496af7ab184SArchie Cobbs 	}
497af7ab184SArchie Cobbs 
498ce52e8f4SAlexander Motin 	/* Compress packet (if compression enabled) */
499af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION
500af7ab184SArchie Cobbs 	if ((d->cfg.bits & MPPC_BIT) != 0) {
501af7ab184SArchie Cobbs 		u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS;
502ce52e8f4SAlexander Motin 		u_char *inbuf, *outbuf;
50367898a23SAlexander Motin 		int outlen, inlen, ina;
504af7ab184SArchie Cobbs 		u_char *source, *dest;
505af7ab184SArchie Cobbs 		u_long sourceCnt, destCnt;
506af7ab184SArchie Cobbs 		int rtn;
507af7ab184SArchie Cobbs 
508ce52e8f4SAlexander Motin 		/* Work with contiguous regions of memory. */
509ce52e8f4SAlexander Motin 		inlen = m->m_pkthdr.len;
51067898a23SAlexander Motin 		if (m->m_next == NULL) {
51167898a23SAlexander Motin 			inbuf = mtod(m, u_char *);
51267898a23SAlexander Motin 			ina = 0;
51367898a23SAlexander Motin 		} else {
514ce52e8f4SAlexander Motin 			inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
51511d1cadeSAlexander Motin 			if (inbuf == NULL)
51611d1cadeSAlexander Motin 				goto err1;
517ce52e8f4SAlexander Motin 			m_copydata(m, 0, inlen, (caddr_t)inbuf);
51867898a23SAlexander Motin 			ina = 1;
51967898a23SAlexander Motin 		}
520ce52e8f4SAlexander Motin 
521ce52e8f4SAlexander Motin 		outlen = MPPC_MAX_BLOWUP(inlen);
522ce52e8f4SAlexander Motin 		outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT);
523ce52e8f4SAlexander Motin 		if (outbuf == NULL) {
52467898a23SAlexander Motin 			if (ina)
525ce52e8f4SAlexander Motin 				free(inbuf, M_NETGRAPH_MPPC);
52611d1cadeSAlexander Motin err1:
52711d1cadeSAlexander Motin 			m_freem(m);
52811d1cadeSAlexander Motin 			MPPC_InitCompressionHistory(d->history);
52911d1cadeSAlexander Motin 			d->flushed = 1;
530ce52e8f4SAlexander Motin 			return (ENOMEM);
531ce52e8f4SAlexander Motin 		}
532ce52e8f4SAlexander Motin 
533af7ab184SArchie Cobbs 		/* Prepare to compress */
534af7ab184SArchie Cobbs 		source = inbuf;
535af7ab184SArchie Cobbs 		sourceCnt = inlen;
536ce52e8f4SAlexander Motin 		dest = outbuf;
537ce52e8f4SAlexander Motin 		destCnt = outlen;
538af7ab184SArchie Cobbs 		if ((d->cfg.bits & MPPE_STATELESS) == 0)
539af7ab184SArchie Cobbs 			flags |= MPPC_SAVE_HISTORY;
540af7ab184SArchie Cobbs 
541af7ab184SArchie Cobbs 		/* Compress */
542af7ab184SArchie Cobbs 		rtn = MPPC_Compress(&source, &dest, &sourceCnt,
543af7ab184SArchie Cobbs 			&destCnt, d->history, flags, 0);
544af7ab184SArchie Cobbs 
545af7ab184SArchie Cobbs 		/* Check return value */
5466e551fb6SDavid E. O'Brien 		KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
547af7ab184SArchie Cobbs 		if ((rtn & MPPC_EXPANDED) == 0
548af7ab184SArchie Cobbs 		    && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) {
549af7ab184SArchie Cobbs 			outlen -= destCnt;
550af7ab184SArchie Cobbs 			header |= MPPC_FLAG_COMPRESSED;
551af7ab184SArchie Cobbs 			if ((rtn & MPPC_RESTART_HISTORY) != 0)
552af7ab184SArchie Cobbs 				header |= MPPC_FLAG_RESTART;
553ce52e8f4SAlexander Motin 
554ce52e8f4SAlexander Motin 			/* Replace m by the compresed one. */
555e4651e05SAlexander Motin 			m_copyback(m, 0, outlen, (caddr_t)outbuf);
556e4651e05SAlexander Motin 			if (m->m_pkthdr.len < outlen) {
557ce52e8f4SAlexander Motin 				m_freem(m);
558e4651e05SAlexander Motin 				m = NULL;
559e4651e05SAlexander Motin 			} else if (outlen < m->m_pkthdr.len)
560e4651e05SAlexander Motin 				m_adj(m, outlen - m->m_pkthdr.len);
561af7ab184SArchie Cobbs 		}
562af7ab184SArchie Cobbs 		d->flushed = (rtn & MPPC_EXPANDED) != 0
563af7ab184SArchie Cobbs 		    || (flags & MPPC_SAVE_HISTORY) == 0;
564ce52e8f4SAlexander Motin 
56567898a23SAlexander Motin 		if (ina)
566ce52e8f4SAlexander Motin 			free(inbuf, M_NETGRAPH_MPPC);
567ce52e8f4SAlexander Motin 		free(outbuf, M_NETGRAPH_MPPC);
568ce52e8f4SAlexander Motin 
569e4651e05SAlexander Motin 		/* Check mbuf chain reload result. */
57011d1cadeSAlexander Motin 		if (m == NULL) {
57111d1cadeSAlexander Motin 			if (!d->flushed) {
57211d1cadeSAlexander Motin 				MPPC_InitCompressionHistory(d->history);
57311d1cadeSAlexander Motin 				d->flushed = 1;
57411d1cadeSAlexander Motin 			}
575ce52e8f4SAlexander Motin 			return (ENOMEM);
576af7ab184SArchie Cobbs 		}
57711d1cadeSAlexander Motin 	}
578af7ab184SArchie Cobbs #endif
579af7ab184SArchie Cobbs 
580af7ab184SArchie Cobbs 	/* Now encrypt packet (if encryption enabled) */
581af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION
582af7ab184SArchie Cobbs 	if ((d->cfg.bits & MPPE_BITS) != 0) {
583ce52e8f4SAlexander Motin 		struct mbuf *m1;
584af7ab184SArchie Cobbs 
5856370fd6bSAlexander Motin 		/* Set header bits */
586af7ab184SArchie Cobbs 		header |= MPPC_FLAG_ENCRYPTED;
587af7ab184SArchie Cobbs 
588af7ab184SArchie Cobbs 		/* Update key if it's time */
589af7ab184SArchie Cobbs 		if ((d->cfg.bits & MPPE_STATELESS) != 0
590af7ab184SArchie Cobbs 		    || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
591af7ab184SArchie Cobbs 			ng_mppc_updatekey(d->cfg.bits,
592af7ab184SArchie Cobbs 			    d->cfg.startkey, d->key, &d->rc4);
5936370fd6bSAlexander Motin 		} else if ((header & MPPC_FLAG_FLUSHED) != 0) {
5946370fd6bSAlexander Motin 			/* Need to reset key if we say we did
5956370fd6bSAlexander Motin 			   and ng_mppc_updatekey wasn't called to do it also. */
5966370fd6bSAlexander Motin 			rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
597af7ab184SArchie Cobbs 		}
598af7ab184SArchie Cobbs 
599af7ab184SArchie Cobbs 		/* Encrypt packet */
600ce52e8f4SAlexander Motin 		m1 = m;
601ce52e8f4SAlexander Motin 		while (m1) {
602ce52e8f4SAlexander Motin 			rc4_crypt(&d->rc4, mtod(m1, u_char *),
603ce52e8f4SAlexander Motin 			    mtod(m1, u_char *), m1->m_len);
604ce52e8f4SAlexander Motin 			m1 = m1->m_next;
605ce52e8f4SAlexander Motin 		}
606af7ab184SArchie Cobbs 	}
607af7ab184SArchie Cobbs #endif
608af7ab184SArchie Cobbs 
609755bc287SAlexander Motin 	/* Update coherency count for next time (12 bit arithmetic) */
610755bc287SAlexander Motin 	MPPC_CCOUNT_INC(d->cc);
611af7ab184SArchie Cobbs 
612af7ab184SArchie Cobbs 	/* Install header */
613eb1b1807SGleb Smirnoff 	M_PREPEND(m, MPPC_HDRLEN, M_NOWAIT);
614ce52e8f4SAlexander Motin 	if (m != NULL)
61539228864SAlexander Motin 		be16enc(mtod(m, void *), header);
616af7ab184SArchie Cobbs 
617ce52e8f4SAlexander Motin 	*datap = m;
618ce52e8f4SAlexander Motin 	return (*datap == NULL ? ENOBUFS : 0);
619af7ab184SArchie Cobbs }
620af7ab184SArchie Cobbs 
621af7ab184SArchie Cobbs /*
622af7ab184SArchie Cobbs  * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
623af7ab184SArchie Cobbs  * The original mbuf is not free'd.
624af7ab184SArchie Cobbs  */
625af7ab184SArchie Cobbs static int
626ce52e8f4SAlexander Motin ng_mppc_decompress(node_p node, struct mbuf **datap)
627af7ab184SArchie Cobbs {
62830400f03SJulian Elischer 	const priv_p priv = NG_NODE_PRIVATE(node);
629af7ab184SArchie Cobbs 	struct ng_mppc_dir *const d = &priv->recv;
630f3059f39SArchie Cobbs 	u_int16_t header, cc;
631f3059f39SArchie Cobbs 	u_int numLost;
632ce52e8f4SAlexander Motin 	struct mbuf *m = *datap;
633af7ab184SArchie Cobbs 
634e4651e05SAlexander Motin 	/* We must own the mbuf chain exclusively to modify it. */
635eb1b1807SGleb Smirnoff 	m = m_unshare(m, M_NOWAIT);
636e4651e05SAlexander Motin 	if (m == NULL)
637e4651e05SAlexander Motin 		return (ENOMEM);
638e4651e05SAlexander Motin 
639af7ab184SArchie Cobbs 	/* Pull off header */
640ce52e8f4SAlexander Motin 	if (m->m_pkthdr.len < MPPC_HDRLEN) {
641ce52e8f4SAlexander Motin 		m_freem(m);
642af7ab184SArchie Cobbs 		return (EINVAL);
643ce52e8f4SAlexander Motin 	}
64439228864SAlexander Motin 	header = be16dec(mtod(m, void *));
645af7ab184SArchie Cobbs 	cc = (header & MPPC_CCOUNT_MASK);
646ce52e8f4SAlexander Motin 	m_adj(m, MPPC_HDRLEN);
647af7ab184SArchie Cobbs 
648f3059f39SArchie Cobbs 	/* Check for an unexpected jump in the sequence number */
649af7ab184SArchie Cobbs 	numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK);
650af7ab184SArchie Cobbs 
651af7ab184SArchie Cobbs 	/* If flushed bit set, we can always handle packet */
652af7ab184SArchie Cobbs 	if ((header & MPPC_FLAG_FLUSHED) != 0) {
653af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION
654af7ab184SArchie Cobbs 		if (d->history != NULL)
655af7ab184SArchie Cobbs 			MPPC_InitDecompressionHistory(d->history);
656af7ab184SArchie Cobbs #endif
657af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION
658af7ab184SArchie Cobbs 		if ((d->cfg.bits & MPPE_BITS) != 0) {
659f3059f39SArchie Cobbs 			u_int rekey;
660af7ab184SArchie Cobbs 
661f3059f39SArchie Cobbs 			/* How many times are we going to have to re-key? */
662f3059f39SArchie Cobbs 			rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ?
663f3059f39SArchie Cobbs 			    numLost : (numLost / (MPPE_UPDATE_MASK + 1));
664ee652839SAlexander Motin 			if (rekey > mppe_max_rekey) {
665ee652839SAlexander Motin 			    if (mppe_block_on_max_rekey) {
666ee652839SAlexander Motin 				if (mppe_log_max_rekey) {
6675372c30bSGleb Smirnoff 				    log(LOG_ERR, "%s: too many (%d) packets"
668ee652839SAlexander Motin 					" dropped, disabling node %p!\n",
6695372c30bSGleb Smirnoff 					__func__, numLost, node);
670ee652839SAlexander Motin 				}
6715372c30bSGleb Smirnoff 				priv->recv.cfg.enable = 0;
6725372c30bSGleb Smirnoff 				goto failed;
673ee652839SAlexander Motin 			    } else {
674ee652839SAlexander Motin 				if (mppe_log_max_rekey) {
675ee652839SAlexander Motin 				    log(LOG_ERR, "%s: %d packets"
676ee652839SAlexander Motin 					" dropped, node %p\n",
677ee652839SAlexander Motin 					__func__, numLost, node);
678ee652839SAlexander Motin 				}
679ee652839SAlexander Motin 				goto failed;
680ee652839SAlexander Motin 			    }
6815372c30bSGleb Smirnoff 			}
682f3059f39SArchie Cobbs 
6835372c30bSGleb Smirnoff 			/* Re-key as necessary to catch up to peer */
684af7ab184SArchie Cobbs 			while (d->cc != cc) {
685f3059f39SArchie Cobbs 				if ((d->cfg.bits & MPPE_STATELESS) != 0
686af7ab184SArchie Cobbs 				    || (d->cc & MPPE_UPDATE_MASK)
687af7ab184SArchie Cobbs 				      == MPPE_UPDATE_FLAG) {
688af7ab184SArchie Cobbs 					ng_mppc_updatekey(d->cfg.bits,
689af7ab184SArchie Cobbs 					    d->cfg.startkey, d->key, &d->rc4);
690af7ab184SArchie Cobbs 				}
691755bc287SAlexander Motin 				MPPC_CCOUNT_INC(d->cc);
692af7ab184SArchie Cobbs 			}
693af7ab184SArchie Cobbs 
694af7ab184SArchie Cobbs 			/* Reset key (except in stateless mode, see below) */
695af7ab184SArchie Cobbs 			if ((d->cfg.bits & MPPE_STATELESS) == 0)
696af7ab184SArchie Cobbs 				rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
697af7ab184SArchie Cobbs 		}
698af7ab184SArchie Cobbs #endif
699af7ab184SArchie Cobbs 		d->cc = cc;		/* skip over lost seq numbers */
700af7ab184SArchie Cobbs 		numLost = 0;		/* act like no packets were lost */
701af7ab184SArchie Cobbs 	}
702af7ab184SArchie Cobbs 
703af7ab184SArchie Cobbs 	/* Can't decode non-sequential packets without a flushed bit */
704af7ab184SArchie Cobbs 	if (numLost != 0)
705af7ab184SArchie Cobbs 		goto failed;
706af7ab184SArchie Cobbs 
707af7ab184SArchie Cobbs 	/* Decrypt packet */
708af7ab184SArchie Cobbs 	if ((header & MPPC_FLAG_ENCRYPTED) != 0) {
709ce52e8f4SAlexander Motin #ifdef NETGRAPH_MPPC_ENCRYPTION
710ce52e8f4SAlexander Motin 		struct mbuf *m1;
711ce52e8f4SAlexander Motin #endif
712af7ab184SArchie Cobbs 
713af7ab184SArchie Cobbs 		/* Are we not expecting encryption? */
714af7ab184SArchie Cobbs 		if ((d->cfg.bits & MPPE_BITS) == 0) {
715af7ab184SArchie Cobbs 			log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
7166e551fb6SDavid E. O'Brien 				__func__, "encrypted");
717af7ab184SArchie Cobbs 			goto failed;
718af7ab184SArchie Cobbs 		}
719af7ab184SArchie Cobbs 
720af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION
721af7ab184SArchie Cobbs 		/* Update key if it's time (always in stateless mode) */
722af7ab184SArchie Cobbs 		if ((d->cfg.bits & MPPE_STATELESS) != 0
723af7ab184SArchie Cobbs 		    || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
724af7ab184SArchie Cobbs 			ng_mppc_updatekey(d->cfg.bits,
725af7ab184SArchie Cobbs 			    d->cfg.startkey, d->key, &d->rc4);
726af7ab184SArchie Cobbs 		}
727af7ab184SArchie Cobbs 
728af7ab184SArchie Cobbs 		/* Decrypt packet */
729ce52e8f4SAlexander Motin 		m1 = m;
730ce52e8f4SAlexander Motin 		while (m1 != NULL) {
731ce52e8f4SAlexander Motin 			rc4_crypt(&d->rc4, mtod(m1, u_char *),
732ce52e8f4SAlexander Motin 			    mtod(m1, u_char *), m1->m_len);
733ce52e8f4SAlexander Motin 			m1 = m1->m_next;
734ce52e8f4SAlexander Motin 		}
735af7ab184SArchie Cobbs #endif
736af7ab184SArchie Cobbs 	} else {
737af7ab184SArchie Cobbs 
738af7ab184SArchie Cobbs 		/* Are we expecting encryption? */
739af7ab184SArchie Cobbs 		if ((d->cfg.bits & MPPE_BITS) != 0) {
740af7ab184SArchie Cobbs 			log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
7416e551fb6SDavid E. O'Brien 				__func__, "unencrypted");
742af7ab184SArchie Cobbs 			goto failed;
743af7ab184SArchie Cobbs 		}
744af7ab184SArchie Cobbs 	}
745af7ab184SArchie Cobbs 
746af7ab184SArchie Cobbs 	/* Update coherency count for next time (12 bit arithmetic) */
747755bc287SAlexander Motin 	MPPC_CCOUNT_INC(d->cc);
748af7ab184SArchie Cobbs 
749af7ab184SArchie Cobbs 	/* Check for unexpected compressed packet */
750af7ab184SArchie Cobbs 	if ((header & MPPC_FLAG_COMPRESSED) != 0
751af7ab184SArchie Cobbs 	    && (d->cfg.bits & MPPC_BIT) == 0) {
752af7ab184SArchie Cobbs 		log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
7536e551fb6SDavid E. O'Brien 			__func__, "compressed");
754af7ab184SArchie Cobbs failed:
755ce52e8f4SAlexander Motin 		m_freem(m);
756af7ab184SArchie Cobbs 		return (EINVAL);
757af7ab184SArchie Cobbs 	}
758af7ab184SArchie Cobbs 
759af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION
760af7ab184SArchie Cobbs 	/* Decompress packet */
761af7ab184SArchie Cobbs 	if ((header & MPPC_FLAG_COMPRESSED) != 0) {
762af7ab184SArchie Cobbs 		int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS;
76367898a23SAlexander Motin 		u_char *inbuf, *outbuf;
76467898a23SAlexander Motin 		int inlen, outlen, ina;
76567898a23SAlexander Motin 		u_char *source, *dest;
766af7ab184SArchie Cobbs 		u_long sourceCnt, destCnt;
76767898a23SAlexander Motin 		int rtn;
768ce52e8f4SAlexander Motin 
769ce52e8f4SAlexander Motin 		/* Copy payload into a contiguous region of memory. */
77067898a23SAlexander Motin 		inlen = m->m_pkthdr.len;
77167898a23SAlexander Motin 		if (m->m_next == NULL) {
77267898a23SAlexander Motin                 	inbuf = mtod(m, u_char *);
77367898a23SAlexander Motin 			ina = 0;
77467898a23SAlexander Motin 		} else {
77567898a23SAlexander Motin 		        inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
77667898a23SAlexander Motin 			if (inbuf == NULL) {
777ce52e8f4SAlexander Motin 				m_freem(m);
778ce52e8f4SAlexander Motin 				return (ENOMEM);
779ce52e8f4SAlexander Motin 			}
78067898a23SAlexander Motin 			m_copydata(m, 0, inlen, (caddr_t)inbuf);
78167898a23SAlexander Motin 			ina = 1;
78267898a23SAlexander Motin 		}
783af7ab184SArchie Cobbs 
784af7ab184SArchie Cobbs 		/* Allocate a buffer for decompressed data */
78567898a23SAlexander Motin 		outbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY,
786ce52e8f4SAlexander Motin 		    M_NETGRAPH_MPPC, M_NOWAIT);
78767898a23SAlexander Motin 		if (outbuf == NULL) {
788ce52e8f4SAlexander Motin 			m_freem(m);
78967898a23SAlexander Motin 			if (ina)
79067898a23SAlexander Motin 				free(inbuf, M_NETGRAPH_MPPC);
791af7ab184SArchie Cobbs 			return (ENOMEM);
792af7ab184SArchie Cobbs 		}
79367898a23SAlexander Motin 		outlen = MPPC_DECOMP_BUFSIZE;
794af7ab184SArchie Cobbs 
795af7ab184SArchie Cobbs 		/* Prepare to decompress */
79667898a23SAlexander Motin 		source = inbuf;
79767898a23SAlexander Motin 		sourceCnt = inlen;
79867898a23SAlexander Motin 		dest = outbuf;
79967898a23SAlexander Motin 		destCnt = outlen;
800af7ab184SArchie Cobbs 		if ((header & MPPC_FLAG_RESTART) != 0)
801af7ab184SArchie Cobbs 			flags |= MPPC_RESTART_HISTORY;
802af7ab184SArchie Cobbs 
803af7ab184SArchie Cobbs 		/* Decompress */
804af7ab184SArchie Cobbs 		rtn = MPPC_Decompress(&source, &dest,
805af7ab184SArchie Cobbs 			&sourceCnt, &destCnt, d->history, flags);
806af7ab184SArchie Cobbs 
807af7ab184SArchie Cobbs 		/* Check return value */
8086e551fb6SDavid E. O'Brien 		KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
809af7ab184SArchie Cobbs 		if ((rtn & MPPC_DEST_EXHAUSTED) != 0
810af7ab184SArchie Cobbs 		    || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) {
811af7ab184SArchie Cobbs 			log(LOG_ERR, "%s: decomp returned 0x%x",
8126e551fb6SDavid E. O'Brien 			    __func__, rtn);
81367898a23SAlexander Motin 			if (ina)
81467898a23SAlexander Motin 				free(inbuf, M_NETGRAPH_MPPC);
81567898a23SAlexander Motin 			free(outbuf, M_NETGRAPH_MPPC);
816af7ab184SArchie Cobbs 			goto failed;
817af7ab184SArchie Cobbs 		}
818af7ab184SArchie Cobbs 
819af7ab184SArchie Cobbs 		/* Replace compressed data with decompressed data */
82067898a23SAlexander Motin 		if (ina)
82167898a23SAlexander Motin 			free(inbuf, M_NETGRAPH_MPPC);
82267898a23SAlexander Motin 		outlen -= destCnt;
823ce52e8f4SAlexander Motin 
82467898a23SAlexander Motin 		m_copyback(m, 0, outlen, (caddr_t)outbuf);
82567898a23SAlexander Motin 		if (m->m_pkthdr.len < outlen) {
826ce52e8f4SAlexander Motin 			m_freem(m);
827e4651e05SAlexander Motin 			m = NULL;
82867898a23SAlexander Motin 		} else if (outlen < m->m_pkthdr.len)
82967898a23SAlexander Motin 			m_adj(m, outlen - m->m_pkthdr.len);
83067898a23SAlexander Motin 		free(outbuf, M_NETGRAPH_MPPC);
831af7ab184SArchie Cobbs 	}
832af7ab184SArchie Cobbs #endif
833af7ab184SArchie Cobbs 
834af7ab184SArchie Cobbs 	/* Return result in an mbuf */
835ce52e8f4SAlexander Motin 	*datap = m;
836ce52e8f4SAlexander Motin 	return (*datap == NULL ? ENOBUFS : 0);
837af7ab184SArchie Cobbs }
838af7ab184SArchie Cobbs 
839af7ab184SArchie Cobbs /*
840af7ab184SArchie Cobbs  * The peer has sent us a CCP ResetRequest, so reset our transmit state.
841af7ab184SArchie Cobbs  */
842af7ab184SArchie Cobbs static void
843af7ab184SArchie Cobbs ng_mppc_reset_req(node_p node)
844af7ab184SArchie Cobbs {
84530400f03SJulian Elischer 	const priv_p priv = NG_NODE_PRIVATE(node);
846af7ab184SArchie Cobbs 	struct ng_mppc_dir *const d = &priv->xmit;
847af7ab184SArchie Cobbs 
848af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_COMPRESSION
849af7ab184SArchie Cobbs 	if (d->history != NULL)
850af7ab184SArchie Cobbs 		MPPC_InitCompressionHistory(d->history);
851af7ab184SArchie Cobbs #endif
852af7ab184SArchie Cobbs #ifdef NETGRAPH_MPPC_ENCRYPTION
853af7ab184SArchie Cobbs 	if ((d->cfg.bits & MPPE_STATELESS) == 0)
854af7ab184SArchie Cobbs 		rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
855af7ab184SArchie Cobbs #endif
856af7ab184SArchie Cobbs 	d->flushed = 1;
857af7ab184SArchie Cobbs }
858af7ab184SArchie Cobbs 
85906c51e6eSAlexander Motin #ifdef NETGRAPH_MPPC_ENCRYPTION
860af7ab184SArchie Cobbs /*
861af7ab184SArchie Cobbs  * Generate a new encryption key
862af7ab184SArchie Cobbs  */
863af7ab184SArchie Cobbs static void
864af7ab184SArchie Cobbs ng_mppc_getkey(const u_char *h, u_char *h2, int len)
865af7ab184SArchie Cobbs {
866b3d298b9SAlexander Motin 	static const u_char pad1[40] =
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 	      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
870b3d298b9SAlexander Motin 	      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
871b3d298b9SAlexander Motin 	static const u_char pad2[40] =
872b3d298b9SAlexander Motin 	    { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
873b3d298b9SAlexander Motin 	      0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
874b3d298b9SAlexander Motin 	      0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
875b3d298b9SAlexander Motin 	      0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 };
876af7ab184SArchie Cobbs 	u_char hash[20];
877af7ab184SArchie Cobbs 	SHA1_CTX c;
878af7ab184SArchie Cobbs 
879af7ab184SArchie Cobbs 	SHA1Init(&c);
880af7ab184SArchie Cobbs 	SHA1Update(&c, h, len);
881592009a3SAlexander Motin 	SHA1Update(&c, pad1, sizeof(pad1));
882af7ab184SArchie Cobbs 	SHA1Update(&c, h2, len);
883af7ab184SArchie Cobbs 	SHA1Update(&c, pad2, sizeof(pad2));
884af7ab184SArchie Cobbs 	SHA1Final(hash, &c);
885af7ab184SArchie Cobbs 	bcopy(hash, h2, len);
886af7ab184SArchie Cobbs }
887af7ab184SArchie Cobbs 
888af7ab184SArchie Cobbs /*
889af7ab184SArchie Cobbs  * Update the encryption key
890af7ab184SArchie Cobbs  */
891af7ab184SArchie Cobbs static void
892af7ab184SArchie Cobbs ng_mppc_updatekey(u_int32_t bits,
893af7ab184SArchie Cobbs 	u_char *key0, u_char *key, struct rc4_state *rc4)
894af7ab184SArchie Cobbs {
895af7ab184SArchie Cobbs 	const int keylen = KEYLEN(bits);
896af7ab184SArchie Cobbs 
897af7ab184SArchie Cobbs 	ng_mppc_getkey(key0, key, keylen);
898af7ab184SArchie Cobbs 	rc4_init(rc4, key, keylen);
899af7ab184SArchie Cobbs 	rc4_crypt(rc4, key, key, keylen);
90034fd2381SArchie Cobbs 	if ((bits & MPPE_40) != 0)
90134fd2381SArchie Cobbs 		bcopy(&ng_mppe_weakenkey, key, 3);
90234fd2381SArchie Cobbs 	else if ((bits & MPPE_56) != 0)
90334fd2381SArchie Cobbs 		bcopy(&ng_mppe_weakenkey, key, 1);
904af7ab184SArchie Cobbs 	rc4_init(rc4, key, keylen);
905af7ab184SArchie Cobbs }
90606c51e6eSAlexander Motin #endif
907af7ab184SArchie Cobbs 
908