VIAVideo - Does something different now!
[tpg/acess2.git] / KernelLand / Modules / IPStack / sctp.c
1 /*
2  * Acess2 IP Stack
3  * - SCTP (Stream Control Transmission Protocol) Handling
4  */
5 #include "ipstack.h"
6 #include <api_drv_common.h>
7 #include "sctp.h"
8
9 #define SCTP_ALLOC_BASE 0xC000
10
11 // === PROTOTYPES ===
12 void    SCTP_Initialise();
13 void    SCTP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer);
14 void    SCTP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer);
15 void    SCTP_SendPacket(tSCTPChannel *Channel, void *Data, size_t Length);
16 // --- Listening Server
17 tVFS_Node       *SCTP_Server_Init(tInterface *Interface);
18 char    *SCTP_Server_ReadDir(tVFS_Node *Node, int ID);
19 tVFS_Node       *SCTP_Server_FindDir(tVFS_Node *Node, const char *Name);
20  int    SCTP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data);
21 void    SCTP_Server_Close(tVFS_Node *Node);
22 // --- Client Channels
23 tVFS_Node       *SCTP_Channel_Init(tInterface *Interface);
24 Uint64  SCTP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
25 Uint64  SCTP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
26  int    SCTP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data);
27 void    SCTP_Channel_Close(tVFS_Node *Node);
28 // --- Helpers
29 Uint16  SCTP_int_AllocatePort();
30  int    SCTP_int_MarkPortAsUsed(Uint16 Port);
31 void    SCTP_int_FreePort(Uint16 Port);
32
33 // === GLOBALS ===
34 tMutex  glSCTP_Servers;
35 tSCTPServer     *gpSCTP_Servers;
36
37 tMutex  glSCTP_Channels;
38 tSCTPChannel    *gpSCTP_Channels;
39
40 tMutex  glSCTP_Ports;
41 Uint32  gSCTP_Ports[0x10000/32];
42
43 tSocketFile     gSCTP_ServerFile = {NULL, "sctps", SCTP_Server_Init};
44 tSocketFile     gSCTP_ClientFile = {NULL, "sctpc", SCTP_Channel_Init};
45
46 // === CODE ===
47 /**
48  * \fn void TCP_Initialise()
49  * \brief Initialise the TCP Layer
50  */
51 void SCTP_Initialise()
52 {
53         IPStack_AddFile(&gSCTP_ServerFile);
54         IPStack_AddFile(&gSCTP_ClientFile);
55         //IPv4_RegisterCallback(IP4PROT_SCTP, SCTP_GetPacket, SCTP_Unreachable);
56         IPv4_RegisterCallback(IP4PROT_SCTP, SCTP_GetPacket);
57 }
58
59 /**
60  * \brief Scan a list of tSCTPChannels and find process the first match
61  * \return 0 if no match was found, -1 on error and 1 if a match was found
62  */
63 int SCTP_int_ScanList(tSCTPChannel *List, tInterface *Interface, void *Address, int Length, void *Buffer)
64 {
65         tSCTPHeader     *hdr = Buffer;
66         tSCTPChannel    *chan;
67         tSCTPPacket     *pack;
68          int    len;
69         
70         for(chan = List;
71                 chan;
72                 chan = chan->Next)
73         {
74                 if(chan->Interface != Interface)        continue;
75                 if(chan->LocalPort != ntohs(hdr->DestPort))     continue;
76                 if(chan->RemotePort != ntohs(hdr->SourcePort))  continue;
77                 
78                 if(Interface->Type == 4) {
79                         if(!IP4_EQU(chan->RemoteAddr.v4, *(tIPv4*)Address))     continue;
80                 }
81                 else if(Interface->Type == 6) {
82                         if(!IP6_EQU(chan->RemoteAddr.v6, *(tIPv6*)Address))     continue;
83                 }
84                 else {
85                         Log_Warning("SCTP", "Address type %i unknown", Interface->Type);
86                         Mutex_Release(&glSCTP_Channels);
87                         return -1;
88                 }
89                 
90                 Log_Log("SCTP", "Recieved packet for %p", chan);
91                 // Create the cached packet
92                 len = ntohs(hdr->Length);
93                 pack = malloc(sizeof(tSCTPPacket) + len);
94                 pack->Next = NULL;
95                 pack->Length = len;
96                 memcpy(pack->Data, hdr->Data, len);
97                 
98                 // Add the packet to the channel's queue
99                 SHORTLOCK(&chan->lQueue);
100                 if(chan->Queue)
101                         chan->QueueEnd->Next = pack;
102                 else
103                         chan->QueueEnd = chan->Queue = pack;
104                 SHORTREL(&chan->lQueue);
105                 Mutex_Release(&glSCTP_Channels);
106                 return 1;
107         }
108         return 0;
109 }
110
111 /**
112  * \fn void SCTP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
113  * \brief Handles a packet from the IP Layer
114  */
115 void SCTP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
116 {
117         tSCTPHeader     *hdr = Buffer;
118         tSCTPServer     *srv;
119          int    ret;
120         
121         Log_Log("SCTP", "hdr->SourcePort = %i", ntohs(hdr->SourcePort));
122         Log_Log("SCTP", "hdr->DestPort = %i", ntohs(hdr->DestPort));
123         Log_Log("SCTP", "hdr->VerifcationTag = %i", ntohs(hdr->VerifcationTag));
124         Log_Log("SCTP", "hdr->Checksum = 0x%x", ntohs(hdr->Checksum));
125         
126         // Check registered connections
127         Mutex_Acquire(&glSCTP_Channels);
128         ret = SCTP_int_ScanList(gpSCTP_Channels, Interface, Address, Length, Buffer);
129         Mutex_Release(&glSCTP_Channels);
130         if(ret != 0)    return ;
131         
132         
133         // TODO: Server/Listener
134         Mutex_Acquire(&glSCTP_Servers);
135         for(srv = gpSCTP_Servers;
136                 srv;
137                 srv = srv->Next)
138         {
139                 if(srv->Interface != Interface) continue;
140                 if(srv->ListenPort != ntohs(hdr->DestPort))     continue;
141                 ret = SCTP_int_ScanList(srv->Channels, Interface, Address, Length, Buffer);
142                 if(ret != 0)    break;
143                 
144                 // Add connection
145                 Log_Warning("SCTP", "TODO - Add channel on connection");
146                 //TODO
147         }
148         Mutex_Release(&glSCTP_Servers);
149         
150 }
151
152 /**
153  * \brief Handle an ICMP Unrechable Error
154  */
155 void SCTP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer)
156 {
157         
158 }
159
160 /**
161  * \brief Send a packet
162  * \param Channel       Channel to send the packet from
163  * \param Data  Packet data
164  * \param Length        Length in bytes of packet data
165  */
166 void SCTP_SendPacket(tSCTPChannel *Channel, void *Data, size_t Length)
167 {
168         tSCTPHeader     *hdr;
169         
170         switch(Channel->Interface->Type)
171         {
172         case 4:
173                 // Create the packet
174                 hdr = malloc(sizeof(tSCTPHeader)+Length);
175                 hdr->SourcePort = htons( Channel->LocalPort );
176                 hdr->DestPort = htons( Channel->RemotePort );
177                 hdr->Length = htons( sizeof(tSCTPHeader) + Length );
178                 hdr->Checksum = 0;      // Checksum can be zero on IPv4
179                 memcpy(hdr->Data, Data, Length);
180                 // Pass on the the IPv4 Layer
181                 IPv4_SendPacket(Channel->Interface, Channel->RemoteAddr.v4, IP4PROT_SCTP, 0, sizeof(tSCTPHeader)+Length, hdr);
182                 // Free allocated packet
183                 free(hdr);
184                 break;
185         }
186 }
187
188 // --- Listening Server
189 tVFS_Node *SCTP_Server_Init(tInterface *Interface)
190 {
191         tSCTPServer     *new;
192         new = calloc( sizeof(tSCTPServer), 1 );
193         if(!new)        return NULL;
194         
195         new->Node.ImplPtr = new;
196         new->Node.Flags = VFS_FFLAG_DIRECTORY;
197         new->Node.NumACLs = 1;
198         new->Node.ACLs = &gVFS_ACL_EveryoneRX;
199         new->Node.ReadDir = SCTP_Server_ReadDir;
200         new->Node.FindDir = SCTP_Server_FindDir;
201         new->Node.IOCtl = SCTP_Server_IOCtl;
202         new->Node.Close = SCTP_Server_Close;
203         
204         Mutex_Acquire(&glSCTP_Servers);
205         new->Next = gpSCTP_Servers;
206         gpSCTP_Servers = new;
207         Mutex_Release(&glSCTP_Servers);
208         
209         return &new->Node;
210 }
211
212 /**
213  * \brief Wait for a connection and return its ID in a string
214  */
215 char *SCTP_Server_ReadDir(tVFS_Node *Node, int ID)
216 {
217         tSCTPServer     *srv = Node->ImplPtr;
218         tSCTPChannel    *chan;
219         char    *ret;
220         
221         if( srv->ListenPort == 0 )      return NULL;
222         
223         // Lock (so another thread can't collide with us here) and wait for a connection
224         Mutex_Acquire( &srv->Lock );
225         while( srv->NewChannels == NULL )       Threads_Yield();
226         // Pop the connection off the new list
227         chan = srv->NewChannels;
228         srv->NewChannels = chan->Next;
229         // Release the lock
230         Mutex_Release( &srv->Lock );
231         
232         // Create the ID string and return it
233         ret = malloc(11+1);
234         sprintf(ret, "%i", chan->Node.ImplInt);
235         
236         return ret;
237 }
238
239 /**
240  * \brief Take a string and find the channel
241  */
242 tVFS_Node *SCTP_Server_FindDir(tVFS_Node *Node, const char *Name)
243 {
244         tSCTPServer     *srv = Node->ImplPtr;
245         tSCTPChannel    *chan;
246          int    id = atoi(Name);
247         
248         for(chan = srv->Channels;
249                 chan;
250                 chan = chan->Next)
251         {
252                 if( chan->Node.ImplInt < id )   continue;
253                 if( chan->Node.ImplInt > id )   break;  // Go sorted lists!
254                 
255                 return &chan->Node;
256         }
257         
258         return NULL;
259 }
260
261 /**
262  * \brief Names for server IOCtl Calls
263  */
264 static const char *casIOCtls_Server[] = {
265         DRV_IOCTLNAMES,
266         "getset_listenport",
267         NULL
268         };
269 /**
270  * \brief Channel IOCtls
271  */
272 int SCTP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data)
273 {
274         tSCTPServer     *srv = Node->ImplPtr;
275         
276         ENTER("pNode iID pData", Node, ID, Data);
277         switch(ID)
278         {
279         BASE_IOCTLS(DRV_TYPE_MISC, "SCTP Server", 0x100, casIOCtls_Server);
280         
281         case 4: // getset_localport (returns bool success)
282                 if(!Data)       LEAVE_RET('i', srv->ListenPort);
283                 if(!CheckMem( Data, sizeof(Uint16) ) ) {
284                         LOG("Invalid pointer %p", Data);
285                         LEAVE_RET('i', -1);
286                 }
287                 // Set port
288                 srv->ListenPort = *(Uint16*)Data;
289                 // Permissions check (Ports lower than 1024 are root-only)
290                 if(srv->ListenPort != 0 && srv->ListenPort < 1024) {
291                         if( Threads_GetUID() != 0 ) {
292                                 LOG("Attempt by non-superuser to listen on port %i", srv->ListenPort);
293                                 srv->ListenPort = 0;
294                                 LEAVE_RET('i', -1);
295                         }
296                 }
297                 // Allocate a random port if requested
298                 if( srv->ListenPort == 0 )
299                         srv->ListenPort = SCTP_int_AllocatePort();
300                 else
301                 {
302                         // Else, mark the requested port as used
303                         if( SCTP_int_MarkPortAsUsed(srv->ListenPort) == 0 ) {
304                                 LOG("Port %i us currently in use", srv->ListenPort);
305                                 srv->ListenPort = 0;
306                                 LEAVE_RET('i', -1);
307                         }
308                         LEAVE_RET('i', 1);
309                 }
310                 LEAVE_RET('i', 1);
311         
312         default:
313                 LEAVE_RET('i', -1);
314         }
315         LEAVE_RET('i', 0);
316 }
317
318 void SCTP_Server_Close(tVFS_Node *Node)
319 {
320         tSCTPServer     *srv = Node->ImplPtr;
321         tSCTPServer     *prev;
322         tSCTPChannel    *chan;
323         tSCTPPacket     *tmp;
324         
325         
326         // Remove from the main list first
327         Mutex_Acquire(&glSCTP_Servers);
328         if(gpSCTP_Servers == srv)
329                 gpSCTP_Servers = gpSCTP_Servers->Next;
330         else
331         {
332                 for(prev = gpSCTP_Servers;
333                         prev->Next && prev->Next != srv;
334                         prev = prev->Next);
335                 if(!prev->Next)
336                         Log_Warning("SCTP", "Bookeeping Fail, server %p is not in main list", srv);
337                 else
338                         prev->Next = prev->Next->Next;
339         }
340         Mutex_Release(&glSCTP_Servers);
341         
342         
343         Mutex_Acquire(&srv->Lock);
344         for(chan = srv->Channels;
345                 chan;
346                 chan = chan->Next)
347         {
348                 // Clear Queue
349                 SHORTLOCK(&chan->lQueue);
350                 while(chan->Queue)
351                 {
352                         tmp = chan->Queue;
353                         chan->Queue = tmp->Next;
354                         free(tmp);
355                 }
356                 SHORTREL(&chan->lQueue);
357                 
358                 // Free channel structure
359                 free(chan);
360         }
361         Mutex_Release(&srv->Lock);
362         
363         free(srv);
364 }
365
366 // --- Client Channels
367 tVFS_Node *SCTP_Channel_Init(tInterface *Interface)
368 {
369         tSCTPChannel    *new;
370         new = calloc( sizeof(tSCTPChannel), 1 );
371         new->Interface = Interface;
372         new->Node.ImplPtr = new;
373         new->Node.NumACLs = 1;
374         new->Node.ACLs = &gVFS_ACL_EveryoneRW;
375         new->Node.Read = SCTP_Channel_Read;
376         new->Node.Write = SCTP_Channel_Write;
377         new->Node.IOCtl = SCTP_Channel_IOCtl;
378         new->Node.Close = SCTP_Channel_Close;
379         
380         Mutex_Acquire(&glSCTP_Channels);
381         new->Next = gpSCTP_Channels;
382         gpSCTP_Channels = new;
383         Mutex_Release(&glSCTP_Channels);
384         
385         return &new->Node;
386 }
387
388 /**
389  * \brief Read from the channel file (wait for a packet)
390  */
391 Uint64 SCTP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
392 {
393         tSCTPChannel    *chan = Node->ImplPtr;
394         tSCTPPacket     *pack;
395         
396         if(chan->LocalPort == 0)        return 0;
397         if(chan->RemotePort == 0)       return 0;
398         
399         while(chan->Queue == NULL)      Threads_Yield();
400         
401         for(;;)
402         {
403                 SHORTLOCK(&chan->lQueue);
404                 if(chan->Queue == NULL) {
405                         SHORTREL(&chan->lQueue);
406                         continue;
407                 }
408                 pack = chan->Queue;
409                 chan->Queue = pack->Next;
410                 if(!chan->Queue)        chan->QueueEnd = NULL;
411                 SHORTREL(&chan->lQueue);
412                 break;
413         }
414         
415         // Clip length to packet length
416         if(Length > pack->Length)       Length = pack->Length;
417         // Copy packet data from cache
418         memcpy(Buffer, pack->Data, Length);
419         // Free cached packet
420         free(pack);     
421         
422         return Length;
423 }
424
425 /**
426  * \brief Write to the channel file (send a packet)
427  */
428 Uint64 SCTP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
429 {
430         tSCTPChannel    *chan = Node->ImplPtr;
431         if(chan->RemotePort == 0)       return 0;
432         
433         SCTP_SendPacket(chan, Buffer, (size_t)Length);
434         
435         return 0;
436 }
437
438 /**
439  * \brief Names for channel IOCtl Calls
440  */
441 static const char *casIOCtls_Channel[] = {
442         DRV_IOCTLNAMES,
443         "getset_localport",
444         "getset_remoteport",
445         "set_remoteaddr",
446         NULL
447         };
448 /**
449  * \brief Channel IOCtls
450  */
451 int SCTP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data)
452 {
453         tSCTPChannel    *chan = Node->ImplPtr;
454         ENTER("pNode iID pData", Node, ID, Data);
455         switch(ID)
456         {
457         BASE_IOCTLS(DRV_TYPE_MISC, "SCTP Channel", 0x100, casIOCtls_Channel);
458         
459         case 4: // getset_localport (returns bool success)
460                 if(!Data)       LEAVE_RET('i', chan->LocalPort);
461                 if(!CheckMem( Data, sizeof(Uint16) ) ) {
462                         LOG("Invalid pointer %p", Data);
463                         LEAVE_RET('i', -1);
464                 }
465                 // Set port
466                 chan->LocalPort = *(Uint16*)Data;
467                 // Permissions check (Ports lower than 1024 are root-only)
468                 if(chan->LocalPort != 0 && chan->LocalPort < 1024) {
469                         if( Threads_GetUID() != 0 ) {
470                                 LOG("Attempt by non-superuser to listen on port %i", chan->LocalPort);
471                                 chan->LocalPort = 0;
472                                 LEAVE_RET('i', -1);
473                         }
474                 }
475                 // Allocate a random port if requested
476                 if( chan->LocalPort == 0 )
477                         chan->LocalPort = SCTP_int_AllocatePort();
478                 else
479                 {
480                         // Else, mark the requested port as used
481                         if( SCTP_int_MarkPortAsUsed(chan->LocalPort) == 0 ) {
482                                 LOG("Port %i us currently in use", chan->LocalPort);
483                                 chan->LocalPort = 0;
484                                 LEAVE_RET('i', 0);
485                         }
486                         LEAVE_RET('i', 1);
487                 }
488                 LEAVE_RET('i', 1);
489         
490         case 5: // getset_remoteport (returns bool success)
491                 if(!Data)       LEAVE_RET('i', chan->RemotePort);
492                 if(!CheckMem( Data, sizeof(Uint16) ) ) {
493                         LOG("Invalid pointer %p", Data);
494                         LEAVE_RET('i', -1);
495                 }
496                 chan->RemotePort = *(Uint16*)Data;
497                 return 1;
498         
499         case 6: // set_remoteaddr (returns bool success)
500                 switch(chan->Interface->Type)
501                 {
502                 case 4:
503                         if(!CheckMem(Data, sizeof(tIPv4))) {
504                                 LOG("Invalid pointer %p", Data);
505                                 LEAVE_RET('i', -1);
506                         }
507                         chan->RemoteAddr.v4 = *(tIPv4*)Data;
508                         break;
509                 }
510                 break;
511         }
512         LEAVE_RET('i', 0);
513 }
514
515 /**
516  * \brief Close and destroy an open channel
517  */
518 void SCTP_Channel_Close(tVFS_Node *Node)
519 {
520         tSCTPChannel    *chan = Node->ImplPtr;
521         tSCTPChannel    *prev;
522         
523         // Remove from the main list first
524         Mutex_Acquire(&glSCTP_Channels);
525         if(gpSCTP_Channels == chan)
526                 gpSCTP_Channels = gpSCTP_Channels->Next;
527         else
528         {
529                 for(prev = gpSCTP_Channels;
530                         prev->Next && prev->Next != chan;
531                         prev = prev->Next);
532                 if(!prev->Next)
533                         Log_Warning("SCTP", "Bookeeping Fail, channel %p is not in main list", chan);
534                 else
535                         prev->Next = prev->Next->Next;
536         }
537         Mutex_Release(&glSCTP_Channels);
538         
539         // Clear Queue
540         SHORTLOCK(&chan->lQueue);
541         while(chan->Queue)
542         {
543                 tSCTPPacket     *tmp;
544                 tmp = chan->Queue;
545                 chan->Queue = tmp->Next;
546                 free(tmp);
547         }
548         SHORTREL(&chan->lQueue);
549         
550         // Free channel structure
551         free(chan);
552 }
553
554 /**
555  * \return Port Number on success, or zero on failure
556  */
557 Uint16 SCTP_int_AllocatePort()
558 {
559          int    i;
560         Mutex_Acquire(&glSCTP_Ports);
561         // Fast Search
562         for( i = SCTP_ALLOC_BASE; i < 0x10000; i += 32 )
563                 if( gSCTP_Ports[i/32] != 0xFFFFFFFF )
564                         break;
565         if(i == 0x10000)        return 0;
566         for( ;; i++ )
567         {
568                 if( !(gSCTP_Ports[i/32] & (1 << (i%32))) )
569                         return i;
570         }
571         Mutex_Release(&glSCTP_Ports);
572 }
573
574 /**
575  * \brief Allocate a specific port
576  * \return Boolean Success
577  */
578 int SCTP_int_MarkPortAsUsed(Uint16 Port)
579 {
580         Mutex_Acquire(&glSCTP_Ports);
581         if( gSCTP_Ports[Port/32] & (1 << (Port%32)) ) {
582                 return 0;
583                 Mutex_Release(&glSCTP_Ports);
584         }
585         gSCTP_Ports[Port/32] |= 1 << (Port%32);
586         Mutex_Release(&glSCTP_Ports);
587         return 1;
588 }
589
590 /**
591  * \brief Free an allocated port
592  */
593 void SCTP_int_FreePort(Uint16 Port)
594 {
595         Mutex_Acquire(&glSCTP_Ports);
596         gSCTP_Ports[Port/32] &= ~(1 << (Port%32));
597         Mutex_Release(&glSCTP_Ports);
598 }

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