1#include "tcp_helper.h"
2
3#include "lwip/priv/tcp_priv.h"
4#include "lwip/stats.h"
5#include "lwip/pbuf.h"
6#include "lwip/inet_chksum.h"
7#include "lwip/ip_addr.h"
8
9#if !LWIP_STATS || !TCP_STATS || !MEMP_STATS
10#error "This tests needs TCP- and MEMP-statistics enabled"
11#endif
12
13const ip_addr_t test_local_ip = IPADDR4_INIT_BYTES(192, 168, 1, 1);
14const ip_addr_t test_remote_ip = IPADDR4_INIT_BYTES(192, 168, 1, 2);
15const ip_addr_t test_netmask = IPADDR4_INIT_BYTES(255, 255, 255, 0);
16
17/** Remove all pcbs on the given list. */
18static void
19tcp_remove(struct tcp_pcb* pcb_list)
20{
21  struct tcp_pcb *pcb = pcb_list;
22  struct tcp_pcb *pcb2;
23
24  while(pcb != NULL) {
25    pcb2 = pcb;
26    pcb = pcb->next;
27    tcp_abort(pcb2);
28  }
29}
30
31/** Remove all pcbs on listen-, active- and time-wait-list (bound- isn't exported). */
32void
33tcp_remove_all(void)
34{
35  tcp_remove(tcp_listen_pcbs.pcbs);
36  tcp_remove(tcp_bound_pcbs);
37  tcp_remove(tcp_active_pcbs);
38  tcp_remove(tcp_tw_pcbs);
39  fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0);
40  fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB_LISTEN) == 0);
41  fail_unless(MEMP_STATS_GET(used, MEMP_TCP_SEG) == 0);
42  fail_unless(MEMP_STATS_GET(used, MEMP_PBUF_POOL) == 0);
43}
44
45/** Create a TCP segment usable for passing to tcp_input */
46static struct pbuf*
47tcp_create_segment_wnd(ip_addr_t* src_ip, ip_addr_t* dst_ip,
48                   u16_t src_port, u16_t dst_port, void* data, size_t data_len,
49                   u32_t seqno, u32_t ackno, u8_t headerflags, u16_t wnd)
50{
51  struct pbuf *p, *q;
52  struct ip_hdr* iphdr;
53  struct tcp_hdr* tcphdr;
54  u16_t pbuf_len = (u16_t)(sizeof(struct ip_hdr) + sizeof(struct tcp_hdr) + data_len);
55  LWIP_ASSERT("data_len too big", data_len <= 0xFFFF);
56
57  p = pbuf_alloc(PBUF_RAW, pbuf_len, PBUF_POOL);
58  EXPECT_RETNULL(p != NULL);
59  /* first pbuf must be big enough to hold the headers */
60  EXPECT_RETNULL(p->len >= (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr)));
61  if (data_len > 0) {
62    /* first pbuf must be big enough to hold at least 1 data byte, too */
63    EXPECT_RETNULL(p->len > (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr)));
64  }
65
66  for(q = p; q != NULL; q = q->next) {
67    memset(q->payload, 0, q->len);
68  }
69
70  iphdr = (struct ip_hdr*)p->payload;
71  /* fill IP header */
72  iphdr->dest.addr = ip_2_ip4(dst_ip)->addr;
73  iphdr->src.addr = ip_2_ip4(src_ip)->addr;
74  IPH_VHL_SET(iphdr, 4, IP_HLEN / 4);
75  IPH_TOS_SET(iphdr, 0);
76  IPH_LEN_SET(iphdr, htons(p->tot_len));
77  IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
78
79  /* let p point to TCP header */
80  pbuf_header(p, -(s16_t)sizeof(struct ip_hdr));
81
82  tcphdr = (struct tcp_hdr*)p->payload;
83  tcphdr->src   = htons(src_port);
84  tcphdr->dest  = htons(dst_port);
85  tcphdr->seqno = htonl(seqno);
86  tcphdr->ackno = htonl(ackno);
87  TCPH_HDRLEN_SET(tcphdr, sizeof(struct tcp_hdr)/4);
88  TCPH_FLAGS_SET(tcphdr, headerflags);
89  tcphdr->wnd   = htons(wnd);
90
91  if (data_len > 0) {
92    /* let p point to TCP data */
93    pbuf_header(p, -(s16_t)sizeof(struct tcp_hdr));
94    /* copy data */
95    pbuf_take(p, data, (u16_t)data_len);
96    /* let p point to TCP header again */
97    pbuf_header(p, sizeof(struct tcp_hdr));
98  }
99
100  /* calculate checksum */
101
102  tcphdr->chksum = ip_chksum_pseudo(p,
103          IP_PROTO_TCP, p->tot_len, src_ip, dst_ip);
104
105  pbuf_header(p, sizeof(struct ip_hdr));
106
107  return p;
108}
109
110/** Create a TCP segment usable for passing to tcp_input */
111struct pbuf*
112tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip,
113                   u16_t src_port, u16_t dst_port, void* data, size_t data_len,
114                   u32_t seqno, u32_t ackno, u8_t headerflags)
115{
116  return tcp_create_segment_wnd(src_ip, dst_ip, src_port, dst_port, data,
117    data_len, seqno, ackno, headerflags, TCP_WND);
118}
119
120/** Create a TCP segment usable for passing to tcp_input
121 * - IP-addresses, ports, seqno and ackno are taken from pcb
122 * - seqno and ackno can be altered with an offset
123 */
124struct pbuf*
125tcp_create_rx_segment(struct tcp_pcb* pcb, void* data, size_t data_len, u32_t seqno_offset,
126                      u32_t ackno_offset, u8_t headerflags)
127{
128  return tcp_create_segment(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port,
129    data, data_len, pcb->rcv_nxt + seqno_offset, pcb->lastack + ackno_offset, headerflags);
130}
131
132/** Create a TCP segment usable for passing to tcp_input
133 * - IP-addresses, ports, seqno and ackno are taken from pcb
134 * - seqno and ackno can be altered with an offset
135 * - TCP window can be adjusted
136 */
137struct pbuf* tcp_create_rx_segment_wnd(struct tcp_pcb* pcb, void* data, size_t data_len,
138                   u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags, u16_t wnd)
139{
140  return tcp_create_segment_wnd(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port,
141    data, data_len, pcb->rcv_nxt + seqno_offset, pcb->lastack + ackno_offset, headerflags, wnd);
142}
143
144/** Safely bring a tcp_pcb into the requested state */
145void
146tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, const ip_addr_t* local_ip,
147                   const ip_addr_t* remote_ip, u16_t local_port, u16_t remote_port)
148{
149  u32_t iss;
150
151  /* @todo: are these all states? */
152  /* @todo: remove from previous list */
153  pcb->state = state;
154
155  iss = tcp_next_iss(pcb);
156  pcb->snd_wl2 = iss;
157  pcb->snd_nxt = iss;
158  pcb->lastack = iss;
159  pcb->snd_lbb = iss;
160
161  if (state == ESTABLISHED) {
162    TCP_REG(&tcp_active_pcbs, pcb);
163    ip_addr_copy(pcb->local_ip, *local_ip);
164    pcb->local_port = local_port;
165    ip_addr_copy(pcb->remote_ip, *remote_ip);
166    pcb->remote_port = remote_port;
167  } else if(state == LISTEN) {
168    TCP_REG(&tcp_listen_pcbs.pcbs, pcb);
169    ip_addr_copy(pcb->local_ip, *local_ip);
170    pcb->local_port = local_port;
171  } else if(state == TIME_WAIT) {
172    TCP_REG(&tcp_tw_pcbs, pcb);
173    ip_addr_copy(pcb->local_ip, *local_ip);
174    pcb->local_port = local_port;
175    ip_addr_copy(pcb->remote_ip, *remote_ip);
176    pcb->remote_port = remote_port;
177  } else {
178    fail();
179  }
180}
181
182void
183test_tcp_counters_err(void* arg, err_t err)
184{
185  struct test_tcp_counters* counters = (struct test_tcp_counters*)arg;
186  EXPECT_RET(arg != NULL);
187  counters->err_calls++;
188  counters->last_err = err;
189}
190
191static void
192test_tcp_counters_check_rxdata(struct test_tcp_counters* counters, struct pbuf* p)
193{
194  struct pbuf* q;
195  u32_t i, received;
196  if(counters->expected_data == NULL) {
197    /* no data to compare */
198    return;
199  }
200  EXPECT_RET(counters->recved_bytes + p->tot_len <= counters->expected_data_len);
201  received = counters->recved_bytes;
202  for(q = p; q != NULL; q = q->next) {
203    char *data = (char*)q->payload;
204    for(i = 0; i < q->len; i++) {
205      EXPECT_RET(data[i] == counters->expected_data[received]);
206      received++;
207    }
208  }
209  EXPECT(received == counters->recved_bytes + p->tot_len);
210}
211
212err_t
213test_tcp_counters_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err)
214{
215  struct test_tcp_counters* counters = (struct test_tcp_counters*)arg;
216  EXPECT_RETX(arg != NULL, ERR_OK);
217  EXPECT_RETX(pcb != NULL, ERR_OK);
218  EXPECT_RETX(err == ERR_OK, ERR_OK);
219
220  if (p != NULL) {
221    if (counters->close_calls == 0) {
222      counters->recv_calls++;
223      test_tcp_counters_check_rxdata(counters, p);
224      counters->recved_bytes += p->tot_len;
225    } else {
226      counters->recv_calls_after_close++;
227      counters->recved_bytes_after_close += p->tot_len;
228    }
229    pbuf_free(p);
230  } else {
231    counters->close_calls++;
232  }
233  EXPECT(counters->recv_calls_after_close == 0 && counters->recved_bytes_after_close == 0);
234  return ERR_OK;
235}
236
237/** Allocate a pcb and set up the test_tcp_counters_* callbacks */
238struct tcp_pcb*
239test_tcp_new_counters_pcb(struct test_tcp_counters* counters)
240{
241  struct tcp_pcb* pcb = tcp_new();
242  if (pcb != NULL) {
243    /* set up args and callbacks */
244    tcp_arg(pcb, counters);
245    tcp_recv(pcb, test_tcp_counters_recv);
246    tcp_err(pcb, test_tcp_counters_err);
247    pcb->snd_wnd = TCP_WND;
248    pcb->snd_wnd_max = TCP_WND;
249  }
250  return pcb;
251}
252
253/** Calls tcp_input() after adjusting current_iphdr_dest */
254void test_tcp_input(struct pbuf *p, struct netif *inp)
255{
256  struct ip_hdr *iphdr = (struct ip_hdr*)p->payload;
257  /* these lines are a hack, don't use them as an example :-) */
258  ip_addr_copy_from_ip4(*ip_current_dest_addr(), iphdr->dest);
259  ip_addr_copy_from_ip4(*ip_current_src_addr(), iphdr->src);
260  ip_current_netif() = inp;
261  ip_data.current_ip4_header = iphdr;
262
263  /* since adding IPv6, p->payload must point to tcp header, not ip header */
264  pbuf_header(p, -(s16_t)sizeof(struct ip_hdr));
265
266  tcp_input(p, inp);
267
268  ip_addr_set_zero(ip_current_dest_addr());
269  ip_addr_set_zero(ip_current_src_addr());
270  ip_current_netif() = NULL;
271  ip_data.current_ip4_header = NULL;
272}
273
274static err_t test_tcp_netif_output(struct netif *netif, struct pbuf *p,
275       const ip4_addr_t *ipaddr)
276{
277  struct test_tcp_txcounters *txcounters = (struct test_tcp_txcounters*)netif->state;
278  LWIP_UNUSED_ARG(ipaddr);
279  if (txcounters != NULL)
280  {
281    txcounters->num_tx_calls++;
282    txcounters->num_tx_bytes += p->tot_len;
283    if (txcounters->copy_tx_packets) {
284      struct pbuf *p_copy = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
285      err_t err;
286      EXPECT(p_copy != NULL);
287      err = pbuf_copy(p_copy, p);
288      EXPECT(err == ERR_OK);
289      if (txcounters->tx_packets == NULL) {
290        txcounters->tx_packets = p_copy;
291      } else {
292        pbuf_cat(txcounters->tx_packets, p_copy);
293      }
294    }
295  }
296  return ERR_OK;
297}
298
299void test_tcp_init_netif(struct netif *netif, struct test_tcp_txcounters *txcounters,
300                         const ip_addr_t *ip_addr, const ip_addr_t *netmask)
301{
302  struct netif *n;
303  memset(netif, 0, sizeof(struct netif));
304  if (txcounters != NULL) {
305    memset(txcounters, 0, sizeof(struct test_tcp_txcounters));
306    netif->state = txcounters;
307  }
308  netif->output = test_tcp_netif_output;
309  netif->flags |= NETIF_FLAG_UP | NETIF_FLAG_LINK_UP;
310  ip_addr_copy_from_ip4(netif->netmask, *ip_2_ip4(netmask));
311  ip_addr_copy_from_ip4(netif->ip_addr, *ip_2_ip4(ip_addr));
312  for (n = netif_list; n != NULL; n = n->next) {
313    if (n == netif) {
314      return;
315    }
316  }
317  netif->next = NULL;
318  netif_list = netif;
319}
320