BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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 | |||
13 | const ip_addr_t test_local_ip = IPADDR4_INIT_BYTES(192, 168, 1, 1); |
||
14 | const ip_addr_t test_remote_ip = IPADDR4_INIT_BYTES(192, 168, 1, 2); |
||
15 | const ip_addr_t test_netmask = IPADDR4_INIT_BYTES(255, 255, 255, 0); |
||
16 | |||
17 | /** Remove all pcbs on the given list. */ |
||
18 | static void |
||
19 | tcp_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). */ |
||
32 | void |
||
33 | tcp_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 */ |
||
46 | static struct pbuf* |
||
47 | tcp_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 */ |
||
111 | struct pbuf* |
||
112 | tcp_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 | */ |
||
124 | struct pbuf* |
||
125 | tcp_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 | */ |
||
137 | struct 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 */ |
||
145 | void |
||
146 | tcp_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 | |||
182 | void |
||
183 | test_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 | |||
191 | static void |
||
192 | test_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 | |||
212 | err_t |
||
213 | test_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 */ |
||
238 | struct tcp_pcb* |
||
239 | test_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 */ |
||
254 | void 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 | |||
274 | static 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 | |||
299 | void 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 | } |