STM32F769IDiscovery  1.00
uDANTE Audio Networking with STM32F7 DISCO board
tcp_helper.c
Go to the documentation of this file.
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 
14 static void
15 tcp_remove(struct tcp_pcb* pcb_list)
16 {
17  struct tcp_pcb *pcb = pcb_list;
18  struct tcp_pcb *pcb2;
19 
20  while(pcb != NULL) {
21  pcb2 = pcb;
22  pcb = pcb->next;
23  tcp_abort(pcb2);
24  }
25 }
26 
28 void
30 {
31  tcp_remove(tcp_listen_pcbs.pcbs);
32  tcp_remove(tcp_active_pcbs);
33  tcp_remove(tcp_tw_pcbs);
34  fail_unless(lwip_stats.memp[MEMP_TCP_PCB].used == 0);
35  fail_unless(lwip_stats.memp[MEMP_TCP_PCB_LISTEN].used == 0);
36  fail_unless(lwip_stats.memp[MEMP_TCP_SEG].used == 0);
37  fail_unless(lwip_stats.memp[MEMP_PBUF_POOL].used == 0);
38 }
39 
41 static struct pbuf*
42 tcp_create_segment_wnd(ip_addr_t* src_ip, ip_addr_t* dst_ip,
43  u16_t src_port, u16_t dst_port, void* data, size_t data_len,
44  u32_t seqno, u32_t ackno, u8_t headerflags, u16_t wnd)
45 {
46  struct pbuf *p, *q;
47  struct ip_hdr* iphdr;
48  struct tcp_hdr* tcphdr;
49  u16_t pbuf_len = (u16_t)(sizeof(struct ip_hdr) + sizeof(struct tcp_hdr) + data_len);
50  LWIP_ASSERT("data_len too big", data_len <= 0xFFFF);
51 
52  p = pbuf_alloc(PBUF_RAW, pbuf_len, PBUF_POOL);
53  EXPECT_RETNULL(p != NULL);
54  /* first pbuf must be big enough to hold the headers */
55  EXPECT_RETNULL(p->len >= (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr)));
56  if (data_len > 0) {
57  /* first pbuf must be big enough to hold at least 1 data byte, too */
58  EXPECT_RETNULL(p->len > (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr)));
59  }
60 
61  for(q = p; q != NULL; q = q->next) {
62  memset(q->payload, 0, q->len);
63  }
64 
65  iphdr = p->payload;
66  /* fill IP header */
67  iphdr->dest.addr = ip_2_ip4(dst_ip)->addr;
68  iphdr->src.addr = ip_2_ip4(src_ip)->addr;
69  IPH_VHL_SET(iphdr, 4, IP_HLEN / 4);
70  IPH_TOS_SET(iphdr, 0);
71  IPH_LEN_SET(iphdr, htons(p->tot_len));
72  IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
73 
74  /* let p point to TCP header */
75  pbuf_header(p, -(s16_t)sizeof(struct ip_hdr));
76 
77  tcphdr = p->payload;
78  tcphdr->src = htons(src_port);
79  tcphdr->dest = htons(dst_port);
80  tcphdr->seqno = htonl(seqno);
81  tcphdr->ackno = htonl(ackno);
82  TCPH_HDRLEN_SET(tcphdr, sizeof(struct tcp_hdr)/4);
83  TCPH_FLAGS_SET(tcphdr, headerflags);
84  tcphdr->wnd = htons(wnd);
85 
86  if (data_len > 0) {
87  /* let p point to TCP data */
88  pbuf_header(p, -(s16_t)sizeof(struct tcp_hdr));
89  /* copy data */
90  pbuf_take(p, data, (u16_t)data_len);
91  /* let p point to TCP header again */
92  pbuf_header(p, sizeof(struct tcp_hdr));
93  }
94 
95  /* calculate checksum */
96 
97  tcphdr->chksum = ip_chksum_pseudo(p,
98  IP_PROTO_TCP, p->tot_len, src_ip, dst_ip);
99 
100  pbuf_header(p, sizeof(struct ip_hdr));
101 
102  return p;
103 }
104 
106 struct pbuf*
108  u16_t src_port, u16_t dst_port, void* data, size_t data_len,
109  u32_t seqno, u32_t ackno, u8_t headerflags)
110 {
111  return tcp_create_segment_wnd(src_ip, dst_ip, src_port, dst_port, data,
112  data_len, seqno, ackno, headerflags, TCP_WND);
113 }
114 
119 struct pbuf*
120 tcp_create_rx_segment(struct tcp_pcb* pcb, void* data, size_t data_len, u32_t seqno_offset,
121  u32_t ackno_offset, u8_t headerflags)
122 {
123  return tcp_create_segment(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port,
124  data, data_len, pcb->rcv_nxt + seqno_offset, pcb->lastack + ackno_offset, headerflags);
125 }
126 
132 struct pbuf* tcp_create_rx_segment_wnd(struct tcp_pcb* pcb, void* data, size_t data_len,
133  u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags, u16_t wnd)
134 {
135  return tcp_create_segment_wnd(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port,
136  data, data_len, pcb->rcv_nxt + seqno_offset, pcb->lastack + ackno_offset, headerflags, wnd);
137 }
138 
140 void
141 tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, ip_addr_t* local_ip,
142  ip_addr_t* remote_ip, u16_t local_port, u16_t remote_port)
143 {
144  /* @todo: are these all states? */
145  /* @todo: remove from previous list */
146  pcb->state = state;
147  if (state == ESTABLISHED) {
148  TCP_REG(&tcp_active_pcbs, pcb);
149  pcb->local_ip.addr = local_ip->addr;
150  pcb->local_port = local_port;
151  pcb->remote_ip.addr = remote_ip->addr;
152  pcb->remote_port = remote_port;
153  } else if(state == LISTEN) {
154  TCP_REG(&tcp_listen_pcbs.pcbs, pcb);
155  pcb->local_ip.addr = local_ip->addr;
156  pcb->local_port = local_port;
157  } else if(state == TIME_WAIT) {
158  TCP_REG(&tcp_tw_pcbs, pcb);
159  pcb->local_ip.addr = local_ip->addr;
160  pcb->local_port = local_port;
161  pcb->remote_ip.addr = remote_ip->addr;
162  pcb->remote_port = remote_port;
163  } else {
164  fail();
165  }
166 }
167 
168 void
170 {
171  struct test_tcp_counters* counters = arg;
172  EXPECT_RET(arg != NULL);
173  counters->err_calls++;
174  counters->last_err = err;
175 }
176 
177 static void
178 test_tcp_counters_check_rxdata(struct test_tcp_counters* counters, struct pbuf* p)
179 {
180  struct pbuf* q;
181  u32_t i, received;
182  if(counters->expected_data == NULL) {
183  /* no data to compare */
184  return;
185  }
186  EXPECT_RET(counters->recved_bytes + p->tot_len <= counters->expected_data_len);
187  received = counters->recved_bytes;
188  for(q = p; q != NULL; q = q->next) {
189  char *data = q->payload;
190  for(i = 0; i < q->len; i++) {
191  EXPECT_RET(data[i] == counters->expected_data[received]);
192  received++;
193  }
194  }
195  EXPECT(received == counters->recved_bytes + p->tot_len);
196 }
197 
198 err_t
199 test_tcp_counters_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err)
200 {
201  struct test_tcp_counters* counters = arg;
202  EXPECT_RETX(arg != NULL, ERR_OK);
203  EXPECT_RETX(pcb != NULL, ERR_OK);
204  EXPECT_RETX(err == ERR_OK, ERR_OK);
205 
206  if (p != NULL) {
207  if (counters->close_calls == 0) {
208  counters->recv_calls++;
209  test_tcp_counters_check_rxdata(counters, p);
210  counters->recved_bytes += p->tot_len;
211  } else {
212  counters->recv_calls_after_close++;
213  counters->recved_bytes_after_close += p->tot_len;
214  }
215  pbuf_free(p);
216  } else {
217  counters->close_calls++;
218  }
219  EXPECT(counters->recv_calls_after_close == 0 && counters->recved_bytes_after_close == 0);
220  return ERR_OK;
221 }
222 
224 struct tcp_pcb*
226 {
227  struct tcp_pcb* pcb = tcp_new();
228  if (pcb != NULL) {
229  /* set up args and callbacks */
230  tcp_arg(pcb, counters);
231  tcp_recv(pcb, test_tcp_counters_recv);
232  tcp_err(pcb, test_tcp_counters_err);
233  pcb->snd_wnd = TCP_WND;
234  pcb->snd_wnd_max = TCP_WND;
235  }
236  return pcb;
237 }
238 
240 void test_tcp_input(struct pbuf *p, struct netif *inp)
241 {
242  struct ip_hdr *iphdr = (struct ip_hdr*)p->payload;
243  /* these lines are a hack, don't use them as an example :-) */
244  ip_addr_copy_from_ip4(*ip_current_dest_addr(), iphdr->dest);
245  ip_addr_copy_from_ip4(*ip_current_src_addr(), iphdr->src);
246  ip_current_netif() = inp;
247  ip_data.current_ip4_header = iphdr;
248 
249  /* since adding IPv6, p->payload must point to tcp header, not ip header */
250  pbuf_header(p, -(s16_t)sizeof(struct ip_hdr));
251 
252  tcp_input(p, inp);
253 
257  ip_data.current_ip4_header = NULL;
258 }
259 
260 static err_t test_tcp_netif_output(struct netif *netif, struct pbuf *p,
261  const ip4_addr_t *ipaddr)
262 {
263  struct test_tcp_txcounters *txcounters = (struct test_tcp_txcounters*)netif->state;
264  LWIP_UNUSED_ARG(ipaddr);
265  if (txcounters != NULL)
266  {
267  txcounters->num_tx_calls++;
268  txcounters->num_tx_bytes += p->tot_len;
269  if (txcounters->copy_tx_packets) {
270  struct pbuf *p_copy = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
271  err_t err;
272  EXPECT(p_copy != NULL);
273  err = pbuf_copy(p_copy, p);
274  EXPECT(err == ERR_OK);
275  if (txcounters->tx_packets == NULL) {
276  txcounters->tx_packets = p_copy;
277  } else {
278  pbuf_cat(txcounters->tx_packets, p_copy);
279  }
280  }
281  }
282  return ERR_OK;
283 }
284 
285 void test_tcp_init_netif(struct netif *netif, struct test_tcp_txcounters *txcounters,
286  ip_addr_t *ip_addr, ip_addr_t *netmask)
287 {
288  struct netif *n;
289  memset(netif, 0, sizeof(struct netif));
290  if (txcounters != NULL) {
291  memset(txcounters, 0, sizeof(struct test_tcp_txcounters));
292  netif->state = txcounters;
293  }
294  netif->output = test_tcp_netif_output;
296  ip4_addr_copy(netif->netmask, *ip_2_ip4(netmask));
297  ip4_addr_copy(netif->ip_addr, *ip_2_ip4(ip_addr));
298  for (n = netif_list; n != NULL; n = n->next) {
299  if (n == netif) {
300  return;
301  }
302  }
303  netif->next = NULL;
304  netif_list = netif;
305 }
struct tcp_pcb * test_tcp_new_counters_pcb(struct test_tcp_counters *counters)
Definition: tcp_helper.c:225
u16_t ip_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, const ip_addr_t *src, const ip_addr_t *dest)
Definition: inet_chksum.c:382
u8_t flags
Definition: netif.h:269
struct netif * netif_list
Definition: netif.c:84
void test_tcp_init_netif(struct netif *netif, struct test_tcp_txcounters *txcounters, ip_addr_t *ip_addr, ip_addr_t *netmask)
Definition: tcp_helper.c:285
#define ip_current_netif()
Definition: ip.h:154
u32_t recv_calls_after_close
Definition: tcp_helper.h:13
void * state
Definition: netif.h:234
struct pbuf * tcp_create_segment(ip_addr_t *src_ip, ip_addr_t *dst_ip, u16_t src_port, u16_t dst_port, void *data, size_t data_len, u32_t seqno, u32_t ackno, u8_t headerflags)
Definition: tcp_helper.c:107
signed short s16_t
Definition: cc.h:41
void test_tcp_counters_err(void *arg, err_t err)
Definition: tcp_helper.c:169
#define NETIF_FLAG_UP
Definition: netif.h:77
u8_t pbuf_header(struct pbuf *p, s16_t header_size_increment)
Definition: pbuf.c:603
struct netif * next
Definition: netif.h:184
#define NETIF_FLAG_LINK_UP
Definition: netif.h:86
#define htons(x)
Definition: def.h:86
#define IP_PROTO_TCP
Definition: ip.h:53
u32_t recved_bytes_after_close
Definition: tcp_helper.h:14
u16_t len
Definition: pbuf.h:125
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition: pbuf.c:199
#define ip_current_dest_addr()
Definition: ip.h:238
Definition: pbuf.h:77
u16_t inet_chksum(const void *dataptr, u16_t len)
Definition: inet_chksum.c:558
Definition: pbuf.h:66
#define EXPECT_RET(x)
Definition: lwip_check.h:12
#define NULL
Definition: usbd_def.h:53
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:652
Definition: pbuf.h:68
err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
Definition: pbuf.c:886
void tcp_remove_all(void)
Definition: tcp_helper.c:29
#define EXPECT(x)
Definition: lwip_check.h:11
unsigned long u32_t
Definition: cc.h:42
char * expected_data
Definition: tcp_helper.h:18
err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
Definition: pbuf.c:1075
void tcp_set_state(struct tcp_pcb *pcb, enum tcp_state state, ip_addr_t *local_ip, ip_addr_t *remote_ip, u16_t local_port, u16_t remote_port)
Definition: tcp_helper.c:141
#define ERR_OK
Definition: err.h:52
u16_t tot_len
Definition: pbuf.h:122
Definition: pbuf.h:108
s8_t err_t
Definition: err.h:47
#define TCP_WND
Definition: lwipopts.h:128
void test_tcp_input(struct pbuf *p, struct netif *inp)
Definition: tcp_helper.c:240
Definition: pbuf.h:90
struct pbuf * tcp_create_rx_segment(struct tcp_pcb *pcb, void *data, size_t data_len, u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags)
Definition: tcp_helper.c:120
u32_t expected_data_len
Definition: tcp_helper.h:19
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:70
#define EXPECT_RETNULL(x)
Definition: lwip_check.h:14
Definition: netif.h:182
struct pbuf * next
Definition: pbuf.h:110
struct ip_globals ip_data
err_t test_tcp_counters_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
Definition: tcp_helper.c:199
#define ip_current_src_addr()
Definition: ip.h:236
void pbuf_cat(struct pbuf *h, struct pbuf *t)
Definition: pbuf.c:779
unsigned char u8_t
Definition: cc.h:38
ip6_addr_t ip_addr_t
Definition: ip_addr.h:194
#define ip_addr_set_zero(ipaddr)
Definition: ip_addr.h:207
struct pbuf * tx_packets
Definition: tcp_helper.h:26
struct pbuf * tcp_create_rx_segment_wnd(struct tcp_pcb *pcb, void *data, size_t data_len, u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags, u16_t wnd)
Definition: tcp_helper.c:132
#define EXPECT_RETX(x, y)
Definition: lwip_check.h:13
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:89
#define htonl(x)
Definition: def.h:88
unsigned short u16_t
Definition: cc.h:40
void * payload
Definition: pbuf.h:113