mirror of
https://gitlab.com/qemu-project/ipxe.git
synced 2025-11-03 07:59:06 +08:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2dcef4b7a1 | |||
| f07630c74f | |||
| 5a2fa6040e | |||
| c4c03e5be8 | |||
| 47af48012e | |||
| ab19546386 | |||
| 7147532c3f | |||
| 60b5532cfc | |||
| b9571ca12e | |||
| 099e4d39b3 | |||
| 0f3ace92c6 | |||
| d879c8e4d9 | |||
| 5e62b4bc6c |
@ -59,7 +59,7 @@ static void cachedhcp_init ( void ) {
|
||||
}
|
||||
|
||||
/* Record cached DHCPACK */
|
||||
if ( ( rc = cachedhcp_record ( &cached_dhcpack,
|
||||
if ( ( rc = cachedhcp_record ( &cached_dhcpack, 0,
|
||||
phys_to_user ( cached_dhcpack_phys ),
|
||||
sizeof ( BOOTPLAYER_t ) ) ) != 0 ) {
|
||||
DBGC ( colour, "CACHEDHCP could not record DHCPACK: %s\n",
|
||||
|
||||
@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <ipxe/dhcppkt.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <ipxe/vlan.h>
|
||||
#include <ipxe/cachedhcp.h>
|
||||
|
||||
/** @file
|
||||
@ -43,6 +44,8 @@ struct cached_dhcp_packet {
|
||||
const char *name;
|
||||
/** DHCP packet (if any) */
|
||||
struct dhcp_packet *dhcppkt;
|
||||
/** VLAN tag (if applicable) */
|
||||
unsigned int vlan;
|
||||
};
|
||||
|
||||
/** Cached DHCPACK */
|
||||
@ -136,15 +139,26 @@ static int cachedhcp_apply ( struct cached_dhcp_packet *cache,
|
||||
* matches this network device.
|
||||
*/
|
||||
if ( memcmp ( ll_addr, chaddr, ll_addr_len ) != 0 ) {
|
||||
DBGC ( colour, "CACHEDHCP %s does not match %s\n",
|
||||
cache->name, netdev->name );
|
||||
DBGC ( colour, "CACHEDHCP %s %s does not match %s\n",
|
||||
cache->name, ll_protocol->ntoa ( chaddr ),
|
||||
netdev->name );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do nothing unless cached packet's VLAN tag matches
|
||||
* this network device.
|
||||
*/
|
||||
if ( vlan_tag ( netdev ) != cache->vlan ) {
|
||||
DBGC ( colour, "CACHEDHCP %s VLAN %d does not match "
|
||||
"%s\n", cache->name, cache->vlan,
|
||||
netdev->name );
|
||||
return 0;
|
||||
}
|
||||
DBGC ( colour, "CACHEDHCP %s is for %s\n",
|
||||
cache->name, netdev->name );
|
||||
|
||||
/* Use network device's settings block */
|
||||
settings = netdev_settings ( netdev );
|
||||
DBGC ( colour, "CACHEDHCP %s is for %s\n",
|
||||
cache->name, netdev->name );
|
||||
}
|
||||
|
||||
/* Register settings */
|
||||
@ -165,12 +179,13 @@ static int cachedhcp_apply ( struct cached_dhcp_packet *cache,
|
||||
* Record cached DHCP packet
|
||||
*
|
||||
* @v cache Cached DHCP packet
|
||||
* @v vlan VLAN tag, if any
|
||||
* @v data DHCPACK packet buffer
|
||||
* @v max_len Maximum possible length
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int cachedhcp_record ( struct cached_dhcp_packet *cache, userptr_t data,
|
||||
size_t max_len ) {
|
||||
int cachedhcp_record ( struct cached_dhcp_packet *cache, unsigned int vlan,
|
||||
userptr_t data, size_t max_len ) {
|
||||
struct dhcp_packet *dhcppkt;
|
||||
struct dhcp_packet *tmp;
|
||||
struct dhcphdr *dhcphdr;
|
||||
@ -225,36 +240,55 @@ int cachedhcp_record ( struct cached_dhcp_packet *cache, userptr_t data,
|
||||
DBGC ( colour, "CACHEDHCP %s at %#08lx+%#zx/%#zx\n", cache->name,
|
||||
user_to_phys ( data, 0 ), len, max_len );
|
||||
cache->dhcppkt = dhcppkt;
|
||||
cache->vlan = vlan;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cached DHCPACK startup function
|
||||
* Cached DHCP packet startup function
|
||||
*
|
||||
*/
|
||||
static void cachedhcp_startup ( void ) {
|
||||
|
||||
/* Apply cached ProxyDHCPOFFER, if any */
|
||||
cachedhcp_apply ( &cached_proxydhcp, NULL );
|
||||
cachedhcp_free ( &cached_proxydhcp );
|
||||
|
||||
/* Apply cached PXEBSACK, if any */
|
||||
cachedhcp_apply ( &cached_pxebs, NULL );
|
||||
cachedhcp_free ( &cached_pxebs );
|
||||
|
||||
/* Free any remaining cached packets */
|
||||
/* Report unclaimed DHCPACK, if any. Do not free yet, since
|
||||
* it may still be claimed by a dynamically created device
|
||||
* such as a VLAN device.
|
||||
*/
|
||||
if ( cached_dhcpack.dhcppkt ) {
|
||||
DBGC ( colour, "CACHEDHCP %s unclaimed\n",
|
||||
cached_dhcpack.name );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cached DHCP packet shutdown function
|
||||
*
|
||||
* @v booting System is shutting down for OS boot
|
||||
*/
|
||||
static void cachedhcp_shutdown ( int booting __unused ) {
|
||||
|
||||
/* Free cached DHCPACK, if any */
|
||||
if ( cached_dhcpack.dhcppkt ) {
|
||||
DBGC ( colour, "CACHEDHCP %s never claimed\n",
|
||||
cached_dhcpack.name );
|
||||
}
|
||||
cachedhcp_free ( &cached_dhcpack );
|
||||
cachedhcp_free ( &cached_proxydhcp );
|
||||
cachedhcp_free ( &cached_pxebs );
|
||||
}
|
||||
|
||||
/** Cached DHCPACK startup function */
|
||||
struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = {
|
||||
.name = "cachedhcp",
|
||||
.startup = cachedhcp_startup,
|
||||
.shutdown = cachedhcp_shutdown,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -121,10 +121,9 @@ int ecm_fetch_mac ( struct usb_function *func,
|
||||
}
|
||||
|
||||
/* Apply system-specific MAC address as current link-layer
|
||||
* address, if present and not already used.
|
||||
* address, if present.
|
||||
*/
|
||||
if ( ( ( rc = acpi_mac ( amac ) ) == 0 ) &&
|
||||
! find_netdev_by_ll_addr ( ðernet_protocol, amac ) ) {
|
||||
if ( ( rc = acpi_mac ( amac ) ) == 0 ) {
|
||||
memcpy ( netdev->ll_addr, amac, ETH_ALEN );
|
||||
DBGC ( usb, "USB %s using system-specific MAC %s\n",
|
||||
func->name, eth_ntoa ( netdev->ll_addr ) );
|
||||
|
||||
@ -921,18 +921,17 @@ static int nii_set_station_address ( struct nii_nic *nii,
|
||||
* Set receive filters
|
||||
*
|
||||
* @v nii NII NIC
|
||||
* @v flags Flags
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int nii_set_rx_filters ( struct nii_nic *nii ) {
|
||||
static int nii_set_rx_filters ( struct nii_nic *nii, unsigned int flags ) {
|
||||
uint32_t implementation = nii->undi->Implementation;
|
||||
unsigned int flags;
|
||||
unsigned int op;
|
||||
int stat;
|
||||
int rc;
|
||||
|
||||
/* Construct receive filter set */
|
||||
flags = ( PXE_OPFLAGS_RECEIVE_FILTER_ENABLE |
|
||||
PXE_OPFLAGS_RECEIVE_FILTER_UNICAST );
|
||||
flags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;
|
||||
if ( implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED )
|
||||
flags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
|
||||
if ( implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED )
|
||||
@ -944,14 +943,40 @@ static int nii_set_rx_filters ( struct nii_nic *nii ) {
|
||||
op = NII_OP ( PXE_OPCODE_RECEIVE_FILTERS, flags );
|
||||
if ( ( stat = nii_issue ( nii, op ) ) < 0 ) {
|
||||
rc = -EIO_STAT ( stat );
|
||||
DBGC ( nii, "NII %s could not set receive filters %#04x: %s\n",
|
||||
nii->dev.name, flags, strerror ( rc ) );
|
||||
DBGC ( nii, "NII %s could not %s%sable receive filters "
|
||||
"%#04x: %s\n", nii->dev.name,
|
||||
( ( flags & PXE_OPFLAGS_RECEIVE_FILTER_ENABLE ) ?
|
||||
"en" : "" ),
|
||||
( ( flags & PXE_OPFLAGS_RECEIVE_FILTER_DISABLE ) ?
|
||||
"dis" : "" ), flags, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable receive filters
|
||||
*
|
||||
* @v nii NII NIC
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int nii_enable_rx_filters ( struct nii_nic *nii ) {
|
||||
|
||||
return nii_set_rx_filters ( nii, PXE_OPFLAGS_RECEIVE_FILTER_ENABLE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable receive filters
|
||||
*
|
||||
* @v nii NII NIC
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int nii_disable_rx_filters ( struct nii_nic *nii ) {
|
||||
|
||||
return nii_set_rx_filters ( nii, PXE_OPFLAGS_RECEIVE_FILTER_DISABLE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmit packet
|
||||
*
|
||||
@ -1175,13 +1200,25 @@ static int nii_open ( struct net_device *netdev ) {
|
||||
/* Treat as non-fatal */
|
||||
}
|
||||
|
||||
/* Set receive filters */
|
||||
if ( ( rc = nii_set_rx_filters ( nii ) ) != 0 )
|
||||
goto err_set_rx_filters;
|
||||
/* Disable receive filters
|
||||
*
|
||||
* We have no reason to disable receive filters here (or
|
||||
* anywhere), but some NII drivers have a bug which prevents
|
||||
* packets from being received unless we attempt to disable
|
||||
* the receive filters.
|
||||
*
|
||||
* Ignore any failures, since we genuinely don't care if the
|
||||
* NII driver cannot disable the filters.
|
||||
*/
|
||||
nii_disable_rx_filters ( nii );
|
||||
|
||||
/* Enable receive filters */
|
||||
if ( ( rc = nii_enable_rx_filters ( nii ) ) != 0 )
|
||||
goto err_enable_rx_filters;
|
||||
|
||||
return 0;
|
||||
|
||||
err_set_rx_filters:
|
||||
err_enable_rx_filters:
|
||||
nii_shutdown ( nii );
|
||||
err_initialise:
|
||||
return rc;
|
||||
|
||||
@ -59,6 +59,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
EUNIQ ( EINFO_EIO, ( -(status) & 0x1f ), \
|
||||
EIO_NETIF_RSP_ERROR, EIO_NETIF_RSP_DROPPED )
|
||||
|
||||
/** List of netfront devices */
|
||||
static LIST_HEAD ( netfront_devices );
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* XenStore interface
|
||||
@ -952,6 +955,7 @@ static int netfront_probe ( struct xen_device *xendev ) {
|
||||
netdev->dev = &xendev->dev;
|
||||
netfront = netdev->priv;
|
||||
netfront->xendev = xendev;
|
||||
netfront->netdev = netdev;
|
||||
INIT_LIST_HEAD ( &netfront->rx_partial );
|
||||
DBGC ( netfront, "NETFRONT %s backend=\"%s\" in domain %ld\n",
|
||||
xendev->key, xendev->backend, xendev->backend_id );
|
||||
@ -991,9 +995,13 @@ static int netfront_probe ( struct xen_device *xendev ) {
|
||||
/* Set initial link state */
|
||||
netdev_link_down ( netdev );
|
||||
|
||||
/* Add to list of netfront devices */
|
||||
list_add_tail ( &netfront->list, &netfront_devices );
|
||||
|
||||
xen_set_drvdata ( xendev, netdev );
|
||||
return 0;
|
||||
|
||||
list_del ( &netfront->list );
|
||||
unregister_netdev ( netdev );
|
||||
err_register_netdev:
|
||||
err_read_mac:
|
||||
@ -1015,6 +1023,9 @@ static void netfront_remove ( struct xen_device *xendev ) {
|
||||
struct netfront_nic *netfront = netdev->priv;
|
||||
struct xen_hypervisor *xen = xendev->xen;
|
||||
|
||||
/* Remove from list of netfront devices */
|
||||
list_del ( &netfront->list );
|
||||
|
||||
/* Unregister network device */
|
||||
unregister_netdev ( netdev );
|
||||
|
||||
@ -1033,3 +1044,41 @@ struct xen_driver netfront_driver __xen_driver = {
|
||||
.probe = netfront_probe,
|
||||
.remove = netfront_remove,
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Emulated PCI device inhibitor
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Inhibit emulated PCI devices
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int netfront_net_probe ( struct net_device *netdev ) {
|
||||
struct netfront_nic *netfront;
|
||||
|
||||
/* Inhibit emulated PCI devices matching an existing netfront device */
|
||||
list_for_each_entry ( netfront, &netfront_devices, list ) {
|
||||
if ( ( netdev->dev != netfront->netdev->dev ) &&
|
||||
( netdev->ll_protocol->ll_addr_len == ETH_ALEN ) &&
|
||||
( memcmp ( netdev->hw_addr, netfront->netdev->hw_addr,
|
||||
ETH_ALEN ) == 0 ) ) {
|
||||
DBGC ( netfront, "NETFRONT %s inhibiting emulated %s "
|
||||
"%s\n", netfront->xendev->key,
|
||||
netdev->dev->driver_name, netdev->dev->name );
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Emulated PCI device inhibitor driver */
|
||||
struct net_driver netfront_net_driver __net_driver = {
|
||||
.name = "netfront",
|
||||
.probe = netfront_net_probe,
|
||||
};
|
||||
|
||||
@ -159,6 +159,11 @@ struct netfront_nic {
|
||||
/** Grant references */
|
||||
grant_ref_t refs[NETFRONT_REF_COUNT];
|
||||
|
||||
/** Network device */
|
||||
struct net_device *netdev;
|
||||
/** List of netfront NICs */
|
||||
struct list_head list;
|
||||
|
||||
/** Transmit ring */
|
||||
struct netfront_ring tx;
|
||||
/** Transmit front ring */
|
||||
|
||||
@ -18,7 +18,8 @@ extern struct cached_dhcp_packet cached_dhcpack;
|
||||
extern struct cached_dhcp_packet cached_proxydhcp;
|
||||
extern struct cached_dhcp_packet cached_pxebs;
|
||||
|
||||
extern int cachedhcp_record ( struct cached_dhcp_packet *cache, userptr_t data,
|
||||
extern int cachedhcp_record ( struct cached_dhcp_packet *cache,
|
||||
unsigned int vlan, userptr_t data,
|
||||
size_t max_len );
|
||||
|
||||
#endif /* _IPXE_CACHEDHCP_H */
|
||||
|
||||
@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/efi/efi.h>
|
||||
|
||||
extern int efi_set_autoboot_ll_addr ( EFI_HANDLE device );
|
||||
extern int efi_set_autoboot_ll_addr ( EFI_HANDLE device,
|
||||
EFI_DEVICE_PATH_PROTOCOL *path );
|
||||
|
||||
#endif /* _IPXE_EFI_AUTOBOOT_H */
|
||||
|
||||
@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/efi/efi.h>
|
||||
|
||||
extern int efi_cachedhcp_record ( EFI_HANDLE device );
|
||||
extern int efi_cachedhcp_record ( EFI_HANDLE device,
|
||||
EFI_DEVICE_PATH_PROTOCOL *path );
|
||||
|
||||
#endif /* _IPXE_EFI_CACHEDHCP_H */
|
||||
|
||||
@ -19,9 +19,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <ipxe/efi/Protocol/PxeBaseCode.h>
|
||||
#include <ipxe/efi/Protocol/SimpleNetwork.h>
|
||||
#include <ipxe/efi/Protocol/UsbIo.h>
|
||||
#include <ipxe/efi/Protocol/VlanConfig.h>
|
||||
|
||||
extern void efi_nullify_snp ( EFI_SIMPLE_NETWORK_PROTOCOL *snp );
|
||||
extern void efi_nullify_nii ( EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *nii );
|
||||
extern void efi_nullify_vlan ( EFI_VLAN_CONFIG_PROTOCOL *vcfg );
|
||||
extern void efi_nullify_name2 ( EFI_COMPONENT_NAME2_PROTOCOL *name2 );
|
||||
extern void efi_nullify_load_file ( EFI_LOAD_FILE_PROTOCOL *load_file );
|
||||
extern void efi_nullify_hii ( EFI_HII_CONFIG_ACCESS_PROTOCOL *hii );
|
||||
|
||||
@ -21,9 +21,12 @@ struct fcp_description;
|
||||
struct ib_srp_device;
|
||||
struct usb_function;
|
||||
|
||||
extern EFI_DEVICE_PATH_PROTOCOL *
|
||||
efi_path_next ( EFI_DEVICE_PATH_PROTOCOL *path );
|
||||
extern EFI_DEVICE_PATH_PROTOCOL *
|
||||
efi_path_end ( EFI_DEVICE_PATH_PROTOCOL *path );
|
||||
extern size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path );
|
||||
extern unsigned int efi_path_vlan ( EFI_DEVICE_PATH_PROTOCOL *path );
|
||||
extern EFI_DEVICE_PATH_PROTOCOL * efi_paths ( EFI_DEVICE_PATH_PROTOCOL *first,
|
||||
... );
|
||||
extern EFI_DEVICE_PATH_PROTOCOL * efi_netdev_path ( struct net_device *netdev );
|
||||
|
||||
@ -19,6 +19,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#include <ipxe/efi/Protocol/HiiConfigAccess.h>
|
||||
#include <ipxe/efi/Protocol/HiiDatabase.h>
|
||||
#include <ipxe/efi/Protocol/LoadFile.h>
|
||||
#include <ipxe/efi/Protocol/VlanConfig.h>
|
||||
|
||||
/** SNP transmit completion ring size */
|
||||
#define EFI_SNP_NUM_TX 32
|
||||
@ -51,6 +52,8 @@ struct efi_snp_device {
|
||||
struct list_head rx;
|
||||
/** The network interface identifier */
|
||||
EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL nii;
|
||||
/** VLAN configuration protocol */
|
||||
EFI_VLAN_CONFIG_PROTOCOL vcfg;
|
||||
/** Component name protocol */
|
||||
EFI_COMPONENT_NAME2_PROTOCOL name2;
|
||||
/** Load file protocol handle */
|
||||
|
||||
@ -356,8 +356,8 @@ struct net_device {
|
||||
struct list_head list;
|
||||
/** List of open network devices */
|
||||
struct list_head open_list;
|
||||
/** Index of this network device */
|
||||
unsigned int index;
|
||||
/** Scope ID */
|
||||
unsigned int scope_id;
|
||||
/** Name of this network device */
|
||||
char name[NETDEV_NAME_LEN];
|
||||
/** Underlying hardware device */
|
||||
@ -726,11 +726,9 @@ extern void netdev_close ( struct net_device *netdev );
|
||||
extern void unregister_netdev ( struct net_device *netdev );
|
||||
extern void netdev_irq ( struct net_device *netdev, int enable );
|
||||
extern struct net_device * find_netdev ( const char *name );
|
||||
extern struct net_device * find_netdev_by_index ( unsigned int index );
|
||||
extern struct net_device * find_netdev_by_scope_id ( unsigned int scope_id );
|
||||
extern struct net_device * find_netdev_by_location ( unsigned int bus_type,
|
||||
unsigned int location );
|
||||
extern struct net_device *
|
||||
find_netdev_by_ll_addr ( struct ll_protocol *ll_protocol, const void *ll_addr );
|
||||
extern struct net_device * last_opened_netdev ( void );
|
||||
extern int net_tx ( struct io_buffer *iobuf, struct net_device *netdev,
|
||||
struct net_protocol *net_protocol, const void *ll_dest,
|
||||
|
||||
@ -61,11 +61,26 @@ struct vlan_header {
|
||||
*/
|
||||
#define VLAN_PRIORITY_IS_VALID( priority ) ( (priority) <= 7 )
|
||||
|
||||
extern unsigned int vlan_tag ( struct net_device *netdev );
|
||||
extern unsigned int vlan_tci ( struct net_device *netdev );
|
||||
|
||||
/**
|
||||
* Get the VLAN tag
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @ret tag VLAN tag, or 0 if device is not a VLAN device
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) unsigned int
|
||||
vlan_tag ( struct net_device *netdev ) {
|
||||
return VLAN_TAG ( vlan_tci ( netdev ) );
|
||||
}
|
||||
|
||||
extern struct net_device * vlan_find ( struct net_device *trunk,
|
||||
unsigned int tag );
|
||||
extern int vlan_can_be_trunk ( struct net_device *trunk );
|
||||
extern int vlan_create ( struct net_device *trunk, unsigned int tag,
|
||||
unsigned int priority );
|
||||
extern int vlan_destroy ( struct net_device *netdev );
|
||||
extern void vlan_auto ( const void *ll_addr, unsigned int tag );
|
||||
extern void vlan_netdev_rx ( struct net_device *netdev, unsigned int tag,
|
||||
struct io_buffer *iobuf );
|
||||
extern void vlan_netdev_rx_err ( struct net_device *netdev, unsigned int tag,
|
||||
|
||||
@ -28,7 +28,8 @@ enum uriboot_flags {
|
||||
|
||||
extern void set_autoboot_busloc ( unsigned int bus_type,
|
||||
unsigned int location );
|
||||
extern void set_autoboot_ll_addr ( const void *ll_addr, size_t len );
|
||||
extern void set_autoboot_ll_addr ( const void *ll_addr, size_t len,
|
||||
unsigned int vlan );
|
||||
|
||||
extern int uriboot ( struct uri *filename, struct uri **root_paths,
|
||||
unsigned int root_path_count, int drive,
|
||||
|
||||
@ -25,7 +25,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/if_ether.h>
|
||||
#include <ipxe/vlan.h>
|
||||
#include <ipxe/efi/efi.h>
|
||||
#include <ipxe/efi/efi_path.h>
|
||||
#include <ipxe/efi/efi_autoboot.h>
|
||||
#include <ipxe/efi/Protocol/SimpleNetwork.h>
|
||||
#include <usr/autoboot.h>
|
||||
@ -40,9 +43,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* Identify autoboot device
|
||||
*
|
||||
* @v device Device handle
|
||||
* @v path Device path
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int efi_set_autoboot_ll_addr ( EFI_HANDLE device ) {
|
||||
int efi_set_autoboot_ll_addr ( EFI_HANDLE device,
|
||||
EFI_DEVICE_PATH_PROTOCOL *path ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
union {
|
||||
EFI_SIMPLE_NETWORK_PROTOCOL *snp;
|
||||
@ -50,6 +55,7 @@ int efi_set_autoboot_ll_addr ( EFI_HANDLE device ) {
|
||||
} snp;
|
||||
EFI_SIMPLE_NETWORK_MODE *mode;
|
||||
EFI_STATUS efirc;
|
||||
unsigned int vlan;
|
||||
int rc;
|
||||
|
||||
/* Look for an SNP instance on the image's device handle */
|
||||
@ -66,10 +72,23 @@ int efi_set_autoboot_ll_addr ( EFI_HANDLE device ) {
|
||||
|
||||
/* Record autoboot device */
|
||||
mode = snp.snp->Mode;
|
||||
set_autoboot_ll_addr ( &mode->CurrentAddress, mode->HwAddressSize );
|
||||
vlan = efi_path_vlan ( path );
|
||||
set_autoboot_ll_addr ( &mode->CurrentAddress, mode->HwAddressSize,
|
||||
vlan );
|
||||
DBGC ( device, "EFI %s found autoboot link-layer address:\n",
|
||||
efi_handle_name ( device ) );
|
||||
DBGC_HDA ( device, 0, &mode->CurrentAddress, mode->HwAddressSize );
|
||||
if ( vlan ) {
|
||||
DBGC ( device, "EFI %s found autoboot VLAN %d\n",
|
||||
efi_handle_name ( device ), vlan );
|
||||
}
|
||||
|
||||
/* Configure automatic VLAN device, if applicable */
|
||||
if ( vlan && ( mode->HwAddressSize == ETH_ALEN ) ) {
|
||||
vlan_auto ( &mode->CurrentAddress, vlan );
|
||||
DBGC ( device, "EFI %s configured automatic VLAN %d\n",
|
||||
efi_handle_name ( device ), vlan );
|
||||
}
|
||||
|
||||
/* Close protocol */
|
||||
bs->CloseProtocol ( device, &efi_simple_network_protocol_guid,
|
||||
|
||||
@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <errno.h>
|
||||
#include <ipxe/cachedhcp.h>
|
||||
#include <ipxe/efi/efi.h>
|
||||
#include <ipxe/efi/efi_path.h>
|
||||
#include <ipxe/efi/efi_cachedhcp.h>
|
||||
#include <ipxe/efi/Protocol/PxeBaseCode.h>
|
||||
|
||||
@ -40,10 +41,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* Record cached DHCP packet
|
||||
*
|
||||
* @v device Device handle
|
||||
* @v path Device path
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int efi_cachedhcp_record ( EFI_HANDLE device ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
int efi_cachedhcp_record ( EFI_HANDLE device,
|
||||
EFI_DEVICE_PATH_PROTOCOL *path ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
unsigned int vlan;
|
||||
union {
|
||||
EFI_PXE_BASE_CODE_PROTOCOL *pxe;
|
||||
void *interface;
|
||||
@ -52,6 +56,9 @@ int efi_cachedhcp_record ( EFI_HANDLE device ) {
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
|
||||
/* Get VLAN tag, if any */
|
||||
vlan = efi_path_vlan ( path );
|
||||
|
||||
/* Look for a PXE base code instance on the image's device handle */
|
||||
if ( ( efirc = bs->OpenProtocol ( device,
|
||||
&efi_pxe_base_code_protocol_guid,
|
||||
@ -75,7 +82,7 @@ int efi_cachedhcp_record ( EFI_HANDLE device ) {
|
||||
|
||||
/* Record DHCPACK, if present */
|
||||
if ( mode->DhcpAckReceived &&
|
||||
( ( rc = cachedhcp_record ( &cached_dhcpack,
|
||||
( ( rc = cachedhcp_record ( &cached_dhcpack, vlan,
|
||||
virt_to_user ( &mode->DhcpAck ),
|
||||
sizeof ( mode->DhcpAck ) ) ) != 0 ) ) {
|
||||
DBGC ( device, "EFI %s could not record DHCPACK: %s\n",
|
||||
@ -85,7 +92,7 @@ int efi_cachedhcp_record ( EFI_HANDLE device ) {
|
||||
|
||||
/* Record ProxyDHCPOFFER, if present */
|
||||
if ( mode->ProxyOfferReceived &&
|
||||
( ( rc = cachedhcp_record ( &cached_proxydhcp,
|
||||
( ( rc = cachedhcp_record ( &cached_proxydhcp, vlan,
|
||||
virt_to_user ( &mode->ProxyOffer ),
|
||||
sizeof ( mode->ProxyOffer ) ) ) != 0)){
|
||||
DBGC ( device, "EFI %s could not record ProxyDHCPOFFER: %s\n",
|
||||
@ -95,7 +102,7 @@ int efi_cachedhcp_record ( EFI_HANDLE device ) {
|
||||
|
||||
/* Record PxeBSACK, if present */
|
||||
if ( mode->PxeReplyReceived &&
|
||||
( ( rc = cachedhcp_record ( &cached_pxebs,
|
||||
( ( rc = cachedhcp_record ( &cached_pxebs, vlan,
|
||||
virt_to_user ( &mode->PxeReply ),
|
||||
sizeof ( mode->PxeReply ) ) ) != 0)){
|
||||
DBGC ( device, "EFI %s could not record PXEBSACK: %s\n",
|
||||
|
||||
@ -419,14 +419,15 @@ static int efi_local_open_resolved ( struct efi_local *local,
|
||||
* Open specified path
|
||||
*
|
||||
* @v local Local file
|
||||
* @v path Path to file
|
||||
* @v filename Path to file relative to our own image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int efi_local_open_path ( struct efi_local *local, const char *path ) {
|
||||
FILEPATH_DEVICE_PATH *fp = container_of ( efi_loaded_image->FilePath,
|
||||
FILEPATH_DEVICE_PATH, Header);
|
||||
size_t fp_len = ( fp ? efi_path_len ( &fp->Header ) : 0 );
|
||||
char base[ fp_len / 2 /* Cannot exceed this length */ ];
|
||||
static int efi_local_open_path ( struct efi_local *local,
|
||||
const char *filename ) {
|
||||
EFI_DEVICE_PATH_PROTOCOL *path = efi_loaded_image->FilePath;
|
||||
EFI_DEVICE_PATH_PROTOCOL *next;
|
||||
FILEPATH_DEVICE_PATH *fp;
|
||||
char base[ efi_path_len ( path ) / 2 /* Cannot exceed this length */ ];
|
||||
size_t remaining = sizeof ( base );
|
||||
size_t len;
|
||||
char *resolved;
|
||||
@ -436,13 +437,12 @@ static int efi_local_open_path ( struct efi_local *local, const char *path ) {
|
||||
/* Construct base path to our own image, if possible */
|
||||
memset ( base, 0, sizeof ( base ) );
|
||||
tmp = base;
|
||||
while ( fp && ( fp->Header.Type != END_DEVICE_PATH_TYPE ) ) {
|
||||
for ( ; ( next = efi_path_next ( path ) ) ; path = next ) {
|
||||
fp = container_of ( path, FILEPATH_DEVICE_PATH, Header );
|
||||
len = snprintf ( tmp, remaining, "%ls", fp->PathName );
|
||||
assert ( len < remaining );
|
||||
tmp += len;
|
||||
remaining -= len;
|
||||
fp = ( ( ( void * ) fp ) + ( ( fp->Header.Length[1] << 8 ) |
|
||||
fp->Header.Length[0] ) );
|
||||
}
|
||||
DBGC2 ( local, "LOCAL %p base path \"%s\"\n",
|
||||
local, base );
|
||||
@ -454,7 +454,7 @@ static int efi_local_open_path ( struct efi_local *local, const char *path ) {
|
||||
}
|
||||
|
||||
/* Resolve path */
|
||||
resolved = resolve_path ( base, path );
|
||||
resolved = resolve_path ( base, filename );
|
||||
if ( ! resolved ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_resolve;
|
||||
|
||||
@ -193,6 +193,48 @@ void efi_nullify_nii ( EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *nii ) {
|
||||
nii->Id = ( ( intptr_t ) &efi_null_undi );
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* VLAN configuration protocol
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
static EFI_STATUS EFIAPI
|
||||
efi_null_vlan_set ( EFI_VLAN_CONFIG_PROTOCOL *vcfg __unused,
|
||||
UINT16 tag __unused, UINT8 priority __unused ) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static EFI_STATUS EFIAPI
|
||||
efi_null_vlan_find ( EFI_VLAN_CONFIG_PROTOCOL *vcfg __unused,
|
||||
UINT16 *filter __unused, UINT16 *count __unused,
|
||||
EFI_VLAN_FIND_DATA **entries __unused ) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static EFI_STATUS EFIAPI
|
||||
efi_null_vlan_remove ( EFI_VLAN_CONFIG_PROTOCOL *vcfg __unused,
|
||||
UINT16 tag __unused ) {
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static EFI_VLAN_CONFIG_PROTOCOL efi_null_vlan = {
|
||||
.Set = efi_null_vlan_set,
|
||||
.Find = efi_null_vlan_find,
|
||||
.Remove = efi_null_vlan_remove,
|
||||
};
|
||||
|
||||
/**
|
||||
* Nullify VLAN configuration interface
|
||||
*
|
||||
* @v vcfg VLAN configuration protocol
|
||||
*/
|
||||
void efi_nullify_vlan ( EFI_VLAN_CONFIG_PROTOCOL *vcfg ) {
|
||||
|
||||
memcpy ( vcfg, &efi_null_vlan, sizeof ( *vcfg ) );
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Component name protocol
|
||||
|
||||
@ -40,19 +40,43 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Find next element in device path
|
||||
*
|
||||
* @v path Device path, or NULL
|
||||
* @v next Next element in device path, or NULL if at end
|
||||
*/
|
||||
EFI_DEVICE_PATH_PROTOCOL * efi_path_next ( EFI_DEVICE_PATH_PROTOCOL *path ) {
|
||||
|
||||
/* Check for non-existent device path */
|
||||
if ( ! path )
|
||||
return NULL;
|
||||
|
||||
/* Check for end of device path */
|
||||
if ( path->Type == END_DEVICE_PATH_TYPE )
|
||||
return NULL;
|
||||
|
||||
/* Move to next component of the device path */
|
||||
path = ( ( ( void * ) path ) +
|
||||
/* There's this amazing new-fangled thing known as
|
||||
* a UINT16, but who wants to use one of those? */
|
||||
( ( path->Length[1] << 8 ) | path->Length[0] ) );
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find end of device path
|
||||
*
|
||||
* @v path Path to device
|
||||
* @ret path_end End of device path
|
||||
* @v path Device path, or NULL
|
||||
* @ret path_end End of device path, or NULL
|
||||
*/
|
||||
EFI_DEVICE_PATH_PROTOCOL * efi_path_end ( EFI_DEVICE_PATH_PROTOCOL *path ) {
|
||||
EFI_DEVICE_PATH_PROTOCOL *next;
|
||||
|
||||
while ( path->Type != END_DEVICE_PATH_TYPE ) {
|
||||
path = ( ( ( void * ) path ) +
|
||||
/* There's this amazing new-fangled thing known as
|
||||
* a UINT16, but who wants to use one of those? */
|
||||
( ( path->Length[1] << 8 ) | path->Length[0] ) );
|
||||
/* Find end of device path */
|
||||
while ( ( next = efi_path_next ( path ) ) != NULL ) {
|
||||
path = next;
|
||||
}
|
||||
|
||||
return path;
|
||||
@ -61,7 +85,7 @@ EFI_DEVICE_PATH_PROTOCOL * efi_path_end ( EFI_DEVICE_PATH_PROTOCOL *path ) {
|
||||
/**
|
||||
* Find length of device path (excluding terminator)
|
||||
*
|
||||
* @v path Path to device
|
||||
* @v path Device path, or NULL
|
||||
* @ret path_len Length of device path
|
||||
*/
|
||||
size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ) {
|
||||
@ -70,6 +94,29 @@ size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ) {
|
||||
return ( ( ( void * ) end ) - ( ( void * ) path ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get VLAN tag from device path
|
||||
*
|
||||
* @v path Device path
|
||||
* @ret tag VLAN tag, or 0 if not a VLAN
|
||||
*/
|
||||
unsigned int efi_path_vlan ( EFI_DEVICE_PATH_PROTOCOL *path ) {
|
||||
EFI_DEVICE_PATH_PROTOCOL *next;
|
||||
VLAN_DEVICE_PATH *vlan;
|
||||
|
||||
/* Search for VLAN device path */
|
||||
for ( ; ( next = efi_path_next ( path ) ) ; path = next ) {
|
||||
if ( ( path->Type == MESSAGING_DEVICE_PATH ) &&
|
||||
( path->SubType == MSG_VLAN_DP ) ) {
|
||||
vlan = container_of ( path, VLAN_DEVICE_PATH, Header );
|
||||
return vlan->VlanId;
|
||||
}
|
||||
}
|
||||
|
||||
/* No VLAN device path found */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate EFI device paths
|
||||
*
|
||||
|
||||
@ -199,7 +199,7 @@ static void efi_pxe_ip_sockaddr ( struct efi_pxe *pxe, EFI_IP_ADDRESS *ip,
|
||||
memset ( sockaddr, 0, sizeof ( *sockaddr ) );
|
||||
sockaddr->sa.sa_family = pxe->tcpip->sa_family;
|
||||
memcpy ( &sockaddr->se.se_addr, ip, pxe->net->net_addr_len );
|
||||
sockaddr->se.se_scope_id = pxe->netdev->index;
|
||||
sockaddr->se.se_scope_id = pxe->netdev->scope_id;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -934,11 +934,11 @@ static uint8_t efi_undi_checksum ( void *data, size_t len ) {
|
||||
*/
|
||||
static unsigned int efi_undi_ifnum ( struct efi_snp_device *snpdev ) {
|
||||
|
||||
/* iPXE network device indexes are one-based (leaving zero
|
||||
/* iPXE network device scope IDs are one-based (leaving zero
|
||||
* meaning "unspecified"). UNDI interface numbers are
|
||||
* zero-based.
|
||||
*/
|
||||
return ( snpdev->netdev->index - 1 );
|
||||
return ( snpdev->netdev->scope_id - 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1488,6 +1488,164 @@ static EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL efi_snp_device_nii = {
|
||||
.Ipv6Supported = TRUE, /* This is a raw packet interface, FFS! */
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* VLAN configuration protocol
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create or modify VLAN device
|
||||
*
|
||||
* @v vcfg VLAN configuration protocol
|
||||
* @v tag VLAN tag
|
||||
* @v priority Default VLAN priority
|
||||
* @ret efirc EFI status code
|
||||
*/
|
||||
static EFI_STATUS EFIAPI efi_vlan_set ( EFI_VLAN_CONFIG_PROTOCOL *vcfg,
|
||||
UINT16 tag, UINT8 priority ) {
|
||||
struct efi_snp_device *snpdev =
|
||||
container_of ( vcfg, struct efi_snp_device, vcfg );
|
||||
struct net_device *trunk = snpdev->netdev;
|
||||
struct efi_saved_tpl tpl;
|
||||
int rc;
|
||||
|
||||
/* Raise TPL */
|
||||
efi_raise_tpl ( &tpl );
|
||||
|
||||
/* Create or modify VLAN device */
|
||||
if ( ( rc = vlan_create ( trunk, tag, priority ) ) != 0 ) {
|
||||
DBGC ( snpdev, "SNPDEV %p could not create VLAN tag %d: %s\n",
|
||||
snpdev, tag, strerror ( rc ) );
|
||||
goto err_create;
|
||||
}
|
||||
DBGC ( snpdev, "SNPDEV %p created VLAN tag %d priority %d\n",
|
||||
snpdev, tag, priority );
|
||||
|
||||
err_create:
|
||||
efi_restore_tpl ( &tpl );
|
||||
return EFIRC ( rc );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find VLAN device(s)
|
||||
*
|
||||
* @v vcfg VLAN configuration protocol
|
||||
* @v filter VLAN tag, or NULL to find all VLANs
|
||||
* @v count Number of VLANs
|
||||
* @v entries List of VLANs
|
||||
* @ret efirc EFI status code
|
||||
*/
|
||||
static EFI_STATUS EFIAPI efi_vlan_find ( EFI_VLAN_CONFIG_PROTOCOL *vcfg,
|
||||
UINT16 *filter, UINT16 *count,
|
||||
EFI_VLAN_FIND_DATA **entries ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
struct efi_snp_device *snpdev =
|
||||
container_of ( vcfg, struct efi_snp_device, vcfg );
|
||||
struct net_device *trunk = snpdev->netdev;
|
||||
struct net_device *vlan;
|
||||
struct efi_saved_tpl tpl;
|
||||
EFI_VLAN_FIND_DATA *entry;
|
||||
VOID *buffer;
|
||||
unsigned int tag;
|
||||
unsigned int tci;
|
||||
size_t len;
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
|
||||
/* Raise TPL */
|
||||
efi_raise_tpl ( &tpl );
|
||||
|
||||
/* Count number of matching VLANs */
|
||||
*count = 0;
|
||||
for ( tag = 1 ; VLAN_TAG_IS_VALID ( tag ) ; tag++ ) {
|
||||
if ( filter && ( tag != *filter ) )
|
||||
continue;
|
||||
if ( ! ( vlan = vlan_find ( trunk, tag ) ) )
|
||||
continue;
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
/* Allocate buffer to hold results */
|
||||
len = ( (*count) * sizeof ( *entry ) );
|
||||
if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, len,
|
||||
&buffer ) ) != 0 ) {
|
||||
rc = -EEFI ( efirc );
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
/* Fill in buffer */
|
||||
*entries = buffer;
|
||||
entry = *entries;
|
||||
for ( tag = 1 ; VLAN_TAG_IS_VALID ( tag ) ; tag++ ) {
|
||||
if ( filter && ( tag != *filter ) )
|
||||
continue;
|
||||
if ( ! ( vlan = vlan_find ( trunk, tag ) ) )
|
||||
continue;
|
||||
tci = vlan_tci ( vlan );
|
||||
entry->VlanId = VLAN_TAG ( tci );
|
||||
entry->Priority = VLAN_PRIORITY ( tci );
|
||||
assert ( entry->VlanId == tag );
|
||||
entry++;
|
||||
}
|
||||
assert ( entry == &(*entries)[*count] );
|
||||
|
||||
/* Success */
|
||||
rc = 0;
|
||||
|
||||
err_alloc:
|
||||
efi_restore_tpl ( &tpl );
|
||||
return EFIRC ( rc );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove VLAN device
|
||||
*
|
||||
* @v vcfg VLAN configuration protocol
|
||||
* @v tag VLAN tag
|
||||
* @ret efirc EFI status code
|
||||
*/
|
||||
static EFI_STATUS EFIAPI efi_vlan_remove ( EFI_VLAN_CONFIG_PROTOCOL *vcfg,
|
||||
UINT16 tag ) {
|
||||
struct efi_snp_device *snpdev =
|
||||
container_of ( vcfg, struct efi_snp_device, vcfg );
|
||||
struct net_device *trunk = snpdev->netdev;
|
||||
struct net_device *vlan;
|
||||
struct efi_saved_tpl tpl;
|
||||
int rc;
|
||||
|
||||
/* Raise TPL */
|
||||
efi_raise_tpl ( &tpl );
|
||||
|
||||
/* Identify VLAN device */
|
||||
vlan = vlan_find ( trunk, tag );
|
||||
if ( ! vlan ) {
|
||||
DBGC ( snpdev, "SNPDEV %p could not find VLAN tag %d\n",
|
||||
snpdev, tag );
|
||||
rc = -ENOENT;
|
||||
goto err_find;
|
||||
}
|
||||
|
||||
/* Remove VLAN device */
|
||||
vlan_destroy ( vlan );
|
||||
DBGC ( snpdev, "SNPDEV %p removed VLAN tag %d\n", snpdev, tag );
|
||||
|
||||
/* Success */
|
||||
rc = 0;
|
||||
|
||||
err_find:
|
||||
efi_restore_tpl ( &tpl );
|
||||
return EFIRC ( rc );
|
||||
}
|
||||
|
||||
/** VLAN configuration protocol */
|
||||
static EFI_VLAN_CONFIG_PROTOCOL efi_vlan = {
|
||||
.Set = efi_vlan_set,
|
||||
.Find = efi_vlan_find,
|
||||
.Remove = efi_vlan_remove,
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Component name protocol
|
||||
@ -1627,6 +1785,8 @@ static int efi_snp_probe ( struct net_device *netdev ) {
|
||||
struct efi_snp_device *snpdev;
|
||||
unsigned int ifcnt;
|
||||
void *interface;
|
||||
unsigned int tci;
|
||||
char vlan_name[ 12 /* ", VLAN xxxx" + NUL */ ];
|
||||
int leak = 0;
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
@ -1687,17 +1847,27 @@ static int efi_snp_probe ( struct net_device *netdev ) {
|
||||
efi_snp_undi.Fudge -= efi_undi_checksum ( &efi_snp_undi,
|
||||
sizeof ( efi_snp_undi ) );
|
||||
|
||||
/* Populate the VLAN configuration protocol */
|
||||
memcpy ( &snpdev->vcfg, &efi_vlan, sizeof ( snpdev->vcfg ) );
|
||||
|
||||
/* Populate the component name structure */
|
||||
efi_snprintf ( snpdev->driver_name,
|
||||
( sizeof ( snpdev->driver_name ) /
|
||||
sizeof ( snpdev->driver_name[0] ) ),
|
||||
"%s %s", product_short_name, netdev->dev->driver_name );
|
||||
tci = vlan_tci ( netdev );
|
||||
if ( tci ) {
|
||||
snprintf ( vlan_name, sizeof ( vlan_name ), ", VLAN %d",
|
||||
VLAN_TAG ( tci ) );
|
||||
} else {
|
||||
vlan_name[0] = '\0';
|
||||
}
|
||||
efi_snprintf ( snpdev->controller_name,
|
||||
( sizeof ( snpdev->controller_name ) /
|
||||
sizeof ( snpdev->controller_name[0] ) ),
|
||||
"%s %s (%s, %s)", product_short_name,
|
||||
"%s %s (%s, %s%s)", product_short_name,
|
||||
netdev->dev->driver_name, netdev->dev->name,
|
||||
netdev_addr ( netdev ) );
|
||||
netdev_addr ( netdev ), vlan_name );
|
||||
snpdev->name2.GetDriverName = efi_snp_get_driver_name;
|
||||
snpdev->name2.GetControllerName = efi_snp_get_controller_name;
|
||||
snpdev->name2.SupportedLanguages = "en";
|
||||
@ -1725,6 +1895,7 @@ static int efi_snp_probe ( struct net_device *netdev ) {
|
||||
&efi_device_path_protocol_guid, snpdev->path,
|
||||
&efi_nii_protocol_guid, &snpdev->nii,
|
||||
&efi_nii31_protocol_guid, &snpdev->nii,
|
||||
&efi_vlan_config_protocol_guid, &snpdev->vcfg,
|
||||
&efi_component_name2_protocol_guid, &snpdev->name2,
|
||||
&efi_load_file_protocol_guid, &snpdev->load_file,
|
||||
NULL ) ) != 0 ) {
|
||||
@ -1811,6 +1982,7 @@ static int efi_snp_probe ( struct net_device *netdev ) {
|
||||
&efi_device_path_protocol_guid, snpdev->path,
|
||||
&efi_nii_protocol_guid, &snpdev->nii,
|
||||
&efi_nii31_protocol_guid, &snpdev->nii,
|
||||
&efi_vlan_config_protocol_guid, &snpdev->vcfg,
|
||||
&efi_component_name2_protocol_guid, &snpdev->name2,
|
||||
&efi_load_file_protocol_guid, &snpdev->load_file,
|
||||
NULL ) ) != 0 ) {
|
||||
@ -1820,6 +1992,7 @@ static int efi_snp_probe ( struct net_device *netdev ) {
|
||||
}
|
||||
efi_nullify_snp ( &snpdev->snp );
|
||||
efi_nullify_nii ( &snpdev->nii );
|
||||
efi_nullify_vlan ( &snpdev->vcfg );
|
||||
efi_nullify_name2 ( &snpdev->name2 );
|
||||
efi_nullify_load_file ( &snpdev->load_file );
|
||||
err_install_protocol_interface:
|
||||
@ -1899,6 +2072,7 @@ static void efi_snp_remove ( struct net_device *netdev ) {
|
||||
&efi_device_path_protocol_guid, snpdev->path,
|
||||
&efi_nii_protocol_guid, &snpdev->nii,
|
||||
&efi_nii31_protocol_guid, &snpdev->nii,
|
||||
&efi_vlan_config_protocol_guid, &snpdev->vcfg,
|
||||
&efi_component_name2_protocol_guid, &snpdev->name2,
|
||||
&efi_load_file_protocol_guid, &snpdev->load_file,
|
||||
NULL ) ) != 0 ) ) {
|
||||
@ -1908,6 +2082,7 @@ static void efi_snp_remove ( struct net_device *netdev ) {
|
||||
}
|
||||
efi_nullify_snp ( &snpdev->snp );
|
||||
efi_nullify_nii ( &snpdev->nii );
|
||||
efi_nullify_vlan ( &snpdev->vcfg );
|
||||
efi_nullify_name2 ( &snpdev->name2 );
|
||||
efi_nullify_load_file ( &snpdev->load_file );
|
||||
if ( ! leak )
|
||||
|
||||
@ -78,12 +78,13 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle,
|
||||
*/
|
||||
static void efi_init_application ( void ) {
|
||||
EFI_HANDLE device = efi_loaded_image->DeviceHandle;
|
||||
EFI_DEVICE_PATH_PROTOCOL *path = efi_loaded_image_path;
|
||||
|
||||
/* Identify autoboot device, if any */
|
||||
efi_set_autoboot_ll_addr ( device );
|
||||
efi_set_autoboot_ll_addr ( device, path );
|
||||
|
||||
/* Store cached DHCP packet, if any */
|
||||
efi_cachedhcp_record ( device );
|
||||
efi_cachedhcp_record ( device, path );
|
||||
|
||||
/* Load autoexec script, if any */
|
||||
efi_autoexec_load ( device );
|
||||
|
||||
@ -163,7 +163,7 @@ static struct ipv4_miniroute * ipv4_route ( unsigned int scope_id,
|
||||
/* If destination is non-global, and the scope ID
|
||||
* matches this network device, then use this route.
|
||||
*/
|
||||
if ( miniroute->netdev->index == scope_id )
|
||||
if ( miniroute->netdev->scope_id == scope_id )
|
||||
return miniroute;
|
||||
|
||||
} else {
|
||||
|
||||
@ -330,7 +330,7 @@ struct ipv6_miniroute * ipv6_route ( unsigned int scope_id,
|
||||
/* Skip entries with a non-matching scope ID, if
|
||||
* destination specifies a scope ID.
|
||||
*/
|
||||
if ( scope_id && ( miniroute->netdev->index != scope_id ) )
|
||||
if ( scope_id && ( miniroute->netdev->scope_id != scope_id ) )
|
||||
continue;
|
||||
|
||||
/* Skip entries that are out of scope */
|
||||
@ -789,12 +789,12 @@ static int ipv6_rx ( struct io_buffer *iobuf, struct net_device *netdev,
|
||||
src.sin6.sin6_family = AF_INET6;
|
||||
memcpy ( &src.sin6.sin6_addr, &iphdr->src,
|
||||
sizeof ( src.sin6.sin6_addr ) );
|
||||
src.sin6.sin6_scope_id = netdev->index;
|
||||
src.sin6.sin6_scope_id = netdev->scope_id;
|
||||
memset ( &dest, 0, sizeof ( dest ) );
|
||||
dest.sin6.sin6_family = AF_INET6;
|
||||
memcpy ( &dest.sin6.sin6_addr, &iphdr->dest,
|
||||
sizeof ( dest.sin6.sin6_addr ) );
|
||||
dest.sin6.sin6_scope_id = netdev->index;
|
||||
dest.sin6.sin6_scope_id = netdev->scope_id;
|
||||
iob_pull ( iobuf, hdrlen );
|
||||
pshdr_csum = ipv6_pshdr_chksum ( iphdr, iob_len ( iobuf ),
|
||||
next_header, TCPIP_EMPTY_CSUM );
|
||||
@ -957,7 +957,7 @@ static const char * ipv6_sock_ntoa ( struct sockaddr *sa ) {
|
||||
|
||||
/* Identify network device, if applicable */
|
||||
if ( IN6_IS_ADDR_LINKLOCAL ( in ) || IN6_IS_ADDR_MULTICAST ( in ) ) {
|
||||
netdev = find_netdev_by_index ( sin6->sin6_scope_id );
|
||||
netdev = find_netdev_by_scope_id ( sin6->sin6_scope_id );
|
||||
netdev_name = ( netdev ? netdev->name : "UNKNOWN" );
|
||||
} else {
|
||||
netdev_name = NULL;
|
||||
@ -1020,7 +1020,7 @@ static int ipv6_sock_aton ( const char *string, struct sockaddr *sa ) {
|
||||
rc = -ENODEV;
|
||||
goto err_find_netdev;
|
||||
}
|
||||
sin6->sin6_scope_id = netdev->index;
|
||||
sin6->sin6_scope_id = netdev->scope_id;
|
||||
|
||||
} else if ( IN6_IS_ADDR_LINKLOCAL ( &in ) ||
|
||||
IN6_IS_ADDR_MULTICAST ( &in ) ) {
|
||||
@ -1031,7 +1031,7 @@ static int ipv6_sock_aton ( const char *string, struct sockaddr *sa ) {
|
||||
*/
|
||||
netdev = last_opened_netdev();
|
||||
if ( netdev )
|
||||
sin6->sin6_scope_id = netdev->index;
|
||||
sin6->sin6_scope_id = netdev->scope_id;
|
||||
}
|
||||
|
||||
/* Copy IPv6 address portion to socket address */
|
||||
|
||||
@ -140,7 +140,7 @@ static int ndp_tx_request ( struct net_device *netdev,
|
||||
/* Construct multicast destination address */
|
||||
memset ( &sin6_dest, 0, sizeof ( sin6_dest ) );
|
||||
sin6_dest.sin6_family = AF_INET6;
|
||||
sin6_dest.sin6_scope_id = netdev->index;
|
||||
sin6_dest.sin6_scope_id = netdev->scope_id;
|
||||
ipv6_solicited_node ( &sin6_dest.sin6_addr, net_dest );
|
||||
|
||||
/* Construct neighbour header */
|
||||
@ -177,7 +177,7 @@ static int ndp_tx_router_solicitation ( struct net_device *netdev ) {
|
||||
/* Construct multicast destination address */
|
||||
memset ( &sin6_dest, 0, sizeof ( sin6_dest ) );
|
||||
sin6_dest.sin6_family = AF_INET6;
|
||||
sin6_dest.sin6_scope_id = netdev->index;
|
||||
sin6_dest.sin6_scope_id = netdev->scope_id;
|
||||
ipv6_all_routers ( &sin6_dest.sin6_addr );
|
||||
|
||||
/* Construct router solicitation */
|
||||
|
||||
@ -55,9 +55,6 @@ struct list_head net_devices = LIST_HEAD_INIT ( net_devices );
|
||||
/** List of open network devices, in reverse order of opening */
|
||||
static struct list_head open_net_devices = LIST_HEAD_INIT ( open_net_devices );
|
||||
|
||||
/** Network device index */
|
||||
static unsigned int netdev_index = 0;
|
||||
|
||||
/** Network polling profiler */
|
||||
static struct profiler net_poll_profiler __profiler = { .name = "net.poll" };
|
||||
|
||||
@ -723,6 +720,7 @@ int register_netdev ( struct net_device *netdev ) {
|
||||
struct ll_protocol *ll_protocol = netdev->ll_protocol;
|
||||
struct net_driver *driver;
|
||||
struct net_device *duplicate;
|
||||
unsigned int i;
|
||||
uint32_t seed;
|
||||
int rc;
|
||||
|
||||
@ -737,18 +735,6 @@ int register_netdev ( struct net_device *netdev ) {
|
||||
ll_protocol->ll_header_len );
|
||||
}
|
||||
|
||||
/* Reject network devices that are already available via a
|
||||
* different hardware device.
|
||||
*/
|
||||
duplicate = find_netdev_by_ll_addr ( ll_protocol, netdev->ll_addr );
|
||||
if ( duplicate && ( duplicate->dev != netdev->dev ) ) {
|
||||
DBGC ( netdev, "NETDEV rejecting duplicate (phys %s) of %s "
|
||||
"(phys %s)\n", netdev->dev->name, duplicate->name,
|
||||
duplicate->dev->name );
|
||||
rc = -EEXIST;
|
||||
goto err_duplicate;
|
||||
}
|
||||
|
||||
/* Reject named network devices that already exist */
|
||||
if ( netdev->name[0] && ( duplicate = find_netdev ( netdev->name ) ) ) {
|
||||
DBGC ( netdev, "NETDEV rejecting duplicate name %s\n",
|
||||
@ -757,12 +743,21 @@ int register_netdev ( struct net_device *netdev ) {
|
||||
goto err_duplicate;
|
||||
}
|
||||
|
||||
/* Record device index and create device name */
|
||||
/* Assign a unique device name, if not already set */
|
||||
if ( netdev->name[0] == '\0' ) {
|
||||
snprintf ( netdev->name, sizeof ( netdev->name ), "net%d",
|
||||
netdev_index );
|
||||
for ( i = 0 ; ; i++ ) {
|
||||
snprintf ( netdev->name, sizeof ( netdev->name ),
|
||||
"net%d", i );
|
||||
if ( find_netdev ( netdev->name ) == NULL )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Assign a unique non-zero scope ID */
|
||||
for ( netdev->scope_id = 1 ; ; netdev->scope_id++ ) {
|
||||
if ( find_netdev_by_scope_id ( netdev->scope_id ) == NULL )
|
||||
break;
|
||||
}
|
||||
netdev->index = ++netdev_index;
|
||||
|
||||
/* Use least significant bits of the link-layer address to
|
||||
* improve the randomness of the (non-cryptographic) random
|
||||
@ -916,10 +911,6 @@ void unregister_netdev ( struct net_device *netdev ) {
|
||||
DBGC ( netdev, "NETDEV %s unregistered\n", netdev->name );
|
||||
list_del ( &netdev->list );
|
||||
netdev_put ( netdev );
|
||||
|
||||
/* Reset network device index if no devices remain */
|
||||
if ( list_empty ( &net_devices ) )
|
||||
netdev_index = 0;
|
||||
}
|
||||
|
||||
/** Enable or disable interrupts
|
||||
@ -962,17 +953,17 @@ struct net_device * find_netdev ( const char *name ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get network device by index
|
||||
* Get network device by scope ID
|
||||
*
|
||||
* @v index Network device index
|
||||
* @ret netdev Network device, or NULL
|
||||
*/
|
||||
struct net_device * find_netdev_by_index ( unsigned int index ) {
|
||||
struct net_device * find_netdev_by_scope_id ( unsigned int scope_id ) {
|
||||
struct net_device *netdev;
|
||||
|
||||
/* Identify network device by index */
|
||||
list_for_each_entry ( netdev, &net_devices, list ) {
|
||||
if ( netdev->index == index )
|
||||
if ( netdev->scope_id == scope_id )
|
||||
return netdev;
|
||||
}
|
||||
|
||||
@ -999,27 +990,6 @@ struct net_device * find_netdev_by_location ( unsigned int bus_type,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get network device by link-layer address
|
||||
*
|
||||
* @v ll_protocol Link-layer protocol
|
||||
* @v ll_addr Link-layer address
|
||||
* @ret netdev Network device, or NULL
|
||||
*/
|
||||
struct net_device * find_netdev_by_ll_addr ( struct ll_protocol *ll_protocol,
|
||||
const void *ll_addr ) {
|
||||
struct net_device *netdev;
|
||||
|
||||
list_for_each_entry ( netdev, &net_devices, list ) {
|
||||
if ( ( netdev->ll_protocol == ll_protocol ) &&
|
||||
( memcmp ( netdev->ll_addr, ll_addr,
|
||||
ll_protocol->ll_addr_len ) == 0 ) )
|
||||
return netdev;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get most recently opened network device
|
||||
*
|
||||
@ -1171,12 +1141,12 @@ static void net_step ( struct process *process __unused ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the VLAN tag (when VLAN support is not present)
|
||||
* Get the VLAN tag control information (when VLAN support is not present)
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @ret tag 0, indicating that device is not a VLAN device
|
||||
*/
|
||||
__weak unsigned int vlan_tag ( struct net_device *netdev __unused ) {
|
||||
__weak unsigned int vlan_tci ( struct net_device *netdev __unused ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -189,7 +189,7 @@ static void peerdisc_socket_tx ( const char *uuid, const char *id ) {
|
||||
/* Skip unopened network devices */
|
||||
if ( ! netdev_is_open ( netdev ) )
|
||||
continue;
|
||||
address.st.st_scope_id = netdev->index;
|
||||
address.st.st_scope_id = netdev->scope_id;
|
||||
|
||||
/* Discard request (for test purposes) if applicable */
|
||||
if ( inject_fault ( PEERDISC_DISCARD_RATE ) )
|
||||
|
||||
@ -955,7 +955,7 @@ int start_dhcpv6 ( struct interface *job, struct net_device *netdev,
|
||||
addresses.client.sin6.sin6_port = htons ( DHCPV6_CLIENT_PORT );
|
||||
addresses.server.sin6.sin6_family = AF_INET6;
|
||||
ipv6_all_dhcp_relay_and_servers ( &addresses.server.sin6.sin6_addr );
|
||||
addresses.server.sin6.sin6_scope_id = netdev->index;
|
||||
addresses.server.sin6.sin6_scope_id = netdev->scope_id;
|
||||
addresses.server.sin6.sin6_port = htons ( DHCPV6_SERVER_PORT );
|
||||
|
||||
/* Construct client DUID from system UUID */
|
||||
|
||||
@ -55,6 +55,12 @@ struct vlan_device {
|
||||
unsigned int priority;
|
||||
};
|
||||
|
||||
/** Automatic VLAN device link-layer address */
|
||||
static uint8_t vlan_auto_ll_addr[ETH_ALEN];
|
||||
|
||||
/** Automatic VLAN tag */
|
||||
static unsigned int vlan_auto_tag;
|
||||
|
||||
/**
|
||||
* Open VLAN device
|
||||
*
|
||||
@ -199,8 +205,7 @@ static void vlan_sync ( struct net_device *netdev ) {
|
||||
* @v tag VLAN tag
|
||||
* @ret netdev VLAN device, if any
|
||||
*/
|
||||
static struct net_device * vlan_find ( struct net_device *trunk,
|
||||
unsigned int tag ) {
|
||||
struct net_device * vlan_find ( struct net_device *trunk, unsigned int tag ) {
|
||||
struct net_device *netdev;
|
||||
struct vlan_device *vlan;
|
||||
|
||||
@ -288,17 +293,17 @@ struct net_protocol vlan_protocol __net_protocol = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the VLAN tag
|
||||
* Get the VLAN tag control information
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @ret tag VLAN tag, or 0 if device is not a VLAN device
|
||||
* @ret tci VLAN tag control information, or 0 if not a VLAN device
|
||||
*/
|
||||
unsigned int vlan_tag ( struct net_device *netdev ) {
|
||||
unsigned int vlan_tci ( struct net_device *netdev ) {
|
||||
struct vlan_device *vlan;
|
||||
|
||||
if ( netdev->op == &vlan_operations ) {
|
||||
vlan = netdev->priv;
|
||||
return vlan->tag;
|
||||
return ( VLAN_TCI ( vlan->tag, vlan->priority ) );
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@ -448,6 +453,47 @@ int vlan_destroy ( struct net_device *netdev ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure automatic VLAN device
|
||||
*
|
||||
* @v ll_addr Link-layer address
|
||||
* @v tag VLAN tag
|
||||
*/
|
||||
void vlan_auto ( const void *ll_addr, unsigned int tag ) {
|
||||
|
||||
/* Record link-layer address and VLAN tag */
|
||||
memcpy ( vlan_auto_ll_addr, ll_addr, ETH_ALEN );
|
||||
vlan_auto_tag = tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create automatic VLAN device
|
||||
*
|
||||
* @v trunk Trunk network device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int vlan_probe ( struct net_device *trunk ) {
|
||||
int rc;
|
||||
|
||||
/* Do nothing unless an automatic VLAN exists */
|
||||
if ( ! vlan_auto_tag )
|
||||
return 0;
|
||||
|
||||
/* Ignore non-trunk devices */
|
||||
if ( ! vlan_can_be_trunk ( trunk ) )
|
||||
return 0;
|
||||
|
||||
/* Ignore non-matching link-layer addresses */
|
||||
if ( memcmp ( trunk->ll_addr, vlan_auto_ll_addr, ETH_ALEN ) != 0 )
|
||||
return 0;
|
||||
|
||||
/* Create automatic VLAN device */
|
||||
if ( ( rc = vlan_create ( trunk, vlan_auto_tag, 0 ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle trunk network device link state change
|
||||
*
|
||||
@ -504,6 +550,7 @@ static void vlan_remove ( struct net_device *trunk ) {
|
||||
/** VLAN driver */
|
||||
struct net_driver vlan_driver __net_driver = {
|
||||
.name = "VLAN",
|
||||
.probe = vlan_probe,
|
||||
.notify = vlan_notify,
|
||||
.remove = vlan_remove,
|
||||
};
|
||||
|
||||
@ -127,7 +127,7 @@ static const struct in6_addr sample_multicast = {
|
||||
/** Dummy network device used for routing tests */
|
||||
static struct net_device ipv6_test_netdev = {
|
||||
.refcnt = REF_INIT ( ref_no_free ),
|
||||
.index = 42,
|
||||
.scope_id = 42,
|
||||
.state = NETDEV_OPEN,
|
||||
};
|
||||
|
||||
@ -349,7 +349,7 @@ static void ipv6_route_okx ( struct ipv6_test_table *table, const char *dest,
|
||||
|
||||
/* Perform routing */
|
||||
actual = &in_dest;
|
||||
miniroute = ipv6_route ( ipv6_test_netdev.index, &actual );
|
||||
miniroute = ipv6_route ( ipv6_test_netdev.scope_id, &actual );
|
||||
|
||||
/* Validate result */
|
||||
if ( src ) {
|
||||
|
||||
@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <ipxe/vlan.h>
|
||||
#include <ipxe/dhcp.h>
|
||||
#include <ipxe/settings.h>
|
||||
#include <ipxe/image.h>
|
||||
@ -57,6 +58,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
/** Link-layer address of preferred autoboot device, if known */
|
||||
static uint8_t autoboot_ll_addr[MAX_LL_ADDR_LEN];
|
||||
|
||||
/** VLAN tag of preferred autoboot device, if known */
|
||||
static unsigned int autoboot_vlan;
|
||||
|
||||
/** Device location of preferred autoboot device, if known */
|
||||
static struct device_description autoboot_desc;
|
||||
|
||||
@ -494,8 +498,9 @@ void set_autoboot_busloc ( unsigned int bus_type, unsigned int location ) {
|
||||
*/
|
||||
static int is_autoboot_ll_addr ( struct net_device *netdev ) {
|
||||
|
||||
return ( memcmp ( netdev->ll_addr, autoboot_ll_addr,
|
||||
netdev->ll_protocol->ll_addr_len ) == 0 );
|
||||
return ( ( memcmp ( netdev->ll_addr, autoboot_ll_addr,
|
||||
netdev->ll_protocol->ll_addr_len ) == 0 ) &&
|
||||
( vlan_tag ( netdev ) == autoboot_vlan ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -503,14 +508,19 @@ static int is_autoboot_ll_addr ( struct net_device *netdev ) {
|
||||
*
|
||||
* @v ll_addr Link-layer address
|
||||
* @v len Length of link-layer address
|
||||
* @v vlan VLAN tag
|
||||
*/
|
||||
void set_autoboot_ll_addr ( const void *ll_addr, size_t len ) {
|
||||
void set_autoboot_ll_addr ( const void *ll_addr, size_t len,
|
||||
unsigned int vlan ) {
|
||||
|
||||
/* Record autoboot link-layer address (truncated if necessary) */
|
||||
if ( len > sizeof ( autoboot_ll_addr ) )
|
||||
len = sizeof ( autoboot_ll_addr );
|
||||
memcpy ( autoboot_ll_addr, ll_addr, len );
|
||||
|
||||
/* Record autoboot VLAN tag */
|
||||
autoboot_vlan = vlan;
|
||||
|
||||
/* Mark autoboot device as present */
|
||||
is_autoboot_device = is_autoboot_ll_addr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user