Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers tcp_helper.c Source File

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 }