Marco Zecchini
/
Example_RTOS
Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
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 u32_t iss; 00145 00146 /* @todo: are these all states? */ 00147 /* @todo: remove from previous list */ 00148 pcb->state = state; 00149 00150 iss = tcp_next_iss(pcb); 00151 pcb->snd_wl2 = iss; 00152 pcb->snd_nxt = iss; 00153 pcb->lastack = iss; 00154 pcb->snd_lbb = iss; 00155 00156 if (state == ESTABLISHED) { 00157 TCP_REG(&tcp_active_pcbs, pcb); 00158 ip_addr_copy(pcb->local_ip, *local_ip); 00159 pcb->local_port = local_port; 00160 ip_addr_copy(pcb->remote_ip, *remote_ip); 00161 pcb->remote_port = remote_port; 00162 } else if(state == LISTEN) { 00163 TCP_REG(&tcp_listen_pcbs.pcbs, pcb); 00164 ip_addr_copy(pcb->local_ip, *local_ip); 00165 pcb->local_port = local_port; 00166 } else if(state == TIME_WAIT) { 00167 TCP_REG(&tcp_tw_pcbs, pcb); 00168 ip_addr_copy(pcb->local_ip, *local_ip); 00169 pcb->local_port = local_port; 00170 ip_addr_copy(pcb->remote_ip, *remote_ip); 00171 pcb->remote_port = remote_port; 00172 } else { 00173 fail(); 00174 } 00175 } 00176 00177 void 00178 test_tcp_counters_err(void* arg, err_t err) 00179 { 00180 struct test_tcp_counters* counters = (struct test_tcp_counters*)arg; 00181 EXPECT_RET(arg != NULL); 00182 counters->err_calls++; 00183 counters->last_err = err; 00184 } 00185 00186 static void 00187 test_tcp_counters_check_rxdata(struct test_tcp_counters* counters, struct pbuf* p) 00188 { 00189 struct pbuf* q; 00190 u32_t i, received; 00191 if(counters->expected_data == NULL) { 00192 /* no data to compare */ 00193 return; 00194 } 00195 EXPECT_RET(counters->recved_bytes + p->tot_len <= counters->expected_data_len); 00196 received = counters->recved_bytes; 00197 for(q = p; q != NULL; q = q->next) { 00198 char *data = (char*)q->payload; 00199 for(i = 0; i < q->len; i++) { 00200 EXPECT_RET(data[i] == counters->expected_data[received]); 00201 received++; 00202 } 00203 } 00204 EXPECT(received == counters->recved_bytes + p->tot_len); 00205 } 00206 00207 err_t 00208 test_tcp_counters_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err) 00209 { 00210 struct test_tcp_counters* counters = (struct test_tcp_counters*)arg; 00211 EXPECT_RETX(arg != NULL, ERR_OK); 00212 EXPECT_RETX(pcb != NULL, ERR_OK); 00213 EXPECT_RETX(err == ERR_OK, ERR_OK); 00214 00215 if (p != NULL) { 00216 if (counters->close_calls == 0) { 00217 counters->recv_calls++; 00218 test_tcp_counters_check_rxdata(counters, p); 00219 counters->recved_bytes += p->tot_len; 00220 } else { 00221 counters->recv_calls_after_close++; 00222 counters->recved_bytes_after_close += p->tot_len; 00223 } 00224 pbuf_free(p); 00225 } else { 00226 counters->close_calls++; 00227 } 00228 EXPECT(counters->recv_calls_after_close == 0 && counters->recved_bytes_after_close == 0); 00229 return ERR_OK; 00230 } 00231 00232 /** Allocate a pcb and set up the test_tcp_counters_* callbacks */ 00233 struct tcp_pcb* 00234 test_tcp_new_counters_pcb(struct test_tcp_counters* counters) 00235 { 00236 struct tcp_pcb* pcb = tcp_new(); 00237 if (pcb != NULL) { 00238 /* set up args and callbacks */ 00239 tcp_arg(pcb, counters); 00240 tcp_recv(pcb, test_tcp_counters_recv); 00241 tcp_err(pcb, test_tcp_counters_err); 00242 pcb->snd_wnd = TCP_WND; 00243 pcb->snd_wnd_max = TCP_WND; 00244 } 00245 return pcb; 00246 } 00247 00248 /** Calls tcp_input() after adjusting current_iphdr_dest */ 00249 void test_tcp_input(struct pbuf *p, struct netif *inp) 00250 { 00251 struct ip_hdr *iphdr = (struct ip_hdr*)p->payload; 00252 /* these lines are a hack, don't use them as an example :-) */ 00253 ip_addr_copy_from_ip4(*ip_current_dest_addr(), iphdr->dest); 00254 ip_addr_copy_from_ip4(*ip_current_src_addr(), iphdr->src); 00255 ip_current_netif() = inp; 00256 ip_data.current_ip4_header = iphdr; 00257 00258 /* since adding IPv6, p->payload must point to tcp header, not ip header */ 00259 pbuf_header(p, -(s16_t)sizeof(struct ip_hdr)); 00260 00261 tcp_input(p, inp); 00262 00263 ip_addr_set_zero(ip_current_dest_addr()); 00264 ip_addr_set_zero(ip_current_src_addr()); 00265 ip_current_netif() = NULL; 00266 ip_data.current_ip4_header = NULL; 00267 } 00268 00269 static err_t test_tcp_netif_output(struct netif *netif, struct pbuf *p, 00270 const ip4_addr_t *ipaddr) 00271 { 00272 struct test_tcp_txcounters *txcounters = (struct test_tcp_txcounters*)netif->state; 00273 LWIP_UNUSED_ARG(ipaddr); 00274 if (txcounters != NULL) 00275 { 00276 txcounters->num_tx_calls++; 00277 txcounters->num_tx_bytes += p->tot_len; 00278 if (txcounters->copy_tx_packets) { 00279 struct pbuf *p_copy = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); 00280 err_t err; 00281 EXPECT(p_copy != NULL); 00282 err = pbuf_copy(p_copy, p); 00283 EXPECT(err == ERR_OK); 00284 if (txcounters->tx_packets == NULL) { 00285 txcounters->tx_packets = p_copy; 00286 } else { 00287 pbuf_cat(txcounters->tx_packets, p_copy); 00288 } 00289 } 00290 } 00291 return ERR_OK; 00292 } 00293 00294 void test_tcp_init_netif(struct netif *netif, struct test_tcp_txcounters *txcounters, 00295 ip_addr_t *ip_addr, ip_addr_t *netmask) 00296 { 00297 struct netif *n; 00298 memset(netif, 0, sizeof(struct netif)); 00299 if (txcounters != NULL) { 00300 memset(txcounters, 0, sizeof(struct test_tcp_txcounters)); 00301 netif->state = txcounters; 00302 } 00303 netif->output = test_tcp_netif_output; 00304 netif->flags |= NETIF_FLAG_UP | NETIF_FLAG_LINK_UP; 00305 ip_addr_copy_from_ip4(netif->netmask, *ip_2_ip4(netmask)); 00306 ip_addr_copy_from_ip4(netif->ip_addr, *ip_2_ip4(ip_addr)); 00307 for (n = netif_list; n != NULL; n = n->next) { 00308 if (n == netif) { 00309 return; 00310 } 00311 } 00312 netif->next = NULL; 00313 netif_list = netif; 00314 }
Generated on Sun Jul 17 2022 08:25:31 by 1.7.2