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

📄 vjcomp.c

📁 WinCE5.0部分核心源码
💻 C
📖 第 1 页 / 共 3 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//

/*
    * Portions 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.
    */

/*****************************************************************************
* 
*
*   @doc
*   @module vjcomp.c | Van Jacobsen TCP/IP Header Compression 
*
*   Date:   11-13-95
*
*   @comm   Modified originial VJ Header Compression Code for ndis buffer
*           input. Performed cleanup on general structure and comments for
*           functional clarity.
*
*/

//  Include Files

#include "windows.h"
#include "cclib.h"
#include "memory.h"
#include "cxport.h"

// VJ Compression Include Files
#include "winsock.h"
#include "ndis.h"
#include "ndiswan.h"
#include "tcpip.h"
#include "vjcomp.h"

// PPP Include Files

#include "protocol.h"
#include "ppp.h"
#include "lcp.h"
#include "ipcp.h"
#include "mac.h"
#include "ip_intf.h"
#include "ras.h"


// TCP and IP Header Length Access Macros
// 
// Note: Both macros incorporate a times 4 factor for int to byte conversion.
//       All header arithmetic is always done as bytes.

#define IpHdrLen( x )           ((((x)->iph_verlen) & 0x0f) << 2)

// Bits in first octet of compressed packet 
// flag bits for what changed in a 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 
//
// Echoed interactive traffic 

#define SPECIAL_I               ( NEW_S | NEW_W | NEW_U )     

// Unidirectional data 

#define SPECIAL_D               ( NEW_S | NEW_A | NEW_W | NEW_U )  
#define SPECIALS_MASK           ( NEW_S | NEW_A | NEW_W | NEW_U )

// Debug macro to help pretty-print changes
#define DEBUG_OUTPUT_CHANGES(c) \
	((c) & NEW_C        ? 'C' : ' '), \
	((c) & NEW_I        ? 'I' : ' '), \
	((c) & TCP_PUSH_BIT ? 'P' : ' '), \
	((c) & NEW_S        ? 'S' : ' '), \
	((c) & NEW_A        ? 'A' : ' '), \
	((c) & NEW_W        ? 'W' : ' '), \
	((c) & NEW_U        ? 'U' : ' ')

static PBYTE
EncodeValue(
    IN  PBYTE     pEncode,
	IN  USHORT    value)
{
	if (1 <= value && value <= 255)
	{
		*pEncode++ = (BYTE)value;
	}
	else
	{
		pEncode[0] = 0;
		pEncode[1] = (BYTE)(value >> 8); // MSB first
		pEncode[2] = (BYTE)(value);      // LSB second
		pEncode += 3;
	}
	return pEncode;
}

#define ENCODE( n )  cp = EncodeValue(cp, (n))
#define ENCODEZ( n ) cp = EncodeValue(cp, (n))

static USHORT
CompressedValueGet(
	IN OUT PBYTE *pcp,
	IN     PBYTE  end)
//
//  Value may be encoded as one byte if it is in range 1-255.
//  If it is >255, then it will be encoded as 0x00 followed by 2 bytes.
//
{
	USHORT Value;
	PBYTE  cp = *pcp;
	
	if (cp >= end)
	{
		// No more data available, bad packet.
		// We tell the caller of the bad packet by setting cp
		// beyond the end of the data.
		Value = 0;
		cp = end + 1;
	}
	else
	{
		Value = *cp++;
		if (Value == 0)
		{
			// Value is in next 2 bytes
			if ((cp + 1) < end)
				Value = (cp[0] << 8) | cp[1];

			cp += 2;
		}
		*pcp = cp;
	}

	return Value;
}

static ULONG 
NetLongAdd(
	IN     ULONG  OldValue,
	IN     USHORT Addend)
//
//  Add a USHORT (in host byte order) to a ULONG (in net byte order).
//  Return the sum as a ULONG (in net byte order).
//
{
	ULONG  NewValue;

	OldValue = ntohl(OldValue);
	NewValue = OldValue + Addend;
	return htonl(NewValue);
}

static ULONG
NetLongAddCompressed(
	IN OUT PBYTE *pcp,
	IN     PBYTE  end,
	IN     ULONG  OldValue)
{
	USHORT  Addend;

	Addend = CompressedValueGet(pcp, end);
	return NetLongAdd(OldValue, Addend);
}

static USHORT 
NetShortAdd(
	IN     USHORT OldValue,
	IN     USHORT Addend)
//
//  Add a USHORT (in host byte order) to a USHORT (in net byte order).
//  Return the sum as a USHORT (in net byte order).
//
{
	USHORT  NewValue;

	OldValue = ntohs(OldValue);
	NewValue = OldValue + Addend;
	return htons(NewValue);
}

static USHORT
NetShortAddCompressed(
	IN OUT PBYTE *pcp,
	IN     PBYTE  end,
	IN     USHORT OldValue)
{
	USHORT  Addend;

	Addend = CompressedValueGet(pcp, end);
	return NetShortAdd(OldValue, Addend);
}

static  BYTE
TcpHdrLen( struct TCPHeader *arg )
//
//	Return the length in bytes of the TCP header.
//
{
	BYTE	bHeaderLength;

	// Flags is a USHORT field that looks like:
	//
	//     4 bit header length in DWORDS
	//     6 bits reserved
	//     6 bits URG/ACK/PSH/RST/SYN/FIN
	//
	bHeaderLength = *(PBYTE)(&arg->tcp_flags);
	bHeaderLength = (bHeaderLength & 0xF0) >> 2;

	return bHeaderLength;
}

//   A.2  Compression
//
//   This routine looks daunting but isn't really.  The code splits into four
//   approximately equal sized sections:  The first quarter manages a
//   circularly linked, least-recently-used list of `active' TCP
//   connections./47/  The second figures out the sequence/ack/window/urg
//   changes and builds the bulk of the compressed packet.  The third handles
//   the special-case encodings.  The last quarter does packet ID and
//   connection ID encoding and replaces the original packet header with the
//   compressed header.
//
//   The arguments to this routine are a pointer to a packet to be
//   compressed, a pointer to the compression state data for the serial line,
//   and a flag which enables or disables connection id (C bit) compression.
//
//   Compression is done `in-place' so, if a compressed packet is created,
//   both the start address and length of the incoming packet (the off and
//   len fields of m) will be updated to reflect the removal of the original
//   header and its replacement by the compressed header.  If either a
//   compressed or uncompressed packet is created, the compression state is
//   updated.  This routines returns the packet type for the transmit framer
//   (TYPE_IP, TYPE_UNCOMPRESSED_TCP or TYPE_COMPRESSED_TCP).
//
//   Because 16 and 32 bit arithmetic is done on various header fields, the
//   incoming IP packet must be aligned appropriately (e.g., on a SPARC, the
//   IP header is aligned on a 32-bit boundary).  Substantial changes would
//   have to be made to the code below if this were not true (and it would
//   probably be cheaper to byte copy the incoming header to somewhere
//   correctly aligned than to make those changes).
//
//   Note that the outgoing packet will be aligned arbitrarily (e.g., it
//   could easily start on an odd-byte boundary).
//
//   ----------------------------
//    47. The two most common operations on the connection list are a `find'
//   that terminates at the first entry (a new packet for the most recently
//   used connection) and moving the last entry on the list to the head of
//   the list (the first packet from a new connection).  A circular list
//   efficiently handles these two operations.
//   ----------------------------

USHORT
sl_compress_tcp(
	IN  PNDIS_WAN_PACKET  pPacket, 
	IN  slcompress_t     *comp)
{
	cstate_t            *cs;                    // compression state pntr
	struct IPHeader     *ip;                    // current ip header 
	struct TCPHeader    *tcp;                   // current TCP header 
	BYTE                ipLen;                  // ip header length
	BYTE                tcpLen;                 // tcp header length
	BYTE                totalLen;               // total length of headers
	u_int               orig_xsum;              // original checksum
	u_int               newHdrLen;              // new header length
	u_int               changes = 0;            // change mask 
	BYTE                new_seq[ 16 ];          // last to current changes
	BYTE                *cp = new_seq;
	u_int               deltaS;                 // general purpose vars 
	u_int               deltaA;                 // general purpose vars 
	u_int               deltaW;                 // general purpose vars 

	memset(new_seq, 0, 16);

    if (pPacket->CurrentLength < sizeof(TCPHeader) + sizeof(IPHeader))
    {
		// Too small to be a TCP packet, no compression possible
        return PPP_PROTOCOL_IP;
    }

    // Init headers pointers and lengths

    ip     = (struct IPHeader *)pPacket->CurrentBuffer;
    ipLen  = IpHdrLen(ip);

	//
	// Check the protocol type to confirm that it is TCP
	// If not TCP, don't try to do TCP header compression!
	//
	if (ip->iph_protocol != 6) // 6==PROTOCOL_TCP
	{
		return PPP_PROTOCOL_IP;
	}

    tcp    = (struct TCPHeader *)((BYTE *)ip + ipLen);
    tcpLen = TcpHdrLen(tcp); 

    totalLen = ipLen + tcpLen;

    // Exit if this is an ip fragment

    if (ip->iph_offset & 0xff3f)
    {
		DEBUGMSG(ZONE_VJ, (L"PPP: TX VJ cannot compress - fragmented (offset=%x)\n", ip->iph_offset));
        return PPP_PROTOCOL_IP;
    }

    // Exit if the TCP packet isn't `compressible' i.e.the ACK isn't set 
    // or some other control bit is set.

    if ((tcp->tcp_flags & 
        (TCP_FLAG_SYN | TCP_FLAG_FIN | TCP_FLAG_RST | TCP_FLAG_ACK)) 
        != TCP_FLAG_ACK)
    {
		DEBUGMSG(ZONE_VJ, (L"PPP: TX VJ cannot compress - tcp_flags=0x%x\n", tcp->tcp_flags));
        return PPP_PROTOCOL_IP;
    }

    // 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 & we don't have to do any reordering if it's used.
    // Compare the ip/tcp src and dest fields.

    cs = comp->last_cs->cs_next;                // access compression state

    if ((ip->iph_src   != cs->cs_ip.iph_src   ) ||
        (ip->iph_dest  != cs->cs_ip.iph_dest  ) ||
        (tcp->tcp_src  != cs->cs_tcp->tcp_src ) ||
        (tcp->tcp_dest != cs->cs_tcp->tcp_dest) )
    {
        // 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 head of the list 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.
             
        cstate_t *lcs;
        cstate_t *lastcs = comp->last_cs;

        do 
        {
            lcs = cs;
            cs = cs->cs_next;

            // Compare connection data

            if ((ip->iph_src   == cs->cs_ip.iph_src   ) && 
                (ip->iph_dest  == cs->cs_ip.iph_dest  ) && 
                (tcp->tcp_src  == cs->cs_tcp->tcp_src ) &&
                (tcp->tcp_dest == cs->cs_tcp->tcp_dest) )
            {

                goto found;
            }

        } 
        while(cs != lastcs);

        // Didn't find it -- re-use oldest cstate_t. 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;
		DEBUGMSG(ZONE_VJ, (L"PPP: TX VJ slot %x No previous cstate, uncompressed\n", cs->cs_id));
        goto uncompressed;


found:  //----------------------------------------------------------------------
        // Found State -- move to the front on the connection list. 

        if (lastcs == cs)
        {
            comp->last_cs = lcs;
        }
        else 

⌨️ 快捷键说明

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