More work on IPStack (Also fixed Proc_SpawnWorker)
[tpg/acess2.git] / Modules / IPStack / ipv4.c
1 /*
2  * Acess2 IP Stack
3  * - IPv4 Protcol Handling
4  */
5 #include "ipstack.h"
6 #include "link.h"
7 #include "ipv4.h"
8
9 // === IMPORTS ===
10 extern tInterface       *gIP_Interfaces;
11 extern void     ICMP_Initialise();
12 extern void     UDP_Initialise();
13
14 // === PROTOTYPES ===
15  int    IPv4_Initialise();
16  int    IPv4_RegisterCallback(int ID, tIPCallback Callback);
17 void    IPv4_int_GetPacket(tAdapter *Interface, tMacAddr From, int Length, void *Buffer);
18 tInterface      *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast);
19 Uint32  IPv4_Netmask(int FixedBits);
20
21 // === GLOBALS ===
22 tIPCallback     gaIPv4_Callbacks[256];
23
24 // === CODE ===
25 /**
26  * \fn int IPv4_Initialise()
27  */
28 int IPv4_Initialise()
29 {
30         ICMP_Initialise();
31         UDP_Initialise();
32         Link_RegisterType(IPV4_ETHERNET_ID, IPv4_int_GetPacket);
33         return 1;
34 }
35
36 /**
37  * \fn int IPv4_RegisterCallback( int ID, tIPCallback Callback )
38  * \brief Registers a callback
39  */
40 int IPv4_RegisterCallback(int ID, tIPCallback Callback)
41 {
42         if( ID < 0 || ID > 255 )        return 0;
43         if( gaIPv4_Callbacks[ID] )      return 0;
44         gaIPv4_Callbacks[ID] = Callback;
45         return 1;
46 }
47
48 /**
49  * \fn void IPv4_int_GetPacket(tInterface *Adapter, tMacAddr From, int Length, void *Buffer)
50  * \brief Process an IPv4 Packet
51  */
52 void IPv4_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer)
53 {
54         tIPv4Header     *hdr = Buffer;
55         tInterface      *iface;
56         Uint8   *data;
57          int    dataLength;
58         if(Length < sizeof(tIPv4Header))        return;
59         
60         //Log("[IPv4 ] Version = %i", hdr->Version);
61         Log("[IPv4 ] HeaderLength = %i", hdr->HeaderLength);
62         Log("[IPv4 ] DiffServices = %i", hdr->DiffServices);
63         //Log("[IPv4 ] TotalLength = %i", ntohs(hdr->TotalLength) );
64         //Log("[IPv4 ] Identifcation = %i", ntohs(hdr->Identifcation) );
65         //Log("[IPv4 ] TTL = %i", hdr->TTL );
66         Log("[IPv4 ] Protocol = %i", hdr->Protocol );
67         //Log("[IPv4 ] HeaderChecksum = 0x%x", ntohs(hdr->HeaderChecksum) );
68         Log("[IPv4 ] Source = %i.%i.%i.%i",
69                 hdr->Source.B[0], hdr->Source.B[1], hdr->Source.B[2], hdr->Source.B[3] );
70         Log("[IPv4 ] Destination = %i.%i.%i.%i",
71                 hdr->Destination.B[0], hdr->Destination.B[1],
72                 hdr->Destination.B[2], hdr->Destination.B[3] );
73         
74         // Check that the version IS IPv4
75         if(hdr->Version != 4) {
76                 Log("[IPv4 ] hdr->Version(%i) != 4", hdr->Version);
77                 return;
78         }
79         
80         // Check Header checksum
81         //TODO
82         
83         // Check Packet length
84         if( ntohs(hdr->TotalLength) > Length) {
85                 Log("[IPv4 ] hdr->TotalLength(%i) > Length(%i)", hdr->TotalLength, Length);
86                 return;
87         }
88         
89         // Get Interface (allowing broadcasts)
90         iface = IPv4_GetInterface(Adapter, hdr->Destination, 1);
91         if(!iface) {
92                 Log("[IPv4 ] Ignoring Packet (Not for us)");
93                 return; // Not for us? Well, let's ignore it
94         }
95         
96         // Defragment
97         //TODO
98         
99         dataLength = hdr->TotalLength - sizeof(tIPv4Header);
100         data = &hdr->Options[0];
101         
102         // Send it on
103         gaIPv4_Callbacks[hdr->Protocol] (iface, &hdr->Source, dataLength, data);
104 }
105
106 /**
107  * \fn tInterface *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address)
108  * \brief Searches an adapter for a matching address
109  */
110 tInterface *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast)
111 {
112         tInterface      *iface = NULL;
113         Uint32  netmask;
114         Uint32  addr, this;
115         
116         addr = ntohl( Address.L );
117         
118         for( iface = gIP_Interfaces; iface; iface = iface->Next)
119         {
120                 if( iface->Adapter != Adapter ) continue;
121                 if( iface->Type != 4 )  continue;
122                 if( IP4_EQU(Address, iface->IP4.Address) )
123                         return iface;
124                 
125                 if( !Broadcast )        continue;
126                 
127                 this = ntohl( iface->IP4.Address.L );
128                 
129                 // Check for broadcast
130                 netmask = IPv4_Netmask(iface->IP4.SubnetBits);
131                 
132                 //Log("netmask = 0x%08x", netmask);
133                 //Log("addr = 0x%08x", addr);
134                 //Log("this = 0x%08x", this);
135                 //Log("%08x == %08x && %08x == %08x",
136                 //      (addr & netmask), (this & netmask),
137                 //      (addr & ~netmask), (0xFFFFFFFF & ~netmask)
138                 //      );
139                 if( (addr & netmask) == (this & netmask)
140                  && (addr & ~netmask) == (0xFFFFFFFF & ~netmask) )
141                         return iface;
142         }
143         return NULL;
144 }
145
146 /**
147  * \brief Convert a network prefix to a netmask
148  * 
149  * For example /24 will become 255.255.255.0
150  */
151 Uint32 IPv4_Netmask(int FixedBits)
152 {
153         Uint32  ret = 0xFFFFFFFF;
154         ret >>= (32-FixedBits);
155         ret <<= (32-FixedBits);
156         // Returs a little endian netmask
157         return ret;
158 }

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