Kernel - Fixing small errors exposed by new compiler
[tpg/acess2.git] / KernelLand / Modules / IPStack / ipv6.c
1 /*
2  * Acess2 IP Stack
3  * - IPv6 Protcol Handling
4  */
5 #include "ipstack.h"
6 #include "link.h"
7 #include "ipv6.h"
8 #include "firewall.h"
9
10 // === IMPORTS ===
11 extern tInterface       *gIP_Interfaces;
12 extern Uint32   IPv4_Netmask(int FixedBits);
13
14 // === PROTOTYPES ===
15  int    IPv6_Initialise();
16  int    IPv6_RegisterCallback(int ID, tIPCallback Callback);
17 void    IPv6_int_GetPacket(tAdapter *Interface, tMacAddr From, int Length, void *Buffer);
18 tInterface      *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast);
19
20 // === GLOBALS ===
21 tIPCallback     gaIPv6_Callbacks[256];
22
23 // === CODE ===
24 /**
25  * \brief Initialise the IPv6 handling code
26  */
27 int IPv6_Initialise()
28 {
29         Link_RegisterType(IPV6_ETHERNET_ID, IPv6_int_GetPacket);
30         return 1;
31 }
32
33 /**
34  * \brief Registers a callback
35  * \param ID    8-bit packet type ID
36  * \param Callback      Callback function
37  */
38 int IPv6_RegisterCallback(int ID, tIPCallback Callback)
39 {
40         if( ID < 0 || ID > 255 )        return 0;
41         if( gaIPv6_Callbacks[ID] )      return 0;
42         gaIPv6_Callbacks[ID] = Callback;
43         return 1;
44 }
45
46 /**
47  * \brief Creates and sends an IPv6 Packet
48  * \param Iface Interface
49  * \param Destination   Destination IP
50  * \param Protocol      Protocol ID
51  * \param Length        Data Length
52  * \param Data  Packet Data
53  * \return Boolean Success
54  */
55 int IPv6_SendPacket(tInterface *Iface, tIPv6 Destination, int Protocol, size_t Length, const void *Data)
56 {
57         return 0;
58 }
59
60 /**
61  * \fn void IPv6_int_GetPacket(tInterface *Interface, tMacAddr From, int Length, void *Buffer)
62  * \brief Process an IPv6 Packet
63  * \param Interface     Input interface
64  * \param From  Source MAC address
65  * \param Length        Packet length
66  * \param Buffer        Packet data
67  */
68 void IPv6_int_GetPacket(tAdapter *Adapter, tMacAddr From, int Length, void *Buffer)
69 {
70         tInterface      *iface;
71         tIPv6Header     *hdr = Buffer;
72          int    ret;
73         char    *dataPtr;
74         Uint8   nextHeader;
75         
76         if(Length < sizeof(tIPv6Header))        return;
77         
78         hdr->Head = ntohl(hdr->Head);
79         
80         //if( ((hdr->Head >> (20+8)) & 0xF) != 6 )
81         if( hdr->Version != 6 )
82                 return;
83         
84         #if 1
85         Log_Debug("IPv6", "hdr = {");
86         Log_Debug("IPv6", " .Version       = %i", hdr->Version );
87         Log_Debug("IPv6", " .TrafficClass  = %i", hdr->TrafficClass );
88         Log_Debug("IPv6", " .FlowLabel     = %i", hdr->FlowLabel );
89         Log_Debug("IPv6", " .PayloadLength = 0x%04x", ntohs(hdr->PayloadLength) );
90         Log_Debug("IPv6", " .NextHeader    = 0x%02x", hdr->NextHeader );
91         Log_Debug("IPv6", " .HopLimit      = 0x%02x", hdr->HopLimit );
92         Log_Debug("IPv6", " .Source        = %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", hdr->Source );
93         Log_Debug("IPv6", " .Destination   = %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", hdr->Destination );
94         Log_Debug("IPv6", "}");
95         #endif
96         
97         // No checksum in IPv6
98         
99         // Check Packet length
100         if( ntohs(hdr->PayloadLength)+sizeof(tIPv6Header) > Length) {
101                 Log_Log("IPv6", "hdr->PayloadLength(%i) > Length(%i)", ntohs(hdr->PayloadLength), Length);
102                 return;
103         }
104         
105         // Process Options
106         nextHeader = hdr->NextHeader;
107         dataPtr = hdr->Data;
108         for( ;; )
109         {
110                 struct {
111                         Uint8   NextHeader;
112                         Uint8   Length; // In 8-byte chunks, with 0 being 8 bytes long
113                         Uint8   Data[];
114                 }       *optionHdr;
115                 optionHdr = (void*)dataPtr;
116                 // Hop-by-hop options
117                 if(nextHeader == 0)
118                 {
119                         // TODO: Parse the options (actually, RFC2460 doesn't specify any)
120                 }
121                 // Routing Options
122                 else if(nextHeader == 43)
123                 {
124                         // TODO: Routing Header options
125                 }
126                 else
127                 {
128                         break;  // Unknown, pass on
129                 }
130                 nextHeader = optionHdr->NextHeader;
131                 dataPtr += (optionHdr->Length + 1) * 8; // 8-octet length (0 = 8 bytes long)
132         }
133         
134         // Get Interface (allowing broadcasts)
135         iface = IPv6_GetInterface(Adapter, hdr->Destination, 1);
136         
137         // Firewall rules
138         if( iface ) {
139                 // Incoming Packets
140                 ret = IPTables_TestChain("INPUT",
141                         6, &hdr->Source, &hdr->Destination,
142                         hdr->NextHeader, 0,
143                         hdr->PayloadLength, hdr->Data
144                         );
145         }
146         else {
147                 // Routed packets
148                 ret = IPTables_TestChain("FORWARD",
149                         6, &hdr->Source, &hdr->Destination,
150                         hdr->NextHeader, 0,
151                         hdr->PayloadLength, hdr->Data
152                         );
153         }
154         
155         switch(ret)
156         {
157         // 0 - Allow
158         case 0: break;
159         // 1 - Silent Drop
160         case 1:
161                 Log_Debug("IPv6", "Silently dropping packet");
162                 return ;
163         // Unknown, silent drop
164         default:
165                 return ;
166         }
167         
168         // Routing
169         if(!iface)
170         {
171                 #if 0
172                 tMacAddr        to;
173                 tRoute  *rt;
174                 
175                 Log_Debug("IPv6", "Route the packet");
176                 // Drop the packet if the TTL is zero
177                 if( hdr->HopLimit == 0 ) {
178                         Log_Warning("IPv6", "TODO: Sent ICMP-Timeout when TTL exceeded");
179                         return ;
180                 }
181                 
182                 hdr->HopLimit --;
183                 
184                 rt = IPStack_FindRoute(6, NULL, &hdr->Destination);     // Get the route (gets the interface)
185                 to = ICMP6_ResolveHWAddr(rt->Interface, hdr->Destination);      // Resolve address
186                 
187                 // Send packet
188                 Log_Log("IPv6", "Forwarding packet");
189                 Link_SendPacket(rt->Interface->Adapter, IPV6_ETHERNET_ID, to, Length, Buffer);
190                 #endif
191                 
192                 return ;
193         }
194         
195         // Send it on
196         if( !gaIPv6_Callbacks[hdr->NextHeader] ) {
197                 Log_Log("IPv6", "Unknown Protocol %i", hdr->NextHeader);
198                 return ;
199         }
200         
201         gaIPv6_Callbacks[hdr->NextHeader]( iface, &hdr->Source, hdr->PayloadLength, hdr->Data );
202 }
203
204 /**
205  * \fn tInterface *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address)
206  * \brief Searches an adapter for a matching address
207  * \param Adapter       Source adapter
208  * \param Address       Destination Address
209  * \param Broadcast     Allow broadcast?
210  */
211 tInterface *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast)
212 {
213          int    i, j;
214         tInterface      *iface = NULL;
215         Uint32  netmask;
216         
217         for( iface = gIP_Interfaces; iface; iface = iface->Next)
218         {
219                 tIPv6   *thisAddr;
220                 
221                 // Check for this adapter
222                 if( iface->Adapter != Adapter ) continue;
223                 
224                 // Skip non-IPv6 Interfaces
225                 if( iface->Type != 6 )  continue;
226                 
227                 thisAddr = (tIPv6*)iface->Address;
228                 // If the address is a perfect match, return this interface
229                 if( IP6_EQU(Address, *thisAddr) )       return iface;
230                 
231                 // Check if we want to match broadcast addresses
232                 if( !Broadcast )        continue;
233                 
234                 // Check for broadcast
235                 // - Check first DWORDs
236                 if( iface->SubnetBits > 32 && Address.L[0] != thisAddr->L[0] )
237                         continue;
238                 if( iface->SubnetBits > 64 && Address.L[1] != thisAddr->L[1] )
239                         continue;
240                 if( iface->SubnetBits > 96 && Address.L[2] != thisAddr->L[2] )
241                         continue;
242                 
243                 // Check final DWORD
244                 j = iface->SubnetBits / 32;
245                 i = iface->SubnetBits % 32;
246                 netmask = IPv4_Netmask( iface->SubnetBits % 32 );
247                 
248                 // Check the last bit of the netmask
249                 if( (Address.L[j] >> i) != (thisAddr->L[j] >> i) )      continue;
250                 
251                 // Check that the host portion is one
252                 if( (Address.L[j] & ~netmask) != (0xFFFFFFFF & ~netmask) )      continue;
253                 if( j >= 2 && Address.L[3] != 0xFFFFFFFF)       continue;
254                 if( j >= 1 && Address.L[2] != 0xFFFFFFFF)       continue;
255                 if( j >= 0 && Address.L[1] != 0xFFFFFFFF)       continue;
256                 
257                 return iface;
258         }
259         return NULL;
260 }

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