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 /* XXX NETGRAPH_MPPC_COMPRESSION isn't functional yet */
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 MALLOC_DEFINE(M_NETGRAPH_MPPC, "netgraph_mppc", "netgraph mppc node ");
80 #define M_NETGRAPH_MPPC M_NETGRAPH
83 #ifdef NETGRAPH_MPPC_COMPRESSION
84 /* XXX this file doesn't exist yet, but hopefully someday it will... */
87 #ifdef NETGRAPH_MPPC_ENCRYPTION
88 #include <crypto/rc4/rc4.h>
90 #include <crypto/sha1.h>
92 /* Decompression blowup */
93 #define MPPC_DECOMP_BUFSIZE 8092 /* allocate buffer this big */
94 #define MPPC_DECOMP_SAFETY 100 /* plus this much margin */
96 /* MPPC/MPPE header length */
100 #define KEYLEN(b) (((b) & MPPE_128) ? 16 : 8)
103 * When packets are lost with MPPE, we may have to re-key arbitrarily
104 * many times to 'catch up' to the new jumped-ahead sequence number.
105 * Since this can be expensive, we pose a limit on how many re-keyings
106 * we will do at one time to avoid a possible D.O.S. vulnerability.
107 * This should instead be a configurable parameter.
109 #define MPPE_MAX_REKEY 1000
111 SYSCTL_NODE(_net_graph, OID_AUTO, mppe, CTLFLAG_RW, 0, "MPPE");
113 static int mppe_block_on_max_rekey = 0;
114 TUNABLE_INT("net.graph.mppe.block_on_max_rekey", &mppe_block_on_max_rekey);
115 SYSCTL_INT(_net_graph_mppe, OID_AUTO, block_on_max_rekey, CTLFLAG_RW,
116 &mppe_block_on_max_rekey, 0, "Block node on max MPPE key re-calculations");
118 static int mppe_log_max_rekey = 1;
119 TUNABLE_INT("net.graph.mppe.log_max_rekey", &mppe_log_max_rekey);
120 SYSCTL_INT(_net_graph_mppe, OID_AUTO, log_max_rekey, CTLFLAG_RW,
121 &mppe_log_max_rekey, 0, "Log max MPPE key re-calculations event");
123 static int mppe_max_rekey = MPPE_MAX_REKEY;
124 TUNABLE_INT("net.graph.mppe.max_rekey", &mppe_max_rekey);
125 SYSCTL_INT(_net_graph_mppe, OID_AUTO, max_rekey, CTLFLAG_RW,
126 &mppe_max_rekey, 0, "Maximum number of MPPE key re-calculations");
128 /* MPPC packet header bits */
129 #define MPPC_FLAG_FLUSHED 0x8000 /* xmitter reset state */
130 #define MPPC_FLAG_RESTART 0x4000 /* compress history restart */
131 #define MPPC_FLAG_COMPRESSED 0x2000 /* packet is compresed */
132 #define MPPC_FLAG_ENCRYPTED 0x1000 /* packet is encrypted */
133 #define MPPC_CCOUNT_MASK 0x0fff /* sequence number mask */
135 #define MPPC_CCOUNT_INC(d) ((d) = (((d) + 1) & MPPC_CCOUNT_MASK))
137 #define MPPE_UPDATE_MASK 0xff /* coherency count when we're */
138 #define MPPE_UPDATE_FLAG 0xff /* supposed to update key */
140 #define MPPC_COMP_OK 0x05
141 #define MPPC_DECOMP_OK 0x05
143 /* Per direction info */
145 struct ng_mppc_config cfg; /* configuration */
146 hook_p hook; /* netgraph hook */
147 u_int16_t cc:12; /* coherency count */
148 u_char flushed; /* clean history (xmit only) */
149 #ifdef NETGRAPH_MPPC_COMPRESSION
150 u_char *history; /* compression history */
152 #ifdef NETGRAPH_MPPC_ENCRYPTION
153 u_char key[MPPE_KEY_LEN]; /* session key */
154 struct rc4_state rc4; /* rc4 state */
158 /* Node private data */
159 struct ng_mppc_private {
160 struct ng_mppc_dir xmit; /* compress/encrypt config */
161 struct ng_mppc_dir recv; /* decompress/decrypt config */
162 ng_ID_t ctrlnode; /* path to controlling node */
164 typedef struct ng_mppc_private *priv_p;
166 /* Netgraph node methods */
167 static ng_constructor_t ng_mppc_constructor;
168 static ng_rcvmsg_t ng_mppc_rcvmsg;
169 static ng_shutdown_t ng_mppc_shutdown;
170 static ng_newhook_t ng_mppc_newhook;
171 static ng_rcvdata_t ng_mppc_rcvdata;
172 static ng_disconnect_t ng_mppc_disconnect;
174 /* Helper functions */
175 static int ng_mppc_compress(node_p node,
176 struct mbuf **datap);
177 static int ng_mppc_decompress(node_p node,
178 struct mbuf **datap);
179 #ifdef NETGRAPH_MPPC_ENCRYPTION
180 static void ng_mppc_getkey(const u_char *h, u_char *h2, int len);
181 static void ng_mppc_updatekey(u_int32_t bits,
182 u_char *key0, u_char *key, struct rc4_state *rc4);
184 static void ng_mppc_reset_req(node_p node);
186 /* Node type descriptor */
187 static struct ng_type ng_mppc_typestruct = {
188 .version = NG_ABI_VERSION,
189 .name = NG_MPPC_NODE_TYPE,
190 .constructor = ng_mppc_constructor,
191 .rcvmsg = ng_mppc_rcvmsg,
192 .shutdown = ng_mppc_shutdown,
193 .newhook = ng_mppc_newhook,
194 .rcvdata = ng_mppc_rcvdata,
195 .disconnect = ng_mppc_disconnect,
197 NETGRAPH_INIT(mppc, &ng_mppc_typestruct);
199 #ifdef NETGRAPH_MPPC_ENCRYPTION
200 /* Depend on separate rc4 module */
201 MODULE_DEPEND(ng_mppc, rc4, 1, 1, 1);
204 /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
205 static const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e };
207 #define ERROUT(x) do { error = (x); goto done; } while (0)
209 /************************************************************************
211 ************************************************************************/
214 * Node type constructor
217 ng_mppc_constructor(node_p node)
221 /* Allocate private structure */
222 priv = malloc(sizeof(*priv), M_NETGRAPH_MPPC, M_NOWAIT | M_ZERO);
226 NG_NODE_SET_PRIVATE(node, priv);
228 /* This node is not thread safe. */
229 NG_NODE_FORCE_WRITER(node);
236 * Give our OK for a hook to be added
239 ng_mppc_newhook(node_p node, hook_p hook, const char *name)
241 const priv_p priv = NG_NODE_PRIVATE(node);
244 /* Check hook name */
245 if (strcmp(name, NG_MPPC_HOOK_COMP) == 0)
246 hookPtr = &priv->xmit.hook;
247 else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0)
248 hookPtr = &priv->recv.hook;
252 /* See if already connected */
253 if (*hookPtr != NULL)
262 * Receive a control message
265 ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook)
267 const priv_p priv = NG_NODE_PRIVATE(node);
268 struct ng_mesg *resp = NULL;
272 NGI_GET_MSG(item, msg);
273 switch (msg->header.typecookie) {
274 case NGM_MPPC_COOKIE:
275 switch (msg->header.cmd) {
276 case NGM_MPPC_CONFIG_COMP:
277 case NGM_MPPC_CONFIG_DECOMP:
279 struct ng_mppc_config *const cfg
280 = (struct ng_mppc_config *)msg->data;
282 msg->header.cmd == NGM_MPPC_CONFIG_COMP;
283 struct ng_mppc_dir *const d = isComp ?
284 &priv->xmit : &priv->recv;
286 /* Check configuration */
287 if (msg->header.arglen != sizeof(*cfg))
290 if ((cfg->bits & ~MPPC_VALID_BITS) != 0)
292 #ifndef NETGRAPH_MPPC_COMPRESSION
293 if ((cfg->bits & MPPC_BIT) != 0)
294 ERROUT(EPROTONOSUPPORT);
296 #ifndef NETGRAPH_MPPC_ENCRYPTION
297 if ((cfg->bits & MPPE_BITS) != 0)
298 ERROUT(EPROTONOSUPPORT);
303 /* Save return address so we can send reset-req's */
305 priv->ctrlnode = NGI_RETADDR(item);
307 /* Configuration is OK, reset to it */
310 #ifdef NETGRAPH_MPPC_COMPRESSION
311 /* Initialize state buffers for compression */
312 if (d->history != NULL) {
313 free(d->history, M_NETGRAPH_MPPC);
316 if ((cfg->bits & MPPC_BIT) != 0) {
317 d->history = malloc(isComp ?
318 MPPC_SizeOfCompressionHistory() :
319 MPPC_SizeOfDecompressionHistory(),
320 M_NETGRAPH_MPPC, M_NOWAIT);
321 if (d->history == NULL)
324 MPPC_InitCompressionHistory(d->history);
326 MPPC_InitDecompressionHistory(
332 #ifdef NETGRAPH_MPPC_ENCRYPTION
333 /* Generate initial session keys for encryption */
334 if ((cfg->bits & MPPE_BITS) != 0) {
335 const int keylen = KEYLEN(cfg->bits);
337 bcopy(cfg->startkey, d->key, keylen);
338 ng_mppc_getkey(cfg->startkey, d->key, keylen);
339 if ((cfg->bits & MPPE_40) != 0)
340 bcopy(&ng_mppe_weakenkey, d->key, 3);
341 else if ((cfg->bits & MPPE_56) != 0)
342 bcopy(&ng_mppe_weakenkey, d->key, 1);
343 rc4_init(&d->rc4, d->key, keylen);
347 /* Initialize other state */
353 case NGM_MPPC_RESETREQ:
354 ng_mppc_reset_req(node);
367 NG_RESPOND_MSG(error, node, item, resp);
373 * Receive incoming data on our hook.
376 ng_mppc_rcvdata(hook_p hook, item_p item)
378 const node_p node = NG_HOOK_NODE(hook);
379 const priv_p priv = NG_NODE_PRIVATE(node);
384 /* Compress and/or encrypt */
385 if (hook == priv->xmit.hook) {
386 if (!priv->xmit.cfg.enable) {
391 if ((error = ng_mppc_compress(node, &m)) != 0) {
395 NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m);
399 /* Decompress and/or decrypt */
400 if (hook == priv->recv.hook) {
401 if (!priv->recv.cfg.enable) {
406 if ((error = ng_mppc_decompress(node, &m)) != 0) {
408 if (error == EINVAL && priv->ctrlnode != 0) {
411 /* Need to send a reset-request */
412 NG_MKMESSAGE(msg, NGM_MPPC_COOKIE,
413 NGM_MPPC_RESETREQ, 0, M_NOWAIT);
416 NG_SEND_MSG_ID(error, node, msg,
421 NG_FWD_NEW_DATA(error, item, priv->recv.hook, m);
426 panic("%s: unknown hook", __func__);
427 #ifdef RESTARTABLE_PANICS
436 ng_mppc_shutdown(node_p node)
438 const priv_p priv = NG_NODE_PRIVATE(node);
440 /* Take down netgraph node */
441 #ifdef NETGRAPH_MPPC_COMPRESSION
442 if (priv->xmit.history != NULL)
443 free(priv->xmit.history, M_NETGRAPH_MPPC);
444 if (priv->recv.history != NULL)
445 free(priv->recv.history, M_NETGRAPH_MPPC);
447 bzero(priv, sizeof(*priv));
448 free(priv, M_NETGRAPH_MPPC);
449 NG_NODE_SET_PRIVATE(node, NULL);
450 NG_NODE_UNREF(node); /* let the node escape */
458 ng_mppc_disconnect(hook_p hook)
460 const node_p node = NG_HOOK_NODE(hook);
461 const priv_p priv = NG_NODE_PRIVATE(node);
463 /* Zero out hook pointer */
464 if (hook == priv->xmit.hook)
465 priv->xmit.hook = NULL;
466 if (hook == priv->recv.hook)
467 priv->recv.hook = NULL;
469 /* Go away if no longer connected */
470 if ((NG_NODE_NUMHOOKS(node) == 0)
471 && NG_NODE_IS_VALID(node))
472 ng_rmnode_self(node);
476 /************************************************************************
478 ************************************************************************/
481 * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
482 * The original mbuf is not free'd.
485 ng_mppc_compress(node_p node, struct mbuf **datap)
487 const priv_p priv = NG_NODE_PRIVATE(node);
488 struct ng_mppc_dir *const d = &priv->xmit;
490 struct mbuf *m = *datap;
492 /* We must own the mbuf chain exclusively to modify it. */
493 m = m_unshare(m, M_DONTWAIT);
500 /* Always set the flushed bit in stateless mode */
501 if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) {
502 header |= MPPC_FLAG_FLUSHED;
506 /* Compress packet (if compression enabled) */
507 #ifdef NETGRAPH_MPPC_COMPRESSION
508 if ((d->cfg.bits & MPPC_BIT) != 0) {
509 u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS;
510 u_char *inbuf, *outbuf;
511 int outlen, inlen, ina;
512 u_char *source, *dest;
513 u_long sourceCnt, destCnt;
516 /* Work with contiguous regions of memory. */
517 inlen = m->m_pkthdr.len;
518 if (m->m_next == NULL) {
519 inbuf = mtod(m, u_char *);
522 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
525 m_copydata(m, 0, inlen, (caddr_t)inbuf);
529 outlen = MPPC_MAX_BLOWUP(inlen);
530 outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT);
531 if (outbuf == NULL) {
533 free(inbuf, M_NETGRAPH_MPPC);
536 MPPC_InitCompressionHistory(d->history);
541 /* Prepare to compress */
546 if ((d->cfg.bits & MPPE_STATELESS) == 0)
547 flags |= MPPC_SAVE_HISTORY;
550 rtn = MPPC_Compress(&source, &dest, &sourceCnt,
551 &destCnt, d->history, flags, 0);
553 /* Check return value */
554 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
555 if ((rtn & MPPC_EXPANDED) == 0
556 && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) {
558 header |= MPPC_FLAG_COMPRESSED;
559 if ((rtn & MPPC_RESTART_HISTORY) != 0)
560 header |= MPPC_FLAG_RESTART;
562 /* Replace m by the compresed one. */
563 m_copyback(m, 0, outlen, (caddr_t)outbuf);
564 if (m->m_pkthdr.len < outlen) {
567 } else if (outlen < m->m_pkthdr.len)
568 m_adj(m, outlen - m->m_pkthdr.len);
570 d->flushed = (rtn & MPPC_EXPANDED) != 0
571 || (flags & MPPC_SAVE_HISTORY) == 0;
574 free(inbuf, M_NETGRAPH_MPPC);
575 free(outbuf, M_NETGRAPH_MPPC);
577 /* Check mbuf chain reload result. */
580 MPPC_InitCompressionHistory(d->history);
588 /* Now encrypt packet (if encryption enabled) */
589 #ifdef NETGRAPH_MPPC_ENCRYPTION
590 if ((d->cfg.bits & MPPE_BITS) != 0) {
593 /* Set header bits */
594 header |= MPPC_FLAG_ENCRYPTED;
596 /* Update key if it's time */
597 if ((d->cfg.bits & MPPE_STATELESS) != 0
598 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
599 ng_mppc_updatekey(d->cfg.bits,
600 d->cfg.startkey, d->key, &d->rc4);
601 } else if ((header & MPPC_FLAG_FLUSHED) != 0) {
602 /* Need to reset key if we say we did
603 and ng_mppc_updatekey wasn't called to do it also. */
604 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
610 rc4_crypt(&d->rc4, mtod(m1, u_char *),
611 mtod(m1, u_char *), m1->m_len);
617 /* Update coherency count for next time (12 bit arithmetic) */
618 MPPC_CCOUNT_INC(d->cc);
621 M_PREPEND(m, MPPC_HDRLEN, M_DONTWAIT);
623 be16enc(mtod(m, void *), header);
626 return (*datap == NULL ? ENOBUFS : 0);
630 * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
631 * The original mbuf is not free'd.
634 ng_mppc_decompress(node_p node, struct mbuf **datap)
636 const priv_p priv = NG_NODE_PRIVATE(node);
637 struct ng_mppc_dir *const d = &priv->recv;
638 u_int16_t header, cc;
640 struct mbuf *m = *datap;
642 /* We must own the mbuf chain exclusively to modify it. */
643 m = m_unshare(m, M_DONTWAIT);
647 /* Pull off header */
648 if (m->m_pkthdr.len < MPPC_HDRLEN) {
652 header = be16dec(mtod(m, void *));
653 cc = (header & MPPC_CCOUNT_MASK);
654 m_adj(m, MPPC_HDRLEN);
656 /* Check for an unexpected jump in the sequence number */
657 numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK);
659 /* If flushed bit set, we can always handle packet */
660 if ((header & MPPC_FLAG_FLUSHED) != 0) {
661 #ifdef NETGRAPH_MPPC_COMPRESSION
662 if (d->history != NULL)
663 MPPC_InitDecompressionHistory(d->history);
665 #ifdef NETGRAPH_MPPC_ENCRYPTION
666 if ((d->cfg.bits & MPPE_BITS) != 0) {
669 /* How many times are we going to have to re-key? */
670 rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ?
671 numLost : (numLost / (MPPE_UPDATE_MASK + 1));
672 if (rekey > mppe_max_rekey) {
673 if (mppe_block_on_max_rekey) {
674 if (mppe_log_max_rekey) {
675 log(LOG_ERR, "%s: too many (%d) packets"
676 " dropped, disabling node %p!\n",
677 __func__, numLost, node);
679 priv->recv.cfg.enable = 0;
682 if (mppe_log_max_rekey) {
683 log(LOG_ERR, "%s: %d packets"
684 " dropped, node %p\n",
685 __func__, numLost, node);
691 /* Re-key as necessary to catch up to peer */
692 while (d->cc != cc) {
693 if ((d->cfg.bits & MPPE_STATELESS) != 0
694 || (d->cc & MPPE_UPDATE_MASK)
695 == MPPE_UPDATE_FLAG) {
696 ng_mppc_updatekey(d->cfg.bits,
697 d->cfg.startkey, d->key, &d->rc4);
699 MPPC_CCOUNT_INC(d->cc);
702 /* Reset key (except in stateless mode, see below) */
703 if ((d->cfg.bits & MPPE_STATELESS) == 0)
704 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
707 d->cc = cc; /* skip over lost seq numbers */
708 numLost = 0; /* act like no packets were lost */
711 /* Can't decode non-sequential packets without a flushed bit */
716 if ((header & MPPC_FLAG_ENCRYPTED) != 0) {
717 #ifdef NETGRAPH_MPPC_ENCRYPTION
721 /* Are we not expecting encryption? */
722 if ((d->cfg.bits & MPPE_BITS) == 0) {
723 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
724 __func__, "encrypted");
728 #ifdef NETGRAPH_MPPC_ENCRYPTION
729 /* Update key if it's time (always in stateless mode) */
730 if ((d->cfg.bits & MPPE_STATELESS) != 0
731 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
732 ng_mppc_updatekey(d->cfg.bits,
733 d->cfg.startkey, d->key, &d->rc4);
739 rc4_crypt(&d->rc4, mtod(m1, u_char *),
740 mtod(m1, u_char *), m1->m_len);
746 /* Are we expecting encryption? */
747 if ((d->cfg.bits & MPPE_BITS) != 0) {
748 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
749 __func__, "unencrypted");
754 /* Update coherency count for next time (12 bit arithmetic) */
755 MPPC_CCOUNT_INC(d->cc);
757 /* Check for unexpected compressed packet */
758 if ((header & MPPC_FLAG_COMPRESSED) != 0
759 && (d->cfg.bits & MPPC_BIT) == 0) {
760 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
761 __func__, "compressed");
767 #ifdef NETGRAPH_MPPC_COMPRESSION
768 /* Decompress packet */
769 if ((header & MPPC_FLAG_COMPRESSED) != 0) {
770 int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS;
771 u_char *inbuf, *outbuf;
772 int inlen, outlen, ina;
773 u_char *source, *dest;
774 u_long sourceCnt, destCnt;
777 /* Copy payload into a contiguous region of memory. */
778 inlen = m->m_pkthdr.len;
779 if (m->m_next == NULL) {
780 inbuf = mtod(m, u_char *);
783 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
788 m_copydata(m, 0, inlen, (caddr_t)inbuf);
792 /* Allocate a buffer for decompressed data */
793 outbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY,
794 M_NETGRAPH_MPPC, M_NOWAIT);
795 if (outbuf == NULL) {
798 free(inbuf, M_NETGRAPH_MPPC);
801 outlen = MPPC_DECOMP_BUFSIZE;
803 /* Prepare to decompress */
808 if ((header & MPPC_FLAG_RESTART) != 0)
809 flags |= MPPC_RESTART_HISTORY;
812 rtn = MPPC_Decompress(&source, &dest,
813 &sourceCnt, &destCnt, d->history, flags);
815 /* Check return value */
816 KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__));
817 if ((rtn & MPPC_DEST_EXHAUSTED) != 0
818 || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) {
819 log(LOG_ERR, "%s: decomp returned 0x%x",
822 free(inbuf, M_NETGRAPH_MPPC);
823 free(outbuf, M_NETGRAPH_MPPC);
827 /* Replace compressed data with decompressed data */
829 free(inbuf, M_NETGRAPH_MPPC);
832 m_copyback(m, 0, outlen, (caddr_t)outbuf);
833 if (m->m_pkthdr.len < outlen) {
836 } else if (outlen < m->m_pkthdr.len)
837 m_adj(m, outlen - m->m_pkthdr.len);
838 free(outbuf, M_NETGRAPH_MPPC);
842 /* Return result in an mbuf */
844 return (*datap == NULL ? ENOBUFS : 0);
848 * The peer has sent us a CCP ResetRequest, so reset our transmit state.
851 ng_mppc_reset_req(node_p node)
853 const priv_p priv = NG_NODE_PRIVATE(node);
854 struct ng_mppc_dir *const d = &priv->xmit;
856 #ifdef NETGRAPH_MPPC_COMPRESSION
857 if (d->history != NULL)
858 MPPC_InitCompressionHistory(d->history);
860 #ifdef NETGRAPH_MPPC_ENCRYPTION
861 if ((d->cfg.bits & MPPE_STATELESS) == 0)
862 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
867 #ifdef NETGRAPH_MPPC_ENCRYPTION
869 * Generate a new encryption key
872 ng_mppc_getkey(const u_char *h, u_char *h2, int len)
874 static const u_char pad1[40] =
875 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
876 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
877 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
878 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
879 static const u_char pad2[40] =
880 { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
881 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
882 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
883 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 };
888 SHA1Update(&c, h, len);
889 SHA1Update(&c, pad1, sizeof(pad1));
890 SHA1Update(&c, h2, len);
891 SHA1Update(&c, pad2, sizeof(pad2));
893 bcopy(hash, h2, len);
897 * Update the encryption key
900 ng_mppc_updatekey(u_int32_t bits,
901 u_char *key0, u_char *key, struct rc4_state *rc4)
903 const int keylen = KEYLEN(bits);
905 ng_mppc_getkey(key0, key, keylen);
906 rc4_init(rc4, key, keylen);
907 rc4_crypt(rc4, key, key, keylen);
908 if ((bits & MPPE_40) != 0)
909 bcopy(&ng_mppe_weakenkey, key, 3);
910 else if ((bits & MPPE_56) != 0)
911 bcopy(&ng_mppe_weakenkey, key, 1);
912 rc4_init(rc4, key, keylen);