Skip to content
66 changes: 44 additions & 22 deletions src/wolfip.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ struct wolfIP_icmp_packet;

struct PACKED pkt_desc {
uint32_t pos, len;
uint16_t flags, time_sent;
uint32_t flags;
uint32_t time_sent;
};

struct fifo {
Expand Down Expand Up @@ -955,6 +956,13 @@ static inline struct ipconf *wolfIP_primary_ipconf(struct wolfIP *s)
return wolfIP_ipconf_at(s, WOLFIP_PRIMARY_IF_IDX);
}

static inline uint16_t ipcounter_next(struct wolfIP *s)
{
uint16_t id = s->ipcounter;
s->ipcounter = (uint16_t)(id + 1);
return ee16(id);
}

static inline int ip_is_local_conf(const struct ipconf *conf, ip4 addr)
{
if (!conf)
Expand Down Expand Up @@ -1141,7 +1149,7 @@ static void wolfIP_send_ttl_exceeded(struct wolfIP *s, unsigned int if_idx, stru
icmp.ip.ver_ihl = 0x45;
icmp.ip.ttl = 64;
icmp.ip.proto = WI_IPPROTO_ICMP;
icmp.ip.id = ee16(s->ipcounter++);
icmp.ip.id = ipcounter_next(s);
icmp.ip.len = ee16(IP_HEADER_LEN + ICMP_TTL_EXCEEDED_SIZE);
icmp.ip.src = ee32(wolfIP_ipconf_at(s, if_idx)->ip);
icmp.ip.dst = orig->src;
Expand Down Expand Up @@ -1558,6 +1566,14 @@ static void tcp_send_syn(struct tsocket *t, uint8_t flags)
fifo_push(&t->sock.tcp.txbuf, tcp, sizeof(struct wolfIP_tcp_seg) + opt_len);
}

/* Increment a TCP sequence number (wraps at 2^32) */
static inline uint32_t tcp_seq_inc(uint32_t seq, uint32_t n)
{
if (n > UINT32_MAX - seq)
return n - (UINT32_MAX - seq) - 1;
return seq + n;
}

/* Add a segment to the rx buffer for the application to consume */
static void tcp_recv(struct tsocket *t, struct wolfIP_tcp_seg *seg)
{
Expand All @@ -1573,7 +1589,7 @@ static void tcp_recv(struct tsocket *t, struct wolfIP_tcp_seg *seg)
/* Buffer full, dropped. This will send a duplicate ack. */
} else {
/* Advance ack counter */
t->sock.tcp.ack = seq + seg_len;
t->sock.tcp.ack = tcp_seq_inc(seq, seg_len);
timer_binheap_cancel(&t->S->timers, t->sock.tcp.tmr_rto);
t->sock.tcp.tmr_rto = NO_TIMER;
t->events |= CB_EVENT_READABLE;
Expand Down Expand Up @@ -1742,7 +1758,8 @@ static int ip_output_add_header(struct tsocket *t, struct wolfIP_ip_packet *ip,
ip->flags_fo = 0;
ip->ttl = 64;
ip->proto = proto;
ip->id = ee16(t->S->ipcounter++);
ip->id = ee16(t->S->ipcounter);
t->S->ipcounter = (uint16_t)(t->S->ipcounter + 1);
ip->csum = 0;
iphdr_set_checksum(ip);

Expand Down Expand Up @@ -1815,11 +1832,14 @@ static int tcp_process_ts(struct tsocket *t, const struct wolfIP_tcp_seg *tcp,
t->sock.tcp.last_ts = ts->val;
if (ts->ecr == 0)
return -1; /* No echoed timestamp; fall back to coarse RTT. */
if (ee32(ts->ecr) > t->S->last_tick)
return -1; /* Echoed timestamp in the future; ignore. */
if (t->sock.tcp.rtt == 0)
t->sock.tcp.rtt = (uint32_t)(t->S->last_tick - ee32(ts->ecr));
else {
t->sock.tcp.rtt = (uint32_t)(7 * (t->sock.tcp.rtt << 3)) +
((t->S->last_tick - ee32(ts->ecr)) << 3);
uint64_t rtt_scaled = (uint64_t)t->sock.tcp.rtt << 3;
uint64_t sample_scaled = (t->S->last_tick - ee32(ts->ecr)) << 3;
t->sock.tcp.rtt = (uint32_t)(7 * rtt_scaled + sample_scaled);
}
return 0;
} else {
Expand All @@ -1830,22 +1850,17 @@ static int tcp_process_ts(struct tsocket *t, const struct wolfIP_tcp_seg *tcp,
return -1;
}

/* Increment a TCP sequence number (wraps at 2^32) */
static inline uint32_t tcp_seq_inc(uint32_t seq, uint32_t n)
{
if (n > UINT32_MAX - seq)
return n - (UINT32_MAX - seq) - 1;
return seq + n;
}

#define SEQ_DIFF(a,b) ((a - b) > 0x7FFFFFFF) ? (b - a) : (a - b)

/* Return true if a <= b
* Take into account wrapping.
*/
static inline int tcp_seq_leq(uint32_t a, uint32_t b)
{
return ((int32_t)a - (int32_t)b) <= 0;
if (a <= b)
return (b - a) <= 0x80000000U;
else
return (a - b) >= 0x80000000U;
}

/* Receive an ack */
Expand Down Expand Up @@ -1886,7 +1901,11 @@ static void tcp_ack(struct tsocket *t, const struct wolfIP_tcp_seg *tcp)
if (t->sock.tcp.snd_una != ack &&
tcp_seq_leq(t->sock.tcp.snd_una, ack) &&
tcp_seq_leq(ack, t->sock.tcp.seq)) {
uint32_t delta = ack - t->sock.tcp.snd_una;
uint32_t delta;
if (ack >= t->sock.tcp.snd_una)
delta = ack - t->sock.tcp.snd_una;
else
delta = ack + (UINT32_MAX - t->sock.tcp.snd_una) + 1;
if (delta >= t->sock.tcp.bytes_in_flight)
t->sock.tcp.bytes_in_flight = 0;
else
Expand All @@ -1909,11 +1928,14 @@ static void tcp_ack(struct tsocket *t, const struct wolfIP_tcp_seg *tcp)
/* Update rtt */
if (tcp_process_ts(t, seg, fresh_desc->len) < 0) {
/* No timestamp option, use coarse RTT estimation */
int rtt = t->S->last_tick - fresh_desc->time_sent;
if (t->sock.tcp.rtt == 0) {
t->sock.tcp.rtt = rtt;
} else {
t->sock.tcp.rtt = (7 * (t->sock.tcp.rtt << 3)) + (rtt << 3);
if (t->S->last_tick >= fresh_desc->time_sent) {
uint32_t rtt = (uint32_t)(t->S->last_tick - fresh_desc->time_sent);
if (t->sock.tcp.rtt == 0) {
t->sock.tcp.rtt = rtt;
} else {
uint64_t rtt_scaled = (uint64_t)t->sock.tcp.rtt << 3;
t->sock.tcp.rtt = (uint32_t)(7 * rtt_scaled + ((uint64_t)rtt << 3));
}
}
}
/* Update cwnd only if we were cwnd-limited. */
Expand Down Expand Up @@ -3101,7 +3123,7 @@ static void icmp_input(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_p
tmp = ip->src;
ip->src = ip->dst;
ip->dst = tmp;
ip->id = ee16(s->ipcounter++);
ip->id = ipcounter_next(s);
ip->csum = 0;
iphdr_set_checksum(ip);
eth_output_add_header(s, if_idx, ip->eth.src, &ip->eth, ETH_TYPE_IP);
Expand Down