1#include "test_udp.h"
2
3#include "lwip/udp.h"
4#include "lwip/stats.h"
5#include "lwip/inet_chksum.h"
6
7#if !LWIP_STATS || !UDP_STATS || !MEMP_STATS
8#error "This tests needs UDP- and MEMP-statistics enabled"
9#endif
10
11struct test_udp_rxdata {
12  u32_t rx_cnt;
13  u32_t rx_bytes;
14  struct udp_pcb *pcb;
15};
16
17static struct netif test_netif1, test_netif2;
18static ip4_addr_t test_gw1, test_ipaddr1, test_netmask1;
19static ip4_addr_t test_gw2, test_ipaddr2, test_netmask2;
20static int output_ctr, linkoutput_ctr;
21
22/* Helper functions */
23static void
24udp_remove_all(void)
25{
26  struct udp_pcb *pcb = udp_pcbs;
27  struct udp_pcb *pcb2;
28
29  while(pcb != NULL) {
30    pcb2 = pcb;
31    pcb = pcb->next;
32    udp_remove(pcb2);
33  }
34  fail_unless(MEMP_STATS_GET(used, MEMP_UDP_PCB) == 0);
35}
36
37static err_t
38default_netif_output(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr)
39{
40  fail_unless((netif == &test_netif1) || (netif == &test_netif2));
41  fail_unless(p != NULL);
42  fail_unless(ipaddr != NULL);
43  output_ctr++;
44  return ERR_OK;
45}
46
47static err_t
48default_netif_linkoutput(struct netif *netif, struct pbuf *p)
49{
50  fail_unless((netif == &test_netif1) || (netif == &test_netif2));
51  fail_unless(p != NULL);
52  linkoutput_ctr++;
53  return ERR_OK;
54}
55
56static err_t
57default_netif_init(struct netif *netif)
58{
59  fail_unless(netif != NULL);
60  netif->output = default_netif_output;
61  netif->linkoutput = default_netif_linkoutput;
62  netif->mtu = 1500;
63  netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
64  netif->hwaddr_len = 6;
65  return ERR_OK;
66}
67
68static void
69default_netif_add(void)
70{
71  struct netif *n;
72
73#if LWIP_HAVE_LOOPIF
74  fail_unless(netif_list != NULL); /* the loopif */
75  fail_unless(netif_list->next == NULL);
76#else
77  fail_unless(netif_list == NULL);
78#endif
79  fail_unless(netif_default == NULL);
80
81  IP4_ADDR(&test_ipaddr1, 192,168,0,1);
82  IP4_ADDR(&test_netmask1, 255,255,255,0);
83  IP4_ADDR(&test_gw1, 192,168,0,254);
84  n = netif_add(&test_netif1, &test_ipaddr1, &test_netmask1,
85                &test_gw1, NULL, default_netif_init, NULL);
86  fail_unless(n == &test_netif1);
87
88  IP4_ADDR(&test_ipaddr2, 192,168,1,1);
89  IP4_ADDR(&test_netmask2, 255,255,255,0);
90  IP4_ADDR(&test_gw2, 192,168,1,254);
91  n = netif_add(&test_netif2, &test_ipaddr2, &test_netmask2,
92                &test_gw2, NULL, default_netif_init, NULL);
93  fail_unless(n == &test_netif2);
94
95  netif_set_default(&test_netif1);
96  netif_set_up(&test_netif1);
97  netif_set_up(&test_netif2);
98}
99
100static void
101default_netif_remove(void)
102{
103  fail_unless(netif_default == &test_netif1);
104  netif_remove(&test_netif1);
105  netif_remove(&test_netif2);
106  fail_unless(netif_default == NULL);
107#if LWIP_HAVE_LOOPIF
108  fail_unless(netif_list != NULL); /* the loopif */
109  fail_unless(netif_list->next == NULL);
110#else
111  fail_unless(netif_list == NULL);
112#endif
113}
114/* Setups/teardown functions */
115
116static void
117udp_setup(void)
118{
119  udp_remove_all();
120  default_netif_add();
121  lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
122}
123
124static void
125udp_teardown(void)
126{
127  udp_remove_all();
128  default_netif_remove();
129  lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
130}
131
132
133/* Test functions */
134
135START_TEST(test_udp_new_remove)
136{
137  struct udp_pcb* pcb;
138  LWIP_UNUSED_ARG(_i);
139
140  fail_unless(MEMP_STATS_GET(used, MEMP_UDP_PCB) == 0);
141
142  pcb = udp_new();
143  fail_unless(pcb != NULL);
144  if (pcb != NULL) {
145    fail_unless(MEMP_STATS_GET(used, MEMP_UDP_PCB) == 1);
146    udp_remove(pcb);
147    fail_unless(MEMP_STATS_GET(used, MEMP_UDP_PCB) == 0);
148  }
149}
150END_TEST
151
152static void test_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p,
153    const ip_addr_t *addr, u16_t port)
154{
155  struct test_udp_rxdata *ctr = (struct test_udp_rxdata *)arg;
156
157  LWIP_UNUSED_ARG(addr);
158  LWIP_UNUSED_ARG(port);
159
160  fail_unless(arg != NULL);
161  fail_unless(ctr->pcb == pcb);
162
163  ctr->rx_cnt++;
164  ctr->rx_bytes += p->tot_len;
165
166  if (p != NULL) {
167    pbuf_free(p);
168  }
169}
170
171static struct pbuf *
172test_udp_create_test_packet(u16_t length, u16_t port, u32_t dst_addr)
173{
174  err_t err;
175  u8_t ret;
176  struct udp_hdr *uh;
177  struct ip_hdr *ih;
178  struct pbuf *p;
179  const u8_t test_data[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
180
181  p = pbuf_alloc(PBUF_TRANSPORT, length, PBUF_POOL);
182  fail_unless(p != NULL);
183  if (p == NULL) {
184    return NULL;
185  }
186  fail_unless(p->next == NULL);
187  err = pbuf_take(p, test_data, length);
188  fail_unless(err == ERR_OK);
189
190  /* add UDP header */
191  ret = pbuf_add_header(p, sizeof(struct udp_hdr));
192  fail_unless(!ret);
193  uh = (struct udp_hdr *)p->payload;
194  uh->chksum = 0;
195  uh->dest = uh->src = lwip_htons(port);
196  uh->len = lwip_htons(p->tot_len);
197  /* add IPv4 header */
198  ret = pbuf_add_header(p, sizeof(struct ip_hdr));
199  fail_unless(!ret);
200  ih = (struct ip_hdr *)p->payload;
201  memset(ih, 0, sizeof(*ih));
202  ih->dest.addr = dst_addr;
203  ih->_len = lwip_htons(p->tot_len);
204  ih->_ttl = 32;
205  ih->_proto = IP_PROTO_UDP;
206  IPH_VHL_SET(ih, 4, sizeof(struct ip_hdr) / 4);
207  IPH_CHKSUM_SET(ih, inet_chksum(ih, sizeof(struct ip_hdr)));
208  return p;
209}
210
211/* bind 2 pcbs to specific netif IP and test which one gets broadcasts */
212START_TEST(test_udp_broadcast_rx_with_2_netifs)
213{
214  err_t err;
215  struct udp_pcb *pcb1, *pcb2;
216  const u16_t port = 12345;
217  struct test_udp_rxdata ctr1, ctr2;
218  struct pbuf *p;
219#if SO_REUSE
220  struct udp_pcb *pcb_any;
221  struct test_udp_rxdata ctr_any;
222#endif
223  LWIP_UNUSED_ARG(_i);
224
225  pcb1 = udp_new();
226  fail_unless(pcb1 != NULL);
227  pcb2 = udp_new();
228  fail_unless(pcb2 != NULL);
229
230#if SO_REUSE
231  pcb_any = udp_new();
232  fail_unless(pcb_any != NULL);
233
234  ip_set_option(pcb1, SOF_REUSEADDR);
235  ip_set_option(pcb2, SOF_REUSEADDR);
236  ip_set_option(pcb_any, SOF_REUSEADDR);
237
238  err = udp_bind(pcb_any, NULL, port);
239  fail_unless(err == ERR_OK);
240  memset(&ctr_any, 0, sizeof(ctr_any));
241  ctr_any.pcb = pcb_any;
242  udp_recv(pcb_any, test_recv, &ctr_any);
243#endif
244
245  err = udp_bind(pcb1, &test_netif1.ip_addr, port);
246  fail_unless(err == ERR_OK);
247  err = udp_bind(pcb2, &test_netif2.ip_addr, port);
248  fail_unless(err == ERR_OK);
249
250  memset(&ctr1, 0, sizeof(ctr1));
251  ctr1.pcb = pcb1;
252  memset(&ctr2, 0, sizeof(ctr2));
253  ctr2.pcb = pcb2;
254
255  udp_recv(pcb1, test_recv, &ctr1);
256  udp_recv(pcb2, test_recv, &ctr2);
257
258  /* unicast to netif1 */
259  p = test_udp_create_test_packet(16, port, test_ipaddr1.addr);
260  EXPECT_RET(p != NULL);
261  err = ip4_input(p, &test_netif1);
262  fail_unless(err == ERR_OK);
263  fail_unless(ctr1.rx_cnt == 1);
264  fail_unless(ctr1.rx_bytes == 16);
265  fail_unless(ctr2.rx_cnt == 0);
266#if SO_REUSE
267  fail_unless(ctr_any.rx_cnt == 0);
268#endif
269  ctr1.rx_cnt = ctr1.rx_bytes = 0;
270
271  /* unicast to netif2 */
272  p = test_udp_create_test_packet(16, port, test_ipaddr2.addr);
273  EXPECT_RET(p != NULL);
274  err = ip4_input(p, &test_netif2);
275  fail_unless(err == ERR_OK);
276  fail_unless(ctr2.rx_cnt == 1);
277  fail_unless(ctr2.rx_bytes == 16);
278  fail_unless(ctr1.rx_cnt == 0);
279#if SO_REUSE
280  fail_unless(ctr_any.rx_cnt == 0);
281#endif
282  ctr2.rx_cnt = ctr2.rx_bytes = 0;
283
284  /* broadcast to netif1-broadcast, input to netif2 */
285  p = test_udp_create_test_packet(16, port, test_ipaddr1.addr | ~test_netmask1.addr);
286  EXPECT_RET(p != NULL);
287  err = ip4_input(p, &test_netif2);
288  fail_unless(err == ERR_OK);
289  fail_unless(ctr1.rx_cnt == 1);
290  fail_unless(ctr1.rx_bytes == 16);
291  fail_unless(ctr2.rx_cnt == 0);
292#if SO_REUSE
293  fail_unless(ctr_any.rx_cnt == 0);
294#endif
295  ctr1.rx_cnt = ctr1.rx_bytes = 0;
296
297  /* broadcast to netif2-broadcast, input to netif1 */
298  p = test_udp_create_test_packet(16, port, test_ipaddr2.addr | ~test_netmask2.addr);
299  EXPECT_RET(p != NULL);
300  err = ip4_input(p, &test_netif1);
301  fail_unless(err == ERR_OK);
302  fail_unless(ctr2.rx_cnt == 1);
303  fail_unless(ctr2.rx_bytes == 16);
304  fail_unless(ctr1.rx_cnt == 0);
305#if SO_REUSE
306  fail_unless(ctr_any.rx_cnt == 0);
307#endif
308  ctr2.rx_cnt = ctr2.rx_bytes = 0;
309
310  /* broadcast to global-broadcast, input to netif1 */
311  p = test_udp_create_test_packet(16, port, 0xffffffff);
312  EXPECT_RET(p != NULL);
313  err = ip4_input(p, &test_netif1);
314  fail_unless(err == ERR_OK);
315  fail_unless(ctr1.rx_cnt == 1);
316  fail_unless(ctr1.rx_bytes == 16);
317  fail_unless(ctr2.rx_cnt == 0);
318#if SO_REUSE
319  fail_unless(ctr_any.rx_cnt == 0);
320#endif
321  ctr1.rx_cnt = ctr1.rx_bytes = 0;
322
323  /* broadcast to global-broadcast, input to netif2 */
324  p = test_udp_create_test_packet(16, port, 0xffffffff);
325  EXPECT_RET(p != NULL);
326  err = ip4_input(p, &test_netif2);
327  fail_unless(err == ERR_OK);
328  fail_unless(ctr2.rx_cnt == 1);
329  fail_unless(ctr2.rx_bytes == 16);
330  fail_unless(ctr1.rx_cnt == 0);
331#if SO_REUSE
332  fail_unless(ctr_any.rx_cnt == 0);
333#endif
334  ctr2.rx_cnt = ctr2.rx_bytes = 0;
335}
336END_TEST
337
338/** Create the suite including all tests for this module */
339Suite *
340udp_suite(void)
341{
342  testfunc tests[] = {
343    TESTFUNC(test_udp_new_remove),
344    TESTFUNC(test_udp_broadcast_rx_with_2_netifs)
345  };
346  return create_suite("UDP", tests, sizeof(tests)/sizeof(testfunc), udp_setup, udp_teardown);
347}
348