e3803208bd585648e74e69189a31a4e4283df65e
[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         "ping",
272         NULL
273         };
274 /**
275  * \brief Handles IOCtls for the IPStack interfaces
276  */
277 int IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data)
278 {
279          int    tmp;
280         tInterface      *iface = (tInterface*)Node->ImplPtr;
281         ENTER("pNode iID pData", Node, ID, Data);
282         
283         switch(ID)
284         {
285         // --- Standard IOCtls (0-3) ---
286         case DRV_IOCTL_TYPE:
287                 LEAVE('i', DRV_TYPE_MISC);
288                 return DRV_TYPE_MISC;
289         
290         case DRV_IOCTL_IDENT:
291                 tmp = ModUtil_SetIdent(Data, STR(IDENT));
292                 LEAVE('i', 1);
293                 return 1;
294         
295         case DRV_IOCTL_VERSION:
296                 LEAVE('x', VERSION);
297                 return VERSION;
298         
299         case DRV_IOCTL_LOOKUP:
300                 tmp = ModUtil_LookupString( (char**)casIOCtls_Iface, (char*)Data );
301                 LEAVE('i', tmp);
302                 return tmp;
303         
304         /*
305          * getset_type
306          * - Get/Set the interface type
307          */
308         case 4:
309                 // Set Type?
310                 if( Data )
311                 {
312                         // Ok, it's set type
313                         if( Threads_GetUID() != 0 ) {
314                                 LOG("Attempt by non-root to alter an interface (%i)", Threads_GetUID());
315                                 LEAVE('i', -1);
316                                 return -1;
317                         }
318                         if( !CheckMem( Data, sizeof(int) ) ) {
319                                 LOG("Invalid pointer %p", Data);
320                                 LEAVE('i', -1);
321                                 return -1;
322                         }
323                         switch( *(int*)Data )
324                         {
325                         case 0: // Disable
326                                 iface->Type = 0;
327                                 memset(&iface->IP6, 0, sizeof(tIPv6));  // Clear address
328                                 break;
329                         case 4: // IPv4
330                                 iface->Type = 4;
331                                 memset(&iface->IP4, 0, sizeof(tIPv4));
332                                 break;
333                         case 6: // IPv6
334                                 iface->Type = 6;
335                                 memset(&iface->IP6, 0, sizeof(tIPv6));
336                                 break;
337                         default:
338                                 LEAVE('i', -1);
339                                 return -1;
340                         }
341                 }
342                 LEAVE('i', iface->Type);
343                 return iface->Type;
344         
345         /*
346          * get_address
347          * - Get the interface's address
348          */
349         case 5:
350                 switch(iface->Type)
351                 {
352                 case 0: LEAVE_RET('i', 1);
353                 case 4:
354                         if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
355                         memcpy( Data, &iface->IP4.Address, sizeof(tIPv4) );
356                         LEAVE_RET('i', 1);
357                 case 6:
358                         if( !CheckMem( Data, sizeof(tIPv6) ) )  LEAVE_RET('i', -1);
359                         memcpy( Data, &iface->IP6.Address, sizeof(tIPv6) );
360                         LEAVE_RET('i', 1);
361                 }
362                 LEAVE_RET('i', 0);
363         
364         /*
365          * set_address
366          * - Get the interface's address
367          */
368         case 6:
369                 if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
370                 switch(iface->Type)
371                 {
372                 case 0: LEAVE_RET('i', 1);
373                 case 4:
374                         if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
375                         iface->Type = 0;        // One very hacky mutex/trash protector
376                         memcpy( &iface->IP4.Address, Data, sizeof(tIPv4) );
377                         iface->Type = 4;
378                         LEAVE_RET('i', 1);
379                 case 6:
380                         if( !CheckMem( Data, sizeof(tIPv6) ) )  LEAVE_RET('i', -1);
381                         iface->Type = 0;
382                         memcpy( &iface->IP6.Address, Data, sizeof(tIPv6) );
383                         iface->Type = 6;
384                         LEAVE_RET('i', 1);
385                 }
386                 LEAVE_RET('i', 0);
387         
388         /*
389          * getset_subnet
390          * - Get/Set the bits in the address subnet
391          */
392         case 7:
393                 // Get?
394                 if( Data == NULL )
395                 {
396                         switch( iface->Type )
397                         {
398                         case 4:         LEAVE_RET('i', iface->IP4.SubnetBits);
399                         case 6:         LEAVE_RET('i', iface->IP6.SubnetBits);
400                         default:        LEAVE_RET('i', 0);
401                         }
402                 }
403                 
404                 // Ok, set.
405                 if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
406                 if( !CheckMem(Data, sizeof(int)) )      LEAVE_RET('i', -1);
407                 
408                 // Check and set the subnet bits
409                 switch( iface->Type )
410                 {
411                 case 4:
412                         if( *(int*)Data < 0 || *(int*)Data > 31 )       LEAVE_RET('i', -1);
413                         iface->IP4.SubnetBits = *(int*)Data;
414                         LEAVE_RET('i', iface->IP4.SubnetBits);
415                 case 6:
416                         if( *(int*)Data < 0 || *(int*)Data > 127 )      LEAVE_RET('i', -1);
417                         iface->IP6.SubnetBits = *(int*)Data;
418                         LEAVE_RET('i', iface->IP6.SubnetBits);
419                 default:
420                         break;
421                 }
422                 
423                 LEAVE('i', 0);
424                 return 0;
425                 
426         /*
427          * get_gateway
428          * - Get the interface's IPv4 gateway
429          */
430         case 8:
431                 switch(iface->Type)
432                 {
433                 case 0:
434                         LEAVE_RET('i', 1);
435                 case 4:
436                         if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
437                         memcpy( Data, &iface->IP4.Gateway, sizeof(tIPv4) );
438                         LEAVE_RET('i', 1);
439                 case 6:
440                         LEAVE_RET('i', 1);
441                 }
442                 LEAVE('i', 0);
443                 return 0;
444         
445         /*
446          * set_gateway
447          * - Get/Set the interface's IPv4 gateway
448          */
449         case 9:
450                 if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
451                 switch(iface->Type)
452                 {
453                 case 0:
454                         LEAVE_RET('i', 1);
455                 
456                 case 4:
457                         if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
458                         iface->Type = 0;        // One very hacky mutex/trash protector
459                         memcpy( &iface->IP4.Gateway, Data, sizeof(tIPv4) );
460                         iface->Type = 4;
461                         LEAVE_RET('i', 1);
462                         
463                 case 6:
464                         LEAVE_RET('i', 1);
465                 }
466                 break;
467         
468         /*
469          * ping
470          * - Send an ICMP Echo
471          */
472         case 10:
473                 switch(iface->Type)
474                 {
475                 case 0:
476                         LEAVE_RET('i', 1);
477                 
478                 case 4:
479                         if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
480                         tmp = IPv4_Ping(iface, *(tIPv4*)Data);
481                         LEAVE('i', tmp);
482                         return tmp;
483                         
484                 case 6:
485                         LEAVE_RET('i', 1);
486                 }
487                 break;
488         
489         }
490         
491         LEAVE('i', 0);
492         return 0;
493 }
494
495 // --- Internal ---
496 /**
497  * \fn int IPStack_AddInterface(char *Device)
498  * \brief Adds an interface to the list
499  */
500 int IPStack_AddInterface(char *Device)
501 {
502         tInterface      *iface;
503         
504         ENTER("sDevice", Device);
505         
506         iface = malloc(sizeof(tInterface));
507         if(!iface) {
508                 LEAVE('i', -2);
509                 return -2;      // Return ERR_MYBAD
510         }
511         
512         iface->Next = NULL;
513         iface->Type = 0;        // Unset type
514         
515         // Create Node
516         iface->Node.ImplPtr = iface;
517         iface->Node.ImplInt = giIP_NextIfaceId++;
518         iface->Node.Flags = VFS_FFLAG_DIRECTORY;
519         iface->Node.Size = -1;
520         iface->Node.NumACLs = 1;
521         iface->Node.ACLs = &gVFS_ACL_EveryoneRX;
522         iface->Node.ReadDir = IPStack_Iface_ReadDir;
523         iface->Node.FindDir = IPStack_Iface_FindDir;
524         iface->Node.IOCtl = IPStack_Iface_IOCtl;
525         
526         // Set Defaults
527         iface->TimeoutDelay = DEFAULT_TIMEOUT;
528         
529         // Get adapter handle
530         iface->Adapter = IPStack_GetAdapter(Device);
531         if( !iface->Adapter ) {
532                 free( iface );
533                 LEAVE('i', -1);
534                 return -1;      // Return ERR_YOUFAIL
535         }
536         
537         // Append to list
538         LOCK( &glIP_Interfaces );
539         if( gIP_Interfaces ) {
540                 gIP_Interfaces_Last->Next = iface;
541                 gIP_Interfaces_Last = iface;
542         }
543         else {
544                 gIP_Interfaces = iface;
545                 gIP_Interfaces_Last = iface;
546         }
547         RELEASE( &glIP_Interfaces );
548         
549         gIP_DriverInfo.RootNode.Size ++;
550         
551         // Success!
552         LEAVE('i', iface->Node.ImplInt);
553         return iface->Node.ImplInt;
554 }
555
556 /**
557  * \fn tAdapter *IPStack_GetAdapter(char *Path)
558  * \brief Gets/opens an adapter given the path
559  */
560 tAdapter *IPStack_GetAdapter(char *Path)
561 {
562         tAdapter        *dev;
563          int    tmp;
564         
565         ENTER("sPath", Path);
566         
567         LOCK( &glIP_Adapters );
568         
569         // Check if this adapter is already open
570         for( dev = gIP_Adapters; dev; dev = dev->Next )
571         {
572                 if( strcmp(dev->Device, Path) == 0 ) {
573                         dev->NRef ++;
574                         RELEASE( &glIP_Adapters );
575                         LEAVE('p', dev);
576                         return dev;
577                 }
578         }
579         
580         // Ok, so let's open it
581         dev = malloc( sizeof(tAdapter) + strlen(Path) + 1 );
582         if(!dev) {
583                 RELEASE( &glIP_Adapters );
584                 LEAVE('n');
585                 return NULL;
586         }
587         
588         // Fill Structure
589         strcpy( dev->Device, Path );
590         dev->NRef = 1;
591         
592         // Open Device
593         dev->DeviceFD = VFS_Open( dev->Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE );
594         if( dev->DeviceFD == -1 ) {
595                 free( dev );
596                 RELEASE( &glIP_Adapters );
597                 LEAVE('n');
598                 return NULL;
599         }
600         
601         // Check that it is a network interface
602         tmp = VFS_IOCtl(dev->DeviceFD, 0, NULL);
603         LOG("Device type = %i", tmp);
604         if( tmp != DRV_TYPE_NETWORK ) {
605                 Warning("IPStack_GetAdapter: '%s' is not a network interface", dev->Device);
606                 VFS_Close( dev->DeviceFD );
607                 free( dev );
608                 RELEASE( &glIP_Adapters );
609                 LEAVE('n');
610                 return NULL;
611         }
612         
613         // Get MAC Address
614         VFS_IOCtl(dev->DeviceFD, NET_IOCTL_GETMAC, &dev->MacAddr);
615         
616         // Add to list
617         dev->Next = gIP_Adapters;
618         gIP_Adapters = dev;
619         
620         RELEASE( &glIP_Adapters );
621         
622         // Start watcher
623         Link_WatchDevice( dev );
624         
625         LEAVE('p', dev);
626         return dev;
627 }

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