Usermode/libc - Fix strchr and strrchr behavior
[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         LOG("Creating interface '%s'", iface->Name);
283         
284         // Append to list
285         SHORTLOCK( &glIP_Interfaces );
286         if( gIP_Interfaces ) {
287                 gIP_Interfaces_Last->Next = iface;
288                 gIP_Interfaces_Last = iface;
289         }
290         else {
291                 gIP_Interfaces = iface;
292                 gIP_Interfaces_Last = iface;
293         }
294         SHORTREL( &glIP_Interfaces );
295
296         // Success!
297         LEAVE('p', iface);
298         return iface;
299 }
300
301 /**
302  * \brief Adds a file to the socket list
303  */
304 int IPStack_AddFile(tSocketFile *File)
305 {
306 //      Log_Log("IPStack", "Added file '%s'", File->Name);
307         File->Next = gIP_FileTemplates;
308         gIP_FileTemplates = File;
309         return 0;
310 }
311
312 // ---
313 // VFS Functions
314 // ---
315 /**
316  * \brief Read from an interface's directory
317  */
318 int IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
319 {
320         tSocketFile     *file = gIP_FileTemplates;
321         while(Pos-- && file) {
322                 file = file->Next;
323         }
324         
325         if(!file)
326                 return -EINVAL;
327         
328         strncpy(Dest, file->Name, FILENAME_MAX);
329         return 0;
330 }
331
332 /**
333  * \brief Gets a named node from an interface directory
334  */
335 tVFS_Node *IPStack_Iface_FindDir(tVFS_Node *Node, const char *Name, Uint Flags)
336 {
337         tSocketFile     *file = gIP_FileTemplates;
338         
339         // Get file definition
340         for(;file;file = file->Next)
341         {
342                 if( strcmp(file->Name, Name) == 0 )     break;
343         }
344         if(!file) {
345                 LOG("File '%s' unknown", Name);
346                 return NULL;
347         }
348         
349         // Pass the buck!
350         LOG("File '%s' calling %p", file->Init);
351         return file->Init(Node->ImplPtr);
352 }
353
354 /**
355  * \brief Names for interface IOCtl Calls
356  */
357 static const char *casIOCtls_Iface[] = {
358         DRV_IOCTLNAMES,
359         "getset_type",
360         "get_address", "set_address",
361         "getset_subnet",
362         "get_device",
363         "ping",
364         NULL
365         };
366 /**
367  * \brief Handles IOCtls for the IPStack interfaces
368  */
369 int IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data)
370 {
371          int    tmp, size;
372         tInterface      *iface = (tInterface*)Node->ImplPtr;
373         ENTER("pNode iID pData", Node, ID, Data);
374         
375         switch(ID)
376         {
377         // --- Standard IOCtls (0-3) ---
378         BASE_IOCTLS(DRV_TYPE_MISC, "IPStack", VERSION, casIOCtls_Iface)
379         
380         /*
381          * getset_type
382          * - Get/Set the interface type
383          */
384         case 4:
385                 // Set Type?
386                 if( Data )
387                 {
388 #if 0
389                         // Ok, it's set type
390                         if( Threads_GetUID() != 0 ) {
391                                 LOG("Attempt by non-root to alter an interface (%i)", Threads_GetUID());
392                                 LEAVE('i', -1);
393                                 return -1;
394                         }
395                         if( !CheckMem( Data, sizeof(int) ) ) {
396                                 LOG("Invalid pointer %p", Data);
397                                 LEAVE('i', -1);
398                                 return -1;
399                         }
400                         
401                         // Set type
402                         iface->Type = *(int*)Data;
403                         LOG("Interface type set to %i", iface->Type);
404                         size = IPStack_GetAddressSize(iface->Type);
405                         // Check it's actually valid
406                         if( iface->Type != 0 && size == 0 ) {
407                                 iface->Type = 0;
408                                 LEAVE('i', -1);
409                                 return -1;
410                         }
411                         
412                         // Clear address
413                         memset(iface->Address, 0, size);
414 #endif
415                         Log_Notice("IPStack", "Interface ioctl(settype) no longer usable");
416                 }
417                 LEAVE('i', iface->Type);
418                 return iface->Type;
419         
420         /*
421          * get_address
422          * - Get the interface's address
423          */
424         case 5:
425                 size = IPStack_GetAddressSize(iface->Type);
426                 if( !CheckMem( Data, size ) )   LEAVE_RET('i', -1);
427                 memcpy( Data, iface->Address, size );
428                 LEAVE('i', 1);
429                 return 1;
430         
431         /*
432          * set_address
433          * - Set the interface's address
434          */
435         case 6:
436                 if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
437                 
438                 size = IPStack_GetAddressSize(iface->Type);
439                 if( !CheckMem( Data, size ) )   LEAVE_RET('i', -1);
440                 // TODO: Protect against trashing
441                 LOG("Interface address set to '%s'", IPStack_PrintAddress(iface->Type, Data));
442                 memcpy( iface->Address, Data, size );
443                 LEAVE_RET('i', 1);
444         
445         /*
446          * getset_subnet
447          * - Get/Set the bits in the address subnet
448          */
449         case 7:
450                 // Do we want to set the value?
451                 if( Data )
452                 {
453                         // Are we root? (TODO: Check Owner/Group)
454                         if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
455                         // Is the memory valid
456                         if( !CheckMem(Data, sizeof(int)) )      LEAVE_RET('i', -1);
457                         
458                         // Is the mask sane?
459                         if( *(int*)Data < 0 || *(int*)Data > IPStack_GetAddressSize(iface->Type)*8-1 )
460                                 LEAVE_RET('i', -1);
461                         LOG("Set subnet bits to %i", *(int*)Data);
462                         // Ok, set it
463                         iface->SubnetBits = *(int*)Data;
464                 }
465                 LEAVE_RET('i', iface->SubnetBits);
466         
467         /*
468          * get_device
469          * - Gets the name of the attached device
470          */
471         case 8:
472                 if( iface->Adapter == NULL )
473                         LEAVE_RET('i', 0);
474                 char *name = Adapter_GetName(iface->Adapter);
475                  int len = strlen(name);
476                 if( Data ) {
477                         if( !CheckMem( Data, len+1 ) ) {
478                                 free(name);
479                                 LEAVE_RET('i', -1);
480                         }
481                         strcpy( Data, name );
482                 }
483                 free(name);
484                 LEAVE_RET('i', len);
485         
486         /*
487          * ping
488          * - Send an ICMP Echo
489          */
490         case 9:
491                 switch(iface->Type)
492                 {
493                 case 0:
494                         LEAVE_RET('i', 1);
495                 
496                 case 4:
497                         if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
498                         tmp = IPv4_Ping(iface, *(tIPv4*)Data);
499                         LEAVE_RET('i', tmp);
500                         
501                 case 6:
502                         LEAVE_RET('i', 1);
503                 }
504                 break;
505         
506         }
507         
508         LEAVE('i', 0);
509         return 0;
510 }
511

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