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

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