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

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