@@ -92,6 +92,30 @@ static LPSTR ibft_ipaddr ( PIBFT_IPADDR ipaddr ) {
92
92
return inet_ntoa ( ipaddr -> in );
93
93
}
94
94
95
+ /**
96
+ * Convert subnet mask prefix to subnet mask
97
+ *
98
+ * @v prefix Subnet mask prefix
99
+ * @ret mask Subnet mask
100
+ */
101
+ static ULONG ibft_subnet_mask ( UCHAR prefix ) {
102
+ return RtlUlongByteSwap ( 0xffffffffUL << ( 32 - prefix ) );
103
+ }
104
+
105
+ /**
106
+ * Fill in an IP address field within iBFT
107
+ *
108
+ * @v ipaddr IP address field
109
+ * @v in IPv4 address
110
+ */
111
+ static void ibft_set_ipaddr ( PIBFT_IPADDR ipaddr , ULONG in ) {
112
+ memset ( ipaddr , 0 , sizeof ( * ipaddr ) );
113
+ if ( in ) {
114
+ ipaddr -> in = in ;
115
+ ipaddr -> ones = 0xffff ;
116
+ }
117
+ }
118
+
95
119
/**
96
120
* Parse iBFT initiator structure
97
121
*
@@ -217,8 +241,7 @@ static NTSTATUS store_tcpip_parameters ( PDEVICE_OBJECT pdo,
217
241
goto err_reg_store ;
218
242
219
243
/* Store subnet mask */
220
- subnet_mask = RtlUlongByteSwap ( 0xffffffffUL <<
221
- ( 32 - nic -> subnet_mask_prefix ) );
244
+ subnet_mask = ibft_subnet_mask ( nic -> subnet_mask_prefix );
222
245
status = store_ipv4_parameter_multi_sz ( reg_key , L"SubnetMask" ,
223
246
subnet_mask );
224
247
if ( ! NT_SUCCESS ( status ) )
@@ -257,6 +280,7 @@ static NTSTATUS store_tcpip_parameters ( PDEVICE_OBJECT pdo,
257
280
*/
258
281
static VOID parse_ibft_nic ( PIBFT_TABLE ibft , PIBFT_NIC nic ) {
259
282
PIBFT_HEADER header = & nic -> header ;
283
+ ULONG subnet_mask ;
260
284
NTSTATUS status ;
261
285
262
286
/* Dump structure information */
@@ -270,8 +294,9 @@ static VOID parse_ibft_nic ( PIBFT_TABLE ibft, PIBFT_NIC nic ) {
270
294
? ", global address" : ", link local address" ) );
271
295
if ( ! ( header -> flags & IBFT_FL_NIC_BLOCK_VALID ) )
272
296
return ;
273
- DbgPrint ( " IP = %s/%d\n" , ibft_ipaddr ( & nic -> ip_address ),
274
- nic -> subnet_mask_prefix );
297
+ DbgPrint ( " IP = %s/" , ibft_ipaddr ( & nic -> ip_address ) );
298
+ subnet_mask = ibft_subnet_mask ( nic -> subnet_mask_prefix );
299
+ DbgPrint ( "%s\n" , inet_ntoa ( subnet_mask ) );
275
300
DbgPrint ( " Origin = %d\n" , nic -> origin );
276
301
DbgPrint ( " Gateway = %s\n" , ibft_ipaddr ( & nic -> gateway ) );
277
302
DbgPrint ( " DNS = %s" , ibft_ipaddr ( & nic -> dns [0 ] ) );
@@ -349,42 +374,103 @@ static VOID parse_ibft_target ( PIBFT_TABLE ibft, PIBFT_TARGET target ) {
349
374
"<omitted>" : "" ) );
350
375
}
351
376
377
+ /**
378
+ * Iterate over entries in the iBFT
379
+ *
380
+ * @v entry Structure
381
+ * @v TYPE Type of structure
382
+ * @v ibft iBFT
383
+ * @v offset Loop counter
384
+ */
385
+ #define for_each_ibft_entry ( entry , TYPE , ibft , offset ) \
386
+ for ( offset = &ibft->control.extensions, \
387
+ entry = ( ( PIBFT_ ## TYPE ) ( ( ( PUCHAR ) ibft ) + *offset ));\
388
+ ( ( PUCHAR ) offset ) < ( ( ( PUCHAR ) &ibft->control ) + \
389
+ ibft->control.header.length ) ; \
390
+ offset++, \
391
+ entry = ( ( PIBFT_ ## TYPE ) ( ( ( PUCHAR ) ibft ) + *offset )))\
392
+ if ( ( *offset == 0 ) || \
393
+ ( entry->header.structure_id != \
394
+ IBFT_STRUCTURE_ID_ ## TYPE ) ) continue; \
395
+ else
396
+
352
397
/**
353
398
* Parse iBFT
354
399
*
355
400
* @v acpi ACPI description header
356
401
*/
357
402
VOID parse_ibft ( PACPI_DESCRIPTION_HEADER acpi ) {
358
403
PIBFT_TABLE ibft = ( PIBFT_TABLE ) acpi ;
359
- PIBFT_CONTROL control = & ibft -> control ;
360
- PUSHORT offset ;
361
- PIBFT_HEADER header ;
362
-
363
- /* Scan through all entries in the Control structure */
364
- for ( offset = & control -> extensions ;
365
- ( ( PUCHAR ) offset ) <
366
- ( ( ( PUCHAR ) control ) + control -> header .length ) ;
367
- offset ++ ) {
368
- if ( ! * offset )
404
+ PUSHORT initiator_offset ;
405
+ PIBFT_INITIATOR initiator ;
406
+ PUSHORT nic_offset ;
407
+ PIBFT_NIC nic ;
408
+ PUSHORT target_offset ;
409
+ PIBFT_TARGET target ;
410
+ ULONG gateway ;
411
+ ULONG network ;
412
+ ULONG netmask ;
413
+ ULONG attached_targets ;
414
+
415
+ /* Scan through all iBFT entries */
416
+ for_each_ibft_entry ( initiator , INITIATOR , ibft , initiator_offset )
417
+ parse_ibft_initiator ( ibft , initiator );
418
+ for_each_ibft_entry ( nic , NIC , ibft , nic_offset )
419
+ parse_ibft_nic ( ibft , nic );
420
+ for_each_ibft_entry ( target , TARGET , ibft , target_offset )
421
+ parse_ibft_target ( ibft , target );
422
+
423
+ /* If a gateway is specified in the iBFT, the Microsoft iSCSI
424
+ * initiator will create a static route to the iSCSI target
425
+ * via that gateway. (See the knowledge base article at
426
+ * http://support.microsoft.com/kb/960104 for details.) If
427
+ * the target is in the same subnet then this is undesirable,
428
+ * since it will mean duplicating every outbound packet on the
429
+ * network.
430
+ *
431
+ * We work around this by replacing the gateway address as
432
+ * follows:
433
+ *
434
+ * a) if no targets are directly attached to this NIC's
435
+ * subnet, we leave the gateway address as-is,
436
+ *
437
+ * b) if exactly one target is directly attached to this
438
+ * NIC's subnet, we set the gateway address to the
439
+ * target's own IP address, thus giving a target-
440
+ * specific route that will remain correct even if the
441
+ * subnet route is later removed.
442
+ *
443
+ * c) if more than one target is directly attached to this
444
+ * NIC's subnet, we blank out the gateway address, thus
445
+ * preventing the creation of the undesirable routes.
446
+ *
447
+ * Note that none of this affects the normal TCP/IP stack
448
+ * configuration, which has already been carried out; this
449
+ * affects only the dedicated routes created by the Microsoft
450
+ * iSCSI initiator.
451
+ */
452
+ for_each_ibft_entry ( nic , NIC , ibft , nic_offset ) {
453
+ gateway = nic -> gateway .in ;
454
+ if ( ! gateway )
369
455
continue ;
370
- header = ( ( PIBFT_HEADER ) ( ( ( PUCHAR ) ibft ) + * offset ) );
371
- switch ( header -> structure_id ) {
372
- case IBFT_STRUCTURE_ID_INITIATOR :
373
- parse_ibft_initiator ( ibft ,
374
- ( ( PIBFT_INITIATOR ) header ));
375
- break ;
376
- case IBFT_STRUCTURE_ID_NIC :
377
- parse_ibft_nic ( ibft , ( ( PIBFT_NIC ) header ) );
378
- break ;
379
- case IBFT_STRUCTURE_ID_TARGET :
380
- parse_ibft_target ( ibft ,
381
- ( ( PIBFT_TARGET ) header ) );
382
- break ;
383
- default :
384
- DbgPrint ( "Ignoring unknown iBFT structure ID %d "
385
- "index %d\n" , header -> structure_id ,
386
- header -> index );
387
- break ;
456
+ netmask = ibft_subnet_mask ( nic -> subnet_mask_prefix );
457
+ network = ( nic -> ip_address . in & netmask );
458
+ attached_targets = 0 ;
459
+ for_each_ibft_entry ( target , TARGET , ibft , target_offset ) {
460
+ if ( ( target -> ip_address . in & netmask ) != network )
461
+ continue ;
462
+ gateway = ( ( attached_targets == 0 ) ?
463
+ target -> ip_address . in : 0 );
464
+ attached_targets ++ ;
465
+ }
466
+ DbgPrint ( "Found %d target(s) directly attached via iBFT NIC "
467
+ "%d\n" , attached_targets , nic -> header . index );
468
+ if ( gateway != nic -> gateway . in ) {
469
+ DbgPrint ( "Amending gateway for iBFT NIC %d from %s" ,
470
+ nic -> header . index ,
471
+ ibft_ipaddr ( & nic -> gateway ) );
472
+ ibft_set_ipaddr ( & nic -> gateway , gateway );
473
+ DbgPrint ( " to %s\n" , ibft_ipaddr ( & nic -> gateway ) ) ;
388
474
}
389
475
}
390
476
}
0 commit comments