Annotation of embedaddon/mpd/src/ccp_pred1.c, revision 1.1.1.2
1.1 misho 1:
2: /*
3: * ccp_pred1.c
4: *
5: * Rewritten by Alexander Motin <mav@FreeBSD.org>
6: * Written by Archie Cobbs <archie@freebsd.org>
7: * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
8: * See ``COPYRIGHT.whistle''
9: */
10:
11: /*
12: * pred1.c
13: *
14: * Test program for Dave Rand's rendition of the predictor algorithm
15: *
16: * Updated by: archie@freebsd.org (Archie Cobbs)
17: * Updated by: iand@labtam.labtam.oz.au (Ian Donaldson)
18: * Updated by: Carsten Bormann <cabo@cs.tu-berlin.de>
19: * Original : Dave Rand <dlr@bungi.com>/<dave_rand@novell.com>
20: */
21:
22: #include "ppp.h"
23: #include "ccp.h"
24: #include "util.h"
25: #include "ngfunc.h"
26:
27: #ifdef USE_NG_PRED1
28: #include <netgraph/ng_message.h>
29: #include <netgraph.h>
30: #endif
31:
32: /*
33: * DEFINITIONS
34: */
35:
36: #define PRED1_DECOMP_BUF_SIZE 4096
37:
38: #define PRED1_MAX_BLOWUP(n) ((n) * 9 / 8 + 24)
39:
40: /*
41: * The following hash code is the heart of the algorithm:
42: * It builds a sliding hash sum of the previous 3-and-a-bit characters
43: * which will be used to index the guess table.
44: * A better hash function would result in additional compression,
45: * at the expense of time.
46: */
47:
48: #define IHASH(x) p->iHash = (p->iHash << 4) ^ (x)
49: #define OHASH(x) p->oHash = (p->oHash << 4) ^ (x)
50:
51: /*
52: * INTERNAL FUNCTIONS
53: */
54:
55: static int Pred1Init(Bund b, int direction);
56: static void Pred1Cleanup(Bund b, int direction);
57: #ifndef USE_NG_PRED1
58: static Mbuf Pred1Compress(Bund b, Mbuf plain);
59: static Mbuf Pred1Decompress(Bund b, Mbuf comp);
60: #endif
61:
62: static u_char *Pred1BuildConfigReq(Bund b, u_char *cp, int *ok);
63: static void Pred1DecodeConfigReq(Fsm fp, FsmOption opt, int mode);
64: static Mbuf Pred1RecvResetReq(Bund b, int id, Mbuf bp, int *noAck);
65: static Mbuf Pred1SendResetReq(Bund b);
66: static void Pred1RecvResetAck(Bund b, int id, Mbuf bp);
67: static int Pred1Negotiated(Bund b, int xmit);
68: static int Pred1SubtractBloat(Bund b, int size);
69: static int Pred1Stat(Context ctx, int dir);
70:
71: #ifndef USE_NG_PRED1
72: static int Compress(Bund b, u_char *source, u_char *dest, int len);
73: static int Decompress(Bund b, u_char *source, u_char *dest, int slen, int dlen);
74: static void SyncTable(Bund b, u_char *source, u_char *dest, int len);
75: #endif
76:
77: /*
78: * GLOBAL VARIABLES
79: */
80:
81: const struct comptype gCompPred1Info =
82: {
83: "pred1",
84: CCP_TY_PRED1,
85: 1,
86: Pred1Init,
87: NULL,
88: NULL,
89: NULL,
90: Pred1SubtractBloat,
91: Pred1Cleanup,
92: Pred1BuildConfigReq,
93: Pred1DecodeConfigReq,
94: Pred1SendResetReq,
95: Pred1RecvResetReq,
96: Pred1RecvResetAck,
97: Pred1Negotiated,
98: Pred1Stat,
99: #ifndef USE_NG_PRED1
100: Pred1Compress,
101: Pred1Decompress,
102: #else
103: NULL,
104: NULL,
105: #endif
106: };
107:
108: /*
109: * Pred1Init()
110: */
111:
112: static int
113: Pred1Init(Bund b, int dir)
114: {
115: #ifndef USE_NG_PRED1
116: Pred1Info p = &b->ccp.pred1;
117:
118: if (dir == COMP_DIR_XMIT) {
119: p->oHash = 0;
120: p->OutputGuessTable = Malloc(MB_COMP, PRED1_TABLE_SIZE);
121: } else {
122: p->iHash = 0;
123: p->InputGuessTable = Malloc(MB_COMP, PRED1_TABLE_SIZE);
124: }
125: #else
126: struct ngm_mkpeer mp;
127: struct ng_pred1_config conf;
128: const char *pred1hook, *ppphook;
129: char path[NG_PATHSIZ];
130: ng_ID_t id;
131:
132: memset(&conf, 0, sizeof(conf));
133: conf.enable = 1;
134: if (dir == COMP_DIR_XMIT) {
135: ppphook = NG_PPP_HOOK_COMPRESS;
136: pred1hook = NG_PRED1_HOOK_COMP;
137: } else {
138: ppphook = NG_PPP_HOOK_DECOMPRESS;
139: pred1hook = NG_PRED1_HOOK_DECOMP;
140: }
141:
142: /* Attach a new PRED1 node to the PPP node */
143: snprintf(path, sizeof(path), "[%x]:", b->nodeID);
144: strcpy(mp.type, NG_PRED1_NODE_TYPE);
145: strcpy(mp.ourhook, ppphook);
146: strcpy(mp.peerhook, pred1hook);
147: if (NgSendMsg(gCcpCsock, path,
148: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
149: Perror("[%s] can't create %s node", b->name, mp.type);
150: return(-1);
151: }
152:
153: strlcat(path, ppphook, sizeof(path));
154:
1.1.1.2 ! misho 155: if ((id = NgGetNodeID(-1, path)) == 0) {
! 156: Perror("[%s] Cannot get %s node id", b->name, NG_PRED1_NODE_TYPE);
! 157: goto fail;
! 158: }
! 159:
1.1 misho 160: if (dir == COMP_DIR_XMIT) {
161: b->ccp.comp_node_id = id;
162: } else {
163: b->ccp.decomp_node_id = id;
164: }
165:
166: /* Configure PRED1 node */
167: snprintf(path, sizeof(path), "[%x]:", id);
168: if (NgSendMsg(gCcpCsock, path,
169: NGM_PRED1_COOKIE, NGM_PRED1_CONFIG, &conf, sizeof(conf)) < 0) {
170: Perror("[%s] can't config %s node at %s",
171: b->name, NG_PRED1_NODE_TYPE, path);
1.1.1.2 ! misho 172: goto fail;
1.1 misho 173: }
174: #endif
175: return 0;
1.1.1.2 ! misho 176:
! 177: fail:
! 178: NgFuncShutdownNode(gCcpCsock, b->name, path);
! 179: return(-1);
1.1 misho 180: }
181:
182: /*
183: * Pred1Cleanup()
184: */
185:
186: void
187: Pred1Cleanup(Bund b, int dir)
188: {
189: #ifndef USE_NG_PRED1
190: Pred1Info p = &b->ccp.pred1;
191:
192: if (dir == COMP_DIR_XMIT) {
193: assert(p->OutputGuessTable);
194: Freee(p->OutputGuessTable);
195: p->OutputGuessTable = NULL;
196: memset(&p->xmit_stats, 0, sizeof(p->xmit_stats));
197: } else {
198: assert(p->InputGuessTable);
199: Freee(p->InputGuessTable);
200: p->InputGuessTable = NULL;
201: memset(&p->recv_stats, 0, sizeof(p->recv_stats));
202: }
203: #else
204: char path[NG_PATHSIZ];
205:
206: /* Remove node */
207: if (dir == COMP_DIR_XMIT) {
208: snprintf(path, sizeof(path), "[%x]:", b->ccp.comp_node_id);
209: b->ccp.comp_node_id = 0;
210: } else {
211: snprintf(path, sizeof(path), "[%x]:", b->ccp.decomp_node_id);
212: b->ccp.decomp_node_id = 0;
213: }
214: NgFuncShutdownNode(gCcpCsock, b->name, path);
215: #endif
216: }
217:
218: #ifndef USE_NG_PRED1
219: /*
220: * Pred1Compress()
221: *
222: * Compress a packet and return a compressed version.
223: * The original is untouched.
224: */
225:
226: Mbuf
227: Pred1Compress(Bund b, Mbuf plain)
228: {
229: u_char *wp, *uncomp, *comp;
230: u_int16_t fcs;
231: int len;
232: Mbuf res;
233: int orglen;
234: Pred1Info p = &b->ccp.pred1;
235:
236: orglen = MBLEN(plain);
237: uncomp = MBDATA(plain);
238:
239: p->xmit_stats.InOctets += orglen;
240: p->xmit_stats.FramesPlain++;
241:
242: res = mballoc(PRED1_MAX_BLOWUP(orglen + 2));
243: comp = MBDATA(res);
244:
245: wp = comp;
246:
247: *wp++ = (orglen >> 8) & 0x7F;
248: *wp++ = orglen & 0xFF;
249:
250: /* Compute FCS */
251:
252: fcs = Crc16(PPP_INITFCS, comp, 2);
253: fcs = Crc16(fcs, uncomp, orglen);
254: fcs = ~fcs;
255:
256: /* Compress data */
257:
258: len = Compress(b, uncomp, wp, orglen);
259:
260: /* What happened? */
261:
262: if (len < orglen)
263: {
264: *comp |= 0x80;
265: wp += len;
266: p->xmit_stats.FramesComp++;
267: }
268: else
269: {
270: memcpy(wp, uncomp, orglen);
271: wp += orglen;
272: p->xmit_stats.FramesUncomp++;
273: }
274:
275: /* Add FCS */
276:
277: *wp++ = fcs & 0xFF;
278: *wp++ = fcs >> 8;
279:
280: res->cnt = (wp - comp);
281:
282: mbfree(plain);
283: Log(LG_CCP2, ("[%s] Pred1: orig (%d) --> comp (%d)", b->name, orglen, res->cnt));
284:
285: p->xmit_stats.OutOctets += res->cnt;
286:
287: return res;
288: }
289:
290: /*
291: * Pred1Decompress()
292: *
293: * Decompress a packet and return a compressed version.
294: * The original is untouched.
295: */
296:
297: Mbuf
298: Pred1Decompress(Bund b, Mbuf mbcomp)
299: {
300: u_char *uncomp, *comp;
301: u_char *cp;
302: u_int16_t len, len1, cf, lenn;
303: u_int16_t fcs;
304: int orglen;
305: Mbuf mbuncomp;
306: Pred1Info p = &b->ccp.pred1;
307:
308: orglen = MBLEN(mbcomp);
309: comp = MBDATA(mbcomp);
310: cp = comp;
311:
312: p->recv_stats.InOctets += orglen;
313:
314: mbuncomp = mballoc(PRED1_DECOMP_BUF_SIZE);
315: uncomp = MBDATA(mbuncomp);
316:
317: /* Get initial length value */
318: len = *cp++ << 8;
319: len += *cp++;
320:
321: cf = (len & 0x8000);
322: len &= 0x7fff;
323:
324: /* Is data compressed or not really? */
325: if (cf)
326: {
327: p->recv_stats.FramesComp++;
328: len1 = Decompress(b, cp, uncomp, orglen - 4, PRED1_DECOMP_BUF_SIZE);
329: if (len != len1) /* Error is detected. Send reset request */
330: {
331: Log(LG_CCP2, ("[%s] Length error (%d) --> len (%d)", b->name, len, len1));
332: p->recv_stats.Errors++;
333: mbfree(mbcomp);
334: mbfree(mbuncomp);
335: CcpSendResetReq(b);
336: return NULL;
337: }
338: cp += orglen - 4;
339: }
340: else
341: {
342: p->recv_stats.FramesUncomp++;
343: SyncTable(b, cp, uncomp, len);
344: cp += len;
345: }
346:
347: mbuncomp->cnt = len;
348:
349: /* Check CRC */
350: lenn = htons(len);
351: fcs = Crc16(PPP_INITFCS, (u_char *)&lenn, 2);
352: fcs = Crc16(fcs, uncomp, len);
353: fcs = Crc16(fcs, cp, 2);
354:
355: #ifdef DEBUG
356: if (fcs != PPP_GOODFCS)
357: Log(LG_CCP2, ("fcs = %04x (%s), len = %x, olen = %x",
358: fcs, (fcs == PPP_GOODFCS)? "good" : "bad", len, orglen));
359: #endif
360:
361: if (fcs != PPP_GOODFCS)
362: {
363: Log(LG_CCP2, ("[%s] Pred1: Bad CRC-16", b->name));
364: p->recv_stats.Errors++;
365: mbfree(mbcomp);
366: mbfree(mbuncomp);
367: CcpSendResetReq(b);
368: return NULL;
369: }
370:
371: Log(LG_CCP2, ("[%s] Pred1: orig (%d) <-- comp (%d)", b->name, mbuncomp->cnt, orglen));
372: mbfree(mbcomp);
373:
374: p->recv_stats.FramesPlain++;
375: p->recv_stats.OutOctets += mbuncomp->cnt;
376:
377: return mbuncomp;
378: }
379: #endif
380:
381: /*
382: * Pred1RecvResetReq()
383: */
384:
385: static Mbuf
386: Pred1RecvResetReq(Bund b, int id, Mbuf bp, int *noAck)
387: {
1.1.1.2 ! misho 388: (void)id;
! 389: (void)bp;
! 390: (void)noAck;
1.1 misho 391: #ifndef USE_NG_PRED1
392: Pred1Info p = &b->ccp.pred1;
1.1.1.2 ! misho 393:
! 394: (void)id;
! 395: (void)bp;
! 396: (void)noAck;
! 397:
1.1 misho 398: Pred1Init(b, COMP_DIR_XMIT);
399: p->xmit_stats.Errors++;
400: #else
401: char path[NG_PATHSIZ];
1.1.1.2 ! misho 402:
! 403: (void)id;
! 404: (void)bp;
! 405: (void)noAck;
! 406:
1.1 misho 407: /* Forward ResetReq to the Predictor1 compression node */
408: snprintf(path, sizeof(path), "[%x]:", b->ccp.comp_node_id);
409: if (NgSendMsg(gCcpCsock, path,
410: NGM_PRED1_COOKIE, NGM_PRED1_RESETREQ, NULL, 0) < 0) {
411: Perror("[%s] reset to %s node", b->name, NG_PRED1_NODE_TYPE);
412: }
413: #endif
1.1.1.2 ! misho 414: return(NULL);
1.1 misho 415: }
416:
417: /*
418: * Pred1SendResetReq()
419: */
420:
421: static Mbuf
422: Pred1SendResetReq(Bund b)
423: {
424: #ifndef USE_NG_PRED1
425: Pred1Init(b, COMP_DIR_RECV);
1.1.1.2 ! misho 426: #else
! 427: (void)b;
1.1 misho 428: #endif
429: return(NULL);
430: }
431:
432: /*
433: * Pred1RecvResetAck()
434: */
435:
436: static void
437: Pred1RecvResetAck(Bund b, int id, Mbuf bp)
438: {
439: #ifndef USE_NG_PRED1
1.1.1.2 ! misho 440: (void)id;
! 441: (void)bp;
1.1 misho 442: Pred1Init(b, COMP_DIR_RECV);
443: #else
444: char path[NG_PATHSIZ];
1.1.1.2 ! misho 445:
! 446: (void)id;
! 447: (void)bp;
! 448:
1.1 misho 449: /* Forward ResetReq to the Predictor1 decompression node */
450: snprintf(path, sizeof(path), "[%x]:", b->ccp.decomp_node_id);
451: if (NgSendMsg(gCcpCsock, path,
452: NGM_PRED1_COOKIE, NGM_PRED1_RESETREQ, NULL, 0) < 0) {
453: Perror("[%s] reset to %s node", b->name, NG_PRED1_NODE_TYPE);
454: }
455: #endif
456: }
457:
458: /*
459: * Pred1BuildConfigReq()
460: */
461:
462: static u_char *
463: Pred1BuildConfigReq(Bund b, u_char *cp, int *ok)
464: {
1.1.1.2 ! misho 465: (void)b;
1.1 misho 466: cp = FsmConfValue(cp, CCP_TY_PRED1, 0, NULL);
467: *ok = 1;
468: return (cp);
469: }
470:
471: /*
472: * Pred1DecodeConfigReq()
473: */
474:
475: static void
476: Pred1DecodeConfigReq(Fsm fp, FsmOption opt, int mode)
477: {
478: /* Deal with it */
479: switch (mode) {
480: case MODE_REQ:
481: FsmAck(fp, opt);
482: break;
483:
484: case MODE_NAK:
485: break;
486: }
487: }
488:
489: /*
490: * Pred1Negotiated()
491: */
492:
493: static int
494: Pred1Negotiated(Bund b, int dir)
495: {
1.1.1.2 ! misho 496: (void)b;
! 497: (void)dir;
! 498:
1.1 misho 499: return 1;
500: }
501:
502: /*
503: * Pred1SubtractBloat()
504: */
505:
506: static int
507: Pred1SubtractBloat(Bund b, int size)
508: {
1.1.1.2 ! misho 509: (void)b;
1.1 misho 510: return(size - 4);
511: }
512:
513: static int
514: Pred1Stat(Context ctx, int dir)
515: {
516: #ifndef USE_NG_PRED1
517: Pred1Info p = &ctx->bund->ccp.pred1;
518:
519: switch (dir) {
520: case COMP_DIR_XMIT:
521: Printf("\tBytes\t: %llu -> %llu (%+lld%%)\r\n",
522: (unsigned long long)p->xmit_stats.InOctets,
523: (unsigned long long)p->xmit_stats.OutOctets,
524: ((p->xmit_stats.InOctets!=0)?
525: ((long long)(p->xmit_stats.OutOctets - p->xmit_stats.InOctets)
526: *100/(long long)p->xmit_stats.InOctets):
527: 0));
528: Printf("\tFrames\t: %llu -> %lluc + %lluu\r\n",
529: (unsigned long long)p->xmit_stats.FramesPlain,
530: (unsigned long long)p->xmit_stats.FramesComp,
531: (unsigned long long)p->xmit_stats.FramesUncomp);
532: Printf("\tErrors\t: %llu\r\n",
533: (unsigned long long)p->recv_stats.Errors);
534: break;
535: case COMP_DIR_RECV:
536: Printf("\tBytes\t: %llu <- %llu (%+lld%%)\r\n",
537: (unsigned long long)p->recv_stats.OutOctets,
538: (unsigned long long)p->recv_stats.InOctets,
539: ((p->recv_stats.OutOctets!=0)?
540: ((long long)(p->recv_stats.InOctets - p->recv_stats.OutOctets)
541: *100/(long long)p->recv_stats.OutOctets):
542: 0));
543: Printf("\tFrames\t: %llu <- %lluc + %lluu\r\n",
544: (unsigned long long)p->xmit_stats.FramesPlain,
545: (unsigned long long)p->xmit_stats.FramesComp,
546: (unsigned long long)p->xmit_stats.FramesUncomp);
547: Printf("\tErrors\t: %llu\r\n",
548: (unsigned long long)p->recv_stats.Errors);
549: break;
550: default:
551: assert(0);
552: }
553: return (0);
554: #else
555: Bund b = ctx->bund;
556: char path[NG_PATHSIZ];
557: struct ng_pred1_stats stats;
558: union {
559: u_char buf[sizeof(struct ng_mesg) + sizeof(stats)];
560: struct ng_mesg reply;
561: } u;
562:
563: switch (dir) {
564: case COMP_DIR_XMIT:
565: snprintf(path, sizeof(path), "mpd%d-%s:%s", gPid, b->name,
566: NG_PPP_HOOK_COMPRESS);
567: break;
568: case COMP_DIR_RECV:
569: snprintf(path, sizeof(path), "mpd%d-%s:%s", gPid, b->name,
570: NG_PPP_HOOK_DECOMPRESS);
571: break;
572: default:
573: assert(0);
574: }
575: if (NgFuncSendQuery(path, NGM_PRED1_COOKIE, NGM_PRED1_GET_STATS, NULL, 0,
576: &u.reply, sizeof(u), NULL) < 0) {
577: Perror("[%s] can't get %s stats", b->name, NG_PRED1_NODE_TYPE);
578: return(0);
579: }
580: memcpy(&stats, u.reply.data, sizeof(stats));
581: switch (dir) {
582: case COMP_DIR_XMIT:
583: Printf("\tBytes\t: %llu -> %llu (%+lld%%)\r\n",
584: stats.InOctets,
585: stats.OutOctets,
586: ((stats.InOctets!=0)?
587: ((int64_t)(stats.OutOctets - stats.InOctets)*100/(int64_t)stats.InOctets):
588: 0));
589: Printf("\tFrames\t: %llu -> %lluc + %lluu\r\n",
590: stats.FramesPlain,
591: stats.FramesComp,
592: stats.FramesUncomp);
593: Printf("\tErrors\t: %llu\r\n",
594: stats.Errors);
595: break;
596: case COMP_DIR_RECV:
597: Printf("\tBytes\t: %llu <- %llu (%+lld%%)\r\n",
598: stats.OutOctets,
599: stats.InOctets,
600: ((stats.OutOctets!=0)?
601: ((int64_t)(stats.InOctets - stats.OutOctets)*100/(int64_t)stats.OutOctets):
602: 0));
603: Printf("\tFrames\t: %llu <- %lluc + %lluu\r\n",
604: stats.FramesPlain,
605: stats.FramesComp,
606: stats.FramesUncomp);
607: Printf("\tErrors\t: %llu\r\n",
608: stats.Errors);
609: break;
610: default:
611: assert(0);
612: }
613: return (0);
614: #endif
615: }
616:
617: #ifndef USE_NG_PRED1
618: /*
619: * Compress()
620: */
621:
622: static int
623: Compress(Bund b, u_char *source, u_char *dest, int len)
624: {
625: Pred1Info p = &b->ccp.pred1;
626: int i, bitmask;
627: u_char flags;
628: u_char *flagdest, *orgdest;
629:
630: orgdest = dest;
631: while (len)
632: {
633: flagdest = dest++; flags = 0; /* All guess wrong initially */
634: for (bitmask=1, i=0; i < 8 && len; i++, bitmask <<= 1) {
635: if (p->OutputGuessTable[p->oHash] == *source)
636: flags |= bitmask; /* Guess was right - don't output */
637: else
638: {
639: p->OutputGuessTable[p->oHash] = *source;
640: *dest++ = *source; /* Guess wrong, output char */
641: }
642: OHASH(*source++);
643: len--;
644: }
645: *flagdest = flags;
646: }
647: return(dest - orgdest);
648: }
649:
650: /*
651: * Decompress()
652: *
653: * Returns decompressed size, or -1 if we ran out of space
654: */
655:
656: static int
657: Decompress(Bund b, u_char *source, u_char *dest, int slen, int dlen)
658: {
659: Pred1Info p = &b->ccp.pred1;
660: int i, bitmask;
661: u_char flags, *orgdest;
662:
663: orgdest = dest;
664: while (slen)
665: {
666: flags = *source++;
667: slen--;
668: for (i=0, bitmask = 1; i < 8; i++, bitmask <<= 1)
669: {
670: if (dlen <= 0)
671: return(-1);
672: if (flags & bitmask)
673: *dest = p->InputGuessTable[p->iHash]; /* Guess correct */
674: else
675: {
676: if (!slen)
677: break; /* we seem to be really done -- cabo */
678: p->InputGuessTable[p->iHash] = *source; /* Guess wrong */
679: *dest = *source++; /* Read from source */
680: slen--;
681: }
682: IHASH(*dest++);
683: dlen--;
684: }
685: }
686: return(dest - orgdest);
687: }
688:
689: /*
690: * SyncTable()
691: */
692:
693: static void
694: SyncTable(Bund b, u_char *source, u_char *dest, int len)
695: {
696: Pred1Info p = &b->ccp.pred1;
697:
698: while (len--)
699: {
700: if (p->InputGuessTable[p->iHash] != *source)
701: p->InputGuessTable[p->iHash] = *source;
702: IHASH(*dest++ = *source++);
703: }
704: }
705: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>