6 * Copyright (c) 1996-2000 Whistle Communications, Inc.
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.
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
38 * Author: Archie Cobbs <archie@freebsd.org>
40 * $Whistle: ng_mppc.c,v 1.4 1999/11/25 00:10:12 archie Exp $
45 * Microsoft PPP compression (MPPC) and encryption (MPPE) netgraph node type.
47 * You must define one or both of the NETGRAPH_MPPC_COMPRESSION and/or
48 * NETGRAPH_MPPC_ENCRYPTION options for this node type to be useful.
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/kernel.h>
55 #include <sys/malloc.h>
56 #include <sys/endian.h>
57 #include <sys/errno.h>
58 #include <sys/sysctl.h>
59 #include <sys/syslog.h>
61 #include <netgraph/ng_message.h>
62 #include <netgraph/netgraph.h>
63 #include <netgraph/ng_mppc.h>
65 #include "opt_netgraph.h"
67 #if !defined(NETGRAPH_MPPC_COMPRESSION) && !defined(NETGRAPH_MPPC_ENCRYPTION)
69 /* XXX NETGRAPH_MPPC_COMPRESSION isn't functional yet */
70 #define NETGRAPH_MPPC_ENCRYPTION
72 /* This case is indicative of an error in sys/conf files */
73 #error Need either NETGRAPH_MPPC_COMPRESSION or NETGRAPH_MPPC_ENCRYPTION
77 #ifdef NG_SEPARATE_MALLOC
78 static MALLOC_DEFINE(M_NETGRAPH_MPPC, "netgraph_mppc", "netgraph mppc node");
80 #define M_NETGRAPH_MPPC M_NETGRAPH
83 #ifdef NETGRAPH_MPPC_COMPRESSION
84 /* XXX this file doesn't exist yet, but hopefully someday it will... */
87 #ifdef NETGRAPH_MPPC_ENCRYPTION
88 #include <crypto/rc4/rc4.h>
90 #include <crypto/sha1.h>
92 /* Decompression blowup */
93 #define MPPC_DECOMP_BUFSIZE 8092 /* allocate buffer this big */
94 #define MPPC_DECOMP_SAFETY 100 /* plus this much margin */
96 /* MPPC/MPPE header length */
100 #define KEYLEN(b) (((b) & MPPE_128) ? 16 : 8)
103 * When packets are lost with MPPE, we may have to re-key arbitrarily
104 * many times to 'catch up' to the new jumped-ahead sequence number.
105 * Since this can be expensive, we pose a limit on how many re-keyings
106 * we will do at one time to avoid a possible D.O.S. vulnerability.
107 * This should instead be a configurable parameter.
109 #define MPPE_MAX_REKEY 1000
111 SYSCTL_NODE(_net_graph, OID_AUTO, mppe, CTLFLAG_RW, 0, "MPPE");
113 static int mppe_block_on_max_rekey = 0;
114 TUNABLE_INT("net.graph.mppe.block_on_max_rekey", &mppe_block_on_max_rekey);
115 SYSCTL_INT(_net_graph_mppe, OID_AUTO, block_on_max_rekey, CTLFLAG_RW,
116 &mppe_block_on_max_rekey, 0, "Block node on max MPPE key re-calculations");
118 static int mppe_log_max_rekey = 1;
119 TUNABLE_INT("net.graph.mppe.log_max_rekey", &mppe_log_max_rekey);
120 SYSCTL_INT(_net_graph_mppe, OID_AUTO, log_max_rekey, CTLFLAG_RW,
121 &mppe_log_max_rekey, 0, "Log max MPPE key re-calculations event");
123 static int mppe_max_rekey = MPPE_MAX_REKEY;
124 TUNABLE_INT("net.graph.mppe.max_rekey", &mppe_max_rekey);
125 SYSCTL_INT(_net_graph_mppe, OID_AUTO, max_rekey, CTLFLAG_RW,
126 &mppe_max_rekey, 0, "Maximum number of MPPE key re-calculations");
128 /* MPPC packet header bits */
129 #define MPPC_FLAG_FLUSHED 0x8000 /* xmitter reset state */
130 #define MPPC_FLAG_RESTART 0x4000 /* compress history restart */
131 #define MPPC_FLAG_COMPRESSED 0x2000 /* packet is compresed */
132 #define MPPC_FLAG_ENCRYPTED 0x1000 /* packet is encrypted */
133 #define MPPC_CCOUNT_MASK 0x0fff /* sequence number mask */
135 #define MPPC_CCOUNT_INC(d) ((d) = (((d) + 1) & MPPC_CCOUNT_MASK))
137 #define MPPE_UPDATE_MASK 0xff /* coherency count when we're */
138 #define MPPE_UPDATE_FLAG 0xff /* supposed to update key */
140 #define MPPC_COMP_OK 0x05
141 #define MPPC_DECOMP_OK 0x05
143 /* Per direction info */
145 struct ng_mppc_config cfg; /* configuration */
146 hook_p hook; /* netgraph hook */
147 u_int16_t cc:12; /* coherency count */
148 u_char flushed; /* clean history (xmit only) */
149 #ifdef NETGRAPH_MPPC_COMPRESSION
150 u_char *history; /* compression history */
152 #ifdef NETGRAPH_MPPC_ENCRYPTION
153 u_char key[MPPE_KEY_LEN]; /* session key */
154 struct rc4_state rc4; /* rc4 state */
158 /* Node private data */
159 struct ng_mppc_private {
160 struct ng_mppc_dir xmit; /* compress/encrypt config */
161 struct ng_mppc_dir recv; /* decompress/decrypt config */
162 ng_ID_t ctrlnode; /* path to controlling node */
164 typedef struct ng_mppc_private *priv_p;
166 /* Netgraph node methods */
167 static ng_constructor_t ng_mppc_constructor;
168 static ng_rcvmsg_t ng_mppc_rcvmsg;
169 static ng_shutdown_t ng_mppc_shutdown;
170 static ng_newhook_t ng_mppc_newhook;
171 static ng_rcvdata_t ng_mppc_rcvdata;
172 static ng_disconnect_t ng_mppc_disconnect;
174 /* Helper functions */
175 static int ng_mppc_compress(node_p node,
176 struct mbuf **datap);
177 static int ng_mppc_decompress(node_p node,
178 struct mbuf **datap);
179 #ifdef NETGRAPH_MPPC_ENCRYPTION
180 static void ng_mppc_getkey(const u_char *h, u_char *h2, int len);
181 static void ng_mppc_updatekey(u_int32_t bits,
182 u_char *key0, u_char *key, struct rc4_state *rc4);
184 static void ng_mppc_reset_req(node_p node);
186 /* Node type descriptor */
187 static struct ng_type ng_mppc_typestruct = {
188 .version = NG_ABI_VERSION,
189 .name = NG_MPPC_NODE_TYPE,
190 .constructor = ng_mppc_constructor,
191 .rcvmsg = ng_mppc_rcvmsg,
192 .shutdown = ng_mppc_shutdown,
193 .newhook = ng_mppc_newhook,
194 .rcvdata = ng_mppc_rcvdata,
195 .disconnect = ng_mppc_disconnect,
197 NETGRAPH_INIT(mppc, &ng_mppc_typestruct);
199 #ifdef NETGRAPH_MPPC_ENCRYPTION
200 /* Depend on separate rc4 module */
201 MODULE_DEPEND(ng_mppc, rc4, 1, 1, 1);
204 /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
205 static const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e };
207 #define ERROUT(x) do { error = (x); goto done; } while (0)
209 /************************************************************************
211 ************************************************************************/
214 * Node type constructor
217 ng_mppc_constructor(node_p node)
221 /* Allocate private structure */
222 priv = malloc(sizeof(*priv), M_NETGRAPH_MPPC, M_WAITOK | M_ZERO);
224 NG_NODE_SET_PRIVATE(node, priv);
226 /* This node is not thread safe. */
227 NG_NODE_FORCE_WRITER(node);
234 * Give our OK for a hook to be added
237 ng_mppc_newhook(node_p node, hook_p hook, const char *name)
239 const priv_p priv = NG_NODE_PRIVATE(node);
242 /* Check hook name */
243 if (strcmp(name, NG_MPPC_HOOK_COMP) == 0)
244 hookPtr = &priv->xmit.hook;
245 else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0)
246 hookPtr = &priv->recv.hook;
250 /* See if already connected */
251 if (*hookPtr != NULL)
260 * Receive a control message
263 ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook)
265 const priv_p priv = NG_NODE_PRIVATE(node);
266 struct ng_mesg *resp = NULL;
270 NGI_GET_MSG(item, msg);
271 switch (msg->header.typecookie) {
272 case NGM_MPPC_COOKIE:
273 switch (msg->header.cmd) {
274 case NGM_MPPC_CONFIG_COMP:
275 case NGM_MPPC_CONFIG_DECOMP:
277 struct ng_mppc_config *const cfg
278 = (struct ng_mppc_config *)msg->data;
280 msg->header.cmd == NGM_MPPC_CONFIG_COMP;
281 struct ng_mppc_dir *const d = isComp ?
282 &priv->xmit : &priv->recv;
284 /* Check configuration */
285 if (msg->header.arglen != sizeof(*cfg))
288 if ((cfg->bits & ~MPPC_VALID_BITS) != 0)
290 #ifndef NETGRAPH_MPPC_COMPRESSION
291 if ((cfg->bits & MPPC_BIT) != 0)
292 ERROUT(EPROTONOSUPPORT);
294 #ifndef NETGRAPH_MPPC_ENCRYPTION
295 if ((cfg->bits & MPPE_BITS) != 0)
296 ERROUT(EPROTONOSUPPORT);
301 /* Save return address so we can send reset-req's */
303 priv->ctrlnode = NGI_RETADDR(item);
305 /* Configuration is OK, reset to it */
308 #ifdef NETGRAPH_MPPC_COMPRESSION
309 /* Initialize state buffers for compression */
310 if (d->history != NULL) {
311 free(d->history, M_NETGRAPH_MPPC);
314 if ((cfg->bits & MPPC_BIT) != 0) {
315 d->history = malloc(isComp ?
316 MPPC_SizeOfCompressionHistory() :
317 MPPC_SizeOfDecompressionHistory(),
318 M_NETGRAPH_MPPC, M_NOWAIT);
319 if (d->history == NULL)
322 MPPC_InitCompressionHistory(d->history);
324 MPPC_InitDecompressionHistory(
330 #ifdef NETGRAPH_MPPC_ENCRYPTION
331 /* Generate initial session keys for encryption */
332 if ((cfg->bits & MPPE_BITS) != 0) {
333 const int keylen = KEYLEN(cfg->bits);
335 bcopy(cfg->startkey, d->key, keylen);
336 ng_mppc_getkey(cfg->startkey, d->key, keylen);
337 if ((cfg->bits & MPPE_40) != 0)
338 bcopy(&ng_mppe_weakenkey, d->key, 3);
339 else if ((cfg->bits & MPPE_56) != 0)
340 bcopy(&ng_mppe_weakenkey, d->key, 1);
341 rc4_init(&d->rc4, d->key, keylen);
345 /* Initialize other state */
351 case NGM_MPPC_RESETREQ:
352 ng_mppc_reset_req(node);
365 NG_RESPOND_MSG(error, node, item, resp);
371 * Receive incoming data on our hook.
374 ng_mppc_rcvdata(hook_p hook, item_p item)
376 const node_p node = NG_HOOK_NODE(hook);
377 const priv_p priv = NG_NODE_PRIVATE(node);
382 /* Compress and/or encrypt */
383 if (hook == priv->xmit.hook) {
384 if (!priv->xmit.cfg.enable) {
389 if ((error = ng_mppc_compress(node, &m)) != 0) {
393 NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m);
397 /* Decompress and/or decrypt */
398 if (hook == priv->recv.hook) {
399 if (!priv->recv.cfg.enable) {
404 if ((error = ng_mppc_decompress(node, &m)) != 0) {
406 if (error == EINVAL && priv->ctrlnode != 0) {
409 /* Need to send a reset-request */
410 NG_MKMESSAGE(msg, NGM_MPPC_COOKIE,
411 NGM_MPPC_RESETREQ, 0, M_NOWAIT);
414 NG_SEND_MSG_ID(error, node, msg,
419 NG_FWD_NEW_DATA(error, item, priv->recv.hook, m);
424 panic("%s: unknown hook", __func__);
431 ng_mppc_shutdown(node_p node)
433 const priv_p priv = NG_NODE_PRIVATE(node);
435 /* Take down netgraph node */
436 #ifdef NETGRAPH_MPPC_COMPRESSION
437 if (priv->xmit.history != NULL)
438 free(priv->xmit.history, M_NETGRAPH_MPPC);
439 if (priv->recv.history != NULL)
440 free(priv->recv.history, M_NETGRAPH_MPPC);
442 bzero(priv, sizeof(*priv));
443 free(priv, M_NETGRAPH_MPPC);
444 NG_NODE_SET_PRIVATE(node, NULL);
445 NG_NODE_UNREF(node); /* let the node escape */
453 ng_mppc_disconnect(hook_p hook)
455 const node_p node = NG_HOOK_NODE(hook);
456 const priv_p priv = NG_NODE_PRIVATE(node);
458 /* Zero out hook pointer */
459 if (hook == priv->xmit.hook)
460 priv->xmit.hook = NULL;
461 if (hook == priv->recv.hook)
462 priv->recv.hook = NULL;
464 /* Go away if no longer connected */
465 if ((NG_NODE_NUMHOOKS(node) == 0)
466 && NG_NODE_IS_VALID(node))
467 ng_rmnode_self(node);
471 /************************************************************************
473 ************************************************************************/
476 * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
477 * The original mbuf is not free'd.
480 ng_mppc_compress(node_p node, struct mbuf **datap)
482 const priv_p priv = NG_NODE_PRIVATE(node);
483 struct ng_mppc_dir *const d = &priv->xmit;
485 struct mbuf *m = *datap;
487 /* We must own the mbuf chain exclusively to modify it. */
488 m = m_unshare(m, M_DONTWAIT);
495 /* Always set the flushed bit in stateless mode */
496 if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) {
497 header |= MPPC_FLAG_FLUSHED;
501 /* Compress packet (if compression enabled) */
502 #ifdef NETGRAPH_MPPC_COMPRESSION
503 if ((d->cfg.bits & MPPC_BIT) != 0) {
504 u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS;
505 u_char *inbuf, *outbuf;
506 int outlen, inlen, ina;
507 u_char *source, *dest;
508 u_long sourceCnt, destCnt;
511 /* Work with contiguous regions of memory. */
512 inlen = m->m_pkthdr.len;
513 if (m->m_next == NULL) {
514 inbuf = mtod(m, u_char *);
517 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
520 m_copydata(m, 0, inlen, (caddr_t)inbuf);
524 outlen = MPPC_MAX_BLOWUP(inlen);
525 outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT);
526 if (outbuf == NULL) {
528 free(inbuf, M_NETGRAPH_MPPC);
531 MPPC_InitCompressionHistory(d->history);
536 /* Prepare to compress */
541 if ((d->cfg.bits & MPPE_STATELESS) == 0)
542 flags |= MPPC_SAVE_HISTORY;
545 rtn = MPPC_Compress(&source, &dest, &sourceCnt,
546 &destCnt, d->history, flags, 0);
548 /* Check return value */
549 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
550 if ((rtn & MPPC_EXPANDED) == 0
551 && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) {
553 header |= MPPC_FLAG_COMPRESSED;
554 if ((rtn & MPPC_RESTART_HISTORY) != 0)
555 header |= MPPC_FLAG_RESTART;
557 /* Replace m by the compresed one. */
558 m_copyback(m, 0, outlen, (caddr_t)outbuf);
559 if (m->m_pkthdr.len < outlen) {
562 } else if (outlen < m->m_pkthdr.len)
563 m_adj(m, outlen - m->m_pkthdr.len);
565 d->flushed = (rtn & MPPC_EXPANDED) != 0
566 || (flags & MPPC_SAVE_HISTORY) == 0;
569 free(inbuf, M_NETGRAPH_MPPC);
570 free(outbuf, M_NETGRAPH_MPPC);
572 /* Check mbuf chain reload result. */
575 MPPC_InitCompressionHistory(d->history);
583 /* Now encrypt packet (if encryption enabled) */
584 #ifdef NETGRAPH_MPPC_ENCRYPTION
585 if ((d->cfg.bits & MPPE_BITS) != 0) {
588 /* Set header bits */
589 header |= MPPC_FLAG_ENCRYPTED;
591 /* Update key if it's time */
592 if ((d->cfg.bits & MPPE_STATELESS) != 0
593 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
594 ng_mppc_updatekey(d->cfg.bits,
595 d->cfg.startkey, d->key, &d->rc4);
596 } else if ((header & MPPC_FLAG_FLUSHED) != 0) {
597 /* Need to reset key if we say we did
598 and ng_mppc_updatekey wasn't called to do it also. */
599 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
605 rc4_crypt(&d->rc4, mtod(m1, u_char *),
606 mtod(m1, u_char *), m1->m_len);
612 /* Update coherency count for next time (12 bit arithmetic) */
613 MPPC_CCOUNT_INC(d->cc);
616 M_PREPEND(m, MPPC_HDRLEN, M_DONTWAIT);
618 be16enc(mtod(m, void *), header);
621 return (*datap == NULL ? ENOBUFS : 0);
625 * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
626 * The original mbuf is not free'd.
629 ng_mppc_decompress(node_p node, struct mbuf **datap)
631 const priv_p priv = NG_NODE_PRIVATE(node);
632 struct ng_mppc_dir *const d = &priv->recv;
633 u_int16_t header, cc;
635 struct mbuf *m = *datap;
637 /* We must own the mbuf chain exclusively to modify it. */
638 m = m_unshare(m, M_DONTWAIT);
642 /* Pull off header */
643 if (m->m_pkthdr.len < MPPC_HDRLEN) {
647 header = be16dec(mtod(m, void *));
648 cc = (header & MPPC_CCOUNT_MASK);
649 m_adj(m, MPPC_HDRLEN);
651 /* Check for an unexpected jump in the sequence number */
652 numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK);
654 /* If flushed bit set, we can always handle packet */
655 if ((header & MPPC_FLAG_FLUSHED) != 0) {
656 #ifdef NETGRAPH_MPPC_COMPRESSION
657 if (d->history != NULL)
658 MPPC_InitDecompressionHistory(d->history);
660 #ifdef NETGRAPH_MPPC_ENCRYPTION
661 if ((d->cfg.bits & MPPE_BITS) != 0) {
664 /* How many times are we going to have to re-key? */
665 rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ?
666 numLost : (numLost / (MPPE_UPDATE_MASK + 1));
667 if (rekey > mppe_max_rekey) {
668 if (mppe_block_on_max_rekey) {
669 if (mppe_log_max_rekey) {
670 log(LOG_ERR, "%s: too many (%d) packets"
671 " dropped, disabling node %p!\n",
672 __func__, numLost, node);
674 priv->recv.cfg.enable = 0;
677 if (mppe_log_max_rekey) {
678 log(LOG_ERR, "%s: %d packets"
679 " dropped, node %p\n",
680 __func__, numLost, node);
686 /* Re-key as necessary to catch up to peer */
687 while (d->cc != cc) {
688 if ((d->cfg.bits & MPPE_STATELESS) != 0
689 || (d->cc & MPPE_UPDATE_MASK)
690 == MPPE_UPDATE_FLAG) {
691 ng_mppc_updatekey(d->cfg.bits,
692 d->cfg.startkey, d->key, &d->rc4);
694 MPPC_CCOUNT_INC(d->cc);
697 /* Reset key (except in stateless mode, see below) */
698 if ((d->cfg.bits & MPPE_STATELESS) == 0)
699 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
702 d->cc = cc; /* skip over lost seq numbers */
703 numLost = 0; /* act like no packets were lost */
706 /* Can't decode non-sequential packets without a flushed bit */
711 if ((header & MPPC_FLAG_ENCRYPTED) != 0) {
712 #ifdef NETGRAPH_MPPC_ENCRYPTION
716 /* Are we not expecting encryption? */
717 if ((d->cfg.bits & MPPE_BITS) == 0) {
718 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
719 __func__, "encrypted");
723 #ifdef NETGRAPH_MPPC_ENCRYPTION
724 /* Update key if it's time (always in stateless mode) */
725 if ((d->cfg.bits & MPPE_STATELESS) != 0
726 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
727 ng_mppc_updatekey(d->cfg.bits,
728 d->cfg.startkey, d->key, &d->rc4);
734 rc4_crypt(&d->rc4, mtod(m1, u_char *),
735 mtod(m1, u_char *), m1->m_len);
741 /* Are we expecting encryption? */
742 if ((d->cfg.bits & MPPE_BITS) != 0) {
743 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
744 __func__, "unencrypted");
749 /* Update coherency count for next time (12 bit arithmetic) */
750 MPPC_CCOUNT_INC(d->cc);
752 /* Check for unexpected compressed packet */
753 if ((header & MPPC_FLAG_COMPRESSED) != 0
754 && (d->cfg.bits & MPPC_BIT) == 0) {
755 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
756 __func__, "compressed");
762 #ifdef NETGRAPH_MPPC_COMPRESSION
763 /* Decompress packet */
764 if ((header & MPPC_FLAG_COMPRESSED) != 0) {
765 int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS;
766 u_char *inbuf, *outbuf;
767 int inlen, outlen, ina;
768 u_char *source, *dest;
769 u_long sourceCnt, destCnt;
772 /* Copy payload into a contiguous region of memory. */
773 inlen = m->m_pkthdr.len;
774 if (m->m_next == NULL) {
775 inbuf = mtod(m, u_char *);
778 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
783 m_copydata(m, 0, inlen, (caddr_t)inbuf);
787 /* Allocate a buffer for decompressed data */
788 outbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY,
789 M_NETGRAPH_MPPC, M_NOWAIT);
790 if (outbuf == NULL) {
793 free(inbuf, M_NETGRAPH_MPPC);
796 outlen = MPPC_DECOMP_BUFSIZE;
798 /* Prepare to decompress */
803 if ((header & MPPC_FLAG_RESTART) != 0)
804 flags |= MPPC_RESTART_HISTORY;
807 rtn = MPPC_Decompress(&source, &dest,
808 &sourceCnt, &destCnt, d->history, flags);
810 /* Check return value */
811 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
812 if ((rtn & MPPC_DEST_EXHAUSTED) != 0
813 || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) {
814 log(LOG_ERR, "%s: decomp returned 0x%x",
817 free(inbuf, M_NETGRAPH_MPPC);
818 free(outbuf, M_NETGRAPH_MPPC);
822 /* Replace compressed data with decompressed data */
824 free(inbuf, M_NETGRAPH_MPPC);
827 m_copyback(m, 0, outlen, (caddr_t)outbuf);
828 if (m->m_pkthdr.len < outlen) {
831 } else if (outlen < m->m_pkthdr.len)
832 m_adj(m, outlen - m->m_pkthdr.len);
833 free(outbuf, M_NETGRAPH_MPPC);
837 /* Return result in an mbuf */
839 return (*datap == NULL ? ENOBUFS : 0);
843 * The peer has sent us a CCP ResetRequest, so reset our transmit state.
846 ng_mppc_reset_req(node_p node)
848 const priv_p priv = NG_NODE_PRIVATE(node);
849 struct ng_mppc_dir *const d = &priv->xmit;
851 #ifdef NETGRAPH_MPPC_COMPRESSION
852 if (d->history != NULL)
853 MPPC_InitCompressionHistory(d->history);
855 #ifdef NETGRAPH_MPPC_ENCRYPTION
856 if ((d->cfg.bits & MPPE_STATELESS) == 0)
857 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
862 #ifdef NETGRAPH_MPPC_ENCRYPTION
864 * Generate a new encryption key
867 ng_mppc_getkey(const u_char *h, u_char *h2, int len)
869 static const u_char pad1[40] =
870 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
871 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
872 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
873 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
874 static const u_char pad2[40] =
875 { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
876 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
877 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
878 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 };
883 SHA1Update(&c, h, len);
884 SHA1Update(&c, pad1, sizeof(pad1));
885 SHA1Update(&c, h2, len);
886 SHA1Update(&c, pad2, sizeof(pad2));
888 bcopy(hash, h2, len);
892 * Update the encryption key
895 ng_mppc_updatekey(u_int32_t bits,
896 u_char *key0, u_char *key, struct rc4_state *rc4)
898 const int keylen = KEYLEN(bits);
900 ng_mppc_getkey(key0, key, keylen);
901 rc4_init(rc4, key, keylen);
902 rc4_crypt(rc4, key, key, keylen);
903 if ((bits & MPPE_40) != 0)
904 bcopy(&ng_mppe_weakenkey, key, 3);
905 else if ((bits & MPPE_56) != 0)
906 bcopy(&ng_mppe_weakenkey, key, 1);
907 rc4_init(rc4, key, keylen);