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

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