# SPDX-License-Identifier: LSL-1.0 # Copyright (c) 2026 Markus Maiwald # Stewardship: Self Sovereign Society Foundation # # This file is part of the Nexus Sovereign Core. # See legal/LICENSE_SOVEREIGN.md for license terms. # SPEC-093: UTCP Protocol Implementation # Sovereign Transport for Intra-Cluster Communication # Import C decls for kernel logging proc kprint(s: cstring) {.importc, cdecl.} proc kprintln(s: cstring) {.importc, cdecl.} proc kprint_hex(n: uint64) {.importc, cdecl.} # --- Protocol Constants --- const ETHERTYPE_UTCP* = 0x88B5'u16 # Flags UTCP_FLAG_SYN* = 0x01'u8 UTCP_FLAG_ACK* = 0x02'u8 UTCP_FLAG_NACK* = 0x04'u8 UTCP_FLAG_FIN* = 0x08'u8 UTCP_FLAG_DATA* = 0x10'u8 # --- Types --- type CellID* = object ## 128-bit SipHash result representing a Node Identity lo*: uint64 hi*: uint64 UtcpHeader* {.packed.} = object ## 32-Byte Fixed Header (SPEC-093) eth_type*: uint16 # 0x88B5 (Big Endian) flags*: uint8 reserved*: uint8 target_id*: CellID # 16 bytes sender_id*: CellID # 16 bytes seq_num*: uint64 # 8 bytes (Big Endian) payload_len*: uint16 # 2 bytes (Big Endian) # Total = 46 bytes. # 46 bytes + 14 byte Eth header = 60 bytes minimum frame size. UtcpState* = enum CLOSED, LISTEN, SYN_SENT, SYN_RCVD, ESTABLISHED, FIN_WAIT UtcpControlBlock* = object state*: UtcpState local_id*: CellID remote_id*: CellID local_seq*: uint64 remote_seq*: uint64 last_ack*: uint64 const MAX_CONNECTIONS = 16 var utcp_pcb_table: array[MAX_CONNECTIONS, UtcpControlBlock] # --- Helper Functions --- proc ntohs(n: uint16): uint16 {.inline.} = return (n shr 8) or (n shl 8) proc ntohll(n: uint64): uint64 {.inline.} = var b = cast[array[8, byte]](n) # Reverse bytes return (uint64(b[0]) shl 56) or (uint64(b[1]) shl 48) or (uint64(b[2]) shl 40) or (uint64(b[3]) shl 32) or (uint64(b[4]) shl 24) or (uint64(b[5]) shl 16) or (uint64(b[6]) shl 8) or uint64(b[7]) proc htonll(n: uint64): uint64 {.inline.} = return ntohll(n) # Symmetric proc cellid_eq(a, b: CellID): bool = return a.lo == b.lo and a.hi == b.hi proc utcp_find_pcb(remote_id: CellID): ptr UtcpControlBlock = for i in 0 ..< MAX_CONNECTIONS: if utcp_pcb_table[i].state != CLOSED and cellid_eq(utcp_pcb_table[i].remote_id, remote_id): return addr utcp_pcb_table[i] return nil proc utcp_alloc_pcb(): ptr UtcpControlBlock = for i in 0 ..< MAX_CONNECTIONS: if utcp_pcb_table[i].state == CLOSED: return addr utcp_pcb_table[i] return nil # --- Logic --- proc utcp_handle_packet*(data: ptr UncheckedArray[byte], len: uint16) {.exportc, cdecl.} = ## Handle raw UTCP frame (stripped of UDP/IP headers if tunnelled) if len < uint16(sizeof(UtcpHeader)): kprintln("[UTCP] Drop: Frame too short") return let header = cast[ptr UtcpHeader](data) # Validate Magic if ntohs(header.eth_type) != ETHERTYPE_UTCP: # Allow 0x88B5 for now, but log if mismatch discard let seq_num = ntohll(header.seq_num) let flags = header.flags # Log Packet kprint("[UTCP] RX Seq="); kprint_hex(seq_num); kprint(" Flags="); kprint_hex(uint64(flags)); kprintln("") # State Machine var pcb = utcp_find_pcb(header.sender_id) if pcb == nil: # New Connection? if (flags and UTCP_FLAG_SYN) != 0: kprintln("[UTCP] New SYN received") pcb = utcp_alloc_pcb() if pcb != nil: pcb.state = SYN_RCVD pcb.remote_id = header.sender_id pcb.local_id = header.target_id pcb.remote_seq = seq_num pcb.local_seq = 1000 # Randomize? kprintln("[UTCP] State -> SYN_RCVD. Sending SYN-ACK (TODO)") # TODO: Send SYN-ACK else: kprintln("[UTCP] Drop: Table full") else: kprintln("[UTCP] Drop: Packet for unknown connection") return else: # Existing Connection kprint("[UTCP] Match PCB. State="); kprint_hex(uint64(pcb.state)); kprintln("") case pcb.state: of SYN_RCVD: if (flags and UTCP_FLAG_ACK) != 0: pcb.state = ESTABLISHED kprintln("[UTCP] State -> ESTABLISHED") of ESTABLISHED: if (flags and UTCP_FLAG_DATA) != 0: kprintln("[UTCP] Data received") # TODO: Enqueue data elif (flags and UTCP_FLAG_FIN) != 0: pcb.state = CLOSED # Simplify for now kprintln("[UTCP] Connection-Teardown (FIN)") else: discard