/** Create a TCP segment usable for passing to tcp_input */ struct pbuf* tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip, u16_t src_port, u16_t dst_port, void* data, size_t data_len, u32_t seqno, u32_t ackno, u8_t headerflags) { struct pbuf* p; struct ip_hdr* iphdr; struct tcp_hdr* tcphdr; u16_t pbuf_len = (u16_t)(sizeof(struct ip_hdr) + sizeof(struct tcp_hdr) + data_len); p = pbuf_alloc(PBUF_RAW, pbuf_len, PBUF_POOL); EXPECT_RETNULL(p != NULL); EXPECT_RETNULL(p->next == NULL); memset(p->payload, 0, p->len); iphdr = p->payload; /* fill IP header */ iphdr->dest.addr = dst_ip->addr; iphdr->src.addr = src_ip->addr; IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, 0); IPH_LEN_SET(iphdr, htons(p->tot_len)); IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); pbuf_header(p, -(s16_t)sizeof(struct ip_hdr)); tcphdr = p->payload; tcphdr->src = htons(src_port); tcphdr->dest = htons(dst_port); tcphdr->seqno = htonl(seqno); tcphdr->ackno = htonl(ackno); TCPH_HDRLEN_SET(tcphdr, sizeof(struct tcp_hdr)/4); TCPH_FLAGS_SET(tcphdr, headerflags); tcphdr->wnd = htons(TCP_WND); /* copy data */ memcpy((char*)tcphdr + sizeof(struct tcp_hdr), data, data_len); /* calculate checksum */ tcphdr->chksum = inet_chksum_pseudo(p, src_ip, dst_ip, IP_PROTO_TCP, p->tot_len); pbuf_header(p, sizeof(struct ip_hdr)); return p; }
/** Create a TCP segment usable for passing to tcp_input */ static struct pbuf* tcp_create_segment_wnd(ip_addr_t* src_ip, ip_addr_t* dst_ip, u16_t src_port, u16_t dst_port, void* data, size_t data_len, u32_t seqno, u32_t ackno, u8_t headerflags, u16_t wnd) { struct pbuf *p, *q; struct ip_hdr* iphdr; struct tcp_hdr* tcphdr; u16_t pbuf_len = (u16_t)(sizeof(struct ip_hdr) + sizeof(struct tcp_hdr) + data_len); LWIP_ASSERT("data_len too big", data_len <= 0xFFFF); p = pbuf_alloc(PBUF_RAW, pbuf_len, PBUF_POOL); EXPECT_RETNULL(p != NULL); /* first pbuf must be big enough to hold the headers */ EXPECT_RETNULL(p->len >= (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr))); if (data_len > 0) { /* first pbuf must be big enough to hold at least 1 data byte, too */ EXPECT_RETNULL(p->len > (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr))); } for(q = p; q != NULL; q = q->next) { memset(q->payload, 0, q->len); } iphdr = (struct ip_hdr*)p->payload; /* fill IP header */ iphdr->dest.addr = ip_2_ip4(dst_ip)->addr; iphdr->src.addr = ip_2_ip4(src_ip)->addr; IPH_VHL_SET(iphdr, 4, IP_HLEN / 4); IPH_TOS_SET(iphdr, 0); IPH_LEN_SET(iphdr, htons(p->tot_len)); IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); /* let p point to TCP header */ pbuf_header(p, -(s16_t)sizeof(struct ip_hdr)); tcphdr = (struct tcp_hdr*)p->payload; tcphdr->src = htons(src_port); tcphdr->dest = htons(dst_port); tcphdr->seqno = htonl(seqno); tcphdr->ackno = htonl(ackno); TCPH_HDRLEN_SET(tcphdr, sizeof(struct tcp_hdr)/4); TCPH_FLAGS_SET(tcphdr, headerflags); tcphdr->wnd = htons(wnd); if (data_len > 0) { /* let p point to TCP data */ pbuf_header(p, -(s16_t)sizeof(struct tcp_hdr)); /* copy data */ pbuf_take(p, data, (u16_t)data_len); /* let p point to TCP header again */ pbuf_header(p, sizeof(struct tcp_hdr)); } /* calculate checksum */ tcphdr->chksum = ip_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, src_ip, dst_ip); pbuf_header(p, sizeof(struct ip_hdr)); return p; }