Initial c661x version
[keystone-rtos/ibl.git] / src / driver / eth / arp.c
1 /** 
2  *   @file  arp.c
3  *
4  *   @brief   
5  *      The file implements the NET Module ARP 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  *  \par
39  *
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"
48 /**********************************************************************
49  *************************** LOCAL Structures *************************
50  **********************************************************************/
52 /**
53  * @brief 
54  *  The structure describes the ARP Cache 
55  *
56  * @details
57  *  This describes the ARP Cache which keeps track of the IPv4 address and
58  *  the corresponding Layer2 MAC Address. 
59  */
60 typedef struct NET_ARP_CACHE
61 {
62     /**
63      * @brief   This is the MAC Address i.e. Layer2 address matching the
64      * corresponding IP Address.
65      */
66     Uint8       mac_address[6];
68     /**
69      * @brief   This is the IP Address stored in network order.
70      */
71     IPN         ip_address;
73     /**
74      * @brief   When the upper layers tries to send a packet and 
75      * the MAC Address is not resolved; packets are stored in this 
76      * temporary area. The ARP stack sends out an ARP request packet 
77      * and resolves the IP  address. Once the resolution is done pending 
78      * packets are transmitted. 
79      */
80     Uint8      pending_packet[NET_MAX_MTU];
82     /**
83      * @brief   This is the length of the pending packet. A value of 0
84      * indicates that there is no pending packet in the ARP cache.
85      */    
86     Uint16     pending_packet_len;
87 }NET_ARP_CACHE;
89 /**********************************************************************
90  *************************** GLOBAL Variables *************************
91  **********************************************************************/
93 /**
94  * @brief   This is the ARP cache; which keeps track of the IP Address to
95  * MAC Address mapping.
96  */
97 NET_ARP_CACHE      net_arp_cache;
99 /**********************************************************************
100  **************************** ARP Functions ***************************
101  **********************************************************************/
103 /**
104  *  @b Description
105  *  @n  
106  *      This function is called by the IP Layer to resolve the layer3 
107  *      address to a layer2 MAC address. The function checks the ARP cache
108  *      for a match but if no entry exists then the functions sends out
109  *      an ARP request and it places this packet into the pending queue.
110  *
111  *  @param[in]  dst_ip
112  *      This is the destination IP address of the packet.
113  *  @param[in]  ptr_iphdr
114  *      This is the pointer to the IP header
115  *  @param[in]  l3_pkt_size
116  *      This is the size of the packet (including the IP Header)
117  *
118  *  @retval
119  *      Not Applicable.
120  */
121 void arp_resolve (IPN dst_ip, IPHDR* ptr_iphdr, Uint16 l3_pkt_size)
123     ARPHDR* ptr_arphdr;
124     ETHHDR* ptr_ethhdr;
125     Uint8   BroadcastMac[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
127     /* Special Case: Are we sending the packet to 255.255.255.255? */
128     if (dst_ip == (IPN)0xFFFFFFFF)
129     {
130         /* YES. This implies that the destination MAC Address in the packet is the Broadcast address
131          * We dont need to lookup the cache. */
132         ptr_ethhdr = net_create_eth_header ((Uint8 *)ptr_iphdr, (void *)&BroadcastMac[0], 0x800);
133         if (ptr_ethhdr == NULL)
134             return;
136         /* We now have a completed Ethernet packet; send it across. */
137         net_send_packet (ptr_ethhdr, sizeof(ETHHDR) + l3_pkt_size);
139         /* The packet has been transmitted and we can clean it up now. */
140         net_free_tx_packet ((Uint8 *)ptr_iphdr);
141         return;            
142     }
144     /* Check if the destination IP Address matches the ARP cache */
145     if (net_arp_cache.ip_address == dst_ip)
146     {
147         /* Make sure the MAC Address in the CACHE has been resolved i.e. Non-Zero. */
148         if ( (net_arp_cache.mac_address[0] != 0x00) || (net_arp_cache.mac_address[1] != 0x00) ||
149              (net_arp_cache.mac_address[2] != 0x00) || (net_arp_cache.mac_address[3] != 0x00) || 
150              (net_arp_cache.mac_address[4] != 0x00) || (net_arp_cache.mac_address[5] != 0x00) )
151         {
152             /* Perfect; the MAC Address is already resolved. 
153              *  We can simply use the ARP CACHE MAC address to create the layer2 header. */
154             ptr_ethhdr = net_create_eth_header ((Uint8 *)ptr_iphdr, (void *)&net_arp_cache.mac_address[0], 0x800);
155             if (ptr_ethhdr == NULL)
156                 return;
158             /* We now have a completed Ethernet packet; send it across. */
159             net_send_packet (ptr_ethhdr, sizeof(ETHHDR) + l3_pkt_size);
161             /* The packet has been transmitted and we can clean it up now. */
162             net_free_tx_packet ((Uint8 *)ptr_iphdr);
163             return;
164         }
165     }
167     /* Initialize the ARP Cache: The cache did not have information for the resolution to work
168      * Reset the cache and start again.  */
169     netMemset ((void *)&net_arp_cache, 0, sizeof(NET_ARP_CACHE));
171     /* Populate the ARP Cache */
172     net_arp_cache.ip_address         = dst_ip;    
173     net_arp_cache.pending_packet_len = l3_pkt_size;
174     netMemcpy ((void *)&net_arp_cache.pending_packet[0], (void *)ptr_iphdr, l3_pkt_size);
176     /* Free up the packet now; we have already stored it in the ARP cache. */
177     net_free_tx_packet ((Uint8 *)ptr_iphdr);
179     /* Allocate a new packet to send out the ARP request. */
180     ptr_arphdr = (ARPHDR *)net_alloc_tx_packet(sizeof(ARPHDR));
181     if (ptr_arphdr == NULL)
182         return;
184     /* Populate the ARP Header. */
185     ptr_arphdr->HardType     = htons(0x1);
186     ptr_arphdr->ProtocolType = htons(0x800);
187     ptr_arphdr->HardSize     = 0x6;
188     ptr_arphdr->ProtocolSize = 0x4;
189     ptr_arphdr->Op           = htons(0x1);
191     /* Populate the Source IP/MAC Address */
192     netMemcpy ((void *)&ptr_arphdr->SrcAddr[0], (void *)&netmcb.net_device.mac_address[0], 6);
193     netMemcpy ((void *)&ptr_arphdr->IPSrc[0], (void *)&netmcb.net_device.ip_address, 4);
195     /* Populate the Target IP/MAC Address: This is set to 0 since the cache has been reset above. */
196     netMemcpy ((void *)&ptr_arphdr->DstAddr[0], (void *)&net_arp_cache.mac_address[0], 6);
197     netMemcpy ((void *)&ptr_arphdr->IPDst[0], (void *)&dst_ip, 4);
199     /* Create the Ethernet header. */
200     ptr_ethhdr = net_create_eth_header ((Uint8 *)ptr_arphdr, &BroadcastMac[0], 0x806);
201     if (ptr_ethhdr == NULL)
202         return;
204     /* Send the packet out. */
205     net_send_packet (ptr_ethhdr, sizeof(ETHHDR) + sizeof(ARPHDR));
207     /* The packet has been transmitted and we can clean it up now. */
208     net_free_tx_packet ((Uint8 *)ptr_arphdr);
209     return;
212 /**
213  *  @b Description
214  *  @n  
215  *       The function handles the reception and processing of ARP packets.
216  *
217  *  @param[in]  ptr_arphdr
218  *      This is the pointer to the received ARP header.
219  *  @param[in]  num_bytes
220  *      This is the size of the ARP packet.
221  *
222  *  @retval
223  *      Success -   0
224  *  @retval
225  *      Error   -   <0
226  */
227 Int32 arp_receive (ARPHDR* ptr_arphdr, Int32 num_bytes)
229     Uint32  IPAddress;
230     Uint8*  ptr_pending_pkt;
231     ETHHDR* ptr_ethhdr;
233     /* Extract the intended target and convert it to host format. */
234     IPAddress = READ32(ptr_arphdr->IPDst);
236     /* Ensure that the packet has not been looped back and we received our own frame. */
237     if ((ptr_arphdr->SrcAddr[0] == netmcb.net_device.mac_address[0]) &&
238         (ptr_arphdr->SrcAddr[1] == netmcb.net_device.mac_address[1]) &&
239         (ptr_arphdr->SrcAddr[2] == netmcb.net_device.mac_address[2]) &&
240         (ptr_arphdr->SrcAddr[3] == netmcb.net_device.mac_address[3]) &&
241         (ptr_arphdr->SrcAddr[4] == netmcb.net_device.mac_address[4]) &&
242         (ptr_arphdr->SrcAddr[5] == netmcb.net_device.mac_address[5]))
243     {
244         /* We received our own frame; ignore this. */
245         return -1;
246     }
248     /* Check if the packet is meant for us? If it not meant for us we drop the packet. */
249     if (IPAddress != netmcb.net_device.ip_address)
250         return -1;
252     /* The ARP packet was meant for us; we need to update the ARP cache with the request. */
253     net_arp_cache.ip_address = READ32(ptr_arphdr->IPSrc);
254     netMemcpy ((void *)&net_arp_cache.mac_address[0], (void *)&ptr_arphdr->SrcAddr[0], 6);
256     /* Check if the packet is an ARP request? */
257     if (ptr_arphdr->Op == htons(0x1))
258     {
259         /* YES. We need to send out an ARP Reply; so create the packet. 
260          *  Ensure that the Layer3 headers are aligned on the 4 byte boundary 
261          *  and yet we have sufficient space for the Ethernet header. */
262         ptr_arphdr = (ARPHDR *)net_alloc_tx_packet(sizeof(ARPHDR));
263         if (ptr_arphdr == NULL)
264             return -1;
266         /* Populate the ARP Header. */
267         ptr_arphdr->HardType     = htons(0x1);
268         ptr_arphdr->ProtocolType = htons(0x800);
269         ptr_arphdr->HardSize     = 0x6;
270         ptr_arphdr->ProtocolSize = 0x4;
271         ptr_arphdr->Op           = htons(0x2);
273         /* Populate the Source IP/MAC Address in the ARP Header */
274         netMemcpy ((void *)&ptr_arphdr->SrcAddr[0], (void *)&netmcb.net_device.mac_address[0], 6);
275         netMemcpy ((void *)&ptr_arphdr->IPSrc[0], (void *)&netmcb.net_device.ip_address, 4);
277         /* Populate the Target IP/MAC Address in the ARP Header */
278         netMemcpy ((void *)&ptr_arphdr->DstAddr[0], (void *)&net_arp_cache.mac_address[0], 6);
279         netMemcpy ((void *)&ptr_arphdr->IPDst[0], (void *)&net_arp_cache.ip_address, 4);
281         /* Create the Ethernet header. */
282         ptr_ethhdr = net_create_eth_header ((Uint8 *)ptr_arphdr, &net_arp_cache.mac_address[0], 0x806);
283         if (ptr_ethhdr == NULL)
284             return -1;
286         /* Send the packet out. */
287         net_send_packet (ptr_ethhdr, sizeof(ETHHDR) + sizeof(ARPHDR));
289         /* The packet has been transmitted and we can clean it up now. */
290         net_free_tx_packet ((Uint8 *)ptr_arphdr);
291     }
293     /* Check if there are any packet awaiting resolution? */
294     if (net_arp_cache.pending_packet_len != 0)
295     {
296         /* There was a packet in the ARP cache which was awaiting resolution. 
297          * We need to send out the packet now. */
298         ptr_pending_pkt = net_alloc_tx_packet(net_arp_cache.pending_packet_len);
299         if (ptr_pending_pkt == NULL)
300             return -1;
302         /* We now copy the contents of this packet from the ARP cache */
303         netMemcpy ((void *)ptr_pending_pkt, (void *)&net_arp_cache.pending_packet[0], 
304                     net_arp_cache.pending_packet_len);
306         /* We create the Ethernet header. 
307          *  Only IPv4 packets await resolution. */
308         ptr_ethhdr = net_create_eth_header ((Uint8 *)ptr_pending_pkt, &net_arp_cache.mac_address[0], 0x800);
309         if (ptr_ethhdr == NULL)
310             return -1;
312         /* Send the packet out. */
313         net_send_packet (ptr_ethhdr, sizeof(ETHHDR) + net_arp_cache.pending_packet_len);
315         /* The pending packet in the cache has been sent out. */
316         net_arp_cache.pending_packet_len = 0;
318         /* The packet has been transmitted and can be cleaned up. */
319         net_free_tx_packet (ptr_pending_pkt);
320     }
322     /* ARP Packet has been successfully processed. */
323     return 0;
326 /**
327  *  @b Description
328  *  @n  
329  *       The function initializes the ARP Module in the NET Boot module.
330  *
331  *  @retval
332  *      Not Applicable
333  */
334 void arp_init (void)
336     netMemset (&net_arp_cache, 0, sizeof(NET_ARP_CACHE));
337     return;