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/syslog.h>
60 #include <netgraph/ng_message.h>
61 #include <netgraph/netgraph.h>
62 #include <netgraph/ng_mppc.h>
64 #include "opt_netgraph.h"
66 #if !defined(NETGRAPH_MPPC_COMPRESSION) && !defined(NETGRAPH_MPPC_ENCRYPTION)
68 /* XXX NETGRAPH_MPPC_COMPRESSION isn't functional yet */
69 #define NETGRAPH_MPPC_ENCRYPTION
71 /* This case is indicative of an error in sys/conf files */
72 #error Need either NETGRAPH_MPPC_COMPRESSION or NETGRAPH_MPPC_ENCRYPTION
76 #ifdef NG_SEPARATE_MALLOC
77 MALLOC_DEFINE(M_NETGRAPH_MPPC, "netgraph_mppc", "netgraph mppc node ");
79 #define M_NETGRAPH_MPPC M_NETGRAPH
82 #ifdef NETGRAPH_MPPC_COMPRESSION
83 /* XXX this file doesn't exist yet, but hopefully someday it will... */
86 #ifdef NETGRAPH_MPPC_ENCRYPTION
87 #include <crypto/rc4/rc4.h>
89 #include <crypto/sha1.h>
91 /* Decompression blowup */
92 #define MPPC_DECOMP_BUFSIZE 8092 /* allocate buffer this big */
93 #define MPPC_DECOMP_SAFETY 100 /* plus this much margin */
95 /* MPPC/MPPE header length */
99 #define KEYLEN(b) (((b) & MPPE_128) ? 16 : 8)
102 * When packets are lost with MPPE, we may have to re-key arbitrarily
103 * many times to 'catch up' to the new jumped-ahead sequence number.
104 * Since this can be expensive, we pose a limit on how many re-keyings
105 * we will do at one time to avoid a possible D.O.S. vulnerability.
106 * This should instead be a configurable parameter.
108 #define MPPE_MAX_REKEY 1000
110 /* MPPC packet header bits */
111 #define MPPC_FLAG_FLUSHED 0x8000 /* xmitter reset state */
112 #define MPPC_FLAG_RESTART 0x4000 /* compress history restart */
113 #define MPPC_FLAG_COMPRESSED 0x2000 /* packet is compresed */
114 #define MPPC_FLAG_ENCRYPTED 0x1000 /* packet is encrypted */
115 #define MPPC_CCOUNT_MASK 0x0fff /* sequence number mask */
117 #define MPPC_CCOUNT_INC(d) ((d) = (((d) + 1) & MPPC_CCOUNT_MASK))
119 #define MPPE_UPDATE_MASK 0xff /* coherency count when we're */
120 #define MPPE_UPDATE_FLAG 0xff /* supposed to update key */
122 #define MPPC_COMP_OK 0x05
123 #define MPPC_DECOMP_OK 0x05
125 /* Per direction info */
127 struct ng_mppc_config cfg; /* configuration */
128 hook_p hook; /* netgraph hook */
129 u_int16_t cc:12; /* coherency count */
130 u_char flushed; /* clean history (xmit only) */
131 #ifdef NETGRAPH_MPPC_COMPRESSION
132 u_char *history; /* compression history */
134 #ifdef NETGRAPH_MPPC_ENCRYPTION
135 u_char key[MPPE_KEY_LEN]; /* session key */
136 struct rc4_state rc4; /* rc4 state */
140 /* Node private data */
141 struct ng_mppc_private {
142 struct ng_mppc_dir xmit; /* compress/encrypt config */
143 struct ng_mppc_dir recv; /* decompress/decrypt config */
144 ng_ID_t ctrlnode; /* path to controlling node */
146 typedef struct ng_mppc_private *priv_p;
148 /* Netgraph node methods */
149 static ng_constructor_t ng_mppc_constructor;
150 static ng_rcvmsg_t ng_mppc_rcvmsg;
151 static ng_shutdown_t ng_mppc_shutdown;
152 static ng_newhook_t ng_mppc_newhook;
153 static ng_rcvdata_t ng_mppc_rcvdata;
154 static ng_disconnect_t ng_mppc_disconnect;
156 /* Helper functions */
157 static int ng_mppc_compress(node_p node,
158 struct mbuf **datap);
159 static int ng_mppc_decompress(node_p node,
160 struct mbuf **datap);
161 #ifdef NETGRAPH_MPPC_ENCRYPTION
162 static void ng_mppc_getkey(const u_char *h, u_char *h2, int len);
163 static void ng_mppc_updatekey(u_int32_t bits,
164 u_char *key0, u_char *key, struct rc4_state *rc4);
166 static void ng_mppc_reset_req(node_p node);
168 /* Node type descriptor */
169 static struct ng_type ng_mppc_typestruct = {
170 .version = NG_ABI_VERSION,
171 .name = NG_MPPC_NODE_TYPE,
172 .constructor = ng_mppc_constructor,
173 .rcvmsg = ng_mppc_rcvmsg,
174 .shutdown = ng_mppc_shutdown,
175 .newhook = ng_mppc_newhook,
176 .rcvdata = ng_mppc_rcvdata,
177 .disconnect = ng_mppc_disconnect,
179 NETGRAPH_INIT(mppc, &ng_mppc_typestruct);
181 #ifdef NETGRAPH_MPPC_ENCRYPTION
182 /* Depend on separate rc4 module */
183 MODULE_DEPEND(ng_mppc, rc4, 1, 1, 1);
186 /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
187 static const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e };
189 #define ERROUT(x) do { error = (x); goto done; } while (0)
191 /************************************************************************
193 ************************************************************************/
196 * Node type constructor
199 ng_mppc_constructor(node_p node)
203 /* Allocate private structure */
204 priv = malloc(sizeof(*priv), M_NETGRAPH_MPPC, M_WAITOK | M_ZERO);
206 NG_NODE_SET_PRIVATE(node, priv);
208 /* This node is not thread safe. */
209 NG_NODE_FORCE_WRITER(node);
216 * Give our OK for a hook to be added
219 ng_mppc_newhook(node_p node, hook_p hook, const char *name)
221 const priv_p priv = NG_NODE_PRIVATE(node);
224 /* Check hook name */
225 if (strcmp(name, NG_MPPC_HOOK_COMP) == 0)
226 hookPtr = &priv->xmit.hook;
227 else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0)
228 hookPtr = &priv->recv.hook;
232 /* See if already connected */
233 if (*hookPtr != NULL)
242 * Receive a control message
245 ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook)
247 const priv_p priv = NG_NODE_PRIVATE(node);
248 struct ng_mesg *resp = NULL;
252 NGI_GET_MSG(item, msg);
253 switch (msg->header.typecookie) {
254 case NGM_MPPC_COOKIE:
255 switch (msg->header.cmd) {
256 case NGM_MPPC_CONFIG_COMP:
257 case NGM_MPPC_CONFIG_DECOMP:
259 struct ng_mppc_config *const cfg
260 = (struct ng_mppc_config *)msg->data;
262 msg->header.cmd == NGM_MPPC_CONFIG_COMP;
263 struct ng_mppc_dir *const d = isComp ?
264 &priv->xmit : &priv->recv;
266 /* Check configuration */
267 if (msg->header.arglen != sizeof(*cfg))
270 if ((cfg->bits & ~MPPC_VALID_BITS) != 0)
272 #ifndef NETGRAPH_MPPC_COMPRESSION
273 if ((cfg->bits & MPPC_BIT) != 0)
274 ERROUT(EPROTONOSUPPORT);
276 #ifndef NETGRAPH_MPPC_ENCRYPTION
277 if ((cfg->bits & MPPE_BITS) != 0)
278 ERROUT(EPROTONOSUPPORT);
283 /* Save return address so we can send reset-req's */
285 priv->ctrlnode = NGI_RETADDR(item);
287 /* Configuration is OK, reset to it */
290 #ifdef NETGRAPH_MPPC_COMPRESSION
291 /* Initialize state buffers for compression */
292 if (d->history != NULL) {
293 free(d->history, M_NETGRAPH_MPPC);
296 if ((cfg->bits & MPPC_BIT) != 0) {
297 d->history = malloc(isComp ?
298 MPPC_SizeOfCompressionHistory() :
299 MPPC_SizeOfDecompressionHistory(),
300 M_NETGRAPH_MPPC, M_NOWAIT);
301 if (d->history == NULL)
304 MPPC_InitCompressionHistory(d->history);
306 MPPC_InitDecompressionHistory(
312 #ifdef NETGRAPH_MPPC_ENCRYPTION
313 /* Generate initial session keys for encryption */
314 if ((cfg->bits & MPPE_BITS) != 0) {
315 const int keylen = KEYLEN(cfg->bits);
317 bcopy(cfg->startkey, d->key, keylen);
318 ng_mppc_getkey(cfg->startkey, d->key, keylen);
319 if ((cfg->bits & MPPE_40) != 0)
320 bcopy(&ng_mppe_weakenkey, d->key, 3);
321 else if ((cfg->bits & MPPE_56) != 0)
322 bcopy(&ng_mppe_weakenkey, d->key, 1);
323 rc4_init(&d->rc4, d->key, keylen);
327 /* Initialize other state */
333 case NGM_MPPC_RESETREQ:
334 ng_mppc_reset_req(node);
347 NG_RESPOND_MSG(error, node, item, resp);
353 * Receive incoming data on our hook.
356 ng_mppc_rcvdata(hook_p hook, item_p item)
358 const node_p node = NG_HOOK_NODE(hook);
359 const priv_p priv = NG_NODE_PRIVATE(node);
364 /* Compress and/or encrypt */
365 if (hook == priv->xmit.hook) {
366 if (!priv->xmit.cfg.enable) {
371 if ((error = ng_mppc_compress(node, &m)) != 0) {
375 NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m);
379 /* Decompress and/or decrypt */
380 if (hook == priv->recv.hook) {
381 if (!priv->recv.cfg.enable) {
386 if ((error = ng_mppc_decompress(node, &m)) != 0) {
388 if (error == EINVAL && priv->ctrlnode != 0) {
391 /* Need to send a reset-request */
392 NG_MKMESSAGE(msg, NGM_MPPC_COOKIE,
393 NGM_MPPC_RESETREQ, 0, M_NOWAIT);
396 NG_SEND_MSG_ID(error, node, msg,
401 NG_FWD_NEW_DATA(error, item, priv->recv.hook, m);
406 panic("%s: unknown hook", __func__);
407 #ifdef RESTARTABLE_PANICS
416 ng_mppc_shutdown(node_p node)
418 const priv_p priv = NG_NODE_PRIVATE(node);
420 /* Take down netgraph node */
421 #ifdef NETGRAPH_MPPC_COMPRESSION
422 if (priv->xmit.history != NULL)
423 free(priv->xmit.history, M_NETGRAPH_MPPC);
424 if (priv->recv.history != NULL)
425 free(priv->recv.history, M_NETGRAPH_MPPC);
427 bzero(priv, sizeof(*priv));
428 free(priv, M_NETGRAPH_MPPC);
429 NG_NODE_SET_PRIVATE(node, NULL);
430 NG_NODE_UNREF(node); /* let the node escape */
438 ng_mppc_disconnect(hook_p hook)
440 const node_p node = NG_HOOK_NODE(hook);
441 const priv_p priv = NG_NODE_PRIVATE(node);
443 /* Zero out hook pointer */
444 if (hook == priv->xmit.hook)
445 priv->xmit.hook = NULL;
446 if (hook == priv->recv.hook)
447 priv->recv.hook = NULL;
449 /* Go away if no longer connected */
450 if ((NG_NODE_NUMHOOKS(node) == 0)
451 && NG_NODE_IS_VALID(node))
452 ng_rmnode_self(node);
456 /************************************************************************
458 ************************************************************************/
461 * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
462 * The original mbuf is not free'd.
465 ng_mppc_compress(node_p node, struct mbuf **datap)
467 const priv_p priv = NG_NODE_PRIVATE(node);
468 struct ng_mppc_dir *const d = &priv->xmit;
470 struct mbuf *m = *datap;
472 /* We must own the mbuf chain exclusively to modify it. */
473 m = m_unshare(m, M_DONTWAIT);
480 /* Always set the flushed bit in stateless mode */
481 if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) {
482 header |= MPPC_FLAG_FLUSHED;
486 /* Compress packet (if compression enabled) */
487 #ifdef NETGRAPH_MPPC_COMPRESSION
488 if ((d->cfg.bits & MPPC_BIT) != 0) {
489 u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS;
490 u_char *inbuf, *outbuf;
491 int outlen, inlen, ina;
492 u_char *source, *dest;
493 u_long sourceCnt, destCnt;
496 /* Work with contiguous regions of memory. */
497 inlen = m->m_pkthdr.len;
498 if (m->m_next == NULL) {
499 inbuf = mtod(m, u_char *);
502 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
505 m_copydata(m, 0, inlen, (caddr_t)inbuf);
509 outlen = MPPC_MAX_BLOWUP(inlen);
510 outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT);
511 if (outbuf == NULL) {
513 free(inbuf, M_NETGRAPH_MPPC);
516 MPPC_InitCompressionHistory(d->history);
521 /* Prepare to compress */
526 if ((d->cfg.bits & MPPE_STATELESS) == 0)
527 flags |= MPPC_SAVE_HISTORY;
530 rtn = MPPC_Compress(&source, &dest, &sourceCnt,
531 &destCnt, d->history, flags, 0);
533 /* Check return value */
534 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
535 if ((rtn & MPPC_EXPANDED) == 0
536 && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) {
538 header |= MPPC_FLAG_COMPRESSED;
539 if ((rtn & MPPC_RESTART_HISTORY) != 0)
540 header |= MPPC_FLAG_RESTART;
542 /* Replace m by the compresed one. */
543 m_copyback(m, 0, outlen, (caddr_t)outbuf);
544 if (m->m_pkthdr.len < outlen) {
547 } else if (outlen < m->m_pkthdr.len)
548 m_adj(m, outlen - m->m_pkthdr.len);
550 d->flushed = (rtn & MPPC_EXPANDED) != 0
551 || (flags & MPPC_SAVE_HISTORY) == 0;
554 free(inbuf, M_NETGRAPH_MPPC);
555 free(outbuf, M_NETGRAPH_MPPC);
557 /* Check mbuf chain reload result. */
560 MPPC_InitCompressionHistory(d->history);
568 /* Now encrypt packet (if encryption enabled) */
569 #ifdef NETGRAPH_MPPC_ENCRYPTION
570 if ((d->cfg.bits & MPPE_BITS) != 0) {
573 /* Set header bits */
574 header |= MPPC_FLAG_ENCRYPTED;
576 /* Update key if it's time */
577 if ((d->cfg.bits & MPPE_STATELESS) != 0
578 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
579 ng_mppc_updatekey(d->cfg.bits,
580 d->cfg.startkey, d->key, &d->rc4);
581 } else if ((header & MPPC_FLAG_FLUSHED) != 0) {
582 /* Need to reset key if we say we did
583 and ng_mppc_updatekey wasn't called to do it also. */
584 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
590 rc4_crypt(&d->rc4, mtod(m1, u_char *),
591 mtod(m1, u_char *), m1->m_len);
597 /* Update coherency count for next time (12 bit arithmetic) */
598 MPPC_CCOUNT_INC(d->cc);
601 M_PREPEND(m, MPPC_HDRLEN, M_DONTWAIT);
603 be16enc(mtod(m, void *), header);
606 return (*datap == NULL ? ENOBUFS : 0);
610 * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
611 * The original mbuf is not free'd.
614 ng_mppc_decompress(node_p node, struct mbuf **datap)
616 const priv_p priv = NG_NODE_PRIVATE(node);
617 struct ng_mppc_dir *const d = &priv->recv;
618 u_int16_t header, cc;
620 struct mbuf *m = *datap;
622 /* We must own the mbuf chain exclusively to modify it. */
623 m = m_unshare(m, M_DONTWAIT);
627 /* Pull off header */
628 if (m->m_pkthdr.len < MPPC_HDRLEN) {
632 header = be16dec(mtod(m, void *));
633 cc = (header & MPPC_CCOUNT_MASK);
634 m_adj(m, MPPC_HDRLEN);
636 /* Check for an unexpected jump in the sequence number */
637 numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK);
639 /* If flushed bit set, we can always handle packet */
640 if ((header & MPPC_FLAG_FLUSHED) != 0) {
641 #ifdef NETGRAPH_MPPC_COMPRESSION
642 if (d->history != NULL)
643 MPPC_InitDecompressionHistory(d->history);
645 #ifdef NETGRAPH_MPPC_ENCRYPTION
646 if ((d->cfg.bits & MPPE_BITS) != 0) {
649 /* How many times are we going to have to re-key? */
650 rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ?
651 numLost : (numLost / (MPPE_UPDATE_MASK + 1));
652 if (rekey > MPPE_MAX_REKEY) {
653 log(LOG_ERR, "%s: too many (%d) packets"
654 " dropped, disabling node %p!",
655 __func__, numLost, node);
656 priv->recv.cfg.enable = 0;
660 /* Re-key as necessary to catch up to peer */
661 while (d->cc != cc) {
662 if ((d->cfg.bits & MPPE_STATELESS) != 0
663 || (d->cc & MPPE_UPDATE_MASK)
664 == MPPE_UPDATE_FLAG) {
665 ng_mppc_updatekey(d->cfg.bits,
666 d->cfg.startkey, d->key, &d->rc4);
668 MPPC_CCOUNT_INC(d->cc);
671 /* Reset key (except in stateless mode, see below) */
672 if ((d->cfg.bits & MPPE_STATELESS) == 0)
673 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
676 d->cc = cc; /* skip over lost seq numbers */
677 numLost = 0; /* act like no packets were lost */
680 /* Can't decode non-sequential packets without a flushed bit */
685 if ((header & MPPC_FLAG_ENCRYPTED) != 0) {
686 #ifdef NETGRAPH_MPPC_ENCRYPTION
690 /* Are we not expecting encryption? */
691 if ((d->cfg.bits & MPPE_BITS) == 0) {
692 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
693 __func__, "encrypted");
697 #ifdef NETGRAPH_MPPC_ENCRYPTION
698 /* Update key if it's time (always in stateless mode) */
699 if ((d->cfg.bits & MPPE_STATELESS) != 0
700 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
701 ng_mppc_updatekey(d->cfg.bits,
702 d->cfg.startkey, d->key, &d->rc4);
708 rc4_crypt(&d->rc4, mtod(m1, u_char *),
709 mtod(m1, u_char *), m1->m_len);
715 /* Are we expecting encryption? */
716 if ((d->cfg.bits & MPPE_BITS) != 0) {
717 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
718 __func__, "unencrypted");
723 /* Update coherency count for next time (12 bit arithmetic) */
724 MPPC_CCOUNT_INC(d->cc);
726 /* Check for unexpected compressed packet */
727 if ((header & MPPC_FLAG_COMPRESSED) != 0
728 && (d->cfg.bits & MPPC_BIT) == 0) {
729 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
730 __func__, "compressed");
736 #ifdef NETGRAPH_MPPC_COMPRESSION
737 /* Decompress packet */
738 if ((header & MPPC_FLAG_COMPRESSED) != 0) {
739 int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS;
740 u_char *inbuf, *outbuf;
741 int inlen, outlen, ina;
742 u_char *source, *dest;
743 u_long sourceCnt, destCnt;
746 /* Copy payload into a contiguous region of memory. */
747 inlen = m->m_pkthdr.len;
748 if (m->m_next == NULL) {
749 inbuf = mtod(m, u_char *);
752 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
757 m_copydata(m, 0, inlen, (caddr_t)inbuf);
761 /* Allocate a buffer for decompressed data */
762 outbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY,
763 M_NETGRAPH_MPPC, M_NOWAIT);
764 if (outbuf == NULL) {
767 free(inbuf, M_NETGRAPH_MPPC);
770 outlen = MPPC_DECOMP_BUFSIZE;
772 /* Prepare to decompress */
777 if ((header & MPPC_FLAG_RESTART) != 0)
778 flags |= MPPC_RESTART_HISTORY;
781 rtn = MPPC_Decompress(&source, &dest,
782 &sourceCnt, &destCnt, d->history, flags);
784 /* Check return value */
785 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
786 if ((rtn & MPPC_DEST_EXHAUSTED) != 0
787 || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) {
788 log(LOG_ERR, "%s: decomp returned 0x%x",
791 free(inbuf, M_NETGRAPH_MPPC);
792 free(outbuf, M_NETGRAPH_MPPC);
796 /* Replace compressed data with decompressed data */
798 free(inbuf, M_NETGRAPH_MPPC);
801 m_copyback(m, 0, outlen, (caddr_t)outbuf);
802 if (m->m_pkthdr.len < outlen) {
805 } else if (outlen < m->m_pkthdr.len)
806 m_adj(m, outlen - m->m_pkthdr.len);
807 free(outbuf, M_NETGRAPH_MPPC);
811 /* Return result in an mbuf */
813 return (*datap == NULL ? ENOBUFS : 0);
817 * The peer has sent us a CCP ResetRequest, so reset our transmit state.
820 ng_mppc_reset_req(node_p node)
822 const priv_p priv = NG_NODE_PRIVATE(node);
823 struct ng_mppc_dir *const d = &priv->xmit;
825 #ifdef NETGRAPH_MPPC_COMPRESSION
826 if (d->history != NULL)
827 MPPC_InitCompressionHistory(d->history);
829 #ifdef NETGRAPH_MPPC_ENCRYPTION
830 if ((d->cfg.bits & MPPE_STATELESS) == 0)
831 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
836 #ifdef NETGRAPH_MPPC_ENCRYPTION
838 * Generate a new encryption key
841 ng_mppc_getkey(const u_char *h, u_char *h2, int len)
843 static const u_char pad1[40] =
844 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
845 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
846 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
847 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
848 static const u_char pad2[40] =
849 { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
850 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
851 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
852 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 };
857 SHA1Update(&c, h, len);
858 SHA1Update(&c, pad1, sizeof(pad1));
859 SHA1Update(&c, h2, len);
860 SHA1Update(&c, pad2, sizeof(pad2));
862 bcopy(hash, h2, len);
866 * Update the encryption key
869 ng_mppc_updatekey(u_int32_t bits,
870 u_char *key0, u_char *key, struct rc4_state *rc4)
872 const int keylen = KEYLEN(bits);
874 ng_mppc_getkey(key0, key, keylen);
875 rc4_init(rc4, key, keylen);
876 rc4_crypt(rc4, key, key, keylen);
877 if ((bits & MPPE_40) != 0)
878 bcopy(&ng_mppe_weakenkey, key, 3);
879 else if ((bits & MPPE_56) != 0)
880 bcopy(&ng_mppe_weakenkey, key, 1);
881 rc4_init(rc4, key, keylen);