static const efi_guid_t efi_pxe_base_code_protocol_guid =
EFI_PXE_BASE_CODE_PROTOCOL_GUID;
static struct efi_pxe_packet *dhcp_ack;
-static bool new_rx_packet;
static void *new_tx_packet;
static void *transmit_buffer;
+static uchar **receive_buffer;
+static size_t *receive_lengths;
+static int rx_packet_idx;
+static int rx_packet_num;
/*
* The notification function of this event is called in every timer cycle
} else {
/* Disable hardware and put it into the reset state */
eth_halt();
+ /* Clear cache of packets */
+ rx_packet_num = 0;
this->mode->state = EFI_NETWORK_STOPPED;
}
out:
net_init();
/* Disable hardware and put it into the reset state */
eth_halt();
+ /* Clear cache of packets */
+ rx_packet_num = 0;
/* Set current device according to environment variables */
eth_set_current();
/* Get hardware ready for send and receive operations */
break;
}
- if (!new_rx_packet) {
+ if (!rx_packet_num) {
ret = EFI_NOT_READY;
goto out;
}
/* Fill export parameters */
- eth_hdr = (struct ethernet_hdr *)net_rx_packet;
+ eth_hdr = (struct ethernet_hdr *)receive_buffer[rx_packet_idx];
protlen = ntohs(eth_hdr->et_protlen);
if (protlen == 0x8100) {
hdr_size += 4;
- protlen = ntohs(*(u16 *)&net_rx_packet[hdr_size - 2]);
+ protlen = ntohs(*(u16 *)&receive_buffer[rx_packet_idx][hdr_size - 2]);
}
if (header_size)
*header_size = hdr_size;
memcpy(src_addr, eth_hdr->et_src, ARP_HLEN);
if (protocol)
*protocol = protlen;
- if (*buffer_size < net_rx_packet_len) {
+ if (*buffer_size < receive_lengths[rx_packet_idx]) {
/* Packet doesn't fit, try again with bigger buffer */
- *buffer_size = net_rx_packet_len;
+ *buffer_size = receive_lengths[rx_packet_idx];
ret = EFI_BUFFER_TOO_SMALL;
goto out;
}
/* Copy packet */
- memcpy(buffer, net_rx_packet, net_rx_packet_len);
- *buffer_size = net_rx_packet_len;
- new_rx_packet = 0;
- this->int_status &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+ memcpy(buffer, receive_buffer[rx_packet_idx],
+ receive_lengths[rx_packet_idx]);
+ *buffer_size = receive_lengths[rx_packet_idx];
+ rx_packet_idx = (rx_packet_idx + 1) % ETH_PACKETS_BATCH_RECV;
+ rx_packet_num--;
+ if (rx_packet_num)
+ wait_for_packet->is_signaled = true;
+ else
+ this->int_status &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
out:
return EFI_EXIT(ret);
}
*/
static void efi_net_push(void *pkt, int len)
{
- new_rx_packet = true;
+ int rx_packet_next;
+
+ /* Check that we at least received an Ethernet header */
+ if (len < sizeof(struct ethernet_hdr))
+ return;
+
+ /* Check that the buffer won't overflow */
+ if (len > PKTSIZE_ALIGN)
+ return;
+
+ /* Can't store more than pre-alloced buffer */
+ if (rx_packet_num >= ETH_PACKETS_BATCH_RECV)
+ return;
+
+ rx_packet_next = (rx_packet_idx + rx_packet_num) %
+ ETH_PACKETS_BATCH_RECV;
+ memcpy(receive_buffer[rx_packet_next], pkt, len);
+ receive_lengths[rx_packet_next] = len;
+
+ rx_packet_num++;
}
/**
if (!this || this->mode->state != EFI_NETWORK_INITIALIZED)
goto out;
- if (!new_rx_packet) {
+ if (!rx_packet_num) {
push_packet = efi_net_push;
eth_rx();
push_packet = NULL;
- if (new_rx_packet) {
- /* Check that we at least received an Ethernet header */
- if (net_rx_packet_len >=
- sizeof(struct ethernet_hdr)) {
- this->int_status |=
- EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
- wait_for_packet->is_signaled = true;
- } else {
- new_rx_packet = 0;
- }
+ if (rx_packet_num) {
+ this->int_status |=
+ EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+ wait_for_packet->is_signaled = true;
}
}
out:
{
struct efi_net_obj *netobj = NULL;
efi_status_t r;
+ int i;
if (!eth_get_dev()) {
/* No network device active, don't expose any */
goto out_of_resources;
transmit_buffer = (void *)ALIGN((uintptr_t)transmit_buffer, PKTALIGN);
+ /* Allocate a number of receive buffers */
+ receive_buffer = calloc(ETH_PACKETS_BATCH_RECV,
+ sizeof(*receive_buffer));
+ if (!receive_buffer)
+ goto out_of_resources;
+ for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++) {
+ receive_buffer[i] = malloc(PKTSIZE_ALIGN);
+ if (!receive_buffer[i])
+ goto out_of_resources;
+ }
+ receive_lengths = calloc(ETH_PACKETS_BATCH_RECV,
+ sizeof(*receive_lengths));
+ if (!receive_lengths)
+ goto out_of_resources;
+
/* Hook net up to the device list */
efi_add_handle(&netobj->header);
return r;
out_of_resources:
free(netobj);
- /* free(transmit_buffer) not needed yet */
+ free(transmit_buffer);
+ if (receive_buffer)
+ for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++)
+ free(receive_buffer[i]);
+ free(receive_buffer);
+ free(receive_lengths);
printf("ERROR: Out of memory\n");
return EFI_OUT_OF_RESOURCES;
}