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

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