net: e1000 receive fixes?

This commit is contained in:
K. Lange 2021-09-08 19:11:28 +09:00
parent 6510dd73bd
commit fd10920585
4 changed files with 125 additions and 62 deletions

View File

@ -80,6 +80,7 @@
/* what's 5 (0x20)? */
#define ICR_RXO (1 << 6) /* Receive overrun */
#define ICR_RXT0 (1 << 7) /* Receive timer interrupt? */
#define ICR_ACK (1 << 17)
struct e1000_rx_desc {
volatile uint64_t addr;

View File

@ -693,51 +693,61 @@ static long sock_tcp_send(sock_t * sock, const struct msghdr *msg, int flags) {
}
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;
size_t size_into = 0;
size_t size_remaining = msg->msg_iov[0].iov_len;
fs_node_t * nic = net_if_any();
while (size_remaining) {
size_t size_to_send = size_remaining > 1024 ? 1024 : size_remaining;
size_t total_length = sizeof(struct ipv4_packet) + sizeof(struct tcp_header) + size_to_send;
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;
sock->priv[2]++;
response->ident = htons(sock->priv[2]);
response->flags_fragment = htons(0x0);
response->version_ihl = 0x45;
response->dscp_ecn = 0;
response->checksum = 0;
response->checksum = htons(calculate_ipv4_checksum(response));
fs_node_t * nic = net_if_any();
/* 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(DEFAULT_TCP_WINDOW_SIZE);
tcp_header->checksum = 0;
tcp_header->urgent = 0;
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;
sock->priv[2]++;
response->ident = htons(sock->priv[2]);
response->flags_fragment = htons(0x0);
response->version_ihl = 0x45;
response->dscp_ecn = 0;
response->checksum = 0;
response->checksum = htons(calculate_ipv4_checksum(response));
sock->priv32[0] += msg->msg_iov[0].iov_len;
/* 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(DEFAULT_TCP_WINDOW_SIZE);
tcp_header->checksum = 0;
tcp_header->urgent = 0;
/* 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),
};
sock->priv32[0] += size_to_send;
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));
net_ipv4_send(response,nic);
free(response);
return 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) + size_to_send),
};
memcpy(tcp_header->payload, (char*)msg->msg_iov[0].iov_base + size_into, size_to_send);
tcp_header->checksum = htons(calculate_tcp_checksum(&check_hd, tcp_header, tcp_header->payload, size_to_send));
net_ipv4_send(response,nic);
free(response);
size_remaining -= size_to_send;
size_into += size_to_send;
}
return size_into;
}
ssize_t sock_tcp_write(fs_node_t *node, off_t offset, size_t size, uint8_t *buffer) {

View File

@ -341,3 +341,35 @@ struct hostent * gethostbyname(const char * name) {
return &_hostent;
}
int getnameinfo(const struct sockaddr *addr, socklen_t addrlen,
char *host, socklen_t hostlen,
char *serv, socklen_t servlen, int flags) {
return -ENOSYS;
}
int getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints,
struct addrinfo **res) {
struct hostent * ent = gethostbyname(node);
if (!ent) return -EINVAL; /* EAI_FAIL */
*res = malloc(sizeof(struct addrinfo));
(*res)->ai_flags = 0;
(*res)->ai_family = AF_INET;
(*res)->ai_socktype = 0;
(*res)->ai_protocol = 0;
(*res)->ai_addrlen = sizeof(struct sockaddr_in);
struct sockaddr_in * addr = malloc(sizeof(struct sockaddr_in));
addr->sin_family = AF_INET;
memcpy(&addr->sin_addr.s_addr, ent->h_addr, ent->h_length);
(*res)->ai_addr = (struct sockaddr *)addr;
(*res)->ai_canonname = NULL;
(*res)->ai_next = NULL;
return 0;
}
void freeaddrinfo(struct addrinfo *res) {
if (res->ai_addr) free(res->ai_addr);
free(res);
}

View File

@ -30,7 +30,7 @@
#include <sys/socket.h>
#include <net/if.h>
#define INTS ((1 << 2) | (1 << 6) | (1 << 7) | (1 << 1) | (1 << 0))
#define INTS (ICR_LSC | ICR_RXO | ICR_RXT0 | ICR_TXQE | ICR_TXDW | ICR_ACK | ICR_RXDMT0)
struct e1000_nic {
struct EthernetDevice eth;
@ -175,10 +175,10 @@ static void e1000_alert_waiters(struct e1000_nic * nic) {
static void e1000_handle(struct e1000_nic * nic, uint32_t status) {
if (status & ICR_LSC) {
/* TODO: Change interface link status. */
nic->link_status= (read_command(nic, E1000_REG_STATUS) & (1 << 1));
}
#if 0
if (status & ICR_TXQE) {
/* Transmit queue empty; nothing to do. */
}
@ -187,31 +187,42 @@ static void e1000_handle(struct e1000_nic * nic, uint32_t status) {
/* transmit descriptor written */
}
if (status & (ICR_RXO | ICR_RXT0)) {
/* Packet received. */
do {
nic->rx_index = read_command(nic, E1000_REG_RXDESCTAIL);
if (nic->rx_index == (int)read_command(nic, E1000_REG_RXDESCHEAD)) return;
nic->rx_index = (nic->rx_index + 1) % E1000_NUM_RX_DESC;
if (nic->rx[nic->rx_index].status & 0x01) {
uint8_t * pbuf = (uint8_t *)nic->rx_virt[nic->rx_index];
uint16_t plen = nic->rx[nic->rx_index].length;
if (status & (ICR_RXO | ICR_RXT0 | ICR_ACK)) {
/* Receive ack */
}
#endif
void * packet = malloc(8192);
if (plen > 8192) {
printf("??? plen is too big\n");
}
memcpy(packet, pbuf, plen);
int current_tail = read_command(nic, E1000_REG_RXDESCTAIL);
int did_something = 0;
nic->rx[nic->rx_index].status = 0;
int i = (current_tail + 1) % E1000_NUM_RX_DESC;
while (1) {
/* Don't let the head run out... */
int current_head = read_command(nic, E1000_REG_RXDESCHEAD);
if (i == current_head) break; /* Don't receive the head... */
if (nic->rx[i].status & 0x01) {
uint8_t * pbuf = (uint8_t *)nic->rx_virt[i];
uint16_t plen = nic->rx[i].length;
enqueue_packet(nic, packet);
write_command(nic, E1000_REG_RXDESCTAIL, nic->rx_index);
} else {
break;
void * packet = malloc(8192);
if (plen > 8192) {
printf("??? plen is too big\n");
}
} while (1);
memcpy(packet, pbuf, plen);
nic->rx[i].status = 0;
enqueue_packet(nic, packet);
write_command(nic, E1000_REG_RXDESCTAIL, i);
did_something = 1;
} else {
break;
}
i = (i + 1) % E1000_NUM_RX_DESC;
}
if (did_something) {
wakeup_queue(nic->rx_wait);
e1000_alert_waiters(nic);
}
@ -244,6 +255,15 @@ static void send_packet(struct e1000_nic * device, uint8_t* payload, size_t payl
spin_lock(device->tx_lock);
device->tx_index = read_command(device, E1000_REG_TXDESCTAIL);
while ((device->tx[device->tx_index].status & 1) != 1) {
if (device->tx[device->tx_index].length == 0) break;
printf("warning: tx overrun; yielding until descriptor is available; tx index %d: status = %x; length = %x\n",
device->tx_index,
device->tx[device->tx_index].status,
device->tx[device->tx_index].length);
switch_task(1);
}
memcpy(device->tx_virt[device->tx_index], payload, payload_size);
device->tx[device->tx_index].length = payload_size;
device->tx[device->tx_index].cmd = CMD_EOP | CMD_IFCS | CMD_RS; //| CMD_RPS;