Fixed compilation issues in IPStack
[tpg/acess2.git] / Modules / IPStack / main.c
1 /*
2  * Acess2 IP Stack
3  * - Stack Initialisation
4  */
5 #define DEBUG   0
6 #define VERSION VER2(0,10)
7 #include "ipstack.h"
8 #include "link.h"
9 #include <modules.h>
10 #include <fs_devfs.h>
11 #include <tpl_drv_common.h>
12 #include <tpl_drv_network.h>
13
14 // === CONSTANTS ===
15 //! Default timeout value, 30 seconds
16 #define DEFAULT_TIMEOUT (30*1000)
17
18 // === IMPORTS ===
19 extern int      ARP_Initialise();
20 extern void     UDP_Initialise();
21 extern void     TCP_Initialise();
22 extern int      IPv4_Initialise();
23 extern int      IPv4_Ping(tInterface *Iface, tIPv4 Addr);
24 extern int      IPv6_Initialise();
25 //extern int    IPv6_Ping(tInterface *Iface, tIPv6 Addr);
26 extern tVFS_Node        gIP_RouteNode;
27
28 // === PROTOTYPES ===
29  int    IPStack_Install(char **Arguments);
30  int    IPStack_IOCtlRoot(tVFS_Node *Node, int ID, void *Data);
31 char    *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos);
32 tVFS_Node       *IPStack_Root_FindDir(tVFS_Node *Node, const char *Name);
33  int    IPStack_Root_IOCtl(tVFS_Node *Node, int ID, void *Data);
34  
35 char    *IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos);
36 tVFS_Node       *IPStack_Iface_FindDir(tVFS_Node *Node, const char *Name);
37  int    IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data);
38  
39  int    IPStack_AddInterface(const char *Device, const char *Name);
40 tAdapter        *IPStack_GetAdapter(const char *Path);
41
42 // === GLOBALS ===
43 MODULE_DEFINE(0, VERSION, IPStack, IPStack_Install, NULL, NULL);
44 tDevFS_Driver   gIP_DriverInfo = {
45         NULL, "ip",
46         {
47         .Size = 0,      // Number of interfaces
48         .NumACLs = 1,
49         .ACLs = &gVFS_ACL_EveryoneRX,
50         .Flags = VFS_FFLAG_DIRECTORY,
51         .ReadDir = IPStack_Root_ReadDir,
52         .FindDir = IPStack_Root_FindDir,
53         .IOCtl = IPStack_Root_IOCtl
54         }
55 };
56 tShortSpinlock  glIP_Interfaces;
57 //! Loopback (127.0.0.0/8, ::1) Pseudo-Interface
58 tInterface      gIP_LoopInterface = {
59         Node: {
60                 ImplPtr: &gIP_LoopInterface,
61                 Flags: VFS_FFLAG_DIRECTORY,
62                 Size: -1,
63                 NumACLs: 1,
64                 ACLs: &gVFS_ACL_EveryoneRX,
65                 ReadDir: IPStack_Iface_ReadDir,
66                 FindDir: IPStack_Iface_FindDir,
67                 IOCtl: IPStack_Iface_IOCtl
68         },
69         Adapter: NULL,
70         Type: 0
71 };
72 tInterface      *gIP_Interfaces = NULL;
73 tInterface      *gIP_Interfaces_Last = NULL;
74  int    giIP_NextIfaceId = 1;
75 tMutex  glIP_Adapters;
76 tAdapter        *gIP_Adapters = NULL;
77 tSocketFile     *gIP_FileTemplates;
78
79 // === CODE ===
80 /**
81  * \fn int IPStack_Install(char **Arguments)
82  * \brief Intialise the relevant parts of the stack and register with DevFS
83  */
84 int IPStack_Install(char **Arguments)
85 {
86          int    i = 0;
87         
88         // Layer 3 - Network Layer Protocols
89         ARP_Initialise();
90         IPv4_Initialise();
91         IPv6_Initialise();
92         // Layer 4 - Transport Layer Protocols
93         TCP_Initialise();
94         UDP_Initialise();
95         
96         if(Arguments)
97         {
98                 // Parse module arguments
99                 for( i = 0; Arguments[i]; i++ )
100                 {
101                         // TODO:
102                         // Define interfaces by <Device>,<Type>,<HexStreamAddress>,<Bits>
103                         // Where:
104                         // - <Device> is the device path (E.g. /Devices/ne2k/0)
105                         // - <Type> is a number (e.g. 4) or symbol (e.g. AF_INET4)
106                         // - <HexStreamAddress> is a condensed hexadecimal stream (in big endian)
107                         //      (E.g. 0A000201 for 10.0.2.1 IPv4)
108                         // - <Bits> is the number of subnet bits (E.g. 24 for an IPv4 Class C)
109                 }
110         }
111         
112         gIP_LoopInterface.Adapter = IPStack_GetAdapter("/Devices/fifo/anon");
113         
114         DevFS_AddDevice( &gIP_DriverInfo );
115         
116         return MODULE_ERR_OK;
117 }
118
119 /**
120  * \brief Adds a file to the socket list
121  */
122 int IPStack_AddFile(tSocketFile *File)
123 {
124         Log_Log("IPStack", "Added file '%s'", File->Name);
125         File->Next = gIP_FileTemplates;
126         gIP_FileTemplates = File;
127         return 0;
128 }
129
130 /**
131  * \brief Read from the IP Stack's Device Directory
132  */
133 char *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos)
134 {
135         tInterface      *iface;
136         char    *name;
137         ENTER("pNode iPos", Node, Pos);
138         
139
140         // Routing Subdir
141         if( Pos == 0 ) {
142                 return strdup("routes");
143         }
144         // Pseudo Interfaces
145         if( Pos == 1 ) {
146                 return strdup("lo");
147         }
148         Pos -= 2;
149         
150         // Traverse the list
151         for( iface = gIP_Interfaces; iface && Pos--; iface = iface->Next ) ;
152         
153         // Did we run off the end?
154         if(!iface) {
155                 LEAVE('n');
156                 return NULL;
157         }
158         
159         name = malloc(4);
160         if(!name) {
161                 Log_Warning("IPStack", "IPStack_Root_ReadDir - malloc error");
162                 LEAVE('n');
163                 return NULL;
164         }
165         
166         // Create the name
167         Pos = iface->Node.ImplInt;
168         if(Pos < 10) {
169                 name[0] = '0' + Pos;
170                 name[1] = '\0';
171         }
172         else if(Pos < 100) {
173                 name[0] = '0' + Pos/10;
174                 name[1] = '0' + Pos%10;
175                 name[2] = '\0';
176         }
177         else {
178                 name[0] = '0' + Pos/100;
179                 name[1] = '0' + (Pos/10)%10;
180                 name[2] = '0' + Pos%10;
181                 name[3] = '\0';
182         }
183         
184         LEAVE('s', name);
185         // Return the pre-generated name
186         return name;
187 }
188
189 /**
190  * \brief Get the node of an interface
191  */
192 tVFS_Node *IPStack_Root_FindDir(tVFS_Node *Node, const char *Name)
193 {
194          int    i, num;
195         tInterface      *iface;
196         
197         ENTER("pNode sName", Node, Name);
198         
199         // Routing subdir
200         if( strcmp(Name, "routes") == 0 ) {
201                 return &gIP_RouteNode;
202         }
203         
204         // Loopback
205         if( strcmp(Name, "lo") == 0 ) {
206                 return &gIP_LoopInterface.Node;
207         }
208         
209         i = 0;  num = 0;
210         while('0' <= Name[i] && Name[i] <= '9')
211         {
212                 num *= 10;
213                 num += Name[i] - '0';
214                 i ++;
215         }
216         if(Name[i] != '\0') {
217                 LEAVE('n');
218                 return NULL;
219         }
220         
221         for( iface = gIP_Interfaces; iface; iface = iface->Next )
222         {
223                 if( (int)iface->Node.ImplInt == num )
224                 {
225                         LEAVE('p', &iface->Node);
226                         return &iface->Node;
227                 }
228         }
229         LEAVE('p', NULL);
230         return NULL;
231 }
232
233 static const char *casIOCtls_Root[] = { DRV_IOCTLNAMES, "add_interface", NULL };
234 /**
235  * \brief Handles IOCtls for the IPStack root
236  */
237 int IPStack_Root_IOCtl(tVFS_Node *Node, int ID, void *Data)
238 {
239          int    tmp;
240         ENTER("pNode iID pData", Node, ID, Data);
241         
242         switch(ID)
243         {
244         // --- Standard IOCtls (0-3) ---
245         case DRV_IOCTL_TYPE:
246                 LEAVE('i', DRV_TYPE_MISC);
247                 return DRV_TYPE_MISC;
248         
249         case DRV_IOCTL_IDENT:
250                 tmp = ModUtil_SetIdent(Data, "IPStack");
251                 LEAVE('i', 1);
252                 return 1;
253         
254         case DRV_IOCTL_VERSION:
255                 LEAVE('x', VERSION);
256                 return VERSION;
257         
258         case DRV_IOCTL_LOOKUP:
259                 tmp = ModUtil_LookupString( (char**)casIOCtls_Root, (char*)Data );
260                 LEAVE('i', tmp);
261                 return tmp;
262                 
263                 /*
264                  * add_interface
265                  * - Adds a new IP interface and binds it to a device
266                  */
267         case 4:
268                 if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
269                 if( !CheckString( Data ) )      LEAVE_RET('i', -1);
270                 {
271                         char    name[4] = "";
272                         tmp = IPStack_AddInterface(Data, name);
273                 }
274                 LEAVE_RET('i', tmp);
275         }
276         LEAVE('i', 0);
277         return 0;
278 }
279
280 /**
281  * \brief Read from an interface's directory
282  */
283 char *IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos)
284 {
285         tSocketFile     *file = gIP_FileTemplates;
286         while(Pos-- && file) {
287                 file = file->Next;
288         }
289         
290         if(!file)       return NULL;
291         
292         return strdup(file->Name);
293 }
294
295 /**
296  * \brief Gets a named node from an interface directory
297  */
298 tVFS_Node *IPStack_Iface_FindDir(tVFS_Node *Node, const char *Name)
299 {
300         tSocketFile     *file = gIP_FileTemplates;
301         
302         // Get file definition
303         for(;file;file = file->Next)
304         {
305                 if( strcmp(file->Name, Name) == 0 )     break;
306         }
307         if(!file)       return NULL;
308         
309         // Pass the buck!
310         return file->Init(Node->ImplPtr);
311 }
312
313 /**
314  * \brief Names for interface IOCtl Calls
315  */
316 static const char *casIOCtls_Iface[] = {
317         DRV_IOCTLNAMES,
318         "getset_type",
319         "get_address", "set_address",
320         "getset_subnet",
321         "get_gateway", "set_gateway",
322         "get_device",
323         "ping",
324         NULL
325         };
326 /**
327  * \brief Handles IOCtls for the IPStack interfaces
328  */
329 int IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data)
330 {
331          int    tmp;
332         tInterface      *iface = (tInterface*)Node->ImplPtr;
333         ENTER("pNode iID pData", Node, ID, Data);
334         
335         switch(ID)
336         {
337         // --- Standard IOCtls (0-3) ---
338         case DRV_IOCTL_TYPE:
339                 LEAVE('i', DRV_TYPE_MISC);
340                 return DRV_TYPE_MISC;
341         
342         case DRV_IOCTL_IDENT:
343                 tmp = ModUtil_SetIdent(Data, STR(IDENT));
344                 LEAVE('i', 1);
345                 return 1;
346         
347         case DRV_IOCTL_VERSION:
348                 LEAVE('x', VERSION);
349                 return VERSION;
350         
351         case DRV_IOCTL_LOOKUP:
352                 tmp = ModUtil_LookupString( (char**)casIOCtls_Iface, (char*)Data );
353                 LEAVE('i', tmp);
354                 return tmp;
355         
356         /*
357          * getset_type
358          * - Get/Set the interface type
359          */
360         case 4:
361                 // Set Type?
362                 if( Data )
363                 {
364                         // Ok, it's set type
365                         if( Threads_GetUID() != 0 ) {
366                                 LOG("Attempt by non-root to alter an interface (%i)", Threads_GetUID());
367                                 LEAVE('i', -1);
368                                 return -1;
369                         }
370                         if( !CheckMem( Data, sizeof(int) ) ) {
371                                 LOG("Invalid pointer %p", Data);
372                                 LEAVE('i', -1);
373                                 return -1;
374                         }
375                         switch( *(int*)Data )
376                         {
377                         case 0: // Disable
378                                 iface->Type = 0;
379                                 memset(&iface->IP6, 0, sizeof(tIPv6));  // Clear address
380                                 break;
381                         case 4: // IPv4
382                                 iface->Type = 4;
383                                 memset(&iface->IP4, 0, sizeof(tIPv4));
384                                 break;
385                         case 6: // IPv6
386                                 iface->Type = 6;
387                                 memset(&iface->IP6, 0, sizeof(tIPv6));
388                                 break;
389                         default:
390                                 LEAVE('i', -1);
391                                 return -1;
392                         }
393                 }
394                 LEAVE('i', iface->Type);
395                 return iface->Type;
396         
397         /*
398          * get_address
399          * - Get the interface's address
400          */
401         case 5:
402                 switch(iface->Type)
403                 {
404                 case 0: LEAVE_RET('i', 1);
405                 case 4:
406                         if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
407                         memcpy( Data, &iface->IP4.Address, sizeof(tIPv4) );
408                         LEAVE_RET('i', 1);
409                 case 6:
410                         if( !CheckMem( Data, sizeof(tIPv6) ) )  LEAVE_RET('i', -1);
411                         memcpy( Data, &iface->IP6.Address, sizeof(tIPv6) );
412                         LEAVE_RET('i', 1);
413                 }
414                 LEAVE_RET('i', 0);
415         
416         /*
417          * set_address
418          * - Get the interface's address
419          */
420         case 6:
421                 if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
422                 switch(iface->Type)
423                 {
424                 case 0: LEAVE_RET('i', 1);
425                 case 4:
426                         if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
427                         iface->Type = 0;        // One very hacky mutex/trash protector
428                         memcpy( &iface->IP4.Address, Data, sizeof(tIPv4) );
429                         iface->Type = 4;
430                         LEAVE_RET('i', 1);
431                 case 6:
432                         if( !CheckMem( Data, sizeof(tIPv6) ) )  LEAVE_RET('i', -1);
433                         iface->Type = 0;
434                         memcpy( &iface->IP6.Address, Data, sizeof(tIPv6) );
435                         iface->Type = 6;
436                         LEAVE_RET('i', 1);
437                 }
438                 LEAVE_RET('i', 0);
439         
440         /*
441          * getset_subnet
442          * - Get/Set the bits in the address subnet
443          */
444         case 7:
445                 // Get?
446                 if( Data == NULL )
447                 {
448                         switch( iface->Type )
449                         {
450                         case 4:         LEAVE_RET('i', iface->IP4.SubnetBits);
451                         case 6:         LEAVE_RET('i', iface->IP6.SubnetBits);
452                         default:        LEAVE_RET('i', 0);
453                         }
454                 }
455                 
456                 // Ok, set.
457                 if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
458                 if( !CheckMem(Data, sizeof(int)) )      LEAVE_RET('i', -1);
459                 
460                 // Check and set the subnet bits
461                 switch( iface->Type )
462                 {
463                 case 4:
464                         if( *(int*)Data < 0 || *(int*)Data > 31 )       LEAVE_RET('i', -1);
465                         iface->IP4.SubnetBits = *(int*)Data;
466                         LEAVE_RET('i', iface->IP4.SubnetBits);
467                 case 6:
468                         if( *(int*)Data < 0 || *(int*)Data > 127 )      LEAVE_RET('i', -1);
469                         iface->IP6.SubnetBits = *(int*)Data;
470                         LEAVE_RET('i', iface->IP6.SubnetBits);
471                 default:
472                         break;
473                 }
474                 
475                 LEAVE('i', 0);
476                 return 0;
477                 
478         /*
479          * get_gateway
480          * - Get the interface's IPv4 gateway
481          */
482         case 8:
483                 switch(iface->Type)
484                 {
485                 case 0:
486                         LEAVE_RET('i', 1);
487                 case 4:
488                         if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
489                         memcpy( Data, &iface->IP4.Gateway, sizeof(tIPv4) );
490                         LEAVE_RET('i', 1);
491                 case 6:
492                         LEAVE_RET('i', 1);
493                 }
494                 LEAVE('i', 0);
495                 return 0;
496         
497         /*
498          * set_gateway
499          * - Get/Set the interface's IPv4 gateway
500          */
501         case 9:
502                 if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
503                 switch(iface->Type)
504                 {
505                 case 0:
506                         LEAVE_RET('i', 1);
507                 
508                 case 4:
509                         if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
510                         iface->Type = 0;        // One very hacky mutex/trash protector
511                         memcpy( &iface->IP4.Gateway, Data, sizeof(tIPv4) );
512                         iface->Type = 4;
513                         LEAVE_RET('i', 1);
514                         
515                 case 6:
516                         LEAVE_RET('i', 1);
517                 }
518                 break;
519         
520         /*
521          * get_device
522          * - Gets the name of the attached device
523          */
524         case 10:
525                 if( Data == NULL )
526                         LEAVE_RET('i', iface->Adapter->DeviceLen);
527                 if( !CheckMem( Data, iface->Adapter->DeviceLen+1 ) )
528                         LEAVE_RET('i', -1);
529                 strcpy( Data, iface->Adapter->Device );
530                 return iface->Adapter->DeviceLen;
531         
532         /*
533          * ping
534          * - Send an ICMP Echo
535          */
536         case 11:
537                 switch(iface->Type)
538                 {
539                 case 0:
540                         LEAVE_RET('i', 1);
541                 
542                 case 4:
543                         if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
544                         tmp = IPv4_Ping(iface, *(tIPv4*)Data);
545                         LEAVE('i', tmp);
546                         return tmp;
547                         
548                 case 6:
549                         LEAVE_RET('i', 1);
550                 }
551                 break;
552         
553         }
554         
555         LEAVE('i', 0);
556         return 0;
557 }
558
559 // --- Internal ---
560 /**
561  * \fn int IPStack_AddInterface(char *Device)
562  * \brief Adds an interface to the list
563  */
564 int IPStack_AddInterface(const char *Device, const char *Name)
565 {
566         tInterface      *iface;
567         tAdapter        *card;
568         
569         ENTER("sDevice", Device);
570         
571         card = IPStack_GetAdapter(Device);
572         
573         iface = malloc(sizeof(tInterface) + strlen(Name));
574         if(!iface) {
575                 LEAVE('i', -2);
576                 return -2;      // Return ERR_MYBAD
577         }
578         
579         iface->Next = NULL;
580         iface->Type = 0;        // Unset type
581         
582         // Create Node
583         iface->Node.ImplPtr = iface;
584         iface->Node.Flags = VFS_FFLAG_DIRECTORY;
585         iface->Node.Size = -1;
586         iface->Node.NumACLs = 1;
587         iface->Node.ACLs = &gVFS_ACL_EveryoneRX;
588         iface->Node.ReadDir = IPStack_Iface_ReadDir;
589         iface->Node.FindDir = IPStack_Iface_FindDir;
590         iface->Node.IOCtl = IPStack_Iface_IOCtl;
591         iface->Node.MkNod = NULL;
592         iface->Node.Link = NULL;
593         iface->Node.Relink = NULL;
594         iface->Node.Close = NULL;
595         
596         // Set Defaults
597         iface->TimeoutDelay = DEFAULT_TIMEOUT;
598         
599         // Get adapter handle
600         iface->Adapter = IPStack_GetAdapter(Device);
601         if( !iface->Adapter ) {
602                 free( iface );
603                 LEAVE('i', -1);
604                 return -1;      // Return ERR_YOUFAIL
605         }
606         
607         // Delay setting ImplInt until after the adapter is opened
608         // Keeps things simple
609         iface->Node.ImplInt = giIP_NextIfaceId++;
610         
611         // Append to list
612         SHORTLOCK( &glIP_Interfaces );
613         if( gIP_Interfaces ) {
614                 gIP_Interfaces_Last->Next = iface;
615                 gIP_Interfaces_Last = iface;
616         }
617         else {
618                 gIP_Interfaces = iface;
619                 gIP_Interfaces_Last = iface;
620         }
621         SHORTREL( &glIP_Interfaces );
622         
623         gIP_DriverInfo.RootNode.Size ++;
624         
625         // Success!
626         LEAVE('i', iface->Node.ImplInt);
627         return iface->Node.ImplInt;
628 }
629
630 /**
631  * \fn tAdapter *IPStack_GetAdapter(const char *Path)
632  * \brief Gets/opens an adapter given the path
633  */
634 tAdapter *IPStack_GetAdapter(const char *Path)
635 {
636         tAdapter        *dev;
637          int    tmp;
638         
639         ENTER("sPath", Path);
640         
641         Mutex_Acquire( &glIP_Adapters );
642         
643         // Check if this adapter is already open
644         for( dev = gIP_Adapters; dev; dev = dev->Next )
645         {
646                 if( strcmp(dev->Device, Path) == 0 ) {
647                         dev->NRef ++;
648                         Mutex_Release( &glIP_Adapters );
649                         LEAVE('p', dev);
650                         return dev;
651                 }
652         }
653         
654         // Ok, so let's open it
655         dev = malloc( sizeof(tAdapter) + strlen(Path) + 1 );
656         if(!dev) {
657                 Mutex_Release( &glIP_Adapters );
658                 LEAVE('n');
659                 return NULL;
660         }
661         
662         // Fill Structure
663         strcpy( dev->Device, Path );
664         dev->NRef = 1;
665         dev->DeviceLen = strlen(Path);
666         
667         // Open Device
668         dev->DeviceFD = VFS_Open( dev->Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE );
669         if( dev->DeviceFD == -1 ) {
670                 free( dev );
671                 Mutex_Release( &glIP_Adapters );
672                 LEAVE('n');
673                 return NULL;
674         }
675         
676         // Check that it is a network interface
677         tmp = VFS_IOCtl(dev->DeviceFD, 0, NULL);
678         LOG("Device type = %i", tmp);
679         if( tmp != DRV_TYPE_NETWORK ) {
680                 Warning("IPStack_GetAdapter: '%s' is not a network interface", dev->Device);
681                 VFS_Close( dev->DeviceFD );
682                 free( dev );
683                 Mutex_Release( &glIP_Adapters );
684                 LEAVE('n');
685                 return NULL;
686         }
687         
688         // Get MAC Address
689         VFS_IOCtl(dev->DeviceFD, NET_IOCTL_GETMAC, &dev->MacAddr);
690         
691         // Add to list
692         dev->Next = gIP_Adapters;
693         gIP_Adapters = dev;
694         
695         Mutex_Release( &glIP_Adapters );
696         
697         // Start watcher
698         Link_WatchDevice( dev );
699         
700         LEAVE('p', dev);
701         return dev;
702 }
703
704 /**
705  * \brief Gets the size (in bytes) of a specified form of address
706  */
707 int IPStack_GetAddressSize(int AddressType)
708 {
709         switch(AddressType)
710         {
711         default:
712         case AF_NULL:
713                 return 0;
714         case AF_INET4:
715                 return sizeof(tIPv4);
716         case AF_INET6:
717                 return sizeof(tIPv6);
718         }
719 }

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