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 MALLOC(priv, priv_p, 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 MALLOC(d->history, u_char *,
299 isComp ? 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;
492 int outlen, inlen, ina;
493 u_char *source, *dest;
494 u_long sourceCnt, destCnt;
497 /* Work with contiguous regions of memory. */
498 inlen = m->m_pkthdr.len;
499 if (m->m_next == NULL) {
500 inbuf = mtod(m, u_char *);
503 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
506 m_copydata(m, 0, inlen, (caddr_t)inbuf);
510 outlen = MPPC_MAX_BLOWUP(inlen);
511 outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT);
512 if (outbuf == NULL) {
514 free(inbuf, M_NETGRAPH_MPPC);
517 MPPC_InitCompressionHistory(d->history);
522 /* Prepare to compress */
527 if ((d->cfg.bits & MPPE_STATELESS) == 0)
528 flags |= MPPC_SAVE_HISTORY;
531 rtn = MPPC_Compress(&source, &dest, &sourceCnt,
532 &destCnt, d->history, flags, 0);
534 /* Check return value */
535 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
536 if ((rtn & MPPC_EXPANDED) == 0
537 && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) {
539 header |= MPPC_FLAG_COMPRESSED;
540 if ((rtn & MPPC_RESTART_HISTORY) != 0)
541 header |= MPPC_FLAG_RESTART;
543 /* Replace m by the compresed one. */
544 m_copyback(m, 0, outlen, (caddr_t)outbuf);
545 if (m->m_pkthdr.len < outlen) {
548 } else if (outlen < m->m_pkthdr.len)
549 m_adj(m, outlen - m->m_pkthdr.len);
551 d->flushed = (rtn & MPPC_EXPANDED) != 0
552 || (flags & MPPC_SAVE_HISTORY) == 0;
555 free(inbuf, M_NETGRAPH_MPPC);
556 free(outbuf, M_NETGRAPH_MPPC);
558 /* Check mbuf chain reload result. */
561 MPPC_InitCompressionHistory(d->history);
569 /* Now encrypt packet (if encryption enabled) */
570 #ifdef NETGRAPH_MPPC_ENCRYPTION
571 if ((d->cfg.bits & MPPE_BITS) != 0) {
574 /* Set header bits */
575 header |= MPPC_FLAG_ENCRYPTED;
577 /* Update key if it's time */
578 if ((d->cfg.bits & MPPE_STATELESS) != 0
579 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
580 ng_mppc_updatekey(d->cfg.bits,
581 d->cfg.startkey, d->key, &d->rc4);
582 } else if ((header & MPPC_FLAG_FLUSHED) != 0) {
583 /* Need to reset key if we say we did
584 and ng_mppc_updatekey wasn't called to do it also. */
585 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
591 rc4_crypt(&d->rc4, mtod(m1, u_char *),
592 mtod(m1, u_char *), m1->m_len);
598 /* Update coherency count for next time (12 bit arithmetic) */
599 MPPC_CCOUNT_INC(d->cc);
602 M_PREPEND(m, MPPC_HDRLEN, M_DONTWAIT);
604 *(mtod(m, uint16_t *)) = htons(header);
607 return (*datap == NULL ? ENOBUFS : 0);
611 * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
612 * The original mbuf is not free'd.
615 ng_mppc_decompress(node_p node, struct mbuf **datap)
617 const priv_p priv = NG_NODE_PRIVATE(node);
618 struct ng_mppc_dir *const d = &priv->recv;
619 u_int16_t header, cc;
621 struct mbuf *m = *datap;
623 /* We must own the mbuf chain exclusively to modify it. */
624 m = m_unshare(m, M_DONTWAIT);
628 /* Pull off header */
629 if (m->m_pkthdr.len < MPPC_HDRLEN) {
633 m_copydata(m, 0, MPPC_HDRLEN, (caddr_t)&header);
634 header = ntohs(header);
635 cc = (header & MPPC_CCOUNT_MASK);
636 m_adj(m, MPPC_HDRLEN);
638 /* Check for an unexpected jump in the sequence number */
639 numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK);
641 /* If flushed bit set, we can always handle packet */
642 if ((header & MPPC_FLAG_FLUSHED) != 0) {
643 #ifdef NETGRAPH_MPPC_COMPRESSION
644 if (d->history != NULL)
645 MPPC_InitDecompressionHistory(d->history);
647 #ifdef NETGRAPH_MPPC_ENCRYPTION
648 if ((d->cfg.bits & MPPE_BITS) != 0) {
651 /* How many times are we going to have to re-key? */
652 rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ?
653 numLost : (numLost / (MPPE_UPDATE_MASK + 1));
654 if (rekey > MPPE_MAX_REKEY) {
655 log(LOG_ERR, "%s: too many (%d) packets"
656 " dropped, disabling node %p!",
657 __func__, numLost, node);
658 priv->recv.cfg.enable = 0;
662 /* Re-key as necessary to catch up to peer */
663 while (d->cc != cc) {
664 if ((d->cfg.bits & MPPE_STATELESS) != 0
665 || (d->cc & MPPE_UPDATE_MASK)
666 == MPPE_UPDATE_FLAG) {
667 ng_mppc_updatekey(d->cfg.bits,
668 d->cfg.startkey, d->key, &d->rc4);
670 MPPC_CCOUNT_INC(d->cc);
673 /* Reset key (except in stateless mode, see below) */
674 if ((d->cfg.bits & MPPE_STATELESS) == 0)
675 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
678 d->cc = cc; /* skip over lost seq numbers */
679 numLost = 0; /* act like no packets were lost */
682 /* Can't decode non-sequential packets without a flushed bit */
687 if ((header & MPPC_FLAG_ENCRYPTED) != 0) {
688 #ifdef NETGRAPH_MPPC_ENCRYPTION
692 /* Are we not expecting encryption? */
693 if ((d->cfg.bits & MPPE_BITS) == 0) {
694 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
695 __func__, "encrypted");
699 #ifdef NETGRAPH_MPPC_ENCRYPTION
700 /* Update key if it's time (always in stateless mode) */
701 if ((d->cfg.bits & MPPE_STATELESS) != 0
702 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
703 ng_mppc_updatekey(d->cfg.bits,
704 d->cfg.startkey, d->key, &d->rc4);
710 rc4_crypt(&d->rc4, mtod(m1, u_char *),
711 mtod(m1, u_char *), m1->m_len);
717 /* Are we expecting encryption? */
718 if ((d->cfg.bits & MPPE_BITS) != 0) {
719 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
720 __func__, "unencrypted");
725 /* Update coherency count for next time (12 bit arithmetic) */
726 MPPC_CCOUNT_INC(d->cc);
728 /* Check for unexpected compressed packet */
729 if ((header & MPPC_FLAG_COMPRESSED) != 0
730 && (d->cfg.bits & MPPC_BIT) == 0) {
731 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
732 __func__, "compressed");
738 #ifdef NETGRAPH_MPPC_COMPRESSION
739 /* Decompress packet */
740 if ((header & MPPC_FLAG_COMPRESSED) != 0) {
741 int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS;
742 u_char *inbuf, *outbuf;
743 int inlen, outlen, ina;
744 u_char *source, *dest;
745 u_long sourceCnt, destCnt;
748 /* Copy payload into a contiguous region of memory. */
749 inlen = m->m_pkthdr.len;
750 if (m->m_next == NULL) {
751 inbuf = mtod(m, u_char *);
754 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
759 m_copydata(m, 0, inlen, (caddr_t)inbuf);
763 /* Allocate a buffer for decompressed data */
764 outbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY,
765 M_NETGRAPH_MPPC, M_NOWAIT);
766 if (outbuf == NULL) {
769 free(inbuf, M_NETGRAPH_MPPC);
772 outlen = MPPC_DECOMP_BUFSIZE;
774 /* Prepare to decompress */
779 if ((header & MPPC_FLAG_RESTART) != 0)
780 flags |= MPPC_RESTART_HISTORY;
783 rtn = MPPC_Decompress(&source, &dest,
784 &sourceCnt, &destCnt, d->history, flags);
786 /* Check return value */
787 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
788 if ((rtn & MPPC_DEST_EXHAUSTED) != 0
789 || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) {
790 log(LOG_ERR, "%s: decomp returned 0x%x",
793 free(inbuf, M_NETGRAPH_MPPC);
794 free(outbuf, M_NETGRAPH_MPPC);
798 /* Replace compressed data with decompressed data */
800 free(inbuf, M_NETGRAPH_MPPC);
803 m_copyback(m, 0, outlen, (caddr_t)outbuf);
804 if (m->m_pkthdr.len < outlen) {
807 } else if (outlen < m->m_pkthdr.len)
808 m_adj(m, outlen - m->m_pkthdr.len);
809 free(outbuf, M_NETGRAPH_MPPC);
813 /* Return result in an mbuf */
815 return (*datap == NULL ? ENOBUFS : 0);
819 * The peer has sent us a CCP ResetRequest, so reset our transmit state.
822 ng_mppc_reset_req(node_p node)
824 const priv_p priv = NG_NODE_PRIVATE(node);
825 struct ng_mppc_dir *const d = &priv->xmit;
827 #ifdef NETGRAPH_MPPC_COMPRESSION
828 if (d->history != NULL)
829 MPPC_InitCompressionHistory(d->history);
831 #ifdef NETGRAPH_MPPC_ENCRYPTION
832 if ((d->cfg.bits & MPPE_STATELESS) == 0)
833 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
838 #ifdef NETGRAPH_MPPC_ENCRYPTION
840 * Generate a new encryption key
843 ng_mppc_getkey(const u_char *h, u_char *h2, int len)
845 static const u_char pad1[40] =
846 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
847 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
848 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
849 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
850 static const u_char pad2[40] =
851 { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
852 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
853 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
854 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 };
859 SHA1Update(&c, h, len);
860 SHA1Update(&c, pad1, sizeof(pad1));
861 SHA1Update(&c, h2, len);
862 SHA1Update(&c, pad2, sizeof(pad2));
864 bcopy(hash, h2, len);
868 * Update the encryption key
871 ng_mppc_updatekey(u_int32_t bits,
872 u_char *key0, u_char *key, struct rc4_state *rc4)
874 const int keylen = KEYLEN(bits);
876 ng_mppc_getkey(key0, key, keylen);
877 rc4_init(rc4, key, keylen);
878 rc4_crypt(rc4, key, key, keylen);
879 if ((bits & MPPE_40) != 0)
880 bcopy(&ng_mppe_weakenkey, key, 3);
881 else if ((bits & MPPE_56) != 0)
882 bcopy(&ng_mppe_weakenkey, key, 1);
883 rc4_init(rc4, key, keylen);