Example program with HTTPServer and sensor data streaming over TCPSockets, using Donatien Garnier's Net APIs and services code on top of LWIP. Files StreamServer.h and .cpp encapsulate streaming over TCPSockets. Broadcast is done by sendToAll(), and all incoming data is echoed back to the client. Echo code can be replaced with some remote control of the streaming interface. See main() that shows how to periodically send some data to all subscribed clients. To subscribe, a client should open a socket at <mbed_ip> port 123. I used few lines in TCL code to set up a quick sink for the data. HTTP files are served on port 80 concurrently to the streaming.

Dependencies:   mbed

Committer:
iva2k
Date:
Sat Jun 12 06:01:50 2010 +0000
Revision:
0:e614f7875b60

        

Who changed what in which revision?

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