diff options
Diffstat (limited to 'private/ntos/ndis/ndiswan/vjslip.c')
-rw-r--r-- | private/ntos/ndis/ndiswan/vjslip.c | 885 |
1 files changed, 885 insertions, 0 deletions
diff --git a/private/ntos/ndis/ndiswan/vjslip.c b/private/ntos/ndis/ndiswan/vjslip.c new file mode 100644 index 000000000..6e2288200 --- /dev/null +++ b/private/ntos/ndis/ndiswan/vjslip.c @@ -0,0 +1,885 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + vjslip.c + +Abstract: + +Author: + + Thomas J. Dimitri (TommyD) + +Environment: + +Revision History: + +--*/ +#include "wan.h" +#include "tcpip.h" +#include "vjslip.h" + +#define INCR(counter) ++comp->counter; + +// 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). +// + +UCHAR +sl_compress_tcp( + PUUCHAR UNALIGNED *m_off, // Frame start (points to IP header) + ULONG *m_len, // Length of entire frame + struct slcompress *comp, // Compression struct for this link + ULONG compress_cid) { // Compress connection id boolean + + struct cstate *cs = comp->last_cs->cs_next; + struct ip UNALIGNED *ip = (struct ip UNALIGNED *)*m_off; + ULONG hlen = ip->ip_hl & 0x0F; // last 4 bits are the length + struct tcphdr UNALIGNED *oth; /* last TCP header */ + struct tcphdr UNALIGNED *th; /* current TCP header */ + +// ---------------------------- +// 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. + + ULONG deltaS, deltaA; /* general purpose temporaries */ + ULONG changes = 0; /* change mask */ + UCHAR new_seq[16]; /* changes from last to current */ + UCHAR UNALIGNED *cp = new_seq; + USHORT ip_len; + + /* + * 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). Or if it does not contain the TCP protocol. + */ + if ((ip->ip_off & 0xff3f) || *m_len < 40 || ip->ip_p != IPPROTO_TCP) + return (TYPE_IP); + + th = (struct tcphdr UNALIGNED *) & ((PULONG) ip)[hlen]; + if ((th->th_flags & (TH_SYN | TH_FIN | TH_RST | TH_ACK)) != TH_ACK) + 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. + */ + + // + // Keep stats here + // + INCR(OutPackets); + + if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr || + ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr || + *(ULONG UNALIGNED *) th != ((ULONG UNALIGNED *) &cs->cs_ip)[cs->cs_ip.ip_hl & 0x0F]) { + + /* + * 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; + + do { + lcs = cs; + cs = cs->cs_next; + INCR(OutSearches); + + if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr && + ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr && + *(ULONG UNALIGNED *) th == ((ULONG UNALIGNED *) &cs->cs_ip)[cs->cs_ip.ip_hl & 0x0F]) + + 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. + */ + + INCR(OutMisses); + + // + // A miss! + // + comp->last_cs = lcs; + hlen += (th->th_off >> 4); + hlen <<= 2; + + if (hlen > *m_len) { + return(TYPE_IP); + } + + goto uncompressed; + +found: + /* Found it -- move to the front on the connection list. */ + if (cs == lastcs) + comp->last_cs = lcs; + else { + 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 = (struct tcphdr UNALIGNED *) & ((ULONG UNALIGNED *) &cs->cs_ip)[hlen]; + deltaS = hlen; + hlen += (th->th_off >> 4); + hlen <<= 2; + + // + // Bug fix? It's in cslip.tar.Z + // + if (hlen > *m_len) { + NdisWanDbgOut(DBG_FAILURE, DBG_VJ,("Bad TCP packet length\n")); + return(TYPE_IP); + } + + if (((PUSHORT) ip)[0] != ((PUSHORT) &cs->cs_ip)[0] || + ((PUSHORT) ip)[3] != ((PUSHORT) &cs->cs_ip)[3] || + ((PUSHORT) ip)[4] != ((PUSHORT) &cs->cs_ip)[4] || + (th->th_off >> 4) != (oth->th_off >> 4) || + (deltaS > 5 && + memcmp((PUCHAR)(ip + 1), (PUCHAR)(&cs->cs_ip + 1), (deltaS - 5) << 2)) || + ((th->th_off >> 4) > 5 && + memcmp((PUCHAR)(th + 1), (PUCHAR)(oth + 1), ((th->th_off >> 4) - 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->th_flags & TH_URG) { + deltaS = ntohs(th->th_urp); + ENCODEZ(deltaS); + changes |= NEW_U; + } else if (th->th_urp != oth->th_urp) { + + /* + * 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 = (USHORT) (ntohs(th->th_win) - ntohs(oth->th_win))) { + ENCODE(deltaS); + changes |= NEW_W; + } + if (deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack)) { + if (deltaA > 0xffff) { + goto uncompressed; + } + + ENCODE(deltaA); + changes |= NEW_A; + } + if (deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq)) { + if (deltaS > 0xffff) { + goto uncompressed; + } + + ENCODE(deltaS); + changes |= NEW_S; + } + + ip_len = ntohs(cs->cs_ip.ip_len); + + /* + * Look for the special-case encodings. + */ + 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->ip_len != cs->cs_ip.ip_len && + ip_len == hlen) + + break; + + /* (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 == ip_len - hlen) { + /* special case for echoed terminal traffic */ + changes = SPECIAL_I; + cp = new_seq; + } + break; + + case NEW_S: + if (deltaS == ip_len - hlen) { + /* special case for data xfer */ + changes = SPECIAL_D; + cp = new_seq; + } + break; + } + + deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id); + + if (deltaS != 1) { + ENCODEZ(deltaS); + changes |= NEW_I; + } + + if (th->th_flags & TH_PUSH) + changes |= TCP_PUSH_BIT; + /* + * Grab the cksum before we overwrite it below. Then update our + * state with this packet's header. + */ + deltaA = (th->th_sumhi << 8) + th->th_sumlo; + + NdisMoveMemory((PUCHAR)&cs->cs_ip, + (PUCHAR)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 = (UCHAR UNALIGNED *) ip; + + if (compress_cid == 0 || comp->last_xmit != cs->cs_id) { + comp->last_xmit = cs->cs_id; + hlen -= deltaS + 4; + cp += hlen; + *cp++ = (UCHAR)(changes | NEW_C); + *cp++ = cs->cs_id; + } else { + hlen -= deltaS + 3; + cp += hlen; + *cp++ = (UCHAR)changes; + } + + *m_len -= hlen; + *m_off += hlen; + *cp++ = (UCHAR)(deltaA >> 8); + *cp++ = (UCHAR)(deltaA); + + NdisMoveMemory((PUCHAR)cp, + (PUCHAR)new_seq, + deltaS); + + INCR(OutCompressed); + return (TYPE_COMPRESSED_TCP); + +uncompressed: + /* + * 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). + */ + + NdisMoveMemory((PUCHAR)&cs->cs_ip, + (PUCHAR)ip, + hlen); + + ip->ip_p = cs->cs_id; + comp->last_xmit = cs->cs_id; + return (TYPE_UNCOMPRESSED_TCP); +} + + + + + +// A.3 Decompression +// +// This routine decompresses a received packet. It is called with a +// pointer to the packet, the packet length and type, and a pointer to the +// compression state structure for the incoming serial line. It returns a +// pointer to the resulting packet or zero if there were errors in the +// incoming packet. If the packet is COMPRESSED_TCP or UNCOMPRESSED_TCP, +// the compression state will be updated. +// +// The new packet will be constructed in-place. That means that there must +// be 128 bytes of free space in front of bufp to allow room for the +// reconstructed IP and TCP headers. The reconstructed packet will be +// aligned on a 32-bit boundary. +// + +//LONG +//sl_uncompress_tcp( +// PUUCHAR UNALIGNED *bufp, +// LONG len, +// UCHAR type, +// struct slcompress *comp) { +LONG +sl_uncompress_tcp( + PUUCHAR UNALIGNED *InBuffer, + PULONG InLength, + UCHAR UNALIGNED *OutBuffer, + PULONG OutLength, + UCHAR type, + struct slcompress *comp + ) +{ + UCHAR UNALIGNED *cp; + ULONG inlen; + ULONG hlen, changes; + struct tcphdr UNALIGNED *th; + struct cstate *cs; + struct ip UNALIGNED *ip; + + inlen = *InLength; + + switch (type) { + + case TYPE_ERROR: + default: + NdisWanDbgOut(DBG_FAILURE, DBG_VJ, ("Packet transmission error type 0x%.2x\n",type)); + goto bad; + + case TYPE_IP: + break; + + case TYPE_UNCOMPRESSED_TCP: + /* + * Locate the saved state for this connection. If the state + * index is legal, clear the 'discard' flag. + */ + ip = (struct ip UNALIGNED *) *InBuffer; + if (ip->ip_p >= comp->MaxStates) { + NdisWanDbgOut(DBG_FAILURE, DBG_VJ, ("Max state exceeded %u\n", ip->ip_p)); + goto bad; + } + + cs = &comp->rstate[comp->last_recv = ip->ip_p]; + comp->flags &= ~SLF_TOSS; + + /* + * Restore the IP protocol field then save a copy of this + * packet header. (The checksum is zeroed in the copy so we + * don't have to zero it each time we process a compressed + * packet. + */ + hlen = ip->ip_hl & 0x0F; + hlen += ((struct tcphdr UNALIGNED *) & ((ULONG UNALIGNED *) ip)[hlen])->th_off >> 4; + hlen <<= 2; + + NdisMoveMemory((PUCHAR)&cs->cs_ip, + (PUCHAR)ip, + hlen); + + cs->cs_ip.ip_p = IPPROTO_TCP; + + NdisMoveMemory((PUCHAR)OutBuffer, + (PUCHAR)&cs->cs_ip, + hlen); + + cs->cs_ip.ip_sum = 0; + cs->cs_hlen = (USHORT)hlen; + + *InBuffer = (PUCHAR)ip + hlen; + *InLength = inlen - hlen; + *OutLength = hlen; + + INCR(InUncompressed); + return (inlen); + + case TYPE_COMPRESSED_TCP: + break; + } + + /* We've got a compressed packet. */ + INCR(InCompressed); + cp = *InBuffer; + changes = *cp++; + + 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 >= comp->MaxStates) { + NdisWanDbgOut(DBG_FAILURE, DBG_VJ, ("MaxState of %u too big\n", *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) { + NdisWanDbgOut(DBG_FAILURE, DBG_VJ,("Packet has state index, have to toss it\n")); + INCR(InTossed); + return (0); + } + } + + /* + * Find the state then fill in the TCP checksum and PUSH bit. + */ + + cs = &comp->rstate[comp->last_recv]; + hlen = (cs->cs_ip.ip_hl & 0x0F) << 2; + th = (struct tcphdr UNALIGNED *) & ((UCHAR UNALIGNED *) &cs->cs_ip)[hlen]; + + th->th_sumhi = cp[0]; + th->th_sumlo = cp[1]; + + cp += 2; + if (changes & TCP_PUSH_BIT) + th->th_flags |= TH_PUSH; + else + th->th_flags &= ~TH_PUSH; + + /* + * Fix up the state's ack, seq, urg and win fields based on the + * changemask. + */ + switch (changes & SPECIALS_MASK) { + case SPECIAL_I: + { + UCHAR UNALIGNED * piplen=(UCHAR UNALIGNED *)&(cs->cs_ip.ip_len); + UCHAR UNALIGNED * ptcplen; + ULONG tcplen; + ULONG i; + + i = ((piplen[0] << 8) + piplen[1]) - cs->cs_hlen; + +// th->th_ack = htonl(ntohl(th->th_ack) + i); + + ptcplen=(UCHAR UNALIGNED *)&(th->th_ack); + tcplen=(ptcplen[0] << 24) + (ptcplen[1] << 16) + + (ptcplen[2] << 8) + ptcplen[3] + i; + ptcplen[3]=(UCHAR)(tcplen); + ptcplen[2]=(UCHAR)(tcplen >> 8); + ptcplen[1]=(UCHAR)(tcplen >> 16); + ptcplen[0]=(UCHAR)(tcplen >> 24); + + +// th->th_seq = htonl(ntohl(th->th_seq) + i); + + ptcplen=(UCHAR UNALIGNED *)&(th->th_seq); + tcplen=(ptcplen[0] << 24) + (ptcplen[1] << 16) + + (ptcplen[2] << 8) + ptcplen[3] + i; + ptcplen[3]=(UCHAR)(tcplen); + ptcplen[2]=(UCHAR)(tcplen >> 8); + ptcplen[1]=(UCHAR)(tcplen >> 16); + ptcplen[0]=(UCHAR)(tcplen >> 24); + + } + break; + + case SPECIAL_D: + { +// th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) +// - cs->cs_hlen); + + UCHAR UNALIGNED *piplen=(UCHAR UNALIGNED *)&(cs->cs_ip.ip_len); + UCHAR UNALIGNED *ptcplen; + ULONG tcplen; + ULONG i; + + i = ((piplen[0] << 8) + piplen[1]) - cs->cs_hlen; + + ptcplen=(UCHAR UNALIGNED *)&(th->th_seq); + tcplen=(ptcplen[0] << 24) + (ptcplen[1] << 16) + + (ptcplen[2] << 8) + ptcplen[3] + i; + + ptcplen[3]=(UCHAR)(tcplen); + ptcplen[2]=(UCHAR)(tcplen >> 8); + ptcplen[1]=(UCHAR)(tcplen >> 16); + ptcplen[0]=(UCHAR)(tcplen >> 24); + + + } + + break; + + default: + if (changes & NEW_U) { + th->th_flags |= TH_URG; + DECODEU(th->th_urp) + } else + th->th_flags &= ~TH_URG; + + if (changes & NEW_W) + DECODES(th->th_win); + if (changes & NEW_A) + DECODEL(th->th_ack) + if (changes & NEW_S) + DECODEL(th->th_seq) + + break; + } + /* Update the IP ID */ + if (changes & NEW_I) { + + DECODES(cs->cs_ip.ip_id) + + } else { + + USHORT id; + UCHAR UNALIGNED *pid = (UCHAR UNALIGNED *)&(cs->cs_ip.ip_id); + +// cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1); + id=(pid[0] << 8) + pid[1] + 1; + pid[0]=(UCHAR)(id >> 8); + pid[1]=(UCHAR)(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 lenth to account for the new header + * & fill in the IP total length. + */ +// len -= (cp - *bufp); + inlen -= (cp - *InBuffer); + + if (inlen < 0) { + + /* + * we must have dropped some characters (crc should detect + * this but the old slip framing won't) + */ + NdisWanDbgOut(DBG_FAILURE, DBG_VJ,("len has dropped below 0!\n")); + goto bad; + } +// +// SCREW 4 byte alignement! It's just a useless big copy! +// +// if ((ULONG) cp & 3) { +// if (len > 0) +// // +// // BUG BUG we want OVBCOPY.. +// // +// NdisMoveMemory( +// (PUCHAR)((ULONG) cp & ~3), +// cp, +// len); +// cp = (PUCHAR) ((ULONG) cp & ~3); +// } + +// cp -= cs->cs_hlen; +// len += cs->cs_hlen; + +// cs->cs_ip.ip_len = htons(len); + cs->cs_ip.ip_len = htons(inlen + cs->cs_hlen); + +// NdisMoveMemory( +// (PUCHAR)cp, +// (PUCHAR)&cs->cs_ip, +// cs->cs_hlen); + + NdisMoveMemory((PUCHAR)OutBuffer, + (PUCHAR)&cs->cs_ip, + cs->cs_hlen); + +// *bufp = cp; + *InBuffer = cp; + *InLength = inlen; + *OutLength = cs->cs_hlen; + + /* recompute the ip header checksum */ + { +// USHORT UNALIGNED * bp = (USHORT UNALIGNED *) cp; + USHORT UNALIGNED * bp = (USHORT UNALIGNED *) OutBuffer; + + for (changes = 0; hlen > 0; hlen -= 2) + changes += *bp++; + + changes = (changes & 0xffff) + (changes >> 16); + changes = (changes & 0xffff) + (changes >> 16); +// ((struct ip UNALIGNED *) cp)->ip_sum = (USHORT)~changes; + ((struct ip UNALIGNED *) OutBuffer)->ip_sum = (USHORT)~changes; + } + + return (inlen + cs->cs_hlen); + +bad: + comp->flags |= SLF_TOSS; + INCR(InErrors); + return (0); +} + + + + +// A.4 Initialization +// +// This routine initializes the state structure for both the transmit and +// receive halves of some serial line. It must be called each time the +// line is brought up. +// + +NDIS_STATUS +sl_compress_init( + struct slcompress **retcomp, + UCHAR MaxStates + ) +{ + ULONG i; + struct cstate *tstate; // = comp->tstate; + struct slcompress *comp; + + comp = *retcomp; + + // + // Do we need to allocate memory for this bundle + // + + if (comp != NULL) { + return (NDIS_STATUS_SUCCESS); + } + + + NdisWanAllocateMemory(&comp, sizeof(slcompress)); + + // + // If there was no memory to allocate + // + if (comp == NULL) { + + return(NDIS_STATUS_RESOURCES); + } + + tstate = comp->tstate; + + /* + * Clean out any junk left from the last time line was used. + */ + NdisZeroMemory( + (PUCHAR) comp, + sizeof(*comp)); + + /* + * Link the transmit states into a circular list. + */ + for (i = MaxStates - 1; i > 0; --i) { + tstate[i].cs_id = (UCHAR)i; + tstate[i].cs_next = &tstate[i - 1]; + } + + tstate[0].cs_next = &tstate[MaxStates - 1]; + tstate[0].cs_id = 0; + comp->last_cs = &tstate[0]; + + /* + * Make sure we don't accidentally do CID compression + * (assumes MAX_VJ_STATES < 255). + */ + comp->last_recv = 255; + comp->last_xmit = 255; + comp->flags = SLF_TOSS; + comp->MaxStates=MaxStates; + + *retcomp = comp; + + return (NDIS_STATUS_SUCCESS); +} + +VOID +sl_compress_terminate( + struct slcompress **comp + ) +{ + if (*comp != NULL) { + NdisWanFreeMemory(*comp); + *comp = NULL; + } +} + +// A.5 Berkeley Unix dependencies +// +// Note: The following is of interest only if you are trying to bring the +// sample code up on a system that is not derived from 4BSD (Berkeley +// Unix). +// +// The code uses the normal Berkeley Unix header files (from +// /usr/include/netinet) for definitions of the structure of IP and TCP +// headers. The structure tags tend to follow the protocol RFCs closely +// and should be obvious even if you do not have access to a 4BSD +// system./48/ +// +// ---------------------------- +// 48. In the event they are not obvious, the header files (and all the +// Berkeley networking code) can be anonymous ftp'd from host +// +// +// The macro BCOPY(src, dst, amt) is invoked to copy amt bytes from src to +// dst. In BSD, it translates into a call to BCOPY. If you have the +// misfortune to be running System-V Unix, it can be translated into a call +// to memcpy. The macro OVBCOPY(src, dst, amt) is used to copy when src +// and dst overlap (i.e., when doing the 4-byte alignment copy). In the +// BSD kernel, it translates into a call to ovbcopy. Since AT&T botched +// the definition of memcpy, this should probably translate into a copy +// loop under System-V. +// +// The macro BCMP(src, dst, amt) is invoked to compare amt bytes of src and +// dst for equality. In BSD, it translates into a call to bcmp. In +// System-V, it can be translated into a call to memcmp or you can write a +// routine to do the compare. The routine should return zero if all bytes +// of src and dst are equal and non-zero otherwise. +// +// The routine ntohl(dat) converts (4 byte) long dat from network byte +// order to host byte order. On a reasonable cpu this can be the no-op +// macro: +// #define ntohl(dat) (dat) +// +// On a Vax or IBM PC (or anything with Intel byte order), you will have to +// define a macro or routine to rearrange bytes. +// +// The routine ntohs(dat) is like ntohl but converts (2 byte) shorts +// instead of longs. The routines htonl(dat) and htons(dat) do the inverse +// transform (host to network byte order) for longs and shorts. +// +// A struct mbuf is used in the call to sl_compress_tcp because that +// routine needs to modify both the start address and length if the +// incoming packet is compressed. In BSD, an mbuf is the kernel's buffer +// management structure. If other systems, the following definition should +// be sufficient: +// +// struct mbuf { +// UCHAR *m_off; /* pointer to start of data */ +// int m_len; /* length of data */ +// }; +// +// #define mtod(m, t) ((t)(m->m_off)) +// +// +// B Compatibility with past mistakes +// +// +// When combined with the modern PPP serial line protocol[9], the use of +// header compression is automatic and invisible to the user. +// Unfortunately, many sites have existing users of the SLIP described in +// [12] which doesn't allow for different protocol types to distinguish +// header compressed packets from IP packets or for version numbers or an +// option exchange that could be used to automatically negotiate header +// compression. +// +// The author has used the following tricks to allow header compressed SLIP +// to interoperate with the existing servers and clients. Note that these +// are hacks for compatibility with past mistakes and should be offensive +// to any right thinking person. They are offered solely to ease the pain +// of running SLIP while users wait patiently for vendors to release PPP. +// +// +// B.1 Living without a framing `type' byte +// +// The bizarre packet type numbers in sec. A.1 were chosen to allow a +// `packet type' to be sent on lines where it is undesirable or impossible +// to add an explicit type byte. Note that the first byte of an IP packet +// always contains `4' (the IP protocol version) in the top four bits. And +// that the most significant bit of the first byte of the compressed header +// is ignored. Using the packet types in sec. A.1, the type can be encoded +// in the most significant bits of the outgoing packet using the code +// +// p->dat[0] |= sl_compress_tcp(p, comp); +// +// and decoded on the receive side by +// +// if (p->dat[0] & 0x80) +// type = TYPE_COMPRESSED_TCP; +// else if (p->dat[0] >= 0x70) { +// type = TYPE_UNCOMPRESSED_TCP; +// p->dat[0] &=~ 0x30; +// } else +// type = TYPE_IP; +// status = sl_uncompress_tcp(p, type, comp); + + |