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 TUNABLE_INT("net.graph.mppe.block_on_max_rekey", &mppe_block_on_max_rekey);
114 SYSCTL_INT(_net_graph_mppe, OID_AUTO, block_on_max_rekey, CTLFLAG_RW,
115 &mppe_block_on_max_rekey, 0, "Block node on max MPPE key re-calculations");
117 static int mppe_log_max_rekey = 1;
118 TUNABLE_INT("net.graph.mppe.log_max_rekey", &mppe_log_max_rekey);
119 SYSCTL_INT(_net_graph_mppe, OID_AUTO, log_max_rekey, CTLFLAG_RW,
120 &mppe_log_max_rekey, 0, "Log max MPPE key re-calculations event");
122 static int mppe_max_rekey = MPPE_MAX_REKEY;
123 TUNABLE_INT("net.graph.mppe.max_rekey", &mppe_max_rekey);
124 SYSCTL_INT(_net_graph_mppe, OID_AUTO, max_rekey, CTLFLAG_RW,
125 &mppe_max_rekey, 0, "Maximum number of MPPE key re-calculations");
127 /* MPPC packet header bits */
128 #define MPPC_FLAG_FLUSHED 0x8000 /* xmitter reset state */
129 #define MPPC_FLAG_RESTART 0x4000 /* compress history restart */
130 #define MPPC_FLAG_COMPRESSED 0x2000 /* packet is compresed */
131 #define MPPC_FLAG_ENCRYPTED 0x1000 /* packet is encrypted */
132 #define MPPC_CCOUNT_MASK 0x0fff /* sequence number mask */
134 #define MPPC_CCOUNT_INC(d) ((d) = (((d) + 1) & MPPC_CCOUNT_MASK))
136 #define MPPE_UPDATE_MASK 0xff /* coherency count when we're */
137 #define MPPE_UPDATE_FLAG 0xff /* supposed to update key */
139 #define MPPC_COMP_OK 0x05
140 #define MPPC_DECOMP_OK 0x05
142 /* Per direction info */
144 struct ng_mppc_config cfg; /* configuration */
145 hook_p hook; /* netgraph hook */
146 u_int16_t cc:12; /* coherency count */
147 u_char flushed; /* clean history (xmit only) */
148 #ifdef NETGRAPH_MPPC_COMPRESSION
149 u_char *history; /* compression history */
151 #ifdef NETGRAPH_MPPC_ENCRYPTION
152 u_char key[MPPE_KEY_LEN]; /* session key */
153 struct rc4_state rc4; /* rc4 state */
157 /* Node private data */
158 struct ng_mppc_private {
159 struct ng_mppc_dir xmit; /* compress/encrypt config */
160 struct ng_mppc_dir recv; /* decompress/decrypt config */
161 ng_ID_t ctrlnode; /* path to controlling node */
163 typedef struct ng_mppc_private *priv_p;
165 /* Netgraph node methods */
166 static ng_constructor_t ng_mppc_constructor;
167 static ng_rcvmsg_t ng_mppc_rcvmsg;
168 static ng_shutdown_t ng_mppc_shutdown;
169 static ng_newhook_t ng_mppc_newhook;
170 static ng_rcvdata_t ng_mppc_rcvdata;
171 static ng_disconnect_t ng_mppc_disconnect;
173 /* Helper functions */
174 static int ng_mppc_compress(node_p node,
175 struct mbuf **datap);
176 static int ng_mppc_decompress(node_p node,
177 struct mbuf **datap);
178 #ifdef NETGRAPH_MPPC_ENCRYPTION
179 static void ng_mppc_getkey(const u_char *h, u_char *h2, int len);
180 static void ng_mppc_updatekey(u_int32_t bits,
181 u_char *key0, u_char *key, struct rc4_state *rc4);
183 static void ng_mppc_reset_req(node_p node);
185 /* Node type descriptor */
186 static struct ng_type ng_mppc_typestruct = {
187 .version = NG_ABI_VERSION,
188 .name = NG_MPPC_NODE_TYPE,
189 .constructor = ng_mppc_constructor,
190 .rcvmsg = ng_mppc_rcvmsg,
191 .shutdown = ng_mppc_shutdown,
192 .newhook = ng_mppc_newhook,
193 .rcvdata = ng_mppc_rcvdata,
194 .disconnect = ng_mppc_disconnect,
196 NETGRAPH_INIT(mppc, &ng_mppc_typestruct);
198 #ifdef NETGRAPH_MPPC_ENCRYPTION
199 /* Depend on separate rc4 module */
200 MODULE_DEPEND(ng_mppc, rc4, 1, 1, 1);
203 /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
204 static const u_char ng_mppe_weakenkey[3] = { 0xd1, 0x26, 0x9e };
206 #define ERROUT(x) do { error = (x); goto done; } while (0)
208 /************************************************************************
210 ************************************************************************/
213 * Node type constructor
216 ng_mppc_constructor(node_p node)
220 /* Allocate private structure */
221 priv = malloc(sizeof(*priv), M_NETGRAPH_MPPC, M_WAITOK | M_ZERO);
223 NG_NODE_SET_PRIVATE(node, priv);
225 /* This node is not thread safe. */
226 NG_NODE_FORCE_WRITER(node);
233 * Give our OK for a hook to be added
236 ng_mppc_newhook(node_p node, hook_p hook, const char *name)
238 const priv_p priv = NG_NODE_PRIVATE(node);
241 /* Check hook name */
242 if (strcmp(name, NG_MPPC_HOOK_COMP) == 0)
243 hookPtr = &priv->xmit.hook;
244 else if (strcmp(name, NG_MPPC_HOOK_DECOMP) == 0)
245 hookPtr = &priv->recv.hook;
249 /* See if already connected */
250 if (*hookPtr != NULL)
259 * Receive a control message
262 ng_mppc_rcvmsg(node_p node, item_p item, hook_p lasthook)
264 const priv_p priv = NG_NODE_PRIVATE(node);
265 struct ng_mesg *resp = NULL;
269 NGI_GET_MSG(item, msg);
270 switch (msg->header.typecookie) {
271 case NGM_MPPC_COOKIE:
272 switch (msg->header.cmd) {
273 case NGM_MPPC_CONFIG_COMP:
274 case NGM_MPPC_CONFIG_DECOMP:
276 struct ng_mppc_config *const cfg
277 = (struct ng_mppc_config *)msg->data;
279 msg->header.cmd == NGM_MPPC_CONFIG_COMP;
280 struct ng_mppc_dir *const d = isComp ?
281 &priv->xmit : &priv->recv;
283 /* Check configuration */
284 if (msg->header.arglen != sizeof(*cfg))
287 if ((cfg->bits & ~MPPC_VALID_BITS) != 0)
289 #ifndef NETGRAPH_MPPC_COMPRESSION
290 if ((cfg->bits & MPPC_BIT) != 0)
291 ERROUT(EPROTONOSUPPORT);
293 #ifndef NETGRAPH_MPPC_ENCRYPTION
294 if ((cfg->bits & MPPE_BITS) != 0)
295 ERROUT(EPROTONOSUPPORT);
300 /* Save return address so we can send reset-req's */
302 priv->ctrlnode = NGI_RETADDR(item);
304 /* Configuration is OK, reset to it */
307 #ifdef NETGRAPH_MPPC_COMPRESSION
308 /* Initialize state buffers for compression */
309 if (d->history != NULL) {
310 free(d->history, M_NETGRAPH_MPPC);
313 if ((cfg->bits & MPPC_BIT) != 0) {
314 d->history = malloc(isComp ?
315 MPPC_SizeOfCompressionHistory() :
316 MPPC_SizeOfDecompressionHistory(),
317 M_NETGRAPH_MPPC, M_NOWAIT);
318 if (d->history == NULL)
321 MPPC_InitCompressionHistory(d->history);
323 MPPC_InitDecompressionHistory(
329 #ifdef NETGRAPH_MPPC_ENCRYPTION
330 /* Generate initial session keys for encryption */
331 if ((cfg->bits & MPPE_BITS) != 0) {
332 const int keylen = KEYLEN(cfg->bits);
334 bcopy(cfg->startkey, d->key, keylen);
335 ng_mppc_getkey(cfg->startkey, d->key, keylen);
336 if ((cfg->bits & MPPE_40) != 0)
337 bcopy(&ng_mppe_weakenkey, d->key, 3);
338 else if ((cfg->bits & MPPE_56) != 0)
339 bcopy(&ng_mppe_weakenkey, d->key, 1);
340 rc4_init(&d->rc4, d->key, keylen);
344 /* Initialize other state */
350 case NGM_MPPC_RESETREQ:
351 ng_mppc_reset_req(node);
364 NG_RESPOND_MSG(error, node, item, resp);
370 * Receive incoming data on our hook.
373 ng_mppc_rcvdata(hook_p hook, item_p item)
375 const node_p node = NG_HOOK_NODE(hook);
376 const priv_p priv = NG_NODE_PRIVATE(node);
381 /* Compress and/or encrypt */
382 if (hook == priv->xmit.hook) {
383 if (!priv->xmit.cfg.enable) {
388 if ((error = ng_mppc_compress(node, &m)) != 0) {
392 NG_FWD_NEW_DATA(error, item, priv->xmit.hook, m);
396 /* Decompress and/or decrypt */
397 if (hook == priv->recv.hook) {
398 if (!priv->recv.cfg.enable) {
403 if ((error = ng_mppc_decompress(node, &m)) != 0) {
405 if (error == EINVAL && priv->ctrlnode != 0) {
408 /* Need to send a reset-request */
409 NG_MKMESSAGE(msg, NGM_MPPC_COOKIE,
410 NGM_MPPC_RESETREQ, 0, M_NOWAIT);
413 NG_SEND_MSG_ID(error, node, msg,
418 NG_FWD_NEW_DATA(error, item, priv->recv.hook, m);
423 panic("%s: unknown hook", __func__);
430 ng_mppc_shutdown(node_p node)
432 const priv_p priv = NG_NODE_PRIVATE(node);
434 /* Take down netgraph node */
435 #ifdef NETGRAPH_MPPC_COMPRESSION
436 if (priv->xmit.history != NULL)
437 free(priv->xmit.history, M_NETGRAPH_MPPC);
438 if (priv->recv.history != NULL)
439 free(priv->recv.history, M_NETGRAPH_MPPC);
441 bzero(priv, sizeof(*priv));
442 free(priv, M_NETGRAPH_MPPC);
443 NG_NODE_SET_PRIVATE(node, NULL);
444 NG_NODE_UNREF(node); /* let the node escape */
452 ng_mppc_disconnect(hook_p hook)
454 const node_p node = NG_HOOK_NODE(hook);
455 const priv_p priv = NG_NODE_PRIVATE(node);
457 /* Zero out hook pointer */
458 if (hook == priv->xmit.hook)
459 priv->xmit.hook = NULL;
460 if (hook == priv->recv.hook)
461 priv->recv.hook = NULL;
463 /* Go away if no longer connected */
464 if ((NG_NODE_NUMHOOKS(node) == 0)
465 && NG_NODE_IS_VALID(node))
466 ng_rmnode_self(node);
470 /************************************************************************
472 ************************************************************************/
475 * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
476 * The original mbuf is not free'd.
479 ng_mppc_compress(node_p node, struct mbuf **datap)
481 const priv_p priv = NG_NODE_PRIVATE(node);
482 struct ng_mppc_dir *const d = &priv->xmit;
484 struct mbuf *m = *datap;
486 /* We must own the mbuf chain exclusively to modify it. */
487 m = m_unshare(m, M_NOWAIT);
494 /* Always set the flushed bit in stateless mode */
495 if (d->flushed || ((d->cfg.bits & MPPE_STATELESS) != 0)) {
496 header |= MPPC_FLAG_FLUSHED;
500 /* Compress packet (if compression enabled) */
501 #ifdef NETGRAPH_MPPC_COMPRESSION
502 if ((d->cfg.bits & MPPC_BIT) != 0) {
503 u_short flags = MPPC_MANDATORY_COMPRESS_FLAGS;
504 u_char *inbuf, *outbuf;
505 int outlen, inlen, ina;
506 u_char *source, *dest;
507 u_long sourceCnt, destCnt;
510 /* Work with contiguous regions of memory. */
511 inlen = m->m_pkthdr.len;
512 if (m->m_next == NULL) {
513 inbuf = mtod(m, u_char *);
516 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
519 m_copydata(m, 0, inlen, (caddr_t)inbuf);
523 outlen = MPPC_MAX_BLOWUP(inlen);
524 outbuf = malloc(outlen, M_NETGRAPH_MPPC, M_NOWAIT);
525 if (outbuf == NULL) {
527 free(inbuf, M_NETGRAPH_MPPC);
530 MPPC_InitCompressionHistory(d->history);
535 /* Prepare to compress */
540 if ((d->cfg.bits & MPPE_STATELESS) == 0)
541 flags |= MPPC_SAVE_HISTORY;
544 rtn = MPPC_Compress(&source, &dest, &sourceCnt,
545 &destCnt, d->history, flags, 0);
547 /* Check return value */
548 /* KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); */
549 if ((rtn & MPPC_EXPANDED) == 0
550 && (rtn & MPPC_COMP_OK) == MPPC_COMP_OK) {
552 header |= MPPC_FLAG_COMPRESSED;
553 if ((rtn & MPPC_RESTART_HISTORY) != 0)
554 header |= MPPC_FLAG_RESTART;
556 /* Replace m by the compresed one. */
557 m_copyback(m, 0, outlen, (caddr_t)outbuf);
558 if (m->m_pkthdr.len < outlen) {
561 } else if (outlen < m->m_pkthdr.len)
562 m_adj(m, outlen - m->m_pkthdr.len);
564 d->flushed = (rtn & MPPC_EXPANDED) != 0
565 || (flags & MPPC_SAVE_HISTORY) == 0;
568 free(inbuf, M_NETGRAPH_MPPC);
569 free(outbuf, M_NETGRAPH_MPPC);
571 /* Check mbuf chain reload result. */
574 MPPC_InitCompressionHistory(d->history);
582 /* Now encrypt packet (if encryption enabled) */
583 #ifdef NETGRAPH_MPPC_ENCRYPTION
584 if ((d->cfg.bits & MPPE_BITS) != 0) {
587 /* Set header bits */
588 header |= MPPC_FLAG_ENCRYPTED;
590 /* Update key if it's time */
591 if ((d->cfg.bits & MPPE_STATELESS) != 0
592 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
593 ng_mppc_updatekey(d->cfg.bits,
594 d->cfg.startkey, d->key, &d->rc4);
595 } else if ((header & MPPC_FLAG_FLUSHED) != 0) {
596 /* Need to reset key if we say we did
597 and ng_mppc_updatekey wasn't called to do it also. */
598 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
604 rc4_crypt(&d->rc4, mtod(m1, u_char *),
605 mtod(m1, u_char *), m1->m_len);
611 /* Update coherency count for next time (12 bit arithmetic) */
612 MPPC_CCOUNT_INC(d->cc);
615 M_PREPEND(m, MPPC_HDRLEN, M_NOWAIT);
617 be16enc(mtod(m, void *), header);
620 return (*datap == NULL ? ENOBUFS : 0);
624 * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
625 * The original mbuf is not free'd.
628 ng_mppc_decompress(node_p node, struct mbuf **datap)
630 const priv_p priv = NG_NODE_PRIVATE(node);
631 struct ng_mppc_dir *const d = &priv->recv;
632 u_int16_t header, cc;
634 struct mbuf *m = *datap;
636 /* We must own the mbuf chain exclusively to modify it. */
637 m = m_unshare(m, M_NOWAIT);
641 /* Pull off header */
642 if (m->m_pkthdr.len < MPPC_HDRLEN) {
646 header = be16dec(mtod(m, void *));
647 cc = (header & MPPC_CCOUNT_MASK);
648 m_adj(m, MPPC_HDRLEN);
650 /* Check for an unexpected jump in the sequence number */
651 numLost = ((cc - d->cc) & MPPC_CCOUNT_MASK);
653 /* If flushed bit set, we can always handle packet */
654 if ((header & MPPC_FLAG_FLUSHED) != 0) {
655 #ifdef NETGRAPH_MPPC_COMPRESSION
656 if (d->history != NULL)
657 MPPC_InitDecompressionHistory(d->history);
659 #ifdef NETGRAPH_MPPC_ENCRYPTION
660 if ((d->cfg.bits & MPPE_BITS) != 0) {
663 /* How many times are we going to have to re-key? */
664 rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ?
665 numLost : (numLost / (MPPE_UPDATE_MASK + 1));
666 if (rekey > mppe_max_rekey) {
667 if (mppe_block_on_max_rekey) {
668 if (mppe_log_max_rekey) {
669 log(LOG_ERR, "%s: too many (%d) packets"
670 " dropped, disabling node %p!\n",
671 __func__, numLost, node);
673 priv->recv.cfg.enable = 0;
676 if (mppe_log_max_rekey) {
677 log(LOG_ERR, "%s: %d packets"
678 " dropped, node %p\n",
679 __func__, numLost, node);
685 /* Re-key as necessary to catch up to peer */
686 while (d->cc != cc) {
687 if ((d->cfg.bits & MPPE_STATELESS) != 0
688 || (d->cc & MPPE_UPDATE_MASK)
689 == MPPE_UPDATE_FLAG) {
690 ng_mppc_updatekey(d->cfg.bits,
691 d->cfg.startkey, d->key, &d->rc4);
693 MPPC_CCOUNT_INC(d->cc);
696 /* Reset key (except in stateless mode, see below) */
697 if ((d->cfg.bits & MPPE_STATELESS) == 0)
698 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
701 d->cc = cc; /* skip over lost seq numbers */
702 numLost = 0; /* act like no packets were lost */
705 /* Can't decode non-sequential packets without a flushed bit */
710 if ((header & MPPC_FLAG_ENCRYPTED) != 0) {
711 #ifdef NETGRAPH_MPPC_ENCRYPTION
715 /* Are we not expecting encryption? */
716 if ((d->cfg.bits & MPPE_BITS) == 0) {
717 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
718 __func__, "encrypted");
722 #ifdef NETGRAPH_MPPC_ENCRYPTION
723 /* Update key if it's time (always in stateless mode) */
724 if ((d->cfg.bits & MPPE_STATELESS) != 0
725 || (d->cc & MPPE_UPDATE_MASK) == MPPE_UPDATE_FLAG) {
726 ng_mppc_updatekey(d->cfg.bits,
727 d->cfg.startkey, d->key, &d->rc4);
733 rc4_crypt(&d->rc4, mtod(m1, u_char *),
734 mtod(m1, u_char *), m1->m_len);
740 /* Are we expecting encryption? */
741 if ((d->cfg.bits & MPPE_BITS) != 0) {
742 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
743 __func__, "unencrypted");
748 /* Update coherency count for next time (12 bit arithmetic) */
749 MPPC_CCOUNT_INC(d->cc);
751 /* Check for unexpected compressed packet */
752 if ((header & MPPC_FLAG_COMPRESSED) != 0
753 && (d->cfg.bits & MPPC_BIT) == 0) {
754 log(LOG_ERR, "%s: rec'd unexpectedly %s packet",
755 __func__, "compressed");
761 #ifdef NETGRAPH_MPPC_COMPRESSION
762 /* Decompress packet */
763 if ((header & MPPC_FLAG_COMPRESSED) != 0) {
764 int flags = MPPC_MANDATORY_DECOMPRESS_FLAGS;
765 u_char *inbuf, *outbuf;
766 int inlen, outlen, ina;
767 u_char *source, *dest;
768 u_long sourceCnt, destCnt;
771 /* Copy payload into a contiguous region of memory. */
772 inlen = m->m_pkthdr.len;
773 if (m->m_next == NULL) {
774 inbuf = mtod(m, u_char *);
777 inbuf = malloc(inlen, M_NETGRAPH_MPPC, M_NOWAIT);
782 m_copydata(m, 0, inlen, (caddr_t)inbuf);
786 /* Allocate a buffer for decompressed data */
787 outbuf = malloc(MPPC_DECOMP_BUFSIZE + MPPC_DECOMP_SAFETY,
788 M_NETGRAPH_MPPC, M_NOWAIT);
789 if (outbuf == NULL) {
792 free(inbuf, M_NETGRAPH_MPPC);
795 outlen = MPPC_DECOMP_BUFSIZE;
797 /* Prepare to decompress */
802 if ((header & MPPC_FLAG_RESTART) != 0)
803 flags |= MPPC_RESTART_HISTORY;
806 rtn = MPPC_Decompress(&source, &dest,
807 &sourceCnt, &destCnt, d->history, flags);
809 /* Check return value */
810 /* KASSERT(rtn != MPPC_INVALID, ("%s: invalid", __func__)); */
811 if ((rtn & MPPC_DEST_EXHAUSTED) != 0
812 || (rtn & MPPC_DECOMP_OK) != MPPC_DECOMP_OK) {
813 log(LOG_ERR, "%s: decomp returned 0x%x",
816 free(inbuf, M_NETGRAPH_MPPC);
817 free(outbuf, M_NETGRAPH_MPPC);
821 /* Replace compressed data with decompressed data */
823 free(inbuf, M_NETGRAPH_MPPC);
826 m_copyback(m, 0, outlen, (caddr_t)outbuf);
827 if (m->m_pkthdr.len < outlen) {
830 } else if (outlen < m->m_pkthdr.len)
831 m_adj(m, outlen - m->m_pkthdr.len);
832 free(outbuf, M_NETGRAPH_MPPC);
836 /* Return result in an mbuf */
838 return (*datap == NULL ? ENOBUFS : 0);
842 * The peer has sent us a CCP ResetRequest, so reset our transmit state.
845 ng_mppc_reset_req(node_p node)
847 const priv_p priv = NG_NODE_PRIVATE(node);
848 struct ng_mppc_dir *const d = &priv->xmit;
850 #ifdef NETGRAPH_MPPC_COMPRESSION
851 if (d->history != NULL)
852 MPPC_InitCompressionHistory(d->history);
854 #ifdef NETGRAPH_MPPC_ENCRYPTION
855 if ((d->cfg.bits & MPPE_STATELESS) == 0)
856 rc4_init(&d->rc4, d->key, KEYLEN(d->cfg.bits));
861 #ifdef NETGRAPH_MPPC_ENCRYPTION
863 * Generate a new encryption key
866 ng_mppc_getkey(const u_char *h, u_char *h2, int len)
868 static const u_char pad1[40] =
869 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
870 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
871 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
872 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
873 static const u_char pad2[40] =
874 { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
875 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
876 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
877 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2 };
882 SHA1Update(&c, h, len);
883 SHA1Update(&c, pad1, sizeof(pad1));
884 SHA1Update(&c, h2, len);
885 SHA1Update(&c, pad2, sizeof(pad2));
887 bcopy(hash, h2, len);
891 * Update the encryption key
894 ng_mppc_updatekey(u_int32_t bits,
895 u_char *key0, u_char *key, struct rc4_state *rc4)
897 const int keylen = KEYLEN(bits);
899 ng_mppc_getkey(key0, key, keylen);
900 rc4_init(rc4, key, keylen);
901 rc4_crypt(rc4, key, key, keylen);
902 if ((bits & MPPE_40) != 0)
903 bcopy(&ng_mppe_weakenkey, key, 3);
904 else if ((bits & MPPE_56) != 0)
905 bcopy(&ng_mppe_weakenkey, key, 1);
906 rc4_init(rc4, key, keylen);