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 * \par
12 */
13 #include "types.h"
14 #include "iblloc.h"
15 #include "net.h"
16 #include "netif.h"
17 #include <string.h>
18 #include "net_osal.h"
20 /**********************************************************************
21 *************************** LOCAL Structures *************************
22 **********************************************************************/
24 /**
25 * @brief
26 * The structure describes the ARP Cache
27 *
28 * @details
29 * This describes the ARP Cache which keeps track of the IPv4 address and
30 * the corresponding Layer2 MAC Address.
31 */
32 typedef struct NET_ARP_CACHE
33 {
34 /**
35 * @brief This is the MAC Address i.e. Layer2 address matching the
36 * corresponding IP Address.
37 */
38 Uint8 mac_address[6];
40 /**
41 * @brief This is the IP Address stored in network order.
42 */
43 IPN ip_address;
45 /**
46 * @brief When the upper layers tries to send a packet and
47 * the MAC Address is not resolved; packets are stored in this
48 * temporary area. The ARP stack sends out an ARP request packet
49 * and resolves the IP address. Once the resolution is done pending
50 * packets are transmitted.
51 */
52 Uint8 pending_packet[NET_MAX_MTU];
54 /**
55 * @brief This is the length of the pending packet. A value of 0
56 * indicates that there is no pending packet in the ARP cache.
57 */
58 Uint16 pending_packet_len;
59 }NET_ARP_CACHE;
61 /**********************************************************************
62 *************************** GLOBAL Variables *************************
63 **********************************************************************/
65 /**
66 * @brief This is the ARP cache; which keeps track of the IP Address to
67 * MAC Address mapping.
68 */
69 NET_ARP_CACHE net_arp_cache;
71 /**********************************************************************
72 **************************** ARP Functions ***************************
73 **********************************************************************/
75 /**
76 * @b Description
77 * @n
78 * This function is called by the IP Layer to resolve the layer3
79 * address to a layer2 MAC address. The function checks the ARP cache
80 * for a match but if no entry exists then the functions sends out
81 * an ARP request and it places this packet into the pending queue.
82 *
83 * @param[in] dst_ip
84 * This is the destination IP address of the packet.
85 * @param[in] ptr_iphdr
86 * This is the pointer to the IP header
87 * @param[in] l3_pkt_size
88 * This is the size of the packet (including the IP Header)
89 *
90 * @retval
91 * Not Applicable.
92 */
93 void arp_resolve (IPN dst_ip, IPHDR* ptr_iphdr, Uint16 l3_pkt_size)
94 {
95 ARPHDR* ptr_arphdr;
96 ETHHDR* ptr_ethhdr;
97 Uint8 BroadcastMac[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
99 /* Special Case: Are we sending the packet to 255.255.255.255? */
100 if (dst_ip == (IPN)0xFFFFFFFF)
101 {
102 /* YES. This implies that the destination MAC Address in the packet is the Broadcast address
103 * We dont need to lookup the cache. */
104 ptr_ethhdr = net_create_eth_header ((Uint8 *)ptr_iphdr, (void *)&BroadcastMac[0], 0x800);
105 if (ptr_ethhdr == NULL)
106 return;
108 /* We now have a completed Ethernet packet; send it across. */
109 net_send_packet (ptr_ethhdr, sizeof(ETHHDR) + l3_pkt_size);
111 /* The packet has been transmitted and we can clean it up now. */
112 net_free_tx_packet ((Uint8 *)ptr_iphdr);
113 return;
114 }
116 /* Check if the destination IP Address matches the ARP cache */
117 if (net_arp_cache.ip_address == dst_ip)
118 {
119 /* Make sure the MAC Address in the CACHE has been resolved i.e. Non-Zero. */
120 if ( (net_arp_cache.mac_address[0] != 0x00) || (net_arp_cache.mac_address[1] != 0x00) ||
121 (net_arp_cache.mac_address[2] != 0x00) || (net_arp_cache.mac_address[3] != 0x00) ||
122 (net_arp_cache.mac_address[4] != 0x00) || (net_arp_cache.mac_address[5] != 0x00) )
123 {
124 /* Perfect; the MAC Address is already resolved.
125 * We can simply use the ARP CACHE MAC address to create the layer2 header. */
126 ptr_ethhdr = net_create_eth_header ((Uint8 *)ptr_iphdr, (void *)&net_arp_cache.mac_address[0], 0x800);
127 if (ptr_ethhdr == NULL)
128 return;
130 /* We now have a completed Ethernet packet; send it across. */
131 net_send_packet (ptr_ethhdr, sizeof(ETHHDR) + l3_pkt_size);
133 /* The packet has been transmitted and we can clean it up now. */
134 net_free_tx_packet ((Uint8 *)ptr_iphdr);
135 return;
136 }
137 }
139 /* Initialize the ARP Cache: The cache did not have information for the resolution to work
140 * Reset the cache and start again. */
141 netMemset ((void *)&net_arp_cache, 0, sizeof(NET_ARP_CACHE));
143 /* Populate the ARP Cache */
144 net_arp_cache.ip_address = dst_ip;
145 net_arp_cache.pending_packet_len = l3_pkt_size;
146 netMemcpy ((void *)&net_arp_cache.pending_packet[0], (void *)ptr_iphdr, l3_pkt_size);
148 /* Free up the packet now; we have already stored it in the ARP cache. */
149 net_free_tx_packet ((Uint8 *)ptr_iphdr);
151 /* Allocate a new packet to send out the ARP request. */
152 ptr_arphdr = (ARPHDR *)net_alloc_tx_packet(sizeof(ARPHDR));
153 if (ptr_arphdr == NULL)
154 return;
156 /* Populate the ARP Header. */
157 ptr_arphdr->HardType = htons(0x1);
158 ptr_arphdr->ProtocolType = htons(0x800);
159 ptr_arphdr->HardSize = 0x6;
160 ptr_arphdr->ProtocolSize = 0x4;
161 ptr_arphdr->Op = htons(0x1);
163 /* Populate the Source IP/MAC Address */
164 netMemcpy ((void *)&ptr_arphdr->SrcAddr[0], (void *)&netmcb.net_device.mac_address[0], 6);
165 netMemcpy ((void *)&ptr_arphdr->IPSrc[0], (void *)&netmcb.net_device.ip_address, 4);
167 /* Populate the Target IP/MAC Address: This is set to 0 since the cache has been reset above. */
168 netMemcpy ((void *)&ptr_arphdr->DstAddr[0], (void *)&net_arp_cache.mac_address[0], 6);
169 netMemcpy ((void *)&ptr_arphdr->IPDst[0], (void *)&dst_ip, 4);
171 /* Create the Ethernet header. */
172 ptr_ethhdr = net_create_eth_header ((Uint8 *)ptr_arphdr, &BroadcastMac[0], 0x806);
173 if (ptr_ethhdr == NULL)
174 return;
176 /* Send the packet out. */
177 net_send_packet (ptr_ethhdr, sizeof(ETHHDR) + sizeof(ARPHDR));
179 /* The packet has been transmitted and we can clean it up now. */
180 net_free_tx_packet ((Uint8 *)ptr_arphdr);
181 return;
182 }
184 /**
185 * @b Description
186 * @n
187 * The function handles the reception and processing of ARP packets.
188 *
189 * @param[in] ptr_arphdr
190 * This is the pointer to the received ARP header.
191 * @param[in] num_bytes
192 * This is the size of the ARP packet.
193 *
194 * @retval
195 * Success - 0
196 * @retval
197 * Error - <0
198 */
199 Int32 arp_receive (ARPHDR* ptr_arphdr, Int32 num_bytes)
200 {
201 Uint32 IPAddress;
202 Uint8* ptr_pending_pkt;
203 ETHHDR* ptr_ethhdr;
205 /* Extract the intended target and convert it to host format. */
206 IPAddress = READ32(ptr_arphdr->IPDst);
208 /* Ensure that the packet has not been looped back and we received our own frame. */
209 if ((ptr_arphdr->SrcAddr[0] == netmcb.net_device.mac_address[0]) &&
210 (ptr_arphdr->SrcAddr[1] == netmcb.net_device.mac_address[1]) &&
211 (ptr_arphdr->SrcAddr[2] == netmcb.net_device.mac_address[2]) &&
212 (ptr_arphdr->SrcAddr[3] == netmcb.net_device.mac_address[3]) &&
213 (ptr_arphdr->SrcAddr[4] == netmcb.net_device.mac_address[4]) &&
214 (ptr_arphdr->SrcAddr[5] == netmcb.net_device.mac_address[5]))
215 {
216 /* We received our own frame; ignore this. */
217 return -1;
218 }
220 /* Check if the packet is meant for us? If it not meant for us we drop the packet. */
221 if (IPAddress != netmcb.net_device.ip_address)
222 return -1;
224 /* The ARP packet was meant for us; we need to update the ARP cache with the request. */
225 net_arp_cache.ip_address = READ32(ptr_arphdr->IPSrc);
226 netMemcpy ((void *)&net_arp_cache.mac_address[0], (void *)&ptr_arphdr->SrcAddr[0], 6);
228 /* Check if the packet is an ARP request? */
229 if (ptr_arphdr->Op == htons(0x1))
230 {
231 /* YES. We need to send out an ARP Reply; so create the packet.
232 * Ensure that the Layer3 headers are aligned on the 4 byte boundary
233 * and yet we have sufficient space for the Ethernet header. */
234 ptr_arphdr = (ARPHDR *)net_alloc_tx_packet(sizeof(ARPHDR));
235 if (ptr_arphdr == NULL)
236 return -1;
238 /* Populate the ARP Header. */
239 ptr_arphdr->HardType = htons(0x1);
240 ptr_arphdr->ProtocolType = htons(0x800);
241 ptr_arphdr->HardSize = 0x6;
242 ptr_arphdr->ProtocolSize = 0x4;
243 ptr_arphdr->Op = htons(0x2);
245 /* Populate the Source IP/MAC Address in the ARP Header */
246 netMemcpy ((void *)&ptr_arphdr->SrcAddr[0], (void *)&netmcb.net_device.mac_address[0], 6);
247 netMemcpy ((void *)&ptr_arphdr->IPSrc[0], (void *)&netmcb.net_device.ip_address, 4);
249 /* Populate the Target IP/MAC Address in the ARP Header */
250 netMemcpy ((void *)&ptr_arphdr->DstAddr[0], (void *)&net_arp_cache.mac_address[0], 6);
251 netMemcpy ((void *)&ptr_arphdr->IPDst[0], (void *)&net_arp_cache.ip_address, 4);
253 /* Create the Ethernet header. */
254 ptr_ethhdr = net_create_eth_header ((Uint8 *)ptr_arphdr, &net_arp_cache.mac_address[0], 0x806);
255 if (ptr_ethhdr == NULL)
256 return -1;
258 /* Send the packet out. */
259 net_send_packet (ptr_ethhdr, sizeof(ETHHDR) + sizeof(ARPHDR));
261 /* The packet has been transmitted and we can clean it up now. */
262 net_free_tx_packet ((Uint8 *)ptr_arphdr);
263 }
265 /* Check if there are any packet awaiting resolution? */
266 if (net_arp_cache.pending_packet_len != 0)
267 {
268 /* There was a packet in the ARP cache which was awaiting resolution.
269 * We need to send out the packet now. */
270 ptr_pending_pkt = net_alloc_tx_packet(net_arp_cache.pending_packet_len);
271 if (ptr_pending_pkt == NULL)
272 return -1;
274 /* We now copy the contents of this packet from the ARP cache */
275 netMemcpy ((void *)ptr_pending_pkt, (void *)&net_arp_cache.pending_packet[0],
276 net_arp_cache.pending_packet_len);
278 /* We create the Ethernet header.
279 * Only IPv4 packets await resolution. */
280 ptr_ethhdr = net_create_eth_header ((Uint8 *)ptr_pending_pkt, &net_arp_cache.mac_address[0], 0x800);
281 if (ptr_ethhdr == NULL)
282 return -1;
284 /* Send the packet out. */
285 net_send_packet (ptr_ethhdr, sizeof(ETHHDR) + net_arp_cache.pending_packet_len);
287 /* The pending packet in the cache has been sent out. */
288 net_arp_cache.pending_packet_len = 0;
290 /* The packet has been transmitted and can be cleaned up. */
291 net_free_tx_packet (ptr_pending_pkt);
292 }
294 /* ARP Packet has been successfully processed. */
295 return 0;
296 }
298 /**
299 * @b Description
300 * @n
301 * The function initializes the ARP Module in the NET Boot module.
302 *
303 * @retval
304 * Not Applicable
305 */
306 void arp_init (void)
307 {
308 netMemset (&net_arp_cache, 0, sizeof(NET_ARP_CACHE));
309 return;
310 }