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

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