17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * ccp.c - PPP Compression Control Protocol.
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * Copyright (c) 2000 by Sun Microsystems, Inc.
57c478bd9Sstevel@tonic-gate  * All rights reserved.
67c478bd9Sstevel@tonic-gate  *
77c478bd9Sstevel@tonic-gate  * Copyright (c) 1994 The Australian National University.
87c478bd9Sstevel@tonic-gate  * All rights reserved.
97c478bd9Sstevel@tonic-gate  *
107c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software and its
117c478bd9Sstevel@tonic-gate  * documentation is hereby granted, provided that the above copyright
127c478bd9Sstevel@tonic-gate  * notice appears in all copies.  This software is provided without any
137c478bd9Sstevel@tonic-gate  * warranty, express or implied. The Australian National University
147c478bd9Sstevel@tonic-gate  * makes no representations about the suitability of this software for
157c478bd9Sstevel@tonic-gate  * any purpose.
167c478bd9Sstevel@tonic-gate  *
177c478bd9Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
187c478bd9Sstevel@tonic-gate  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
197c478bd9Sstevel@tonic-gate  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
207c478bd9Sstevel@tonic-gate  * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
217c478bd9Sstevel@tonic-gate  * OF SUCH DAMAGE.
227c478bd9Sstevel@tonic-gate  *
237c478bd9Sstevel@tonic-gate  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
247c478bd9Sstevel@tonic-gate  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
257c478bd9Sstevel@tonic-gate  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
267c478bd9Sstevel@tonic-gate  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
277c478bd9Sstevel@tonic-gate  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
287c478bd9Sstevel@tonic-gate  * OR MODIFICATIONS.
297c478bd9Sstevel@tonic-gate  */
30*48bbca81SDaniel Hoffman /*
31*48bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
32*48bbca81SDaniel Hoffman  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <stdlib.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include "pppd.h"
387c478bd9Sstevel@tonic-gate #include "fsm.h"
397c478bd9Sstevel@tonic-gate #include "ccp.h"
407c478bd9Sstevel@tonic-gate #include <net/ppp-comp.h>
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate  * Command-line options.
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate static int setbsdcomp __P((char **, option_t *));
467c478bd9Sstevel@tonic-gate static int setdeflate __P((char **, option_t *));
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate static option_t ccp_option_list[] = {
497c478bd9Sstevel@tonic-gate     { "noccp", o_bool, &ccp_protent.enabled_flag,
507c478bd9Sstevel@tonic-gate       "Disable CCP negotiation" },
517c478bd9Sstevel@tonic-gate     { "-ccp", o_bool, &ccp_protent.enabled_flag,
527c478bd9Sstevel@tonic-gate       "Disable CCP negotiation" },
537c478bd9Sstevel@tonic-gate     { "bsdcomp", o_special, (void *)setbsdcomp,
547c478bd9Sstevel@tonic-gate       "Request BSD-Compress packet compression" },
557c478bd9Sstevel@tonic-gate     { "nobsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress,
567c478bd9Sstevel@tonic-gate       "don't allow BSD-Compress", OPT_A2COPY,
577c478bd9Sstevel@tonic-gate       &ccp_allowoptions[0].bsd_compress },
587c478bd9Sstevel@tonic-gate     { "-bsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress,
597c478bd9Sstevel@tonic-gate       "don't allow BSD-Compress", OPT_A2COPY,
607c478bd9Sstevel@tonic-gate       &ccp_allowoptions[0].bsd_compress },
617c478bd9Sstevel@tonic-gate     { "deflate", o_special, (void *)setdeflate,
627c478bd9Sstevel@tonic-gate       "request Deflate compression" },
637c478bd9Sstevel@tonic-gate     { "nodeflate", o_bool, &ccp_wantoptions[0].deflate,
647c478bd9Sstevel@tonic-gate       "don't allow Deflate compression", OPT_A2COPY,
657c478bd9Sstevel@tonic-gate       &ccp_allowoptions[0].deflate },
667c478bd9Sstevel@tonic-gate     { "-deflate", o_bool, &ccp_wantoptions[0].deflate,
677c478bd9Sstevel@tonic-gate       "don't allow Deflate compression", OPT_A2COPY,
687c478bd9Sstevel@tonic-gate       &ccp_allowoptions[0].deflate },
697c478bd9Sstevel@tonic-gate     { "nodeflatedraft", o_bool, &ccp_wantoptions[0].deflate_draft,
707c478bd9Sstevel@tonic-gate       "don't use draft deflate #", OPT_A2COPY,
717c478bd9Sstevel@tonic-gate       &ccp_allowoptions[0].deflate_draft },
727c478bd9Sstevel@tonic-gate     { "predictor1", o_bool, &ccp_wantoptions[0].predictor_1,
737c478bd9Sstevel@tonic-gate       "request Predictor-1", 1, &ccp_allowoptions[0].predictor_1 },
747c478bd9Sstevel@tonic-gate     { "nopredictor1", o_bool, &ccp_wantoptions[0].predictor_1,
757c478bd9Sstevel@tonic-gate       "don't allow Predictor-1", OPT_A2COPY,
767c478bd9Sstevel@tonic-gate       &ccp_allowoptions[0].predictor_1 },
777c478bd9Sstevel@tonic-gate     { "-predictor1", o_bool, &ccp_wantoptions[0].predictor_1,
787c478bd9Sstevel@tonic-gate       "don't allow Predictor-1", OPT_A2COPY,
797c478bd9Sstevel@tonic-gate       &ccp_allowoptions[0].predictor_1 },
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate     { NULL }
827c478bd9Sstevel@tonic-gate };
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate  * Protocol entry points from main code.
867c478bd9Sstevel@tonic-gate  */
877c478bd9Sstevel@tonic-gate static void ccp_init __P((int unit));
887c478bd9Sstevel@tonic-gate static void ccp_open __P((int unit));
897c478bd9Sstevel@tonic-gate static void ccp_close __P((int unit, char *));
907c478bd9Sstevel@tonic-gate static void ccp_lowerup __P((int unit));
917c478bd9Sstevel@tonic-gate static void ccp_lowerdown __P((int));
927c478bd9Sstevel@tonic-gate static void ccp_input __P((int unit, u_char *pkt, int len));
937c478bd9Sstevel@tonic-gate static void ccp_protrej __P((int unit));
947c478bd9Sstevel@tonic-gate static int  ccp_printpkt __P((u_char *pkt, int len,
957c478bd9Sstevel@tonic-gate 			      void (*printer) __P((void *, const char *, ...)),
967c478bd9Sstevel@tonic-gate 			      void *arg));
977c478bd9Sstevel@tonic-gate static void ccp_datainput __P((int unit, u_char *pkt, int len));
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate struct protent ccp_protent = {
1007c478bd9Sstevel@tonic-gate     PPP_CCP,
1017c478bd9Sstevel@tonic-gate     ccp_init,
1027c478bd9Sstevel@tonic-gate     ccp_input,
1037c478bd9Sstevel@tonic-gate     ccp_protrej,
1047c478bd9Sstevel@tonic-gate     ccp_lowerup,
1057c478bd9Sstevel@tonic-gate     ccp_lowerdown,
1067c478bd9Sstevel@tonic-gate     ccp_open,
1077c478bd9Sstevel@tonic-gate     ccp_close,
1087c478bd9Sstevel@tonic-gate     ccp_printpkt,
1097c478bd9Sstevel@tonic-gate     ccp_datainput,
1107c478bd9Sstevel@tonic-gate     1,
1117c478bd9Sstevel@tonic-gate     "CCP",
1127c478bd9Sstevel@tonic-gate     "Compressed",
1137c478bd9Sstevel@tonic-gate     ccp_option_list,
1147c478bd9Sstevel@tonic-gate     NULL,
1157c478bd9Sstevel@tonic-gate     NULL,
1167c478bd9Sstevel@tonic-gate     NULL
1177c478bd9Sstevel@tonic-gate };
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate fsm ccp_fsm[NUM_PPP];
1207c478bd9Sstevel@tonic-gate ccp_options ccp_wantoptions[NUM_PPP];	/* what to request the peer to use */
1217c478bd9Sstevel@tonic-gate ccp_options ccp_gotoptions[NUM_PPP];	/* what the peer agreed to do */
1227c478bd9Sstevel@tonic-gate ccp_options ccp_allowoptions[NUM_PPP];	/* what we'll agree to do */
1237c478bd9Sstevel@tonic-gate ccp_options ccp_hisoptions[NUM_PPP];	/* what we agreed to do */
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /*
1267c478bd9Sstevel@tonic-gate  * Callbacks for fsm code.
1277c478bd9Sstevel@tonic-gate  */
1287c478bd9Sstevel@tonic-gate static void ccp_resetci __P((fsm *));
1297c478bd9Sstevel@tonic-gate static int  ccp_cilen __P((fsm *));
1307c478bd9Sstevel@tonic-gate static void ccp_addci __P((fsm *, u_char *, int *));
1317c478bd9Sstevel@tonic-gate static int  ccp_ackci __P((fsm *, u_char *, int));
1327c478bd9Sstevel@tonic-gate static int  ccp_nakci __P((fsm *, u_char *, int));
1337c478bd9Sstevel@tonic-gate static int  ccp_rejci __P((fsm *, u_char *, int));
1347c478bd9Sstevel@tonic-gate static int  ccp_reqci __P((fsm *, u_char *, int *, int));
1357c478bd9Sstevel@tonic-gate static void ccp_up __P((fsm *));
1367c478bd9Sstevel@tonic-gate static void ccp_down __P((fsm *));
1377c478bd9Sstevel@tonic-gate static int  ccp_extcode __P((fsm *, int, int, u_char *, int));
1387c478bd9Sstevel@tonic-gate static int  ccp_codereject __P((fsm *p, int code, int id, u_char *inp,
1397c478bd9Sstevel@tonic-gate     int len));
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate static fsm_callbacks ccp_callbacks = {
1427c478bd9Sstevel@tonic-gate     ccp_resetci,		/* Reset our Configuration Information */
1437c478bd9Sstevel@tonic-gate     ccp_cilen,                  /* Length of our Configuration Information */
1447c478bd9Sstevel@tonic-gate     ccp_addci,                  /* Add our Configuration Information */
1457c478bd9Sstevel@tonic-gate     ccp_ackci,                  /* ACK our Configuration Information */
1467c478bd9Sstevel@tonic-gate     ccp_nakci,                  /* NAK our Configuration Information */
1477c478bd9Sstevel@tonic-gate     ccp_rejci,                  /* Reject our Configuration Information */
1487c478bd9Sstevel@tonic-gate     ccp_reqci,                  /* Request peer's Configuration Information */
1497c478bd9Sstevel@tonic-gate     ccp_up,                     /* Called when fsm reaches OPENED state */
1507c478bd9Sstevel@tonic-gate     ccp_down,                   /* Called when fsm leaves OPENED state */
1517c478bd9Sstevel@tonic-gate     NULL,                       /* Called when we want the lower layer up */
1527c478bd9Sstevel@tonic-gate     NULL,                       /* Called when we want the lower layer down */
1537c478bd9Sstevel@tonic-gate     NULL,			/* Retransmission is necessary */
1547c478bd9Sstevel@tonic-gate     ccp_extcode,                /* Called to handle LCP-specific codes */
1557c478bd9Sstevel@tonic-gate     "CCP",			/* String name of protocol */
1567c478bd9Sstevel@tonic-gate     ccp_codereject,             /* Peer rejected a code number */
1577c478bd9Sstevel@tonic-gate };
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate /*
1607c478bd9Sstevel@tonic-gate  * Local statics.
1617c478bd9Sstevel@tonic-gate  */
1627c478bd9Sstevel@tonic-gate static void ccp_rack_timeout __P((void *));
1637c478bd9Sstevel@tonic-gate static char * method_name __P((ccp_options *, ccp_options *));
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate /*
1667c478bd9Sstevel@tonic-gate  * Do we want / did we get any compression?
1677c478bd9Sstevel@tonic-gate  */
1687c478bd9Sstevel@tonic-gate #define ANY_COMPRESS(opt)	((opt).deflate || (opt).bsd_compress \
1697c478bd9Sstevel@tonic-gate 				 || (opt).predictor_1 || (opt).predictor_2)
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate /*
1727c478bd9Sstevel@tonic-gate  * Local state (mainly for handling reset-reqs and reset-acks).
1737c478bd9Sstevel@tonic-gate  */
1747c478bd9Sstevel@tonic-gate static int ccp_localstate[NUM_PPP];
1757c478bd9Sstevel@tonic-gate #define RACK_PENDING	0x0001	/* waiting for reset-ack */
1767c478bd9Sstevel@tonic-gate #define RREQ_REPEAT	0x0002	/* send another reset-req if no reset-ack */
1777c478bd9Sstevel@tonic-gate #define RREQ_REJECTED	0x0004	/* peer code-rejected reset-request */
1787c478bd9Sstevel@tonic-gate #define RACK_REJECTED	0x0008	/* peer code-rejected reset-ack */
1797c478bd9Sstevel@tonic-gate #define RREQ_IGNORED	0x0010	/* peer just ignored reset-request */
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate #define RACKTIMEOUT	1	/* time in seconds between Reset-Requests */
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate static int all_rejected[NUM_PPP];	/* we rejected all peer's options */
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate #ifdef COMP_TUNE
1867c478bd9Sstevel@tonic-gate static int deflate_tune = -1;	/* compression effort level for deflate */
1877c478bd9Sstevel@tonic-gate #endif
1887c478bd9Sstevel@tonic-gate static int deflate_rmax = DEFLATE_MAX_SIZE;	/* max rbits */
1897c478bd9Sstevel@tonic-gate static int deflate_amax = DEFLATE_MAX_SIZE;	/* max abits */
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate /*
1927c478bd9Sstevel@tonic-gate  * Option parsing.
1937c478bd9Sstevel@tonic-gate  */
1947c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1957c478bd9Sstevel@tonic-gate static int
setbsdcomp(argv,opt)1967c478bd9Sstevel@tonic-gate setbsdcomp(argv, opt)
1977c478bd9Sstevel@tonic-gate     char **argv;
1987c478bd9Sstevel@tonic-gate     option_t *opt;
1997c478bd9Sstevel@tonic-gate {
2007c478bd9Sstevel@tonic-gate     int rbits, abits;
2017c478bd9Sstevel@tonic-gate     char *str, *endp;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate     str = *argv;
2047c478bd9Sstevel@tonic-gate     abits = rbits = strtol(str, &endp, 0);
2057c478bd9Sstevel@tonic-gate     if (endp != str && *endp == ',') {
2067c478bd9Sstevel@tonic-gate 	str = endp + 1;
2077c478bd9Sstevel@tonic-gate 	abits = strtol(str, &endp, 0);
2087c478bd9Sstevel@tonic-gate     }
2097c478bd9Sstevel@tonic-gate     if (*endp != '\0' || endp == str) {
2107c478bd9Sstevel@tonic-gate 	option_error("invalid parameter '%s' for bsdcomp option", *argv);
2117c478bd9Sstevel@tonic-gate 	return 0;
2127c478bd9Sstevel@tonic-gate     }
2137c478bd9Sstevel@tonic-gate     if ((rbits != 0 && (rbits < BSD_MIN_BITS || rbits > BSD_MAX_BITS))
2147c478bd9Sstevel@tonic-gate 	|| (abits != 0 && (abits < BSD_MIN_BITS || abits > BSD_MAX_BITS))) {
2157c478bd9Sstevel@tonic-gate 	option_error("bsdcomp option values must be 0 or %d .. %d",
2167c478bd9Sstevel@tonic-gate 		     BSD_MIN_BITS, BSD_MAX_BITS);
2177c478bd9Sstevel@tonic-gate 	return 0;
2187c478bd9Sstevel@tonic-gate     }
2197c478bd9Sstevel@tonic-gate     if (rbits > 0) {
2207c478bd9Sstevel@tonic-gate 	ccp_wantoptions[0].bsd_compress = 1;
2217c478bd9Sstevel@tonic-gate 	ccp_wantoptions[0].bsd_bits = rbits;
2227c478bd9Sstevel@tonic-gate     } else
2237c478bd9Sstevel@tonic-gate 	ccp_wantoptions[0].bsd_compress = 0;
2247c478bd9Sstevel@tonic-gate     if (abits > 0) {
2257c478bd9Sstevel@tonic-gate 	ccp_allowoptions[0].bsd_compress = 1;
2267c478bd9Sstevel@tonic-gate 	ccp_allowoptions[0].bsd_bits = abits;
2277c478bd9Sstevel@tonic-gate     } else
2287c478bd9Sstevel@tonic-gate 	ccp_allowoptions[0].bsd_compress = 0;
2297c478bd9Sstevel@tonic-gate     return 1;
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2337c478bd9Sstevel@tonic-gate static int
setdeflate(argv,opt)2347c478bd9Sstevel@tonic-gate setdeflate(argv, opt)
2357c478bd9Sstevel@tonic-gate     char **argv;
2367c478bd9Sstevel@tonic-gate     option_t *opt;
2377c478bd9Sstevel@tonic-gate {
2387c478bd9Sstevel@tonic-gate     int rbits, abits, def_rmax, def_amax;
2397c478bd9Sstevel@tonic-gate     char *str, *endp;
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate     str = endp = *argv;
2427c478bd9Sstevel@tonic-gate     if (*str == ',')
2437c478bd9Sstevel@tonic-gate 	abits = rbits = -1;
2447c478bd9Sstevel@tonic-gate     else
2457c478bd9Sstevel@tonic-gate 	abits = rbits = strtol(str, &endp, 0);
2467c478bd9Sstevel@tonic-gate     if (*endp == ',') {
2477c478bd9Sstevel@tonic-gate 	str = ++endp;
2487c478bd9Sstevel@tonic-gate 	if (*str == ',')
2497c478bd9Sstevel@tonic-gate 	    abits = rbits;
2507c478bd9Sstevel@tonic-gate 	else
2517c478bd9Sstevel@tonic-gate 	    abits = strtol(str, &endp, 0);
2527c478bd9Sstevel@tonic-gate     }
2537c478bd9Sstevel@tonic-gate #ifdef COMP_TUNE
2547c478bd9Sstevel@tonic-gate     if (*endp == ',' && privileged_option) {
2557c478bd9Sstevel@tonic-gate 	str = ++endp;
2567c478bd9Sstevel@tonic-gate 	deflate_tune = strtol(str, &endp, 0);
2577c478bd9Sstevel@tonic-gate     }
2587c478bd9Sstevel@tonic-gate #endif
2597c478bd9Sstevel@tonic-gate     if (*endp != '\0' || endp == str) {
2607c478bd9Sstevel@tonic-gate 	option_error("invalid parameter '%s' for deflate option", *argv);
2617c478bd9Sstevel@tonic-gate 	return 0;
2627c478bd9Sstevel@tonic-gate     }
2637c478bd9Sstevel@tonic-gate     if (privileged_option) {
2647c478bd9Sstevel@tonic-gate 	def_rmax = def_amax = DEFLATE_MAX_SIZE;
2657c478bd9Sstevel@tonic-gate     } else {
2667c478bd9Sstevel@tonic-gate 	def_rmax = deflate_rmax;
2677c478bd9Sstevel@tonic-gate 	def_amax = deflate_amax;
2687c478bd9Sstevel@tonic-gate     }
2697c478bd9Sstevel@tonic-gate     if (rbits < 0)
2707c478bd9Sstevel@tonic-gate 	rbits = def_rmax;
2717c478bd9Sstevel@tonic-gate     if (abits < 0)
2727c478bd9Sstevel@tonic-gate 	abits = def_amax;
2737c478bd9Sstevel@tonic-gate     if ((rbits != 0 && (rbits <= DEFLATE_MIN_SIZE || rbits > def_rmax))
2747c478bd9Sstevel@tonic-gate 	|| (abits != 0 && (abits <= DEFLATE_MIN_SIZE || abits > def_amax))) {
2757c478bd9Sstevel@tonic-gate 	option_error("deflate option values must be 0 or {%d,%d} .. {%d,%d}",
276*48bbca81SDaniel Hoffman 		     DEFLATE_MIN_SIZE+1, DEFLATE_MIN_SIZE+1,
2777c478bd9Sstevel@tonic-gate 		     def_rmax, def_amax);
2787c478bd9Sstevel@tonic-gate 	return 0;
2797c478bd9Sstevel@tonic-gate     }
2807c478bd9Sstevel@tonic-gate     if (privileged_option) {
2817c478bd9Sstevel@tonic-gate 	deflate_rmax = rbits;
2827c478bd9Sstevel@tonic-gate 	deflate_amax = abits;
2837c478bd9Sstevel@tonic-gate     }
2847c478bd9Sstevel@tonic-gate     if (rbits > 0) {
2857c478bd9Sstevel@tonic-gate 	ccp_wantoptions[0].deflate = 1;
2867c478bd9Sstevel@tonic-gate 	ccp_wantoptions[0].deflate_size = rbits;
2877c478bd9Sstevel@tonic-gate     } else
2887c478bd9Sstevel@tonic-gate 	ccp_wantoptions[0].deflate = 0;
2897c478bd9Sstevel@tonic-gate     if (abits > 0) {
2907c478bd9Sstevel@tonic-gate 	ccp_allowoptions[0].deflate = 1;
2917c478bd9Sstevel@tonic-gate 	ccp_allowoptions[0].deflate_size = abits;
2927c478bd9Sstevel@tonic-gate     } else
2937c478bd9Sstevel@tonic-gate 	ccp_allowoptions[0].deflate = 0;
2947c478bd9Sstevel@tonic-gate     return 1;
2957c478bd9Sstevel@tonic-gate }
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate /*
2997c478bd9Sstevel@tonic-gate  * ccp_init - initialize CCP.
3007c478bd9Sstevel@tonic-gate  */
3017c478bd9Sstevel@tonic-gate static void
ccp_init(unit)3027c478bd9Sstevel@tonic-gate ccp_init(unit)
3037c478bd9Sstevel@tonic-gate     int unit;
3047c478bd9Sstevel@tonic-gate {
3057c478bd9Sstevel@tonic-gate     fsm *f = &ccp_fsm[unit];
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate     f->unit = unit;
3087c478bd9Sstevel@tonic-gate     f->protocol = PPP_CCP;
3097c478bd9Sstevel@tonic-gate     f->callbacks = &ccp_callbacks;
3107c478bd9Sstevel@tonic-gate     fsm_init(f);
3117c478bd9Sstevel@tonic-gate     f->flags |= OPT_RESTART;
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate     BZERO(&ccp_wantoptions[unit],  sizeof(ccp_options));
3147c478bd9Sstevel@tonic-gate     BZERO(&ccp_gotoptions[unit],   sizeof(ccp_options));
3157c478bd9Sstevel@tonic-gate     BZERO(&ccp_allowoptions[unit], sizeof(ccp_options));
3167c478bd9Sstevel@tonic-gate     BZERO(&ccp_hisoptions[unit],   sizeof(ccp_options));
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate     ccp_wantoptions[0].deflate = 1;
3197c478bd9Sstevel@tonic-gate     ccp_wantoptions[0].deflate_size = DEFLATE_MAX_SIZE;
3207c478bd9Sstevel@tonic-gate     ccp_wantoptions[0].deflate_correct = 1;
3217c478bd9Sstevel@tonic-gate     ccp_wantoptions[0].deflate_draft = 1;
3227c478bd9Sstevel@tonic-gate     ccp_allowoptions[0].deflate = 1;
3237c478bd9Sstevel@tonic-gate     ccp_allowoptions[0].deflate_size = DEFLATE_MAX_SIZE;
3247c478bd9Sstevel@tonic-gate     ccp_allowoptions[0].deflate_correct = 1;
3257c478bd9Sstevel@tonic-gate     ccp_allowoptions[0].deflate_draft = 1;
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate     ccp_wantoptions[0].bsd_compress = 1;
3287c478bd9Sstevel@tonic-gate     ccp_wantoptions[0].bsd_bits = BSD_MAX_BITS;
3297c478bd9Sstevel@tonic-gate     ccp_allowoptions[0].bsd_compress = 1;
3307c478bd9Sstevel@tonic-gate     ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate     ccp_allowoptions[0].predictor_1 = 1;
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate /*
3367c478bd9Sstevel@tonic-gate  * ccp_open - CCP is allowed to come up.
3377c478bd9Sstevel@tonic-gate  */
3387c478bd9Sstevel@tonic-gate static void
ccp_open(unit)3397c478bd9Sstevel@tonic-gate ccp_open(unit)
3407c478bd9Sstevel@tonic-gate     int unit;
3417c478bd9Sstevel@tonic-gate {
3427c478bd9Sstevel@tonic-gate     fsm *f = &ccp_fsm[unit];
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate     /*
3457c478bd9Sstevel@tonic-gate      * If we haven't gone open yet (first time through), then go open
3467c478bd9Sstevel@tonic-gate      * but not up.  Otherwise, skip this to allow reopen to reset the
3477c478bd9Sstevel@tonic-gate      * compressor.
3487c478bd9Sstevel@tonic-gate      */
3497c478bd9Sstevel@tonic-gate     if (f->state != OPENED)
3507c478bd9Sstevel@tonic-gate 	ccp_flags_set(unit, 1, 0);
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate     /*
3537c478bd9Sstevel@tonic-gate      * Find out which compressors the kernel supports before
3547c478bd9Sstevel@tonic-gate      * deciding whether to open in silent mode.
3557c478bd9Sstevel@tonic-gate      */
3567c478bd9Sstevel@tonic-gate     ccp_resetci(f);
3577c478bd9Sstevel@tonic-gate     if (!ANY_COMPRESS(ccp_gotoptions[unit]))
3587c478bd9Sstevel@tonic-gate 	f->flags |= OPT_SILENT;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate     fsm_open(f);
3617c478bd9Sstevel@tonic-gate }
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate /*
3647c478bd9Sstevel@tonic-gate  * ccp_close - Terminate CCP.
3657c478bd9Sstevel@tonic-gate  */
3667c478bd9Sstevel@tonic-gate static void
ccp_close(unit,reason)3677c478bd9Sstevel@tonic-gate ccp_close(unit, reason)
3687c478bd9Sstevel@tonic-gate     int unit;
3697c478bd9Sstevel@tonic-gate     char *reason;
3707c478bd9Sstevel@tonic-gate {
3717c478bd9Sstevel@tonic-gate     ccp_flags_set(unit, 0, 0);
3727c478bd9Sstevel@tonic-gate     fsm_close(&ccp_fsm[unit], reason);
3737c478bd9Sstevel@tonic-gate }
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate /*
3767c478bd9Sstevel@tonic-gate  * ccp_lowerup - we may now transmit CCP packets.
3777c478bd9Sstevel@tonic-gate  */
3787c478bd9Sstevel@tonic-gate static void
ccp_lowerup(unit)3797c478bd9Sstevel@tonic-gate ccp_lowerup(unit)
3807c478bd9Sstevel@tonic-gate     int unit;
3817c478bd9Sstevel@tonic-gate {
3827c478bd9Sstevel@tonic-gate     fsm_lowerup(&ccp_fsm[unit]);
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate /*
3867c478bd9Sstevel@tonic-gate  * ccp_lowerdown - we may not transmit CCP packets.
3877c478bd9Sstevel@tonic-gate  */
3887c478bd9Sstevel@tonic-gate static void
ccp_lowerdown(unit)3897c478bd9Sstevel@tonic-gate ccp_lowerdown(unit)
3907c478bd9Sstevel@tonic-gate     int unit;
3917c478bd9Sstevel@tonic-gate {
3927c478bd9Sstevel@tonic-gate     fsm_lowerdown(&ccp_fsm[unit]);
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate /*
3967c478bd9Sstevel@tonic-gate  * ccp_input - process a received CCP packet.
3977c478bd9Sstevel@tonic-gate  */
3987c478bd9Sstevel@tonic-gate static void
ccp_input(unit,p,len)3997c478bd9Sstevel@tonic-gate ccp_input(unit, p, len)
4007c478bd9Sstevel@tonic-gate     int unit;
4017c478bd9Sstevel@tonic-gate     u_char *p;
4027c478bd9Sstevel@tonic-gate     int len;
4037c478bd9Sstevel@tonic-gate {
4047c478bd9Sstevel@tonic-gate     fsm *f = &ccp_fsm[unit];
4057c478bd9Sstevel@tonic-gate     int oldstate;
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate     /*
4087c478bd9Sstevel@tonic-gate      * Check for a terminate-request so we can print a message.
4097c478bd9Sstevel@tonic-gate      */
4107c478bd9Sstevel@tonic-gate     oldstate = f->state;
4117c478bd9Sstevel@tonic-gate     fsm_input(f, p, len);
4127c478bd9Sstevel@tonic-gate     if (oldstate == OPENED && p[0] == CODE_TERMREQ && f->state != OPENED)
4137c478bd9Sstevel@tonic-gate 	notice("Compression disabled by peer.");
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate     /*
4167c478bd9Sstevel@tonic-gate      * If we get a terminate-ack and we're not asking for compression,
4177c478bd9Sstevel@tonic-gate      * close CCP.  (Terminate-Request is handled by fsm_input() above.)
4187c478bd9Sstevel@tonic-gate      */
4197c478bd9Sstevel@tonic-gate     if (oldstate == REQSENT && p[0] == CODE_TERMACK
4207c478bd9Sstevel@tonic-gate 	&& !ANY_COMPRESS(ccp_gotoptions[unit]))
4217c478bd9Sstevel@tonic-gate 	ccp_close(unit, "No compression negotiated");
4227c478bd9Sstevel@tonic-gate }
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate /*
4257c478bd9Sstevel@tonic-gate  * Handle a CCP-specific code.
4267c478bd9Sstevel@tonic-gate  */
4277c478bd9Sstevel@tonic-gate static int
ccp_extcode(f,code,id,p,len)4287c478bd9Sstevel@tonic-gate ccp_extcode(f, code, id, p, len)
4297c478bd9Sstevel@tonic-gate     fsm *f;
4307c478bd9Sstevel@tonic-gate     int code, id;
4317c478bd9Sstevel@tonic-gate     u_char *p;
4327c478bd9Sstevel@tonic-gate     int len;
4337c478bd9Sstevel@tonic-gate {
4347c478bd9Sstevel@tonic-gate     switch (code) {
4357c478bd9Sstevel@tonic-gate     case CCP_RESETREQ:
4367c478bd9Sstevel@tonic-gate 	/* If not open, then silently ignore. */
4377c478bd9Sstevel@tonic-gate 	if (f->state != OPENED)
4387c478bd9Sstevel@tonic-gate 	    break;
4397c478bd9Sstevel@tonic-gate 	/* send a reset-ack, which our transmitter module will see and
4407c478bd9Sstevel@tonic-gate 	   reset its compression state. */
4417c478bd9Sstevel@tonic-gate 	fsm_sdata(f, CCP_RESETACK, id, p, len);
4427c478bd9Sstevel@tonic-gate 	break;
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate     case CCP_RESETACK:
4457c478bd9Sstevel@tonic-gate 	/*
4467c478bd9Sstevel@tonic-gate 	 * Note that the compression module isn't picky about ID
4477c478bd9Sstevel@tonic-gate 	 * numbers and such.
4487c478bd9Sstevel@tonic-gate 	 */
4497c478bd9Sstevel@tonic-gate 	ccp_localstate[f->unit] &= ~RREQ_IGNORED & ~RREQ_REJECTED;
4507c478bd9Sstevel@tonic-gate 	if ((ccp_localstate[f->unit] & RACK_PENDING) && id == f->reqid) {
4517c478bd9Sstevel@tonic-gate 	    ccp_localstate[f->unit] &= ~RACK_PENDING & ~RREQ_REPEAT;
4527c478bd9Sstevel@tonic-gate 	    UNTIMEOUT(ccp_rack_timeout, f);
4537c478bd9Sstevel@tonic-gate 	}
4547c478bd9Sstevel@tonic-gate 	break;
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate     default:
4577c478bd9Sstevel@tonic-gate 	/* Tell fsm to send code reject */
4587c478bd9Sstevel@tonic-gate 	return (0);
4597c478bd9Sstevel@tonic-gate     }
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate     return (1);
4627c478bd9Sstevel@tonic-gate }
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate /*
4657c478bd9Sstevel@tonic-gate  * Handle Code-Reject for one of our extended codes by dropping back to
4667c478bd9Sstevel@tonic-gate  * reopen as mechanism to restart compression.
4677c478bd9Sstevel@tonic-gate  */
4687c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4697c478bd9Sstevel@tonic-gate static int
ccp_codereject(f,code,id,inp,len)4707c478bd9Sstevel@tonic-gate ccp_codereject(f, code, id, inp, len)
4717c478bd9Sstevel@tonic-gate     fsm *f;
4727c478bd9Sstevel@tonic-gate     int code, id;
4737c478bd9Sstevel@tonic-gate     u_char *inp;
4747c478bd9Sstevel@tonic-gate     int len;
4757c478bd9Sstevel@tonic-gate {
4767c478bd9Sstevel@tonic-gate     switch (code) {
4777c478bd9Sstevel@tonic-gate     case CCP_RESETREQ:
4787c478bd9Sstevel@tonic-gate 	if (!(ccp_localstate[f->unit] & RREQ_REJECTED)) {
4797c478bd9Sstevel@tonic-gate 	    info("peer has rejected CCP Reset-Request; falling back on Open");
4807c478bd9Sstevel@tonic-gate 	    if (f->state == OPENED)
4817c478bd9Sstevel@tonic-gate 		ccp_open(f->unit);
4827c478bd9Sstevel@tonic-gate 	}
4837c478bd9Sstevel@tonic-gate 	ccp_localstate[f->unit] |= RREQ_REJECTED;
4847c478bd9Sstevel@tonic-gate 	return (0);
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate     case CCP_RESETACK:
4877c478bd9Sstevel@tonic-gate 	/*
488*48bbca81SDaniel Hoffman 	 * Peer must have sent us CCP Reset-Request but then code-rejected when
489*48bbca81SDaniel Hoffman 	 * we sent CCP Reset-Ack.  It seems to have changed its mind, and we
490*48bbca81SDaniel Hoffman 	 * have to obey its wishes.
4917c478bd9Sstevel@tonic-gate 	 */
4927c478bd9Sstevel@tonic-gate 	ccp_localstate[f->unit] |= RACK_REJECTED;
4937c478bd9Sstevel@tonic-gate 	notice("peer has erroneously rejected CCP Reset-Ack");
4947c478bd9Sstevel@tonic-gate 	f->term_reason = "peer sent Code-Reject for CCP Reset-Ack";
4957c478bd9Sstevel@tonic-gate 	f->term_reason_len = strlen(f->term_reason);
4967c478bd9Sstevel@tonic-gate 	break;
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate     default:
4997c478bd9Sstevel@tonic-gate 	f->term_reason = "peer sent invalid Code-Reject";
5007c478bd9Sstevel@tonic-gate 	break;
5017c478bd9Sstevel@tonic-gate     }
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate     f->term_reason_len = strlen(f->term_reason);
5047c478bd9Sstevel@tonic-gate     return (1);
5057c478bd9Sstevel@tonic-gate }
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate /*
5087c478bd9Sstevel@tonic-gate  * ccp_protrej - peer doesn't talk CCP.
5097c478bd9Sstevel@tonic-gate  */
5107c478bd9Sstevel@tonic-gate static void
ccp_protrej(unit)5117c478bd9Sstevel@tonic-gate ccp_protrej(unit)
5127c478bd9Sstevel@tonic-gate     int unit;
5137c478bd9Sstevel@tonic-gate {
5147c478bd9Sstevel@tonic-gate     /* Neither open nor up. */
5157c478bd9Sstevel@tonic-gate     ccp_flags_set(unit, 0, 0);
5167c478bd9Sstevel@tonic-gate     fsm_lowerdown(&ccp_fsm[unit]);
5177c478bd9Sstevel@tonic-gate }
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate /*
5207c478bd9Sstevel@tonic-gate  * ccp_resetci - initialize at start of negotiation.
5217c478bd9Sstevel@tonic-gate  */
5227c478bd9Sstevel@tonic-gate static void
ccp_resetci(f)5237c478bd9Sstevel@tonic-gate ccp_resetci(f)
5247c478bd9Sstevel@tonic-gate     fsm *f;
5257c478bd9Sstevel@tonic-gate {
5267c478bd9Sstevel@tonic-gate     ccp_options *go = &ccp_gotoptions[f->unit];
5277c478bd9Sstevel@tonic-gate     u_char opt_buf[16];
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate     *go = ccp_wantoptions[f->unit];
5307c478bd9Sstevel@tonic-gate     all_rejected[f->unit] = 0;
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate     /*
5337c478bd9Sstevel@tonic-gate      * Check whether the kernel knows about the various
5347c478bd9Sstevel@tonic-gate      * decompression methods we might request.
5357c478bd9Sstevel@tonic-gate      */
5367c478bd9Sstevel@tonic-gate     if (go->bsd_compress) {
5377c478bd9Sstevel@tonic-gate 	opt_buf[0] = CI_BSD_COMPRESS;
5387c478bd9Sstevel@tonic-gate 	opt_buf[1] = CILEN_BSD_COMPRESS;
5397c478bd9Sstevel@tonic-gate 	opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, BSD_MIN_BITS);
5407c478bd9Sstevel@tonic-gate 	if (ccp_test(f->unit, opt_buf, CILEN_BSD_COMPRESS, 0) <= 0)
5417c478bd9Sstevel@tonic-gate 	    go->bsd_compress = 0;
5427c478bd9Sstevel@tonic-gate     }
5437c478bd9Sstevel@tonic-gate     if (go->deflate) {
5447c478bd9Sstevel@tonic-gate 	if (go->deflate_correct) {
5457c478bd9Sstevel@tonic-gate 	    opt_buf[0] = CI_DEFLATE;
5467c478bd9Sstevel@tonic-gate 	    opt_buf[1] = CILEN_DEFLATE;
5477c478bd9Sstevel@tonic-gate 	    opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE+1);
5487c478bd9Sstevel@tonic-gate 	    opt_buf[3] = DEFLATE_CHK_SEQUENCE;
5497c478bd9Sstevel@tonic-gate 	    if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
5507c478bd9Sstevel@tonic-gate 		go->deflate_correct = 0;
5517c478bd9Sstevel@tonic-gate 	}
5527c478bd9Sstevel@tonic-gate 	if (go->deflate_draft) {
5537c478bd9Sstevel@tonic-gate 	    opt_buf[0] = CI_DEFLATE_DRAFT;
5547c478bd9Sstevel@tonic-gate 	    opt_buf[1] = CILEN_DEFLATE;
5557c478bd9Sstevel@tonic-gate 	    opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE+1);
5567c478bd9Sstevel@tonic-gate 	    opt_buf[3] = DEFLATE_CHK_SEQUENCE;
5577c478bd9Sstevel@tonic-gate 	    if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
5587c478bd9Sstevel@tonic-gate 		go->deflate_draft = 0;
5597c478bd9Sstevel@tonic-gate 	}
5607c478bd9Sstevel@tonic-gate 	if (!go->deflate_correct && !go->deflate_draft)
5617c478bd9Sstevel@tonic-gate 	    go->deflate = 0;
5627c478bd9Sstevel@tonic-gate     }
5637c478bd9Sstevel@tonic-gate     if (go->predictor_1) {
5647c478bd9Sstevel@tonic-gate 	opt_buf[0] = CI_PREDICTOR_1;
5657c478bd9Sstevel@tonic-gate 	opt_buf[1] = CILEN_PREDICTOR_1;
5667c478bd9Sstevel@tonic-gate 	if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_1, 0) <= 0)
5677c478bd9Sstevel@tonic-gate 	    go->predictor_1 = 0;
5687c478bd9Sstevel@tonic-gate     }
5697c478bd9Sstevel@tonic-gate     if (go->predictor_2) {
5707c478bd9Sstevel@tonic-gate 	opt_buf[0] = CI_PREDICTOR_2;
5717c478bd9Sstevel@tonic-gate 	opt_buf[1] = CILEN_PREDICTOR_2;
5727c478bd9Sstevel@tonic-gate 	if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_2, 0) <= 0)
5737c478bd9Sstevel@tonic-gate 	    go->predictor_2 = 0;
5747c478bd9Sstevel@tonic-gate     }
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate /*
5787c478bd9Sstevel@tonic-gate  * ccp_cilen - Return total length of our configuration info.
5797c478bd9Sstevel@tonic-gate  */
5807c478bd9Sstevel@tonic-gate static int
ccp_cilen(f)5817c478bd9Sstevel@tonic-gate ccp_cilen(f)
5827c478bd9Sstevel@tonic-gate     fsm *f;
5837c478bd9Sstevel@tonic-gate {
5847c478bd9Sstevel@tonic-gate     ccp_options *go = &ccp_gotoptions[f->unit];
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate     return (go->bsd_compress? CILEN_BSD_COMPRESS: 0)
5877c478bd9Sstevel@tonic-gate 	+ (go->deflate && go->deflate_correct ? CILEN_DEFLATE : 0)
5887c478bd9Sstevel@tonic-gate 	+ (go->deflate && go->deflate_draft ? CILEN_DEFLATE : 0)
5897c478bd9Sstevel@tonic-gate 	+ (go->predictor_1? CILEN_PREDICTOR_1: 0)
5907c478bd9Sstevel@tonic-gate 	+ (go->predictor_2? CILEN_PREDICTOR_2: 0);
5917c478bd9Sstevel@tonic-gate }
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate /*
5947c478bd9Sstevel@tonic-gate  * ccp_addci - put our requests in a packet.
5957c478bd9Sstevel@tonic-gate  */
5967c478bd9Sstevel@tonic-gate static void
ccp_addci(f,p,lenp)5977c478bd9Sstevel@tonic-gate ccp_addci(f, p, lenp)
5987c478bd9Sstevel@tonic-gate     fsm *f;
5997c478bd9Sstevel@tonic-gate     u_char *p;
6007c478bd9Sstevel@tonic-gate     int *lenp;
6017c478bd9Sstevel@tonic-gate {
6027c478bd9Sstevel@tonic-gate     int res;
6037c478bd9Sstevel@tonic-gate     ccp_options *go = &ccp_gotoptions[f->unit];
6047c478bd9Sstevel@tonic-gate     u_char *p0 = p;
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate     /*
6077c478bd9Sstevel@tonic-gate      * Add the compression types that we can receive, in decreasing
6087c478bd9Sstevel@tonic-gate      * preference order.  Get the kernel to allocate the first one
6097c478bd9Sstevel@tonic-gate      * in case it gets Acked.
6107c478bd9Sstevel@tonic-gate      */
6117c478bd9Sstevel@tonic-gate     if (go->deflate) {
6127c478bd9Sstevel@tonic-gate 	p[0] = go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT;
6137c478bd9Sstevel@tonic-gate 	p[1] = CILEN_DEFLATE;
6147c478bd9Sstevel@tonic-gate 	p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
6157c478bd9Sstevel@tonic-gate 	p[3] = DEFLATE_CHK_SEQUENCE;
6167c478bd9Sstevel@tonic-gate 	for (;;) {
6177c478bd9Sstevel@tonic-gate 	    res = ccp_test(f->unit, p, CILEN_DEFLATE, 0);
6187c478bd9Sstevel@tonic-gate 	    if (res > 0) {
6197c478bd9Sstevel@tonic-gate 		p += CILEN_DEFLATE;
6207c478bd9Sstevel@tonic-gate 		break;
6217c478bd9Sstevel@tonic-gate 	    }
6227c478bd9Sstevel@tonic-gate 	    if (res < 0 || go->deflate_size <= DEFLATE_MIN_SIZE+1) {
6237c478bd9Sstevel@tonic-gate 		go->deflate = 0;
6247c478bd9Sstevel@tonic-gate 		break;
6257c478bd9Sstevel@tonic-gate 	    }
6267c478bd9Sstevel@tonic-gate 	    --go->deflate_size;
6277c478bd9Sstevel@tonic-gate 	    p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
6287c478bd9Sstevel@tonic-gate 	}
6297c478bd9Sstevel@tonic-gate 	/* If we're offering both, then this is second. */
6307c478bd9Sstevel@tonic-gate 	if (p != p0 && go->deflate_correct && go->deflate_draft) {
6317c478bd9Sstevel@tonic-gate 	    p[0] = CI_DEFLATE_DRAFT;
6327c478bd9Sstevel@tonic-gate 	    p[1] = CILEN_DEFLATE;
6337c478bd9Sstevel@tonic-gate 	    p[2] = p[2 - CILEN_DEFLATE];
6347c478bd9Sstevel@tonic-gate 	    p[3] = DEFLATE_CHK_SEQUENCE;
6357c478bd9Sstevel@tonic-gate 	    p += CILEN_DEFLATE;
6367c478bd9Sstevel@tonic-gate 	}
6377c478bd9Sstevel@tonic-gate     }
6387c478bd9Sstevel@tonic-gate     if (go->bsd_compress) {
6397c478bd9Sstevel@tonic-gate 	p[0] = CI_BSD_COMPRESS;
6407c478bd9Sstevel@tonic-gate 	p[1] = CILEN_BSD_COMPRESS;
6417c478bd9Sstevel@tonic-gate 	p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
6427c478bd9Sstevel@tonic-gate 	if (p != p0) {
6437c478bd9Sstevel@tonic-gate 	    p += CILEN_BSD_COMPRESS;	/* not the first option */
6447c478bd9Sstevel@tonic-gate 	} else {
6457c478bd9Sstevel@tonic-gate 	    for (;;) {
6467c478bd9Sstevel@tonic-gate 		res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0);
6477c478bd9Sstevel@tonic-gate 		if (res > 0) {
6487c478bd9Sstevel@tonic-gate 		    p += CILEN_BSD_COMPRESS;
6497c478bd9Sstevel@tonic-gate 		    break;
6507c478bd9Sstevel@tonic-gate 		}
6517c478bd9Sstevel@tonic-gate 		if (res < 0 || go->bsd_bits <= BSD_MIN_BITS) {
6527c478bd9Sstevel@tonic-gate 		    go->bsd_compress = 0;
6537c478bd9Sstevel@tonic-gate 		    break;
6547c478bd9Sstevel@tonic-gate 		}
6557c478bd9Sstevel@tonic-gate 		--go->bsd_bits;
6567c478bd9Sstevel@tonic-gate 		p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
6577c478bd9Sstevel@tonic-gate 	    }
6587c478bd9Sstevel@tonic-gate 	}
6597c478bd9Sstevel@tonic-gate     }
6607c478bd9Sstevel@tonic-gate     /*
6617c478bd9Sstevel@tonic-gate      * Prefer Predictor-1 over Predictor-2.  (The latter requires the use
6627c478bd9Sstevel@tonic-gate      * of LAP-B and has no known implementations.)
6637c478bd9Sstevel@tonic-gate      */
6647c478bd9Sstevel@tonic-gate     if (go->predictor_1) {
6657c478bd9Sstevel@tonic-gate 	p[0] = CI_PREDICTOR_1;
6667c478bd9Sstevel@tonic-gate 	p[1] = CILEN_PREDICTOR_1;
6677c478bd9Sstevel@tonic-gate 	if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_1, 0) <= 0) {
6687c478bd9Sstevel@tonic-gate 	    go->predictor_1 = 0;
6697c478bd9Sstevel@tonic-gate 	} else {
6707c478bd9Sstevel@tonic-gate 	    p += CILEN_PREDICTOR_1;
6717c478bd9Sstevel@tonic-gate 	}
6727c478bd9Sstevel@tonic-gate     }
6737c478bd9Sstevel@tonic-gate     if (go->predictor_2) {
6747c478bd9Sstevel@tonic-gate 	p[0] = CI_PREDICTOR_2;
6757c478bd9Sstevel@tonic-gate 	p[1] = CILEN_PREDICTOR_2;
6767c478bd9Sstevel@tonic-gate 	if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_2, 0) <= 0) {
6777c478bd9Sstevel@tonic-gate 	    go->predictor_2 = 0;
6787c478bd9Sstevel@tonic-gate 	} else {
6797c478bd9Sstevel@tonic-gate 	    p += CILEN_PREDICTOR_2;
6807c478bd9Sstevel@tonic-gate 	}
6817c478bd9Sstevel@tonic-gate     }
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate     go->method = (p > p0)? p0[0]: -1;
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate     *lenp = p - p0;
6867c478bd9Sstevel@tonic-gate }
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate /*
6897c478bd9Sstevel@tonic-gate  * ccp_ackci - process a received configure-ack, and return
6907c478bd9Sstevel@tonic-gate  * 1 iff the packet was OK.
6917c478bd9Sstevel@tonic-gate  */
6927c478bd9Sstevel@tonic-gate static int
ccp_ackci(f,p,len)6937c478bd9Sstevel@tonic-gate ccp_ackci(f, p, len)
6947c478bd9Sstevel@tonic-gate     fsm *f;
6957c478bd9Sstevel@tonic-gate     u_char *p;
6967c478bd9Sstevel@tonic-gate     int len;
6977c478bd9Sstevel@tonic-gate {
6987c478bd9Sstevel@tonic-gate     ccp_options *go = &ccp_gotoptions[f->unit];
6997c478bd9Sstevel@tonic-gate     u_char *p0 = p;
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate     if (go->deflate && go->deflate_correct) {
7027c478bd9Sstevel@tonic-gate 	if (len < CILEN_DEFLATE
7037c478bd9Sstevel@tonic-gate 	    || p[0] != CI_DEFLATE || p[1] != CILEN_DEFLATE
7047c478bd9Sstevel@tonic-gate 	    || p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
7057c478bd9Sstevel@tonic-gate 	    || p[3] != DEFLATE_CHK_SEQUENCE)
7067c478bd9Sstevel@tonic-gate 	    return 0;
7077c478bd9Sstevel@tonic-gate 	/* Cope with non-standard first/fast ack */
7087c478bd9Sstevel@tonic-gate 	if (p == p0 && len == 0)
7097c478bd9Sstevel@tonic-gate 	    return 1;
7107c478bd9Sstevel@tonic-gate 	p += CILEN_DEFLATE;
7117c478bd9Sstevel@tonic-gate 	len -= CILEN_DEFLATE;
7127c478bd9Sstevel@tonic-gate     }
7137c478bd9Sstevel@tonic-gate     if (go->deflate && go->deflate_draft) {
7147c478bd9Sstevel@tonic-gate 	if (len < CILEN_DEFLATE
7157c478bd9Sstevel@tonic-gate 	    || p[0] != CI_DEFLATE_DRAFT || p[1] != CILEN_DEFLATE
7167c478bd9Sstevel@tonic-gate 	    || p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
7177c478bd9Sstevel@tonic-gate 	    || p[3] != DEFLATE_CHK_SEQUENCE)
7187c478bd9Sstevel@tonic-gate 	    return 0;
7197c478bd9Sstevel@tonic-gate 	/* Cope with non-standard first/fast ack */
7207c478bd9Sstevel@tonic-gate 	if (p == p0 && len == 0)
7217c478bd9Sstevel@tonic-gate 	    return 1;
7227c478bd9Sstevel@tonic-gate 	p += CILEN_DEFLATE;
7237c478bd9Sstevel@tonic-gate 	len -= CILEN_DEFLATE;
7247c478bd9Sstevel@tonic-gate     }
7257c478bd9Sstevel@tonic-gate     if (go->bsd_compress) {
7267c478bd9Sstevel@tonic-gate 	if (len < CILEN_BSD_COMPRESS
7277c478bd9Sstevel@tonic-gate 	    || p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS
7287c478bd9Sstevel@tonic-gate 	    || p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
7297c478bd9Sstevel@tonic-gate 	    return 0;
7307c478bd9Sstevel@tonic-gate 	/* Cope with non-standard first/fast ack */
7317c478bd9Sstevel@tonic-gate 	if (p == p0 && len == 0)
7327c478bd9Sstevel@tonic-gate 	    return 1;
7337c478bd9Sstevel@tonic-gate 	p += CILEN_BSD_COMPRESS;
7347c478bd9Sstevel@tonic-gate 	len -= CILEN_BSD_COMPRESS;
7357c478bd9Sstevel@tonic-gate     }
7367c478bd9Sstevel@tonic-gate     if (go->predictor_1) {
7377c478bd9Sstevel@tonic-gate 	if (len < CILEN_PREDICTOR_1
7387c478bd9Sstevel@tonic-gate 	    || p[0] != CI_PREDICTOR_1 || p[1] != CILEN_PREDICTOR_1)
7397c478bd9Sstevel@tonic-gate 	    return 0;
7407c478bd9Sstevel@tonic-gate 	/* Cope with non-standard first/fast ack */
7417c478bd9Sstevel@tonic-gate 	if (p == p0 && len == 0)
7427c478bd9Sstevel@tonic-gate 	    return 1;
7437c478bd9Sstevel@tonic-gate 	p += CILEN_PREDICTOR_1;
7447c478bd9Sstevel@tonic-gate 	len -= CILEN_PREDICTOR_1;
7457c478bd9Sstevel@tonic-gate     }
7467c478bd9Sstevel@tonic-gate     if (go->predictor_2) {
7477c478bd9Sstevel@tonic-gate 	if (len < CILEN_PREDICTOR_2
7487c478bd9Sstevel@tonic-gate 	    || p[0] != CI_PREDICTOR_2 || p[1] != CILEN_PREDICTOR_2)
7497c478bd9Sstevel@tonic-gate 	    return 0;
7507c478bd9Sstevel@tonic-gate 	/* Cope with non-standard first/fast ack */
7517c478bd9Sstevel@tonic-gate 	if (p == p0 && len == 0)
7527c478bd9Sstevel@tonic-gate 	    return 1;
7537c478bd9Sstevel@tonic-gate 	p += CILEN_PREDICTOR_2;
7547c478bd9Sstevel@tonic-gate 	len -= CILEN_PREDICTOR_2;
7557c478bd9Sstevel@tonic-gate     }
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate     /* Peer cannot ack something that wasn't sent. */
7587c478bd9Sstevel@tonic-gate     if (len != 0)
7597c478bd9Sstevel@tonic-gate 	return 0;
7607c478bd9Sstevel@tonic-gate     return 1;
7617c478bd9Sstevel@tonic-gate }
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate /*
7647c478bd9Sstevel@tonic-gate  * ccp_nakci - process received configure-nak.
7657c478bd9Sstevel@tonic-gate  * Returns 1 iff the nak was OK.
7667c478bd9Sstevel@tonic-gate  */
7677c478bd9Sstevel@tonic-gate static int
ccp_nakci(f,p,len)7687c478bd9Sstevel@tonic-gate ccp_nakci(f, p, len)
7697c478bd9Sstevel@tonic-gate     fsm *f;
7707c478bd9Sstevel@tonic-gate     u_char *p;
7717c478bd9Sstevel@tonic-gate     int len;
7727c478bd9Sstevel@tonic-gate {
7737c478bd9Sstevel@tonic-gate     ccp_options *go = &ccp_gotoptions[f->unit];
7747c478bd9Sstevel@tonic-gate     ccp_options no;		/* options we've seen already */
7757c478bd9Sstevel@tonic-gate     ccp_options try;		/* options to ask for next time */
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate     BZERO(&no, sizeof(no));
7787c478bd9Sstevel@tonic-gate     try = *go;
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate     if (go->deflate && go->deflate_correct && len >= CILEN_DEFLATE &&
7817c478bd9Sstevel@tonic-gate 	p[0] == CI_DEFLATE) {
7827c478bd9Sstevel@tonic-gate 	no.deflate = 1;
7837c478bd9Sstevel@tonic-gate 	/*
7847c478bd9Sstevel@tonic-gate 	 * Peer wants us to use a different code size or something.
785*48bbca81SDaniel Hoffman 	 * Stop asking for Deflate if we don't understand its suggestion.
7867c478bd9Sstevel@tonic-gate 	 */
7877c478bd9Sstevel@tonic-gate 	if (p[1] != CILEN_DEFLATE
7887c478bd9Sstevel@tonic-gate 	    || DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
7897c478bd9Sstevel@tonic-gate 	    || DEFLATE_SIZE(p[2]) <= DEFLATE_MIN_SIZE
7907c478bd9Sstevel@tonic-gate 	    || p[3] != DEFLATE_CHK_SEQUENCE)
7917c478bd9Sstevel@tonic-gate 	    try.deflate_correct = 0;
7927c478bd9Sstevel@tonic-gate 	else if (DEFLATE_SIZE(p[2]) < go->deflate_size)
7937c478bd9Sstevel@tonic-gate 	    try.deflate_size = DEFLATE_SIZE(p[2]);
7947c478bd9Sstevel@tonic-gate 	len -= p[1];
7957c478bd9Sstevel@tonic-gate 	p += p[1];
7967c478bd9Sstevel@tonic-gate     }
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate     if (go->deflate && go->deflate_draft && len >= CILEN_DEFLATE &&
7997c478bd9Sstevel@tonic-gate 	p[0] == CI_DEFLATE_DRAFT) {
8007c478bd9Sstevel@tonic-gate 	no.deflate = 1;
8017c478bd9Sstevel@tonic-gate 	/*
8027c478bd9Sstevel@tonic-gate 	 * Peer wants us to use a different code size or something.
8037c478bd9Sstevel@tonic-gate 	 * Stop asking for Deflate using the old algorithm number if
804*48bbca81SDaniel Hoffman 	 * we don't understand its suggestion.  (Note that this will
8057c478bd9Sstevel@tonic-gate 	 * happen if the peer is running Magnalink instead of
8067c478bd9Sstevel@tonic-gate 	 * old-style Deflate.)
8077c478bd9Sstevel@tonic-gate 	 */
8087c478bd9Sstevel@tonic-gate 	if (p[1] != CILEN_DEFLATE
8097c478bd9Sstevel@tonic-gate 	    || DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
8107c478bd9Sstevel@tonic-gate 	    || DEFLATE_SIZE(p[2]) <= DEFLATE_MIN_SIZE
8117c478bd9Sstevel@tonic-gate 	    || p[3] != DEFLATE_CHK_SEQUENCE)
8127c478bd9Sstevel@tonic-gate 	    try.deflate_draft = 0;
8137c478bd9Sstevel@tonic-gate 	else if (DEFLATE_SIZE(p[2]) < go->deflate_size)
8147c478bd9Sstevel@tonic-gate 	    try.deflate_size = DEFLATE_SIZE(p[2]);
8157c478bd9Sstevel@tonic-gate 	len -= p[1];
8167c478bd9Sstevel@tonic-gate 	p += p[1];
8177c478bd9Sstevel@tonic-gate     }
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate     if (!try.deflate_correct && !try.deflate_draft)
8207c478bd9Sstevel@tonic-gate 	try.deflate = 0;
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate     if (go->bsd_compress && len >= CILEN_BSD_COMPRESS &&
8237c478bd9Sstevel@tonic-gate 	p[0] == CI_BSD_COMPRESS) {
8247c478bd9Sstevel@tonic-gate 	no.bsd_compress = 1;
8257c478bd9Sstevel@tonic-gate 	/*
8267c478bd9Sstevel@tonic-gate 	 * Peer wants us to use a different number of bits
8277c478bd9Sstevel@tonic-gate 	 * or a different version.
8287c478bd9Sstevel@tonic-gate 	 */
8297c478bd9Sstevel@tonic-gate 	if (p[1] != CILEN_BSD_COMPRESS ||
8307c478bd9Sstevel@tonic-gate 	    BSD_VERSION(p[2]) != BSD_CURRENT_VERSION)
8317c478bd9Sstevel@tonic-gate 	    try.bsd_compress = 0;
8327c478bd9Sstevel@tonic-gate 	else if (BSD_NBITS(p[2]) < go->bsd_bits)
8337c478bd9Sstevel@tonic-gate 	    try.bsd_bits = BSD_NBITS(p[2]);
8347c478bd9Sstevel@tonic-gate 	len -= p[1];
8357c478bd9Sstevel@tonic-gate 	p += p[1];
8367c478bd9Sstevel@tonic-gate     }
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate     /*
8397c478bd9Sstevel@tonic-gate      * Predictor-1 and 2 have no options, so they can't be Naked.
8407c478bd9Sstevel@tonic-gate      *
8417c478bd9Sstevel@tonic-gate      * There may be remaining options but we ignore them.
8427c478bd9Sstevel@tonic-gate      */
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate     if (f->state != OPENED)
8457c478bd9Sstevel@tonic-gate 	*go = try;
8467c478bd9Sstevel@tonic-gate     return 1;
8477c478bd9Sstevel@tonic-gate }
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate /*
8507c478bd9Sstevel@tonic-gate  * ccp_rejci - peer rejects some of our suggested compression methods.
8517c478bd9Sstevel@tonic-gate  */
8527c478bd9Sstevel@tonic-gate static int
ccp_rejci(f,p,len)8537c478bd9Sstevel@tonic-gate ccp_rejci(f, p, len)
8547c478bd9Sstevel@tonic-gate     fsm *f;
8557c478bd9Sstevel@tonic-gate     u_char *p;
8567c478bd9Sstevel@tonic-gate     int len;
8577c478bd9Sstevel@tonic-gate {
8587c478bd9Sstevel@tonic-gate     ccp_options *go = &ccp_gotoptions[f->unit];
8597c478bd9Sstevel@tonic-gate     ccp_options try;		/* options to request next time */
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate     try = *go;
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate     /*
8647c478bd9Sstevel@tonic-gate      * Cope with empty configure-rejects by ceasing to send
8657c478bd9Sstevel@tonic-gate      * configure-requests.
8667c478bd9Sstevel@tonic-gate      */
8677c478bd9Sstevel@tonic-gate     if (len == 0 && all_rejected[f->unit])
8687c478bd9Sstevel@tonic-gate 	return -1;
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate     if (go->deflate && go->deflate_correct && len >= CILEN_DEFLATE &&
8717c478bd9Sstevel@tonic-gate 	p[0] == CI_DEFLATE && p[1] == CILEN_DEFLATE) {
8727c478bd9Sstevel@tonic-gate 	if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
8737c478bd9Sstevel@tonic-gate 	    || p[3] != DEFLATE_CHK_SEQUENCE)
8747c478bd9Sstevel@tonic-gate 	    return 0;		/* Rej is bad */
8757c478bd9Sstevel@tonic-gate 	try.deflate_correct = 0;
8767c478bd9Sstevel@tonic-gate 	p += CILEN_DEFLATE;
8777c478bd9Sstevel@tonic-gate 	len -= CILEN_DEFLATE;
8787c478bd9Sstevel@tonic-gate     }
8797c478bd9Sstevel@tonic-gate     if (go->deflate && go->deflate_draft && len >= CILEN_DEFLATE &&
8807c478bd9Sstevel@tonic-gate 	p[0] == CI_DEFLATE_DRAFT && p[1] == CILEN_DEFLATE) {
8817c478bd9Sstevel@tonic-gate 	if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
8827c478bd9Sstevel@tonic-gate 	    || p[3] != DEFLATE_CHK_SEQUENCE)
8837c478bd9Sstevel@tonic-gate 	    return 0;		/* Rej is bad */
8847c478bd9Sstevel@tonic-gate 	try.deflate_draft = 0;
8857c478bd9Sstevel@tonic-gate 	p += CILEN_DEFLATE;
8867c478bd9Sstevel@tonic-gate 	len -= CILEN_DEFLATE;
8877c478bd9Sstevel@tonic-gate     }
8887c478bd9Sstevel@tonic-gate     if (!try.deflate_correct && !try.deflate_draft)
8897c478bd9Sstevel@tonic-gate 	try.deflate = 0;
8907c478bd9Sstevel@tonic-gate     if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
8917c478bd9Sstevel@tonic-gate 	&& p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
8927c478bd9Sstevel@tonic-gate 	if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
8937c478bd9Sstevel@tonic-gate 	    return 0;
8947c478bd9Sstevel@tonic-gate 	try.bsd_compress = 0;
8957c478bd9Sstevel@tonic-gate 	p += CILEN_BSD_COMPRESS;
8967c478bd9Sstevel@tonic-gate 	len -= CILEN_BSD_COMPRESS;
8977c478bd9Sstevel@tonic-gate     }
8987c478bd9Sstevel@tonic-gate     if (go->predictor_1 && len >= CILEN_PREDICTOR_1
8997c478bd9Sstevel@tonic-gate 	&& p[0] == CI_PREDICTOR_1 && p[1] == CILEN_PREDICTOR_1) {
9007c478bd9Sstevel@tonic-gate 	try.predictor_1 = 0;
9017c478bd9Sstevel@tonic-gate 	p += CILEN_PREDICTOR_1;
9027c478bd9Sstevel@tonic-gate 	len -= CILEN_PREDICTOR_1;
9037c478bd9Sstevel@tonic-gate     }
9047c478bd9Sstevel@tonic-gate     if (go->predictor_2 && len >= CILEN_PREDICTOR_2
9057c478bd9Sstevel@tonic-gate 	&& p[0] == CI_PREDICTOR_2 && p[1] == CILEN_PREDICTOR_2) {
9067c478bd9Sstevel@tonic-gate 	try.predictor_2 = 0;
9077c478bd9Sstevel@tonic-gate 	p += CILEN_PREDICTOR_2;
9087c478bd9Sstevel@tonic-gate 	len -= CILEN_PREDICTOR_2;
9097c478bd9Sstevel@tonic-gate     }
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate     if (len != 0)
9127c478bd9Sstevel@tonic-gate 	return 0;
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate     if (f->state != OPENED)
9157c478bd9Sstevel@tonic-gate 	*go = try;
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate     return 1;
9187c478bd9Sstevel@tonic-gate }
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate /*
9217c478bd9Sstevel@tonic-gate  * ccp_reqci - process a received configure-request.
9227c478bd9Sstevel@tonic-gate  *
9237c478bd9Sstevel@tonic-gate  * Returns CODE_CONFACK, CODE_CONFNAK or CODE_CONFREJ and the packet
9247c478bd9Sstevel@tonic-gate  * is modified appropriately.
9257c478bd9Sstevel@tonic-gate  */
9267c478bd9Sstevel@tonic-gate static int
ccp_reqci(f,p,lenp,dont_nak)9277c478bd9Sstevel@tonic-gate ccp_reqci(f, p, lenp, dont_nak)
9287c478bd9Sstevel@tonic-gate     fsm *f;
9297c478bd9Sstevel@tonic-gate     u_char *p;
9307c478bd9Sstevel@tonic-gate     int *lenp;
9317c478bd9Sstevel@tonic-gate     int dont_nak;
9327c478bd9Sstevel@tonic-gate {
9337c478bd9Sstevel@tonic-gate     int ret, newret, res;
9347c478bd9Sstevel@tonic-gate     u_char *p0, *nakp, *rejp, *pv;
9357c478bd9Sstevel@tonic-gate     int len, clen, type, nb;
9367c478bd9Sstevel@tonic-gate     ccp_options *ho = &ccp_hisoptions[f->unit];
9377c478bd9Sstevel@tonic-gate     ccp_options *ao = &ccp_allowoptions[f->unit];
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate     ret = CODE_CONFACK;
9407c478bd9Sstevel@tonic-gate     rejp = p0 = p;
9417c478bd9Sstevel@tonic-gate     nakp = nak_buffer;
9427c478bd9Sstevel@tonic-gate     len = *lenp;
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate     BZERO(ho, sizeof(ccp_options));
9457c478bd9Sstevel@tonic-gate     ho->method = (len > 0)? p[0]: -1;
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate     for (; len > 0; len -= clen, p += clen) {
9487c478bd9Sstevel@tonic-gate 	newret = CODE_CONFACK;
9497c478bd9Sstevel@tonic-gate 	if (len < 2 || p[1] > len) {
9507c478bd9Sstevel@tonic-gate 	    /*
9517c478bd9Sstevel@tonic-gate 	     * RFC 1661 page 40 -- if the option extends beyond the
9527c478bd9Sstevel@tonic-gate 	     * packet, then discard the entire packet.
9537c478bd9Sstevel@tonic-gate 	     */
9547c478bd9Sstevel@tonic-gate 	    return (0);
9557c478bd9Sstevel@tonic-gate 	}
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	type = p[0];
9587c478bd9Sstevel@tonic-gate 	clen = p[1];
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate 	pv = p;
9617c478bd9Sstevel@tonic-gate 	switch (type) {
9627c478bd9Sstevel@tonic-gate 	case CI_DEFLATE:
9637c478bd9Sstevel@tonic-gate 	case CI_DEFLATE_DRAFT:
9647c478bd9Sstevel@tonic-gate 	    if (!ao->deflate ||
9657c478bd9Sstevel@tonic-gate 		(!ao->deflate_correct && type == CI_DEFLATE) ||
9667c478bd9Sstevel@tonic-gate 		(!ao->deflate_draft && type == CI_DEFLATE_DRAFT)) {
9677c478bd9Sstevel@tonic-gate 		newret = CODE_CONFREJ;
9687c478bd9Sstevel@tonic-gate 		break;
9697c478bd9Sstevel@tonic-gate 	    }
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	    ho->deflate = 1;
9727c478bd9Sstevel@tonic-gate 	    nb = clen < CILEN_DEFLATE ? ao->deflate_size : DEFLATE_SIZE(p[2]);
9737c478bd9Sstevel@tonic-gate 	    ho->deflate_size = nb;
9747c478bd9Sstevel@tonic-gate 	    if (clen != CILEN_DEFLATE ||
9757c478bd9Sstevel@tonic-gate 		DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL ||
9767c478bd9Sstevel@tonic-gate 		p[3] != DEFLATE_CHK_SEQUENCE || nb > ao->deflate_size ||
9777c478bd9Sstevel@tonic-gate 		nb <= DEFLATE_MIN_SIZE) {
9787c478bd9Sstevel@tonic-gate 		newret = CODE_CONFNAK;
9797c478bd9Sstevel@tonic-gate 		if (dont_nak)
9807c478bd9Sstevel@tonic-gate 		    break;
9817c478bd9Sstevel@tonic-gate 		if (nb > ao->deflate_size)
9827c478bd9Sstevel@tonic-gate 		    nb = ao->deflate_size;
9837c478bd9Sstevel@tonic-gate 		else if (nb <= DEFLATE_MIN_SIZE)
9847c478bd9Sstevel@tonic-gate 		    nb = DEFLATE_MIN_SIZE+1;
9857c478bd9Sstevel@tonic-gate 		pv = nakp;
9867c478bd9Sstevel@tonic-gate 		PUTCHAR(type, nakp);
9877c478bd9Sstevel@tonic-gate 		PUTCHAR(CILEN_DEFLATE, nakp);
9887c478bd9Sstevel@tonic-gate 		PUTCHAR(DEFLATE_MAKE_OPT(nb), nakp);
9897c478bd9Sstevel@tonic-gate 		PUTCHAR(DEFLATE_CHK_SEQUENCE, nakp);
9907c478bd9Sstevel@tonic-gate 	    }
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 	    /*
9937c478bd9Sstevel@tonic-gate 	     * Check whether we can do Deflate with the window
9947c478bd9Sstevel@tonic-gate 	     * size they want.  If the window is too big, reduce
9957c478bd9Sstevel@tonic-gate 	     * it until the kernel can cope and nak with that.
9967c478bd9Sstevel@tonic-gate 	     * We only check this for the first option.
9977c478bd9Sstevel@tonic-gate 	     */
9987c478bd9Sstevel@tonic-gate 	    if (p == p0) {
9997c478bd9Sstevel@tonic-gate 		for (;;) {
10007c478bd9Sstevel@tonic-gate 		    res = ccp_test(f->unit, pv, CILEN_DEFLATE, 1);
10017c478bd9Sstevel@tonic-gate 		    if (res > 0)
10027c478bd9Sstevel@tonic-gate 			break;		/* it's OK now */
10037c478bd9Sstevel@tonic-gate 		    if (res < 0 || nb <= DEFLATE_MIN_SIZE+1 || dont_nak) {
10047c478bd9Sstevel@tonic-gate 			newret = CODE_CONFREJ;
10057c478bd9Sstevel@tonic-gate 			break;
10067c478bd9Sstevel@tonic-gate 		    }
10077c478bd9Sstevel@tonic-gate 		    if (newret == CODE_CONFACK) {
10087c478bd9Sstevel@tonic-gate 			BCOPY(pv, nakp, CILEN_DEFLATE);
10097c478bd9Sstevel@tonic-gate 			pv = nakp;
10107c478bd9Sstevel@tonic-gate 			nakp += CILEN_DEFLATE;
10117c478bd9Sstevel@tonic-gate 			newret = CODE_CONFNAK;
10127c478bd9Sstevel@tonic-gate 		    }
10137c478bd9Sstevel@tonic-gate 		    --nb;
10147c478bd9Sstevel@tonic-gate 		    pv[2] = DEFLATE_MAKE_OPT(nb);
10157c478bd9Sstevel@tonic-gate 		}
10167c478bd9Sstevel@tonic-gate #ifdef COMP_TUNE
10177c478bd9Sstevel@tonic-gate 		/* Tune Deflate compression effort. */
10187c478bd9Sstevel@tonic-gate 		if (newret == CODE_CONFACK)
10197c478bd9Sstevel@tonic-gate 		    ccp_tune(f->unit, deflate_tune);
10207c478bd9Sstevel@tonic-gate #endif
10217c478bd9Sstevel@tonic-gate 	    }
10227c478bd9Sstevel@tonic-gate 	    break;
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 	case CI_BSD_COMPRESS:
10257c478bd9Sstevel@tonic-gate 	    if (!ao->bsd_compress) {
10267c478bd9Sstevel@tonic-gate 		newret = CODE_CONFREJ;
10277c478bd9Sstevel@tonic-gate 		break;
10287c478bd9Sstevel@tonic-gate 	    }
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 	    ho->bsd_compress = 1;
10317c478bd9Sstevel@tonic-gate 	    nb = clen < CILEN_BSD_COMPRESS ? ao->bsd_bits : BSD_NBITS(p[2]);
10327c478bd9Sstevel@tonic-gate 	    ho->bsd_bits = nb;
10337c478bd9Sstevel@tonic-gate 	    if (clen != CILEN_BSD_COMPRESS ||
10347c478bd9Sstevel@tonic-gate 		BSD_VERSION(p[2]) != BSD_CURRENT_VERSION ||
10357c478bd9Sstevel@tonic-gate 		nb > ao->bsd_bits || nb < BSD_MIN_BITS) {
10367c478bd9Sstevel@tonic-gate 		newret = CODE_CONFNAK;
10377c478bd9Sstevel@tonic-gate 		if (dont_nak)
10387c478bd9Sstevel@tonic-gate 		    break;
10397c478bd9Sstevel@tonic-gate 		if (nb > ao->bsd_bits)
10407c478bd9Sstevel@tonic-gate 		    nb = ao->bsd_bits;
10417c478bd9Sstevel@tonic-gate 		else if (nb < BSD_MIN_BITS)
10427c478bd9Sstevel@tonic-gate 		    nb = BSD_MIN_BITS;
10437c478bd9Sstevel@tonic-gate 		pv = nakp;
10447c478bd9Sstevel@tonic-gate 		PUTCHAR(type, nakp);
10457c478bd9Sstevel@tonic-gate 		PUTCHAR(CILEN_BSD_COMPRESS, nakp);
10467c478bd9Sstevel@tonic-gate 		PUTCHAR(BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb), nakp);
10477c478bd9Sstevel@tonic-gate 	    }
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	    /*
10507c478bd9Sstevel@tonic-gate 	     * Check whether we can do BSD-Compress with the code
10517c478bd9Sstevel@tonic-gate 	     * size they want.  If the code size is too big, reduce
10527c478bd9Sstevel@tonic-gate 	     * it until the kernel can cope and nak with that.
10537c478bd9Sstevel@tonic-gate 	     * We only check this for the first option.
10547c478bd9Sstevel@tonic-gate 	     */
10557c478bd9Sstevel@tonic-gate 	    if (p == p0) {
10567c478bd9Sstevel@tonic-gate 		for (;;) {
10577c478bd9Sstevel@tonic-gate 		    res = ccp_test(f->unit, pv, CILEN_BSD_COMPRESS, 1);
10587c478bd9Sstevel@tonic-gate 		    if (res > 0)
10597c478bd9Sstevel@tonic-gate 			break;
10607c478bd9Sstevel@tonic-gate 		    if (res < 0 || nb == BSD_MIN_BITS || dont_nak) {
10617c478bd9Sstevel@tonic-gate 			newret = CODE_CONFREJ;
10627c478bd9Sstevel@tonic-gate 			break;
10637c478bd9Sstevel@tonic-gate 		    }
10647c478bd9Sstevel@tonic-gate 		    if (newret == CODE_CONFACK) {
10657c478bd9Sstevel@tonic-gate 			BCOPY(pv, nakp, CILEN_BSD_COMPRESS);
10667c478bd9Sstevel@tonic-gate 			pv = nakp;
10677c478bd9Sstevel@tonic-gate 			nakp += CILEN_BSD_COMPRESS;
10687c478bd9Sstevel@tonic-gate 			newret = CODE_CONFNAK;
10697c478bd9Sstevel@tonic-gate 		    }
10707c478bd9Sstevel@tonic-gate 		    --nb;
10717c478bd9Sstevel@tonic-gate 		    pv[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb);
10727c478bd9Sstevel@tonic-gate 		}
10737c478bd9Sstevel@tonic-gate 	    }
10747c478bd9Sstevel@tonic-gate 	    break;
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 	case CI_PREDICTOR_1:
10777c478bd9Sstevel@tonic-gate 	    if (!ao->predictor_1) {
10787c478bd9Sstevel@tonic-gate 		newret = CODE_CONFREJ;
10797c478bd9Sstevel@tonic-gate 		break;
10807c478bd9Sstevel@tonic-gate 	    }
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	    ho->predictor_1 = 1;
10837c478bd9Sstevel@tonic-gate 	    if (clen != CILEN_PREDICTOR_1) {
10847c478bd9Sstevel@tonic-gate 		newret = CODE_CONFNAK;
10857c478bd9Sstevel@tonic-gate 		if (dont_nak)
10867c478bd9Sstevel@tonic-gate 		    break;
10877c478bd9Sstevel@tonic-gate 		pv = nakp;
10887c478bd9Sstevel@tonic-gate 		PUTCHAR(type, nakp);
10897c478bd9Sstevel@tonic-gate 		PUTCHAR(CILEN_PREDICTOR_1, nakp);
10907c478bd9Sstevel@tonic-gate 	    }
10917c478bd9Sstevel@tonic-gate 	    if (p == p0 &&
10927c478bd9Sstevel@tonic-gate 		ccp_test(f->unit, pv, CILEN_PREDICTOR_1, 1) <= 0) {
10937c478bd9Sstevel@tonic-gate 		newret = CODE_CONFREJ;
10947c478bd9Sstevel@tonic-gate 	    }
10957c478bd9Sstevel@tonic-gate 	    break;
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate 	case CI_PREDICTOR_2:
10987c478bd9Sstevel@tonic-gate 	    if (!ao->predictor_2) {
10997c478bd9Sstevel@tonic-gate 		newret = CODE_CONFREJ;
11007c478bd9Sstevel@tonic-gate 		break;
11017c478bd9Sstevel@tonic-gate 	    }
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 	    ho->predictor_2 = 1;
11047c478bd9Sstevel@tonic-gate 	    if (clen != CILEN_PREDICTOR_2) {
11057c478bd9Sstevel@tonic-gate 		newret = CODE_CONFNAK;
11067c478bd9Sstevel@tonic-gate 		if (dont_nak)
11077c478bd9Sstevel@tonic-gate 		    break;
11087c478bd9Sstevel@tonic-gate 		pv = nakp;
11097c478bd9Sstevel@tonic-gate 		PUTCHAR(type, nakp);
11107c478bd9Sstevel@tonic-gate 		PUTCHAR(CILEN_PREDICTOR_2, nakp);
11117c478bd9Sstevel@tonic-gate 	    }
11127c478bd9Sstevel@tonic-gate 	    if (p == p0 &&
11137c478bd9Sstevel@tonic-gate 		ccp_test(f->unit, p, CILEN_PREDICTOR_2, 1) <= 0) {
11147c478bd9Sstevel@tonic-gate 		newret = CODE_CONFREJ;
11157c478bd9Sstevel@tonic-gate 	    }
11167c478bd9Sstevel@tonic-gate 	    break;
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	default:
11197c478bd9Sstevel@tonic-gate 	    newret = CODE_CONFREJ;
11207c478bd9Sstevel@tonic-gate 	    break;
11217c478bd9Sstevel@tonic-gate 	}
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 	/* Cope with confused peers. */
11247c478bd9Sstevel@tonic-gate 	if (clen < 2)
11257c478bd9Sstevel@tonic-gate 	    clen = 2;
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate 	if (newret == CODE_CONFACK && ret != CODE_CONFACK)
11287c478bd9Sstevel@tonic-gate 	    continue;
11297c478bd9Sstevel@tonic-gate 	if (newret == CODE_CONFNAK) {
11307c478bd9Sstevel@tonic-gate 	    if (dont_nak) {
11317c478bd9Sstevel@tonic-gate 		newret = CODE_CONFREJ;
11327c478bd9Sstevel@tonic-gate 	    } else {
11337c478bd9Sstevel@tonic-gate 		/* Ignore subsequent nakable things if rejecting. */
11347c478bd9Sstevel@tonic-gate 		if (ret == CODE_CONFREJ)
11357c478bd9Sstevel@tonic-gate 		    continue;
11367c478bd9Sstevel@tonic-gate 		ret = CODE_CONFNAK;
11377c478bd9Sstevel@tonic-gate 	    }
11387c478bd9Sstevel@tonic-gate 	}
11397c478bd9Sstevel@tonic-gate 	if (newret == CODE_CONFREJ) {
11407c478bd9Sstevel@tonic-gate 	    ret = CODE_CONFREJ;
11417c478bd9Sstevel@tonic-gate 	    if (p != rejp)
11427c478bd9Sstevel@tonic-gate 		BCOPY(p, rejp, clen);
11437c478bd9Sstevel@tonic-gate 	    rejp += clen;
11447c478bd9Sstevel@tonic-gate 	}
11457c478bd9Sstevel@tonic-gate     }
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate     switch (ret) {
11487c478bd9Sstevel@tonic-gate     case CODE_CONFACK:
11497c478bd9Sstevel@tonic-gate 	*lenp = p - p0;
11507c478bd9Sstevel@tonic-gate 	break;
11517c478bd9Sstevel@tonic-gate     case CODE_CONFNAK:
11527c478bd9Sstevel@tonic-gate 	*lenp = nakp - nak_buffer;
11537c478bd9Sstevel@tonic-gate 	BCOPY(nak_buffer, p0, *lenp);
11547c478bd9Sstevel@tonic-gate 	break;
11557c478bd9Sstevel@tonic-gate     case CODE_CONFREJ:
11567c478bd9Sstevel@tonic-gate 	*lenp = rejp - p0;
1157