diff --git a/src/wolfip.c b/src/wolfip.c index 9fcfdb2..18cd706 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -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 { @@ -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) @@ -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; @@ -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) { @@ -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; @@ -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); @@ -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 { @@ -1830,14 +1850,6 @@ 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 @@ -1845,7 +1857,10 @@ static inline uint32_t tcp_seq_inc(uint32_t seq, uint32_t n) */ 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 */ @@ -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 @@ -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. */ @@ -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);