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, 0, "MPPE");
112 static int mppe_block_on_max_rekey = 0;
113 SYSCTL_INT(_net_graph_mppe, OID_AUTO, block_on_max_rekey, CTLFLAG_RWTUN,
114 &mppe_block_on_max_rekey, 0, "Block node on max MPPE key re-calculations");
116 static int mppe_log_max_rekey = 1;
117 SYSCTL_INT(_net_graph_mppe, OID_AUTO, log_max_rekey, CTLFLAG_RWTUN,
118 &mppe_log_max_rekey, 0, "Log max MPPE key re-calculations event");
120 static int mppe_max_rekey = MPPE_MAX_REKEY;
121 SYSCTL_INT(_net_graph_mppe, OID_AUTO, max_rekey, CTLFLAG_RWTUN,
122 &mppe_max_rekey, 0, "Maximum number of MPPE key re-calculations");
124 /* MPPC packet header bits */
125 #define MPPC_FLAG_FLUSHED 0x8000 /* xmitter reset state */
126 #define MPPC_FLAG_RESTART 0x4000 /* compress history restart */
127 #define MPPC_FLAG_COMPRESSED 0x2000 /* packet is compresed */
128 #define MPPC_FLAG_ENCRYPTED 0x1000 /* packet is encrypted */
129 #define MPPC_CCOUNT_MASK 0x0fff /* sequence number mask */
131 #define MPPC_CCOUNT_INC(d) ((d) = (((d) + 1) & MPPC_CCOUNT_MASK))
133 #define MPPE_UPDATE_MASK 0xff /* coherency count when we're */
134 #define MPPE_UPDATE_FLAG 0xff /* supposed to update key */
136 #define MPPC_COMP_OK 0x05
137 #define MPPC_DECOMP_OK 0x05
139 /* Per direction info */
141 struct ng_mppc_config cfg; /* configuration */
142 hook_p hook; /* netgraph hook */
143 u_int16_t cc:12; /* coherency count */
144 u_char flushed; /* clean history (xmit only) */
145 #ifdef NETGRAPH_MPPC_COMPRESSION
146 u_char *history; /* compression history */
148 #ifdef NETGRAPH_MPPC_ENCRYPTION
149 u_char key[MPPE_KEY_LEN]; /* session key */
150 struct rc4_state rc4; /* rc4 state */
154 /* Node private data */
155 struct ng_mppc_private {
156 struct ng_mppc_dir xmit; /* compress/encrypt config */
157 struct ng_mppc_dir recv; /* decompress/decrypt config */
158 ng_ID_t ctrlnode; /* path to controlling node */
160 typedef struct ng_mppc_private *priv_p;
162 /* Netgraph node methods */
163 static ng_constructor_t ng_mppc_constructor;
164 static ng_rcvmsg_t ng_mppc_rcvmsg;
165 static ng_shutdown_t ng_mppc_shutdown;
166 static ng_newhook_t ng_mppc_newhook;
167 static ng_rcvdata_t ng_mppc_rcvdata;
168 static ng_disconnect_t ng_mppc_disconnect;
170 /* Helper functions */
171 static int ng_mppc_compress(node_p node,
172 struct mbuf **datap);
173 static int ng_mppc_decompress(node_p node,
174 struct mbuf **datap);
175 #ifdef NETGRAPH_MPPC_ENCRYPTION
176 static void ng_mppc_getkey(const u_char *h, u_char *h2, int len);
177 static void ng_mppc_updatekey(u_int32_t bits,
178 u_char *key0, u_char *key, struct rc4_state *rc4);
180 static void ng_mppc_reset_req(node_p node);
182 /* Node type descriptor */
183 static struct ng_type ng_mppc_typestruct = {
184 .version = NG_ABI_VERSION,
185 .name = NG_MPPC_NODE_TYPE,
186 .constructor = ng_mppc_constructor,
187 .rcvmsg = ng_mppc_rcvmsg,
188 .shutdown = ng_mppc_shutdown,
189 .newhook = ng_mppc_newhook,
190 .rcvdata = ng_mppc_rcvdata,
191 .disconnect = ng_mppc_disconnect,
193 NETGRAPH_INIT(mppc, &ng_mppc_typestruct);
195 #ifdef NETGRAPH_MPPC_ENCRYPTION
196 /* Depend on separate rc4 module */
197 MODULE_DEPEND(ng_mppc, rc4, 1, 1, 1);
200 /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
201 static const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e };
203 #define ERROUT(x) do { error = (x); goto done; } while (0)
205 /************************************************************************
207 ************************************************************************/
210 * Node type constructor
213 ng_mppc_constructor(node_p node)
217 /* Allocate private structure */
218 priv = malloc(sizeof(*priv), M_NETGRAPH_MPPC, M_WAITOK | M_ZERO);
220 NG_NODE_SET_PRIVATE(node, priv);
222 /* This node is not thread safe. */
223 NG_NODE_FORCE_WRITER(node);
230 * Give our OK for a hook to be added
233 ng_mppc_newhook(node_p node, hook_p hook, const char *name)
235 const priv_p priv = NG_NODE_PRIVATE(node);
238 /* Check hook name */
239 if (strcmp(name, NG_MPPC_HOOK_COMP) == 0)
240 hookPtr = &priv->xmit.hook;
241 else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0)
242 hookPtr = &priv->recv.hook;
246 /* See if already connected */
247 if (*hookPtr != NULL)
256 * Receive a control message
259 ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook)
261 const priv_p priv = NG_NODE_PRIVATE(node);
262 struct ng_mesg *resp = NULL;
266 NGI_GET_MSG(item, msg);
267 switch (msg->header.typecookie) {
268 case NGM_MPPC_COOKIE:
269 switch (msg->header.cmd) {
270 case NGM_MPPC_CONFIG_COMP:
271 case NGM_MPPC_CONFIG_DECOMP:
273 struct ng_mppc_config *const cfg
274 = (struct ng_mppc_config *)msg->data;
276 msg->header.cmd == NGM_MPPC_CONFIG_COMP;
277 struct ng_mppc_dir *const d = isComp ?
278 &priv->xmit : &priv->recv;
280 /* Check configuration */
281 if (msg->header.arglen != sizeof(*cfg))
284 if ((cfg->bits & ~MPPC_VALID_BITS) != 0)
286 #ifndef NETGRAPH_MPPC_COMPRESSION
287 if ((cfg->bits & MPPC_BIT) != 0)
288 ERROUT(EPROTONOSUPPORT);
290 #ifndef NETGRAPH_MPPC_ENCRYPTION
291 if ((cfg->bits & MPPE_BITS) != 0)
292 ERROUT(EPROTONOSUPPORT);
297 /* Save return address so we can send reset-req's */
299 priv->ctrlnode = NGI_RETADDR(item);
301 /* Configuration is OK, reset to it */
304 #ifdef NETGRAPH_MPPC_COMPRESSION
305 /* Initialize state buffers for compression */
306 if (d->history != NULL) {
307 free(d->history, M_NETGRAPH_MPPC);
310 if ((cfg->bits & MPPC_BIT) != 0) {
311 d->history = malloc(isComp ?
312 MPPC_SizeOfCompressionHistory() :
313 MPPC_SizeOfDecompressionHistory(),
314 M_NETGRAPH_MPPC, M_NOWAIT);
315 if (d->history == NULL)
318 MPPC_InitCompressionHistory(d->history);
320 MPPC_InitDecompressionHistory(
326 #ifdef NETGRAPH_MPPC_ENCRYPTION
327 /* Generate initial session keys for encryption */
328 if ((cfg->bits & MPPE_BITS) != 0) {
329 const int keylen = KEYLEN(cfg->bits);
331 bcopy(cfg->startkey, d->key, keylen);
332 ng_mppc_getkey(cfg->startkey, d->key, keylen);
333 if ((cfg->bits & MPPE_40) != 0)
334 bcopy(&ng_mppe_weakenkey, d->key, 3);
335 else if ((cfg->bits & MPPE_56) != 0)
336 bcopy(&ng_mppe_weakenkey, d->key, 1);
337 rc4_init(&d->rc4, d->key, keylen);
341 /* Initialize other state */
347 case NGM_MPPC_RESETREQ:
348 ng_mppc_reset_req(node);
361 NG_RESPOND_MSG(error, node, item, resp);
367 * Receive incoming data on our hook.
370 ng_mppc_rcvdata(hook_p hook, item_p item)
372 const node_p node = NG_HOOK_NODE(hook);
373 const priv_p priv = NG_NODE_PRIVATE(node);
378 /* Compress and/or encrypt */
379 if (hook == priv->xmit.hook) {
380 if (!priv->xmit.cfg.enable) {
385 if ((error = ng_mppc_compress(node, &m)) != 0) {
389 NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m);
393 /* Decompress and/or decrypt */
394 if (hook == priv->recv.hook) {
395 if (!priv->recv.cfg.enable) {
400 if ((error = ng_mppc_decompress(node, &m)) != 0) {
402 if (error == EINVAL && priv->ctrlnode != 0) {
405 /* Need to send a reset-request */
406 NG_MKMESSAGE(msg, NGM_MPPC_COOKIE,
407 NGM_MPPC_RESETREQ, 0, M_NOWAIT);
410 NG_SEND_MSG_ID(error, node, msg,
415 NG_FWD_NEW_DATA(error, item, priv->recv.hook, m);
420 panic("%s: unknown hook", __func__);
427 ng_mppc_shutdown(node_p node)
429 const priv_p priv = NG_NODE_PRIVATE(node);
431 /* Take down netgraph node */
432 #ifdef NETGRAPH_MPPC_COMPRESSION
433 if (priv->xmit.history != NULL)
434 free(priv->xmit.history, M_NETGRAPH_MPPC);
435 if (priv->recv.history != NULL)
436 free(priv->recv.history, M_NETGRAPH_MPPC);
438 bzero(priv, sizeof(*priv));
439 free(priv, M_NETGRAPH_MPPC);
440 NG_NODE_SET_PRIVATE(node, NULL);
441 NG_NODE_UNREF(node); /* let the node escape */
449 ng_mppc_disconnect(hook_p hook)
451 const node_p node = NG_HOOK_NODE(hook);
452 const priv_p priv = NG_NODE_PRIVATE(node);
454 /* Zero out hook pointer */
455 if (hook == priv->xmit.hook)
456 priv->xmit.hook = NULL;
457 if (hook == priv->recv.hook)
458 priv->recv.hook = NULL;
460 /* Go away if no longer connected */
461 if ((NG_NODE_NUMHOOKS(node) == 0)
462 && NG_NODE_IS_VALID(node))
463 ng_rmnode_self(node);
467 /************************************************************************
469 ************************************************************************/
472 * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
473 * The original mbuf is not free'd.
476 ng_mppc_compress(node_p node, struct mbuf **datap)
478 const priv_p priv = NG_NODE_PRIVATE(node);
479 struct ng_mppc_dir *const d = &priv->xmit;
481 struct mbuf *m = *datap;
483 /* We must own the mbuf chain exclusively to modify it. */
484 m = m_unshare(m, M_NOWAIT);
491 /* Always set the flushed bit in stateless mode */
492 if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) {
493 header |= MPPC_FLAG_FLUSHED;
497 /* Compress packet (if compression enabled) */
498 #ifdef NETGRAPH_MPPC_COMPRESSION
499 if ((d->cfg.bits & MPPC_BIT) != 0) {
500 u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS;
501 u_char *inbuf, *outbuf;
502 int outlen, inlen, ina;
503 u_char *source, *dest;
504 u_long sourceCnt, destCnt;
507 /* Work with contiguous regions of memory. */
508 inlen = m->m_pkthdr.len;
509 if (m->m_next == NULL) {
510 inbuf = mtod(m, u_char *);
513 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
516 m_copydata(m, 0, inlen, (caddr_t)inbuf);
520 outlen = MPPC_MAX_BLOWUP(inlen);
521 outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT);
522 if (outbuf == NULL) {
524 free(inbuf, M_NETGRAPH_MPPC);
527 MPPC_InitCompressionHistory(d->history);
532 /* Prepare to compress */
537 if ((d->cfg.bits & MPPE_STATELESS) == 0)
538 flags |= MPPC_SAVE_HISTORY;
541 rtn = MPPC_Compress(&source, &dest, &sourceCnt,
542 &destCnt, d->history, flags, 0);
544 /* Check return value */
545 /* KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); */
546 if ((rtn & MPPC_EXPANDED) == 0
547 && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) {
549 header |= MPPC_FLAG_COMPRESSED;
550 if ((rtn & MPPC_RESTART_HISTORY) != 0)
551 header |= MPPC_FLAG_RESTART;
553 /* Replace m by the compresed one. */
554 m_copyback(m, 0, outlen, (caddr_t)outbuf);
555 if (m->m_pkthdr.len < outlen) {
558 } else if (outlen < m->m_pkthdr.len)
559 m_adj(m, outlen - m->m_pkthdr.len);
561 d->flushed = (rtn & MPPC_EXPANDED) != 0
562 || (flags & MPPC_SAVE_HISTORY) == 0;
565 free(inbuf, M_NETGRAPH_MPPC);
566 free(outbuf, M_NETGRAPH_MPPC);
568 /* Check mbuf chain reload result. */
571 MPPC_InitCompressionHistory(d->history);
579 /* Now encrypt packet (if encryption enabled) */
580 #ifdef NETGRAPH_MPPC_ENCRYPTION
581 if ((d->cfg.bits & MPPE_BITS) != 0) {
584 /* Set header bits */
585 header |= MPPC_FLAG_ENCRYPTED;
587 /* Update key if it's time */
588 if ((d->cfg.bits & MPPE_STATELESS) != 0
589 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
590 ng_mppc_updatekey(d->cfg.bits,
591 d->cfg.startkey, d->key, &d->rc4);
592 } else if ((header & MPPC_FLAG_FLUSHED) != 0) {
593 /* Need to reset key if we say we did
594 and ng_mppc_updatekey wasn't called to do it also. */
595 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
601 rc4_crypt(&d->rc4, mtod(m1, u_char *),
602 mtod(m1, u_char *), m1->m_len);
608 /* Update coherency count for next time (12 bit arithmetic) */
609 MPPC_CCOUNT_INC(d->cc);
612 M_PREPEND(m, MPPC_HDRLEN, M_NOWAIT);
614 be16enc(mtod(m, void *), header);
617 return (*datap == NULL ? ENOBUFS : 0);
621 * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
622 * The original mbuf is not free'd.
625 ng_mppc_decompress(node_p node, struct mbuf **datap)
627 const priv_p priv = NG_NODE_PRIVATE(node);
628 struct ng_mppc_dir *const d = &priv->recv;
629 u_int16_t header, cc;
631 struct mbuf *m = *datap;
633 /* We must own the mbuf chain exclusively to modify it. */
634 m = m_unshare(m, M_NOWAIT);
638 /* Pull off header */
639 if (m->m_pkthdr.len < MPPC_HDRLEN) {
643 header = be16dec(mtod(m, void *));
644 cc = (header & MPPC_CCOUNT_MASK);
645 m_adj(m, MPPC_HDRLEN);
647 /* Check for an unexpected jump in the sequence number */
648 numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK);
650 /* If flushed bit set, we can always handle packet */
651 if ((header & MPPC_FLAG_FLUSHED) != 0) {
652 #ifdef NETGRAPH_MPPC_COMPRESSION
653 if (d->history != NULL)
654 MPPC_InitDecompressionHistory(d->history);
656 #ifdef NETGRAPH_MPPC_ENCRYPTION
657 if ((d->cfg.bits & MPPE_BITS) != 0) {
660 /* How many times are we going to have to re-key? */
661 rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ?
662 numLost : (numLost / (MPPE_UPDATE_MASK + 1));
663 if (rekey > mppe_max_rekey) {
664 if (mppe_block_on_max_rekey) {
665 if (mppe_log_max_rekey) {
666 log(LOG_ERR, "%s: too many (%d) packets"
667 " dropped, disabling node %p!\n",
668 __func__, numLost, node);
670 priv->recv.cfg.enable = 0;
673 if (mppe_log_max_rekey) {
674 log(LOG_ERR, "%s: %d packets"
675 " dropped, node %p\n",
676 __func__, numLost, node);
682 /* Re-key as necessary to catch up to peer */
683 while (d->cc != cc) {
684 if ((d->cfg.bits & MPPE_STATELESS) != 0
685 || (d->cc & MPPE_UPDATE_MASK)
686 == MPPE_UPDATE_FLAG) {
687 ng_mppc_updatekey(d->cfg.bits,
688 d->cfg.startkey, d->key, &d->rc4);
690 MPPC_CCOUNT_INC(d->cc);
693 /* Reset key (except in stateless mode, see below) */
694 if ((d->cfg.bits & MPPE_STATELESS) == 0)
695 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
698 d->cc = cc; /* skip over lost seq numbers */
699 numLost = 0; /* act like no packets were lost */
702 /* Can't decode non-sequential packets without a flushed bit */
707 if ((header & MPPC_FLAG_ENCRYPTED) != 0) {
708 #ifdef NETGRAPH_MPPC_ENCRYPTION
712 /* Are we not expecting encryption? */
713 if ((d->cfg.bits & MPPE_BITS) == 0) {
714 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
715 __func__, "encrypted");
719 #ifdef NETGRAPH_MPPC_ENCRYPTION
720 /* Update key if it's time (always in stateless mode) */
721 if ((d->cfg.bits & MPPE_STATELESS) != 0
722 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
723 ng_mppc_updatekey(d->cfg.bits,
724 d->cfg.startkey, d->key, &d->rc4);
730 rc4_crypt(&d->rc4, mtod(m1, u_char *),
731 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);