1195972f6Sopenharmony_ci#include "test_etharp.h"
2195972f6Sopenharmony_ci
3195972f6Sopenharmony_ci#include "lwip/udp.h"
4195972f6Sopenharmony_ci#include "lwip/etharp.h"
5195972f6Sopenharmony_ci#include "netif/ethernet.h"
6195972f6Sopenharmony_ci#include "lwip/stats.h"
7195972f6Sopenharmony_ci#include "lwip/prot/iana.h"
8195972f6Sopenharmony_ci
9195972f6Sopenharmony_ci#if !LWIP_STATS || !UDP_STATS || !MEMP_STATS || !ETHARP_STATS
10195972f6Sopenharmony_ci#error "This tests needs UDP-, MEMP- and ETHARP-statistics enabled"
11195972f6Sopenharmony_ci#endif
12195972f6Sopenharmony_ci#if !ETHARP_SUPPORT_STATIC_ENTRIES
13195972f6Sopenharmony_ci#error "This test needs ETHARP_SUPPORT_STATIC_ENTRIES enabled"
14195972f6Sopenharmony_ci#endif
15195972f6Sopenharmony_ci
16195972f6Sopenharmony_cistatic struct netif test_netif;
17195972f6Sopenharmony_cistatic ip4_addr_t test_ipaddr, test_netmask, test_gw;
18195972f6Sopenharmony_cistruct eth_addr test_ethaddr =  {{1,1,1,1,1,1}};
19195972f6Sopenharmony_cistruct eth_addr test_ethaddr2 = {{1,1,1,1,1,2}};
20195972f6Sopenharmony_cistruct eth_addr test_ethaddr3 = {{1,1,1,1,1,3}};
21195972f6Sopenharmony_cistruct eth_addr test_ethaddr4 = {{1,1,1,1,1,4}};
22195972f6Sopenharmony_cistatic int linkoutput_ctr;
23195972f6Sopenharmony_ci
24195972f6Sopenharmony_ci/* Helper functions */
25195972f6Sopenharmony_cistatic void
26195972f6Sopenharmony_cietharp_remove_all(void)
27195972f6Sopenharmony_ci{
28195972f6Sopenharmony_ci  int i;
29195972f6Sopenharmony_ci  /* call etharp_tmr often enough to have all entries cleaned */
30195972f6Sopenharmony_ci  for(i = 0; i < 0xff; i++) {
31195972f6Sopenharmony_ci    etharp_tmr();
32195972f6Sopenharmony_ci  }
33195972f6Sopenharmony_ci}
34195972f6Sopenharmony_ci
35195972f6Sopenharmony_cistatic err_t
36195972f6Sopenharmony_cidefault_netif_linkoutput(struct netif *netif, struct pbuf *p)
37195972f6Sopenharmony_ci{
38195972f6Sopenharmony_ci  fail_unless(netif == &test_netif);
39195972f6Sopenharmony_ci  fail_unless(p != NULL);
40195972f6Sopenharmony_ci  linkoutput_ctr++;
41195972f6Sopenharmony_ci  return ERR_OK;
42195972f6Sopenharmony_ci}
43195972f6Sopenharmony_ci
44195972f6Sopenharmony_cistatic err_t
45195972f6Sopenharmony_cidefault_netif_init(struct netif *netif)
46195972f6Sopenharmony_ci{
47195972f6Sopenharmony_ci  fail_unless(netif != NULL);
48195972f6Sopenharmony_ci  netif->linkoutput = default_netif_linkoutput;
49195972f6Sopenharmony_ci  netif->output = etharp_output;
50195972f6Sopenharmony_ci  netif->mtu = 1500;
51195972f6Sopenharmony_ci  netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
52195972f6Sopenharmony_ci  netif->hwaddr_len = ETHARP_HWADDR_LEN;
53195972f6Sopenharmony_ci  return ERR_OK;
54195972f6Sopenharmony_ci}
55195972f6Sopenharmony_ci
56195972f6Sopenharmony_cistatic void
57195972f6Sopenharmony_cidefault_netif_add(void)
58195972f6Sopenharmony_ci{
59195972f6Sopenharmony_ci  IP4_ADDR(&test_gw, 192,168,0,1);
60195972f6Sopenharmony_ci  IP4_ADDR(&test_ipaddr, 192,168,0,1);
61195972f6Sopenharmony_ci  IP4_ADDR(&test_netmask, 255,255,0,0);
62195972f6Sopenharmony_ci
63195972f6Sopenharmony_ci  fail_unless(netif_default == NULL);
64195972f6Sopenharmony_ci  netif_set_default(netif_add(&test_netif, &test_ipaddr, &test_netmask,
65195972f6Sopenharmony_ci                              &test_gw, NULL, default_netif_init, NULL));
66195972f6Sopenharmony_ci  netif_set_up(&test_netif);
67195972f6Sopenharmony_ci}
68195972f6Sopenharmony_ci
69195972f6Sopenharmony_cistatic void
70195972f6Sopenharmony_cidefault_netif_remove(void)
71195972f6Sopenharmony_ci{
72195972f6Sopenharmony_ci  fail_unless(netif_default == &test_netif);
73195972f6Sopenharmony_ci  netif_remove(&test_netif);
74195972f6Sopenharmony_ci}
75195972f6Sopenharmony_ci
76195972f6Sopenharmony_cistatic void
77195972f6Sopenharmony_cicreate_arp_response(ip4_addr_t *adr)
78195972f6Sopenharmony_ci{
79195972f6Sopenharmony_ci  int k;
80195972f6Sopenharmony_ci  struct eth_hdr *ethhdr;
81195972f6Sopenharmony_ci  struct etharp_hdr *etharphdr;
82195972f6Sopenharmony_ci  struct pbuf *p = pbuf_alloc(PBUF_RAW, sizeof(struct eth_hdr) + sizeof(struct etharp_hdr), PBUF_RAM);
83195972f6Sopenharmony_ci  if(p == NULL) {
84195972f6Sopenharmony_ci    FAIL_RET();
85195972f6Sopenharmony_ci  }
86195972f6Sopenharmony_ci  ethhdr = (struct eth_hdr*)p->payload;
87195972f6Sopenharmony_ci  etharphdr = (struct etharp_hdr*)(ethhdr + 1);
88195972f6Sopenharmony_ci
89195972f6Sopenharmony_ci  ethhdr->dest = test_ethaddr;
90195972f6Sopenharmony_ci  ethhdr->src = test_ethaddr2;
91195972f6Sopenharmony_ci  ethhdr->type = htons(ETHTYPE_ARP);
92195972f6Sopenharmony_ci
93195972f6Sopenharmony_ci  etharphdr->hwtype = htons(LWIP_IANA_HWTYPE_ETHERNET);
94195972f6Sopenharmony_ci  etharphdr->proto = htons(ETHTYPE_IP);
95195972f6Sopenharmony_ci  etharphdr->hwlen = ETHARP_HWADDR_LEN;
96195972f6Sopenharmony_ci  etharphdr->protolen = sizeof(ip4_addr_t);
97195972f6Sopenharmony_ci  etharphdr->opcode = htons(ARP_REPLY);
98195972f6Sopenharmony_ci
99195972f6Sopenharmony_ci  SMEMCPY(&etharphdr->sipaddr, adr, sizeof(ip4_addr_t));
100195972f6Sopenharmony_ci  SMEMCPY(&etharphdr->dipaddr, &test_ipaddr, sizeof(ip4_addr_t));
101195972f6Sopenharmony_ci
102195972f6Sopenharmony_ci  k = 6;
103195972f6Sopenharmony_ci  while(k > 0) {
104195972f6Sopenharmony_ci    k--;
105195972f6Sopenharmony_ci    /* Write the ARP MAC-Addresses */
106195972f6Sopenharmony_ci    etharphdr->shwaddr.addr[k] = test_ethaddr2.addr[k];
107195972f6Sopenharmony_ci    etharphdr->dhwaddr.addr[k] = test_ethaddr.addr[k];
108195972f6Sopenharmony_ci    /* Write the Ethernet MAC-Addresses */
109195972f6Sopenharmony_ci    ethhdr->dest.addr[k] = test_ethaddr.addr[k];
110195972f6Sopenharmony_ci    ethhdr->src.addr[k]  = test_ethaddr2.addr[k];
111195972f6Sopenharmony_ci  }
112195972f6Sopenharmony_ci
113195972f6Sopenharmony_ci  ethernet_input(p, &test_netif);
114195972f6Sopenharmony_ci}
115195972f6Sopenharmony_ci
116195972f6Sopenharmony_ci/* Setups/teardown functions */
117195972f6Sopenharmony_ci
118195972f6Sopenharmony_cistatic void
119195972f6Sopenharmony_cietharp_setup(void)
120195972f6Sopenharmony_ci{
121195972f6Sopenharmony_ci  etharp_remove_all();
122195972f6Sopenharmony_ci  default_netif_add();
123195972f6Sopenharmony_ci  lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
124195972f6Sopenharmony_ci}
125195972f6Sopenharmony_ci
126195972f6Sopenharmony_cistatic void
127195972f6Sopenharmony_cietharp_teardown(void)
128195972f6Sopenharmony_ci{
129195972f6Sopenharmony_ci  etharp_remove_all();
130195972f6Sopenharmony_ci  default_netif_remove();
131195972f6Sopenharmony_ci  lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
132195972f6Sopenharmony_ci}
133195972f6Sopenharmony_ci
134195972f6Sopenharmony_ci
135195972f6Sopenharmony_ci/* Test functions */
136195972f6Sopenharmony_ci
137195972f6Sopenharmony_ciSTART_TEST(test_etharp_table)
138195972f6Sopenharmony_ci{
139195972f6Sopenharmony_ci#if ETHARP_SUPPORT_STATIC_ENTRIES
140195972f6Sopenharmony_ci  err_t err;
141195972f6Sopenharmony_ci#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
142195972f6Sopenharmony_ci  ssize_t idx;
143195972f6Sopenharmony_ci  const ip4_addr_t *unused_ipaddr;
144195972f6Sopenharmony_ci  struct eth_addr *unused_ethaddr;
145195972f6Sopenharmony_ci  struct udp_pcb* pcb;
146195972f6Sopenharmony_ci  LWIP_UNUSED_ARG(_i);
147195972f6Sopenharmony_ci
148195972f6Sopenharmony_ci  if (netif_default != &test_netif) {
149195972f6Sopenharmony_ci    fail("This test needs a default netif");
150195972f6Sopenharmony_ci  }
151195972f6Sopenharmony_ci
152195972f6Sopenharmony_ci  linkoutput_ctr = 0;
153195972f6Sopenharmony_ci
154195972f6Sopenharmony_ci  pcb = udp_new();
155195972f6Sopenharmony_ci  fail_unless(pcb != NULL);
156195972f6Sopenharmony_ci  if (pcb != NULL) {
157195972f6Sopenharmony_ci    ip4_addr_t adrs[ARP_TABLE_SIZE + 2];
158195972f6Sopenharmony_ci    int i;
159195972f6Sopenharmony_ci    for(i = 0; i < ARP_TABLE_SIZE + 2; i++) {
160195972f6Sopenharmony_ci      IP4_ADDR(&adrs[i], 192,168,0,i+2);
161195972f6Sopenharmony_ci    }
162195972f6Sopenharmony_ci    /* fill ARP-table with dynamic entries */
163195972f6Sopenharmony_ci    for(i = 0; i < ARP_TABLE_SIZE; i++) {
164195972f6Sopenharmony_ci      struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 10, PBUF_RAM);
165195972f6Sopenharmony_ci      fail_unless(p != NULL);
166195972f6Sopenharmony_ci      if (p != NULL) {
167195972f6Sopenharmony_ci        err_t err2;
168195972f6Sopenharmony_ci        ip_addr_t dst;
169195972f6Sopenharmony_ci        ip_addr_copy_from_ip4(dst, adrs[i]);
170195972f6Sopenharmony_ci        err2 = udp_sendto(pcb, p, &dst, 123);
171195972f6Sopenharmony_ci        fail_unless(err2 == ERR_OK);
172195972f6Sopenharmony_ci        /* etharp request sent? */
173195972f6Sopenharmony_ci        fail_unless(linkoutput_ctr == (2*i) + 1);
174195972f6Sopenharmony_ci        pbuf_free(p);
175195972f6Sopenharmony_ci
176195972f6Sopenharmony_ci        /* create an ARP response */
177195972f6Sopenharmony_ci        create_arp_response(&adrs[i]);
178195972f6Sopenharmony_ci        /* queued UDP packet sent? */
179195972f6Sopenharmony_ci        fail_unless(linkoutput_ctr == (2*i) + 2);
180195972f6Sopenharmony_ci
181195972f6Sopenharmony_ci        idx = etharp_find_addr(NULL, &adrs[i], &unused_ethaddr, &unused_ipaddr);
182195972f6Sopenharmony_ci        fail_unless(idx == i);
183195972f6Sopenharmony_ci        etharp_tmr();
184195972f6Sopenharmony_ci      }
185195972f6Sopenharmony_ci    }
186195972f6Sopenharmony_ci    linkoutput_ctr = 0;
187195972f6Sopenharmony_ci#if ETHARP_SUPPORT_STATIC_ENTRIES
188195972f6Sopenharmony_ci    /* create one static entry */
189195972f6Sopenharmony_ci    err = etharp_add_static_entry(&adrs[ARP_TABLE_SIZE], &test_ethaddr3);
190195972f6Sopenharmony_ci    fail_unless(err == ERR_OK);
191195972f6Sopenharmony_ci    idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr);
192195972f6Sopenharmony_ci    fail_unless(idx == 0);
193195972f6Sopenharmony_ci    fail_unless(linkoutput_ctr == 0);
194195972f6Sopenharmony_ci#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
195195972f6Sopenharmony_ci
196195972f6Sopenharmony_ci    linkoutput_ctr = 0;
197195972f6Sopenharmony_ci    /* fill ARP-table with dynamic entries */
198195972f6Sopenharmony_ci    for(i = 0; i < ARP_TABLE_SIZE; i++) {
199195972f6Sopenharmony_ci      struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 10, PBUF_RAM);
200195972f6Sopenharmony_ci      fail_unless(p != NULL);
201195972f6Sopenharmony_ci      if (p != NULL) {
202195972f6Sopenharmony_ci        err_t err2;
203195972f6Sopenharmony_ci        ip_addr_t dst;
204195972f6Sopenharmony_ci        ip_addr_copy_from_ip4(dst, adrs[i]);
205195972f6Sopenharmony_ci        err2 = udp_sendto(pcb, p, &dst, 123);
206195972f6Sopenharmony_ci        fail_unless(err2 == ERR_OK);
207195972f6Sopenharmony_ci        /* etharp request sent? */
208195972f6Sopenharmony_ci        fail_unless(linkoutput_ctr == (2*i) + 1);
209195972f6Sopenharmony_ci        pbuf_free(p);
210195972f6Sopenharmony_ci
211195972f6Sopenharmony_ci        /* create an ARP response */
212195972f6Sopenharmony_ci        create_arp_response(&adrs[i]);
213195972f6Sopenharmony_ci        /* queued UDP packet sent? */
214195972f6Sopenharmony_ci        fail_unless(linkoutput_ctr == (2*i) + 2);
215195972f6Sopenharmony_ci
216195972f6Sopenharmony_ci        idx = etharp_find_addr(NULL, &adrs[i], &unused_ethaddr, &unused_ipaddr);
217195972f6Sopenharmony_ci        if (i < ARP_TABLE_SIZE - 1) {
218195972f6Sopenharmony_ci          fail_unless(idx == i+1);
219195972f6Sopenharmony_ci        } else {
220195972f6Sopenharmony_ci          /* the last entry must not overwrite the static entry! */
221195972f6Sopenharmony_ci          fail_unless(idx == 1);
222195972f6Sopenharmony_ci        }
223195972f6Sopenharmony_ci        etharp_tmr();
224195972f6Sopenharmony_ci      }
225195972f6Sopenharmony_ci    }
226195972f6Sopenharmony_ci#if ETHARP_SUPPORT_STATIC_ENTRIES
227195972f6Sopenharmony_ci    /* create a second static entry */
228195972f6Sopenharmony_ci    err = etharp_add_static_entry(&adrs[ARP_TABLE_SIZE+1], &test_ethaddr4);
229195972f6Sopenharmony_ci    fail_unless(err == ERR_OK);
230195972f6Sopenharmony_ci    idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr);
231195972f6Sopenharmony_ci    fail_unless(idx == 0);
232195972f6Sopenharmony_ci    idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE+1], &unused_ethaddr, &unused_ipaddr);
233195972f6Sopenharmony_ci    fail_unless(idx == 2);
234195972f6Sopenharmony_ci    /* and remove it again */
235195972f6Sopenharmony_ci    err = etharp_remove_static_entry(&adrs[ARP_TABLE_SIZE+1]);
236195972f6Sopenharmony_ci    fail_unless(err == ERR_OK);
237195972f6Sopenharmony_ci    idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr);
238195972f6Sopenharmony_ci    fail_unless(idx == 0);
239195972f6Sopenharmony_ci    idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE+1], &unused_ethaddr, &unused_ipaddr);
240195972f6Sopenharmony_ci    fail_unless(idx == -1);
241195972f6Sopenharmony_ci#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
242195972f6Sopenharmony_ci
243195972f6Sopenharmony_ci    /* check that static entries don't time out */
244195972f6Sopenharmony_ci    etharp_remove_all();
245195972f6Sopenharmony_ci    idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr);
246195972f6Sopenharmony_ci    fail_unless(idx == 0);
247195972f6Sopenharmony_ci
248195972f6Sopenharmony_ci#if ETHARP_SUPPORT_STATIC_ENTRIES
249195972f6Sopenharmony_ci    /* remove the first static entry */
250195972f6Sopenharmony_ci    err = etharp_remove_static_entry(&adrs[ARP_TABLE_SIZE]);
251195972f6Sopenharmony_ci    fail_unless(err == ERR_OK);
252195972f6Sopenharmony_ci    idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr);
253195972f6Sopenharmony_ci    fail_unless(idx == -1);
254195972f6Sopenharmony_ci    idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE+1], &unused_ethaddr, &unused_ipaddr);
255195972f6Sopenharmony_ci    fail_unless(idx == -1);
256195972f6Sopenharmony_ci#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
257195972f6Sopenharmony_ci
258195972f6Sopenharmony_ci    udp_remove(pcb);
259195972f6Sopenharmony_ci  }
260195972f6Sopenharmony_ci}
261195972f6Sopenharmony_ciEND_TEST
262195972f6Sopenharmony_ci
263195972f6Sopenharmony_ci
264195972f6Sopenharmony_ci/** Create the suite including all tests for this module */
265195972f6Sopenharmony_ciSuite *
266195972f6Sopenharmony_cietharp_suite(void)
267195972f6Sopenharmony_ci{
268195972f6Sopenharmony_ci  testfunc tests[] = {
269195972f6Sopenharmony_ci    TESTFUNC(test_etharp_table)
270195972f6Sopenharmony_ci  };
271195972f6Sopenharmony_ci  return create_suite("ETHARP", tests, sizeof(tests)/sizeof(testfunc), etharp_setup, etharp_teardown);
272195972f6Sopenharmony_ci}
273