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

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