gblues 6904101c44 Clean up trailing whitespace
== DETAILS

Really simple code cleanup, because my editor flags trailing whitespaces
and it's pretty annoying.
2017-12-12 00:24:18 -08:00

1479 lines
37 KiB
C

#include <stdlib.h>
#include <string.h>
#include "memb.h"
#include "uip.h"
#include "uip_arch.h"
#include "uip_ip.h"
#include "uip_tcp.h"
#include "uip_pbuf.h"
#include "uip_netif.h"
#if UIP_LOGGING == 1
#include <stdio.h>
#define UIP_LOG(m) uip_log(__FILE__,__LINE__,m)
#else
#define UIP_LOG(m)
#endif /* UIP_LOGGING == 1 */
#if UIP_ERRORING == 1
#include <stdio.h>
#define UIP_ERROR(m) uip_log(__FILE__,__LINE__,m)
#else
#define UIP_ERROR(m)
#endif /* UIP_ERRORING == 1 */
#if UIP_STATISTICS == 1
struct uip_stats uip_stat;
#define UIP_STAT(s) s
#else
#define UIP_STAT(s)
#endif /* UIP_STATISTICS == 1 */
static u8_t uip_tcp_timer;
static u8_t uip_flags,uip_recv_flags;
static u16_t uip_tcplen;
static u32_t uip_seqno,uip_ackno;
static struct uip_tcpseg uip_inseg;
static struct uip_pbuf *uip_recv_data = NULL;
static struct uip_ip_hdr *uip_iphdr = NULL;
static struct uip_tcp_hdr *uip_tcphdr = NULL;
u32_t uip_tcp_ticks;
struct uip_tcp_pcb *uip_tcp_tmp_pcb = NULL;
struct uip_tcp_pcb *uip_tcp_input_pcb = NULL;
struct uip_tcp_pcb *uip_tcp_active_pcbs = NULL;
struct uip_tcp_pcb *uip_tcp_tw_pcbs = NULL;
union uip_tcp_listen_pcbs_t uip_tcp_listen_pcbs;
const u8_t uip_tcp_backoff[13] = { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};
MEMB(uip_listen_tcp_pcbs,sizeof(struct uip_tcp_pcb_listen),UIP_LISTEN_TCP_PCBS);
MEMB(uip_tcp_pcbs,sizeof(struct uip_tcp_pcb),UIP_TCP_PCBS);
MEMB(uip_tcp_segs,sizeof(struct uip_tcpseg),UIP_TCP_SEGS);
static s8_t uip_tcp_nullaccept(void *arg,struct uip_tcp_pcb *pcb,s8_t err);
static s8_t uip_tcp_nullrecv(void *arg,struct uip_tcp_pcb *pcb,struct uip_pbuf *p,s8_t err);
static void uip_tcp_parseopt(struct uip_tcp_pcb *pcb);
static void uip_tcpoutput_segments(struct uip_tcpseg *seg,struct uip_tcp_pcb *pcb);
static s8_t uip_tcpinput_listen(struct uip_tcp_pcb_listen *pcb);
static s8_t uip_tcpinput_timewait(struct uip_tcp_pcb *pcb);
static s8_t uip_tcpprocess(struct uip_tcp_pcb *pcb);
static void uip_tcpreceive(struct uip_tcp_pcb *pcb);
static u16_t uip_tcp_newport();
s8_t uip_tcp_sendctrl(struct uip_tcp_pcb *pcb,u8_t flags)
{
return uip_tcpenqueue(pcb,NULL,0,flags,1,NULL,0);
}
s8_t uip_tcp_write(struct uip_tcp_pcb *pcb,const void *arg,u16_t len,u8_t copy)
{
if(pcb->state==UIP_ESTABLISHED || pcb->state==UIP_CLOSE_WAIT ||
pcb->state==UIP_SYN_SENT || pcb->state==UIP_SYN_RCVD) {
if(len>0) {
return uip_tcpenqueue(pcb,(void*)arg,len,0,copy,NULL,0);
}
return UIP_ERR_OK;
}
return UIP_ERR_CONN;
}
s8_t uip_tcpenqueue(struct uip_tcp_pcb *pcb,void *arg,u16_t len,u8_t flags,u8_t copy,u8_t *optdata,u8_t optlen)
{
struct uip_pbuf *p;
struct uip_tcpseg *seg,*useg,*queue = NULL;
u32_t left,seqno;
u16_t seglen;
void *ptr;
u8_t queue_len;
if(len>pcb->snd_buf) {
UIP_ERROR("uip_tcpenqueue: too much data (len>pcb->snd_buf).\n");
return UIP_ERR_MEM;
}
left = len;
ptr = arg;
seqno = pcb->snd_lbb;
queue_len = pcb->snd_queuelen;
if(queue_len>=UIP_TCP_SND_QUEUELEN) {
UIP_ERROR("uip_tcpenqueue: too long queue.");
goto memerr;
}
useg = seg = queue = NULL;
seglen = 0;
while(queue==NULL || left>0) {
seglen = left>pcb->mss?pcb->mss:len;
seg = memb_alloc(&uip_tcp_segs);
if(seg==NULL) {
UIP_ERROR("uip_tcpenqueue: could not allocate memory for tcp_seg.");
goto memerr;
}
seg->next = NULL;
seg->p = NULL;
if(queue==NULL) queue = seg;
else useg->next = seg;
useg = seg;
if(optdata!=NULL) {
if((seg->p=uip_pbuf_alloc(UIP_PBUF_TRANSPORT,optlen,UIP_PBUF_RAM))==NULL) {
UIP_ERROR("uip_tcpenqueue: could not allocate memory for pbuf opdata.");
goto memerr;
}
++queue_len;
seg->dataptr = seg->p->payload;
} else if(copy) {
if((seg->p=uip_pbuf_alloc(UIP_PBUF_TRANSPORT,seglen,UIP_PBUF_RAM))==NULL) {
UIP_ERROR("uip_tcpenqueue: could not allocate memory for pbuf copy size.");
goto memerr;
}
++queue_len;
if(ptr!=NULL) UIP_MEMCPY(seg->p->payload,ptr,seglen);
seg->dataptr = seg->p->payload;
} else {
if((p=uip_pbuf_alloc(UIP_PBUF_TRANSPORT,seglen,UIP_PBUF_ROM))==NULL) {
UIP_ERROR("uip_tcpenqueue: could not allocate memory for zero-copy pbuf.");
goto memerr;
}
++queue_len;
p->payload = ptr;
seg->dataptr = ptr;
if((seg->p=uip_pbuf_alloc(UIP_PBUF_TRANSPORT,0,UIP_PBUF_RAM))==NULL) {
UIP_LOG("uip_tcpenqueue: could not allocate memory for header pbuf.");
uip_pbuf_free(p);
goto memerr;
}
++queue_len;
uip_pbuf_cat(seg->p,p);
p = NULL;
}
if(queue_len>UIP_TCP_SND_QUEUELEN) {
UIP_ERROR("uip_tcpenqueue: queue too long.");
goto memerr;
}
seg->len = seglen;
if(uip_pbuf_header(seg->p,UIP_TCP_HLEN)) {
UIP_ERROR("uip_tcpenqueue: no room for TCP header in pbuf.");
goto memerr;
}
seg->tcphdr = seg->p->payload;
seg->tcphdr->src = htons(pcb->local_port);
seg->tcphdr->dst = htons(pcb->remote_port);
seg->tcphdr->seqno = htonl(seqno);
seg->tcphdr->urgp = 0;
UIP_TCPH_FLAGS_SET(seg->tcphdr,flags);
if(optdata==NULL) UIP_TCPH_HDRLEN_SET(seg->tcphdr,5);
else {
UIP_TCPH_HDRLEN_SET(seg->tcphdr,(5+(optlen/4)));
UIP_MEMCPY(seg->dataptr,optdata,optlen);
}
left -= seglen;
seqno += seglen;
ptr = (void*)((u8_t*)ptr+seglen);
}
if(pcb->unsent==NULL) useg = NULL;
else {
for(useg=pcb->unsent;useg->next!=NULL;useg=useg->next);
}
if(useg!=NULL &&
UIP_TCP_TCPLEN(useg)!=0 &&
!(UIP_TCPH_FLAGS(useg->tcphdr)&(UIP_TCP_SYN|UIP_TCP_FIN)) &&
!(flags&(UIP_TCP_SYN|UIP_TCP_FIN)) &&
useg->len+queue->len<=pcb->mss) {
uip_pbuf_header(queue->p,-UIP_TCP_HLEN);
uip_pbuf_cat(useg->p,queue->p);
useg->len += queue->len;
useg->next = queue->next;
if(seg==queue) seg = NULL;
memb_free(&uip_tcp_segs,queue);
} else {
if(useg==NULL) pcb->unsent = queue;
else useg->next = queue;
}
if(flags&UIP_TCP_SYN || flags&UIP_TCP_FIN) len++;
pcb->snd_lbb += len;
pcb->snd_buf -= len;
pcb->snd_queuelen = queue_len;
if(seg!=NULL && seglen>0 && seg->tcphdr!=NULL) UIP_TCPH_SET_FLAG(seg->tcphdr,UIP_TCP_PSH);
return UIP_ERR_OK;
memerr:
if(queue!=NULL) uip_tcpsegs_free(queue);
return UIP_ERR_MEM;
}
void uip_tcpinput(struct uip_pbuf *p,struct uip_netif *inp)
{
s8_t err;
u8_t hdr_len;
struct uip_tcp_pcb *pcb,*prev;
struct uip_tcp_pcb_listen *lpcb;
uip_iphdr = p->payload;
uip_tcphdr = (struct uip_tcp_hdr*)((u8_t*)p->payload+UIP_IPH_HL(uip_iphdr)*4);
if(uip_pbuf_header(p,-((s16_t)(UIP_IPH_HL(uip_iphdr)*4))) || p->tot_len<sizeof(struct uip_tcp_hdr)) {
UIP_LOG("uip_tcpinput: short packet discarded.");
uip_pbuf_free(p);
return;
}
if(ip_addr_isbroadcast(&uip_iphdr->dst,inp) ||
ip_addr_ismulticast(&uip_iphdr->dst)) {
uip_pbuf_free(p);
return;
}
if(uip_chksum_pseudo(p,&uip_iphdr->src,&uip_iphdr->dst,UIP_PROTO_TCP,p->tot_len)!=0) {
UIP_LOG("uip_tcpinput: packet discarded due to failing checksum.");
uip_pbuf_free(p);
return;
}
hdr_len = UIP_TCPH_HDRLEN(uip_tcphdr);
uip_pbuf_header(p,-(hdr_len*4));
uip_tcphdr->src = ntohs(uip_tcphdr->src);
uip_tcphdr->dst = ntohs(uip_tcphdr->dst);
uip_seqno = uip_tcphdr->seqno = ntohl(uip_tcphdr->seqno);
uip_ackno = uip_tcphdr->ackno = ntohl(uip_tcphdr->ackno);
uip_tcphdr->wnd = ntohs(uip_tcphdr->wnd);
uip_flags = UIP_TCPH_FLAGS(uip_tcphdr)&UIP_TCP_FLAGS;
uip_tcplen = p->tot_len+((uip_flags&UIP_TCP_FIN||uip_flags&UIP_TCP_SYN)?1:0);
prev = NULL;
for(pcb=uip_tcp_active_pcbs;pcb!=NULL;pcb=pcb->next) {
if(pcb->state!=UIP_CLOSED && pcb->state!=UIP_TIME_WAIT && pcb->state!=UIP_LISTEN) {
if(pcb->remote_port==uip_tcphdr->src &&
pcb->local_port==uip_tcphdr->dst &&
ip_addr_cmp(&pcb->remote_ip,&uip_iphdr->src) &&
ip_addr_cmp(&pcb->local_ip,&uip_iphdr->dst)) {
if(prev!=NULL) {
prev->next = pcb->next;
pcb->next = uip_tcp_active_pcbs;
uip_tcp_active_pcbs = pcb;
}
break;
}
prev = pcb;
}
}
if(pcb==NULL) {
for(pcb=uip_tcp_tw_pcbs;pcb!=NULL;pcb=pcb->next) {
if(pcb->state==UIP_TIME_WAIT &&
pcb->remote_port==uip_tcphdr->src &&
pcb->local_port==uip_tcphdr->dst &&
ip_addr_cmp(&pcb->remote_ip,&uip_iphdr->src) &&
ip_addr_cmp(&pcb->local_ip,&uip_iphdr->dst)) {
uip_tcpinput_timewait(pcb);
return;
}
}
prev = NULL;
for(lpcb=uip_tcp_listen_pcbs.listen_pcbs;lpcb!=NULL;lpcb=lpcb->next) {
if((ip_addr_isany(&lpcb->local_ip) || ip_addr_cmp(&lpcb->local_ip,&uip_iphdr->dst)) &&
lpcb->local_port==uip_tcphdr->dst) {
if(prev!=NULL) {
((struct uip_tcp_pcb_listen*)prev)->next = lpcb->next;
lpcb->next = uip_tcp_listen_pcbs.listen_pcbs;
uip_tcp_listen_pcbs.listen_pcbs = lpcb;
}
uip_tcpinput_listen(lpcb);
return;
}
prev = (struct uip_tcp_pcb*)lpcb;
}
}
if(pcb!=NULL) {
uip_inseg.next = NULL;
uip_inseg.len = p->tot_len;
uip_inseg.dataptr = p->payload;
uip_inseg.p = p;
uip_inseg.tcphdr = uip_tcphdr;
uip_recv_data = NULL;
uip_recv_flags = 0;
uip_tcp_input_pcb = pcb;
err = uip_tcpprocess(pcb);
uip_tcp_input_pcb = NULL;
if(err!=UIP_ERR_ABRT) {
if(uip_recv_flags&UIP_TF_RESET) {
if(pcb->errf) pcb->errf(pcb->cb_arg,UIP_ERR_RST);
uip_tcp_pcbremove(&uip_tcp_active_pcbs,pcb);
memb_free(&uip_tcp_pcbs,pcb);
} else if(uip_recv_flags&UIP_TF_CLOSED) {
uip_tcp_pcbremove(&uip_tcp_active_pcbs,pcb);
memb_free(&uip_tcp_pcbs,pcb);
} else {
err = UIP_ERR_OK;
if(pcb->acked>0) {
if(pcb->sent) err = pcb->sent(pcb->cb_arg,pcb,pcb->acked);
}
if(uip_recv_data!=NULL) {
if(pcb->recv) err = pcb->recv(pcb->cb_arg,pcb,uip_recv_data,UIP_ERR_OK);
}
if(err==UIP_ERR_OK) uip_tcpoutput(pcb);
}
}
if(uip_inseg.p!=NULL) uip_pbuf_free(uip_inseg.p);
} else {
if(!(UIP_TCPH_FLAGS(uip_tcphdr)&UIP_TCP_RST))
uip_tcp_rst(uip_ackno,uip_seqno+uip_tcplen,&uip_iphdr->dst,&uip_iphdr->src,uip_tcphdr->dst,uip_tcphdr->src);
uip_pbuf_free(p);
}
}
s8_t uip_tcpoutput(struct uip_tcp_pcb *pcb)
{
u32_t wnd;
struct uip_pbuf *p;
struct uip_tcp_hdr *tcphdr;
struct uip_tcpseg *seg,*useg;
if(uip_tcp_input_pcb==pcb) return 0;
wnd = UIP_MIN(pcb->snd_wnd,pcb->cwnd);
seg = pcb->unsent;
useg = pcb->unacked;
if(useg!=NULL) {
for(;useg->next!=NULL;useg=useg->next);
}
if(pcb->flags&UIP_TF_ACK_NOW &&
(seg==NULL || ntohl(seg->tcphdr->seqno)-pcb->lastack+seg->len>wnd)) {
//printf("uip_tcpout: ACK - seqno = %u, ackno = %u\n",pcb->snd_nxt,pcb->rcv_nxt);
p = uip_pbuf_alloc(UIP_PBUF_IP,UIP_TCP_HLEN,UIP_PBUF_RAM);
if(p==NULL) {
UIP_ERROR("uip_tcpoutput: (ACK) could not allocate pbuf.");
return UIP_ERR_BUF;
}
pcb->flags &= ~(UIP_TF_ACK_DELAY|UIP_TF_ACK_NOW);
tcphdr = p->payload;
tcphdr->src = htons(pcb->local_port);
tcphdr->dst = htons(pcb->remote_port);
tcphdr->seqno = htonl(pcb->snd_nxt);
tcphdr->ackno = htonl(pcb->rcv_nxt);
UIP_TCPH_FLAGS_SET(tcphdr,UIP_TCP_ACK);
tcphdr->wnd = htons(pcb->rcv_wnd);
tcphdr->urgp = 0;
UIP_TCPH_HDRLEN_SET(tcphdr,5);
tcphdr->chksum = 0;
tcphdr->chksum = uip_chksum_pseudo(p,&pcb->local_ip,&pcb->remote_ip,UIP_PROTO_TCP,p->tot_len);
uip_ipoutput(p,&pcb->local_ip,&pcb->remote_ip,pcb->ttl,pcb->tos,UIP_PROTO_TCP);
uip_pbuf_free(p);
return UIP_ERR_OK;
}
while(seg!=NULL && ntohl(seg->tcphdr->seqno)-pcb->lastack+seg->len<=wnd) {
pcb->unsent = seg->next;
if(pcb->state!=UIP_SYN_SENT) {
UIP_TCPH_SET_FLAG(seg->tcphdr,UIP_TCP_ACK);
pcb->flags &= ~(UIP_TF_ACK_DELAY|UIP_TF_ACK_NOW);
}
uip_tcpoutput_segments(seg,pcb);
pcb->snd_nxt = ntohl(seg->tcphdr->seqno)+UIP_TCP_TCPLEN(seg);
if(UIP_TCP_SEQ_LT(pcb->snd_max,pcb->snd_nxt)) pcb->snd_max = pcb->snd_nxt;
if(UIP_TCP_TCPLEN(seg)>0) {
seg->next = NULL;
if(pcb->unacked==NULL) {
pcb->unacked = seg;
useg = seg;
} else {
if(UIP_TCP_SEQ_LT(ntohl(seg->tcphdr->seqno),ntohl(useg->tcphdr->seqno))) {
seg->next = pcb->unacked;
pcb->unacked = seg;
} else {
useg->next = seg;
useg = useg->next;
}
}
} else
uip_tcpseg_free(seg);
seg = pcb->unsent;
}
return UIP_ERR_OK;
}
void uip_tcp_tmr()
{
uip_tcp_fasttmr();
if(++uip_tcp_timer&1) uip_tcp_slowtmr();
}
void uip_tcp_init()
{
memb_init(&uip_tcp_pcbs);
memb_init(&uip_listen_tcp_pcbs);
memb_init(&uip_tcp_segs);
uip_tcp_listen_pcbs.listen_pcbs = NULL;
uip_tcp_active_pcbs = NULL;
uip_tcp_tw_pcbs = NULL;
uip_tcp_ticks = 0;
uip_tcp_timer = 0;
}
void uip_tcp_accept(struct uip_tcp_pcb *pcb,s8_t (*accept)(void *,struct uip_tcp_pcb *,s8_t))
{
((struct uip_tcp_pcb_listen*)pcb)->accept = accept;
}
void uip_tcp_err(struct uip_tcp_pcb *pcb,void (*errf)(void *,s8_t))
{
pcb->errf = errf;
}
void uip_tcp_recv(struct uip_tcp_pcb *pcb,s8_t (*recv)(void *,struct uip_tcp_pcb *,struct uip_pbuf *,s8_t))
{
pcb->recv = recv;
}
void uip_tcp_sent(struct uip_tcp_pcb *pcb,s8_t (*sent)(void *,struct uip_tcp_pcb *,u16_t))
{
pcb->sent = sent;
}
void uip_tcp_poll(struct uip_tcp_pcb *pcb,s8_t (*poll)(void *,struct uip_tcp_pcb *),u8_t interval)
{
pcb->poll = poll;
pcb->pollinterval = interval;
}
void uip_tcp_arg(struct uip_tcp_pcb *pcb,void *arg)
{
pcb->cb_arg = arg;
}
struct uip_tcp_pcb* uip_tcp_pcballoc(u8_t prio)
{
u32_t iss;
struct uip_tcp_pcb *pcb = NULL;
pcb = memb_alloc(&uip_tcp_pcbs);
if(pcb!=NULL) {
UIP_MEMSET(pcb,0,sizeof(struct uip_tcp_pcb));
pcb->prio = UIP_TCP_PRIO_NORMAL;
pcb->snd_buf = UIP_TCP_SND_BUF;
pcb->snd_queuelen = 0;
pcb->rcv_wnd = UIP_TCP_WND;
pcb->tos = 0;
pcb->ttl = UIP_TCP_TTL;
pcb->mss = UIP_TCP_MSS;
pcb->rto = 3000/UIP_TCP_SLOW_INTERVAL;
pcb->sa = 0;
pcb->sv = 3000/UIP_TCP_SLOW_INTERVAL;
pcb->rtime = 0;
pcb->cwnd = 1;
iss = uip_tcpiss_next();
pcb->snd_wl2 = iss;
pcb->snd_nxt = iss;
pcb->snd_max = iss;
pcb->lastack = iss;
pcb->snd_lbb = iss;
pcb->tmr = uip_tcp_ticks;
pcb->polltmr = 0;
pcb->recv = uip_tcp_nullrecv;
pcb->keepalive = UIP_TCP_KEEPDEFAULT;
pcb->keepcnt = 0;
}
return pcb;
}
void uip_tcp_pcbremove(struct uip_tcp_pcb **pcblist,struct uip_tcp_pcb *pcb)
{
UIP_TCP_RMV(pcblist,pcb);
uip_tcp_pcbpurge(pcb);
if(pcb->state!=UIP_TIME_WAIT &&
pcb->state!=UIP_LISTEN &&
pcb->flags&UIP_TF_ACK_DELAY) {
pcb->flags |= UIP_TF_ACK_NOW;
uip_tcpoutput(pcb);
}
pcb->state = UIP_CLOSED;
}
void uip_tcp_pcbpurge(struct uip_tcp_pcb *pcb)
{
if(pcb->state!=UIP_CLOSED &&
pcb->state!=UIP_TIME_WAIT &&
pcb->state!=UIP_LISTEN) {
uip_tcpsegs_free(pcb->ooseq);
uip_tcpsegs_free(pcb->unsent);
uip_tcpsegs_free(pcb->unacked);
pcb->unsent = pcb->unacked = pcb->ooseq = NULL;
}
}
struct uip_tcp_pcb* uip_tcp_new()
{
return uip_tcp_pcballoc(UIP_TCP_PRIO_NORMAL);
}
s8_t uip_tcp_bind(struct uip_tcp_pcb *pcb,struct uip_ip_addr *ipaddr,u16_t port)
{
struct uip_tcp_pcb *cpcb;
if(port==0) port = uip_tcp_newport();
for(cpcb=(struct uip_tcp_pcb*)uip_tcp_listen_pcbs.pcbs;cpcb!=NULL;cpcb=cpcb->next) {
if(cpcb->local_port==port) {
if(ip_addr_isany(&cpcb->local_ip) ||
ip_addr_isany(ipaddr) ||
ip_addr_cmp(&cpcb->local_ip,ipaddr)) return UIP_ERR_USE;
}
}
for(cpcb=uip_tcp_active_pcbs;cpcb!=NULL;cpcb=cpcb->next) {
if(cpcb->local_port==port) {
if(ip_addr_isany(&cpcb->local_ip) ||
ip_addr_isany(ipaddr) ||
ip_addr_cmp(&cpcb->local_ip,ipaddr)) return UIP_ERR_USE;
}
}
if(!ip_addr_isany(ipaddr)) pcb->local_ip = *ipaddr;
pcb->local_port = port;
return UIP_ERR_OK;
}
struct uip_tcp_pcb* uip_tcp_listen(struct uip_tcp_pcb *pcb)
{
struct uip_tcp_pcb_listen *lpcb;
if(pcb->state==UIP_LISTEN) return pcb;
lpcb = memb_alloc(&uip_listen_tcp_pcbs);
if(lpcb==NULL) return NULL;
lpcb->cb_arg = pcb->cb_arg;
lpcb->local_port = pcb->local_port;
lpcb->state = UIP_LISTEN;
lpcb->so_options = pcb->so_options;
lpcb->so_options |= UIP_SOF_ACCEPTCONN;
lpcb->ttl = pcb->ttl;
lpcb->tos = pcb->tos;
ip_addr_set(&lpcb->local_ip,&pcb->local_ip);
memb_free(&uip_tcp_pcbs,pcb);
lpcb->accept = uip_tcp_nullaccept;
UIP_TCP_REG(&uip_tcp_listen_pcbs.listen_pcbs,lpcb);
return (struct uip_tcp_pcb*)lpcb;
}
void uip_tcp_recved(struct uip_tcp_pcb *pcb,u16_t len)
{
if((u32_t)pcb->rcv_wnd+len>UIP_TCP_WND) pcb->rcv_wnd = UIP_TCP_WND;
else pcb->rcv_wnd += len;
if(!(pcb->flags&UIP_TF_ACK_DELAY) && !(pcb->flags&UIP_TF_ACK_NOW)) {
uip_tcp_ack(pcb);
} else if(pcb->flags&UIP_TF_ACK_DELAY && pcb->rcv_wnd>=UIP_TCP_WND/2) {
uip_tcp_acknow(pcb);
}
}
s8_t uip_tcp_close(struct uip_tcp_pcb *pcb)
{
s8_t err;
switch(pcb->state) {
case UIP_CLOSED:
err = UIP_ERR_OK;
memb_free(&uip_tcp_pcbs,pcb);
pcb = NULL;
break;
case UIP_LISTEN:
err = UIP_ERR_OK;
uip_tcp_pcbremove((struct uip_tcp_pcb**)&uip_tcp_listen_pcbs.pcbs,pcb);
memb_free(&uip_listen_tcp_pcbs,pcb);
pcb = NULL;
break;
case UIP_SYN_SENT:
err = UIP_ERR_OK;
uip_tcp_pcbremove(&uip_tcp_active_pcbs,pcb);
memb_free(&uip_tcp_pcbs,pcb);
pcb = NULL;
break;
case UIP_SYN_RCVD:
case UIP_ESTABLISHED:
err = uip_tcp_sendctrl(pcb,UIP_TCP_FIN);
if(err==UIP_ERR_OK) pcb->state = UIP_FIN_WAIT_1;
break;
case UIP_CLOSE_WAIT:
err = uip_tcp_sendctrl(pcb,UIP_TCP_FIN);
if(err==UIP_ERR_OK) pcb->state = UIP_LAST_ACK;
break;
default:
err = UIP_ERR_OK;
pcb = NULL;
break;
}
if(pcb!=NULL && err==UIP_ERR_OK) uip_tcpoutput(pcb);
return err;
}
void uip_tcp_rst(u32_t seqno,u32_t ackno,struct uip_ip_addr *lipaddr,struct uip_ip_addr *ripaddr,u16_t lport,u16_t rport)
{
struct uip_pbuf *p;
struct uip_tcp_hdr *tcphdr;
p = uip_pbuf_alloc(UIP_PBUF_IP,UIP_TCP_HLEN,UIP_PBUF_RAM);
if(p==NULL) {
UIP_LOG("uip_tcp_rst: could not allocate memory for pbuf.\n");
return;
}
tcphdr = p->payload;
tcphdr->src = htons(lport);
tcphdr->dst = htons(rport);
tcphdr->seqno = htonl(seqno);
tcphdr->ackno = htonl(ackno);
UIP_TCPH_FLAGS_SET(tcphdr,UIP_TCP_RST|UIP_TCP_ACK);
tcphdr->wnd = htons(UIP_TCP_WND);
tcphdr->urgp = 0;
UIP_TCPH_HDRLEN_SET(tcphdr,5);
tcphdr->chksum = 0;
tcphdr->chksum = uip_chksum_pseudo(p,lipaddr,ripaddr,UIP_PROTO_TCP,p->tot_len);
uip_ipoutput(p,lipaddr,ripaddr,UIP_TCP_TTL,0,UIP_PROTO_TCP);
uip_pbuf_free(p);
}
void uip_tcp_abort(struct uip_tcp_pcb *pcb)
{
u32_t seqno,ackno;
u16_t remote_port,local_port;
struct uip_ip_addr remote_ip,local_ip;
void (*errf)(void *arg,s8_t err);
void *errf_arg;
if(pcb->state==UIP_TIME_WAIT) {
memb_free(&uip_tcp_pcbs,pcb);
} else {
seqno = pcb->snd_nxt;
ackno = pcb->rcv_nxt;
ip_addr_set(&local_ip,&pcb->local_ip);
ip_addr_set(&remote_ip,&pcb->remote_ip);
local_port = pcb->local_port;
remote_port = pcb->remote_port;
errf = pcb->errf;
errf_arg = pcb->cb_arg;
uip_tcp_pcbremove(&uip_tcp_active_pcbs,pcb);
if(pcb->unacked!=NULL)
uip_tcpsegs_free(pcb->unacked);
if(pcb->unsent!=NULL)
uip_tcpsegs_free(pcb->unsent);
if(pcb->ooseq!=NULL)
uip_tcpsegs_free(pcb->ooseq);
memb_free(&uip_tcp_pcbs,pcb);
if(errf) errf(errf_arg,UIP_ERR_ABRT);
uip_tcp_rst(seqno,ackno,&local_ip,&remote_ip,local_port,remote_port);
}
}
void uip_tcp_keepalive(struct uip_tcp_pcb *pcb)
{
struct uip_pbuf *p;
struct uip_tcp_hdr *tcphdr;
p = uip_pbuf_alloc(UIP_PBUF_IP,UIP_TCP_HLEN,UIP_PBUF_RAM);
if(p==NULL) return;
tcphdr = p->payload;
tcphdr->src = htons(pcb->local_port);
tcphdr->dst = htons(pcb->remote_port);
tcphdr->seqno = htonl(pcb->snd_nxt-1);
tcphdr->ackno = htonl(pcb->rcv_nxt);
tcphdr->wnd = htons(pcb->rcv_wnd);
tcphdr->urgp = 0;
UIP_TCPH_HDRLEN_SET(tcphdr,5);
tcphdr->chksum = 0;
tcphdr->chksum = uip_chksum_pseudo(p,&pcb->local_ip,&pcb->remote_ip,UIP_PROTO_TCP,p->tot_len);
uip_ipoutput(p,&pcb->local_ip,&pcb->remote_ip,pcb->ttl,0,UIP_PROTO_TCP);
uip_pbuf_free(p);
}
void uip_tcp_rexmit(struct uip_tcp_pcb *pcb)
{
struct uip_tcpseg *seg;
if(pcb->unacked==NULL) return;
seg = pcb->unacked->next;
pcb->unacked->next = pcb->unsent;
pcb->unsent = pcb->unacked;
pcb->unacked = seg;
pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
pcb->nrtx++;
pcb->rttest = 0;
uip_tcpoutput(pcb);
}
void uip_tcp_rexmit_rto(struct uip_tcp_pcb *pcb)
{
struct uip_tcpseg *seg;
if(pcb->unacked==NULL) return;
for(seg=pcb->unacked;seg->next!=NULL;seg=seg->next);
seg->next = pcb->unsent;
pcb->unsent = pcb->unacked;
pcb->unacked = NULL;
pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
pcb->nrtx++;
uip_tcpoutput(pcb);
}
void uip_tcp_fasttmr()
{
struct uip_tcp_pcb *pcb;
for(pcb=uip_tcp_active_pcbs;pcb!=NULL;pcb=pcb->next) {
if(pcb->flags&UIP_TF_ACK_DELAY) {
uip_tcp_acknow(pcb);
pcb->flags &= ~(UIP_TF_ACK_DELAY|UIP_TF_ACK_NOW);
}
}
}
void uip_tcp_slowtmr()
{
struct uip_tcp_pcb *prev,*pcb,*pcb2;
u32 eff_wnd;
u8_t pcb_remove;
s8_t err;
err = UIP_ERR_OK;
uip_tcp_ticks++;
prev = NULL;
pcb = uip_tcp_active_pcbs;
while(pcb!=NULL) {
pcb_remove = 0;
if(pcb->state==UIP_SYN_SENT && pcb->nrtx==UIP_MAXSYNRTX) pcb_remove++;
else if(pcb->nrtx==UIP_MAXRTX) pcb_remove++;
else {
pcb->rtime++;
if(pcb->unacked!=NULL && pcb->rtime>=pcb->rto) {
if(pcb->state==UIP_SYN_SENT) pcb->rto = ((pcb->sa>>3)+pcb->sv)<<uip_tcp_backoff[pcb->nrtx];
eff_wnd = UIP_MIN(pcb->cwnd,pcb->snd_wnd);
pcb->ssthresh = eff_wnd>>1;
if(pcb->ssthresh<pcb->mss) pcb->ssthresh = pcb->mss*2;
pcb->cwnd = pcb->mss;
uip_tcp_rexmit_rto(pcb);
}
}
if(pcb->state==UIP_FIN_WAIT_2) {
if((u32_t)(uip_tcp_ticks-pcb->tmr)>UIP_TCP_FIN_WAIT_TIMEOUT/UIP_TCP_SLOW_INTERVAL) pcb_remove++;
}
if(pcb->so_options&UIP_SOF_KEEPALIVE &&
(pcb->state==UIP_ESTABLISHED || pcb->state==UIP_CLOSE_WAIT)) {
if((u32_t)(uip_tcp_ticks-pcb->tmr)>(pcb->keepalive+UIP_TCP_MAXIDLE)/UIP_TCP_SLOW_INTERVAL) uip_tcp_abort(pcb);
else if((u32_t)(uip_tcp_ticks-pcb->tmr)>(pcb->keepalive+pcb->keepcnt*UIP_TCP_KEEPINTVL)/UIP_TCP_SLOW_INTERVAL) {
uip_tcp_keepalive(pcb);
pcb->keepcnt++;
}
}
if(pcb->ooseq!=NULL && (u32_t)uip_tcp_ticks-pcb->tmr>=pcb->rto*UIP_TCP_OOSEQ_TIMEOUT) {
uip_tcpsegs_free(pcb->ooseq);
pcb->ooseq = NULL;
}
if(pcb->state==UIP_SYN_RCVD) {
if((u32_t)(uip_tcp_ticks-pcb->tmr)>UIP_TCP_SYN_RCVD_TIMEOUT/UIP_TCP_SLOW_INTERVAL) pcb_remove++;
}
if(pcb_remove) {
uip_tcp_pcbpurge(pcb);
if(prev!=NULL) prev->next = pcb->next;
else uip_tcp_active_pcbs = pcb->next;
if(pcb->errf) pcb->errf(pcb->cb_arg,UIP_ERR_ABRT);
pcb2 = pcb->next;
memb_free(&uip_tcp_pcbs,pcb);
pcb = pcb2;
} else {
pcb->polltmr++;
if(pcb->polltmr>=pcb->pollinterval) {
pcb->polltmr = 0;
if(pcb->poll) err = pcb->poll(pcb->cb_arg,pcb);
if(err==UIP_ERR_OK) uip_tcpoutput(pcb);
}
prev = pcb;
pcb = pcb->next;
}
}
prev = NULL;
pcb = uip_tcp_tw_pcbs;
while(pcb!=NULL) {
pcb_remove = 0;
if((u32_t)(uip_tcp_ticks-pcb->tmr)>2*UIP_TCP_MSL/UIP_TCP_SLOW_INTERVAL) pcb_remove++;
if(pcb_remove) {
uip_tcp_pcbpurge(pcb);
if(prev!=NULL) prev->next = pcb->next;
else uip_tcp_tw_pcbs = pcb->next;
pcb2 = pcb->next;
memb_free(&uip_tcp_pcbs,pcb);
pcb = pcb2;
} else {
prev = pcb;
pcb = pcb->next;
}
}
}
u32_t uip_tcpiss_next()
{
static u32_t iss = 6510;
iss += uip_tcp_ticks;
return iss;
}
struct uip_tcpseg* uip_tcpseg_copy(struct uip_tcpseg *seg)
{
struct uip_tcpseg *cseg;
cseg = memb_alloc(&uip_tcp_segs);
if(cseg==NULL) return NULL;
UIP_MEMCPY(cseg,seg,sizeof(struct uip_tcpseg));
uip_pbuf_ref(cseg->p);
return cseg;
}
u8_t uip_tcpsegs_free(struct uip_tcpseg *seg)
{
u8_t cnt = 0;
struct uip_tcpseg *next;
while(seg!=NULL) {
next = seg->next;
cnt += uip_tcpseg_free(seg);
seg = next;
}
return cnt;
}
u8_t uip_tcpseg_free(struct uip_tcpseg *seg)
{
u8_t cnt = 0;
if(seg!=NULL) {
if(seg->p!=NULL) {
cnt = uip_pbuf_free(seg->p);
}
memb_free(&uip_tcp_segs,seg);
}
return cnt;
}
#ifndef TCP_LOCAL_PORT_RANGE_START
#define TCP_LOCAL_PORT_RANGE_START 4096
#define TCP_LOCAL_PORT_RANGE_END 0x7fff
#endif
static u16_t uip_tcp_newport()
{
struct uip_tcp_pcb *pcb;
static u16_t port = TCP_LOCAL_PORT_RANGE_START;
again:
if(++port>=TCP_LOCAL_PORT_RANGE_END) port = TCP_LOCAL_PORT_RANGE_START;
for(pcb=uip_tcp_active_pcbs;pcb!=NULL;pcb=pcb->next) {
if(pcb->local_port==port) goto again;
}
for(pcb=uip_tcp_tw_pcbs;pcb!=NULL;pcb=pcb->next) {
if(pcb->local_port==port) goto again;
}
for(pcb=(struct uip_tcp_pcb*)uip_tcp_listen_pcbs.pcbs;pcb!=NULL;pcb=pcb->next) {
if(pcb->local_port==port) goto again;
}
return port;
}
static void uip_tcp_parseopt(struct uip_tcp_pcb *pcb)
{
u8_t c;
u8_t *opts,opt;
u16_t mss;
opts = (u8_t*)uip_tcphdr+UIP_TCP_HLEN;
if(UIP_TCPH_HDRLEN(uip_tcphdr)>0x05) {
for(c=0;c<((UIP_TCPH_HDRLEN(uip_tcphdr)-5)<<2);) {
opt = opts[c];
if(opt==0x00) break;
else if(opt==0x01) c++;
else if(opt==0x02 && opts[c+1]==0x04) {
mss = (opts[c+2]<<8|opts[c+3]);
pcb->mss = mss>UIP_TCP_MSS?UIP_TCP_MSS:mss;
break;
} else {
if(opts[c+1]==0) break;
c += opts[c+1];
}
}
}
}
static void uip_tcpoutput_segments(struct uip_tcpseg *seg,struct uip_tcp_pcb *pcb)
{
u16_t len;
struct uip_netif *netif;
seg->tcphdr->ackno = htonl(pcb->rcv_nxt);
if(pcb->rcv_wnd<pcb->mss) seg->tcphdr->wnd = 0;
else seg->tcphdr->wnd = htons(pcb->rcv_wnd);
if(ip_addr_isany(&pcb->local_ip)) {
netif = uip_iproute(&pcb->remote_ip);
if(netif==NULL) {
UIP_ERROR("uip_tcpoutput_segments: no route found.");
return;
}
ip_addr_set(&pcb->local_ip,&netif->ip_addr);
}
pcb->rtime = 0;
if(pcb->rttest==0) {
pcb->rttest = uip_tcp_ticks;
pcb->rtseq = ntohl(seg->tcphdr->seqno);
}
len = (u16_t)((u8_t*)seg->tcphdr-(u8_t*)seg->p->payload);
seg->p->len -= len;
seg->p->tot_len -= len;
seg->p->payload = seg->tcphdr;
seg->tcphdr->chksum = 0;
seg->tcphdr->chksum = uip_chksum_pseudo(seg->p,&pcb->local_ip,&pcb->remote_ip,UIP_PROTO_TCP,seg->p->tot_len);
uip_ipoutput(seg->p,&pcb->local_ip,&pcb->remote_ip,pcb->ttl,pcb->tos,UIP_PROTO_TCP);
}
static s8_t uip_tcpinput_listen(struct uip_tcp_pcb_listen *pcb)
{
u32_t optdata;
struct uip_tcp_pcb *npcb;
if(uip_flags&UIP_TCP_ACK) {
UIP_LOG("uip_tcp_listen_input: ACK in LISTEN, sending reset.\n");
uip_tcp_rst(uip_ackno+1,uip_seqno+uip_tcplen,&uip_iphdr->dst,&uip_iphdr->src,uip_tcphdr->dst,uip_tcphdr->src);
} else if(uip_flags&UIP_TCP_SYN) {
npcb = uip_tcp_pcballoc(pcb->prio);
if(!npcb) return UIP_ERR_MEM;
ip_addr_set(&npcb->local_ip,&uip_iphdr->dst);
npcb->local_port = pcb->local_port;
ip_addr_set(&npcb->remote_ip,&uip_iphdr->src);
npcb->remote_port = uip_tcphdr->src;
npcb->state = UIP_SYN_RCVD;
npcb->rcv_nxt = uip_seqno+1;
npcb->snd_wnd = uip_tcphdr->wnd;
npcb->ssthresh = npcb->snd_wnd;
npcb->snd_wl1 = uip_seqno-1;
npcb->cb_arg = pcb->cb_arg;
npcb->accept = pcb->accept;
npcb->so_options = pcb->so_options&(UIP_SOF_DEBUG|UIP_SOF_DONTROUTE|UIP_SOF_KEEPALIVE|UIP_SOF_OOBINLINE|UIP_SOF_LINGER);
UIP_TCP_REG(&uip_tcp_active_pcbs,npcb);
uip_tcp_parseopt(npcb);
optdata = htonl((((u32_t)2<<24)|((u32_t)4<<16)|(((u32_t)npcb->mss/256)<<8)|((u32_t)npcb->mss&255)));
uip_tcpenqueue(npcb,NULL,0,UIP_TCP_SYN|UIP_TCP_ACK,0,(u8_t*)&optdata,4);
return uip_tcpoutput(npcb);
}
return UIP_ERR_OK;
}
static s8_t uip_tcpinput_timewait(struct uip_tcp_pcb *pcb)
{
if(UIP_TCP_SEQ_GT(uip_seqno+uip_tcplen,pcb->rcv_nxt)) pcb->rcv_nxt = uip_seqno+uip_tcplen;
if(uip_tcplen>0) {
uip_tcp_acknow(pcb);
}
return uip_tcpoutput(pcb);
}
static s8_t uip_tcpprocess(struct uip_tcp_pcb *pcb)
{
struct uip_tcpseg *rseg;
u8_t acceptable = 0;
s8_t err;
err = 0;
if(uip_flags&UIP_TCP_RST) {
if(pcb->state==UIP_SYN_SENT) {
if(uip_ackno==pcb->snd_nxt) acceptable = 1;
} else {
if(UIP_TCP_SEQ_BETWEEN(uip_seqno,pcb->rcv_nxt,pcb->rcv_nxt+pcb->rcv_wnd)) acceptable = 1;
}
if(acceptable) {
uip_recv_flags = UIP_TF_RESET;
pcb->flags &= ~UIP_TF_ACK_DELAY;
return UIP_ERR_RST;
} else
return UIP_ERR_OK;
}
pcb->tmr = uip_tcp_ticks;
pcb->keepcnt = 0;
switch(pcb->state) {
case UIP_SYN_SENT:
if(uip_flags&UIP_TCP_ACK && uip_flags&UIP_TCP_SYN &&
uip_ackno==ntohl(pcb->unacked->tcphdr->seqno)+1) {
pcb->snd_buf++;
pcb->rcv_nxt = uip_seqno+1;
pcb->lastack = uip_ackno;
pcb->snd_wnd = uip_tcphdr->wnd;
pcb->snd_wl1 = uip_seqno-1;
pcb->state = UIP_ESTABLISHED;
pcb->cwnd = pcb->mss;
pcb->snd_queuelen--;
rseg = pcb->unacked;
pcb->unacked = rseg->next;
uip_tcpseg_free(rseg);
uip_tcp_parseopt(pcb);
if(pcb->connected!=NULL) err = pcb->connected(pcb->cb_arg,pcb,UIP_ERR_OK);
uip_tcp_ack(pcb);
} else if(uip_flags&UIP_TCP_ACK) {
uip_tcp_rst(uip_ackno,uip_seqno+uip_tcplen,&uip_iphdr->dst,&uip_iphdr->src,uip_tcphdr->dst,uip_tcphdr->src);
}
break;
case UIP_SYN_RCVD:
if(uip_flags&UIP_TCP_ACK && !(uip_flags&UIP_TCP_RST)) {
if(UIP_TCP_SEQ_BETWEEN(uip_ackno,pcb->lastack+1,pcb->snd_nxt)) {
pcb->state = UIP_ESTABLISHED;
if(pcb->accept!=NULL) err = pcb->accept(pcb->cb_arg,pcb,UIP_ERR_OK);
if(err!=UIP_ERR_OK) {
uip_tcp_abort(pcb);
return UIP_ERR_ABRT;
}
uip_tcpreceive(pcb);
pcb->cwnd = pcb->mss;
} else {
uip_tcp_rst(uip_ackno,uip_seqno+uip_tcplen,&uip_iphdr->dst,&uip_iphdr->src,uip_tcphdr->dst,uip_tcphdr->src);
}
}
break;
case UIP_CLOSE_WAIT:
case UIP_ESTABLISHED:
uip_tcpreceive(pcb);
if(uip_flags&UIP_TCP_FIN) {
uip_tcp_acknow(pcb);
pcb->state = UIP_CLOSE_WAIT;
}
break;
case UIP_FIN_WAIT_1:
uip_tcpreceive(pcb);
if(uip_flags&UIP_TCP_FIN) {
if(uip_flags&UIP_TCP_ACK && uip_ackno==pcb->snd_nxt) {
uip_tcp_acknow(pcb);
uip_tcp_pcbpurge(pcb);
UIP_TCP_RMV(&uip_tcp_active_pcbs,pcb);
pcb->state = UIP_TIME_WAIT;
UIP_TCP_REG(&uip_tcp_tw_pcbs,pcb);
} else {
uip_tcp_acknow(pcb);
pcb->state = UIP_CLOSING;
}
} else if(uip_flags&UIP_TCP_ACK && uip_ackno==pcb->snd_nxt) {
pcb->state = UIP_FIN_WAIT_2;
}
break;
case UIP_FIN_WAIT_2:
uip_tcpreceive(pcb);
if(uip_flags&UIP_TCP_FIN) {
uip_tcp_acknow(pcb);
uip_tcp_pcbpurge(pcb);
UIP_TCP_RMV(&uip_tcp_active_pcbs,pcb);
pcb->state = UIP_TIME_WAIT;
UIP_TCP_REG(&uip_tcp_tw_pcbs,pcb);
}
break;
case UIP_CLOSING:
uip_tcpreceive(pcb);
if(uip_flags&UIP_TCP_ACK && uip_ackno==pcb->snd_nxt) {
uip_tcp_acknow(pcb);
uip_tcp_pcbpurge(pcb);
UIP_TCP_RMV(&uip_tcp_active_pcbs,pcb);
pcb->state = UIP_TIME_WAIT;
UIP_TCP_REG(&uip_tcp_tw_pcbs,pcb);
}
break;
case UIP_LAST_ACK:
uip_tcpreceive(pcb);
if(uip_flags&UIP_TCP_ACK && uip_ackno==pcb->snd_nxt) {
pcb->state = UIP_CLOSED;
uip_recv_flags = UIP_TF_CLOSED;
}
break;
default:
break;
}
return UIP_ERR_OK;
}
static void uip_tcpreceive(struct uip_tcp_pcb *pcb)
{
struct uip_tcpseg *next,*prev;
struct uip_tcpseg *cseg;
struct uip_pbuf *p;
s32_t off,m;
u32_t right_wnd_edge;
u16_t new_tot_len;
if(uip_flags&UIP_TCP_ACK) {
right_wnd_edge = pcb->snd_wnd+pcb->snd_wl1;
if(UIP_TCP_SEQ_LT(pcb->snd_wl1,uip_seqno) ||
(pcb->snd_wl1==uip_seqno && UIP_TCP_SEQ_LT(pcb->snd_wl2,uip_ackno)) ||
(pcb->snd_wl2==uip_ackno && uip_tcphdr->wnd>pcb->snd_wnd)) {
pcb->snd_wnd = uip_tcphdr->wnd;
pcb->snd_wl1 = uip_seqno;
pcb->snd_wl2 = uip_ackno;
}
if(pcb->lastack==uip_ackno) {
pcb->acked = 0;
if(pcb->snd_wl1+pcb->snd_wnd==right_wnd_edge) {
pcb->dupacks++;
if(pcb->dupacks>=3 && pcb->unacked!=NULL) {
if(!(uip_flags&UIP_TF_INFR)) {
UIP_LOG("uip_tcpreceive: dupacks, fast retransmit.");
uip_tcp_rexmit(pcb) ;
if(pcb->cwnd>pcb->snd_wnd) pcb->ssthresh = pcb->snd_wnd/2;
else pcb->ssthresh = pcb->cwnd/2;
pcb->cwnd = pcb->ssthresh+3*pcb->mss;
pcb->flags |= UIP_TF_INFR;
} else {
if((u16_t)(pcb->cwnd+pcb->mss)>pcb->cwnd) pcb->cwnd += pcb->mss;
}
}
}
} else if(UIP_TCP_SEQ_BETWEEN(uip_ackno,pcb->lastack+1,pcb->snd_max)) {
if(pcb->flags&UIP_TF_INFR) {
pcb->flags &= ~UIP_TF_INFR;
pcb->cwnd = pcb->ssthresh;
}
pcb->nrtx = 0;
pcb->rto = (pcb->sa>>3)+pcb->sv;
pcb->acked = uip_ackno-pcb->lastack;
pcb->snd_buf += pcb->acked;
pcb->dupacks = 0;
pcb->lastack = uip_ackno;
if(pcb->state>=UIP_ESTABLISHED) {
if(pcb->cwnd<pcb->ssthresh) {
if((u16_t)(pcb->cwnd+pcb->mss)>pcb->cwnd) pcb->cwnd += pcb->mss;
} else {
u16_t new_cwnd = (pcb->cwnd+pcb->mss*pcb->mss/pcb->cwnd);
if(new_cwnd>pcb->cwnd) pcb->cwnd = new_cwnd;
}
}
while(pcb->unacked!=NULL &&
UIP_TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno)+UIP_TCP_TCPLEN(pcb->unacked),uip_ackno)) {
next = pcb->unacked;
pcb->unacked = pcb->unacked->next;
pcb->snd_queuelen -= uip_pbuf_clen(next->p);
uip_tcpseg_free(next);
}
pcb->polltmr = 0;
}
while(pcb->unsent!=NULL &&
UIP_TCP_SEQ_BETWEEN(uip_ackno,ntohl(pcb->unsent->tcphdr->seqno)+UIP_TCP_TCPLEN(pcb->unsent),pcb->snd_max)) {
next = pcb->unsent;
pcb->unsent = pcb->unsent->next;
pcb->snd_queuelen -= uip_pbuf_clen(next->p);
uip_tcpseg_free(next);
if(pcb->unsent!=NULL) pcb->snd_nxt = htonl(pcb->unsent->tcphdr->seqno);
}
if(pcb->rttest && UIP_TCP_SEQ_LT(pcb->rtseq,uip_ackno)) {
m = uip_tcp_ticks - pcb->rttest;
m = m - (pcb->sa>>3);
pcb->sa += m;
if(m<0) m -= m;
m = m - (pcb->sv>>2);
pcb->sv += m;
pcb->rto = (pcb->sa>>3)+pcb->sv;
pcb->rttest = 0;
}
}
if(uip_tcplen>0) {
if(UIP_TCP_SEQ_BETWEEN(pcb->rcv_nxt,uip_seqno+1,uip_seqno+uip_tcplen-1)) {
off = pcb->rcv_nxt - uip_seqno;
p = uip_inseg.p;
if(uip_inseg.p->len<off) {
new_tot_len = uip_inseg.p->tot_len - off;
while(p->len<off) {
off -= p->len;
p->tot_len = new_tot_len;
p->len = 0;
p = p->next;
}
uip_pbuf_header(p,-off);
} else {
uip_pbuf_header(uip_inseg.p,-off);
}
uip_inseg.dataptr = p->payload;
uip_inseg.len -= pcb->rcv_nxt - uip_seqno;
uip_inseg.tcphdr->seqno = uip_seqno = pcb->rcv_nxt;
} else {
if(UIP_TCP_SEQ_LT(uip_seqno,pcb->rcv_nxt)) {
UIP_LOG("uip_tcpreceive: duplicate seqno.");
uip_tcp_acknow(pcb);
}
}
if(UIP_TCP_SEQ_BETWEEN(uip_seqno,pcb->rcv_nxt,pcb->rcv_nxt+pcb->rcv_wnd-1)) {
//printf("uip_tcpreceive: seqno = %u, rcv_nxt = %u, wnd = %u\n",uip_seqno,pcb->rcv_nxt,(pcb->rcv_nxt+pcb->rcv_wnd-1));
if(pcb->rcv_nxt==uip_seqno) {
if(pcb->ooseq!=NULL && UIP_TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno,uip_seqno+uip_inseg.len)) {
uip_inseg.len = pcb->ooseq->tcphdr->seqno - uip_seqno;
uip_pbuf_realloc(uip_inseg.p,uip_inseg.len);
}
uip_tcplen = UIP_TCP_TCPLEN(&uip_inseg);
if(pcb->state!=UIP_CLOSE_WAIT) pcb->rcv_nxt += uip_tcplen;
//printf("uip_tcpreceive: uip_tcplen = %u, rcv_nxt = %u\n",uip_tcplen,pcb->rcv_nxt);
if(pcb->rcv_wnd<uip_tcplen) pcb->rcv_wnd = 0;
else pcb->rcv_wnd -= uip_tcplen;
if(uip_inseg.p->tot_len>0) {
uip_recv_data = uip_inseg.p;
uip_inseg.p = NULL;
}
if(UIP_TCPH_FLAGS(uip_inseg.tcphdr)&UIP_TCP_FIN) {
UIP_LOG("uip_tcpreceive: received FIN.\n");
uip_recv_flags = UIP_TF_GOT_FIN;
}
while(pcb->ooseq!=NULL && pcb->ooseq->tcphdr->seqno==pcb->rcv_nxt) {
cseg = pcb->ooseq;
uip_seqno = pcb->ooseq->tcphdr->seqno;
pcb->rcv_nxt += UIP_TCP_TCPLEN(cseg);
if(pcb->rcv_wnd<UIP_TCP_TCPLEN(cseg)) pcb->rcv_wnd = 0;
else pcb->rcv_wnd -= UIP_TCP_TCPLEN(cseg);
if(cseg->p->tot_len>0) {
if(uip_recv_data) uip_pbuf_cat(uip_recv_data,cseg->p);
else uip_recv_data = cseg->p;
cseg->p = NULL;
}
if(UIP_TCPH_FLAGS(cseg->tcphdr)&UIP_TCP_FIN) {
UIP_LOG("uip_tcpreceive: dequeued FIN.\n");
uip_recv_flags = UIP_TF_GOT_FIN;
}
pcb->ooseq = cseg->next;
uip_tcpseg_free(cseg);
}
//printf("uip_tcpreceive: pcb->flags = %02x\n",pcb->flags);
uip_tcp_ack(pcb);
//printf("uip_tcpreceive: pcb->flags = %02x\n",pcb->flags);
} else {
UIP_LOG("uip_tcpreceive: packet out-of-sequence.");
uip_tcp_acknow(pcb);
if(pcb->ooseq==NULL)
uip_tcpseg_copy(&uip_inseg);
else {
prev = NULL;
for(next=pcb->ooseq;next!=NULL;next=next->next) {
if(uip_seqno==next->tcphdr->seqno) {
if(uip_inseg.len>next->len) {
cseg = uip_tcpseg_copy(&uip_inseg);
if(cseg!=NULL) {
cseg->next = next->next;
if(prev!=NULL) prev->next = cseg;
else pcb->ooseq = cseg;
}
break;
} else
break;
} else {
if(prev==NULL) {
if(UIP_TCP_SEQ_LT(uip_seqno,next->tcphdr->seqno)) {
if(UIP_TCP_SEQ_GT(uip_seqno+uip_inseg.len,next->tcphdr->seqno)) {
uip_inseg.len = next->tcphdr->seqno - uip_seqno;
uip_pbuf_realloc(uip_inseg.p,uip_inseg.len);
}
cseg = uip_tcpseg_copy(&uip_inseg);
if(cseg!=NULL) {
cseg->next = next;
pcb->ooseq = cseg;
}
break;
}
} else if(UIP_TCP_SEQ_BETWEEN(uip_seqno,prev->tcphdr->seqno+1,next->tcphdr->seqno-1)) {
if(UIP_TCP_SEQ_GT(uip_seqno+uip_inseg.len,next->tcphdr->seqno)) {
uip_inseg.len = next->tcphdr->seqno - uip_seqno;
uip_pbuf_realloc(uip_inseg.p,uip_inseg.len);
}
cseg = uip_tcpseg_copy(&uip_inseg);
if(cseg!=NULL) {
cseg->next = next;
prev->next = cseg;
if(UIP_TCP_SEQ_GT(prev->tcphdr->seqno+prev->len,uip_seqno)) {
prev->len = uip_seqno - prev->tcphdr->seqno;
uip_pbuf_realloc(prev->p,prev->len);
}
}
break;
}
if(next->next==NULL && UIP_TCP_SEQ_GT(uip_seqno,next->tcphdr->seqno)) {
next->next = uip_tcpseg_copy(&uip_inseg);
if(next->next!=NULL) {
if(UIP_TCP_SEQ_GT(next->tcphdr->seqno+next->len,uip_seqno)) {
next->len = uip_seqno - next->tcphdr->seqno;
uip_pbuf_realloc(next->p,next->len);
}
}
}
}
prev = next;
}
}
}
} else {
if(!UIP_TCP_SEQ_BETWEEN(uip_seqno,pcb->rcv_nxt,pcb->rcv_nxt+pcb->rcv_wnd-1)) {
uip_tcp_acknow(pcb);
}
}
} else {
if(!UIP_TCP_SEQ_BETWEEN(uip_seqno,pcb->rcv_nxt,pcb->rcv_nxt+pcb->rcv_wnd-1)) {
uip_tcp_acknow(pcb);
}
}
}
static s8_t uip_tcp_nullaccept(void *arg,struct uip_tcp_pcb *pcb,s8_t err)
{
return UIP_ERR_ABRT;
}
static s8_t uip_tcp_nullrecv(void *arg,struct uip_tcp_pcb *pcb,struct uip_pbuf *p,s8_t err)
{
if(p!=NULL) uip_pbuf_free(p);
else if(err==UIP_ERR_OK) return uip_tcp_close(pcb);
return UIP_ERR_OK;
}