mirror of https://github.com/ipxe/ipxe.git
Prepare for iBFT merge when possible. iscsiboot.c contains a really,
really ugly hack at present, but that doesn't hugely matter since I'm aiming to change the interface to iSCSI devices anyway within the next week.pull/1/head
parent
84c347c7de
commit
47a86bca2d
|
@ -115,6 +115,7 @@
|
||||||
#define ERRFILE_cipher ( ERRFILE_OTHER | 0x00090000 )
|
#define ERRFILE_cipher ( ERRFILE_OTHER | 0x00090000 )
|
||||||
#define ERRFILE_image_cmd ( ERRFILE_OTHER | 0x000a0000 )
|
#define ERRFILE_image_cmd ( ERRFILE_OTHER | 0x000a0000 )
|
||||||
#define ERRFILE_uri_test ( ERRFILE_OTHER | 0x000b0000 )
|
#define ERRFILE_uri_test ( ERRFILE_OTHER | 0x000b0000 )
|
||||||
|
#define ERRFILE_ibft ( ERRFILE_OTHER | 0x000c0000 )
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <gpxe/socket.h>
|
||||||
#include <gpxe/scsi.h>
|
#include <gpxe/scsi.h>
|
||||||
#include <gpxe/chap.h>
|
#include <gpxe/chap.h>
|
||||||
#include <gpxe/refcnt.h>
|
#include <gpxe/refcnt.h>
|
||||||
|
@ -501,6 +502,8 @@ struct iscsi_session {
|
||||||
char *target_iqn;
|
char *target_iqn;
|
||||||
/** Logical Unit Number (LUN) */
|
/** Logical Unit Number (LUN) */
|
||||||
uint64_t lun;
|
uint64_t lun;
|
||||||
|
/** Target socket address (recorded only for iBFT) */
|
||||||
|
struct sockaddr target_sockaddr;
|
||||||
|
|
||||||
/** Session status
|
/** Session status
|
||||||
*
|
*
|
||||||
|
@ -514,6 +517,11 @@ struct iscsi_session {
|
||||||
* Reset upon a successful connection.
|
* Reset upon a successful connection.
|
||||||
*/
|
*/
|
||||||
int retry_count;
|
int retry_count;
|
||||||
|
|
||||||
|
/** Username (if any) */
|
||||||
|
char *username;
|
||||||
|
/** Password (if any) */
|
||||||
|
char *password;
|
||||||
/** CHAP challenge/response */
|
/** CHAP challenge/response */
|
||||||
struct chap_challenge chap;
|
struct chap_challenge chap;
|
||||||
|
|
||||||
|
@ -641,5 +649,6 @@ struct iscsi_session {
|
||||||
|
|
||||||
extern int iscsi_attach ( struct scsi_device *scsi, const char *root_path );
|
extern int iscsi_attach ( struct scsi_device *scsi, const char *root_path );
|
||||||
extern void iscsi_detach ( struct scsi_device *scsi );
|
extern void iscsi_detach ( struct scsi_device *scsi );
|
||||||
|
extern const char * iscsi_initiator_iqn ( void );
|
||||||
|
|
||||||
#endif /* _GPXE_ISCSI_H */
|
#endif /* _GPXE_ISCSI_H */
|
||||||
|
|
|
@ -41,16 +41,16 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** iSCSI initiator name (explicitly specified) */
|
/** iSCSI initiator name (explicitly specified) */
|
||||||
char *iscsi_initiator_iqn;
|
static char *iscsi_explicit_initiator_iqn;
|
||||||
|
|
||||||
/** Default iSCSI initiator name (constructed from hostname) */
|
/** Default iSCSI initiator name (constructed from hostname) */
|
||||||
char *iscsi_default_initiator_iqn;
|
static char *iscsi_default_initiator_iqn;
|
||||||
|
|
||||||
/** iSCSI username */
|
/** iSCSI username */
|
||||||
char *iscsi_username;
|
static char *iscsi_username;
|
||||||
|
|
||||||
/** iSCSI password */
|
/** iSCSI password */
|
||||||
char *iscsi_password;
|
static char *iscsi_password;
|
||||||
|
|
||||||
static void iscsi_start_tx ( struct iscsi_session *iscsi );
|
static void iscsi_start_tx ( struct iscsi_session *iscsi );
|
||||||
static void iscsi_start_login ( struct iscsi_session *iscsi );
|
static void iscsi_start_login ( struct iscsi_session *iscsi );
|
||||||
|
@ -78,6 +78,8 @@ static void iscsi_free ( struct refcnt *refcnt ) {
|
||||||
|
|
||||||
free ( iscsi->target_address );
|
free ( iscsi->target_address );
|
||||||
free ( iscsi->target_iqn );
|
free ( iscsi->target_iqn );
|
||||||
|
free ( iscsi->username );
|
||||||
|
free ( iscsi->password );
|
||||||
chap_finish ( &iscsi->chap );
|
chap_finish ( &iscsi->chap );
|
||||||
iscsi_rx_buffered_data_done ( iscsi );
|
iscsi_rx_buffered_data_done ( iscsi );
|
||||||
free ( iscsi );
|
free ( iscsi );
|
||||||
|
@ -436,22 +438,16 @@ static int iscsi_tx_data_out ( struct iscsi_session *iscsi ) {
|
||||||
*/
|
*/
|
||||||
static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
|
static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
|
||||||
void *data, size_t len ) {
|
void *data, size_t len ) {
|
||||||
char *initiator_iqn;
|
|
||||||
unsigned int used = 0;
|
unsigned int used = 0;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
if ( iscsi->status & ISCSI_STATUS_STRINGS_SECURITY ) {
|
if ( iscsi->status & ISCSI_STATUS_STRINGS_SECURITY ) {
|
||||||
initiator_iqn = iscsi_initiator_iqn;
|
|
||||||
if ( ! initiator_iqn )
|
|
||||||
initiator_iqn = iscsi_default_initiator_iqn;
|
|
||||||
if ( ! initiator_iqn )
|
|
||||||
initiator_iqn = "iqn.2000-09.org.etherboot:UNKNOWN";
|
|
||||||
used += ssnprintf ( data + used, len - used,
|
used += ssnprintf ( data + used, len - used,
|
||||||
"InitiatorName=%s%c"
|
"InitiatorName=%s%c"
|
||||||
"TargetName=%s%c"
|
"TargetName=%s%c"
|
||||||
"SessionType=Normal%c"
|
"SessionType=Normal%c"
|
||||||
"AuthMethod=CHAP,None%c",
|
"AuthMethod=CHAP,None%c",
|
||||||
initiator_iqn, 0,
|
iscsi_initiator_iqn(), 0,
|
||||||
iscsi->target_iqn, 0, 0, 0 );
|
iscsi->target_iqn, 0, 0, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,10 +456,10 @@ static int iscsi_build_login_request_strings ( struct iscsi_session *iscsi,
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_RESPONSE ) &&
|
if ( ( iscsi->status & ISCSI_STATUS_STRINGS_CHAP_RESPONSE ) &&
|
||||||
iscsi_username ) {
|
iscsi->username ) {
|
||||||
used += ssnprintf ( data + used, len - used,
|
used += ssnprintf ( data + used, len - used,
|
||||||
"CHAP_N=%s%cCHAP_R=0x",
|
"CHAP_N=%s%cCHAP_R=0x",
|
||||||
iscsi_username, 0 );
|
iscsi->username, 0 );
|
||||||
for ( i = 0 ; i < iscsi->chap.response_len ; i++ ) {
|
for ( i = 0 ; i < iscsi->chap.response_len ; i++ ) {
|
||||||
used += ssnprintf ( data + used, len - used, "%02x",
|
used += ssnprintf ( data + used, len - used, "%02x",
|
||||||
iscsi->chap.response[i] );
|
iscsi->chap.response[i] );
|
||||||
|
@ -647,9 +643,9 @@ static int iscsi_handle_chap_i_value ( struct iscsi_session *iscsi,
|
||||||
* challenge.
|
* challenge.
|
||||||
*/
|
*/
|
||||||
chap_set_identifier ( &iscsi->chap, identifier );
|
chap_set_identifier ( &iscsi->chap, identifier );
|
||||||
if ( iscsi_password ) {
|
if ( iscsi->password ) {
|
||||||
chap_update ( &iscsi->chap, iscsi_password,
|
chap_update ( &iscsi->chap, iscsi->password,
|
||||||
strlen ( iscsi_password ) );
|
strlen ( iscsi->password ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1279,10 +1275,43 @@ static void iscsi_socket_close ( struct xfer_interface *socket, int rc ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle redirection event
|
||||||
|
*
|
||||||
|
* @v socket Transport layer interface
|
||||||
|
* @v type Location type
|
||||||
|
* @v args Remaining arguments depend upon location type
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static int iscsi_vredirect ( struct xfer_interface *socket, int type,
|
||||||
|
va_list args ) {
|
||||||
|
struct iscsi_session *iscsi =
|
||||||
|
container_of ( socket, struct iscsi_session, socket );
|
||||||
|
va_list tmp;
|
||||||
|
struct sockaddr *peer;
|
||||||
|
|
||||||
|
/* Intercept redirects to a LOCATION_SOCKET and record the IP
|
||||||
|
* address for the iBFT. This is a bit of a hack, but avoids
|
||||||
|
* inventing an ioctl()-style call to retrieve the socket
|
||||||
|
* address from a data-xfer interface.
|
||||||
|
*/
|
||||||
|
if ( type == LOCATION_SOCKET ) {
|
||||||
|
va_copy ( tmp, args );
|
||||||
|
( void ) va_arg ( tmp, int ); /* Discard "semantics" */
|
||||||
|
peer = va_arg ( tmp, struct sockaddr * );
|
||||||
|
memcpy ( &iscsi->target_sockaddr, peer,
|
||||||
|
sizeof ( iscsi->target_sockaddr ) );
|
||||||
|
va_end ( tmp );
|
||||||
|
}
|
||||||
|
|
||||||
|
return xfer_vopen ( socket, type, args );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** iSCSI socket operations */
|
/** iSCSI socket operations */
|
||||||
static struct xfer_interface_operations iscsi_socket_operations = {
|
static struct xfer_interface_operations iscsi_socket_operations = {
|
||||||
.close = iscsi_socket_close,
|
.close = iscsi_socket_close,
|
||||||
.vredirect = xfer_vopen,
|
.vredirect = iscsi_vredirect,
|
||||||
.seek = ignore_xfer_seek,
|
.seek = ignore_xfer_seek,
|
||||||
.window = unlimited_xfer_window,
|
.window = unlimited_xfer_window,
|
||||||
.alloc_iob = default_xfer_alloc_iob,
|
.alloc_iob = default_xfer_alloc_iob,
|
||||||
|
@ -1460,6 +1489,32 @@ static int iscsi_parse_root_path ( struct iscsi_session *iscsi,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set iSCSI authentication details
|
||||||
|
*
|
||||||
|
* @v iscsi iSCSI session
|
||||||
|
* @v username Username, if any
|
||||||
|
* @v password Password, if any
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static int iscsi_set_auth ( struct iscsi_session *iscsi,
|
||||||
|
const char *username, const char *password ) {
|
||||||
|
|
||||||
|
if ( username ) {
|
||||||
|
iscsi->username = strdup ( username );
|
||||||
|
if ( ! iscsi->username )
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( password ) {
|
||||||
|
iscsi->password = strdup ( password );
|
||||||
|
if ( ! iscsi->password )
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach iSCSI interface
|
* Attach iSCSI interface
|
||||||
*
|
*
|
||||||
|
@ -1482,6 +1537,10 @@ int iscsi_attach ( struct scsi_device *scsi, const char *root_path ) {
|
||||||
/* Parse root path */
|
/* Parse root path */
|
||||||
if ( ( rc = iscsi_parse_root_path ( iscsi, root_path ) ) != 0 )
|
if ( ( rc = iscsi_parse_root_path ( iscsi, root_path ) ) != 0 )
|
||||||
goto err;
|
goto err;
|
||||||
|
/* Set fields not specified by root path */
|
||||||
|
if ( ( rc = iscsi_set_auth ( iscsi, iscsi_username,
|
||||||
|
iscsi_password ) ) != 0 )
|
||||||
|
goto err;
|
||||||
|
|
||||||
/* Sanity checks */
|
/* Sanity checks */
|
||||||
if ( ! iscsi->target_address ) {
|
if ( ! iscsi->target_address ) {
|
||||||
|
@ -1533,7 +1592,7 @@ static int apply_dhcp_iscsi_string ( unsigned int tag,
|
||||||
/* Identify string and prefix */
|
/* Identify string and prefix */
|
||||||
switch ( tag ) {
|
switch ( tag ) {
|
||||||
case DHCP_ISCSI_INITIATOR_IQN:
|
case DHCP_ISCSI_INITIATOR_IQN:
|
||||||
string = &iscsi_initiator_iqn;
|
string = &iscsi_explicit_initiator_iqn;
|
||||||
break;
|
break;
|
||||||
case DHCP_EB_USERNAME:
|
case DHCP_EB_USERNAME:
|
||||||
string = &iscsi_username;
|
string = &iscsi_username;
|
||||||
|
@ -1584,3 +1643,24 @@ struct dhcp_option_applicator dhcp_iscsi_applicators[] __dhcp_applicator = {
|
||||||
.apply = apply_dhcp_iscsi_string,
|
.apply = apply_dhcp_iscsi_string,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* Initiator name
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get iSCSI initiator IQN
|
||||||
|
*
|
||||||
|
* @v iscsi iSCSI session
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
const char * iscsi_initiator_iqn ( void ) {
|
||||||
|
|
||||||
|
if ( iscsi_explicit_initiator_iqn )
|
||||||
|
return iscsi_explicit_initiator_iqn;
|
||||||
|
if ( iscsi_default_initiator_iqn )
|
||||||
|
return iscsi_default_initiator_iqn;
|
||||||
|
return "iqn.2000-09.org.etherboot:UNKNOWN";
|
||||||
|
}
|
||||||
|
|
|
@ -3,9 +3,27 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <gpxe/iscsi.h>
|
#include <gpxe/iscsi.h>
|
||||||
#include <gpxe/dhcp.h>
|
#include <gpxe/dhcp.h>
|
||||||
|
#include <gpxe/netdevice.h>
|
||||||
|
#include <gpxe/ibft.h>
|
||||||
#include <int13.h>
|
#include <int13.h>
|
||||||
#include <usr/iscsiboot.h>
|
#include <usr/iscsiboot.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Guess boot network device
|
||||||
|
*
|
||||||
|
* @ret netdev Boot network device
|
||||||
|
*/
|
||||||
|
static struct net_device * guess_boot_netdev ( void ) {
|
||||||
|
struct net_device *boot_netdev;
|
||||||
|
|
||||||
|
/* Just use the first network device */
|
||||||
|
for_each_netdev ( boot_netdev ) {
|
||||||
|
return boot_netdev;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int iscsiboot ( const char *root_path ) {
|
int iscsiboot ( const char *root_path ) {
|
||||||
struct scsi_device scsi;
|
struct scsi_device scsi;
|
||||||
struct int13_drive drive;
|
struct int13_drive drive;
|
||||||
|
@ -30,6 +48,12 @@ int iscsiboot ( const char *root_path ) {
|
||||||
drive.drive = find_global_dhcp_num_option ( DHCP_EB_BIOS_DRIVE );
|
drive.drive = find_global_dhcp_num_option ( DHCP_EB_BIOS_DRIVE );
|
||||||
drive.blockdev = &scsi.blockdev;
|
drive.blockdev = &scsi.blockdev;
|
||||||
|
|
||||||
|
/* FIXME: ugly, ugly hack */
|
||||||
|
struct net_device *netdev = guess_boot_netdev();
|
||||||
|
struct iscsi_session *iscsi =
|
||||||
|
container_of ( scsi.backend, struct iscsi_session, refcnt );
|
||||||
|
ibft_fill_data ( netdev, iscsi );
|
||||||
|
|
||||||
register_int13_drive ( &drive );
|
register_int13_drive ( &drive );
|
||||||
printf ( "Registered as BIOS drive %#02x\n", drive.drive );
|
printf ( "Registered as BIOS drive %#02x\n", drive.drive );
|
||||||
printf ( "Booting from BIOS drive %#02x\n", drive.drive );
|
printf ( "Booting from BIOS drive %#02x\n", drive.drive );
|
||||||
|
|
Loading…
Reference in New Issue