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

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