2a02fd27cc4a98525207efd2b5409ffdc9b58d8b
[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  int    Adapter_ReadDir(tVFS_Node *Node, int Pos, char Name[FILENAME_MAX]);
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         Mutex_Acquire( &glIP_Adapters );
83         gpIP_AdapterList_Last->Next = ret;
84         gpIP_AdapterList_Last = ret;
85         Mutex_Release( &glIP_Adapters );
86         
87         // Watch the adapter for incoming packets
88         tTID tid = Proc_SpawnWorker(Adapter_int_WatchThread, ret);
89         if(tid < 0) {
90                 Log_Warning("IPStack", "Unable to create watcher thread for %p", ret);
91         }
92         
93         return ret;
94 }
95
96 void *IPStack_Adapter_AddVFS(const char *Path)
97 {
98          int    fd, tmp;
99         char    mac[6];
100
101         ENTER("sPath", Path);   
102
103         // Open Device
104         fd = VFS_Open( Path, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE );
105         if( fd == -1 ) {
106                 LEAVE('n');
107                 return NULL;
108         }
109         
110         // Check that it is a network interface
111         tmp = VFS_IOCtl(fd, 0, NULL);
112         LOG("Device type = %i", tmp);
113         if( tmp != DRV_TYPE_NETWORK ) {
114                 Log_Warning("IPStack", "IPStack_Adapter_AddVFS: '%s' is not a network interface", Path);
115                 VFS_Close( fd );
116                 LEAVE('n');
117                 return NULL;
118         }
119         
120         // Get MAC Address
121         VFS_IOCtl(fd, NET_IOCTL_GETMAC, mac);
122
123         return IPStack_Adapter_Add(NULL, (void*)(tVAddr)fd, mac);
124 }
125
126 void IPStack_Adapter_Del(void *Handle)
127 {
128         Log_Error("IPStack", "TODO: Implement IPStack_Adapter_Del");
129         // TODO: Allow removing adapters during system operation
130 }
131
132 // --- VFS API ---
133 int Adapter_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
134 {
135         if( Pos < 0 )   return -EINVAL;
136
137         // Loopback
138         if( Pos == 0 ) {
139                 strcpy(Dest, "lo");
140                 return 0;
141         }
142         Pos --;
143         
144         #define CHECK_LIST(list, type) do{ \
145                 tAdapter *a;  int i;\
146                 for(i=0,a=list; i < Pos && a; i ++, a = a->Next ); \
147                 if( a ) { \
148                         strncpy(Dest, Adapter_GetName(a), FILENAME_MAX);\
149                         return 0;\
150                 } \
151                 Pos -= i; \
152         } while(0);
153
154         CHECK_LIST(gpIP_AdapterList, "eth");
155         // TODO: Support other types of adapters (wifi, tap, ...)
156
157         return -EINVAL;
158 }
159
160 tVFS_Node *Adapter_FindDir(tVFS_Node *Node, const char *Name)
161 {
162         tAdapter *a = Adapter_GetByName(Name);
163         if(!a)
164                 return NULL;
165         else
166                 return &a->Node;
167 }
168
169 static const char *casIOCtls_Root[] = { DRV_IOCTLNAMES, "add_vfs_adapter", NULL };
170 int Adapter_DirIOCtl(tVFS_Node *Node, int Num, void *Data)
171 {
172         switch(Num)
173         {
174         BASE_IOCTLS(DRV_TYPE_MISC, "IPStack-AdapterList", VERSION, casIOCtls_Root)
175         
176         case 4:
177                 if( !CheckString(Data) )
178                         return -1;
179
180                 // Return non-zero if add fails
181                 return IPStack_Adapter_AddVFS(Data) == NULL;
182         }
183         return -1;
184 }
185
186 static const char *casIOCtls_Dev[] = { DRV_IOCTLNAMES, "get_hwaddr", NULL };
187 int Adapter_IOCtl(tVFS_Node *Node, int Num, void *Data)
188 {
189         tAdapter *adapter = Node->ImplPtr;
190         switch(Num)
191         {
192         BASE_IOCTLS(DRV_TYPE_MISC, "IPStack-Adapter", VERSION, casIOCtls_Dev)
193         
194         case 4:
195                 if( !CheckMem(Data, 6) )
196                         return -1;
197
198                 memcpy(Data, adapter->HWAddr, 6);
199                 return 0;
200         }
201         return -1;
202 }
203
204 // --- "Internal" (IPStack) API ---
205 tAdapter *Adapter_GetByName(const char *Name)
206 {
207         if( strcmp(Name, "lo") == 0 ) {
208                 return &gIP_LoopAdapter;
209         }
210         
211         if( strncmp(Name, "eth", 3) == 0 )
212         {
213                 // Possibly an ethX interface
214                  int    index, ofs;
215                 
216                 // Get the index at the end
217                 ofs = ParseInt(Name + 3, &index);
218                 if( ofs == 0 || Name[3+ofs] != '\0' )
219                         return NULL;
220                 
221                 // Find the adapter with that index
222                 for( tAdapter *a = gpIP_AdapterList; a && a->Index <= index; a = a->Next ) {
223                         if( a->Index == index )
224                                 return a;
225                 }
226                 
227                 return NULL;
228         }
229         
230         return NULL;
231 }
232
233 char *Adapter_GetName(tAdapter *Adapter)
234 {
235         if( Adapter == &gIP_LoopAdapter )
236         {
237                 return strdup("lo");
238         }
239         else
240         {
241                 // TODO: Support multiple adapter types
242                 char    buf[sizeof("eth")+10];
243                 sprintf(buf, "eth%i", Adapter->Index);
244                 return strdup(buf);
245         }
246 }
247
248 void Adapter_SendPacket(tAdapter *Handle, tIPStackBuffer *Buffer)
249 {
250         if( Handle->Type == NULL )
251         {
252                 size_t outlen = 0;
253                 void *data = IPStack_Buffer_CompactBuffer(Buffer, &outlen);
254                 VFS_Write((tVAddr)Handle->CardHandle, outlen, data);
255                 free(data);
256         }
257         else
258         {
259                 Handle->Type->SendPacket( Handle->CardHandle, Buffer );
260         }
261 }
262
263 // --- Helpers ---
264 void Adapter_int_WatchThread(void *Ptr)
265 {
266         tAdapter        *Adapter = Ptr;
267         const int       MTU = 1520;
268         tIPStackBuffer  *buf = NULL;
269         void    *data = NULL;
270         
271         if( Adapter->Type == NULL )
272         {
273                 data = malloc( MTU );
274                 buf = IPStack_Buffer_CreateBuffer(1);
275         }
276
277         
278         Threads_SetName("Adapter Watcher");
279         Log_Log("IPStack", "Thread %i watching eth%i '%s'", Threads_GetTID(), Adapter->Index,
280                 Adapter->Type?Adapter->Type->Name:"VFS");
281
282         for( ;; )
283         {
284                 if( Adapter->Type == NULL )
285                 {
286                         int len = VFS_Read((tVAddr)Adapter->CardHandle, MTU, data);
287                         IPStack_Buffer_AppendSubBuffer(buf, len, 0, buf, NULL, NULL);
288                 }
289                 else
290                 {
291                         buf = Adapter->Type->WaitForPacket( Adapter->CardHandle );
292                 }
293         
294                 Link_HandlePacket(Adapter, buf);
295         
296                 if( Adapter->Type == NULL )
297                 {
298                         IPStack_Buffer_ClearBuffer(buf);
299                 }
300                 else
301                 {
302                         IPStack_Buffer_DestroyBuffer(buf);
303                 }
304         }
305 }
306
307 tIPStackBuffer *Adapter_int_LoopbackWaitPacket(void *Unused)
308 {
309         Threads_Sleep();
310         return NULL;
311 }
312
313 int Adapter_int_LoopbackSendPacket(void *Unused, tIPStackBuffer *Buffer)
314 {
315         // This is a little hacky :)
316         Link_HandlePacket(&gIP_LoopAdapter, Buffer);
317         return 0;
318 }
319
320 // --- Broadcast Debugging ---
321 extern Uint16   IPv4_Checksum(const void *Buf, size_t Length);
322 void IPStack_SendDebugText(const char *Text)
323 {
324         const Uint8     pkt_hdr[] = {
325                 0xFF,0xFF, 0xFF,0xFF, 0xFF,0xFF,
326                 0x00,0x00, 0x00,0x00, 0x00,0x00,
327                 0x08,0x00,
328                 
329                 0x45,0x00,      // Version/Length, DiffServices
330                 0xFF,0xFF,      // Total Length
331                 0x00,0x00,      // Identifcation
332                 0x00,0x00, 0xFF,0x11,   // Flags,Fragment, TTL=255,proto=UDP
333                 0x00,0x00,      // Header checksum
334                 0x00,0x00,0x00,0x00,    // Source
335                 0xFF,0xFF,0xFF,0xFF,    // Destination
336                 
337                 0x80,0x00, 0x80,0x00,
338                 0xFF,0xFF, 0xFF,0xFF,
339         };
340         static tShortSpinlock   lLock;
341
342         // Fast return if there's no avaliable adapters
343         if( !gpIP_AdapterList )
344                 return ;
345
346         if( CPU_HAS_LOCK(&lLock) )
347                 return ;        // Nested!
348         SHORTLOCK(&lLock);
349         #if ARCHDIR_is_x86
350         __asm__ __volatile__ ("sti");   // Start interrupts (x86 specific)
351         #endif
352
353         // Cache packets until a newline
354         static char     cache[1500 - (sizeof(pkt_hdr) + 4)];
355         static int      cache_len;
356         
357          int    len = strlen(Text);
358
359         // Append to cache
360         strncpy(cache + cache_len, Text, sizeof(cache) - cache_len);
361         cache_len += len;
362         // TODO: Detect overflows.
363         
364         // If there's no newline, only buffer
365         if( strpos(Text, '\n') == -1 ) {
366                 SHORTREL(&lLock);
367                 return ;
368         }
369
370         // Build packet
371          int    link_checksum_ofs = sizeof(pkt_hdr) + cache_len;
372         char    buffer[sizeof(pkt_hdr) + cache_len + 4];
373
374         memcpy(buffer, pkt_hdr, sizeof(pkt_hdr));
375         memcpy(buffer + sizeof(pkt_hdr), cache, cache_len);
376         
377         ((Uint16*)buffer)[(14+2)/2] = BigEndian16( sizeof(pkt_hdr)-14 + cache_len );    // IP Size
378         ((Uint16*)buffer)[(14+10)/2] = BigEndian16( 0 );        // IP Header
379         ((Uint16*)buffer)[(14+20+4)/2] = BigEndian16( 8+cache_len );    // UDP Size
380         ((Uint16*)buffer)[(14+20+6)/2] = BigEndian16( 0 );      // UDP Checksum
381 //      *(Uint32*)&buffer[link_checksum_ofs] = BigEndian32( 0 );        // 802.3 checksum?
382         // TODO: Calculate checksums
383         ((Uint16*)buffer)[(14+10)/2] = BigEndian16( IPv4_Checksum(buffer+14,20) );      // IP Header
384         
385         // Create buffer
386         tIPStackBuffer  *buf = IPStack_Buffer_CreateBuffer(1);
387         IPStack_Buffer_AppendSubBuffer(buf, link_checksum_ofs+4, 0, buffer, NULL, NULL);
388
389         // Send 'er off
390         for( tAdapter *a = gpIP_AdapterList; a; a = a->Next )
391         {
392                 a->Type->SendPacket( a->CardHandle, buf );
393         }
394
395         IPStack_Buffer_DestroyBuffer(buf);
396
397         cache_len = 0;
398
399         SHORTREL(&lLock);
400 }
401

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