Working on UDP, removed debug from some code, fixed ARP setting hwtype to 0x100 ...
[tpg/acess2.git] / Modules / IPStack / tcp.c
1 /*
2  * Acess2 IP Stack
3  * - TCP Handling
4  */
5 #include "ipstack.h"
6 #include "ipv4.h"
7 #include "tcp.h"
8
9 #define TCP_MIN_DYNPORT 0x1000
10 #define TCP_MAX_HALFOPEN        1024    // Should be enough
11
12 // === PROTOTYPES ===
13 void    TCP_Initialise();
14 void    TCP_StartConnection(tTCPConnection *Conn);
15 void    TCP_SendPacket( tTCPConnection *Conn, size_t Length, tTCPHeader *Data );
16 void    TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer);
17 void    TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header);
18 Uint16  TCP_GetUnusedPort();
19  int    TCP_AllocatePort(Uint16 Port);
20  int    TCP_DeallocatePort(Uint16 Port);
21 // --- Server
22 tVFS_Node       *TCP_Server_Init(tInterface *Interface);
23 char    *TCP_Server_ReadDir(tVFS_Node *Node, int Pos);
24 tVFS_Node       *TCP_Server_FindDir(tVFS_Node *Node, char *Name);
25  int    TCP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data);
26 void    TCP_Server_Close(tVFS_Node *Node);
27 // --- Client
28 tVFS_Node       *TCP_Client_Init(tInterface *Interface);
29 Uint64  TCP_Client_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
30 Uint64  TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
31  int    TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data);
32 void    TCP_Client_Close(tVFS_Node *Node);
33
34 // === TEMPLATES ===
35 tSocketFile     gTCP_ServerFile = {NULL, "tcps", TCP_Server_Init};
36 tSocketFile     gTCP_ClientFile = {NULL, "tcpc", TCP_Client_Init};
37
38 // === GLOBALS ===
39  int    giTCP_NumHalfopen = 0;
40 tSpinlock       glTCP_Listeners;
41 tTCPListener    *gTCP_Listeners;
42 tSpinlock       glTCP_OutbountCons;
43 tTCPConnection  *gTCP_OutbountCons;
44 Uint32  gaTCP_PortBitmap[0x800];
45  int    giTCP_NextOutPort = TCP_MIN_DYNPORT;
46
47 // === CODE ===
48 /**
49  * \fn void TCP_Initialise()
50  * \brief Initialise the TCP Layer
51  */
52 void TCP_Initialise()
53 {
54         IPStack_AddFile(&gTCP_ServerFile);
55         IPStack_AddFile(&gTCP_ClientFile);
56         IPv4_RegisterCallback(IP4PROT_TCP, TCP_GetPacket);
57 }
58
59 /**
60  * \brief Open a connection to another host using TCP
61  */
62 void TCP_StartConnection(tTCPConnection *Conn)
63 {
64         tTCPHeader      hdr;
65
66         hdr.SourcePort = Conn->LocalPort;
67         hdr.DestPort = Conn->RemotePort;
68         Conn->NextSequenceSend = rand();
69         hdr.SequenceNumber = Conn->NextSequenceSend;
70         hdr.DataOffset = (sizeof(tTCPHeader)+3)/4;
71         hdr.Flags = TCP_FLAG_SYN;
72         hdr.WindowSize = 0;     // TODO
73         hdr.Checksum = 0;       // TODO
74         hdr.UrgentPointer = 0;
75         // SEND PACKET
76         TCP_SendPacket( Conn, sizeof(tTCPHeader), &hdr );
77         return ;
78 }
79
80 /**
81  * \brief Sends a packet from the specified connection, calculating the checksums
82  * \param Conn  Connection
83  * \param Length        Length of data
84  * \param Data  Packet data
85  */
86 void TCP_SendPacket( tTCPConnection *Conn, size_t Length, tTCPHeader *Data )
87 {
88         size_t  buflen;
89         Uint32  *buf;
90         switch( Conn->Interface->Type )
91         {
92         case 4: // Append IPv4 Pseudo Header
93                 buflen = 4 + 4 + 4 + ((Length+1)&1);
94                 buf = malloc( buflen );
95                 buf[0] = Conn->Interface->IP4.Address.L;
96                 buf[1] = Conn->RemoteIP.v4.L;
97                 buf[2] = (htons(Length)<<16) | (6<<8) | 0;
98                 Data->Checksum = 0;
99                 memcpy( &buf[3], Data, Length );
100                 Data->Checksum = IPv4_Checksum( buf, buflen );
101                 free(buf);
102                 IPv4_SendPacket(Conn->Interface, Conn->RemoteIP.v4, IP4PROT_TCP, 0, buflen, buf);
103                 break;
104         }
105 }
106
107 /**
108  * \fn void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
109  * \brief Handles a packet from the IP Layer
110  */
111 void TCP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
112 {
113         tTCPHeader      *hdr = Buffer;
114         tTCPListener    *srv;
115         tTCPConnection  *conn;
116
117         Log("[TCP  ] sizeof(tTCPHeader) = %i", sizeof(tTCPHeader));
118         Log("[TCP  ] DestPort = %i", ntohs(hdr->DestPort));
119         Log("[TCP  ] DestPort = %i", ntohs(hdr->DestPort));
120         Log("[TCP  ] SequenceNumber = %i", ntohl(hdr->SequenceNumber));
121         Log("[TCP  ] AcknowlegementNumber = %i", ntohl(hdr->AcknowlegementNumber));
122         Log("[TCP  ] DataOffset = %i", hdr->DataOffset >> 4);
123         Log("[TCP  ] Flags = {");
124         Log("[TCP  ]   CWR = %B", !!(hdr->Flags & TCP_FLAG_CWR));
125         Log("[TCP  ]   ECE = %B", !!(hdr->Flags & TCP_FLAG_ECE));
126         Log("[TCP  ]   URG = %B", !!(hdr->Flags & TCP_FLAG_URG));
127         Log("[TCP  ]   ACK = %B", !!(hdr->Flags & TCP_FLAG_ACK));
128         Log("[TCP  ]   PSH = %B", !!(hdr->Flags & TCP_FLAG_PSH));
129         Log("[TCP  ]   RST = %B", !!(hdr->Flags & TCP_FLAG_RST));
130         Log("[TCP  ]   SYN = %B", !!(hdr->Flags & TCP_FLAG_SYN));
131         Log("[TCP  ]   FIN = %B", !!(hdr->Flags & TCP_FLAG_FIN));
132         Log("[TCP  ] }");
133         Log("[TCP  ] WindowSize = %i", htons(hdr->WindowSize));
134         Log("[TCP  ] Checksum = 0x%x", htons(hdr->Checksum));
135         Log("[TCP  ] UrgentPointer = 0x%x", htons(hdr->UrgentPointer));
136
137         // Check Servers
138         {
139                 for( srv = gTCP_Listeners; srv; srv = srv->Next )
140                 {
141                         // Check if the server is active
142                         if(srv->Port == 0)      continue;
143                         // Check the interface
144                         if(srv->Interface && srv->Interface != Interface)       continue;
145                         // Check the destination port
146                         if(srv->Port != hdr->DestPort)  continue;
147
148                         // Is this in an established connection?
149                         for( conn = srv->Connections; conn; conn = conn->Next )
150                         {
151                                 // Check that it is coming in on the same interface
152                                 if(conn->Interface != Interface)        continue;
153
154                                 // Check Source Port
155                                 if(conn->RemotePort != hdr->SourcePort) continue;
156
157                                 // Check Source IP
158                                 if(conn->Interface->Type == 6 && !IP6_EQU(conn->RemoteIP.v6, *(tIPv6*)Address))
159                                         continue;
160                                 if(conn->Interface->Type == 4 && !IP4_EQU(conn->RemoteIP.v4, *(tIPv4*)Address))
161                                         continue;
162
163                                 // We have a response!
164                                 TCP_INT_HandleConnectionPacket(conn, hdr);
165
166                                 return;
167                         }
168
169                         // Open a new connection (well, check that it's a SYN)
170                         //TODO
171
172                         break;
173                 }
174         }
175
176
177         // Check Open Connections
178         {
179                 for( conn = gTCP_OutbountCons; conn; conn = conn->Next )
180                 {
181                         // Check that it is coming in on the same interface
182                         if(conn->Interface != Interface)        continue;
183
184                         // Check Source Port
185                         if(conn->RemotePort != hdr->SourcePort) continue;
186
187                         // Check Source IP
188                         if(conn->Interface->Type == 6 && !IP6_EQU(conn->RemoteIP.v6, *(tIPv6*)Address))
189                                 continue;
190                         if(conn->Interface->Type == 4 && !IP4_EQU(conn->RemoteIP.v4, *(tIPv4*)Address))
191                                 continue;
192
193                         TCP_INT_HandleConnectionPacket(conn, hdr);
194                 }
195         }
196 }
197
198 /**
199  * \brief Handles a packet sent to a specific connection
200  */
201 void TCP_INT_HandleConnectionPacket(tTCPConnection *Connection, tTCPHeader *Header)
202 {
203
204 }
205
206 /**
207  * \fn Uint16 TCP_GetUnusedPort()
208  * \brief Gets an unused port and allocates it
209  */
210 Uint16 TCP_GetUnusedPort()
211 {
212         Uint16  ret;
213
214         // Get Next outbound port
215         ret = giTCP_NextOutPort++;
216         while( gaTCP_PortBitmap[ret/32] & (1 << (ret%32)) )
217         {
218                 ret ++;
219                 giTCP_NextOutPort++;
220                 if(giTCP_NextOutPort == 0x10000) {
221                         ret = giTCP_NextOutPort = TCP_MIN_DYNPORT;
222                 }
223         }
224
225         // Mark the new port as used
226         gaTCP_PortBitmap[ret/32] |= 1 << (ret%32);
227
228         return ret;
229 }
230
231 /**
232  * \fn int TCP_AllocatePort(Uint16 Port)
233  * \brief Marks a port as used
234  */
235 int TCP_AllocatePort(Uint16 Port)
236 {
237         // Check if the port has already been allocated
238         if( gaTCP_PortBitmap[Port/32] & (1 << (Port%32)) )
239                 return 0;
240
241         // Allocate
242         gaTCP_PortBitmap[Port/32] |= 1 << (Port%32);
243
244         return 1;
245 }
246
247 /**
248  * \fn int TCP_DeallocatePort(Uint16 Port)
249  * \brief Marks a port as unused
250  */
251 int TCP_DeallocatePort(Uint16 Port)
252 {
253         // Check if the port has already been allocated
254         if( !(gaTCP_PortBitmap[Port/32] & (1 << (Port%32))) )
255                 return 0;
256
257         // Allocate
258         gaTCP_PortBitmap[Port/32] &= ~(1 << (Port%32));
259
260         return 1;
261 }
262
263 // --- Server
264 tVFS_Node *TCP_Server_Init(tInterface *Interface)
265 {
266         tTCPListener    *srv = malloc( sizeof(tTCPListener) );
267
268         srv->Interface = Interface;
269         srv->Port = 0;
270         srv->NextID = 0;
271         srv->Connections = NULL;
272         srv->Next = NULL;
273         srv->Node.ImplPtr = srv;
274         srv->Node.NumACLs = 1;
275         srv->Node.ACLs = &gVFS_ACL_EveryoneRW;
276         srv->Node.ReadDir = TCP_Server_ReadDir;
277         srv->Node.FindDir = TCP_Server_FindDir;
278         srv->Node.IOCtl = TCP_Server_IOCtl;
279         srv->Node.Close = TCP_Server_Close;
280
281         LOCK(&glTCP_Listeners);
282         srv->Next = gTCP_Listeners;
283         gTCP_Listeners = srv;
284         RELEASE(&glTCP_Listeners);
285
286         return &srv->Node;
287 }
288
289 /**
290  * \brief Wait for a new connection and return the connection ID
291  * \note Blocks until a new connection is made
292  * \param Node  Server node
293  * \param Pos   Position (ignored)
294  */
295 char *TCP_Server_ReadDir(tVFS_Node *Node, int Pos)
296 {
297         tTCPListener    *srv = Node->ImplPtr;
298         tTCPConnection  *conn;
299         char    *ret;
300
301         while( srv->NewConnections == NULL )    Threads_Yield();
302
303         conn = srv->NewConnections;
304         srv->NewConnections = conn->Next;
305
306         ret = malloc(9);
307         itoa(ret, Node->ImplInt, 16, '0', 8);
308         return ret;
309 }
310
311 /**
312  * \brief Gets a client connection node
313  * \param Node  Server node
314  * \param Name  Hexadecimal ID of the node
315  */
316 tVFS_Node *TCP_Server_FindDir(tVFS_Node *Node, char *Name)
317 {
318         return NULL;
319 }
320
321 int TCP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data)
322 {
323         tTCPListener    *srv = Node->ImplPtr;
324
325         switch(ID)
326         {
327         case 4: // Get/Set Port
328                 if(!Data)       // Get Port
329                         return srv->Port;
330
331                 if(srv->Port)   // Wait, you can't CHANGE the port
332                         return -1;
333
334                 if(!CheckMem(Data, sizeof(Uint16)))     // Sanity check
335                         return -1;
336
337                 // Permissions check
338                 if(Threads_GetUID() != 0
339                 && *(Uint16*)Data != 0
340                 && *(Uint16*)Data < 1024)
341                         return -1;
342
343                 // TODO: Check if a port is in use
344
345                 // Set Port
346                 srv->Port = *(Uint16*)Data;
347                 if(srv->Port == 0)      // Allocate a random port
348                         srv->Port = TCP_GetUnusedPort();
349                 else    // Else, mark this as used
350                         TCP_AllocatePort(srv->Port);
351                 return srv->Port;
352         }
353         return 0;
354 }
355
356 void TCP_Server_Close(tVFS_Node *Node)
357 {
358         free(Node->ImplPtr);
359 }
360
361 // --- Client
362 tVFS_Node *TCP_Client_Init(tInterface *Interface)
363 {
364         tTCPConnection  *conn = malloc( sizeof(tTCPConnection) );
365
366         conn->State = TCP_ST_CLOSED;
367         conn->Interface = Interface;
368         conn->LocalPort = 0;
369         conn->RemotePort = 0;
370         memset( &conn->RemoteIP, 0, sizeof(conn->RemoteIP) );
371
372         conn->Node.ImplPtr = conn;
373         conn->Node.NumACLs = 1;
374         conn->Node.ACLs = &gVFS_ACL_EveryoneRW;
375         conn->Node.Read = TCP_Client_Read;
376         conn->Node.Write = TCP_Client_Write;
377         conn->Node.IOCtl = TCP_Client_IOCtl;
378         conn->Node.Close = TCP_Client_Close;
379
380         LOCK(&glTCP_OutbountCons);
381         conn->Next = gTCP_OutbountCons;
382         gTCP_OutbountCons = conn;
383         RELEASE(&glTCP_OutbountCons);
384
385         return &conn->Node;
386 }
387
388 Uint64 TCP_Client_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
389 {
390         return 0;
391 }
392
393 Uint64 TCP_Client_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
394 {
395         return 0;
396 }
397
398 /**
399  * \brief Control a client socket
400  */
401 int TCP_Client_IOCtl(tVFS_Node *Node, int ID, void *Data)
402 {
403         tTCPConnection  *conn = Node->ImplPtr;
404
405         switch(ID)
406         {
407         case 4: // Get/Set local port
408                 if(!Data)
409                         return conn->LocalPort;
410                 if(conn->State != TCP_ST_CLOSED)
411                         return -1;
412                 if(!CheckMem(Data, sizeof(Uint16)))
413                         return -1;
414
415                 if(Threads_GetUID() != 0 && *(Uint16*)Data < 1024)
416                         return -1;
417
418                 conn->LocalPort = *(Uint16*)Data;
419                 return 0;
420
421         case 5: // Get/Set remote port
422                 if(!Data)       return conn->RemotePort;
423                 if(conn->State != TCP_ST_CLOSED)        return -1;
424                 if(!CheckMem(Data, sizeof(Uint16)))     return -1;
425                 conn->RemotePort = *(Uint16*)Data;
426                 return 0;
427
428         case 6: // Set Remote IP
429                 if( conn->State != TCP_ST_CLOSED )
430                         return -1;
431                 if( conn->Interface->Type == 4 )
432                 {
433                         if(!CheckMem(Data, sizeof(tIPv4)))      return -1;
434                         conn->RemoteIP.v4 = *(tIPv4*)Data;
435                 }
436                 else if( conn->Interface->Type == 6 )
437                 {
438                         if(!CheckMem(Data, sizeof(tIPv6)))      return -1;
439                         conn->RemoteIP.v6 = *(tIPv6*)Data;
440                 }
441                 return 0;
442
443         case 7: // Connect
444                 if(conn->LocalPort == -1)
445                         conn->LocalPort = TCP_GetUnusedPort();
446                 if(conn->RemotePort == -1)
447                         return 0;
448
449                 TCP_StartConnection(conn);
450                 return 1;
451         }
452
453         return 0;
454 }
455
456 void TCP_Client_Close(tVFS_Node *Node)
457 {
458         free(Node->ImplPtr);
459 }

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