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 #define NETGRAPH_MPPC_COMPRESSION
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
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 SYSCTL_NODE(_net_graph, OID_AUTO, mppe, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
113 static int mppe_block_on_max_rekey = 0;
114 SYSCTL_INT(_net_graph_mppe, OID_AUTO, block_on_max_rekey, CTLFLAG_RWTUN,
115 &mppe_block_on_max_rekey, 0, "Block node on max MPPE key re-calculations");
117 static int mppe_log_max_rekey = 1;
118 SYSCTL_INT(_net_graph_mppe, OID_AUTO, log_max_rekey, CTLFLAG_RWTUN,
119 &mppe_log_max_rekey, 0, "Log max MPPE key re-calculations event");
121 static int mppe_max_rekey = MPPE_MAX_REKEY;
122 SYSCTL_INT(_net_graph_mppe, OID_AUTO, max_rekey, CTLFLAG_RWTUN,
123 &mppe_max_rekey, 0, "Maximum number of MPPE key re-calculations");
125 /* MPPC packet header bits */
126 #define MPPC_FLAG_FLUSHED 0x8000 /* xmitter reset state */
127 #define MPPC_FLAG_RESTART 0x4000 /* compress history restart */
128 #define MPPC_FLAG_COMPRESSED 0x2000 /* packet is compresed */
129 #define MPPC_FLAG_ENCRYPTED 0x1000 /* packet is encrypted */
130 #define MPPC_CCOUNT_MASK 0x0fff /* sequence number mask */
132 #define MPPC_CCOUNT_INC(d) ((d) = (((d) + 1) & MPPC_CCOUNT_MASK))
134 #define MPPE_UPDATE_MASK 0xff /* coherency count when we're */
135 #define MPPE_UPDATE_FLAG 0xff /* supposed to update key */
137 #define MPPC_COMP_OK 0x05
138 #define MPPC_DECOMP_OK 0x05
140 /* Per direction info */
142 struct ng_mppc_config cfg; /* configuration */
143 hook_p hook; /* netgraph hook */
144 u_int16_t cc:12; /* coherency count */
145 u_char flushed; /* clean history (xmit only) */
146 #ifdef NETGRAPH_MPPC_COMPRESSION
147 u_char *history; /* compression history */
149 #ifdef NETGRAPH_MPPC_ENCRYPTION
150 u_char key[MPPE_KEY_LEN]; /* session key */
151 struct rc4_state rc4; /* rc4 state */
155 /* Node private data */
156 struct ng_mppc_private {
157 struct ng_mppc_dir xmit; /* compress/encrypt config */
158 struct ng_mppc_dir recv; /* decompress/decrypt config */
159 ng_ID_t ctrlnode; /* path to controlling node */
161 typedef struct ng_mppc_private *priv_p;
163 /* Netgraph node methods */
164 static ng_constructor_t ng_mppc_constructor;
165 static ng_rcvmsg_t ng_mppc_rcvmsg;
166 static ng_shutdown_t ng_mppc_shutdown;
167 static ng_newhook_t ng_mppc_newhook;
168 static ng_rcvdata_t ng_mppc_rcvdata;
169 static ng_disconnect_t ng_mppc_disconnect;
171 /* Helper functions */
172 static int ng_mppc_compress(node_p node,
173 struct mbuf **datap);
174 static int ng_mppc_decompress(node_p node,
175 struct mbuf **datap);
176 #ifdef NETGRAPH_MPPC_ENCRYPTION
177 static void ng_mppc_getkey(const u_char *h, u_char *h2, int len);
178 static void ng_mppc_updatekey(u_int32_t bits,
179 u_char *key0, u_char *key, struct rc4_state *rc4);
181 static void ng_mppc_reset_req(node_p node);
183 /* Node type descriptor */
184 static struct ng_type ng_mppc_typestruct = {
185 .version = NG_ABI_VERSION,
186 .name = NG_MPPC_NODE_TYPE,
187 .constructor = ng_mppc_constructor,
188 .rcvmsg = ng_mppc_rcvmsg,
189 .shutdown = ng_mppc_shutdown,
190 .newhook = ng_mppc_newhook,
191 .rcvdata = ng_mppc_rcvdata,
192 .disconnect = ng_mppc_disconnect,
194 NETGRAPH_INIT(mppc, &ng_mppc_typestruct);
196 #ifdef NETGRAPH_MPPC_ENCRYPTION
197 /* Depend on separate rc4 module */
198 MODULE_DEPEND(ng_mppc, rc4, 1, 1, 1);
201 /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
202 static const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e };
204 #define ERROUT(x) do { error = (x); goto done; } while (0)
206 /************************************************************************
208 ************************************************************************/
211 * Node type constructor
214 ng_mppc_constructor(node_p node)
218 /* Allocate private structure */
219 priv = malloc(sizeof(*priv), M_NETGRAPH_MPPC, M_WAITOK | M_ZERO);
221 NG_NODE_SET_PRIVATE(node, priv);
223 /* This node is not thread safe. */
224 NG_NODE_FORCE_WRITER(node);
231 * Give our OK for a hook to be added
234 ng_mppc_newhook(node_p node, hook_p hook, const char *name)
236 const priv_p priv = NG_NODE_PRIVATE(node);
239 /* Check hook name */
240 if (strcmp(name, NG_MPPC_HOOK_COMP) == 0)
241 hookPtr = &priv->xmit.hook;
242 else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0)
243 hookPtr = &priv->recv.hook;
247 /* See if already connected */
248 if (*hookPtr != NULL)
257 * Receive a control message
260 ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook)
262 const priv_p priv = NG_NODE_PRIVATE(node);
263 struct ng_mesg *resp = NULL;
267 NGI_GET_MSG(item, msg);
268 switch (msg->header.typecookie) {
269 case NGM_MPPC_COOKIE:
270 switch (msg->header.cmd) {
271 case NGM_MPPC_CONFIG_COMP:
272 case NGM_MPPC_CONFIG_DECOMP:
274 struct ng_mppc_config *const cfg
275 = (struct ng_mppc_config *)msg->data;
277 msg->header.cmd == NGM_MPPC_CONFIG_COMP;
278 struct ng_mppc_dir *const d = isComp ?
279 &priv->xmit : &priv->recv;
281 /* Check configuration */
282 if (msg->header.arglen != sizeof(*cfg))
285 if ((cfg->bits & ~MPPC_VALID_BITS) != 0)
287 #ifndef NETGRAPH_MPPC_COMPRESSION
288 if ((cfg->bits & MPPC_BIT) != 0)
289 ERROUT(EPROTONOSUPPORT);
291 #ifndef NETGRAPH_MPPC_ENCRYPTION
292 if ((cfg->bits & MPPE_BITS) != 0)
293 ERROUT(EPROTONOSUPPORT);
298 /* Save return address so we can send reset-req's */
300 priv->ctrlnode = NGI_RETADDR(item);
302 /* Configuration is OK, reset to it */
305 #ifdef NETGRAPH_MPPC_COMPRESSION
306 /* Initialize state buffers for compression */
307 if (d->history != NULL) {
308 free(d->history, M_NETGRAPH_MPPC);
311 if ((cfg->bits & MPPC_BIT) != 0) {
312 d->history = malloc(isComp ?
313 MPPC_SizeOfCompressionHistory() :
314 MPPC_SizeOfDecompressionHistory(),
315 M_NETGRAPH_MPPC, M_NOWAIT);
316 if (d->history == NULL)
319 MPPC_InitCompressionHistory(d->history);
321 MPPC_InitDecompressionHistory(
327 #ifdef NETGRAPH_MPPC_ENCRYPTION
328 /* Generate initial session keys for encryption */
329 if ((cfg->bits & MPPE_BITS) != 0) {
330 const int keylen = KEYLEN(cfg->bits);
332 bcopy(cfg->startkey, d->key, keylen);
333 ng_mppc_getkey(cfg->startkey, d->key, keylen);
334 if ((cfg->bits & MPPE_40) != 0)
335 bcopy(&ng_mppe_weakenkey, d->key, 3);
336 else if ((cfg->bits & MPPE_56) != 0)
337 bcopy(&ng_mppe_weakenkey, d->key, 1);
338 rc4_init(&d->rc4, d->key, keylen);
342 /* Initialize other state */
348 case NGM_MPPC_RESETREQ:
349 ng_mppc_reset_req(node);
362 NG_RESPOND_MSG(error, node, item, resp);
368 * Receive incoming data on our hook.
371 ng_mppc_rcvdata(hook_p hook, item_p item)
373 const node_p node = NG_HOOK_NODE(hook);
374 const priv_p priv = NG_NODE_PRIVATE(node);
379 /* Compress and/or encrypt */
380 if (hook == priv->xmit.hook) {
381 if (!priv->xmit.cfg.enable) {
386 if ((error = ng_mppc_compress(node, &m)) != 0) {
390 NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m);
394 /* Decompress and/or decrypt */
395 if (hook == priv->recv.hook) {
396 if (!priv->recv.cfg.enable) {
401 if ((error = ng_mppc_decompress(node, &m)) != 0) {
403 if (error == EINVAL && priv->ctrlnode != 0) {
406 /* Need to send a reset-request */
407 NG_MKMESSAGE(msg, NGM_MPPC_COOKIE,
408 NGM_MPPC_RESETREQ, 0, M_NOWAIT);
411 NG_SEND_MSG_ID(error, node, msg,
416 NG_FWD_NEW_DATA(error, item, priv->recv.hook, m);
421 panic("%s: unknown hook", __func__);
428 ng_mppc_shutdown(node_p node)
430 const priv_p priv = NG_NODE_PRIVATE(node);
432 /* Take down netgraph node */
433 #ifdef NETGRAPH_MPPC_COMPRESSION
434 if (priv->xmit.history != NULL)
435 free(priv->xmit.history, M_NETGRAPH_MPPC);
436 if (priv->recv.history != NULL)
437 free(priv->recv.history, M_NETGRAPH_MPPC);
439 bzero(priv, sizeof(*priv));
440 free(priv, M_NETGRAPH_MPPC);
441 NG_NODE_SET_PRIVATE(node, NULL);
442 NG_NODE_UNREF(node); /* let the node escape */
450 ng_mppc_disconnect(hook_p hook)
452 const node_p node = NG_HOOK_NODE(hook);
453 const priv_p priv = NG_NODE_PRIVATE(node);
455 /* Zero out hook pointer */
456 if (hook == priv->xmit.hook)
457 priv->xmit.hook = NULL;
458 if (hook == priv->recv.hook)
459 priv->recv.hook = NULL;
461 /* Go away if no longer connected */
462 if ((NG_NODE_NUMHOOKS(node) == 0)
463 && NG_NODE_IS_VALID(node))
464 ng_rmnode_self(node);
468 /************************************************************************
470 ************************************************************************/
473 * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
474 * The original mbuf is not free'd.
477 ng_mppc_compress(node_p node, struct mbuf **datap)
479 const priv_p priv = NG_NODE_PRIVATE(node);
480 struct ng_mppc_dir *const d = &priv->xmit;
482 struct mbuf *m = *datap;
484 /* We must own the mbuf chain exclusively to modify it. */
485 m = m_unshare(m, M_NOWAIT);
492 /* Always set the flushed bit in stateless mode */
493 if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) {
494 header |= MPPC_FLAG_FLUSHED;
498 /* Compress packet (if compression enabled) */
499 #ifdef NETGRAPH_MPPC_COMPRESSION
500 if ((d->cfg.bits & MPPC_BIT) != 0) {
501 u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS;
502 u_char *inbuf, *outbuf;
503 int outlen, inlen, ina;
504 u_char *source, *dest;
505 u_long sourceCnt, destCnt;
508 /* Work with contiguous regions of memory. */
509 inlen = m->m_pkthdr.len;
510 if (m->m_next == NULL) {
511 inbuf = mtod(m, u_char *);
514 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
517 m_copydata(m, 0, inlen, (caddr_t)inbuf);
521 outlen = MPPC_MAX_BLOWUP(inlen);
522 outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT);
523 if (outbuf == NULL) {
525 free(inbuf, M_NETGRAPH_MPPC);
528 MPPC_InitCompressionHistory(d->history);
533 /* Prepare to compress */
538 if ((d->cfg.bits & MPPE_STATELESS) == 0)
539 flags |= MPPC_SAVE_HISTORY;
542 rtn = MPPC_Compress(&source, &dest, &sourceCnt,
543 &destCnt, d->history, flags, 0);
545 /* Check return value */
546 /* KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); */
547 if ((rtn & MPPC_EXPANDED) == 0
548 && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) {
550 header |= MPPC_FLAG_COMPRESSED;
551 if ((rtn & MPPC_RESTART_HISTORY) != 0)
552 header |= MPPC_FLAG_RESTART;
554 /* Replace m by the compresed one. */
555 m_copyback(m, 0, outlen, (caddr_t)outbuf);
556 if (m->m_pkthdr.len < outlen) {
559 } else if (outlen < m->m_pkthdr.len)
560 m_adj(m, outlen - m->m_pkthdr.len);
562 d->flushed = (rtn & MPPC_EXPANDED) != 0
563 || (flags & MPPC_SAVE_HISTORY) == 0;
566 free(inbuf, M_NETGRAPH_MPPC);
567 free(outbuf, M_NETGRAPH_MPPC);
569 /* Check mbuf chain reload result. */
572 MPPC_InitCompressionHistory(d->history);
580 /* Now encrypt packet (if encryption enabled) */
581 #ifdef NETGRAPH_MPPC_ENCRYPTION
582 if ((d->cfg.bits & MPPE_BITS) != 0) {
585 /* Set header bits */
586 header |= MPPC_FLAG_ENCRYPTED;
588 /* Update key if it's time */
589 if ((d->cfg.bits & MPPE_STATELESS) != 0
590 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
591 ng_mppc_updatekey(d->cfg.bits,
592 d->cfg.startkey, d->key, &d->rc4);
593 } else if ((header & MPPC_FLAG_FLUSHED) != 0) {
594 /* Need to reset key if we say we did
595 and ng_mppc_updatekey wasn't called to do it also. */
596 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
602 rc4_crypt(&d->rc4, mtod(m1, u_char *),
603 mtod(m1, u_char *), m1->m_len);
609 /* Update coherency count for next time (12 bit arithmetic) */
610 MPPC_CCOUNT_INC(d->cc);
613 M_PREPEND(m, MPPC_HDRLEN, M_NOWAIT);
615 be16enc(mtod(m, void *), header);
618 return (*datap == NULL ? ENOBUFS : 0);
622 * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
623 * The original mbuf is not free'd.
626 ng_mppc_decompress(node_p node, struct mbuf **datap)
628 const priv_p priv = NG_NODE_PRIVATE(node);
629 struct ng_mppc_dir *const d = &priv->recv;
630 u_int16_t header, cc;
632 struct mbuf *m = *datap;
634 /* We must own the mbuf chain exclusively to modify it. */
635 m = m_unshare(m, M_NOWAIT);
639 /* Pull off header */
640 if (m->m_pkthdr.len < MPPC_HDRLEN) {
644 header = be16dec(mtod(m, void *));
645 cc = (header & MPPC_CCOUNT_MASK);
646 m_adj(m, MPPC_HDRLEN);
648 /* Check for an unexpected jump in the sequence number */
649 numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK);
651 /* If flushed bit set, we can always handle packet */
652 if ((header & MPPC_FLAG_FLUSHED) != 0) {
653 #ifdef NETGRAPH_MPPC_COMPRESSION
654 if (d->history != NULL)
655 MPPC_InitDecompressionHistory(d->history);
657 #ifdef NETGRAPH_MPPC_ENCRYPTION
658 if ((d->cfg.bits & MPPE_BITS) != 0) {
661 /* How many times are we going to have to re-key? */
662 rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ?
663 numLost : (numLost / (MPPE_UPDATE_MASK + 1));
664 if (rekey > mppe_max_rekey) {
665 if (mppe_block_on_max_rekey) {
666 if (mppe_log_max_rekey) {
667 log(LOG_ERR, "%s: too many (%d) packets"
668 " dropped, disabling node %p!\n",
669 __func__, numLost, node);
671 priv->recv.cfg.enable = 0;
674 if (mppe_log_max_rekey) {
675 log(LOG_ERR, "%s: %d packets"
676 " dropped, node %p\n",
677 __func__, numLost, node);
683 /* Re-key as necessary to catch up to peer */
684 while (d->cc != cc) {
685 if ((d->cfg.bits & MPPE_STATELESS) != 0
686 || (d->cc & MPPE_UPDATE_MASK)
687 == MPPE_UPDATE_FLAG) {
688 ng_mppc_updatekey(d->cfg.bits,
689 d->cfg.startkey, d->key, &d->rc4);
691 MPPC_CCOUNT_INC(d->cc);
694 /* Reset key (except in stateless mode, see below) */
695 if ((d->cfg.bits & MPPE_STATELESS) == 0)
696 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
699 d->cc = cc; /* skip over lost seq numbers */
700 numLost = 0; /* act like no packets were lost */
703 /* Can't decode non-sequential packets without a flushed bit */
708 if ((header & MPPC_FLAG_ENCRYPTED) != 0) {
709 #ifdef NETGRAPH_MPPC_ENCRYPTION
713 /* Are we not expecting encryption? */
714 if ((d->cfg.bits & MPPE_BITS) == 0) {
715 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
716 __func__, "encrypted");
720 #ifdef NETGRAPH_MPPC_ENCRYPTION
721 /* Update key if it's time (always in stateless mode) */
722 if ((d->cfg.bits & MPPE_STATELESS) != 0
723 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
724 ng_mppc_updatekey(d->cfg.bits,
725 d->cfg.startkey, d->key, &d->rc4);
731 rc4_crypt(&d->rc4, mtod(m1, u_char *),
732 mtod(m1, u_char *), m1->m_len);
737 /* Are we expecting encryption? */
738 if ((d->cfg.bits & MPPE_BITS) != 0) {
739 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
740 __func__, "unencrypted");
745 /* Update coherency count for next time (12 bit arithmetic) */
746 MPPC_CCOUNT_INC(d->cc);
748 /* Check for unexpected compressed packet */
749 if ((header & MPPC_FLAG_COMPRESSED) != 0
750 && (d->cfg.bits & MPPC_BIT) == 0) {
751 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
752 __func__, "compressed");
758 #ifdef NETGRAPH_MPPC_COMPRESSION
759 /* Decompress packet */
760 if ((header & MPPC_FLAG_COMPRESSED) != 0) {
761 int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS;
762 u_char *inbuf, *outbuf;
763 int inlen, outlen, ina;
764 u_char *source, *dest;
765 u_long sourceCnt, destCnt;
768 /* Copy payload into a contiguous region of memory. */
769 inlen = m->m_pkthdr.len;
770 if (m->m_next == NULL) {
771 inbuf = mtod(m, u_char *);
774 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
779 m_copydata(m, 0, inlen, (caddr_t)inbuf);
783 /* Allocate a buffer for decompressed data */
784 outbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY,
785 M_NETGRAPH_MPPC, M_NOWAIT);
786 if (outbuf == NULL) {
789 free(inbuf, M_NETGRAPH_MPPC);
792 outlen = MPPC_DECOMP_BUFSIZE;
794 /* Prepare to decompress */
799 if ((header & MPPC_FLAG_RESTART) != 0)
800 flags |= MPPC_RESTART_HISTORY;
803 rtn = MPPC_Decompress(&source, &dest,
804 &sourceCnt, &destCnt, d->history, flags);
806 /* Check return value */
807 /* KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); */
808 if ((rtn & MPPC_DEST_EXHAUSTED) != 0
809 || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) {
810 log(LOG_ERR, "%s: decomp returned 0x%x",
813 free(inbuf, M_NETGRAPH_MPPC);
814 free(outbuf, M_NETGRAPH_MPPC);
818 /* Replace compressed data with decompressed data */
820 free(inbuf, M_NETGRAPH_MPPC);
823 m_copyback(m, 0, outlen, (caddr_t)outbuf);
824 if (m->m_pkthdr.len < outlen) {
827 } else if (outlen < m->m_pkthdr.len)
828 m_adj(m, outlen - m->m_pkthdr.len);
829 free(outbuf, M_NETGRAPH_MPPC);
833 /* Return result in an mbuf */
835 return (*datap == NULL ? ENOBUFS : 0);
839 * The peer has sent us a CCP ResetRequest, so reset our transmit state.
842 ng_mppc_reset_req(node_p node)
844 const priv_p priv = NG_NODE_PRIVATE(node);
845 struct ng_mppc_dir *const d = &priv->xmit;
847 #ifdef NETGRAPH_MPPC_COMPRESSION
848 if (d->history != NULL)
849 MPPC_InitCompressionHistory(d->history);
851 #ifdef NETGRAPH_MPPC_ENCRYPTION
852 if ((d->cfg.bits & MPPE_STATELESS) == 0)
853 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
858 #ifdef NETGRAPH_MPPC_ENCRYPTION
860 * Generate a new encryption key
863 ng_mppc_getkey(const u_char *h, u_char *h2, int len)
865 static const u_char pad1[40] =
866 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
867 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
868 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
869 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
870 static const u_char pad2[40] =
871 { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
872 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
873 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
874 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 };
879 SHA1Update(&c, h, len);
880 SHA1Update(&c, pad1, sizeof(pad1));
881 SHA1Update(&c, h2, len);
882 SHA1Update(&c, pad2, sizeof(pad2));
884 bcopy(hash, h2, len);
888 * Update the encryption key
891 ng_mppc_updatekey(u_int32_t bits,
892 u_char *key0, u_char *key, struct rc4_state *rc4)
894 const int keylen = KEYLEN(bits);
896 ng_mppc_getkey(key0, key, keylen);
897 rc4_init(rc4, key, keylen);
898 rc4_crypt(rc4, key, key, keylen);
899 if ((bits & MPPE_40) != 0)
900 bcopy(&ng_mppe_weakenkey, key, 3);
901 else if ((bits & MPPE_56) != 0)
902 bcopy(&ng_mppe_weakenkey, key, 1);
903 rc4_init(rc4, key, keylen);