Files
Deshab-OS/CODE/tools/net_stack.h
T

745 lines
27 KiB
C
Raw Normal View History

/* net_stack.h — Deshab 用户态共享网络协议栈(static inline,无库)
*
* 前置条件:包含者已定义 u8/u16/u32/u64/i64 基础类型。
* 通过 dkm_kernel_api + 0x48 的 net API 收发原始以太帧(轮询模型,无 IRQ)。
*
* 能力:eth II / ARP(含应答)/ IPv4 / ICMP echo / UDP DNS / TCP 最小 client。
* 默认拓扑:QEMU slirp — guest 10.0.2.15 / gw 10.0.2.2 / dns 10.0.2.3。
*
* 用法:
* ns_init(ctx->dkm_kernel_api) — 初始化,选第一个有线 tx/rx ready 设备
* ns_ping(ip, seq, timeout, &rtt, &ttl) — 单次 ICMP echo
* ns_dns_resolve(host, &ip) — A 记录查询(数字 IP 直接返回)
* ns_tcp_connect(ip, port, timeout)
* ns_tcp_send(data, len)
* ns_tcp_recv(buf, cap, idle_timeout) — 收至 FIN/超时,返回累计长度
* ns_tcp_close()
*
* IP 以 u32 网络序数值表示(NS_IP4(10,0,2,15))。
*/
#ifndef DESHAB_NET_STACK_H
#define DESHAB_NET_STACK_H
/* ---- 默认网络配置(QEMU user-mode slirp) ---- */
#define NS_IP4(a,b,c,d) ((u32)((((u32)(a))<<24)|(((u32)(b))<<16)|(((u32)(c))<<8)|((u32)(d))))
#define NS_GUEST_IP NS_IP4(10,0,2,15)
#define NS_GATEWAY_IP NS_IP4(10,0,2,2)
#define NS_DNS_IP NS_IP4(10,0,2,3)
#define NS_NETMASK NS_IP4(255,255,255,0)
2026-08-09 22:14:01 +08:00
/* 当前生效 IP 配置:默认 slirp 硬编码;netman 租约经 ns_apply_lease 覆盖。
* 租约约定:dsk_boot_context.reserved[7] 存放指向 net_lease_info(dsk.h)的
* 指针,结构由 DSK 常驻持有,netman 在 DHCP/静态配置成功后写入。 */
static u32 ns_guest_ip = NS_GUEST_IP;
static u32 ns_gateway_ip = NS_GATEWAY_IP;
static u32 ns_dns_ip = NS_DNS_IP;
static inline void ns_apply_lease(u32 ip, u32 gw, u32 dns) {
if (ip) ns_guest_ip = ip;
if (gw) ns_gateway_ip = gw;
if (dns) ns_dns_ip = dns;
}
/* 从 boot context 读取 netman 租约(存在且 valid 则应用)。
* ctx_u64 为 dsk_boot_context 指针值。reserved[8] 位于偏移 160
* (第 20 个 u64 起),reserved[7] = 第 27 个 u64,存 net_lease_info 指针:
* +0 magic("NETL" 0x4E45544C) +4 flags(bit0 valid) +8 ip +12 gw +16 dns */
static inline void ns_apply_lease_from_ctx(u64 ctx_u64) {
if (!ctx_u64) return;
const u64 *ctx = (const u64 *)ctx_u64;
u64 lease_ptr = ctx[27]; /* reserved[7] */
if (!lease_ptr) return;
const u32 *li = (const u32 *)lease_ptr;
if (li[0] != 0x4E45544Cu) return; /* NET_LEASE_MAGIC */
if (!(li[1] & 1u)) return; /* NET_LEASE_F_VALID */
ns_apply_lease(li[2], li[3], li[4]);
}
#define NS_ETH_ARP 0x0806
#define NS_ETH_IPV4 0x0800
#define NS_IP_ICMP 1
#define NS_IP_TCP 6
#define NS_IP_UDP 17
#define NS_ARP_CACHE_SIZE 8
#define NS_TCP_RX_CAP 65536
/* dkm_net_device_desc.flags 位(与 utsm/net.h 一致) */
#define NS_NET_F_TX_READY 0x2
#define NS_NET_F_RX_READY 0x4
#define NS_NET_F_WIRELESS 0x8
/* ---- 端口 I/O / TSC(ns_ 前缀避免与包含者冲突) ---- */
static inline void ns_outb(u16 p, u8 v) { __asm__ volatile("outb %0,%1"::"a"(v),"Nd"(p)); }
static inline u8 ns_inb(u16 p) { u8 v; __asm__ volatile("inb %1,%0":"=a"(v):"Nd"(p)); return v; }
static inline u64 ns_rdtsc(void) {
u32 lo, hi;
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
return ((u64)hi << 32) | lo;
}
/* PIT ch0 ~10ms 校准 TSC(与 shell/dsk 同法) */
static u64 ns_tsc_per_ms = 0;
static inline void ns_tsc_calibrate(void) {
if (ns_tsc_per_ms) return;
ns_outb(0x43, 0x30);
ns_outb(0x40, 0x7C);
ns_outb(0x40, 0x2E);
u64 t0 = ns_rdtsc();
u16 prev = 0; u64 loops = 0;
for (;;) {
ns_outb(0x43, 0x00);
u16 cur = (u16)ns_inb(0x40) | ((u16)ns_inb(0x40) << 8);
if (cur > prev && loops > 10) break;
prev = cur; loops++;
}
ns_tsc_per_ms = (ns_rdtsc() - t0) / 10;
if (!ns_tsc_per_ms) ns_tsc_per_ms = 3000; /* 兜底 ~3GHz */
}
static inline int ns_deadline_reached(u64 deadline) {
return (i64)(ns_rdtsc() - deadline) >= 0;
}
/* ---- 字节序/校验和 ---- */
static inline void ns_w16(u8 *p, u16 v) { p[0] = (u8)(v >> 8); p[1] = (u8)v; }
static inline void ns_w32(u8 *p, u32 v) { p[0] = (u8)(v >> 24); p[1] = (u8)(v >> 16); p[2] = (u8)(v >> 8); p[3] = (u8)v; }
static inline u16 ns_r16(const u8 *p) { return (u16)(((u16)p[0] << 8) | p[1]); }
static inline u32 ns_r32(const u8 *p) { return ((u32)p[0] << 24) | ((u32)p[1] << 16) | ((u32)p[2] << 8) | p[3]; }
static inline u16 ns_checksum(const void *data, u32 len) {
const u8 *p = (const u8 *)data;
u32 sum = 0;
while (len > 1) { sum += ((u16)p[0] << 8) | p[1]; p += 2; len -= 2; }
if (len) sum += ((u16)p[0] << 8);
while (sum >> 16) sum = (sum & 0xFFFF) + (sum >> 16);
return (u16)~sum;
}
static inline void ns_memcpy(void *d, const void *s, u32 n) {
u8 *dd = (u8 *)d; const u8 *ss = (const u8 *)s;
while (n--) *dd++ = *ss++;
}
static inline void ns_memset(void *d, u8 c, u32 n) {
u8 *dd = (u8 *)d; while (n--) *dd++ = c;
}
/* ---- 十进制/IP 字符串 ---- */
static inline void ns_u32_dec(char *buf, u32 v) {
char tmp[12]; int n = 0;
if (!v) { buf[0] = '0'; buf[1] = 0; return; }
while (v && n < 11) { tmp[n++] = (char)('0' + v % 10); v /= 10; }
for (int i = 0; i < n; i++) buf[i] = tmp[n - 1 - i];
buf[n] = 0;
}
static inline void ns_fmt_ip(u32 ip, char *out) {
int p = 0;
for (int i = 3; i >= 0; i--) {
char d[4]; ns_u32_dec(d, (ip >> (i * 8)) & 0xFF);
for (int j = 0; d[j]; j++) out[p++] = d[j];
if (i) out[p++] = '.';
}
out[p] = 0;
}
/* 解析 "a.b.c.d" → 网络序 u32。返回 0 成功。 */
static inline int ns_parse_ip(const char *s, u32 *out) {
u32 v = 0;
for (int part = 0; part < 4; part++) {
u32 n = 0; int digits = 0;
while (*s >= '0' && *s <= '9') {
n = n * 10 + (u32)(*s - '0');
if (n > 255) return -1;
s++; digits++;
}
if (!digits) return -1;
v = (v << 8) | n;
if (part < 3) {
if (*s != '.') return -1;
s++;
}
}
if (*s && *s != ' ') return -1;
*out = v;
return 0;
}
/* ---- net API 绑定 ---- */
typedef int (*ns_net_tx_fn)(u32 index, const void *packet, u32 length);
typedef int (*ns_net_rx_poll_fn)(u32 index, void *buffer, u32 capacity, u32 *out_length);
typedef u32 (*ns_net_count_fn)(void);
typedef int (*ns_net_info_fn)(u32 index, void *out);
static int ns_ready = 0;
static u32 ns_dev_index = 0;
static u8 ns_mac[6] = {0};
static ns_net_tx_fn ns_net_tx = 0;
static ns_net_rx_poll_fn ns_net_rx_poll_fn_ptr = 0;
static u16 ns_ip_id = 1;
/* dkm_net_device_info 布局:name ptr @0, mac[6] @8, flags @16(对齐填充后 size 24) */
typedef struct __attribute__((packed)) {
u64 name;
u8 mac[6];
u16 pad;
u32 flags;
} ns_dev_info;
static inline int ns_init(u64 dkm_kernel_api) {
if (ns_ready) return 0;
if (!dkm_kernel_api) return -1;
u64 net = *(u64 *)(dkm_kernel_api + 0x48);
if (!net) return -2;
ns_net_count_fn device_count = (ns_net_count_fn)*(u64 *)(net + 0x08);
ns_net_info_fn device_info = (ns_net_info_fn)*(u64 *)(net + 0x10);
ns_net_tx = (ns_net_tx_fn)*(u64 *)(net + 0x18);
ns_net_rx_poll_fn_ptr = (ns_net_rx_poll_fn)*(u64 *)(net + 0x20);
if (!device_count || !device_info || !ns_net_tx || !ns_net_rx_poll_fn_ptr) return -3;
u32 n = device_count();
if (!n) return -4;
int picked = -1;
ns_dev_info info;
for (u32 i = 0; i < n && i < 8; i++) {
ns_memset(&info, 0, sizeof(info));
if (device_info(i, &info) != 0) continue;
if (info.flags & NS_NET_F_WIRELESS) continue;
if ((info.flags & NS_NET_F_TX_READY) && (info.flags & NS_NET_F_RX_READY)) {
picked = (int)i;
for (int k = 0; k < 6; k++) ns_mac[k] = info.mac[k];
break;
}
}
if (picked < 0) {
ns_memset(&info, 0, sizeof(info));
if (device_info(0, &info) != 0) return -5;
picked = 0;
for (int k = 0; k < 6; k++) ns_mac[k] = info.mac[k];
}
ns_dev_index = (u32)picked;
ns_tsc_calibrate();
ns_ready = 1;
return 0;
}
/* ---- 帧缓冲 ---- */
static u8 ns_txbuf[2048];
static u8 ns_rxframe[2048];
/* 发送以太帧 */
static inline int ns_send_eth(const u8 dst_mac[6], u16 ethertype, const u8 *payload, u32 len) {
if (len + 14 > sizeof(ns_txbuf)) return -1;
for (int i = 0; i < 6; i++) ns_txbuf[i] = dst_mac[i];
for (int i = 0; i < 6; i++) ns_txbuf[6 + i] = ns_mac[i];
ns_w16(ns_txbuf + 12, ethertype);
ns_memcpy(ns_txbuf + 14, payload, len);
u32 total = len + 14;
if (total < 60) { /* 以太网最小帧 */
ns_memset(ns_txbuf + total, 0, 60 - total);
total = 60;
}
return ns_net_tx(ns_dev_index, ns_txbuf, total);
}
/* ---- ARP ---- */
typedef struct {
u32 ip;
u8 mac[6];
u8 valid;
} ns_arp_entry;
static ns_arp_entry ns_arp_cache[NS_ARP_CACHE_SIZE];
static u8 ns_arp_reply_mac[6];
static volatile int ns_arp_reply_valid = 0;
static inline void ns_arp_cache_put(u32 ip, const u8 mac[6]) {
int slot = -1;
for (int i = 0; i < NS_ARP_CACHE_SIZE; i++) {
if (ns_arp_cache[i].valid && ns_arp_cache[i].ip == ip) { slot = i; break; }
}
if (slot < 0) {
for (int i = 0; i < NS_ARP_CACHE_SIZE; i++) {
if (!ns_arp_cache[i].valid) { slot = i; break; }
}
}
if (slot < 0) slot = 0;
ns_arp_cache[slot].ip = ip;
for (int k = 0; k < 6; k++) ns_arp_cache[slot].mac[k] = mac[k];
ns_arp_cache[slot].valid = 1;
}
static inline int ns_arp_cache_get(u32 ip, u8 mac[6]) {
for (int i = 0; i < NS_ARP_CACHE_SIZE; i++) {
if (ns_arp_cache[i].valid && ns_arp_cache[i].ip == ip) {
for (int k = 0; k < 6; k++) mac[k] = ns_arp_cache[i].mac[k];
return 0;
}
}
return -1;
}
/* 构造 ARP 包到 out(42 字节),oper 1=request 2=reply */
static inline void ns_arp_build(u8 *out, u16 oper,
const u8 sha[6], u32 spa,
const u8 tha[6], u32 tpa) {
ns_w16(out + 0, 1); /* htype eth */
ns_w16(out + 2, NS_ETH_IPV4); /* ptype */
out[4] = 6; out[5] = 4;
ns_w16(out + 6, oper);
for (int i = 0; i < 6; i++) out[8 + i] = sha[i];
ns_w32(out + 14, spa);
for (int i = 0; i < 6; i++) out[18 + i] = tha[i];
ns_w32(out + 24, tpa);
}
/* 处理收到的 ARP 包:应答对我们的请求,记录 reply。 */
static inline void ns_arp_handle(const u8 *pkt, u32 len) {
if (len < 28) return;
u16 oper = ns_r16(pkt + 6);
u32 spa = ns_r32(pkt + 14);
u32 tpa = ns_r32(pkt + 24);
2026-08-09 22:14:01 +08:00
if (oper == 1 && tpa == ns_guest_ip) {
/* 请求我们的 IP → 回复 */
u8 reply[28];
2026-08-09 22:14:01 +08:00
ns_arp_build(reply, 2, ns_mac, ns_guest_ip, pkt + 8, spa);
ns_send_eth(pkt + 8, NS_ETH_ARP, reply, 28);
} else if (oper == 2) {
ns_arp_cache_put(spa, pkt + 8);
for (int k = 0; k < 6; k++) ns_arp_reply_mac[k] = pkt[8 + k];
ns_arp_reply_valid = 1;
}
}
/* 轮询一帧;ARP 内部处理(不返回给调用者)。
* 返回 0=收到非 ARP 帧(*out_et 为 ethertype),1=超时。 */
static inline int ns_wait_frame(u8 *buf, u32 cap, u32 *out_len, u16 *out_et, u32 timeout_ms) {
u64 deadline = ns_rdtsc() + ns_tsc_per_ms * timeout_ms;
for (;;) {
u32 len = 0;
int rc = ns_net_rx_poll_fn_ptr(ns_dev_index, buf, cap, &len);
if (rc == 0 && len >= 14) {
u16 et = ns_r16(buf + 12);
if (et == NS_ETH_ARP) {
ns_arp_handle(buf + 14, len - 14);
/* 继续等待 */
} else {
*out_len = len;
*out_et = et;
return 0;
}
}
if (ns_deadline_reached(deadline)) return 1;
__asm__ volatile("pause");
}
}
/* ARP 解析 ip → mac,3 次重传。返回 0 成功。 */
static inline int ns_arp_resolve(u32 ip, u8 out_mac[6]) {
if (ns_arp_cache_get(ip, out_mac) == 0) return 0;
static const u8 bcast[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
static const u8 zero_mac[6] = {0,0,0,0,0,0};
for (int attempt = 0; attempt < 3; attempt++) {
u8 req[28];
2026-08-09 22:14:01 +08:00
ns_arp_build(req, 1, ns_mac, ns_guest_ip, zero_mac, ip);
ns_arp_reply_valid = 0;
if (ns_send_eth(bcast, NS_ETH_ARP, req, 28) != 0) continue;
u64 deadline = ns_rdtsc() + ns_tsc_per_ms * 1000;
while (!ns_deadline_reached(deadline)) {
u32 len = 0;
int rc = ns_net_rx_poll_fn_ptr(ns_dev_index, ns_rxframe, sizeof(ns_rxframe), &len);
if (rc == 0 && len >= 14 && ns_r16(ns_rxframe + 12) == NS_ETH_ARP) {
ns_arp_handle(ns_rxframe + 14, len - 14);
if (ns_arp_reply_valid) {
u32 spa = ns_r32(ns_rxframe + 14 + 14);
if (spa == ip) {
for (int k = 0; k < 6; k++) out_mac[k] = ns_arp_reply_mac[k];
return 0;
}
ns_arp_reply_valid = 0;
}
}
__asm__ volatile("pause");
}
}
return -1;
}
/* 目标 IP 的下一跳 MAC(同子网直连,否则走网关)。返回 0 成功。 */
static inline int ns_route_mac(u32 dst_ip, u8 out_mac[6]) {
u32 next = dst_ip;
2026-08-09 22:14:01 +08:00
if ((dst_ip & NS_NETMASK) != (ns_guest_ip & NS_NETMASK)) next = ns_gateway_ip;
return ns_arp_resolve(next, out_mac);
}
/* ---- IPv4 发送 ---- */
static inline void ns_ipv4_build(u8 *out, u8 proto, u32 src, u32 dst, u32 payload_len) {
out[0] = 0x45; /* ver=4 ihl=5 */
out[1] = 0; /* tos */
ns_w16(out + 2, (u16)(20 + payload_len));
ns_w16(out + 4, ns_ip_id++);
ns_w16(out + 6, 0x4000); /* DF */
out[8] = 64; /* ttl */
out[9] = proto;
ns_w16(out + 10, 0);
ns_w32(out + 12, src);
ns_w32(out + 16, dst);
ns_w16(out + 10, ns_checksum(out, 20));
}
/* ---- ICMP echo(ping) ----
* 返回 0 成功(*out_rtt_ms / *out_ttl 有效),-1 ARP 失败,-2 超时。 */
static inline int ns_ping(u32 dst_ip, u16 seq, u32 timeout_ms, u32 *out_rtt_ms, u8 *out_ttl) {
u8 dst_mac[6];
if (ns_route_mac(dst_ip, dst_mac) != 0) return -1;
u8 pkt[20 + 8 + 32];
2026-08-09 22:14:01 +08:00
ns_ipv4_build(pkt, NS_IP_ICMP, ns_guest_ip, dst_ip, 8 + 32);
u8 *icmp = pkt + 20;
icmp[0] = 8; /* echo request */
icmp[1] = 0;
ns_w16(icmp + 2, 0);
ns_w16(icmp + 4, 0xD5AB); /* identifier */
ns_w16(icmp + 6, seq);
for (int i = 0; i < 32; i++) icmp[8 + i] = (u8)(0x61 + (i % 26));
ns_w16(icmp + 2, ns_checksum(icmp, 8 + 32));
if (ns_send_eth(dst_mac, NS_ETH_IPV4, pkt, sizeof(pkt)) != 0) return -3;
u64 t0 = ns_rdtsc();
u64 deadline = t0 + ns_tsc_per_ms * timeout_ms;
while (!ns_deadline_reached(deadline)) {
u32 len = 0;
int rc = ns_net_rx_poll_fn_ptr(ns_dev_index, ns_rxframe, sizeof(ns_rxframe), &len);
if (rc == 0 && len >= 14) {
u16 et = ns_r16(ns_rxframe + 12);
if (et == NS_ETH_ARP) {
ns_arp_handle(ns_rxframe + 14, len - 14);
} else if (et == NS_ETH_IPV4 && len >= 14 + 20 + 8) {
const u8 *ip = ns_rxframe + 14;
u8 ihl = (u8)((ip[0] & 0x0F) * 4);
if (ihl < 20 || len < 14 + ihl + 8) continue;
if (ip[9] != NS_IP_ICMP) continue;
const u8 *ic = ip + ihl;
if (ic[0] == 0 && ns_r16(ic + 4) == 0xD5AB && ns_r16(ic + 6) == seq) {
u64 dt = ns_rdtsc() - t0;
if (out_rtt_ms) {
u32 ms = (u32)(dt / ns_tsc_per_ms);
*out_rtt_ms = ms;
}
if (out_ttl) *out_ttl = ip[8];
return 0;
}
}
}
__asm__ volatile("pause");
}
return -2;
}
/* ---- UDP DNS A 查询 ----
* host 为数字 IP 时直接解析返回。返回 0 成功。 */
static inline int ns_dns_resolve(const char *host, u32 *out_ip) {
if (ns_parse_ip(host, out_ip) == 0) return 0;
u8 dst_mac[6];
2026-08-09 22:14:01 +08:00
if (ns_route_mac(ns_dns_ip, dst_mac) != 0) return -1;
/* 构造查询:header + qname + qtype/qclass */
u8 q[512];
u16 txid = (u16)(ns_rdtsc() & 0xFFFF);
if (!txid) txid = 0x1234;
ns_w16(q + 0, txid);
ns_w16(q + 2, 0x0100); /* RD */
ns_w16(q + 4, 1); /* qdcount */
ns_w16(q + 6, 0); ns_w16(q + 8, 0); ns_w16(q + 10, 0);
u32 p = 12;
u32 i = 0;
while (host[i]) {
u32 start = p++;
u8 n = 0;
while (host[i] && host[i] != '.') {
if (n >= 63 || p >= 500) return -2;
q[p++] = (u8)host[i++]; n++;
}
q[start] = n;
if (host[i] == '.') i++;
}
q[p++] = 0;
ns_w16(q + p, 1); p += 2; /* A */
ns_w16(q + p, 1); p += 2; /* IN */
u32 qlen = p;
u8 pkt[20 + 8 + 512];
2026-08-09 22:14:01 +08:00
ns_ipv4_build(pkt, NS_IP_UDP, ns_guest_ip, ns_dns_ip, 8 + qlen);
u8 *udp = pkt + 20;
ns_w16(udp + 0, 49153);
ns_w16(udp + 2, 53);
ns_w16(udp + 4, (u16)(8 + qlen));
ns_w16(udp + 6, 0); /* 不校验 UDP checksum */
ns_memcpy(udp + 8, q, qlen);
for (int attempt = 0; attempt < 2; attempt++) {
if (ns_send_eth(dst_mac, NS_ETH_IPV4, pkt, 20 + 8 + qlen) != 0) continue;
u64 deadline = ns_rdtsc() + ns_tsc_per_ms * 3000;
while (!ns_deadline_reached(deadline)) {
u32 len = 0;
int rc = ns_net_rx_poll_fn_ptr(ns_dev_index, ns_rxframe, sizeof(ns_rxframe), &len);
if (rc == 0 && len >= 14) {
u16 et = ns_r16(ns_rxframe + 12);
if (et == NS_ETH_ARP) {
ns_arp_handle(ns_rxframe + 14, len - 14);
} else if (et == NS_ETH_IPV4 && len >= 14 + 20 + 8 + 12) {
const u8 *ip = ns_rxframe + 14;
u8 ihl = (u8)((ip[0] & 0x0F) * 4);
if (ihl < 20 || ip[9] != NS_IP_UDP) continue;
const u8 *ru = ip + ihl;
if (ns_r16(ru + 2) != 49153) continue;
const u8 *d = ru + 8;
if (ns_r16(d + 0) != txid) continue;
u16 qd = ns_r16(d + 4);
u16 an = ns_r16(d + 6);
u32 off = 12;
/* 跳过问题段 */
for (u16 qq = 0; qq < qd; qq++) {
while (off < len) {
u8 b = d[off];
if (b == 0) { off++; break; }
if ((b & 0xC0) == 0xC0) { off += 2; break; }
off += 1 + b;
}
off += 4;
}
/* 遍历应答 RR */
for (u16 rr = 0; rr < an; rr++) {
while (off < len) { /* 跳过 name */
u8 b = d[off];
if (b == 0) { off++; break; }
if ((b & 0xC0) == 0xC0) { off += 2; break; }
off += 1 + b;
}
if (off + 10 > len) break;
u16 rtype = ns_r16(d + off);
u16 rdlen = ns_r16(d + off + 8);
off += 10;
if (rtype == 1 && rdlen == 4 && off + 4 <= len) {
*out_ip = ns_r32(d + off);
return 0;
}
off += rdlen;
}
}
}
__asm__ volatile("pause");
}
}
return -3;
}
/* ---- TCP 最小 client ---- */
#define NS_TCP_CLOSED 0
#define NS_TCP_SYN_SENT 1
#define NS_TCP_ESTAB 2
#define NS_TCP_FIN_WAIT 3
static struct {
u32 state;
u32 dst_ip;
u16 dst_port;
u16 src_port;
u32 snd_nxt;
u32 rcv_nxt;
u8 dst_mac[6];
} ns_tc = {0, 0, 0, 0, 0, 0, {0}};
static u8 ns_tcp_rx[NS_TCP_RX_CAP];
static u32 ns_tcp_rx_len = 0;
static volatile int ns_tcp_got_fin = 0;
static volatile int ns_tcp_got_rst = 0;
#define NS_TCP_FIN 0x01
#define NS_TCP_SYN 0x02
#define NS_TCP_RST 0x04
#define NS_TCP_PSH 0x08
#define NS_TCP_ACK 0x10
/* 构造并发送 TCP 段(data 可为 0)。 */
static inline int ns_tcp_emit(u8 flags, const u8 *data, u32 len, u32 seq) {
u8 pkt[20 + 20 + 1460];
if (len > 1460) return -1;
u32 tcp_len = 20 + len;
2026-08-09 22:14:01 +08:00
ns_ipv4_build(pkt, NS_IP_TCP, ns_guest_ip, ns_tc.dst_ip, tcp_len);
u8 *t = pkt + 20;
ns_w16(t + 0, ns_tc.src_port);
ns_w16(t + 2, ns_tc.dst_port);
ns_w32(t + 4, seq);
ns_w32(t + 8, (flags & NS_TCP_ACK) ? ns_tc.rcv_nxt : 0);
t[12] = (5 << 4); /* data offset */
t[13] = flags;
ns_w16(t + 14, 64240); /* window */
ns_w16(t + 16, 0);
ns_w16(t + 18, 0);
if (len) ns_memcpy(t + 20, data, len);
/* 伪头部校验和 */
u8 ph[12];
2026-08-09 22:14:01 +08:00
ns_w32(ph + 0, ns_guest_ip);
ns_w32(ph + 4, ns_tc.dst_ip);
ph[8] = 0; ph[9] = NS_IP_TCP;
ns_w16(ph + 10, (u16)tcp_len);
u32 sum = 0;
for (u32 k = 0; k < 12; k += 2) sum += ((u16)ph[k] << 8) | ph[k + 1];
for (u32 k = 0; k + 1 < tcp_len; k += 2) sum += ((u16)t[k] << 8) | t[k + 1];
if (tcp_len & 1) sum += ((u16)t[tcp_len - 1] << 8);
while (sum >> 16) sum = (sum & 0xFFFF) + (sum >> 16);
ns_w16(t + 16, (u16)~sum);
return ns_send_eth(ns_tc.dst_mac, NS_ETH_IPV4, pkt, 20 + tcp_len);
}
/* 处理收到的 IPv4/TCP 段。返回 1 表示属于本连接并已处理。 */
static inline int ns_tcp_process(const u8 *ip, u32 ip_len) {
if (ip_len < 20) return 0;
u8 ihl = (u8)((ip[0] & 0x0F) * 4);
if (ihl < 20 || ip_len < ihl + 20) return 0;
if (ip[9] != NS_IP_TCP) return 0;
if (ns_r32(ip + 12) != ns_tc.dst_ip) return 0;
const u8 *t = ip + ihl;
if (ns_r16(t + 0) != ns_tc.dst_port) return 0;
if (ns_r16(t + 2) != ns_tc.src_port) return 0;
u32 seq = ns_r32(t + 4);
u32 ack = ns_r32(t + 8);
u8 doff = (u8)((t[12] >> 4) * 4);
u8 flags = t[13];
u16 ip_total = ns_r16(ip + 2);
u32 data_len = (u32)ip_total - ihl - doff;
const u8 *data = t + doff;
if (flags & NS_TCP_RST) { ns_tcp_got_rst = 1; ns_tc.state = NS_TCP_CLOSED; return 1; }
if (ns_tc.state == NS_TCP_SYN_SENT) {
if ((flags & (NS_TCP_SYN | NS_TCP_ACK)) == (NS_TCP_SYN | NS_TCP_ACK)) {
ns_tc.rcv_nxt = seq + 1;
ns_tc.snd_nxt = ack;
ns_tc.state = NS_TCP_ESTAB;
ns_tcp_emit(NS_TCP_ACK, 0, 0, ns_tc.snd_nxt);
}
return 1;
}
if (ns_tc.state == NS_TCP_ESTAB || ns_tc.state == NS_TCP_FIN_WAIT) {
if (data_len > 0) {
if (seq == ns_tc.rcv_nxt) {
u32 room = NS_TCP_RX_CAP - ns_tcp_rx_len;
u32 take = data_len < room ? data_len : room;
ns_memcpy(ns_tcp_rx + ns_tcp_rx_len, data, take);
ns_tcp_rx_len += take;
ns_tc.rcv_nxt += data_len;
ns_tcp_emit(NS_TCP_ACK, 0, 0, ns_tc.snd_nxt);
} else {
/* 乱序超前或重复段:重 ACK 当前期望序号 */
ns_tcp_emit(NS_TCP_ACK, 0, 0, ns_tc.snd_nxt);
}
}
if (flags & NS_TCP_FIN) {
if (seq + data_len == ns_tc.rcv_nxt || data_len == 0) {
ns_tc.rcv_nxt = seq + data_len + 1;
ns_tcp_emit(NS_TCP_ACK, 0, 0, ns_tc.snd_nxt);
ns_tcp_got_fin = 1;
ns_tc.state = NS_TCP_CLOSED;
}
}
return 1;
}
return 1;
}
/* 在超时窗口内收帧并喂给 TCP;返回 0=收到本连接段,1=超时。 */
static inline int ns_tcp_wait(u32 timeout_ms) {
u64 deadline = ns_rdtsc() + ns_tsc_per_ms * timeout_ms;
while (!ns_deadline_reached(deadline)) {
u32 len = 0;
int rc = ns_net_rx_poll_fn_ptr(ns_dev_index, ns_rxframe, sizeof(ns_rxframe), &len);
if (rc == 0 && len >= 14) {
u16 et = ns_r16(ns_rxframe + 12);
if (et == NS_ETH_ARP) {
ns_arp_handle(ns_rxframe + 14, len - 14);
} else if (et == NS_ETH_IPV4) {
if (ns_tcp_process(ns_rxframe + 14, len - 14)) return 0;
}
}
__asm__ volatile("pause");
}
return 1;
}
/* 返回 0 成功(state=ESTAB),-1 ARP 失败,-2 超时/RST。 */
static inline int ns_tcp_connect(u32 dst_ip, u16 dst_port, u32 timeout_ms) {
if (ns_route_mac(dst_ip, ns_tc.dst_mac) != 0) return -1;
ns_tc.dst_ip = dst_ip;
ns_tc.dst_port = dst_port;
ns_tc.src_port = (u16)(49152 + (ns_rdtsc() & 0x0FFF));
u32 iss = (u32)ns_rdtsc();
ns_tcp_rx_len = 0;
ns_tcp_got_fin = 0;
ns_tcp_got_rst = 0;
for (int attempt = 0; attempt < 3; attempt++) {
ns_tc.state = NS_TCP_SYN_SENT;
if (ns_tcp_emit(NS_TCP_SYN, 0, 0, iss) != 0) continue;
u64 deadline = ns_rdtsc() + ns_tsc_per_ms * timeout_ms;
while (!ns_deadline_reached(deadline)) {
if (ns_tcp_got_rst) { ns_tc.state = NS_TCP_CLOSED; return -2; }
if (ns_tc.state == NS_TCP_ESTAB) return 0;
ns_tcp_wait(50);
}
}
ns_tc.state = NS_TCP_CLOSED;
return -2;
}
/* 发送数据并等待 ACK(数据段可能在等待期间到达,已入缓冲)。 */
static inline int ns_tcp_send(const u8 *data, u32 len) {
if (ns_tc.state != NS_TCP_ESTAB) return -1;
for (int attempt = 0; attempt < 3; attempt++) {
u32 expect = ns_tc.snd_nxt + len;
if (ns_tcp_emit((u8)(NS_TCP_PSH | NS_TCP_ACK), data, len, ns_tc.snd_nxt) != 0) return -2;
u64 deadline = ns_rdtsc() + ns_tsc_per_ms * 2000;
while (!ns_deadline_reached(deadline)) {
if (ns_tcp_got_rst) { ns_tc.state = NS_TCP_CLOSED; return -3; }
/* 检查 snd_una 是否被 ACK 推进:ns_tcp_process 不记录 una,
* 简单起见此处认为发出后收到任何本连接段即推进。
* 对 HTTP/1.0 请求-响应模式足够(对端 ACK+数据一起回来)。 */
if (ns_tcp_wait(100) == 0) {
ns_tc.snd_nxt = expect;
return 0;
}
}
}
return -4;
}
/* 收至 FIN 或空闲超时;把累计数据拷到 buf(最多 cap)。返回长度或负值。 */
static inline int ns_tcp_recv(u8 *buf, u32 cap, u32 idle_timeout_ms) {
u64 idle_deadline = ns_rdtsc() + ns_tsc_per_ms * idle_timeout_ms;
for (;;) {
if (ns_tcp_got_rst) return -1;
if (ns_tcp_got_fin) break;
if (ns_deadline_reached(idle_deadline)) break;
if (ns_tcp_wait(100) == 0) {
idle_deadline = ns_rdtsc() + ns_tsc_per_ms * idle_timeout_ms;
}
}
u32 n = ns_tcp_rx_len < cap ? ns_tcp_rx_len : cap;
if (buf && n) ns_memcpy(buf, ns_tcp_rx, n);
return (int)n;
}
static inline void ns_tcp_close(void) {
if (ns_tc.state == NS_TCP_ESTAB) {
ns_tcp_emit((u8)(NS_TCP_FIN | NS_TCP_ACK), 0, 0, ns_tc.snd_nxt);
}
ns_tc.state = NS_TCP_CLOSED;
}
#endif /* DESHAB_NET_STACK_H */