00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 FILE_LICENCE ( BSD2 );
00029
00030 #include <stdint.h>
00031 #include <stdio.h>
00032 #include <string.h>
00033 #include <errno.h>
00034 #include <byteswap.h>
00035 #include <realmode.h>
00036 #include <gpxe/pci.h>
00037 #include <gpxe/acpi.h>
00038 #include <gpxe/in.h>
00039 #include <gpxe/netdevice.h>
00040 #include <gpxe/ethernet.h>
00041 #include <gpxe/dhcp.h>
00042 #include <gpxe/iscsi.h>
00043 #include <gpxe/ibft.h>
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 #define ibftab __use_data16 ( ibftab )
00057
00058 struct gpxe_ibft __data16 ( ibftab ) = {
00059
00060 .table = {
00061
00062 .acpi = {
00063 .signature = IBFT_SIG,
00064 .length = sizeof ( ibftab ),
00065 .revision = 1,
00066 .oem_id = "FENSYS",
00067 .oem_table_id = "gPXE",
00068 },
00069
00070 .control = {
00071 .header = {
00072 .structure_id = IBFT_STRUCTURE_ID_CONTROL,
00073 .version = 1,
00074 .length = sizeof ( ibftab.table.control ),
00075 .flags = 0,
00076 },
00077 .initiator = offsetof ( typeof ( ibftab ), initiator ),
00078 .nic_0 = offsetof ( typeof ( ibftab ), nic ),
00079 .target_0 = offsetof ( typeof ( ibftab ), target ),
00080 },
00081 },
00082
00083 .initiator = {
00084 .header = {
00085 .structure_id = IBFT_STRUCTURE_ID_INITIATOR,
00086 .version = 1,
00087 .length = sizeof ( ibftab.initiator ),
00088 .flags = ( IBFT_FL_INITIATOR_BLOCK_VALID |
00089 IBFT_FL_INITIATOR_FIRMWARE_BOOT_SELECTED ),
00090 },
00091 },
00092
00093 .nic = {
00094 .header = {
00095 .structure_id = IBFT_STRUCTURE_ID_NIC,
00096 .version = 1,
00097 .length = sizeof ( ibftab.nic ),
00098 .flags = ( IBFT_FL_NIC_BLOCK_VALID |
00099 IBFT_FL_NIC_FIRMWARE_BOOT_SELECTED ),
00100 },
00101 },
00102
00103 .target = {
00104 .header = {
00105 .structure_id = IBFT_STRUCTURE_ID_TARGET,
00106 .version = 1,
00107 .length = sizeof ( ibftab.target ),
00108 .flags = ( IBFT_FL_TARGET_BLOCK_VALID |
00109 IBFT_FL_TARGET_FIRMWARE_BOOT_SELECTED ),
00110 },
00111 },
00112 };
00113
00114
00115
00116
00117
00118
00119
00120 static void ibft_set_ipaddr ( struct ibft_ipaddr *ipaddr, struct in_addr in ) {
00121 memset ( ipaddr, 0, sizeof ( ipaddr ) );
00122 if ( in.s_addr ) {
00123 ipaddr->in = in;
00124 ipaddr->ones = 0xffff;
00125 }
00126 }
00127
00128
00129
00130
00131
00132
00133
00134
00135 static void ibft_set_ipaddr_option ( struct ibft_ipaddr *ipaddr,
00136 struct setting *setting ) {
00137 struct in_addr in = { 0 };
00138 fetch_ipv4_setting ( NULL, setting, &in );
00139 ibft_set_ipaddr ( ipaddr, in );
00140 }
00141
00142
00143
00144
00145
00146
00147
00148
00149 static const char * ibft_ipaddr ( struct ibft_ipaddr *ipaddr ) {
00150 return inet_ntoa ( ipaddr->in );
00151 }
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161 static int ibft_alloc_string ( struct ibft_string_block *strings,
00162 struct ibft_string *string, size_t len ) {
00163 char *dest;
00164 unsigned int remaining;
00165
00166 dest = ( ( ( char * ) strings->table ) + strings->offset );
00167 remaining = ( strings->table->acpi.length - strings->offset );
00168 if ( len >= remaining )
00169 return -ENOMEM;
00170
00171 string->offset = strings->offset;
00172 string->length = len;
00173 strings->offset += ( len + 1 );
00174 return 0;
00175 }
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185 static int ibft_set_string ( struct ibft_string_block *strings,
00186 struct ibft_string *string, const char *data ) {
00187 char *dest;
00188 int rc;
00189
00190 if ( ! data )
00191 return 0;
00192
00193 if ( ( rc = ibft_alloc_string ( strings, string,
00194 strlen ( data ) ) ) != 0 )
00195 return rc;
00196 dest = ( ( ( char * ) strings->table ) + string->offset );
00197 strcpy ( dest, data );
00198
00199 return 0;
00200 }
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210 static int ibft_set_string_option ( struct ibft_string_block *strings,
00211 struct ibft_string *string,
00212 struct setting *setting ) {
00213 int len;
00214 char *dest;
00215 int rc;
00216
00217 len = fetch_setting_len ( NULL, setting );
00218 if ( len < 0 ) {
00219 string->offset = 0;
00220 string->length = 0;
00221 return 0;
00222 }
00223
00224 if ( ( rc = ibft_alloc_string ( strings, string, len ) ) != 0 )
00225 return rc;
00226 dest = ( ( ( char * ) strings->table ) + string->offset );
00227 fetch_string_setting ( NULL, setting, dest, ( len + 1 ) );
00228 return 0;
00229 }
00230
00231
00232
00233
00234
00235
00236
00237
00238 static const char * ibft_string ( struct ibft_string_block *strings,
00239 struct ibft_string *string ) {
00240 return ( string->offset ?
00241 ( ( ( char * ) strings->table ) + string->offset ) : NULL );
00242 }
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252 static int ibft_fill_nic ( struct ibft_nic *nic,
00253 struct ibft_string_block *strings,
00254 struct net_device *netdev ) {
00255 struct ll_protocol *ll_protocol = netdev->ll_protocol;
00256 struct in_addr netmask_addr = { 0 };
00257 unsigned int netmask_count = 0;
00258 int rc;
00259
00260
00261 ibft_set_ipaddr_option ( &nic->ip_address, &ip_setting );
00262 DBG ( "iBFT NIC IP = %s\n", ibft_ipaddr ( &nic->ip_address ) );
00263 ibft_set_ipaddr_option ( &nic->gateway, &gateway_setting );
00264 DBG ( "iBFT NIC gateway = %s\n", ibft_ipaddr ( &nic->gateway ) );
00265 ibft_set_ipaddr_option ( &nic->dns[0], &dns_setting );
00266 DBG ( "iBFT NIC DNS = %s\n", ibft_ipaddr ( &nic->dns[0] ) );
00267 if ( ( rc = ibft_set_string_option ( strings, &nic->hostname,
00268 &hostname_setting ) ) != 0 )
00269 return rc;
00270 DBG ( "iBFT NIC hostname = %s\n",
00271 ibft_string ( strings, &nic->hostname ) );
00272
00273
00274 fetch_ipv4_setting ( NULL, &netmask_setting, &netmask_addr );
00275 while ( netmask_addr.s_addr ) {
00276 if ( netmask_addr.s_addr & 0x1 )
00277 netmask_count++;
00278 netmask_addr.s_addr >>= 1;
00279 }
00280 nic->subnet_mask_prefix = netmask_count;
00281 DBG ( "iBFT NIC subnet = /%d\n", nic->subnet_mask_prefix );
00282
00283
00284 if ( ( rc = ll_protocol->eth_addr ( netdev->ll_addr,
00285 nic->mac_address ) ) != 0 ) {
00286 DBG ( "Could not determine iBFT MAC: %s\n", strerror ( rc ) );
00287 return rc;
00288 }
00289 DBG ( "iBFT NIC MAC = %s\n", eth_ntoa ( nic->mac_address ) );
00290 nic->pci_bus_dev_func = netdev->dev->desc.location;
00291 DBG ( "iBFT NIC PCI = %04x\n", nic->pci_bus_dev_func );
00292
00293 return 0;
00294 }
00295
00296
00297
00298
00299
00300
00301
00302
00303 static int ibft_fill_initiator ( struct ibft_initiator *initiator,
00304 struct ibft_string_block *strings ) {
00305 const char *initiator_iqn = iscsi_initiator_iqn();
00306 int rc;
00307
00308 if ( ( rc = ibft_set_string ( strings, &initiator->initiator_name,
00309 initiator_iqn ) ) != 0 )
00310 return rc;
00311 DBG ( "iBFT initiator hostname = %s\n",
00312 ibft_string ( strings, &initiator->initiator_name ) );
00313
00314 return 0;
00315 }
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325 static int ibft_fill_target_chap ( struct ibft_target *target,
00326 struct ibft_string_block *strings,
00327 struct iscsi_session *iscsi ) {
00328 int rc;
00329
00330 if ( ! ( iscsi->status & ISCSI_STATUS_AUTH_FORWARD_REQUIRED ) )
00331 return 0;
00332
00333 assert ( iscsi->initiator_username );
00334 assert ( iscsi->initiator_password );
00335
00336 target->chap_type = IBFT_CHAP_ONE_WAY;
00337 if ( ( rc = ibft_set_string ( strings, &target->chap_name,
00338 iscsi->initiator_username ) ) != 0 )
00339 return rc;
00340 DBG ( "iBFT target username = %s\n",
00341 ibft_string ( strings, &target->chap_name ) );
00342 if ( ( rc = ibft_set_string ( strings, &target->chap_secret,
00343 iscsi->initiator_password ) ) != 0 )
00344 return rc;
00345 DBG ( "iBFT target password = <redacted>\n" );
00346
00347 return 0;
00348 }
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358 static int ibft_fill_target_reverse_chap ( struct ibft_target *target,
00359 struct ibft_string_block *strings,
00360 struct iscsi_session *iscsi ) {
00361 int rc;
00362
00363 if ( ! ( iscsi->status & ISCSI_STATUS_AUTH_REVERSE_REQUIRED ) )
00364 return 0;
00365
00366 assert ( iscsi->initiator_username );
00367 assert ( iscsi->initiator_password );
00368 assert ( iscsi->target_username );
00369 assert ( iscsi->target_password );
00370
00371 target->chap_type = IBFT_CHAP_MUTUAL;
00372 if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_name,
00373 iscsi->target_username ) ) != 0 )
00374 return rc;
00375 DBG ( "iBFT target reverse username = %s\n",
00376 ibft_string ( strings, &target->chap_name ) );
00377 if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_secret,
00378 iscsi->target_password ) ) != 0 )
00379 return rc;
00380 DBG ( "iBFT target reverse password = <redacted>\n" );
00381
00382 return 0;
00383 }
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393 static int ibft_fill_target ( struct ibft_target *target,
00394 struct ibft_string_block *strings,
00395 struct iscsi_session *iscsi ) {
00396 struct sockaddr_in *sin_target =
00397 ( struct sockaddr_in * ) &iscsi->target_sockaddr;
00398 int rc;
00399
00400
00401 ibft_set_ipaddr ( &target->ip_address, sin_target->sin_addr );
00402 DBG ( "iBFT target IP = %s\n", ibft_ipaddr ( &target->ip_address ) );
00403 target->socket = ntohs ( sin_target->sin_port );
00404 DBG ( "iBFT target port = %d\n", target->socket );
00405 if ( ( rc = ibft_set_string ( strings, &target->target_name,
00406 iscsi->target_iqn ) ) != 0 )
00407 return rc;
00408 DBG ( "iBFT target name = %s\n",
00409 ibft_string ( strings, &target->target_name ) );
00410 if ( ( rc = ibft_fill_target_chap ( target, strings, iscsi ) ) != 0 )
00411 return rc;
00412 if ( ( rc = ibft_fill_target_reverse_chap ( target, strings,
00413 iscsi ) ) != 0 )
00414 return rc;
00415
00416 return 0;
00417 }
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429 int ibft_fill_data ( struct net_device *netdev,
00430 struct iscsi_session *iscsi ) {
00431 struct ibft_string_block strings = {
00432 .table = &ibftab.table,
00433 .offset = offsetof ( typeof ( ibftab ), strings ),
00434 };
00435 int rc;
00436
00437
00438 if ( ( rc = ibft_fill_nic ( &ibftab.nic, &strings, netdev ) ) != 0 )
00439 return rc;
00440 if ( ( rc = ibft_fill_initiator ( &ibftab.initiator,
00441 &strings ) ) != 0 )
00442 return rc;
00443 if ( ( rc = ibft_fill_target ( &ibftab.target, &strings,
00444 iscsi ) ) != 0 )
00445 return rc;
00446
00447
00448 acpi_fix_checksum ( &ibftab.table.acpi );
00449
00450 return 0;
00451 }