+static void ack(struct utcp_connection *c, bool sendatleastone) {
+ int32_t left = seqdiff(c->snd.last, c->snd.nxt);
+ int32_t cwndleft = c->snd.cwnd - seqdiff(c->snd.nxt, c->snd.una);
+ char *data = c->sndbuf + seqdiff(c->snd.nxt, c->snd.una);
+
+ assert(left >= 0);
+
+ if(cwndleft <= 0)
+ cwndleft = 0;
+
+ if(cwndleft < left)
+ left = cwndleft;
+
+ if(!left && !sendatleastone)
+ return;
+
+ struct {
+ struct hdr hdr;
+ char data[];
+ } *pkt;
+
+ pkt = malloc(sizeof pkt->hdr + c->utcp->mtu);
+ if(!pkt->data)
+ return;
+
+ pkt->hdr.src = c->src;
+ pkt->hdr.dst = c->dst;
+ pkt->hdr.ack = c->rcv.nxt;
+ pkt->hdr.wnd = c->snd.wnd;
+ pkt->hdr.ctl = ACK;
+ pkt->hdr.aux = 0;
+
+ do {
+ uint32_t seglen = left > c->utcp->mtu ? c->utcp->mtu : left;
+ pkt->hdr.seq = c->snd.nxt;
+
+ memcpy(pkt->data, data, seglen);
+
+ c->snd.nxt += seglen;
+ data += seglen;
+ left -= seglen;
+
+ if(c->state != ESTABLISHED && !left && seglen) {
+ switch(c->state) {
+ case FIN_WAIT_1:
+ case CLOSING:
+ seglen--;
+ pkt->hdr.ctl |= FIN;
+ break;
+ default:
+ break;
+ }
+ }
+
+ print_packet(c->utcp, "send", pkt, sizeof pkt->hdr + seglen);
+ c->utcp->send(c->utcp, pkt, sizeof pkt->hdr + seglen);
+ } while(left);
+
+ free(pkt);
+}
+