5 * Copyright (c) 1996-2000 Whistle Communications, Inc.
8 * Subject to the following obligations and disclaimer of warranty, use and
9 * redistribution of this software, in source or object code forms, with or
10 * without modifications are expressly permitted by Whistle Communications;
11 * provided, however, that:
12 * 1. Any and all reproductions of the source or object code must include the
13 * copyright notice above and the following disclaimer of warranties; and
14 * 2. No rights are granted, in any manner or form, to use Whistle
15 * Communications, Inc. trademarks, including the mark "WHISTLE
16 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17 * such appears in the above copyright notice or in the software.
19 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
25 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
37 * Author: Archie Cobbs <archie@freebsd.org>
39 * $Whistle: ng_mppc.c,v 1.4 1999/11/25 00:10:12 archie Exp $
40 * $FreeBSD: src/sys/netgraph/ng_mppc.c,v 1.1.2.7 2002/12/16 17:58:42 archie Exp $
41 * $DragonFly: src/sys/netgraph/mppc/ng_mppc.c,v 1.6 2008/01/05 14:02:39 swildner 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>
56 #include <sys/malloc.h>
57 #include <sys/errno.h>
58 #include <sys/syslog.h>
60 #include <netgraph/ng_message.h>
61 #include <netgraph/netgraph.h>
64 #include "opt_netgraph.h"
66 #if !defined(NETGRAPH_MPPC_COMPRESSION) && !defined(NETGRAPH_MPPC_ENCRYPTION)
67 #error Need either NETGRAPH_MPPC_COMPRESSION or NETGRAPH_MPPC_ENCRYPTION
70 #ifdef NETGRAPH_MPPC_COMPRESSION
71 /* XXX this file doesn't exist yet, but hopefully someday it will... */
74 #ifdef NETGRAPH_MPPC_ENCRYPTION
75 #include <crypto/rc4/rc4.h>
77 #include <crypto/sha1.h>
79 /* Decompression blowup */
80 #define MPPC_DECOMP_BUFSIZE 8092 /* allocate buffer this big */
81 #define MPPC_DECOMP_SAFETY 100 /* plus this much margin */
83 /* MPPC/MPPE header length */
87 #define KEYLEN(b) (((b) & MPPE_128) ? 16 : 8)
90 * When packets are lost with MPPE, we may have to re-key arbitrarily
91 * many times to 'catch up' to the new jumped-ahead sequence number.
92 * Since this can be expensive, we pose a limit on how many re-keyings
93 * we will do at one time to avoid a possible D.O.S. vulnerability.
94 * This should instead be a configurable parameter.
96 #define MPPE_MAX_REKEY 1000
98 /* MPPC packet header bits */
99 #define MPPC_FLAG_FLUSHED 0x8000 /* xmitter reset state */
100 #define MPPC_FLAG_RESTART 0x4000 /* compress history restart */
101 #define MPPC_FLAG_COMPRESSED 0x2000 /* packet is compresed */
102 #define MPPC_FLAG_ENCRYPTED 0x1000 /* packet is encrypted */
103 #define MPPC_CCOUNT_MASK 0x0fff /* sequence number mask */
105 #define MPPE_UPDATE_MASK 0xff /* coherency count when we're */
106 #define MPPE_UPDATE_FLAG 0xff /* supposed to update key */
108 #define MPPC_COMP_OK 0x05
109 #define MPPC_DECOMP_OK 0x05
111 /* Per direction info */
113 struct ng_mppc_config cfg
; /* configuration */
114 hook_p hook
; /* netgraph hook */
115 u_int16_t cc
:12; /* coherency count */
116 u_char flushed
; /* clean history (xmit only) */
117 #ifdef NETGRAPH_MPPC_COMPRESSION
118 u_char
*history
; /* compression history */
120 #ifdef NETGRAPH_MPPC_ENCRYPTION
121 u_char key
[MPPE_KEY_LEN
]; /* session key */
122 struct rc4_state rc4
; /* rc4 state */
126 /* Node private data */
127 struct ng_mppc_private
{
128 struct ng_mppc_dir xmit
; /* compress/encrypt config */
129 struct ng_mppc_dir recv
; /* decompress/decrypt config */
130 char *ctrlpath
; /* path to controlling node */
132 typedef struct ng_mppc_private
*priv_p
;
134 /* Netgraph node methods */
135 static ng_constructor_t ng_mppc_constructor
;
136 static ng_rcvmsg_t ng_mppc_rcvmsg
;
137 static ng_shutdown_t ng_mppc_rmnode
;
138 static ng_newhook_t ng_mppc_newhook
;
139 static ng_rcvdata_t ng_mppc_rcvdata
;
140 static ng_disconnect_t ng_mppc_disconnect
;
142 /* Helper functions */
143 static int ng_mppc_compress(node_p node
,
144 struct mbuf
*m
, struct mbuf
**resultp
);
145 static int ng_mppc_decompress(node_p node
,
146 struct mbuf
*m
, struct mbuf
**resultp
);
147 static void ng_mppc_getkey(const u_char
*h
, u_char
*h2
, int len
);
148 static void ng_mppc_updatekey(u_int32_t bits
,
149 u_char
*key0
, u_char
*key
, struct rc4_state
*rc4
);
150 static void ng_mppc_reset_req(node_p node
);
152 /* Node type descriptor */
153 static struct ng_type ng_mppc_typestruct
= {
168 NETGRAPH_INIT(mppc
, &ng_mppc_typestruct
);
170 /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
171 static const u_char ng_mppe_weakenkey
[3] = { 0xd1, 0x26, 0x9e };
173 #define ERROUT(x) do { error = (x); goto done; } while (0)
175 /************************************************************************
177 ************************************************************************/
180 * Node type constructor
183 ng_mppc_constructor(node_p
*nodep
)
188 /* Allocate private structure */
189 MALLOC(priv
, priv_p
, sizeof(*priv
), M_NETGRAPH
, M_NOWAIT
| M_ZERO
);
193 /* Call generic node constructor */
194 if ((error
= ng_make_node_common(&ng_mppc_typestruct
, nodep
))) {
195 FREE(priv
, M_NETGRAPH
);
198 (*nodep
)->private = priv
;
205 * Give our OK for a hook to be added
208 ng_mppc_newhook(node_p node
, hook_p hook
, const char *name
)
210 const priv_p priv
= node
->private;
213 /* Check hook name */
214 if (strcmp(name
, NG_MPPC_HOOK_COMP
) == 0)
215 hookPtr
= &priv
->xmit
.hook
;
216 else if (strcmp(name
, NG_MPPC_HOOK_DECOMP
) == 0)
217 hookPtr
= &priv
->recv
.hook
;
221 /* See if already connected */
222 if (*hookPtr
!= NULL
)
231 * Receive a control message
234 ng_mppc_rcvmsg(node_p node
, struct ng_mesg
*msg
,
235 const char *raddr
, struct ng_mesg
**rptr
)
237 const priv_p priv
= node
->private;
238 struct ng_mesg
*resp
= NULL
;
241 switch (msg
->header
.typecookie
) {
242 case NGM_MPPC_COOKIE
:
243 switch (msg
->header
.cmd
) {
244 case NGM_MPPC_CONFIG_COMP
:
245 case NGM_MPPC_CONFIG_DECOMP
:
247 struct ng_mppc_config
*const cfg
248 = (struct ng_mppc_config
*)msg
->data
;
250 msg
->header
.cmd
== NGM_MPPC_CONFIG_COMP
;
251 struct ng_mppc_dir
*const d
= isComp
?
252 &priv
->xmit
: &priv
->recv
;
254 /* Check configuration */
255 if (msg
->header
.arglen
!= sizeof(*cfg
))
258 if ((cfg
->bits
& ~MPPC_VALID_BITS
) != 0)
260 #ifndef NETGRAPH_MPPC_COMPRESSION
261 if ((cfg
->bits
& MPPC_BIT
) != 0)
262 ERROUT(EPROTONOSUPPORT
);
264 #ifndef NETGRAPH_MPPC_ENCRYPTION
265 if ((cfg
->bits
& MPPE_BITS
) != 0)
266 ERROUT(EPROTONOSUPPORT
);
271 /* Save return address so we can send reset-req's */
272 if (!isComp
&& priv
->ctrlpath
!= NULL
) {
273 FREE(priv
->ctrlpath
, M_NETGRAPH
);
274 priv
->ctrlpath
= NULL
;
276 if (!isComp
&& raddr
!= NULL
) {
277 MALLOC(priv
->ctrlpath
, char *,
278 strlen(raddr
) + 1, M_NETGRAPH
, M_NOWAIT
);
279 if (priv
->ctrlpath
== NULL
)
281 strcpy(priv
->ctrlpath
, raddr
);
284 /* Configuration is OK, reset to it */
287 #ifdef NETGRAPH_MPPC_COMPRESSION
288 /* Initialize state buffers for compression */
289 if (d
->history
!= NULL
) {
290 FREE(d
->history
, M_NETGRAPH
);
293 if ((cfg
->bits
& MPPC_BIT
) != 0) {
294 MALLOC(d
->history
, u_char
*,
295 isComp
? MPPC_SizeOfCompressionHistory() :
296 MPPC_SizeOfDecompressionHistory(),
297 M_NETGRAPH
, M_NOWAIT
);
298 if (d
->history
== NULL
)
301 MPPC_InitCompressionHistory(d
->history
);
303 MPPC_InitDecompressionHistory(
309 #ifdef NETGRAPH_MPPC_ENCRYPTION
310 /* Generate initial session keys for encryption */
311 if ((cfg
->bits
& MPPE_BITS
) != 0) {
312 const int keylen
= KEYLEN(cfg
->bits
);
314 bcopy(cfg
->startkey
, d
->key
, keylen
);
315 ng_mppc_getkey(cfg
->startkey
, d
->key
, keylen
);
316 if ((cfg
->bits
& MPPE_40
) != 0)
317 bcopy(&ng_mppe_weakenkey
, d
->key
, 3);
318 else if ((cfg
->bits
& MPPE_56
) != 0)
319 bcopy(&ng_mppe_weakenkey
, d
->key
, 1);
320 rc4_init(&d
->rc4
, d
->key
, keylen
);
324 /* Initialize other state */
330 case NGM_MPPC_RESETREQ
:
331 ng_mppc_reset_req(node
);
346 FREE(resp
, M_NETGRAPH
);
349 FREE(msg
, M_NETGRAPH
);
354 * Receive incoming data on our hook.
357 ng_mppc_rcvdata(hook_p hook
, struct mbuf
*m
, meta_p meta
)
359 const node_p node
= hook
->node
;
360 const priv_p priv
= node
->private;
364 /* Compress and/or encrypt */
365 if (hook
== priv
->xmit
.hook
) {
366 if (!priv
->xmit
.cfg
.enable
) {
367 NG_FREE_DATA(m
, meta
);
370 if ((error
= ng_mppc_compress(node
, m
, &out
)) != 0) {
371 NG_FREE_DATA(m
, meta
);
375 NG_SEND_DATA(error
, priv
->xmit
.hook
, out
, meta
);
379 /* Decompress and/or decrypt */
380 if (hook
== priv
->recv
.hook
) {
381 if (!priv
->recv
.cfg
.enable
) {
382 NG_FREE_DATA(m
, meta
);
385 if ((error
= ng_mppc_decompress(node
, m
, &out
)) != 0) {
386 NG_FREE_DATA(m
, meta
);
387 if (error
== EINVAL
&& priv
->ctrlpath
!= NULL
) {
390 /* Need to send a reset-request */
391 NG_MKMESSAGE(msg
, NGM_MPPC_COOKIE
,
392 NGM_MPPC_RESETREQ
, 0, M_NOWAIT
);
395 ng_send_msg(node
, msg
, priv
->ctrlpath
, NULL
);
400 NG_SEND_DATA(error
, priv
->recv
.hook
, out
, meta
);
405 panic("%s: unknown hook", __func__
);
412 ng_mppc_rmnode(node_p node
)
414 const priv_p priv
= node
->private;
416 /* Take down netgraph node */
417 node
->flags
|= NG_INVALID
;
420 if (priv
->ctrlpath
!= NULL
)
421 FREE(priv
->ctrlpath
, M_NETGRAPH
);
422 #ifdef NETGRAPH_MPPC_COMPRESSION
423 if (priv
->xmit
.history
!= NULL
)
424 FREE(priv
->xmit
.history
, M_NETGRAPH
);
425 if (priv
->recv
.history
!= NULL
)
426 FREE(priv
->recv
.history
, M_NETGRAPH
);
428 bzero(priv
, sizeof(*priv
));
429 FREE(priv
, M_NETGRAPH
);
430 node
->private = NULL
;
431 ng_unref(node
); /* let the node escape */
439 ng_mppc_disconnect(hook_p hook
)
441 const node_p node
= hook
->node
;
442 const priv_p priv
= node
->private;
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 (node
->numhooks
== 0)
456 /************************************************************************
458 ************************************************************************/
461 * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
462 * The original mbuf is not free'd.
465 ng_mppc_compress(node_p node
, struct mbuf
*m
, struct mbuf
**resultp
)
467 const priv_p priv
= node
->private;
468 struct ng_mppc_dir
*const d
= &priv
->xmit
;
469 u_char
*inbuf
, *outbuf
;
477 header
|= MPPC_FLAG_FLUSHED
;
481 /* Work with contiguous regions of memory */
482 inlen
= m
->m_pkthdr
.len
;
483 MALLOC(inbuf
, u_char
*, inlen
, M_NETGRAPH
, M_NOWAIT
);
486 m_copydata(m
, 0, inlen
, (caddr_t
)inbuf
);
487 if ((d
->cfg
.bits
& MPPC_BIT
) != 0)
488 outlen
= MPPC_MAX_BLOWUP(inlen
);
490 outlen
= MPPC_HDRLEN
+ inlen
;
491 MALLOC(outbuf
, u_char
*, outlen
, M_NETGRAPH
, M_NOWAIT
);
492 if (outbuf
== NULL
) {
493 FREE(inbuf
, M_NETGRAPH
);
497 /* Compress "inbuf" into "outbuf" (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
*source
, *dest
;
502 u_long sourceCnt
, destCnt
;
505 /* Prepare to compress */
508 dest
= outbuf
+ MPPC_HDRLEN
;
509 destCnt
= outlen
- MPPC_HDRLEN
;
510 if ((d
->cfg
.bits
& MPPE_STATELESS
) == 0)
511 flags
|= MPPC_SAVE_HISTORY
;
514 rtn
= MPPC_Compress(&source
, &dest
, &sourceCnt
,
515 &destCnt
, d
->history
, flags
, 0);
517 /* Check return value */
518 KASSERT(rtn
!= MPPC_INVALID
, ("%s: invalid", __func__
));
519 if ((rtn
& MPPC_EXPANDED
) == 0
520 && (rtn
& MPPC_COMP_OK
) == MPPC_COMP_OK
) {
522 header
|= MPPC_FLAG_COMPRESSED
;
523 if ((rtn
& MPPC_RESTART_HISTORY
) != 0)
524 header
|= MPPC_FLAG_RESTART
;
526 d
->flushed
= (rtn
& MPPC_EXPANDED
) != 0
527 || (flags
& MPPC_SAVE_HISTORY
) == 0;
531 /* If we did not compress this packet, copy it to output buffer */
532 if ((header
& MPPC_FLAG_COMPRESSED
) == 0) {
533 bcopy(inbuf
, outbuf
+ MPPC_HDRLEN
, inlen
);
534 outlen
= MPPC_HDRLEN
+ inlen
;
536 FREE(inbuf
, M_NETGRAPH
);
538 /* Always set the flushed bit in stateless mode */
539 if ((d
->cfg
.bits
& MPPE_STATELESS
) != 0)
540 header
|= MPPC_FLAG_FLUSHED
;
542 /* Now encrypt packet (if encryption enabled) */
543 #ifdef NETGRAPH_MPPC_ENCRYPTION
544 if ((d
->cfg
.bits
& MPPE_BITS
) != 0) {
546 /* Set header bits; need to reset key if we say we did */
547 header
|= MPPC_FLAG_ENCRYPTED
;
548 if ((header
& MPPC_FLAG_FLUSHED
) != 0)
549 rc4_init(&d
->rc4
, d
->key
, KEYLEN(d
->cfg
.bits
));
551 /* Update key if it's time */
552 if ((d
->cfg
.bits
& MPPE_STATELESS
) != 0
553 || (d
->cc
& MPPE_UPDATE_MASK
) == MPPE_UPDATE_FLAG
) {
554 ng_mppc_updatekey(d
->cfg
.bits
,
555 d
->cfg
.startkey
, d
->key
, &d
->rc4
);
559 rc4_crypt(&d
->rc4
, outbuf
+ MPPC_HDRLEN
,
560 outbuf
+ MPPC_HDRLEN
, outlen
- MPPC_HDRLEN
);
564 /* Update sequence number */
568 *((u_int16_t
*)outbuf
) = htons(header
);
570 /* Return packet in an mbuf */
571 *resultp
= m_devget((caddr_t
)outbuf
, outlen
, 0, NULL
, NULL
);
572 FREE(outbuf
, M_NETGRAPH
);
573 return (*resultp
== NULL
? ENOBUFS
: 0);
577 * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
578 * The original mbuf is not free'd.
581 ng_mppc_decompress(node_p node
, struct mbuf
*m
, struct mbuf
**resultp
)
583 const priv_p priv
= node
->private;
584 struct ng_mppc_dir
*const d
= &priv
->recv
;
585 u_int16_t header
, cc
;
590 /* Pull off header */
591 if (m
->m_pkthdr
.len
< MPPC_HDRLEN
)
593 m_copydata(m
, 0, MPPC_HDRLEN
, (caddr_t
)&header
);
594 header
= ntohs(header
);
595 cc
= (header
& MPPC_CCOUNT_MASK
);
597 /* Copy payload into a contiguous region of memory */
598 len
= m
->m_pkthdr
.len
- MPPC_HDRLEN
;
599 MALLOC(buf
, u_char
*, len
, M_NETGRAPH
, M_NOWAIT
);
602 m_copydata(m
, MPPC_HDRLEN
, len
, (caddr_t
)buf
);
604 /* Check for an unexpected jump in the sequence number */
605 numLost
= ((cc
- d
->cc
) & MPPC_CCOUNT_MASK
);
607 /* If flushed bit set, we can always handle packet */
608 if ((header
& MPPC_FLAG_FLUSHED
) != 0) {
609 #ifdef NETGRAPH_MPPC_COMPRESSION
610 if (d
->history
!= NULL
)
611 MPPC_InitDecompressionHistory(d
->history
);
613 #ifdef NETGRAPH_MPPC_ENCRYPTION
614 if ((d
->cfg
.bits
& MPPE_BITS
) != 0) {
617 /* How many times are we going to have to re-key? */
618 rekey
= ((d
->cfg
.bits
& MPPE_STATELESS
) != 0) ?
619 numLost
: (numLost
/ (MPPE_UPDATE_MASK
+ 1));
620 if (rekey
> MPPE_MAX_REKEY
) {
621 log(LOG_ERR
, "%s: too many (%d) packets"
622 " dropped, disabling node %p!",
623 __func__
, numLost
, node
);
624 priv
->recv
.cfg
.enable
= 0;
628 /* Re-key as necessary to catch up to peer */
629 while (d
->cc
!= cc
) {
630 if ((d
->cfg
.bits
& MPPE_STATELESS
) != 0
631 || (d
->cc
& MPPE_UPDATE_MASK
)
632 == MPPE_UPDATE_FLAG
) {
633 ng_mppc_updatekey(d
->cfg
.bits
,
634 d
->cfg
.startkey
, d
->key
, &d
->rc4
);
639 /* Reset key (except in stateless mode, see below) */
640 if ((d
->cfg
.bits
& MPPE_STATELESS
) == 0)
641 rc4_init(&d
->rc4
, d
->key
, KEYLEN(d
->cfg
.bits
));
644 d
->cc
= cc
; /* skip over lost seq numbers */
645 numLost
= 0; /* act like no packets were lost */
648 /* Can't decode non-sequential packets without a flushed bit */
653 if ((header
& MPPC_FLAG_ENCRYPTED
) != 0) {
655 /* Are we not expecting encryption? */
656 if ((d
->cfg
.bits
& MPPE_BITS
) == 0) {
657 log(LOG_ERR
, "%s: rec'd unexpectedly %s packet",
658 __func__
, "encrypted");
662 #ifdef NETGRAPH_MPPC_ENCRYPTION
663 /* Update key if it's time (always in stateless mode) */
664 if ((d
->cfg
.bits
& MPPE_STATELESS
) != 0
665 || (d
->cc
& MPPE_UPDATE_MASK
) == MPPE_UPDATE_FLAG
) {
666 ng_mppc_updatekey(d
->cfg
.bits
,
667 d
->cfg
.startkey
, d
->key
, &d
->rc4
);
671 rc4_crypt(&d
->rc4
, buf
, buf
, len
);
675 /* Are we expecting encryption? */
676 if ((d
->cfg
.bits
& MPPE_BITS
) != 0) {
677 log(LOG_ERR
, "%s: rec'd unexpectedly %s packet",
678 __func__
, "unencrypted");
683 /* Update coherency count for next time (12 bit arithmetic) */
686 /* Check for unexpected compressed packet */
687 if ((header
& MPPC_FLAG_COMPRESSED
) != 0
688 && (d
->cfg
.bits
& MPPC_BIT
) == 0) {
689 log(LOG_ERR
, "%s: rec'd unexpectedly %s packet",
690 __func__
, "compressed");
692 FREE(buf
, M_NETGRAPH
);
696 #ifdef NETGRAPH_MPPC_COMPRESSION
697 /* Decompress packet */
698 if ((header
& MPPC_FLAG_COMPRESSED
) != 0) {
699 int flags
= MPPC_MANDATORY_DECOMPRESS_FLAGS
;
700 u_char
*decompbuf
, *source
, *dest
;
701 u_long sourceCnt
, destCnt
;
704 /* Allocate a buffer for decompressed data */
705 MALLOC(decompbuf
, u_char
*, MPPC_DECOMP_BUFSIZE
706 + MPPC_DECOMP_SAFETY
, M_NETGRAPH
, M_NOWAIT
);
707 if (decompbuf
== NULL
) {
708 FREE(buf
, M_NETGRAPH
);
711 decomplen
= MPPC_DECOMP_BUFSIZE
;
713 /* Prepare to decompress */
718 if ((header
& MPPC_FLAG_RESTART
) != 0)
719 flags
|= MPPC_RESTART_HISTORY
;
722 rtn
= MPPC_Decompress(&source
, &dest
,
723 &sourceCnt
, &destCnt
, d
->history
, flags
);
725 /* Check return value */
726 KASSERT(rtn
!= MPPC_INVALID
, ("%s: invalid", __func__
));
727 if ((rtn
& MPPC_DEST_EXHAUSTED
) != 0
728 || (rtn
& MPPC_DECOMP_OK
) != MPPC_DECOMP_OK
) {
729 log(LOG_ERR
, "%s: decomp returned 0x%x",
731 FREE(decompbuf
, M_NETGRAPH
);
735 /* Replace compressed data with decompressed data */
736 FREE(buf
, M_NETGRAPH
);
738 len
= decomplen
- destCnt
;
742 /* Return result in an mbuf */
743 *resultp
= m_devget((caddr_t
)buf
, len
, 0, NULL
, NULL
);
744 FREE(buf
, M_NETGRAPH
);
745 return (*resultp
== NULL
? ENOBUFS
: 0);
749 * The peer has sent us a CCP ResetRequest, so reset our transmit state.
752 ng_mppc_reset_req(node_p node
)
754 const priv_p priv
= node
->private;
755 struct ng_mppc_dir
*const d
= &priv
->xmit
;
757 #ifdef NETGRAPH_MPPC_COMPRESSION
758 if (d
->history
!= NULL
)
759 MPPC_InitCompressionHistory(d
->history
);
761 #ifdef NETGRAPH_MPPC_ENCRYPTION
762 if ((d
->cfg
.bits
& MPPE_STATELESS
) == 0)
763 rc4_init(&d
->rc4
, d
->key
, KEYLEN(d
->cfg
.bits
));
769 * Generate a new encryption key
772 ng_mppc_getkey(const u_char
*h
, u_char
*h2
, int len
)
774 static const u_char pad1
[10] =
775 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
776 static const u_char pad2
[10] =
777 { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, };
782 bzero(&hash
, sizeof(hash
));
784 SHA1Update(&c
, h
, len
);
785 for (k
= 0; k
< 4; k
++)
786 SHA1Update(&c
, pad1
, sizeof(pad2
));
787 SHA1Update(&c
, h2
, len
);
788 for (k
= 0; k
< 4; k
++)
789 SHA1Update(&c
, pad2
, sizeof(pad2
));
791 bcopy(hash
, h2
, len
);
795 * Update the encryption key
798 ng_mppc_updatekey(u_int32_t bits
,
799 u_char
*key0
, u_char
*key
, struct rc4_state
*rc4
)
801 const int keylen
= KEYLEN(bits
);
803 ng_mppc_getkey(key0
, key
, keylen
);
804 rc4_init(rc4
, key
, keylen
);
805 rc4_crypt(rc4
, key
, key
, keylen
);
806 if ((bits
& MPPE_40
) != 0)
807 bcopy(&ng_mppe_weakenkey
, key
, 3);
808 else if ((bits
& MPPE_56
) != 0)
809 bcopy(&ng_mppe_weakenkey
, key
, 1);
810 rc4_init(rc4
, key
, keylen
);