2
* Copyright Fen Systems Ltd. 2007. Portions of this code are derived
3
* from IBM Corporation Sample Programs. Copyright IBM Corporation
4
* 2004, 2007. All rights reserved.
6
* Permission is hereby granted, free of charge, to any person
7
* obtaining a copy of this software and associated documentation
8
* files (the "Software"), to deal in the Software without
9
* restriction, including without limitation the rights to use, copy,
10
* modify, merge, publish, distribute, sublicense, and/or sell copies
11
* of the Software, and to permit persons to whom the Software is
12
* furnished to do so, subject to the following conditions:
14
* The above copyright notice and this permission notice shall be
15
* included in all copies or substantial portions of the Software.
17
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
FILE_LICENCE ( BSD2 );
36
#include <ipxe/acpi.h>
38
#include <ipxe/netdevice.h>
39
#include <ipxe/ethernet.h>
40
#include <ipxe/vlan.h>
41
#include <ipxe/dhcp.h>
42
#include <ipxe/iscsi.h>
43
#include <ipxe/ibft.h>
47
* iSCSI boot firmware table
49
* The information in this file is derived from the document "iSCSI
50
* Boot Firmware Table (iBFT)" as published by IBM at
52
* ftp://ftp.software.ibm.com/systems/support/system_x_pdf/ibm_iscsi_boot_firmware_table_v1.02.pdf
57
* An iBFT created by iPXE
61
/** The fixed section */
62
struct ibft_table table;
63
/** The Initiator section */
64
struct ibft_initiator initiator __attribute__ (( aligned ( 16 ) ));
65
/** The NIC section */
66
struct ibft_nic nic __attribute__ (( aligned ( 16 ) ));
67
/** The Target section */
68
struct ibft_target target __attribute__ (( aligned ( 16 ) ));
71
} __attribute__ (( packed, aligned ( 16 ) ));
74
* iSCSI string block descriptor
76
* This is an internal structure that we use to keep track of the
77
* allocation of string data.
80
/** The iBFT containing these strings */
81
struct ibft_table *table;
82
/** Offset of first free byte within iBFT */
84
/** Total length of the iBFT */
89
* Fill in an IP address field within iBFT
91
* @v ipaddr IP address field
94
static void ibft_set_ipaddr ( struct ibft_ipaddr *ipaddr, struct in_addr in ) {
95
memset ( ipaddr, 0, sizeof ( *ipaddr ) );
98
ipaddr->ones = 0xffff;
103
* Fill in an IP address within iBFT from configuration setting
105
* @v settings Parent settings block, or NULL
106
* @v ipaddr IP address field
107
* @v setting Configuration setting
108
* @v count Maximum number of IP addresses
110
static void ibft_set_ipaddr_setting ( struct settings *settings,
111
struct ibft_ipaddr *ipaddr,
112
const struct setting *setting,
113
unsigned int count ) {
114
struct in_addr in[count];
117
fetch_ipv4_array_setting ( settings, setting, in, count );
118
for ( i = 0 ; i < count ; i++ ) {
119
ibft_set_ipaddr ( &ipaddr[i], in[i] );
124
* Read IP address from iBFT (for debugging)
126
* @v strings iBFT string block descriptor
127
* @v string String field
128
* @ret ipaddr IP address string
130
static const char * ibft_ipaddr ( struct ibft_ipaddr *ipaddr ) {
131
return inet_ntoa ( ipaddr->in );
135
* Allocate a string within iBFT
137
* @v strings iBFT string block descriptor
138
* @v string String field to fill in
139
* @v len Length of string to allocate (excluding NUL)
140
* @ret dest String destination, or NULL
142
static char * ibft_alloc_string ( struct ibft_strings *strings,
143
struct ibft_string *string, size_t len ) {
145
if ( ( strings->offset + len ) >= strings->len )
148
string->offset = cpu_to_le16 ( strings->offset );
149
string->len = cpu_to_le16 ( len );
150
strings->offset += ( len + 1 );
152
return ( ( ( char * ) strings->table ) + string->offset );
156
* Fill in a string field within iBFT
158
* @v strings iBFT string block descriptor
159
* @v string String field
160
* @v data String to fill in, or NULL
161
* @ret rc Return status code
163
static int ibft_set_string ( struct ibft_strings *strings,
164
struct ibft_string *string, const char *data ) {
170
dest = ibft_alloc_string ( strings, string, strlen ( data ) );
173
strcpy ( dest, data );
179
* Fill in a string field within iBFT from configuration setting
181
* @v settings Parent settings block, or NULL
182
* @v strings iBFT string block descriptor
183
* @v string String field
184
* @v setting Configuration setting
185
* @ret rc Return status code
187
static int ibft_set_string_setting ( struct settings *settings,
188
struct ibft_strings *strings,
189
struct ibft_string *string,
190
const struct setting *setting ) {
191
struct settings *origin;
192
struct setting fetched;
196
len = fetch_setting ( settings, setting, &origin, &fetched, NULL, 0 );
203
dest = ibft_alloc_string ( strings, string, len );
206
fetch_string_setting ( origin, &fetched, dest, ( len + 1 ));
212
* Read string from iBFT (for debugging)
214
* @v strings iBFT string block descriptor
215
* @v string String field
216
* @ret data String content (or "<empty>")
218
static const char * ibft_string ( struct ibft_strings *strings,
219
struct ibft_string *string ) {
220
return ( string->offset ?
221
( ( ( char * ) strings->table ) + string->offset ) : NULL );
225
* Fill in NIC portion of iBFT
227
* @v nic NIC portion of iBFT
228
* @v strings iBFT string block descriptor
229
* @v netdev Network device
230
* @ret rc Return status code
232
static int ibft_fill_nic ( struct ibft_nic *nic,
233
struct ibft_strings *strings,
234
struct net_device *netdev ) {
235
struct ll_protocol *ll_protocol = netdev->ll_protocol;
236
struct in_addr netmask_addr = { 0 };
237
unsigned int netmask_count = 0;
238
struct settings *parent = netdev_settings ( netdev );
239
struct settings *origin;
242
/* Fill in common header */
243
nic->header.structure_id = IBFT_STRUCTURE_ID_NIC;
244
nic->header.version = 1;
245
nic->header.length = cpu_to_le16 ( sizeof ( *nic ) );
246
nic->header.flags = ( IBFT_FL_NIC_BLOCK_VALID |
247
IBFT_FL_NIC_FIRMWARE_BOOT_SELECTED );
249
/* Determine origin of IP address */
250
fetch_setting ( parent, &ip_setting, &origin, NULL, NULL, 0 );
251
nic->origin = ( ( origin == parent ) ?
252
IBFT_NIC_ORIGIN_MANUAL : IBFT_NIC_ORIGIN_DHCP );
253
DBG ( "iBFT NIC origin = %d\n", nic->origin );
255
/* Extract values from configuration settings */
256
ibft_set_ipaddr_setting ( parent, &nic->ip_address, &ip_setting, 1 );
257
DBG ( "iBFT NIC IP = %s\n", ibft_ipaddr ( &nic->ip_address ) );
258
ibft_set_ipaddr_setting ( parent, &nic->gateway, &gateway_setting, 1 );
259
DBG ( "iBFT NIC gateway = %s\n", ibft_ipaddr ( &nic->gateway ) );
260
ibft_set_ipaddr_setting ( NULL, &nic->dns[0], &dns_setting,
261
( sizeof ( nic->dns ) /
262
sizeof ( nic->dns[0] ) ) );
263
ibft_set_ipaddr_setting ( parent, &nic->dhcp, &dhcp_server_setting, 1 );
264
DBG ( "iBFT NIC DNS = %s", ibft_ipaddr ( &nic->dns[0] ) );
265
DBG ( ", %s\n", ibft_ipaddr ( &nic->dns[1] ) );
266
if ( ( rc = ibft_set_string_setting ( NULL, strings, &nic->hostname,
267
&hostname_setting ) ) != 0 )
269
DBG ( "iBFT NIC hostname = %s\n",
270
ibft_string ( strings, &nic->hostname ) );
272
/* Derive subnet mask prefix from subnet mask */
273
fetch_ipv4_setting ( parent, &netmask_setting, &netmask_addr );
274
while ( netmask_addr.s_addr ) {
275
if ( netmask_addr.s_addr & 0x1 )
277
netmask_addr.s_addr >>= 1;
279
nic->subnet_mask_prefix = netmask_count;
280
DBG ( "iBFT NIC subnet = /%d\n", nic->subnet_mask_prefix );
282
/* Extract values from net-device configuration */
283
nic->vlan = cpu_to_le16 ( vlan_tag ( netdev ) );
284
DBG ( "iBFT NIC VLAN = %02x\n", le16_to_cpu ( nic->vlan ) );
285
if ( ( rc = ll_protocol->eth_addr ( netdev->ll_addr,
286
nic->mac_address ) ) != 0 ) {
287
DBG ( "Could not determine iBFT MAC: %s\n", strerror ( rc ) );
290
DBG ( "iBFT NIC MAC = %s\n", eth_ntoa ( nic->mac_address ) );
291
nic->pci_bus_dev_func = cpu_to_le16 ( netdev->dev->desc.location );
292
DBG ( "iBFT NIC PCI = %04x\n", le16_to_cpu ( nic->pci_bus_dev_func ) );
298
* Fill in Initiator portion of iBFT
300
* @v initiator Initiator portion of iBFT
301
* @v strings iBFT string block descriptor
302
* @v iscsi iSCSI session
303
* @ret rc Return status code
305
static int ibft_fill_initiator ( struct ibft_initiator *initiator,
306
struct ibft_strings *strings,
307
struct iscsi_session *iscsi ) {
310
/* Fill in common header */
311
initiator->header.structure_id = IBFT_STRUCTURE_ID_INITIATOR;
312
initiator->header.version = 1;
313
initiator->header.length = cpu_to_le16 ( sizeof ( *initiator ) );
314
initiator->header.flags = ( IBFT_FL_INITIATOR_BLOCK_VALID |
315
IBFT_FL_INITIATOR_FIRMWARE_BOOT_SELECTED );
317
/* Fill in hostname */
318
if ( ( rc = ibft_set_string ( strings, &initiator->initiator_name,
319
iscsi->initiator_iqn ) ) != 0 )
321
DBG ( "iBFT initiator hostname = %s\n",
322
ibft_string ( strings, &initiator->initiator_name ) );
328
* Fill in Target CHAP portion of iBFT
330
* @v target Target portion of iBFT
331
* @v strings iBFT string block descriptor
332
* @v iscsi iSCSI session
333
* @ret rc Return status code
335
static int ibft_fill_target_chap ( struct ibft_target *target,
336
struct ibft_strings *strings,
337
struct iscsi_session *iscsi ) {
340
if ( ! ( iscsi->status & ISCSI_STATUS_AUTH_FORWARD_REQUIRED ) )
343
assert ( iscsi->initiator_username );
344
assert ( iscsi->initiator_password );
346
target->chap_type = IBFT_CHAP_ONE_WAY;
347
if ( ( rc = ibft_set_string ( strings, &target->chap_name,
348
iscsi->initiator_username ) ) != 0 )
350
DBG ( "iBFT target username = %s\n",
351
ibft_string ( strings, &target->chap_name ) );
352
if ( ( rc = ibft_set_string ( strings, &target->chap_secret,
353
iscsi->initiator_password ) ) != 0 )
355
DBG ( "iBFT target password = <redacted>\n" );
361
* Fill in Target Reverse CHAP portion of iBFT
363
* @v target Target portion of iBFT
364
* @v strings iBFT string block descriptor
365
* @v iscsi iSCSI session
366
* @ret rc Return status code
368
static int ibft_fill_target_reverse_chap ( struct ibft_target *target,
369
struct ibft_strings *strings,
370
struct iscsi_session *iscsi ) {
373
if ( ! ( iscsi->status & ISCSI_STATUS_AUTH_REVERSE_REQUIRED ) )
376
assert ( iscsi->initiator_username );
377
assert ( iscsi->initiator_password );
378
assert ( iscsi->target_username );
379
assert ( iscsi->target_password );
381
target->chap_type = IBFT_CHAP_MUTUAL;
382
if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_name,
383
iscsi->target_username ) ) != 0 )
385
DBG ( "iBFT target reverse username = %s\n",
386
ibft_string ( strings, &target->chap_name ) );
387
if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_secret,
388
iscsi->target_password ) ) != 0 )
390
DBG ( "iBFT target reverse password = <redacted>\n" );
396
* Fill in Target portion of iBFT
398
* @v target Target portion of iBFT
399
* @v strings iBFT string block descriptor
400
* @v iscsi iSCSI session
401
* @ret rc Return status code
403
static int ibft_fill_target ( struct ibft_target *target,
404
struct ibft_strings *strings,
405
struct iscsi_session *iscsi ) {
406
struct sockaddr_in *sin_target =
407
( struct sockaddr_in * ) &iscsi->target_sockaddr;
410
/* Fill in common header */
411
target->header.structure_id = IBFT_STRUCTURE_ID_TARGET;
412
target->header.version = 1;
413
target->header.length = cpu_to_le16 ( sizeof ( *target ) );
414
target->header.flags = ( IBFT_FL_TARGET_BLOCK_VALID |
415
IBFT_FL_TARGET_FIRMWARE_BOOT_SELECTED );
417
/* Fill in Target values */
418
ibft_set_ipaddr ( &target->ip_address, sin_target->sin_addr );
419
DBG ( "iBFT target IP = %s\n", ibft_ipaddr ( &target->ip_address ) );
420
target->socket = cpu_to_le16 ( ntohs ( sin_target->sin_port ) );
421
DBG ( "iBFT target port = %d\n", target->socket );
422
memcpy ( &target->boot_lun, &iscsi->lun, sizeof ( target->boot_lun ) );
423
DBG ( "iBFT target boot LUN = " SCSI_LUN_FORMAT "\n",
424
SCSI_LUN_DATA ( target->boot_lun ) );
425
if ( ( rc = ibft_set_string ( strings, &target->target_name,
426
iscsi->target_iqn ) ) != 0 )
428
DBG ( "iBFT target name = %s\n",
429
ibft_string ( strings, &target->target_name ) );
430
if ( ( rc = ibft_fill_target_chap ( target, strings, iscsi ) ) != 0 )
432
if ( ( rc = ibft_fill_target_reverse_chap ( target, strings,
442
* @v iscsi iSCSI session
444
* @v len Length of ACPI table
445
* @ret rc Return status code
447
int ibft_describe ( struct iscsi_session *iscsi,
448
struct acpi_description_header *acpi,
450
struct ipxe_ibft *ibft =
451
container_of ( acpi, struct ipxe_ibft, table.acpi );
452
struct ibft_strings strings = {
453
.table = &ibft->table,
454
.offset = offsetof ( typeof ( *ibft ), strings ),
457
struct net_device *netdev;
460
/* Ugly hack. Now that we have a generic interface mechanism
461
* that can support ioctls, we can potentially eliminate this.
463
netdev = last_opened_netdev();
465
DBGC ( iscsi, "iSCSI %p cannot guess network device\n",
470
/* Fill in ACPI header */
471
ibft->table.acpi.signature = cpu_to_le32 ( IBFT_SIG );
472
ibft->table.acpi.length = cpu_to_le32 ( len );
473
ibft->table.acpi.revision = 1;
475
/* Fill in Control block */
476
ibft->table.control.header.structure_id = IBFT_STRUCTURE_ID_CONTROL;
477
ibft->table.control.header.version = 1;
478
ibft->table.control.header.length =
479
cpu_to_le16 ( sizeof ( ibft->table.control ) );
480
ibft->table.control.initiator =
481
cpu_to_le16 ( offsetof ( typeof ( *ibft ), initiator ) );
482
ibft->table.control.nic_0 =
483
cpu_to_le16 ( offsetof ( typeof ( *ibft ), nic ) );
484
ibft->table.control.target_0 =
485
cpu_to_le16 ( offsetof ( typeof ( *ibft ), target ) );
487
/* Fill in NIC, Initiator and Target blocks */
488
if ( ( rc = ibft_fill_nic ( &ibft->nic, &strings, netdev ) ) != 0 )
490
if ( ( rc = ibft_fill_initiator ( &ibft->initiator, &strings,
493
if ( ( rc = ibft_fill_target ( &ibft->target, &strings,