net: complete most of a TCP stream?

This commit is contained in:
K. Lange 2021-06-14 21:35:28 +09:00
parent 23e1b8811e
commit ef1026fb40
6 changed files with 188 additions and 90 deletions

View File

@ -29,3 +29,12 @@ struct EthernetDevice {
};
void net_eth_send(struct EthernetDevice *, size_t, void*, uint16_t, uint8_t*);
struct ArpCacheEntry {
uint8_t hwaddr[6];
uint16_t flags;
struct EthernetDevice * iface;
};
struct ArpCacheEntry * net_arp_cache_get(uint32_t addr);
void net_arp_cache_add(struct EthernetDevice * iface, uint32_t addr, uint8_t * hwaddr, uint16_t flags);

View File

@ -0,0 +1,60 @@
#pragma once
#include <stdint.h>
struct ipv4_packet {
uint8_t version_ihl;
uint8_t dscp_ecn;
uint16_t length;
uint16_t ident;
uint16_t flags_fragment;
uint8_t ttl;
uint8_t protocol;
uint16_t checksum;
uint32_t source;
uint32_t destination;
uint8_t payload[];
} __attribute__ ((packed)) __attribute__((aligned(2)));
struct icmp_header {
uint8_t type;
uint8_t code;
uint16_t csum;
uint16_t rest_of_header;
uint8_t data[];
} __attribute__((packed)) __attribute__((aligned(2)));
struct udp_packet {
uint16_t source_port;
uint16_t destination_port;
uint16_t length;
uint16_t checksum;
uint8_t payload[];
} __attribute__ ((packed)) __attribute__((aligned(2)));
struct tcp_header {
uint16_t source_port;
uint16_t destination_port;
uint32_t seq_number;
uint32_t ack_number;
uint16_t flags;
uint16_t window_size;
uint16_t checksum;
uint16_t urgent;
uint8_t payload[];
} __attribute__((packed)) __attribute__((aligned(2)));
struct tcp_check_header {
uint32_t source;
uint32_t destination;
uint8_t zeros;
uint8_t protocol;
uint16_t tcp_len;
uint8_t tcp_header[];
};
#define IPV4_PROT_UDP 17
#define IPV4_PROT_TCP 6

View File

@ -25,6 +25,9 @@ typedef struct SockData {
long (*sock_send)(struct SockData * sock, const struct msghdr *msg, int flags);
void (*sock_close)(struct SockData * sock);
long (*sock_connect)(struct SockData * sock, const struct sockaddr *addr, socklen_t addrlen);
struct sockaddr dest;
uint32_t priv32[4];
} sock_t;
void net_sock_alert(sock_t * sock);

View File

@ -38,12 +38,6 @@ static void ip_ntoa(const uint32_t src_addr, char * out) {
spin_lock_t net_arp_cache_lock = {0};
hashmap_t * net_arp_cache = NULL;
struct ArpCacheEntry {
uint8_t hwaddr[6];
uint16_t flags;
struct EthernetDevice * iface;
};
void net_arp_cache_add(struct EthernetDevice * iface, uint32_t addr, uint8_t * hwaddr, uint16_t flags) {
spin_lock(net_arp_cache_lock);
if (!net_arp_cache) net_arp_cache = hashmap_create_int(10);

View File

@ -9,6 +9,7 @@
#include <kernel/mod/net.h>
#include <kernel/net/netif.h>
#include <kernel/net/eth.h>
#include <kernel/net/ipv4.h>
#include <errno.h>
#include <sys/socket.h>
@ -43,10 +44,15 @@ void net_eth_handle(struct ethernet_packet * frame, fs_node_t * nic) {
case ETHERNET_TYPE_ARP:
net_arp_handle(&frame->payload, nic);
break;
case ETHERNET_TYPE_IPV4:
case ETHERNET_TYPE_IPV4: {
struct ipv4_packet * packet = (struct ipv4_packet*)&frame->payload;
printf("net: eth: %s: rx ipv4 packet\n", nic->name);
net_ipv4_handle(&frame->payload, nic);
if (packet->source != 0xFFFFFFFF) {
net_arp_cache_add(nic->device, packet->source, frame->source, 0);
}
net_ipv4_handle(packet, nic);
break;
}
}
}

View File

@ -16,66 +16,10 @@
#include <kernel/net/netif.h>
#include <kernel/net/eth.h>
#include <kernel/net/ipv4.h>
#include <sys/socket.h>
struct ipv4_packet {
uint8_t version_ihl;
uint8_t dscp_ecn;
uint16_t length;
uint16_t ident;
uint16_t flags_fragment;
uint8_t ttl;
uint8_t protocol;
uint16_t checksum;
uint32_t source;
uint32_t destination;
uint8_t payload[];
} __attribute__ ((packed)) __attribute__((aligned(2)));
struct icmp_header {
uint8_t type;
uint8_t code;
uint16_t csum;
uint16_t rest_of_header;
uint8_t data[];
} __attribute__((packed)) __attribute__((aligned(2)));
struct udp_packet {
uint16_t source_port;
uint16_t destination_port;
uint16_t length;
uint16_t checksum;
uint8_t payload[];
} __attribute__ ((packed)) __attribute__((aligned(2)));
struct tcp_header {
uint16_t source_port;
uint16_t destination_port;
uint32_t seq_number;
uint32_t ack_number;
uint16_t flags;
uint16_t window_size;
uint16_t checksum;
uint16_t urgent;
uint8_t payload[];
} __attribute__((packed)) __attribute__((aligned(2)));
struct tcp_check_header {
uint32_t source;
uint32_t destination;
uint8_t zeros;
uint8_t protocol;
uint16_t tcp_len;
uint8_t tcp_header[];
};
#define IPV4_PROT_UDP 17
#define IPV4_PROT_TCP 6
static void ip_ntoa(const uint32_t src_addr, char * out) {
snprintf(out, 16, "%d.%d.%d.%d",
(src_addr & 0xFF000000) >> 24,
@ -159,8 +103,6 @@ uint16_t calculate_tcp_checksum(struct tcp_check_header * p, struct tcp_header *
return ~(sum & 0xFFFF) & 0xFFFF;
}
static void icmp_handle(struct ipv4_packet * packet, const char * src, const char * dest, fs_node_t * nic) {
struct icmp_header * header = (void*)&packet->payload;
if (header->type == 8 && header->code == 0) {
@ -208,7 +150,7 @@ static hashmap_t * tcp_sockets = NULL;
#define TCP_FLAGS_NS (1 << 8)
#define DATA_OFFSET_5 (0x5 << 12)
static void tcp_ack(fs_node_t * nic, sock_t * sock, struct ipv4_packet * packet) {
static void tcp_ack(fs_node_t * nic, sock_t * sock, struct ipv4_packet * packet, int isSynAck, size_t payload_len) {
sock->priv[1] = 2;
size_t total_length = sizeof(struct ipv4_packet) + sizeof(struct tcp_header);
@ -220,28 +162,27 @@ static void tcp_ack(fs_node_t * nic, sock_t * sock, struct ipv4_packet * packet)
response->source = ((struct EthernetDevice*)nic->device)->ipv4_addr;
response->ttl = 64;
response->protocol = IPV4_PROT_TCP;
response->ident = 0;
response->flags_fragment = htons(0x4000);
response->ident = htons(1);
response->flags_fragment = htons(0x0);
response->version_ihl = 0x45;
response->dscp_ecn = 0;
response->checksum = 0;
response->checksum = htons(calculate_ipv4_checksum(response));
sock->priv[2] = 1;
sock->priv32[0] = isSynAck ? 1 : sock->priv32[0];
sock->priv32[1] = (ntohl(tcp->seq_number) + payload_len) & 0xFFFFFFFF;
/* Stick TCP header into payload */
struct tcp_header * tcp_header = (struct tcp_header*)&response->payload;
tcp_header->source_port = htons(sock->priv[0]);
tcp_header->destination_port = tcp->source_port;
tcp_header->seq_number = htonl(sock->priv[2]);
tcp_header->ack_number = tcp->seq_number;
tcp_header->seq_number = htonl(sock->priv32[0]);
tcp_header->ack_number = htonl(sock->priv32[1]);
tcp_header->flags = htons((TCP_FLAGS_ACK) | 0x5000);
tcp_header->window_size = htons(1548-54);
tcp_header->checksum = 0;
tcp_header->urgent = 0;
sock->priv[2]++;
/* Calculate checksum */
struct tcp_check_header check_hd = {
.source = response->source,
@ -254,8 +195,6 @@ static void tcp_ack(fs_node_t * nic, sock_t * sock, struct ipv4_packet * packet)
tcp_header->checksum = htons(calculate_tcp_checksum(&check_hd, tcp_header, NULL, 0));
net_eth_send((struct EthernetDevice*)nic->device, ntohs(response->length), response, ETHERNET_TYPE_IPV4, ETHERNET_BROADCAST_MAC);
net_sock_add(sock, packet, ntohs(packet->length));
}
void net_ipv4_handle(struct ipv4_packet * packet, fs_node_t * nic) {
@ -293,10 +232,18 @@ void net_ipv4_handle(struct ipv4_packet * packet, fs_node_t * nic) {
/* Awaiting SYN ACK, is this one? */
if ((ntohs(tcp->flags) & (TCP_FLAGS_SYN | TCP_FLAGS_ACK)) == (TCP_FLAGS_SYN | TCP_FLAGS_ACK)) {
printf("tcp: synack\n");
tcp_ack(nic, sock, packet);
tcp_ack(nic, sock, packet, 1, 1);
net_sock_add(sock, packet, ntohs(packet->length));
}
} else if (sock->priv[1] == 2) {
net_sock_add(sock, packet, ntohs(packet->length));
size_t packet_len = ntohs(packet->length) - sizeof(struct ipv4_packet);
size_t hlen = ((ntohs(tcp->flags) & 0xF000) >> 12) * 4;
size_t payload_len = packet_len - hlen;
if (payload_len) {
printf("acking because payload_len = %zu (hlen=%zu, packet_len=%zu)\n", payload_len, hlen, packet_len);
tcp_ack(nic, sock, packet, 0, payload_len);
net_sock_add(sock, packet, ntohs(packet->length));
}
}
}
break;
@ -402,11 +349,6 @@ static long sock_udp_recv(sock_t * sock, struct msghdr * msg, int flags) {
return resp;
}
static long sock_tcp_send(sock_t * sock, const struct msghdr *msg, int flags) {
printf("tcp: send called\n");
return 0;
}
static void sock_udp_close(sock_t * sock) {
if (sock->priv[0] && udp_sockets) {
printf("udp: removing port %d from bound map\n", sock->priv[0]);
@ -435,7 +377,7 @@ static void sock_tcp_close(sock_t * sock) {
}
}
static int next_tcp_port = 12345;
static int next_tcp_port = 49152;
static int tcp_get_port(sock_t * sock) {
spin_lock(tcp_port_lock);
int out = next_tcp_port++;
@ -464,8 +406,10 @@ static long sock_tcp_recv(sock_t * sock, struct msghdr * msg, int flags) {
struct ipv4_packet * data = net_sock_get(sock);
printf("tcp: got response, size is %u\n",
ntohs(data->length));
long resp = ntohs(data->length) - sizeof(struct ipv4_packet) - sizeof(struct tcp_header);
memcpy(msg->msg_iov[0].iov_base, data->payload + sizeof(struct tcp_header), resp);
free(data);
return 0;
return resp;
}
static long sock_tcp_connect(sock_t * sock, const struct sockaddr *addr, socklen_t addrlen) {
@ -486,6 +430,8 @@ static long sock_tcp_connect(sock_t * sock, const struct sockaddr *addr, socklen
/* Mark as awaiting connection, send initial SYN */
sock->priv[1] = 1;
memcpy(&sock->dest, addr, addrlen);
fs_node_t * nic = net_if_any();
size_t total_length = sizeof(struct ipv4_packet) + sizeof(struct tcp_header);
@ -496,8 +442,8 @@ static long sock_tcp_connect(sock_t * sock, const struct sockaddr *addr, socklen
response->source = ((struct EthernetDevice*)nic->device)->ipv4_addr;
response->ttl = 64;
response->protocol = IPV4_PROT_TCP;
response->ident = 0;
response->flags_fragment = htons(0x4000);
response->ident = htons(1);
response->flags_fragment = htons(0x0);
response->version_ihl = 0x45;
response->dscp_ecn = 0;
response->checksum = 0;
@ -543,11 +489,91 @@ static long sock_tcp_connect(sock_t * sock, const struct sockaddr *addr, socklen
ssize_t sock_tcp_read(fs_node_t *node, off_t offset, size_t size, uint8_t *buffer) {
printf("tcp: read into buffer of %zu bytes\n", size);
return 0;
struct iovec _iovec = {
buffer, size
};
struct msghdr _header = {
.msg_name = NULL,
.msg_namelen = 0,
.msg_iov = &_iovec,
.msg_iovlen = 1,
.msg_control = NULL,
.msg_controllen = 0,
.msg_flags = 0,
};
return sock_tcp_recv((sock_t*)node, &_header, 0);
}
static long sock_tcp_send(sock_t * sock, const struct msghdr *msg, int flags) {
printf("tcp: send called\n");
if (msg->msg_iovlen > 1) {
printf("net: todo: can't send multiple iovs\n");
return -ENOTSUP;
}
if (msg->msg_iovlen == 0) return 0;
size_t total_length = sizeof(struct ipv4_packet) + sizeof(struct tcp_header) + msg->msg_iov[0].iov_len;
fs_node_t * nic = net_if_any();
struct ipv4_packet * response = malloc(total_length);
response->length = htons(total_length);
response->destination = ((struct sockaddr_in*)&sock->dest)->sin_addr.s_addr;
response->source = ((struct EthernetDevice*)nic->device)->ipv4_addr;
response->ttl = 64;
response->protocol = IPV4_PROT_TCP;
response->ident = htons(1);
response->flags_fragment = htons(0x0);
response->version_ihl = 0x45;
response->dscp_ecn = 0;
response->checksum = 0;
response->checksum = htons(calculate_ipv4_checksum(response));
/* Stick TCP header into payload */
struct tcp_header * tcp_header = (struct tcp_header*)&response->payload;
tcp_header->source_port = htons(sock->priv[0]);
tcp_header->destination_port = ((struct sockaddr_in*)&sock->dest)->sin_port;
tcp_header->seq_number = htonl(sock->priv32[0]);
tcp_header->ack_number = htonl(sock->priv32[1]);
tcp_header->flags = htons(TCP_FLAGS_PSH | TCP_FLAGS_ACK | 0x5000);
tcp_header->window_size = htons(1548-54);
tcp_header->checksum = 0;
tcp_header->urgent = 0;
sock->priv32[0] += msg->msg_iov[0].iov_len;
/* Calculate checksum */
struct tcp_check_header check_hd = {
.source = response->source,
.destination = response->destination,
.zeros = 0,
.protocol = IPV4_PROT_TCP,
.tcp_len = htons(sizeof(struct tcp_header) + msg->msg_iov[0].iov_len),
};
memcpy(tcp_header->payload, msg->msg_iov[0].iov_base, msg->msg_iov[0].iov_len);
tcp_header->checksum = htons(calculate_tcp_checksum(&check_hd, tcp_header, tcp_header->payload, msg->msg_iov[0].iov_len));
struct ArpCacheEntry * resp = net_arp_cache_get(response->destination);
net_eth_send((struct EthernetDevice*)nic->device, ntohs(response->length), response, ETHERNET_TYPE_IPV4, resp ? resp->hwaddr : ETHERNET_BROADCAST_MAC);
return msg->msg_iov[0].iov_len;
}
ssize_t sock_tcp_write(fs_node_t *node, off_t offset, size_t size, uint8_t *buffer) {
printf("tcp: write of %zu bytes\n", size);
return 0;
struct iovec _iovec = {
(void*)buffer, size
};
struct msghdr _header = {
.msg_name = NULL,
.msg_namelen = 0,
.msg_iov = &_iovec,
.msg_iovlen = 1,
.msg_control = NULL,
.msg_controllen = 0,
.msg_flags = 0,
};
return sock_tcp_send((sock_t*)node, &_header, 0);
}
static int tcp_socket(void) {