Annotation of embedaddon/mpd/src/ccp_pred1.c, revision 1.1.1.1
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:
155: id = NgGetNodeID(-1, path);
156: if (dir == COMP_DIR_XMIT) {
157: b->ccp.comp_node_id = id;
158: } else {
159: b->ccp.decomp_node_id = id;
160: }
161:
162: /* Configure PRED1 node */
163: snprintf(path, sizeof(path), "[%x]:", id);
164: if (NgSendMsg(gCcpCsock, path,
165: NGM_PRED1_COOKIE, NGM_PRED1_CONFIG, &conf, sizeof(conf)) < 0) {
166: Perror("[%s] can't config %s node at %s",
167: b->name, NG_PRED1_NODE_TYPE, path);
168: NgFuncShutdownNode(gCcpCsock, b->name, path);
169: return(-1);
170: }
171: #endif
172: return 0;
173: }
174:
175: /*
176: * Pred1Cleanup()
177: */
178:
179: void
180: Pred1Cleanup(Bund b, int dir)
181: {
182: #ifndef USE_NG_PRED1
183: Pred1Info p = &b->ccp.pred1;
184:
185: if (dir == COMP_DIR_XMIT) {
186: assert(p->OutputGuessTable);
187: Freee(p->OutputGuessTable);
188: p->OutputGuessTable = NULL;
189: memset(&p->xmit_stats, 0, sizeof(p->xmit_stats));
190: } else {
191: assert(p->InputGuessTable);
192: Freee(p->InputGuessTable);
193: p->InputGuessTable = NULL;
194: memset(&p->recv_stats, 0, sizeof(p->recv_stats));
195: }
196: #else
197: char path[NG_PATHSIZ];
198:
199: /* Remove node */
200: if (dir == COMP_DIR_XMIT) {
201: snprintf(path, sizeof(path), "[%x]:", b->ccp.comp_node_id);
202: b->ccp.comp_node_id = 0;
203: } else {
204: snprintf(path, sizeof(path), "[%x]:", b->ccp.decomp_node_id);
205: b->ccp.decomp_node_id = 0;
206: }
207: NgFuncShutdownNode(gCcpCsock, b->name, path);
208: #endif
209: }
210:
211: #ifndef USE_NG_PRED1
212: /*
213: * Pred1Compress()
214: *
215: * Compress a packet and return a compressed version.
216: * The original is untouched.
217: */
218:
219: Mbuf
220: Pred1Compress(Bund b, Mbuf plain)
221: {
222: u_char *wp, *uncomp, *comp;
223: u_int16_t fcs;
224: int len;
225: Mbuf res;
226: int orglen;
227: Pred1Info p = &b->ccp.pred1;
228:
229: orglen = MBLEN(plain);
230: uncomp = MBDATA(plain);
231:
232: p->xmit_stats.InOctets += orglen;
233: p->xmit_stats.FramesPlain++;
234:
235: res = mballoc(PRED1_MAX_BLOWUP(orglen + 2));
236: comp = MBDATA(res);
237:
238: wp = comp;
239:
240: *wp++ = (orglen >> 8) & 0x7F;
241: *wp++ = orglen & 0xFF;
242:
243: /* Compute FCS */
244:
245: fcs = Crc16(PPP_INITFCS, comp, 2);
246: fcs = Crc16(fcs, uncomp, orglen);
247: fcs = ~fcs;
248:
249: /* Compress data */
250:
251: len = Compress(b, uncomp, wp, orglen);
252:
253: /* What happened? */
254:
255: if (len < orglen)
256: {
257: *comp |= 0x80;
258: wp += len;
259: p->xmit_stats.FramesComp++;
260: }
261: else
262: {
263: memcpy(wp, uncomp, orglen);
264: wp += orglen;
265: p->xmit_stats.FramesUncomp++;
266: }
267:
268: /* Add FCS */
269:
270: *wp++ = fcs & 0xFF;
271: *wp++ = fcs >> 8;
272:
273: res->cnt = (wp - comp);
274:
275: mbfree(plain);
276: Log(LG_CCP2, ("[%s] Pred1: orig (%d) --> comp (%d)", b->name, orglen, res->cnt));
277:
278: p->xmit_stats.OutOctets += res->cnt;
279:
280: return res;
281: }
282:
283: /*
284: * Pred1Decompress()
285: *
286: * Decompress a packet and return a compressed version.
287: * The original is untouched.
288: */
289:
290: Mbuf
291: Pred1Decompress(Bund b, Mbuf mbcomp)
292: {
293: u_char *uncomp, *comp;
294: u_char *cp;
295: u_int16_t len, len1, cf, lenn;
296: u_int16_t fcs;
297: int orglen;
298: Mbuf mbuncomp;
299: Pred1Info p = &b->ccp.pred1;
300:
301: orglen = MBLEN(mbcomp);
302: comp = MBDATA(mbcomp);
303: cp = comp;
304:
305: p->recv_stats.InOctets += orglen;
306:
307: mbuncomp = mballoc(PRED1_DECOMP_BUF_SIZE);
308: uncomp = MBDATA(mbuncomp);
309:
310: /* Get initial length value */
311: len = *cp++ << 8;
312: len += *cp++;
313:
314: cf = (len & 0x8000);
315: len &= 0x7fff;
316:
317: /* Is data compressed or not really? */
318: if (cf)
319: {
320: p->recv_stats.FramesComp++;
321: len1 = Decompress(b, cp, uncomp, orglen - 4, PRED1_DECOMP_BUF_SIZE);
322: if (len != len1) /* Error is detected. Send reset request */
323: {
324: Log(LG_CCP2, ("[%s] Length error (%d) --> len (%d)", b->name, len, len1));
325: p->recv_stats.Errors++;
326: mbfree(mbcomp);
327: mbfree(mbuncomp);
328: CcpSendResetReq(b);
329: return NULL;
330: }
331: cp += orglen - 4;
332: }
333: else
334: {
335: p->recv_stats.FramesUncomp++;
336: SyncTable(b, cp, uncomp, len);
337: cp += len;
338: }
339:
340: mbuncomp->cnt = len;
341:
342: /* Check CRC */
343: lenn = htons(len);
344: fcs = Crc16(PPP_INITFCS, (u_char *)&lenn, 2);
345: fcs = Crc16(fcs, uncomp, len);
346: fcs = Crc16(fcs, cp, 2);
347:
348: #ifdef DEBUG
349: if (fcs != PPP_GOODFCS)
350: Log(LG_CCP2, ("fcs = %04x (%s), len = %x, olen = %x",
351: fcs, (fcs == PPP_GOODFCS)? "good" : "bad", len, orglen));
352: #endif
353:
354: if (fcs != PPP_GOODFCS)
355: {
356: Log(LG_CCP2, ("[%s] Pred1: Bad CRC-16", b->name));
357: p->recv_stats.Errors++;
358: mbfree(mbcomp);
359: mbfree(mbuncomp);
360: CcpSendResetReq(b);
361: return NULL;
362: }
363:
364: Log(LG_CCP2, ("[%s] Pred1: orig (%d) <-- comp (%d)", b->name, mbuncomp->cnt, orglen));
365: mbfree(mbcomp);
366:
367: p->recv_stats.FramesPlain++;
368: p->recv_stats.OutOctets += mbuncomp->cnt;
369:
370: return mbuncomp;
371: }
372: #endif
373:
374: /*
375: * Pred1RecvResetReq()
376: */
377:
378: static Mbuf
379: Pred1RecvResetReq(Bund b, int id, Mbuf bp, int *noAck)
380: {
381: #ifndef USE_NG_PRED1
382: Pred1Info p = &b->ccp.pred1;
383: Pred1Init(b, COMP_DIR_XMIT);
384: p->xmit_stats.Errors++;
385: #else
386: char path[NG_PATHSIZ];
387: /* Forward ResetReq to the Predictor1 compression node */
388: snprintf(path, sizeof(path), "[%x]:", b->ccp.comp_node_id);
389: if (NgSendMsg(gCcpCsock, path,
390: NGM_PRED1_COOKIE, NGM_PRED1_RESETREQ, NULL, 0) < 0) {
391: Perror("[%s] reset to %s node", b->name, NG_PRED1_NODE_TYPE);
392: }
393: #endif
394: return(NULL);
395: }
396:
397: /*
398: * Pred1SendResetReq()
399: */
400:
401: static Mbuf
402: Pred1SendResetReq(Bund b)
403: {
404: #ifndef USE_NG_PRED1
405: Pred1Init(b, COMP_DIR_RECV);
406: #endif
407: return(NULL);
408: }
409:
410: /*
411: * Pred1RecvResetAck()
412: */
413:
414: static void
415: Pred1RecvResetAck(Bund b, int id, Mbuf bp)
416: {
417: #ifndef USE_NG_PRED1
418: Pred1Init(b, COMP_DIR_RECV);
419: #else
420: char path[NG_PATHSIZ];
421: /* Forward ResetReq to the Predictor1 decompression node */
422: snprintf(path, sizeof(path), "[%x]:", b->ccp.decomp_node_id);
423: if (NgSendMsg(gCcpCsock, path,
424: NGM_PRED1_COOKIE, NGM_PRED1_RESETREQ, NULL, 0) < 0) {
425: Perror("[%s] reset to %s node", b->name, NG_PRED1_NODE_TYPE);
426: }
427: #endif
428: }
429:
430: /*
431: * Pred1BuildConfigReq()
432: */
433:
434: static u_char *
435: Pred1BuildConfigReq(Bund b, u_char *cp, int *ok)
436: {
437: cp = FsmConfValue(cp, CCP_TY_PRED1, 0, NULL);
438: *ok = 1;
439: return (cp);
440: }
441:
442: /*
443: * Pred1DecodeConfigReq()
444: */
445:
446: static void
447: Pred1DecodeConfigReq(Fsm fp, FsmOption opt, int mode)
448: {
449: /* Deal with it */
450: switch (mode) {
451: case MODE_REQ:
452: FsmAck(fp, opt);
453: break;
454:
455: case MODE_NAK:
456: break;
457: }
458: }
459:
460: /*
461: * Pred1Negotiated()
462: */
463:
464: static int
465: Pred1Negotiated(Bund b, int dir)
466: {
467: return 1;
468: }
469:
470: /*
471: * Pred1SubtractBloat()
472: */
473:
474: static int
475: Pred1SubtractBloat(Bund b, int size)
476: {
477: return(size - 4);
478: }
479:
480: static int
481: Pred1Stat(Context ctx, int dir)
482: {
483: #ifndef USE_NG_PRED1
484: Pred1Info p = &ctx->bund->ccp.pred1;
485:
486: switch (dir) {
487: case COMP_DIR_XMIT:
488: Printf("\tBytes\t: %llu -> %llu (%+lld%%)\r\n",
489: (unsigned long long)p->xmit_stats.InOctets,
490: (unsigned long long)p->xmit_stats.OutOctets,
491: ((p->xmit_stats.InOctets!=0)?
492: ((long long)(p->xmit_stats.OutOctets - p->xmit_stats.InOctets)
493: *100/(long long)p->xmit_stats.InOctets):
494: 0));
495: Printf("\tFrames\t: %llu -> %lluc + %lluu\r\n",
496: (unsigned long long)p->xmit_stats.FramesPlain,
497: (unsigned long long)p->xmit_stats.FramesComp,
498: (unsigned long long)p->xmit_stats.FramesUncomp);
499: Printf("\tErrors\t: %llu\r\n",
500: (unsigned long long)p->recv_stats.Errors);
501: break;
502: case COMP_DIR_RECV:
503: Printf("\tBytes\t: %llu <- %llu (%+lld%%)\r\n",
504: (unsigned long long)p->recv_stats.OutOctets,
505: (unsigned long long)p->recv_stats.InOctets,
506: ((p->recv_stats.OutOctets!=0)?
507: ((long long)(p->recv_stats.InOctets - p->recv_stats.OutOctets)
508: *100/(long long)p->recv_stats.OutOctets):
509: 0));
510: Printf("\tFrames\t: %llu <- %lluc + %lluu\r\n",
511: (unsigned long long)p->xmit_stats.FramesPlain,
512: (unsigned long long)p->xmit_stats.FramesComp,
513: (unsigned long long)p->xmit_stats.FramesUncomp);
514: Printf("\tErrors\t: %llu\r\n",
515: (unsigned long long)p->recv_stats.Errors);
516: break;
517: default:
518: assert(0);
519: }
520: return (0);
521: #else
522: Bund b = ctx->bund;
523: char path[NG_PATHSIZ];
524: struct ng_pred1_stats stats;
525: union {
526: u_char buf[sizeof(struct ng_mesg) + sizeof(stats)];
527: struct ng_mesg reply;
528: } u;
529:
530: switch (dir) {
531: case COMP_DIR_XMIT:
532: snprintf(path, sizeof(path), "mpd%d-%s:%s", gPid, b->name,
533: NG_PPP_HOOK_COMPRESS);
534: break;
535: case COMP_DIR_RECV:
536: snprintf(path, sizeof(path), "mpd%d-%s:%s", gPid, b->name,
537: NG_PPP_HOOK_DECOMPRESS);
538: break;
539: default:
540: assert(0);
541: }
542: if (NgFuncSendQuery(path, NGM_PRED1_COOKIE, NGM_PRED1_GET_STATS, NULL, 0,
543: &u.reply, sizeof(u), NULL) < 0) {
544: Perror("[%s] can't get %s stats", b->name, NG_PRED1_NODE_TYPE);
545: return(0);
546: }
547: memcpy(&stats, u.reply.data, sizeof(stats));
548: switch (dir) {
549: case COMP_DIR_XMIT:
550: Printf("\tBytes\t: %llu -> %llu (%+lld%%)\r\n",
551: stats.InOctets,
552: stats.OutOctets,
553: ((stats.InOctets!=0)?
554: ((int64_t)(stats.OutOctets - stats.InOctets)*100/(int64_t)stats.InOctets):
555: 0));
556: Printf("\tFrames\t: %llu -> %lluc + %lluu\r\n",
557: stats.FramesPlain,
558: stats.FramesComp,
559: stats.FramesUncomp);
560: Printf("\tErrors\t: %llu\r\n",
561: stats.Errors);
562: break;
563: case COMP_DIR_RECV:
564: Printf("\tBytes\t: %llu <- %llu (%+lld%%)\r\n",
565: stats.OutOctets,
566: stats.InOctets,
567: ((stats.OutOctets!=0)?
568: ((int64_t)(stats.InOctets - stats.OutOctets)*100/(int64_t)stats.OutOctets):
569: 0));
570: Printf("\tFrames\t: %llu <- %lluc + %lluu\r\n",
571: stats.FramesPlain,
572: stats.FramesComp,
573: stats.FramesUncomp);
574: Printf("\tErrors\t: %llu\r\n",
575: stats.Errors);
576: break;
577: default:
578: assert(0);
579: }
580: return (0);
581: #endif
582: }
583:
584: #ifndef USE_NG_PRED1
585: /*
586: * Compress()
587: */
588:
589: static int
590: Compress(Bund b, u_char *source, u_char *dest, int len)
591: {
592: Pred1Info p = &b->ccp.pred1;
593: int i, bitmask;
594: u_char flags;
595: u_char *flagdest, *orgdest;
596:
597: orgdest = dest;
598: while (len)
599: {
600: flagdest = dest++; flags = 0; /* All guess wrong initially */
601: for (bitmask=1, i=0; i < 8 && len; i++, bitmask <<= 1) {
602: if (p->OutputGuessTable[p->oHash] == *source)
603: flags |= bitmask; /* Guess was right - don't output */
604: else
605: {
606: p->OutputGuessTable[p->oHash] = *source;
607: *dest++ = *source; /* Guess wrong, output char */
608: }
609: OHASH(*source++);
610: len--;
611: }
612: *flagdest = flags;
613: }
614: return(dest - orgdest);
615: }
616:
617: /*
618: * Decompress()
619: *
620: * Returns decompressed size, or -1 if we ran out of space
621: */
622:
623: static int
624: Decompress(Bund b, u_char *source, u_char *dest, int slen, int dlen)
625: {
626: Pred1Info p = &b->ccp.pred1;
627: int i, bitmask;
628: u_char flags, *orgdest;
629:
630: orgdest = dest;
631: while (slen)
632: {
633: flags = *source++;
634: slen--;
635: for (i=0, bitmask = 1; i < 8; i++, bitmask <<= 1)
636: {
637: if (dlen <= 0)
638: return(-1);
639: if (flags & bitmask)
640: *dest = p->InputGuessTable[p->iHash]; /* Guess correct */
641: else
642: {
643: if (!slen)
644: break; /* we seem to be really done -- cabo */
645: p->InputGuessTable[p->iHash] = *source; /* Guess wrong */
646: *dest = *source++; /* Read from source */
647: slen--;
648: }
649: IHASH(*dest++);
650: dlen--;
651: }
652: }
653: return(dest - orgdest);
654: }
655:
656: /*
657: * SyncTable()
658: */
659:
660: static void
661: SyncTable(Bund b, u_char *source, u_char *dest, int len)
662: {
663: Pred1Info p = &b->ccp.pred1;
664:
665: while (len--)
666: {
667: if (p->InputGuessTable[p->iHash] != *source)
668: p->InputGuessTable[p->iHash] = *source;
669: IHASH(*dest++ = *source++);
670: }
671: }
672: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>