Initial c661x version
[keystone-rtos/ibl.git] / src / driver / eth / ip.c
1 /** 
2  *   @file  ip.c
3  *
4  *   @brief   
5  *      The file implements the NET Module IPv4 functionality.
6  *
7  *  \par
8  *  NOTE:
9  *      (C) Copyright 2008, Texas Instruments, Inc.
10  * 
11  *  Redistribution and use in source and binary forms, with or without 
12  *  modification, are permitted provided that the following conditions 
13  *  are met:
14  *
15  *    Redistributions of source code must retain the above copyright 
16  *    notice, this list of conditions and the following disclaimer.
17  *
18  *    Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the 
20  *    documentation and/or other materials provided with the   
21  *    distribution.
22  *
23  *    Neither the name of Texas Instruments Incorporated nor the names of
24  *    its contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
28  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
29  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
31  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
32  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
33  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
36  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
37  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38  *
39  *  \par
40 */
41 #include "types.h"
42 #include "iblloc.h"
43 #include "net.h"
44 #include "netif.h"
45 #include <string.h>
46 #include "net_osal.h"
49 /**
50  * @brief   This is the size of the NET Boot Module Routing table.
51  * This definition should never be modified. If changed then the API
52  * for adding/deleting routes will also need to be modified.
53  */
54 #define MAX_RT_TABLE_SIZE   2
56 /**
57  * @brief   This is the global routing table which is used by 
58  * the stack to determine the route on which the packet needs to 
59  * be transmitted.
60  */
61 RT_ENTRY    rt_table[MAX_RT_TABLE_SIZE];
63 /**********************************************************************
64  **************************** IP Functions ****************************
65  **********************************************************************/
67 /**
68  *  @b Description
69  *  @n  
70  *       The function adds a route to the routing table. Default routes are 
71  *       always added to the last entry in the routing table. There is no
72  *       duplicate route checking done here and if an entry exists it is
73  *       overriden with the new values.
74  *
75  *  @param[in]  flag
76  *      Flag properties associated with the route
77  *  @param[in]  ip_address
78  *      IP Address associated with the route. 
79  *  @param[in]  net_mask
80  *      Network Mask associated with the route
81  *  @param[in]  next_hop
82  *      Next Hop Address associated with the route. This is applicable
83  *      for default gateways. For network routes this is ignored.
84  *
85  *  @retval
86  *      Success -   0
87  *  @retval
88  *      Error   -   <0
89  */
90 Int32 ip_add_route (Uint32 flag, IPN ip_address, IPN net_mask, IPN next_hop)
91 {
92     RT_ENTRY*   ptr_rt;
94     /* Basic Sanity Check: The flag should be correct! */
95     if ((flag != FLG_RT_NETWORK) && (flag != FLG_RT_DEFAULT))
96         return -1;
98     /* Check if the flag is a network route being added? */
99     if (flag == FLG_RT_NETWORK)
100     {
101         /* Network route is being added. */
102         ptr_rt = &rt_table[0];
104         /* Populate the routing entry. */
105         ptr_rt->flags    = FLG_RT_NETWORK;
106         ptr_rt->ip_addr  = ip_address;
107         ptr_rt->net_mask = net_mask;
108         ptr_rt->net_addr = ip_address & net_mask;
109         ptr_rt->next_hop = ip_address;
110     }
111     else
112     {
113         /* Default route is being added. */
114         ptr_rt = &rt_table[1];
116         /* Populate the routing entry. */
117         ptr_rt->flags    = FLG_RT_DEFAULT;
118         ptr_rt->ip_addr  = 0x0;
119         ptr_rt->net_mask = 0x0;
120         ptr_rt->net_addr = 0x0;
121         ptr_rt->next_hop = next_hop;
122     }
124     /* Routes were added successfully. */
125     return 0;
128 /**
129  *  @b Description
130  *  @n  
131  *       The function checks the routing table to determine a
132  *       suitable route which needs to be taken to send out the
133  *       packet.
134  *
135  *  @param[in]  ip_address
136  *      IP Address for which the route is being looked up.
137  *
138  *  @retval
139  *      Success -  Pointer to the routing entry being used.
140  *  @retval
141  *      Error   -  NULL (There is no route which can be used)
142  */
143 RT_ENTRY* ip_lookup_route (IPN ip_address)
145     Int32       index = 0;
146     RT_ENTRY*   ptr_rt;
147     IPN         network_address;
149     /* Cycle through the routing table. */
150     for (index = 0; index < MAX_RT_TABLE_SIZE; index++)
151     {
152         /* Get the pointer to the routing table entry. */
153         ptr_rt = &rt_table[index];
155         /* Check if there is a valid entry or not? */
156         if (ptr_rt->flags & (FLG_RT_NETWORK | FLG_RT_DEFAULT))
157         {
158             /* Valid routing entry was found;  calculate the network address 
159              * with respect to the route netmask and match it. */
160             network_address = ip_address & ptr_rt->net_mask;
162             /* Check if this matches the same network to which we are sending the packet. */
163             if (network_address == ptr_rt->net_addr)
164             {
165                 /* YES. Perfect; we can return this routing entry. */
166                 return ptr_rt;
167             }
168         }
169     }
171     /* Control comes here indicates that there was no routing entry which could be used. */
172     return NULL;
175 /**
176  *  @b Description
177  *  @n  
178  *       The function deletes the routing table entry.
179  *
180  *  @param[in]  flag
181  *      This is the routing entry which is being deleted. 
182  *
183  *  @retval
184  *      Not Applicable.
185  */
186 void ip_del_route (Uint32 flag)
188     RT_ENTRY*   ptr_rt;
190     /* Check if the flag is a network route being added? */
191     if (flag == FLG_RT_NETWORK)
192     {
193         /* Network route is being deleted. */
194         ptr_rt = &rt_table[0];
195     }
196     else
197     {
198         if (flag == FLG_RT_DEFAULT)
199         {
200             /* Default route is being deleted. */
201             ptr_rt = &rt_table[0];
202         }
203         else
204         {
205             /* Invalid Flag combination passed. */
206             return;
207         }           
208     }
209     
210     /* Simply reset all the fields */
211     netMemset ((void *)ptr_rt, 0, sizeof(RT_ENTRY));
212     return;
215 /**
216  *  @b Description
217  *  @n  
218  *       The function computes the IP checksum. The computed checksum
219  *       is populated in the IP header.
220  *
221  *  @param[in]  ptr_iphdr
222  *      This is the pointer to the IPv4 header for which the checksum
223  *      is computed.
224  *
225  *  @retval
226  *      Not Applicable.
227  */
228 static void ip_checksum(IPHDR *ptr_iphdr)
230     Int32   tmp1;
231     Uint16  *pw;
232     Uint32  TSum = 0;
234     /* Get header size in 4 byte chunks */
235     tmp1 = ptr_iphdr->VerLen & 0xF;
237     /* Checksum field is NULL in checksum calculations */
238     ptr_iphdr->Checksum = 0;
240     /* Checksum the header */
241     pw = (Uint16 *)ptr_iphdr;
242     do {
243         TSum += (Uint32)*pw++;
244         TSum += (Uint32)*pw++;
245     } while( --tmp1 );
246     TSum = (TSum&0xFFFF) + (TSum>>16);
247     TSum = (TSum&0xFFFF) + (TSum>>16);
248     TSum = ~TSum;
250     /* Note checksum is Net/Host byte order independent */
251     ptr_iphdr->Checksum = (Uint16)TSum;
252     return;
255 /**
256  *  @b Description
257  *  @n  
258  *       The function handles the processing of IPv4 packets.
259  *
260  *  @param[in]  ptr_iphdr
261  *      This is the pointer to the IPv4 header.
262  *  @param[in]  num_bytes
263  *      This is the total number of bytes which includes the IPv4 header 
264  *      and data payload.
265  *
266  *  @retval
267  *      Success -   0
268  *  @retval
269  *      Error   -   <0
270  */
271 Int32 ip_receive (IPHDR* ptr_iphdr, Int32 num_bytes)
273     Uint32  checksum;
275     /* Basic IPv4 Packet Validations: Ensure that this is an IPv4 packet. */
276     if ((ptr_iphdr->VerLen & 0xF0) != 0x40)
277         return -1;
279     /* Validate the length of the received packet; it cannot be greater 
280      * than the total length of the received packet. */
281     if (ntohs(ptr_iphdr->TotalLen) > num_bytes)
282         return -1;
284     /* Checksum validation. */
285     checksum = ptr_iphdr->Checksum;
286     if (checksum == 0xFFFF )
287         checksum = 0;
288     ip_checksum (ptr_iphdr);
289     if (checksum != ptr_iphdr->Checksum )
290         return -1;
292     /* We dont handle any IP option processing. 
293      *  Thus if the IP header length is greater than 20 bytes the packet is dropped. */
294     if (((ptr_iphdr->VerLen & 0xF) << 2) != IPHDR_SIZE)
295         return -1;
297     /* We accept only the following packets:-
298      *  a) Destination Address is the address of the NET Boot module. 
299      *  b) Destination Address is the a special 255.255.255.255 address for BOOTP Reply*/
300     if (netmcb.net_device.use_bootp_server_ip == 0)
301         if ((ptr_iphdr->IPDst != netmcb.net_device.ip_address) && (ptr_iphdr->IPDst != 0xFFFFFFFF))
302                 return -1;
304     /* Pass the packet to the layer4 receive handlers. */
305     switch (ptr_iphdr->Protocol)
306     {
307 #ifdef INCLUDE_BLF_NET_ICMP
308         case IPPROTO_ICMP:
309         {
310             icmp_receive (ptr_iphdr);
311             break;
312         }
313 #endif /* INCLUDE_BLF_NET_ICMP */
314         case IPPROTO_UDP:
315         {
316             /* UDP Packet. */
317             if (udp_receive (ptr_iphdr) < 0)
318                 net_stats.rx_udp_dropped++;
319             break;
320         }
321         default:
322         {
323             /* No other protocol is handled. */
324             return -1;
325         }
326     }
328     /* Packet has been successfully processed at the IP layer. */
329     return 0;
332 /**
333  *  @b Description
334  *  @n  
335  *       The function is called from the layer4 protocol to send 
336  *       out an IPv4 packet.
337  *
338  *  @param[in]  ptr_iphdr
339  *      This is the pointer to the IPv4 header + payload which includes
340  *      the layer4 header and actual data payload.
341  *      The layer4 protocol is supposed to populate the following IPv4 fields:-
342  *          - Protocol
343  *          - Destination IP
344  *      The rest of the fields in the IPv4 header are populated by this function.
345  *
346  *  @param[in]  size
347  *      This is the total number of bytes which includes the layer4 header
348  *      and data payload and the IPv4 header.
349  *
350  *  @retval
351  *      Not Applicable.
352  */
353 void ip_send (IPHDR* ptr_iphdr, Uint16 size)
355     RT_ENTRY* ptr_rt;
356     IPN       next_hop_address;
358     /* Special Case: If the IP Address of the packet is 255.255.255.255 
359      * we dont need to check the routing table. */
360     if (ptr_iphdr->IPDst != 0xFFFFFFFF)
361     {
362         /* Lookup the routing table for a routing entry. */
363         ptr_rt = ip_lookup_route (ptr_iphdr->IPDst);
364         if (ptr_rt == NULL)
365         {
366             /* There is no route which exists to send the packet. Drop it! */
367             net_free_tx_packet ((Uint8 *)ptr_iphdr);
368             return;
369         }
371         /* Control comes here indicating that a route exists and the packet
372          * can be sent out. There are 2 types of routes in the system:-
373          *  a) Network Routes which are directly attached and in this case
374          *     the next hop ip address is the same as the destination IP address
375          *  b) Default Routes which is the address of the default gateway to which
376          *     we need to send the packet since the destination network is not
377          *     directly connected.
378          * So here we determine the next hop address based on the route type. */
379         if (ptr_rt->flags == FLG_RT_NETWORK)
380             next_hop_address = ptr_iphdr->IPDst;
381         else
382             next_hop_address = ptr_rt->next_hop;
383     }
384     else
385     {
386         /* This is a BOOTP request being sent out to 255.255.255.255. Set the
387          * next hop address to be the same. */
388         next_hop_address = ptr_iphdr->IPDst;
389     }
391     /* Ensure all the fields in the IPv4 header are populated correctly */
392     ptr_iphdr->VerLen   = 0x45;
393     ptr_iphdr->Tos      = 0;
394     ptr_iphdr->Id       = netmcb.ipID++;
395     ptr_iphdr->FlagOff  = 0;
396     ptr_iphdr->Ttl      = 64;
397     ptr_iphdr->TotalLen = htons(size);
398     ptr_iphdr->IPSrc    = netmcb.net_device.ip_address;
400     /* Here we recompute the IP Checksum. */
401     ip_checksum (ptr_iphdr);
403     /* Layer2 resolution is done on the Next hop address. */
404     arp_resolve (next_hop_address, ptr_iphdr, size);
405     return;
408 /**
409  *  @b Description
410  *  @n  
411  *       The function initializes the IP Module in the NET Boot module.
412  *
413  *  @retval
414  *      Not Applicable
415  */
416 void ip_init (void)
418     /* Reset the routing table */
419     netMemset (&rt_table, 0, sizeof(rt_table));
420     return;