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