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 $
44 * Microsoft PPP compression (MPPC) and encryption (MPPE) netgraph node type.
46 * You must define one or both of the NETGRAPH_MPPC_COMPRESSION and/or
47 * NETGRAPH_MPPC_ENCRYPTION options for this node type to be useful.
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/kernel.h>
55 #include <sys/malloc.h>
56 #include <sys/errno.h>
57 #include <sys/syslog.h>
59 #include <netgraph/ng_message.h>
60 #include <netgraph/netgraph.h>
63 #include "opt_netgraph.h"
65 #if !defined(NETGRAPH_MPPC_COMPRESSION) && !defined(NETGRAPH_MPPC_ENCRYPTION)
66 #error Need either NETGRAPH_MPPC_COMPRESSION or NETGRAPH_MPPC_ENCRYPTION
69 #ifdef NETGRAPH_MPPC_COMPRESSION
70 /* XXX this file doesn't exist yet, but hopefully someday it will... */
73 #ifdef NETGRAPH_MPPC_ENCRYPTION
74 #include <crypto/rc4/rc4.h>
76 #include <crypto/sha1.h>
78 /* Decompression blowup */
79 #define MPPC_DECOMP_BUFSIZE 8092 /* allocate buffer this big */
80 #define MPPC_DECOMP_SAFETY 100 /* plus this much margin */
82 /* MPPC/MPPE header length */
86 #define KEYLEN(b) (((b) & MPPE_128) ? 16 : 8)
89 * When packets are lost with MPPE, we may have to re-key arbitrarily
90 * many times to 'catch up' to the new jumped-ahead sequence number.
91 * Since this can be expensive, we pose a limit on how many re-keyings
92 * we will do at one time to avoid a possible D.O.S. vulnerability.
93 * This should instead be a configurable parameter.
95 #define MPPE_MAX_REKEY 1000
97 /* MPPC packet header bits */
98 #define MPPC_FLAG_FLUSHED 0x8000 /* xmitter reset state */
99 #define MPPC_FLAG_RESTART 0x4000 /* compress history restart */
100 #define MPPC_FLAG_COMPRESSED 0x2000 /* packet is compresed */
101 #define MPPC_FLAG_ENCRYPTED 0x1000 /* packet is encrypted */
102 #define MPPC_CCOUNT_MASK 0x0fff /* sequence number mask */
104 #define MPPE_UPDATE_MASK 0xff /* coherency count when we're */
105 #define MPPE_UPDATE_FLAG 0xff /* supposed to update key */
107 #define MPPC_COMP_OK 0x05
108 #define MPPC_DECOMP_OK 0x05
110 /* Per direction info */
112 struct ng_mppc_config cfg
; /* configuration */
113 hook_p hook
; /* netgraph hook */
114 u_int16_t cc
:12; /* coherency count */
115 u_char flushed
; /* clean history (xmit only) */
116 #ifdef NETGRAPH_MPPC_COMPRESSION
117 u_char
*history
; /* compression history */
119 #ifdef NETGRAPH_MPPC_ENCRYPTION
120 u_char key
[MPPE_KEY_LEN
]; /* session key */
121 struct rc4_state rc4
; /* rc4 state */
125 /* Node private data */
126 struct ng_mppc_private
{
127 struct ng_mppc_dir xmit
; /* compress/encrypt config */
128 struct ng_mppc_dir recv
; /* decompress/decrypt config */
129 char *ctrlpath
; /* path to controlling node */
131 typedef struct ng_mppc_private
*priv_p
;
133 /* Netgraph node methods */
134 static ng_constructor_t ng_mppc_constructor
;
135 static ng_rcvmsg_t ng_mppc_rcvmsg
;
136 static ng_shutdown_t ng_mppc_rmnode
;
137 static ng_newhook_t ng_mppc_newhook
;
138 static ng_rcvdata_t ng_mppc_rcvdata
;
139 static ng_disconnect_t ng_mppc_disconnect
;
141 /* Helper functions */
142 static int ng_mppc_compress(node_p node
,
143 struct mbuf
*m
, struct mbuf
**resultp
);
144 static int ng_mppc_decompress(node_p node
,
145 struct mbuf
*m
, struct mbuf
**resultp
);
146 static void ng_mppc_getkey(const u_char
*h
, u_char
*h2
, int len
);
147 static void ng_mppc_updatekey(u_int32_t bits
,
148 u_char
*key0
, u_char
*key
, struct rc4_state
*rc4
);
149 static void ng_mppc_reset_req(node_p node
);
151 /* Node type descriptor */
152 static struct ng_type ng_mppc_typestruct
= {
167 NETGRAPH_INIT(mppc
, &ng_mppc_typestruct
);
169 /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
170 static const u_char ng_mppe_weakenkey
[3] = { 0xd1, 0x26, 0x9e };
172 #define ERROUT(x) do { error = (x); goto done; } while (0)
174 /************************************************************************
176 ************************************************************************/
179 * Node type constructor
182 ng_mppc_constructor(node_p
*nodep
)
187 /* Allocate private structure */
188 priv
= kmalloc(sizeof(*priv
), M_NETGRAPH
, M_NOWAIT
| M_ZERO
);
192 /* Call generic node constructor */
193 if ((error
= ng_make_node_common(&ng_mppc_typestruct
, nodep
))) {
194 kfree(priv
, M_NETGRAPH
);
197 (*nodep
)->private = priv
;
204 * Give our OK for a hook to be added
207 ng_mppc_newhook(node_p node
, hook_p hook
, const char *name
)
209 const priv_p priv
= node
->private;
212 /* Check hook name */
213 if (strcmp(name
, NG_MPPC_HOOK_COMP
) == 0)
214 hookPtr
= &priv
->xmit
.hook
;
215 else if (strcmp(name
, NG_MPPC_HOOK_DECOMP
) == 0)
216 hookPtr
= &priv
->recv
.hook
;
220 /* See if already connected */
221 if (*hookPtr
!= NULL
)
230 * Receive a control message
233 ng_mppc_rcvmsg(node_p node
, struct ng_mesg
*msg
,
234 const char *raddr
, struct ng_mesg
**rptr
)
236 const priv_p priv
= node
->private;
237 struct ng_mesg
*resp
= NULL
;
240 switch (msg
->header
.typecookie
) {
241 case NGM_MPPC_COOKIE
:
242 switch (msg
->header
.cmd
) {
243 case NGM_MPPC_CONFIG_COMP
:
244 case NGM_MPPC_CONFIG_DECOMP
:
246 struct ng_mppc_config
*const cfg
247 = (struct ng_mppc_config
*)msg
->data
;
249 msg
->header
.cmd
== NGM_MPPC_CONFIG_COMP
;
250 struct ng_mppc_dir
*const d
= isComp
?
251 &priv
->xmit
: &priv
->recv
;
253 /* Check configuration */
254 if (msg
->header
.arglen
!= sizeof(*cfg
))
257 if ((cfg
->bits
& ~MPPC_VALID_BITS
) != 0)
259 #ifndef NETGRAPH_MPPC_COMPRESSION
260 if ((cfg
->bits
& MPPC_BIT
) != 0)
261 ERROUT(EPROTONOSUPPORT
);
263 #ifndef NETGRAPH_MPPC_ENCRYPTION
264 if ((cfg
->bits
& MPPE_BITS
) != 0)
265 ERROUT(EPROTONOSUPPORT
);
270 /* Save return address so we can send reset-req's */
271 if (!isComp
&& priv
->ctrlpath
!= NULL
) {
272 kfree(priv
->ctrlpath
, M_NETGRAPH
);
273 priv
->ctrlpath
= NULL
;
275 if (!isComp
&& raddr
!= NULL
) {
276 priv
->ctrlpath
= kmalloc(strlen(raddr
) + 1,
277 M_NETGRAPH
, M_NOWAIT
);
278 if (priv
->ctrlpath
== NULL
)
280 strcpy(priv
->ctrlpath
, raddr
);
283 /* Configuration is OK, reset to it */
286 #ifdef NETGRAPH_MPPC_COMPRESSION
287 /* Initialize state buffers for compression */
288 if (d
->history
!= NULL
) {
289 kfree(d
->history
, M_NETGRAPH
);
292 if ((cfg
->bits
& MPPC_BIT
) != 0) {
293 d
->history
= kmalloc(isComp
? MPPC_SizeOfCompressionHistory() : MPPC_SizeOfDecompressionHistory(),
294 M_NETGRAPH
, M_NOWAIT
);
295 if (d
->history
== NULL
)
298 MPPC_InitCompressionHistory(d
->history
);
300 MPPC_InitDecompressionHistory(
306 #ifdef NETGRAPH_MPPC_ENCRYPTION
307 /* Generate initial session keys for encryption */
308 if ((cfg
->bits
& MPPE_BITS
) != 0) {
309 const int keylen
= KEYLEN(cfg
->bits
);
311 bcopy(cfg
->startkey
, d
->key
, keylen
);
312 ng_mppc_getkey(cfg
->startkey
, d
->key
, keylen
);
313 if ((cfg
->bits
& MPPE_40
) != 0)
314 bcopy(&ng_mppe_weakenkey
, d
->key
, 3);
315 else if ((cfg
->bits
& MPPE_56
) != 0)
316 bcopy(&ng_mppe_weakenkey
, d
->key
, 1);
317 rc4_init(&d
->rc4
, d
->key
, keylen
);
321 /* Initialize other state */
327 case NGM_MPPC_RESETREQ
:
328 ng_mppc_reset_req(node
);
343 kfree(resp
, M_NETGRAPH
);
346 kfree(msg
, M_NETGRAPH
);
351 * Receive incoming data on our hook.
354 ng_mppc_rcvdata(hook_p hook
, struct mbuf
*m
, meta_p meta
)
356 const node_p node
= hook
->node
;
357 const priv_p priv
= node
->private;
361 /* Compress and/or encrypt */
362 if (hook
== priv
->xmit
.hook
) {
363 if (!priv
->xmit
.cfg
.enable
) {
364 NG_FREE_DATA(m
, meta
);
367 if ((error
= ng_mppc_compress(node
, m
, &out
)) != 0) {
368 NG_FREE_DATA(m
, meta
);
372 NG_SEND_DATA(error
, priv
->xmit
.hook
, out
, meta
);
376 /* Decompress and/or decrypt */
377 if (hook
== priv
->recv
.hook
) {
378 if (!priv
->recv
.cfg
.enable
) {
379 NG_FREE_DATA(m
, meta
);
382 if ((error
= ng_mppc_decompress(node
, m
, &out
)) != 0) {
383 NG_FREE_DATA(m
, meta
);
384 if (error
== EINVAL
&& priv
->ctrlpath
!= NULL
) {
387 /* Need to send a reset-request */
388 NG_MKMESSAGE(msg
, NGM_MPPC_COOKIE
,
389 NGM_MPPC_RESETREQ
, 0, M_NOWAIT
);
392 ng_send_msg(node
, msg
, priv
->ctrlpath
, NULL
);
397 NG_SEND_DATA(error
, priv
->recv
.hook
, out
, meta
);
402 panic("%s: unknown hook", __func__
);
409 ng_mppc_rmnode(node_p node
)
411 const priv_p priv
= node
->private;
413 /* Take down netgraph node */
414 node
->flags
|= NG_INVALID
;
417 if (priv
->ctrlpath
!= NULL
)
418 kfree(priv
->ctrlpath
, M_NETGRAPH
);
419 #ifdef NETGRAPH_MPPC_COMPRESSION
420 if (priv
->xmit
.history
!= NULL
)
421 kfree(priv
->xmit
.history
, M_NETGRAPH
);
422 if (priv
->recv
.history
!= NULL
)
423 kfree(priv
->recv
.history
, M_NETGRAPH
);
425 bzero(priv
, sizeof(*priv
));
426 kfree(priv
, M_NETGRAPH
);
427 node
->private = NULL
;
428 ng_unref(node
); /* let the node escape */
436 ng_mppc_disconnect(hook_p hook
)
438 const node_p node
= hook
->node
;
439 const priv_p priv
= node
->private;
441 /* Zero out hook pointer */
442 if (hook
== priv
->xmit
.hook
)
443 priv
->xmit
.hook
= NULL
;
444 if (hook
== priv
->recv
.hook
)
445 priv
->recv
.hook
= NULL
;
447 /* Go away if no longer connected */
448 if (node
->numhooks
== 0)
453 /************************************************************************
455 ************************************************************************/
458 * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
459 * The original mbuf is not free'd.
462 ng_mppc_compress(node_p node
, struct mbuf
*m
, struct mbuf
**resultp
)
464 const priv_p priv
= node
->private;
465 struct ng_mppc_dir
*const d
= &priv
->xmit
;
466 u_char
*inbuf
, *outbuf
;
474 header
|= MPPC_FLAG_FLUSHED
;
478 /* Work with contiguous regions of memory */
479 inlen
= m
->m_pkthdr
.len
;
480 inbuf
= kmalloc(inlen
, M_NETGRAPH
, M_NOWAIT
);
483 m_copydata(m
, 0, inlen
, (caddr_t
)inbuf
);
484 if ((d
->cfg
.bits
& MPPC_BIT
) != 0)
485 outlen
= MPPC_MAX_BLOWUP(inlen
);
487 outlen
= MPPC_HDRLEN
+ inlen
;
488 outbuf
= kmalloc(outlen
, M_NETGRAPH
, M_NOWAIT
);
489 if (outbuf
== NULL
) {
490 kfree(inbuf
, M_NETGRAPH
);
494 /* Compress "inbuf" into "outbuf" (if compression enabled) */
495 #ifdef NETGRAPH_MPPC_COMPRESSION
496 if ((d
->cfg
.bits
& MPPC_BIT
) != 0) {
497 u_short flags
= MPPC_MANDATORY_COMPRESS_FLAGS
;
498 u_char
*source
, *dest
;
499 u_long sourceCnt
, destCnt
;
502 /* Prepare to compress */
505 dest
= outbuf
+ MPPC_HDRLEN
;
506 destCnt
= outlen
- MPPC_HDRLEN
;
507 if ((d
->cfg
.bits
& MPPE_STATELESS
) == 0)
508 flags
|= MPPC_SAVE_HISTORY
;
511 rtn
= MPPC_Compress(&source
, &dest
, &sourceCnt
,
512 &destCnt
, d
->history
, flags
, 0);
514 /* Check return value */
515 KASSERT(rtn
!= MPPC_INVALID
, ("%s: invalid", __func__
));
516 if ((rtn
& MPPC_EXPANDED
) == 0
517 && (rtn
& MPPC_COMP_OK
) == MPPC_COMP_OK
) {
519 header
|= MPPC_FLAG_COMPRESSED
;
520 if ((rtn
& MPPC_RESTART_HISTORY
) != 0)
521 header
|= MPPC_FLAG_RESTART
;
523 d
->flushed
= (rtn
& MPPC_EXPANDED
) != 0
524 || (flags
& MPPC_SAVE_HISTORY
) == 0;
528 /* If we did not compress this packet, copy it to output buffer */
529 if ((header
& MPPC_FLAG_COMPRESSED
) == 0) {
530 bcopy(inbuf
, outbuf
+ MPPC_HDRLEN
, inlen
);
531 outlen
= MPPC_HDRLEN
+ inlen
;
533 kfree(inbuf
, M_NETGRAPH
);
535 /* Always set the flushed bit in stateless mode */
536 if ((d
->cfg
.bits
& MPPE_STATELESS
) != 0)
537 header
|= MPPC_FLAG_FLUSHED
;
539 /* Now encrypt packet (if encryption enabled) */
540 #ifdef NETGRAPH_MPPC_ENCRYPTION
541 if ((d
->cfg
.bits
& MPPE_BITS
) != 0) {
543 /* Set header bits; need to reset key if we say we did */
544 header
|= MPPC_FLAG_ENCRYPTED
;
545 if ((header
& MPPC_FLAG_FLUSHED
) != 0)
546 rc4_init(&d
->rc4
, d
->key
, KEYLEN(d
->cfg
.bits
));
548 /* Update key if it's time */
549 if ((d
->cfg
.bits
& MPPE_STATELESS
) != 0
550 || (d
->cc
& MPPE_UPDATE_MASK
) == MPPE_UPDATE_FLAG
) {
551 ng_mppc_updatekey(d
->cfg
.bits
,
552 d
->cfg
.startkey
, d
->key
, &d
->rc4
);
556 rc4_crypt(&d
->rc4
, outbuf
+ MPPC_HDRLEN
,
557 outbuf
+ MPPC_HDRLEN
, outlen
- MPPC_HDRLEN
);
561 /* Update sequence number */
565 *((u_int16_t
*)outbuf
) = htons(header
);
567 /* Return packet in an mbuf */
568 *resultp
= m_devget((caddr_t
)outbuf
, outlen
, 0, NULL
);
569 kfree(outbuf
, M_NETGRAPH
);
570 return (*resultp
== NULL
? ENOBUFS
: 0);
574 * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
575 * The original mbuf is not free'd.
578 ng_mppc_decompress(node_p node
, struct mbuf
*m
, struct mbuf
**resultp
)
580 const priv_p priv
= node
->private;
581 struct ng_mppc_dir
*const d
= &priv
->recv
;
582 u_int16_t header
, cc
;
587 /* Pull off header */
588 if (m
->m_pkthdr
.len
< MPPC_HDRLEN
)
590 m_copydata(m
, 0, MPPC_HDRLEN
, (caddr_t
)&header
);
591 header
= ntohs(header
);
592 cc
= (header
& MPPC_CCOUNT_MASK
);
594 /* Copy payload into a contiguous region of memory */
595 len
= m
->m_pkthdr
.len
- MPPC_HDRLEN
;
596 buf
= kmalloc(len
, M_NETGRAPH
, M_NOWAIT
);
599 m_copydata(m
, MPPC_HDRLEN
, len
, (caddr_t
)buf
);
601 /* Check for an unexpected jump in the sequence number */
602 numLost
= ((cc
- d
->cc
) & MPPC_CCOUNT_MASK
);
604 /* If flushed bit set, we can always handle packet */
605 if ((header
& MPPC_FLAG_FLUSHED
) != 0) {
606 #ifdef NETGRAPH_MPPC_COMPRESSION
607 if (d
->history
!= NULL
)
608 MPPC_InitDecompressionHistory(d
->history
);
610 #ifdef NETGRAPH_MPPC_ENCRYPTION
611 if ((d
->cfg
.bits
& MPPE_BITS
) != 0) {
614 /* How many times are we going to have to re-key? */
615 rekey
= ((d
->cfg
.bits
& MPPE_STATELESS
) != 0) ?
616 numLost
: (numLost
/ (MPPE_UPDATE_MASK
+ 1));
617 if (rekey
> MPPE_MAX_REKEY
) {
618 log(LOG_ERR
, "%s: too many (%d) packets"
619 " dropped, disabling node %p!",
620 __func__
, numLost
, node
);
621 priv
->recv
.cfg
.enable
= 0;
625 /* Re-key as necessary to catch up to peer */
626 while (d
->cc
!= cc
) {
627 if ((d
->cfg
.bits
& MPPE_STATELESS
) != 0
628 || (d
->cc
& MPPE_UPDATE_MASK
)
629 == MPPE_UPDATE_FLAG
) {
630 ng_mppc_updatekey(d
->cfg
.bits
,
631 d
->cfg
.startkey
, d
->key
, &d
->rc4
);
636 /* Reset key (except in stateless mode, see below) */
637 if ((d
->cfg
.bits
& MPPE_STATELESS
) == 0)
638 rc4_init(&d
->rc4
, d
->key
, KEYLEN(d
->cfg
.bits
));
641 d
->cc
= cc
; /* skip over lost seq numbers */
642 numLost
= 0; /* act like no packets were lost */
645 /* Can't decode non-sequential packets without a flushed bit */
650 if ((header
& MPPC_FLAG_ENCRYPTED
) != 0) {
652 /* Are we not expecting encryption? */
653 if ((d
->cfg
.bits
& MPPE_BITS
) == 0) {
654 log(LOG_ERR
, "%s: rec'd unexpectedly %s packet",
655 __func__
, "encrypted");
659 #ifdef NETGRAPH_MPPC_ENCRYPTION
660 /* Update key if it's time (always in stateless mode) */
661 if ((d
->cfg
.bits
& MPPE_STATELESS
) != 0
662 || (d
->cc
& MPPE_UPDATE_MASK
) == MPPE_UPDATE_FLAG
) {
663 ng_mppc_updatekey(d
->cfg
.bits
,
664 d
->cfg
.startkey
, d
->key
, &d
->rc4
);
668 rc4_crypt(&d
->rc4
, buf
, buf
, len
);
672 /* Are we expecting encryption? */
673 if ((d
->cfg
.bits
& MPPE_BITS
) != 0) {
674 log(LOG_ERR
, "%s: rec'd unexpectedly %s packet",
675 __func__
, "unencrypted");
680 /* Update coherency count for next time (12 bit arithmetic) */
683 /* Check for unexpected compressed packet */
684 if ((header
& MPPC_FLAG_COMPRESSED
) != 0
685 && (d
->cfg
.bits
& MPPC_BIT
) == 0) {
686 log(LOG_ERR
, "%s: rec'd unexpectedly %s packet",
687 __func__
, "compressed");
689 kfree(buf
, M_NETGRAPH
);
693 #ifdef NETGRAPH_MPPC_COMPRESSION
694 /* Decompress packet */
695 if ((header
& MPPC_FLAG_COMPRESSED
) != 0) {
696 int flags
= MPPC_MANDATORY_DECOMPRESS_FLAGS
;
697 u_char
*decompbuf
, *source
, *dest
;
698 u_long sourceCnt
, destCnt
;
701 /* Allocate a buffer for decompressed data */
702 decompbuf
= kmalloc(MPPC_DECOMP_BUFSIZE
+ MPPC_DECOMP_SAFETY
,
703 M_NETGRAPH
, M_NOWAIT
);
704 if (decompbuf
== NULL
) {
705 kfree(buf
, M_NETGRAPH
);
708 decomplen
= MPPC_DECOMP_BUFSIZE
;
710 /* Prepare to decompress */
715 if ((header
& MPPC_FLAG_RESTART
) != 0)
716 flags
|= MPPC_RESTART_HISTORY
;
719 rtn
= MPPC_Decompress(&source
, &dest
,
720 &sourceCnt
, &destCnt
, d
->history
, flags
);
722 /* Check return value */
723 KASSERT(rtn
!= MPPC_INVALID
, ("%s: invalid", __func__
));
724 if ((rtn
& MPPC_DEST_EXHAUSTED
) != 0
725 || (rtn
& MPPC_DECOMP_OK
) != MPPC_DECOMP_OK
) {
726 log(LOG_ERR
, "%s: decomp returned 0x%x",
728 kfree(decompbuf
, M_NETGRAPH
);
732 /* Replace compressed data with decompressed data */
733 kfree(buf
, M_NETGRAPH
);
735 len
= decomplen
- destCnt
;
739 /* Return result in an mbuf */
740 *resultp
= m_devget((caddr_t
)buf
, len
, 0, NULL
);
741 kfree(buf
, M_NETGRAPH
);
742 return (*resultp
== NULL
? ENOBUFS
: 0);
746 * The peer has sent us a CCP ResetRequest, so reset our transmit state.
749 ng_mppc_reset_req(node_p node
)
751 const priv_p priv
= node
->private;
752 struct ng_mppc_dir
*const d
= &priv
->xmit
;
754 #ifdef NETGRAPH_MPPC_COMPRESSION
755 if (d
->history
!= NULL
)
756 MPPC_InitCompressionHistory(d
->history
);
758 #ifdef NETGRAPH_MPPC_ENCRYPTION
759 if ((d
->cfg
.bits
& MPPE_STATELESS
) == 0)
760 rc4_init(&d
->rc4
, d
->key
, KEYLEN(d
->cfg
.bits
));
766 * Generate a new encryption key
769 ng_mppc_getkey(const u_char
*h
, u_char
*h2
, int len
)
771 static const u_char pad1
[10] =
772 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
773 static const u_char pad2
[10] =
774 { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, };
779 bzero(&hash
, sizeof(hash
));
781 SHA1Update(&c
, h
, len
);
782 for (k
= 0; k
< 4; k
++)
783 SHA1Update(&c
, pad1
, sizeof(pad2
));
784 SHA1Update(&c
, h2
, len
);
785 for (k
= 0; k
< 4; k
++)
786 SHA1Update(&c
, pad2
, sizeof(pad2
));
788 bcopy(hash
, h2
, len
);
792 * Update the encryption key
795 ng_mppc_updatekey(u_int32_t bits
,
796 u_char
*key0
, u_char
*key
, struct rc4_state
*rc4
)
798 const int keylen
= KEYLEN(bits
);
800 ng_mppc_getkey(key0
, key
, keylen
);
801 rc4_init(rc4
, key
, keylen
);
802 rc4_crypt(rc4
, key
, key
, keylen
);
803 if ((bits
& MPPE_40
) != 0)
804 bcopy(&ng_mppe_weakenkey
, key
, 3);
805 else if ((bits
& MPPE_56
) != 0)
806 bcopy(&ng_mppe_weakenkey
, key
, 1);
807 rc4_init(rc4
, key
, keylen
);