Modules/IPStack - Fixed compile warning
[tpg/acess2.git] / Modules / IPStack / udp.c
1 /*
2  * Acess2 IP Stack
3  * - UDP Handling
4  */
5 #include "ipstack.h"
6 #include <api_drv_common.h>
7 #include "udp.h"
8
9 #define UDP_ALLOC_BASE  0xC000
10
11 // === PROTOTYPES ===
12 void    UDP_Initialise();
13 void    UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer);
14 void    UDP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer);
15 void    UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, Uint16 Port, const void *Data, size_t Length);
16 // --- Client Channels
17 tVFS_Node       *UDP_Channel_Init(tInterface *Interface);
18 Uint64  UDP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
19 Uint64  UDP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer);
20  int    UDP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data);
21 void    UDP_Channel_Close(tVFS_Node *Node);
22 // --- Helpers
23 Uint16  UDP_int_AllocatePort();
24  int    UDP_int_MarkPortAsUsed(Uint16 Port);
25 void    UDP_int_FreePort(Uint16 Port);
26
27 // === GLOBALS ===
28 tVFS_NodeType   gUDP_NodeType = {
29         .Read = UDP_Channel_Read,
30         .Write = UDP_Channel_Write,
31         .IOCtl = UDP_Channel_IOCtl,
32         .Close = UDP_Channel_Close
33 };
34 tMutex  glUDP_Channels;
35 tUDPChannel     *gpUDP_Channels;
36
37 tMutex  glUDP_Ports;
38 Uint32  gUDP_Ports[0x10000/32];
39
40 tSocketFile     gUDP_SocketFile = {NULL, "udp", UDP_Channel_Init};
41
42 // === CODE ===
43 /**
44  * \fn void TCP_Initialise()
45  * \brief Initialise the TCP Layer
46  */
47 void UDP_Initialise()
48 {
49         IPStack_AddFile(&gUDP_SocketFile);
50         //IPv4_RegisterCallback(IP4PROT_UDP, UDP_GetPacket, UDP_Unreachable);
51         IPv4_RegisterCallback(IP4PROT_UDP, UDP_GetPacket);
52 }
53
54 /**
55  * \brief Scan a list of tUDPChannels and find process the first match
56  * \return 0 if no match was found, -1 on error and 1 if a match was found
57  */
58 int UDP_int_ScanList(tUDPChannel *List, tInterface *Interface, void *Address, int Length, void *Buffer)
59 {
60         tUDPHeader      *hdr = Buffer;
61         tUDPChannel     *chan;
62         tUDPPacket      *pack;
63          int    len;
64         
65         for(chan = List;
66                 chan;
67                 chan = chan->Next)
68         {
69                 // Match local endpoint
70                 if(chan->Interface && chan->Interface != Interface)     continue;
71                 if(chan->LocalPort != ntohs(hdr->DestPort))     continue;
72                 
73                 // Check for remote port restriction
74                 if(chan->Remote.Port && chan->Remote.Port != ntohs(hdr->SourcePort))
75                         continue;
76                 // Check for remote address restriction
77                 if(chan->RemoteMask)
78                 {
79                         if(chan->Remote.AddrType != Interface->Type)
80                                 continue;
81                         if(!IPStack_CompareAddress(Interface->Type, Address,
82                                 &chan->Remote.Addr, chan->RemoteMask)
83                                 )
84                                 continue;
85                 }
86                 
87                 Log_Log("UDP", "Recieved packet for %p", chan);
88                 // Create the cached packet
89                 len = ntohs(hdr->Length);
90                 pack = malloc(sizeof(tUDPPacket) + len);
91                 pack->Next = NULL;
92                 memcpy(&pack->Remote.Addr, Address, IPStack_GetAddressSize(Interface->Type));
93                 pack->Remote.Port = ntohs(hdr->SourcePort);
94                 pack->Length = len;
95                 memcpy(pack->Data, hdr->Data, len);
96                 
97                 // Add the packet to the channel's queue
98                 SHORTLOCK(&chan->lQueue);
99                 if(chan->Queue)
100                         chan->QueueEnd->Next = pack;
101                 else
102                         chan->QueueEnd = chan->Queue = pack;
103                 SHORTREL(&chan->lQueue);
104                 VFS_MarkAvaliable(&chan->Node, 1);
105                 Mutex_Release(&glUDP_Channels);
106                 return 1;
107         }
108         return 0;
109 }
110
111 /**
112  * \fn void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
113  * \brief Handles a packet from the IP Layer
114  */
115 void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
116 {
117         tUDPHeader      *hdr = Buffer;
118         
119         Log_Debug("UDP", "hdr->SourcePort = %i", ntohs(hdr->SourcePort));
120         Log_Debug("UDP", "hdr->DestPort = %i", ntohs(hdr->DestPort));
121         Log_Debug("UDP", "hdr->Length = %i", ntohs(hdr->Length));
122         Log_Debug("UDP", "hdr->Checksum = 0x%x", ntohs(hdr->Checksum));
123         
124         // Check registered connections
125         Mutex_Acquire(&glUDP_Channels);
126         UDP_int_ScanList(gpUDP_Channels, Interface, Address, Length, Buffer);
127         Mutex_Release(&glUDP_Channels);
128 }
129
130 /**
131  * \brief Handle an ICMP Unrechable Error
132  */
133 void UDP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer)
134 {
135         
136 }
137
138 /**
139  * \brief Send a packet
140  * \param Channel       Channel to send the packet from
141  * \param Data  Packet data
142  * \param Length        Length in bytes of packet data
143  */
144 void UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, Uint16 Port, const void *Data, size_t Length)
145 {
146         tUDPHeader      *hdr;
147
148         if(Channel->Interface && Channel->Interface->Type != AddrType)  return ;
149         
150         switch(AddrType)
151         {
152         case 4:
153                 // Create the packet
154                 hdr = malloc(sizeof(tUDPHeader)+Length);
155                 hdr->SourcePort = htons( Channel->LocalPort );
156                 hdr->DestPort = htons( Port );
157                 hdr->Length = htons( sizeof(tUDPHeader) + Length );
158                 hdr->Checksum = 0;      // Checksum can be zero on IPv4
159                 memcpy(hdr->Data, Data, Length);
160                 // Pass on the the IPv4 Layer
161                 // TODO: What if Channel->Interface is NULL here?
162                 IPv4_SendPacket(Channel->Interface, *(tIPv4*)Address, IP4PROT_UDP, 0, sizeof(tUDPHeader)+Length, hdr);
163                 // Free allocated packet
164                 free(hdr);
165                 break;
166         }
167 }
168
169 // --- Client Channels
170 tVFS_Node *UDP_Channel_Init(tInterface *Interface)
171 {
172         tUDPChannel     *new;
173         new = calloc( sizeof(tUDPChannel), 1 );
174         new->Interface = Interface;
175         new->Node.ImplPtr = new;
176         new->Node.NumACLs = 1;
177         new->Node.ACLs = &gVFS_ACL_EveryoneRW;
178         new->Node.Type = &gUDP_NodeType;
179         
180         Mutex_Acquire(&glUDP_Channels);
181         new->Next = gpUDP_Channels;
182         gpUDP_Channels = new;
183         Mutex_Release(&glUDP_Channels);
184         
185         return &new->Node;
186 }
187
188 /**
189  * \brief Read from the channel file (wait for a packet)
190  */
191 Uint64 UDP_Channel_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
192 {
193         tUDPChannel     *chan = Node->ImplPtr;
194         tUDPPacket      *pack;
195         tUDPEndpoint    *ep;
196          int    ofs;
197         
198         if(chan->LocalPort == 0) {
199                 Log_Notice("UDP", "Channel %p sent with no local port", chan);
200                 return 0;
201         }
202         
203         while(chan->Queue == NULL)      Threads_Yield();
204         
205         for(;;)
206         {
207                 VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "UDP_Channel_Read");
208                 SHORTLOCK(&chan->lQueue);
209                 if(chan->Queue == NULL) {
210                         SHORTREL(&chan->lQueue);
211                         continue;
212                 }
213                 pack = chan->Queue;
214                 chan->Queue = pack->Next;
215                 if(!chan->Queue) {
216                         chan->QueueEnd = NULL;
217                         VFS_MarkAvaliable(Node, 0);     // Nothing left
218                 }
219                 SHORTREL(&chan->lQueue);
220                 break;
221         }
222
223         // Check that the header fits
224         ep = Buffer;
225         ofs = 4 + IPStack_GetAddressSize(pack->Remote.AddrType);
226         if(Length < ofs) {
227                 free(pack);
228                 Log_Notice("UDP", "Insuficient space for header in buffer (%i < %i)", (int)Length, ofs);
229                 return 0;
230         }
231         
232         // Fill header
233         ep->Port = pack->Remote.Port;
234         ep->AddrType = pack->Remote.AddrType;
235         memcpy(&ep->Addr, &pack->Remote.Addr, IPStack_GetAddressSize(pack->Remote.AddrType));
236         
237         // Copy packet data
238         if(Length > ofs + pack->Length) Length = ofs + pack->Length;
239         memcpy((char*)Buffer + ofs, pack->Data, Length - ofs);
240
241         // Free cached packet
242         free(pack);
243         
244         return Length;
245 }
246
247 /**
248  * \brief Write to the channel file (send a packet)
249  */
250 Uint64 UDP_Channel_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, const void *Buffer)
251 {
252         tUDPChannel     *chan = Node->ImplPtr;
253         const tUDPEndpoint      *ep;
254         const void      *data;
255          int    ofs;
256         if(chan->LocalPort == 0)        return 0;
257         
258         ep = Buffer;    
259         ofs = 2 + 2 + IPStack_GetAddressSize( ep->AddrType );
260
261         data = (const char *)Buffer + ofs;
262
263         UDP_SendPacketTo(chan, ep->AddrType, &ep->Addr, ep->Port, data, (size_t)Length - ofs);
264         
265         return 0;
266 }
267
268 /**
269  * \brief Names for channel IOCtl Calls
270  */
271 static const char *casIOCtls_Channel[] = {
272         DRV_IOCTLNAMES,
273         "getset_localport",
274         "getset_remoteport",
275         "getset_remotemask",
276         "set_remoteaddr",
277         NULL
278         };
279 /**
280  * \brief Channel IOCtls
281  */
282 int UDP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data)
283 {
284         tUDPChannel     *chan = Node->ImplPtr;
285         ENTER("pNode iID pData", Node, ID, Data);
286         switch(ID)
287         {
288         BASE_IOCTLS(DRV_TYPE_MISC, "UDP Channel", 0x100, casIOCtls_Channel);
289         
290         case 4: // getset_localport (returns bool success)
291                 if(!Data)       LEAVE_RET('i', chan->LocalPort);
292                 if(!CheckMem( Data, sizeof(Uint16) ) ) {
293                         LOG("Invalid pointer %p", Data);
294                         LEAVE_RET('i', -1);
295                 }
296                 // Set port
297                 chan->LocalPort = *(Uint16*)Data;
298                 // Permissions check (Ports lower than 1024 are root-only)
299                 if(chan->LocalPort != 0 && chan->LocalPort < 1024) {
300                         if( Threads_GetUID() != 0 ) {
301                                 LOG("Attempt by non-superuser to listen on port %i", chan->LocalPort);
302                                 chan->LocalPort = 0;
303                                 LEAVE_RET('i', -1);
304                         }
305                 }
306                 // Allocate a random port if requested
307                 if( chan->LocalPort == 0 )
308                         chan->LocalPort = UDP_int_AllocatePort();
309                 else
310                 {
311                         // Else, mark the requested port as used
312                         if( UDP_int_MarkPortAsUsed(chan->LocalPort) == 0 ) {
313                                 LOG("Port %i us currently in use", chan->LocalPort);
314                                 chan->LocalPort = 0;
315                                 LEAVE_RET('i', 0);
316                         }
317                         LEAVE_RET('i', 1);
318                 }
319                 LEAVE_RET('i', 1);
320         
321         case 5: // getset_remoteport (returns bool success)
322                 if(!Data)       LEAVE_RET('i', chan->Remote.Port);
323                 if(!CheckMem( Data, sizeof(Uint16) ) ) {
324                         LOG("Invalid pointer %p", Data);
325                         LEAVE_RET('i', -1);
326                 }
327                 chan->Remote.Port = *(Uint16*)Data;
328                 return 1;
329         
330         case 6: // getset_remotemask (returns bool success)
331                 if(!Data)       LEAVE_RET('i', chan->RemoteMask);
332                 if(!CheckMem(Data, sizeof(int)))        LEAVE_RET('i', -1);
333                 if( !chan->Interface ) {
334                         LOG("Can't set remote mask on NULL interface");
335                         LEAVE_RET('i', -1);
336                 }
337                 if( *(int*)Data > IPStack_GetAddressSize(chan->Interface->Type) )
338                         LEAVE_RET('i', -1);
339                 chan->RemoteMask = *(int*)Data;
340                 return 1;       
341
342         case 7: // set_remoteaddr (returns bool success)
343                 if( !chan->Interface ) {
344                         LOG("Can't set remote address on NULL interface");
345                         LEAVE_RET('i', -1);
346                 }
347                 if(!CheckMem(Data, IPStack_GetAddressSize(chan->Interface->Type))) {
348                         LOG("Invalid pointer");
349                         LEAVE_RET('i', -1);
350                 }
351                 memcpy(&chan->Remote.Addr, Data, IPStack_GetAddressSize(chan->Interface->Type));
352                 return 0;
353         }
354         LEAVE_RET('i', 0);
355 }
356
357 /**
358  * \brief Close and destroy an open channel
359  */
360 void UDP_Channel_Close(tVFS_Node *Node)
361 {
362         tUDPChannel     *chan = Node->ImplPtr;
363         tUDPChannel     *prev;
364         
365         // Remove from the main list first
366         Mutex_Acquire(&glUDP_Channels);
367         if(gpUDP_Channels == chan)
368                 gpUDP_Channels = gpUDP_Channels->Next;
369         else
370         {
371                 for(prev = gpUDP_Channels;
372                         prev->Next && prev->Next != chan;
373                         prev = prev->Next);
374                 if(!prev->Next)
375                         Log_Warning("UDP", "Bookeeping Fail, channel %p is not in main list", chan);
376                 else
377                         prev->Next = prev->Next->Next;
378         }
379         Mutex_Release(&glUDP_Channels);
380         
381         // Clear Queue
382         SHORTLOCK(&chan->lQueue);
383         while(chan->Queue)
384         {
385                 tUDPPacket      *tmp;
386                 tmp = chan->Queue;
387                 chan->Queue = tmp->Next;
388                 free(tmp);
389         }
390         SHORTREL(&chan->lQueue);
391         
392         // Free channel structure
393         free(chan);
394 }
395
396 /**
397  * \return Port Number on success, or zero on failure
398  */
399 Uint16 UDP_int_AllocatePort()
400 {
401          int    i;
402         Mutex_Acquire(&glUDP_Ports);
403         // Fast Search
404         for( i = UDP_ALLOC_BASE; i < 0x10000; i += 32 )
405                 if( gUDP_Ports[i/32] != 0xFFFFFFFF )
406                         break;
407         if(i == 0x10000)        return 0;
408         for( ;; i++ )
409         {
410                 if( !(gUDP_Ports[i/32] & (1 << (i%32))) )
411                         return i;
412         }
413         Mutex_Release(&glUDP_Ports);
414 }
415
416 /**
417  * \brief Allocate a specific port
418  * \return Boolean Success
419  */
420 int UDP_int_MarkPortAsUsed(Uint16 Port)
421 {
422         Mutex_Acquire(&glUDP_Ports);
423         if( gUDP_Ports[Port/32] & (1 << (Port%32)) ) {
424                 return 0;
425                 Mutex_Release(&glUDP_Ports);
426         }
427         gUDP_Ports[Port/32] |= 1 << (Port%32);
428         Mutex_Release(&glUDP_Ports);
429         return 1;
430 }
431
432 /**
433  * \brief Free an allocated port
434  */
435 void UDP_int_FreePort(Uint16 Port)
436 {
437         Mutex_Acquire(&glUDP_Ports);
438         gUDP_Ports[Port/32] &= ~(1 << (Port%32));
439         Mutex_Release(&glUDP_Ports);
440 }

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