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

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