Modules/RAMDisk - a bit more work
[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
12 // === CONSTANTS ===
13 //! Default timeout value, 5 seconds
14 #define DEFAULT_TIMEOUT (5*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 extern tVFS_Node        gIP_AdaptersNode;
21
22 // === PROTOTYPES ===
23 char    *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos);
24 tVFS_Node       *IPStack_Root_FindDir(tVFS_Node *Node, const char *Name);
25  int    IPStack_Root_IOCtl(tVFS_Node *Node, int ID, void *Data);
26
27  int    IPStack_AddFile(tSocketFile *File);
28 tInterface      *IPStack_AddInterface(const char *Device, const char *Name);
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  int    giIP_NextIfaceId = 1;
57
58 tSocketFile     *gIP_FileTemplates;
59
60 // === CODE ===
61
62 /**
63  * \brief Read from the IP Stack's Device Directory
64  */
65 char *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos)
66 {
67         tInterface      *iface;
68         char    *name;
69         ENTER("pNode iPos", Node, Pos);
70         
71
72         // Routing Subdir
73         if( Pos == 0 ) {
74                 LEAVE('s', "routes");
75                 return strdup("routes");
76         }
77         // Adapters
78         if( Pos == 1 ) {
79                 LEAVE('s', "adapters");
80                 return strdup("adapters");
81         }
82         // Pseudo Interfaces
83         if( Pos == 2 ) {
84                 LEAVE('s', "lo");
85                 return strdup("lo");
86         }
87         Pos -= 3;
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                 LEAVE('p', &gIP_RouteNode);
143                 return &gIP_RouteNode;
144         }
145         
146         // Adapters subdir
147         if( strcmp(Name, "adapters") == 0 ) {
148                 LEAVE('p', &gIP_AdaptersNode);
149                 return &gIP_AdaptersNode;
150         }
151         
152         // Loopback
153         if( strcmp(Name, "lo") == 0 ) {
154                 LEAVE('p', &gIP_LoopInterface.Node);
155                 return &gIP_LoopInterface.Node;
156         }
157         
158         for( iface = gIP_Interfaces; iface; iface = iface->Next )
159         {
160                 if( strcmp(iface->Name, Name) == 0 )
161                 {
162                         LEAVE('p', &iface->Node);
163                         return &iface->Node;
164                 }
165         }
166         
167         LEAVE('p', NULL);
168         return NULL;
169 }
170
171 static const char *casIOCtls_Root[] = { DRV_IOCTLNAMES, "add_interface", NULL };
172 /**
173  * \brief Handles IOCtls for the IPStack root
174  */
175 int IPStack_Root_IOCtl(tVFS_Node *Node, int ID, void *Data)
176 {
177          int    tmp;
178         ENTER("pNode iID pData", Node, ID, Data);
179         
180         switch(ID)
181         {
182         // --- Standard IOCtls (0-3) ---
183         BASE_IOCTLS(DRV_TYPE_MISC, "IPStack", VERSION, casIOCtls_Root)
184                 
185         /*
186          * add_interface
187          * - Adds a new IP interface and binds it to a device
188          */
189         case 4:
190                 if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
191                 if( !CheckString( Data ) )      LEAVE_RET('i', -1);
192                 LOG("New interface for '%s'", Data);
193                 {
194                         char    name[4] = "";
195                         tInterface      *iface = IPStack_AddInterface(Data, name);
196                         if(iface == NULL)       LEAVE_RET('i', -1);
197                         tmp = iface->Node.ImplInt;
198                 }
199                 LEAVE_RET('i', tmp);
200         }
201         LEAVE('i', 0);
202         return 0;
203 }
204
205 /**
206  * \fn tInterface *IPStack_AddInterface(char *Device)
207  * \brief Adds an interface to the list
208  */
209 tInterface *IPStack_AddInterface(const char *Device, const char *Name)
210 {
211         tInterface      *iface;
212         tAdapter        *card;
213          int    nameLen;
214         
215         ENTER("sDevice", Device);
216         
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         nameLen = sprintf(NULL, "%i", giIP_NextIfaceId);
225         
226         iface = malloc(
227                 sizeof(tInterface)
228                 + nameLen + 1
229                 + IPStack_GetAddressSize(-1)*3  // Address, Route->Network, Route->NextHop
230                 );
231         if(!iface) {
232                 Log_Warning("IPStack", "AddInterface - malloc() failed");
233                 LEAVE('n');
234                 return NULL;    // Return ERR_MYBAD
235         }
236         
237         iface->Next = NULL;
238         iface->Type = 0;        // Unset type
239         iface->Address = iface->Name + nameLen + 1;     // Address
240         memset(&iface->Route, 0, sizeof(iface->Route));
241         iface->Route.Network = iface->Address + IPStack_GetAddressSize(-1);
242         iface->Route.NextHop = iface->Route.Network + IPStack_GetAddressSize(-1);
243         
244         // Create Node
245         iface->Node.ImplPtr = iface;
246         iface->Node.Flags = VFS_FFLAG_DIRECTORY;
247         iface->Node.Size = -1;
248         iface->Node.NumACLs = 1;
249         iface->Node.ACLs = &gVFS_ACL_EveryoneRX;
250         iface->Node.Type = &gIP_InterfaceNodeType;
251         
252         // Set Defaults
253         iface->TimeoutDelay = DEFAULT_TIMEOUT;
254         
255         // Get adapter handle
256         iface->Adapter = card;
257         
258         // Delay setting ImplInt until after the adapter is opened
259         // Keeps things simple
260         iface->Node.ImplInt = giIP_NextIfaceId++;
261         sprintf(iface->Name, "%i", (int)iface->Node.ImplInt);
262         
263         // Append to list
264         SHORTLOCK( &glIP_Interfaces );
265         if( gIP_Interfaces ) {
266                 gIP_Interfaces_Last->Next = iface;
267                 gIP_Interfaces_Last = iface;
268         }
269         else {
270                 gIP_Interfaces = iface;
271                 gIP_Interfaces_Last = iface;
272         }
273         SHORTREL( &glIP_Interfaces );
274
275 //      gIP_DriverInfo.RootNode.Size ++;
276         
277         // Success!
278         LEAVE('p', iface);
279         return iface;
280 }
281
282 /**
283  * \brief Adds a file to the socket list
284  */
285 int IPStack_AddFile(tSocketFile *File)
286 {
287         Log_Log("IPStack", "Added file '%s'", File->Name);
288         File->Next = gIP_FileTemplates;
289         gIP_FileTemplates = File;
290         return 0;
291 }
292
293 // ---
294 // VFS Functions
295 // ---
296 /**
297  * \brief Read from an interface's directory
298  */
299 char *IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos)
300 {
301         tSocketFile     *file = gIP_FileTemplates;
302         while(Pos-- && file) {
303                 file = file->Next;
304         }
305         
306         if(!file)       return NULL;
307         
308         return strdup(file->Name);
309 }
310
311 /**
312  * \brief Gets a named node from an interface directory
313  */
314 tVFS_Node *IPStack_Iface_FindDir(tVFS_Node *Node, const char *Name)
315 {
316         tSocketFile     *file = gIP_FileTemplates;
317         
318         // Get file definition
319         for(;file;file = file->Next)
320         {
321                 if( strcmp(file->Name, Name) == 0 )     break;
322         }
323         if(!file)       return NULL;
324         
325         // Pass the buck!
326         return file->Init(Node->ImplPtr);
327 }
328
329 /**
330  * \brief Names for interface IOCtl Calls
331  */
332 static const char *casIOCtls_Iface[] = {
333         DRV_IOCTLNAMES,
334         "getset_type",
335         "get_address", "set_address",
336         "getset_subnet",
337         "get_device",
338         "ping",
339         NULL
340         };
341 /**
342  * \brief Handles IOCtls for the IPStack interfaces
343  */
344 int IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data)
345 {
346          int    tmp, size;
347         tInterface      *iface = (tInterface*)Node->ImplPtr;
348         ENTER("pNode iID pData", Node, ID, Data);
349         
350         switch(ID)
351         {
352         // --- Standard IOCtls (0-3) ---
353         BASE_IOCTLS(DRV_TYPE_MISC, "IPStack", VERSION, casIOCtls_Iface)
354         
355         /*
356          * getset_type
357          * - Get/Set the interface type
358          */
359         case 4:
360                 // Set Type?
361                 if( Data )
362                 {
363                         // Ok, it's set type
364                         if( Threads_GetUID() != 0 ) {
365                                 LOG("Attempt by non-root to alter an interface (%i)", Threads_GetUID());
366                                 LEAVE('i', -1);
367                                 return -1;
368                         }
369                         if( !CheckMem( Data, sizeof(int) ) ) {
370                                 LOG("Invalid pointer %p", Data);
371                                 LEAVE('i', -1);
372                                 return -1;
373                         }
374                         
375                         // Set type
376                         iface->Type = *(int*)Data;
377                         LOG("Interface type set to %i", iface->Type);
378                         size = IPStack_GetAddressSize(iface->Type);
379                         // Check it's actually valid
380                         if( iface->Type != 0 && size == 0 ) {
381                                 iface->Type = 0;
382                                 LEAVE('i', -1);
383                                 return -1;
384                         }
385                         
386                         // Clear address
387                         memset(iface->Address, 0, size);
388                 }
389                 LEAVE('i', iface->Type);
390                 return iface->Type;
391         
392         /*
393          * get_address
394          * - Get the interface's address
395          */
396         case 5:
397                 size = IPStack_GetAddressSize(iface->Type);
398                 if( !CheckMem( Data, size ) )   LEAVE_RET('i', -1);
399                 memcpy( Data, iface->Address, size );
400                 LEAVE('i', 1);
401                 return 1;
402         
403         /*
404          * set_address
405          * - Set the interface's address
406          */
407         case 6:
408                 if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
409                 
410                 size = IPStack_GetAddressSize(iface->Type);
411                 if( !CheckMem( Data, size ) )   LEAVE_RET('i', -1);
412                 // TODO: Protect against trashing
413                 LOG("Interface address set to '%s'", IPStack_PrintAddress(iface->Type, Data));
414                 memcpy( iface->Address, Data, size );
415                 LEAVE_RET('i', 1);
416         
417         /*
418          * getset_subnet
419          * - Get/Set the bits in the address subnet
420          */
421         case 7:
422                 // Do we want to set the value?
423                 if( Data )
424                 {
425                         // Are we root? (TODO: Check Owner/Group)
426                         if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
427                         // Is the memory valid
428                         if( !CheckMem(Data, sizeof(int)) )      LEAVE_RET('i', -1);
429                         
430                         // Is the mask sane?
431                         if( *(int*)Data < 0 || *(int*)Data > IPStack_GetAddressSize(iface->Type)*8-1 )
432                                 LEAVE_RET('i', -1);
433                         LOG("Set subnet bits to %i", *(int*)Data);
434                         // Ok, set it
435                         iface->SubnetBits = *(int*)Data;
436                 }
437                 LEAVE_RET('i', iface->SubnetBits);
438         
439         /*
440          * get_device
441          * - Gets the name of the attached device
442          */
443         case 8:
444                 if( iface->Adapter == NULL )
445                         LEAVE_RET('i', 0);
446                 char *name = Adapter_GetName(iface->Adapter);
447                  int len = strlen(name);
448                 if( Data ) {
449                         if( !CheckMem( Data, len+1 ) ) {
450                                 free(name);
451                                 LEAVE_RET('i', -1);
452                         }
453                         strcpy( Data, name );
454                 }
455                 free(name);
456                 LEAVE_RET('i', len);
457         
458         /*
459          * ping
460          * - Send an ICMP Echo
461          */
462         case 9:
463                 switch(iface->Type)
464                 {
465                 case 0:
466                         LEAVE_RET('i', 1);
467                 
468                 case 4:
469                         if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
470                         tmp = IPv4_Ping(iface, *(tIPv4*)Data);
471                         LEAVE_RET('i', tmp);
472                         
473                 case 6:
474                         LEAVE_RET('i', 1);
475                 }
476                 break;
477         
478         }
479         
480         LEAVE('i', 0);
481         return 0;
482 }
483

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