00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "lwip/opt.h"
00032
00033 #if PPP_SUPPORT
00034
00035 #include "ppp.h"
00036 #include "pppdebug.h"
00037
00038 #include "vj.h"
00039
00040 #include <string.h>
00041
00042 #if VJ_SUPPORT
00043
00044 #if LINK_STATS
00045 #define INCR(counter) ++comp->stats.counter
00046 #else
00047 #define INCR(counter)
00048 #endif
00049
00050 #if defined(NO_CHAR_BITFIELDS)
00051 #define getip_hl(base) ((base).ip_hl_v&0xf)
00052 #define getth_off(base) (((base).th_x2_off&0xf0)>>4)
00053 #else
00054 #define getip_hl(base) ((base).ip_hl)
00055 #define getth_off(base) ((base).th_off)
00056 #endif
00057
00058 void
00059 vj_compress_init(struct vjcompress *comp)
00060 {
00061 register u_int i;
00062 register struct cstate *tstate = comp->tstate;
00063
00064 #if MAX_SLOTS == 0
00065 memset((char *)comp, 0, sizeof(*comp));
00066 #endif
00067 comp->maxSlotIndex = MAX_SLOTS - 1;
00068 comp->compressSlot = 0;
00069 for (i = MAX_SLOTS - 1; i > 0; --i) {
00070 tstate[i].cs_id = i;
00071 tstate[i].cs_next = &tstate[i - 1];
00072 }
00073 tstate[0].cs_next = &tstate[MAX_SLOTS - 1];
00074 tstate[0].cs_id = 0;
00075 comp->last_cs = &tstate[0];
00076 comp->last_recv = 255;
00077 comp->last_xmit = 255;
00078 comp->flags = VJF_TOSS;
00079 }
00080
00081
00082
00083
00084
00085
00086 #define ENCODE(n) { \
00087 if ((u_short)(n) >= 256) { \
00088 *cp++ = 0; \
00089 cp[1] = (n); \
00090 cp[0] = (n) >> 8; \
00091 cp += 2; \
00092 } else { \
00093 *cp++ = (n); \
00094 } \
00095 }
00096 #define ENCODEZ(n) { \
00097 if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \
00098 *cp++ = 0; \
00099 cp[1] = (n); \
00100 cp[0] = (n) >> 8; \
00101 cp += 2; \
00102 } else { \
00103 *cp++ = (n); \
00104 } \
00105 }
00106
00107 #define DECODEL(f) { \
00108 if (*cp == 0) {\
00109 u32_t tmp = ntohl(f) + ((cp[1] << 8) | cp[2]); \
00110 (f) = htonl(tmp); \
00111 cp += 3; \
00112 } else { \
00113 u32_t tmp = ntohl(f) + (u32_t)*cp++; \
00114 (f) = htonl(tmp); \
00115 } \
00116 }
00117
00118 #define DECODES(f) { \
00119 if (*cp == 0) {\
00120 u_short tmp = ntohs(f) + (((u_short)cp[1] << 8) | cp[2]); \
00121 (f) = htons(tmp); \
00122 cp += 3; \
00123 } else { \
00124 u_short tmp = ntohs(f) + (u_short)*cp++; \
00125 (f) = htons(tmp); \
00126 } \
00127 }
00128
00129 #define DECODEU(f) { \
00130 if (*cp == 0) {\
00131 (f) = htons(((u_short)cp[1] << 8) | cp[2]); \
00132 cp += 3; \
00133 } else { \
00134 (f) = htons((u_short)*cp++); \
00135 } \
00136 }
00137
00138
00139
00140
00141
00142
00143
00144
00145 u_int
00146 vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb)
00147 {
00148 register struct ip *ip = (struct ip *)pb->payload;
00149 register struct cstate *cs = comp->last_cs->cs_next;
00150 register u_short hlen = getip_hl(*ip);
00151 register struct tcphdr *oth;
00152 register struct tcphdr *th;
00153 register u_short deltaS, deltaA;
00154 register u_long deltaL;
00155 register u_int changes = 0;
00156 u_char new_seq[16];
00157 register u_char *cp = new_seq;
00158
00159
00160
00161
00162 if (ip->ip_p != IPPROTO_TCP) {
00163 return (TYPE_IP);
00164 }
00165
00166
00167
00168
00169
00170
00171 if ((ip->ip_off & htons(0x3fff)) || pb->tot_len < 40) {
00172 return (TYPE_IP);
00173 }
00174 th = (struct tcphdr *)&((long *)ip)[hlen];
00175 if ((th->th_flags & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK) {
00176 return (TYPE_IP);
00177 }
00178
00179
00180
00181
00182
00183
00184
00185 INCR(vjs_packets);
00186 if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr
00187 || ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr
00188 || *(long *)th != ((long *)&cs->cs_ip)[getip_hl(cs->cs_ip)]) {
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201 register struct cstate *lcs;
00202 register struct cstate *lastcs = comp->last_cs;
00203
00204 do {
00205 lcs = cs; cs = cs->cs_next;
00206 INCR(vjs_searches);
00207 if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr
00208 && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr
00209 && *(long *)th == ((long *)&cs->cs_ip)[getip_hl(cs->cs_ip)]) {
00210 goto found;
00211 }
00212 } while (cs != lastcs);
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222 INCR(vjs_misses);
00223 comp->last_cs = lcs;
00224 hlen += getth_off(*th);
00225 hlen <<= 2;
00226
00227 if (hlen > pb->len) {
00228 return (TYPE_IP);
00229 }
00230 goto uncompressed;
00231
00232 found:
00233
00234
00235
00236 if (cs == lastcs) {
00237 comp->last_cs = lcs;
00238 } else {
00239 lcs->cs_next = cs->cs_next;
00240 cs->cs_next = lastcs->cs_next;
00241 lastcs->cs_next = cs;
00242 }
00243 }
00244
00245 oth = (struct tcphdr *)&((long *)&cs->cs_ip)[hlen];
00246 deltaS = hlen;
00247 hlen += getth_off(*th);
00248 hlen <<= 2;
00249
00250 if (hlen > pb->len) {
00251 PPPDEBUG((LOG_INFO, "vj_compress_tcp: header len %d spans buffers\n", hlen));
00252 return (TYPE_IP);
00253 }
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266 if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0]
00267 || ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3]
00268 || ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4]
00269 || getth_off(*th) != getth_off(*oth)
00270 || (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2))
00271 || (getth_off(*th) > 5 && BCMP(th + 1, oth + 1, (getth_off(*th) - 5) << 2))) {
00272 goto uncompressed;
00273 }
00274
00275
00276
00277
00278
00279
00280
00281 if (th->th_flags & TCP_URG) {
00282 deltaS = ntohs(th->th_urp);
00283 ENCODEZ(deltaS);
00284 changes |= NEW_U;
00285 } else if (th->th_urp != oth->th_urp) {
00286
00287
00288
00289
00290 goto uncompressed;
00291 }
00292
00293 if ((deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win))) != 0) {
00294 ENCODE(deltaS);
00295 changes |= NEW_W;
00296 }
00297
00298 if ((deltaL = ntohl(th->th_ack) - ntohl(oth->th_ack)) != 0) {
00299 if (deltaL > 0xffff) {
00300 goto uncompressed;
00301 }
00302 deltaA = (u_short)deltaL;
00303 ENCODE(deltaA);
00304 changes |= NEW_A;
00305 }
00306
00307 if ((deltaL = ntohl(th->th_seq) - ntohl(oth->th_seq)) != 0) {
00308 if (deltaL > 0xffff) {
00309 goto uncompressed;
00310 }
00311 deltaS = (u_short)deltaL;
00312 ENCODE(deltaS);
00313 changes |= NEW_S;
00314 }
00315
00316 switch(changes) {
00317 case 0:
00318
00319
00320
00321
00322
00323
00324
00325
00326 if (ip->ip_len != cs->cs_ip.ip_len &&
00327 ntohs(cs->cs_ip.ip_len) == hlen) {
00328 break;
00329 }
00330
00331
00332
00333 case SPECIAL_I:
00334 case SPECIAL_D:
00335
00336
00337
00338
00339 goto uncompressed;
00340
00341 case NEW_S|NEW_A:
00342 if (deltaS == deltaA && deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
00343
00344 changes = SPECIAL_I;
00345 cp = new_seq;
00346 }
00347 break;
00348
00349 case NEW_S:
00350 if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
00351
00352 changes = SPECIAL_D;
00353 cp = new_seq;
00354 }
00355 break;
00356 }
00357
00358 deltaS = (u_short)(ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id));
00359 if (deltaS != 1) {
00360 ENCODEZ(deltaS);
00361 changes |= NEW_I;
00362 }
00363 if (th->th_flags & TCP_PSH) {
00364 changes |= TCP_PUSH_BIT;
00365 }
00366
00367
00368
00369
00370 deltaA = ntohs(th->th_sum);
00371 BCOPY(ip, &cs->cs_ip, hlen);
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382 deltaS = (u_short)(cp - new_seq);
00383 if (!comp->compressSlot || comp->last_xmit != cs->cs_id) {
00384 comp->last_xmit = cs->cs_id;
00385 hlen -= deltaS + 4;
00386 if(pbuf_header(pb, -hlen)){
00387
00388 LWIP_ASSERT("pbuf_header failed\n", 0);
00389 }
00390 cp = (u_char *)pb->payload;
00391 *cp++ = changes | NEW_C;
00392 *cp++ = cs->cs_id;
00393 } else {
00394 hlen -= deltaS + 3;
00395 if(pbuf_header(pb, -hlen)) {
00396
00397 LWIP_ASSERT("pbuf_header failed\n", 0);
00398 }
00399 cp = (u_char *)pb->payload;
00400 *cp++ = changes;
00401 }
00402 *cp++ = deltaA >> 8;
00403 *cp++ = deltaA;
00404 BCOPY(new_seq, cp, deltaS);
00405 INCR(vjs_compressed);
00406 return (TYPE_COMPRESSED_TCP);
00407
00408
00409
00410
00411
00412
00413 uncompressed:
00414 BCOPY(ip, &cs->cs_ip, hlen);
00415 ip->ip_p = cs->cs_id;
00416 comp->last_xmit = cs->cs_id;
00417 return (TYPE_UNCOMPRESSED_TCP);
00418 }
00419
00420
00421
00422
00423 void
00424 vj_uncompress_err(struct vjcompress *comp)
00425 {
00426 comp->flags |= VJF_TOSS;
00427 INCR(vjs_errorin);
00428 }
00429
00430
00431
00432
00433
00434 int
00435 vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp)
00436 {
00437 register u_int hlen;
00438 register struct cstate *cs;
00439 register struct ip *ip;
00440
00441 ip = (struct ip *)nb->payload;
00442 hlen = getip_hl(*ip) << 2;
00443 if (ip->ip_p >= MAX_SLOTS
00444 || hlen + sizeof(struct tcphdr) > nb->len
00445 || (hlen += getth_off(*((struct tcphdr *)&((char *)ip)[hlen])) << 2)
00446 > nb->len
00447 || hlen > MAX_HDR) {
00448 PPPDEBUG((LOG_INFO, "vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n",
00449 ip->ip_p, hlen, nb->len));
00450 comp->flags |= VJF_TOSS;
00451 INCR(vjs_errorin);
00452 return -1;
00453 }
00454 cs = &comp->rstate[comp->last_recv = ip->ip_p];
00455 comp->flags &=~ VJF_TOSS;
00456 ip->ip_p = IPPROTO_TCP;
00457 BCOPY(ip, &cs->cs_ip, hlen);
00458 cs->cs_hlen = hlen;
00459 INCR(vjs_uncompressedin);
00460 return 0;
00461 }
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471 int
00472 vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp)
00473 {
00474 u_char *cp;
00475 struct tcphdr *th;
00476 struct cstate *cs;
00477 u_short *bp;
00478 struct pbuf *n0 = *nb;
00479 u32_t tmp;
00480 u_int vjlen, hlen, changes;
00481
00482 INCR(vjs_compressedin);
00483 cp = (u_char *)n0->payload;
00484 changes = *cp++;
00485 if (changes & NEW_C) {
00486
00487
00488
00489
00490 if (*cp >= MAX_SLOTS) {
00491 PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: bad cid=%d\n", *cp));
00492 goto bad;
00493 }
00494
00495 comp->flags &=~ VJF_TOSS;
00496 comp->last_recv = *cp++;
00497 } else {
00498
00499
00500
00501
00502
00503 if (comp->flags & VJF_TOSS) {
00504 PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: tossing\n"));
00505 INCR(vjs_tossed);
00506 return (-1);
00507 }
00508 }
00509 cs = &comp->rstate[comp->last_recv];
00510 hlen = getip_hl(cs->cs_ip) << 2;
00511 th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen];
00512 th->th_sum = htons((*cp << 8) | cp[1]);
00513 cp += 2;
00514 if (changes & TCP_PUSH_BIT) {
00515 th->th_flags |= TCP_PSH;
00516 } else {
00517 th->th_flags &=~ TCP_PSH;
00518 }
00519
00520 switch (changes & SPECIALS_MASK) {
00521 case SPECIAL_I:
00522 {
00523 register u32_t i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
00524
00525 tmp = ntohl(th->th_ack) + i;
00526 th->th_ack = htonl(tmp);
00527 tmp = ntohl(th->th_seq) + i;
00528 th->th_seq = htonl(tmp);
00529 }
00530 break;
00531
00532 case SPECIAL_D:
00533
00534 tmp = ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
00535 th->th_seq = htonl(tmp);
00536 break;
00537
00538 default:
00539 if (changes & NEW_U) {
00540 th->th_flags |= TCP_URG;
00541 DECODEU(th->th_urp);
00542 } else {
00543 th->th_flags &=~ TCP_URG;
00544 }
00545 if (changes & NEW_W) {
00546 DECODES(th->th_win);
00547 }
00548 if (changes & NEW_A) {
00549 DECODEL(th->th_ack);
00550 }
00551 if (changes & NEW_S) {
00552 DECODEL(th->th_seq);
00553 }
00554 break;
00555 }
00556 if (changes & NEW_I) {
00557 DECODES(cs->cs_ip.ip_id);
00558 } else {
00559 cs->cs_ip.ip_id = ntohs(cs->cs_ip.ip_id) + 1;
00560 cs->cs_ip.ip_id = htons(cs->cs_ip.ip_id);
00561 }
00562
00563
00564
00565
00566
00567
00568 vjlen = (u_short)(cp - (u_char*)n0->payload);
00569 if (n0->len < vjlen) {
00570
00571
00572
00573
00574 PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: head buffer %d too short %d\n",
00575 n0->len, vjlen));
00576 goto bad;
00577 }
00578
00579 #if BYTE_ORDER == LITTLE_ENDIAN
00580 tmp = n0->tot_len - vjlen + cs->cs_hlen;
00581 cs->cs_ip.ip_len = htons(tmp);
00582 #else
00583 cs->cs_ip.ip_len = htons(n0->tot_len - vjlen + cs->cs_hlen);
00584 #endif
00585
00586
00587 bp = (u_short *) &cs->cs_ip;
00588 cs->cs_ip.ip_sum = 0;
00589 for (tmp = 0; hlen > 0; hlen -= 2) {
00590 tmp += *bp++;
00591 }
00592 tmp = (tmp & 0xffff) + (tmp >> 16);
00593 tmp = (tmp & 0xffff) + (tmp >> 16);
00594 cs->cs_ip.ip_sum = (u_short)(~tmp);
00595
00596
00597 if(pbuf_header(n0, -((s16_t)(vjlen)))) {
00598
00599 LWIP_ASSERT("pbuf_header failed\n", 0);
00600 goto bad;
00601 }
00602
00603 if(LWIP_MEM_ALIGN(n0->payload) != n0->payload) {
00604 struct pbuf *np, *q;
00605 u8_t *bufptr;
00606
00607 np = pbuf_alloc(PBUF_RAW, n0->len + cs->cs_hlen, PBUF_POOL);
00608 if(!np) {
00609 PPPDEBUG((LOG_WARNING, "vj_uncompress_tcp: realign failed\n"));
00610 goto bad;
00611 }
00612
00613 if(pbuf_header(np, -cs->cs_hlen)) {
00614
00615 LWIP_ASSERT("pbuf_header failed\n", 0);
00616 goto bad;
00617 }
00618
00619 bufptr = n0->payload;
00620 for(q = np; q != NULL; q = q->next) {
00621 MEMCPY(q->payload, bufptr, q->len);
00622 bufptr += q->len;
00623 }
00624
00625 if(n0->next) {
00626 pbuf_chain(np, n0->next);
00627 pbuf_dechain(n0);
00628 }
00629 pbuf_free(n0);
00630 n0 = np;
00631 }
00632
00633 if(pbuf_header(n0, cs->cs_hlen)) {
00634 struct pbuf *np;
00635
00636 LWIP_ASSERT("vj_uncompress_tcp: cs->cs_hlen <= PBUF_POOL_BUFSIZE", cs->cs_hlen <= PBUF_POOL_BUFSIZE);
00637 np = pbuf_alloc(PBUF_RAW, cs->cs_hlen, PBUF_POOL);
00638 if(!np) {
00639 PPPDEBUG((LOG_WARNING, "vj_uncompress_tcp: prepend failed\n"));
00640 goto bad;
00641 }
00642 pbuf_cat(np, n0);
00643 n0 = np;
00644 }
00645 LWIP_ASSERT("n0->len >= cs->cs_hlen", n0->len >= cs->cs_hlen);
00646 MEMCPY(n0->payload, &cs->cs_ip, cs->cs_hlen);
00647
00648 *nb = n0;
00649
00650 return vjlen;
00651
00652 bad:
00653 comp->flags |= VJF_TOSS;
00654 INCR(vjs_errorin);
00655 return (-1);
00656 }
00657
00658 #endif
00659
00660 #endif