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 $
41 * $FreeBSD: src/sys/netgraph/ng_mppc.c,v 1.31 2007/05/18 15:28:01 mav Exp $
42 * $DragonFly: src/sys/netgraph7/ng_mppc.c,v 1.2 2008/06/26 23:05:35 dillon Exp $
46 * Microsoft PPP compression (MPPC) and encryption (MPPE) netgraph node type.
48 * You must define one or both of the NETGRAPH_MPPC_COMPRESSION and/or
49 * NETGRAPH_MPPC_ENCRYPTION options for this node type to be useful.
52 #include <sys/param.h>
53 #include <sys/systm.h>
54 #include <sys/kernel.h>
56 #include <sys/malloc.h>
57 #include <sys/errno.h>
58 #include <sys/syslog.h>
60 #include "ng_message.h"
64 #include "opt_netgraph.h"
66 #if !defined(NETGRAPH7_MPPC_COMPRESSION) && !defined(NETGRAPH7_MPPC_ENCRYPTION)
68 /* XXX NETGRAPH7_MPPC_COMPRESSION isn't functional yet */
69 #define NETGRAPH7_MPPC_ENCRYPTION
71 /* This case is indicative of an error in sys/conf files */
72 #error Need either NETGRAPH7_MPPC_COMPRESSION or NETGRAPH7_MPPC_ENCRYPTION
76 #ifdef NG_SEPARATE_MALLOC
77 MALLOC_DEFINE(M_NETGRAPH_MPPC
, "netgraph_mppc", "netgraph mppc node ");
79 #define M_NETGRAPH_MPPC M_NETGRAPH
82 #ifdef NETGRAPH7_MPPC_COMPRESSION
83 /* XXX this file doesn't exist yet, but hopefully someday it will... */
86 #ifdef NETGRAPH7_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 /* MPPC packet header bits */
111 #define MPPC_FLAG_FLUSHED 0x8000 /* xmitter reset state */
112 #define MPPC_FLAG_RESTART 0x4000 /* compress history restart */
113 #define MPPC_FLAG_COMPRESSED 0x2000 /* packet is compresed */
114 #define MPPC_FLAG_ENCRYPTED 0x1000 /* packet is encrypted */
115 #define MPPC_CCOUNT_MASK 0x0fff /* sequence number mask */
117 #define MPPC_CCOUNT_INC(d) ((d) = (((d) + 1) & MPPC_CCOUNT_MASK))
119 #define MPPE_UPDATE_MASK 0xff /* coherency count when we're */
120 #define MPPE_UPDATE_FLAG 0xff /* supposed to update key */
122 #define MPPC_COMP_OK 0x05
123 #define MPPC_DECOMP_OK 0x05
125 /* Per direction info */
127 struct ng_mppc_config cfg
; /* configuration */
128 hook_p hook
; /* netgraph hook */
129 u_int16_t cc
:12; /* coherency count */
130 u_char flushed
; /* clean history (xmit only) */
131 #ifdef NETGRAPH7_MPPC_COMPRESSION
132 u_char
*history
; /* compression history */
134 #ifdef NETGRAPH7_MPPC_ENCRYPTION
135 u_char key
[MPPE_KEY_LEN
]; /* session key */
136 struct rc4_state rc4
; /* rc4 state */
140 /* Node private data */
141 struct ng_mppc_private
{
142 struct ng_mppc_dir xmit
; /* compress/encrypt config */
143 struct ng_mppc_dir recv
; /* decompress/decrypt config */
144 ng_ID_t ctrlnode
; /* path to controlling node */
146 typedef struct ng_mppc_private
*priv_p
;
148 /* Netgraph node methods */
149 static ng_constructor_t ng_mppc_constructor
;
150 static ng_rcvmsg_t ng_mppc_rcvmsg
;
151 static ng_shutdown_t ng_mppc_shutdown
;
152 static ng_newhook_t ng_mppc_newhook
;
153 static ng_rcvdata_t ng_mppc_rcvdata
;
154 static ng_disconnect_t ng_mppc_disconnect
;
156 /* Helper functions */
157 static int ng_mppc_compress(node_p node
,
158 struct mbuf
**datap
);
159 static int ng_mppc_decompress(node_p node
,
160 struct mbuf
**datap
);
161 #ifdef NETGRAPH7_MPPC_ENCRYPTION
162 static void ng_mppc_getkey(const u_char
*h
, u_char
*h2
, int len
);
163 static void ng_mppc_updatekey(u_int32_t bits
,
164 u_char
*key0
, u_char
*key
, struct rc4_state
*rc4
);
166 static void ng_mppc_reset_req(node_p node
);
168 /* Node type descriptor */
169 static struct ng_type ng_mppc_typestruct
= {
170 .version
= NG_ABI_VERSION
,
171 .name
= NG_MPPC_NODE_TYPE
,
172 .constructor
= ng_mppc_constructor
,
173 .rcvmsg
= ng_mppc_rcvmsg
,
174 .shutdown
= ng_mppc_shutdown
,
175 .newhook
= ng_mppc_newhook
,
176 .rcvdata
= ng_mppc_rcvdata
,
177 .disconnect
= ng_mppc_disconnect
,
179 NETGRAPH_INIT(mppc
, &ng_mppc_typestruct
);
181 #ifdef NETGRAPH7_MPPC_ENCRYPTION
182 /* Depend on separate rc4 module */
183 MODULE_DEPEND(ng_mppc
, rc4
, 1, 1, 1);
186 /* Fixed bit pattern to weaken keysize down to 40 or 56 bits */
187 static const u_char ng_mppe_weakenkey
[3] = { 0xd1, 0x26, 0x9e };
189 #define ERROUT(x) do { error = (x); goto done; } while (0)
191 /************************************************************************
193 ************************************************************************/
196 * Node type constructor
199 ng_mppc_constructor(node_p node
)
203 /* Allocate private structure */
204 MALLOC(priv
, priv_p
, sizeof(*priv
), M_NETGRAPH_MPPC
, M_WAITOK
| M_NULLOK
| M_ZERO
);
208 NG_NODE_SET_PRIVATE(node
, priv
);
210 /* This node is not thread safe. */
211 NG_NODE_FORCE_WRITER(node
);
218 * Give our OK for a hook to be added
221 ng_mppc_newhook(node_p node
, hook_p hook
, const char *name
)
223 const priv_p priv
= NG_NODE_PRIVATE(node
);
226 /* Check hook name */
227 if (strcmp(name
, NG_MPPC_HOOK_COMP
) == 0)
228 hookPtr
= &priv
->xmit
.hook
;
229 else if (strcmp(name
, NG_MPPC_HOOK_DECOMP
) == 0)
230 hookPtr
= &priv
->recv
.hook
;
234 /* See if already connected */
235 if (*hookPtr
!= NULL
)
244 * Receive a control message
247 ng_mppc_rcvmsg(node_p node
, item_p item
, hook_p lasthook
)
249 const priv_p priv
= NG_NODE_PRIVATE(node
);
250 struct ng_mesg
*resp
= NULL
;
254 NGI_GET_MSG(item
, msg
);
255 switch (msg
->header
.typecookie
) {
256 case NGM_MPPC_COOKIE
:
257 switch (msg
->header
.cmd
) {
258 case NGM_MPPC_CONFIG_COMP
:
259 case NGM_MPPC_CONFIG_DECOMP
:
261 struct ng_mppc_config
*const cfg
262 = (struct ng_mppc_config
*)msg
->data
;
264 msg
->header
.cmd
== NGM_MPPC_CONFIG_COMP
;
265 struct ng_mppc_dir
*const d
= isComp
?
266 &priv
->xmit
: &priv
->recv
;
268 /* Check configuration */
269 if (msg
->header
.arglen
!= sizeof(*cfg
))
272 if ((cfg
->bits
& ~MPPC_VALID_BITS
) != 0)
274 #ifndef NETGRAPH7_MPPC_COMPRESSION
275 if ((cfg
->bits
& MPPC_BIT
) != 0)
276 ERROUT(EPROTONOSUPPORT
);
278 #ifndef NETGRAPH7_MPPC_ENCRYPTION
279 if ((cfg
->bits
& MPPE_BITS
) != 0)
280 ERROUT(EPROTONOSUPPORT
);
285 /* Save return address so we can send reset-req's */
287 priv
->ctrlnode
= NGI_RETADDR(item
);
289 /* Configuration is OK, reset to it */
292 #ifdef NETGRAPH7_MPPC_COMPRESSION
293 /* Initialize state buffers for compression */
294 if (d
->history
!= NULL
) {
295 FREE(d
->history
, M_NETGRAPH_MPPC
);
298 if ((cfg
->bits
& MPPC_BIT
) != 0) {
299 MALLOC(d
->history
, u_char
*,
300 isComp
? MPPC_SizeOfCompressionHistory() :
301 MPPC_SizeOfDecompressionHistory(),
302 M_NETGRAPH_MPPC
, M_WAITOK
| M_NULLOK
);
303 if (d
->history
== NULL
)
306 MPPC_InitCompressionHistory(d
->history
);
308 MPPC_InitDecompressionHistory(
314 #ifdef NETGRAPH7_MPPC_ENCRYPTION
315 /* Generate initial session keys for encryption */
316 if ((cfg
->bits
& MPPE_BITS
) != 0) {
317 const int keylen
= KEYLEN(cfg
->bits
);
319 bcopy(cfg
->startkey
, d
->key
, keylen
);
320 ng_mppc_getkey(cfg
->startkey
, d
->key
, keylen
);
321 if ((cfg
->bits
& MPPE_40
) != 0)
322 bcopy(&ng_mppe_weakenkey
, d
->key
, 3);
323 else if ((cfg
->bits
& MPPE_56
) != 0)
324 bcopy(&ng_mppe_weakenkey
, d
->key
, 1);
325 rc4_init(&d
->rc4
, d
->key
, keylen
);
329 /* Initialize other state */
335 case NGM_MPPC_RESETREQ
:
336 ng_mppc_reset_req(node
);
349 NG_RESPOND_MSG(error
, node
, item
, resp
);
355 * Receive incoming data on our hook.
358 ng_mppc_rcvdata(hook_p hook
, item_p item
)
360 const node_p node
= NG_HOOK_NODE(hook
);
361 const priv_p priv
= NG_NODE_PRIVATE(node
);
366 /* Compress and/or encrypt */
367 if (hook
== priv
->xmit
.hook
) {
368 if (!priv
->xmit
.cfg
.enable
) {
373 if ((error
= ng_mppc_compress(node
, &m
)) != 0) {
377 NG_FWD_NEW_DATA(error
, item
, priv
->xmit
.hook
, m
);
381 /* Decompress and/or decrypt */
382 if (hook
== priv
->recv
.hook
) {
383 if (!priv
->recv
.cfg
.enable
) {
388 if ((error
= ng_mppc_decompress(node
, &m
)) != 0) {
390 if (error
== EINVAL
&& priv
->ctrlnode
!= 0) {
393 /* Need to send a reset-request */
394 NG_MKMESSAGE(msg
, NGM_MPPC_COOKIE
,
395 NGM_MPPC_RESETREQ
, 0, M_WAITOK
| M_NULLOK
);
398 NG_SEND_MSG_ID(error
, node
, msg
,
403 NG_FWD_NEW_DATA(error
, item
, priv
->recv
.hook
, m
);
408 panic("%s: unknown hook", __func__
);
409 #ifdef RESTARTABLE_PANICS
418 ng_mppc_shutdown(node_p node
)
420 const priv_p priv
= NG_NODE_PRIVATE(node
);
422 /* Take down netgraph node */
423 #ifdef NETGRAPH7_MPPC_COMPRESSION
424 if (priv
->xmit
.history
!= NULL
)
425 FREE(priv
->xmit
.history
, M_NETGRAPH_MPPC
);
426 if (priv
->recv
.history
!= NULL
)
427 FREE(priv
->recv
.history
, M_NETGRAPH_MPPC
);
429 bzero(priv
, sizeof(*priv
));
430 FREE(priv
, M_NETGRAPH_MPPC
);
431 NG_NODE_SET_PRIVATE(node
, NULL
);
432 NG_NODE_UNREF(node
); /* let the node escape */
440 ng_mppc_disconnect(hook_p hook
)
442 const node_p node
= NG_HOOK_NODE(hook
);
443 const priv_p priv
= NG_NODE_PRIVATE(node
);
445 /* Zero out hook pointer */
446 if (hook
== priv
->xmit
.hook
)
447 priv
->xmit
.hook
= NULL
;
448 if (hook
== priv
->recv
.hook
)
449 priv
->recv
.hook
= NULL
;
451 /* Go away if no longer connected */
452 if ((NG_NODE_NUMHOOKS(node
) == 0)
453 && NG_NODE_IS_VALID(node
))
454 ng_rmnode_self(node
);
458 /************************************************************************
460 ************************************************************************/
463 * Compress/encrypt a packet and put the result in a new mbuf at *resultp.
464 * The original mbuf is not free'd.
467 ng_mppc_compress(node_p node
, struct mbuf
**datap
)
469 const priv_p priv
= NG_NODE_PRIVATE(node
);
470 struct ng_mppc_dir
*const d
= &priv
->xmit
;
472 struct mbuf
*m
= *datap
;
477 /* Always set the flushed bit in stateless mode */
478 if (d
->flushed
|| ((d
->cfg
.bits
& MPPE_STATELESS
) != 0)) {
479 header
|= MPPC_FLAG_FLUSHED
;
483 /* Compress packet (if compression enabled) */
484 #ifdef NETGRAPH7_MPPC_COMPRESSION
485 if ((d
->cfg
.bits
& MPPC_BIT
) != 0) {
486 u_short flags
= MPPC_MANDATORY_COMPRESS_FLAGS
;
487 u_char
*inbuf
, *outbuf
;
489 u_char
*source
, *dest
;
490 u_long sourceCnt
, destCnt
;
493 /* Work with contiguous regions of memory. */
494 inlen
= m
->m_pkthdr
.len
;
495 inbuf
= kmalloc(inlen
, M_NETGRAPH_MPPC
, M_WAITOK
| M_NULLOK
);
500 m_copydata(m
, 0, inlen
, (caddr_t
)inbuf
);
502 outlen
= MPPC_MAX_BLOWUP(inlen
);
503 outbuf
= kmalloc(outlen
, M_NETGRAPH_MPPC
, M_WAITOK
| M_NULLOK
);
504 if (outbuf
== NULL
) {
506 kfree(inbuf
, M_NETGRAPH_MPPC
);
510 /* Prepare to compress */
515 if ((d
->cfg
.bits
& MPPE_STATELESS
) == 0)
516 flags
|= MPPC_SAVE_HISTORY
;
519 rtn
= MPPC_Compress(&source
, &dest
, &sourceCnt
,
520 &destCnt
, d
->history
, flags
, 0);
522 /* Check return value */
523 KASSERT(rtn
!= MPPC_INVALID
, ("%s: invalid", __func__
));
524 if ((rtn
& MPPC_EXPANDED
) == 0
525 && (rtn
& MPPC_COMP_OK
) == MPPC_COMP_OK
) {
527 header
|= MPPC_FLAG_COMPRESSED
;
528 if ((rtn
& MPPC_RESTART_HISTORY
) != 0)
529 header
|= MPPC_FLAG_RESTART
;
531 /* Replace m by the compresed one. */
533 m
= m_devget((caddr_t
)outbuf
, outlen
, 0, NULL
, NULL
);
535 d
->flushed
= (rtn
& MPPC_EXPANDED
) != 0
536 || (flags
& MPPC_SAVE_HISTORY
) == 0;
538 kfree(inbuf
, M_NETGRAPH_MPPC
);
539 kfree(outbuf
, M_NETGRAPH_MPPC
);
541 /* Check m_devget() result. */
547 /* Now encrypt packet (if encryption enabled) */
548 #ifdef NETGRAPH7_MPPC_ENCRYPTION
549 if ((d
->cfg
.bits
& MPPE_BITS
) != 0) {
552 /* Set header bits */
553 header
|= MPPC_FLAG_ENCRYPTED
;
555 /* Update key if it's time */
556 if ((d
->cfg
.bits
& MPPE_STATELESS
) != 0
557 || (d
->cc
& MPPE_UPDATE_MASK
) == MPPE_UPDATE_FLAG
) {
558 ng_mppc_updatekey(d
->cfg
.bits
,
559 d
->cfg
.startkey
, d
->key
, &d
->rc4
);
560 } else if ((header
& MPPC_FLAG_FLUSHED
) != 0) {
561 /* Need to reset key if we say we did
562 and ng_mppc_updatekey wasn't called to do it also. */
563 rc4_init(&d
->rc4
, d
->key
, KEYLEN(d
->cfg
.bits
));
566 /* We must own the mbuf chain exclusively to modify it. */
567 m
= m_unshare(m
, MB_DONTWAIT
);
574 rc4_crypt(&d
->rc4
, mtod(m1
, u_char
*),
575 mtod(m1
, u_char
*), m1
->m_len
);
581 /* Update coherency count for next time (12 bit arithmetic) */
582 MPPC_CCOUNT_INC(d
->cc
);
585 M_PREPEND(m
, MPPC_HDRLEN
, MB_DONTWAIT
);
587 *(mtod(m
, uint16_t *)) = htons(header
);
590 return (*datap
== NULL
? ENOBUFS
: 0);
594 * Decompress/decrypt packet and put the result in a new mbuf at *resultp.
595 * The original mbuf is not free'd.
598 ng_mppc_decompress(node_p node
, struct mbuf
**datap
)
600 const priv_p priv
= NG_NODE_PRIVATE(node
);
601 struct ng_mppc_dir
*const d
= &priv
->recv
;
602 u_int16_t header
, cc
;
604 struct mbuf
*m
= *datap
;
606 /* Pull off header */
607 if (m
->m_pkthdr
.len
< MPPC_HDRLEN
) {
611 m_copydata(m
, 0, MPPC_HDRLEN
, (caddr_t
)&header
);
612 header
= ntohs(header
);
613 cc
= (header
& MPPC_CCOUNT_MASK
);
614 m_adj(m
, MPPC_HDRLEN
);
616 /* Check for an unexpected jump in the sequence number */
617 numLost
= ((cc
- d
->cc
) & MPPC_CCOUNT_MASK
);
619 /* If flushed bit set, we can always handle packet */
620 if ((header
& MPPC_FLAG_FLUSHED
) != 0) {
621 #ifdef NETGRAPH7_MPPC_COMPRESSION
622 if (d
->history
!= NULL
)
623 MPPC_InitDecompressionHistory(d
->history
);
625 #ifdef NETGRAPH7_MPPC_ENCRYPTION
626 if ((d
->cfg
.bits
& MPPE_BITS
) != 0) {
629 /* How many times are we going to have to re-key? */
630 rekey
= ((d
->cfg
.bits
& MPPE_STATELESS
) != 0) ?
631 numLost
: (numLost
/ (MPPE_UPDATE_MASK
+ 1));
632 if (rekey
> MPPE_MAX_REKEY
) {
633 log(LOG_ERR
, "%s: too many (%d) packets"
634 " dropped, disabling node %p!",
635 __func__
, numLost
, node
);
636 priv
->recv
.cfg
.enable
= 0;
640 /* Re-key as necessary to catch up to peer */
641 while (d
->cc
!= cc
) {
642 if ((d
->cfg
.bits
& MPPE_STATELESS
) != 0
643 || (d
->cc
& MPPE_UPDATE_MASK
)
644 == MPPE_UPDATE_FLAG
) {
645 ng_mppc_updatekey(d
->cfg
.bits
,
646 d
->cfg
.startkey
, d
->key
, &d
->rc4
);
648 MPPC_CCOUNT_INC(d
->cc
);
651 /* Reset key (except in stateless mode, see below) */
652 if ((d
->cfg
.bits
& MPPE_STATELESS
) == 0)
653 rc4_init(&d
->rc4
, d
->key
, KEYLEN(d
->cfg
.bits
));
656 d
->cc
= cc
; /* skip over lost seq numbers */
657 numLost
= 0; /* act like no packets were lost */
660 /* Can't decode non-sequential packets without a flushed bit */
665 if ((header
& MPPC_FLAG_ENCRYPTED
) != 0) {
666 #ifdef NETGRAPH7_MPPC_ENCRYPTION
670 /* Are we not expecting encryption? */
671 if ((d
->cfg
.bits
& MPPE_BITS
) == 0) {
672 log(LOG_ERR
, "%s: rec'd unexpectedly %s packet",
673 __func__
, "encrypted");
677 #ifdef NETGRAPH7_MPPC_ENCRYPTION
678 /* Update key if it's time (always in stateless mode) */
679 if ((d
->cfg
.bits
& MPPE_STATELESS
) != 0
680 || (d
->cc
& MPPE_UPDATE_MASK
) == MPPE_UPDATE_FLAG
) {
681 ng_mppc_updatekey(d
->cfg
.bits
,
682 d
->cfg
.startkey
, d
->key
, &d
->rc4
);
685 /* We must own the mbuf chain exclusively to modify it. */
686 m
= m_unshare(m
, MB_DONTWAIT
);
693 rc4_crypt(&d
->rc4
, mtod(m1
, u_char
*),
694 mtod(m1
, u_char
*), m1
->m_len
);
700 /* Are we expecting encryption? */
701 if ((d
->cfg
.bits
& MPPE_BITS
) != 0) {
702 log(LOG_ERR
, "%s: rec'd unexpectedly %s packet",
703 __func__
, "unencrypted");
708 /* Update coherency count for next time (12 bit arithmetic) */
709 MPPC_CCOUNT_INC(d
->cc
);
711 /* Check for unexpected compressed packet */
712 if ((header
& MPPC_FLAG_COMPRESSED
) != 0
713 && (d
->cfg
.bits
& MPPC_BIT
) == 0) {
714 log(LOG_ERR
, "%s: rec'd unexpectedly %s packet",
715 __func__
, "compressed");
721 #ifdef NETGRAPH7_MPPC_COMPRESSION
722 /* Decompress packet */
723 if ((header
& MPPC_FLAG_COMPRESSED
) != 0) {
724 int flags
= MPPC_MANDATORY_DECOMPRESS_FLAGS
;
725 u_char
*decompbuf
, *source
, *dest
;
726 u_long sourceCnt
, destCnt
;
731 /* Copy payload into a contiguous region of memory. */
732 len
= m
->m_pkthdr
.len
;
733 buf
= kmalloc(len
, M_NETGRAPH_MPPC
, M_WAITOK
| M_NULLOK
);
738 m_copydata(m
, 0, len
, (caddr_t
)buf
);
740 /* Allocate a buffer for decompressed data */
741 decompbuf
= kmalloc(MPPC_DECOMP_BUFSIZE
+ MPPC_DECOMP_SAFETY
,
742 M_NETGRAPH_MPPC
, M_WAITOK
| M_NULLOK
);
743 if (decompbuf
== NULL
) {
745 kfree(buf
, M_NETGRAPH_MPPC
);
748 decomplen
= MPPC_DECOMP_BUFSIZE
;
750 /* Prepare to decompress */
755 if ((header
& MPPC_FLAG_RESTART
) != 0)
756 flags
|= MPPC_RESTART_HISTORY
;
759 rtn
= MPPC_Decompress(&source
, &dest
,
760 &sourceCnt
, &destCnt
, d
->history
, flags
);
762 /* Check return value */
763 KASSERT(rtn
!= MPPC_INVALID
, ("%s: invalid", __func__
));
764 if ((rtn
& MPPC_DEST_EXHAUSTED
) != 0
765 || (rtn
& MPPC_DECOMP_OK
) != MPPC_DECOMP_OK
) {
766 log(LOG_ERR
, "%s: decomp returned 0x%x",
768 kfree(buf
, M_NETGRAPH_MPPC
);
769 kfree(decompbuf
, M_NETGRAPH_MPPC
);
773 /* Replace compressed data with decompressed data */
774 kfree(buf
, M_NETGRAPH_MPPC
);
775 len
= decomplen
- destCnt
;
778 m
= m_devget((caddr_t
)decompbuf
, len
, 0, NULL
, NULL
);
779 kfree(decompbuf
, M_NETGRAPH_MPPC
);
783 /* Return result in an mbuf */
785 return (*datap
== NULL
? ENOBUFS
: 0);
789 * The peer has sent us a CCP ResetRequest, so reset our transmit state.
792 ng_mppc_reset_req(node_p node
)
794 const priv_p priv
= NG_NODE_PRIVATE(node
);
795 struct ng_mppc_dir
*const d
= &priv
->xmit
;
797 #ifdef NETGRAPH7_MPPC_COMPRESSION
798 if (d
->history
!= NULL
)
799 MPPC_InitCompressionHistory(d
->history
);
801 #ifdef NETGRAPH7_MPPC_ENCRYPTION
802 if ((d
->cfg
.bits
& MPPE_STATELESS
) == 0)
803 rc4_init(&d
->rc4
, d
->key
, KEYLEN(d
->cfg
.bits
));
808 #ifdef NETGRAPH7_MPPC_ENCRYPTION
810 * Generate a new encryption key
813 ng_mppc_getkey(const u_char
*h
, u_char
*h2
, int len
)
815 static const u_char pad1
[10] =
816 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
817 static const u_char pad2
[10] =
818 { 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, };
824 SHA1Update(&c
, h
, len
);
825 for (k
= 0; k
< 4; k
++)
826 SHA1Update(&c
, pad1
, sizeof(pad1
));
827 SHA1Update(&c
, h2
, len
);
828 for (k
= 0; k
< 4; k
++)
829 SHA1Update(&c
, pad2
, sizeof(pad2
));
831 bcopy(hash
, h2
, len
);
835 * Update the encryption key
838 ng_mppc_updatekey(u_int32_t bits
,
839 u_char
*key0
, u_char
*key
, struct rc4_state
*rc4
)
841 const int keylen
= KEYLEN(bits
);
843 ng_mppc_getkey(key0
, key
, keylen
);
844 rc4_init(rc4
, key
, keylen
);
845 rc4_crypt(rc4
, key
, key
, keylen
);
846 if ((bits
& MPPE_40
) != 0)
847 bcopy(&ng_mppe_weakenkey
, key
, 3);
848 else if ((bits
& MPPE_56
) != 0)
849 bcopy(&ng_mppe_weakenkey
, key
, 1);
850 rc4_init(rc4
, key
, keylen
);