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