sl_compress.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:15k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* sl_compress.c - TCP/IP header compression routines */
  2. /* Copyright 1990-2000 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*-
  5.  * Copyright (c) 1989, 1993, 1994
  6.  * The Regents of the University of California.  All rights reserved.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  * This product includes software developed by the University of
  19.  * California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  *
  36.  * @(#)slcompress.c 8.2 (Berkeley) 4/16/94
  37.  */
  38. /*
  39.  * Routines to compress and uncompess tcp packets (for transmission
  40.  * over low speed serial lines.
  41.  *
  42.  * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
  43.  * - Initial distribution.
  44.  *
  45.  * static char rcsid[] =
  46.  * "$Header: slcompress.c,v 1.19 89/12/31 08:52:59 van Exp $";
  47.  */
  48. /*
  49. modification history
  50. --------------------
  51. 01f,11mar00,ham  fixed compilation warnings.
  52. 01e,01aug96,vin  merged with bsd4.4. moved to netinet made it universal for 
  53.  PPP as well as CSLIP. 
  54. 01d,16jun95,dzb  header file consolidation.  removed BCOPY.
  55. 01c,27jan95,dab  fixes to DECODE macros.
  56. 01b,13jan95,dzb  prepended "ppp_" due to CSLIP name space conflict.
  57. 01a,21dec94,dab  VxWorks port - first WRS version.
  58.    +dzb  added: path for ppp header files, WRS copyright.
  59. */
  60. #include <vxWorks.h>
  61. #include <sys/types.h>
  62. #include <net/mbuf.h>
  63. #include <net/socketvar.h>
  64. #include <netinet/in.h>
  65. #include <netinet/in_systm.h>
  66. #include <netinet/ip.h>
  67. #include <netinet/tcp.h>
  68. #include <netinet/sl_compress.h>
  69. /*******************************************************************************
  70. *
  71. * sl_compress_init - initialize compressed TCP/IP header stack
  72. *
  73. * This routine initializes a TCP/IP compression structure.  Each
  74. * structure contains an array of connections characterized by the
  75. * most recently reconstructed TCP/IP header.
  76. *
  77. * RETURNS: N/A
  78. *
  79. * NOMANUAL
  80. */
  81. void
  82. sl_compress_init(comp)
  83. struct slcompress *comp;
  84. {
  85. register u_int i;
  86. register struct cstate *tstate = comp->tstate;
  87. bzero((char *)comp, sizeof(*comp));
  88. for (i = MAX_STATES - 1; i > 0; --i) {
  89. tstate[i].cs_id = i;
  90. tstate[i].cs_next = &tstate[i - 1];
  91. }
  92. tstate[0].cs_next = &tstate[MAX_STATES - 1];
  93. tstate[0].cs_id = 0;
  94. comp->last_cs = &tstate[0];
  95. comp->last_recv = 255;
  96. comp->last_xmit = 255;
  97. comp->flags = SLF_TOSS;
  98. }
  99. /*******************************************************************************
  100. *
  101. * sl_compress_tcp - compress the TCP/IP header in the given mbuf chain
  102. *
  103. * RETURNS: The converted protocol version of the given mbuf chain.
  104. *
  105. * NOMANUAL
  106. */
  107. u_int
  108. sl_compress_tcp(m, ip, comp, compress_cid)
  109. struct mbuf *m;
  110. register struct ip *ip;
  111. struct slcompress *comp;
  112. int compress_cid;
  113. {
  114. register struct cstate *cs = comp->last_cs->cs_next;
  115. register u_int hlen = ip->ip_hl;
  116. register struct tcphdr *oth;
  117. register struct tcphdr *th;
  118. register u_int deltaS, deltaA;
  119. register u_int changes = 0;
  120. u_char new_seq[16];
  121. register u_char *cp = new_seq;
  122. /*
  123.  * Bail if this is an IP fragment or if the TCP packet isn't
  124.  * `compressible' (i.e., ACK isn't set or some other control bit is
  125.  * set).  (We assume that the caller has already made sure the
  126.  * packet is IP proto TCP).
  127.  */
  128. if ((ip->ip_off & htons(0x3fff)) || m->m_len < 40)
  129. return (TYPE_IP);
  130. th = (struct tcphdr *)&((int *)ip)[hlen];
  131. if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK)
  132. return (TYPE_IP);
  133. /*
  134.  * Packet is compressible -- we're going to send either a
  135.  * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way we need
  136.  * to locate (or create) the connection state.  Special case the
  137.  * most recently used connection since it's most likely to be used
  138.  * again & we don't have to do any reordering if it's used.
  139.  */
  140. INCR(sls_packets)
  141. if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr ||
  142.     ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr ||
  143.     *(int *)th != ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl]) {
  144. /*
  145.  * Wasn't the first -- search for it.
  146.  *
  147.  * States are kept in a circularly linked list with
  148.  * last_cs pointing to the end of the list.  The
  149.  * list is kept in lru order by moving a state to the
  150.  * head of the list whenever it is referenced.  Since
  151.  * the list is short and, empirically, the connection
  152.  * we want is almost always near the front, we locate
  153.  * states via linear search.  If we don't find a state
  154.  * for the datagram, the oldest state is (re-)used.
  155.  */
  156. register struct cstate *lcs;
  157. register struct cstate *lastcs = comp->last_cs;
  158. do {
  159. lcs = cs; cs = cs->cs_next;
  160. INCR(sls_searches)
  161. if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr
  162.     && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr
  163.     && *(int *)th == ((int *)&cs->cs_ip)[cs->cs_ip.ip_hl])
  164. goto found;
  165. } while (cs != lastcs);
  166. /*
  167.  * Didn't find it -- re-use oldest cstate.  Send an
  168.  * uncompressed packet that tells the other side what
  169.  * connection number we're using for this conversation.
  170.  * Note that since the state list is circular, the oldest
  171.  * state points to the newest and we only need to set
  172.  * last_cs to update the lru linkage.
  173.  */
  174. INCR(sls_misses)
  175. comp->last_cs = lcs;
  176. hlen += th->th_off;
  177. hlen <<= 2;
  178. goto uncompressed;
  179. found:
  180. /*
  181.  * Found it -- move to the front on the connection list.
  182.  */
  183. if (cs == lastcs)
  184. comp->last_cs = lcs;
  185. else {
  186. lcs->cs_next = cs->cs_next;
  187. cs->cs_next = lastcs->cs_next;
  188. lastcs->cs_next = cs;
  189. }
  190. }
  191. /*
  192.  * Make sure that only what we expect to change changed. The first
  193.  * line of the `if' checks the IP protocol version, header length &
  194.  * type of service.  The 2nd line checks the "Don't fragment" bit.
  195.  * The 3rd line checks the time-to-live and protocol (the protocol
  196.  * check is unnecessary but costless).  The 4th line checks the TCP
  197.  * header length.  The 5th line checks IP options, if any.  The 6th
  198.  * line checks TCP options, if any.  If any of these things are
  199.  * different between the previous & current datagram, we send the
  200.  * current datagram `uncompressed'.
  201.  */
  202. oth = (struct tcphdr *)&((int *)&cs->cs_ip)[hlen];
  203. deltaS = hlen;
  204. hlen += th->th_off;
  205. hlen <<= 2;
  206. if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] ||
  207.     ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] ||
  208.     ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] ||
  209.     th->th_off != oth->th_off ||
  210.     (deltaS > 5 &&
  211.      BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) ||
  212.     (th->th_off > 5 &&
  213.      BCMP(th + 1, oth + 1, (th->th_off - 5) << 2)))
  214. goto uncompressed;
  215. /*
  216.  * Figure out which of the changing fields changed.  The
  217.  * receiver expects changes in the order: urgent, window,
  218.  * ack, seq (the order minimizes the number of temporaries
  219.  * needed in this section of code).
  220.  */
  221. if (th->th_flags & TH_URG) {
  222. deltaS = ntohs(th->th_urp);
  223. ENCODEZ(deltaS);
  224. changes |= NEW_U;
  225. } else if (th->th_urp != oth->th_urp)
  226. /* argh! URG not set but urp changed -- a sensible
  227.  * implementation should never do this but RFC793
  228.  * doesn't prohibit the change so we have to deal
  229.  * with it. */
  230.  goto uncompressed;
  231. if ((deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win)))) {
  232. ENCODE(deltaS);
  233. changes |= NEW_W;
  234. }
  235. if ((deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack))) {
  236. if (deltaA > 0xffff)
  237. goto uncompressed;
  238. ENCODE(deltaA);
  239. changes |= NEW_A;
  240. }
  241. if ((deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq))) {
  242. if (deltaS > 0xffff)
  243. goto uncompressed;
  244. ENCODE(deltaS);
  245. changes |= NEW_S;
  246. }
  247. switch(changes) {
  248. case 0:
  249. /*
  250.  * Nothing changed. If this packet contains data and the
  251.  * last one didn't, this is probably a data packet following
  252.  * an ack (normal on an interactive connection) and we send
  253.  * it compressed.  Otherwise it's probably a retransmit,
  254.  * retransmitted ack or window probe.  Send it uncompressed
  255.  * in case the other side missed the compressed version.
  256.  */
  257. if (ip->ip_len != cs->cs_ip.ip_len &&
  258.     ntohs(cs->cs_ip.ip_len) == hlen)
  259. break;
  260. /* (fall through) */
  261. case SPECIAL_I:
  262. case SPECIAL_D:
  263. /*
  264.  * actual changes match one of our special case encodings --
  265.  * send packet uncompressed.
  266.  */
  267. goto uncompressed;
  268. case NEW_S|NEW_A:
  269. if (deltaS == deltaA &&
  270.     deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
  271. /* special case for echoed terminal traffic */
  272. changes = SPECIAL_I;
  273. cp = new_seq;
  274. }
  275. break;
  276. case NEW_S:
  277. if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
  278. /* special case for data xfer */
  279. changes = SPECIAL_D;
  280. cp = new_seq;
  281. }
  282. break;
  283. }
  284. deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id);
  285. if (deltaS != 1) {
  286. ENCODEZ(deltaS);
  287. changes |= NEW_I;
  288. }
  289. if (th->th_flags & TH_PUSH)
  290. changes |= TCP_PUSH_BIT;
  291. /*
  292.  * Grab the cksum before we overwrite it below.  Then update our
  293.  * state with this packet's header.
  294.  */
  295. deltaA = ntohs(th->th_sum);
  296. BCOPY(ip, &cs->cs_ip, hlen);
  297. /*
  298.  * We want to use the original packet as our compressed packet.
  299.  * (cp - new_seq) is the number of bytes we need for compressed
  300.  * sequence numbers.  In addition we need one byte for the change
  301.  * mask, one for the connection id and two for the tcp checksum.
  302.  * So, (cp - new_seq) + 4 bytes of header are needed.  hlen is how
  303.  * many bytes of the original packet to toss so subtract the two to
  304.  * get the new packet size.
  305.  */
  306. deltaS = cp - new_seq;
  307. cp = (u_char *)ip;
  308. if (compress_cid == 0 || comp->last_xmit != cs->cs_id) {
  309. comp->last_xmit = cs->cs_id;
  310. hlen -= deltaS + 4;
  311. cp += hlen;
  312. *cp++ = changes | NEW_C;
  313. *cp++ = cs->cs_id;
  314. } else {
  315. hlen -= deltaS + 3;
  316. cp += hlen;
  317. *cp++ = changes;
  318. }
  319. m->m_len -= hlen;
  320. m->m_data += hlen;
  321. *cp++ = deltaA >> 8;
  322. *cp++ = deltaA;
  323. BCOPY(new_seq, cp, deltaS);
  324. INCR(sls_compressed)
  325. return (TYPE_COMPRESSED_TCP);
  326. /*
  327.  * Update connection state cs & send uncompressed packet ('uncompressed'
  328.  * means a regular ip/tcp packet but with the 'conversation id' we hope
  329.  * to use on future compressed packets in the protocol field).
  330.  */
  331. uncompressed:
  332. BCOPY(ip, &cs->cs_ip, hlen);
  333. ip->ip_p = cs->cs_id;
  334. comp->last_xmit = cs->cs_id;
  335. return (TYPE_UNCOMPRESSED_TCP);
  336. }
  337. /*******************************************************************************
  338. *
  339. * sl_uncompress_tcp - uncompress the TCP/IP header in the given buffer.
  340. *
  341. * RETURNS: The length of the uncompressed TCP/IP header, 0 if ERROR.
  342. *
  343. * NOMANUAL
  344. */
  345. int
  346. sl_uncompress_tcp(bufp, len, type, comp)
  347. u_char **bufp;
  348. int len;
  349. u_int type;
  350. struct slcompress *comp;
  351. {
  352. register u_char *cp;
  353. register u_int hlen, changes;
  354. register struct tcphdr *th;
  355. register struct cstate *cs;
  356. register struct ip *ip;
  357. switch (type) {
  358. case TYPE_UNCOMPRESSED_TCP:
  359. ip = (struct ip *) *bufp;
  360. if (ip->ip_p >= MAX_STATES)
  361. goto bad;
  362. cs = &comp->rstate[comp->last_recv = ip->ip_p];
  363. comp->flags &=~ SLF_TOSS;
  364. ip->ip_p = IPPROTO_TCP;
  365. hlen = ip->ip_hl;
  366. hlen += ((struct tcphdr *)&((int *)ip)[hlen])->th_off;
  367. hlen <<= 2;
  368. BCOPY(ip, &cs->cs_ip, hlen);
  369. cs->cs_ip.ip_sum = 0;
  370. cs->cs_hlen = hlen;
  371. INCR(sls_uncompressedin)
  372. return (len);
  373. default:
  374. goto bad;
  375. case TYPE_COMPRESSED_TCP:
  376. break;
  377. }
  378. /* We've got a compressed packet. */
  379. INCR(sls_compressedin)
  380. cp = *bufp;
  381. changes = *cp++;
  382. if (changes & NEW_C) {
  383. /* Make sure the state index is in range, then grab the state.
  384.  * If we have a good state index, clear the 'discard' flag. */
  385. if (*cp >= MAX_STATES)
  386. goto bad;
  387. comp->flags &=~ SLF_TOSS;
  388. comp->last_recv = *cp++;
  389. } else {
  390. /* this packet has an implicit state index.  If we've
  391.  * had a line error since the last time we got an
  392.  * explicit state index, we have to toss the packet. */
  393. if (comp->flags & SLF_TOSS) {
  394. INCR(sls_tossed)
  395. return (0);
  396. }
  397. }
  398. cs = &comp->rstate[comp->last_recv];
  399. hlen = cs->cs_ip.ip_hl << 2;
  400. th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen];
  401. th->th_sum = htons((*cp << 8) | cp[1]);
  402. cp += 2;
  403. if (changes & TCP_PUSH_BIT)
  404. th->th_flags |= TH_PUSH;
  405. else
  406. th->th_flags &=~ TH_PUSH;
  407. switch (changes & SPECIALS_MASK) {
  408. case SPECIAL_I:
  409. {
  410. register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
  411. th->th_ack = htonl(ntohl(th->th_ack) + i);
  412. th->th_seq = htonl(ntohl(th->th_seq) + i);
  413. }
  414. break;
  415. case SPECIAL_D:
  416. th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len)
  417.    - cs->cs_hlen);
  418. break;
  419. default:
  420. if (changes & NEW_U) {
  421. th->th_flags |= TH_URG;
  422. DECODEU(th->th_urp)
  423. } else
  424. th->th_flags &=~ TH_URG;
  425. if (changes & NEW_W)
  426. DECODES(th->th_win)
  427. if (changes & NEW_A)
  428. DECODEL(th->th_ack)
  429. if (changes & NEW_S)
  430. DECODEL(th->th_seq)
  431. break;
  432. }
  433. if (changes & NEW_I) {
  434. DECODES(cs->cs_ip.ip_id)
  435. } else
  436. cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1);
  437. /*
  438.  * At this point, cp points to the first byte of data in the
  439.  * packet.  If we're not aligned on a 4-byte boundary, copy the
  440.  * data down so the ip & tcp headers will be aligned.  Then back up
  441.  * cp by the tcp/ip header length to make room for the reconstructed
  442.  * header (we assume the packet we were handed has enough space to
  443.  * prepend 128 bytes of header).  Adjust the length to account for
  444.  * the new header & fill in the IP total length.
  445.  */
  446. len -= (cp - *bufp);
  447. if (len < 0)
  448. /* we must have dropped some characters (crc should detect
  449.  * this but the old slip framing won't) */
  450. goto bad;
  451. if ((int)cp & 3) {
  452. if (len > 0)
  453. (void) ovbcopy(cp, (caddr_t)((int)cp &~ 3), len);
  454. cp = (u_char *)((int)cp &~ 3);
  455. }
  456. cp -= cs->cs_hlen;
  457. len += cs->cs_hlen;
  458. cs->cs_ip.ip_len = htons(len);
  459. BCOPY(&cs->cs_ip, cp, cs->cs_hlen);
  460. *bufp = cp;
  461. /* recompute the ip header checksum */
  462. {
  463. register u_short *bp = (u_short *)cp;
  464. for (changes = 0; hlen > 0; hlen -= 2)
  465. changes += *bp++;
  466. changes = (changes & 0xffff) + (changes >> 16);
  467. changes = (changes & 0xffff) + (changes >> 16);
  468. ((struct ip *)cp)->ip_sum = ~ changes;
  469. }
  470. return (len);
  471. bad:
  472. comp->flags |= SLF_TOSS;
  473. INCR(sls_errorin)
  474. return (0);
  475. }