"SfR Fresh" - the SfR Freeware/Shareware Archive

Member "slirp-1.0.16/src/ppp/ccp.c" of archive slirp-1.0.16.tar.gz:


As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
    1 /*
    2  * ccp.c - PPP Compression Control Protocol.
    3  *
    4  * Copyright (c) 1994 The Australian National University.
    5  * All rights reserved.
    6  *
    7  * Permission to use, copy, modify, and distribute this software and its
    8  * documentation is hereby granted, provided that the above copyright
    9  * notice appears in all copies.  This software is provided without any
   10  * warranty, express or implied. The Australian National University
   11  * makes no representations about the suitability of this software for
   12  * any purpose.
   13  *
   14  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
   15  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
   16  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
   17  * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
   18  * OF SUCH DAMAGE.
   19  *
   20  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
   21  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
   22  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
   23  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
   24  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
   25  * OR MODIFICATIONS.
   26  */
   27 
   28 #ifndef lint
   29 static char rcsid[] = "$Id: ccp.c,v 1.10 1995/06/06 01:52:23 paulus Exp $";
   30 #endif
   31 
   32 #include <syslog.h>
   33 #include <slirp.h>
   34 #include "ppp-comp.h"
   35 
   36 #include "pppd.h"
   37 #include "fsm.h"
   38 #include "ccp.h"
   39 
   40 fsm ccp_fsm[NUM_PPP];
   41 ccp_options ccp_wantoptions[NUM_PPP];	/* what to request the peer to use */
   42 ccp_options ccp_gotoptions[NUM_PPP];	/* what the peer agreed to do */
   43 ccp_options ccp_allowoptions[NUM_PPP];	/* what we'll agree to do */
   44 ccp_options ccp_hisoptions[NUM_PPP];	/* what we agreed to do */
   45 
   46 /*
   47  * Callbacks for fsm code.
   48  */
   49 static void ccp_resetci __P((fsm *));
   50 static int  ccp_cilen __P((fsm *));
   51 static void ccp_addci __P((fsm *, u_char *, int *));
   52 static int  ccp_ackci __P((fsm *, u_char *, int));
   53 static int  ccp_nakci __P((fsm *, u_char *, int));
   54 static int  ccp_rejci __P((fsm *, u_char *, int));
   55 static int  ccp_reqci __P((fsm *, u_char *, int *, int));
   56 static void ccp_up __P((fsm *));
   57 static void ccp_down __P((fsm *));
   58 static int  ccp_extcode __P((fsm *, int, int, u_char *, int));
   59 static void ccp_rack_timeout __P(());
   60 
   61 static fsm_callbacks ccp_callbacks = {
   62     ccp_resetci,
   63     ccp_cilen,
   64     ccp_addci,
   65     ccp_ackci,
   66     ccp_nakci,
   67     ccp_rejci,
   68     ccp_reqci,
   69     ccp_up,
   70     ccp_down,
   71     NULL,
   72     NULL,
   73     NULL,
   74     NULL,
   75     ccp_extcode,
   76     "CCP"
   77 };
   78 
   79 /*
   80  * Do we want / did we get any compression?
   81  */
   82 #define ANY_COMPRESS(opt)	((opt).bsd_compress)
   83 
   84 /*
   85  * Local state (mainly for handling reset-reqs and reset-acks
   86  */
   87 static int ccp_localstate[NUM_PPP];
   88 #define RACK_PENDING	1	/* waiting for reset-ack */
   89 #define RREQ_REPEAT	2	/* send another reset-req if no reset-ack */
   90 
   91 #define RACKTIMEOUT	1	/* second */
   92 
   93 /*
   94  * ccp_init - initialize CCP.
   95  */
   96 void
   97 ccp_init(unit)
   98     int unit;
   99 {
  100     fsm *f = &ccp_fsm[unit];
  101 
  102     f->unit = unit;
  103     f->protocol = PPP_CCP;
  104     f->callbacks = &ccp_callbacks;
  105     fsm_init(f);
  106 
  107     memset(&ccp_wantoptions[unit],  0, sizeof(ccp_options));
  108     memset(&ccp_gotoptions[unit],   0, sizeof(ccp_options));
  109     memset(&ccp_allowoptions[unit], 0, sizeof(ccp_options));
  110     memset(&ccp_hisoptions[unit],   0, sizeof(ccp_options));
  111 
  112     ccp_wantoptions[0].bsd_compress = 1;
  113     ccp_wantoptions[0].bsd_bits = 12;	/* default value */
  114 
  115     ccp_allowoptions[0].bsd_compress = 1;
  116     ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS;
  117 }
  118 
  119 /*
  120  * ccp_open - CCP is allowed to come up.
  121  */
  122 void
  123 ccp_open(unit)
  124     int unit;
  125 {
  126     fsm *f = &ccp_fsm[unit];
  127 
  128     if (f->state != OPENED)
  129 	ccp_flags_set(unit, 1, 0);
  130     if (!ANY_COMPRESS(ccp_wantoptions[unit]))
  131 	f->flags |= OPT_SILENT;
  132     fsm_open(f);
  133 }
  134 
  135 /*
  136  * ccp_close - Terminate CCP.
  137  */
  138 void
  139 ccp_close(unit)
  140     int unit;
  141 {
  142     ccp_flags_set(unit, 0, 0);
  143     fsm_close(&ccp_fsm[unit]);
  144 }
  145 
  146 /*
  147  * ccp_lowerup - we may now transmit CCP packets.
  148  */
  149 void
  150 ccp_lowerup(unit)
  151     int unit;
  152 {
  153     fsm_lowerup(&ccp_fsm[unit]);
  154 }
  155 
  156 /*
  157  * ccp_lowerdown - we may not transmit CCP packets.
  158  */
  159 void
  160 ccp_lowerdown(unit)
  161     int unit;
  162 {
  163     fsm_lowerdown(&ccp_fsm[unit]);
  164 }
  165 
  166 /*
  167  * ccp_input - process a received CCP packet.
  168  */
  169 void
  170 ccp_input(unit, p, len)
  171     int unit;
  172     u_char *p;
  173     int len;
  174 {
  175     fsm *f = &ccp_fsm[unit];
  176     int oldstate;
  177 
  178     /*
  179      * Check for a terminate-request so we can print a message.
  180      */
  181     oldstate = f->state;
  182     fsm_input(f, p, len);
  183     if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED)
  184 	do_syslog(LOG_NOTICE, "Compression disabled by peer.");
  185 
  186     /*
  187      * If we get a terminate-ack and we're not asking for compression,
  188      * close CCP.
  189      */
  190     if (oldstate == REQSENT && p[0] == TERMACK
  191        && !ANY_COMPRESS(ccp_gotoptions[unit]))
  192        ccp_close(unit);
  193 
  194 }
  195 
  196 /*
  197  * Handle a CCP-specific code.
  198  */
  199 static int
  200 ccp_extcode(f, code, id, p, len)
  201     fsm *f;
  202     int code, id;
  203     u_char *p;
  204     int len;
  205 {
  206     switch (code) {
  207     case CCP_RESETREQ:
  208 	if (f->state != OPENED)
  209 	    break;
  210 	/* send a reset-ack, which the transmitter will see and
  211 	   reset its compression state. */
  212 	fsm_sdata(f, CCP_RESETACK, id, NULL, 0);
  213 	break;
  214 
  215     case CCP_RESETACK:
  216 	if (ccp_localstate[f->unit] & RACK_PENDING && id == f->reqid) {
  217 	    ccp_localstate[f->unit] &= ~(RACK_PENDING | RREQ_REPEAT);
  218 	    UNTIMEOUT(ccp_rack_timeout, (caddr_t) f);
  219 	}
  220 	break;
  221 
  222     default:
  223 	return 0;
  224     }
  225 
  226     return 1;
  227 }
  228 
  229 /*
  230  * ccp_protrej - peer doesn't talk CCP.
  231  */
  232 void
  233 ccp_protrej(unit)
  234     int unit;
  235 {
  236     ccp_flags_set(unit, 0, 0);
  237     fsm_lowerdown(&ccp_fsm[unit]);
  238 }
  239 
  240 /*
  241  * ccp_resetci - initialize at start of negotiation.
  242  */
  243 static void
  244 ccp_resetci(f)
  245     fsm *f;
  246 {
  247     ccp_options *go = &ccp_gotoptions[f->unit];
  248     u_char opt_buf[16];
  249 
  250     *go = ccp_wantoptions[f->unit];
  251     if (go->bsd_compress) {
  252 	opt_buf[0] = CI_BSD_COMPRESS;
  253 	opt_buf[1] = CILEN_BSD_COMPRESS;
  254 	opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
  255 	if (!ccp_test(f->unit, opt_buf, CILEN_BSD_COMPRESS, 0))
  256 	    go->bsd_compress = 0;
  257     }
  258 }
  259 
  260 /*
  261  * ccp_cilen - Return total length of our configuration info.
  262  */
  263 static int
  264 ccp_cilen(f)
  265     fsm *f;
  266 {
  267     ccp_options *go = &ccp_gotoptions[f->unit];
  268 
  269     return (go->bsd_compress? CILEN_BSD_COMPRESS: 0);
  270 }
  271 
  272 /*
  273  * ccp_addci - put our requests in a packet.
  274  */
  275 static void
  276 ccp_addci(f, p, lenp)
  277     fsm *f;
  278     u_char *p;
  279     int *lenp;
  280 {
  281     ccp_options *go = &ccp_gotoptions[f->unit];
  282     u_char *p0 = p;
  283 
  284     if (go->bsd_compress) {
  285 	p[0] = CI_BSD_COMPRESS;
  286 	p[1] = CILEN_BSD_COMPRESS;
  287 	p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
  288 	if (ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0))
  289 	    p += CILEN_BSD_COMPRESS;
  290 	else
  291 	    go->bsd_compress = 0;
  292     }
  293     *lenp = p - p0;
  294 }
  295 
  296 /*
  297  * ccp_ackci - process a received configure-ack, and return
  298  * 1 iff the packet was OK.
  299  */
  300 static int
  301 ccp_ackci(f, p, len)
  302     fsm *f;
  303     u_char *p;
  304     int len;
  305 {
  306     ccp_options *go = &ccp_gotoptions[f->unit];
  307 
  308     if (go->bsd_compress) {
  309 	if (len < CILEN_BSD_COMPRESS
  310 	    || p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS
  311 	    || p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
  312 	    return 0;
  313 	p += CILEN_BSD_COMPRESS;
  314 	len -= CILEN_BSD_COMPRESS;
  315     }
  316     if (len != 0)
  317 	return 0;
  318     return 1;
  319 }
  320 
  321 /*
  322  * ccp_nakci - process received configure-nak.
  323  * Returns 1 iff the nak was OK.
  324  */
  325 static int
  326 ccp_nakci(f, p, len)
  327     fsm *f;
  328     u_char *p;
  329     int len;
  330 {
  331     ccp_options *go = &ccp_gotoptions[f->unit];
  332     ccp_options no;		/* options we've seen already */
  333     ccp_options try;		/* options to ask for next time */
  334 
  335     memset(&no, 0, sizeof(no));
  336     try = *go;
  337 
  338     if (go->bsd_compress && !no.bsd_compress && len >= CILEN_BSD_COMPRESS
  339 	&& p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
  340 	no.bsd_compress = 1;
  341 	/*
  342 	 * Peer wants us to use a different number of bits
  343 	 * or a different version.
  344 	 */
  345 	if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION)
  346 	    try.bsd_compress = 0;
  347 	else if (BSD_NBITS(p[2]) < go->bsd_bits)
  348 	    try.bsd_bits = BSD_NBITS(p[2]);
  349 	p += CILEN_BSD_COMPRESS;
  350 	len -= CILEN_BSD_COMPRESS;
  351     }
  352 
  353     /*
  354      * Have a look at any remaining options...???
  355      */
  356 
  357     if (len != 0)
  358 	return 0;
  359 
  360     if (f->state != OPENED)
  361 	*go = try;
  362     return 1;
  363 }
  364 
  365 /*
  366  * ccp_rejci - reject some of our suggested compression methods.
  367  */
  368 static int
  369 ccp_rejci(f, p, len)
  370     fsm *f;
  371     u_char *p;
  372     int len;
  373 {
  374     ccp_options *go = &ccp_gotoptions[f->unit];
  375     ccp_options try;		/* options to request next time */
  376 
  377     try = *go;
  378 
  379     if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
  380 	&& p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
  381 	if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
  382 	    return 0;
  383 	try.bsd_compress = 0;
  384 	p += CILEN_BSD_COMPRESS;
  385 	len -= CILEN_BSD_COMPRESS;
  386     }
  387 
  388     if (len != 0)
  389 	return 0;
  390 
  391     if (f->state != OPENED)
  392 	*go = try;
  393 
  394     return 1;
  395 }
  396 
  397 /*
  398  * ccp_reqci - processed a received configure-request.
  399  * Returns CONFACK, CONFNAK or CONFREJ and the packet modified
  400  * appropriately.
  401  */
  402 static int
  403 ccp_reqci(f, p, lenp, dont_nak)
  404     fsm *f;
  405     u_char *p;
  406     int *lenp;
  407     int dont_nak;
  408 {
  409     int ret, newret;
  410     u_char *p0, *retp;
  411     int len, clen, type, nb;
  412     ccp_options *ho = &ccp_hisoptions[f->unit];
  413     ccp_options *ao = &ccp_allowoptions[f->unit];
  414 
  415     ret = CONFACK;
  416     retp = p0 = p;
  417     len = *lenp;
  418 
  419     memset(ho, 0, sizeof(ccp_options));
  420 
  421     while (len > 0) {
  422 	newret = CONFACK;
  423 	if (len < 2 || p[1] < 2 || p[1] > len) {
  424 	    /* length is bad */
  425 	    clen = len;
  426 	    newret = CONFREJ;
  427 
  428 	} else {
  429 	    type = p[0];
  430 	    clen = p[1];
  431 
  432 	    switch (type) {
  433 	    case CI_BSD_COMPRESS:
  434 		if (!ao->bsd_compress || clen != CILEN_BSD_COMPRESS) {
  435 		    newret = CONFREJ;
  436 		    break;
  437 		}
  438 
  439 		ho->bsd_compress = 1;
  440 		ho->bsd_bits = nb = BSD_NBITS(p[2]);
  441 		if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION
  442 		    || nb > ao->bsd_bits) {
  443 		    newret = CONFNAK;
  444 		    nb = ao->bsd_bits;
  445 		} else if (nb < BSD_MIN_BITS) {
  446 		    newret = CONFREJ;
  447 		} else if (!ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 1)) {
  448 		    if (nb > BSD_MIN_BITS) {
  449 			--nb;
  450 			newret = CONFNAK;
  451 		    } else
  452 			newret = CONFREJ;
  453 		}
  454 		if (newret == CONFNAK && !dont_nak) {
  455 		    p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb);
  456 		}
  457 
  458 		break;
  459 
  460 	    default:
  461 		newret = CONFREJ;
  462 	    }
  463 	}
  464 
  465 	if (newret == CONFNAK && dont_nak)
  466 	    newret = CONFREJ;
  467 	if (!(newret == CONFACK || newret == CONFNAK && ret == CONFREJ)) {
  468 	    /* we're returning this option */
  469 	    if (newret == CONFREJ && ret == CONFNAK)
  470 		retp = p0;
  471 	    ret = newret;
  472 	    if (p != retp)
  473 		BCOPY(p, retp, clen);
  474 	    retp += clen;
  475 	}
  476 
  477 	p += clen;
  478 	len -= clen;
  479     }
  480 
  481     if (ret != CONFACK)
  482 	*lenp = retp - p0;
  483     return ret;
  484 }
  485 
  486 /*
  487  * CCP has come up - inform the kernel driver.
  488  */
  489 static void
  490 ccp_up(f)
  491     fsm *f;
  492 {
  493     ccp_options *go = &ccp_gotoptions[f->unit];
  494     ccp_options *ho = &ccp_hisoptions[f->unit];
  495 
  496     ccp_flags_set(f->unit, 1, 1);
  497     if (go->bsd_compress || ho->bsd_compress)
  498 	do_syslog(LOG_NOTICE, "%s enabled",
  499 	       go->bsd_compress? ho->bsd_compress? "Compression":
  500 	       "Receive compression": "Transmit compression");
  501 }
  502 
  503 /*
  504  * CCP has gone down - inform the kernel driver.
  505  */
  506 static void
  507 ccp_down(f)
  508     fsm *f;
  509 {
  510     if (ccp_localstate[f->unit] & RACK_PENDING)
  511 	UNTIMEOUT(ccp_rack_timeout, (caddr_t) f);
  512     ccp_localstate[f->unit] = 0;
  513     ccp_flags_set(f->unit, 1, 0);
  514 }
  515 
  516 /*
  517  * Print the contents of a CCP packet.
  518  */
  519 char *ccp_codenames[] = {
  520     "ConfReq", "ConfAck", "ConfNak", "ConfRej",
  521     "TermReq", "TermAck", "CodeRej",
  522     NULL, NULL, NULL, NULL, NULL, NULL,
  523     "ResetReq", "ResetAck",
  524 };
  525 
  526 int
  527 ccp_printpkt(p, plen, printer, arg)
  528     u_char *p;
  529     int plen;
  530     void (*printer) __P((void *, char *, ...));
  531     void *arg;
  532 {
  533     u_char *p0, *optend;
  534     int code, id, len;
  535     int optlen;
  536 
  537     p0 = p;
  538     if (plen < HEADERLEN)
  539 	return 0;
  540     code = p[0];
  541     id = p[1];
  542     len = (p[2] << 8) + p[3];
  543     if (len < HEADERLEN || len > plen)
  544 	return 0;
  545 
  546     if (code >= 1 && code <= sizeof(ccp_codenames) / sizeof(char *)
  547 	&& ccp_codenames[code-1] != NULL)
  548 	printer(arg, " %s", ccp_codenames[code-1]);
  549     else
  550 	printer(arg, " code=0x%x", code);
  551     printer(arg, " id=0x%x", id);
  552     len -= HEADERLEN;
  553     p += HEADERLEN;
  554 
  555     switch (code) {
  556     case CONFREQ:
  557     case CONFACK:
  558     case CONFNAK:
  559     case CONFREJ:
  560 	/* print list of possible compression methods */
  561 	while (len >= 2) {
  562 	    code = p[0];
  563 	    optlen = p[1];
  564 	    if (optlen < 2 || optlen > len)
  565 		break;
  566 	    printer(arg, " <");
  567 	    len -= optlen;
  568 	    optend = p + optlen;
  569 	    switch (code) {
  570 	    case CI_BSD_COMPRESS:
  571 		if (optlen >= CILEN_BSD_COMPRESS) {
  572 		    printer(arg, "bsd v%d %d", BSD_VERSION(p[2]),
  573 			    BSD_NBITS(p[2]));
  574 		    p += CILEN_BSD_COMPRESS;
  575 		}
  576 		break;
  577 	    }
  578 	    while (p < optend)
  579 		printer(arg, " %.2x", *p++);
  580 	    printer(arg, ">");
  581 	}
  582 	break;
  583     }
  584 
  585     /* dump out the rest of the packet in hex */
  586     while (--len >= 0)
  587 	printer(arg, " %.2x", *p++);
  588 
  589     return p - p0;
  590 }
  591 
  592 /*
  593  * We have received a packet that the decompressor failed to
  594  * decompress.  Here we would expect to issue a reset-request, but
  595  * Motorola has a patent on resetting the compressor as a result of
  596  * detecting an error in the decompressed data after decompression.
  597  * (See US patent 5,130,993; international patent publication number
  598  * WO 91/10289; Australian patent 73296/91.)
  599  *
  600  * So we ask the kernel whether the error was detected after
  601  * decompression; if it was, we take CCP down, thus disabling
  602  * compression :-(, otherwise we issue the reset-request.
  603  */
  604 void
  605 ccp_datainput(unit, pkt, len)
  606     int unit;
  607     u_char *pkt;
  608     int len;
  609 {
  610     fsm *f;
  611 
  612     f = &ccp_fsm[unit];
  613     if (f->state == OPENED) {
  614 	if (ccp_fatal_error(unit)) {
  615 	    /*
  616 	     * Disable compression by taking CCP down.
  617 	     */
  618 	    do_syslog(LOG_ERR, "Lost compression sync: disabling compression");
  619 	    ccp_close(unit);
  620 	} else {
  621 	    /*
  622 	     * Send a reset-request to reset the peer's compressor.
  623 	     * We don't do that if we are still waiting for an
  624 	     * acknowledgement to a previous reset-request.
  625 	     */
  626 	    if (!(ccp_localstate[f->unit] & RACK_PENDING)) {
  627 		fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0);
  628 		TIMEOUT(ccp_rack_timeout, (caddr_t) f, RACKTIMEOUT);
  629 		ccp_localstate[f->unit] |= RACK_PENDING;
  630 	    } else
  631 		ccp_localstate[f->unit] |= RREQ_REPEAT;
  632 	}
  633     }
  634 }
  635 
  636 /*
  637  * Timeout waiting for reset-ack.
  638  */
  639 static void
  640 ccp_rack_timeout(arg)
  641     caddr_t arg;
  642 {
  643     fsm *f = (fsm *) arg;
  644 
  645     if (f->state == OPENED && ccp_localstate[f->unit] & RREQ_REPEAT) {
  646 	fsm_sdata(f, CCP_RESETREQ, f->reqid, NULL, 0);
  647 	TIMEOUT(ccp_rack_timeout, (caddr_t) f, RACKTIMEOUT);
  648 	ccp_localstate[f->unit] &= ~RREQ_REPEAT;
  649     } else
  650 	ccp_localstate[f->unit] &= ~RACK_PENDING;
  651 }
  652