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/errno.h>
57 #include <sys/syslog.h>
59 #include <netgraph/ng_message.h>
60 #include <netgraph/netgraph.h>
61 #include <netgraph/ng_mppc.h>
63 #include "opt_netgraph.h"
65 #if !defined(NETGRAPH_MPPC_COMPRESSION) && !defined(NETGRAPH_MPPC_ENCRYPTION)
67 /* XXX NETGRAPH_MPPC_COMPRESSION isn't functional yet */
68 #define NETGRAPH_MPPC_ENCRYPTION
70 /* This case is indicative of an error in sys/conf files */
71 #error Need either NETGRAPH_MPPC_COMPRESSION or NETGRAPH_MPPC_ENCRYPTION
75 #ifdef NG_SEPARATE_MALLOC
76 MALLOC_DEFINE(M_NETGRAPH_MPPC, "netgraph_mppc", "netgraph mppc node ");
78 #define M_NETGRAPH_MPPC M_NETGRAPH
81 #ifdef NETGRAPH_MPPC_COMPRESSION
82 /* XXX this file doesn't exist yet, but hopefully someday it will... */
85 #ifdef NETGRAPH_MPPC_ENCRYPTION
86 #include <crypto/rc4/rc4.h>
88 #include <crypto/sha1.h>
90 /* Decompression blowup */
91 #define MPPC_DECOMP_BUFSIZE 8092 /* allocate buffer this big */
92 #define MPPC_DECOMP_SAFETY 100 /* plus this much margin */
94 /* MPPC/MPPE header length */
98 #define KEYLEN(b) (((b) & MPPE_128) ? 16 : 8)
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.
107 #define MPPE_MAX_REKEY 1000
109 /* MPPC packet header bits */
110 #define MPPC_FLAG_FLUSHED 0x8000 /* xmitter reset state */
111 #define MPPC_FLAG_RESTART 0x4000 /* compress history restart */
112 #define MPPC_FLAG_COMPRESSED 0x2000 /* packet is compresed */
113 #define MPPC_FLAG_ENCRYPTED 0x1000 /* packet is encrypted */
114 #define MPPC_CCOUNT_MASK 0x0fff /* sequence number mask */
116 #define MPPC_CCOUNT_INC(d) ((d) = (((d) + 1) & MPPC_CCOUNT_MASK))
118 #define MPPE_UPDATE_MASK 0xff /* coherency count when we're */
119 #define MPPE_UPDATE_FLAG 0xff /* supposed to update key */
121 #define MPPC_COMP_OK 0x05
122 #define MPPC_DECOMP_OK 0x05
124 /* Per direction info */
126 struct ng_mppc_config cfg; /* configuration */
127 hook_p hook; /* netgraph hook */
128 u_int16_t cc:12; /* coherency count */
129 u_char flushed; /* clean history (xmit only) */
130 #ifdef NETGRAPH_MPPC_COMPRESSION
131 u_char *history; /* compression history */
133 #ifdef NETGRAPH_MPPC_ENCRYPTION
134 u_char key[MPPE_KEY_LEN]; /* session key */
135 struct rc4_state rc4; /* rc4 state */
139 /* Node private data */
140 struct ng_mppc_private {
141 struct ng_mppc_dir xmit; /* compress/encrypt config */
142 struct ng_mppc_dir recv; /* decompress/decrypt config */
143 ng_ID_t ctrlnode; /* path to controlling node */
145 typedef struct ng_mppc_private *priv_p;
147 /* Netgraph node methods */
148 static ng_constructor_t ng_mppc_constructor;
149 static ng_rcvmsg_t ng_mppc_rcvmsg;
150 static ng_shutdown_t ng_mppc_shutdown;
151 static ng_newhook_t ng_mppc_newhook;
152 static ng_rcvdata_t ng_mppc_rcvdata;
153 static ng_disconnect_t ng_mppc_disconnect;
155 /* Helper functions */
156 static int ng_mppc_compress(node_p node,
157 struct mbuf **datap);
158 static int ng_mppc_decompress(node_p node,
159 struct mbuf **datap);
160 #ifdef NETGRAPH_MPPC_ENCRYPTION
161 static void ng_mppc_getkey(const u_char *h, u_char *h2, int len);
162 static void ng_mppc_updatekey(u_int32_t bits,
163 u_char *key0, u_char *key, struct rc4_state *rc4);
165 static void ng_mppc_reset_req(node_p node);
167 /* Node type descriptor */
168 static struct ng_type ng_mppc_typestruct = {
169 .version = NG_ABI_VERSION,
170 .name = NG_MPPC_NODE_TYPE,
171 .constructor = ng_mppc_constructor,
172 .rcvmsg = ng_mppc_rcvmsg,
173 .shutdown = ng_mppc_shutdown,
174 .newhook = ng_mppc_newhook,
175 .rcvdata = ng_mppc_rcvdata,
176 .disconnect = ng_mppc_disconnect,
178 NETGRAPH_INIT(mppc, &ng_mppc_typestruct);
180 #ifdef NETGRAPH_MPPC_ENCRYPTION
181 /* Depend on separate rc4 module */
182 MODULE_DEPEND(ng_mppc, rc4, 1, 1, 1);
185 /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
186 static const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e };
188 #define ERROUT(x) do { error = (x); goto done; } while (0)
190 /************************************************************************
192 ************************************************************************/
195 * Node type constructor
198 ng_mppc_constructor(node_p node)
202 /* Allocate private structure */
203 priv = malloc(sizeof(*priv), M_NETGRAPH_MPPC, M_NOWAIT | M_ZERO);
207 NG_NODE_SET_PRIVATE(node, priv);
209 /* This node is not thread safe. */
210 NG_NODE_FORCE_WRITER(node);
217 * Give our OK for a hook to be added
220 ng_mppc_newhook(node_p node, hook_p hook, const char *name)
222 const priv_p priv = NG_NODE_PRIVATE(node);
225 /* Check hook name */
226 if (strcmp(name, NG_MPPC_HOOK_COMP) == 0)
227 hookPtr = &priv->xmit.hook;
228 else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0)
229 hookPtr = &priv->recv.hook;
233 /* See if already connected */
234 if (*hookPtr != NULL)
243 * Receive a control message
246 ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook)
248 const priv_p priv = NG_NODE_PRIVATE(node);
249 struct ng_mesg *resp = NULL;
253 NGI_GET_MSG(item, msg);
254 switch (msg->header.typecookie) {
255 case NGM_MPPC_COOKIE:
256 switch (msg->header.cmd) {
257 case NGM_MPPC_CONFIG_COMP:
258 case NGM_MPPC_CONFIG_DECOMP:
260 struct ng_mppc_config *const cfg
261 = (struct ng_mppc_config *)msg->data;
263 msg->header.cmd == NGM_MPPC_CONFIG_COMP;
264 struct ng_mppc_dir *const d = isComp ?
265 &priv->xmit : &priv->recv;
267 /* Check configuration */
268 if (msg->header.arglen != sizeof(*cfg))
271 if ((cfg->bits & ~MPPC_VALID_BITS) != 0)
273 #ifndef NETGRAPH_MPPC_COMPRESSION
274 if ((cfg->bits & MPPC_BIT) != 0)
275 ERROUT(EPROTONOSUPPORT);
277 #ifndef NETGRAPH_MPPC_ENCRYPTION
278 if ((cfg->bits & MPPE_BITS) != 0)
279 ERROUT(EPROTONOSUPPORT);
284 /* Save return address so we can send reset-req's */
286 priv->ctrlnode = NGI_RETADDR(item);
288 /* Configuration is OK, reset to it */
291 #ifdef NETGRAPH_MPPC_COMPRESSION
292 /* Initialize state buffers for compression */
293 if (d->history != NULL) {
294 free(d->history, M_NETGRAPH_MPPC);
297 if ((cfg->bits & MPPC_BIT) != 0) {
298 d->history = malloc(isComp ?
299 MPPC_SizeOfCompressionHistory() :
300 MPPC_SizeOfDecompressionHistory(),
301 M_NETGRAPH_MPPC, M_NOWAIT);
302 if (d->history == NULL)
305 MPPC_InitCompressionHistory(d->history);
307 MPPC_InitDecompressionHistory(
313 #ifdef NETGRAPH_MPPC_ENCRYPTION
314 /* Generate initial session keys for encryption */
315 if ((cfg->bits & MPPE_BITS) != 0) {
316 const int keylen = KEYLEN(cfg->bits);
318 bcopy(cfg->startkey, d->key, keylen);
319 ng_mppc_getkey(cfg->startkey, d->key, keylen);
320 if ((cfg->bits & MPPE_40) != 0)
321 bcopy(&ng_mppe_weakenkey, d->key, 3);
322 else if ((cfg->bits & MPPE_56) != 0)
323 bcopy(&ng_mppe_weakenkey, d->key, 1);
324 rc4_init(&d->rc4, d->key, keylen);
328 /* Initialize other state */
334 case NGM_MPPC_RESETREQ:
335 ng_mppc_reset_req(node);
348 NG_RESPOND_MSG(error, node, item, resp);
354 * Receive incoming data on our hook.
357 ng_mppc_rcvdata(hook_p hook, item_p item)
359 const node_p node = NG_HOOK_NODE(hook);
360 const priv_p priv = NG_NODE_PRIVATE(node);
365 /* Compress and/or encrypt */
366 if (hook == priv->xmit.hook) {
367 if (!priv->xmit.cfg.enable) {
372 if ((error = ng_mppc_compress(node, &m)) != 0) {
376 NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m);
380 /* Decompress and/or decrypt */
381 if (hook == priv->recv.hook) {
382 if (!priv->recv.cfg.enable) {
387 if ((error = ng_mppc_decompress(node, &m)) != 0) {
389 if (error == EINVAL && priv->ctrlnode != 0) {
392 /* Need to send a reset-request */
393 NG_MKMESSAGE(msg, NGM_MPPC_COOKIE,
394 NGM_MPPC_RESETREQ, 0, M_NOWAIT);
397 NG_SEND_MSG_ID(error, node, msg,
402 NG_FWD_NEW_DATA(error, item, priv->recv.hook, m);
407 panic("%s: unknown hook", __func__);
408 #ifdef RESTARTABLE_PANICS
417 ng_mppc_shutdown(node_p node)
419 const priv_p priv = NG_NODE_PRIVATE(node);
421 /* Take down netgraph node */
422 #ifdef NETGRAPH_MPPC_COMPRESSION
423 if (priv->xmit.history != NULL)
424 free(priv->xmit.history, M_NETGRAPH_MPPC);
425 if (priv->recv.history != NULL)
426 free(priv->recv.history, M_NETGRAPH_MPPC);
428 bzero(priv, sizeof(*priv));
429 free(priv, M_NETGRAPH_MPPC);
430 NG_NODE_SET_PRIVATE(node, NULL);
431 NG_NODE_UNREF(node); /* let the node escape */
439 ng_mppc_disconnect(hook_p hook)
441 const node_p node = NG_HOOK_NODE(hook);
442 const priv_p priv = NG_NODE_PRIVATE(node);
444 /* Zero out hook pointer */
445 if (hook == priv->xmit.hook)
446 priv->xmit.hook = NULL;
447 if (hook == priv->recv.hook)
448 priv->recv.hook = NULL;
450 /* Go away if no longer connected */
451 if ((NG_NODE_NUMHOOKS(node) == 0)
452 && NG_NODE_IS_VALID(node))
453 ng_rmnode_self(node);
457 /************************************************************************
459 ************************************************************************/
462 * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
463 * The original mbuf is not free'd.
466 ng_mppc_compress(node_p node, struct mbuf **datap)
468 const priv_p priv = NG_NODE_PRIVATE(node);
469 struct ng_mppc_dir *const d = &priv->xmit;
471 struct mbuf *m = *datap;
473 /* We must own the mbuf chain exclusively to modify it. */
474 m = m_unshare(m, M_DONTWAIT);
481 /* Always set the flushed bit in stateless mode */
482 if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) {
483 header |= MPPC_FLAG_FLUSHED;
487 /* Compress packet (if compression enabled) */
488 #ifdef NETGRAPH_MPPC_COMPRESSION
489 if ((d->cfg.bits & MPPC_BIT) != 0) {
490 u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS;
491 u_char *inbuf, *outbuf;
493 u_char *source, *dest;
494 u_long sourceCnt, destCnt;
497 /* Work with contiguous regions of memory. */
498 inlen = m->m_pkthdr.len;
499 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
502 m_copydata(m, 0, inlen, (caddr_t)inbuf);
504 outlen = MPPC_MAX_BLOWUP(inlen);
505 outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT);
506 if (outbuf == NULL) {
507 free(inbuf, M_NETGRAPH_MPPC);
510 MPPC_InitCompressionHistory(d->history);
515 /* Prepare to compress */
520 if ((d->cfg.bits & MPPE_STATELESS) == 0)
521 flags |= MPPC_SAVE_HISTORY;
524 rtn = MPPC_Compress(&source, &dest, &sourceCnt,
525 &destCnt, d->history, flags, 0);
527 /* Check return value */
528 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
529 if ((rtn & MPPC_EXPANDED) == 0
530 && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) {
532 header |= MPPC_FLAG_COMPRESSED;
533 if ((rtn & MPPC_RESTART_HISTORY) != 0)
534 header |= MPPC_FLAG_RESTART;
536 /* Replace m by the compresed one. */
537 m_copyback(m, 0, outlen, (caddr_t)outbuf);
538 if (m->m_pkthdr.len < outlen) {
541 } else if (outlen < m->m_pkthdr.len)
542 m_adj(m, outlen - m->m_pkthdr.len);
544 d->flushed = (rtn & MPPC_EXPANDED) != 0
545 || (flags & MPPC_SAVE_HISTORY) == 0;
547 free(inbuf, M_NETGRAPH_MPPC);
548 free(outbuf, M_NETGRAPH_MPPC);
550 /* Check mbuf chain reload result. */
553 MPPC_InitCompressionHistory(d->history);
561 /* Now encrypt packet (if encryption enabled) */
562 #ifdef NETGRAPH_MPPC_ENCRYPTION
563 if ((d->cfg.bits & MPPE_BITS) != 0) {
566 /* Set header bits */
567 header |= MPPC_FLAG_ENCRYPTED;
569 /* Update key if it's time */
570 if ((d->cfg.bits & MPPE_STATELESS) != 0
571 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
572 ng_mppc_updatekey(d->cfg.bits,
573 d->cfg.startkey, d->key, &d->rc4);
574 } else if ((header & MPPC_FLAG_FLUSHED) != 0) {
575 /* Need to reset key if we say we did
576 and ng_mppc_updatekey wasn't called to do it also. */
577 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
583 rc4_crypt(&d->rc4, mtod(m1, u_char *),
584 mtod(m1, u_char *), m1->m_len);
590 /* Update coherency count for next time (12 bit arithmetic) */
591 MPPC_CCOUNT_INC(d->cc);
594 M_PREPEND(m, MPPC_HDRLEN, M_DONTWAIT);
596 *(mtod(m, uint16_t *)) = htons(header);
599 return (*datap == NULL ? ENOBUFS : 0);
603 * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
604 * The original mbuf is not free'd.
607 ng_mppc_decompress(node_p node, struct mbuf **datap)
609 const priv_p priv = NG_NODE_PRIVATE(node);
610 struct ng_mppc_dir *const d = &priv->recv;
611 u_int16_t header, cc;
613 struct mbuf *m = *datap;
615 /* We must own the mbuf chain exclusively to modify it. */
616 m = m_unshare(m, M_DONTWAIT);
620 /* Pull off header */
621 if (m->m_pkthdr.len < MPPC_HDRLEN) {
625 m_copydata(m, 0, MPPC_HDRLEN, (caddr_t)&header);
626 header = ntohs(header);
627 cc = (header & MPPC_CCOUNT_MASK);
628 m_adj(m, MPPC_HDRLEN);
630 /* Check for an unexpected jump in the sequence number */
631 numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK);
633 /* If flushed bit set, we can always handle packet */
634 if ((header & MPPC_FLAG_FLUSHED) != 0) {
635 #ifdef NETGRAPH_MPPC_COMPRESSION
636 if (d->history != NULL)
637 MPPC_InitDecompressionHistory(d->history);
639 #ifdef NETGRAPH_MPPC_ENCRYPTION
640 if ((d->cfg.bits & MPPE_BITS) != 0) {
643 /* How many times are we going to have to re-key? */
644 rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ?
645 numLost : (numLost / (MPPE_UPDATE_MASK + 1));
646 if (rekey > MPPE_MAX_REKEY) {
647 log(LOG_ERR, "%s: too many (%d) packets"
648 " dropped, disabling node %p!",
649 __func__, numLost, node);
650 priv->recv.cfg.enable = 0;
654 /* Re-key as necessary to catch up to peer */
655 while (d->cc != cc) {
656 if ((d->cfg.bits & MPPE_STATELESS) != 0
657 || (d->cc & MPPE_UPDATE_MASK)
658 == MPPE_UPDATE_FLAG) {
659 ng_mppc_updatekey(d->cfg.bits,
660 d->cfg.startkey, d->key, &d->rc4);
662 MPPC_CCOUNT_INC(d->cc);
665 /* Reset key (except in stateless mode, see below) */
666 if ((d->cfg.bits & MPPE_STATELESS) == 0)
667 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
670 d->cc = cc; /* skip over lost seq numbers */
671 numLost = 0; /* act like no packets were lost */
674 /* Can't decode non-sequential packets without a flushed bit */
679 if ((header & MPPC_FLAG_ENCRYPTED) != 0) {
680 #ifdef NETGRAPH_MPPC_ENCRYPTION
684 /* Are we not expecting encryption? */
685 if ((d->cfg.bits & MPPE_BITS) == 0) {
686 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
687 __func__, "encrypted");
691 #ifdef NETGRAPH_MPPC_ENCRYPTION
692 /* Update key if it's time (always in stateless mode) */
693 if ((d->cfg.bits & MPPE_STATELESS) != 0
694 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
695 ng_mppc_updatekey(d->cfg.bits,
696 d->cfg.startkey, d->key, &d->rc4);
702 rc4_crypt(&d->rc4, mtod(m1, u_char *),
703 mtod(m1, u_char *), m1->m_len);
709 /* Are we expecting encryption? */
710 if ((d->cfg.bits & MPPE_BITS) != 0) {
711 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
712 __func__, "unencrypted");
717 /* Update coherency count for next time (12 bit arithmetic) */
718 MPPC_CCOUNT_INC(d->cc);
720 /* Check for unexpected compressed packet */
721 if ((header & MPPC_FLAG_COMPRESSED) != 0
722 && (d->cfg.bits & MPPC_BIT) == 0) {
723 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
724 __func__, "compressed");
730 #ifdef NETGRAPH_MPPC_COMPRESSION
731 /* Decompress packet */
732 if ((header & MPPC_FLAG_COMPRESSED) != 0) {
733 int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS;
734 u_char *decompbuf, *source, *dest;
735 u_long sourceCnt, destCnt;
740 /* Copy payload into a contiguous region of memory. */
741 len = m->m_pkthdr.len;
742 buf = malloc(len, M_NETGRAPH_MPPC, M_NOWAIT);
747 m_copydata(m, 0, len, (caddr_t)buf);
749 /* Allocate a buffer for decompressed data */
750 decompbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY,
751 M_NETGRAPH_MPPC, M_NOWAIT);
752 if (decompbuf == NULL) {
754 free(buf, M_NETGRAPH_MPPC);
757 decomplen = MPPC_DECOMP_BUFSIZE;
759 /* Prepare to decompress */
764 if ((header & MPPC_FLAG_RESTART) != 0)
765 flags |= MPPC_RESTART_HISTORY;
768 rtn = MPPC_Decompress(&source, &dest,
769 &sourceCnt, &destCnt, d->history, flags);
771 /* Check return value */
772 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
773 if ((rtn & MPPC_DEST_EXHAUSTED) != 0
774 || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) {
775 log(LOG_ERR, "%s: decomp returned 0x%x",
777 free(buf, M_NETGRAPH_MPPC);
778 free(decompbuf, M_NETGRAPH_MPPC);
782 /* Replace compressed data with decompressed data */
783 free(buf, M_NETGRAPH_MPPC);
784 len = decomplen - destCnt;
786 m_copyback(m, 0, len, (caddr_t)decompbuf);
787 if (m->m_pkthdr.len < len) {
790 } else if (len < m->m_pkthdr.len)
791 m_adj(m, len - m->m_pkthdr.len);
792 free(decompbuf, M_NETGRAPH_MPPC);
796 /* Return result in an mbuf */
798 return (*datap == NULL ? ENOBUFS : 0);
802 * The peer has sent us a CCP ResetRequest, so reset our transmit state.
805 ng_mppc_reset_req(node_p node)
807 const priv_p priv = NG_NODE_PRIVATE(node);
808 struct ng_mppc_dir *const d = &priv->xmit;
810 #ifdef NETGRAPH_MPPC_COMPRESSION
811 if (d->history != NULL)
812 MPPC_InitCompressionHistory(d->history);
814 #ifdef NETGRAPH_MPPC_ENCRYPTION
815 if ((d->cfg.bits & MPPE_STATELESS) == 0)
816 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
821 #ifdef NETGRAPH_MPPC_ENCRYPTION
823 * Generate a new encryption key
826 ng_mppc_getkey(const u_char *h, u_char *h2, int len)
828 static const u_char pad1[40] =
829 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
830 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
831 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
832 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
833 static const u_char pad2[40] =
834 { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
835 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
836 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
837 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 };
842 SHA1Update(&c, h, len);
843 SHA1Update(&c, pad1, sizeof(pad1));
844 SHA1Update(&c, h2, len);
845 SHA1Update(&c, pad2, sizeof(pad2));
847 bcopy(hash, h2, len);
851 * Update the encryption key
854 ng_mppc_updatekey(u_int32_t bits,
855 u_char *key0, u_char *key, struct rc4_state *rc4)
857 const int keylen = KEYLEN(bits);
859 ng_mppc_getkey(key0, key, keylen);
860 rc4_init(rc4, key, keylen);
861 rc4_crypt(rc4, key, key, keylen);
862 if ((bits & MPPE_40) != 0)
863 bcopy(&ng_mppe_weakenkey, key, 3);
864 else if ((bits & MPPE_56) != 0)
865 bcopy(&ng_mppe_weakenkey, key, 1);
866 rc4_init(rc4, key, keylen);