⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vjhc.c

📁 用于嵌入式系统的TCP/IP协议栈
💻 C
📖 第 1 页 / 共 2 页
字号:
/***********************************************************************//*                                                                     *//*   Module:  tcp_ip/ppp/vjhc.c                                        *//*   Release: 2001.3                                                   *//*   Version: 2001.0                                                   *//*   Purpose: Van Jacobson TCP/IP header compression                   *//*                                                                     *//*---------------------------------------------------------------------*//*                                                                     *//*               Copyright 2001, Blunk Microsystems                    *//*                      ALL RIGHTS RESERVED                            *//*                                                                     *//*   Licensees have the non-exclusive right to use, modify, or extract *//*   this computer program for software development at a single site.  *//*   This program may be resold or disseminated in executable format   *//*   only. The source code may not be redistributed or resold.         *//*                                                                     *//*---------------------------------------------------------------------*//*                                                                     *//*   Copyright (c) 1989 Regents of the University of California.       *//*   All rights reserved.                                              *//*                                                                     *//*   Redistribution and use in source and binary forms are permitted   *//*   provided that the above copyright notice and this paragraph are   *//*   duplicated in all such forms and that any documentation,          *//*   advertising materials, and other materials related to such        *//*   distribution and use acknowledge that the software was developed  *//*   by the University of California, Berkeley.  The name of the       *//*   University may not be used to endorse or promote products derived *//*   from this software without specific prior written permission.     *//*                                                                     *//*   THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR    *//*   IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED    *//*   WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR        *//*   PURPOSE.                                                          *//*                                                                     *//***********************************************************************/#include "pppp.h"#include <string.h>#if MAX_PPP_INTF/***********************************************************************//* Symbol Definitions                                                  *//***********************************************************************//*** Change Mask Definitions (first byte of compressed packet)*/#define NEW_C   0x40#define NEW_I   0x20#define TCP_PUSH_BIT 0x10#define NEW_S   0x08#define NEW_A   0x04#define NEW_W   0x02#define NEW_U   0x01/*** Reserved, special-case values of above*/#define SPECIAL_I (NEW_S|NEW_W|NEW_U)    /* echoed interactive traffic */#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U)  /* unidirectional data */#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)/*** Flag Value*/#define VJHCF_TOSS  1   /* tossing rcvd frames because of input err *//***********************************************************************//* Macro Definitions                                                   *//***********************************************************************//*** The following macros are used to encode and decode numbers. They all** assume `cp' points to a buffer where the next byte encoded (decoded)** is to be stored (retrieved). Since the decode routines do arithmetic,** they have to convert from and to network byte order.*//*** ENCODE encodes a number that is known to be non-zero. ENCODEZ checks** for zero (zero has to be encoded in the long, 3 byte form).*/#define ENCODE(n) \  { \    if ((ui16)(n) >= 256) \    { \      *cp++ = 0; \      cp[1] = (n); \      cp[0] = (n) >> 8; \      cp += 2; \    } \    else \    { \      *cp++ = (n); \    } \  }#define ENCODEZ(n) \  { \    if ((ui16)(n) >= 256 || (ui16)(n) == 0) \    { \      *cp++ = 0; \      cp[1] = (n); \      cp[0] = (n) >> 8; \      cp += 2; \    } \    else \    { \      *cp++ = (n); \    } \  }/*** DECODEL takes the (compressed) change at byte cp and adds it to the** current value of packet field 'f' (which must be a 4-byte (long)** integer in network byte order). DECODES does the same for a 2-byte** (short) field. DECODEU takes the change at cp and stuffs it into the** (short) field f. 'cp' is updated to point to the next field in the** compressed header.*/#define DECODEL(f) \  { \    if (*cp == 0) \    { \      (f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \      cp += 3; \    } \    else \    { \      (f) = htonl(ntohl(f) + (ui32)*cp++); \    } \  }#define DECODES(f) \  { \    if (*cp == 0) \    { \      (f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \      cp += 3; \    } \    else \    { \      (f) = htons(ntohs(f) + (ui32)*cp++); \    } \  }#define DECODEU(f) \  { \    if (*cp == 0) \    { \      (f) = htons((cp[1] << 8) | cp[2]); \      cp += 3; \    } \    else \    { \      (f) = htons((ui32)*cp++); \    } \  }/***********************************************************************//* Global Function Definitions                                         *//***********************************************************************//***********************************************************************//*   vjhc_init: Initialize the state structure for both the transmit   *//*              and receive halves of a serial line. Must be called    *//*              each time a line is brought up.                        *//*                                                                     *//***********************************************************************/void vjhc_init(struct vjcompress *comp, int rslots, int tslots){  uint i;  struct cstate *tstate = comp->tstate;  /*-------------------------------------------------------------------*/  /* Clean out any old state information.                              */  /*-------------------------------------------------------------------*/  memset(comp, 0, sizeof(struct vjcompress));  /*-------------------------------------------------------------------*/  /* Initialize connection's compression constants.                    */  /*-------------------------------------------------------------------*/  comp->rslot_limit = rslots - 1;  comp->tslot_limit = tslots - 1;  /*-------------------------------------------------------------------*/  /* Link the transmit states into a circular list.                    */  /*-------------------------------------------------------------------*/  for (i = comp->tslot_limit; i > 0; --i)  {    tstate[i].cs_id = i;    tstate[i].cs_next = &tstate[i - 1];  }  tstate[0].cs_id = 0;  tstate[0].cs_next = &tstate[comp->tslot_limit];  comp->last_cs = &tstate[0];  /*-------------------------------------------------------------------*/  /* Make sure we don't accidentally do connection ID compression      */  /* (assumes MAX_STATES < 255).                                       */  /*-------------------------------------------------------------------*/  comp->last_recv = 255;  comp->last_xmit = 255;}/***********************************************************************//* vjhc_compress: Compresses an outbound TCP packet                    *//*                                                                     *//*      Inputs: buf = pointer to packet being compressed               *//*              comp = pointer to line's compression state data        *//*              comp_cid = flags whether connection id is omitted      *//*                                                                     *//*     Returns: Protocol type (PPP_IP_PROTO, PPP_UNCOMP_PROTO, or      *//*              PPP_COMP_PROTO)                                        *//*                                                                     *//***********************************************************************/uint vjhc_compress(NetBuf *buf, struct vjcompress *comp, int comp_cid){  struct cstate *cs = comp->last_cs->cs_next;  Ip *ip = (Ip *)buf->ip_pkt;  uint hlen = ip->ver_len & 0xF;  Tcp *oth;       /* last TCP header */  Tcp *th;        /* current TCP header */  uint deltaS, deltaA;      /* general purpose temporaries */  uint changes = 0;         /* change mask */  ui8 new_seq[16];          /* changes from last to current */  ui8 *cp = new_seq;  /*-------------------------------------------------------------------*/  /* Bail if this is an IP fragment, not a TCP packet, or if the TCP   */  /* packet isn't `compressible' (i.e., ACK isn't set or some other    */  /* control bit is set).                                              */  /*-------------------------------------------------------------------*/  if ((ip->frag_off & htons(0x3FFF)) ||      (ip->protocol != IPT_TCP) ||       buf->length < 40)    return PPP_IP_PROTO;  th = (Tcp *) &((int *)ip)[hlen];  if ((th->flags & (TCPF_SYN | TCPF_FIN | TCPF_RST | TCPF_ACK))      != TCPF_ACK)    return PPP_IP_PROTO;  /*-------------------------------------------------------------------*/  /* Packet is compressible -- we're going to send either a            */  /* COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need to  */  /* locate (or create) the connection state. Special case the most    */  /* recently used connection since it's most likely to be used again  */  /* and we don't have to do any reordering if it's used.              */  /*-------------------------------------------------------------------*/  if ((ip->src_ip != cs->cs_ip.src_ip) ||      (ip->dst_ip != cs->cs_ip.dst_ip) ||      (*(int *) th != ((int *) &cs->cs_ip)[cs->cs_ip.ver_len & 0xF]))  {    /*-----------------------------------------------------------------*/    /* Wasn't the first -- search for it. States are kept in a         */    /* circularly linked list with last_cs pointing to the end of the  */    /* list. The list is kept in LRU order by moving a state to the    */    /* list head whenever it is referenced. Since the list is short    */    /* and, empirically, the connection we want is almost always near  */    /* the front, we locate states via linear search.  If we don't     */    /* find a state for the datagram, the oldest state is (re-)used.   */    /*-----------------------------------------------------------------*/    struct cstate *lcs;    struct cstate *lastcs = comp->last_cs;    do    {      lcs = cs;      cs = cs->cs_next;      if ((ip->src_ip == cs->cs_ip.src_ip)       && (ip->dst_ip == cs->cs_ip.dst_ip)       && (*(int *) th == ((int *) &cs->cs_ip)[cs->cs_ip.ver_len & 0xF]))        goto found;    } while (cs != lastcs);    /*-----------------------------------------------------------------*/    /* Didn't find it -- re-use oldest cstate. Send an uncompressed    */    /* packet that tells the other side what connection number we're   */    /* using for this conversation. Note that since the state list is  */    /* circular, the oldest state points to the newest and we only     */    /* need to set last_cs to update the LRU linkage.                  */    /*-----------------------------------------------------------------*/    comp->last_cs = lcs;    hlen += (th->offset >> 4);    hlen <<= 2;    goto uncompressed;found:    /*-----------------------------------------------------------------*/    /* Found it -- move to the front on the connection list.           */    /*-----------------------------------------------------------------*/    if (lastcs == cs)      comp->last_cs = lcs;    else    {      lcs->cs_next = cs->cs_next;      cs->cs_next = lastcs->cs_next;      lastcs->cs_next = cs;    }  }  /*-------------------------------------------------------------------*/  /* Make sure only what we expect to change changed. The first line   */  /* of the `if' checks the IP protocol version, header length, and    */  /* type of service. The 2nd line checks the "Don't fragment" bit.    */  /* The 3rd line checks the time-to-live and protocol (the protocol   */  /* check is unnecessary but costless). The 4th line checks the TCP   */  /* header length. The 5th line checks IP options, if any. The 6th    */  /* line checks TCP options, if any. If any of these things are       */  /* different between the previous and current datagram, we send the  */  /* current datagram `uncompressed'.                                  */  /*-------------------------------------------------------------------*/  oth = (Tcp *) &((int *)&cs->cs_ip)[hlen];  deltaS = hlen;  deltaA = th->offset >> 4;  hlen += deltaA;  hlen <<= 2;  if (((ui16 *) ip)[0] != ((ui16 *) &cs->cs_ip)[0] ||      ((ui16 *) ip)[3] != ((ui16 *) &cs->cs_ip)[3] ||      ((ui16 *) ip)[4] != ((ui16 *) &cs->cs_ip)[4] ||      th->offset != oth->offset ||      (deltaA > 5 && memcmp(th + 1, oth + 1, (deltaA - 5) << 2)) ||      (deltaS > 5 && memcmp(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)))    goto uncompressed;  /*-------------------------------------------------------------------*/  /* Figure out which of the changing fields changed. The receiver     */  /* expects changes in the order: urgent, window, ack, seq.           */  /*-------------------------------------------------------------------*/  if (th->flags & TCPF_URG)  {    deltaS = ntohs(th->urg_ptr);    ENCODEZ(deltaS);    changes |= NEW_U;  }  else if (th->urg_ptr != oth->urg_ptr)  {    /*-----------------------------------------------------------------*/    /* Argh! URG not set but urp changed -- a sensible implementation  */    /* should never do this but RFC793 doesn't prohibit the change so  */    /* we have to deal with it.                                        */    /*-----------------------------------------------------------------*/    goto uncompressed;  }  deltaS = (ui16)(ntohs(th->window) - ntohs(oth->window));  if (deltaS)  {    ENCODE(deltaS);    changes |= NEW_W;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -