home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HAM Radio 1
/
HamRadio.cdr
/
misc
/
src0131
/
tcphdr.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-01-29
|
4KB
|
157 lines
/* TCP header conversion routines
* Copyright 1991 Phil Karn, KA9Q
*/
#include "global.h"
#include "mbuf.h"
#include "tcp.h"
#include "ip.h"
#include "internet.h"
/* Convert TCP header in host format into mbuf ready for transmission,
* link in data (if any). If ph != NULL, compute checksum, otherwise
* take checksum from tcph->checksum
*/
struct mbuf *
htontcp(tcph,data,ph)
register struct tcp *tcph;
struct mbuf *data;
struct pseudo_header *ph;
{
int16 hdrlen;
struct mbuf *bp;
register char *cp;
hdrlen = TCPLEN;
if(tcph->optlen > 0 && tcph->optlen <= TCP_MAXOPT){
hdrlen += tcph->optlen;
} else if(tcph->mss != 0){
hdrlen += MSS_LENGTH;
}
if((bp = pushdown(data,hdrlen)) == NULLBUF){
free_p(data);
return NULLBUF;
}
cp = bp->data;
cp = put16(cp,tcph->source);
cp = put16(cp,tcph->dest);
cp = put32(cp,tcph->seq);
cp = put32(cp,tcph->ack);
*cp++ = hdrlen << 2; /* Offset field */
*cp = 0;
if(tcph->flags.urg)
*cp |= 32;
if(tcph->flags.ack)
*cp |= 16;
if(tcph->flags.psh)
*cp |= 8;
if(tcph->flags.rst)
*cp |= 4;
if(tcph->flags.syn)
*cp |= 2;
if(tcph->flags.fin)
*cp |= 1;
cp++;
cp = put16(cp,tcph->wnd);
if(ph == NULLHEADER){
/* Use user-supplied checksum */
cp = put16(cp,tcph->checksum);
} else {
/* Zero out checksum field for later recalculation */
*cp++ = 0;
*cp++ = 0;
}
cp = put16(cp,tcph->up);
/* Write options, if any */
if(hdrlen > TCPLEN){
if(tcph->mss != 0){
*cp++ = MSS_KIND;
*cp++ = MSS_LENGTH;
cp = put16(cp,tcph->mss);
} else
memcpy(cp,tcph->options,tcph->optlen);
}
/* Recompute checksum, if requested */
if(ph != NULLHEADER)
put16(&bp->data[16],cksum(ph,bp,ph->length));
return bp;
}
/* Pull TCP header off mbuf */
int
ntohtcp(tcph,bpp)
register struct tcp *tcph;
struct mbuf **bpp;
{
int hdrlen,i,optlen,kind;
register int flags;
char hdrbuf[TCPLEN],*cp;
i = pullup(bpp,hdrbuf,TCPLEN);
/* Note that the results will be garbage if the header is too short.
* We don't check for this because returned ICMP messages will be
* truncated, and we at least want to get the port numbers.
*/
tcph->source = get16(&hdrbuf[0]);
tcph->dest = get16(&hdrbuf[2]);
tcph->seq = get32(&hdrbuf[4]);
tcph->ack = get32(&hdrbuf[8]);
hdrlen = (hdrbuf[12] & 0xf0) >> 2;
flags = hdrbuf[13];
tcph->flags.urg = flags & 32;
tcph->flags.ack = flags & 16;
tcph->flags.psh = flags & 8;
tcph->flags.rst = flags & 4;
tcph->flags.syn = flags & 2;
tcph->flags.fin = flags & 1;
tcph->wnd = get16(&hdrbuf[14]);
tcph->checksum = get16(&hdrbuf[16]);
tcph->up = get16(&hdrbuf[18]);
tcph->mss = 0;
tcph->optlen = hdrlen - TCPLEN;
/* Check for option field. Only space for one is allowed, but
* since there's only one TCP option (MSS) this isn't a problem
*/
if(i < TCPLEN || hdrlen < TCPLEN)
return -1; /* Header smaller than legal minimum */
if(tcph->optlen == 0)
return (int)hdrlen; /* No options, all done */
if(tcph->optlen > len_p(*bpp)){
/* Remainder too short for options length specified */
return -1;
}
pullup(bpp,tcph->options,tcph->optlen); /* "Can't fail" */
/* Process options */
for(cp=tcph->options,i=tcph->optlen; i > 0;){
kind = *cp++;
/* Process single-byte options */
switch(kind){
case EOL_KIND:
i--;
cp++;
return (int)hdrlen; /* End of options list */
case NOOP_KIND:
i--;
cp++;
continue; /* Go look for next option */
}
/* All other options have a length field */
optlen = uchar(*cp++);
/* Process valid multi-byte options */
switch(kind){
case MSS_KIND:
if(optlen == MSS_LENGTH){
tcph->mss = get16(cp);
}
break;
}
optlen = max(2,optlen); /* Enforce legal minimum */
i -= optlen;
cp += optlen - 2;
}
return (int)hdrlen;
}