5bfcda77f90cc730987ddc2597a3659de73cbd9f
[tpg/acess2.git] / Modules / IPStack / interface.c
1 /*
2  * Acess2 IP Stack
3  * - Interface Control
4  */
5 #define DEBUG   0
6 #define VERSION VER2(0,10)
7 #include "ipstack.h"
8 #include "link.h"
9 #include <api_drv_common.h>
10 #include <api_drv_network.h>
11
12 // === CONSTANTS ===
13 //! Default timeout value, 30 seconds
14 #define DEFAULT_TIMEOUT (30*1000)
15
16 // === IMPORTS ===
17 extern int      IPv4_Ping(tInterface *Iface, tIPv4 Addr);
18 //extern int    IPv6_Ping(tInterface *Iface, tIPv6 Addr);
19 extern tVFS_Node        gIP_RouteNode;
20
21 // === PROTOTYPES ===
22 char    *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos);
23 tVFS_Node       *IPStack_Root_FindDir(tVFS_Node *Node, const char *Name);
24  int    IPStack_Root_IOCtl(tVFS_Node *Node, int ID, void *Data);
25
26  int    IPStack_AddFile(tSocketFile *File);
27 tInterface      *IPStack_AddInterface(const char *Device, const char *Name);
28 tAdapter        *IPStack_GetAdapter(const char *Path);
29
30 char    *IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos);
31 tVFS_Node       *IPStack_Iface_FindDir(tVFS_Node *Node, const char *Name);
32  int    IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data);
33
34 // === GLOBALS ===
35 tVFS_NodeType   gIP_InterfaceNodeType = {
36                 .ReadDir = IPStack_Iface_ReadDir,
37                 .FindDir = IPStack_Iface_FindDir,
38                 .IOCtl = IPStack_Iface_IOCtl
39 };
40 //! Loopback (127.0.0.0/8, ::1) Pseudo-Interface
41 tInterface      gIP_LoopInterface = {
42         .Node = {
43                 .ImplPtr = &gIP_LoopInterface,
44                 .Flags = VFS_FFLAG_DIRECTORY,
45                 .Size = -1,
46                 .NumACLs = 1,
47                 .ACLs = &gVFS_ACL_EveryoneRX,
48                 .Type = &gIP_InterfaceNodeType
49         },
50         .Adapter = NULL,
51         .Type = 0
52 };
53 tShortSpinlock  glIP_Interfaces;
54 tInterface      *gIP_Interfaces = NULL;
55 tInterface      *gIP_Interfaces_Last = NULL;
56
57 tSocketFile     *gIP_FileTemplates;
58
59 tAdapter        gIP_LoopAdapter = {
60         .DeviceLen = 8,
61         .Device = "LOOPBACK"
62         };
63 tMutex  glIP_Adapters;
64 tAdapter        *gIP_Adapters = NULL;
65  int    giIP_NextIfaceId = 1;
66
67 // === CODE ===
68
69 /**
70  * \brief Read from the IP Stack's Device Directory
71  */
72 char *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos)
73 {
74         tInterface      *iface;
75         char    *name;
76         ENTER("pNode iPos", Node, Pos);
77         
78
79         // Routing Subdir
80         if( Pos == 0 ) {
81                 return strdup("routes");
82         }
83         // Pseudo Interfaces
84         if( Pos == 1 ) {
85                 return strdup("lo");
86         }
87         Pos -= 2;
88         
89         // Traverse the list
90         for( iface = gIP_Interfaces; iface && Pos--; iface = iface->Next ) ;
91         
92         // Did we run off the end?
93         if(!iface) {
94                 LEAVE('n');
95                 return NULL;
96         }
97         
98         name = malloc(4);
99         if(!name) {
100                 Log_Warning("IPStack", "IPStack_Root_ReadDir - malloc error");
101                 LEAVE('n');
102                 return NULL;
103         }
104         
105         // Create the name
106         Pos = iface->Node.ImplInt;
107         if(Pos < 10) {
108                 name[0] = '0' + Pos;
109                 name[1] = '\0';
110         }
111         else if(Pos < 100) {
112                 name[0] = '0' + Pos/10;
113                 name[1] = '0' + Pos%10;
114                 name[2] = '\0';
115         }
116         else {
117                 name[0] = '0' + Pos/100;
118                 name[1] = '0' + (Pos/10)%10;
119                 name[2] = '0' + Pos%10;
120                 name[3] = '\0';
121         }
122         
123         LEAVE('s', name);
124         // Return the pre-generated name
125         return name;
126 }
127
128 /**
129  * \brief Get the node of an interface
130  */
131 tVFS_Node *IPStack_Root_FindDir(tVFS_Node *Node, const char *Name)
132 {
133         #if 0
134          int    i, num;
135         #endif
136         tInterface      *iface;
137         
138         ENTER("pNode sName", Node, Name);
139         
140         // Routing subdir
141         if( strcmp(Name, "routes") == 0 ) {
142                 return &gIP_RouteNode;
143         }
144         
145         // Loopback
146         if( strcmp(Name, "lo") == 0 ) {
147                 return &gIP_LoopInterface.Node;
148         }
149         
150         for( iface = gIP_Interfaces; iface; iface = iface->Next )
151         {
152                 if( strcmp(iface->Name, Name) == 0 )
153                 {
154                         LEAVE('p', &iface->Node);
155                         return &iface->Node;
156                 }
157         }
158         
159         LEAVE('p', NULL);
160         return NULL;
161 }
162
163 static const char *casIOCtls_Root[] = { DRV_IOCTLNAMES, "add_interface", NULL };
164 /**
165  * \brief Handles IOCtls for the IPStack root
166  */
167 int IPStack_Root_IOCtl(tVFS_Node *Node, int ID, void *Data)
168 {
169          int    tmp;
170         ENTER("pNode iID pData", Node, ID, Data);
171         
172         switch(ID)
173         {
174         // --- Standard IOCtls (0-3) ---
175         BASE_IOCTLS(DRV_TYPE_MISC, "IPStack", VERSION, casIOCtls_Root)
176                 
177         /*
178          * add_interface
179          * - Adds a new IP interface and binds it to a device
180          */
181         case 4:
182                 if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
183                 if( !CheckString( Data ) )      LEAVE_RET('i', -1);
184                 {
185                         char    name[4] = "";
186                         tInterface      *iface = IPStack_AddInterface(Data, name);
187                         if(iface == NULL)       LEAVE_RET('i', -1);
188                         tmp = iface->Node.ImplInt;
189                 }
190                 LEAVE_RET('i', tmp);
191         }
192         LEAVE('i', 0);
193         return 0;
194 }
195
196 /**
197  * \fn tInterface *IPStack_AddInterface(char *Device)
198  * \brief Adds an interface to the list
199  */
200 tInterface *IPStack_AddInterface(const char *Device, const char *Name)
201 {
202         tInterface      *iface;
203         tAdapter        *card;
204          int    nameLen;
205         
206         ENTER("sDevice", Device);
207         
208         card = IPStack_GetAdapter(Device);
209         if( !card ) {
210                 Log_Debug("IPStack", "Unable to open card '%s'", Device);
211                 LEAVE('n');
212                 return NULL;    // ERR_YOURBAD
213         }
214         
215         nameLen = sprintf(NULL, "%i", giIP_NextIfaceId);
216         
217         iface = malloc(
218                 sizeof(tInterface)
219                 + nameLen + 1
220                 + IPStack_GetAddressSize(-1)*3  // Address, Route->Network, Route->NextHop
221                 );
222         if(!iface) {
223                 Log_Warning("IPStack", "AddInterface - malloc() failed");
224                 LEAVE('n');
225                 return NULL;    // Return ERR_MYBAD
226         }
227         
228         iface->Next = NULL;
229         iface->Type = 0;        // Unset type
230         iface->Address = iface->Name + nameLen + 1;     // Address
231         iface->Route.Network = iface->Address + IPStack_GetAddressSize(-1);
232         iface->Route.NextHop = iface->Route.Network + IPStack_GetAddressSize(-1);
233         
234         // Create Node
235         iface->Node.ImplPtr = iface;
236         iface->Node.Flags = VFS_FFLAG_DIRECTORY;
237         iface->Node.Size = -1;
238         iface->Node.NumACLs = 1;
239         iface->Node.ACLs = &gVFS_ACL_EveryoneRX;
240         iface->Node.Type = &gIP_InterfaceNodeType;
241         
242         // Set Defaults
243         iface->TimeoutDelay = DEFAULT_TIMEOUT;
244         
245         // Get adapter handle
246         iface->Adapter = card;
247         
248         // Delay setting ImplInt until after the adapter is opened
249         // Keeps things simple
250         iface->Node.ImplInt = giIP_NextIfaceId++;
251         sprintf(iface->Name, "%i", (int)iface->Node.ImplInt);
252         
253         // Append to list
254         SHORTLOCK( &glIP_Interfaces );
255         if( gIP_Interfaces ) {
256                 gIP_Interfaces_Last->Next = iface;
257                 gIP_Interfaces_Last = iface;
258         }
259         else {
260                 gIP_Interfaces = iface;
261                 gIP_Interfaces_Last = iface;
262         }
263         SHORTREL( &glIP_Interfaces );
264
265 //      gIP_DriverInfo.RootNode.Size ++;
266         
267         // Success!
268         LEAVE('p', iface);
269         return iface;
270 }
271
272 /**
273  * \brief Adds a file to the socket list
274  */
275 int IPStack_AddFile(tSocketFile *File)
276 {
277         Log_Log("IPStack", "Added file '%s'", File->Name);
278         File->Next = gIP_FileTemplates;
279         gIP_FileTemplates = File;
280         return 0;
281 }
282
283 // ---
284 // VFS Functions
285 // ---
286 /**
287  * \brief Read from an interface's directory
288  */
289 char *IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos)
290 {
291         tSocketFile     *file = gIP_FileTemplates;
292         while(Pos-- && file) {
293                 file = file->Next;
294         }
295         
296         if(!file)       return NULL;
297         
298         return strdup(file->Name);
299 }
300
301 /**
302  * \brief Gets a named node from an interface directory
303  */
304 tVFS_Node *IPStack_Iface_FindDir(tVFS_Node *Node, const char *Name)
305 {
306         tSocketFile     *file = gIP_FileTemplates;
307         
308         // Get file definition
309         for(;file;file = file->Next)
310         {
311                 if( strcmp(file->Name, Name) == 0 )     break;
312         }
313         if(!file)       return NULL;
314         
315         // Pass the buck!
316         return file->Init(Node->ImplPtr);
317 }
318
319 /**
320  * \brief Names for interface IOCtl Calls
321  */
322 static const char *casIOCtls_Iface[] = {
323         DRV_IOCTLNAMES,
324         "getset_type",
325         "get_address", "set_address",
326         "getset_subnet",
327         "get_device",
328         "ping",
329         NULL
330         };
331 /**
332  * \brief Handles IOCtls for the IPStack interfaces
333  */
334 int IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data)
335 {
336          int    tmp, size;
337         tInterface      *iface = (tInterface*)Node->ImplPtr;
338         ENTER("pNode iID pData", Node, ID, Data);
339         
340         switch(ID)
341         {
342         // --- Standard IOCtls (0-3) ---
343         BASE_IOCTLS(DRV_TYPE_MISC, "IPStack", VERSION, casIOCtls_Iface)
344         
345         /*
346          * getset_type
347          * - Get/Set the interface type
348          */
349         case 4:
350                 // Set Type?
351                 if( Data )
352                 {
353                         // Ok, it's set type
354                         if( Threads_GetUID() != 0 ) {
355                                 LOG("Attempt by non-root to alter an interface (%i)", Threads_GetUID());
356                                 LEAVE('i', -1);
357                                 return -1;
358                         }
359                         if( !CheckMem( Data, sizeof(int) ) ) {
360                                 LOG("Invalid pointer %p", Data);
361                                 LEAVE('i', -1);
362                                 return -1;
363                         }
364                         
365                         // Set type
366                         iface->Type = *(int*)Data;
367                         size = IPStack_GetAddressSize(iface->Type);
368                         // Check it's actually valid
369                         if( iface->Type != 0 && size == 0 ) {
370                                 iface->Type = 0;
371                                 LEAVE('i', -1);
372                                 return -1;
373                         }
374                         
375                         // Clear address
376                         memset(iface->Address, 0, size);
377                 }
378                 LEAVE('i', iface->Type);
379                 return iface->Type;
380         
381         /*
382          * get_address
383          * - Get the interface's address
384          */
385         case 5:
386                 size = IPStack_GetAddressSize(iface->Type);
387                 if( !CheckMem( Data, size ) )   LEAVE_RET('i', -1);
388                 memcpy( Data, iface->Address, size );
389                 LEAVE('i', 1);
390                 return 1;
391         
392         /*
393          * set_address
394          * - Set the interface's address
395          */
396         case 6:
397                 if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
398                 
399                 size = IPStack_GetAddressSize(iface->Type);
400                 if( !CheckMem( Data, size ) )   LEAVE_RET('i', -1);
401                 // TODO: Protect against trashing
402                 memcpy( iface->Address, Data, size );
403                 LEAVE('i', 1);
404                 return 1;
405         
406         /*
407          * getset_subnet
408          * - Get/Set the bits in the address subnet
409          */
410         case 7:
411                 // Do we want to set the value?
412                 if( Data )
413                 {
414                         // Are we root? (TODO: Check Owner/Group)
415                         if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
416                         // Is the memory valid
417                         if( !CheckMem(Data, sizeof(int)) )      LEAVE_RET('i', -1);
418                         
419                         // Is the mask sane?
420                         if( *(int*)Data < 0 || *(int*)Data > IPStack_GetAddressSize(iface->Type)*8-1 )
421                                 LEAVE_RET('i', -1);
422                         
423                         // Ok, set it
424                         iface->SubnetBits = *(int*)Data;
425                 }
426                 LEAVE('i', iface->SubnetBits);
427                 return iface->SubnetBits;
428         
429         /*
430          * get_device
431          * - Gets the name of the attached device
432          */
433         case 8:
434                 if( iface->Adapter == NULL )
435                         LEAVE_RET('i', 0);
436                 if( Data == NULL )
437                         LEAVE_RET('i', iface->Adapter->DeviceLen);
438                 if( !CheckMem( Data, iface->Adapter->DeviceLen+1 ) )
439                         LEAVE_RET('i', -1);
440                 strcpy( Data, iface->Adapter->Device );
441                 return iface->Adapter->DeviceLen;
442         
443         /*
444          * ping
445          * - Send an ICMP Echo
446          */
447         case 9:
448                 switch(iface->Type)
449                 {
450                 case 0:
451                         LEAVE_RET('i', 1);
452                 
453                 case 4:
454                         if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
455                         tmp = IPv4_Ping(iface, *(tIPv4*)Data);
456                         LEAVE('i', tmp);
457                         return tmp;
458                         
459                 case 6:
460                         LEAVE_RET('i', 1);
461                 }
462                 break;
463         
464         }
465         
466         LEAVE('i', 0);
467         return 0;
468 }
469
470 // --- Internal ---
471 /**
472  * \fn tAdapter *IPStack_GetAdapter(const char *Path)
473  * \brief Gets/opens an adapter given the path
474  */
475 tAdapter *IPStack_GetAdapter(const char *Path)
476 {
477         tAdapter        *dev;
478          int    tmp;
479         
480         ENTER("sPath", Path);
481         
482         // Check for loopback
483         if( strcmp(Path, "LOOPBACK") == 0 )
484         {
485                 // Initialise if required
486                 if( gIP_LoopAdapter.DeviceFD == 0 )
487                 {
488                         dev = &gIP_LoopAdapter;
489                         
490                         dev->NRef = 1;
491                         dev->DeviceLen = 8;
492                         
493                         dev->DeviceFD = VFS_Open( "/Devices/fifo/anon", VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE );
494                         if( dev->DeviceFD == -1 ) {
495                                 Log_Warning("IPStack", "Unable to open FIFO '/Devices/fifo/anon' for loopback");
496                                 return NULL;
497                         }
498                         
499                         dev->MacAddr.B[0] = 'A';
500                         dev->MacAddr.B[1] = 'c';
501                         dev->MacAddr.B[2] = 'e';
502                         dev->MacAddr.B[3] = 's';
503                         dev->MacAddr.B[4] = 's';
504                         dev->MacAddr.B[5] = '2';
505                         
506                         // Start watcher
507                         Link_WatchDevice( dev );
508                 }
509                 LEAVE('p', &gIP_LoopAdapter);
510                 return &gIP_LoopAdapter;
511         }
512         
513         Mutex_Acquire( &glIP_Adapters );
514         
515         // Check if this adapter is already open
516         for( dev = gIP_Adapters; dev; dev = dev->Next )
517         {
518                 if( strcmp(dev->Device, Path) == 0 ) {
519                         dev->NRef ++;
520                         Mutex_Release( &glIP_Adapters );
521                         LEAVE('p', dev);
522                         return dev;
523                 }
524         }
525         
526         // Ok, so let's open it
527         dev = malloc( sizeof(tAdapter) + strlen(Path) + 1 );
528         if(!dev) {
529                 Log_Warning("IPStack", "GetAdapter - malloc() failed");
530                 Mutex_Release( &glIP_Adapters );
531                 LEAVE('n');
532                 return NULL;
533         }
534         
535         // Fill Structure
536         strcpy( dev->Device, Path );
537         dev->NRef = 1;
538         dev->DeviceLen = strlen(Path);
539         
540         // Open Device
541         dev->DeviceFD = VFS_Open( dev->Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE );
542         if( dev->DeviceFD == -1 ) {
543                 free( dev );
544                 Mutex_Release( &glIP_Adapters );
545                 LEAVE('n');
546                 return NULL;
547         }
548         
549         // Check that it is a network interface
550         tmp = VFS_IOCtl(dev->DeviceFD, 0, NULL);
551         LOG("Device type = %i", tmp);
552         if( tmp != DRV_TYPE_NETWORK ) {
553                 Log_Warning("IPStack", "IPStack_GetAdapter: '%s' is not a network interface", dev->Device);
554                 VFS_Close( dev->DeviceFD );
555                 free( dev );
556                 Mutex_Release( &glIP_Adapters );
557                 LEAVE('n');
558                 return NULL;
559         }
560         
561         // Get MAC Address
562         VFS_IOCtl(dev->DeviceFD, NET_IOCTL_GETMAC, &dev->MacAddr);
563         
564         // Add to list
565         dev->Next = gIP_Adapters;
566         gIP_Adapters = dev;
567         
568         Mutex_Release( &glIP_Adapters );
569         
570         // Start watcher
571         Link_WatchDevice( dev );
572         
573         LEAVE('p', dev);
574         return dev;
575 }

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