1 /* 2 * PPP Compression Control Protocol (CCP) Module 3 * 4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5 * 6 * Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the Internet Initiative Japan, Inc. The name of the 14 * IIJ may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $Id: ccp.c,v 1.39 1998/08/26 17:39:36 brian Exp $ 21 * 22 * TODO: 23 * o Support other compression protocols 24 */ 25 #include <sys/types.h> 26 #include <netinet/in.h> 27 #include <netinet/in_systm.h> 28 #include <netinet/ip.h> 29 #include <sys/un.h> 30 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <termios.h> 35 36 #include "defs.h" 37 #include "command.h" 38 #include "mbuf.h" 39 #include "log.h" 40 #include "timer.h" 41 #include "fsm.h" 42 #include "lcpproto.h" 43 #include "lcp.h" 44 #include "ccp.h" 45 #include "pred.h" 46 #include "deflate.h" 47 #include "throughput.h" 48 #include "iplist.h" 49 #include "slcompress.h" 50 #include "lqr.h" 51 #include "hdlc.h" 52 #include "ipcp.h" 53 #include "filter.h" 54 #include "descriptor.h" 55 #include "prompt.h" 56 #include "link.h" 57 #include "mp.h" 58 #include "async.h" 59 #include "physical.h" 60 #include "bundle.h" 61 62 static void CcpSendConfigReq(struct fsm *); 63 static void CcpSentTerminateReq(struct fsm *); 64 static void CcpSendTerminateAck(struct fsm *, u_char); 65 static void CcpDecodeConfig(struct fsm *, u_char *, int, int, 66 struct fsm_decode *); 67 static void CcpLayerStart(struct fsm *); 68 static void CcpLayerFinish(struct fsm *); 69 static int CcpLayerUp(struct fsm *); 70 static void CcpLayerDown(struct fsm *); 71 static void CcpInitRestartCounter(struct fsm *); 72 static void CcpRecvResetReq(struct fsm *); 73 static void CcpRecvResetAck(struct fsm *, u_char); 74 75 static struct fsm_callbacks ccp_Callbacks = { 76 CcpLayerUp, 77 CcpLayerDown, 78 CcpLayerStart, 79 CcpLayerFinish, 80 CcpInitRestartCounter, 81 CcpSendConfigReq, 82 CcpSentTerminateReq, 83 CcpSendTerminateAck, 84 CcpDecodeConfig, 85 CcpRecvResetReq, 86 CcpRecvResetAck 87 }; 88 89 static const char *ccp_TimerNames[] = 90 {"CCP restart", "CCP openmode", "CCP stopped"}; 91 92 static char const *cftypes[] = { 93 /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */ 94 "OUI", /* 0: OUI */ 95 "PRED1", /* 1: Predictor type 1 */ 96 "PRED2", /* 2: Predictor type 2 */ 97 "PUDDLE", /* 3: Puddle Jumber */ 98 "???", "???", "???", "???", "???", "???", 99 "???", "???", "???", "???", "???", "???", 100 "HWPPC", /* 16: Hewlett-Packard PPC */ 101 "STAC", /* 17: Stac Electronics LZS (rfc1974) */ 102 "MPPC", /* 18: Microsoft PPC (rfc2118) */ 103 "GAND", /* 19: Gandalf FZA (rfc1993) */ 104 "V42BIS", /* 20: ARG->DATA.42bis compression */ 105 "BSD", /* 21: BSD LZW Compress */ 106 "???", 107 "LZS-DCP", /* 23: LZS-DCP Compression Protocol (rfc1967) */ 108 "MAGNALINK/DEFLATE", /* 24: Magnalink Variable Resource (rfc1975) */ 109 /* 24: Deflate (according to pppd-2.3.*) */ 110 "DCE", /* 25: Data Circuit-Terminating Equip (rfc1976) */ 111 "DEFLATE", /* 26: Deflate (rfc1979) */ 112 }; 113 114 #define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) 115 116 static const char * 117 protoname(int proto) 118 { 119 if (proto < 0 || proto > NCFTYPES) 120 return "none"; 121 return cftypes[proto]; 122 } 123 124 /* We support these algorithms, and Req them in the given order */ 125 static const struct ccp_algorithm *algorithm[] = { 126 &DeflateAlgorithm, 127 &Pred1Algorithm, 128 &PppdDeflateAlgorithm 129 }; 130 131 #define NALGORITHMS (sizeof algorithm/sizeof algorithm[0]) 132 133 int 134 ccp_ReportStatus(struct cmdargs const *arg) 135 { 136 struct link *l; 137 struct ccp *ccp; 138 139 l = command_ChooseLink(arg); 140 ccp = &l->ccp; 141 142 prompt_Printf(arg->prompt, "%s: %s [%s]\n", l->name, ccp->fsm.name, 143 State2Nam(ccp->fsm.state)); 144 prompt_Printf(arg->prompt, " My protocol = %s, His protocol = %s\n", 145 protoname(ccp->my_proto), protoname(ccp->his_proto)); 146 prompt_Printf(arg->prompt, " Output: %ld --> %ld, Input: %ld --> %ld\n", 147 ccp->uncompout, ccp->compout, 148 ccp->compin, ccp->uncompin); 149 150 prompt_Printf(arg->prompt, "\n Defaults: "); 151 prompt_Printf(arg->prompt, "FSM retry = %us\n", ccp->cfg.fsmretry); 152 prompt_Printf(arg->prompt, " deflate windows: "); 153 prompt_Printf(arg->prompt, "incoming = %d, ", ccp->cfg.deflate.in.winsize); 154 prompt_Printf(arg->prompt, "outgoing = %d\n", ccp->cfg.deflate.out.winsize); 155 prompt_Printf(arg->prompt, " DEFLATE: %s\n", 156 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE])); 157 prompt_Printf(arg->prompt, " PREDICTOR1: %s\n", 158 command_ShowNegval(ccp->cfg.neg[CCP_NEG_PRED1])); 159 prompt_Printf(arg->prompt, " DEFLATE24: %s\n", 160 command_ShowNegval(ccp->cfg.neg[CCP_NEG_DEFLATE24])); 161 return 0; 162 } 163 164 void 165 ccp_SetupCallbacks(struct ccp *ccp) 166 { 167 ccp->fsm.fn = &ccp_Callbacks; 168 ccp->fsm.FsmTimer.name = ccp_TimerNames[0]; 169 ccp->fsm.OpenTimer.name = ccp_TimerNames[1]; 170 ccp->fsm.StoppedTimer.name = ccp_TimerNames[2]; 171 } 172 173 void 174 ccp_Init(struct ccp *ccp, struct bundle *bundle, struct link *l, 175 const struct fsm_parent *parent) 176 { 177 /* Initialise ourselves */ 178 179 fsm_Init(&ccp->fsm, "CCP", PROTO_CCP, 1, CCP_MAXCODE, 10, LogCCP, 180 bundle, l, parent, &ccp_Callbacks, ccp_TimerNames); 181 182 ccp->cfg.deflate.in.winsize = 0; 183 ccp->cfg.deflate.out.winsize = 15; 184 ccp->cfg.fsmretry = DEF_FSMRETRY; 185 ccp->cfg.neg[CCP_NEG_DEFLATE] = NEG_ENABLED|NEG_ACCEPTED; 186 ccp->cfg.neg[CCP_NEG_PRED1] = NEG_ENABLED|NEG_ACCEPTED; 187 ccp->cfg.neg[CCP_NEG_DEFLATE24] = 0; 188 189 ccp_Setup(ccp); 190 } 191 192 void 193 ccp_Setup(struct ccp *ccp) 194 { 195 /* Set ourselves up for a startup */ 196 ccp->fsm.open_mode = 0; 197 ccp->fsm.maxconfig = 10; 198 ccp->his_proto = ccp->my_proto = -1; 199 ccp->reset_sent = ccp->last_reset = -1; 200 ccp->in.algorithm = ccp->out.algorithm = -1; 201 ccp->in.state = ccp->out.state = NULL; 202 ccp->in.opt.id = -1; 203 ccp->out.opt = NULL; 204 ccp->his_reject = ccp->my_reject = 0; 205 ccp->uncompout = ccp->compout = 0; 206 ccp->uncompin = ccp->compin = 0; 207 } 208 209 static void 210 CcpInitRestartCounter(struct fsm *fp) 211 { 212 /* Set fsm timer load */ 213 struct ccp *ccp = fsm2ccp(fp); 214 215 fp->FsmTimer.load = ccp->cfg.fsmretry * SECTICKS; 216 fp->restart = DEF_REQs; 217 } 218 219 static void 220 CcpSendConfigReq(struct fsm *fp) 221 { 222 /* Send config REQ please */ 223 struct ccp *ccp = fsm2ccp(fp); 224 struct ccp_opt **o; 225 u_char *cp, buff[100]; 226 int f, alloc; 227 228 cp = buff; 229 o = &ccp->out.opt; 230 alloc = ccp->his_reject == 0 && ccp->out.opt == NULL; 231 ccp->my_proto = -1; 232 ccp->out.algorithm = -1; 233 for (f = 0; f < NALGORITHMS; f++) 234 if (IsEnabled(ccp->cfg.neg[algorithm[f]->Neg]) && 235 !REJECTED(ccp, algorithm[f]->id)) { 236 237 if (!alloc) 238 for (o = &ccp->out.opt; *o != NULL; o = &(*o)->next) 239 if ((*o)->val.id == algorithm[f]->id && (*o)->algorithm == f) 240 break; 241 242 if (alloc || *o == NULL) { 243 *o = (struct ccp_opt *)malloc(sizeof(struct ccp_opt)); 244 (*o)->val.id = algorithm[f]->id; 245 (*o)->val.len = 2; 246 (*o)->next = NULL; 247 (*o)->algorithm = f; 248 (*algorithm[f]->o.OptInit)(&(*o)->val, &ccp->cfg); 249 } 250 251 if (cp + (*o)->val.len > buff + sizeof buff) { 252 log_Printf(LogERROR, "%s: CCP REQ buffer overrun !\n", fp->link->name); 253 break; 254 } 255 memcpy(cp, &(*o)->val, (*o)->val.len); 256 cp += (*o)->val.len; 257 258 ccp->my_proto = (*o)->val.id; 259 ccp->out.algorithm = f; 260 261 if (alloc) 262 o = &(*o)->next; 263 } 264 265 fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, cp - buff); 266 } 267 268 void 269 ccp_SendResetReq(struct fsm *fp) 270 { 271 /* We can't read our input - ask peer to reset */ 272 struct ccp *ccp = fsm2ccp(fp); 273 274 ccp->reset_sent = fp->reqid; 275 ccp->last_reset = -1; 276 fsm_Output(fp, CODE_RESETREQ, fp->reqid, NULL, 0); 277 } 278 279 static void 280 CcpSentTerminateReq(struct fsm *fp) 281 { 282 /* Term REQ just sent by FSM */ 283 } 284 285 static void 286 CcpSendTerminateAck(struct fsm *fp, u_char id) 287 { 288 /* Send Term ACK please */ 289 fsm_Output(fp, CODE_TERMACK, id, NULL, 0); 290 } 291 292 static void 293 CcpRecvResetReq(struct fsm *fp) 294 { 295 /* Got a reset REQ, reset outgoing dictionary */ 296 struct ccp *ccp = fsm2ccp(fp); 297 if (ccp->out.state != NULL) 298 (*algorithm[ccp->out.algorithm]->o.Reset)(ccp->out.state); 299 } 300 301 static void 302 CcpLayerStart(struct fsm *fp) 303 { 304 /* We're about to start up ! */ 305 log_Printf(LogCCP, "%s: LayerStart.\n", fp->link->name); 306 } 307 308 static void 309 CcpLayerDown(struct fsm *fp) 310 { 311 /* About to come down */ 312 struct ccp *ccp = fsm2ccp(fp); 313 struct ccp_opt *next; 314 315 log_Printf(LogCCP, "%s: LayerDown.\n", fp->link->name); 316 if (ccp->in.state != NULL) { 317 (*algorithm[ccp->in.algorithm]->i.Term)(ccp->in.state); 318 ccp->in.state = NULL; 319 ccp->in.algorithm = -1; 320 } 321 if (ccp->out.state != NULL) { 322 (*algorithm[ccp->out.algorithm]->o.Term)(ccp->out.state); 323 ccp->out.state = NULL; 324 ccp->out.algorithm = -1; 325 } 326 ccp->his_reject = ccp->my_reject = 0; 327 328 while (ccp->out.opt) { 329 next = ccp->out.opt->next; 330 free(ccp->out.opt); 331 ccp->out.opt = next; 332 } 333 ccp_Setup(ccp); 334 } 335 336 static void 337 CcpLayerFinish(struct fsm *fp) 338 { 339 /* We're now down */ 340 log_Printf(LogCCP, "%s: LayerFinish.\n", fp->link->name); 341 } 342 343 /* 344 * Called when CCP has reached the OPEN state 345 */ 346 static int 347 CcpLayerUp(struct fsm *fp) 348 { 349 /* We're now up */ 350 struct ccp *ccp = fsm2ccp(fp); 351 log_Printf(LogCCP, "%s: LayerUp.\n", fp->link->name); 352 if (ccp->in.state == NULL && ccp->in.algorithm >= 0 && 353 ccp->in.algorithm < NALGORITHMS) { 354 ccp->in.state = (*algorithm[ccp->in.algorithm]->i.Init)(&ccp->in.opt); 355 if (ccp->in.state == NULL) { 356 log_Printf(LogERROR, "%s: %s (in) initialisation failure\n", 357 fp->link->name, protoname(ccp->his_proto)); 358 ccp->his_proto = ccp->my_proto = -1; 359 fsm_Close(fp); 360 } 361 } 362 363 if (ccp->out.state == NULL && ccp->out.algorithm >= 0 && 364 ccp->out.algorithm < NALGORITHMS) { 365 ccp->out.state = (*algorithm[ccp->out.algorithm]->o.Init) 366 (&ccp->out.opt->val); 367 if (ccp->out.state == NULL) { 368 log_Printf(LogERROR, "%s: %s (out) initialisation failure\n", 369 fp->link->name, protoname(ccp->my_proto)); 370 ccp->his_proto = ccp->my_proto = -1; 371 fsm_Close(fp); 372 } 373 } 374 375 log_Printf(LogCCP, "%s: Out = %s[%d], In = %s[%d]\n", 376 fp->link->name, protoname(ccp->my_proto), ccp->my_proto, 377 protoname(ccp->his_proto), ccp->his_proto); 378 return 1; 379 } 380 381 static void 382 CcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type, 383 struct fsm_decode *dec) 384 { 385 /* Deal with incoming data */ 386 struct ccp *ccp = fsm2ccp(fp); 387 int type, length; 388 int f; 389 const char *end; 390 391 while (plen >= sizeof(struct fsmconfig)) { 392 type = *cp; 393 length = cp[1]; 394 395 if (length == 0) { 396 log_Printf(LogCCP, "%s: CCP size zero\n", fp->link->name); 397 break; 398 } 399 400 if (length > sizeof(struct lcp_opt)) { 401 length = sizeof(struct lcp_opt); 402 log_Printf(LogCCP, "%s: Warning: Truncating length to %d\n", 403 fp->link->name, length); 404 } 405 406 for (f = NALGORITHMS-1; f > -1; f--) 407 if (algorithm[f]->id == type) 408 break; 409 410 end = f == -1 ? "" : (*algorithm[f]->Disp)((struct lcp_opt *)cp); 411 if (end == NULL) 412 end = ""; 413 414 if (type < NCFTYPES) 415 log_Printf(LogCCP, " %s[%d] %s\n", cftypes[type], length, end); 416 else 417 log_Printf(LogCCP, " ???[%d] %s\n", length, end); 418 419 if (f == -1) { 420 /* Don't understand that :-( */ 421 if (mode_type == MODE_REQ) { 422 ccp->my_reject |= (1 << type); 423 memcpy(dec->rejend, cp, length); 424 dec->rejend += length; 425 } 426 } else { 427 struct ccp_opt *o; 428 429 switch (mode_type) { 430 case MODE_REQ: 431 if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) && 432 ccp->in.algorithm == -1) { 433 memcpy(&ccp->in.opt, cp, length); 434 switch ((*algorithm[f]->i.Set)(&ccp->in.opt, &ccp->cfg)) { 435 case MODE_REJ: 436 memcpy(dec->rejend, &ccp->in.opt, ccp->in.opt.len); 437 dec->rejend += ccp->in.opt.len; 438 break; 439 case MODE_NAK: 440 memcpy(dec->nakend, &ccp->in.opt, ccp->in.opt.len); 441 dec->nakend += ccp->in.opt.len; 442 break; 443 case MODE_ACK: 444 memcpy(dec->ackend, cp, length); 445 dec->ackend += length; 446 ccp->his_proto = type; 447 ccp->in.algorithm = f; /* This one'll do :-) */ 448 break; 449 } 450 } else { 451 memcpy(dec->rejend, cp, length); 452 dec->rejend += length; 453 } 454 break; 455 case MODE_NAK: 456 for (o = ccp->out.opt; o != NULL; o = o->next) 457 if (o->val.id == cp[0]) 458 break; 459 if (o == NULL) 460 log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent option\n", 461 fp->link->name); 462 else { 463 memcpy(&o->val, cp, length); 464 if ((*algorithm[f]->o.Set)(&o->val) == MODE_ACK) 465 ccp->my_proto = algorithm[f]->id; 466 else { 467 ccp->his_reject |= (1 << type); 468 ccp->my_proto = -1; 469 } 470 } 471 break; 472 case MODE_REJ: 473 ccp->his_reject |= (1 << type); 474 ccp->my_proto = -1; 475 break; 476 } 477 } 478 479 plen -= cp[1]; 480 cp += cp[1]; 481 } 482 483 if (mode_type != MODE_NOP) { 484 if (dec->rejend != dec->rej) { 485 /* rejects are preferred */ 486 dec->ackend = dec->ack; 487 dec->nakend = dec->nak; 488 if (ccp->in.state == NULL) { 489 ccp->his_proto = -1; 490 ccp->in.algorithm = -1; 491 } 492 } else if (dec->nakend != dec->nak) { 493 /* then NAKs */ 494 dec->ackend = dec->ack; 495 if (ccp->in.state == NULL) { 496 ccp->his_proto = -1; 497 ccp->in.algorithm = -1; 498 } 499 } 500 } 501 } 502 503 void 504 ccp_Input(struct ccp *ccp, struct bundle *bundle, struct mbuf *bp) 505 { 506 /* Got PROTO_CCP from link */ 507 if (bundle_Phase(bundle) == PHASE_NETWORK) 508 fsm_Input(&ccp->fsm, bp); 509 else { 510 if (bundle_Phase(bundle) < PHASE_NETWORK) 511 log_Printf(LogCCP, "%s: Error: Unexpected CCP in phase %s (ignored)\n", 512 ccp->fsm.link->name, bundle_PhaseName(bundle)); 513 mbuf_Free(bp); 514 } 515 } 516 517 static void 518 CcpRecvResetAck(struct fsm *fp, u_char id) 519 { 520 /* Got a reset ACK, reset incoming dictionary */ 521 struct ccp *ccp = fsm2ccp(fp); 522 523 if (ccp->reset_sent != -1) { 524 if (id != ccp->reset_sent) { 525 log_Printf(LogWARN, "CCP: %s: Incorrect ResetAck (id %d, not %d)" 526 " ignored\n", fp->link->name, id, ccp->reset_sent); 527 return; 528 } 529 /* Whaddaya know - a correct reset ack */ 530 } else if (id == ccp->last_reset) 531 log_Printf(LogCCP, "%s: Duplicate ResetAck (resetting again)\n", 532 fp->link->name); 533 else { 534 log_Printf(LogWARN, "CCP: %s: Unexpected ResetAck (id %d) ignored\n", 535 fp->link->name, id); 536 return; 537 } 538 539 ccp->last_reset = ccp->reset_sent; 540 ccp->reset_sent = -1; 541 if (ccp->in.state != NULL) 542 (*algorithm[ccp->in.algorithm]->i.Reset)(ccp->in.state); 543 } 544 545 int 546 ccp_Compress(struct ccp *ccp, struct link *l, int pri, u_short proto, 547 struct mbuf *m) 548 { 549 /* 550 * Compress outgoing data. It's already deemed to be suitable Network 551 * Layer data. 552 */ 553 if (ccp->fsm.state == ST_OPENED && ccp->out.state != NULL) 554 return (*algorithm[ccp->out.algorithm]->o.Write) 555 (ccp->out.state, ccp, l, pri, proto, m); 556 return 0; 557 } 558 559 struct mbuf * 560 ccp_Decompress(struct ccp *ccp, u_short *proto, struct mbuf *bp) 561 { 562 /* 563 * If proto isn't PROTO_[I]COMPD, we still want to pass it to the 564 * decompression routines so that the dictionary's updated 565 */ 566 if (ccp->fsm.state == ST_OPENED) { 567 if (*proto == PROTO_COMPD || *proto == PROTO_ICOMPD) { 568 /* Decompress incoming data */ 569 if (ccp->reset_sent != -1) 570 /* Send another REQ and put the packet in the bit bucket */ 571 fsm_Output(&ccp->fsm, CODE_RESETREQ, ccp->reset_sent, NULL, 0); 572 else if (ccp->in.state != NULL) 573 return (*algorithm[ccp->in.algorithm]->i.Read) 574 (ccp->in.state, ccp, proto, bp); 575 mbuf_Free(bp); 576 bp = NULL; 577 } else if (PROTO_COMPRESSIBLE(*proto) && ccp->in.state != NULL) 578 /* Add incoming Network Layer traffic to our dictionary */ 579 (*algorithm[ccp->in.algorithm]->i.DictSetup) 580 (ccp->in.state, ccp, *proto, bp); 581 } 582 583 return bp; 584 } 585 586 u_short 587 ccp_Proto(struct ccp *ccp) 588 { 589 return !link2physical(ccp->fsm.link) || !ccp->fsm.bundle->ncp.mp.active ? 590 PROTO_COMPD : PROTO_ICOMPD; 591 } 592 593 int 594 ccp_SetOpenMode(struct ccp *ccp) 595 { 596 int f; 597 598 for (f = 0; f < CCP_NEG_TOTAL; f++) 599 if (IsEnabled(ccp->cfg.neg[f])) { 600 ccp->fsm.open_mode = 0; 601 return 1; 602 } 603 604 ccp->fsm.open_mode = OPEN_PASSIVE; /* Go straight to ST_STOPPED ? */ 605 606 for (f = 0; f < CCP_NEG_TOTAL; f++) 607 if (IsAccepted(ccp->cfg.neg[f])) 608 return 1; 609 610 return 0; /* No CCP at all */ 611 } 612