[build] Handle all driver list construction via parserom.pl
Handle construction of the EFI, Linux, Xen, and VMBus driver build rules via parserom.pl to ensure consistency. In particular, this allows those drivers to appear in the DRIVERS_SECBOOT list used to filter out non-permitted drivers in a Secure Boot build. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -1,325 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 David Decotigny <ddecotig@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ipxe/linux_api.h>
|
||||
#include <ipxe/list.h>
|
||||
#include <ipxe/linux.h>
|
||||
#include <ipxe/malloc.h>
|
||||
#include <ipxe/device.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <ipxe/iobuf.h>
|
||||
#include <ipxe/ethernet.h>
|
||||
#include <ipxe/settings.h>
|
||||
#include <ipxe/socket.h>
|
||||
|
||||
/* This hack prevents pre-2.6.32 headers from redefining struct sockaddr */
|
||||
#define _SYS_SOCKET_H
|
||||
#define __GLIBC__ 2
|
||||
#include <linux/socket.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_packet.h>
|
||||
#undef __GLIBC__
|
||||
#include <byteswap.h>
|
||||
|
||||
/* linux-specifc syscall params */
|
||||
#define LINUX_AF_PACKET 17
|
||||
#define LINUX_SOCK_RAW 3
|
||||
#define LINUX_SIOCGIFINDEX 0x8933
|
||||
#define LINUX_SIOCGIFHWADDR 0x8927
|
||||
|
||||
#define RX_BUF_SIZE 1536
|
||||
|
||||
/** @file
|
||||
*
|
||||
* The AF_PACKET driver.
|
||||
*
|
||||
* Bind to an existing linux network interface.
|
||||
*/
|
||||
|
||||
struct af_packet_nic {
|
||||
/** Linux network interface name */
|
||||
char * ifname;
|
||||
/** Packet socket descriptor */
|
||||
int fd;
|
||||
/** ifindex */
|
||||
int ifindex;
|
||||
};
|
||||
|
||||
/** Open the linux interface */
|
||||
static int af_packet_nic_open ( struct net_device * netdev )
|
||||
{
|
||||
struct af_packet_nic * nic = netdev->priv;
|
||||
struct sockaddr_ll socket_address;
|
||||
struct ifreq if_data;
|
||||
int ret;
|
||||
|
||||
nic->fd = linux_socket(LINUX_AF_PACKET, LINUX_SOCK_RAW,
|
||||
htons(ETH_P_ALL));
|
||||
if (nic->fd < 0) {
|
||||
DBGC(nic, "af_packet %p socket(AF_PACKET) = %d (%s)\n",
|
||||
nic, nic->fd, linux_strerror(linux_errno));
|
||||
return nic->fd;
|
||||
}
|
||||
|
||||
/* resolve ifindex of ifname */
|
||||
memset(&if_data, 0, sizeof(if_data));
|
||||
strncpy(if_data.ifr_name, nic->ifname, sizeof(if_data.ifr_name));
|
||||
ret = linux_ioctl(nic->fd, LINUX_SIOCGIFINDEX, &if_data);
|
||||
if (ret < 0) {
|
||||
DBGC(nic, "af_packet %p ioctl(SIOCGIFINDEX) = %d (%s)\n",
|
||||
nic, ret, linux_strerror(linux_errno));
|
||||
linux_close(nic->fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
nic->ifindex = if_data.ifr_ifindex;
|
||||
|
||||
/* bind to interface */
|
||||
memset(&socket_address, 0, sizeof(socket_address));
|
||||
socket_address.sll_family = LINUX_AF_PACKET;
|
||||
socket_address.sll_ifindex = nic->ifindex;
|
||||
socket_address.sll_protocol = htons(ETH_P_ALL);
|
||||
ret = linux_bind(nic->fd, (void *) &socket_address,
|
||||
sizeof(socket_address));
|
||||
if (ret == -1) {
|
||||
DBGC(nic, "af_packet %p bind() = %d (%s)\n",
|
||||
nic, ret, linux_strerror(linux_errno));
|
||||
linux_close(nic->fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set nonblocking mode to make af_packet_nic_poll() easier */
|
||||
ret = linux_fcntl(nic->fd, F_SETFL, O_NONBLOCK);
|
||||
if (ret != 0) {
|
||||
DBGC(nic, "af_packet %p fcntl(%d, ...) = %d (%s)\n",
|
||||
nic, nic->fd, ret, linux_strerror(linux_errno));
|
||||
linux_close(nic->fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Close the packet socket */
|
||||
static void af_packet_nic_close ( struct net_device *netdev )
|
||||
{
|
||||
struct af_packet_nic * nic = netdev->priv;
|
||||
linux_close(nic->fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmit an ethernet packet.
|
||||
*
|
||||
* The packet can be written to the socket and marked as complete immediately.
|
||||
*/
|
||||
static int af_packet_nic_transmit ( struct net_device *netdev,
|
||||
struct io_buffer *iobuf )
|
||||
{
|
||||
struct af_packet_nic * nic = netdev->priv;
|
||||
struct sockaddr_ll socket_address;
|
||||
const struct ethhdr * eh;
|
||||
int rc;
|
||||
|
||||
memset(&socket_address, 0, sizeof(socket_address));
|
||||
socket_address.sll_family = LINUX_AF_PACKET;
|
||||
socket_address.sll_ifindex = nic->ifindex;
|
||||
socket_address.sll_halen = ETH_ALEN;
|
||||
|
||||
eh = iobuf->data;
|
||||
memcpy(socket_address.sll_addr, eh->h_dest, ETH_ALEN);
|
||||
|
||||
rc = linux_sendto(nic->fd, iobuf->data, iobuf->tail - iobuf->data,
|
||||
0, (struct sockaddr *)&socket_address,
|
||||
sizeof(socket_address));
|
||||
|
||||
DBGC2(nic, "af_packet %p wrote %d bytes\n", nic, rc);
|
||||
netdev_tx_complete(netdev, iobuf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Poll for new packets */
|
||||
static void af_packet_nic_poll ( struct net_device *netdev )
|
||||
{
|
||||
struct af_packet_nic * nic = netdev->priv;
|
||||
struct pollfd pfd;
|
||||
struct io_buffer * iobuf;
|
||||
int r;
|
||||
|
||||
pfd.fd = nic->fd;
|
||||
pfd.events = POLLIN;
|
||||
if (linux_poll(&pfd, 1, 0) == -1) {
|
||||
DBGC(nic, "af_packet %p poll failed (%s)\n",
|
||||
nic, linux_strerror(linux_errno));
|
||||
return;
|
||||
}
|
||||
if ((pfd.revents & POLLIN) == 0)
|
||||
return;
|
||||
|
||||
/* At this point we know there is at least one new packet to be read */
|
||||
|
||||
iobuf = alloc_iob(RX_BUF_SIZE);
|
||||
if (! iobuf)
|
||||
goto allocfail;
|
||||
|
||||
while ((r = linux_read(nic->fd, iobuf->data, RX_BUF_SIZE)) > 0) {
|
||||
DBGC2(nic, "af_packet %p read %d bytes\n", nic, r);
|
||||
|
||||
iob_put(iobuf, r);
|
||||
netdev_rx(netdev, iobuf);
|
||||
|
||||
iobuf = alloc_iob(RX_BUF_SIZE);
|
||||
if (! iobuf)
|
||||
goto allocfail;
|
||||
}
|
||||
|
||||
free_iob(iobuf);
|
||||
return;
|
||||
|
||||
allocfail:
|
||||
DBGC(nic, "af_packet %p alloc_iob failed\n", nic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set irq.
|
||||
*
|
||||
* Not used on linux, provide a dummy implementation.
|
||||
*/
|
||||
static void af_packet_nic_irq ( struct net_device *netdev, int enable )
|
||||
{
|
||||
struct af_packet_nic *nic = netdev->priv;
|
||||
|
||||
DBGC(nic, "af_packet %p irq enable = %d\n", nic, enable);
|
||||
}
|
||||
|
||||
|
||||
static int af_packet_update_properties ( struct net_device *netdev )
|
||||
{
|
||||
struct af_packet_nic *nic = netdev->priv;
|
||||
struct ifreq if_data;
|
||||
int ret;
|
||||
|
||||
/* retrieve default MAC address */
|
||||
int fd = linux_socket(LINUX_AF_PACKET, LINUX_SOCK_RAW, 0);
|
||||
if (fd < 0) {
|
||||
DBGC(nic, "af_packet %p cannot create raw socket (%s)\n",
|
||||
nic, linux_strerror(linux_errno));
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* retrieve host's MAC address */
|
||||
memset(&if_data, 0, sizeof(if_data));
|
||||
strncpy(if_data.ifr_name, nic->ifname, sizeof(if_data.ifr_name));
|
||||
ret = linux_ioctl(fd, LINUX_SIOCGIFHWADDR, &if_data);
|
||||
if (ret < 0) {
|
||||
DBGC(nic, "af_packet %p cannot get mac addr (%s)\n",
|
||||
nic, linux_strerror(linux_errno));
|
||||
linux_close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
linux_close(fd);
|
||||
/* struct sockaddr = { u16 family, u8 pad[14] (equiv. sa_data) }; */
|
||||
memcpy(netdev->ll_addr, if_data.ifr_hwaddr.pad, ETH_ALEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** AF_PACKET operations */
|
||||
static struct net_device_operations af_packet_nic_operations = {
|
||||
.open = af_packet_nic_open,
|
||||
.close = af_packet_nic_close,
|
||||
.transmit = af_packet_nic_transmit,
|
||||
.poll = af_packet_nic_poll,
|
||||
.irq = af_packet_nic_irq,
|
||||
};
|
||||
|
||||
/** Handle a device request for the af_packet driver */
|
||||
static int af_packet_nic_probe ( struct linux_device *device,
|
||||
struct linux_device_request *request )
|
||||
{
|
||||
struct linux_setting *if_setting;
|
||||
struct net_device *netdev;
|
||||
struct af_packet_nic *nic;
|
||||
int rc;
|
||||
|
||||
netdev = alloc_etherdev(sizeof(*nic));
|
||||
if (! netdev)
|
||||
return -ENOMEM;
|
||||
|
||||
netdev_init(netdev, &af_packet_nic_operations);
|
||||
nic = netdev->priv;
|
||||
linux_set_drvdata(device, netdev);
|
||||
netdev->dev = &device->dev;
|
||||
|
||||
memset(nic, 0, sizeof(*nic));
|
||||
|
||||
/* Look for the mandatory if setting */
|
||||
if_setting = linux_find_setting("if", &request->settings);
|
||||
|
||||
/* No if setting */
|
||||
if (! if_setting) {
|
||||
printf("af_packet missing a mandatory if setting\n");
|
||||
rc = -EINVAL;
|
||||
goto err_settings;
|
||||
}
|
||||
|
||||
nic->ifname = if_setting->value;
|
||||
snprintf ( device->dev.name, sizeof ( device->dev.name ), "%s",
|
||||
nic->ifname );
|
||||
device->dev.desc.bus_type = BUS_TYPE_TAP;
|
||||
af_packet_update_properties(netdev);
|
||||
if_setting->applied = 1;
|
||||
|
||||
/* Apply rest of the settings */
|
||||
linux_apply_settings(&request->settings, &netdev->settings.settings);
|
||||
|
||||
/* Register network device */
|
||||
if ((rc = register_netdev(netdev)) != 0)
|
||||
goto err_register;
|
||||
|
||||
netdev_link_up(netdev);
|
||||
|
||||
return 0;
|
||||
|
||||
unregister_netdev(netdev);
|
||||
err_register:
|
||||
err_settings:
|
||||
netdev_nullify(netdev);
|
||||
netdev_put(netdev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/** Remove the device */
|
||||
static void af_packet_nic_remove ( struct linux_device *device )
|
||||
{
|
||||
struct net_device *netdev = linux_get_drvdata(device);
|
||||
unregister_netdev(netdev);
|
||||
netdev_nullify(netdev);
|
||||
netdev_put(netdev);
|
||||
}
|
||||
|
||||
/** AF_PACKET linux_driver */
|
||||
struct linux_driver af_packet_nic_driver __linux_driver = {
|
||||
.name = "af_packet",
|
||||
.probe = af_packet_nic_probe,
|
||||
.remove = af_packet_nic_remove,
|
||||
};
|
||||
@@ -1,552 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <ipxe/ethernet.h>
|
||||
#include <ipxe/if_ether.h>
|
||||
#include <ipxe/in.h>
|
||||
#include <ipxe/timer.h>
|
||||
#include <ipxe/retry.h>
|
||||
#include <ipxe/linux.h>
|
||||
#include <ipxe/linux_api.h>
|
||||
#include <ipxe/slirp.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Linux Slirp network driver
|
||||
*
|
||||
*/
|
||||
|
||||
/** Maximum number of open file descriptors */
|
||||
#define SLIRP_MAX_FDS 128
|
||||
|
||||
/** A Slirp network interface */
|
||||
struct slirp_nic {
|
||||
/** The libslirp device object */
|
||||
struct Slirp *slirp;
|
||||
/** Polling file descriptor list */
|
||||
struct pollfd pollfds[SLIRP_MAX_FDS];
|
||||
/** Number of file descriptors */
|
||||
unsigned int numfds;
|
||||
};
|
||||
|
||||
/** A Slirp alarm timer */
|
||||
struct slirp_alarm {
|
||||
/** Slirp network interface */
|
||||
struct slirp_nic *slirp;
|
||||
/** Retry timer */
|
||||
struct retry_timer timer;
|
||||
/** Callback function */
|
||||
void ( __asmcall * callback ) ( void *opaque );
|
||||
/** Opaque value for callback function */
|
||||
void *opaque;
|
||||
};
|
||||
|
||||
/** Default MAC address */
|
||||
static const uint8_t slirp_default_mac[ETH_ALEN] =
|
||||
{ 0x52, 0x54, 0x00, 0x12, 0x34, 0x56 };
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Slirp interface
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Send packet
|
||||
*
|
||||
* @v buf Data buffer
|
||||
* @v len Length of data
|
||||
* @v device Device opaque pointer
|
||||
* @ret len Consumed length (or negative on error)
|
||||
*/
|
||||
static ssize_t __asmcall slirp_send_packet ( const void *buf, size_t len,
|
||||
void *device ) {
|
||||
struct net_device *netdev = device;
|
||||
struct io_buffer *iobuf;
|
||||
|
||||
/* Allocate I/O buffer */
|
||||
iobuf = alloc_iob ( len );
|
||||
if ( ! iobuf )
|
||||
return -1;
|
||||
|
||||
/* Populate I/O buffer */
|
||||
memcpy ( iob_put ( iobuf, len ), buf, len );
|
||||
|
||||
/* Hand off to network stack */
|
||||
netdev_rx ( netdev, iobuf );
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print an error message
|
||||
*
|
||||
* @v msg Error message
|
||||
* @v device Device opaque pointer
|
||||
*/
|
||||
static void __asmcall slirp_guest_error ( const char *msg, void *device ) {
|
||||
struct net_device *netdev = device;
|
||||
struct slirp_nic *slirp = netdev->priv;
|
||||
|
||||
DBGC ( slirp, "SLIRP %p error: %s\n", slirp, msg );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get virtual clock
|
||||
*
|
||||
* @v device Device opaque pointer
|
||||
* @ret clock_ns Clock time in nanoseconds
|
||||
*/
|
||||
static int64_t __asmcall slirp_clock_get_ns ( void *device __unused ) {
|
||||
int64_t time;
|
||||
|
||||
time = currticks();
|
||||
return ( time * ( 1000000 / TICKS_PER_MS ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle timer expiry
|
||||
*
|
||||
* @v timer Retry timer
|
||||
* @v over Failure indicator
|
||||
*/
|
||||
static void slirp_expired ( struct retry_timer *timer, int over __unused ) {
|
||||
struct slirp_alarm *alarm =
|
||||
container_of ( timer, struct slirp_alarm, timer );
|
||||
struct slirp_nic *slirp = alarm->slirp;
|
||||
|
||||
/* Notify callback */
|
||||
DBGC ( slirp, "SLIRP %p timer fired\n", slirp );
|
||||
alarm->callback ( alarm->opaque );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new timer
|
||||
*
|
||||
* @v callback Timer callback
|
||||
* @v opaque Timer opaque pointer
|
||||
* @v device Device opaque pointer
|
||||
* @ret timer Timer
|
||||
*/
|
||||
static void * __asmcall
|
||||
slirp_timer_new ( void ( __asmcall * callback ) ( void *opaque ),
|
||||
void *opaque, void *device ) {
|
||||
struct net_device *netdev = device;
|
||||
struct slirp_nic *slirp = netdev->priv;
|
||||
struct slirp_alarm *alarm;
|
||||
|
||||
/* Allocate timer */
|
||||
alarm = malloc ( sizeof ( *alarm ) );
|
||||
if ( ! alarm ) {
|
||||
DBGC ( slirp, "SLIRP %p could not allocate timer\n", slirp );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialise timer */
|
||||
memset ( alarm, 0, sizeof ( *alarm ) );
|
||||
alarm->slirp = slirp;
|
||||
timer_init ( &alarm->timer, slirp_expired, NULL );
|
||||
alarm->callback = callback;
|
||||
alarm->opaque = opaque;
|
||||
DBGC ( slirp, "SLIRP %p timer %p has callback %p (%p)\n",
|
||||
slirp, alarm, alarm->callback, alarm->opaque );
|
||||
|
||||
return alarm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a timer
|
||||
*
|
||||
* @v timer Timer
|
||||
* @v device Device opaque pointer
|
||||
*/
|
||||
static void __asmcall slirp_timer_free ( void *timer, void *device ) {
|
||||
struct net_device *netdev = device;
|
||||
struct slirp_nic *slirp = netdev->priv;
|
||||
struct slirp_alarm *alarm = timer;
|
||||
|
||||
/* Ignore timers that failed to allocate */
|
||||
if ( ! alarm )
|
||||
return;
|
||||
|
||||
/* Stop timer */
|
||||
stop_timer ( &alarm->timer );
|
||||
|
||||
/* Free timer */
|
||||
free ( alarm );
|
||||
DBGC ( slirp, "SLIRP %p timer %p freed\n", slirp, alarm );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set timer expiry time
|
||||
*
|
||||
* @v timer Timer
|
||||
* @v expire Expiry time
|
||||
* @v device Device opaque pointer
|
||||
*/
|
||||
static void __asmcall slirp_timer_mod ( void *timer, int64_t expire,
|
||||
void *device ) {
|
||||
struct net_device *netdev = device;
|
||||
struct slirp_nic *slirp = netdev->priv;
|
||||
struct slirp_alarm *alarm = timer;
|
||||
int64_t timeout_ms;
|
||||
unsigned long timeout;
|
||||
|
||||
/* Ignore timers that failed to allocate */
|
||||
if ( ! alarm )
|
||||
return;
|
||||
|
||||
/* (Re)start timer */
|
||||
timeout_ms = ( expire - ( currticks() / TICKS_PER_MS ) );
|
||||
if ( timeout_ms < 0 )
|
||||
timeout_ms = 0;
|
||||
timeout = ( timeout_ms * TICKS_PER_MS );
|
||||
start_timer_fixed ( &alarm->timer, timeout );
|
||||
DBGC ( slirp, "SLIRP %p timer %p set for %ld ticks\n",
|
||||
slirp, alarm, timeout );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register file descriptor for polling
|
||||
*
|
||||
* @v fd File descriptor
|
||||
* @v device Device opaque pointer
|
||||
*/
|
||||
static void __asmcall slirp_register_poll_fd ( int fd, void *device ) {
|
||||
struct net_device *netdev = device;
|
||||
struct slirp_nic *slirp = netdev->priv;
|
||||
|
||||
DBGC ( slirp, "SLIRP %p registered FD %d\n", slirp, fd );
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister file descriptor
|
||||
*
|
||||
* @v fd File descriptor
|
||||
* @v device Device opaque pointer
|
||||
*/
|
||||
static void __asmcall slirp_unregister_poll_fd ( int fd, void *device ) {
|
||||
struct net_device *netdev = device;
|
||||
struct slirp_nic *slirp = netdev->priv;
|
||||
|
||||
DBGC ( slirp, "SLIRP %p unregistered FD %d\n", slirp, fd );
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify that new events are ready
|
||||
*
|
||||
* @v device Device opaque pointer
|
||||
*/
|
||||
static void __asmcall slirp_notify ( void *device ) {
|
||||
struct net_device *netdev = device;
|
||||
struct slirp_nic *slirp = netdev->priv;
|
||||
|
||||
DBGC2 ( slirp, "SLIRP %p notified\n", slirp );
|
||||
}
|
||||
|
||||
/** Slirp callbacks */
|
||||
static struct slirp_callbacks slirp_callbacks = {
|
||||
.send_packet = slirp_send_packet,
|
||||
.guest_error = slirp_guest_error,
|
||||
.clock_get_ns = slirp_clock_get_ns,
|
||||
.timer_new = slirp_timer_new,
|
||||
.timer_free = slirp_timer_free,
|
||||
.timer_mod = slirp_timer_mod,
|
||||
.register_poll_fd = slirp_register_poll_fd,
|
||||
.unregister_poll_fd = slirp_unregister_poll_fd,
|
||||
.notify = slirp_notify,
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Network device interface
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Open network device
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int slirp_open ( struct net_device *netdev ) {
|
||||
struct slirp_nic *slirp = netdev->priv;
|
||||
|
||||
/* Nothing to do */
|
||||
DBGC ( slirp, "SLIRP %p opened\n", slirp );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close network device
|
||||
*
|
||||
* @v netdev Network device
|
||||
*/
|
||||
static void slirp_close ( struct net_device *netdev ) {
|
||||
struct slirp_nic *slirp = netdev->priv;
|
||||
|
||||
/* Nothing to do */
|
||||
DBGC ( slirp, "SLIRP %p closed\n", slirp );
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmit packet
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @v iobuf I/O buffer
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int slirp_transmit ( struct net_device *netdev,
|
||||
struct io_buffer *iobuf ) {
|
||||
struct slirp_nic *slirp = netdev->priv;
|
||||
|
||||
/* Transmit packet */
|
||||
linux_slirp_input ( slirp->slirp, iobuf->data, iob_len ( iobuf ) );
|
||||
netdev_tx_complete ( netdev, iobuf );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add polling file descriptor
|
||||
*
|
||||
* @v fd File descriptor
|
||||
* @v events Events of interest
|
||||
* @v device Device opaque pointer
|
||||
* @ret index File descriptor index
|
||||
*/
|
||||
static int __asmcall slirp_add_poll ( int fd, int events, void *device ) {
|
||||
struct net_device *netdev = device;
|
||||
struct slirp_nic *slirp = netdev->priv;
|
||||
struct pollfd *pollfd;
|
||||
unsigned int index;
|
||||
|
||||
/* Fail if too many descriptors are registered */
|
||||
if ( slirp->numfds >= SLIRP_MAX_FDS ) {
|
||||
DBGC ( slirp, "SLIRP %p too many file descriptors\n", slirp );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Populate polling file descriptor */
|
||||
index = slirp->numfds++;
|
||||
pollfd = &slirp->pollfds[index];
|
||||
pollfd->fd = fd;
|
||||
pollfd->events = 0;
|
||||
if ( events & SLIRP_EVENT_IN )
|
||||
pollfd->events |= POLLIN;
|
||||
if ( events & SLIRP_EVENT_OUT )
|
||||
pollfd->events |= POLLOUT;
|
||||
if ( events & SLIRP_EVENT_PRI )
|
||||
pollfd->events |= POLLPRI;
|
||||
if ( events & SLIRP_EVENT_ERR )
|
||||
pollfd->events |= POLLERR;
|
||||
if ( events & SLIRP_EVENT_HUP )
|
||||
pollfd->events |= ( POLLHUP | POLLRDHUP );
|
||||
DBGCP ( slirp, "SLIRP %p polling FD %d event mask %#04x(%#04x)\n",
|
||||
slirp, fd, events, pollfd->events );
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get returned events for a file descriptor
|
||||
*
|
||||
* @v index File descriptor index
|
||||
* @v device Device opaque pointer
|
||||
* @ret events Returned events
|
||||
*/
|
||||
static int __asmcall slirp_get_revents ( int index, void *device ) {
|
||||
struct net_device *netdev = device;
|
||||
struct slirp_nic *slirp = netdev->priv;
|
||||
int revents;
|
||||
int events;
|
||||
|
||||
/* Ignore failed descriptors */
|
||||
if ( index < 0 )
|
||||
return 0;
|
||||
|
||||
/* Collect events */
|
||||
revents = slirp->pollfds[index].revents;
|
||||
events = 0;
|
||||
if ( revents & POLLIN )
|
||||
events |= SLIRP_EVENT_IN;
|
||||
if ( revents & POLLOUT )
|
||||
events |= SLIRP_EVENT_OUT;
|
||||
if ( revents & POLLPRI )
|
||||
events |= SLIRP_EVENT_PRI;
|
||||
if ( revents & POLLERR )
|
||||
events |= SLIRP_EVENT_ERR;
|
||||
if ( revents & ( POLLHUP | POLLRDHUP ) )
|
||||
events |= SLIRP_EVENT_HUP;
|
||||
if ( events ) {
|
||||
DBGC2 ( slirp, "SLIRP %p polled FD %d events %#04x(%#04x)\n",
|
||||
slirp, slirp->pollfds[index].fd, events, revents );
|
||||
}
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll for completed and received packets
|
||||
*
|
||||
* @v netdev Network device
|
||||
*/
|
||||
static void slirp_poll ( struct net_device *netdev ) {
|
||||
struct slirp_nic *slirp = netdev->priv;
|
||||
uint32_t timeout = 0;
|
||||
int ready;
|
||||
int error;
|
||||
|
||||
/* Rebuild polling file descriptor list */
|
||||
slirp->numfds = 0;
|
||||
linux_slirp_pollfds_fill ( slirp->slirp, &timeout,
|
||||
slirp_add_poll, netdev );
|
||||
|
||||
/* Poll descriptors */
|
||||
ready = linux_poll ( slirp->pollfds, slirp->numfds, 0 );
|
||||
error = ( ready == -1 );
|
||||
linux_slirp_pollfds_poll ( slirp->slirp, error, slirp_get_revents,
|
||||
netdev );
|
||||
|
||||
/* Record polling errors */
|
||||
if ( error ) {
|
||||
DBGC ( slirp, "SLIRP %p poll failed: %s\n",
|
||||
slirp, linux_strerror ( linux_errno ) );
|
||||
netdev_rx_err ( netdev, NULL, -ELINUX ( linux_errno ) );
|
||||
}
|
||||
}
|
||||
|
||||
/** Network device operations */
|
||||
static struct net_device_operations slirp_operations = {
|
||||
.open = slirp_open,
|
||||
.close = slirp_close,
|
||||
.transmit = slirp_transmit,
|
||||
.poll = slirp_poll,
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Linux driver interface
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Probe device
|
||||
*
|
||||
* @v linux Linux device
|
||||
* @v request Device creation request
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int slirp_probe ( struct linux_device *linux,
|
||||
struct linux_device_request *request ) {
|
||||
struct net_device *netdev;
|
||||
struct slirp_nic *slirp;
|
||||
struct slirp_config config;
|
||||
int rc;
|
||||
|
||||
/* Allocate device */
|
||||
netdev = alloc_etherdev ( sizeof ( *slirp ) );
|
||||
if ( ! netdev ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
netdev_init ( netdev, &slirp_operations );
|
||||
linux_set_drvdata ( linux, netdev );
|
||||
snprintf ( linux->dev.name, sizeof ( linux->dev.name ), "host" );
|
||||
netdev->dev = &linux->dev;
|
||||
memcpy ( netdev->hw_addr, slirp_default_mac, ETH_ALEN );
|
||||
slirp = netdev->priv;
|
||||
memset ( slirp, 0, sizeof ( *slirp ) );
|
||||
|
||||
/* Apply requested settings */
|
||||
linux_apply_settings ( &request->settings,
|
||||
netdev_settings ( netdev ) );
|
||||
|
||||
/* Initialise default configuration (matching qemu) */
|
||||
memset ( &config, 0, sizeof ( config ) );
|
||||
config.version = 1;
|
||||
config.in_enabled = true;
|
||||
config.vnetwork.s_addr = htonl ( 0x0a000200 ); /* 10.0.2.0 */
|
||||
config.vnetmask.s_addr = htonl ( 0xffffff00 ); /* 255.255.255.0 */
|
||||
config.vhost.s_addr = htonl ( 0x0a000202 ); /* 10.0.2.2 */
|
||||
config.in6_enabled = true;
|
||||
config.vdhcp_start.s_addr = htonl ( 0x0a00020f ); /* 10.0.2.15 */
|
||||
config.vnameserver.s_addr = htonl ( 0x0a000203 ); /* 10.0.2.3 */
|
||||
|
||||
/* Instantiate device */
|
||||
slirp->slirp = linux_slirp_new ( &config, &slirp_callbacks, netdev );
|
||||
if ( ! slirp->slirp ) {
|
||||
DBGC ( slirp, "SLIRP could not instantiate\n" );
|
||||
rc = -ENODEV;
|
||||
goto err_new;
|
||||
}
|
||||
|
||||
/* Register network device */
|
||||
if ( ( rc = register_netdev ( netdev ) ) != 0 )
|
||||
goto err_register;
|
||||
|
||||
/* Set link up since there is no concept of link state */
|
||||
netdev_link_up ( netdev );
|
||||
|
||||
return 0;
|
||||
|
||||
unregister_netdev ( netdev );
|
||||
err_register:
|
||||
linux_slirp_cleanup ( slirp->slirp );
|
||||
err_new:
|
||||
netdev_nullify ( netdev );
|
||||
netdev_put ( netdev );
|
||||
err_alloc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove device
|
||||
*
|
||||
* @v linux Linux device
|
||||
*/
|
||||
static void slirp_remove ( struct linux_device *linux ) {
|
||||
struct net_device *netdev = linux_get_drvdata ( linux );
|
||||
struct slirp_nic *slirp = netdev->priv;
|
||||
|
||||
/* Unregister network device */
|
||||
unregister_netdev ( netdev );
|
||||
|
||||
/* Shut down device */
|
||||
linux_slirp_cleanup ( slirp->slirp );
|
||||
|
||||
/* Free network device */
|
||||
netdev_nullify ( netdev );
|
||||
netdev_put ( netdev );
|
||||
}
|
||||
|
||||
/** Slirp driver */
|
||||
struct linux_driver slirp_driver __linux_driver = {
|
||||
.name = "slirp",
|
||||
.probe = slirp_probe,
|
||||
.remove = slirp_remove,
|
||||
};
|
||||
@@ -1,261 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ipxe/linux_api.h>
|
||||
#include <ipxe/list.h>
|
||||
#include <ipxe/linux.h>
|
||||
#include <ipxe/malloc.h>
|
||||
#include <ipxe/device.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <ipxe/iobuf.h>
|
||||
#include <ipxe/ethernet.h>
|
||||
#include <ipxe/settings.h>
|
||||
#include <ipxe/socket.h>
|
||||
|
||||
/* This hack prevents pre-2.6.32 headers from redefining struct sockaddr */
|
||||
#define _SYS_SOCKET_H
|
||||
#define __GLIBC__ 2
|
||||
#include <linux/socket.h>
|
||||
#undef __GLIBC__
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_tun.h>
|
||||
|
||||
#define RX_BUF_SIZE 1536
|
||||
#define RX_QUOTA 4
|
||||
|
||||
/** @file
|
||||
*
|
||||
* The TAP driver.
|
||||
*
|
||||
* The TAP is a Virtual Ethernet network device.
|
||||
*/
|
||||
|
||||
struct tap_nic {
|
||||
/** Tap interface name */
|
||||
char * interface;
|
||||
/** File descriptor of the opened tap device */
|
||||
int fd;
|
||||
};
|
||||
|
||||
/** Default MAC address */
|
||||
static const uint8_t tap_default_mac[ETH_ALEN] =
|
||||
{ 0x52, 0x54, 0x00, 0x12, 0x34, 0x56 };
|
||||
|
||||
/** Open the TAP device */
|
||||
static int tap_open(struct net_device * netdev)
|
||||
{
|
||||
struct tap_nic * nic = netdev->priv;
|
||||
struct ifreq ifr;
|
||||
int ret;
|
||||
|
||||
nic->fd = linux_open("/dev/net/tun", O_RDWR);
|
||||
if (nic->fd < 0) {
|
||||
DBGC(nic, "tap %p open('/dev/net/tun') = %d (%s)\n", nic, nic->fd, linux_strerror(linux_errno));
|
||||
return nic->fd;
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
/* IFF_NO_PI for no extra packet information */
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
strncpy(ifr.ifr_name, nic->interface, IFNAMSIZ);
|
||||
DBGC(nic, "tap %p interface = '%s'\n", nic, nic->interface);
|
||||
|
||||
ret = linux_ioctl(nic->fd, TUNSETIFF, &ifr);
|
||||
|
||||
if (ret != 0) {
|
||||
DBGC(nic, "tap %p ioctl(%d, ...) = %d (%s)\n", nic, nic->fd, ret, linux_strerror(linux_errno));
|
||||
linux_close(nic->fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set nonblocking mode to make tap_poll easier */
|
||||
ret = linux_fcntl(nic->fd, F_SETFL, O_NONBLOCK);
|
||||
|
||||
if (ret != 0) {
|
||||
DBGC(nic, "tap %p fcntl(%d, ...) = %d (%s)\n", nic, nic->fd, ret, linux_strerror(linux_errno));
|
||||
linux_close(nic->fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Close the TAP device */
|
||||
static void tap_close(struct net_device *netdev)
|
||||
{
|
||||
struct tap_nic * nic = netdev->priv;
|
||||
linux_close(nic->fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmit an ethernet packet.
|
||||
*
|
||||
* The packet can be written to the TAP device and marked as complete immediately.
|
||||
*/
|
||||
static int tap_transmit(struct net_device *netdev, struct io_buffer *iobuf)
|
||||
{
|
||||
struct tap_nic * nic = netdev->priv;
|
||||
int rc;
|
||||
|
||||
/* Pad and align packet */
|
||||
iob_pad(iobuf, ETH_ZLEN);
|
||||
|
||||
rc = linux_write(nic->fd, iobuf->data, iobuf->tail - iobuf->data);
|
||||
DBGC2(nic, "tap %p wrote %d bytes\n", nic, rc);
|
||||
netdev_tx_complete(netdev, iobuf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Poll for new packets */
|
||||
static void tap_poll(struct net_device *netdev)
|
||||
{
|
||||
struct tap_nic * nic = netdev->priv;
|
||||
struct pollfd pfd;
|
||||
struct io_buffer * iobuf;
|
||||
unsigned int quota = RX_QUOTA;
|
||||
int r;
|
||||
|
||||
pfd.fd = nic->fd;
|
||||
pfd.events = POLLIN;
|
||||
if (linux_poll(&pfd, 1, 0) == -1) {
|
||||
DBGC(nic, "tap %p poll failed (%s)\n", nic, linux_strerror(linux_errno));
|
||||
return;
|
||||
}
|
||||
if ((pfd.revents & POLLIN) == 0)
|
||||
return;
|
||||
|
||||
/* At this point we know there is at least one new packet to be read */
|
||||
|
||||
iobuf = alloc_iob(RX_BUF_SIZE);
|
||||
if (! iobuf)
|
||||
goto allocfail;
|
||||
|
||||
while (quota-- &&
|
||||
((r = linux_read(nic->fd, iobuf->data, RX_BUF_SIZE)) > 0)) {
|
||||
DBGC2(nic, "tap %p read %d bytes\n", nic, r);
|
||||
|
||||
iob_put(iobuf, r);
|
||||
netdev_rx(netdev, iobuf);
|
||||
|
||||
iobuf = alloc_iob(RX_BUF_SIZE);
|
||||
if (! iobuf)
|
||||
goto allocfail;
|
||||
}
|
||||
|
||||
free_iob(iobuf);
|
||||
return;
|
||||
|
||||
allocfail:
|
||||
DBGC(nic, "tap %p alloc_iob failed\n", nic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set irq.
|
||||
*
|
||||
* Not used on linux, provide a dummy implementation.
|
||||
*/
|
||||
static void tap_irq(struct net_device *netdev, int enable)
|
||||
{
|
||||
struct tap_nic *nic = netdev->priv;
|
||||
|
||||
DBGC(nic, "tap %p irq enable = %d\n", nic, enable);
|
||||
}
|
||||
|
||||
/** Tap operations */
|
||||
static struct net_device_operations tap_operations = {
|
||||
.open = tap_open,
|
||||
.close = tap_close,
|
||||
.transmit = tap_transmit,
|
||||
.poll = tap_poll,
|
||||
.irq = tap_irq,
|
||||
};
|
||||
|
||||
/** Handle a device request for the tap driver */
|
||||
static int tap_probe(struct linux_device *device, struct linux_device_request *request)
|
||||
{
|
||||
struct linux_setting *if_setting;
|
||||
struct net_device *netdev;
|
||||
struct tap_nic *nic;
|
||||
int rc;
|
||||
|
||||
netdev = alloc_etherdev(sizeof(*nic));
|
||||
if (! netdev)
|
||||
return -ENOMEM;
|
||||
|
||||
netdev_init(netdev, &tap_operations);
|
||||
nic = netdev->priv;
|
||||
linux_set_drvdata(device, netdev);
|
||||
netdev->dev = &device->dev;
|
||||
memcpy ( netdev->hw_addr, tap_default_mac, ETH_ALEN );
|
||||
memset(nic, 0, sizeof(*nic));
|
||||
|
||||
/* Look for the mandatory if setting */
|
||||
if_setting = linux_find_setting("if", &request->settings);
|
||||
|
||||
/* No if setting */
|
||||
if (! if_setting) {
|
||||
printf("tap missing a mandatory if setting\n");
|
||||
rc = -EINVAL;
|
||||
goto err_settings;
|
||||
}
|
||||
|
||||
nic->interface = if_setting->value;
|
||||
snprintf ( device->dev.name, sizeof ( device->dev.name ), "%s",
|
||||
nic->interface );
|
||||
device->dev.desc.bus_type = BUS_TYPE_TAP;
|
||||
if_setting->applied = 1;
|
||||
|
||||
/* Apply rest of the settings */
|
||||
linux_apply_settings(&request->settings, &netdev->settings.settings);
|
||||
|
||||
/* Register network device */
|
||||
if ((rc = register_netdev(netdev)) != 0)
|
||||
goto err_register;
|
||||
|
||||
netdev_link_up(netdev);
|
||||
|
||||
return 0;
|
||||
|
||||
unregister_netdev(netdev);
|
||||
err_register:
|
||||
err_settings:
|
||||
netdev_nullify(netdev);
|
||||
netdev_put(netdev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/** Remove the device */
|
||||
static void tap_remove(struct linux_device *device)
|
||||
{
|
||||
struct net_device *netdev = linux_get_drvdata(device);
|
||||
unregister_netdev(netdev);
|
||||
netdev_nullify(netdev);
|
||||
netdev_put(netdev);
|
||||
}
|
||||
|
||||
/** Tap linux_driver */
|
||||
struct linux_driver tap_driver __linux_driver = {
|
||||
.name = "tap",
|
||||
.probe = tap_probe,
|
||||
.remove = tap_remove,
|
||||
};
|
||||
Reference in New Issue
Block a user