LwIP with PPP & Ethernet integration

Dependents:   NetworkingCoreLib

This is the mbed port of the LwIP stack: http://savannah.nongnu.org/projects/lwip/

It includes contributed content from NXP's port for LPCxxxx devices: http://www.lpcware.com/content/project/lightweight-ip-lwip-networking-stack

Licence

LwIP is licenced under the BSD licence:

Copyright (c) 2001-2004 Swedish Institute of Computer Science. 
All rights reserved. 
Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met: 
1. Redistributions of source code must retain the above copyright notice, 
this list of conditions and the following disclaimer. 
2. Redistributions in binary form must reproduce the above copyright notice, 
this list of conditions and the following disclaimer in the documentation 
and/or other materials provided with the distribution. 
3. The name of the author may not be used to endorse or promote products 
derived from this software without specific prior written permission. 
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
OF SUCH DAMAGE.
Committer:
donatien
Date:
Fri May 25 08:56:35 2012 +0000
Revision:
2:1a87f74b8e3b
Parent:
0:8e01dca41002
Removed compilation of EMAC driver when using PPP

Who changed what in which revision?

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