www.pudn.com > TcpIpOn8051.rar > TCP.C


/*------------------------------------------------------------------------------ 
tcp.C 
 
 
------------------------------------------------------------------------------*/ 
#include "public.h" 
#include "ether.h" 
#include "ip.h" 
#include "tcp.h" 
 
 
TCP_SOCK xdata tsock[nsocks]; 
 
extern mycomp xdata mypara; 
extern netcard xdata sendbuffer[2]; 
extern ippack_senflag xdata ipsenflag[2]; 
 
void tcp_send_pack(TCP_SOCK *ts); 
void tcp_newstate(TCP_SOCK *ts, TCP_STATE news); 
void tcp_make_sock(TCP_SOCK *ts, BYTE flags, WORD dlen); 
void tcp_reset_net(netcard *netbuf, WORD rdlen); 
void tcp_reset_ts(TCP_SOCK *ts, WORD rdlen); 
void tcp_sock_auto(TCP_SOCK *ts,WORD dlen,bit rxortx); 
void tcp_remake_sock(TCP_SOCK *ts); 
WORD tcp_tsestab_rx(TCP_SOCK *ts, tcppacket *tcp, WORD dlen); 
void tcp_tsestab_tx(TCP_SOCK *ts,WORD force); 
WORD tcp_upcall(TCP_SOCK *ts, CONN_STATE conn,BYTE server); 
 
extern WORD mindata(WORD a, WORD b); 
extern DWORD get_current(); 
extern WORD csum(void *dp, WORD count); 
extern bit ip_send_pack(netcard *netbuf,BYTE bufnum,ip destip,BYTE pcol,WORD len); 
extern void ip_send(netcard *netbuf,ip destip,WORD *macaddr,BYTE pcol,WORD dlen); 
extern WORD buff_in(CBUFF *bp, BYTE *tdata, WORD len); 
extern WORD buff_dlen(CBUFF *bp); 
extern WORD buff_untriedlen(CBUFF *bp); 
extern WORD buff_trylen(CBUFF *bp); 
extern WORD buff_try(CBUFF *bp, BYTE *tdata, WORD maxlen); 
extern void buff_setall(CBUFF *bp, DWORD start); 
extern WORD buff_out(CBUFF *bp, BYTE *tdata, WORD maxlen); 
extern WORD buff_instr(CBUFF *bp, char *str); 
extern void print(char str[]); 
extern WORD server_action(TCP_SOCK *ts, CONN_STATE conn); 
extern WORD client_action(TCP_SOCK *ts, CONN_STATE conn); 
 
#define TCP_RXWIN 1024 
#define TCP_TIMEOUT 2000 
#define TCP_RETRNUM 4 
#define TCP_MAXDATA 512 
 
 
/*--------------------------- 
tcp upcall,to match user application  
----------------------------*/ 
void tcp_init(void) 
{ 
	register BYTE i; 
	for(i=0;i=msec) 
    { 
        *timep = tim; 
        tout = 1; 
    } 
    return(tout); 
} 
/*--------------------------- 
 
----------------------------*/ 
 
WORD tcp_check(tcppacket *tcp,DWORD srcip,DWORD destip,WORD tlen) 
{ 
	pheader tph; 
	DWORD sum; 
 
    sum = csum(&tcp->t,tlen);            // Checksum TCP segment  
    tph.len = tlen;                // Make pseudo-header  
    tph.srce = srcip; 
    tph.dest = destip; 
    tph.z = 0; 
    tph.pcol = tcp->i.type; 
    sum += csum(&tph, sizeof(pheader));             // Checksum pseudo-header  
    return(WORD)(sum + (sum>>16));              // Return total plus carry  
} 
/*--------------------------- 
 
----------------------------*/ 
WORD gettcp_opt(tcppacket *tcp, WORD *mssp) 
{ 
    WORD olen; 
 
    olen = ((tcp->t.hlen & 0xf0) >> 2) - sizeof(tcpheader); 
    if (mssp && olen>=4 && tcp->tcpdata[0]==2 && tcp->tcpdata[1]==4) 
        *mssp = *(WORD *)&tcp->tcpdata[2]; 
    return(olen); 
} 
/*--------------------------- 
 
----------------------------*/ 
BYTE tcp_open(TCP_SOCK *ts,ip destip, WORD destport) 
{ 
    WORD ok=0; 
 
    if ((ok = ts->state==TCP_CLOSED)!=0) 
    { 
		ts->remport = destport; 
        ts->remip = destip; 
        tcp_newstate(ts,TCP_AOPEN); 
    } 
	tcp_sock_auto(ts,0,(bit)0); 
    return(ok); 
} 
/*--------------------------- 
 
----------------------------*/ 
BYTE tcp_close(TCP_SOCK *ts) 
{ 
    if (ts->state==TCP_EST || ts->state==TCP_SYNR) 
        tcp_newstate(ts, TCP_ACLOSE); 
    return(ts->state == TCP_CLOSED); 
} 
/*--------------------------- 
 
----------------------------*/ 
void tcp_reset(TCP_SOCK *ts) 
{ 
    if (ts->state) 
        tcp_make_sock(ts,TRST,0); 
 
} 
/*--------------------------- 
 
----------------------------*/ 
void tcp_newstate(TCP_SOCK *ts, TCP_STATE news) 
{ 
    if (news != ts->state) 
        ts->state = news; 
    //mstimeout(&ts->time, 0); 
	ts->time=get_current(); 
    ts->retries = TCP_RETRNUM; 
    ts->timeout = TCP_TIMEOUT; 
} 
/*--------------------------- 
tcp upcall,to match user application  
----------------------------*/ 
/* 
BYTE tcp_upcall(TCP_SOCK *ts,CONN_STATE conn) 
{ 
	return 0; 
} 
*/ 
/*--------------------------- 
tcp upcall,to match user application  
----------------------------*/ 
void tcp_make_sock(TCP_SOCK *ts, BYTE flags, WORD dlen) 
{ 
    BYTE st; 
    DWORD tseq, tack; 
 
    tseq = ts->txbuf.trial;               /* Seq and ack values if connected */ 
    tack = ts->rxbuf.in; 
    if ((st=ts->state)==TCP_SYNR || st==TCP_SYNS) 
        tseq--;                         /* Decrement SEQ if sending SYN */ 
    else if (st==TCP_CLING || st==TCP_FINWT2 || st==TCP_TWAIT) 
        tseq++;                         /* ..or increment if sending FIN */ 
    if (st==TCP_LASTACK || st==TCP_CLWAIT || st==TCP_CLING || st==TCP_TWAIT) 
        tack++;                         /* Increment ACK if FIN received */ 
	ts->txbuf.seqnum=tseq; 
	ts->txbuf.acknum=tack; 
	ts->txbuf.flags=flags; 
	ts->txbuf.dlen=dlen; 
	ts->txbuf.yesornot=1; 
} 
/*---------------------------------------- 
tcp_poll 
-----------------------------------------*/ 
void tcp_poll(void) 
{ 
	register BYTE i; 
	BYTE ok=0; 
	TCP_SOCK *ts; 
 
	for(i=0;i<2;i++) 
	{ 
        ts=&tsock[i]; 
		if(ts->rxbuf.yesornot==1) 
			tcp_sock_auto(ts,ts->rxbuf.dlen,(bit)1); 
		else  
		{ 
        	if (ts->state) 
        	{ 
//				if(ts->state==TCP_SYNS) 
//					if(mstimeout(&ts->time, ts->timeout)) 
            	if (ts->timeout && mstimeout(&ts->time, ts->timeout)) 
            	{ 
                	ts->timeout += ts->timeout; 
					ts->retries--; 
                	if (ts->retries > 0) 
                    	tcp_remake_sock(ts); 
                	else 
                	{ 
                    	tcp_newstate(ts, TCP_CLOSED); 
                    	tcp_make_sock(ts, TRST, 0); 
                	} 
            	} 
            	else                						// Send Tx data  
                	tcp_sock_auto(ts,0,(bit)0); 
        	} 
		} 
		if(tsock[i].txbuf.yesornot==1) 
			tcp_send_pack(&tsock[i]); 
	} 
} 
/*--------------------------- 
查看有无要发送的数据,在tcp发送缓冲区中, 
若有,检查ip发送缓冲区有无空闲 
空闲则发送出数据包,由任务调度 
保证发送出数据 
----------------------------*/ 
void tcp_send_pack(TCP_SOCK *ts) 
{ 
	register j; 
	BYTE ok=0; 
	WORD hlen,tlen,dlen,olen=0; 
	tcppacket *tcp; 
	ip srcip,destip; 
 
	for(j=0;j<2 && !ok;j++) 
	{ 
		if(ok=ipsenflag[j].flag==0) 
		{ 
			tcp=(tcppacket *)sendbuffer[j].etherframe.packet; 
			tcp->t.seq=ts->txbuf.seqnum; 
			tcp->t.ack=ts->txbuf.acknum; 
			tcp->t.window=ts->rxwin; 
			if(ts->rxwin==0) 
				ts->rxwin=TCP_RXWIN; 
			tcp->t.sport=ts->locport; 
			tcp->t.dport=ts->remport; 
			hlen=sizeof(tcpheader); 
			dlen=ts->txbuf.dlen; 
 
 
			if (dlen > 0)                       // Get the Tx data  
        		dlen = buff_try(&ts->txbuf, tcp->tcpdata, dlen);	//copy data 
 
 
			if(ts->txbuf.flags & TSYN && dlen==0) 
			{ 
				hlen+=(olen=4); 
				tcp->tcpdata[0]=2; 
				tcp->tcpdata[1]=4; 
				*(WORD *)&tcp->tcpdata[2]=TCP_MAXDATA; 
			} 
			tcp->t.hlen=(BYTE)(hlen<<2); 
			tcp->t.flags=ts->txbuf.flags; 
			tcp->t.urgent=tcp->t.check=0; 
			//degug 
			tlen=hlen+dlen; 
			srcip=mypara.myip; 
			destip=ts->remip; 
			tcp->t.check=~tcp_check(tcp,srcip,destip,tlen); 
			ts->txbuf.yesornot=0;								//release txd buffer 
			ip_send_pack(&sendbuffer[j],j,destip,PTCP,tlen); 
		} 
	} 
} 
/*--------------------------- 
 
----------------------------*/ 
void tcp_deal_pack(netcard *netbuf) 
{ 
	register BYTE i; 
	tcppacket *tcp; 
	TCP_SOCK *ts; 
	WORD sum; 
	WORD len,olen,dlen,rdlen; 
	BYTE ok=0; 
 
	tcp=(tcppacket *)netbuf->etherframe.packet; 
	rdlen=len=tcp->i.totallen-sizeof(ipheader); 
	//check protocal and minimum length 
	if(tcp->i.type==PTCP && len>=sizeof(tcpheader) && tcp->t.hlen>=0x50) 
	{ 
		sum=tcp_check(tcp,tcp->i.srcip,tcp->i.destip,len);	//check tcp 
		//sum=0xffff; 
		if(sum==0xffff)										//if correct 
		{ 
			len=len-sizeof(tcpheader); 
			len -= gettcp_opt(tcp, 0);  // Subtract options len  
            dlen = len;    				// Return 0 if data len=0  
			olen = ((tcp->t.hlen & 0xf0) >> 2) - sizeof(tcpheader); 
			len=len-olen; 
			for(i=0;ii.destip==mypara.myip && tcp->t.dport==ts->locport &&  
					tcp->i.srcip==ts->remip && tcp->t.sport==ts->remport; 
			} 
			for(i=0;istate==TCP_CLOSED)!=0) 
				{ 
					ts->locport=tcp->t.dport; 
					ts->remip=tcp->i.srcip; 
					ts->remport=tcp->t.sport; 
				} 
			} 
			if(ok) 
			{ 
			 
				ts->rxbuf.flags=tcp->t.flags & (TFIN+TSYN+TRST+TACK); 
				ts->rxseq = tcp->t.seq; 
        		ts->rxack = tcp->t.ack; 
        		ts->txwin = tcp->t.window; 
 
				ts->rxbuf.yesornot=1; 
				ts->rxbuf.dlen=dlen; 
				if(dlen!=0) 
					if(ts->state==TCP_SYNR || ts->state==TCP_EST || ts->state==TCP_ACLOSE || ts->state==TCP_FINWT1 || 
			 			ts->state==TCP_FINWT2 || ts->state==TCP_SYNR) 
						tcp_tsestab_rx(ts,tcp,dlen);					//rxbuffer 
				//tcp_sock_auto(ts,dlen); 
			} 
			if(!ok) 
			{ 
				//reset 
				tcp_reset_net(netbuf, rdlen); 
			} 
		} 
 
	} 
 
} 
/*--------------------------- 
deal sock data and update sock state 
rxortx:if rx 1,else if tx 0 
----------------------------*/ 
 
void tcp_sock_auto(TCP_SOCK *ts,WORD dlen,bit rxortx) 
{ 
    BYTE rflags=0; 
	BYTE upcall=1; 
    WORD txlen=0; 
	WORD tx=0; 
    static WORD eport=mineport; 
//    WORD (*upcall)(TCP_SOCK *ts, CONN_STATE conn); 
	//CONN_STATE conn; 
//	server_upcall=server_action; 
//	client_upcall=client_action; 
	if(dlen) 
		dlen=ts->rxbuf.dlen; 
//    upcall = ts->server ? server_upcall : client_upcall; 
    if (rxortx) 
    { 
		ts->rxbuf.yesornot=0; 
        rflags = ts->rxbuf.flags; 
        if (rflags & TRST) 
            tcp_newstate(ts, TCP_RSTR); 
        else if (rflags&TACK && 
                 ts->rxack>=ts->txbuf.out && ts->rxack<=ts->txbuf.trial) 
            ts->txbuf.out = ts->rxack; 
    } 
    // Passive (remote) open a connection  
    if(ts->state==TCP_CLOSED) 
	{ 
        if (rflags == TSYN)                     // If closed & SYN received..  
        { 
            buff_setall(&ts->rxbuf, ++ts->rxseq); // Load my ACK value  
            buff_setall(&ts->txbuf, get_current()*0x100L); // ..and my SEQ  
            ts->rxwin = TCP_RXWIN;              // Default Rx window  
            ts->connflags = 0;                  // No special flags  
            if (upcall && !tcp_upcall(ts, TCP_OPEN,1)) // Upcall err?  
                tcp_reset_ts(ts, dlen); // ..don't accept SYN  
            else 
            { 
                tcp_newstate(ts, TCP_SYNR);        // If OK, send SYN+ACK  
                tcp_make_sock(ts, TSYN+TACK, 0); 
                ts->server = 1;                 // Identify as server socket  
            } 
        } 
        else                                    // If not SYN..  
            tcp_reset_ts(ts, dlen); // ..send reset  
	} 
    else if(ts->state==TCP_SYNR)                              // SYN+ACK sent, if ACK Rx..  
	{ 
        if (rflags==TACK && ts->rxseq==ts->rxbuf.in && ts->rxack==ts->txbuf.out) 
        { 
            if (upcall && !tcp_upcall(ts, TCP_CONN,ts->server))// If upcall not OK..  
                tcp_newstate(ts, TCP_ACLOSE);      // ..close after sending data  
            else                                // If OK..  
                 tcp_newstate(ts, TCP_EST);        // ..go established  
        } 
        else if (dlen && ts->rxseq==ts->rxbuf.in-1)   // If repeat SYN..  
            tcp_make_sock(ts, TSYN+TACK, 0); 
	} 
    // Connection established  
    else if(ts->state==TCP_EST) 
	{ 
        if (rflags)                                 // Refresh timer if Rx  
            tcp_newstate(ts, ts->state); 
        if (rflags & TFIN && ts->rxseq==ts->rxbuf.in)   // If remote close..  
        { 
            if (!upcall || tcp_upcall(ts, TCP_CLOSE,ts->server)) 
            { 
                tcp_newstate(ts, TCP_LASTACK);         // ..FIN+ACK if OK  
                tcp_make_sock(ts, TFIN+TACK, 0); 
            } 
            else 
            { 
                tcp_newstate(ts, TCP_CLWAIT);          // ..or send data if not  
                tcp_tsestab_tx(ts, 1); 
            } 
        } 
        else 
        { 
            if (upcall && !tcp_upcall(ts, dlen>0 ? TCP_DATA : TCP_NODATA,ts->server)) 
            { 
                tcp_newstate(ts, TCP_ACLOSE);      // If upcall 0, start close  
                tx = 1; 
            } 
            else if (dlen > 0)                  // If Rx data, send ack  
                tx = 1; 
				//tx=0; 
            tcp_tsestab_tx(ts,tx);// Send packet, maybe Tx data  
        } 
	} 
    // Passive (remote) close a connection  
    else if(ts->state==TCP_CLWAIT)                            // Do upcall to application  
	{ 
        if (!upcall || tcp_upcall(ts, TCP_CLOSE,ts->server))   // If OK, send FIN  
        { 
            tcp_newstate(ts, TCP_LASTACK); 
            tcp_make_sock(ts, TFIN+TACK, 0); 
        } 
        else                                    // If not, keep open  
            tcp_tsestab_tx(ts, 0); 
	} 
    else if(ts->state==TCP_LASTACK)                           // If ACK of my FIN..  
	{ 
        if (rflags==TACK && ts->rxseq==ts->rxbuf.in+1) 
            tcp_newstate(ts, TCP_CLOSED);          // ..connection closed  
	} 
    // Active (local) open a connection  
    else if(ts->state==TCP_AOPEN) 
	{ 
        ts->server = 0;                         // Identify as client socket  
        buff_setall(&ts->txbuf, get_current()*100L);   // ARPed: set my SEQ value  
        ts->rxwin = TCP_RXWIN;                  // Default window size  
        ts->connflags = 0;                      // No special flags  
        ts->locport = ++eport>=maxeport ? mineport : eport;// New port num  
        if (upcall)                             // Do upcall  
            tcp_upcall(ts, TCP_OPEN,ts->server); 
        tcp_newstate(ts, TCP_SYNS); 
        tcp_make_sock(ts, TSYN, 0); 
	} 
    else if(ts->state==TCP_SYNS)                              // Sent SYN, if SYN+ACK Rx  
	{ 
        if (rflags==TSYN+TACK && ts->rxack==ts->txbuf.out) 
        { 
            buff_setall(&ts->rxbuf, ts->rxseq+1); // Set my ACK value  
            if (upcall)                         // Do upcall  
                tcp_upcall(ts, TCP_CONN,ts->server); 
            tcp_newstate(ts, TCP_EST);             // ..send ACK, go established  
            tcp_make_sock(ts, TACK, 0); 
        } 
        else if (rflags)                        // If anything else..  
            tcp_reset_ts(ts, dlen); // ..send reset  
	} 
    // Active (local) close a connection  
    else if(ts->state==TCP_ACLOSE) 
	{ 
        if (buff_dlen(&ts->txbuf))                // If any Tx data left..  
            tcp_tsestab_tx(ts,0); // If unsent, send it  
        else                                    // All data sent: close conn  
        { 
            if (upcall)                         // Do upcall  
                tcp_upcall(ts, TCP_CLOSE,ts->server); 
            tcp_newstate(ts, TCP_FINWT1); 
            tcp_make_sock(ts, TFIN+TACK, 0); 
        } 
	} 
    else if(ts->state==TCP_FINWT1) 
	{ 
        if (rflags&TFIN && ts->rxseq==ts->rxbuf.in) 
        { 
            if (rflags&TACK && ts->rxack==ts->txbuf.trial+1) 
                tcp_newstate(ts, TCP_TWAIT);       // If ACK+FIN, close  
            else if (!(rflags&TACK) || ts->rxack==ts->txbuf.trial) 
                tcp_newstate(ts, TCP_CLING);       // If FIN, wait for ACK  
            tcp_make_sock(ts, TACK, 0); 
        } 
        else if (rflags&TACK && ts->rxack==ts->txbuf.trial+1) 
            tcp_newstate(ts, TCP_FINWT2);          // If just ACK, half-close  
	} 
    else if(ts->state==TCP_FINWT2)                            // Half-closed: awaiting FIN  
	{ 
        if (rflags&TFIN && ts->rxseq==ts->rxbuf.in) 
        { 
            tcp_newstate(ts, TCP_TWAIT);           // Got FIN, close  
            tcp_make_sock(ts, TACK, 0); 
        } 
	} 
    else if(ts->state==TCP_CLING)                             // Closing: need final ACK  
	{ 
        if (rflags==TACK && ts->rxseq==ts->rxbuf.in+1) 
            tcp_newstate(ts, TCP_CLOSED); 
	} 
    else if(ts->state==TCP_TWAIT)                             // Timed wait: just close!  
		tcp_newstate(ts, TCP_CLOSED); 
    else  
        tcp_newstate(ts, TCP_CLOSED); 
} 
 
/* Put Rx data into an established socket, return non-zero if Tx ACK required */ 
WORD tcp_tsestab_rx(TCP_SOCK *ts, tcppacket *tcp, WORD dlen) 
{ 
    WORD oset=0, oldlen, tx=0; 
    WORD rdlen=0; 
    DWORD rxdiff; 
	WORD mss; 
 
    if (dlen > 0)                               // If any data received..  
    { 
        oset = gettcp_opt(tcp, &mss); 
		if(oset>=4) 
			ts->txmss=mindata(mss,(WORD)TCP_MAXDATA); 
        rxdiff = ts->rxseq - ts->rxbuf.in;        // Find posn w.r.t. last data  
        if (rxdiff == 0)                        // If next block, accept it  
            rdlen = (WORD)dlen; 
        else if (rxdiff < 0)                    // If part or all is a repeat  
        { 
            oldlen = -(WORD)rxdiff;              // ..read in new part  
            if (oldlen<=ts->rxwin && dlen>oldlen) 
            { 
                rdlen = dlen - oldlen; 
                oset += (WORD)oldlen; 
            } 
        } 
        if (rdlen)                               // Read the data in  
            buff_in(&ts->rxbuf, &tcp->tcpdata[oset], rdlen); 
        tx = tcp->t.flags&TPUSH || rxdiff<0 || buff_dlen(&ts->rxbuf)>ts->rxwin/2; 
    } 
    return(tx); 
} 
/* Prepare Tx frame containing outgoing data for connection, return frame len 
** If 'force' is non-zero, make frame even if there is no data */ 
void tcp_tsestab_tx(TCP_SOCK *ts,WORD force) 
{ 
    WORD tdlen, txlen=0; 
 
    tdlen = mindata(buff_untriedlen(&ts->txbuf), ts->txmss); 
    tdlen = mindata(tdlen, ts->txwin-buff_trylen(&ts->txbuf)); 
    if (tdlen>0 && !force) 
        force = buff_trylen(&ts->txbuf)==0 || tdlen < ts->txmss/2; 
    if (force) 
        tcp_make_sock(ts, (BYTE)(TACK+ts->connflags), (WORD)tdlen); 
//    return(txlen); 
} 
 
void tcp_remake_sock(TCP_SOCK *ts) 
{ 
    WORD txlen=0; 
 
    if (ts->state==TCP_EST||ts->state==TCP_CLWAIT||ts->state==TCP_ACLOSE) 
    { 
        ts->txbuf.trial = ts->txbuf.out; 
        tcp_tsestab_tx(ts, 1); 
    } 
    else if (ts->state) 
        tcp_make_sock(ts, ts->txflags, 0); 
//    return(txlen); 
} 
//reset tcp with netcard type 
 
void tcp_reset_net(netcard *netbuf, WORD rdlen) 
{ 
    tcppacket *tcp; 
    DWORD ack; 
	WORD port,hlen; 
 
    tcp=(tcppacket *)netbuf->etherframe.packet; 
    ack = tcp->t.seq + (rdlen>0?rdlen:0); 
    if (tcp->t.flags & (TSYN+TFIN)) 
        ack++; 
	 
    tcp->t.seq = tcp->t.ack;                   // Set seq and ack values  
    tcp->t.ack = ack; 
    tcp->t.window = 0;             // Window size, srce & dest port nums  
    port=tcp->t.sport; 
	tcp->t.sport=tcp->t.dport; 
    tcp->t.dport = port; 
    hlen = sizeof(tcpheader);              // TCP header len  
    tcp->t.hlen = (BYTE)(hlen<<2);      // Set TCP header len, and flags  
    tcp->t.flags = TRST+TACK; 
    tcp->t.urgent = tcp->t.check = 0; 
    tcp->t.check = ~tcp_check(tcp, mypara.myip, tcp->i.srcip, hlen); 
	ip_send(netbuf,tcp->i.srcip,&netbuf->etherframe.sourcenodeid[0],PTCP,hlen); 
} 
//reset tcp in TCP_SOCK type 
void tcp_reset_ts(TCP_SOCK *ts, WORD rdlen) 
{ 
    DWORD ack; 
 
    ack = ts->rxseq + (rdlen>0?rdlen:0); 
    if (ts->rxbuf.flags & (TSYN+TFIN)) 
        ack++; 
	ts->txbuf.flags=TRST+TACK; 
	ts->txbuf.acknum=ack; 
	ts->txbuf.seqnum=ts->rxack; 
	ts->txbuf.dlen=0; 
	ts->txbuf.yesornot=1; 
	ts->rxwin=0; 
} 
/*---------------------------------------- 
 
----------------------------------------*/ 
WORD tcp_upcall(TCP_SOCK *ts, CONN_STATE conn,BYTE server) 
{ 
	WORD ok; 
	if(server) ok=server_action(ts,conn); 
	else ok=client_action(ts,conn); 
	return ok; 
} 
 
/*EOF*/