ccp.c revision 32658
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.28 1998/01/10 01:55:08 brian Exp $ 21 * 22 * TODO: 23 * o Support other compression protocols 24 */ 25#include <sys/param.h> 26#include <netinet/in.h> 27 28#include <stdio.h> 29#include <string.h> 30 31#include "command.h" 32#include "mbuf.h" 33#include "log.h" 34#include "defs.h" 35#include "timer.h" 36#include "fsm.h" 37#include "lcpproto.h" 38#include "lcp.h" 39#include "ccp.h" 40#include "phase.h" 41#include "loadalias.h" 42#include "vars.h" 43#include "pred.h" 44#include "deflate.h" 45 46struct ccpstate CcpInfo = { -1, -1, -1, -1 }; 47 48static void CcpSendConfigReq(struct fsm *); 49static void CcpSendTerminateReq(struct fsm *); 50static void CcpSendTerminateAck(struct fsm *); 51static void CcpDecodeConfig(u_char *, int, int); 52static void CcpLayerStart(struct fsm *); 53static void CcpLayerFinish(struct fsm *); 54static void CcpLayerUp(struct fsm *); 55static void CcpLayerDown(struct fsm *); 56static void CcpInitRestartCounter(struct fsm *); 57 58struct fsm CcpFsm = { 59 "CCP", 60 PROTO_CCP, 61 CCP_MAXCODE, 62 0, 63 ST_INITIAL, 64 0, 0, 0, 65 0, 66 {0, 0, 0, NULL, NULL, NULL}, /* FSM timer */ 67 {0, 0, 0, NULL, NULL, NULL}, /* Open timer */ 68 {0, 0, 0, NULL, NULL, NULL}, /* Stopped timer */ 69 LogCCP, 70 71 CcpLayerUp, 72 CcpLayerDown, 73 CcpLayerStart, 74 CcpLayerFinish, 75 CcpInitRestartCounter, 76 CcpSendConfigReq, 77 CcpSendTerminateReq, 78 CcpSendTerminateAck, 79 CcpDecodeConfig, 80}; 81 82static char const *cftypes[] = { 83 /* Check out the latest ``Compression Control Protocol'' rfc (rfc1962.txt) */ 84 "OUI", /* 0: OUI */ 85 "PRED1", /* 1: Predictor type 1 */ 86 "PRED2", /* 2: Predictor type 2 */ 87 "PUDDLE", /* 3: Puddle Jumber */ 88 "???", "???", "???", "???", "???", "???", 89 "???", "???", "???", "???", "???", "???", 90 "HWPPC", /* 16: Hewlett-Packard PPC */ 91 "STAC", /* 17: Stac Electronics LZS (rfc1974) */ 92 "MSPPC", /* 18: Microsoft PPC */ 93 "GAND", /* 19: Gandalf FZA (rfc1993) */ 94 "V42BIS", /* 20: ARG->DATA.42bis compression */ 95 "BSD", /* 21: BSD LZW Compress */ 96 "???", 97 "LZS-DCP", /* 23: LZS-DCP Compression Protocol (rfc1967) */ 98 "MAGNALINK/DEFLATE", /* 24: Magnalink Variable Resource (rfc1975) */ 99 /* 24: Deflate (according to pppd-2.3.1) */ 100 "DCE", /* 25: Data Circuit-Terminating Equip (rfc1976) */ 101 "DEFLATE", /* 26: Deflate (rfc1979) */ 102}; 103 104#define NCFTYPES (sizeof cftypes/sizeof cftypes[0]) 105 106static const char * 107protoname(int proto) 108{ 109 if (proto < 0 || proto > NCFTYPES) 110 return "none"; 111 return cftypes[proto]; 112} 113 114/* We support these algorithms, and Req them in the given order */ 115static const struct ccp_algorithm *algorithm[] = { 116 &DeflateAlgorithm, 117 &Pred1Algorithm, 118 &PppdDeflateAlgorithm 119}; 120 121static int in_algorithm = -1; 122static int out_algorithm = -1; 123#define NALGORITHMS (sizeof algorithm/sizeof algorithm[0]) 124 125int 126ReportCcpStatus(struct cmdargs const *arg) 127{ 128 if (VarTerm) { 129 fprintf(VarTerm, "%s [%s]\n", CcpFsm.name, StateNames[CcpFsm.state]); 130 fprintf(VarTerm, "My protocol = %s, His protocol = %s\n", 131 protoname(CcpInfo.my_proto), protoname(CcpInfo.his_proto)); 132 fprintf(VarTerm, "Output: %ld --> %ld, Input: %ld --> %ld\n", 133 CcpInfo.uncompout, CcpInfo.compout, 134 CcpInfo.compin, CcpInfo.uncompin); 135 } 136 return 0; 137} 138 139static void 140ccpstateInit(void) 141{ 142 if (CcpInfo.in_init) 143 (*algorithm[in_algorithm]->i.Term)(); 144 if (CcpInfo.out_init) 145 (*algorithm[out_algorithm]->o.Term)(); 146 in_algorithm = -1; 147 out_algorithm = -1; 148 memset(&CcpInfo, '\0', sizeof CcpInfo); 149 CcpInfo.his_proto = CcpInfo.my_proto = -1; 150 CcpInfo.reset_sent = CcpInfo.last_reset = -1; 151} 152 153void 154CcpInit() 155{ 156 FsmInit(&CcpFsm); 157 ccpstateInit(); 158 CcpFsm.maxconfig = 10; 159} 160 161static void 162CcpInitRestartCounter(struct fsm *fp) 163{ 164 fp->FsmTimer.load = VarRetryTimeout * SECTICKS; 165 fp->restart = 5; 166} 167 168static void 169CcpSendConfigReq(struct fsm *fp) 170{ 171 u_char *cp; 172 int f; 173 174 LogPrintf(LogCCP, "CcpSendConfigReq\n"); 175 cp = ReqBuff; 176 CcpInfo.my_proto = -1; 177 out_algorithm = -1; 178 for (f = 0; f < NALGORITHMS; f++) 179 if (Enabled(algorithm[f]->Conf) && !REJECTED(&CcpInfo, algorithm[f]->id)) { 180 struct lcp_opt o; 181 182 (*algorithm[f]->o.Get)(&o); 183 cp += LcpPutConf(LogCCP, cp, &o, cftypes[o.id], 184 (*algorithm[f]->Disp)(&o)); 185 CcpInfo.my_proto = o.id; 186 out_algorithm = f; 187 } 188 FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff); 189} 190 191void 192CcpSendResetReq(struct fsm *fp) 193{ 194 LogPrintf(LogCCP, "SendResetReq(%d)\n", fp->reqid); 195 CcpInfo.reset_sent = fp->reqid; 196 CcpInfo.last_reset = -1; 197 FsmOutput(fp, CODE_RESETREQ, fp->reqid, NULL, 0); 198} 199 200static void 201CcpSendTerminateReq(struct fsm *fp) 202{ 203 /* XXX: No code yet */ 204} 205 206static void 207CcpSendTerminateAck(struct fsm *fp) 208{ 209 LogPrintf(LogCCP, "CcpSendTerminateAck\n"); 210 FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0); 211} 212 213void 214CcpRecvResetReq(struct fsm *fp) 215{ 216 if (out_algorithm >= 0 && out_algorithm < NALGORITHMS) 217 (*algorithm[out_algorithm]->o.Reset)(); 218} 219 220static void 221CcpLayerStart(struct fsm *fp) 222{ 223 LogPrintf(LogCCP, "CcpLayerStart.\n"); 224} 225 226static void 227CcpLayerFinish(struct fsm *fp) 228{ 229 LogPrintf(LogCCP, "CcpLayerFinish.\n"); 230 ccpstateInit(); 231} 232 233static void 234CcpLayerDown(struct fsm *fp) 235{ 236 LogPrintf(LogCCP, "CcpLayerDown.\n"); 237 ccpstateInit(); 238} 239 240/* 241 * Called when CCP has reached the OPEN state 242 */ 243static void 244CcpLayerUp(struct fsm *fp) 245{ 246 LogPrintf(LogCCP, "CcpLayerUp(%d).\n", fp->state); 247 LogPrintf(LogCCP, "Out = %s[%d], In = %s[%d]\n", 248 protoname(CcpInfo.my_proto), CcpInfo.my_proto, 249 protoname(CcpInfo.his_proto), CcpInfo.his_proto); 250 if (!CcpInfo.in_init && in_algorithm >= 0 && in_algorithm < NALGORITHMS) { 251 (*algorithm[in_algorithm]->i.Init)(); 252 CcpInfo.in_init = 1; 253 } 254 if (!CcpInfo.out_init && out_algorithm >= 0 && out_algorithm < NALGORITHMS) { 255 (*algorithm[out_algorithm]->o.Init)(); 256 CcpInfo.out_init = 1; 257 } 258} 259 260void 261CcpUp() 262{ 263 FsmUp(&CcpFsm); 264 LogPrintf(LogCCP, "CCP Up event!!\n"); 265} 266 267void 268CcpOpen() 269{ 270 int f; 271 272 for (f = 0; f < NALGORITHMS; f++) 273 if (Enabled(algorithm[f]->Conf)) { 274 CcpFsm.open_mode = 0; 275 FsmOpen(&CcpFsm); 276 break; 277 } 278 279 if (f == NALGORITHMS) 280 for (f = 0; f < NALGORITHMS; f++) 281 if (Acceptable(algorithm[f]->Conf)) { 282 CcpFsm.open_mode = OPEN_PASSIVE; 283 FsmOpen(&CcpFsm); 284 break; 285 } 286} 287 288static void 289CcpDecodeConfig(u_char *cp, int plen, int mode_type) 290{ 291 int type, length; 292 int f; 293 294 ackp = AckBuff; 295 nakp = NakBuff; 296 rejp = RejBuff; 297 298 while (plen >= sizeof(struct fsmconfig)) { 299 type = *cp; 300 length = cp[1]; 301 if (type < NCFTYPES) 302 LogPrintf(LogCCP, " %s[%d]\n", cftypes[type], length); 303 else 304 LogPrintf(LogCCP, " ???[%d]\n", length); 305 306 for (f = NALGORITHMS-1; f > -1; f--) 307 if (algorithm[f]->id == type) 308 break; 309 310 if (f == -1) { 311 /* Don't understand that :-( */ 312 if (mode_type == MODE_REQ) { 313 CcpInfo.my_reject |= (1 << type); 314 memcpy(rejp, cp, length); 315 rejp += length; 316 } 317 } else { 318 struct lcp_opt o; 319 320 switch (mode_type) { 321 case MODE_REQ: 322 if (Acceptable(algorithm[f]->Conf) && in_algorithm == -1) { 323 memcpy(&o, cp, length); 324 switch ((*algorithm[f]->i.Set)(&o)) { 325 case MODE_REJ: 326 memcpy(rejp, &o, o.len); 327 rejp += o.len; 328 break; 329 case MODE_NAK: 330 memcpy(nakp, &o, o.len); 331 nakp += o.len; 332 break; 333 case MODE_ACK: 334 memcpy(ackp, cp, length); 335 ackp += length; 336 CcpInfo.his_proto = type; 337 in_algorithm = f; /* This one'll do ! */ 338 break; 339 } 340 } else { 341 memcpy(rejp, cp, length); 342 rejp += length; 343 } 344 break; 345 case MODE_NAK: 346 memcpy(&o, cp, length); 347 if ((*algorithm[f]->o.Set)(&o) == MODE_ACK) 348 CcpInfo.my_proto = algorithm[f]->id; 349 else { 350 CcpInfo.his_reject |= (1 << type); 351 CcpInfo.my_proto = -1; 352 } 353 break; 354 case MODE_REJ: 355 CcpInfo.his_reject |= (1 << type); 356 CcpInfo.my_proto = -1; 357 break; 358 } 359 } 360 361 plen -= length; 362 cp += length; 363 } 364 365 if (rejp != RejBuff) { 366 ackp = AckBuff; /* let's not send both ! */ 367 CcpInfo.his_proto = -1; 368 in_algorithm = -1; 369 } 370} 371 372void 373CcpInput(struct mbuf *bp) 374{ 375 if (phase == PHASE_NETWORK) 376 FsmInput(&CcpFsm, bp); 377 else { 378 if (phase > PHASE_NETWORK) 379 LogPrintf(LogCCP, "Error: Unexpected CCP in phase %d\n", phase); 380 pfree(bp); 381 } 382} 383 384void 385CcpResetInput(u_char id) 386{ 387 if (CcpInfo.reset_sent != -1) { 388 if (id != CcpInfo.reset_sent) { 389 LogPrintf(LogWARN, "CCP: Incorrect ResetAck (id %d, not %d) ignored\n", 390 id, CcpInfo.reset_sent); 391 return; 392 } 393 /* Whaddaya know - a correct reset ack */ 394 } else if (id == CcpInfo.last_reset) 395 LogPrintf(LogCCP, "Duplicate ResetAck (resetting again)\n"); 396 else { 397 LogPrintf(LogWARN, "CCP: Unexpected ResetAck (id %d) ignored\n", id); 398 return; 399 } 400 401 CcpInfo.last_reset = CcpInfo.reset_sent; 402 CcpInfo.reset_sent = -1; 403 if (in_algorithm >= 0 && in_algorithm < NALGORITHMS) 404 (*algorithm[in_algorithm]->i.Reset)(); 405} 406 407int 408CcpOutput(int pri, u_short proto, struct mbuf *m) 409{ 410 if (out_algorithm >= 0 && out_algorithm < NALGORITHMS) 411 return (*algorithm[out_algorithm]->o.Write)(pri, proto, m); 412 return 0; 413} 414 415struct mbuf * 416CompdInput(u_short *proto, struct mbuf *m) 417{ 418 if (CcpInfo.reset_sent != -1) { 419 /* Send another REQ and put the packet in the bit bucket */ 420 LogPrintf(LogCCP, "ReSendResetReq(%d)\n", CcpInfo.reset_sent); 421 FsmOutput(&CcpFsm, CODE_RESETREQ, CcpInfo.reset_sent, NULL, 0); 422 pfree(m); 423 } else if (in_algorithm >= 0 && in_algorithm < NALGORITHMS) 424 return (*algorithm[in_algorithm]->i.Read)(proto, m); 425 return NULL; 426} 427 428void 429CcpDictSetup(u_short proto, struct mbuf *m) 430{ 431 if (in_algorithm >= 0 && in_algorithm < NALGORITHMS) 432 (*algorithm[in_algorithm]->i.DictSetup)(proto, m); 433} 434