Modules/UHCI - Removed redundant packet splitting in bulk transfers
[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                         return Adapter_GetName(a);\
147                 } \
148                 Pos -= i; \
149         } while(0);
150
151         CHECK_LIST(gpIP_AdapterList, "eth");
152         // TODO: Support other types of adapters (wifi, tap, ...)
153
154         return NULL;
155 }
156
157 tVFS_Node *Adapter_FindDir(tVFS_Node *Node, const char *Name)
158 {
159         tAdapter *a = Adapter_GetByName(Name);
160         if(!a)
161                 return NULL;
162         else
163                 return &a->Node;
164 }
165
166 static const char *casIOCtls_Root[] = { DRV_IOCTLNAMES, "add_vfs_adapter", NULL };
167 int Adapter_DirIOCtl(tVFS_Node *Node, int Num, void *Data)
168 {
169         switch(Num)
170         {
171         BASE_IOCTLS(DRV_TYPE_MISC, "IPStack-AdapterList", VERSION, casIOCtls_Root)
172         
173         case 4:
174                 if( !CheckString(Data) )
175                         return -1;
176
177                 // Return non-zero if add fails
178                 return IPStack_Adapter_AddVFS(Data) == NULL;
179         }
180         return -1;
181 }
182
183 static const char *casIOCtls_Dev[] = { DRV_IOCTLNAMES, "get_hwaddr", NULL };
184 int Adapter_IOCtl(tVFS_Node *Node, int Num, void *Data)
185 {
186         tAdapter *adapter = Node->ImplPtr;
187         switch(Num)
188         {
189         BASE_IOCTLS(DRV_TYPE_MISC, "IPStack-Adapter", VERSION, casIOCtls_Dev)
190         
191         case 4:
192                 if( !CheckMem(Data, 6) )
193                         return -1;
194
195                 memcpy(Data, adapter->HWAddr, 6);
196                 return 0;
197         }
198         return -1;
199 }
200
201 // --- "Internal" (IPStack) API ---
202 tAdapter *Adapter_GetByName(const char *Name)
203 {
204         if( strcmp(Name, "lo") == 0 ) {
205                 return &gIP_LoopAdapter;
206         }
207         
208         if( strncmp(Name, "eth", 3) == 0 )
209         {
210                 // Possibly an ethX interface
211                  int    index, ofs;
212                 
213                 // Get the index at the end
214                 ofs = ParseInt(Name + 3, &index);
215                 if( ofs == 0 || Name[3+ofs] != '\0' )
216                         return NULL;
217                 
218                 // Find the adapter with that index
219                 for( tAdapter *a = gpIP_AdapterList; a && a->Index <= index; a = a->Next ) {
220                         if( a->Index == index )
221                                 return a;
222                 }
223                 
224                 return NULL;
225         }
226         
227         return NULL;
228 }
229
230 char *Adapter_GetName(tAdapter *Adapter)
231 {
232         if( Adapter == &gIP_LoopAdapter )
233         {
234                 return strdup("lo");
235         }
236         else
237         {
238                 // TODO: Support multiple adapter types
239                 char    buf[sizeof("eth")+10];
240                 sprintf(buf, "eth%i", Adapter->Index);
241                 return strdup(buf);
242         }
243 }
244
245 void Adapter_SendPacket(tAdapter *Handle, tIPStackBuffer *Buffer)
246 {
247         if( Handle->Type == NULL )
248         {
249                 size_t outlen = 0;
250                 void *data = IPStack_Buffer_CompactBuffer(Buffer, &outlen);
251                 VFS_Write((tVAddr)Handle->CardHandle, outlen, data);
252                 free(data);
253         }
254         else
255         {
256                 Handle->Type->SendPacket( Handle->CardHandle, Buffer );
257         }
258 }
259
260 // --- Helpers ---
261 void Adapter_int_WatchThread(void *Ptr)
262 {
263         tAdapter        *Adapter = Ptr;
264         const int       MTU = 1520;
265         tIPStackBuffer  *buf = NULL;
266         void    *data = NULL;
267         
268         if( Adapter->Type == NULL )
269         {
270                 data = malloc( MTU );
271                 buf = IPStack_Buffer_CreateBuffer(1);
272         }
273
274         
275         Threads_SetName("Adapter Watcher");
276         Log_Log("IPStack", "Thread %i watching eth%i '%s'", Threads_GetTID(), Adapter->Index,
277                 Adapter->Type?Adapter->Type->Name:"VFS");
278
279         for( ;; )
280         {
281                 if( Adapter->Type == NULL )
282                 {
283                         int len = VFS_Read((tVAddr)Adapter->CardHandle, MTU, data);
284                         IPStack_Buffer_AppendSubBuffer(buf, len, 0, buf, NULL, NULL);
285                 }
286                 else
287                 {
288                         buf = Adapter->Type->WaitForPacket( Adapter->CardHandle );
289                 }
290         
291                 Link_HandlePacket(Adapter, buf);
292         
293                 if( Adapter->Type == NULL )
294                 {
295                         IPStack_Buffer_ClearBuffer(buf);
296                 }
297                 else
298                 {
299                         IPStack_Buffer_DestroyBuffer(buf);
300                 }
301         }
302 }
303
304 tIPStackBuffer *Adapter_int_LoopbackWaitPacket(void *Unused)
305 {
306         Threads_Sleep();
307         return NULL;
308 }
309
310 int Adapter_int_LoopbackSendPacket(void *Unused, tIPStackBuffer *Buffer)
311 {
312         // This is a little hacky :)
313         Link_HandlePacket(&gIP_LoopAdapter, Buffer);
314         return 0;
315 }
316

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