static void tcp_setup(void) { /* reset iss to default (6510) */ tcp_ticks = 0; tcp_ticks = 0 - (tcp_next_iss() - 6510); tcp_next_iss(); tcp_ticks = 0; test_tcp_timer = 0; tcp_remove_all(); }
static void tcp_setup(void) { old_netif_list = netif_list; old_netif_default = netif_default; netif_list = NULL; netif_default = NULL; /* reset iss to default (6510) */ tcp_ticks = 0; tcp_ticks = 0 - (tcp_next_iss(NULL) - 6510); tcp_next_iss(NULL); tcp_ticks = 0; test_tcp_timer = 0; tcp_remove_all(); lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT)); }
/** * Connects to another host. The function given as the "connected" * argument will be called when the connection has been established. * * @param pcb the tcp_pcb used to establish the connection * @param ipaddr the remote ip address to connect to * @param port the remote tcp port to connect to * @param connected callback function to call when connected (or on error) * @return ERR_VAL if invalid arguments are given * ERR_OK if connect request has been sent * other err_t values if connect request couldn't be sent */ err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port, err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err)) { err_t ret; u32_t iss; LWIP_ERROR("tcp_connect: can only connected from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); if (ipaddr != NULL) { pcb->remote_ip = *ipaddr; } else { return ERR_VAL; } pcb->remote_port = port; if (pcb->local_port == 0) { pcb->local_port = tcp_new_port(); } iss = tcp_next_iss(); pcb->rcv_nxt = 0; pcb->snd_nxt = iss; pcb->lastack = iss - 1; pcb->snd_lbb = iss - 1; pcb->rcv_wnd = TCP_WND; pcb->rcv_ann_wnd = TCP_WND; pcb->rcv_ann_right_edge = pcb->rcv_nxt; pcb->snd_wnd = TCP_WND; /* As initial send MSS, we use TCP_MSS but limit it to 536. The send MSS is updated when an MSS option is received. */ pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS; #if TCP_CALCULATE_EFF_SEND_MSS pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr); #endif /* TCP_CALCULATE_EFF_SEND_MSS */ pcb->cwnd = 1; pcb->ssthresh = pcb->mss * 10; pcb->state = SYN_SENT; #if LWIP_CALLBACK_API pcb->connected = connected; #endif /* LWIP_CALLBACK_API */ TCP_RMV(&tcp_bound_pcbs, pcb); TCP_REG(&tcp_active_pcbs, pcb); snmp_inc_tcpactiveopens(); ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, TF_SEG_OPTS_MSS #if LWIP_TCP_TIMESTAMPS | TF_SEG_OPTS_TS #endif ); if (ret == ERR_OK) { tcp_output(pcb); } return ret; }
/** * Connects to another host. The function given as the "connected" * argument will be called when the connection has been established. * */ err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port, err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err)) { u32_t optdata; err_t ret; u32_t iss; LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); if (ipaddr != NULL) { pcb->remote_ip = *ipaddr; } else { return ERR_VAL; } pcb->remote_port = port; if (pcb->local_port == 0) { pcb->local_port = tcp_new_port(); } iss = tcp_next_iss(); pcb->rcv_nxt = 0; pcb->snd_nxt = iss; pcb->lastack = iss - 1; pcb->snd_lbb = iss - 1; pcb->rcv_wnd = TCP_WND; pcb->snd_wnd = TCP_WND; pcb->mss = TCP_MSS; pcb->cwnd = 1; pcb->ssthresh = pcb->mss * 10; pcb->state = SYN_SENT; #if LWIP_CALLBACK_API pcb->connected = connected; #endif /* LWIP_CALLBACK_API */ TCP_REG(&tcp_active_pcbs, pcb); snmp_inc_tcpactiveopens(); /* Build an MSS option */ optdata = htonl(((u32_t)2 << 24) | ((u32_t)4 << 16) | (((u32_t)pcb->mss / 256) << 8) | (pcb->mss & 255)); ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, (u8_t *)&optdata, 4); if (ret == ERR_OK) { tcp_output(pcb); } return ret; }
uint8 tcp_connect(TCP_PCB *pcb, IP_ADDR *ipaddr, uint16 port) { uint8 ret; uint32 iss; if (ipaddr != NULL) { pcb->remote_ip = *ipaddr; } else { return ERR_VAL; } pcb->remote_port = port; if (pcb->local_port == 0) { pcb->local_port = 4096; } iss = tcp_next_iss(); pcb->rcv_nxt = 0; pcb->snd_nxt = iss; pcb->lastack = iss - 1; pcb->snd_lbb = iss - 1; pcb->rcv_wnd = TCP_WND; pcb->rcv_ann_wnd = TCP_WND; pcb->rcv_ann_right_edge = pcb->rcv_nxt; pcb->snd_wnd = TCP_WND; /* As initial send MSS, we use TCP_MSS but limit it to 536. The send MSS is updated when an MSS option is received. */ pcb->mss = (TCP_MSS > 1460) ? 1460 : TCP_MSS;//(TCP_MSS > 536) ? 536 : TCP_MSS; pcb->cwnd = 1; pcb->ssthresh = TCP_WND; pcb->state = SYN_SENT; printf("SYN\n"); ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, TCP_WRITE_FLAG_COPY, TF_SEG_OPTS_MSS); if (ret == ERR_OK) { tcp_output(pcb); } return ret; }
/** * Connects to another host. The function given as the "connected" * argument will be called when the connection has been established. * * @param pcb the tcp_pcb used to establish the connection * @param ipaddr the remote ip address to connect to * @param port the remote tcp port to connect to * @param connected callback function to call when connected (or on error) * @return ERR_VAL if invalid arguments are given * ERR_OK if connect request has been sent * other err_t values if connect request couldn't be sent */ err_t tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, tcp_connected_fn connected) { err_t ret; u32_t iss; u16_t old_local_port; LWIP_ERROR("tcp_connect: can only connect from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); if (ipaddr != NULL) { pcb->remote_ip = *ipaddr; } else { return ERR_VAL; } pcb->remote_port = port; /* check if we have a route to the remote host */ if (ip_addr_isany(&(pcb->local_ip))) { /* no local IP address set, yet. */ struct netif *netif = ip_route(&(pcb->remote_ip)); if (netif == NULL) { /* Don't even try to send a SYN packet if we have no route since that will fail. */ return ERR_RTE; } /* Use the netif's IP address as local address. */ ip_addr_copy(pcb->local_ip, netif->ip_addr); } old_local_port = pcb->local_port; if (pcb->local_port == 0) { pcb->local_port = tcp_new_port(); } #if SO_REUSE if ((pcb->so_options & SOF_REUSEADDR) != 0) { /* Since SOF_REUSEADDR allows reusing a local address, we have to make sure now that the 5-tuple is unique. */ struct tcp_pcb *cpcb; int i; /* Don't check listen- and bound-PCBs, check active- and TIME-WAIT PCBs. */ for (i = 2; i < NUM_TCP_PCB_LISTS; i++) { for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { if ((cpcb->local_port == pcb->local_port) && (cpcb->remote_port == port) && ip_addr_cmp(&cpcb->local_ip, &pcb->local_ip) && ip_addr_cmp(&cpcb->remote_ip, ipaddr)) { /* linux returns EISCONN here, but ERR_USE should be OK for us */ return ERR_USE; } } } } #endif /* SO_REUSE */ iss = tcp_next_iss(); pcb->rcv_nxt = 0; pcb->snd_nxt = iss; pcb->lastack = iss - 1; pcb->snd_lbb = iss - 1; pcb->rcv_wnd = TCP_WND; pcb->rcv_ann_wnd = TCP_WND; pcb->rcv_ann_right_edge = pcb->rcv_nxt; pcb->snd_wnd = TCP_WND; /* As initial send MSS, we use TCP_MSS but limit it to 536. The send MSS is updated when an MSS option is received. */ pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS; #if TCP_CALCULATE_EFF_SEND_MSS pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr); #endif /* TCP_CALCULATE_EFF_SEND_MSS */ pcb->cwnd = 1; pcb->ssthresh = pcb->mss * 10; #if LWIP_CALLBACK_API pcb->connected = connected; #else /* LWIP_CALLBACK_API */ LWIP_UNUSED_ARG(connected); #endif /* LWIP_CALLBACK_API */ /* Send a SYN together with the MSS option. */ ret = tcp_enqueue_flags(pcb, TCP_SYN); if (ret == ERR_OK) { /* SYN segment was enqueued, changed the pcbs state now */ pcb->state = SYN_SENT; if (old_local_port != 0) { TCP_RMV(&tcp_bound_pcbs, pcb); } TCP_REG(&tcp_active_pcbs, pcb); snmp_inc_tcpactiveopens(); tcp_output(pcb); } return ret; }
END_TEST /** Send data with sequence numbers that wrap around the u32_t range. * Then, provoke RTO retransmission and check that all * segment lists are still properly sorted. */ START_TEST(test_tcp_rto_rexmit_wraparound) { struct netif netif; struct test_tcp_txcounters txcounters; struct test_tcp_counters counters; struct tcp_pcb* pcb; ip_addr_t remote_ip, local_ip, netmask; u16_t remote_port = 0x100, local_port = 0x101; err_t err; #define SEQNO1 (0xFFFFFF00 - TCP_MSS) #define ISS 6510 u16_t i, sent_total = 0; u32_t seqnos[] = { SEQNO1, SEQNO1 + (1 * TCP_MSS), SEQNO1 + (2 * TCP_MSS), SEQNO1 + (3 * TCP_MSS), SEQNO1 + (4 * TCP_MSS), SEQNO1 + (5 * TCP_MSS)}; LWIP_UNUSED_ARG(_i); for (i = 0; i < sizeof(tx_data); i++) { tx_data[i] = (u8_t)i; } /* initialize local vars */ IP_ADDR4(&local_ip, 192, 168, 1, 1); IP_ADDR4(&remote_ip, 192, 168, 1, 2); IP_ADDR4(&netmask, 255, 255, 255, 0); test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); memset(&counters, 0, sizeof(counters)); /* create and initialize the pcb */ tcp_ticks = 0; tcp_ticks = 0 - tcp_next_iss(); tcp_ticks = SEQNO1 - tcp_next_iss(); pcb = test_tcp_new_counters_pcb(&counters); EXPECT_RET(pcb != NULL); EXPECT(pcb->lastack == SEQNO1); tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); pcb->mss = TCP_MSS; /* disable initial congestion window (we don't send a SYN here...) */ pcb->cwnd = 2*TCP_MSS; /* send 6 mss-sized segments */ for (i = 0; i < 6; i++) { err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY); EXPECT_RET(err == ERR_OK); sent_total += TCP_MSS; } check_seqnos(pcb->unsent, 6, seqnos); EXPECT(pcb->unacked == NULL); err = tcp_output(pcb); EXPECT(txcounters.num_tx_calls == 2); EXPECT(txcounters.num_tx_bytes == 2 * (TCP_MSS + 40U)); memset(&txcounters, 0, sizeof(txcounters)); check_seqnos(pcb->unacked, 2, seqnos); check_seqnos(pcb->unsent, 4, &seqnos[2]); /* call the tcp timer some times */ for (i = 0; i < 10; i++) { test_tcp_tmr(); EXPECT(txcounters.num_tx_calls == 0); } /* 11th call to tcp_tmr: RTO rexmit fires */ test_tcp_tmr(); EXPECT(txcounters.num_tx_calls == 1); check_seqnos(pcb->unacked, 1, seqnos); check_seqnos(pcb->unsent, 5, &seqnos[1]); /* fake greater cwnd */ pcb->cwnd = pcb->snd_wnd; /* send more data */ err = tcp_output(pcb); EXPECT(err == ERR_OK); /* check queues are sorted */ EXPECT(pcb->unsent == NULL); check_seqnos(pcb->unacked, 6, seqnos); /* make sure the pcb is freed */ EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 1); tcp_abort(pcb); EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 0); }
END_TEST /** Send data with sequence numbers that wrap around the u32_t range. * Then, provoke RTO retransmission and check that all * segment lists are still properly sorted. */ START_TEST(test_tcp_rto_rexmit_wraparound) { struct netif netif; struct test_tcp_txcounters txcounters; struct test_tcp_counters counters; struct tcp_pcb* pcb; err_t err; size_t i; u16_t sent_total = 0; LWIP_UNUSED_ARG(_i); for (i = 0; i < sizeof(tx_data); i++) { tx_data[i] = (u8_t)i; } /* initialize local vars */ test_tcp_init_netif(&netif, &txcounters, &test_local_ip, &test_netmask); memset(&counters, 0, sizeof(counters)); /* create and initialize the pcb */ tcp_ticks = 0; tcp_ticks = 0 - tcp_next_iss(NULL); tcp_ticks = SEQNO1 - tcp_next_iss(NULL); pcb = test_tcp_new_counters_pcb(&counters); EXPECT_RET(pcb != NULL); tcp_set_state(pcb, ESTABLISHED, &test_local_ip, &test_remote_ip, TEST_LOCAL_PORT, TEST_REMOTE_PORT); pcb->mss = TCP_MSS; /* disable initial congestion window (we don't send a SYN here...) */ pcb->cwnd = 2*TCP_MSS; /* send 6 mss-sized segments */ for (i = 0; i < 6; i++) { err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY); EXPECT_RET(err == ERR_OK); sent_total += TCP_MSS; } check_seqnos(pcb->unsent, 6, seqnos); EXPECT(pcb->unacked == NULL); err = tcp_output(pcb); EXPECT(txcounters.num_tx_calls == 2); EXPECT(txcounters.num_tx_bytes == 2 * (TCP_MSS + 40U)); memset(&txcounters, 0, sizeof(txcounters)); check_seqnos(pcb->unacked, 2, seqnos); check_seqnos(pcb->unsent, 4, &seqnos[2]); /* call the tcp timer some times */ for (i = 0; i < 10; i++) { test_tcp_tmr(); EXPECT(txcounters.num_tx_calls == 0); } /* 11th call to tcp_tmr: RTO rexmit fires */ test_tcp_tmr(); EXPECT(txcounters.num_tx_calls == 1); check_seqnos(pcb->unacked, 1, seqnos); check_seqnos(pcb->unsent, 5, &seqnos[1]); /* fake greater cwnd */ pcb->cwnd = pcb->snd_wnd; /* send more data */ err = tcp_output(pcb); EXPECT(err == ERR_OK); /* check queues are sorted */ EXPECT(pcb->unsent == NULL); check_seqnos(pcb->unacked, 6, seqnos); /* make sure the pcb is freed */ EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 1); tcp_abort(pcb); EXPECT_RET(MEMP_STATS_GET(used, MEMP_TCP_PCB) == 0); }
/** * Connects to another host. The function given as the "connected" * argument will be called when the connection has been established. * * @param pcb the tcp_pcb used to establish the connection * @param ipaddr the remote ip address to connect to * @param port the remote tcp port to connect to * @param connected callback function to call when connected (or on error) * @return ERR_VAL if invalid arguments are given * ERR_OK if connect request has been sent * other err_t values if connect request couldn't be sent */ err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port, err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err)) { err_t ret; u32_t iss; LWIP_ERROR("tcp_connect: can only connected from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); /* 远端IP地址有效,则记录到TCP控制块中 */ if (ipaddr != NULL) { pcb->remote_ip = *ipaddr; } else { return ERR_VAL; } /* 记录远端PORT */ pcb->remote_port = port; /* 如果本地端口未绑定,则绑定一个短暂端口 */ if (pcb->local_port == 0) { pcb->local_port = tcp_new_port(); } /* 获取初始序号 */ iss = tcp_next_iss(); /* 设置接收窗口下一个接收的序号 */ pcb->rcv_nxt = 0; /* 设置发送窗口各个字段 */ pcb->snd_nxt = iss; pcb->lastack = iss - 1; pcb->snd_lbb = iss - 1; /* 设置接收窗口各个字段 */ pcb->rcv_wnd = TCP_WND; pcb->rcv_ann_wnd = TCP_WND; pcb->rcv_ann_right_edge = pcb->rcv_nxt; pcb->snd_wnd = TCP_WND; /* As initial send MSS, we use TCP_MSS but limit it to 536. The send MSS is updated when an MSS option is received. */ /* 设置MSS */ pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS; #if TCP_CALCULATE_EFF_SEND_MSS pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr); #endif /* TCP_CALCULATE_EFF_SEND_MSS */ /* 初始化阻塞窗口 */ pcb->cwnd = 1; pcb->ssthresh = pcb->mss * 10; /* TCP控制块状态设为SYN_SENT */ pcb->state = SYN_SENT; #if LWIP_CALLBACK_API /* 设置回调函数 */ pcb->connected = connected; #endif /* LWIP_CALLBACK_API */ /* 把TCP控制块从tcp_bound_pcbs链表移除 */ TCP_RMV(&tcp_bound_pcbs, pcb); /* 把TCP控制块插入tcp_active_pcbs链表 */ TCP_REG(&tcp_active_pcbs, pcb); snmp_inc_tcpactiveopens(); /* 构造TCP报文,长度为0,SYN置1,并包含MSS选项字段 */ ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, TF_SEG_OPTS_MSS #if LWIP_TCP_TIMESTAMPS | TF_SEG_OPTS_TS #endif ); if (ret == ERR_OK) { /* 发送构造的TCP报文 */ tcp_output(pcb); } return ret; }