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

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