IPStack - Reworking of network device API
[tpg/acess2.git] / KernelLand / Modules / IPStack / adapters.c
1 /*
2  * Acess2 Networking Stack
3  * - By John Hodge (thePowersGang)
4  *
5  * adapters.c
6  * - Network Adapter Management
7  */
8 #define DEBUG   0
9 #define VERSION VER2(0,1)
10 #include "ipstack.h"
11 #include "include/buffer.h"
12 #include "include/adapters.h"
13 #include "include/adapters_int.h"
14 #include "link.h"
15 #include <api_drv_common.h>     // For the VFS hack
16 #include <api_drv_network.h>
17
18 // === PROTOTYPES ===
19 // --- "External" (NIC) API ---
20 void    *IPStack_Adapter_Add(const tIPStack_AdapterType *Type, void *Ptr, const void *HWAddr);
21 void    IPStack_Adapter_Del(void *Handle);
22 // --- VFS API ---
23 char    *Adapter_ReadDir(tVFS_Node *Node, int Pos);
24 tVFS_Node       *Adapter_FindDir(tVFS_Node *Node, const char *Name);
25  int    Adapter_DirIOCtl(tVFS_Node *Node, int Num, void *Data);
26  int    Adapter_IOCtl(tVFS_Node *Node, int Num, void *Data);
27 // --- "Internal" (IPStack) API ---
28 tAdapter        *Adapter_GetByName(const char *Name);
29 void    Adapter_SendPacket(tAdapter *Handle, tIPStackBuffer *Buffer);
30 // --- Helpers ---
31 void    Adapter_int_WatchThread(void *Ptr);
32 tIPStackBuffer  *Adapter_int_LoopbackWaitPacket(void *Unused);
33  int    Adapter_int_LoopbackSendPacket(void *Unused, tIPStackBuffer *Buffer);
34
35 // === GLOBALS ===
36 // --- VFS Magic ---
37 tVFS_NodeType   gIP_AdaptersDirType = {
38         .ReadDir = Adapter_ReadDir,
39         .FindDir = Adapter_FindDir,
40         .IOCtl = Adapter_DirIOCtl
41 };
42 tVFS_NodeType   gIP_AdapterType = {
43         // TODO: Should direct IO be allowed?
44         .IOCtl = Adapter_IOCtl
45 };
46 tVFS_Node       gIP_AdaptersNode = {
47         .Type = &gIP_AdaptersDirType,
48         .Flags = VFS_FFLAG_DIRECTORY,
49         .Size = -1
50 };
51 // --- Loopback Adapter ---
52 tIPStack_AdapterType    gIP_LoopAdapterType = {
53         .Name = "Loopback",
54         .WaitForPacket = Adapter_int_LoopbackWaitPacket,
55         .SendPacket = Adapter_int_LoopbackSendPacket
56         };
57 tAdapter        gIP_LoopAdapter;
58 // --- Main adapter list ---
59 tMutex  glIP_Adapters;
60 tAdapter        *gpIP_AdapterList;
61 tAdapter        *gpIP_AdapterList_Last = (void*)&gpIP_AdapterList;      // HACK!
62  int    giIP_NextAdapterIndex;
63
64 // === CODE ===
65 // --- "External" (NIC) API ---
66 void *IPStack_Adapter_Add(const tIPStack_AdapterType *Type, void *Ptr, const void *HWAddr)
67 {
68         tAdapter        *ret;
69         
70         ret = malloc(sizeof(tAdapter) + 6);     // TODO: Don't assume 6-byte MAC addresses
71         ret->Next = NULL;
72         ret->Type = Type;
73         ret->CardHandle = Ptr;
74         ret->RefCount = 0;
75         ret->Index = giIP_NextAdapterIndex++;
76         memcpy(ret->HWAddr, HWAddr, 6);
77
78         memset(&ret->Node, 0, sizeof(ret->Node));
79         ret->Node.Type = &gIP_AdapterType;
80         ret->Node.ImplPtr = ret;
81
82         // TODO: Locking
83         gpIP_AdapterList_Last->Next = ret;
84         gpIP_AdapterList_Last = ret;
85         
86         // Watch the adapter for incoming packets
87         tTID tid = Proc_SpawnWorker(Adapter_int_WatchThread, ret);
88         if(tid < 0) {
89                 Log_Warning("IPStack", "Unable to create watcher thread for %p", ret);
90         }
91         
92         return ret;
93 }
94
95 void *IPStack_Adapter_AddVFS(const char *Path)
96 {
97          int    fd, tmp;
98         char    mac[6];
99
100         ENTER("sPath", Path);   
101
102         // Open Device
103         fd = VFS_Open( Path, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE );
104         if( fd == -1 ) {
105                 LEAVE('n');
106                 return NULL;
107         }
108         
109         // Check that it is a network interface
110         tmp = VFS_IOCtl(fd, 0, NULL);
111         LOG("Device type = %i", tmp);
112         if( tmp != DRV_TYPE_NETWORK ) {
113                 Log_Warning("IPStack", "IPStack_Adapter_AddVFS: '%s' is not a network interface", Path);
114                 VFS_Close( fd );
115                 LEAVE('n');
116                 return NULL;
117         }
118         
119         // Get MAC Address
120         VFS_IOCtl(fd, NET_IOCTL_GETMAC, mac);
121
122         return IPStack_Adapter_Add(NULL, (void*)fd, mac);
123 }
124
125 void IPStack_Adapter_Del(void *Handle)
126 {
127         Log_Error("IPStack", "TODO: Implement IPStack_Adapter_Del");
128         // TODO: Allow removing adapters during system operation
129 }
130
131 // --- VFS API ---
132 char *Adapter_ReadDir(tVFS_Node *Node, int Pos)
133 {
134         if( Pos < 0 )   return NULL;
135
136         // Loopback
137         if( Pos == 0 ) {
138                 return strdup("lo");
139         }
140         Pos --;
141         
142         #define CHECK_LIST(list, type) do{ \
143                 tAdapter *a;  int i;\
144                 for(i=0,a=list; i < Pos && a; i ++, a = a->Next ); \
145                 if( a ) { \
146                         char    buf[sizeof(type)+10]; \
147                         sprintf(buf, type"%i", a->Index); \
148                         return strdup(buf); \
149                 } \
150                 Pos -= i; \
151         } while(0);
152
153         CHECK_LIST(gpIP_AdapterList, "eth");
154         // TODO: Support other types of adapters (wifi, tap, ...)
155
156         return NULL;
157 }
158
159 tVFS_Node *Adapter_FindDir(tVFS_Node *Node, const char *Name)
160 {
161         tAdapter *a = Adapter_GetByName(Name);
162         if(!a)
163                 return NULL;
164         else
165                 return &a->Node;
166 }
167
168 static const char *casIOCtls_Root[] = { DRV_IOCTLNAMES, "add_vfs_adapter", NULL };
169 int Adapter_DirIOCtl(tVFS_Node *Node, int Num, void *Data)
170 {
171         switch(Num)
172         {
173         BASE_IOCTLS(DRV_TYPE_MISC, "IPStack-AdapterList", VERSION, casIOCtls_Root)
174         
175         case 4:
176                 if( !CheckString(Data) )
177                         return -1;
178
179                 // Return non-zero if add fails
180                 return IPStack_Adapter_AddVFS(Data) == NULL;
181         }
182         return -1;
183 }
184
185 static const char *casIOCtls_Dev[] = { DRV_IOCTLNAMES, "get_hwaddr", NULL };
186 int Adapter_IOCtl(tVFS_Node *Node, int Num, void *Data)
187 {
188         tAdapter *adapter = Node->ImplPtr;
189         switch(Num)
190         {
191         BASE_IOCTLS(DRV_TYPE_MISC, "IPStack-Adapter", VERSION, casIOCtls_Dev)
192         
193         case 4:
194                 if( !CheckMem(Data, 6) )
195                         return -1;
196
197                 memcpy(Data, adapter->HWAddr, 6);
198                 return 0;
199         }
200         return -1;
201 }
202
203 // --- "Internal" (IPStack) API ---
204 tAdapter *Adapter_GetByName(const char *Name)
205 {
206         if( strcmp(Name, "lo") == 0 ) {
207                 return &gIP_LoopAdapter;
208         }
209         
210         if( strncmp(Name, "eth", 3) == 0 )
211         {
212                 // Possibly an ethX interface
213                  int    index, ofs;
214                 
215                 // Get the index at the end
216                 ofs = ParseInt(Name + 3, &index);
217                 if( ofs == 0 || Name[3+ofs] != '\0' )
218                         return NULL;
219                 
220                 // Find the adapter with that index
221                 for( tAdapter *a = gpIP_AdapterList; a && a->Index <= index; a = a->Next ) {
222                         if( a->Index == index )
223                                 return a;
224                 }
225                 
226                 return NULL;
227         }
228         
229         return NULL;
230 }
231
232 void Adapter_SendPacket(tAdapter *Handle, tIPStackBuffer *Buffer)
233 {
234         if( Handle->Type == NULL )
235         {
236                 size_t outlen = 0;
237                 void *data = IPStack_Buffer_CompactBuffer(Buffer, &outlen);
238                 VFS_Write((tVAddr)Handle->CardHandle, outlen, data);
239                 free(data);
240         }
241         else
242         {
243                 Handle->Type->SendPacket( Handle->CardHandle, Buffer );
244         }
245 }
246
247 // --- Helpers ---
248 void Adapter_int_WatchThread(void *Ptr)
249 {
250         tAdapter        *Adapter = Ptr;
251         const int       MTU = 1520;
252         tIPStackBuffer  *buf = NULL;
253         void    *data = NULL;
254         
255         if( Adapter->Type == NULL )
256         {
257                 data = malloc( MTU );
258                 buf = IPStack_Buffer_CreateBuffer(1);
259         }
260
261         
262         Threads_SetName("Adapter Watcher");
263         Log_Log("IPStack", "Thread %i watching eth%i '%s'", Threads_GetTID(), Adapter->Index,
264                 Adapter->Type?Adapter->Type->Name:"VFS");
265
266         for( ;; )
267         {
268                 if( Adapter->Type == NULL )
269                 {
270                         int len = VFS_Read((tVAddr)Adapter->CardHandle, MTU, data);
271                         IPStack_Buffer_AppendSubBuffer(buf, len, 0, buf, NULL, NULL);
272                 }
273                 else
274                 {
275                         buf = Adapter->Type->WaitForPacket( Adapter->CardHandle );
276                 }
277         
278                 Link_HandlePacket(Adapter, buf);
279         
280                 if( Adapter->Type == NULL )
281                 {
282                         IPStack_Buffer_ClearBuffer(buf);
283                 }
284                 else
285                 {
286                         IPStack_Buffer_DestroyBuffer(buf);
287                 }
288         }
289 }
290
291 tIPStackBuffer *Adapter_int_LoopbackWaitPacket(void *Unused)
292 {
293         Threads_Sleep();
294         return NULL;
295 }
296
297 int Adapter_int_LoopbackSendPacket(void *Unused, tIPStackBuffer *Buffer)
298 {
299         // This is a little hacky :)
300         Link_HandlePacket(&gIP_LoopAdapter, Buffer);
301         return 0;
302 }
303

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