// // Created by epagris on 2023.01.16.. // #include #include #include "tcp_window.h" #include "etherlib/dynmem.h" TcpWindow *tcpw_create(uint32_t size) { uint32_t allocSize = sizeof(TcpWindow) + size; // calculate full allocation size TcpWindow * tcpw = (TcpWindow *) dynmem_alloc(allocSize); // allocate data block at the end tcpw->mp = mp_init(tcpw->data, size); // initialize memory pool return tcpw; } #define TCP_WINDOW_MAX_WINSIZE_PADDING (16) // keep-out zone, this way allocated blocks will not block registry table growth TODO: not the best solution uint32_t tcpw_get_max_window_size(TcpWindow * tcpw) { return mp_largest_free_block_size(tcpw->mp) - sizeof(TcpWindowSegment) - TCP_WINDOW_MAX_WINSIZE_PADDING; } TcpWindowSegment * tcpw_store_segment(TcpWindow * tcpw, const uint8_t * data, uint32_t size, uint32_t seqNum) { TcpWindowSegment * seg = (TcpWindowSegment *) mp_alloc(tcpw->mp, sizeof(TcpWindowSegment) + size); if (seg == NULL) { // could not store... return NULL; } // store segment descriptor seg->size = size; seg->seqNum = seqNum; // store segment memcpy(seg->data, data, size); // chain-in into linked list of segments if (tcpw->firstSeg == NULL) { tcpw->firstSeg = tcpw->lastSeg = seg; } else { tcpw->lastSeg->next = seg; } mp_report(tcpw->mp); return seg; } bool tcpw_acknowledge(TcpWindow * tcpw, uint32_t ackNum) { if (tcpw->firstSeg == NULL) { // cannot acknowledge if there's nothing to acknowledge return false; } uint32_t segAckNum = tcpw->firstSeg->seqNum + tcpw->firstSeg->size; if (segAckNum == ackNum) { // if the acknowledgement number is correct TcpWindowSegment * oldFirst = tcpw->firstSeg; // replace first TcpWindowSegment * newFirst = oldFirst->next; tcpw->firstSeg = newFirst; if (newFirst == NULL) { // if the list is empty, also clear pointer to last segment tcpw->lastSeg = NULL; } mp_free(tcpw->mp, (uint8_t *) oldFirst); // release old first segment mp_report(tcpw->mp); return true; } else { return false; } }