Used in Live Traffic Update Nokia LCD Display Project

Fork of NetServices by Segundo Equipo

Committer:
rrajan8
Date:
Wed Mar 06 19:07:23 2013 +0000
Revision:
8:92b57208ab99
Parent:
0:ac1725ba162c
This project utilizes mbed's networking features to display live traffic updates on the Nokia LCD using the MapQuest API's Traffic Web Service.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
segundo 0:ac1725ba162c 1 /*
segundo 0:ac1725ba162c 2 * Routines to compress and uncompess tcp packets (for transmission
segundo 0:ac1725ba162c 3 * over low speed serial lines.
segundo 0:ac1725ba162c 4 *
segundo 0:ac1725ba162c 5 * Copyright (c) 1989 Regents of the University of California.
segundo 0:ac1725ba162c 6 * All rights reserved.
segundo 0:ac1725ba162c 7 *
segundo 0:ac1725ba162c 8 * Redistribution and use in source and binary forms are permitted
segundo 0:ac1725ba162c 9 * provided that the above copyright notice and this paragraph are
segundo 0:ac1725ba162c 10 * duplicated in all such forms and that any documentation,
segundo 0:ac1725ba162c 11 * advertising materials, and other materials related to such
segundo 0:ac1725ba162c 12 * distribution and use acknowledge that the software was developed
segundo 0:ac1725ba162c 13 * by the University of California, Berkeley. The name of the
segundo 0:ac1725ba162c 14 * University may not be used to endorse or promote products derived
segundo 0:ac1725ba162c 15 * from this software without specific prior written permission.
segundo 0:ac1725ba162c 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
segundo 0:ac1725ba162c 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
segundo 0:ac1725ba162c 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
segundo 0:ac1725ba162c 19 *
segundo 0:ac1725ba162c 20 * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
segundo 0:ac1725ba162c 21 * Initial distribution.
segundo 0:ac1725ba162c 22 *
segundo 0:ac1725ba162c 23 * Modified June 1993 by Paul Mackerras, paulus@cs.anu.edu.au,
segundo 0:ac1725ba162c 24 * so that the entire packet being decompressed doesn't have
segundo 0:ac1725ba162c 25 * to be in contiguous memory (just the compressed header).
segundo 0:ac1725ba162c 26 *
segundo 0:ac1725ba162c 27 * Modified March 1998 by Guy Lancaster, glanca@gesn.com,
segundo 0:ac1725ba162c 28 * for a 16 bit processor.
segundo 0:ac1725ba162c 29 */
segundo 0:ac1725ba162c 30
segundo 0:ac1725ba162c 31 #include "lwip/opt.h"
segundo 0:ac1725ba162c 32
segundo 0:ac1725ba162c 33 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
segundo 0:ac1725ba162c 34
segundo 0:ac1725ba162c 35 #include "ppp.h"
segundo 0:ac1725ba162c 36 #include "pppdebug.h"
segundo 0:ac1725ba162c 37
segundo 0:ac1725ba162c 38 #include "vj.h"
segundo 0:ac1725ba162c 39
segundo 0:ac1725ba162c 40 #include <string.h>
segundo 0:ac1725ba162c 41
segundo 0:ac1725ba162c 42 #if VJ_SUPPORT
segundo 0:ac1725ba162c 43
segundo 0:ac1725ba162c 44 #if LINK_STATS
segundo 0:ac1725ba162c 45 #define INCR(counter) ++comp->stats.counter
segundo 0:ac1725ba162c 46 #else
segundo 0:ac1725ba162c 47 #define INCR(counter)
segundo 0:ac1725ba162c 48 #endif
segundo 0:ac1725ba162c 49
segundo 0:ac1725ba162c 50 void
segundo 0:ac1725ba162c 51 vj_compress_init(struct vjcompress *comp)
segundo 0:ac1725ba162c 52 {
segundo 0:ac1725ba162c 53 register u_char i;
segundo 0:ac1725ba162c 54 register struct cstate *tstate = comp->tstate;
segundo 0:ac1725ba162c 55
segundo 0:ac1725ba162c 56 #if MAX_SLOTS == 0
segundo 0:ac1725ba162c 57 memset((char *)comp, 0, sizeof(*comp));
segundo 0:ac1725ba162c 58 #endif
segundo 0:ac1725ba162c 59 comp->maxSlotIndex = MAX_SLOTS - 1;
segundo 0:ac1725ba162c 60 comp->compressSlot = 0; /* Disable slot ID compression by default. */
segundo 0:ac1725ba162c 61 for (i = MAX_SLOTS - 1; i > 0; --i) {
segundo 0:ac1725ba162c 62 tstate[i].cs_id = i;
segundo 0:ac1725ba162c 63 tstate[i].cs_next = &tstate[i - 1];
segundo 0:ac1725ba162c 64 }
segundo 0:ac1725ba162c 65 tstate[0].cs_next = &tstate[MAX_SLOTS - 1];
segundo 0:ac1725ba162c 66 tstate[0].cs_id = 0;
segundo 0:ac1725ba162c 67 comp->last_cs = &tstate[0];
segundo 0:ac1725ba162c 68 comp->last_recv = 255;
segundo 0:ac1725ba162c 69 comp->last_xmit = 255;
segundo 0:ac1725ba162c 70 comp->flags = VJF_TOSS;
segundo 0:ac1725ba162c 71 }
segundo 0:ac1725ba162c 72
segundo 0:ac1725ba162c 73
segundo 0:ac1725ba162c 74 /* ENCODE encodes a number that is known to be non-zero. ENCODEZ
segundo 0:ac1725ba162c 75 * checks for zero (since zero has to be encoded in the long, 3 byte
segundo 0:ac1725ba162c 76 * form).
segundo 0:ac1725ba162c 77 */
segundo 0:ac1725ba162c 78 #define ENCODE(n) { \
segundo 0:ac1725ba162c 79 if ((u_short)(n) >= 256) { \
segundo 0:ac1725ba162c 80 *cp++ = 0; \
segundo 0:ac1725ba162c 81 cp[1] = (u_char)(n); \
segundo 0:ac1725ba162c 82 cp[0] = (u_char)((n) >> 8); \
segundo 0:ac1725ba162c 83 cp += 2; \
segundo 0:ac1725ba162c 84 } else { \
segundo 0:ac1725ba162c 85 *cp++ = (u_char)(n); \
segundo 0:ac1725ba162c 86 } \
segundo 0:ac1725ba162c 87 }
segundo 0:ac1725ba162c 88 #define ENCODEZ(n) { \
segundo 0:ac1725ba162c 89 if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \
segundo 0:ac1725ba162c 90 *cp++ = 0; \
segundo 0:ac1725ba162c 91 cp[1] = (u_char)(n); \
segundo 0:ac1725ba162c 92 cp[0] = (u_char)((n) >> 8); \
segundo 0:ac1725ba162c 93 cp += 2; \
segundo 0:ac1725ba162c 94 } else { \
segundo 0:ac1725ba162c 95 *cp++ = (u_char)(n); \
segundo 0:ac1725ba162c 96 } \
segundo 0:ac1725ba162c 97 }
segundo 0:ac1725ba162c 98
segundo 0:ac1725ba162c 99 #define DECODEL(f) { \
segundo 0:ac1725ba162c 100 if (*cp == 0) {\
segundo 0:ac1725ba162c 101 u32_t tmp = ntohl(f) + ((cp[1] << 8) | cp[2]); \
segundo 0:ac1725ba162c 102 (f) = htonl(tmp); \
segundo 0:ac1725ba162c 103 cp += 3; \
segundo 0:ac1725ba162c 104 } else { \
segundo 0:ac1725ba162c 105 u32_t tmp = ntohl(f) + (u32_t)*cp++; \
segundo 0:ac1725ba162c 106 (f) = htonl(tmp); \
segundo 0:ac1725ba162c 107 } \
segundo 0:ac1725ba162c 108 }
segundo 0:ac1725ba162c 109
segundo 0:ac1725ba162c 110 #define DECODES(f) { \
segundo 0:ac1725ba162c 111 if (*cp == 0) {\
segundo 0:ac1725ba162c 112 u_short tmp = ntohs(f) + (((u_short)cp[1] << 8) | cp[2]); \
segundo 0:ac1725ba162c 113 (f) = htons(tmp); \
segundo 0:ac1725ba162c 114 cp += 3; \
segundo 0:ac1725ba162c 115 } else { \
segundo 0:ac1725ba162c 116 u_short tmp = ntohs(f) + (u_short)*cp++; \
segundo 0:ac1725ba162c 117 (f) = htons(tmp); \
segundo 0:ac1725ba162c 118 } \
segundo 0:ac1725ba162c 119 }
segundo 0:ac1725ba162c 120
segundo 0:ac1725ba162c 121 #define DECODEU(f) { \
segundo 0:ac1725ba162c 122 if (*cp == 0) {\
segundo 0:ac1725ba162c 123 (f) = htons(((u_short)cp[1] << 8) | cp[2]); \
segundo 0:ac1725ba162c 124 cp += 3; \
segundo 0:ac1725ba162c 125 } else { \
segundo 0:ac1725ba162c 126 (f) = htons((u_short)*cp++); \
segundo 0:ac1725ba162c 127 } \
segundo 0:ac1725ba162c 128 }
segundo 0:ac1725ba162c 129
segundo 0:ac1725ba162c 130 /*
segundo 0:ac1725ba162c 131 * vj_compress_tcp - Attempt to do Van Jacobson header compression on a
segundo 0:ac1725ba162c 132 * packet. This assumes that nb and comp are not null and that the first
segundo 0:ac1725ba162c 133 * buffer of the chain contains a valid IP header.
segundo 0:ac1725ba162c 134 * Return the VJ type code indicating whether or not the packet was
segundo 0:ac1725ba162c 135 * compressed.
segundo 0:ac1725ba162c 136 */
segundo 0:ac1725ba162c 137 u_int
segundo 0:ac1725ba162c 138 vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb)
segundo 0:ac1725ba162c 139 {
segundo 0:ac1725ba162c 140 register struct ip_hdr *ip = (struct ip_hdr *)pb->payload;
segundo 0:ac1725ba162c 141 register struct cstate *cs = comp->last_cs->cs_next;
segundo 0:ac1725ba162c 142 register u_short hlen = IPH_HL(ip);
segundo 0:ac1725ba162c 143 register struct tcp_hdr *oth;
segundo 0:ac1725ba162c 144 register struct tcp_hdr *th;
segundo 0:ac1725ba162c 145 register u_short deltaS, deltaA;
segundo 0:ac1725ba162c 146 register u_long deltaL;
segundo 0:ac1725ba162c 147 register u_int changes = 0;
segundo 0:ac1725ba162c 148 u_char new_seq[16];
segundo 0:ac1725ba162c 149 register u_char *cp = new_seq;
segundo 0:ac1725ba162c 150
segundo 0:ac1725ba162c 151 /*
segundo 0:ac1725ba162c 152 * Check that the packet is IP proto TCP.
segundo 0:ac1725ba162c 153 */
segundo 0:ac1725ba162c 154 if (IPH_PROTO(ip) != IP_PROTO_TCP) {
segundo 0:ac1725ba162c 155 return (TYPE_IP);
segundo 0:ac1725ba162c 156 }
segundo 0:ac1725ba162c 157
segundo 0:ac1725ba162c 158 /*
segundo 0:ac1725ba162c 159 * Bail if this is an IP fragment or if the TCP packet isn't
segundo 0:ac1725ba162c 160 * `compressible' (i.e., ACK isn't set or some other control bit is
segundo 0:ac1725ba162c 161 * set).
segundo 0:ac1725ba162c 162 */
segundo 0:ac1725ba162c 163 if ((IPH_OFFSET(ip) & PP_HTONS(0x3fff)) || pb->tot_len < 40) {
segundo 0:ac1725ba162c 164 return (TYPE_IP);
segundo 0:ac1725ba162c 165 }
segundo 0:ac1725ba162c 166 th = (struct tcp_hdr *)&((long *)ip)[hlen];
segundo 0:ac1725ba162c 167 if ((TCPH_FLAGS(th) & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK) {
segundo 0:ac1725ba162c 168 return (TYPE_IP);
segundo 0:ac1725ba162c 169 }
segundo 0:ac1725ba162c 170 /*
segundo 0:ac1725ba162c 171 * Packet is compressible -- we're going to send either a
segundo 0:ac1725ba162c 172 * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need
segundo 0:ac1725ba162c 173 * to locate (or create) the connection state. Special case the
segundo 0:ac1725ba162c 174 * most recently used connection since it's most likely to be used
segundo 0:ac1725ba162c 175 * again & we don't have to do any reordering if it's used.
segundo 0:ac1725ba162c 176 */
segundo 0:ac1725ba162c 177 INCR(vjs_packets);
segundo 0:ac1725ba162c 178 if (!ip_addr_cmp(&ip->src, &cs->cs_ip.src)
segundo 0:ac1725ba162c 179 || !ip_addr_cmp(&ip->dest, &cs->cs_ip.dest)
segundo 0:ac1725ba162c 180 || *(long *)th != ((long *)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]) {
segundo 0:ac1725ba162c 181 /*
segundo 0:ac1725ba162c 182 * Wasn't the first -- search for it.
segundo 0:ac1725ba162c 183 *
segundo 0:ac1725ba162c 184 * States are kept in a circularly linked list with
segundo 0:ac1725ba162c 185 * last_cs pointing to the end of the list. The
segundo 0:ac1725ba162c 186 * list is kept in lru order by moving a state to the
segundo 0:ac1725ba162c 187 * head of the list whenever it is referenced. Since
segundo 0:ac1725ba162c 188 * the list is short and, empirically, the connection
segundo 0:ac1725ba162c 189 * we want is almost always near the front, we locate
segundo 0:ac1725ba162c 190 * states via linear search. If we don't find a state
segundo 0:ac1725ba162c 191 * for the datagram, the oldest state is (re-)used.
segundo 0:ac1725ba162c 192 */
segundo 0:ac1725ba162c 193 register struct cstate *lcs;
segundo 0:ac1725ba162c 194 register struct cstate *lastcs = comp->last_cs;
segundo 0:ac1725ba162c 195
segundo 0:ac1725ba162c 196 do {
segundo 0:ac1725ba162c 197 lcs = cs; cs = cs->cs_next;
segundo 0:ac1725ba162c 198 INCR(vjs_searches);
segundo 0:ac1725ba162c 199 if (ip_addr_cmp(&ip->src, &cs->cs_ip.src)
segundo 0:ac1725ba162c 200 && ip_addr_cmp(&ip->dest, &cs->cs_ip.dest)
segundo 0:ac1725ba162c 201 && *(long *)th == ((long *)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]) {
segundo 0:ac1725ba162c 202 goto found;
segundo 0:ac1725ba162c 203 }
segundo 0:ac1725ba162c 204 } while (cs != lastcs);
segundo 0:ac1725ba162c 205
segundo 0:ac1725ba162c 206 /*
segundo 0:ac1725ba162c 207 * Didn't find it -- re-use oldest cstate. Send an
segundo 0:ac1725ba162c 208 * uncompressed packet that tells the other side what
segundo 0:ac1725ba162c 209 * connection number we're using for this conversation.
segundo 0:ac1725ba162c 210 * Note that since the state list is circular, the oldest
segundo 0:ac1725ba162c 211 * state points to the newest and we only need to set
segundo 0:ac1725ba162c 212 * last_cs to update the lru linkage.
segundo 0:ac1725ba162c 213 */
segundo 0:ac1725ba162c 214 INCR(vjs_misses);
segundo 0:ac1725ba162c 215 comp->last_cs = lcs;
segundo 0:ac1725ba162c 216 hlen += TCPH_OFFSET(th);
segundo 0:ac1725ba162c 217 hlen <<= 2;
segundo 0:ac1725ba162c 218 /* Check that the IP/TCP headers are contained in the first buffer. */
segundo 0:ac1725ba162c 219 if (hlen > pb->len) {
segundo 0:ac1725ba162c 220 return (TYPE_IP);
segundo 0:ac1725ba162c 221 }
segundo 0:ac1725ba162c 222 goto uncompressed;
segundo 0:ac1725ba162c 223
segundo 0:ac1725ba162c 224 found:
segundo 0:ac1725ba162c 225 /*
segundo 0:ac1725ba162c 226 * Found it -- move to the front on the connection list.
segundo 0:ac1725ba162c 227 */
segundo 0:ac1725ba162c 228 if (cs == lastcs) {
segundo 0:ac1725ba162c 229 comp->last_cs = lcs;
segundo 0:ac1725ba162c 230 } else {
segundo 0:ac1725ba162c 231 lcs->cs_next = cs->cs_next;
segundo 0:ac1725ba162c 232 cs->cs_next = lastcs->cs_next;
segundo 0:ac1725ba162c 233 lastcs->cs_next = cs;
segundo 0:ac1725ba162c 234 }
segundo 0:ac1725ba162c 235 }
segundo 0:ac1725ba162c 236
segundo 0:ac1725ba162c 237 oth = (struct tcp_hdr *)&((long *)&cs->cs_ip)[hlen];
segundo 0:ac1725ba162c 238 deltaS = hlen;
segundo 0:ac1725ba162c 239 hlen += TCPH_OFFSET(th);
segundo 0:ac1725ba162c 240 hlen <<= 2;
segundo 0:ac1725ba162c 241 /* Check that the IP/TCP headers are contained in the first buffer. */
segundo 0:ac1725ba162c 242 if (hlen > pb->len) {
segundo 0:ac1725ba162c 243 PPPDEBUG(LOG_INFO, ("vj_compress_tcp: header len %d spans buffers\n", hlen));
segundo 0:ac1725ba162c 244 return (TYPE_IP);
segundo 0:ac1725ba162c 245 }
segundo 0:ac1725ba162c 246
segundo 0:ac1725ba162c 247 /*
segundo 0:ac1725ba162c 248 * Make sure that only what we expect to change changed. The first
segundo 0:ac1725ba162c 249 * line of the `if' checks the IP protocol version, header length &
segundo 0:ac1725ba162c 250 * type of service. The 2nd line checks the "Don't fragment" bit.
segundo 0:ac1725ba162c 251 * The 3rd line checks the time-to-live and protocol (the protocol
segundo 0:ac1725ba162c 252 * check is unnecessary but costless). The 4th line checks the TCP
segundo 0:ac1725ba162c 253 * header length. The 5th line checks IP options, if any. The 6th
segundo 0:ac1725ba162c 254 * line checks TCP options, if any. If any of these things are
segundo 0:ac1725ba162c 255 * different between the previous & current datagram, we send the
segundo 0:ac1725ba162c 256 * current datagram `uncompressed'.
segundo 0:ac1725ba162c 257 */
segundo 0:ac1725ba162c 258 if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0]
segundo 0:ac1725ba162c 259 || ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3]
segundo 0:ac1725ba162c 260 || ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4]
segundo 0:ac1725ba162c 261 || TCPH_OFFSET(th) != TCPH_OFFSET(oth)
segundo 0:ac1725ba162c 262 || (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2))
segundo 0:ac1725ba162c 263 || (TCPH_OFFSET(th) > 5 && BCMP(th + 1, oth + 1, (TCPH_OFFSET(th) - 5) << 2))) {
segundo 0:ac1725ba162c 264 goto uncompressed;
segundo 0:ac1725ba162c 265 }
segundo 0:ac1725ba162c 266
segundo 0:ac1725ba162c 267 /*
segundo 0:ac1725ba162c 268 * Figure out which of the changing fields changed. The
segundo 0:ac1725ba162c 269 * receiver expects changes in the order: urgent, window,
segundo 0:ac1725ba162c 270 * ack, seq (the order minimizes the number of temporaries
segundo 0:ac1725ba162c 271 * needed in this section of code).
segundo 0:ac1725ba162c 272 */
segundo 0:ac1725ba162c 273 if (TCPH_FLAGS(th) & TCP_URG) {
segundo 0:ac1725ba162c 274 deltaS = ntohs(th->urgp);
segundo 0:ac1725ba162c 275 ENCODEZ(deltaS);
segundo 0:ac1725ba162c 276 changes |= NEW_U;
segundo 0:ac1725ba162c 277 } else if (th->urgp != oth->urgp) {
segundo 0:ac1725ba162c 278 /* argh! URG not set but urp changed -- a sensible
segundo 0:ac1725ba162c 279 * implementation should never do this but RFC793
segundo 0:ac1725ba162c 280 * doesn't prohibit the change so we have to deal
segundo 0:ac1725ba162c 281 * with it. */
segundo 0:ac1725ba162c 282 goto uncompressed;
segundo 0:ac1725ba162c 283 }
segundo 0:ac1725ba162c 284
segundo 0:ac1725ba162c 285 if ((deltaS = (u_short)(ntohs(th->wnd) - ntohs(oth->wnd))) != 0) {
segundo 0:ac1725ba162c 286 ENCODE(deltaS);
segundo 0:ac1725ba162c 287 changes |= NEW_W;
segundo 0:ac1725ba162c 288 }
segundo 0:ac1725ba162c 289
segundo 0:ac1725ba162c 290 if ((deltaL = ntohl(th->ackno) - ntohl(oth->ackno)) != 0) {
segundo 0:ac1725ba162c 291 if (deltaL > 0xffff) {
segundo 0:ac1725ba162c 292 goto uncompressed;
segundo 0:ac1725ba162c 293 }
segundo 0:ac1725ba162c 294 deltaA = (u_short)deltaL;
segundo 0:ac1725ba162c 295 ENCODE(deltaA);
segundo 0:ac1725ba162c 296 changes |= NEW_A;
segundo 0:ac1725ba162c 297 }
segundo 0:ac1725ba162c 298
segundo 0:ac1725ba162c 299 if ((deltaL = ntohl(th->seqno) - ntohl(oth->seqno)) != 0) {
segundo 0:ac1725ba162c 300 if (deltaL > 0xffff) {
segundo 0:ac1725ba162c 301 goto uncompressed;
segundo 0:ac1725ba162c 302 }
segundo 0:ac1725ba162c 303 deltaS = (u_short)deltaL;
segundo 0:ac1725ba162c 304 ENCODE(deltaS);
segundo 0:ac1725ba162c 305 changes |= NEW_S;
segundo 0:ac1725ba162c 306 }
segundo 0:ac1725ba162c 307
segundo 0:ac1725ba162c 308 switch(changes) {
segundo 0:ac1725ba162c 309 case 0:
segundo 0:ac1725ba162c 310 /*
segundo 0:ac1725ba162c 311 * Nothing changed. If this packet contains data and the
segundo 0:ac1725ba162c 312 * last one didn't, this is probably a data packet following
segundo 0:ac1725ba162c 313 * an ack (normal on an interactive connection) and we send
segundo 0:ac1725ba162c 314 * it compressed. Otherwise it's probably a retransmit,
segundo 0:ac1725ba162c 315 * retransmitted ack or window probe. Send it uncompressed
segundo 0:ac1725ba162c 316 * in case the other side missed the compressed version.
segundo 0:ac1725ba162c 317 */
segundo 0:ac1725ba162c 318 if (IPH_LEN(ip) != IPH_LEN(&cs->cs_ip) &&
segundo 0:ac1725ba162c 319 ntohs(IPH_LEN(&cs->cs_ip)) == hlen) {
segundo 0:ac1725ba162c 320 break;
segundo 0:ac1725ba162c 321 }
segundo 0:ac1725ba162c 322
segundo 0:ac1725ba162c 323 /* (fall through) */
segundo 0:ac1725ba162c 324
segundo 0:ac1725ba162c 325 case SPECIAL_I:
segundo 0:ac1725ba162c 326 case SPECIAL_D:
segundo 0:ac1725ba162c 327 /*
segundo 0:ac1725ba162c 328 * actual changes match one of our special case encodings --
segundo 0:ac1725ba162c 329 * send packet uncompressed.
segundo 0:ac1725ba162c 330 */
segundo 0:ac1725ba162c 331 goto uncompressed;
segundo 0:ac1725ba162c 332
segundo 0:ac1725ba162c 333 case NEW_S|NEW_A:
segundo 0:ac1725ba162c 334 if (deltaS == deltaA && deltaS == ntohs(IPH_LEN(&cs->cs_ip)) - hlen) {
segundo 0:ac1725ba162c 335 /* special case for echoed terminal traffic */
segundo 0:ac1725ba162c 336 changes = SPECIAL_I;
segundo 0:ac1725ba162c 337 cp = new_seq;
segundo 0:ac1725ba162c 338 }
segundo 0:ac1725ba162c 339 break;
segundo 0:ac1725ba162c 340
segundo 0:ac1725ba162c 341 case NEW_S:
segundo 0:ac1725ba162c 342 if (deltaS == ntohs(IPH_LEN(&cs->cs_ip)) - hlen) {
segundo 0:ac1725ba162c 343 /* special case for data xfer */
segundo 0:ac1725ba162c 344 changes = SPECIAL_D;
segundo 0:ac1725ba162c 345 cp = new_seq;
segundo 0:ac1725ba162c 346 }
segundo 0:ac1725ba162c 347 break;
segundo 0:ac1725ba162c 348 }
segundo 0:ac1725ba162c 349
segundo 0:ac1725ba162c 350 deltaS = (u_short)(ntohs(IPH_ID(ip)) - ntohs(IPH_ID(&cs->cs_ip)));
segundo 0:ac1725ba162c 351 if (deltaS != 1) {
segundo 0:ac1725ba162c 352 ENCODEZ(deltaS);
segundo 0:ac1725ba162c 353 changes |= NEW_I;
segundo 0:ac1725ba162c 354 }
segundo 0:ac1725ba162c 355 if (TCPH_FLAGS(th) & TCP_PSH) {
segundo 0:ac1725ba162c 356 changes |= TCP_PUSH_BIT;
segundo 0:ac1725ba162c 357 }
segundo 0:ac1725ba162c 358 /*
segundo 0:ac1725ba162c 359 * Grab the cksum before we overwrite it below. Then update our
segundo 0:ac1725ba162c 360 * state with this packet's header.
segundo 0:ac1725ba162c 361 */
segundo 0:ac1725ba162c 362 deltaA = ntohs(th->chksum);
segundo 0:ac1725ba162c 363 BCOPY(ip, &cs->cs_ip, hlen);
segundo 0:ac1725ba162c 364
segundo 0:ac1725ba162c 365 /*
segundo 0:ac1725ba162c 366 * We want to use the original packet as our compressed packet.
segundo 0:ac1725ba162c 367 * (cp - new_seq) is the number of bytes we need for compressed
segundo 0:ac1725ba162c 368 * sequence numbers. In addition we need one byte for the change
segundo 0:ac1725ba162c 369 * mask, one for the connection id and two for the tcp checksum.
segundo 0:ac1725ba162c 370 * So, (cp - new_seq) + 4 bytes of header are needed. hlen is how
segundo 0:ac1725ba162c 371 * many bytes of the original packet to toss so subtract the two to
segundo 0:ac1725ba162c 372 * get the new packet size.
segundo 0:ac1725ba162c 373 */
segundo 0:ac1725ba162c 374 deltaS = (u_short)(cp - new_seq);
segundo 0:ac1725ba162c 375 if (!comp->compressSlot || comp->last_xmit != cs->cs_id) {
segundo 0:ac1725ba162c 376 comp->last_xmit = cs->cs_id;
segundo 0:ac1725ba162c 377 hlen -= deltaS + 4;
segundo 0:ac1725ba162c 378 if(pbuf_header(pb, -hlen)){
segundo 0:ac1725ba162c 379 /* Can we cope with this failing? Just assert for now */
segundo 0:ac1725ba162c 380 LWIP_ASSERT("pbuf_header failed\n", 0);
segundo 0:ac1725ba162c 381 }
segundo 0:ac1725ba162c 382 cp = (u_char *)pb->payload;
segundo 0:ac1725ba162c 383 *cp++ = (u_char)(changes | NEW_C);
segundo 0:ac1725ba162c 384 *cp++ = cs->cs_id;
segundo 0:ac1725ba162c 385 } else {
segundo 0:ac1725ba162c 386 hlen -= deltaS + 3;
segundo 0:ac1725ba162c 387 if(pbuf_header(pb, -hlen)) {
segundo 0:ac1725ba162c 388 /* Can we cope with this failing? Just assert for now */
segundo 0:ac1725ba162c 389 LWIP_ASSERT("pbuf_header failed\n", 0);
segundo 0:ac1725ba162c 390 }
segundo 0:ac1725ba162c 391 cp = (u_char *)pb->payload;
segundo 0:ac1725ba162c 392 *cp++ = (u_char)changes;
segundo 0:ac1725ba162c 393 }
segundo 0:ac1725ba162c 394 *cp++ = (u_char)(deltaA >> 8);
segundo 0:ac1725ba162c 395 *cp++ = (u_char)deltaA;
segundo 0:ac1725ba162c 396 BCOPY(new_seq, cp, deltaS);
segundo 0:ac1725ba162c 397 INCR(vjs_compressed);
segundo 0:ac1725ba162c 398 return (TYPE_COMPRESSED_TCP);
segundo 0:ac1725ba162c 399
segundo 0:ac1725ba162c 400 /*
segundo 0:ac1725ba162c 401 * Update connection state cs & send uncompressed packet (that is,
segundo 0:ac1725ba162c 402 * a regular ip/tcp packet but with the 'conversation id' we hope
segundo 0:ac1725ba162c 403 * to use on future compressed packets in the protocol field).
segundo 0:ac1725ba162c 404 */
segundo 0:ac1725ba162c 405 uncompressed:
segundo 0:ac1725ba162c 406 BCOPY(ip, &cs->cs_ip, hlen);
segundo 0:ac1725ba162c 407 IPH_PROTO_SET(ip, cs->cs_id);
segundo 0:ac1725ba162c 408 comp->last_xmit = cs->cs_id;
segundo 0:ac1725ba162c 409 return (TYPE_UNCOMPRESSED_TCP);
segundo 0:ac1725ba162c 410 }
segundo 0:ac1725ba162c 411
segundo 0:ac1725ba162c 412 /*
segundo 0:ac1725ba162c 413 * Called when we may have missed a packet.
segundo 0:ac1725ba162c 414 */
segundo 0:ac1725ba162c 415 void
segundo 0:ac1725ba162c 416 vj_uncompress_err(struct vjcompress *comp)
segundo 0:ac1725ba162c 417 {
segundo 0:ac1725ba162c 418 comp->flags |= VJF_TOSS;
segundo 0:ac1725ba162c 419 INCR(vjs_errorin);
segundo 0:ac1725ba162c 420 }
segundo 0:ac1725ba162c 421
segundo 0:ac1725ba162c 422 /*
segundo 0:ac1725ba162c 423 * "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP.
segundo 0:ac1725ba162c 424 * Return 0 on success, -1 on failure.
segundo 0:ac1725ba162c 425 */
segundo 0:ac1725ba162c 426 int
segundo 0:ac1725ba162c 427 vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp)
segundo 0:ac1725ba162c 428 {
segundo 0:ac1725ba162c 429 register u_int hlen;
segundo 0:ac1725ba162c 430 register struct cstate *cs;
segundo 0:ac1725ba162c 431 register struct ip_hdr *ip;
segundo 0:ac1725ba162c 432
segundo 0:ac1725ba162c 433 ip = (struct ip_hdr *)nb->payload;
segundo 0:ac1725ba162c 434 hlen = IPH_HL(ip) << 2;
segundo 0:ac1725ba162c 435 if (IPH_PROTO(ip) >= MAX_SLOTS
segundo 0:ac1725ba162c 436 || hlen + sizeof(struct tcp_hdr) > nb->len
segundo 0:ac1725ba162c 437 || (hlen += TCPH_OFFSET(((struct tcp_hdr *)&((char *)ip)[hlen])) << 2)
segundo 0:ac1725ba162c 438 > nb->len
segundo 0:ac1725ba162c 439 || hlen > MAX_HDR) {
segundo 0:ac1725ba162c 440 PPPDEBUG(LOG_INFO, ("vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n",
segundo 0:ac1725ba162c 441 IPH_PROTO(ip), hlen, nb->len));
segundo 0:ac1725ba162c 442 comp->flags |= VJF_TOSS;
segundo 0:ac1725ba162c 443 INCR(vjs_errorin);
segundo 0:ac1725ba162c 444 return -1;
segundo 0:ac1725ba162c 445 }
segundo 0:ac1725ba162c 446 cs = &comp->rstate[comp->last_recv = IPH_PROTO(ip)];
segundo 0:ac1725ba162c 447 comp->flags &=~ VJF_TOSS;
segundo 0:ac1725ba162c 448 IPH_PROTO_SET(ip, IP_PROTO_TCP);
segundo 0:ac1725ba162c 449 BCOPY(ip, &cs->cs_ip, hlen);
segundo 0:ac1725ba162c 450 cs->cs_hlen = (u_short)hlen;
segundo 0:ac1725ba162c 451 INCR(vjs_uncompressedin);
segundo 0:ac1725ba162c 452 return 0;
segundo 0:ac1725ba162c 453 }
segundo 0:ac1725ba162c 454
segundo 0:ac1725ba162c 455 /*
segundo 0:ac1725ba162c 456 * Uncompress a packet of type TYPE_COMPRESSED_TCP.
segundo 0:ac1725ba162c 457 * The packet is composed of a buffer chain and the first buffer
segundo 0:ac1725ba162c 458 * must contain an accurate chain length.
segundo 0:ac1725ba162c 459 * The first buffer must include the entire compressed TCP/IP header.
segundo 0:ac1725ba162c 460 * This procedure replaces the compressed header with the uncompressed
segundo 0:ac1725ba162c 461 * header and returns the length of the VJ header.
segundo 0:ac1725ba162c 462 */
segundo 0:ac1725ba162c 463 int
segundo 0:ac1725ba162c 464 vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp)
segundo 0:ac1725ba162c 465 {
segundo 0:ac1725ba162c 466 u_char *cp;
segundo 0:ac1725ba162c 467 struct tcp_hdr *th;
segundo 0:ac1725ba162c 468 struct cstate *cs;
segundo 0:ac1725ba162c 469 u_short *bp;
segundo 0:ac1725ba162c 470 struct pbuf *n0 = *nb;
segundo 0:ac1725ba162c 471 u32_t tmp;
segundo 0:ac1725ba162c 472 u_int vjlen, hlen, changes;
segundo 0:ac1725ba162c 473
segundo 0:ac1725ba162c 474 INCR(vjs_compressedin);
segundo 0:ac1725ba162c 475 cp = (u_char *)n0->payload;
segundo 0:ac1725ba162c 476 changes = *cp++;
segundo 0:ac1725ba162c 477 if (changes & NEW_C) {
segundo 0:ac1725ba162c 478 /*
segundo 0:ac1725ba162c 479 * Make sure the state index is in range, then grab the state.
segundo 0:ac1725ba162c 480 * If we have a good state index, clear the 'discard' flag.
segundo 0:ac1725ba162c 481 */
segundo 0:ac1725ba162c 482 if (*cp >= MAX_SLOTS) {
segundo 0:ac1725ba162c 483 PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: bad cid=%d\n", *cp));
segundo 0:ac1725ba162c 484 goto bad;
segundo 0:ac1725ba162c 485 }
segundo 0:ac1725ba162c 486
segundo 0:ac1725ba162c 487 comp->flags &=~ VJF_TOSS;
segundo 0:ac1725ba162c 488 comp->last_recv = *cp++;
segundo 0:ac1725ba162c 489 } else {
segundo 0:ac1725ba162c 490 /*
segundo 0:ac1725ba162c 491 * this packet has an implicit state index. If we've
segundo 0:ac1725ba162c 492 * had a line error since the last time we got an
segundo 0:ac1725ba162c 493 * explicit state index, we have to toss the packet.
segundo 0:ac1725ba162c 494 */
segundo 0:ac1725ba162c 495 if (comp->flags & VJF_TOSS) {
segundo 0:ac1725ba162c 496 PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: tossing\n"));
segundo 0:ac1725ba162c 497 INCR(vjs_tossed);
segundo 0:ac1725ba162c 498 return (-1);
segundo 0:ac1725ba162c 499 }
segundo 0:ac1725ba162c 500 }
segundo 0:ac1725ba162c 501 cs = &comp->rstate[comp->last_recv];
segundo 0:ac1725ba162c 502 hlen = IPH_HL(&cs->cs_ip) << 2;
segundo 0:ac1725ba162c 503 th = (struct tcp_hdr *)&((u_char *)&cs->cs_ip)[hlen];
segundo 0:ac1725ba162c 504 th->chksum = htons((*cp << 8) | cp[1]);
segundo 0:ac1725ba162c 505 cp += 2;
segundo 0:ac1725ba162c 506 if (changes & TCP_PUSH_BIT) {
segundo 0:ac1725ba162c 507 TCPH_SET_FLAG(th, TCP_PSH);
segundo 0:ac1725ba162c 508 } else {
segundo 0:ac1725ba162c 509 TCPH_UNSET_FLAG(th, TCP_PSH);
segundo 0:ac1725ba162c 510 }
segundo 0:ac1725ba162c 511
segundo 0:ac1725ba162c 512 switch (changes & SPECIALS_MASK) {
segundo 0:ac1725ba162c 513 case SPECIAL_I:
segundo 0:ac1725ba162c 514 {
segundo 0:ac1725ba162c 515 register u32_t i = ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen;
segundo 0:ac1725ba162c 516 /* some compilers can't nest inline assembler.. */
segundo 0:ac1725ba162c 517 tmp = ntohl(th->ackno) + i;
segundo 0:ac1725ba162c 518 th->ackno = htonl(tmp);
segundo 0:ac1725ba162c 519 tmp = ntohl(th->seqno) + i;
segundo 0:ac1725ba162c 520 th->seqno = htonl(tmp);
segundo 0:ac1725ba162c 521 }
segundo 0:ac1725ba162c 522 break;
segundo 0:ac1725ba162c 523
segundo 0:ac1725ba162c 524 case SPECIAL_D:
segundo 0:ac1725ba162c 525 /* some compilers can't nest inline assembler.. */
segundo 0:ac1725ba162c 526 tmp = ntohl(th->seqno) + ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen;
segundo 0:ac1725ba162c 527 th->seqno = htonl(tmp);
segundo 0:ac1725ba162c 528 break;
segundo 0:ac1725ba162c 529
segundo 0:ac1725ba162c 530 default:
segundo 0:ac1725ba162c 531 if (changes & NEW_U) {
segundo 0:ac1725ba162c 532 TCPH_SET_FLAG(th, TCP_URG);
segundo 0:ac1725ba162c 533 DECODEU(th->urgp);
segundo 0:ac1725ba162c 534 } else {
segundo 0:ac1725ba162c 535 TCPH_UNSET_FLAG(th, TCP_URG);
segundo 0:ac1725ba162c 536 }
segundo 0:ac1725ba162c 537 if (changes & NEW_W) {
segundo 0:ac1725ba162c 538 DECODES(th->wnd);
segundo 0:ac1725ba162c 539 }
segundo 0:ac1725ba162c 540 if (changes & NEW_A) {
segundo 0:ac1725ba162c 541 DECODEL(th->ackno);
segundo 0:ac1725ba162c 542 }
segundo 0:ac1725ba162c 543 if (changes & NEW_S) {
segundo 0:ac1725ba162c 544 DECODEL(th->seqno);
segundo 0:ac1725ba162c 545 }
segundo 0:ac1725ba162c 546 break;
segundo 0:ac1725ba162c 547 }
segundo 0:ac1725ba162c 548 if (changes & NEW_I) {
segundo 0:ac1725ba162c 549 DECODES(cs->cs_ip._id);
segundo 0:ac1725ba162c 550 } else {
segundo 0:ac1725ba162c 551 IPH_ID_SET(&cs->cs_ip, ntohs(IPH_ID(&cs->cs_ip)) + 1);
segundo 0:ac1725ba162c 552 IPH_ID_SET(&cs->cs_ip, htons(IPH_ID(&cs->cs_ip)));
segundo 0:ac1725ba162c 553 }
segundo 0:ac1725ba162c 554
segundo 0:ac1725ba162c 555 /*
segundo 0:ac1725ba162c 556 * At this point, cp points to the first byte of data in the
segundo 0:ac1725ba162c 557 * packet. Fill in the IP total length and update the IP
segundo 0:ac1725ba162c 558 * header checksum.
segundo 0:ac1725ba162c 559 */
segundo 0:ac1725ba162c 560 vjlen = (u_short)(cp - (u_char*)n0->payload);
segundo 0:ac1725ba162c 561 if (n0->len < vjlen) {
segundo 0:ac1725ba162c 562 /*
segundo 0:ac1725ba162c 563 * We must have dropped some characters (crc should detect
segundo 0:ac1725ba162c 564 * this but the old slip framing won't)
segundo 0:ac1725ba162c 565 */
segundo 0:ac1725ba162c 566 PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: head buffer %d too short %d\n",
segundo 0:ac1725ba162c 567 n0->len, vjlen));
segundo 0:ac1725ba162c 568 goto bad;
segundo 0:ac1725ba162c 569 }
segundo 0:ac1725ba162c 570
segundo 0:ac1725ba162c 571 #if BYTE_ORDER == LITTLE_ENDIAN
segundo 0:ac1725ba162c 572 tmp = n0->tot_len - vjlen + cs->cs_hlen;
segundo 0:ac1725ba162c 573 IPH_LEN_SET(&cs->cs_ip, htons((u_short)tmp));
segundo 0:ac1725ba162c 574 #else
segundo 0:ac1725ba162c 575 IPH_LEN_SET(&cs->cs_ip, htons(n0->tot_len - vjlen + cs->cs_hlen));
segundo 0:ac1725ba162c 576 #endif
segundo 0:ac1725ba162c 577
segundo 0:ac1725ba162c 578 /* recompute the ip header checksum */
segundo 0:ac1725ba162c 579 bp = (u_short *) &cs->cs_ip;
segundo 0:ac1725ba162c 580 IPH_CHKSUM_SET(&cs->cs_ip, 0);
segundo 0:ac1725ba162c 581 for (tmp = 0; hlen > 0; hlen -= 2) {
segundo 0:ac1725ba162c 582 tmp += *bp++;
segundo 0:ac1725ba162c 583 }
segundo 0:ac1725ba162c 584 tmp = (tmp & 0xffff) + (tmp >> 16);
segundo 0:ac1725ba162c 585 tmp = (tmp & 0xffff) + (tmp >> 16);
segundo 0:ac1725ba162c 586 IPH_CHKSUM_SET(&cs->cs_ip, (u_short)(~tmp));
segundo 0:ac1725ba162c 587
segundo 0:ac1725ba162c 588 /* Remove the compressed header and prepend the uncompressed header. */
segundo 0:ac1725ba162c 589 if(pbuf_header(n0, -((s16_t)(vjlen)))) {
segundo 0:ac1725ba162c 590 /* Can we cope with this failing? Just assert for now */
segundo 0:ac1725ba162c 591 LWIP_ASSERT("pbuf_header failed\n", 0);
segundo 0:ac1725ba162c 592 goto bad;
segundo 0:ac1725ba162c 593 }
segundo 0:ac1725ba162c 594
segundo 0:ac1725ba162c 595 if(LWIP_MEM_ALIGN(n0->payload) != n0->payload) {
segundo 0:ac1725ba162c 596 struct pbuf *np, *q;
segundo 0:ac1725ba162c 597 u8_t *bufptr;
segundo 0:ac1725ba162c 598
segundo 0:ac1725ba162c 599 np = pbuf_alloc(PBUF_RAW, n0->len + cs->cs_hlen, PBUF_POOL);
segundo 0:ac1725ba162c 600 if(!np) {
segundo 0:ac1725ba162c 601 PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: realign failed\n"));
segundo 0:ac1725ba162c 602 goto bad;
segundo 0:ac1725ba162c 603 }
segundo 0:ac1725ba162c 604
segundo 0:ac1725ba162c 605 if(pbuf_header(np, -cs->cs_hlen)) {
segundo 0:ac1725ba162c 606 /* Can we cope with this failing? Just assert for now */
segundo 0:ac1725ba162c 607 LWIP_ASSERT("pbuf_header failed\n", 0);
segundo 0:ac1725ba162c 608 goto bad;
segundo 0:ac1725ba162c 609 }
segundo 0:ac1725ba162c 610
segundo 0:ac1725ba162c 611 bufptr = (u8_t *)n0->payload;
segundo 0:ac1725ba162c 612 for(q = np; q != NULL; q = q->next) {
segundo 0:ac1725ba162c 613 MEMCPY(q->payload, bufptr, q->len);
segundo 0:ac1725ba162c 614 bufptr += q->len;
segundo 0:ac1725ba162c 615 }
segundo 0:ac1725ba162c 616
segundo 0:ac1725ba162c 617 if(n0->next) {
segundo 0:ac1725ba162c 618 pbuf_chain(np, n0->next);
segundo 0:ac1725ba162c 619 pbuf_dechain(n0);
segundo 0:ac1725ba162c 620 }
segundo 0:ac1725ba162c 621 pbuf_free(n0);
segundo 0:ac1725ba162c 622 n0 = np;
segundo 0:ac1725ba162c 623 }
segundo 0:ac1725ba162c 624
segundo 0:ac1725ba162c 625 if(pbuf_header(n0, cs->cs_hlen)) {
segundo 0:ac1725ba162c 626 struct pbuf *np;
segundo 0:ac1725ba162c 627
segundo 0:ac1725ba162c 628 LWIP_ASSERT("vj_uncompress_tcp: cs->cs_hlen <= PBUF_POOL_BUFSIZE", cs->cs_hlen <= PBUF_POOL_BUFSIZE);
segundo 0:ac1725ba162c 629 np = pbuf_alloc(PBUF_RAW, cs->cs_hlen, PBUF_POOL);
segundo 0:ac1725ba162c 630 if(!np) {
segundo 0:ac1725ba162c 631 PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: prepend failed\n"));
segundo 0:ac1725ba162c 632 goto bad;
segundo 0:ac1725ba162c 633 }
segundo 0:ac1725ba162c 634 pbuf_cat(np, n0);
segundo 0:ac1725ba162c 635 n0 = np;
segundo 0:ac1725ba162c 636 }
segundo 0:ac1725ba162c 637 LWIP_ASSERT("n0->len >= cs->cs_hlen", n0->len >= cs->cs_hlen);
segundo 0:ac1725ba162c 638 MEMCPY(n0->payload, &cs->cs_ip, cs->cs_hlen);
segundo 0:ac1725ba162c 639
segundo 0:ac1725ba162c 640 *nb = n0;
segundo 0:ac1725ba162c 641
segundo 0:ac1725ba162c 642 return vjlen;
segundo 0:ac1725ba162c 643
segundo 0:ac1725ba162c 644 bad:
segundo 0:ac1725ba162c 645 comp->flags |= VJF_TOSS;
segundo 0:ac1725ba162c 646 INCR(vjs_errorin);
segundo 0:ac1725ba162c 647 return (-1);
segundo 0:ac1725ba162c 648 }
segundo 0:ac1725ba162c 649
segundo 0:ac1725ba162c 650 #endif /* VJ_SUPPORT */
segundo 0:ac1725ba162c 651
segundo 0:ac1725ba162c 652 #endif /* PPP_SUPPORT */