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

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