IPStack - Reworking of network device API
[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, 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 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         iface->Route.Network = iface->Address + IPStack_GetAddressSize(-1);
241         iface->Route.NextHop = iface->Route.Network + IPStack_GetAddressSize(-1);
242         
243         // Create Node
244         iface->Node.ImplPtr = iface;
245         iface->Node.Flags = VFS_FFLAG_DIRECTORY;
246         iface->Node.Size = -1;
247         iface->Node.NumACLs = 1;
248         iface->Node.ACLs = &gVFS_ACL_EveryoneRX;
249         iface->Node.Type = &gIP_InterfaceNodeType;
250         
251         // Set Defaults
252         iface->TimeoutDelay = DEFAULT_TIMEOUT;
253         
254         // Get adapter handle
255         iface->Adapter = card;
256         
257         // Delay setting ImplInt until after the adapter is opened
258         // Keeps things simple
259         iface->Node.ImplInt = giIP_NextIfaceId++;
260         sprintf(iface->Name, "%i", (int)iface->Node.ImplInt);
261         
262         // Append to list
263         SHORTLOCK( &glIP_Interfaces );
264         if( gIP_Interfaces ) {
265                 gIP_Interfaces_Last->Next = iface;
266                 gIP_Interfaces_Last = iface;
267         }
268         else {
269                 gIP_Interfaces = iface;
270                 gIP_Interfaces_Last = iface;
271         }
272         SHORTREL( &glIP_Interfaces );
273
274 //      gIP_DriverInfo.RootNode.Size ++;
275         
276         // Success!
277         LEAVE('p', iface);
278         return iface;
279 }
280
281 /**
282  * \brief Adds a file to the socket list
283  */
284 int IPStack_AddFile(tSocketFile *File)
285 {
286         Log_Log("IPStack", "Added file '%s'", File->Name);
287         File->Next = gIP_FileTemplates;
288         gIP_FileTemplates = File;
289         return 0;
290 }
291
292 // ---
293 // VFS Functions
294 // ---
295 /**
296  * \brief Read from an interface's directory
297  */
298 char *IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos)
299 {
300         tSocketFile     *file = gIP_FileTemplates;
301         while(Pos-- && file) {
302                 file = file->Next;
303         }
304         
305         if(!file)       return NULL;
306         
307         return strdup(file->Name);
308 }
309
310 /**
311  * \brief Gets a named node from an interface directory
312  */
313 tVFS_Node *IPStack_Iface_FindDir(tVFS_Node *Node, const char *Name)
314 {
315         tSocketFile     *file = gIP_FileTemplates;
316         
317         // Get file definition
318         for(;file;file = file->Next)
319         {
320                 if( strcmp(file->Name, Name) == 0 )     break;
321         }
322         if(!file)       return NULL;
323         
324         // Pass the buck!
325         return file->Init(Node->ImplPtr);
326 }
327
328 /**
329  * \brief Names for interface IOCtl Calls
330  */
331 static const char *casIOCtls_Iface[] = {
332         DRV_IOCTLNAMES,
333         "getset_type",
334         "get_address", "set_address",
335         "getset_subnet",
336         "get_device",
337         "ping",
338         NULL
339         };
340 /**
341  * \brief Handles IOCtls for the IPStack interfaces
342  */
343 int IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data)
344 {
345          int    tmp, size;
346         tInterface      *iface = (tInterface*)Node->ImplPtr;
347         ENTER("pNode iID pData", Node, ID, Data);
348         
349         switch(ID)
350         {
351         // --- Standard IOCtls (0-3) ---
352         BASE_IOCTLS(DRV_TYPE_MISC, "IPStack", VERSION, casIOCtls_Iface)
353         
354         /*
355          * getset_type
356          * - Get/Set the interface type
357          */
358         case 4:
359                 // Set Type?
360                 if( Data )
361                 {
362                         // Ok, it's set type
363                         if( Threads_GetUID() != 0 ) {
364                                 LOG("Attempt by non-root to alter an interface (%i)", Threads_GetUID());
365                                 LEAVE('i', -1);
366                                 return -1;
367                         }
368                         if( !CheckMem( Data, sizeof(int) ) ) {
369                                 LOG("Invalid pointer %p", Data);
370                                 LEAVE('i', -1);
371                                 return -1;
372                         }
373                         
374                         // Set type
375                         iface->Type = *(int*)Data;
376                         LOG("Interface type set to %i", iface->Type);
377                         size = IPStack_GetAddressSize(iface->Type);
378                         // Check it's actually valid
379                         if( iface->Type != 0 && size == 0 ) {
380                                 iface->Type = 0;
381                                 LEAVE('i', -1);
382                                 return -1;
383                         }
384                         
385                         // Clear address
386                         memset(iface->Address, 0, size);
387                 }
388                 LEAVE('i', iface->Type);
389                 return iface->Type;
390         
391         /*
392          * get_address
393          * - Get the interface's address
394          */
395         case 5:
396                 size = IPStack_GetAddressSize(iface->Type);
397                 if( !CheckMem( Data, size ) )   LEAVE_RET('i', -1);
398                 memcpy( Data, iface->Address, size );
399                 LEAVE('i', 1);
400                 return 1;
401         
402         /*
403          * set_address
404          * - Set the interface's address
405          */
406         case 6:
407                 if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
408                 
409                 size = IPStack_GetAddressSize(iface->Type);
410                 if( !CheckMem( Data, size ) )   LEAVE_RET('i', -1);
411                 // TODO: Protect against trashing
412                 LOG("Interface address set to '%s'", IPStack_PrintAddress(iface->Type, Data));
413                 memcpy( iface->Address, Data, size );
414                 LEAVE_RET('i', 1);
415         
416         /*
417          * getset_subnet
418          * - Get/Set the bits in the address subnet
419          */
420         case 7:
421                 // Do we want to set the value?
422                 if( Data )
423                 {
424                         // Are we root? (TODO: Check Owner/Group)
425                         if( Threads_GetUID() != 0 )     LEAVE_RET('i', -1);
426                         // Is the memory valid
427                         if( !CheckMem(Data, sizeof(int)) )      LEAVE_RET('i', -1);
428                         
429                         // Is the mask sane?
430                         if( *(int*)Data < 0 || *(int*)Data > IPStack_GetAddressSize(iface->Type)*8-1 )
431                                 LEAVE_RET('i', -1);
432                         LOG("Set subnet bits to %i", *(int*)Data);
433                         // Ok, set it
434                         iface->SubnetBits = *(int*)Data;
435                 }
436                 LEAVE_RET('i', iface->SubnetBits);
437         
438         /*
439          * get_device
440          * - Gets the name of the attached device
441          */
442         case 8:
443                 Log_Error("IPStack", "TODO: Reimplement interface.ioctl(get_device)");
444 //              if( iface->Adapter == NULL )
445                         LEAVE_RET('i', 0);
446 //              if( Data == NULL )
447 //                      LEAVE_RET('i', iface->Adapter->DeviceLen);
448 //              if( !CheckMem( Data, iface->Adapter->DeviceLen+1 ) )
449 //                      LEAVE_RET('i', -1);
450 //              strcpy( Data, iface->Adapter->Device );
451 //              LEAVE_RET('i', iface->Adapter->DeviceLen);
452         
453         /*
454          * ping
455          * - Send an ICMP Echo
456          */
457         case 9:
458                 switch(iface->Type)
459                 {
460                 case 0:
461                         LEAVE_RET('i', 1);
462                 
463                 case 4:
464                         if( !CheckMem( Data, sizeof(tIPv4) ) )  LEAVE_RET('i', -1);
465                         tmp = IPv4_Ping(iface, *(tIPv4*)Data);
466                         LEAVE_RET('i', tmp);
467                         
468                 case 6:
469                         LEAVE_RET('i', 1);
470                 }
471                 break;
472         
473         }
474         
475         LEAVE('i', 0);
476         return 0;
477 }
478

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