Modules/RAMDisk - a bit more work
[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, dataLength;
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         dataLength = hdr->PayloadLength;
109         for( ;; )
110         {
111                 struct {
112                         Uint8   NextHeader;
113                         Uint8   Length; // In 8-byte chunks, with 0 being 8 bytes long
114                         Uint8   Data[];
115                 }       *optionHdr;
116                 optionHdr = (void*)dataPtr;
117                 // Hop-by-hop options
118                 if(nextHeader == 0)
119                 {
120                         // TODO: Parse the options (actually, RFC2460 doesn't specify any)
121                 }
122                 // Routing Options
123                 else if(nextHeader == 43)
124                 {
125                         // TODO: Routing Header options
126                 }
127                 else
128                 {
129                         break;  // Unknown, pass on
130                 }
131                 nextHeader = optionHdr->NextHeader;
132                 dataPtr += (optionHdr->Length + 1) * 8; // 8-octet length (0 = 8 bytes long)
133         }
134         
135         // Get Interface (allowing broadcasts)
136         iface = IPv6_GetInterface(Adapter, hdr->Destination, 1);
137         
138         // Firewall rules
139         if( iface ) {
140                 // Incoming Packets
141                 ret = IPTables_TestChain("INPUT",
142                         6, &hdr->Source, &hdr->Destination,
143                         hdr->NextHeader, 0,
144                         hdr->PayloadLength, hdr->Data
145                         );
146         }
147         else {
148                 // Routed packets
149                 ret = IPTables_TestChain("FORWARD",
150                         6, &hdr->Source, &hdr->Destination,
151                         hdr->NextHeader, 0,
152                         hdr->PayloadLength, hdr->Data
153                         );
154         }
155         
156         switch(ret)
157         {
158         // 0 - Allow
159         case 0: break;
160         // 1 - Silent Drop
161         case 1:
162                 Log_Debug("IPv6", "Silently dropping packet");
163                 return ;
164         // Unknown, silent drop
165         default:
166                 return ;
167         }
168         
169         // Routing
170         if(!iface)
171         {
172                 #if 0
173                 tMacAddr        to;
174                 tRoute  *rt;
175                 
176                 Log_Debug("IPv6", "Route the packet");
177                 // Drop the packet if the TTL is zero
178                 if( hdr->HopLimit == 0 ) {
179                         Log_Warning("IPv6", "TODO: Sent ICMP-Timeout when TTL exceeded");
180                         return ;
181                 }
182                 
183                 hdr->HopLimit --;
184                 
185                 rt = IPStack_FindRoute(6, NULL, &hdr->Destination);     // Get the route (gets the interface)
186                 to = ICMP6_ResolveHWAddr(rt->Interface, hdr->Destination);      // Resolve address
187                 
188                 // Send packet
189                 Log_Log("IPv6", "Forwarding packet");
190                 Link_SendPacket(rt->Interface->Adapter, IPV6_ETHERNET_ID, to, Length, Buffer);
191                 #endif
192                 
193                 return ;
194         }
195         
196         // Send it on
197         if( !gaIPv6_Callbacks[hdr->NextHeader] ) {
198                 Log_Log("IPv6", "Unknown Protocol %i", hdr->NextHeader);
199                 return ;
200         }
201         
202         gaIPv6_Callbacks[hdr->NextHeader]( iface, &hdr->Source, hdr->PayloadLength, hdr->Data );
203 }
204
205 /**
206  * \fn tInterface *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address)
207  * \brief Searches an adapter for a matching address
208  * \param Adapter       Source adapter
209  * \param Address       Destination Address
210  * \param Broadcast     Allow broadcast?
211  */
212 tInterface *IPv6_GetInterface(tAdapter *Adapter, tIPv6 Address, int Broadcast)
213 {
214          int    i, j;
215         tInterface      *iface = NULL;
216         Uint32  netmask;
217         
218         for( iface = gIP_Interfaces; iface; iface = iface->Next)
219         {
220                 tIPv6   *thisAddr;
221                 
222                 // Check for this adapter
223                 if( iface->Adapter != Adapter ) continue;
224                 
225                 // Skip non-IPv6 Interfaces
226                 if( iface->Type != 6 )  continue;
227                 
228                 thisAddr = (tIPv6*)iface->Address;
229                 // If the address is a perfect match, return this interface
230                 if( IP6_EQU(Address, *thisAddr) )       return iface;
231                 
232                 // Check if we want to match broadcast addresses
233                 if( !Broadcast )        continue;
234                 
235                 // Check for broadcast
236                 // - Check first DWORDs
237                 if( iface->SubnetBits > 32 && Address.L[0] != thisAddr->L[0] )
238                         continue;
239                 if( iface->SubnetBits > 64 && Address.L[1] != thisAddr->L[1] )
240                         continue;
241                 if( iface->SubnetBits > 96 && Address.L[2] != thisAddr->L[2] )
242                         continue;
243                 
244                 // Check final DWORD
245                 j = iface->SubnetBits / 32;
246                 i = iface->SubnetBits % 32;
247                 netmask = IPv4_Netmask( iface->SubnetBits % 32 );
248                 
249                 // Check the last bit of the netmask
250                 if( (Address.L[j] >> i) != (thisAddr->L[j] >> i) )      continue;
251                 
252                 // Check that the host portion is one
253                 if( (Address.L[j] & ~netmask) != (0xFFFFFFFF & ~netmask) )      continue;
254                 if( j >= 2 && Address.L[3] != 0xFFFFFFFF)       continue;
255                 if( j >= 1 && Address.L[2] != 0xFFFFFFFF)       continue;
256                 if( j >= 0 && Address.L[1] != 0xFFFFFFFF)       continue;
257                 
258                 return iface;
259         }
260         return NULL;
261 }

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