Merge branch 'master' of git://cadel.mutabah.net/acess2
[tpg/acess2.git] / KernelLand / 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 size_t  UDP_Channel_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
19 size_t  UDP_Channel_Write(tVFS_Node *Node, off_t Offset, size_t 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->Remote.AddrType = Interface->Type;
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                 VFS_MarkAvaliable(&chan->Node, 1);
106                 Mutex_Release(&glUDP_Channels);
107                 return 1;
108         }
109         return 0;
110 }
111
112 /**
113  * \fn void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
114  * \brief Handles a packet from the IP Layer
115  */
116 void UDP_GetPacket(tInterface *Interface, void *Address, int Length, void *Buffer)
117 {
118         tUDPHeader      *hdr = Buffer;
119         
120         Log_Debug("UDP", "%i bytes :%i->:%i (Cksum 0x%04x)",
121                 ntohs(hdr->Length), ntohs(hdr->SourcePort), ntohs(hdr->Length), ntohs(hdr->Checksum));
122         
123         // Check registered connections
124         Mutex_Acquire(&glUDP_Channels);
125         UDP_int_ScanList(gpUDP_Channels, Interface, Address, Length, Buffer);
126         Mutex_Release(&glUDP_Channels);
127 }
128
129 /**
130  * \brief Handle an ICMP Unrechable Error
131  */
132 void UDP_Unreachable(tInterface *Interface, int Code, void *Address, int Length, void *Buffer)
133 {
134         
135 }
136
137 /**
138  * \brief Send a packet
139  * \param Channel       Channel to send the packet from
140  * \param Data  Packet data
141  * \param Length        Length in bytes of packet data
142  */
143 void UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, Uint16 Port, const void *Data, size_t Length)
144 {
145         tUDPHeader      hdr;
146
147         if(Channel->Interface && Channel->Interface->Type != AddrType)  return ;
148         
149         switch(AddrType)
150         {
151         case 4:
152                 // Create the packet
153                 hdr.SourcePort = htons( Channel->LocalPort );
154                 hdr.DestPort = htons( Port );
155                 hdr.Length = htons( sizeof(tUDPHeader) + Length );
156                 hdr.Checksum = 0;       // Checksum can be zero on IPv4
157                 // Pass on the the IPv4 Layer
158                 tIPStackBuffer  *buffer = IPStack_Buffer_CreateBuffer(2 + IPV4_BUFFERS);
159                 IPStack_Buffer_AppendSubBuffer(buffer, Length, 0, Data, NULL, NULL);
160                 IPStack_Buffer_AppendSubBuffer(buffer, sizeof(hdr), 0, &hdr, NULL, NULL);
161                 // TODO: What if Channel->Interface is NULL here?
162                 IPv4_SendPacket(Channel->Interface, *(tIPv4*)Address, IP4PROT_UDP, 0, buffer);
163                 IPStack_Buffer_DestroyBuffer(buffer);
164                 break;
165         }
166 }
167
168 // --- Client Channels
169 tVFS_Node *UDP_Channel_Init(tInterface *Interface)
170 {
171         tUDPChannel     *new;
172         new = calloc( sizeof(tUDPChannel), 1 );
173         new->Interface = Interface;
174         new->Node.ImplPtr = new;
175         new->Node.NumACLs = 1;
176         new->Node.ACLs = &gVFS_ACL_EveryoneRW;
177         new->Node.Type = &gUDP_NodeType;
178         
179         Mutex_Acquire(&glUDP_Channels);
180         new->Next = gpUDP_Channels;
181         gpUDP_Channels = new;
182         Mutex_Release(&glUDP_Channels);
183         
184         return &new->Node;
185 }
186
187 /**
188  * \brief Read from the channel file (wait for a packet)
189  */
190 size_t UDP_Channel_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
191 {
192         tUDPChannel     *chan = Node->ImplPtr;
193         tUDPPacket      *pack;
194         tUDPEndpoint    *ep;
195          int    ofs, addrlen;
196         
197         if(chan->LocalPort == 0) {
198                 Log_Notice("UDP", "Channel %p sent with no local port", chan);
199                 return 0;
200         }
201         
202         while(chan->Queue == NULL)      Threads_Yield();
203         
204         for(;;)
205         {
206                 VFS_SelectNode(Node, VFS_SELECT_READ, NULL, "UDP_Channel_Read");
207                 SHORTLOCK(&chan->lQueue);
208                 if(chan->Queue == NULL) {
209                         SHORTREL(&chan->lQueue);
210                         continue;
211                 }
212                 pack = chan->Queue;
213                 chan->Queue = pack->Next;
214                 if(!chan->Queue) {
215                         chan->QueueEnd = NULL;
216                         VFS_MarkAvaliable(Node, 0);     // Nothing left
217                 }
218                 SHORTREL(&chan->lQueue);
219                 break;
220         }
221
222         // Check that the header fits
223         addrlen = IPStack_GetAddressSize(pack->Remote.AddrType);
224         ep = Buffer;
225         ofs = 4 + addrlen;
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, addrlen);
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 size_t UDP_Channel_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
251 {
252         tUDPChannel     *chan = Node->ImplPtr;
253         const tUDPEndpoint      *ep;
254         const void      *data;
255          int    ofs;
256         
257         if(chan->LocalPort == 0) {
258                 Log_Notice("UDP", "Write to channel %p with zero local port", chan);
259                 return 0;
260         }
261         
262         ep = Buffer;    
263         ofs = 2 + 2 + IPStack_GetAddressSize( ep->AddrType );
264
265         data = (const char *)Buffer + ofs;
266
267         UDP_SendPacketTo(chan, ep->AddrType, &ep->Addr, ep->Port, data, (size_t)Length - ofs);
268         
269         return Length;
270 }
271
272 /**
273  * \brief Names for channel IOCtl Calls
274  */
275 static const char *casIOCtls_Channel[] = {
276         DRV_IOCTLNAMES,
277         "getset_localport",
278         "getset_remoteport",
279         "getset_remotemask",
280         "set_remoteaddr",
281         NULL
282         };
283 /**
284  * \brief Channel IOCtls
285  */
286 int UDP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data)
287 {
288         tUDPChannel     *chan = Node->ImplPtr;
289         ENTER("pNode iID pData", Node, ID, Data);
290         switch(ID)
291         {
292         BASE_IOCTLS(DRV_TYPE_MISC, "UDP Channel", 0x100, casIOCtls_Channel);
293         
294         case 4: // getset_localport (returns bool success)
295                 if(!Data)       LEAVE_RET('i', chan->LocalPort);
296                 if(!CheckMem( Data, sizeof(Uint16) ) ) {
297                         LOG("Invalid pointer %p", Data);
298                         LEAVE_RET('i', -1);
299                 }
300                 // Set port
301                 chan->LocalPort = *(Uint16*)Data;
302                 // Permissions check (Ports lower than 1024 are root-only)
303                 if(chan->LocalPort != 0 && chan->LocalPort < 1024) {
304                         if( Threads_GetUID() != 0 ) {
305                                 LOG("Attempt by non-superuser to listen on port %i", chan->LocalPort);
306                                 chan->LocalPort = 0;
307                                 LEAVE_RET('i', -1);
308                         }
309                 }
310                 // Allocate a random port if requested
311                 if( chan->LocalPort == 0 )
312                         chan->LocalPort = UDP_int_AllocatePort();
313                 else
314                 {
315                         // Else, mark the requested port as used
316                         if( UDP_int_MarkPortAsUsed(chan->LocalPort) == 0 ) {
317                                 LOG("Port %i us currently in use", chan->LocalPort);
318                                 chan->LocalPort = 0;
319                                 LEAVE_RET('i', 0);
320                         }
321                         LEAVE_RET('i', 1);
322                 }
323                 LEAVE_RET('i', 1);
324         
325         case 5: // getset_remoteport (returns bool success)
326                 if(!Data)       LEAVE_RET('i', chan->Remote.Port);
327                 if(!CheckMem( Data, sizeof(Uint16) ) ) {
328                         LOG("Invalid pointer %p", Data);
329                         LEAVE_RET('i', -1);
330                 }
331                 chan->Remote.Port = *(Uint16*)Data;
332                 return 1;
333         
334         case 6: // getset_remotemask (returns bool success)
335                 if(!Data)       LEAVE_RET('i', chan->RemoteMask);
336                 if(!CheckMem(Data, sizeof(int)))        LEAVE_RET('i', -1);
337                 if( !chan->Interface ) {
338                         LOG("Can't set remote mask on NULL interface");
339                         LEAVE_RET('i', -1);
340                 }
341                 if( *(int*)Data > IPStack_GetAddressSize(chan->Interface->Type) )
342                         LEAVE_RET('i', -1);
343                 chan->RemoteMask = *(int*)Data;
344                 return 1;       
345
346         case 7: // set_remoteaddr (returns bool success)
347                 if( !chan->Interface ) {
348                         LOG("Can't set remote address on NULL interface");
349                         LEAVE_RET('i', -1);
350                 }
351                 if(!CheckMem(Data, IPStack_GetAddressSize(chan->Interface->Type))) {
352                         LOG("Invalid pointer");
353                         LEAVE_RET('i', -1);
354                 }
355                 memcpy(&chan->Remote.Addr, Data, IPStack_GetAddressSize(chan->Interface->Type));
356                 return 0;
357         }
358         LEAVE_RET('i', 0);
359 }
360
361 /**
362  * \brief Close and destroy an open channel
363  */
364 void UDP_Channel_Close(tVFS_Node *Node)
365 {
366         tUDPChannel     *chan = Node->ImplPtr;
367         tUDPChannel     *prev;
368         
369         // Remove from the main list first
370         Mutex_Acquire(&glUDP_Channels);
371         if(gpUDP_Channels == chan)
372                 gpUDP_Channels = gpUDP_Channels->Next;
373         else
374         {
375                 for(prev = gpUDP_Channels;
376                         prev->Next && prev->Next != chan;
377                         prev = prev->Next);
378                 if(!prev->Next)
379                         Log_Warning("UDP", "Bookeeping Fail, channel %p is not in main list", chan);
380                 else
381                         prev->Next = prev->Next->Next;
382         }
383         Mutex_Release(&glUDP_Channels);
384         
385         // Clear Queue
386         SHORTLOCK(&chan->lQueue);
387         while(chan->Queue)
388         {
389                 tUDPPacket      *tmp;
390                 tmp = chan->Queue;
391                 chan->Queue = tmp->Next;
392                 free(tmp);
393         }
394         SHORTREL(&chan->lQueue);
395         
396         // Free channel structure
397         free(chan);
398 }
399
400 /**
401  * \return Port Number on success, or zero on failure
402  */
403 Uint16 UDP_int_AllocatePort()
404 {
405          int    i;
406         Mutex_Acquire(&glUDP_Ports);
407         // Fast Search
408         for( i = UDP_ALLOC_BASE; i < 0x10000; i += 32 )
409                 if( gUDP_Ports[i/32] != 0xFFFFFFFF )
410                         break;
411         if(i == 0x10000)        return 0;
412         for( ;; i++ )
413         {
414                 if( !(gUDP_Ports[i/32] & (1 << (i%32))) )
415                         return i;
416         }
417         Mutex_Release(&glUDP_Ports);
418 }
419
420 /**
421  * \brief Allocate a specific port
422  * \return Boolean Success
423  */
424 int UDP_int_MarkPortAsUsed(Uint16 Port)
425 {
426         Mutex_Acquire(&glUDP_Ports);
427         if( gUDP_Ports[Port/32] & (1 << (Port%32)) ) {
428                 return 0;
429                 Mutex_Release(&glUDP_Ports);
430         }
431         gUDP_Ports[Port/32] |= 1 << (Port%32);
432         Mutex_Release(&glUDP_Ports);
433         return 1;
434 }
435
436 /**
437  * \brief Free an allocated port
438  */
439 void UDP_int_FreePort(Uint16 Port)
440 {
441         Mutex_Acquire(&glUDP_Ports);
442         gUDP_Ports[Port/32] &= ~(1 << (Port%32));
443         Mutex_Release(&glUDP_Ports);
444 }

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