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

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