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

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