source: edk_user_repository/WARP/sw_services/WARPxilnet_v3_00_a/src/xilnet_eth.c

Last change on this file was 1749, checked in by chunter, 12 years ago

Updated copyright information and improved handling of broadcast IP address

File size: 10.2 KB
Line 
1////////////////////////////////////////////////////////////////////////////////
2// Copyright (c) 2004 Xilinx, Inc.  All rights reserved.
3//
4// Xilinx, Inc.
5// XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
6// COURTESY TO YOU.  BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
7// ONE POSSIBLE   IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
8// STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
9// IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
10// FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
11// XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
12// THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
13// ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
14// FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
15// AND FITNESS FOR A PARTICULAR PURPOSE.
16//
17// File   : eth.c
18// Date   : 2002, March 20.
19// Author : Sathya Thammanur
20// Company: Xilinx
21// Group  : Emerging Software Technologies
22//
23// Summary:
24// Ethernet layer specific functions
25//
26// $Id: eth.c,v 1.2.8.6 2005/11/15 23:41:10 salindac Exp $
27//
28////////////////////////////////////////////////////////////////////////////////
29
30////////////////////////////////////////////////////////////////////////////////
31// see copyright.txt for Rice University/Mango Communications modifications
32////////////////////////////////////////////////////////////////////////////////
33
34#include <string.h>
35#include <xilnet_config.h>
36#include <xilnet_xilsock.h>
37#ifdef _CONFIG_TEMAC_
38#include "xlltemac.h"
39#include "xllfifo.h"
40#include "xdmacentral.h"
41#include "xdmacentral_l.h"
42#endif
43#include "xio.h"
44#include "stdio.h"
45struct xilnet_hw_addr_table xilnet_hw_tbl[HW_ADDR_TBL_ENTRIES];
46unsigned char ishwaddrinit = 0;
47static unsigned long long curr_age = 0;
48
49
50/*
51 * initialize xilnet hardware address
52 */
53void xilnet_eth_init_hw_addr(unsigned char* addr) {
54   int k = 0;
55   int j;
56   int sum = 0;
57   int val = 0;
58   
59   for (j = 0; j < 5; j++) {
60   
61      // parse input for colon separated hw address
62      while(addr[k] != ':') {
63         if (addr[k] >= 'a' && addr[k] <= 'f') 
64            val = addr[k] - 'a' + 10;
65         else if (addr[k] >= 'A' && addr[k] <= 'F')
66            val = addr[k] - 'A' + 10;
67         else
68            val = addr[k] - '0';
69         sum = sum * 16 + val;
70         k++;
71      }
72   
73      k++; // move over the colon
74      mb_hw_addr[j] = (unsigned char) sum;
75      sum = 0;   
76   }
77   
78   // read last byte of hw address
79   while (addr[k] != '\0') {
80      if (addr[k] >= 'a' && addr[k] <= 'f') 
81         val = addr[k] - 'a' + 10;
82      else if (addr[k] >= 'A' && addr[k] <= 'F')
83         val = addr[k] - 'A' + 10;
84      else
85         val = addr[k] - '0';
86      sum = sum * 16 + val;
87      k++;
88   } 
89   mb_hw_addr[5] = (unsigned char) sum;
90}
91
92#ifdef _CONFIG_TEMAC_
93inline void waitForDMA()
94{
95
96    int RegValue;
97
98    //Wait until the DMA transfer is done by checking the Status register
99    do {RegValue = XDmaCentral_GetStatus((XDmaCentral *)DMA_CENTRAL_INST);}
100    while ((RegValue & XDMC_DMASR_BUSY_MASK) == XDMC_DMASR_BUSY_MASK);
101
102    return;
103}
104#endif
105
106/*
107 * Receive frame
108 */
109int xilnet_eth_recv_frame(unsigned char *buf, int len) {
110
111   struct xilnet_eth_hdr *eth;
112   //unsigned short RxPktLength;
113   int size = -1;
114   void* pktBufPtr;
115
116   pktBufPtr = buf;
117   
118   //device specific routine for getting a frame
119
120#ifdef _CONFIG_EMACLITE_
121   size = XEmacLite_RecvFrame(MYMAC_BASEADDR, buf);
122#else
123#ifdef _CONFIG_TEMAC_
124   if(XLlFifo_IsRxEmpty((XLlFifo *)FIFO_INST))
125    {
126        size=-1;
127    }
128    else
129    {
130        if(XLlFifo_RxOccupancy((XLlFifo *)FIFO_INST))
131        {
132            waitForDMA();
133             //Set DMA to non-increment source, increment dest addresses
134             XDmaCentral_SetControl((XDmaCentral *)DMA_CENTRAL_INST, XDMC_DMACR_DEST_INCR_MASK);
135            size = XLlFifo_RxGetLen((XLlFifo *)FIFO_INST);
136            XDmaCentral_Transfer((XDmaCentral *)DMA_CENTRAL_INST,
137                                (u8 *)(((XLlFifo *)FIFO_INST)->BaseAddress+XLLF_RDFD_OFFSET),
138                                (u8 *)pktBufPtr,
139                                size);
140        }
141    }
142#endif
143#endif
144
145#ifdef _DEBUG_
146    xil_printf("Ethernet Recvd Frame of size %d...\r\n", size);
147    xil_printf("src : %d%d%d%d%d%d...\r\n", buf[0], buf[1],buf[2],buf[3],buf[4],buf[5]);
148    xil_printf("dst : %d%d%d%d%d%d...\r\n", buf[6], buf[7],buf[8],buf[9],buf[10],buf[11]);
149    xil_printf("type : %d%d...\r\n", buf[12], buf[13]);
150#endif
151
152//}
153
154 
155  // Strip off the FCS(or CRC) from the received frame
156  //buf[size-1] = 0;
157  //buf[size-2] = 0;
158  //buf[size-3] = 0;
159  //buf[size-4] = 0;
160  size -= 4;
161 
162
163  if(size>0){
164  eth = (struct xilnet_eth_hdr*) buf; 
165   
166  switch (eth->type) {
167  case ETH_PROTO_IP:
168     return (xilnet_ip(buf, size));
169  case ETH_PROTO_ARP:
170     return (xilnet_arp(buf, size));
171  default:
172#ifdef _DEBUG_
173     xil_printf("Unknown protocol %x...\r\n", eth->type);
174#endif
175     break;
176  }
177  }
178  return -1;
179}
180
181
182/*
183 * Send frame to peer ip addr, peer hw addr
184 */
185 
186
187int xilnet_eth_send_frame(unsigned char *pkt, int len, unsigned char *dip_addr,
188                          void *dhw_addr, unsigned short type)
189{
190   int i;
191   int hw_tbl_index = 0;
192   
193   for (i = 0; i < ETH_ADDR_LEN; i++) {
194      ((struct xilnet_eth_hdr*)pkt)->src_addr[i] = mb_hw_addr[i];
195   }           
196   
197   if (dhw_addr) 
198      memcpy(((struct xilnet_eth_hdr*)pkt)->dest_addr, dhw_addr, ETH_ADDR_LEN);
199   else {
200      // find the hw tbl entry index corr to dip_addr
201      hw_tbl_index = xilnet_eth_get_hw_addr(dip_addr);
202     
203      for (i = 0; i < ETH_ADDR_LEN; i++) {
204         ((struct xilnet_eth_hdr*)pkt)->dest_addr[i] = xilnet_hw_tbl[hw_tbl_index].hw_addr[i];
205      }
206   }
207   ((struct xilnet_eth_hdr*)pkt)->type = type;
208   
209   // pad the ethernet frame if < 60 bytes
210   if (len < 60) { 
211      for(i = len; i < ETH_MIN_FRAME_LEN; i++) {
212         pkt[i] = 0;
213      }
214      len = ETH_MIN_FRAME_LEN;
215   }
216    // Write to MAC
217#ifdef _CONFIG_EMACLITE_
218   XEmacLite_SendFrame(MYMAC_BASEADDR, pkt, len);
219#else
220#ifdef _CONFIG_TEMAC_
221    waitForDMA();
222   //Set DMA to increment src, non-increment dest addresses
223   XDmaCentral_SetControl((XDmaCentral *)DMA_CENTRAL_INST, XDMC_DMACR_SOURCE_INCR_MASK);
224   //Transfer the packet into the LLFIFO
225   XDmaCentral_Transfer((XDmaCentral *)DMA_CENTRAL_INST,
226                            (u8 *)(pkt),
227                            (u8 *)(((XLlFifo *)FIFO_INST)->BaseAddress + XLLF_TDFD_OFFSET),
228                            len);
229   waitForDMA();
230   //Write the length to the LL_FIFO; this write initiates the TEMAC transmission
231  //    XIo_Out32( (FIFO_BASEADDR + XLLF_TLF_OFFSET), len);
232   XLlFifo_TxSetLen((XLlFifo *)FIFO_INST, len);
233   
234    //xil_printf("xilnet_eth_send_frame(), len = %d \r\n",len);
235#endif
236#endif
237
238 
239   return len;
240}
241
242
243/*
244 * Update Hardware Address Table
245 */
246
247void xilnet_eth_update_hw_tbl(unsigned char *buf, int proto) {
248   
249   unsigned char ip[IP_VERSION];
250   unsigned char hw[ETH_ADDR_LEN];
251   int i, j;
252   //struct xilnet_eth_hdr *eth = (struct xilnet_eth_hdr*) buf;
253
254   // Update the current age
255   curr_age++;
256   
257   // get hw addr
258   for (i = 0; i < ETH_ADDR_LEN; i++) {
259      hw[i] = ((struct xilnet_eth_hdr*)buf)->src_addr[i];
260   }     
261
262   // get ip addr
263   switch (proto) {
264   case ETH_PROTO_ARP:
265      for (i = 0; i < IP_VERSION; i++) {
266         ip[i] = (buf+ETH_HDR_LEN)[ARP_SIP_OFFSET+i];
267      }
268      break;
269   case ETH_PROTO_IP:
270      for (i = 0; i < IP_VERSION; i++) {
271         ip[i] = (buf+ETH_HDR_LEN)[IP_SADDR_BASE+i];
272      }
273      break;
274   }
275
276   // update the hw addr table
277   
278   for (i = 0; i < HW_ADDR_TBL_ENTRIES; i++) {
279      if (xilnet_hw_tbl[i].flag) {
280         if ( (hw[0] == xilnet_hw_tbl[i].hw_addr[0]) &&
281              (hw[1] == xilnet_hw_tbl[i].hw_addr[1]) &&
282              (hw[2] == xilnet_hw_tbl[i].hw_addr[2]) &&
283              (hw[3] == xilnet_hw_tbl[i].hw_addr[3]) &&
284              (hw[4] == xilnet_hw_tbl[i].hw_addr[4]) &&
285              (hw[5] == xilnet_hw_tbl[i].hw_addr[5])
286              ) {
287            for (j = 0; j < IP_VERSION; j++)
288               xilnet_hw_tbl[i].ip_addr[j] = ip[j];;
289            xilnet_hw_tbl[i].flag = HW_ADDR_ENTRY_IS_TRUE;
290            xilnet_hw_tbl[i].age = curr_age;
291            return;
292         }
293      }
294   }
295   xilnet_add_hw_tbl_entry(ip, hw);
296}
297
298
299/*
300 * Add an entry into Hw Addr table
301 */
302
303void xilnet_add_hw_tbl_entry(unsigned char *ip, unsigned char *hw)
304{
305   int i, j;
306   
307   for (i = 0; i < HW_ADDR_TBL_ENTRIES; i++) {
308      if (!xilnet_hw_tbl[i].flag) {
309         for (j = 0; j < ETH_ADDR_LEN; j++) {
310            xilnet_hw_tbl[i].hw_addr[j] = hw[j];
311         }
312         for (j = 0; j < IP_VERSION; j++)  {
313            xilnet_hw_tbl[i].ip_addr[j] = ip[j];
314         }
315         xilnet_hw_tbl[i].flag = HW_ADDR_ENTRY_IS_TRUE;
316         xilnet_hw_tbl[i].age = curr_age;
317         return;
318      }
319   }
320   
321   // Find an old entry to be eliminated from hw tbl
322   i = xilnet_eth_find_old_entry();
323   for (j = 0; j < ETH_ADDR_LEN; j++) {
324      xilnet_hw_tbl[i].hw_addr[j] = hw[j];
325   }
326   for (j = 0; j < IP_VERSION; j++)  {
327      xilnet_hw_tbl[i].ip_addr[j] = ip[j];
328   }
329   xilnet_hw_tbl[i].flag = HW_ADDR_ENTRY_IS_TRUE;
330   xilnet_hw_tbl[i].age = curr_age;
331   
332}
333
334
335/*
336 * Get index into hw tbl for ip_addr
337 */
338
339int xilnet_eth_get_hw_addr(unsigned char *ip) {
340   
341   int i;
342   
343   for (i = 0; i < HW_ADDR_TBL_ENTRIES; i++) {
344      if (xilnet_hw_tbl[i].flag) 
345         if ( (ip[0] == xilnet_hw_tbl[i].ip_addr[0]) &&
346              (ip[1] == xilnet_hw_tbl[i].ip_addr[1]) &&
347              (ip[2] == xilnet_hw_tbl[i].ip_addr[2]) &&
348              (ip[3] == xilnet_hw_tbl[i].ip_addr[3]) ) {
349            return i;
350         }
351   }
352   
353   xil_printf("Hw Addr Not found for IP \r\n");
354   return -1;
355   
356}
357
358
359/* 
360 * Init the hw addr table
361 */
362
363void xilnet_eth_init_hw_addr_tbl() {
364   
365  int i;
366 
367  for (i = 0; i < HW_ADDR_TBL_ENTRIES; i++) {
368     xilnet_hw_tbl[i].flag = HW_ADDR_ENTRY_IS_FALSE;
369     xilnet_hw_tbl[i].age = 0;
370  }
371 
372  ishwaddrinit = 1;
373}
374
375/*
376 * Find the oldest entry in the Hw Table and
377 * return its index
378 */
379
380int xilnet_eth_find_old_entry()
381{
382   int i;
383   int oldest_age = 0;
384   int oldest = 0;
385   
386   for (i = 0; i < HW_ADDR_TBL_ENTRIES; i++) {
387     
388      if (curr_age - xilnet_hw_tbl[i].age > HW_ADDR_TBL_MAXAGE) {
389         oldest = i;
390         break;
391      }
392      else {
393         if (( curr_age - xilnet_hw_tbl[i].age) > oldest_age) {
394            oldest_age = curr_age - xilnet_hw_tbl[i].age;
395            oldest = i;
396         }
397      }
398   }
399   
400   return oldest;
401   
402}
Note: See TracBrowser for help on using the repository browser.