net: e1000 receive fixes?
This commit is contained in:
parent
6510dd73bd
commit
fd10920585
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue