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)? */ /* what's 5 (0x20)? */
#define ICR_RXO (1 << 6) /* Receive overrun */ #define ICR_RXO (1 << 6) /* Receive overrun */
#define ICR_RXT0 (1 << 7) /* Receive timer interrupt? */ #define ICR_RXT0 (1 << 7) /* Receive timer interrupt? */
#define ICR_ACK (1 << 17)
struct e1000_rx_desc { struct e1000_rx_desc {
volatile uint64_t addr; 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; 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); fs_node_t * nic = net_if_any();
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));
/* Stick TCP header into payload */ struct ipv4_packet * response = malloc(total_length);
struct tcp_header * tcp_header = (struct tcp_header*)&response->payload; response->length = htons(total_length);
tcp_header->source_port = htons(sock->priv[0]); response->destination = ((struct sockaddr_in*)&sock->dest)->sin_addr.s_addr;
tcp_header->destination_port = ((struct sockaddr_in*)&sock->dest)->sin_port; response->source = ((struct EthernetDevice*)nic->device)->ipv4_addr;
tcp_header->seq_number = htonl(sock->priv32[0]); response->ttl = 64;
tcp_header->ack_number = htonl(sock->priv32[1]); response->protocol = IPV4_PROT_TCP;
tcp_header->flags = htons(TCP_FLAGS_PSH | TCP_FLAGS_ACK | 0x5000); sock->priv[2]++;
tcp_header->window_size = htons(DEFAULT_TCP_WINDOW_SIZE); response->ident = htons(sock->priv[2]);
tcp_header->checksum = 0; response->flags_fragment = htons(0x0);
tcp_header->urgent = 0; 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 */ sock->priv32[0] += size_to_send;
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); /* Calculate checksum */
tcp_header->checksum = htons(calculate_tcp_checksum(&check_hd, tcp_header, tcp_header->payload, msg->msg_iov[0].iov_len)); struct tcp_check_header check_hd = {
net_ipv4_send(response,nic); .source = response->source,
free(response); .destination = response->destination,
return msg->msg_iov[0].iov_len; .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) { 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; 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 <sys/socket.h>
#include <net/if.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 e1000_nic {
struct EthernetDevice eth; 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) { static void e1000_handle(struct e1000_nic * nic, uint32_t status) {
if (status & ICR_LSC) { if (status & ICR_LSC) {
/* TODO: Change interface link status. */
nic->link_status= (read_command(nic, E1000_REG_STATUS) & (1 << 1)); nic->link_status= (read_command(nic, E1000_REG_STATUS) & (1 << 1));
} }
#if 0
if (status & ICR_TXQE) { if (status & ICR_TXQE) {
/* Transmit queue empty; nothing to do. */ /* Transmit queue empty; nothing to do. */
} }
@ -187,31 +187,42 @@ static void e1000_handle(struct e1000_nic * nic, uint32_t status) {
/* transmit descriptor written */ /* transmit descriptor written */
} }
if (status & (ICR_RXO | ICR_RXT0)) { if (status & (ICR_RXO | ICR_RXT0 | ICR_ACK)) {
/* Packet received. */ /* Receive ack */
do { }
nic->rx_index = read_command(nic, E1000_REG_RXDESCTAIL); #endif
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;
void * packet = malloc(8192); int current_tail = read_command(nic, E1000_REG_RXDESCTAIL);
if (plen > 8192) { int did_something = 0;
printf("??? plen is too big\n");
}
memcpy(packet, pbuf, plen);
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); void * packet = malloc(8192);
if (plen > 8192) {
write_command(nic, E1000_REG_RXDESCTAIL, nic->rx_index); printf("??? plen is too big\n");
} else {
break;
} }
} 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); wakeup_queue(nic->rx_wait);
e1000_alert_waiters(nic); 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); spin_lock(device->tx_lock);
device->tx_index = read_command(device, E1000_REG_TXDESCTAIL); 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); memcpy(device->tx_virt[device->tx_index], payload, payload_size);
device->tx[device->tx_index].length = payload_size; device->tx[device->tx_index].length = payload_size;
device->tx[device->tx_index].cmd = CMD_EOP | CMD_IFCS | CMD_RS; //| CMD_RPS; device->tx[device->tx_index].cmd = CMD_EOP | CMD_IFCS | CMD_RS; //| CMD_RPS;