mirror of
https://github.com/xcat2/xNBA.git
synced 2026-09-22 17:42:22 +00:00
This commit is contained in:
@@ -31,7 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
* Timer configuration
|
||||
*
|
||||
*/
|
||||
#define BANNER_TIMEOUT 20 /* Tenths of a second for which the shell
|
||||
#define BANNER_TIMEOUT 0 /* Tenths of a second for which the shell
|
||||
banner should appear */
|
||||
|
||||
/*
|
||||
@@ -56,8 +56,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#define DOWNLOAD_PROTO_TFTP /* Trivial File Transfer Protocol */
|
||||
#define DOWNLOAD_PROTO_HTTP /* Hypertext Transfer Protocol */
|
||||
#undef DOWNLOAD_PROTO_HTTPS /* Secure Hypertext Transfer Protocol */
|
||||
#define DOWNLOAD_PROTO_FTP /* File Transfer Protocol */
|
||||
#define DOWNLOAD_PROTO_HTTPS /* Secure Hypertext Transfer Protocol */
|
||||
#undef DOWNLOAD_PROTO_FTP /* File Transfer Protocol */
|
||||
#undef DOWNLOAD_PROTO_TFTM /* Multicast Trivial File Transfer Protocol */
|
||||
#undef DOWNLOAD_PROTO_SLAM /* Scalable Local Area Multicast */
|
||||
|
||||
@@ -99,9 +99,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#undef IMAGE_MULTIBOOT /* MultiBoot image support */
|
||||
#undef IMAGE_AOUT /* a.out image support */
|
||||
#undef IMAGE_WINCE /* WinCE image support */
|
||||
#define IMAGE_PXE /* PXE image support */
|
||||
#define IMAGE_SCRIPT /* iPXE script image support */
|
||||
#define IMAGE_BZIMAGE /* Linux bzImage image support */
|
||||
//#define IMAGE_PXE /* PXE image support */
|
||||
//#define IMAGE_SCRIPT /* iPXE script image support */
|
||||
//#define IMAGE_BZIMAGE /* Linux bzImage image support */
|
||||
#undef IMAGE_COMBOOT /* SYSLINUX COMBOOT image support */
|
||||
//#define IMAGE_EFI /* EFI image support */
|
||||
|
||||
|
||||
+57
-36
@@ -29,6 +29,20 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
*
|
||||
*/
|
||||
|
||||
/* Disambiguate the various error causes */
|
||||
#define EINVAL_ASN1_EMPTY \
|
||||
__einfo_error ( EINFO_EINVAL_ASN1_EMPTY )
|
||||
#define EINFO_EINVAL_ASN1_EMPTY \
|
||||
__einfo_uniqify ( EINFO_EINVAL, 0x01, "Empty or underlength cursor" )
|
||||
#define EINVAL_ASN1_LEN_LEN \
|
||||
__einfo_error ( EINFO_EINVAL_ASN1_LEN_LEN )
|
||||
#define EINFO_EINVAL_ASN1_LEN_LEN \
|
||||
__einfo_uniqify ( EINFO_EINVAL, 0x02, "Length field overruns cursor" )
|
||||
#define EINVAL_ASN1_LEN \
|
||||
__einfo_error ( EINFO_EINVAL_ASN1_LEN )
|
||||
#define EINFO_EINVAL_ASN1_LEN \
|
||||
__einfo_uniqify ( EINFO_EINVAL, 0x03, "Field overruns cursor" )
|
||||
|
||||
/**
|
||||
* Start parsing ASN.1 object
|
||||
*
|
||||
@@ -40,32 +54,23 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
* object body (i.e. the first byte following the length byte(s)), and
|
||||
* the length of the object body (i.e. the number of bytes until the
|
||||
* following object tag, if any) is returned.
|
||||
*
|
||||
* If any error occurs (i.e. if the object is not of the expected
|
||||
* type, or if we overflow beyond the end of the ASN.1 object), then
|
||||
* the cursor will be invalidated and a negative value will be
|
||||
* returned.
|
||||
*/
|
||||
static int asn1_start ( struct asn1_cursor *cursor,
|
||||
unsigned int type ) {
|
||||
static int asn1_start ( struct asn1_cursor *cursor, unsigned int type ) {
|
||||
unsigned int len_len;
|
||||
unsigned int len;
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
if ( cursor->len < 2 /* Tag byte and first length byte */ ) {
|
||||
if ( cursor->len )
|
||||
DBGC ( cursor, "ASN1 %p too short\n", cursor );
|
||||
rc = -EINVAL;
|
||||
goto notfound;
|
||||
return -EINVAL_ASN1_EMPTY;
|
||||
}
|
||||
|
||||
/* Check the tag byte */
|
||||
if ( *( ( uint8_t * ) cursor->data ) != type ) {
|
||||
DBGC ( cursor, "ASN1 %p type mismatch (expected %d, got %d)\n",
|
||||
cursor, type, *( ( uint8_t * ) cursor->data ) );
|
||||
rc = -ENXIO;
|
||||
goto notfound;
|
||||
return -ENXIO;
|
||||
}
|
||||
cursor->data++;
|
||||
cursor->len--;
|
||||
@@ -82,8 +87,7 @@ static int asn1_start ( struct asn1_cursor *cursor,
|
||||
if ( cursor->len < len_len ) {
|
||||
DBGC ( cursor, "ASN1 %p bad length field length %d (max "
|
||||
"%zd)\n", cursor, len_len, cursor->len );
|
||||
rc = -EINVAL;
|
||||
goto notfound;
|
||||
return -EINVAL_ASN1_LEN_LEN;
|
||||
}
|
||||
|
||||
/* Extract the length and sanity check */
|
||||
@@ -96,16 +100,10 @@ static int asn1_start ( struct asn1_cursor *cursor,
|
||||
if ( cursor->len < len ) {
|
||||
DBGC ( cursor, "ASN1 %p bad length %d (max %zd)\n",
|
||||
cursor, len, cursor->len );
|
||||
rc = -EINVAL;
|
||||
goto notfound;
|
||||
return -EINVAL_ASN1_LEN;
|
||||
}
|
||||
|
||||
return len;
|
||||
|
||||
notfound:
|
||||
cursor->data = NULL;
|
||||
cursor->len = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,8 +121,10 @@ int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) {
|
||||
int len;
|
||||
|
||||
len = asn1_start ( cursor, type );
|
||||
if ( len < 0 )
|
||||
if ( len < 0 ) {
|
||||
asn1_invalidate_cursor ( cursor );
|
||||
return len;
|
||||
}
|
||||
|
||||
cursor->len = len;
|
||||
DBGC ( cursor, "ASN1 %p entered object type %02x (len %x)\n",
|
||||
@@ -133,6 +133,37 @@ int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip ASN.1 object if present
|
||||
*
|
||||
* @v cursor ASN.1 object cursor
|
||||
* @v type Expected type
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* The object cursor will be updated to point to the next ASN.1
|
||||
* object. If any error occurs, the object cursor will not be
|
||||
* modified.
|
||||
*/
|
||||
int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ) {
|
||||
int len;
|
||||
|
||||
len = asn1_start ( cursor, type );
|
||||
if ( len < 0 )
|
||||
return len;
|
||||
|
||||
cursor->data += len;
|
||||
cursor->len -= len;
|
||||
DBGC ( cursor, "ASN1 %p skipped object type %02x (len %x)\n",
|
||||
cursor, type, len );
|
||||
|
||||
if ( ! cursor->len ) {
|
||||
DBGC ( cursor, "ASN1 %p reached end of object\n", cursor );
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip ASN.1 object
|
||||
*
|
||||
@@ -145,21 +176,11 @@ int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) {
|
||||
* invalidated.
|
||||
*/
|
||||
int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
|
||||
int len;
|
||||
int rc;
|
||||
|
||||
len = asn1_start ( cursor, type );
|
||||
if ( len < 0 )
|
||||
return len;
|
||||
|
||||
cursor->data += len;
|
||||
cursor->len -= len;
|
||||
DBGC ( cursor, "ASN1 %p skipped object type %02x (len %x)\n",
|
||||
cursor, type, len );
|
||||
|
||||
if ( ! cursor->len ) {
|
||||
DBGC ( cursor, "ASN1 %p reached end of object\n", cursor );
|
||||
cursor->data = NULL;
|
||||
return -ENOENT;
|
||||
if ( ( rc = asn1_skip_if_exists ( cursor, type ) ) < 0 ) {
|
||||
asn1_invalidate_cursor ( cursor );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ static int x509_public_key ( const struct asn1_cursor *certificate,
|
||||
memcpy ( &cursor, certificate, sizeof ( cursor ) );
|
||||
rc = ( asn1_enter ( &cursor, ASN1_SEQUENCE ), /* Certificate */
|
||||
asn1_enter ( &cursor, ASN1_SEQUENCE ), /* tbsCertificate */
|
||||
asn1_skip ( &cursor, ASN1_EXPLICIT_TAG ), /* version */
|
||||
asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ), /* version */
|
||||
asn1_skip ( &cursor, ASN1_INTEGER ), /* serialNumber */
|
||||
asn1_skip ( &cursor, ASN1_SEQUENCE ), /* signature */
|
||||
asn1_skip ( &cursor, ASN1_SEQUENCE ), /* issuer */
|
||||
|
||||
@@ -19,13 +19,97 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <ipxe/efi/efi.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/features.h>
|
||||
#include <ipxe/uri.h>
|
||||
|
||||
FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 );
|
||||
|
||||
/** EFI loaded image protocol GUID */
|
||||
static EFI_GUID efi_loaded_image_protocol_guid
|
||||
= EFI_LOADED_IMAGE_PROTOCOL_GUID;
|
||||
|
||||
|
||||
/**
|
||||
* Create a Unicode command line for the image
|
||||
*
|
||||
* @v image EFI image
|
||||
* @v devpath_out Device path to pass to image (output)
|
||||
* @v cmdline_out Unicode command line (output)
|
||||
* @v cmdline_len_out Length of command line in bytes (output)
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int efi_image_make_cmdline ( struct image *image,
|
||||
EFI_DEVICE_PATH **devpath_out,
|
||||
VOID **cmdline_out,
|
||||
UINT32 *cmdline_len_out ) {
|
||||
char *uri;
|
||||
size_t uri_len;
|
||||
FILEPATH_DEVICE_PATH *devpath;
|
||||
EFI_DEVICE_PATH *endpath;
|
||||
size_t devpath_len;
|
||||
CHAR16 *cmdline = NULL;
|
||||
UINT32 cmdline_len;
|
||||
size_t args_len = 0;
|
||||
UINT32 i;
|
||||
|
||||
/* Get the URI string of the image */
|
||||
uri_len = unparse_uri ( NULL, 0, image->uri, URI_ALL ) + 1;
|
||||
|
||||
/* Compute final command line length */
|
||||
if ( image->cmdline != NULL ) {
|
||||
args_len = strlen ( image->cmdline ) + 1;
|
||||
}
|
||||
cmdline_len = args_len + uri_len;
|
||||
|
||||
/* Allocate space for the uri, final command line and device path */
|
||||
cmdline = malloc ( cmdline_len * sizeof ( CHAR16 ) + uri_len
|
||||
+ SIZE_OF_FILEPATH_DEVICE_PATH
|
||||
+ uri_len * sizeof ( CHAR16 )
|
||||
+ sizeof ( EFI_DEVICE_PATH ) );
|
||||
if ( cmdline == NULL ) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
uri = (char *) ( cmdline + cmdline_len );
|
||||
devpath = (FILEPATH_DEVICE_PATH *) ( uri + uri_len );
|
||||
endpath = (EFI_DEVICE_PATH *) ( (char *) devpath
|
||||
+ SIZE_OF_FILEPATH_DEVICE_PATH
|
||||
+ uri_len * sizeof ( CHAR16 ) );
|
||||
|
||||
/* Build the gPXE device path */
|
||||
devpath->Header.Type = MEDIA_DEVICE_PATH;
|
||||
devpath->Header.SubType = MEDIA_FILEPATH_DP;
|
||||
devpath_len = SIZE_OF_FILEPATH_DEVICE_PATH
|
||||
+ uri_len * sizeof ( CHAR16 );
|
||||
devpath->Header.Length[0] = devpath_len & 0xFF;
|
||||
devpath->Header.Length[1] = devpath_len >> 8;
|
||||
endpath->Type = END_DEVICE_PATH_TYPE;
|
||||
endpath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
|
||||
endpath->Length[0] = 4;
|
||||
endpath->Length[1] = 0;
|
||||
unparse_uri ( uri, uri_len, image->uri, URI_ALL );
|
||||
|
||||
/* Convert to Unicode */
|
||||
for ( i = 0; i < uri_len; i++ ) {
|
||||
cmdline[i] = uri[i];
|
||||
devpath->PathName[i] = uri[i];
|
||||
}
|
||||
if ( image->cmdline ) {
|
||||
cmdline[uri_len - 1] = ' ';
|
||||
}
|
||||
for ( i = 0; i < args_len; i++ ) {
|
||||
cmdline[i + uri_len] = image->cmdline[i];
|
||||
}
|
||||
|
||||
*devpath_out = &devpath->Header;
|
||||
*cmdline_out = cmdline;
|
||||
*cmdline_len_out = cmdline_len * sizeof ( CHAR16 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute EFI image
|
||||
*
|
||||
@@ -34,7 +118,10 @@ FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 );
|
||||
*/
|
||||
static int efi_image_exec ( struct image *image ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
EFI_LOADED_IMAGE_PROTOCOL *loaded_image = NULL;
|
||||
void *loaded_image_void;
|
||||
EFI_HANDLE handle;
|
||||
EFI_HANDLE device_handle = NULL;
|
||||
UINTN exit_data_size;
|
||||
CHAR16 *exit_data;
|
||||
EFI_STATUS efirc;
|
||||
@@ -50,6 +137,23 @@ static int efi_image_exec ( struct image *image ) {
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* Get the loaded image protocol for the newly loaded image */
|
||||
efirc = bs->OpenProtocol ( handle, &efi_loaded_image_protocol_guid,
|
||||
&loaded_image_void, efi_image_handle, NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL );
|
||||
if ( efirc ) {
|
||||
/* Should never happen */
|
||||
rc = EFIRC_TO_RC ( efirc );
|
||||
}
|
||||
loaded_image = loaded_image_void;
|
||||
|
||||
/* Pass an IPXE download protocol to the image */
|
||||
rc = efi_download_install ( &device_handle );
|
||||
loaded_image->DeviceHandle = device_handle;
|
||||
loaded_image->ParentHandle = efi_loaded_image;
|
||||
rc = efi_image_make_cmdline ( image, &loaded_image->FilePath,&loaded_image->LoadOptions,&loaded_image->LoadOptionsSize );
|
||||
|
||||
|
||||
/* Start the image */
|
||||
if ( ( efirc = bs->StartImage ( handle, &exit_data_size,
|
||||
&exit_data ) ) != 0 ) {
|
||||
@@ -57,6 +161,9 @@ static int efi_image_exec ( struct image *image ) {
|
||||
image, efi_strerror ( efirc ) );
|
||||
}
|
||||
rc = EFIRC_TO_RC ( efirc );
|
||||
if ( device_handle ) {
|
||||
efi_download_uninstall ( device_handle );
|
||||
}
|
||||
|
||||
/* Unload the image. We can't leave it loaded, because we
|
||||
* have no "unload" operation.
|
||||
|
||||
+7
-1
@@ -221,11 +221,17 @@ static const char *goto_label;
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int goto_find_label ( const char *line ) {
|
||||
size_t len = strlen ( goto_label );
|
||||
|
||||
if ( line[0] != ':' )
|
||||
return -ENOENT;
|
||||
if ( strcmp ( goto_label, &line[1] ) != 0 )
|
||||
|
||||
if ( strncmp ( goto_label, &line[1], len ) != 0 )
|
||||
return -ENOENT;
|
||||
|
||||
if ( line[ 1 + len ] && ! isspace ( line[ 1 + len ] ) )
|
||||
return -ENOENT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,19 @@ struct asn1_cursor {
|
||||
size_t len;
|
||||
};
|
||||
|
||||
/**
|
||||
* Invalidate ASN.1 object cursor
|
||||
*
|
||||
* @v cursor ASN.1 object cursor
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
asn1_invalidate_cursor ( struct asn1_cursor *cursor ) {
|
||||
cursor->len = 0;
|
||||
}
|
||||
|
||||
extern int asn1_enter ( struct asn1_cursor *cursor, unsigned int type );
|
||||
extern int asn1_skip_if_exists ( struct asn1_cursor *cursor,
|
||||
unsigned int type );
|
||||
extern int asn1_skip ( struct asn1_cursor *cursor, unsigned int type );
|
||||
|
||||
#endif /* _IPXE_ASN1_H */
|
||||
|
||||
@@ -660,15 +660,18 @@ struct dhcphdr {
|
||||
/** Setting block name used for BootServerDHCP responses */
|
||||
#define PXEBS_SETTINGS_NAME "pxebs"
|
||||
|
||||
extern uint32_t dhcp_last_xid;
|
||||
extern unsigned int dhcp_chaddr ( struct net_device *netdev, void *chaddr,
|
||||
uint16_t *flags );
|
||||
extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
|
||||
struct net_device *netdev, uint8_t msgtype,
|
||||
const void *options, size_t options_len,
|
||||
void *data, size_t max_len );
|
||||
uint32_t xid, const void *options,
|
||||
size_t options_len, void *data,
|
||||
size_t max_len );
|
||||
extern int dhcp_create_request ( struct dhcp_packet *dhcppkt,
|
||||
struct net_device *netdev,
|
||||
unsigned int msgtype, struct in_addr ciaddr,
|
||||
unsigned int msgtype, uint32_t xid,
|
||||
struct in_addr ciaddr,
|
||||
void *data, size_t max_len );
|
||||
extern int start_dhcp ( struct interface *job, struct net_device *netdev );
|
||||
extern int start_pxebs ( struct interface *job, struct net_device *netdev,
|
||||
|
||||
@@ -142,5 +142,8 @@ extern EFI_SYSTEM_TABLE *efi_systab;
|
||||
extern const char * efi_strerror ( EFI_STATUS efirc );
|
||||
extern EFI_STATUS efi_init ( EFI_HANDLE image_handle,
|
||||
EFI_SYSTEM_TABLE *systab );
|
||||
extern int efi_download_install ( EFI_HANDLE *device_handle );
|
||||
extern void efi_download_uninstall ( EFI_HANDLE device_handle );
|
||||
|
||||
|
||||
#endif /* _IPXE_EFI_H */
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2010 VMware, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef IPXE_DOWNLOAD_H
|
||||
#define IPXE_DOWNLOAD_H
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* gPXE Download Protocol
|
||||
*
|
||||
* EFI applications started by gPXE may use this interface to download files.
|
||||
*/
|
||||
|
||||
typedef struct _IPXE_DOWNLOAD_PROTOCOL IPXE_DOWNLOAD_PROTOCOL;
|
||||
|
||||
/** Token to represent a currently downloading file */
|
||||
typedef VOID *IPXE_DOWNLOAD_FILE;
|
||||
|
||||
/**
|
||||
* Callback function that is invoked when data arrives for a particular file.
|
||||
*
|
||||
* Not all protocols will deliver data in order. Clients should not rely on the
|
||||
* order of data delivery matching the order in the file.
|
||||
*
|
||||
* Some protocols are capable of determining the file size near the beginning
|
||||
* of data transfer. To allow the client to allocate memory more efficiently,
|
||||
* gPXE may give a hint about the file size by calling the Data callback with
|
||||
* a zero BufferLength and the file size in FileOffset. Clients should be
|
||||
* prepared to deal with more or less data than the hint actually arriving.
|
||||
*
|
||||
* @v Context Context provided to the Start function
|
||||
* @v Buffer New data
|
||||
* @v BufferLength Length of new data in bytes
|
||||
* @v FileOffset Offset of new data in the file
|
||||
* @ret Status EFI_SUCCESS to continue the download,
|
||||
* or any error code to abort.
|
||||
*/
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(EFIAPI *IPXE_DOWNLOAD_DATA_CALLBACK)(
|
||||
IN VOID *Context,
|
||||
IN VOID *Buffer,
|
||||
IN UINTN BufferLength,
|
||||
IN UINTN FileOffset
|
||||
);
|
||||
|
||||
/**
|
||||
* Callback function that is invoked when the file is finished downloading, or
|
||||
* when a connection unexpectedly closes or times out.
|
||||
*
|
||||
* The finish callback is also called when a download is aborted by the Abort
|
||||
* function (below).
|
||||
*
|
||||
* @v Context Context provided to the Start function
|
||||
* @v Status Reason for termination: EFI_SUCCESS when the entire
|
||||
* file was transferred successfully, or an error
|
||||
* otherwise
|
||||
*/
|
||||
typedef
|
||||
void
|
||||
(EFIAPI *IPXE_DOWNLOAD_FINISH_CALLBACK)(
|
||||
IN VOID *Context,
|
||||
IN EFI_STATUS Status
|
||||
);
|
||||
|
||||
/**
|
||||
* Start downloading a file, and register callback functions to handle the
|
||||
* download.
|
||||
*
|
||||
* @v This gPXE Download Protocol instance
|
||||
* @v Url URL to download from
|
||||
* @v DataCallback Callback that will be invoked when data arrives
|
||||
* @v FinishCallback Callback that will be invoked when the download ends
|
||||
* @v Context Context passed to the Data and Finish callbacks
|
||||
* @v File Token that can be used to abort the download
|
||||
* @ret Status EFI status code
|
||||
*/
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(EFIAPI *IPXE_DOWNLOAD_START)(
|
||||
IN IPXE_DOWNLOAD_PROTOCOL *This,
|
||||
IN CHAR8 *Url,
|
||||
IN IPXE_DOWNLOAD_DATA_CALLBACK DataCallback,
|
||||
IN IPXE_DOWNLOAD_FINISH_CALLBACK FinishCallback,
|
||||
IN VOID *Context,
|
||||
OUT IPXE_DOWNLOAD_FILE *File
|
||||
);
|
||||
|
||||
/**
|
||||
* Forcibly abort downloading a file that is currently in progress.
|
||||
*
|
||||
* It is not safe to call this function after the Finish callback has executed.
|
||||
*
|
||||
* @v This gPXE Download Protocol instance
|
||||
* @v File Token obtained from Start
|
||||
* @v Status Reason for aborting the download
|
||||
* @ret Status EFI status code
|
||||
*/
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(EFIAPI *IPXE_DOWNLOAD_ABORT)(
|
||||
IN IPXE_DOWNLOAD_PROTOCOL *This,
|
||||
IN IPXE_DOWNLOAD_FILE File,
|
||||
IN EFI_STATUS Status
|
||||
);
|
||||
|
||||
/**
|
||||
* Poll for more data from gPXE. This function will invoke the registered
|
||||
* callbacks if data is available or if downloads complete.
|
||||
*
|
||||
* @v This gPXE Download Protocol instance
|
||||
* @ret Status EFI status code
|
||||
*/
|
||||
typedef
|
||||
EFI_STATUS
|
||||
(EFIAPI *IPXE_DOWNLOAD_POLL)(
|
||||
IN IPXE_DOWNLOAD_PROTOCOL *This
|
||||
);
|
||||
|
||||
/**
|
||||
* The gPXE Download Protocol.
|
||||
*
|
||||
* gPXE will attach a gPXE Download Protocol to the DeviceHandle in the Loaded
|
||||
* Image Protocol of all child EFI applications.
|
||||
*/
|
||||
struct _IPXE_DOWNLOAD_PROTOCOL {
|
||||
IPXE_DOWNLOAD_START Start;
|
||||
IPXE_DOWNLOAD_ABORT Abort;
|
||||
IPXE_DOWNLOAD_POLL Poll;
|
||||
};
|
||||
|
||||
#define IPXE_DOWNLOAD_PROTOCOL_GUID \
|
||||
{ \
|
||||
0x3eaeaebd, 0xdecf, 0x493b, { 0x9b, 0xd1, 0xcd, 0xb2, 0xde, 0xca, 0xe7, 0x19 } \
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -432,6 +432,9 @@ struct net_driver {
|
||||
/** Bus ID setting tag */
|
||||
#define NETDEV_SETTING_TAG_BUS_ID NETDEV_SETTING_TAG ( 0x02 )
|
||||
|
||||
/** MAC address setting tag */
|
||||
#define NETDEV_SETTING_TAG_MACHYP NETDEV_SETTING_TAG ( 0x03 )
|
||||
|
||||
extern struct list_head net_devices;
|
||||
extern struct net_device_operations null_netdev_operations;
|
||||
extern struct settings_operations netdev_settings_operations;
|
||||
|
||||
@@ -308,6 +308,16 @@ struct tcp_options {
|
||||
*/
|
||||
#define TCP_MSL ( 2 * 60 * TICKS_PER_SEC )
|
||||
|
||||
/**
|
||||
* TCP maximum header length
|
||||
*
|
||||
*/
|
||||
#define TCP_MAX_HEADER_LEN \
|
||||
( MAX_LL_NET_HEADER_LEN + \
|
||||
sizeof ( struct tcp_header ) + \
|
||||
sizeof ( struct tcp_mss_option ) + \
|
||||
sizeof ( struct tcp_timestamp_padded_option ) )
|
||||
|
||||
/**
|
||||
* Compare TCP sequence numbers
|
||||
*
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (C) 2010 VMware, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ipxe/open.h>
|
||||
#include <ipxe/process.h>
|
||||
#include <ipxe/iobuf.h>
|
||||
#include <ipxe/xfer.h>
|
||||
#include <ipxe/efi/efi.h>
|
||||
#include <ipxe/efi/ipxe_download.h>
|
||||
|
||||
/** gPXE download protocol GUID */
|
||||
static EFI_GUID ipxe_download_protocol_guid
|
||||
= IPXE_DOWNLOAD_PROTOCOL_GUID;
|
||||
|
||||
/** A single in-progress file */
|
||||
struct efi_download_file {
|
||||
/** Data transfer interface that provides downloaded data */
|
||||
struct interface xfer;
|
||||
|
||||
/** Current file position */
|
||||
size_t pos;
|
||||
|
||||
/** Data callback */
|
||||
IPXE_DOWNLOAD_DATA_CALLBACK data_callback;
|
||||
|
||||
/** Finish callback */
|
||||
IPXE_DOWNLOAD_FINISH_CALLBACK finish_callback;
|
||||
|
||||
/** Callback context */
|
||||
void *context;
|
||||
};
|
||||
|
||||
/* xfer interface */
|
||||
|
||||
/**
|
||||
* Transfer finished or was aborted
|
||||
*
|
||||
* @v file Data transfer file
|
||||
* @v rc Reason for close
|
||||
*/
|
||||
static void efi_download_close ( struct efi_download_file *file, int rc ) {
|
||||
|
||||
file->finish_callback ( file->context, RC_TO_EFIRC ( rc ) );
|
||||
|
||||
intf_shutdown ( &file->xfer, rc );
|
||||
}
|
||||
|
||||
/**
|
||||
* Process received data
|
||||
*
|
||||
* @v file Data transfer file
|
||||
* @v iobuf I/O buffer
|
||||
* @v meta Data transfer metadata
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int efi_download_deliver_iob ( struct efi_download_file *file,
|
||||
struct io_buffer *iobuf,
|
||||
struct xfer_metadata *meta ) {
|
||||
EFI_STATUS efirc;
|
||||
size_t len = iob_len ( iobuf );
|
||||
|
||||
/* Calculate new buffer position */
|
||||
if ( meta->flags & XFER_FL_ABS_OFFSET )
|
||||
file->pos = 0;
|
||||
file->pos += meta->offset;
|
||||
|
||||
/* Call out to the data handler */
|
||||
efirc = file->data_callback ( file->context, iobuf->data,
|
||||
len, file->pos );
|
||||
|
||||
/* Update current buffer position */
|
||||
file->pos += len;
|
||||
|
||||
free_iob ( iobuf );
|
||||
return EFIRC_TO_RC ( efirc );
|
||||
}
|
||||
|
||||
/** Data transfer interface operations */
|
||||
static struct interface_operation efi_xfer_operations[] = {
|
||||
INTF_OP ( xfer_deliver, struct efi_download_file *, efi_download_deliver_iob ),
|
||||
INTF_OP ( intf_close, struct efi_download_file *, efi_download_close ),
|
||||
};
|
||||
|
||||
/** EFI download data transfer interface descriptor */
|
||||
static struct interface_descriptor efi_download_file_xfer_desc =
|
||||
INTF_DESC ( struct efi_download_file, xfer, efi_xfer_operations );
|
||||
|
||||
/**
|
||||
* Start downloading a file, and register callback functions to handle the
|
||||
* download.
|
||||
*
|
||||
* @v This gPXE Download Protocol instance
|
||||
* @v Url URL to download from
|
||||
* @v DataCallback Callback that will be invoked when data arrives
|
||||
* @v FinishCallback Callback that will be invoked when the download ends
|
||||
* @v Context Context passed to the Data and Finish callbacks
|
||||
* @v File Token that can be used to abort the download
|
||||
* @ret Status EFI status code
|
||||
*/
|
||||
static EFI_STATUS EFIAPI
|
||||
efi_download_start ( IPXE_DOWNLOAD_PROTOCOL *This __unused,
|
||||
CHAR8 *Url,
|
||||
IPXE_DOWNLOAD_DATA_CALLBACK DataCallback,
|
||||
IPXE_DOWNLOAD_FINISH_CALLBACK FinishCallback,
|
||||
VOID *Context,
|
||||
IPXE_DOWNLOAD_FILE *File ) {
|
||||
struct efi_download_file *file;
|
||||
int rc;
|
||||
|
||||
file = malloc ( sizeof ( struct efi_download_file ) );
|
||||
if ( file == NULL ) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
intf_init ( &file->xfer, &efi_download_file_xfer_desc, NULL );
|
||||
rc = xfer_open ( &file->xfer, LOCATION_URI_STRING, Url );
|
||||
if ( rc ) {
|
||||
free ( file );
|
||||
return RC_TO_EFIRC ( rc );
|
||||
}
|
||||
|
||||
file->pos = 0;
|
||||
file->data_callback = DataCallback;
|
||||
file->finish_callback = FinishCallback;
|
||||
file->context = Context;
|
||||
*File = file;
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forcibly abort downloading a file that is currently in progress.
|
||||
*
|
||||
* It is not safe to call this function after the Finish callback has executed.
|
||||
*
|
||||
* @v This gPXE Download Protocol instance
|
||||
* @v File Token obtained from Start
|
||||
* @v Status Reason for aborting the download
|
||||
* @ret Status EFI status code
|
||||
*/
|
||||
static EFI_STATUS EFIAPI
|
||||
efi_download_abort ( IPXE_DOWNLOAD_PROTOCOL *This __unused,
|
||||
IPXE_DOWNLOAD_FILE File,
|
||||
EFI_STATUS Status ) {
|
||||
struct efi_download_file *file = File;
|
||||
|
||||
efi_download_close ( file, EFIRC_TO_RC ( Status ) );
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll for more data from gPXE. This function will invoke the registered
|
||||
* callbacks if data is available or if downloads complete.
|
||||
*
|
||||
* @v This gPXE Download Protocol instance
|
||||
* @ret Status EFI status code
|
||||
*/
|
||||
static EFI_STATUS EFIAPI
|
||||
efi_download_poll ( IPXE_DOWNLOAD_PROTOCOL *This __unused ) {
|
||||
step();
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/** Publicly exposed gPXE download protocol */
|
||||
static IPXE_DOWNLOAD_PROTOCOL ipxe_download_protocol_interface = {
|
||||
.Start = efi_download_start,
|
||||
.Abort = efi_download_abort,
|
||||
.Poll = efi_download_poll
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new device handle with a gPXE download protocol attached to it.
|
||||
*
|
||||
* @v device_handle Newly created device handle (output)
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int efi_download_install ( EFI_HANDLE *device_handle ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
EFI_STATUS efirc;
|
||||
EFI_HANDLE handle = NULL;
|
||||
if (efi_loaded_image->DeviceHandle) { /* TODO: ensure handle is the NIC (maybe efi_image has a better way to indicate the handle doing SNP?) */
|
||||
handle = efi_loaded_image->DeviceHandle;
|
||||
}
|
||||
|
||||
|
||||
|
||||
DBG ( "Installing ipxe protocol interface (%p)... ",
|
||||
&ipxe_download_protocol_interface );
|
||||
efirc = bs->InstallMultipleProtocolInterfaces (
|
||||
&handle,
|
||||
&ipxe_download_protocol_guid,
|
||||
&ipxe_download_protocol_interface,
|
||||
NULL );
|
||||
if ( efirc ) {
|
||||
DBG ( "failed (%s)\n", efi_strerror ( efirc ) );
|
||||
return EFIRC_TO_RC ( efirc );
|
||||
}
|
||||
|
||||
DBG ( "success (%p)\n", handle );
|
||||
*device_handle = handle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the gPXE download protocol from the given handle, and if nothing
|
||||
* else is attached, destroy the handle.
|
||||
*
|
||||
* @v device_handle EFI device handle to remove from
|
||||
*/
|
||||
void efi_download_uninstall ( EFI_HANDLE device_handle ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
|
||||
bs->UninstallMultipleProtocolInterfaces (
|
||||
device_handle,
|
||||
ipxe_download_protocol_guid,
|
||||
ipxe_download_protocol_interface );
|
||||
}
|
||||
+6
-3
@@ -114,7 +114,8 @@ int create_fakedhcpdiscover ( struct net_device *netdev,
|
||||
int rc;
|
||||
|
||||
if ( ( rc = dhcp_create_request ( &dhcppkt, netdev, DHCPDISCOVER,
|
||||
ciaddr, data, max_len ) ) != 0 ) {
|
||||
dhcp_last_xid, ciaddr, data,
|
||||
max_len ) ) != 0 ) {
|
||||
DBG ( "Could not create DHCPDISCOVER: %s\n",
|
||||
strerror ( rc ) );
|
||||
return rc;
|
||||
@@ -139,7 +140,8 @@ int create_fakedhcpack ( struct net_device *netdev,
|
||||
int rc;
|
||||
|
||||
/* Create base DHCPACK packet */
|
||||
if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL, 0,
|
||||
if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK,
|
||||
dhcp_last_xid, NULL, 0,
|
||||
data, max_len ) ) != 0 ) {
|
||||
DBG ( "Could not create DHCPACK: %s\n", strerror ( rc ) );
|
||||
return rc;
|
||||
@@ -190,7 +192,8 @@ int create_fakepxebsack ( struct net_device *netdev,
|
||||
}
|
||||
|
||||
/* Create base DHCPACK packet */
|
||||
if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK, NULL, 0,
|
||||
if ( ( rc = dhcp_create_packet ( &dhcppkt, netdev, DHCPACK,
|
||||
dhcp_last_xid, NULL, 0,
|
||||
data, max_len ) ) != 0 ) {
|
||||
DBG ( "Could not create PXE BS ACK: %s\n",
|
||||
strerror ( rc ) );
|
||||
|
||||
@@ -44,7 +44,7 @@ struct setting machyp_setting __setting ( SETTING_NETDEV ) = {
|
||||
.name = "machyp",
|
||||
.description = "MAC address",
|
||||
.type = &setting_type_hexhyp,
|
||||
.tag = NETDEV_SETTING_TAG_MAC,
|
||||
.tag = NETDEV_SETTING_TAG_MACHYP,
|
||||
};
|
||||
struct setting busid_setting __setting ( SETTING_NETDEV ) = {
|
||||
.name = "busid",
|
||||
|
||||
+4
-4
@@ -509,14 +509,14 @@ static int tcp_xmit ( struct tcp_connection *tcp ) {
|
||||
start_timer ( &tcp->timer );
|
||||
|
||||
/* Allocate I/O buffer */
|
||||
iobuf = alloc_iob ( len + MAX_LL_NET_HEADER_LEN );
|
||||
iobuf = alloc_iob ( len + TCP_MAX_HEADER_LEN );
|
||||
if ( ! iobuf ) {
|
||||
DBGC ( tcp, "TCP %p could not allocate iobuf for %08x..%08x "
|
||||
"%08x\n", tcp, tcp->snd_seq, ( tcp->snd_seq + seq_len ),
|
||||
tcp->rcv_ack );
|
||||
return -ENOMEM;
|
||||
}
|
||||
iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
|
||||
iob_reserve ( iobuf, TCP_MAX_HEADER_LEN );
|
||||
|
||||
/* Fill data payload from transmit queue */
|
||||
tcp_process_tx_queue ( tcp, len, iobuf, 0 );
|
||||
@@ -653,14 +653,14 @@ static int tcp_xmit_reset ( struct tcp_connection *tcp,
|
||||
int rc;
|
||||
|
||||
/* Allocate space for dataless TX buffer */
|
||||
iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN );
|
||||
iobuf = alloc_iob ( TCP_MAX_HEADER_LEN );
|
||||
if ( ! iobuf ) {
|
||||
DBGC ( tcp, "TCP %p could not allocate iobuf for RST "
|
||||
"%08x..%08x %08x\n", tcp, ntohl ( in_tcphdr->ack ),
|
||||
ntohl ( in_tcphdr->ack ), ntohl ( in_tcphdr->seq ) );
|
||||
return -ENOMEM;
|
||||
}
|
||||
iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
|
||||
iob_reserve ( iobuf, TCP_MAX_HEADER_LEN );
|
||||
|
||||
/* Construct RST response */
|
||||
tcphdr = iob_push ( iobuf, sizeof ( *tcphdr ) );
|
||||
|
||||
+24
-23
@@ -116,6 +116,14 @@ struct setting use_cached_setting __setting ( SETTING_MISC ) = {
|
||||
.type = &setting_type_uint8,
|
||||
};
|
||||
|
||||
/**
|
||||
* Most recent DHCP transaction ID
|
||||
*
|
||||
* This is exposed for use by the fakedhcp code when reconstructing
|
||||
* DHCP packets for PXE NBPs.
|
||||
*/
|
||||
uint32_t dhcp_last_xid;
|
||||
|
||||
/**
|
||||
* Name a DHCP packet type
|
||||
*
|
||||
@@ -137,23 +145,6 @@ static inline const char * dhcp_msgtype_name ( unsigned int msgtype ) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate DHCP transaction ID for a network device
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @ret xid DHCP XID
|
||||
*
|
||||
* Extract the least significant bits of the hardware address for use
|
||||
* as the transaction ID.
|
||||
*/
|
||||
static uint32_t dhcp_xid ( struct net_device *netdev ) {
|
||||
uint32_t xid;
|
||||
|
||||
memcpy ( &xid, ( netdev->ll_addr + netdev->ll_protocol->ll_addr_len
|
||||
- sizeof ( xid ) ), sizeof ( xid ) );
|
||||
return xid;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* DHCP session
|
||||
@@ -219,6 +210,8 @@ struct dhcp_session {
|
||||
struct sockaddr_in local;
|
||||
/** State of the session */
|
||||
struct dhcp_session_state *state;
|
||||
/** Transaction ID (in network-endian order) */
|
||||
uint32_t xid;
|
||||
|
||||
/** Offered IP address */
|
||||
struct in_addr offer;
|
||||
@@ -916,6 +909,7 @@ unsigned int dhcp_chaddr ( struct net_device *netdev, void *chaddr,
|
||||
* @v dhcppkt DHCP packet structure to fill in
|
||||
* @v netdev Network device
|
||||
* @v msgtype DHCP message type
|
||||
* @v xid Transaction ID (in network-endian order)
|
||||
* @v options Initial options to include (or NULL)
|
||||
* @v options_len Length of initial options
|
||||
* @v data Buffer for DHCP packet
|
||||
@@ -927,7 +921,7 @@ unsigned int dhcp_chaddr ( struct net_device *netdev, void *chaddr,
|
||||
*/
|
||||
int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
|
||||
struct net_device *netdev, uint8_t msgtype,
|
||||
const void *options, size_t options_len,
|
||||
uint32_t xid, const void *options, size_t options_len,
|
||||
void *data, size_t max_len ) {
|
||||
struct dhcphdr *dhcphdr = data;
|
||||
int rc;
|
||||
@@ -938,7 +932,7 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
|
||||
|
||||
/* Initialise DHCP packet content */
|
||||
memset ( dhcphdr, 0, max_len );
|
||||
dhcphdr->xid = dhcp_xid ( netdev );
|
||||
dhcphdr->xid = xid;
|
||||
dhcphdr->magic = htonl ( DHCP_MAGIC_COOKIE );
|
||||
dhcphdr->htype = ntohs ( netdev->ll_protocol->ll_proto );
|
||||
dhcphdr->op = dhcp_op[msgtype];
|
||||
@@ -964,6 +958,7 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
|
||||
* @v dhcppkt DHCP packet structure to fill in
|
||||
* @v netdev Network device
|
||||
* @v msgtype DHCP message type
|
||||
* @v xid Transaction ID (in network-endian order)
|
||||
* @v ciaddr Client IP address
|
||||
* @v data Buffer for DHCP packet
|
||||
* @v max_len Size of DHCP packet buffer
|
||||
@@ -974,7 +969,8 @@ int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
|
||||
*/
|
||||
int dhcp_create_request ( struct dhcp_packet *dhcppkt,
|
||||
struct net_device *netdev, unsigned int msgtype,
|
||||
struct in_addr ciaddr, void *data, size_t max_len ) {
|
||||
uint32_t xid, struct in_addr ciaddr,
|
||||
void *data, size_t max_len ) {
|
||||
struct dhcp_netdev_desc dhcp_desc;
|
||||
struct dhcp_client_id client_id;
|
||||
struct dhcp_client_uuid client_uuid;
|
||||
@@ -985,7 +981,7 @@ int dhcp_create_request ( struct dhcp_packet *dhcppkt,
|
||||
int rc;
|
||||
|
||||
/* Create DHCP packet */
|
||||
if ( ( rc = dhcp_create_packet ( dhcppkt, netdev, msgtype,
|
||||
if ( ( rc = dhcp_create_packet ( dhcppkt, netdev, msgtype, xid,
|
||||
dhcp_request_options_data,
|
||||
sizeof ( dhcp_request_options_data ),
|
||||
data, max_len ) ) != 0 ) {
|
||||
@@ -1099,7 +1095,8 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) {
|
||||
|
||||
/* Create basic DHCP packet in temporary buffer */
|
||||
if ( ( rc = dhcp_create_request ( &dhcppkt, dhcp->netdev, msgtype,
|
||||
dhcp->local.sin_addr, iobuf->data,
|
||||
dhcp->xid, dhcp->local.sin_addr,
|
||||
iobuf->data,
|
||||
iob_tailroom ( iobuf ) ) ) != 0 ) {
|
||||
DBGC ( dhcp, "DHCP %p could not construct DHCP request: %s\n",
|
||||
dhcp, strerror ( rc ) );
|
||||
@@ -1187,7 +1184,7 @@ static int dhcp_deliver ( struct dhcp_session *dhcp,
|
||||
&server_id, sizeof ( server_id ) );
|
||||
|
||||
/* Check for matching transaction ID */
|
||||
if ( dhcphdr->xid != dhcp_xid ( dhcp->netdev ) ) {
|
||||
if ( dhcphdr->xid != dhcp->xid ) {
|
||||
DBGC ( dhcp, "DHCP %p %s from %s:%d has bad transaction "
|
||||
"ID\n", dhcp, dhcp_msgtype_name ( msgtype ),
|
||||
inet_ntoa ( peer->sin_addr ),
|
||||
@@ -1311,6 +1308,10 @@ int start_dhcp ( struct interface *job, struct net_device *netdev ) {
|
||||
dhcp->netdev = netdev_get ( netdev );
|
||||
dhcp->local.sin_family = AF_INET;
|
||||
dhcp->local.sin_port = htons ( BOOTPC_PORT );
|
||||
dhcp->xid = random();
|
||||
|
||||
/* Store DHCP transaction ID for fakedhcp code */
|
||||
dhcp_last_xid = dhcp->xid;
|
||||
|
||||
/* Instantiate child objects and attach to our interfaces */
|
||||
if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer,
|
||||
|
||||
Executable
+54
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use constant DEVICES => "/proc/bus/pci/devices";
|
||||
|
||||
open my $fh, DEVICES
|
||||
or die "Could not open ".DEVICES.": $!";
|
||||
|
||||
while ( ( my $line = <$fh> ) ) {
|
||||
|
||||
# Parse line from /proc/bus/pci/devices
|
||||
chomp $line;
|
||||
( my $bus, my $devfn, my $vendor, my $device, my $irq, my $bars, my $lengths,
|
||||
my $driver )
|
||||
= ( $line =~ /^ ([0-9a-f]{2}) ([0-9a-f]{2}) \s+
|
||||
([0-9a-f]{4}) ([0-9a-f]{4}) \s+ ([0-9a-f]+) \s+
|
||||
((?:[0-9a-f]+\s+){7}) ((?:[0-9a-f]+\s+){7})
|
||||
(.+)?$/x )
|
||||
or die "Invalid line \"".$line."\"\n";
|
||||
( $bus, $devfn, $vendor, $device, $irq ) =
|
||||
map { hex ( $_ ) } ( $bus, $devfn, $vendor, $device, $irq );
|
||||
my $dev = ( $devfn >> 3 );
|
||||
my $fn = ( $devfn & 0x7 );
|
||||
$bars = [ map { hex ( $_ ) } split ( /\s+/, $bars ) ];
|
||||
$lengths = [ map { hex ( $_ ) } split ( /\s+/, $lengths ) ];
|
||||
|
||||
# Calculate expansion ROM BAR presence and length
|
||||
my $rom_length = $lengths->[6];
|
||||
|
||||
# Look for a BAR that could support a .mrom
|
||||
my $mrom_ok;
|
||||
if ( $rom_length ) {
|
||||
for ( my $bar = 0 ; $bar < 7 ; $bar++ ) {
|
||||
# Skip I/O BARs
|
||||
next if $bars->[$bar] & 0x01;
|
||||
# Skip low half of 64-bit BARs
|
||||
$bar++ if $bars->[$bar] & 0x04;
|
||||
# Skip 64-bit BARs with high dword set
|
||||
next if $bars->[$bar] >> 32;
|
||||
# Skip BARs smaller than the expansion ROM BAR
|
||||
next if $lengths->[$bar] < $rom_length;
|
||||
# This BAR is usable!
|
||||
$mrom_ok = 1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
printf "%02x:%02x.%x (%04x:%04x)", $bus, $dev, $fn, $vendor, $device;
|
||||
printf " supports a %dkB .rom", ( $rom_length / 1024 ) if $rom_length;
|
||||
printf " or .mrom" if $mrom_ok;
|
||||
printf "\n";
|
||||
}
|
||||
Reference in New Issue
Block a user