$NetBSD: patch-bd,v 1.1.1.1 1999/10/08 04:34:43 dbj Exp $

--- pppd/ccp.c.orig	Fri Aug 13 02:46:11 1999
+++ pppd/ccp.c	Sat Sep 25 14:31:25 1999
@@ -33,6 +33,9 @@
 #include "pppd.h"
 #include "fsm.h"
 #include "ccp.h"
+#ifdef MPPE
+#include "mppe.h"
+#endif
 #include <net/ppp-comp.h>
 
 static const char rcsid[] = RCSID;
@@ -75,6 +78,32 @@
     { "-predictor1", o_bool, &ccp_wantoptions[0].predictor_1,
       "don't allow Predictor-1", OPT_A2COPY,
       &ccp_allowoptions[0].predictor_1 },
+#ifdef MPPE
+    { "mppe-40", o_special_noarg, setmppe_40,
+      "Allow 40 bit MPPE encryption" }, 
+    { "+mppe-40", o_special_noarg, setmppe_40,
+      "Allow 40 bit MPPE encryption" }, 
+    { "nomppe-40", o_special_noarg, setnomppe_40,
+      "Disallow 40 bit MPPE encryption" }, 
+    { "-mppe-40", o_special_noarg, setnomppe_40,
+      "Disallow 40 bit MPPE encryption" }, 
+    { "mppe-128", o_special_noarg, setmppe_128,
+      "Allow 128 bit MPPE encryption" }, 
+    { "+mppe-128", o_special_noarg, setmppe_128,
+      "Allow 128 bit MPPE encryption" }, 
+    { "nomppe-128", o_special_noarg, setnomppe_128,
+      "Disallow 128 bit MPPE encryption" }, 
+    { "-mppe-128", o_special_noarg, setnomppe_128,
+      "Disallow 128 bit MPPE encryption" }, 
+    { "mppe-stateless", o_special_noarg, setmppe_stateless,
+      "Allow stateless MPPE encryption" }, 
+    { "+mppe-stateless", o_special_noarg, setmppe_stateless,
+      "Allow stateless MPPE encryption" }, 
+    { "nomppe-stateless", o_special_noarg, setnomppe_stateless,
+      "Disallow stateless MPPE encryption" }, 
+    { "-mppe-stateless", o_special_noarg, setnomppe_stateless,
+      "Disallow stateless MPPE encryption" }, 
+#endif
 
     { NULL }
 };
@@ -157,8 +186,14 @@
 /*
  * Do we want / did we get any compression?
  */
+#ifdef MPPE
+#define ANY_COMPRESS(opt)	((opt).deflate || (opt).bsd_compress \
+				 || (opt).predictor_1 || (opt).predictor_2 \
+				 || (opt).mppe )
+#else
 #define ANY_COMPRESS(opt)	((opt).deflate || (opt).bsd_compress \
 				 || (opt).predictor_1 || (opt).predictor_2)
+#endif
 
 /*
  * Local state (mainly for handling reset-reqs and reset-acks).
@@ -282,6 +317,16 @@
     ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS;
 
     ccp_allowoptions[0].predictor_1 = 1;
+#ifdef MPPE
+    ccp_wantoptions[0].mppe = 0;
+    ccp_wantoptions[0].mppe_stateless = 0;
+    ccp_wantoptions[0].mppe_40 = 0;
+    ccp_wantoptions[0].mppe_128 = 0;
+    ccp_allowoptions[0].mppe_stateless = 1;
+    ccp_allowoptions[0].mppe = 1;
+    ccp_allowoptions[0].mppe_40 = 1;
+    ccp_allowoptions[0].mppe_128 = 1;
+#endif /* MPPE*/
 }
 
 /*
@@ -420,7 +465,7 @@
     fsm *f;
 {
     ccp_options *go = &ccp_gotoptions[f->unit];
-    u_char opt_buf[16];
+    u_char opt_buf[256];
 
     *go = ccp_wantoptions[f->unit];
     all_rejected[f->unit] = 0;
@@ -436,6 +481,18 @@
 	if (ccp_test(f->unit, opt_buf, CILEN_BSD_COMPRESS, 0) <= 0)
 	    go->bsd_compress = 0;
     }
+#ifdef MPPE
+    if (go->mppe) {
+        opt_buf[0] = CI_MPPE;
+        opt_buf[1] = CILEN_MPPE;
+        opt_buf[2] = 0;
+	/* keysize is 8 here */
+        BCOPY(mppe_master_send_key_40, opt_buf+3, 8);
+        BCOPY(mppe_master_recv_key_40, opt_buf+11, 8);
+        if (ccp_test(f->unit, opt_buf, (2*8)+3, 0) <= 0)
+            go->mppe = 0;
+    }
+#endif /*MPPE*/
     if (go->deflate) {
 	if (go->deflate_correct) {
 	    opt_buf[0] = CI_DEFLATE;
@@ -481,6 +538,9 @@
 
     return (go->bsd_compress? CILEN_BSD_COMPRESS: 0)
 	+ (go->deflate? CILEN_DEFLATE: 0)
+#ifdef MPPE
+	+ (go->mppe? CILEN_MPPE: 0)
+#endif
 	+ (go->predictor_1? CILEN_PREDICTOR_1: 0)
 	+ (go->predictor_2? CILEN_PREDICTOR_2: 0);
 }
@@ -529,6 +589,41 @@
 	    p += CILEN_DEFLATE;
 	}
     }
+#ifdef MPPE
+    if (go->mppe) {
+        u_char opt_buf[64];
+        u_int keysize = 0;
+
+        if(!mppe_allowed)
+            go->mppe_stateless = go->mppe_40 = go->mppe_128 = 0;
+        p[0]=CI_MPPE;
+        p[1]=CILEN_MPPE;
+        p[2]=(go->mppe_stateless ? MPPE_STATELESS : 0);
+        p[3]=0;
+        p[4]=0;
+        p[5]=(go->mppe_40 ? MPPE_40BIT : 0) | (go->mppe_128 ? MPPE_128BIT : 0);
+        if(p[5] & MPPE_40BIT) {
+            keysize = 8;
+            BCOPY(mppe_master_send_key_40, opt_buf+3, keysize);
+            BCOPY(mppe_master_recv_key_40, opt_buf+11, keysize);
+        } else if(p[5] & MPPE_128BIT) {
+            keysize = 16;
+            BCOPY(mppe_master_send_key_128, opt_buf+3, keysize);
+            BCOPY(mppe_master_recv_key_128, opt_buf+19, keysize);
+        }
+        if(p[5] != 0) {
+            opt_buf[0]=CI_MPPE;
+            opt_buf[1]=CILEN_MPPE;
+            opt_buf[2] = (go->mppe_stateless) ? 1 : 0;
+            res = ccp_test(f->unit, opt_buf, (2*keysize)+3, 0);
+        } else {
+            res = -1;
+        }
+        if (res > 0) {
+                p += CILEN_MPPE;
+        }
+    }
+#endif /* MPPE*/
     if (go->bsd_compress) {
 	p[0] = CI_BSD_COMPRESS;
 	p[1] = CILEN_BSD_COMPRESS;
@@ -612,6 +707,22 @@
 	    len -= CILEN_DEFLATE;
 	}
     }
+#ifdef MPPE
+    if (go->mppe) {
+        if ( len < CILEN_MPPE
+		|| p[1] != CILEN_MPPE || p[0] != CI_MPPE
+		|| p[2] != (go->mppe_stateless ? MPPE_STATELESS : 0)
+		|| p[3] != 0
+		|| p[4] != 0
+		|| p[5] != ((go->mppe_40 ? MPPE_40BIT : 0) | (go->mppe_128 ? MPPE_128BIT : 0)))
+           return 0;
+        p += CILEN_MPPE;
+        len -= CILEN_MPPE;
+        /* Cope with first/fast ack */
+        if (len == 0)
+            return 1;
+    }
+#endif /* MPPE */
     if (go->bsd_compress) {
 	if (len < CILEN_BSD_COMPRESS
 	    || p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS
@@ -690,6 +801,23 @@
 	}
     }
 
+#ifdef MPPE
+    if (len >= CILEN_MPPE && p[0] == CI_MPPE && p[1] == CILEN_MPPE) {
+	no.mppe = 1;
+	if((p[5] & MPPE_128BIT) == 0)
+	    try.mppe_128 = 0;
+	if((p[5] & MPPE_40BIT) == 0)
+            try.mppe_40 = 0;
+	if((p[2] & MPPE_STATELESS) == 0)
+            try.mppe_stateless = 0;
+	if(!try.mppe_128 && !try.mppe_40) {
+            no.mppe = 0;
+            try.mppe = 0;
+	}
+	p += CILEN_MPPE;
+	len -= CILEN_MPPE;
+    }
+#endif /* MPPE */
     if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
 	&& p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
 	no.bsd_compress = 1;
@@ -762,6 +890,14 @@
 	if (!try.deflate_correct && !try.deflate_draft)
 	    try.deflate = 0;
     }
+#ifdef MPPE
+    if (go->mppe && len >= CILEN_MPPE
+	&& p[0] == CI_MPPE && p[1] == CILEN_MPPE) {
+	try.mppe = 0;
+	p += CILEN_MPPE;
+	len -= CILEN_MPPE;
+    }
+#endif /*MPPE*/
     if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
 	&& p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
 	if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
@@ -875,6 +1011,78 @@
 		}
 		break;
 
+#ifdef MPPE
+	    case CI_MPPE:
+		if (!ao->mppe || clen != CILEN_MPPE) {
+		    newret = CONFREJ;
+		    break;
+		}
+		if(!mppe_allowed)
+		{
+		    newret = CONFREJ;
+		    break;
+		}
+		ho->mppe = 1;
+		if((p[5]&(MPPE_40BIT|MPPE_128BIT)) == (MPPE_40BIT|MPPE_128BIT))
+		{
+		    /* if both are available, select the stronger */
+		    p[5] &= ~MPPE_40BIT;
+		    newret = CONFNAK;
+		}
+		if((p[2] & ~MPPE_STATELESS) != 0
+		   || p[3] != 0
+		   || p[4] != 0
+		   || (p[5] & ~(MPPE_40BIT | MPPE_128BIT)) != 0)
+		{
+    		    ccp_options *wo = &ccp_wantoptions[f->unit];
+		    /* not sure what they want, tell 'em what we got */
+		    p[2] &= MPPE_STATELESS;
+		    p[3] &= 0;
+		    p[4] &= 0;
+		    p[5] &= MPPE_40BIT | MPPE_128BIT;
+		    if(wo->mppe_40)
+		        p[5] |= MPPE_40BIT;
+		    if(wo->mppe_128)
+		        p[5] |= MPPE_128BIT;
+		    newret = CONFNAK;
+		}
+		
+		if((newret == CONFACK) || (newret == CONFNAK))
+		{
+    		    /* 
+		     * The kernel ppp driver needs the session key 
+                     * which is not sent via CCP :( 
+		     */
+		    unsigned int keysize;
+		    unsigned char opt_buf[64];
+		    opt_buf[0] = CI_MPPE;
+		    opt_buf[1] = CILEN_MPPE;
+		    opt_buf[2] = ((p[2] & MPPE_STATELESS) ? 1 : 0);
+		    /* push in our send/receive keys */
+		    if(p[5] & MPPE_40BIT) {
+			ho->mppe_40 = 1;
+			keysize = 8;
+		        BCOPY(mppe_master_send_key_40, opt_buf+3, keysize);
+		        BCOPY(mppe_master_recv_key_40, opt_buf+11, keysize);
+		    } else if(p[5] & MPPE_128BIT) {
+			ho->mppe_128 = 1;
+			keysize = 16;
+		        BCOPY(mppe_master_send_key_128, opt_buf+3, keysize);
+		        BCOPY(mppe_master_recv_key_128, opt_buf+19, keysize);
+		    } else {
+		        ho->mppe = 0;
+		        newret = CONFREJ;
+		        break;
+		    }
+		    /* call ioctl and pass this nasty stuff to the kernel */
+		    if (ccp_test(f->unit, opt_buf, (2*keysize)+3, 1) <= 0){
+			ho->mppe = 0;
+			newret = CONFREJ;
+			break;
+		    }
+		}
+		break;
+#endif /* MPPE */
 	    case CI_BSD_COMPRESS:
 		if (!ao->bsd_compress || clen != CILEN_BSD_COMPRESS) {
 		    newret = CONFREJ;
@@ -996,6 +1204,28 @@
 		     (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""),
 		     opt->deflate_size);
 	break;
+#ifdef MPPE
+    case CI_MPPE:
+	if (opt->mppe_40) {
+	    if (opt->mppe_stateless) {
+		return "MPPE 40 bit, stateless";
+	    } else {
+		return "MPPE 40 bit, non-stateless";
+	    }
+	} else if (opt->mppe_128) {
+	    if (opt->mppe_stateless) {
+		return "MPPE 128 bit, stateless";
+	    } else {
+		return "MPPE 128 bit, non-stateless";
+	    }
+	} else {
+	    if (opt->mppe_stateless) {
+		return "MPPE unknown strength, stateless";
+	    } else {
+		return "MPPE unknown strength, stateless";
+	    }
+	}
+#endif
     case CI_BSD_COMPRESS:
 	if (opt2 != NULL && opt2->bsd_bits != opt->bsd_bits)
 	    slprintf(result, sizeof(result), "BSD-Compress (%d/%d)",
@@ -1134,6 +1364,14 @@
 		    p += CILEN_PREDICTOR_1;
 		}
 		break;
+#ifdef MPPE
+	    case CI_MPPE:
+		if (optlen >= CILEN_MPPE) {
+		    printer(arg, "mppe %x %x %x %x",p[2],p[3],p[4],p[5]);
+		    p += CILEN_MPPE;
+		}
+		break;
+#endif
 	    case CI_PREDICTOR_2:
 		if (optlen >= CILEN_PREDICTOR_2) {
 		    printer(arg, "predictor 2");
@@ -1193,6 +1431,11 @@
 	    error("Lost compression sync: disabling compression");
 	    ccp_close(unit, "Lost compression sync");
 	} else {
+#ifdef MPPE
+	    /* MPPE/MPPC does not requires CCP_RESETREQ */
+	    if (ccp_gotoptions[f->unit].method == CI_MPPE)
+		return;
+#endif
 	    /*
 	     * Send a reset-request to reset the peer's compressor.
 	     * We don't do that if we are still waiting for an
