TheNetNode-CB/src/l3tcp.c

857 lines
34 KiB
C
Raw Permalink Normal View History

2019-05-15 00:19:53 +02:00
#include "tnn.h"
#ifdef TCP_STACK
LHEAD rxSegment; /* RX TCP-Segment. */
LHEAD txSegment; /* TX TCP-Segment. */
LHEAD rxDaten; /* RX-Buffer. */
static void StackRX(void); /* Eingehende RX Segmente. */
static void StackState(void); /* Statusanderungen. */
static void StackTX(void); /* Ausgehende TX Segmente. */
/* Initialisiere, */
void StackInitTCP(void)
{
inithd(&rxSegment); /* Frame fuer Empfangs-Liste. */
inithd(&txSegment); /* Frame fuer Sende-Liste. */
inithd(&rxDaten); /* RX-Bufferung. */
}
/* TCP-Service */
void StackSRV(void)
{
StackRX(); /* Eingehende RX-Segmente. */
StackState(); /* Statusaenderungen. */
StackTX(); /* Ausgehende TX-Segmente. */
}
/* Neues TX-Segment in die Sende-Liste anlegen/anhaengen. */
void PutTXStack(register int i , /* SOCKET */
MBHEAD *Data, /* Daten ohne TCP-Header. */
int DataLen, /* Datenlaenge. */
unsigned short Flags, /* TCP-Flag. */
unsigned char TState) /* Sendestatus. */
{
STACKTX *TSeq;
if ((TSeq = (STACKTX *)allocb(ALLOC_TCPSTACK)) == NULL) /* Buffer besorgen. */
{
sockets[i].TState = TCP_RSTSENT; /* Kein Speicher,Verbindung zuruecksetzen*/
return;
}
TSeq->Sock = i; /* Socket setzen. */
TSeq->Data = Data; /* Daten setzen. */
TSeq->Flags = Flags; /* TCP-Flag setzen. */
TSeq->TState = TState; /* Sende-Status setzen. */
TSeq->TimeLast = time(NULL);
TSeq->Timer = 0; /* Timer zuruecksetzen. */
TSeq->Retry = 0; /* Retry zuruecksetzen. */
++sockets[i].PacNum; /* Ein Frame mehr in der Sende-Liste. */
relink((LEHEAD *)TSeq, (LEHEAD *)txSegment.tail); /* In die Sende-Liste */
} /* haengen. */
/* Entsorge alle RX-Daten. */
static void DelDatenRX(int Sock)
{
DATENRX *Drx;
DATENRX *DrxPrev;
for (Drx = (DATENRX *)rxDaten.head; /* Durchsuche RX-Datenliste. */
Drx != (DATENRX *)&rxDaten;
Drx = DrxPrev)
{
DrxPrev = Drx->next;
if (Drx->Sock != Sock) /* Socketvergleich. */
continue; /* Zum naechsten Eintrag. */
if (Drx->Data != NULL) /* Wenn es Daten gibt, */
dealmb(Drx->Data); /* entsorgen. */
dealoc((MBHEAD *)ulink((LEHEAD *)Drx)); /* RX-Segment entsorgen. */
}
}
/* Entsorge alle TX-Segment. */
static void DelTXSegment(int Sock)
{
STACKTX *TSeq;
for (TSeq = (STACKTX *)txSegment.head; /* Durchsuche die TX-Segmentliste. */
TSeq != (STACKTX *)&txSegment;
TSeq = TSeq->next)
{
if (TSeq->Sock != Sock) /* Socketvegleich. */
continue; /* Zum naechsten Eintrag. */
if (TSeq->Data != NULL) /* Wenn es daten gibt, */
dealmb(TSeq->Data); /* entsorgen. */
dealoc((MBHEAD *)ulink((LEHEAD *)TSeq)); /* TX-Segment entsorgen. */
return;
}
}
/* Entsorge alle Buffer vom Socket. */
void DelSock(int Sock)
{
DelDatenRX(Sock); /* RX-Daten entsorgen. */
DelTXSegment(Sock); /* TX-Segmente entsorgen. */
DelSocket(Sock); /* Socket entsorgen. */
}
/* Einen Eintrag aus der RX-Liste holen. */
DATENRX *GetBuffer(TSOCKET *Sock)
{
DATENRX *Drx;
for (Drx = (DATENRX *)rxDaten.head; /* Durchsuche die RX-Liste. */
Drx != (DATENRX *)&rxDaten;
Drx = Drx->next)
{
if (Sock->Socket != Drx->Sock) /* Socketvergleich. */
continue; /* Zum naechsten Socket. */
return(Drx); /* Aktueller Eintrag. */
}
return(NULL); /* Kein Eintrag gefunden. */
}
/* Eingehende TCP-Daten weiterleiten in die RX-Segmentliste. */
void TCPIPProcess(register IP *ip,
register MBHEAD *bp)
{
MBHEAD *Data;
STACKRX *RSeq;
if ((Data = (MBHEAD *)allocb(ALLOC_MBHEAD)) == NULL) /* Buffer besorgen. */
return; /* Kein Speicher, Empfangsbuffer entsorgt der IP-Router. */
while (bp->mbgc != bp->mbpc) /* Alle Zeichen in den Buffer schreiben. */
putchr(getchr(bp), Data);
rwndmb(Data); /* Buffer zurueckspulen. */
if ((RSeq = (STACKRX *)allocb(ALLOC_TCPSTACK)) == NULL)/* RX-Segment besorgen.*/
{
dealmb(Data); /* Kein Speicher, Buffer entsorgen. */
return;
}
RSeq->Data = Data; /* Empfang-Daten setzen. */
RSeq->IpHdr = ip; /* IP-Header setzen. */
relink((LEHEAD *)RSeq, (LEHEAD *)rxSegment.tail); /* Umhaengen in die */
return; /* Empfangs-Liste. */
}
/* TCP-Header lesen. */
void ReadTcpHeader(TCP *tcp,
IP *ip,
MBHEAD *bp)
{
int temp_flag;
tcp->srcPort = get16(bp); /* Port-Nummer der Quelle. */
tcp->dstPort = get16(bp); /* Port-Nummer des Ziel. */
tcp->seqnum = get32(bp); /* Sequenznummer des 1. Datenbytes */
/* in diesem Segment. */
tcp->acknum = get32(bp); /* Bestaetigungsnummer. */
temp_flag = get16(bp); /* Flags einlesen. */
tcp->data_offset = (temp_flag >> 12) & 0x0f; /* Datenworte im header. */
tcp->res = (temp_flag >> 6) & 0x3f; /* nicht benutzt -> 0.*/
tcp->flags = temp_flag & 0x3f; /* URG,ACK,PSH,RST,SYN & FIN. */
tcp->window = get16(bp); /* Groesse des Buffers fuer diese Verb. */
tcp->checksum = get16(bp); /* CRC-Checksum. */
tcp->urgentPointer = get16(bp); /* Fuer wichtige Daten. */
if (tcp->flags == TSYN) /* Verbindungsaufbau. */
{
int DataLen = 0,
options = 0,
i = 0;
/* Gesamtlaenge ermitteln */
DataLen = ((tcp->data_offset * 4) + (ip->ihl * 4));/* (TCP-Header + Daten).*/
options = (DataLen - TCP_HEADER); /* Optionslaenge ermitteln */
/* (Data - TCP-Header abziehen). */
options = options / 2;
for (i = 0; i < options; i++)
tcp->options[i] = (char)get16(bp); /* Optionen setzen. */
}
}
/* Entsorge alte TX-Segmente. */
void DelSegment(register int i,
TCP *tcp)
{
STACKTX *TSeq;
for (TSeq = (STACKTX *)txSegment.head; /* Durchsuche alle TX-Segmente. */
TSeq != (STACKTX *)&txSegment;
TSeq = TSeq->next)
{
if (TSeq->Sock != sockets[i].Socket) /* Socketvergleich. */
continue; /* Zum naechsten Segment. */
if (sockets[i].SendNext == tcp->acknum) /* Frame uebertragen. */
{
--sockets[i].PacNum; /* Ein Frame weniger. */
sockets[i].SendEvent = TRUE; /* Select signalisieren - weiter senden. */
if (TSeq->Data != NULL) /* Nur wenn es Daten gibt. */
dealmb(TSeq->Data); /* Buffer leeren/entsorgen. */
dealoc((MBHEAD *)ulink((LEHEAD *)TSeq)); /* TX Segment entsorgen. */
return;
}
else /* Frame konnte nicht uebertragen werden. */
{
if (sockets[i].TState != TCP_RSTSENT)
sockets[i].SendEvent = FALSE; /* Select signalisieren - keine */
} /* weiteren Frame senden. */
}
}
/* Daten auslesen und fuer Funktion Recv bereitstellen. */
BOOLEAN ReadBuffer(register IP *ip,
register TCP *tcp,
register int i,
MBHEAD *bp)
{
DATENRX *Drx;
unsigned int DataLen = 0;
/* Gesamtlaenge ermitteln (TCP-Header + Daten). */
DataLen = (ip->length) - ((tcp->data_offset * 4) + (ip->ihl * 4));
if (DataLen >= TCP_HEADER)
DataLen -= TCP_HEADER; /* TCP-Header abziehen. */
else
DataLen = 0;
if (DataLen) /* Es gibt Daten. */
{
if ((Drx = (DATENRX *)allocb(ALLOC_TCPSTACK)) == NULL) /* Besorge Buffer. */
return(TRUE); /* Speicher ist voll. */
/* Besorge Buffer. */
if ((Drx->Data = (MBHEAD *)allocb(ALLOC_TCPSTACK)) == NULL)
{
dealoc((MBHEAD *)ulink((LEHEAD *)Drx)); /* Buffer entsorgen. */
return(TRUE); /* Speicher ist voll. */
}
Drx->Sock = sockets[i].Socket; /* Socket setzen. */
sockets[i].RecvEvent = TRUE; /* Select Siginalisieren, */
/* wir haben was empfangen. */
sockets[i].RecvNext += DataLen; /* Daten an den Seq-Wert anhaengen. */
while (DataLen--) /* Daten in Buffer schreiben. */
putchr(getchr(bp), Drx->Data);
rwndmb(Drx->Data); /* Buffer zurueckspulen. */
relink((LEHEAD *) Drx, (LEHEAD *)rxDaten.tail); /* RX-Liste umhaengen. */
}
return(FALSE); /* Frame angenommen. */
}
/* Eingehende RX-Segment analysieren. */
int ReadRXStack(TCP *tcp, IP *ip, MBHEAD *bp)
{
register int i;
for (i = 1; i < NUM_SOCKETS; ++i) /* Durchsuche die Socketliste. */
{
switch(sockets[i].State) /* Socket status. */
{
case TCP_LISTEN: /* LISTEN-Modus. */
if (tcp->flags != TSYN) /* Nur annehmen, wenn neue Verbindung. */
continue; /* Ansonsten zum naechsten Eintrag. */
if (sockets[i].LocalPort != tcp->dstPort) /* Portvergleich. */
continue; /* Zum naechsten Eintrag. */
if (tcp->flags == TSYN)
{
if (sockets[i].Listen++ >= sockets[i].MaxListen)/* in die Warteschlange. */
continue; /* Warteschlange ist voll, zum naechsten eintrag. */
}
/* Verbindungsaufbau starten. */
sockets[i].IpDest = ip->source;/* Empfaenger, IP-Adresse setzen. */
sockets[i].tos = ip->tos; /* Type of Service setzen. */
sockets[i].RecvEvent = TRUE; /* Select signalisieren - */
/* wir haben was empfangen. */
sockets[i].DestPort = tcp->srcPort; /* Port-Nummer vom Ziel. */
sockets[i].UrgPointer = tcp->urgentPointer; /* Flags einlesen. */
sockets[i].RecvNext = tcp->seqnum + 1;
sockets[i].SendUnacked = 1;
sockets[i].SendNext = sockets[i].SendUnacked + 1;
return(i); /* Socket uebergeben. */
case TCP_CONNECTED: /* CONNECTED-Modus. */
if (sockets[i].DestPort != tcp->srcPort) /* Destportvergleich! */
continue;
return(i); /* Unser gesuchter Socket. */
}
}
return(EOF); /* Nix gefunden. */
}
/* Verbindung nicht annehmen/zuruecksetzen. */
void SendRST(IP *ip, TCP *tcp)
{
register int NewSock;
/* Neuen Socket anlegen. */
if ((NewSock = Socket(AF_INET, SOCK_STREAM, 0)) == EOF)
return; /* Neuer Socket kann nicht erstellt werden. */
sockets[NewSock].IpDest = ip->source;
sockets[NewSock].LocalPort = tcp->dstPort;
sockets[NewSock].DestPort = tcp->srcPort;
sockets[NewSock].SendUnacked= tcp->acknum;
sockets[NewSock].RecvNext = tcp->seqnum + 1;
SendTcpFlag(NewSock, /* Frame an den Nachbarn senden. */
NULL,
0,
(TACK + TRST),
0,
0);
DelSock(NewSock); /* Socket entsorgen. */
}
/* ACK-Statusaendernungen. */
void StateACK(register int i, TCP *tcp)
{
if ( (sockets[i].SendUnacked != tcp->acknum) /* Noch nicht aktualisiert, */
&&(tcp->window != 0)) /* wenn noch was ins Fenster passt!. */
sockets[i].SendUnacked = tcp->acknum; /* ACK-Aktualisieren. */
switch(sockets[i].TState) /* Aktueller Status. */
{
/* Status schliessen: */
case TCP_PSHWAITFIN : /* Sende alle offenstehende Packete. */
if (tcp->window == 0) /* Nachbar kann keine Daten mehr annehmen. */
sockets[i].SendEvent = FALSE; /* Select signalisieren, keine weiteren Frame senden */
else /* Nachbar kann daten annehmen. */
{
if (sockets[i].PacNum) /* Es gibt noch Frame. */
{ /* Neuer Status: */
sockets[i].TState = TCP_PSHSENTFIN; /* Naechstes Packet senden. */
sockets[i].SendEvent = TRUE;/* Select signalisieren, weiter senden.*/
}
else /* Neuer Status: */
sockets[i].TState = TCP_FINSENT; /* Socket sofort schliessen. */
}
break;
case TCP_ACKWAIT : /* Status Stabil: Warte auf ACK-Bestaetigung. */
if (tcp->window == 0) /* Nachbar kann keine Daten mehr annehmen . */
sockets[i].SendEvent = FALSE;/* Select signalisieren, keine weiteren Frame senden. */
else /* Nachbar kann daten annehmen. */
{ /* Neuer Status: */
sockets[i].TState = TCP_ESTABLISHED; /* Verbindung stabil. */
sockets[i].SendEvent = TRUE; /* Select Signalisieren, */
} /* weitere Frames senden. */
break;
/* Status schliessen: */
case TCP_ACKWAITFIN : /* Warte auf ACK, danach FIN senden. */
sockets[i].TState = TCP_FINSENT; /* Neuer Status: */
/* Socket sofort schliessen. */
sockets[i].SendEvent = TRUE;/* Select Signalisieren, weitere Frames senden. */
break;
case TCP_FINACKWAIT : /* Status schliessen: Warte auf ACK-Bestaetigung. */
sockets[i].TState = TCP_FINWAIT; /* Neuer Status: */
/* Warte auf FIN & ACK-Bestaetigung. */
sockets[i].SendEvent = TRUE;/* Select Signalisieren, weitere Frames senden. */
break;
/* Status schliessen: */
case TCP_ACKWAITCLOSED : /* Warte auf ACK-Bestaetigung, Socket entfernen. */
sockets[i].TState = TCP_CLOSED; /* Entsorge Socket. */
break;
}
}
/* RX-Segmente analysieren. */
static void StackRX(void)
{
STACKRX *RSeq;
register int i;
static TCP tcp;
while ((RSeq = (STACKRX *)rxSegment.head) != (STACKRX *)&rxSegment)
{
ReadTcpHeader(&tcp, RSeq->IpHdr, RSeq->Data); /* TCP-Header lesen. */
/* Eingehende RX-Segment analysieren. */
if ((i = ReadRXStack(&tcp, RSeq->IpHdr, RSeq->Data)) != EOF)
{
ReadBuffer(RSeq->IpHdr, &tcp, i, RSeq->Data);
switch (tcp.flags)
{
case (TACK + TFIN) : /* Nachbar will sofort getrennt werden. */
sockets[i].RecvEvent = TRUE; /* Select signalisieren, wir haben was empfangen. */
sockets[i].SendEvent = TRUE; /* Select signalisieren, weitere Frames senden. */
if ( (sockets[i].TState == TCP_ESTABLISHED) /* Verbindung stabil. */
||(sockets[i].TState == TCP_ACKWAIT)
||(sockets[i].TState == TCP_PSHSENTFIN))
{
sockets[i].RecvNext += 1; /* Bei Bestaetigung um ein erhoehen. */
SendTcpFlag(i, /* ACK & FIN mit ACK-bestaetigen. */
NULL,
0,
TACK,
WINSIZE,
0);
/* Neuer Status: ACK & FIN */
sockets[i].TState = TCP_FINSENTCLOSED;/* an den Nachbarn schicken.*/
}
if (sockets[i].TState == TCP_FINWAIT) /* FIN & ACK-Bestaetigung erhalten. */
{
sockets[i].RecvNext += 1; /* Seq-Wert um eins erhoehen. */
SendTcpFlag(i, /* ACK-Bestaetigung senden. */
NULL,
0,
TACK,
WINSIZE,
0);
sockets[i].TState = TCP_CLOSED;/* Socket kann geschlossen werden. */
}
break;
case (TACK + TPSH + TFIN) : /* Nachbar will sofort getrennt werden. */
sockets[i].RecvEvent = TRUE;/* Select signalisieren, wir haben was empfangen. */
sockets[i].SendEvent = TRUE;/* Select signalisieren, weitere Frames senden. */
SendTcpFlag(i, /* Verbindung zuruecksetzen. */
NULL,
0,
TRST,
WINSIZE,
0);
sockets[i].TState = TCP_CLOSED; /* Neuer Status: Socket entsorgen. */
break;
case (TACK) : /* ACK-Bestaetigung. */
StateACK(i, &tcp);
break;
case (TACK + TPSH) : /* Es sind Daten im Header. */
if (sockets[i].SendUnacked != tcp.acknum)
sockets[i].SendUnacked = tcp.acknum;
sockets[i].SendEvent = TRUE;
SendTcpFlag(i, /* ACK-Bestaetigung senden. */
NULL,
0,
TACK,
WINSIZE,
0);
/* Neuer Status: */
sockets[i].TState = TCP_ESTABLISHED; /* Verbindung stabil. */
break;
case (TRST) : /* Verbindung zuruecksetzen. */
sockets[i].TState = TCP_RSTSENT; /* Socket entsorgen. */
sockets[i].SendEvent = TRUE;
DelSock(i);
break;
}
DelSegment(i, &tcp);
}
else
SendRST(RSeq->IpHdr, &tcp); /* Verbindung nicht annehmen/zuruecksetzen. */
dealmb(RSeq->Data); /* Buffer entsorgen. */
dealoc((MBHEAD *)ulink((LEHEAD *)RSeq)); /* RX-Segment entsorgen. */
}
}
/* Je nach Status reagieren. */
static void StackState(void)
{
register int i;
for (i = 1; i < NUM_SOCKETS; ++i) /* durchsuche alle Socket. */
{ /* Socket mit Status */
if ( (sockets[i].State == TCP_CLOSED) /* Socket unbenutzt */
||(sockets[i].State == TCP_LISTEN) /* Listen */
||(sockets[i].TState == TCP_ESTABLISHED) /* Stabile Verbindung und */
||(sockets[i].TState == TCP_PSHSENT)) /* Frame senden nicht beachten. */
continue; /* Zum naechsten Socket. */
switch(sockets[i].TState) /* Socket-Status. */
{
case TCP_SYNCON: /* Verbindungsaufbau bestaetigen. */
PutTXStack(i, /* SYN & ACK senden.*/
NULL,
0,
(TSYN + TACK),
TCP_SYNCON);
sockets[i].TState = TCP_PSHSENT;
continue; /* Zum naechsten Socket. */
case TCP_FINSENT: /* Status schliessen: Socket sofort schliessen. */
PutTXStack(i, /* FIN & ACK senden. */
NULL,
0,
(TACK + TFIN),
TCP_FINSENT);
sockets[i].TState = TCP_PSHSENT; /* Neuer Status: Frames senden. */
continue; /* Zum naechsten Socket. */
/* Status schliessen: */
case TCP_FINSENTCLOSED : /* Nach ACK-Bestaetigung, FIN & ACK-Senden.*/
PutTXStack(i, /* FIN & ACK senden. */
NULL,
0,
(TACK + TFIN),
TCP_FINSENTCLOSED);
sockets[i].TState = TCP_PSHSENT; /* Neuer Status: Frames senden. */
continue; /* Zum naechsten Socket. */
/* Status schliessen: */
case TCP_PSHSENTFIN : /* Naechstes Frame senden. */
if (!sockets[i].PacNum) /* Alle Frame gesendet. */
sockets[i].TState = TCP_FINSENT; /* Neuer Status: FIN & ACK senden. */
continue; /* Zum naechsten Socket. */
case TCP_RSTSENT : /* Status schliessen: Verbindung zuruecksetzen. */
PutTXStack(i, /* Frame mit Flag RST senden. */
NULL,
0,
TRST,
TCP_RSTSENT);
sockets[i].TState = TCP_PSHSENT; /* Neuer Status: Frames senden. */
continue; /* Zum naechsten Socket. */
case TCP_CLOSED : /* Socket leeren/entsorgen. */
DelSock(i);
return;
}
}
}
/* Frame senden. */
static void StackTX(void)
{
STACKTX *TSeq;
register int i;
time_t now;
for (TSeq = (STACKTX *)txSegment.head; /* Durchsuche alle Socket. */
TSeq != (STACKTX *)&txSegment;
TSeq = TSeq->next)
{
if ((i = SearchSock(TSeq->Sock)) == EOF) /* Socket ermitteln. */
{ /* Socket wurde mittlerweile geschlossen. */
if (TSeq->Data != NULL) /* Gibt es Daten. */
dealmb((MBHEAD *)TSeq->Data); /* Buffer leeren/entsorgen. */
dealoc((MBHEAD *)ulink((LEHEAD *)TSeq)); /* TX Segment entsorgen. */
return;
}
if (TSeq->Timer) /* Timer laeuft. */
{
now = time(NULL);
if (TSeq->TimeLast < now)
{
TSeq->TimeLast = time(NULL);
if (TSeq->Timer < 20)
{
++TSeq->Timer;
continue;
}
/* Max. versuche ueberschritten. */
if (TSeq->Retry >= TCP_MAX_RETRY)
{
/* Socket soll geschlossen werden. */
if (sockets[i].TState == TCP_CLOSE)
{
/* Socket schliessen. */
sockets[i].TState = TCP_CLOSED;
/* zum naechsten Frame. */
continue;
}
/* Socket soll geschlossen werden. */
sockets[i].TState = TCP_CLOSE;
/* Select signalisieren. */
sockets[i].RecvEvent = TRUE;
sockets[i].SendEvent = TRUE;
continue;
}
++TSeq->Retry;
TSeq->Timer = 0;
if (TSeq->Data != NULL)
rwndmb(TSeq->Data);
sockets[i].TState = TCP_PSHSENT;
}
}
if ( (sockets[i].TState == TCP_PSHSENT) /* Frame an den Nachbarn senden */
||(sockets[i].TState == TCP_ESTABLISHED) /* wenn Verbindung stabil. */
||(sockets[i].TState == TCP_PSHSENTFIN)) /* Socket soll geschloessen */
{ /* werden, vorher alle Frames senden. */
SendTcpFlag(i, /* Frame senden. */
TSeq->Data,
(TSeq->Data == NULL ? 0 : TSeq->Data->mbpc - TSeq->Data->mbgc),
TSeq->Flags,
WINSIZE,
(unsigned short)(TSeq->Flags == (TSYN + TACK) ? TCP_OPTION : FALSE));
if ((unsigned short)(TSeq->Flags == (TSYN + TACK)))
{
sockets[i].TState = TCP_ACKWAIT; /* Warte auf ACK-Bestaetigung. */
++TSeq->Timer; /* Timer starten. */
continue; /* Zum naechsten Frame. */
}
switch(TSeq->TState) /* Statusaendung. */
{
case TCP_ESTABLISHED : /* Status: Stabile Verbindung. */
case TCP_PSHSENT : /* Status: Frame senden. */
if (sockets[i].TState == TCP_PSHSENTFIN)
{
sockets[i].TState = TCP_PSHWAITFIN;/* offenstehende Frames senden */
++TSeq->Timer; /* Timer starten. */
continue; /* Zum naechsten Frame. */
}
/* Neuer Status: */
sockets[i].TState = TCP_ACKWAIT; /* Warte auf ACK-Bestaetigung. */
++TSeq->Timer; /* Timer starten. */
continue; /* Zum naechsten Frame. */
case TCP_PSHSENTFIN : /* Status schliessen: Naechstes Packet senden. */
sockets[i].TState = TCP_PSHWAITFIN;/* Status: Warte auf ACK-Meldung.*/
++TSeq->Timer; /* Timer starten. */
continue; /* Zum naechsten Frame. */
case TCP_FINSENT :/* Status schliessen: Socket soll geschlossen werden*/
sockets[i].TState = TCP_FINACKWAIT; /* Neuer Status: Warte auf ACK. */
++TSeq->Timer; /* Timer starten. */
continue; /* Zum naechsten Frame. */
/* Status schliessen: */
case TCP_FINSENTCLOSED : /* Nach ACK-Bestaetigung, FIN & ACK-Senden.*/
sockets[i].TState = TCP_ACKWAITCLOSED;/* Neuer Status: Warte auf ACK*/
++TSeq->Timer; /* Timer starten. */
continue; /* Zum naechsten Frame. */
case TCP_RSTSENT : /* Verbindung zuruecksetzen. */
sockets[i].TState = TCP_CLOSED; /* Neuer Status: .Socket schliessen.*/
++TSeq->Timer; /* Timer starten. */
continue; /* Zum naechsten Frame. */
default: /* Fuer alle restlichen Status. */
continue; /* Zum naechsten Frame. */
}
}
}
}
/* TCP-Header zusammenbasteln. */
MBHEAD *
htontcp(register int i, /* Aktueller Socket. */
MBHEAD *Data, /* evl. Daten. */
unsigned short flags, /* TCP-Flags. */
unsigned short tcp_len, /* Headerlaenge. */
unsigned short WinSize, /* Fenstergroesse. */
BOOLEAN options) /* evl. Optionen. */
{
register MBHEAD *bp;
PSEUDO_HEADER pseudo_hdr;
unsigned short checksum;
WORD DataMbpc; /* Sicherung mbpc */
WORD DataMbgc; /* Sicherung mbgc. */
int SaveLen;
bp = (MBHEAD *)allocb(ALLOC_MBHEAD); /* Buffer besorgen. */
put16((unsigned short)sockets[i].LocalPort, bp); /* Dest-Port<72>setzen. */
put16((unsigned short)sockets[i].DestPort, bp); /* Source-Port setzen. */
put32((unsigned long)sockets[i].SendUnacked, bp); /* Ack-Nummer setzen. */
put32((unsigned long)sockets[i].RecvNext, bp); /* Seq-Nummer setzen. */
put16((unsigned short)flags, bp); /* TCP-Flags setzen. (ACK, FIN, SYN...). */
put16((unsigned short)WinSize, bp); /* Fenstergroesse setzen. */
put16((unsigned short)0, bp); /* Checksum ERSTMAL auf 0 setzen. */
put16((unsigned short)sockets[i].UrgPointer, bp); /* Urgent-Flag setzen. */
if (options) /* Nur wenn Optionen gewuenscht wird setzen. */
{
put16((unsigned short)OPTEND, bp); /* End of Option List. */
put16((unsigned short)OPTMSS, bp); /* Maximum Segment Size. */
put16((unsigned short)OPTNOO, bp); /* No-Operation. */
put16((unsigned short)OPTPA3, bp);
}
else /* Keine Optionen setzen. */
{
if (tcp_len > TCP_HEADER) /* Es gibt daten. */
{
int i = 0;
SaveLen = i = Data->mbpc - Data->mbgc; /* Laenge ermitteln. */
DataMbpc = Data->mbpc; /* Werte sichern. */
DataMbgc = Data->mbgc;
while (i--) /* Alle zeichen einlesen und */
putchr(getchr(Data), bp); /* in Buffer schreiben. */
rwndmb(Data); /* Buffer zurueckspulen. */
}
}
rwndmb(bp); /* Frame zurueckspulen. */
/************************ Pseudo-Header ermitteln. *************************/
pseudo_hdr.source = my_ip_addr; /* Unsere IP-Adresse. */
pseudo_hdr.dest = sockets[i].IpDest; /* IP-Adresse vom Nachbarn. */
pseudo_hdr.protocol = TCP_PTCL; /* Protokoll-Typ. */
pseudo_hdr.length = tcp_len; /* TCP-Header + Daten. */
checksum = cksum(&pseudo_hdr, bp, (unsigned short)tcp_len);/* Checksume ermitteln. */
dealmb(bp); /* Alten buffer loeschen. */
bp = (MBHEAD *)allocb(ALLOC_MBHEAD); /* Neuen buffer besorgen. */
put16((unsigned short)sockets[i].LocalPort, bp); /* Dest-Port<72>setzen. */
put16((unsigned short)sockets[i].DestPort, bp); /* Source-Port setzen. */
put32((unsigned long)sockets[i].SendUnacked, bp); /* Ack-Nummer setzen. */
put32((unsigned long)sockets[i].RecvNext, bp); /* Seq-Nummer setzen. */
put16((unsigned short)flags, bp); /* TCP-Flags setzen. (ACK, FIN, SYN...) */
put16((unsigned short)WinSize, bp); /* Fenstergroesse setzen. */
put16((unsigned short)checksum, bp); /* Checksum setzen. */
put16((unsigned short)sockets[i].UrgPointer, bp); /* Urgent-Flag setzen. */
if (options) /* Nur wenn Optionen gewuenscht wird setzen. */
{
put16((unsigned short)OPTEND, bp); /* End of Option List. */
put16((unsigned short)OPTMSS, bp); /* Maximum Segment Size. */
put16((unsigned short)OPTNOO, bp); /* No-Operation. */
put16((unsigned short)OPTPA3, bp);
}
else /* Keine Optionen setzen. */
{
if (tcp_len > TCP_HEADER) /* Es gibt daten. */
{
int i = 0;
i = Data->mbpc - SaveLen; /* Laenge ermitteln. */
if (i != Data->mbpc)
{
while (i--)
getchr(Data);
}
while (SaveLen--) /* Alle zeichen einlesen und */
putchr(getchr(Data), bp); /* in buffer schreiben. */
}
}
rwndmb(bp); /* Daten zurueckspulen. */
return (bp);
}
/* Frame fuer IP-Router vorbereiten. */
void
SendTcpFlag(register int i, /* Aktueller Socket. */
MBHEAD *Data, /* Reine Daten. */
unsigned int DataLen, /* Bufferlaenge. */
unsigned short Flag, /* TCP-Flags. */
unsigned short WinSize, /* Fenstergroesse setzen.*/
unsigned short Options) /* Optionen setzen. */
{
MBHEAD *bp;
unsigned short TcpLen;
unsigned short TcpFlags;
/* TCP-Headerlaenge + evl. Optionen + */
TcpLen = TCP_HEADER + Options + DataLen; /* Reine Daten ermitteln. */
if (Options) /* Nur wenn Optionen gewuenscht wird setzen. */
{
TcpFlags = (TCP_HEADER + Options) << 10; /* TCP-Header + Optionen setzen.*/
Options = TRUE; /* Optionen setzen. */
}
else /* Keine Optionen. */
{
TcpFlags = TCP_HEADER << 10;
Options = FALSE; /* Keine Optionen. */
}
TcpFlags |= Flag;
bp = htontcp(i, /* TCP-Header + Daten zusammenfuegen. */
Data,
TcpFlags,
TcpLen,
WinSize,
Options);
ip_send(my_ip_addr, /* IP-Header basteln und ab in den IP-Router. */
sockets[i].IpDest,
TCP_PTCL,
sockets[i].tos,
0,
bp,
0,
0,
0);
}
#endif /* TCPSTACK */
/* End of src/l3tcp.c. */