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