source: rtems/cpukit/libnetworking/net/slcompress.c @ cb68253

5
Last change on this file since cb68253 was cb68253, checked in by Sebastian Huber <sebastian.huber@…>, on 09/07/18 at 04:19:02

network: Use kernel/user space header files

Add and use <machine/rtems-bsd-kernel-space.h> and
<machine/rtems-bsd-user-space.h> similar to the libbsd to avoid command
line defines and defines scattered throught the code base.

Simplify cpukit/libnetworking/Makefile.am.

Update #3375.

  • Property mode set to 100644
File size: 16.6 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3/*-
4 * Copyright (c) 1989, 1993, 1994
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 4. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 *      @(#)slcompress.c        8.2 (Berkeley) 4/16/94
32 * $FreeBSD: src/sys/net/slcompress.c,v 1.19 2004/04/07 20:46:12 imp Exp $
33 */
34
35/*
36 * Routines to compress and uncompess tcp packets (for transmission
37 * over low speed serial lines.
38 *
39 * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
40 *      - Initial distribution.
41 *
42 */
43
44#ifdef HAVE_CONFIG_H
45#include "config.h"
46#endif
47
48#include <stdint.h>
49
50#include <sys/param.h>
51#include <sys/mbuf.h>
52#include <sys/systm.h>
53
54#include <netinet/in.h>
55#include <netinet/in_systm.h>
56#include <netinet/ip.h>
57#include <netinet/tcp.h>
58
59#include <net/slcompress.h>
60
61#ifndef SL_NO_STATS
62#define INCR(counter) ++comp->counter;
63#else
64#define INCR(counter)
65#endif
66
67#define BCMP(p1, p2, n) bcmp((void *)(p1), (void *)(p2), (int)(n))
68#define BCOPY(p1, p2, n) bcopy((void *)(p1), (void *)(p2), (int)(n))
69
70void
71sl_compress_init(struct slcompress *comp, int max_state)
72{
73        register u_int i;
74        register struct cstate *tstate = comp->tstate;
75
76        if (max_state == -1) {
77                max_state = MAX_STATES - 1;
78                bzero((char *)comp, sizeof(*comp));
79        } else {
80                /* Don't reset statistics */
81                bzero((char *)comp->tstate, sizeof(comp->tstate));
82                bzero((char *)comp->rstate, sizeof(comp->rstate));
83        }
84        for (i = max_state; i > 0; --i) {
85                tstate[i].cs_id = i;
86                tstate[i].cs_next = &tstate[i - 1];
87        }
88        tstate[0].cs_next = &tstate[max_state];
89        tstate[0].cs_id = 0;
90        comp->last_cs = &tstate[0];
91        comp->last_recv = 255;
92        comp->last_xmit = 255;
93        comp->flags = SLF_TOSS;
94}
95
96
97/* ENCODE encodes a number that is known to be non-zero.  ENCODEZ
98 * checks for zero (since zero has to be encoded in the long, 3 byte
99 * form).
100 */
101#define ENCODE(n) { \
102        if ((u_int16_t)(n) >= 256) { \
103                *cp++ = 0; \
104                cp[1] = (n); \
105                cp[0] = (n) >> 8; \
106                cp += 2; \
107        } else { \
108                *cp++ = (n); \
109        } \
110}
111#define ENCODEZ(n) { \
112        if ((u_int16_t)(n) >= 256 || (u_int16_t)(n) == 0) { \
113                *cp++ = 0; \
114                cp[1] = (n); \
115                cp[0] = (n) >> 8; \
116                cp += 2; \
117        } else { \
118                *cp++ = (n); \
119        } \
120}
121
122#define DECODEL(f) { \
123        if (*cp == 0) {\
124                (f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \
125                cp += 3; \
126        } else { \
127                (f) = htonl(ntohl(f) + (u_int32_t)*cp++); \
128        } \
129}
130
131#define DECODES(f) { \
132        if (*cp == 0) {\
133                (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \
134                cp += 3; \
135        } else { \
136                (f) = htons(ntohs(f) + (u_int32_t)*cp++); \
137        } \
138}
139
140#define DECODEU(f) { \
141        if (*cp == 0) {\
142                (f) = htons((cp[1] << 8) | cp[2]); \
143                cp += 3; \
144        } else { \
145                (f) = htons((u_int32_t)*cp++); \
146        } \
147}
148
149/*
150 * Attempt to compress an outgoing TCP packet and return the type of
151 * the result.  The caller must have already verified that the protocol
152 * is TCP.  The first mbuf must contain the complete IP and TCP headers,
153 * and "ip" must be == mtod(m, struct ip *).  "comp" supplies the
154 * compression state, and "compress_cid" tells us whether it is OK
155 * to leave out the CID field when feasible.
156 *
157 * The caller is responsible for adjusting m->m_pkthdr.len upon return,
158 * if m is an M_PKTHDR mbuf.
159 */
160u_int
161sl_compress_tcp(struct mbuf *m, struct ip *ip, struct slcompress *comp,
162        int compress_cid)
163{
164        register struct cstate *cs = comp->last_cs->cs_next;
165        register u_int hlen = ip->ip_hl;
166        register struct tcphdr *oth;
167        register struct tcphdr *th;
168        register u_int deltaS, deltaA;
169        register u_int changes = 0;
170        u_char new_seq[16];
171        register u_char *cp = new_seq;
172
173        /*
174         * Bail if this is an IP fragment or if the TCP packet isn't
175         * `compressible' (i.e., ACK isn't set or some other control bit is
176         * set).  (We assume that the caller has already made sure the
177         * packet is IP proto TCP).
178         */
179        if ((ip->ip_off & htons(0x3fff)) || m->m_len < 40)
180                return (TYPE_IP);
181
182        th = (struct tcphdr *)&((int32_t *)ip)[hlen];
183        if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK)
184                return (TYPE_IP);
185        /*
186         * Packet is compressible -- we're going to send either a
187         * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way we need
188         * to locate (or create) the connection state.  Special case the
189         * most recently used connection since it's most likely to be used
190         * again & we don't have to do any reordering if it's used.
191         */
192        INCR(sls_packets)
193        if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr ||
194            ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr ||
195            *(int32_t *)th != ((int32_t *)&cs->cs_ip)[cs->cs_ip.ip_hl]) {
196                /*
197                 * Wasn't the first -- search for it.
198                 *
199                 * States are kept in a circularly linked list with
200                 * last_cs pointing to the end of the list.  The
201                 * list is kept in lru order by moving a state to the
202                 * head of the list whenever it is referenced.  Since
203                 * the list is short and, empirically, the connection
204                 * we want is almost always near the front, we locate
205                 * states via linear search.  If we don't find a state
206                 * for the datagram, the oldest state is (re-)used.
207                 */
208                register struct cstate *lcs;
209                register struct cstate *lastcs = comp->last_cs;
210
211                do {
212                        lcs = cs; cs = cs->cs_next;
213                        INCR(sls_searches)
214                        if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr
215                            && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr
216                            && *(int32_t *)th ==
217                            ((int32_t *)&cs->cs_ip)[cs->cs_ip.ip_hl])
218                                goto found;
219                } while (cs != lastcs);
220
221                /*
222                 * Didn't find it -- re-use oldest cstate.  Send an
223                 * uncompressed packet that tells the other side what
224                 * connection number we're using for this conversation.
225                 * Note that since the state list is circular, the oldest
226                 * state points to the newest and we only need to set
227                 * last_cs to update the lru linkage.
228                 */
229                INCR(sls_misses)
230                comp->last_cs = lcs;
231                hlen += th->th_off;
232                hlen <<= 2;
233                if (hlen > m->m_len)
234                    return TYPE_IP;
235                goto uncompressed;
236
237        found:
238                /*
239                 * Found it -- move to the front on the connection list.
240                 */
241                if (cs == lastcs)
242                        comp->last_cs = lcs;
243                else {
244                        lcs->cs_next = cs->cs_next;
245                        cs->cs_next = lastcs->cs_next;
246                        lastcs->cs_next = cs;
247                }
248        }
249
250        /*
251         * Make sure that only what we expect to change changed. The first
252         * line of the `if' checks the IP protocol version, header length &
253         * type of service.  The 2nd line checks the "Don't fragment" bit.
254         * The 3rd line checks the time-to-live and protocol (the protocol
255         * check is unnecessary but costless).  The 4th line checks the TCP
256         * header length.  The 5th line checks IP options, if any.  The 6th
257         * line checks TCP options, if any.  If any of these things are
258         * different between the previous & current datagram, we send the
259         * current datagram `uncompressed'.
260         */
261        oth = (struct tcphdr *)&((int32_t *)&cs->cs_ip)[hlen];
262        deltaS = hlen;
263        hlen += th->th_off;
264        hlen <<= 2;
265        if (hlen > m->m_len)
266            return TYPE_IP;
267
268        if (((u_int16_t *)ip)[0] != ((u_int16_t *)&cs->cs_ip)[0] ||
269            ((u_int16_t *)ip)[3] != ((u_int16_t *)&cs->cs_ip)[3] ||
270            ((u_int16_t *)ip)[4] != ((u_int16_t *)&cs->cs_ip)[4] ||
271            th->th_off != oth->th_off ||
272            (deltaS > 5 &&
273             BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) ||
274            (th->th_off > 5 &&
275             BCMP(th + 1, oth + 1, (th->th_off - 5) << 2)))
276                goto uncompressed;
277
278        /*
279         * Figure out which of the changing fields changed.  The
280         * receiver expects changes in the order: urgent, window,
281         * ack, seq (the order minimizes the number of temporaries
282         * needed in this section of code).
283         */
284        if (th->th_flags & TH_URG) {
285                deltaS = ntohs(th->th_urp);
286                ENCODEZ(deltaS);
287                changes |= NEW_U;
288        } else if (th->th_urp != oth->th_urp)
289                /* argh! URG not set but urp changed -- a sensible
290                 * implementation should never do this but RFC793
291                 * doesn't prohibit the change so we have to deal
292                 * with it. */
293                 goto uncompressed;
294
295        deltaS = (u_int16_t)(ntohs(th->th_win) - ntohs(oth->th_win));
296        if (deltaS) {
297                ENCODE(deltaS);
298                changes |= NEW_W;
299        }
300
301        deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack);
302        if (deltaA) {
303                if (deltaA > 0xffff)
304                        goto uncompressed;
305                ENCODE(deltaA);
306                changes |= NEW_A;
307        }
308
309        deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq);
310        if (deltaS) {
311                if (deltaS > 0xffff)
312                        goto uncompressed;
313                ENCODE(deltaS);
314                changes |= NEW_S;
315        }
316
317        switch(changes) {
318
319        case 0:
320                /*
321                 * Nothing changed. If this packet contains data and the
322                 * last one didn't, this is probably a data packet following
323                 * an ack (normal on an interactive connection) and we send
324                 * it compressed.  Otherwise it's probably a retransmit,
325                 * retransmitted ack or window probe.  Send it uncompressed
326                 * in case the other side missed the compressed version.
327                 */
328                if (ip->ip_len != cs->cs_ip.ip_len &&
329                    ntohs(cs->cs_ip.ip_len) == hlen)
330                        break;
331
332                /* FALLTHROUGH */
333
334        case SPECIAL_I:
335        case SPECIAL_D:
336                /*
337                 * actual changes match one of our special case encodings --
338                 * send packet uncompressed.
339                 */
340                goto uncompressed;
341
342        case NEW_S|NEW_A:
343                if (deltaS == deltaA &&
344                    deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
345                        /* special case for echoed terminal traffic */
346                        changes = SPECIAL_I;
347                        cp = new_seq;
348                }
349                break;
350
351        case NEW_S:
352                if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
353                        /* special case for data xfer */
354                        changes = SPECIAL_D;
355                        cp = new_seq;
356                }
357                break;
358        }
359
360        deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id);
361        if (deltaS != 1) {
362                ENCODEZ(deltaS);
363                changes |= NEW_I;
364        }
365        if (th->th_flags & TH_PUSH)
366                changes |= TCP_PUSH_BIT;
367        /*
368         * Grab the cksum before we overwrite it below.  Then update our
369         * state with this packet's header.
370         */
371        deltaA = ntohs(th->th_sum);
372        BCOPY(ip, &cs->cs_ip, hlen);
373
374        /*
375         * We want to use the original packet as our compressed packet.
376         * (cp - new_seq) is the number of bytes we need for compressed
377         * sequence numbers.  In addition we need one byte for the change
378         * mask, one for the connection id and two for the tcp checksum.
379         * So, (cp - new_seq) + 4 bytes of header are needed.  hlen is how
380         * many bytes of the original packet to toss so subtract the two to
381         * get the new packet size.
382         */
383        deltaS = cp - new_seq;
384        cp = (u_char *)ip;
385        if (compress_cid == 0 || comp->last_xmit != cs->cs_id) {
386                comp->last_xmit = cs->cs_id;
387                hlen -= deltaS + 4;
388                cp += hlen;
389                *cp++ = changes | NEW_C;
390                *cp++ = cs->cs_id;
391        } else {
392                hlen -= deltaS + 3;
393                cp += hlen;
394                *cp++ = changes;
395        }
396        m->m_len -= hlen;
397        m->m_data += hlen;
398        *cp++ = deltaA >> 8;
399        *cp++ = deltaA;
400        BCOPY(new_seq, cp, deltaS);
401        INCR(sls_compressed)
402        return (TYPE_COMPRESSED_TCP);
403
404        /*
405         * Update connection state cs & send uncompressed packet ('uncompressed'
406         * means a regular ip/tcp packet but with the 'conversation id' we hope
407         * to use on future compressed packets in the protocol field).
408         */
409uncompressed:
410        BCOPY(ip, &cs->cs_ip, hlen);
411        ip->ip_p = cs->cs_id;
412        comp->last_xmit = cs->cs_id;
413        return (TYPE_UNCOMPRESSED_TCP);
414}
415
416
417int
418sl_uncompress_tcp(u_char **bufp, int len, u_int type, struct slcompress *comp)
419{
420        u_char *hdr, *cp;
421        u_int hlen;
422        int vjlen;
423
424        cp = bufp? *bufp: NULL;
425        vjlen = sl_uncompress_tcp_core(cp, len, len, type, comp, &hdr, &hlen);
426        if (vjlen < 0)
427                return (0);     /* error */
428        if (vjlen == 0)
429                return (len);   /* was uncompressed already */
430
431        cp += vjlen;
432        len -= vjlen;
433
434        /*
435         * At this point, cp points to the first byte of data in the
436         * packet.  If we're not aligned on a 4-byte boundary, copy the
437         * data down so the ip & tcp headers will be aligned.  Then back up
438         * cp by the tcp/ip header length to make room for the reconstructed
439         * header (we assume the packet we were handed has enough space to
440         * prepend 128 bytes of header).
441         */
442        if ((intptr_t)cp & 3) {
443                if (len > 0)
444                        BCOPY(cp, ((intptr_t)cp &~ 3), len);
445                cp = (u_char *)((intptr_t)cp &~ 3);
446        }
447        cp -= hlen;
448        len += hlen;
449        BCOPY(hdr, cp, hlen);
450
451        *bufp = cp;
452        return (len);
453}
454
455/*
456 * Uncompress a packet of total length total_len.  The first buflen
457 * bytes are at buf; this must include the entire (compressed or
458 * uncompressed) TCP/IP header.  This procedure returns the length
459 * of the VJ header, with a pointer to the uncompressed IP header
460 * in *hdrp and its length in *hlenp.
461 */
462int
463sl_uncompress_tcp_core(u_char *buf, int buflen, int total_len,
464        u_int type, struct slcompress *comp,
465        u_char **hdrp, u_int *hlenp)
466{
467        register u_char *cp;
468        register uint32_t hlen, changes;
469        register struct tcphdr *th;
470        register struct cstate *cs;
471        register struct ip *ip;
472        register u_int16_t *bp;
473        register u_int vjlen;
474
475        switch (type) {
476
477        case TYPE_UNCOMPRESSED_TCP:
478                ip = (struct ip *) buf;
479                if (ip->ip_p >= MAX_STATES)
480                        goto bad;
481                cs = &comp->rstate[comp->last_recv = ip->ip_p];
482                comp->flags &=~ SLF_TOSS;
483                ip->ip_p = IPPROTO_TCP;
484                /*
485                 * Calculate the size of the TCP/IP header and make sure that
486                 * we don't overflow the space we have available for it.
487                 */
488                hlen = ip->ip_hl << 2;
489                if (hlen + sizeof(struct tcphdr) > buflen)
490                        goto bad;
491                hlen += ((struct tcphdr *)&((char *)ip)[hlen])->th_off << 2;
492                if (hlen > MAX_HDR || hlen > buflen)
493                        goto bad;
494                BCOPY(ip, &cs->cs_ip, hlen);
495                cs->cs_hlen = hlen;
496                INCR(sls_uncompressedin)
497                *hdrp = (u_char *) &cs->cs_ip;
498                *hlenp = hlen;
499                return (0);
500
501        default:
502                goto bad;
503
504        case TYPE_COMPRESSED_TCP:
505                break;
506        }
507        /* We've got a compressed packet. */
508        INCR(sls_compressedin)
509        cp = buf;
510        changes = *cp++;
511        if (changes & NEW_C) {
512                /* Make sure the state index is in range, then grab the state.
513                 * If we have a good state index, clear the 'discard' flag. */
514                if (*cp >= MAX_STATES)
515                        goto bad;
516
517                comp->flags &=~ SLF_TOSS;
518                comp->last_recv = *cp++;
519        } else {
520                /* this packet has an implicit state index.  If we've
521                 * had a line error since the last time we got an
522                 * explicit state index, we have to toss the packet. */
523                if (comp->flags & SLF_TOSS) {
524                        INCR(sls_tossed)
525                        return (-1);
526                }
527        }
528        cs = &comp->rstate[comp->last_recv];
529        hlen = cs->cs_ip.ip_hl << 2;
530        th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen];
531        th->th_sum = htons((*cp << 8) | cp[1]);
532        cp += 2;
533        if (changes & TCP_PUSH_BIT)
534                th->th_flags |= TH_PUSH;
535        else
536                th->th_flags &=~ TH_PUSH;
537
538        switch (changes & SPECIALS_MASK) {
539        case SPECIAL_I:
540                {
541                register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
542                th->th_ack = htonl(ntohl(th->th_ack) + i);
543                th->th_seq = htonl(ntohl(th->th_seq) + i);
544                }
545                break;
546
547        case SPECIAL_D:
548                th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len)
549                                   - cs->cs_hlen);
550                break;
551
552        default:
553                if (changes & NEW_U) {
554                        th->th_flags |= TH_URG;
555                        DECODEU(th->th_urp)
556                } else
557                        th->th_flags &=~ TH_URG;
558                if (changes & NEW_W)
559                        DECODES(th->th_win)
560                if (changes & NEW_A)
561                        DECODEL(th->th_ack)
562                if (changes & NEW_S)
563                        DECODEL(th->th_seq)
564                break;
565        }
566        if (changes & NEW_I) {
567                DECODES(cs->cs_ip.ip_id)
568        } else
569                cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1);
570
571        /*
572         * At this point, cp points to the first byte of data in the
573         * packet.  Fill in the IP total length and update the IP
574         * header checksum.
575         */
576        vjlen = cp - buf;
577        buflen -= vjlen;
578        if (buflen < 0)
579                /* we must have dropped some characters (crc should detect
580                 * this but the old slip framing won't) */
581                goto bad;
582
583        total_len += cs->cs_hlen - vjlen;
584        cs->cs_ip.ip_len = htons(total_len);
585
586        /* recompute the ip header checksum */
587        bp = (u_int16_t *) &cs->cs_ip;
588        cs->cs_ip.ip_sum = 0;
589                for (changes = 0; hlen > 0; hlen -= 2)
590                        changes += *bp++;
591                changes = (changes & 0xffff) + (changes >> 16);
592                changes = (changes & 0xffff) + (changes >> 16);
593        cs->cs_ip.ip_sum = ~ changes;
594
595        *hdrp = (u_char *) &cs->cs_ip;
596        *hlenp = cs->cs_hlen;
597        return vjlen;
598
599bad:
600        comp->flags |= SLF_TOSS;
601        INCR(sls_errorin)
602        return (-1);
603}
Note: See TracBrowser for help on using the repository browser.