[PPP]: add PPP MPPE encryption module
From: Matt Domsch <Matt_Domsch@dell.com> The patch below implements the Microsoft Point-to-Point Encryption method as a PPP compressor/decompressor. This is necessary for Linux clients and servers to interoperate with Microsoft Point-to-Point Tunneling Protocol (PPTP) servers (either Microsoft PPTP servers or the poptop project) which use MPPE to encrypt data when creating a VPN. This patch differs from the kernel_ppp_mppe DKMS pacakge at pptpclient.sourceforge.net by utilizing the kernel crypto routines rather than providing its own SHA1 and arcfour implementations. Minor changes to ppp_generic.c try to prevent a link from disabling compression (in our case, the encryption) after it has started using compression (encryption). Feedback to <pptpclient-devel@lists.sourceforge.net> please. Signed-off-by: Matt Domsch <Matt_Domsch@dell.com> Cc: James Cameron <james.cameron@hp.com> Cc: "David S. Miller" <davem@davemloft.net> Signed-off-by: Brice Goglin <Brice.Goglin@ens-lyon.org> Acked-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
6722e78c90
commit
b3f9b92a6e
@@ -137,13 +137,14 @@ struct ppp {
|
||||
|
||||
/*
|
||||
* Bits in flags: SC_NO_TCP_CCID, SC_CCP_OPEN, SC_CCP_UP, SC_LOOP_TRAFFIC,
|
||||
* SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP.
|
||||
* SC_MULTILINK, SC_MP_SHORTSEQ, SC_MP_XSHORTSEQ, SC_COMP_TCP, SC_REJ_COMP_TCP,
|
||||
* SC_MUST_COMP
|
||||
* Bits in rstate: SC_DECOMP_RUN, SC_DC_ERROR, SC_DC_FERROR.
|
||||
* Bits in xstate: SC_COMP_RUN
|
||||
*/
|
||||
#define SC_FLAG_BITS (SC_NO_TCP_CCID|SC_CCP_OPEN|SC_CCP_UP|SC_LOOP_TRAFFIC \
|
||||
|SC_MULTILINK|SC_MP_SHORTSEQ|SC_MP_XSHORTSEQ \
|
||||
|SC_COMP_TCP|SC_REJ_COMP_TCP)
|
||||
|SC_COMP_TCP|SC_REJ_COMP_TCP|SC_MUST_COMP)
|
||||
|
||||
/*
|
||||
* Private data structure for each channel.
|
||||
@@ -1027,6 +1028,56 @@ ppp_xmit_process(struct ppp *ppp)
|
||||
ppp_xmit_unlock(ppp);
|
||||
}
|
||||
|
||||
static inline struct sk_buff *
|
||||
pad_compress_skb(struct ppp *ppp, struct sk_buff *skb)
|
||||
{
|
||||
struct sk_buff *new_skb;
|
||||
int len;
|
||||
int new_skb_size = ppp->dev->mtu +
|
||||
ppp->xcomp->comp_extra + ppp->dev->hard_header_len;
|
||||
int compressor_skb_size = ppp->dev->mtu +
|
||||
ppp->xcomp->comp_extra + PPP_HDRLEN;
|
||||
new_skb = alloc_skb(new_skb_size, GFP_ATOMIC);
|
||||
if (!new_skb) {
|
||||
if (net_ratelimit())
|
||||
printk(KERN_ERR "PPP: no memory (comp pkt)\n");
|
||||
return NULL;
|
||||
}
|
||||
if (ppp->dev->hard_header_len > PPP_HDRLEN)
|
||||
skb_reserve(new_skb,
|
||||
ppp->dev->hard_header_len - PPP_HDRLEN);
|
||||
|
||||
/* compressor still expects A/C bytes in hdr */
|
||||
len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2,
|
||||
new_skb->data, skb->len + 2,
|
||||
compressor_skb_size);
|
||||
if (len > 0 && (ppp->flags & SC_CCP_UP)) {
|
||||
kfree_skb(skb);
|
||||
skb = new_skb;
|
||||
skb_put(skb, len);
|
||||
skb_pull(skb, 2); /* pull off A/C bytes */
|
||||
} else if (len == 0) {
|
||||
/* didn't compress, or CCP not up yet */
|
||||
kfree_skb(new_skb);
|
||||
new_skb = skb;
|
||||
} else {
|
||||
/*
|
||||
* (len < 0)
|
||||
* MPPE requires that we do not send unencrypted
|
||||
* frames. The compressor will return -1 if we
|
||||
* should drop the frame. We cannot simply test
|
||||
* the compress_proto because MPPE and MPPC share
|
||||
* the same number.
|
||||
*/
|
||||
if (net_ratelimit())
|
||||
printk(KERN_ERR "ppp: compressor dropped pkt\n");
|
||||
kfree_skb(skb);
|
||||
kfree_skb(new_skb);
|
||||
new_skb = NULL;
|
||||
}
|
||||
return new_skb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compress and send a frame.
|
||||
* The caller should have locked the xmit path,
|
||||
@@ -1113,29 +1164,14 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
|
||||
/* try to do packet compression */
|
||||
if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0
|
||||
&& proto != PPP_LCP && proto != PPP_CCP) {
|
||||
new_skb = alloc_skb(ppp->dev->mtu + ppp->dev->hard_header_len,
|
||||
GFP_ATOMIC);
|
||||
if (new_skb == 0) {
|
||||
printk(KERN_ERR "PPP: no memory (comp pkt)\n");
|
||||
if (!(ppp->flags & SC_CCP_UP) && (ppp->flags & SC_MUST_COMP)) {
|
||||
if (net_ratelimit())
|
||||
printk(KERN_ERR "ppp: compression required but down - pkt dropped.\n");
|
||||
goto drop;
|
||||
}
|
||||
if (ppp->dev->hard_header_len > PPP_HDRLEN)
|
||||
skb_reserve(new_skb,
|
||||
ppp->dev->hard_header_len - PPP_HDRLEN);
|
||||
|
||||
/* compressor still expects A/C bytes in hdr */
|
||||
len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2,
|
||||
new_skb->data, skb->len + 2,
|
||||
ppp->dev->mtu + PPP_HDRLEN);
|
||||
if (len > 0 && (ppp->flags & SC_CCP_UP)) {
|
||||
kfree_skb(skb);
|
||||
skb = new_skb;
|
||||
skb_put(skb, len);
|
||||
skb_pull(skb, 2); /* pull off A/C bytes */
|
||||
} else {
|
||||
/* didn't compress, or CCP not up yet */
|
||||
kfree_skb(new_skb);
|
||||
}
|
||||
skb = pad_compress_skb(ppp, skb);
|
||||
if (!skb)
|
||||
goto drop;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1155,7 +1191,8 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
|
||||
return;
|
||||
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
if (skb)
|
||||
kfree_skb(skb);
|
||||
++ppp->stats.tx_errors;
|
||||
}
|
||||
|
||||
@@ -1552,6 +1589,9 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
|
||||
&& (ppp->rstate & (SC_DC_FERROR | SC_DC_ERROR)) == 0)
|
||||
skb = ppp_decompress_frame(ppp, skb);
|
||||
|
||||
if (ppp->flags & SC_MUST_COMP && ppp->rstate & SC_DC_FERROR)
|
||||
goto err;
|
||||
|
||||
proto = PPP_PROTO(skb);
|
||||
switch (proto) {
|
||||
case PPP_VJC_COMP:
|
||||
|
Reference in New Issue
Block a user