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)
122 {
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;
210 }
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)
228 {
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;
324 }
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)
335 {
336 netMemset (&net_arp_cache, 0, sizeof(NET_ARP_CACHE));
337 return;
338 }