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