Modules/VIARhineII - RX and TX works, but TX is a hack atm
[tpg/acess2.git] / KernelLand / Modules / IPStack / tcp.c
1 /*
2  * Acess2 IP Stack
3  * - TCP Handling
4  */
5 #define DEBUG   0
6 #include "ipstack.h"
7 #include "ipv4.h"
8 #include "ipv6.h"
9 #include "tcp.h"
10
11 #define USE_SELECT      1
12 #define HEXDUMP_INCOMING        0
13 #define HEXDUMP_OUTGOING        0
14 #define CACHE_FUTURE_PACKETS_IN_BYTES   1       // Use a ring buffer to cache out of order packets
15
16 #define TCP_MIN_DYNPORT 0xC000
17 #define TCP_MAX_HALFOPEN        1024    // Should be enough
18
19 #define TCP_MAX_PACKET_SIZE     1024
20 #define TCP_WINDOW_SIZE 0x2000
21 #define TCP_RECIEVE_BUFFER_SIZE 0x4000
22
23 // === PROTOTYPES ===
24 void    TCP_Initialise(void);
25 void    TCP_StartConnection(tTCPConnection *Conn);
26 void    TCP_SendPacket(tTCPConnection *Conn, tTCPHeader *Header, size_t DataLen, const void *Data);
27 void    TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer);
28 void    TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length);
29 int     TCP_INT_AppendRecieved(tTCPConnection *Connection, const void *Data, size_t Length);
30 void    TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection);
31 Uint16  TCP_GetUnusedPort();
32  int    TCP_AllocatePort(Uint16 Port);
33  int    TCP_DeallocatePort(Uint16 Port);
34 // --- Server
35 tVFS_Node       *TCP_Server_Init(tInterface *Interface);
36 char    *TCP_Server_ReadDir(tVFS_Node *Node, int Pos);
37 tVFS_Node       *TCP_Server_FindDir(tVFS_Node *Node, const char *Name);
38  int    TCP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data);
39 void    TCP_Server_Close(tVFS_Node *Node);
40 // --- Client
41 tVFS_Node       *TCP_Client_Init(tInterface *Interface);
42 size_t  TCP_Client_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
43 size_t  TCP_Client_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
44  int    TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data);
45 void    TCP_Client_Close(tVFS_Node *Node);
46 // --- Helpers
47  int    WrapBetween(Uint32 Lower, Uint32 Value, Uint32 Higher, Uint32 MaxValue);
48
49 // === TEMPLATES ===
50 tSocketFile     gTCP_ServerFile = {NULL, "tcps", TCP_Server_Init};
51 tSocketFile     gTCP_ClientFile = {NULL, "tcpc", TCP_Client_Init};
52 tVFS_NodeType   gTCP_ServerNodeType = {
53         .TypeName = "TCP Server",
54         .ReadDir = TCP_Server_ReadDir,
55         .FindDir = TCP_Server_FindDir,
56         .IOCtl   = TCP_Server_IOCtl,
57         .Close   = TCP_Server_Close
58         };
59 tVFS_NodeType   gTCP_ClientNodeType = {
60         .TypeName = "TCP Client/Connection",
61         .Read  = TCP_Client_Read,
62         .Write = TCP_Client_Write,
63         .IOCtl = TCP_Client_IOCtl,
64         .Close = TCP_Client_Close
65         };
66
67 // === GLOBALS ===
68  int    giTCP_NumHalfopen = 0;
69 tShortSpinlock  glTCP_Listeners;
70 tTCPListener    *gTCP_Listeners;
71 tShortSpinlock  glTCP_OutbountCons;
72 tTCPConnection  *gTCP_OutbountCons;
73 Uint32  gaTCP_PortBitmap[0x800];
74  int    giTCP_NextOutPort = TCP_MIN_DYNPORT;
75
76 // === CODE ===
77 /**
78  * \brief Initialise the TCP Layer
79  * 
80  * Registers the client and server files and the GetPacket callback
81  */
82 void TCP_Initialise(void)
83 {
84         giTCP_NextOutPort += rand()%32;
85         IPStack_AddFile(&gTCP_ServerFile);
86         IPStack_AddFile(&gTCP_ClientFile);
87         IPv4_RegisterCallback(IP4PROT_TCP, TCP_GetPacket);
88         IPv6_RegisterCallback(IP4PROT_TCP, TCP_GetPacket);
89 }
90
91 /**
92  * \brief Sends a packet from the specified connection, calculating the checksums
93  * \param Conn  Connection
94  * \param Length        Length of data
95  * \param Data  Packet data (cast as a TCP Header)
96  */
97 void TCP_SendPacket( tTCPConnection *Conn, tTCPHeader *Header, size_t Length, const void *Data )
98 {
99         tIPStackBuffer  *buffer;
100         Uint16  checksum[3];
101          int    packlen = sizeof(*Header) + Length;
102         
103         buffer = IPStack_Buffer_CreateBuffer(2 + IPV4_BUFFERS);
104         if( Data && Length )
105                 IPStack_Buffer_AppendSubBuffer(buffer, Length, 0, Data, NULL, NULL);
106         IPStack_Buffer_AppendSubBuffer(buffer, sizeof(*Header), 0, Header, NULL, NULL);
107
108         LOG("Sending %i+%i to %s:%i", sizeof(*Header), Length,
109                 IPStack_PrintAddress(Conn->Interface->Type, &Conn->RemoteIP),
110                 Conn->RemotePort
111                 );
112
113         Header->Checksum = 0;
114         checksum[1] = htons( ~IPv4_Checksum(Header, sizeof(tTCPHeader)) );
115         checksum[2] = htons( ~IPv4_Checksum(Data, Length) );
116         
117         // TODO: Fragment packet
118         
119         switch( Conn->Interface->Type )
120         {
121         case 4:
122                 // Get IPv4 pseudo-header checksum
123                 {
124                         Uint32  buf[3];
125                         buf[0] = ((tIPv4*)Conn->Interface->Address)->L;
126                         buf[1] = Conn->RemoteIP.v4.L;
127                         buf[2] = (htons(packlen)<<16) | (6<<8) | 0;
128                         checksum[0] = htons( ~IPv4_Checksum(buf, sizeof(buf)) );        // Partial checksum
129                 }
130                 // - Combine checksums
131                 Header->Checksum = htons( IPv4_Checksum(checksum, sizeof(checksum)) );
132                 IPv4_SendPacket(Conn->Interface, Conn->RemoteIP.v4, IP4PROT_TCP, 0, buffer);
133                 break;
134                 
135         case 6:
136                 // Append IPv6 Pseudo Header
137                 {
138                         Uint32  buf[4+4+1+1];
139                         memcpy(buf, Conn->Interface->Address, 16);
140                         memcpy(&buf[4], &Conn->RemoteIP, 16);
141                         buf[8] = htonl(packlen);
142                         buf[9] = htonl(6);
143                         checksum[0] = htons( ~IPv4_Checksum(buf, sizeof(buf)) );        // Partial checksum
144                 }
145                 Header->Checksum = htons( IPv4_Checksum(checksum, sizeof(checksum)) );  // Combine the two
146                 IPv6_SendPacket(Conn->Interface, Conn->RemoteIP.v6, IP4PROT_TCP, Length, Data);
147                 break;
148         }
149 }
150
151 /**
152  * \brief Handles a packet from the IP Layer
153  * \param Interface     Interface the packet arrived from
154  * \param Address       Pointer to the addres structure
155  * \param Length        Size of packet in bytes
156  * \param Buffer        Packet data
157  */
158 void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
159 {
160         tTCPHeader      *hdr = Buffer;
161         tTCPListener    *srv;
162         tTCPConnection  *conn;
163
164         Log_Log("TCP", "TCP_GetPacket: <Local>:%i from [%s]:%i, Flags = %s%s%s%s%s%s%s%s",
165                 ntohs(hdr->DestPort),
166                 IPStack_PrintAddress(Interface->Type, Address),
167                 ntohs(hdr->SourcePort),
168                 (hdr->Flags & TCP_FLAG_CWR) ? "CWR " : "",
169                 (hdr->Flags & TCP_FLAG_ECE) ? "ECE " : "",
170                 (hdr->Flags & TCP_FLAG_URG) ? "URG " : "",
171                 (hdr->Flags & TCP_FLAG_ACK) ? "ACK " : "",
172                 (hdr->Flags & TCP_FLAG_PSH) ? "PSH " : "",
173                 (hdr->Flags & TCP_FLAG_RST) ? "RST " : "",
174                 (hdr->Flags & TCP_FLAG_SYN) ? "SYN " : "",
175                 (hdr->Flags & TCP_FLAG_FIN) ? "FIN " : ""
176                 );
177
178         if( Length > (hdr->DataOffset >> 4)*4 )
179         {
180                 LOG("SequenceNumber = 0x%x", ntohl(hdr->SequenceNumber));
181 #if HEXDUMP_INCOMING
182                 Debug_HexDump(
183                         "TCP_GetPacket: Packet Data = ",
184                         (Uint8*)hdr + (hdr->DataOffset >> 4)*4,
185                         Length - (hdr->DataOffset >> 4)*4
186                         );
187 #endif
188         }
189
190         // Check Servers
191         for( srv = gTCP_Listeners; srv; srv = srv->Next )
192         {
193                 // Check if the server is active
194                 if(srv->Port == 0)      continue;
195                 // Check the interface
196                 if(srv->Interface && srv->Interface != Interface)       continue;
197                 // Check the destination port
198                 if(srv->Port != htons(hdr->DestPort))   continue;
199                 
200                 Log_Log("TCP", "TCP_GetPacket: Matches server %p", srv);
201                 // Is this in an established connection?
202                 for( conn = srv->Connections; conn; conn = conn->Next )
203                 {
204                         // Check that it is coming in on the same interface
205                         if(conn->Interface != Interface)        continue;
206
207                         // Check Source Port
208                         Log_Log("TCP", "TCP_GetPacket: conn->RemotePort(%i) == hdr->SourcePort(%i)",
209                                 conn->RemotePort, ntohs(hdr->SourcePort));
210                         if(conn->RemotePort != ntohs(hdr->SourcePort))  continue;
211
212                         // Check Source IP
213                         Log_Debug("TCP", "TCP_GetPacket: conn->RemoteIP(%s)",
214                                 IPStack_PrintAddress(conn->Interface->Type, &conn->RemoteIP));
215                         Log_Debug("TCP", "                == Address(%s)",
216                                 IPStack_PrintAddress(conn->Interface->Type, Address));
217                         if( IPStack_CompareAddress(conn->Interface->Type, &conn->RemoteIP, Address, -1) == 0 )
218                                 continue ;
219
220                         Log_Log("TCP", "TCP_GetPacket: Matches connection %p", conn);
221                         // We have a response!
222                         TCP_INT_HandleConnectionPacket(conn, hdr, Length);
223
224                         return;
225                 }
226
227                 Log_Log("TCP", "TCP_GetPacket: Opening Connection");
228                 // Open a new connection (well, check that it's a SYN)
229                 if(hdr->Flags != TCP_FLAG_SYN) {
230                         Log_Log("TCP", "TCP_GetPacket: Packet is not a SYN");
231                         return ;
232                 }
233                 
234                 // TODO: Check for halfopen max
235                 
236                 conn = calloc(1, sizeof(tTCPConnection));
237                 conn->State = TCP_ST_SYN_RCVD;
238                 conn->LocalPort = srv->Port;
239                 conn->RemotePort = ntohs(hdr->SourcePort);
240                 conn->Interface = Interface;
241                 
242                 switch(Interface->Type)
243                 {
244                 case 4: conn->RemoteIP.v4 = *(tIPv4*)Address;   break;
245                 case 6: conn->RemoteIP.v6 = *(tIPv6*)Address;   break;
246                 }
247                 
248                 conn->RecievedBuffer = RingBuffer_Create( TCP_RECIEVE_BUFFER_SIZE );
249                 
250                 conn->NextSequenceRcv = ntohl( hdr->SequenceNumber ) + 1;
251                 conn->NextSequenceSend = rand();
252                 
253                 // Create node
254                 conn->Node.NumACLs = 1;
255                 conn->Node.ACLs = &gVFS_ACL_EveryoneRW;
256                 conn->Node.ImplPtr = conn;
257                 conn->Node.ImplInt = srv->NextID ++;
258                 conn->Node.Type = &gTCP_ClientNodeType; // TODO: Special type for the server end?
259                 
260                 // Hmm... Theoretically, this lock will never have to wait,
261                 // as the interface is locked to the watching thread, and this
262                 // runs in the watching thread. But, it's a good idea to have
263                 // it, just in case
264                 // Oh, wait, there is a case where a wildcard can be used
265                 // (srv->Interface == NULL) so having the lock is a good idea
266                 SHORTLOCK(&srv->lConnections);
267                 if( !srv->Connections )
268                         srv->Connections = conn;
269                 else
270                         srv->ConnectionsTail->Next = conn;
271                 srv->ConnectionsTail = conn;
272                 if(!srv->NewConnections)
273                         srv->NewConnections = conn;
274                 VFS_MarkAvaliable( &srv->Node, 1 );
275                 SHORTREL(&srv->lConnections);
276
277                 // Send the SYN ACK
278                 hdr->Flags |= TCP_FLAG_ACK;
279                 hdr->AcknowlegementNumber = htonl(conn->NextSequenceRcv);
280                 hdr->SequenceNumber = htonl(conn->NextSequenceSend);
281                 hdr->DestPort = hdr->SourcePort;
282                 hdr->SourcePort = htons(srv->Port);
283                 hdr->DataOffset = (sizeof(tTCPHeader)/4) << 4;
284                 TCP_SendPacket( conn, hdr, 0, NULL );
285                 conn->NextSequenceSend ++;
286                 return ;
287         }
288
289         // Check Open Connections
290         {
291                 for( conn = gTCP_OutbountCons; conn; conn = conn->Next )
292                 {
293                         // Check that it is coming in on the same interface
294                         if(conn->Interface != Interface)        continue;
295
296                         // Check Source Port
297                         if(conn->RemotePort != ntohs(hdr->SourcePort))  continue;
298
299                         // Check Source IP
300                         if(conn->Interface->Type == 6 && !IP6_EQU(conn->RemoteIP.v6, *(tIPv6*)Address))
301                                 continue;
302                         if(conn->Interface->Type == 4 && !IP4_EQU(conn->RemoteIP.v4, *(tIPv4*)Address))
303                                 continue;
304
305                         TCP_INT_HandleConnectionPacket(conn, hdr, Length);
306                         return ;
307                 }
308         }
309         
310         Log_Log("TCP", "TCP_GetPacket: No Match");
311 }
312
313 /**
314  * \brief Handles a packet sent to a specific connection
315  * \param Connection    TCP Connection pointer
316  * \param Header        TCP Packet pointer
317  * \param Length        Length of the packet
318  */
319 void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header, int Length)
320 {
321          int    dataLen;
322         Uint32  sequence_num;
323         
324         // Silently drop once finished
325         // TODO: Check if this needs to be here
326         if( Connection->State == TCP_ST_FINISHED ) {
327                 Log_Log("TCP", "Packet ignored - connection finnished");
328                 return ;
329         }
330         
331         // Syncronise sequence values
332         if(Header->Flags & TCP_FLAG_SYN) {
333                 // TODO: What if the packet also has data?
334                 Connection->NextSequenceRcv = ntohl(Header->SequenceNumber);
335         }
336         
337         // Ackowledge a sent packet
338         if(Header->Flags & TCP_FLAG_ACK) {
339                 // TODO: Process an ACKed Packet
340                 LOG("Conn %p, Sent packet 0x%x ACKed", Connection, Header->AcknowlegementNumber);
341         }
342         
343         // Get length of data
344         dataLen = Length - (Header->DataOffset>>4)*4;
345         LOG("dataLen = %i", dataLen);
346         
347         // 
348         // State Machine
349         //
350         switch( Connection->State )
351         {
352         // Pre-init connection?
353         case TCP_ST_CLOSED:
354                 Log_Log("TCP", "Packets to a closed connection?!");
355                 break;
356         
357         // --- Init States ---
358         // SYN sent, expecting SYN-ACK Connection Opening
359         case TCP_ST_SYN_SENT:
360                 if( Header->Flags & TCP_FLAG_SYN )
361                 {
362                         Connection->NextSequenceRcv ++;
363                         Header->DestPort = Header->SourcePort;
364                         Header->SourcePort = htons(Connection->LocalPort);
365                         Header->AcknowlegementNumber = htonl(Connection->NextSequenceRcv);
366                         Header->SequenceNumber = htonl(Connection->NextSequenceSend);
367                         Header->WindowSize = htons(TCP_WINDOW_SIZE);
368                         Header->Flags = TCP_FLAG_ACK;
369                         Header->DataOffset = (sizeof(tTCPHeader)/4) << 4;
370                         TCP_SendPacket( Connection, Header, 0, NULL );
371                         
372                         if( Header->Flags & TCP_FLAG_ACK )
373                         {       
374                                 Log_Log("TCP", "ACKing SYN-ACK");
375                                 Connection->State = TCP_ST_OPEN;
376                         }
377                         else
378                         {
379                                 Log_Log("TCP", "ACKing SYN");
380                                 Connection->State = TCP_ST_SYN_RCVD;
381                         }
382                 }
383                 break;
384         
385         // SYN-ACK sent, expecting ACK
386         case TCP_ST_SYN_RCVD:
387                 if( Header->Flags & TCP_FLAG_ACK )
388                 {
389                         // TODO: Handle max half-open limit
390                         Connection->State = TCP_ST_OPEN;
391                         Log_Log("TCP", "Connection fully opened");
392                 }
393                 break;
394                 
395         // --- Established State ---
396         case TCP_ST_OPEN:
397                 // - Handle State changes
398                 //
399                 if( Header->Flags & TCP_FLAG_FIN ) {
400                         Log_Log("TCP", "Conn %p closed, recieved FIN", Connection);
401                         VFS_MarkError(&Connection->Node, 1);
402                         Connection->State = TCP_ST_CLOSE_WAIT;
403 //                      Header->Flags &= ~TCP_FLAG_FIN;
404                         // CLOSE WAIT requires the client to close (or does it?)
405                         #if 0
406                         
407                         #endif
408                 }
409         
410                 // Check for an empty packet
411                 if(dataLen == 0) {
412                         if( Header->Flags == TCP_FLAG_ACK )
413                         {
414                                 Log_Log("TCP", "ACK only packet");
415                                 return ;
416                         }
417                         Connection->NextSequenceRcv ++; // TODO: Is this right? (empty packet counts as one byte)
418                         Log_Log("TCP", "Empty Packet, inc and ACK the current sequence number");
419                         Header->DestPort = Header->SourcePort;
420                         Header->SourcePort = htons(Connection->LocalPort);
421                         Header->AcknowlegementNumber = htonl(Connection->NextSequenceRcv);
422                         Header->SequenceNumber = htonl(Connection->NextSequenceSend);
423                         Header->Flags |= TCP_FLAG_ACK;
424                         TCP_SendPacket( Connection, Header, 0, NULL );
425                         return ;
426                 }
427                 
428                 // NOTES:
429                 // Flags
430                 //    PSH - Has Data?
431                 // /NOTES
432                 
433                 sequence_num = ntohl(Header->SequenceNumber);
434                 
435                 LOG("TCP", "0x%08x <= 0x%08x < 0x%08x",
436                         Connection->NextSequenceRcv,
437                         ntohl(Header->SequenceNumber),
438                         Connection->NextSequenceRcv + TCP_WINDOW_SIZE
439                         );
440                 
441                 // Is this packet the next expected packet?
442                 if( sequence_num == Connection->NextSequenceRcv )
443                 {
444                          int    rv;
445                         // Ooh, Goodie! Add it to the recieved list
446                         rv = TCP_INT_AppendRecieved(Connection,
447                                 (Uint8*)Header + (Header->DataOffset>>4)*4,
448                                 dataLen
449                                 );
450                         if(rv != 0) {
451                                 break;
452                         }
453                         LOG("0x%08x += %i", Connection->NextSequenceRcv, dataLen);
454                         Connection->NextSequenceRcv += dataLen;
455                         
456                         // TODO: This should be moved out of the watcher thread,
457                         // so that a single lost packet on one connection doesn't cause
458                         // all connections on the interface to lag.
459                         // - Meh, no real issue, as the cache shouldn't be that large
460                         TCP_INT_UpdateRecievedFromFuture(Connection);
461                 
462                         // ACK Packet
463                         // TODO: Implement delayed ACK sending
464                         Header->DestPort = Header->SourcePort;
465                         Header->SourcePort = htons(Connection->LocalPort);
466                         Header->AcknowlegementNumber = htonl(Connection->NextSequenceRcv);
467                         Header->SequenceNumber = htonl(Connection->NextSequenceSend);
468                         Header->WindowSize = htons(TCP_WINDOW_SIZE);
469                         Header->Flags &= TCP_FLAG_SYN;  // Eliminate all flags save for SYN
470                         Header->Flags |= TCP_FLAG_ACK;  // Add ACK
471                         LOG("TCP", "Sending ACK for 0x%08x", Connection->NextSequenceRcv);
472                         TCP_SendPacket( Connection, Header, 0, NULL );
473                         //Connection->NextSequenceSend ++;
474                 }
475                 // Check if the packet is in window
476                 else if( WrapBetween(Connection->NextSequenceRcv, sequence_num,
477                                 Connection->NextSequenceRcv+TCP_WINDOW_SIZE, 0xFFFFFFFF) )
478                 {
479                         Uint8   *dataptr = (Uint8*)Header + (Header->DataOffset>>4)*4;
480                         #if CACHE_FUTURE_PACKETS_IN_BYTES
481                         Uint32  index;
482                          int    i;
483                         
484                         index = sequence_num % TCP_WINDOW_SIZE;
485                         for( i = 0; i < dataLen; i ++ )
486                         {
487                                 Connection->FuturePacketValidBytes[index/8] |= 1 << (index%8);
488                                 Connection->FuturePacketData[index] = dataptr[i];
489                                 // Do a wrap increment
490                                 index ++;
491                                 if(index == TCP_WINDOW_SIZE)    index = 0;
492                         }
493                         #else
494                         tTCPStoredPacket        *pkt, *tmp, *prev = NULL;
495                         
496                         // Allocate and fill cached packet
497                         pkt = malloc( sizeof(tTCPStoredPacket) + dataLen );
498                         pkt->Next = NULL;
499                         pkt->Sequence = ntohl(Header->SequenceNumber);
500                         pkt->Length = dataLen;
501                         memcpy(pkt->Data, dataptr, dataLen);
502                         
503                         Log_Log("TCP", "We missed a packet, caching",
504                                 pkt->Sequence, Connection->NextSequenceRcv);
505                         
506                         // No? Well, let's cache it and look at it later
507                         SHORTLOCK( &Connection->lFuturePackets );
508                         for(tmp = Connection->FuturePackets;
509                                 tmp;
510                                 prev = tmp, tmp = tmp->Next)
511                         {
512                                 if(tmp->Sequence >= pkt->Sequence)      break;
513                         }
514                         
515                         // Add if before first, or sequences don't match 
516                         if( !tmp || tmp->Sequence != pkt->Sequence )
517                         {
518                                 if(prev)
519                                         prev->Next = pkt;
520                                 else
521                                         Connection->FuturePackets = pkt;
522                                 pkt->Next = tmp;
523                         }
524                         // Replace if larger
525                         else if(pkt->Length > tmp->Length)
526                         {
527                                 if(prev)
528                                         prev->Next = pkt;
529                                 pkt->Next = tmp->Next;
530                                 free(tmp);
531                         }
532                         else
533                         {
534                                 free(pkt);      // TODO: Find some way to remove this
535                         }
536                         SHORTREL( &Connection->lFuturePackets );
537                         #endif
538                 }
539                 // Badly out of sequence packet
540                 else
541                 {
542                         Log_Log("TCP", "Fully out of sequence packet (0x%08x not between 0x%08x and 0x%08x), dropped",
543                                 sequence_num, Connection->NextSequenceRcv, Connection->NextSequenceRcv+TCP_WINDOW_SIZE);
544                         // TODO: Spec says we should send an empty ACK with the current state
545                 }
546                 break;
547         
548         // --- Remote close states
549         case TCP_ST_CLOSE_WAIT:
550                 
551                 // Ignore everything, CLOSE_WAIT is terminated by the client
552                 Log_Debug("TCP", "CLOSE WAIT - Ignoring packets");
553                 
554                 break;
555         
556         // LAST-ACK - Waiting for the ACK of FIN (from CLOSE WAIT)
557         case TCP_ST_LAST_ACK:
558                 if( Header->Flags & TCP_FLAG_ACK )
559                 {
560                         Connection->State = TCP_ST_FINISHED;    // Connection completed
561                         Log_Log("TCP", "LAST-ACK to CLOSED - Connection remote closed");
562                         // TODO: Destrory the TCB
563                 }
564                 break;
565         
566         // --- Local close States
567         case TCP_ST_FIN_WAIT1:
568                 if( Header->Flags & TCP_FLAG_FIN )
569                 {
570                         Connection->State = TCP_ST_CLOSING;
571                         Log_Debug("TCP", "Conn %p closed, sent FIN and recieved FIN", Connection);
572                         VFS_MarkError(&Connection->Node, 1);
573                         
574                         // ACK Packet
575                         Header->DestPort = Header->SourcePort;
576                         Header->SourcePort = htons(Connection->LocalPort);
577                         Header->AcknowlegementNumber = Header->SequenceNumber;
578                         Header->SequenceNumber = htonl(Connection->NextSequenceSend);
579                         Header->WindowSize = htons(TCP_WINDOW_SIZE);
580                         Header->Flags = TCP_FLAG_ACK;
581                         TCP_SendPacket( Connection, Header, 0, NULL );
582                         break ;
583                 }
584                 
585                 // TODO: Make sure that the packet is actually ACKing the FIN
586                 if( Header->Flags & TCP_FLAG_ACK )
587                 {
588                         Connection->State = TCP_ST_FIN_WAIT2;
589                         Log_Debug("TCP", "Conn %p closed, sent FIN ACKed", Connection);
590                         VFS_MarkError(&Connection->Node, 1);
591                         return ;
592                 }
593                 break;
594         
595         case TCP_ST_FIN_WAIT2:
596                 if( Header->Flags & TCP_FLAG_FIN )
597                 {
598                         Connection->State = TCP_ST_TIME_WAIT;
599                         Log_Debug("TCP", "FIN sent and recieved, ACKing and going into TIME WAIT %p FINWAIT-2 -> TIME WAIT", Connection);
600                         // Send ACK
601                         Header->DestPort = Header->SourcePort;
602                         Header->SourcePort = htons(Connection->LocalPort);
603                         Header->AcknowlegementNumber = Header->SequenceNumber;
604                         Header->SequenceNumber = htonl(Connection->NextSequenceSend);
605                         Header->WindowSize = htons(TCP_WINDOW_SIZE);
606                         Header->Flags = TCP_FLAG_ACK;
607                         TCP_SendPacket( Connection, Header, 0, NULL );
608                 }
609                 break;
610         
611         case TCP_ST_CLOSING:
612                 // TODO: Make sure that the packet is actually ACKing the FIN
613                 if( Header->Flags & TCP_FLAG_ACK )
614                 {
615                         Connection->State = TCP_ST_TIME_WAIT;
616                         Log_Debug("TCP", "Conn %p CLOSING -> TIME WAIT", Connection);
617                         VFS_MarkError(&Connection->Node, 1);
618                         return ;
619                 }
620                 break;
621         
622         // --- Closed (or near closed) states) ---
623         case TCP_ST_TIME_WAIT:
624                 Log_Log("TCP", "Packets on Time-Wait, ignored");
625                 break;
626         
627         case TCP_ST_FINISHED:
628                 Log_Log("TCP", "Packets when CLOSED, ignoring");
629                 break;
630         
631         //default:
632         //      Log_Warning("TCP", "Unhandled TCP state %i", Connection->State);
633         //      break;
634         }
635         
636 }
637
638 /**
639  * \brief Appends a packet to the recieved list
640  * \param Connection    Connection structure
641  * \param Data  Packet contents
642  * \param Length        Length of \a Data
643  */
644 int TCP_INT_AppendRecieved(tTCPConnection *Connection, const void *Data, size_t Length)
645 {
646         Mutex_Acquire( &Connection->lRecievedPackets );
647
648         if(Connection->RecievedBuffer->Length + Length > Connection->RecievedBuffer->Space )
649         {
650                 VFS_MarkAvaliable(&Connection->Node, 1);
651                 Log_Error("TCP", "Buffer filled, packet dropped (:%i) - %i + %i > %i",
652                         Connection->LocalPort, Connection->RecievedBuffer->Length, Length,
653                         Connection->RecievedBuffer->Space
654                         );
655                 Mutex_Release( &Connection->lRecievedPackets );
656                 return 1;
657         }
658         
659         RingBuffer_Write( Connection->RecievedBuffer, Data, Length );
660
661         VFS_MarkAvaliable(&Connection->Node, 1);
662         
663         Mutex_Release( &Connection->lRecievedPackets );
664         return 0;
665 }
666
667 /**
668  * \brief Updates the connections recieved list from the future list
669  * \param Connection    Connection structure
670  * 
671  * Updates the recieved packets list with packets from the future (out 
672  * of order) packets list that are now able to be added in direct
673  * sequence.
674  */
675 void TCP_INT_UpdateRecievedFromFuture(tTCPConnection *Connection)
676 {
677         #if CACHE_FUTURE_PACKETS_IN_BYTES
678          int    i, length = 0;
679         Uint32  index;
680         
681         // Calculate length of contiguous bytes
682         length = Connection->HighestSequenceRcvd - Connection->NextSequenceRcv;
683         index = Connection->NextSequenceRcv % TCP_WINDOW_SIZE;
684         for( i = 0; i < length; i ++ )
685         {
686                 if( Connection->FuturePacketValidBytes[i / 8] == 0xFF ) {
687                         i += 7; index += 7;
688                         continue;
689                 }
690                 else if( !(Connection->FuturePacketValidBytes[i / 8] & (1 << (i%8))) )
691                         break;
692                 
693                 index ++;
694                 if(index > TCP_WINDOW_SIZE)
695                         index -= TCP_WINDOW_SIZE;
696         }
697         length = i;
698         
699         index = Connection->NextSequenceRcv % TCP_WINDOW_SIZE;
700         
701         // Write data to to the ring buffer
702         if( TCP_WINDOW_SIZE - index > length )
703         {
704                 // Simple case
705                 RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData + index, length );
706         }
707         else
708         {
709                  int    endLen = TCP_WINDOW_SIZE - index;
710                 // 2-part case
711                 RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData + index, endLen );
712                 RingBuffer_Write( Connection->RecievedBuffer, Connection->FuturePacketData, endLen - length );
713         }
714         
715         // Mark (now saved) bytes as invalid
716         // - Align index
717         while(index % 8 && length)
718         {
719                 Connection->FuturePacketData[index] = 0;
720                 Connection->FuturePacketData[index/8] &= ~(1 << (index%8));
721                 index ++;
722                 if(index > TCP_WINDOW_SIZE)
723                         index -= TCP_WINDOW_SIZE;
724                 length --;
725         }
726         while( length > 7 )
727         {
728                 Connection->FuturePacketData[index] = 0;
729                 Connection->FuturePacketValidBytes[index/8] = 0;
730                 length -= 8;
731                 index += 8;
732                 if(index > TCP_WINDOW_SIZE)
733                         index -= TCP_WINDOW_SIZE;
734         }
735         while(length)
736         {
737                 Connection->FuturePacketData[index] = 0;
738                 Connection->FuturePacketData[index/8] &= ~(1 << (index%8));
739                 index ++;
740                 if(index > TCP_WINDOW_SIZE)
741                         index -= TCP_WINDOW_SIZE;
742                 length --;
743         }
744         
745         #else
746         tTCPStoredPacket        *pkt;
747         for(;;)
748         {
749                 SHORTLOCK( &Connection->lFuturePackets );
750                 
751                 // Clear out duplicates from cache
752                 // - If a packet has just been recieved, and it is expected, then
753                 //   (since NextSequenceRcv = rcvd->Sequence + rcvd->Length) all
754                 //   packets in cache that are smaller than the next expected
755                 //   are now defunct.
756                 pkt = Connection->FuturePackets;
757                 while(pkt && pkt->Sequence < Connection->NextSequenceRcv)
758                 {
759                         tTCPStoredPacket        *next = pkt->Next;
760                         free(pkt);
761                         pkt = next;
762                 }
763                 
764                 // If there's no packets left in cache, stop looking
765                 if(!pkt || pkt->Sequence > Connection->NextSequenceRcv) {
766                         SHORTREL( &Connection->lFuturePackets );
767                         return;
768                 }
769                 
770                 // Delete packet from future list
771                 Connection->FuturePackets = pkt->Next;
772                 
773                 // Release list
774                 SHORTREL( &Connection->lFuturePackets );
775                 
776                 // Looks like we found one
777                 TCP_INT_AppendRecieved(Connection, pkt);
778                 Connection->NextSequenceRcv += pkt->Length;
779                 free(pkt);
780         }
781         #endif
782 }
783
784 /**
785  * \fn Uint16 TCP_GetUnusedPort()
786  * \brief Gets an unused port and allocates it
787  */
788 Uint16 TCP_GetUnusedPort()
789 {
790         Uint16  ret;
791
792         // Get Next outbound port
793         ret = giTCP_NextOutPort++;
794         while( gaTCP_PortBitmap[ret/32] & (1UL << (ret%32)) )
795         {
796                 ret ++;
797                 giTCP_NextOutPort++;
798                 if(giTCP_NextOutPort == 0x10000) {
799                         ret = giTCP_NextOutPort = TCP_MIN_DYNPORT;
800                 }
801         }
802
803         // Mark the new port as used
804         gaTCP_PortBitmap[ret/32] |= 1 << (ret%32);
805
806         return ret;
807 }
808
809 /**
810  * \fn int TCP_AllocatePort(Uint16 Port)
811  * \brief Marks a port as used
812  */
813 int TCP_AllocatePort(Uint16 Port)
814 {
815         // Check if the port has already been allocated
816         if( gaTCP_PortBitmap[Port/32] & (1 << (Port%32)) )
817                 return 0;
818
819         // Allocate
820         gaTCP_PortBitmap[Port/32] |= 1 << (Port%32);
821
822         return 1;
823 }
824
825 /**
826  * \fn int TCP_DeallocatePort(Uint16 Port)
827  * \brief Marks a port as unused
828  */
829 int TCP_DeallocatePort(Uint16 Port)
830 {
831         // Check if the port has already been allocated
832         if( !(gaTCP_PortBitmap[Port/32] & (1 << (Port%32))) )
833                 return 0;
834
835         // Allocate
836         gaTCP_PortBitmap[Port/32] &= ~(1 << (Port%32));
837
838         return 1;
839 }
840
841 // --- Server
842 tVFS_Node *TCP_Server_Init(tInterface *Interface)
843 {
844         tTCPListener    *srv;
845         
846         srv = calloc( 1, sizeof(tTCPListener) );
847
848         if( srv == NULL ) {
849                 Log_Warning("TCP", "malloc failed for listener (%i) bytes", sizeof(tTCPListener));
850                 return NULL;
851         }
852
853         srv->Interface = Interface;
854         srv->Port = 0;
855         srv->NextID = 0;
856         srv->Connections = NULL;
857         srv->ConnectionsTail = NULL;
858         srv->NewConnections = NULL;
859         srv->Next = NULL;
860         srv->Node.Flags = VFS_FFLAG_DIRECTORY;
861         srv->Node.Size = -1;
862         srv->Node.ImplPtr = srv;
863         srv->Node.NumACLs = 1;
864         srv->Node.ACLs = &gVFS_ACL_EveryoneRW;
865         srv->Node.Type = &gTCP_ServerNodeType;
866
867         SHORTLOCK(&glTCP_Listeners);
868         srv->Next = gTCP_Listeners;
869         gTCP_Listeners = srv;
870         SHORTREL(&glTCP_Listeners);
871
872         return &srv->Node;
873 }
874
875 /**
876  * \brief Wait for a new connection and return the connection ID
877  * \note Blocks until a new connection is made
878  * \param Node  Server node
879  * \param Pos   Position (ignored)
880  */
881 char *TCP_Server_ReadDir(tVFS_Node *Node, int Pos)
882 {
883         tTCPListener    *srv = Node->ImplPtr;
884         tTCPConnection  *conn;
885         char    *ret;
886         
887         ENTER("pNode iPos", Node, Pos);
888
889         Log_Log("TCP", "Thread %i waiting for a connection", Threads_GetTID());
890         for(;;)
891         {
892                 SHORTLOCK( &srv->lConnections );
893                 if( srv->NewConnections != NULL )       break;
894                 SHORTREL( &srv->lConnections );
895                 Threads_Yield();        // TODO: Sleep until poked
896         }
897         
898
899         // Increment the new list (the current connection is still on the 
900         // normal list)
901         conn = srv->NewConnections;
902         srv->NewConnections = conn->Next;
903
904         if( srv->NewConnections == NULL )
905                 VFS_MarkAvaliable( Node, 0 );
906         
907         SHORTREL( &srv->lConnections );
908         
909         LOG("conn = %p", conn);
910         LOG("srv->Connections = %p", srv->Connections);
911         LOG("srv->NewConnections = %p", srv->NewConnections);
912         LOG("srv->ConnectionsTail = %p", srv->ConnectionsTail);
913
914         ret = malloc(9);
915         itoa(ret, conn->Node.ImplInt, 16, 8, '0');
916         Log_Log("TCP", "Thread %i got '%s'", Threads_GetTID(), ret);
917         LEAVE('s', ret);
918         return ret;
919 }
920
921 /**
922  * \brief Gets a client connection node
923  * \param Node  Server node
924  * \param Name  Hexadecimal ID of the node
925  */
926 tVFS_Node *TCP_Server_FindDir(tVFS_Node *Node, const char *Name)
927 {
928         tTCPConnection  *conn;
929         tTCPListener    *srv = Node->ImplPtr;
930         char    tmp[9];
931          int    id = atoi(Name);
932         
933         ENTER("pNode sName", Node, Name);
934
935         // Check for a non-empty name
936         if( Name[0] ) 
937         {       
938                 // Sanity Check
939                 itoa(tmp, id, 16, 8, '0');
940                 if(strcmp(tmp, Name) != 0) {
941                         LOG("'%s' != '%s' (%08x)", Name, tmp, id);
942                         LEAVE('n');
943                         return NULL;
944                 }
945                 
946                 Log_Debug("TCP", "srv->Connections = %p", srv->Connections);
947                 Log_Debug("TCP", "srv->NewConnections = %p", srv->NewConnections);
948                 Log_Debug("TCP", "srv->ConnectionsTail = %p", srv->ConnectionsTail);
949                 
950                 // Search
951                 SHORTLOCK( &srv->lConnections );
952                 for(conn = srv->Connections;
953                         conn;
954                         conn = conn->Next)
955                 {
956                         LOG("conn->Node.ImplInt = %i", conn->Node.ImplInt);
957                         if(conn->Node.ImplInt == id)    break;
958                 }
959                 SHORTREL( &srv->lConnections );
960
961                 // If not found, ret NULL
962                 if(!conn) {
963                         LOG("Connection %i not found", id);
964                         LEAVE('n');
965                         return NULL;
966                 }
967         }
968         // Empty Name - Check for a new connection and if it's there, open it
969         else
970         {
971                 SHORTLOCK( &srv->lConnections );
972                 conn = srv->NewConnections;
973                 if( conn != NULL )
974                         srv->NewConnections = conn->Next;
975                 VFS_MarkAvaliable( Node, srv->NewConnections != NULL );
976                 SHORTREL( &srv->lConnections );
977                 if( !conn ) {
978                         LOG("No new connections");
979                         LEAVE('n');
980                         return NULL;
981                 }
982         }
983                 
984         // Return node
985         LEAVE('p', &conn->Node);
986         return &conn->Node;
987 }
988
989 /**
990  * \brief Handle IOCtl calls
991  */
992 int TCP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data)
993 {
994         tTCPListener    *srv = Node->ImplPtr;
995
996         switch(ID)
997         {
998         case 4: // Get/Set Port
999                 if(!Data)       // Get Port
1000                         return srv->Port;
1001
1002                 if(srv->Port)   // Wait, you can't CHANGE the port
1003                         return -1;
1004
1005                 if(!CheckMem(Data, sizeof(Uint16)))     // Sanity check
1006                         return -1;
1007
1008                 // Permissions check
1009                 if(Threads_GetUID() != 0
1010                 && *(Uint16*)Data != 0
1011                 && *(Uint16*)Data < 1024)
1012                         return -1;
1013
1014                 // TODO: Check if a port is in use
1015
1016                 // Set Port
1017                 srv->Port = *(Uint16*)Data;
1018                 if(srv->Port == 0)      // Allocate a random port
1019                         srv->Port = TCP_GetUnusedPort();
1020                 else    // Else, mark this as used
1021                         TCP_AllocatePort(srv->Port);
1022                 
1023                 Log_Log("TCP", "Server %p listening on port %i", srv, srv->Port);
1024                 
1025                 return srv->Port;
1026         }
1027         return 0;
1028 }
1029
1030 void TCP_Server_Close(tVFS_Node *Node)
1031 {
1032         free(Node->ImplPtr);
1033 }
1034
1035 // --- Client
1036 /**
1037  * \brief Create a client node
1038  */
1039 tVFS_Node *TCP_Client_Init(tInterface *Interface)
1040 {
1041         tTCPConnection  *conn = calloc( sizeof(tTCPConnection) + TCP_WINDOW_SIZE + TCP_WINDOW_SIZE/8, 1 );
1042
1043         conn->State = TCP_ST_CLOSED;
1044         conn->Interface = Interface;
1045         conn->LocalPort = -1;
1046         conn->RemotePort = -1;
1047
1048         conn->Node.ImplPtr = conn;
1049         conn->Node.NumACLs = 1;
1050         conn->Node.ACLs = &gVFS_ACL_EveryoneRW;
1051         conn->Node.Type = &gTCP_ClientNodeType;
1052
1053         conn->RecievedBuffer = RingBuffer_Create( TCP_RECIEVE_BUFFER_SIZE );
1054         #if 0
1055         conn->SentBuffer = RingBuffer_Create( TCP_SEND_BUFFER_SIZE );
1056         Semaphore_Init(conn->SentBufferSpace, 0, TCP_SEND_BUFFER_SIZE, "TCP SentBuffer", conn->Name);
1057         #endif
1058         
1059         #if CACHE_FUTURE_PACKETS_IN_BYTES
1060         // Future recieved data (ahead of the expected sequence number)
1061         conn->FuturePacketData = (Uint8*)conn + sizeof(tTCPConnection);
1062         conn->FuturePacketValidBytes = conn->FuturePacketData + TCP_WINDOW_SIZE;
1063         #endif
1064
1065         SHORTLOCK(&glTCP_OutbountCons);
1066         conn->Next = gTCP_OutbountCons;
1067         gTCP_OutbountCons = conn;
1068         SHORTREL(&glTCP_OutbountCons);
1069
1070         return &conn->Node;
1071 }
1072
1073 /**
1074  * \brief Wait for a packet and return it
1075  * \note If \a Length is smaller than the size of the packet, the rest
1076  *       of the packet's data will be discarded.
1077  */
1078 size_t TCP_Client_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
1079 {
1080         tTCPConnection  *conn = Node->ImplPtr;
1081         size_t  len;
1082         
1083         ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
1084         LOG("conn = %p {State:%i}", conn, conn->State);
1085         
1086         // Check if connection is estabilishing
1087         // - TODO: Sleep instead (maybe using VFS_SelectNode to wait for the
1088         //   data to be availiable
1089         while( conn->State == TCP_ST_SYN_RCVD || conn->State == TCP_ST_SYN_SENT )
1090                 Threads_Yield();
1091         
1092         // If the conneciton is not open, then clean out the recieved buffer
1093         if( conn->State != TCP_ST_OPEN )
1094         {
1095                 Mutex_Acquire( &conn->lRecievedPackets );
1096                 len = RingBuffer_Read( Buffer, conn->RecievedBuffer, Length );
1097                 Mutex_Release( &conn->lRecievedPackets );
1098                 
1099                 if( len == 0 ) {
1100                         VFS_MarkAvaliable(Node, 0);
1101                         LEAVE('i', -1);
1102                         return -1;
1103                 }
1104                 
1105                 LEAVE('i', len);
1106                 return len;
1107         }
1108         
1109         // Wait
1110         VFS_SelectNode(Node, VFS_SELECT_READ|VFS_SELECT_ERROR, NULL, "TCP_Client_Read");
1111         
1112         // Lock list and read as much as possible (up to `Length`)
1113         Mutex_Acquire( &conn->lRecievedPackets );
1114         len = RingBuffer_Read( Buffer, conn->RecievedBuffer, Length );
1115         
1116         if( len == 0 || conn->RecievedBuffer->Length == 0 ) {
1117                 LOG("Marking as none avaliable (len = %i)", len);
1118                 VFS_MarkAvaliable(Node, 0);
1119         }
1120                 
1121         // Release the lock (we don't need it any more)
1122         Mutex_Release( &conn->lRecievedPackets );
1123
1124         LEAVE('i', len);
1125         return len;
1126 }
1127
1128 /**
1129  * \brief Send a data packet on a connection
1130  */
1131 void TCP_INT_SendDataPacket(tTCPConnection *Connection, size_t Length, const void *Data)
1132 {
1133         char    buf[sizeof(tTCPHeader)+Length];
1134         tTCPHeader      *packet = (void*)buf;
1135         
1136         packet->SourcePort = htons(Connection->LocalPort);
1137         packet->DestPort = htons(Connection->RemotePort);
1138         packet->DataOffset = (sizeof(tTCPHeader)/4)*16;
1139         packet->WindowSize = htons(TCP_WINDOW_SIZE);
1140         
1141         packet->AcknowlegementNumber = htonl(Connection->NextSequenceRcv);
1142         packet->SequenceNumber = htonl(Connection->NextSequenceSend);
1143         packet->Flags = TCP_FLAG_PSH|TCP_FLAG_ACK;      // Hey, ACK if you can!
1144         
1145         memcpy(packet->Options, Data, Length);
1146         
1147         Log_Debug("TCP", "Send sequence 0x%08x", Connection->NextSequenceSend);
1148 #if HEXDUMP_OUTGOING
1149         Debug_HexDump("TCP_INT_SendDataPacket: Data = ", Data, Length);
1150 #endif
1151         
1152         TCP_SendPacket( Connection, packet, Length, Data );
1153         
1154         Connection->NextSequenceSend += Length;
1155 }
1156
1157 /**
1158  * \brief Send some bytes on a connection
1159  */
1160 size_t TCP_Client_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
1161 {
1162         tTCPConnection  *conn = Node->ImplPtr;
1163         size_t  rem = Length;
1164         
1165         ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
1166         
1167 //      #if DEBUG
1168 //      Debug_HexDump("TCP_Client_Write: Buffer = ",
1169 //              Buffer, Length);
1170 //      #endif
1171         
1172         // Check if connection is open
1173         while( conn->State == TCP_ST_SYN_RCVD || conn->State == TCP_ST_SYN_SENT )
1174                 Threads_Yield();
1175         
1176         if( conn->State != TCP_ST_OPEN ) {
1177                 VFS_MarkError(Node, 1);
1178                 LEAVE('i', -1);
1179                 return -1;
1180         }
1181         
1182         do
1183         {
1184                  int    len = (rem < TCP_MAX_PACKET_SIZE) ? rem : TCP_MAX_PACKET_SIZE;
1185                 
1186                 #if 0
1187                 // Wait for space in the buffer
1188                 Semaphore_Signal( &Connection->SentBufferSpace, len );
1189                 
1190                 // Save data to buffer (and update the length read by the ammount written)
1191                 len = RingBuffer_Write( &Connection->SentBuffer, Buffer, len);
1192                 #endif
1193                 
1194                 // Send packet
1195                 TCP_INT_SendDataPacket(conn, len, Buffer);
1196                 
1197                 Buffer += len;
1198                 rem -= len;
1199         } while( rem > 0 );
1200         
1201         LEAVE('i', Length);
1202         return Length;
1203 }
1204
1205 /**
1206  * \brief Open a connection to another host using TCP
1207  * \param Conn  Connection structure
1208  */
1209 void TCP_StartConnection(tTCPConnection *Conn)
1210 {
1211         tTCPHeader      hdr = {0};
1212
1213         Conn->State = TCP_ST_SYN_SENT;
1214
1215         hdr.SourcePort = htons(Conn->LocalPort);
1216         hdr.DestPort = htons(Conn->RemotePort);
1217         Conn->NextSequenceSend = rand();
1218         hdr.SequenceNumber = htonl(Conn->NextSequenceSend);
1219         hdr.DataOffset = (sizeof(tTCPHeader)/4) << 4;
1220         hdr.Flags = TCP_FLAG_SYN;
1221         hdr.WindowSize = htons(TCP_WINDOW_SIZE);        // Max
1222         hdr.Checksum = 0;       // TODO
1223         
1224         TCP_SendPacket( Conn, &hdr, 0, NULL );
1225         
1226         Conn->NextSequenceSend ++;
1227         Conn->State = TCP_ST_SYN_SENT;
1228
1229         return ;
1230 }
1231
1232 /**
1233  * \brief Control a client socket
1234  */
1235 int TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data)
1236 {
1237         tTCPConnection  *conn = Node->ImplPtr;
1238         
1239         ENTER("pNode iID pData", Node, ID, Data);
1240
1241         switch(ID)
1242         {
1243         case 4: // Get/Set local port
1244                 if(!Data)
1245                         LEAVE_RET('i', conn->LocalPort);
1246                 if(conn->State != TCP_ST_CLOSED)
1247                         LEAVE_RET('i', -1);
1248                 if(!CheckMem(Data, sizeof(Uint16)))
1249                         LEAVE_RET('i', -1);
1250
1251                 if(Threads_GetUID() != 0 && *(Uint16*)Data < 1024)
1252                         LEAVE_RET('i', -1);
1253
1254                 conn->LocalPort = *(Uint16*)Data;
1255                 LEAVE_RET('i', conn->LocalPort);
1256
1257         case 5: // Get/Set remote port
1258                 if(!Data)       LEAVE_RET('i', conn->RemotePort);
1259                 if(conn->State != TCP_ST_CLOSED)        LEAVE_RET('i', -1);
1260                 if(!CheckMem(Data, sizeof(Uint16)))     LEAVE_RET('i', -1);
1261                 conn->RemotePort = *(Uint16*)Data;
1262                 LEAVE_RET('i', conn->RemotePort);
1263
1264         case 6: // Set Remote IP
1265                 if( conn->State != TCP_ST_CLOSED )
1266                         LEAVE_RET('i', -1);
1267                 if( conn->Interface->Type == 4 )
1268                 {
1269                         if(!CheckMem(Data, sizeof(tIPv4)))      LEAVE_RET('i', -1);
1270                         conn->RemoteIP.v4 = *(tIPv4*)Data;
1271                 }
1272                 else if( conn->Interface->Type == 6 )
1273                 {
1274                         if(!CheckMem(Data, sizeof(tIPv6)))      LEAVE_RET('i', -1);
1275                         conn->RemoteIP.v6 = *(tIPv6*)Data;
1276                 }
1277                 LEAVE_RET('i', 0);
1278
1279         case 7: // Connect
1280                 if(conn->LocalPort == 0xFFFF)
1281                         conn->LocalPort = TCP_GetUnusedPort();
1282                 if(conn->RemotePort == -1)
1283                         LEAVE_RET('i', 0);
1284
1285                 {
1286                         tTime   timeout_end = now() + conn->Interface->TimeoutDelay;
1287         
1288                         TCP_StartConnection(conn);
1289                         // TODO: Wait for connection to open
1290                         while( conn->State == TCP_ST_SYN_SENT && timeout_end > now() ) {
1291                                 Threads_Yield();
1292                         }
1293                         if( conn->State == TCP_ST_SYN_SENT )
1294                                 LEAVE_RET('i', 0);
1295                 }
1296
1297                 LEAVE_RET('i', 1);
1298         
1299         // Get recieve buffer length
1300         case 8:
1301                 LEAVE_RET('i', conn->RecievedBuffer->Length);
1302         }
1303
1304         return 0;
1305 }
1306
1307 void TCP_Client_Close(tVFS_Node *Node)
1308 {
1309         tTCPConnection  *conn = Node->ImplPtr;
1310         tTCPHeader      packet;
1311         
1312         ENTER("pNode", Node);
1313         
1314         if( conn->State == TCP_ST_CLOSE_WAIT || conn->State == TCP_ST_OPEN )
1315         {
1316                 packet.SourcePort = htons(conn->LocalPort);
1317                 packet.DestPort = htons(conn->RemotePort);
1318                 packet.DataOffset = (sizeof(tTCPHeader)/4)*16;
1319                 packet.WindowSize = TCP_WINDOW_SIZE;
1320                 
1321                 packet.AcknowlegementNumber = 0;
1322                 packet.SequenceNumber = htonl(conn->NextSequenceSend);
1323                 packet.Flags = TCP_FLAG_FIN;
1324                 
1325                 TCP_SendPacket( conn, &packet, 0, NULL );
1326         }
1327         
1328         switch( conn->State )
1329         {
1330         case TCP_ST_CLOSE_WAIT:
1331                 conn->State = TCP_ST_LAST_ACK;
1332                 break;
1333         case TCP_ST_OPEN:
1334                 conn->State = TCP_ST_FIN_WAIT1;
1335                 while( conn->State == TCP_ST_FIN_WAIT1 )        Threads_Yield();
1336                 break;
1337         default:
1338                 Log_Warning("TCP", "Unhandled connection state in TCP_Client_Close");
1339                 break;
1340         }
1341         
1342         free(conn);
1343         
1344         LEAVE('-');
1345 }
1346
1347 /**
1348  * \brief Checks if a value is between two others (after taking into account wrapping)
1349  */
1350 int WrapBetween(Uint32 Lower, Uint32 Value, Uint32 Higher, Uint32 MaxValue)
1351 {
1352         if( MaxValue < 0xFFFFFFFF )
1353         {
1354                 Lower %= MaxValue + 1;
1355                 Value %= MaxValue + 1;
1356                 Higher %= MaxValue + 1;
1357         }
1358         
1359         // Simple Case, no wrap ?
1360         //       Lower Value Higher
1361         // | ... + ... + ... + ... |
1362
1363         if( Lower < Higher ) {
1364                 return Lower < Value && Value < Higher;
1365         }
1366         // Higher has wrapped below lower
1367         
1368         // Value > Lower ?
1369         //       Higher Lower Value
1370         // | ... +  ... + ... + ... |
1371         if( Value > Lower ) {
1372                 return 1;
1373         }
1374         
1375         // Value < Higher ?
1376         //       Value Higher Lower
1377         // | ... + ... +  ... + ... |
1378         if( Value < Higher ) {
1379                 return 1;
1380         }
1381         
1382         return 0;
1383 }

UCC git Repository :: git.ucc.asn.au