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

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