/*  slip.c  (c) Steve Adam 1995         steve@netinfo.com.au
 *
 *          Module contains functions for input/output
 *          of slip packets.  Slip conversions are performed
 *          here.  Note that both of these functions are
 *          interruptable.  That is, they do what work they
 *          can then return.  If called again later, they
 *          continue at the same point.
 *
 *          The output queue functions are also here.
 *
 *          Based on RFC1055
 */

#include <stdio.h>      /* Included for NULL.  Might change that later...   */
#include <tos.h>
#include <string.h>
#include <device.h>
#include <stdlib.h>

#include "globdefs.h"
#include "globdecl.h"

extern DEV_LIST *bdev;


/*extern void	*memcpy (void *, const void *, unsigned long);*/
extern int	memcmp (const void *, const void *, unsigned long);
extern void    *memset( void *ptr, int val, size_t len );
/*extern void	*bzero (void *, unsigned long);*/


/* SLIP special character codes
 */
#define END             0300    /* indicates end of packet */
#define ESC             0333    /* indicates byte stuffing */
#define ESC_END         0334    /* ESC ESC_END means END data byte */
#define ESC_ESC         0335    /* ESC ESC_ESC means ESC data byte */

/* Bits in first octet of compressed packet */
#define NEW_C	0x40	/* flag bits for what changed in a packet */
#define NEW_I	0x20
#define NEW_S	0x08
#define NEW_A	0x04
#define NEW_W	0x02
#define NEW_U	0x01

#define TCP_PUSH_BIT 0x10

/* 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)


#define BCMP(p1,p2,n)		memcmp((p2), (p1), (uint32)(n))
#define BCOPY(p1,p2,n)		memcpy((p2), (p1), (uint32)(n))
#define ovbcopy(p1,p2,n)	memcpy((p2), (p1), (uint32)(n))

extern struct slip *myslip;
extern struct slcompress *comp;
extern struct cstate mytstate[MAX_STATES];
extern struct cstate myrstate[MAX_STATES];

octet
slc_type (b)
	GPKT *b;
{
	/*struct ip_header *ip;
	unsigned char c;
	
	ip = (struct ip_header *) b->pip;
	
	c = ip->ver & 0x3;*/
	
	/*octet c = b->fp[0] & 0xf0;  was pip */
	
	octet c = *b->fp & 0xf0; 
	
	/*printf("%s\r\n",&b);*/

	if (c == (IP_VERSION << 4))
			return TYPE_IP;
	if (c & 0x80)
		{
			return TYPE_COMPRESSED_TCP;
		}
	if (c == TYPE_UNCOMPRESSED_TCP)
		{
			return TYPE_UNCOMPRESSED_TCP;
		}

	return TYPE_ERROR;
}

/*  slip_in()
 *
 *      Receives packet data from the serial port and adds it to
 *  the data buffer in the packet structure.  If no packet is
 *  currently allocated, then allocate one.  If no data is
 *  available from the serial port, then return, but REMEMBER
 *  where we're up to so we can continue later.  When a packet
 *  has been completely received, pass it to ip_in() for
 *  further processing.  We don't care what's in the packets,
 *  but if the length is less than an IP header, throw it away.
 *  Do SLIP special character processing in an interruptable way.
 *  (ie: We can return from this function in the middle of things..)
 */

void slip_in(void)
{
    static GPKT *inpkt = (GPKT *)NULL;  /* Packet being read            */
    static char *nextin = (char *)NULL; /* Pointer to next buffer octet */
    /*static int esc_read = FALSE;        Was ESC the last byte read?  */
    static uint16 buf_avail;            /* Max number of chars to read  */
    static uint16 bufsize = 0;          /* Current buffer size          */

    int newch;  /* New character read from serial port              */
    uint16 len; /* Length of packet received.  (Calculated later)   */
    char *mblk;

/*new_packet:*/

    if (inpkt == (GPKT *)NULL) {    /* No current packet, allocate one  */
        bufsize = buf_avail = cfg.mtu;
        inpkt = allocate_packet(bufsize + 68);
        if (inpkt == (GPKT *)NULL)  /* What, no memory? LOG_IT          */
            return;                 /* Try again later                  */

        nextin = inpkt->pip;        /* Init pointer to start of buffer  */
        /*esc_read = FALSE;            Init ESC state flag              */
    }
    else {      /* Check to see if we've about to overflow our buffer   */
                /* If we are, then realloc() to a larger buffer.  This  */
                /* *will* force a copy, but "Be liberal etc."           */
                /* Hopefully this will never happen. (Yeah, right!)     */
        if (buf_avail == 0) {
            buf_avail = cfg.mtu;            /* reset buf_avail      */
            len = bufsize;                  /* Save old size        */
            bufsize += buf_avail;           /* increase bufsize     */
            mblk = KRrealloc(inpkt->pip, (long)bufsize + 128); /* was 68 */
            if (mblk == (char *)NULL)
                ;   /* Ooops, out of memory. LOG_IT and worry later...  */
            else
                inpkt->fp = inpkt->pip = mblk;

            nextin = &inpkt->pip[len];  /* Reinit data pointer          */
        }
    }

    while (TRUE) {      /* Loop till no more data or packet complete    */
        if (CharAvailable(bdev) == FALSE)	/* ATARI: If no serial char waiting */
            	return;             /* then return.  Try again later        */

        newch = PortGetByte(bdev) & 0xff;/*  ATARI: get serial byte.  The */
                                        /* 0xff mask is just in case.   */
                                        
        /*if (myslip.flags & SLF_ESC) { */    /* Last char was ESC, so this one is special    */
           /*esc_read = FALSE;                        Clear ESC state      */
				/*myslip.flags &= ~SLF_ESC;*/

	        switch(newch) 
	            {
	            case ESC_END:
       				*nextin++ = (myslip->flags & SLF_ESC) ? END : newch;
					myslip->flags &= ~SLF_ESC;
                	/*esc_read = FALSE;*/
	                /**nextin++ = (char)END;*/
	                --buf_avail;
	                continue;

	            case ESC_ESC:
	   				*nextin++ = (myslip->flags & SLF_ESC) ? ESC : newch;
					myslip->flags &= ~SLF_ESC;
	            	/*esc_read = FALSE;*/
	                /* *nextin++ = (char)ESC;*/
	                --buf_avail;
	                continue;

	            /* If we fall through to default: then an inappropriate character
	             * followed the ESC character.  This an error condition. LOG_IT
	             * RFC1055 suggested copying the next character as is.  I don't
	             * have any better ideas so...  (Should we discard packet?)
	             */
	           /* default:
	                *nextin++ = (char)newch;
	                --buf_avail;
	                continue;
	            }*/
        /*}

        switch(newch) {*/

			        case END:                       /* End of current packet            */
        			    len = (uint16)(nextin - inpkt->pip);  /* pkt length.                      */

						if (len)
							{
					            inpkt->ip_len = len;                /* Set packet length    */
	
    					        /* realloc should return same block if newsize < oldsize    */
   						        /* so this operation should *NOT* force a memory copy       */
					            /* The extra 68 bytes is to allow a ICMP error packet to be */
		    			        /* constructed from this pkt if necessary.  68 bytes is the */
		    			        /* most such a packet would need (max ip header + 8 bytes)  */

		        			    inpkt->pip=inpkt->fp = KRrealloc(inpkt->pip, (long)len + 128); /*was 68 */

								uncompress(inpkt, myslip);
									
								if (myslip->flags & SLF_TOSS)
									{
										printf("deleting packet\r\n");
								        delete_packet(inpkt, EI_SUM);  /* This is how we `ignore' packets  */
								        return;
									}

								/*printf("back from uncompress and delete test\r\n");*/

								ip_in(inpkt);                   /* Pass the packet to IP    */
	
								/*printf("back from ip_in\r\n");*/
	
					            inpkt = (GPKT *)NULL;           /* Clear our `state'        */

						        bufsize = buf_avail = cfg.mtu;
						        inpkt = allocate_packet(bufsize + 68);
						        if (inpkt == (GPKT *)NULL)   /*What, no memory? LOG_IT          */
			    			        return;                  /*Try again later                  */
						        nextin = inpkt->pip;         /*Init pointer to start of buffer  */

								/*printf("before goto new packet \r\n");*/
							
								goto new_packet;
							   	/*return;                     And give everyone else a go  */
		       				}
           				 break;

			        case ESC:       /* An escape character means skip to the next char  */
    			        /*esc_read = TRUE;             But set ESC state TRUE first...  */
						myslip->flags |= SLF_ESC;
			            break;

        			default:                /* Default case, just copy the char.        */
						myslip->flags &= ~SLF_ESC;
        			    *nextin++ = (char)newch;
        			    --buf_avail;
       				     break;
       			 }
        
        
new_packet:
;
    }
	/*return;*/
    /* This function should never exit here */
}


/*  output_packet()
 *
 *      This function adds a completely processed IP packet to
 *  an output queue.  The queue is just a chain of GPKT's.  They
 *  are chained using the `.pnout' pointer of GPKT.  NULL means
 *  end of list.  New packets are always added to the end of the
 *  list and and later dequeued (by get_outpacket()) from the front.
 *
 *      This function also calls slip_out().  This should always
 *  happen when a packet goes on the queue anyway.  slip_out()
 *  can still be called seperately from elsewhere, though.
 */

static GPKT *outqueue = (GPKT *)NULL;   /* Initial value must be NULL       */

void output_packet(GPKT *opkt)
{
    GPKT *endqueue = outqueue;

/*	extern int pktfd;
    if (pktfd <= 0)
		pktfd = Fcreate("pkt.log", 0);

    Fwrite(pktfd, 2L, &opkt->ip_len);
    Fwrite(pktfd, (long)opkt->ip_len, opkt->pip);
*/
    opkt->next = (GPKT *)NULL; /* It should have been NULL anyway but....  */

    if (outqueue == (GPKT *)NULL) {  /* Queue was empty                      */
        outqueue = opkt;
    }
    else {
        while (endqueue->next != (GPKT *)NULL) /* advance to end of chain   */
            endqueue = endqueue->next;

        endqueue->next = opkt;
    }

	/*printf("in output packet right before slip_out\r\n");*/

    slip_out();
    
    /*printf("Got back from slip_out\r\n");*/
}


/*  get_outpacket()
 *
 *      Return the next packet from the output queue or NULL if none.
 *  If a packet is present, remove it from the queue before returning it.
 */

static GPKT *get_outpacket(void)
{
    GPKT *next_packet = outqueue;

    if (next_packet == (GPKT *)NULL)
        return (GPKT *)NULL;

    outqueue = outqueue->next;  /* Advance pointer (possibly to NULL)   */

    return next_packet;
}


/*  slip_out()
 *
 *      Sends a packet out the serial port, inserting SLIP
 *  special characters at the same time.  If no packet is
 *  currently being sent, get the next packet from the
 *  output queue.  If no packet is available, return.
 *  If the serial buffer can't accept any more characters,
 *  then return.  In this case, REMEMBER where we are up to
 *  so we can continue later.  When a packet has been
 *  completely sent, delete it.
 *
 *      When an ESC is sent this function *doesn't* assume that
 *  the serial buffer is available for just one more char.
 *  Therefore, the condition is noted for special action.
 */

static void ser_out(int c)
{
    PortSendByte(bdev, (char)c);
}


void slip_out(void)
{
    static GPKT *outpkt = (GPKT *)NULL; /* Packet being written             */
    static unsigned char *nextout = (unsigned char *)NULL;   /* next buffer octet    */
    static int esc_sent = FALSE;        /* Was ESC the last byte written    */
    static uint16 out_len;              /* number of chars to write         */
	struct ip_header *ip;

new_out_packet:

/*printf("in slip_out after new_out_packet\r\n");*/

    if (outpkt == (GPKT *)NULL) {       /* No packet being processed        */

		/*printf("attempting to get new packet\r\n");*/

        outpkt = get_outpacket();       /* So get one, if any               */
        if (outpkt == (GPKT *)NULL)
            return;                     /* If not, return;  Try later.      */
        out_len = outpkt->ip_len;       /* Number of chars to send          */
        nextout = (unsigned char *)outpkt->pip; /* Start of buffer to send          */
        esc_sent = FALSE;               /* Make it a *real* init            */

		/*printf("Have set variables for new packet\r\n");*/

		ip = (IP_HDR *)outpkt->pip;

		if (myslip->flags & SLF_COMPRESS &&
			    ip->ptcl == IPPROTO_TCP)
			{
				/*printf("Before slc compress!!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!#!!#!#!#!#!#!#!#!#!#!##!#!#!#\r\n");*/
			
				*outpkt->pip |= slc_compress(outpkt, myslip->comp, myslip->flags & SLF_COMPCID);

				printf("after slc_compress\r\n");

				nextout = (unsigned char *)outpkt->pip;
				out_len = outpkt->ip_len;
				
				/*printf("after the rest of the junk in slccompress test\r\n");*/
			}

 										/* Send an initial end, per RFC1055 */
        ser_out(END);               	/* But only if com buffer not full  */
    }


    while (TRUE) {          /* Send chars until buffer full, or all sent    */
		/* The test for output buffer full might not be supported
		 *	by DEVICE.LIB  I'll have to check up on that...
		 */

        if (out_len == 0) {             /* Packet is completely sent        */

			/*printf("Packet completely sent\r\n");*/

            ser_out(END);               /* ATARI:So send an END             */
            
            /*printf("END sent\r\n");*/
            
            delete_packet(outpkt, NS_SENT);
            
            /*printf("After delete packet\r\n");*/

            outpkt = (GPKT *)NULL;      /* All done..*/
            
            /*printf("Before goto new_out_packet\r\n");                       */

       		goto new_out_packet;
            /*	return;                      Like slip_in(), we return now    */
        }   /* Possibly better for slip_out() to continue if more queued!   */

        if (*nextout == ESC || *nextout == END) {   /* A special case char  */
            if (esc_sent) {             /* But we ESC'd it last time around */
                if (*nextout == ESC) {
                    ser_out(ESC_ESC);    /* ATARI: so send a ESC_ESC */
                }
                else {
                    ser_out(ESC_END);   /* ATARI: or send a ESC_END */
                }
                esc_sent = FALSE;
                ++nextout;
                --out_len;
            }
            else {
                ser_out(ESC);           /* ATARI: Send an ESC char  */
                esc_sent = TRUE;
            }
        }
        else {
            ser_out(*nextout);  /* ATARI: Otherwise just send the char  */
            ++nextout;
            --out_len;
        }
    }
    
    /* Like slip_in() this function never gets here.    */
}

/* ENCODE encodes a number that is known to be non-zero.  ENCODEZ
 * checks for zero (since zero has to be encoded in the long, 3 byte
 * form).
 */
#define ENCODE(n) { \
	if ((int16)(n) >= 256) { \
		*cp++ = 0; \
		cp[1] = (n); \
		cp[0] = (n) >> 8; \
		cp += 2; \
	} else { \
		*cp++ = (n); \
	} \
}
#define ENCODEZ(n) { \
	if ((int16)(n) >= 256 || (int16)(n) == 0) { \
		*cp++ = 0; \
		cp[1] = (n); \
		cp[0] = (n) >> 8; \
		cp += 2; \
	} else { \
		*cp++ = (n); \
	} \
}

#define DECODEL(f) { \
	if (*cp == 0) {\
		(f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \
		cp += 3; \
	} else { \
		(f) = htonl(ntohl(f) + (uint32)*cp++); \
	} \
}

#define DECODES(f) { \
	if (*cp == 0) {\
		f = f + ((cp[1] << 8) | cp[2]); \
		cp += 3; \
	} else { \
		f = f + (uint16)*cp++; \
	} \
}

#define DECODEU(f) { \
	if (*cp == 0) {\
		(f) = (cp[1] << 8) | cp[2]; \
		cp += 3; \
	} else { \
		(f) = (uint16)*cp++; \
	} \
}



/*
 *
 *  DECOMPRESSION ROUTINES
 *
 */


short
uncompress (b, slp)
	GPKT *b;
	struct slip *slp;
{
	octet type;

	type = slc_type(b);

	switch (type) {
	case TYPE_IP:
		/*printf("\r\nType IP\r\n");*/
		return 0;

	case TYPE_COMPRESSED_TCP:
		/*printf ("\r\nCompressed TCP\r\n");*/
		
		if (slp->flags & SLF_COMPRESS) {
			return !slc_uncompress (b, type, slp->comp);
		}
		break;

	case TYPE_UNCOMPRESSED_TCP:
		/*printf("\r\nuncompressed TCP\r\n");*/
		if (slp->flags & SLF_COMPRESS) {
			return !slc_uncompress (b, type, slp->comp);
		}
		if (slp->flags & SLF_AUTOCOMP &&
		    slc_uncompress (b, type, slp->comp)) {
			slp->flags |= SLF_COMPRESS;
			return 0;
		}
		break;
	}
	return 1;
}


unsigned char
slc_compress (b, comp, compress_cid)
	GPKT *b;
	struct slcompress *comp;
	long compress_cid;
{
	register struct cstate *cs = comp->last_cs->cs_next;
	register struct ip_header *ip = (struct ip_header *)b->pip;
	register uint32 hlen = ip->ihl;
	register TCP_HDR *oth;
	TCP_HDR *th;
	register uint32 deltaS, deltaA;
	register int16 changes = 0; /* int16 */
	unsigned char new_seq[16];
	unsigned char *cp = new_seq;


	/*
	 * Bail if this is an IP fragment or if the TCP packet isn't
	 * `compressible' (i.e., ACK isn't set or some other control bit is
	 * set).  (We assume that the caller has already made sure the
	 * packet is IP proto TCP). I fixed this it can be not TCP
	 */
	 
	/* Bail if this packet isn't TCP, or is an IP fragment */
	if(ip->ptcl != IPPROTO_TCP || ip->ofst != 0 || ip->ofst & ~FLAG_DF || b->ip_len < 40)
	{ 
		/* Send as regular IP */
		return TYPE_IP;
	}

	/* Extract TCP header */
	th = (TCP_HDR *)b->mp;

	/*  Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or
	 *  some other control bit is set).
	 */
	if(th->f_syn || th->f_fin || th->f_rst || !th->f_ack){
		/* TCP connection stuff; send as regular IP */
		return TYPE_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.
	 */
	/*INCR (sls_packets);*/

	/*printf("next = %d\r\n",cs_next);	*/

	/*printf(" %lx %lx\r\n",ip->s_ip,ip->d_ip);*/
	
	if (ip->s_ip != cs->cs_ip.s_ip ||
	    ip->d_ip != cs->cs_ip.d_ip ||
	   *(long *)th != ((long *)&cs->cs_ip)[cs->cs_ip.ihl]) {
		/*
		 * 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.
		 */

		struct cstate *lcs;
		struct cstate *lastcs = comp->last_cs;
		/*int junk = 0;*/

		/*printf("lastcs id = %d\r\n",lastcs->cs_id);*/
		
		do {
			lcs = cs; 
			/*printf("cs next pointer = %ld\r\n",cs->cs_next);*/
			/*cs = &comp->tstate[junk];*/
			cs = cs->cs_next;
			
			/*printf("doing my trick\r\n");
			
			cs = ms;*/
			
			/*printf(" in while loop %d\r\n",cs->cs_id);*/
			
			/*Cconin();*/
			
			/*INCR (sls_searches);*/

			if (ip->s_ip == cs->cs_ip.s_ip &&
			    ip->d_ip == cs->cs_ip.d_ip &&
			    *(long *)th == ((long *)&cs->cs_ip)[cs->cs_ip.ihl])
			    {
			    	/*printf("Found it!\r\n");*/
					goto found;
				}
				
			/*junk++;*/
		} while (cs != lastcs); /*(junk != MAX_STATES - 1); */

		/*printf("Didn't find it!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\r\n");*/


		/*
		 * 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.
		 */
		/*INCR (sls_misses);*/
		comp->last_cs = lcs;

		/*printf(" last cs id %d\r\n",lcs->cs_id);*/

		hlen += th->ofst*4;
		hlen <<= 2;
		goto uncompressed;

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

		/*printf("We found it somehow\r\n");*/

		if (cs == lastcs)
			{
				/*printf("cs equals last cs\r\n");*/
				comp->last_cs = lcs;
			}
		else 
			{
				/*printf("cs is not equal to last cs\r\n");*/
				lcs->cs_next = cs->cs_next;
				cs->cs_next = lastcs->cs_next;
				lastcs->cs_next = cs;
			}

	}

	/*
	 * Make sure that only what we expect to change changed. The first
	 * line of the `if' checks the IP protocol version, header length &
	 * 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 & current datagram, we send the
	 * current datagram `uncompressed'.
	 */
	oth = (TCP_HDR *)&((long *)&cs->cs_ip)[hlen];
	deltaS = hlen;
	hlen += th->ofst*4;
	hlen <<= 2;

	/*printf("after search\r\n");*/

	if (((unsigned short *)ip)[0] != ((unsigned short *)&cs->cs_ip)[0] ||
	    ((unsigned short *)ip)[3] != ((unsigned short *)&cs->cs_ip)[3] ||
	    ((unsigned short *)ip)[4] != ((unsigned short *)&cs->cs_ip)[4] ||
	    th->ofst*4 != oth->ofst*4 ||
	    (deltaS > 5 &&
	     BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) ||
	    (th->ofst*4 > 5 &&
	     BCMP(th + 1, oth + 1, (th->ofst*4 - 5) << 2)))
		goto uncompressed;


	/*
	 * Figure out which of the changing fields changed.  The
	 * receiver expects changes in the order: urgent, window,
	 * ack, seq (the order minimizes the number of temporaries
	 * needed in this section of code).
	 */
	if (th->f_urg) {
		deltaS = th->urgent;
		ENCODE(deltaS); /* was ENCODEZ */
		changes |= NEW_U;
	} else if (th->urgent != oth->urgent) {
		/* 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;
	}

	/*if ((deltaS = th->window - oth->window) != 0) */
	if ((deltaS = th->window - oth->window) != 0)
	{
		ENCODE(deltaS);
		changes |= NEW_W;
	}

	if ((deltaA = th->ack - oth->ack)!=0L)
	{
		if (deltaA > 0x0000ffff)
			goto uncompressed;
		ENCODE(deltaA);
		changes |= NEW_A;
	}

	if ((deltaS = th->seq - oth->seq)!=0L) 
	{
		if (deltaS > 0x0000ffff)
			goto uncompressed;
		ENCODE(deltaS);
		changes |= NEW_S;
	}

	/*printf("After encoding\r\n");*/

	switch(changes) {

	case 0:
		/*
		 * Nothing changed. If this packet contains data and the
		 * last one didn't, this is probably a data packet following
		 * an ack (normal on an interactive connection) and we send
		 * it compressed.  Otherwise it's probably a retransmit,
		 * retransmitted ack or window probe.  Send it uncompressed
		 * in case the other side missed the compressed version.
		 */

		if(ip->len != cs->cs_ip.len && cs->cs_ip.len == hlen)
			break;
		/*if (ip->len != mytstate[junk].cs_ip.len &&
		    ntohs(mytstate[junk].cs_ip.len) == hlen)
			break;*/

		goto uncompressed;

		/* (fall through) */

	case SPECIAL_I:
	case SPECIAL_D:
		/*
		 * actual changes match one of our special case encodings --
		 * send packet uncompressed.
		 */
		goto uncompressed;

	case NEW_S|NEW_A:
		if (deltaS == deltaA &&
		    deltaS == cs->cs_ip.len - hlen) {
			/* special case for echoed terminal traffic */
			changes = SPECIAL_I;
			cp = new_seq;
		}
		break;

	case NEW_S:
		if (deltaS == cs->cs_ip.len - hlen) {
			/* special case for data xfer */
			changes = SPECIAL_D;
			cp = new_seq;
		}
		break;
	}

	deltaS = ip->id - cs->cs_ip.id;
	if (deltaS != 1) {
		ENCODE(deltaS);
		changes |= NEW_I;
	}
	if (th->f_psh)
		changes |= TCP_PUSH_BIT;
	/*
	 * Grab the cksum before we overwrite it below.  Then update our
	 * state with this packet's header.
	 */
	deltaA = th->sum;
	BCOPY(ip, &cs->cs_ip, hlen);

	/*
	 * We want to use the original packet as our compressed packet.
	 * (cp - new_seq) is the number of bytes we need for compressed
	 * sequence numbers.  In addition we need one byte for the change
	 * mask, one for the connection id and two for the tcp checksum.
	 * So, (cp - new_seq) + 4 bytes of header are needed.  hlen is how
	 * many bytes of the original packet to toss so subtract the two to
	 * get the new packet size.
	 */
	deltaS = cp - new_seq;
	cp = (unsigned char *)ip;
	if (compress_cid == 0 || comp->last_xmit != cs->cs_id) {
		comp->last_xmit = cs->cs_id;
		hlen -= deltaS + 4;
		cp += hlen;
		*cp++ = changes | NEW_C;
		*cp++ = cs->cs_id;
	} else {
		hlen -= deltaS + 3;
		cp += hlen;
		*cp++ = changes;
	}
	/* I just turned this next line off */
	b->fp += hlen; /* was fp*/
	*cp++ = deltaA >> 8;
	*cp++ = deltaA;
	BCOPY(new_seq, cp, deltaS);
	/*INCR (sls_compressed);*/

	printf("before return compressed\r\n");
	return (TYPE_COMPRESSED_TCP);

	/*
	 * Update connection state cs & send uncompressed packet ('uncompressed'
	 * means a regular ip/tcp packet but with the 'conversation id' we hope
	 * to use on future compressed packets in the protocol field).
	 */
uncompressed:
	BCOPY(ip, &cs->cs_ip, hlen);
	ip->ptcl = cs->cs_id;
	comp->last_xmit = cs->cs_id;
	
	/*printf("comp last xmit %d\r\n",comp->last_xmit);*/
	
	printf("before return uncompressed\r\n");
	return (TYPE_UNCOMPRESSED_TCP);
}


long
slc_uncompress (b, type, comp)
	GPKT *b;
	octet type;
	struct slcompress *comp;
{
	/*octet * */
	char *cp;
	unsigned long hlen;
	int changes;
	TCP_HDR *th;
	struct cstate *cs;
	IP_HDR *ip;
	long len;
	char *newbuf;

	len = b->ip_len;  /*b->dend - b->dstart;*/

	switch (type) {

	case TYPE_UNCOMPRESSED_TCP:
		/*
		 *  Here we grab all the header info for later decompression
		 *  rstate stands for recieve state.
		 */

		printf("Here we are in TYPE_UNCOMPRESSED_TCP!!!!!\r\n");

	    ip = (IP_HDR *)b->pip;
	    /*th = (TCP_HDR *)b->mp;*/

		if (len < 40 || ip->ptcl >= MAX_STATES)
			{
				printf("len or protocol bad\r\n");
				goto bad;
			}
		/*
		 * clear out TYPE_UNCOMPRESSED_TCP
		 */


		ip->ver &= 0x4;
		comp->last_recv = ip->ptcl;
		cs = &comp->rstate[comp->last_recv];
		comp->flags &= ~SLF_TOSS;
		ip->ptcl = IPPROTO_TCP;
		hlen = ip->ihl;
		hlen += ((TCP_HDR *)&((long *)ip)[hlen << 2])->ofst;
		hlen <<= 2;
		BCOPY(ip, &cs->cs_ip, hlen);
		cs->cs_ip.sum = 0;
		cs->cs_hlen = hlen;
		
		return (len);

	case TYPE_COMPRESSED_TCP:
		printf("Compressed TCP\r\n");
		break;

	default:
		printf("don't recognize type\r\n");
		goto bad;
	}

	/* We've got a compressed packet. */
	/* INCR (sls_compressedin); */
	cp = b->fp;	 /* dstart */ /* was fp experimenting now */
	changes = *cp++;

	printf("at the top of the decode routine\r\n");

	printf("ip version = %d\r\n",cs->cs_ip.ver);

	if (changes & NEW_C) {
		/* Make sure the state index is in range, then grab the state.
		 * If we have a good state index, clear the 'discard' flag. */
		if (*cp >= MAX_STATES)
			{
				printf("Bad state index\r\n");
				printf(" index %c %d \r\n",*cp,*cp);
				goto bad;
			}
		comp->flags &= ~SLF_TOSS;
		comp->last_recv = *cp++;
	} else {
		/* this packet has an implicit state index.  If we've
		 * had a line error since the last time we got an
		 * explicit state index, we have to toss the packet. */
		if (comp->flags & SLF_TOSS) {
			/*INCR (sls_tossed);*/
			return (0);
		}
	}
	
	/*cs = &myrstate[comp->last_recv];*/

	printf("ip version = %d\r\n",cs->cs_ip.ver);

	cs = &comp->rstate[comp->last_recv];
	hlen = cs->cs_ip.ihl << 2;
	th = (TCP_HDR *)&((unsigned char *)&cs->cs_ip)[hlen];
	th->sum = (*cp << 8) | cp[1];
	cp += 2;

	printf("ip version = %d\r\n",cs->cs_ip.ver);

	if (changes & TCP_PUSH_BIT)
		th->f_psh = 1;
	else
		th->f_psh = 0;

	switch (changes & SPECIALS_MASK) {

	case SPECIAL_I:
		{
			uint32 i = cs->cs_ip.len - cs->cs_hlen;
			th->ack = th->ack + i;
			th->seq = th->seq + i;
		}
		break;

	case SPECIAL_D:
		th->seq = th->seq + cs->cs_ip.len
				   - cs->cs_hlen;
		break;

	default:
		if (changes & NEW_U) {
			th->f_urg = 1;
			DECODEU(th->urgent); /*DECODEU*/
		} else
			th->f_urg = 0;
		if (changes & NEW_W)
			DECODES (th->window);
		if (changes & NEW_A)
			DECODEL (th->ack);
		if (changes & NEW_S)
			DECODEL (th->seq);
		break;
	}
	if (changes & NEW_I) {
		DECODES (cs->cs_ip.id);
	} else
		cs->cs_ip.id = cs->cs_ip.id++;


	/*
	 * At this point, cp points to the first byte of data in the
	 * packet.  If we're not aligned on a 4-byte boundary, copy the
	 * data down so the ip & tcp headers will be aligned.  Then back up
	 * cp by the tcp/ip header length to make room for the reconstructed
	 * header (we assume the packet we were handed has enough space to
	 * prepend 128 bytes of header).  Adjust the length to account for
	 * the new header & fill in the IP total length.
	 */

	len -= (cp - (char *)b->fp); /* was fp */

	if (len < 0)
		{
		/* we must have dropped some characters (crc should detect
		 * this but the old slip framing won't) */
		printf("dropped some characters\r\n");
		goto bad;
		}

/*	if ((long)cp & 1) {
		if (len > 0)
			ovbcopy(cp, cp-1, len);
		--cp; 
		--b->ip_len;
		--b->mlen;
		--b->dlen;
	}*/
	
	printf("ip version = %d\r\n",cs->cs_ip.ver);


	/*header_len = b->ip_len - b->dlen;*/
	
	
	/*cp -= header_len;
	len += header_len;
	myrstate[comp->last_recv].cs_ip.len = (uint16)len;
	BCOPY(&b->fp, cp, header_len);*/

	/*cp -= th->ofst * 4;
	len += th->ofst * 4;
	myrstate[comp->last_recv].cs_ip.len = (int16)len;
	BCOPY(&myrstate[comp->last_recv].cs_ip, cp, (th->ofst * 4));*/

	/* OK it doesn't like adjusting the beginning of the packet 
		which is what we seem to be doing.  So lets try making space
		building it there and moving it back - worth a try */

    newbuf = KRmalloc((long)b->ip_len);


	/*cp -= cs->cs_hlen;*/
	len += cs->cs_hlen;
	cs->cs_ip.len = (int16)len;
	/*BCOPY(&cs->cs_ip, cp, cs->cs_hlen);*/
	/*b->dstart = cp;*/



	BCOPY(&cs->cs_ip, newbuf, cs->cs_hlen);
	BCOPY(&b->data, newbuf + cs->cs_hlen, b->dlen);

	BCOPY(&newbuf, b, b->ip_len);

	/*b->fp = cp; */
	/* fp */

	KRfree(newbuf);

	printf("before check summing\r\n");

	/* recompute the ip header checksum */
	((IP_HDR *)b)->sum = 0; 		/* Zero sum before new calculation  */

    /*hlen = ip->ihl * 4;             Number of octets in ip header    */

    ((IP_HDR *)b)->sum = calc_sum(b->pip, 0, (int16)hlen>>1);
    /*((IP_HDR *)cp)->sum = calc_sum(b->pip, 0, hlen);*/

	printf("after check summing\r\n");

	printf("ip ver = %d\r\n",cs->cs_ip.ver);

	printf("Right before return\r\n");

	return (len);
bad:
	comp->flags |= SLF_TOSS;
	/*INCR (sls_errorin);*/
	return (0);
}

		/*ip->ver &= 0x4;
		cs = comp->rstate[comp-> = ip->ptcl];
		comp->flags &= ~SLF_TOSS;
		ip->ptcl = IPPROTO_TCP;*/
		/*hlen = b->ip_len;*/
		/*hlen += ((struct tcp_header *)&((long *)ip)[hlen])->hdrlen;*/
		/*hlen <<= 2;*/
		/*BCOPY(ip, &cs->cs_ip, hlen);*/
		/*cs->cs_ip.sum = 0;*/
		/*cs->cs_hlen = hlen;*/
		/*INCR (sls_uncompressedin);*/
		/*return (len);*/
