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

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