Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
tcp_helper.c
00001 #include "tcp_helper.h" 00002 00003 #include "lwip/priv/tcp_priv.h" 00004 #include "lwip/stats.h" 00005 #include "lwip/pbuf.h" 00006 #include "lwip/inet_chksum.h" 00007 #include "lwip/ip_addr.h" 00008 00009 #if !LWIP_STATS || !TCP_STATS || !MEMP_STATS 00010 #error "This tests needs TCP- and MEMP-statistics enabled" 00011 #endif 00012 00013 const ip_addr_t test_local_ip = IPADDR4_INIT_BYTES(192, 168, 1, 1); 00014 const ip_addr_t test_remote_ip = IPADDR4_INIT_BYTES(192, 168, 1, 2); 00015 const ip_addr_t test_netmask = IPADDR4_INIT_BYTES(255, 255, 255, 0); 00016 00017 /** Remove all pcbs on the given list. */ 00018 static void 00019 tcp_remove(struct tcp_pcb* pcb_list) 00020 { 00021 struct tcp_pcb *pcb = pcb_list; 00022 struct tcp_pcb *pcb2; 00023 00024 while(pcb != NULL) { 00025 pcb2 = pcb; 00026 pcb = pcb->next; 00027 tcp_abort(pcb2); 00028 } 00029 } 00030 00031 /** Remove all pcbs on listen-, active- and time-wait-list (bound- isn't exported). */ 00032 void 00033 tcp_remove_all(void) 00034 { 00035 tcp_remove(tcp_listen_pcbs.pcbs); 00036 tcp_remove(tcp_bound_pcbs); 00037 tcp_remove(tcp_active_pcbs); 00038 tcp_remove(tcp_tw_pcbs); 00039 fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); 00040 fail_unless(MEMP_STATS_GET(used, MEMP_TCP_PCB_LISTEN) == 0); 00041 fail_unless(MEMP_STATS_GET(used, MEMP_TCP_SEG) == 0); 00042 fail_unless(MEMP_STATS_GET(used, MEMP_PBUF_POOL) == 0); 00043 } 00044 00045 /** Create a TCP segment usable for passing to tcp_input */ 00046 static struct pbuf* 00047 tcp_create_segment_wnd(ip_addr_t* src_ip, ip_addr_t* dst_ip, 00048 u16_t src_port, u16_t dst_port, void* data, size_t data_len, 00049 u32_t seqno, u32_t ackno, u8_t headerflags, u16_t wnd) 00050 { 00051 struct pbuf *p, *q; 00052 struct ip_hdr* iphdr; 00053 struct tcp_hdr* tcphdr; 00054 u16_t pbuf_len = (u16_t)(sizeof(struct ip_hdr) + sizeof(struct tcp_hdr) + data_len); 00055 LWIP_ASSERT("data_len too big", data_len <= 0xFFFF); 00056 00057 p = pbuf_alloc(PBUF_RAW, pbuf_len, PBUF_POOL); 00058 EXPECT_RETNULL(p != NULL); 00059 /* first pbuf must be big enough to hold the headers */ 00060 EXPECT_RETNULL(p->len >= (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr))); 00061 if (data_len > 0) { 00062 /* first pbuf must be big enough to hold at least 1 data byte, too */ 00063 EXPECT_RETNULL(p->len > (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr))); 00064 } 00065 00066 for(q = p; q != NULL; q = q->next) { 00067 memset(q->payload, 0, q->len); 00068 } 00069 00070 iphdr = (struct ip_hdr*)p->payload; 00071 /* fill IP header */ 00072 iphdr->dest.addr = ip_2_ip4(dst_ip)->addr; 00073 iphdr->src.addr = ip_2_ip4(src_ip)->addr; 00074 IPH_VHL_SET(iphdr, 4, IP_HLEN / 4); 00075 IPH_TOS_SET(iphdr, 0); 00076 IPH_LEN_SET(iphdr, htons(p->tot_len)); 00077 IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); 00078 00079 /* let p point to TCP header */ 00080 pbuf_header(p, -(s16_t)sizeof(struct ip_hdr)); 00081 00082 tcphdr = (struct tcp_hdr*)p->payload; 00083 tcphdr->src = htons(src_port); 00084 tcphdr->dest = htons(dst_port); 00085 tcphdr->seqno = htonl(seqno); 00086 tcphdr->ackno = htonl(ackno); 00087 TCPH_HDRLEN_SET(tcphdr, sizeof(struct tcp_hdr)/4); 00088 TCPH_FLAGS_SET(tcphdr, headerflags); 00089 tcphdr->wnd = htons(wnd); 00090 00091 if (data_len > 0) { 00092 /* let p point to TCP data */ 00093 pbuf_header(p, -(s16_t)sizeof(struct tcp_hdr)); 00094 /* copy data */ 00095 pbuf_take(p, data, (u16_t)data_len); 00096 /* let p point to TCP header again */ 00097 pbuf_header(p, sizeof(struct tcp_hdr)); 00098 } 00099 00100 /* calculate checksum */ 00101 00102 tcphdr->chksum = ip_chksum_pseudo(p, 00103 IP_PROTO_TCP, p->tot_len, src_ip, dst_ip); 00104 00105 pbuf_header(p, sizeof(struct ip_hdr)); 00106 00107 return p; 00108 } 00109 00110 /** Create a TCP segment usable for passing to tcp_input */ 00111 struct pbuf* 00112 tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip, 00113 u16_t src_port, u16_t dst_port, void* data, size_t data_len, 00114 u32_t seqno, u32_t ackno, u8_t headerflags) 00115 { 00116 return tcp_create_segment_wnd(src_ip, dst_ip, src_port, dst_port, data, 00117 data_len, seqno, ackno, headerflags, TCP_WND); 00118 } 00119 00120 /** Create a TCP segment usable for passing to tcp_input 00121 * - IP-addresses, ports, seqno and ackno are taken from pcb 00122 * - seqno and ackno can be altered with an offset 00123 */ 00124 struct pbuf* 00125 tcp_create_rx_segment(struct tcp_pcb* pcb, void* data, size_t data_len, u32_t seqno_offset, 00126 u32_t ackno_offset, u8_t headerflags) 00127 { 00128 return tcp_create_segment(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port, 00129 data, data_len, pcb->rcv_nxt + seqno_offset, pcb->lastack + ackno_offset, headerflags); 00130 } 00131 00132 /** Create a TCP segment usable for passing to tcp_input 00133 * - IP-addresses, ports, seqno and ackno are taken from pcb 00134 * - seqno and ackno can be altered with an offset 00135 * - TCP window can be adjusted 00136 */ 00137 struct pbuf* tcp_create_rx_segment_wnd(struct tcp_pcb* pcb, void* data, size_t data_len, 00138 u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags, u16_t wnd) 00139 { 00140 return tcp_create_segment_wnd(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port, 00141 data, data_len, pcb->rcv_nxt + seqno_offset, pcb->lastack + ackno_offset, headerflags, wnd); 00142 } 00143 00144 /** Safely bring a tcp_pcb into the requested state */ 00145 void 00146 tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, const ip_addr_t* local_ip, 00147 const ip_addr_t* remote_ip, u16_t local_port, u16_t remote_port) 00148 { 00149 u32_t iss; 00150 00151 /* @todo: are these all states? */ 00152 /* @todo: remove from previous list */ 00153 pcb->state = state; 00154 00155 iss = tcp_next_iss(pcb); 00156 pcb->snd_wl2 = iss; 00157 pcb->snd_nxt = iss; 00158 pcb->lastack = iss; 00159 pcb->snd_lbb = iss; 00160 00161 if (state == ESTABLISHED) { 00162 TCP_REG(&tcp_active_pcbs, pcb); 00163 ip_addr_copy(pcb->local_ip, *local_ip); 00164 pcb->local_port = local_port; 00165 ip_addr_copy(pcb->remote_ip, *remote_ip); 00166 pcb->remote_port = remote_port; 00167 } else if(state == LISTEN) { 00168 TCP_REG(&tcp_listen_pcbs.pcbs, pcb); 00169 ip_addr_copy(pcb->local_ip, *local_ip); 00170 pcb->local_port = local_port; 00171 } else if(state == TIME_WAIT) { 00172 TCP_REG(&tcp_tw_pcbs, pcb); 00173 ip_addr_copy(pcb->local_ip, *local_ip); 00174 pcb->local_port = local_port; 00175 ip_addr_copy(pcb->remote_ip, *remote_ip); 00176 pcb->remote_port = remote_port; 00177 } else { 00178 fail(); 00179 } 00180 } 00181 00182 void 00183 test_tcp_counters_err(void* arg, err_t err) 00184 { 00185 struct test_tcp_counters* counters = (struct test_tcp_counters*)arg; 00186 EXPECT_RET(arg != NULL); 00187 counters->err_calls++; 00188 counters->last_err = err; 00189 } 00190 00191 static void 00192 test_tcp_counters_check_rxdata(struct test_tcp_counters* counters, struct pbuf* p) 00193 { 00194 struct pbuf* q; 00195 u32_t i, received; 00196 if(counters->expected_data == NULL) { 00197 /* no data to compare */ 00198 return; 00199 } 00200 EXPECT_RET(counters->recved_bytes + p->tot_len <= counters->expected_data_len); 00201 received = counters->recved_bytes; 00202 for(q = p; q != NULL; q = q->next) { 00203 char *data = (char*)q->payload; 00204 for(i = 0; i < q->len; i++) { 00205 EXPECT_RET(data[i] == counters->expected_data[received]); 00206 received++; 00207 } 00208 } 00209 EXPECT(received == counters->recved_bytes + p->tot_len); 00210 } 00211 00212 err_t 00213 test_tcp_counters_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err) 00214 { 00215 struct test_tcp_counters* counters = (struct test_tcp_counters*)arg; 00216 EXPECT_RETX(arg != NULL, ERR_OK); 00217 EXPECT_RETX(pcb != NULL, ERR_OK); 00218 EXPECT_RETX(err == ERR_OK, ERR_OK); 00219 00220 if (p != NULL) { 00221 if (counters->close_calls == 0) { 00222 counters->recv_calls++; 00223 test_tcp_counters_check_rxdata(counters, p); 00224 counters->recved_bytes += p->tot_len; 00225 } else { 00226 counters->recv_calls_after_close++; 00227 counters->recved_bytes_after_close += p->tot_len; 00228 } 00229 pbuf_free(p); 00230 } else { 00231 counters->close_calls++; 00232 } 00233 EXPECT(counters->recv_calls_after_close == 0 && counters->recved_bytes_after_close == 0); 00234 return ERR_OK; 00235 } 00236 00237 /** Allocate a pcb and set up the test_tcp_counters_* callbacks */ 00238 struct tcp_pcb* 00239 test_tcp_new_counters_pcb(struct test_tcp_counters* counters) 00240 { 00241 struct tcp_pcb* pcb = tcp_new(); 00242 if (pcb != NULL) { 00243 /* set up args and callbacks */ 00244 tcp_arg(pcb, counters); 00245 tcp_recv(pcb, test_tcp_counters_recv); 00246 tcp_err(pcb, test_tcp_counters_err); 00247 pcb->snd_wnd = TCP_WND; 00248 pcb->snd_wnd_max = TCP_WND; 00249 } 00250 return pcb; 00251 } 00252 00253 /** Calls tcp_input() after adjusting current_iphdr_dest */ 00254 void test_tcp_input(struct pbuf *p, struct netif *inp) 00255 { 00256 struct ip_hdr *iphdr = (struct ip_hdr*)p->payload; 00257 /* these lines are a hack, don't use them as an example :-) */ 00258 ip_addr_copy_from_ip4(*ip_current_dest_addr(), iphdr->dest); 00259 ip_addr_copy_from_ip4(*ip_current_src_addr(), iphdr->src); 00260 ip_current_netif() = inp; 00261 ip_data.current_ip4_header = iphdr; 00262 00263 /* since adding IPv6, p->payload must point to tcp header, not ip header */ 00264 pbuf_header(p, -(s16_t)sizeof(struct ip_hdr)); 00265 00266 tcp_input(p, inp); 00267 00268 ip_addr_set_zero(ip_current_dest_addr()); 00269 ip_addr_set_zero(ip_current_src_addr()); 00270 ip_current_netif() = NULL; 00271 ip_data.current_ip4_header = NULL; 00272 } 00273 00274 static err_t test_tcp_netif_output(struct netif *netif, struct pbuf *p, 00275 const ip4_addr_t *ipaddr) 00276 { 00277 struct test_tcp_txcounters *txcounters = (struct test_tcp_txcounters*)netif->state; 00278 LWIP_UNUSED_ARG(ipaddr); 00279 if (txcounters != NULL) 00280 { 00281 txcounters->num_tx_calls++; 00282 txcounters->num_tx_bytes += p->tot_len; 00283 if (txcounters->copy_tx_packets) { 00284 struct pbuf *p_copy = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); 00285 err_t err; 00286 EXPECT(p_copy != NULL); 00287 err = pbuf_copy(p_copy, p); 00288 EXPECT(err == ERR_OK); 00289 if (txcounters->tx_packets == NULL) { 00290 txcounters->tx_packets = p_copy; 00291 } else { 00292 pbuf_cat(txcounters->tx_packets, p_copy); 00293 } 00294 } 00295 } 00296 return ERR_OK; 00297 } 00298 00299 void test_tcp_init_netif(struct netif *netif, struct test_tcp_txcounters *txcounters, 00300 const ip_addr_t *ip_addr, const ip_addr_t *netmask) 00301 { 00302 struct netif *n; 00303 memset(netif, 0, sizeof(struct netif)); 00304 if (txcounters != NULL) { 00305 memset(txcounters, 0, sizeof(struct test_tcp_txcounters)); 00306 netif->state = txcounters; 00307 } 00308 netif->output = test_tcp_netif_output; 00309 netif->flags |= NETIF_FLAG_UP | NETIF_FLAG_LINK_UP; 00310 ip_addr_copy_from_ip4(netif->netmask, *ip_2_ip4(netmask)); 00311 ip_addr_copy_from_ip4(netif->ip_addr, *ip_2_ip4(ip_addr)); 00312 for (n = netif_list; n != NULL; n = n->next) { 00313 if (n == netif) { 00314 return; 00315 } 00316 } 00317 netif->next = NULL; 00318 netif_list = netif; 00319 }
Generated on Tue Jul 12 2022 13:54:55 by
