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

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