6 #include <tpl_drv_common.h>
9 #define UDP_ALLOC_BASE 0xC000
12 void UDP_Initialise();
13 void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer);
14 // --- Listening Server
15 tVFS_Node *UDP_Server_Init(tInterface *Interface);
16 char *UDP_Server_ReadDir(tVFS_Node *Node, int ID);
17 tVFS_Node *UDP_Server_FindDir(tVFS_Node *Node, char *Name);
18 int UDP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data);
19 void UDP_Server_Close(tVFS_Node *Node);
20 // --- Client Channels
21 tVFS_Node *UDP_Channel_Init(tInterface *Interface);
22 Uint64 UDP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
23 Uint64 UDP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
24 int UDP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data);
25 void UDP_Channel_Close(tVFS_Node *Node);
27 Uint16 UDP_int_AllocatePort();
28 int UDP_int_MarkPortAsUsed(Uint16 Port);
29 void UDP_int_FreePort(Uint16 Port);
32 tSpinlock glUDP_Servers;
33 tUDPServer *gpUDP_Servers;
35 tSpinlock glUDP_Channels;
36 tUDPChannel *gpUDP_Channels;
38 tSpinlock glUDP_Ports;
39 Uint32 gUDP_Ports[0x10000/32];
41 tSocketFile gUDP_ServerFile = {NULL, "udps", UDP_Server_Init};
42 tSocketFile gUDP_ClientFile = {NULL, "udpc", UDP_Channel_Init};
46 * \fn void TCP_Initialise()
47 * \brief Initialise the TCP Layer
51 IPStack_AddFile(&gUDP_ServerFile);
52 IPStack_AddFile(&gUDP_ClientFile);
53 IPv4_RegisterCallback(IP4PROT_UDP, UDP_GetPacket);
57 * \brief Scan a list of tUDPChannel's and find process the first match
58 * \return 0 if no match was found, -1 on error and 1 if a match was found
60 int UDP_int_ScanList(tUDPChannel *List, tInterface *Interface, void *Address, int Length, void *Buffer)
62 tUDPHeader *hdr = Buffer;
71 if(chan->Interface != Interface) continue;
72 //Log("[UDP ] Local (0x%04x) == Dest (0x%04x)", chan->LocalPort, ntohs(hdr->DestPort));
73 if(chan->LocalPort != ntohs(hdr->DestPort)) continue;
74 //Log("[UDP ] Remote (0x%04x) == Source (0x%04x)", chan->RemotePort, ntohs(hdr->SourcePort));
75 if(chan->RemotePort != ntohs(hdr->SourcePort)) continue;
77 if(Interface->Type == 4) {
78 if(!IP4_EQU(chan->RemoteAddr.v4, *(tIPv4*)Address)) continue;
80 else if(Interface->Type == 6) {
81 if(!IP6_EQU(chan->RemoteAddr.v6, *(tIPv6*)Address)) continue;
84 Warning("[UDP ] Address type %i unknown", Interface->Type);
85 RELEASE(&glUDP_Channels);
89 Log("[UDP ] Recieved packet for %p", chan);
90 // Create the cached packet
91 len = ntohs(hdr->Length);
92 pack = malloc(sizeof(tUDPPacket) + len);
95 memcpy(pack->Data, hdr->Data, len);
97 // Add the packet to the channel's queue
100 chan->QueueEnd->Next = pack;
102 chan->QueueEnd = chan->Queue = pack;
103 RELEASE(&chan->lQueue);
104 RELEASE(&glUDP_Channels);
111 * \fn void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
112 * \brief Handles a packet from the IP Layer
114 void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
116 tUDPHeader *hdr = Buffer;
120 Log("[UDP ] hdr->SourcePort = %i", ntohs(hdr->SourcePort));
121 Log("[UDP ] hdr->DestPort = %i", ntohs(hdr->DestPort));
122 Log("[UDP ] hdr->Length = %i", ntohs(hdr->Length));
123 Log("[UDP ] hdr->Checksum = 0x%x", ntohs(hdr->Checksum));
125 // Check registered connections
126 LOCK(&glUDP_Channels);
127 ret = UDP_int_ScanList(gpUDP_Channels, Interface, Address, Length, Buffer);
128 RELEASE(&glUDP_Channels);
129 if(ret != 0) return ;
132 // TODO: Server/Listener
133 LOCK(&glUDP_Servers);
134 for(srv = gpUDP_Servers;
138 if(srv->Interface != Interface) continue;
139 if(srv->ListenPort != ntohs(hdr->DestPort)) continue;
140 ret = UDP_int_ScanList(srv->Channels, Interface, Address, Length, Buffer);
144 Warning("[UDP ] TODO - Add channel on connection");
147 RELEASE(&glUDP_Servers);
152 * \brief Send a packet
153 * \param Channel Channel to send the packet from
154 * \param Data Packet data
155 * \param Length Length in bytes of packet data
157 void UDP_SendPacket(tUDPChannel *Channel, void *Data, size_t Length)
161 switch(Channel->Interface->Type)
165 hdr = malloc(sizeof(tUDPHeader)+Length);
166 hdr->SourcePort = htons( Channel->LocalPort );
167 hdr->DestPort = htons( Channel->RemotePort );
168 hdr->Length = htons( sizeof(tUDPHeader) + Length );
169 hdr->Checksum = 0; // Checksum can be zero on IPv4
170 memcpy(hdr->Data, Data, Length);
171 // Pass on the the IPv4 Layer
172 IPv4_SendPacket(Channel->Interface, Channel->RemoteAddr.v4, IP4PROT_UDP, 0, sizeof(tUDPHeader)+Length, hdr);
173 // Free allocated packet
179 // --- Listening Server
180 tVFS_Node *UDP_Server_Init(tInterface *Interface)
183 new = calloc( sizeof(tUDPServer), 1 );
184 if(!new) return NULL;
186 new->Node.ImplPtr = new;
187 new->Node.Flags = VFS_FFLAG_DIRECTORY;
188 new->Node.NumACLs = 1;
189 new->Node.ACLs = &gVFS_ACL_EveryoneRX;
190 new->Node.ReadDir = UDP_Server_ReadDir;
191 new->Node.FindDir = UDP_Server_FindDir;
192 new->Node.IOCtl = UDP_Server_IOCtl;
193 new->Node.Close = UDP_Server_Close;
195 LOCK(&glUDP_Servers);
196 new->Next = gpUDP_Servers;
198 RELEASE(&glUDP_Servers);
204 * \brief Wait for a connection and return its ID in a string
206 char *UDP_Server_ReadDir(tVFS_Node *Node, int ID)
208 tUDPServer *srv = Node->ImplPtr;
212 if( srv->ListenPort == 0 ) return NULL;
214 // Lock (so another thread can't collide with us here) and wait for a connection
216 while( srv->NewChannels == NULL ) Threads_Yield();
217 // Pop the connection off the new list
218 chan = srv->NewChannels;
219 srv->NewChannels = chan->Next;
221 RELEASE( &srv->Lock );
223 // Create the ID string and return it
225 sprintf(ret, "%i", chan->Node.ImplInt);
231 * \brief Take a string and find the channel
233 tVFS_Node *UDP_Server_FindDir(tVFS_Node *Node, char *Name)
235 tUDPServer *srv = Node->ImplPtr;
239 for(chan = srv->Channels;
243 if( chan->Node.ImplInt < id ) continue;
244 if( chan->Node.ImplInt > id ) break; // Go sorted lists!
253 * \brief Names for server IOCtl Calls
255 static const char *casIOCtls_Server[] = {
261 * \brief Channel IOCtls
263 int UDP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data)
265 tUDPServer *srv = Node->ImplPtr;
267 ENTER("pNode iID pData", Node, ID, Data);
270 BASE_IOCTLS(DRV_TYPE_MISC, "UDP Server", 0x100, casIOCtls_Server);
272 case 4: // getset_localport (returns bool success)
273 if(!Data) LEAVE_RET('i', srv->ListenPort);
274 if(!CheckMem( Data, sizeof(Uint16) ) ) {
275 LOG("Invalid pointer %p", Data);
279 srv->ListenPort = *(Uint16*)Data;
280 // Permissions check (Ports lower than 1024 are root-only)
281 if(srv->ListenPort != 0 && srv->ListenPort < 1024) {
282 if( Threads_GetUID() != 0 ) {
283 LOG("Attempt by non-superuser to listen on port %i", srv->ListenPort);
288 // Allocate a random port if requested
289 if( srv->ListenPort == 0 )
290 srv->ListenPort = UDP_int_AllocatePort();
293 // Else, mark the requested port as used
294 if( UDP_int_MarkPortAsUsed(srv->ListenPort) == 0 ) {
295 LOG("Port %i us currently in use", srv->ListenPort);
309 void UDP_Server_Close(tVFS_Node *Node)
311 tUDPServer *srv = Node->ImplPtr;
317 // Remove from the main list first
318 LOCK(&glUDP_Servers);
319 if(gpUDP_Servers == srv)
320 gpUDP_Servers = gpUDP_Servers->Next;
323 for(prev = gpUDP_Servers;
324 prev->Next && prev->Next != srv;
327 Warning("[UDP ] Bookeeping Fail, server %p is not in main list", srv);
329 prev->Next = prev->Next->Next;
331 RELEASE(&glUDP_Servers);
335 for(chan = srv->Channels;
344 chan->Queue = tmp->Next;
347 RELEASE(&chan->lQueue);
349 // Free channel structure
357 // --- Client Channels
358 tVFS_Node *UDP_Channel_Init(tInterface *Interface)
361 new = calloc( sizeof(tUDPChannel), 1 );
362 new->Interface = Interface;
363 new->Node.ImplPtr = new;
364 new->Node.NumACLs = 1;
365 new->Node.ACLs = &gVFS_ACL_EveryoneRW;
366 new->Node.Read = UDP_Channel_Read;
367 new->Node.Write = UDP_Channel_Write;
368 new->Node.IOCtl = UDP_Channel_IOCtl;
369 new->Node.Close = UDP_Channel_Close;
371 LOCK(&glUDP_Channels);
372 new->Next = gpUDP_Channels;
373 gpUDP_Channels = new;
374 RELEASE(&glUDP_Channels);
380 * \brief Read from the channel file (wait for a packet)
382 Uint64 UDP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
384 tUDPChannel *chan = Node->ImplPtr;
387 if(chan->LocalPort == 0) return 0;
388 if(chan->RemotePort == 0) return 0;
390 while(chan->Queue == NULL) Threads_Yield();
395 if(chan->Queue == NULL) {
396 RELEASE(&chan->lQueue);
400 chan->Queue = pack->Next;
401 if(!chan->Queue) chan->QueueEnd = NULL;
402 RELEASE(&chan->lQueue);
406 // Clip length to packet length
407 if(Length > pack->Length) Length = pack->Length;
408 // Copy packet data from cache
409 memcpy(Buffer, pack->Data, Length);
410 // Free cached packet
417 * \brief Write to the channel file (send a packet)
419 Uint64 UDP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
421 tUDPChannel *chan = Node->ImplPtr;
422 if(chan->RemotePort == 0) return 0;
424 UDP_SendPacket(chan, Buffer, (size_t)Length);
430 * \brief Names for channel IOCtl Calls
432 static const char *casIOCtls_Channel[] = {
440 * \brief Channel IOCtls
442 int UDP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data)
444 tUDPChannel *chan = Node->ImplPtr;
445 ENTER("pNode iID pData", Node, ID, Data);
448 BASE_IOCTLS(DRV_TYPE_MISC, "UDP Channel", 0x100, casIOCtls_Channel);
450 case 4: // getset_localport (returns bool success)
451 if(!Data) LEAVE_RET('i', chan->LocalPort);
452 if(!CheckMem( Data, sizeof(Uint16) ) ) {
453 LOG("Invalid pointer %p", Data);
457 chan->LocalPort = *(Uint16*)Data;
458 // Permissions check (Ports lower than 1024 are root-only)
459 if(chan->LocalPort != 0 && chan->LocalPort < 1024) {
460 if( Threads_GetUID() != 0 ) {
461 LOG("Attempt by non-superuser to listen on port %i", chan->LocalPort);
466 // Allocate a random port if requested
467 if( chan->LocalPort == 0 )
468 chan->LocalPort = UDP_int_AllocatePort();
471 // Else, mark the requested port as used
472 if( UDP_int_MarkPortAsUsed(chan->LocalPort) == 0 ) {
473 LOG("Port %i us currently in use", chan->LocalPort);
481 case 5: // getset_remoteport (returns bool success)
482 if(!Data) LEAVE_RET('i', chan->RemotePort);
483 if(!CheckMem( Data, sizeof(Uint16) ) ) {
484 LOG("Invalid pointer %p", Data);
487 chan->RemotePort = *(Uint16*)Data;
490 case 6: // set_remoteaddr (returns bool success)
491 switch(chan->Interface->Type)
494 if(!CheckMem(Data, sizeof(tIPv4))) {
495 LOG("Invalid pointer %p", Data);
498 chan->RemoteAddr.v4 = *(tIPv4*)Data;
507 * \brief Close and destroy an open channel
509 void UDP_Channel_Close(tVFS_Node *Node)
511 tUDPChannel *chan = Node->ImplPtr;
514 // Remove from the main list first
515 LOCK(&glUDP_Channels);
516 if(gpUDP_Channels == chan)
517 gpUDP_Channels = gpUDP_Channels->Next;
520 for(prev = gpUDP_Channels;
521 prev->Next && prev->Next != chan;
524 Warning("[UDP ] Bookeeping Fail, channel %p is not in main list", chan);
526 prev->Next = prev->Next->Next;
528 RELEASE(&glUDP_Channels);
536 chan->Queue = tmp->Next;
539 RELEASE(&chan->lQueue);
541 // Free channel structure
546 * \return Port Number on success, or zero on failure
548 Uint16 UDP_int_AllocatePort()
553 for( i = UDP_ALLOC_BASE; i < 0x10000; i += 32 )
554 if( gUDP_Ports[i/32] != 0xFFFFFFFF )
556 if(i == 0x10000) return 0;
559 if( !(gUDP_Ports[i/32] & (1 << (i%32))) )
562 RELEASE(&glUDP_Ports);
566 * \brief Allocate a specific port
567 * \return Boolean Success
569 int UDP_int_MarkPortAsUsed(Uint16 Port)
572 if( gUDP_Ports[Port/32] & (1 << (Port%32)) ) {
574 RELEASE(&glUDP_Ports);
576 gUDP_Ports[Port/32] |= 1 << (Port%32);
577 RELEASE(&glUDP_Ports);
582 * \brief Free an allocated port
584 void UDP_int_FreePort(Uint16 Port)
587 gUDP_Ports[Port/32] &= ~(1 << (Port%32));
588 RELEASE(&glUDP_Ports);