]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/IScsiDxe/IScsiMisc.c
Use string pointer instead string buffer to avoid string copy operation.
[mirror_edk2.git] / NetworkPkg / IScsiDxe / IScsiMisc.c
1 /** @file
2 Miscellaneous routines for iSCSI driver.
3
4 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "IScsiImpl.h"
16
17 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 IScsiHexString[] = "0123456789ABCDEFabcdef";
18
19 /**
20 Removes (trims) specified leading and trailing characters from a string.
21
22 @param[in, out] Str Pointer to the null-terminated string to be trimmed.
23 On return, Str will hold the trimmed string.
24
25 @param[in] CharC Character will be trimmed from str.
26
27 **/
28 VOID
29 IScsiStrTrim (
30 IN OUT CHAR16 *Str,
31 IN CHAR16 CharC
32 )
33 {
34 CHAR16 *Pointer1;
35 CHAR16 *Pointer2;
36
37 if (*Str == 0) {
38 return ;
39 }
40
41 //
42 // Trim off the leading and trailing characters c
43 //
44 for (Pointer1 = Str; (*Pointer1 != 0) && (*Pointer1 == CharC); Pointer1++) {
45 ;
46 }
47
48 Pointer2 = Str;
49 if (Pointer2 == Pointer1) {
50 while (*Pointer1 != 0) {
51 Pointer2++;
52 Pointer1++;
53 }
54 } else {
55 while (*Pointer1 != 0) {
56 *Pointer2 = *Pointer1;
57 Pointer1++;
58 Pointer2++;
59 }
60 *Pointer2 = 0;
61 }
62
63
64 for (Pointer1 = Str + StrLen(Str) - 1; Pointer1 >= Str && *Pointer1 == CharC; Pointer1--) {
65 ;
66 }
67 if (Pointer1 != Str + StrLen(Str) - 1) {
68 *(Pointer1 + 1) = 0;
69 }
70 }
71
72 /**
73 Calculate the prefix length of the IPv4 subnet mask.
74
75 @param[in] SubnetMask The IPv4 subnet mask.
76
77 @return The prefix length of the subnet mask.
78 @retval 0 Other errors as indicated.
79
80 **/
81 UINT8
82 IScsiGetSubnetMaskPrefixLength (
83 IN EFI_IPv4_ADDRESS *SubnetMask
84 )
85 {
86 UINT8 Len;
87 UINT32 ReverseMask;
88
89 //
90 // The SubnetMask is in network byte order.
91 //
92 ReverseMask = (SubnetMask->Addr[0] << 24) | (SubnetMask->Addr[1] << 16) | (SubnetMask->Addr[2] << 8) | (SubnetMask->Addr[3]);
93
94 //
95 // Reverse it.
96 //
97 ReverseMask = ~ReverseMask;
98
99 if ((ReverseMask & (ReverseMask + 1)) != 0) {
100 return 0;
101 }
102
103 Len = 0;
104
105 while (ReverseMask != 0) {
106 ReverseMask = ReverseMask >> 1;
107 Len++;
108 }
109
110 return (UINT8) (32 - Len);
111 }
112
113
114 /**
115 Convert the hexadecimal encoded LUN string into the 64-bit LUN.
116
117 @param[in] Str The hexadecimal encoded LUN string.
118 @param[out] Lun Storage to return the 64-bit LUN.
119
120 @retval EFI_SUCCESS The 64-bit LUN is stored in Lun.
121 @retval EFI_INVALID_PARAMETER The string is malformatted.
122
123 **/
124 EFI_STATUS
125 IScsiAsciiStrToLun (
126 IN CHAR8 *Str,
127 OUT UINT8 *Lun
128 )
129 {
130 UINTN Index, IndexValue, IndexNum, SizeStr;
131 CHAR8 TemStr[2];
132 UINT8 TemValue;
133 UINT16 Value[4];
134
135 ZeroMem (Lun, 8);
136 ZeroMem (TemStr, 2);
137 ZeroMem ((UINT8 *) Value, sizeof (Value));
138 SizeStr = AsciiStrLen (Str);
139 IndexValue = 0;
140 IndexNum = 0;
141
142 for (Index = 0; Index < SizeStr; Index ++) {
143 TemStr[0] = Str[Index];
144 TemValue = (UINT8) AsciiStrHexToUint64 (TemStr);
145 if (TemValue == 0 && TemStr[0] != '0') {
146 if ((TemStr[0] != '-') || (IndexNum == 0)) {
147 //
148 // Invalid Lun Char.
149 //
150 return EFI_INVALID_PARAMETER;
151 }
152 }
153
154 if ((TemValue == 0) && (TemStr[0] == '-')) {
155 //
156 // Next Lun value.
157 //
158 if (++IndexValue >= 4) {
159 //
160 // Max 4 Lun value.
161 //
162 return EFI_INVALID_PARAMETER;
163 }
164 //
165 // Restart str index for the next lun value.
166 //
167 IndexNum = 0;
168 continue;
169 }
170
171 if (++IndexNum > 4) {
172 //
173 // Each Lun Str can't exceed size 4, because it will be as UINT16 value.
174 //
175 return EFI_INVALID_PARAMETER;
176 }
177
178 //
179 // Combine UINT16 value.
180 //
181 Value[IndexValue] = (UINT16) ((Value[IndexValue] << 4) + TemValue);
182 }
183
184 for (Index = 0; Index <= IndexValue; Index ++) {
185 *((UINT16 *) &Lun[Index * 2]) = HTONS (Value[Index]);
186 }
187
188 return EFI_SUCCESS;
189 }
190
191 /**
192 Convert the 64-bit LUN into the hexadecimal encoded LUN string.
193
194 @param[in] Lun The 64-bit LUN.
195 @param[out] Str The storage to return the hexadecimal encoded LUN string.
196
197 **/
198 VOID
199 IScsiLunToUnicodeStr (
200 IN UINT8 *Lun,
201 OUT CHAR16 *Str
202 )
203 {
204 UINTN Index;
205 CHAR16 *TempStr;
206
207 TempStr = Str;
208
209 for (Index = 0; Index < 4; Index++) {
210
211 if ((Lun[2 * Index] | Lun[2 * Index + 1]) == 0) {
212 CopyMem (TempStr, L"0-", sizeof (L"0-"));
213 } else {
214 TempStr[0] = (CHAR16) IScsiHexString[Lun[2 * Index] >> 4];
215 TempStr[1] = (CHAR16) IScsiHexString[Lun[2 * Index] & 0x0F];
216 TempStr[2] = (CHAR16) IScsiHexString[Lun[2 * Index + 1] >> 4];
217 TempStr[3] = (CHAR16) IScsiHexString[Lun[2 * Index + 1] & 0x0F];
218 TempStr[4] = L'-';
219 TempStr[5] = 0;
220
221 IScsiStrTrim (TempStr, L'0');
222 }
223
224 TempStr += StrLen (TempStr);
225 }
226 //
227 // Remove the last '-'
228 //
229 Str[StrLen (Str) - 1] = 0;
230
231 for (Index = StrLen (Str) - 1; Index > 1; Index = Index - 2) {
232 if ((Str[Index] == L'0') && (Str[Index - 1] == L'-')) {
233 Str[Index - 1] = 0;
234 } else {
235 break;
236 }
237 }
238 }
239
240 /**
241 Convert the formatted IP address into the binary IP address.
242
243 @param[in] Str The UNICODE string.
244 @param[in] IpMode Indicates whether the IP address is v4 or v6.
245 @param[out] Ip The storage to return the ASCII string.
246
247 @retval EFI_SUCCESS The binary IP address is returned in Ip.
248 @retval EFI_INVALID_PARAMETER The IP string is malformatted or IpMode is
249 invalid.
250
251 **/
252 EFI_STATUS
253 IScsiAsciiStrToIp (
254 IN CHAR8 *Str,
255 IN UINT8 IpMode,
256 OUT EFI_IP_ADDRESS *Ip
257 )
258 {
259 EFI_STATUS Status;
260
261 if (IpMode == IP_MODE_IP4 || IpMode == IP_MODE_AUTOCONFIG_IP4) {
262 return NetLibAsciiStrToIp4 (Str, &Ip->v4);
263
264 } else if (IpMode == IP_MODE_IP6 || IpMode == IP_MODE_AUTOCONFIG_IP6) {
265 return NetLibAsciiStrToIp6 (Str, &Ip->v6);
266
267 } else if (IpMode == IP_MODE_AUTOCONFIG) {
268 Status = NetLibAsciiStrToIp4 (Str, &Ip->v4);
269 if (!EFI_ERROR (Status)) {
270 return Status;
271 }
272 return NetLibAsciiStrToIp6 (Str, &Ip->v6);
273
274 }
275
276 return EFI_INVALID_PARAMETER;
277 }
278
279 /**
280 Convert the mac address into a hexadecimal encoded "-" seperated string.
281
282 @param[in] Mac The mac address.
283 @param[in] Len Length in bytes of the mac address.
284 @param[in] VlanId VLAN ID of the network device.
285 @param[out] Str The storage to return the mac string.
286
287 **/
288 VOID
289 IScsiMacAddrToStr (
290 IN EFI_MAC_ADDRESS *Mac,
291 IN UINT32 Len,
292 IN UINT16 VlanId,
293 OUT CHAR16 *Str
294 )
295 {
296 UINT32 Index;
297 CHAR16 *String;
298
299 for (Index = 0; Index < Len; Index++) {
300 Str[3 * Index] = (CHAR16) IScsiHexString[(Mac->Addr[Index] >> 4) & 0x0F];
301 Str[3 * Index + 1] = (CHAR16) IScsiHexString[Mac->Addr[Index] & 0x0F];
302 Str[3 * Index + 2] = L':';
303 }
304
305 String = &Str[3 * Index - 1] ;
306 if (VlanId != 0) {
307 String += UnicodeSPrint (String, 6 * sizeof (CHAR16), L"\\%04x", (UINTN) VlanId);
308 }
309
310 *String = L'\0';
311 }
312
313 /**
314 Convert the binary encoded buffer into a hexadecimal encoded string.
315
316 @param[in] BinBuffer The buffer containing the binary data.
317 @param[in] BinLength Length of the binary buffer.
318 @param[in, out] HexStr Pointer to the string.
319 @param[in, out] HexLength The length of the string.
320
321 @retval EFI_SUCCESS The binary data is converted to the hexadecimal string
322 and the length of the string is updated.
323 @retval EFI_BUFFER_TOO_SMALL The string is too small.
324 @retval EFI_INVALID_PARAMETER The IP string is malformatted.
325
326 **/
327 EFI_STATUS
328 IScsiBinToHex (
329 IN UINT8 *BinBuffer,
330 IN UINT32 BinLength,
331 IN OUT CHAR8 *HexStr,
332 IN OUT UINT32 *HexLength
333 )
334 {
335 UINTN Index;
336
337 if ((HexStr == NULL) || (BinBuffer == NULL) || (BinLength == 0)) {
338 return EFI_INVALID_PARAMETER;
339 }
340
341 if (((*HexLength) - 3) < BinLength * 2) {
342 *HexLength = BinLength * 2 + 3;
343 return EFI_BUFFER_TOO_SMALL;
344 }
345
346 *HexLength = BinLength * 2 + 3;
347 //
348 // Prefix for Hex String.
349 //
350 HexStr[0] = '0';
351 HexStr[1] = 'x';
352
353 for (Index = 0; Index < BinLength; Index++) {
354 HexStr[Index * 2 + 2] = IScsiHexString[BinBuffer[Index] >> 4];
355 HexStr[Index * 2 + 3] = IScsiHexString[BinBuffer[Index] & 0xf];
356 }
357
358 HexStr[Index * 2 + 2] = '\0';
359
360 return EFI_SUCCESS;
361 }
362
363
364 /**
365 Convert the hexadecimal string into a binary encoded buffer.
366
367 @param[in, out] BinBuffer The binary buffer.
368 @param[in, out] BinLength Length of the binary buffer.
369 @param[in] HexStr The hexadecimal string.
370
371 @retval EFI_SUCCESS The hexadecimal string is converted into a binary
372 encoded buffer.
373 @retval EFI_BUFFER_TOO_SMALL The binary buffer is too small to hold the converted data.
374
375 **/
376 EFI_STATUS
377 IScsiHexToBin (
378 IN OUT UINT8 *BinBuffer,
379 IN OUT UINT32 *BinLength,
380 IN CHAR8 *HexStr
381 )
382 {
383 UINTN Index;
384 UINTN Length;
385 UINT8 Digit;
386 CHAR8 TemStr[2];
387
388 ZeroMem (TemStr, sizeof (TemStr));
389
390 //
391 // Find out how many hex characters the string has.
392 //
393 if ((HexStr[0] == '0') && ((HexStr[1] == 'x') || (HexStr[1] == 'X'))) {
394 HexStr += 2;
395 }
396
397 Length = AsciiStrLen (HexStr);
398
399 for (Index = 0; Index < Length; Index ++) {
400 TemStr[0] = HexStr[Index];
401 Digit = (UINT8) AsciiStrHexToUint64 (TemStr);
402 if (Digit == 0 && TemStr[0] != '0') {
403 //
404 // Invalid Lun Char.
405 //
406 break;
407 }
408 if ((Index & 1) == 0) {
409 BinBuffer [Index/2] = Digit;
410 } else {
411 BinBuffer [Index/2] = (UINT8) ((BinBuffer [Index/2] << 4) + Digit);
412 }
413 }
414
415 *BinLength = (UINT32) ((Index + 1)/2);
416
417 return EFI_SUCCESS;
418 }
419
420
421 /**
422 Convert the decimal-constant string or hex-constant string into a numerical value.
423
424 @param[in] Str String in decimal or hex.
425
426 @return The numerical value.
427
428 **/
429 UINTN
430 IScsiNetNtoi (
431 IN CHAR8 *Str
432 )
433 {
434 if ((Str[0] == '0') && ((Str[1] == 'x') || (Str[1] == 'X'))) {
435 Str += 2;
436
437 return AsciiStrHexToUintn (Str);
438 }
439
440 return AsciiStrDecimalToUintn (Str);
441 }
442
443
444 /**
445 Generate random numbers.
446
447 @param[in, out] Rand The buffer to contain random numbers.
448 @param[in] RandLength The length of the Rand buffer.
449
450 **/
451 VOID
452 IScsiGenRandom (
453 IN OUT UINT8 *Rand,
454 IN UINTN RandLength
455 )
456 {
457 UINT32 Random;
458
459 while (RandLength > 0) {
460 Random = NET_RANDOM (NetRandomInitSeed ());
461 *Rand++ = (UINT8) (Random);
462 RandLength--;
463 }
464 }
465
466
467 /**
468 Record the NIC info in global structure.
469
470 @param[in] Controller The handle of the controller.
471
472 @retval EFI_SUCCESS The operation is completed.
473 @retval EFI_OUT_OF_RESOURCES Do not have sufficient resources to finish this
474 operation.
475
476 **/
477 EFI_STATUS
478 IScsiAddNic (
479 IN EFI_HANDLE Controller
480 )
481 {
482 EFI_STATUS Status;
483 ISCSI_NIC_INFO *NicInfo;
484 LIST_ENTRY *Entry;
485 EFI_MAC_ADDRESS MacAddr;
486 UINTN HwAddressSize;
487 UINT16 VlanId;
488
489 //
490 // Get MAC address of this network device.
491 //
492 Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);
493 if (EFI_ERROR (Status)) {
494 return Status;
495 }
496
497 //
498 // Get VLAN ID of this network device.
499 //
500 VlanId = NetLibGetVlanId (Controller);
501
502 //
503 // Check whether the NIC info already exists. Return directly if so.
504 //
505 NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
506 NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
507 if (NicInfo->HwAddressSize == HwAddressSize &&
508 CompareMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize) == 0 &&
509 NicInfo->VlanId == VlanId) {
510 mPrivate->CurrentNic = NicInfo->NicIndex;
511 return EFI_SUCCESS;
512 }
513
514 if (mPrivate->MaxNic < NicInfo->NicIndex) {
515 mPrivate->MaxNic = NicInfo->NicIndex;
516 }
517 }
518
519 //
520 // Record the NIC info in private structure.
521 //
522 NicInfo = AllocateZeroPool (sizeof (ISCSI_NIC_INFO));
523 if (NicInfo == NULL) {
524 return EFI_OUT_OF_RESOURCES;
525 }
526
527 CopyMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize);
528 NicInfo->HwAddressSize = (UINT32) HwAddressSize;
529 NicInfo->VlanId = VlanId;
530 NicInfo->NicIndex = (UINT8) (mPrivate->MaxNic + 1);
531 mPrivate->MaxNic = NicInfo->NicIndex;
532
533 //
534 // Get the PCI location.
535 //
536 IScsiGetNICPciLocation (
537 Controller,
538 &NicInfo->BusNumber,
539 &NicInfo->DeviceNumber,
540 &NicInfo->FunctionNumber
541 );
542
543 InsertTailList (&mPrivate->NicInfoList, &NicInfo->Link);
544 mPrivate->NicCount++;
545
546 mPrivate->CurrentNic = NicInfo->NicIndex;
547 return EFI_SUCCESS;
548 }
549
550
551 /**
552 Delete the recorded NIC info from global structure. Also delete corresponding
553 attempts.
554
555 @param[in] Controller The handle of the controller.
556
557 @retval EFI_SUCCESS The operation is completed.
558 @retval EFI_NOT_FOUND The NIC info to be deleted is not recorded.
559
560 **/
561 EFI_STATUS
562 IScsiRemoveNic (
563 IN EFI_HANDLE Controller
564 )
565 {
566 EFI_STATUS Status;
567 ISCSI_NIC_INFO *NicInfo;
568 LIST_ENTRY *Entry;
569 LIST_ENTRY *NextEntry;
570 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
571 ISCSI_NIC_INFO *ThisNic;
572 EFI_MAC_ADDRESS MacAddr;
573 UINTN HwAddressSize;
574 UINT16 VlanId;
575
576 //
577 // Get MAC address of this network device.
578 //
579 Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);
580 if (EFI_ERROR (Status)) {
581 return Status;
582 }
583
584 //
585 // Get VLAN ID of this network device.
586 //
587 VlanId = NetLibGetVlanId (Controller);
588
589 //
590 // Check whether the NIC information exists.
591 //
592 ThisNic = NULL;
593
594 NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
595 NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
596 if (NicInfo->HwAddressSize == HwAddressSize &&
597 CompareMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize) == 0 &&
598 NicInfo->VlanId == VlanId) {
599
600 ThisNic = NicInfo;
601 break;
602 }
603 }
604
605 if (ThisNic == NULL) {
606 return EFI_NOT_FOUND;
607 }
608
609 mPrivate->CurrentNic = ThisNic->NicIndex;
610
611 RemoveEntryList (&ThisNic->Link);
612 FreePool (ThisNic);
613 mPrivate->NicCount--;
614
615 //
616 // Remove all attempts related to this NIC.
617 //
618 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) {
619 AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
620 if (AttemptConfigData->NicIndex == mPrivate->CurrentNic) {
621 RemoveEntryList (&AttemptConfigData->Link);
622 mPrivate->AttemptCount--;
623
624 if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO && mPrivate->MpioCount > 0) {
625 if (--mPrivate->MpioCount == 0) {
626 mPrivate->EnableMpio = FALSE;
627 }
628
629 if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB && mPrivate->Krb5MpioCount > 0) {
630 mPrivate->Krb5MpioCount--;
631 }
632
633 } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED && mPrivate->SinglePathCount > 0) {
634 mPrivate->SinglePathCount--;
635
636 if (mPrivate->ValidSinglePathCount > 0) {
637 mPrivate->ValidSinglePathCount--;
638 }
639 }
640
641 FreePool (AttemptConfigData);
642 }
643 }
644
645 //
646 // Free attempt is created but not saved to system.
647 //
648 if (mPrivate->NewAttempt != NULL) {
649 FreePool (mPrivate->NewAttempt);
650 mPrivate->NewAttempt = NULL;
651 }
652
653 return EFI_SUCCESS;
654 }
655
656
657 /**
658 Get the recorded NIC info from global structure by the Index.
659
660 @param[in] NicIndex The index indicates the position of NIC info.
661
662 @return Pointer to the NIC info, or NULL if not found.
663
664 **/
665 ISCSI_NIC_INFO *
666 IScsiGetNicInfoByIndex (
667 IN UINT8 NicIndex
668 )
669 {
670 LIST_ENTRY *Entry;
671 ISCSI_NIC_INFO *NicInfo;
672
673 NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
674 NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
675 if (NicInfo->NicIndex == NicIndex) {
676 return NicInfo;
677 }
678 }
679
680 return NULL;
681 }
682
683
684 /**
685 Get the NIC's PCI location and return it accroding to the composited
686 format defined in iSCSI Boot Firmware Table.
687
688 @param[in] Controller The handle of the controller.
689 @param[out] Bus The bus number.
690 @param[out] Device The device number.
691 @param[out] Function The function number.
692
693 @return The composited representation of the NIC PCI location.
694
695 **/
696 UINT16
697 IScsiGetNICPciLocation (
698 IN EFI_HANDLE Controller,
699 OUT UINTN *Bus,
700 OUT UINTN *Device,
701 OUT UINTN *Function
702 )
703 {
704 EFI_STATUS Status;
705 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
706 EFI_HANDLE PciIoHandle;
707 EFI_PCI_IO_PROTOCOL *PciIo;
708 UINTN Segment;
709
710 Status = gBS->HandleProtocol (
711 Controller,
712 &gEfiDevicePathProtocolGuid,
713 (VOID **) &DevicePath
714 );
715 if (EFI_ERROR (Status)) {
716 return 0;
717 }
718
719 Status = gBS->LocateDevicePath (
720 &gEfiPciIoProtocolGuid,
721 &DevicePath,
722 &PciIoHandle
723 );
724 if (EFI_ERROR (Status)) {
725 return 0;
726 }
727
728 Status = gBS->HandleProtocol (PciIoHandle, &gEfiPciIoProtocolGuid, (VOID **) &PciIo);
729 if (EFI_ERROR (Status)) {
730 return 0;
731 }
732
733 Status = PciIo->GetLocation (PciIo, &Segment, Bus, Device, Function);
734 if (EFI_ERROR (Status)) {
735 return 0;
736 }
737
738 return (UINT16) ((*Bus << 8) | (*Device << 3) | *Function);
739 }
740
741
742 /**
743 Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
744 buffer, and the size of the buffer. If failure, return NULL.
745
746 @param[in] Name String part of EFI variable name.
747 @param[in] VendorGuid GUID part of EFI variable name.
748 @param[out] VariableSize Returns the size of the EFI variable that was read.
749
750 @return Dynamically allocated memory that contains a copy of the EFI variable.
751 @return Caller is responsible freeing the buffer.
752 @retval NULL Variable was not read.
753
754 **/
755 VOID *
756 IScsiGetVariableAndSize (
757 IN CHAR16 *Name,
758 IN EFI_GUID *VendorGuid,
759 OUT UINTN *VariableSize
760 )
761 {
762 EFI_STATUS Status;
763 UINTN BufferSize;
764 VOID *Buffer;
765
766 Buffer = NULL;
767
768 //
769 // Pass in a zero size buffer to find the required buffer size.
770 //
771 BufferSize = 0;
772 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
773 if (Status == EFI_BUFFER_TOO_SMALL) {
774 //
775 // Allocate the buffer to return
776 //
777 Buffer = AllocateZeroPool (BufferSize);
778 if (Buffer == NULL) {
779 return NULL;
780 }
781 //
782 // Read variable into the allocated buffer.
783 //
784 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
785 if (EFI_ERROR (Status)) {
786 BufferSize = 0;
787 }
788 }
789
790 *VariableSize = BufferSize;
791 return Buffer;
792 }
793
794
795 /**
796 Create the iSCSI driver data.
797
798 @param[in] Image The handle of the driver image.
799 @param[in] Controller The handle of the controller.
800
801 @return The iSCSI driver data created.
802 @retval NULL Other errors as indicated.
803
804 **/
805 ISCSI_DRIVER_DATA *
806 IScsiCreateDriverData (
807 IN EFI_HANDLE Image,
808 IN EFI_HANDLE Controller
809 )
810 {
811 ISCSI_DRIVER_DATA *Private;
812 EFI_STATUS Status;
813
814 Private = AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA));
815 if (Private == NULL) {
816 return NULL;
817 }
818
819 Private->Signature = ISCSI_DRIVER_DATA_SIGNATURE;
820 Private->Image = Image;
821 Private->Controller = Controller;
822 Private->Session = NULL;
823
824 //
825 // Create an event to be signaled when the BS to RT transition is triggerd so
826 // as to abort the iSCSI session.
827 //
828 Status = gBS->CreateEventEx (
829 EVT_NOTIFY_SIGNAL,
830 TPL_CALLBACK,
831 IScsiOnExitBootService,
832 Private,
833 &gEfiEventExitBootServicesGuid,
834 &Private->ExitBootServiceEvent
835 );
836 if (EFI_ERROR (Status)) {
837 FreePool (Private);
838 return NULL;
839 }
840
841 Private->ExtScsiPassThruHandle = NULL;
842 CopyMem(&Private->IScsiExtScsiPassThru, &gIScsiExtScsiPassThruProtocolTemplate, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL));
843
844 //
845 // 0 is designated to the TargetId, so use another value for the AdapterId.
846 //
847 Private->ExtScsiPassThruMode.AdapterId = 2;
848 Private->ExtScsiPassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
849 Private->ExtScsiPassThruMode.IoAlign = 4;
850 Private->IScsiExtScsiPassThru.Mode = &Private->ExtScsiPassThruMode;
851
852 return Private;
853 }
854
855
856 /**
857 Clean the iSCSI driver data.
858
859 @param[in] Private The iSCSI driver data.
860
861 **/
862 VOID
863 IScsiCleanDriverData (
864 IN ISCSI_DRIVER_DATA *Private
865 )
866 {
867 EFI_STATUS Status;
868
869 if (Private->DevicePath != NULL) {
870 gBS->UninstallProtocolInterface (
871 Private->ExtScsiPassThruHandle,
872 &gEfiDevicePathProtocolGuid,
873 Private->DevicePath
874 );
875
876 FreePool (Private->DevicePath);
877 }
878
879 if (Private->ExtScsiPassThruHandle != NULL) {
880 Status = gBS->UninstallProtocolInterface (
881 Private->ExtScsiPassThruHandle,
882 &gEfiExtScsiPassThruProtocolGuid,
883 &Private->IScsiExtScsiPassThru
884 );
885 if (!EFI_ERROR (Status)) {
886 mPrivate->OneSessionEstablished = FALSE;
887 }
888 }
889
890 gBS->CloseEvent (Private->ExitBootServiceEvent);
891
892 FreePool (Private);
893 }
894
895 /**
896 Check wheather the Controller handle is configured to use DHCP protocol.
897
898 @param[in] Controller The handle of the controller.
899 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
900
901 @retval TRUE The handle of the controller need the Dhcp protocol.
902 @retval FALSE The handle of the controller does not need the Dhcp protocol.
903
904 **/
905 BOOLEAN
906 IScsiDhcpIsConfigured (
907 IN EFI_HANDLE Controller,
908 IN UINT8 IpVersion
909 )
910 {
911 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp;
912 UINT8 *AttemptConfigOrder;
913 UINTN AttemptConfigOrderSize;
914 UINTN Index;
915 EFI_STATUS Status;
916 EFI_MAC_ADDRESS MacAddr;
917 UINTN HwAddressSize;
918 UINT16 VlanId;
919 CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN];
920 CHAR16 AttemptName[ISCSI_NAME_IFR_MAX_SIZE];
921
922 AttemptConfigOrder = IScsiGetVariableAndSize (
923 L"AttemptOrder",
924 &gIScsiConfigGuid,
925 &AttemptConfigOrderSize
926 );
927 if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) {
928 return FALSE;
929 }
930
931 //
932 // Get MAC address of this network device.
933 //
934 Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);
935 if(EFI_ERROR (Status)) {
936 return FALSE;
937 }
938 //
939 // Get VLAN ID of this network device.
940 //
941 VlanId = NetLibGetVlanId (Controller);
942 IScsiMacAddrToStr (&MacAddr, (UINT32) HwAddressSize, VlanId, MacString);
943
944 for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
945 UnicodeSPrint (
946 AttemptName,
947 (UINTN) 128,
948 L"%s%d",
949 MacString,
950 (UINTN) AttemptConfigOrder[Index]
951 );
952 Status = GetVariable2 (
953 AttemptName,
954 &gEfiIScsiInitiatorNameProtocolGuid,
955 (VOID**)&AttemptTmp,
956 NULL
957 );
958 if(AttemptTmp == NULL || EFI_ERROR (Status)) {
959 continue;
960 }
961
962 ASSERT (AttemptConfigOrder[Index] == AttemptTmp->AttemptConfigIndex);
963
964 if (AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED) {
965 FreePool (AttemptTmp);
966 continue;
967 }
968
969 if (AttemptTmp->SessionConfigData.IpMode != IP_MODE_AUTOCONFIG &&
970 AttemptTmp->SessionConfigData.IpMode != ((IpVersion == IP_VERSION_4) ? IP_MODE_IP4 : IP_MODE_IP6)) {
971 FreePool (AttemptTmp);
972 continue;
973 }
974
975 if(AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG ||
976 AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp == TRUE ||
977 AttemptTmp->SessionConfigData.TargetInfoFromDhcp == TRUE) {
978 FreePool (AttemptTmp);
979 FreePool (AttemptConfigOrder);
980 return TRUE;
981 }
982
983 FreePool (AttemptTmp);
984 }
985
986 FreePool (AttemptConfigOrder);
987 return FALSE;
988 }
989
990 /**
991 Get the various configuration data.
992
993 @param[in] Private The iSCSI driver data.
994
995 @retval EFI_SUCCESS The configuration data is retrieved.
996 @retval EFI_NOT_FOUND This iSCSI driver is not configured yet.
997
998 **/
999 EFI_STATUS
1000 IScsiGetConfigData (
1001 IN ISCSI_DRIVER_DATA *Private
1002 )
1003 {
1004 EFI_STATUS Status;
1005 CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN];
1006 UINTN Index;
1007 ISCSI_NIC_INFO *NicInfo;
1008 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
1009 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp;
1010 UINT8 *AttemptConfigOrder;
1011 UINTN AttemptConfigOrderSize;
1012 CHAR16 IScsiMode[64];
1013 CHAR16 IpMode[64];
1014
1015 //
1016 // There should be at least one attempt configured.
1017 //
1018 AttemptConfigOrder = IScsiGetVariableAndSize (
1019 L"AttemptOrder",
1020 &gIScsiConfigGuid,
1021 &AttemptConfigOrderSize
1022 );
1023 if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) {
1024 return EFI_NOT_FOUND;
1025 }
1026
1027 //
1028 // Get the iSCSI Initiator Name.
1029 //
1030 mPrivate->InitiatorNameLength = ISCSI_NAME_MAX_SIZE;
1031 Status = gIScsiInitiatorName.Get (
1032 &gIScsiInitiatorName,
1033 &mPrivate->InitiatorNameLength,
1034 mPrivate->InitiatorName
1035 );
1036 if (EFI_ERROR (Status)) {
1037 return Status;
1038 }
1039
1040 //
1041 // Get the normal configuration.
1042 //
1043 for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
1044
1045 //
1046 // Check whether the attempt exists in AttemptConfig.
1047 //
1048 AttemptTmp = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);
1049 if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED) {
1050 continue;
1051 } else if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled != ISCSI_DISABLED) {
1052 //
1053 // Check the autoconfig path to see whether it should be retried.
1054 //
1055 if (AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&
1056 AttemptTmp->AutoConfigureMode != IP_MODE_AUTOCONFIG_SUCCESS) {
1057 if (mPrivate->Ipv6Flag &&
1058 AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6) {
1059 //
1060 // Autoconfigure for IP6 already attempted but failed. Do not try again.
1061 //
1062 continue;
1063 } else if (!mPrivate->Ipv6Flag &&
1064 AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4) {
1065 //
1066 // Autoconfigure for IP4 already attempted but failed. Do not try again.
1067 //
1068 continue;
1069 } else {
1070 //
1071 // Try another approach for this autoconfigure path.
1072 //
1073 AttemptTmp->AutoConfigureMode =
1074 (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);
1075 AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp = TRUE;
1076 AttemptTmp->SessionConfigData.TargetInfoFromDhcp = TRUE;
1077 AttemptTmp->DhcpSuccess = FALSE;
1078
1079 //
1080 // Get some information from the dhcp server.
1081 //
1082 if (!mPrivate->Ipv6Flag) {
1083 Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);
1084 if (!EFI_ERROR (Status)) {
1085 AttemptTmp->DhcpSuccess = TRUE;
1086 }
1087 } else {
1088 Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);
1089 if (!EFI_ERROR (Status)) {
1090 AttemptTmp->DhcpSuccess = TRUE;
1091 }
1092 }
1093
1094 //
1095 // Refresh the state of this attempt to NVR.
1096 //
1097 AsciiStrToUnicodeStr (AttemptTmp->MacString, MacString);
1098 UnicodeSPrint (
1099 mPrivate->PortString,
1100 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1101 L"%s%d",
1102 MacString,
1103 (UINTN) AttemptTmp->AttemptConfigIndex
1104 );
1105
1106 gRT->SetVariable (
1107 mPrivate->PortString,
1108 &gEfiIScsiInitiatorNameProtocolGuid,
1109 ISCSI_CONFIG_VAR_ATTR,
1110 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
1111 AttemptTmp
1112 );
1113
1114 continue;
1115 }
1116 } else if (AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp && !AttemptTmp->ValidPath) {
1117 //
1118 // Get DHCP information for already added, but failed, attempt.
1119 //
1120 AttemptTmp->DhcpSuccess = FALSE;
1121 if (!mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP4)) {
1122 Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);
1123 if (!EFI_ERROR (Status)) {
1124 AttemptTmp->DhcpSuccess = TRUE;
1125 }
1126 } else if (mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP6)) {
1127 Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);
1128 if (!EFI_ERROR (Status)) {
1129 AttemptTmp->DhcpSuccess = TRUE;
1130 }
1131 }
1132
1133 //
1134 // Refresh the state of this attempt to NVR.
1135 //
1136 AsciiStrToUnicodeStr (AttemptTmp->MacString, MacString);
1137 UnicodeSPrint (
1138 mPrivate->PortString,
1139 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1140 L"%s%d",
1141 MacString,
1142 (UINTN) AttemptTmp->AttemptConfigIndex
1143 );
1144
1145 gRT->SetVariable (
1146 mPrivate->PortString,
1147 &gEfiIScsiInitiatorNameProtocolGuid,
1148 ISCSI_CONFIG_VAR_ATTR,
1149 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
1150 AttemptTmp
1151 );
1152
1153 continue;
1154
1155 } else {
1156 continue;
1157 }
1158 }
1159
1160 //
1161 // This attempt does not exist in AttemptConfig. Try to add a new one.
1162 //
1163
1164 NicInfo = IScsiGetNicInfoByIndex (mPrivate->CurrentNic);
1165 ASSERT (NicInfo != NULL);
1166 IScsiMacAddrToStr (&NicInfo->PermanentAddress, NicInfo->HwAddressSize, NicInfo->VlanId, MacString);
1167 UnicodeSPrint (
1168 mPrivate->PortString,
1169 (UINTN) 128,
1170 L"%s%d",
1171 MacString,
1172 (UINTN) AttemptConfigOrder[Index]
1173 );
1174
1175 GetVariable2 (
1176 mPrivate->PortString,
1177 &gEfiIScsiInitiatorNameProtocolGuid,
1178 (VOID**)&AttemptConfigData,
1179 NULL
1180 );
1181
1182 if (AttemptConfigData == NULL) {
1183 continue;
1184 }
1185
1186 ASSERT (AttemptConfigOrder[Index] == AttemptConfigData->AttemptConfigIndex);
1187
1188 AttemptConfigData->NicIndex = NicInfo->NicIndex;
1189 AttemptConfigData->DhcpSuccess = FALSE;
1190 AttemptConfigData->ValidiBFTPath = (BOOLEAN) (mPrivate->EnableMpio ? TRUE : FALSE);
1191 AttemptConfigData->ValidPath = FALSE;
1192
1193 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {
1194 AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp = TRUE;
1195 AttemptConfigData->SessionConfigData.TargetInfoFromDhcp = TRUE;
1196
1197 AttemptConfigData->AutoConfigureMode =
1198 (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);
1199 }
1200
1201 //
1202 // Get some information from dhcp server.
1203 //
1204 if (AttemptConfigData->SessionConfigData.Enabled != ISCSI_DISABLED &&
1205 AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp) {
1206
1207 if (!mPrivate->Ipv6Flag &&
1208 (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4 ||
1209 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4)) {
1210 Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptConfigData);
1211 if (!EFI_ERROR (Status)) {
1212 AttemptConfigData->DhcpSuccess = TRUE;
1213 }
1214 } else if (mPrivate->Ipv6Flag &&
1215 (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6 ||
1216 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6)) {
1217 Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptConfigData);
1218 if (!EFI_ERROR (Status)) {
1219 AttemptConfigData->DhcpSuccess = TRUE;
1220 }
1221 }
1222
1223 //
1224 // Refresh the state of this attempt to NVR.
1225 //
1226 AsciiStrToUnicodeStr (AttemptConfigData->MacString, MacString);
1227 UnicodeSPrint (
1228 mPrivate->PortString,
1229 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1230 L"%s%d",
1231 MacString,
1232 (UINTN) AttemptConfigData->AttemptConfigIndex
1233 );
1234
1235 gRT->SetVariable (
1236 mPrivate->PortString,
1237 &gEfiIScsiInitiatorNameProtocolGuid,
1238 ISCSI_CONFIG_VAR_ATTR,
1239 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
1240 AttemptConfigData
1241 );
1242 }
1243
1244 //
1245 // Update Attempt Help Info.
1246 //
1247
1248 if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_DISABLED) {
1249 UnicodeSPrint (IScsiMode, 64, L"Disabled");
1250 } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {
1251 UnicodeSPrint (IScsiMode, 64, L"Enabled");
1252 } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
1253 UnicodeSPrint (IScsiMode, 64, L"Enabled for MPIO");
1254 }
1255
1256 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4) {
1257 UnicodeSPrint (IpMode, 64, L"IP4");
1258 } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6) {
1259 UnicodeSPrint (IpMode, 64, L"IP6");
1260 } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {
1261 UnicodeSPrint (IpMode, 64, L"Autoconfigure");
1262 }
1263
1264 UnicodeSPrint (
1265 mPrivate->PortString,
1266 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1267 L"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",
1268 MacString,
1269 NicInfo->BusNumber,
1270 NicInfo->DeviceNumber,
1271 NicInfo->FunctionNumber,
1272 IScsiMode,
1273 IpMode
1274 );
1275
1276 AttemptConfigData->AttemptTitleHelpToken = HiiSetString (
1277 mCallbackInfo->RegisteredHandle,
1278 0,
1279 mPrivate->PortString,
1280 NULL
1281 );
1282 ASSERT (AttemptConfigData->AttemptTitleHelpToken != 0);
1283
1284 //
1285 // Record the attempt in global link list.
1286 //
1287 InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);
1288 mPrivate->AttemptCount++;
1289
1290 if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
1291 mPrivate->MpioCount++;
1292 mPrivate->EnableMpio = TRUE;
1293
1294 if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB) {
1295 mPrivate->Krb5MpioCount++;
1296 }
1297 } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {
1298 mPrivate->SinglePathCount++;
1299 }
1300 }
1301
1302 //
1303 // Reorder the AttemptConfig by the configured order.
1304 //
1305 for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
1306 AttemptConfigData = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);
1307 if (AttemptConfigData == NULL) {
1308 continue;
1309 }
1310
1311 RemoveEntryList (&AttemptConfigData->Link);
1312 InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);
1313 }
1314
1315 //
1316 // Update the Main Form.
1317 //
1318 IScsiConfigUpdateAttempt ();
1319
1320 FreePool (AttemptConfigOrder);
1321
1322 //
1323 // There should be at least one attempt configuration.
1324 //
1325 if (!mPrivate->EnableMpio) {
1326 if (mPrivate->SinglePathCount == 0) {
1327 return EFI_NOT_FOUND;
1328 }
1329 mPrivate->ValidSinglePathCount = mPrivate->SinglePathCount;
1330 }
1331
1332 return EFI_SUCCESS;
1333 }
1334
1335
1336 /**
1337 Get the device path of the iSCSI tcp connection and update it.
1338
1339 @param Session The iSCSI session.
1340
1341 @return The updated device path.
1342 @retval NULL Other errors as indicated.
1343
1344 **/
1345 EFI_DEVICE_PATH_PROTOCOL *
1346 IScsiGetTcpConnDevicePath (
1347 IN ISCSI_SESSION *Session
1348 )
1349 {
1350 ISCSI_CONNECTION *Conn;
1351 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1352 EFI_STATUS Status;
1353 EFI_DEV_PATH *DPathNode;
1354
1355 if (Session->State != SESSION_STATE_LOGGED_IN) {
1356 return NULL;
1357 }
1358
1359 Conn = NET_LIST_USER_STRUCT_S (
1360 Session->Conns.ForwardLink,
1361 ISCSI_CONNECTION,
1362 Link,
1363 ISCSI_CONNECTION_SIGNATURE
1364 );
1365
1366 Status = gBS->HandleProtocol (
1367 Conn->TcpIo.Handle,
1368 &gEfiDevicePathProtocolGuid,
1369 (VOID **) &DevicePath
1370 );
1371 if (EFI_ERROR (Status)) {
1372 return NULL;
1373 }
1374 //
1375 // Duplicate it.
1376 //
1377 DevicePath = DuplicateDevicePath (DevicePath);
1378 if (DevicePath == NULL) {
1379 return NULL;
1380 }
1381
1382 DPathNode = (EFI_DEV_PATH *) DevicePath;
1383
1384 while (!IsDevicePathEnd (&DPathNode->DevPath)) {
1385 if (DevicePathType (&DPathNode->DevPath) == MESSAGING_DEVICE_PATH) {
1386 if (!Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv4_DP) {
1387 DPathNode->Ipv4.LocalPort = 0;
1388
1389 DPathNode->Ipv4.StaticIpAddress =
1390 (BOOLEAN) (!Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp);
1391
1392 IP4_COPY_ADDRESS (
1393 &DPathNode->Ipv4.GatewayIpAddress,
1394 &Session->ConfigData->SessionConfigData.Gateway
1395 );
1396
1397 IP4_COPY_ADDRESS (
1398 &DPathNode->Ipv4.SubnetMask,
1399 &Session->ConfigData->SessionConfigData.SubnetMask
1400 );
1401 break;
1402 } else if (Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv6_DP) {
1403 DPathNode->Ipv6.LocalPort = 0;
1404 DPathNode->Ipv6.IpAddressOrigin = 0;
1405 DPathNode->Ipv6.PrefixLength = IP6_PREFIX_LENGTH;
1406 ZeroMem (&DPathNode->Ipv6.GatewayIpAddress, sizeof (EFI_IPv6_ADDRESS));
1407 break;
1408 }
1409 }
1410
1411 DPathNode = (EFI_DEV_PATH *) NextDevicePathNode (&DPathNode->DevPath);
1412 }
1413
1414 return DevicePath;
1415 }
1416
1417
1418 /**
1419 Abort the session when the transition from BS to RT is initiated.
1420
1421 @param[in] Event The event signaled.
1422 @param[in] Context The iSCSI driver data.
1423
1424 **/
1425 VOID
1426 EFIAPI
1427 IScsiOnExitBootService (
1428 IN EFI_EVENT Event,
1429 IN VOID *Context
1430 )
1431 {
1432 ISCSI_DRIVER_DATA *Private;
1433
1434 Private = (ISCSI_DRIVER_DATA *) Context;
1435 gBS->CloseEvent (Private->ExitBootServiceEvent);
1436
1437 if (Private->Session != NULL) {
1438 IScsiSessionAbort (Private->Session);
1439 }
1440 }
1441
1442 /**
1443 Tests whether a controller handle is being managed by IScsi driver.
1444
1445 This function tests whether the driver specified by DriverBindingHandle is
1446 currently managing the controller specified by ControllerHandle. This test
1447 is performed by evaluating if the the protocol specified by ProtocolGuid is
1448 present on ControllerHandle and is was opened by DriverBindingHandle and Nic
1449 Device handle with an attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
1450 If ProtocolGuid is NULL, then ASSERT().
1451
1452 @param ControllerHandle A handle for a controller to test.
1453 @param DriverBindingHandle Specifies the driver binding handle for the
1454 driver.
1455 @param ProtocolGuid Specifies the protocol that the driver specified
1456 by DriverBindingHandle opens in its Start()
1457 function.
1458
1459 @retval EFI_SUCCESS ControllerHandle is managed by the driver
1460 specified by DriverBindingHandle.
1461 @retval EFI_UNSUPPORTED ControllerHandle is not managed by the driver
1462 specified by DriverBindingHandle.
1463
1464 **/
1465 EFI_STATUS
1466 EFIAPI
1467 IScsiTestManagedDevice (
1468 IN EFI_HANDLE ControllerHandle,
1469 IN EFI_HANDLE DriverBindingHandle,
1470 IN EFI_GUID *ProtocolGuid
1471 )
1472 {
1473 EFI_STATUS Status;
1474 VOID *ManagedInterface;
1475 EFI_HANDLE NicControllerHandle;
1476
1477 ASSERT (ProtocolGuid != NULL);
1478
1479 NicControllerHandle = NetLibGetNicHandle (ControllerHandle, ProtocolGuid);
1480 if (NicControllerHandle == NULL) {
1481 return EFI_UNSUPPORTED;
1482 }
1483
1484 Status = gBS->OpenProtocol (
1485 ControllerHandle,
1486 (EFI_GUID *) ProtocolGuid,
1487 &ManagedInterface,
1488 DriverBindingHandle,
1489 NicControllerHandle,
1490 EFI_OPEN_PROTOCOL_BY_DRIVER
1491 );
1492 if (!EFI_ERROR (Status)) {
1493 gBS->CloseProtocol (
1494 ControllerHandle,
1495 (EFI_GUID *) ProtocolGuid,
1496 DriverBindingHandle,
1497 NicControllerHandle
1498 );
1499 return EFI_UNSUPPORTED;
1500 }
1501
1502 if (Status != EFI_ALREADY_STARTED) {
1503 return EFI_UNSUPPORTED;
1504 }
1505
1506 return EFI_SUCCESS;
1507 }