/* * Closes the connection held by the PCB. * Return 1 on success, 0 on error. */ int tcp_close (tcp_socket_t *s) { mutex_lock (&s->lock); tcp_debug ("tcp_close: state=%S\n", tcp_state_name (s->state)); switch (s->state) { default: /* Has already been closed. */ tcp_queue_free (s); mutex_unlock (&s->lock); return 1; case LISTEN: case SYN_SENT: tcp_queue_free (s); mutex_unlock (&s->lock); mutex_lock (&s->ip->lock); tcp_socket_remove (s->state == LISTEN ? &s->ip->tcp_listen_sockets : &s->ip->tcp_sockets, s); mutex_unlock (&s->ip->lock); return 1; case SYN_RCVD: case ESTABLISHED: case CLOSE_WAIT: break; } for (;;) { if (tcp_enqueue (s, 0, 0, TCP_FIN, 0, 0)) break; mutex_wait (&s->lock); } s->state = (s->state == CLOSE_WAIT) ? LAST_ACK : FIN_WAIT_1; mutex_unlock (&s->lock); mutex_lock (&s->ip->lock); if (s->unsent || (s->flags & TF_ACK_NOW)) tcp_output (s); mutex_unlock (&s->ip->lock); mutex_lock (&s->lock); while (s->state != CLOSED) { if (s->state == TIME_WAIT && ! s->unsent) { tcp_queue_free (s); mutex_unlock (&s->lock); mutex_lock (&s->ip->lock); tcp_socket_remove (&s->ip->tcp_closing_sockets, s); mutex_unlock (&s->ip->lock); return 1; } mutex_wait (&s->lock); } mutex_unlock (&s->lock); return 1; }
/** * 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; }
/* * Connect to another host. Wait until connection established. * Return 1 on success, 0 on error. */ tcp_socket_t * tcp_connect (ip_t *ip, unsigned char *ipaddr, unsigned short port) { tcp_socket_t *s; unsigned long optdata; tcp_debug ("tcp_connect to port %u\n", port); if (ipaddr == 0) return 0; mutex_lock (&ip->lock); s = tcp_alloc (ip); memcpy (s->remote_ip, ipaddr, 4); s->remote_port = port; if (s->local_port == 0) { s->local_port = tcp_new_port (ip); } s->lastack = s->snd_nxt - 1; s->snd_lbb = s->snd_nxt - 1; s->snd_wnd = TCP_WND; s->ssthresh = s->mss * 10; s->state = SYN_SENT; /* Build an MSS option */ optdata = HTONL (((unsigned long)2 << 24) | ((unsigned long)4 << 16) | (((unsigned long)s->mss / 256) << 8) | (s->mss & 255)); if (! tcp_enqueue (s, 0, 0, TCP_SYN, (unsigned char*) &optdata, 4)) { mem_free (s); mutex_unlock (&ip->lock); return 0; } tcp_list_add (&ip->tcp_sockets, s); tcp_output (s); mutex_unlock (&ip->lock); mutex_lock (&s->lock); for (;;) { mutex_wait (&s->lock); if (s->state == ESTABLISHED) { mutex_unlock (&s->lock); return s; } if (s->state == CLOSED) { mutex_unlock (&s->lock); mem_free (s); return 0; } } }
/* * Send len>0 bytes. * Return a number ob transmitted bytes, or -1 on error. */ int tcp_write (tcp_socket_t *s, const void *arg, unsigned short len) { tcp_debug ("tcp_write(s=%p, arg=%p, len=%u)\n", (void*) s, arg, len); mutex_lock (&s->lock); if (s->state != SYN_SENT && s->state != SYN_RCVD && s->state != ESTABLISHED /*&& s->state != CLOSE_WAIT*/) { mutex_unlock (&s->lock); tcp_debug ("tcp_write() called in invalid state\n"); return -1; } if (len == 0) { mutex_unlock (&s->lock); return -1; } mutex_group_t *g = 0; ARRAY (group, sizeof(mutex_group_t) + 2 * sizeof(mutex_slot_t)); while (tcp_enqueue (s, (void*) arg, len, 0, 0, 0) == 0) { /* Не удалось поставить пакет в очередь - мало памяти. */ if (! g) { memset (group, 0, sizeof(group)); g = mutex_group_init (group, sizeof(group)); mutex_group_add (g, &s->lock); mutex_group_add (g, &s->ip->timer->decisec); mutex_group_listen (g); } /* Каждые 100 мсек делаем повторную попытку. */ mutex_unlock (&s->lock); mutex_group_wait (g, 0, 0); mutex_lock (&s->lock); /* Проверим, не закрылось ли соединение. */ if (s->state != SYN_SENT && s->state != SYN_RCVD && s->state != ESTABLISHED /*&& s->state != CLOSE_WAIT*/) { mutex_unlock (&s->lock); if (g) mutex_group_unlisten (g); return -1; } } mutex_unlock (&s->lock); if (g) mutex_group_unlisten (g); mutex_lock (&s->ip->lock); tcp_output (s); mutex_unlock (&s->ip->lock); return len; }
/*-----------------------------------------------------------------------------------*/ err_t tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy) { if(pcb->state == SYN_SENT || pcb->state == SYN_RCVD || pcb->state == ESTABLISHED || pcb->state == CLOSE_WAIT) { if(len > 0) { return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0); } return ERR_OK; } else { return ERR_CONN; } }
/** * Write data for sending (but does not send it immediately). * * It waits in the expectation of more data being sent soon (as * it can send them more efficiently by combining them together). * To prompt the system to send data now, call tcp_output() after * calling tcp_write(). * * @param pcb Protocol control block of the TCP connection to enqueue data for. * @param data pointer to the data to send * @param len length (in bytes) of the data to send * @param apiflags combination of following flags : * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent, * @return ERR_OK if enqueued, another err_t on error * * @see tcp_write() */ err_t tcp_write(struct tcp_pcb *pcb, const void *data, u16_t len, u8_t apiflags) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n", (void *)pcb, data, len, (u16_t)apiflags)); /* connection is in valid state for data transmission? */ if (pcb->state == ESTABLISHED || pcb->state == CLOSE_WAIT || pcb->state == SYN_SENT || pcb->state == SYN_RCVD) { if (len > 0) { #if LWIP_TCP_TIMESTAMPS return tcp_enqueue(pcb, (void *)data, len, 0, apiflags, pcb->flags & TF_TIMESTAMP ? TF_SEG_OPTS_TS : 0); #else return tcp_enqueue(pcb, (void *)data, len, 0, apiflags, 0); #endif } return ERR_OK; } else { LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | LWIP_DBG_LEVEL_SEVERE, ("tcp_write() called in invalid state\n")); return ERR_CONN; } }
/** * 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; }
err_t tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, arg=%p, len=%u, copy=%d)\n", (void *)pcb, arg, len, (unsigned int)copy)); if (pcb->state == SYN_SENT || pcb->state == SYN_RCVD || pcb->state == ESTABLISHED || pcb->state == CLOSE_WAIT) { if (len > 0) { return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0); } return ERR_OK; } else { LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_STATE | 3, ("tcp_write() called in invalid state\n")); return ERR_CONN; } }
err_t tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, arg=%p, len=%"U16_F", copy=%"U16_F")\n", (void *)pcb, arg, len, (u16_t)copy)); /* connection is in valid state for data transmission? */ if (pcb->state == ESTABLISHED || pcb->state == CLOSE_WAIT || pcb->state == SYN_SENT || pcb->state == SYN_RCVD) { if (len > 0) { return tcp_enqueue(pcb, (void *)arg, len, 0, copy, NULL, 0); } return ERR_OK; } else { LWIP_DEBUGF(TCP_OUTPUT_DEBUG | DBG_STATE | 3, ("tcp_write() called in invalid state\n")); return ERR_CONN; } }
/* * Flush output buffer. */ static void stream_flush (tcp_stream_t *u) { /*debug_printf ("tstream output"); buf_print_data (u->outdata, len);*/ tcp_socket_t* s = u->socket; unsigned char* src = u->outdata; while (u->outptr != src){ int len = u->outptr - src; int sent = tcp_enqueue (u->socket, (void*) u->outdata, len, 0); tcp_debug("tcp-stream: sent %d bytes\n", sent); src += sent; if (sent != len) { # if TCP_LOCK_STYLE < TCP_LOCK_RELAXED mutex_unlock (&s->lock); # endif tcp_output (s); # if TCP_LOCK_STYLE < TCP_LOCK_RELAXED mutex_lock (&s->lock); # endif mutex_wait (&s->lock); } } u->outptr = u->outdata; }
err_t tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags) { /* no data, no length, flags, copy=1, no optdata, no optdatalen */ return tcp_enqueue(pcb, NULL, 0, flags, 1, NULL, 0); }
/* * Send len>0 bytes. * Return a number ob transmitted bytes, or -1 on error. */ int tcp_write (tcp_socket_t *s, const void *arg, unsigned short len) { tcp_debug ("tcp_write(s=%p, arg=%p, len=%u)\n", (void*) s, arg, len); if (!tcp_socket_is_state(s, TCP_STATES_TRANSFER)) { tcp_debug ("tcp_write() called in invalid state\n"); return -1; } if (len == 0) { return -1; } mutex_group_t *g = 0; ARRAY (group, sizeof(mutex_group_t) + 2 * sizeof(mutex_slot_t)); const char* ptr = (const char*)arg; unsigned left = len; while (left > 0){ int sent = tcp_enqueue (s, ptr, len, 0); left -= sent; ptr += sent; if (left == 0) break; # if TCP_LOCK_STYLE <= TCP_LOCK_SURE if (mutex_is_my(&s->lock)) mutex_unlock (&s->lock); tcp_output_poll (s); # elif TCP_LOCK_STYLE <= TCP_LOCK_RELAXED tcp_output_poll (s); mutex_unlock (&s->lock); # endif /* Не удалось поставить пакет в очередь - мало памяти. */ if (! g) { memset (group, 0, sizeof(group)); g = mutex_group_init (group, sizeof(group)); mutex_group_add (g, &s->lock); mutex_group_add (g, &s->ip->timer->decisec); mutex_group_listen (g); } /* Каждые 100 мсек делаем повторную попытку. */ mutex_group_wait (g, 0, 0); /* Проверим, не закрылось ли соединение. */ if (!tcp_socket_is_state(s, TCP_STATES_TRANSFER)) { if (g) mutex_group_unlisten (g); return -1; } } if (g) mutex_group_unlisten (g); # if TCP_LOCK_STYLE <= TCP_LOCK_SURE mutex_unlock (&s->lock); tcp_output (s); # elif TCP_LOCK_STYLE <= TCP_LOCK_RELAXED tcp_output (s); mutex_unlock (&s->lock); # endif return len; }
/** * Called by tcp_input() when a segment arrives for a listening * connection (from tcp_input()). * * @param pcb the tcp_pcb_listen for which a segment arrived * @return ERR_OK if the segment was processed * another err_t on error * * @note the return value is not (yet?) used in tcp_input() * @note the segment which arrived is saved in global variables, therefore only the pcb * involved is passed as a parameter to this function */ static err_t tcp_listen_input(struct tcp_pcb_listen *pcb) { struct tcp_pcb *npcb; u32_t optdata; /* In the LISTEN state, we check for incoming SYN segments, creates a new PCB, and responds with a SYN|ACK. */ if (flags & TCP_ACK) { /* For incoming segments with the ACK flag set, respond with a RST. */ LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); tcp_rst(ackno + 1, seqno + tcplen, &(iphdr->dest), &(iphdr->src), tcphdr->dest, tcphdr->src); } else if (flags & TCP_SYN) { LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); #if TCP_LISTEN_BACKLOG if (pcb->accepts_pending >= pcb->backlog) { return ERR_ABRT; } #endif /* TCP_LISTEN_BACKLOG */ npcb = tcp_alloc(pcb->prio); /* If a new PCB could not be created (probably due to lack of memory), we don't do anything, but rely on the sender will retransmit the SYN at a time when we have more memory available. */ if (npcb == NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n")); TCP_STATS_INC(tcp.memerr); return ERR_MEM; } #if TCP_LISTEN_BACKLOG pcb->accepts_pending++; #endif /* TCP_LISTEN_BACKLOG */ /* Set up the new PCB. */ ip_addr_set(&(npcb->local_ip), &(iphdr->dest)); npcb->local_port = pcb->local_port; ip_addr_set(&(npcb->remote_ip), &(iphdr->src)); npcb->remote_port = tcphdr->src; npcb->state = SYN_RCVD; npcb->rcv_nxt = seqno + 1; npcb->snd_wnd = tcphdr->wnd; npcb->ssthresh = npcb->snd_wnd; npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */ npcb->callback_arg = pcb->callback_arg; #if LWIP_CALLBACK_API npcb->accept = pcb->accept; #endif /* LWIP_CALLBACK_API */ /* inherit socket options */ npcb->so_options = pcb->so_options & (SOF_DEBUG|SOF_DONTROUTE|SOF_KEEPALIVE|SOF_OOBINLINE|SOF_LINGER); /* Register the new PCB so that we can begin receiving segments for it. */ TCP_REG(&tcp_active_pcbs, npcb); /* Parse any options in the SYN. */ tcp_parseopt(npcb); #if TCP_CALCULATE_EFF_SEND_MSS npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip)); #endif /* TCP_CALCULATE_EFF_SEND_MSS */ snmp_inc_tcppassiveopens(); /* Build an MSS option. */ optdata = TCP_BUILD_MSS_OPTION(); /* Send a SYN|ACK together with the MSS option. */ tcp_enqueue(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, (u8_t *)&optdata, 4); return tcp_output(npcb); } return ERR_OK; }
/** * 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; }
tcp_socket_t * tcp_accept (tcp_socket_t *s) { tcp_socket_t *ns; buf_t *p; ip_hdr_t *iph; tcp_hdr_t *h; unsigned long optdata; again: mutex_lock (&s->lock); for (;;) { if (s->state != LISTEN) { mutex_unlock (&s->lock); tcp_debug ("tcp_accept: called in invalid state\n"); return 0; } if (! tcp_queue_is_empty (s)) { p = tcp_queue_get (s); break; } mutex_wait (&s->lock); } mutex_unlock (&s->lock); /* Create a new PCB, and respond with a SYN|ACK. * If a new PCB could not be created (probably due to lack of memory), * we don't do anything, but rely on the sender will retransmit * the SYN at a time when we have more memory available. */ mutex_lock (&s->ip->lock); ns = tcp_alloc (s->ip); if (ns == 0) { tcp_debug ("tcp_accept: could not allocate PCB\n"); ++s->ip->tcp_in_discards; mutex_unlock (&s->ip->lock); buf_free (p); goto again; } h = (tcp_hdr_t*) p->payload; iph = ((ip_hdr_t*) p->payload) - 1; /* Set up the new PCB. */ memcpy (ns->local_ip, iph->dest, 4); ns->local_port = s->local_port; memcpy (ns->remote_ip, iph->src, 4); ns->remote_port = h->src; ns->state = SYN_RCVD; ns->rcv_nxt = s->ip->tcp_input_seqno + 1; ns->snd_wnd = h->wnd; ns->ssthresh = ns->snd_wnd; ns->snd_wl1 = s->ip->tcp_input_seqno; ns->ip = s->ip; /* Register the new PCB so that we can begin receiving * segments for it. */ tcp_list_add (&s->ip->tcp_sockets, ns); /* Parse any options in the SYN. */ tcp_parseopt (ns, h); /* Build an MSS option. */ optdata = HTONL (((unsigned long)2 << 24) | ((unsigned long)4 << 16) | (((unsigned long)ns->mss / 256) << 8) | (ns->mss & 255)); buf_free (p); /* Send a SYN|ACK together with the MSS option. */ tcp_enqueue (ns, 0, 0, TCP_SYN | TCP_ACK, (unsigned char*) &optdata, 4); tcp_output (ns); mutex_unlock (&s->ip->lock); return ns; }
/** * Called by tcp_close() to send a segment including flags but not data. * * @param pcb the tcp_pcb over which to send a segment * @param flags the flags to set in the segment header * @return ERR_OK if sent, another err_t otherwise */ err_t tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags) { /* no data, no length, flags, copy=1, no optdata */ return tcp_enqueue(pcb, NULL, 0, flags, TCP_WRITE_FLAG_COPY, 0); }
err_t tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags) { return tcp_enqueue(pcb, NULL, 0, flags, 1, NULL, 0); }