TianoCore EDK2 master
Loading...
Searching...
No Matches
IScsiProto.c
Go to the documentation of this file.
1
9#include "IScsiImpl.h"
10
11UINT32 mDataSegPad = 0;
12
20VOID
22 IN OUT ISCSI_SESSION *Session,
24 )
25{
26 InsertTailList (&Session->Conns, &Conn->Link);
27 Conn->Session = Session;
28 Session->NumConns++;
29}
30
37VOID
40 )
41{
42 RemoveEntryList (&Conn->Link);
43 Conn->Session->NumConns--;
44 Conn->Session = NULL;
45}
46
60 IN OUT UINT32 *ExpSN,
61 IN UINT32 NewSN
62 )
63{
64 if (!ISCSI_SEQ_EQ (NewSN, *ExpSN)) {
65 if (ISCSI_SEQ_LT (NewSN, *ExpSN)) {
66 //
67 // Duplicate
68 //
69 return EFI_NOT_READY;
70 } else {
71 return EFI_PROTOCOL_ERROR;
72 }
73 } else {
74 //
75 // Advance the ExpSN
76 //
77 (*ExpSN)++;
78 return EFI_SUCCESS;
79 }
80}
81
90VOID
92 IN OUT ISCSI_SESSION *Session,
93 IN UINT32 MaxCmdSN,
94 IN UINT32 ExpCmdSN
95 )
96{
97 if (ISCSI_SEQ_LT (MaxCmdSN, ExpCmdSN - 1)) {
98 return;
99 }
100
101 if (ISCSI_SEQ_GT (MaxCmdSN, Session->MaxCmdSN)) {
102 Session->MaxCmdSN = MaxCmdSN;
103 }
104
105 if (ISCSI_SEQ_GT (ExpCmdSN, Session->ExpCmdSN)) {
106 Session->ExpCmdSN = ExpCmdSN;
107 }
108}
109
123 IN OUT ISCSI_CONNECTION *Conn,
124 IN UINT16 Timeout
125 )
126{
127 EFI_STATUS Status;
128
129 //
130 // Start the timer, and wait Timeout seconds to establish the TCP connection.
131 //
132 Status = gBS->SetTimer (
133 Conn->TimeoutEvent,
135 MultU64x32 (Timeout, TICKS_PER_MS)
136 );
137 if (EFI_ERROR (Status)) {
138 return Status;
139 }
140
141 //
142 // Try to establish the tcp connection.
143 //
144 Status = TcpIoConnect (&Conn->TcpIo, Conn->TimeoutEvent);
145 gBS->SetTimer (Conn->TimeoutEvent, TimerCancel, 0);
146
147 if (EFI_ERROR (Status)) {
148 return Status;
149 }
150
151 Conn->State = CONN_STATE_IN_LOGIN;
152
153 //
154 // Connection is established, start the iSCSI Login.
155 //
156 do {
157 Status = IScsiSendLoginReq (Conn);
158 if (EFI_ERROR (Status)) {
159 break;
160 }
161
162 Status = IScsiReceiveLoginRsp (Conn);
163 if (EFI_ERROR (Status)) {
164 break;
165 }
166 } while (Conn->CurrentStage != ISCSI_FULL_FEATURE_PHASE);
167
168 return Status;
169}
170
177VOID
180 )
181{
182 TcpIoReset (&Conn->TcpIo);
183}
184
195 IN ISCSI_SESSION *Session
196 )
197{
198 ISCSI_DRIVER_DATA *Private;
200 ISCSI_CONNECTION *Conn;
201 TCP_IO_CONFIG_DATA TcpIoConfig;
202 TCP4_IO_CONFIG_DATA *Tcp4IoConfig;
203 TCP6_IO_CONFIG_DATA *Tcp6IoConfig;
204 EFI_STATUS Status;
205
206 Private = Session->Private;
207 NvData = &Session->ConfigData->SessionConfigData;
208
209 Conn = AllocateZeroPool (sizeof (ISCSI_CONNECTION));
210 if (Conn == NULL) {
211 return NULL;
212 }
213
214 Conn->Signature = ISCSI_CONNECTION_SIGNATURE;
215 Conn->State = CONN_STATE_FREE;
216 Conn->CurrentStage = ISCSI_SECURITY_NEGOTIATION;
217 Conn->NextStage = ISCSI_LOGIN_OPERATIONAL_NEGOTIATION;
218 Conn->AuthStep = ISCSI_AUTH_INITIAL;
219 Conn->ExpStatSN = 0;
220 Conn->PartialReqSent = FALSE;
221 Conn->PartialRspRcvd = FALSE;
222 Conn->ParamNegotiated = FALSE;
223 Conn->Cid = Session->NextCid++;
224 Conn->Ipv6Flag = NvData->IpMode == IP_MODE_IP6 || Session->ConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6;
225
226 Status = gBS->CreateEvent (
227 EVT_TIMER,
228 TPL_CALLBACK,
229 NULL,
230 NULL,
231 &Conn->TimeoutEvent
232 );
233 if (EFI_ERROR (Status)) {
234 FreePool (Conn);
235 return NULL;
236 }
237
238 NetbufQueInit (&Conn->RspQue);
239
240 //
241 // Set the default connection-only parameters.
242 //
243 Conn->MaxRecvDataSegmentLength = DEFAULT_MAX_RECV_DATA_SEG_LEN;
244 Conn->HeaderDigest = IScsiDigestNone;
245 Conn->DataDigest = IScsiDigestNone;
246
247 if (NvData->DnsMode) {
248 //
249 // perform dns process if target address expressed by domain name.
250 //
251 if (!Conn->Ipv6Flag) {
252 Status = IScsiDns4 (Private->Image, Private->Controller, NvData);
253 } else {
254 Status = IScsiDns6 (Private->Image, Private->Controller, NvData);
255 }
256
257 if (EFI_ERROR (Status)) {
258 DEBUG ((DEBUG_ERROR, "The configuration of Target address or DNS server address is invalid!\n"));
259 FreePool (Conn);
260 return NULL;
261 }
262 }
263
264 if (!Conn->Ipv6Flag) {
265 Tcp4IoConfig = &TcpIoConfig.Tcp4IoConfigData;
266
267 CopyMem (&Tcp4IoConfig->LocalIp, &NvData->LocalIp, sizeof (EFI_IPv4_ADDRESS));
268 CopyMem (&Tcp4IoConfig->SubnetMask, &NvData->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
269 CopyMem (&Tcp4IoConfig->Gateway, &NvData->Gateway, sizeof (EFI_IPv4_ADDRESS));
270 CopyMem (&Tcp4IoConfig->RemoteIp, &NvData->TargetIp, sizeof (EFI_IPv4_ADDRESS));
271
272 Tcp4IoConfig->RemotePort = NvData->TargetPort;
273 Tcp4IoConfig->ActiveFlag = TRUE;
274 Tcp4IoConfig->StationPort = 0;
275 } else {
276 Tcp6IoConfig = &TcpIoConfig.Tcp6IoConfigData;
277
278 CopyMem (&Tcp6IoConfig->RemoteIp, &NvData->TargetIp, sizeof (EFI_IPv6_ADDRESS));
279 Tcp6IoConfig->RemotePort = NvData->TargetPort;
280 Tcp6IoConfig->ActiveFlag = TRUE;
281 Tcp6IoConfig->StationPort = 0;
282 }
283
284 //
285 // Create the TCP IO for this connection.
286 //
287 Status = TcpIoCreateSocket (
288 Private->Image,
289 Private->Controller,
290 (UINT8)(!Conn->Ipv6Flag ? TCP_VERSION_4 : TCP_VERSION_6),
291 &TcpIoConfig,
292 &Conn->TcpIo
293 );
294 if (EFI_ERROR (Status)) {
295 gBS->CloseEvent (Conn->TimeoutEvent);
296 FreePool (Conn);
297 Conn = NULL;
298 }
299
300 return Conn;
301}
302
309VOID
311 IN ISCSI_CONNECTION *Conn
312 )
313{
314 TcpIoDestroySocket (&Conn->TcpIo);
315
316 NetbufQueFlush (&Conn->RspQue);
317 gBS->CloseEvent (Conn->TimeoutEvent);
318 FreePool (Conn);
319}
320
333 IN ISCSI_CONNECTION *Conn
334 )
335{
337 EFI_TCP6_PROTOCOL *Tcp6;
338 EFI_IP6_MODE_DATA Ip6ModeData;
339 EFI_STATUS Status;
340 EFI_IPv6_ADDRESS *TargetIp;
341 UINTN Index;
342 UINT8 SubnetPrefixLength;
343 UINTN RouteEntry;
344
345 NvData = &Conn->Session->ConfigData->SessionConfigData;
346 TargetIp = &NvData->TargetIp.v6;
347 Tcp6 = Conn->TcpIo.Tcp.Tcp6;
348
349 ZeroMem (&Ip6ModeData, sizeof (EFI_IP6_MODE_DATA));
350 Status = Tcp6->GetModeData (
351 Tcp6,
352 NULL,
353 NULL,
354 &Ip6ModeData,
355 NULL,
356 NULL
357 );
358 if (EFI_ERROR (Status)) {
359 return Status;
360 }
361
362 if (!Ip6ModeData.IsConfigured) {
363 Status = EFI_ABORTED;
364 goto ON_EXIT;
365 }
366
367 IP6_COPY_ADDRESS (&NvData->LocalIp, &Ip6ModeData.ConfigData.StationAddress);
368
369 NvData->PrefixLength = 0;
370 for (Index = 0; Index < Ip6ModeData.AddressCount; Index++) {
371 if (EFI_IP6_EQUAL (&NvData->LocalIp.v6, &Ip6ModeData.AddressList[Index].Address)) {
372 NvData->PrefixLength = Ip6ModeData.AddressList[Index].PrefixLength;
373 break;
374 }
375 }
376
377 SubnetPrefixLength = 0;
378 RouteEntry = Ip6ModeData.RouteCount;
379 for (Index = 0; Index < Ip6ModeData.RouteCount; Index++) {
380 if (NetIp6IsNetEqual (TargetIp, &Ip6ModeData.RouteTable[Index].Destination, Ip6ModeData.RouteTable[Index].PrefixLength)) {
381 if (SubnetPrefixLength < Ip6ModeData.RouteTable[Index].PrefixLength) {
382 SubnetPrefixLength = Ip6ModeData.RouteTable[Index].PrefixLength;
383 RouteEntry = Index;
384 }
385 }
386 }
387
388 if (RouteEntry != Ip6ModeData.RouteCount) {
389 IP6_COPY_ADDRESS (&NvData->Gateway, &Ip6ModeData.RouteTable[RouteEntry].Gateway);
390 }
391
392ON_EXIT:
393 if (Ip6ModeData.AddressList != NULL) {
394 FreePool (Ip6ModeData.AddressList);
395 }
396
397 if (Ip6ModeData.GroupTable != NULL) {
398 FreePool (Ip6ModeData.GroupTable);
399 }
400
401 if (Ip6ModeData.RouteTable != NULL) {
402 FreePool (Ip6ModeData.RouteTable);
403 }
404
405 if (Ip6ModeData.NeighborCache != NULL) {
406 FreePool (Ip6ModeData.NeighborCache);
407 }
408
409 if (Ip6ModeData.PrefixTable != NULL) {
410 FreePool (Ip6ModeData.PrefixTable);
411 }
412
413 if (Ip6ModeData.IcmpTypeList != NULL) {
414 FreePool (Ip6ModeData.IcmpTypeList);
415 }
416
417 return Status;
418}
419
429STATIC
430VOID
432 IN OUT ISCSI_SESSION *Session
433 )
434{
435 if (Session->AuthType == ISCSI_AUTH_TYPE_CHAP) {
436 Session->AuthData.CHAP.Hash = NULL;
437 }
438}
439
453 IN ISCSI_SESSION *Session
454 )
455{
456 EFI_STATUS Status;
457 ISCSI_CONNECTION *Conn;
458 VOID *Tcp;
459 EFI_GUID *ProtocolGuid;
460 UINT8 RetryCount;
461 EFI_STATUS MediaStatus;
462
463 //
464 // Check media status before session login.
465 //
466 MediaStatus = EFI_SUCCESS;
467 NetLibDetectMediaWaitTimeout (Session->Private->Controller, ISCSI_CHECK_MEDIA_LOGIN_WAITING_TIME, &MediaStatus);
468 if (MediaStatus != EFI_SUCCESS) {
469 return EFI_NO_MEDIA;
470 }
471
472 //
473 // Set session identifier
474 //
475 CopyMem (Session->Isid, Session->ConfigData->SessionConfigData.IsId, 6);
476
477 RetryCount = 0;
478
479 do {
480 //
481 // Create a connection for the session.
482 //
483 Conn = IScsiCreateConnection (Session);
484 if (Conn == NULL) {
485 return EFI_OUT_OF_RESOURCES;
486 }
487
488 IScsiAttatchConnection (Session, Conn);
489
490 //
491 // Login through the newly created connection.
492 //
494 Status = IScsiConnLogin (Conn, Session->ConfigData->SessionConfigData.ConnectTimeout);
495 if (EFI_ERROR (Status)) {
496 IScsiConnReset (Conn);
499 }
500
501 if (Status != EFI_TIMEOUT) {
502 break;
503 }
504
505 RetryCount++;
506 } while (RetryCount <= Session->ConfigData->SessionConfigData.ConnectRetryCount);
507
508 if (!EFI_ERROR (Status)) {
509 Session->State = SESSION_STATE_LOGGED_IN;
510
511 if (!Conn->Ipv6Flag) {
512 ProtocolGuid = &gEfiTcp4ProtocolGuid;
513 } else {
514 ProtocolGuid = &gEfiTcp6ProtocolGuid;
515 }
516
517 Status = gBS->OpenProtocol (
518 Conn->TcpIo.Handle,
519 ProtocolGuid,
520 (VOID **)&Tcp,
521 Session->Private->Image,
522 Session->Private->ExtScsiPassThruHandle,
523 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
524 );
525
526 ASSERT_EFI_ERROR (Status);
527
528 if (Conn->Ipv6Flag) {
529 Status = IScsiGetIp6NicInfo (Conn);
530 }
531 }
532
533 return Status;
534}
535
548 IN ISCSI_SESSION *Session
549 )
550{
551 EFI_STATUS Status;
552 EFI_STATUS TimerStatus;
553 EFI_EVENT Timer;
554
555 Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);
556 if (EFI_ERROR (Status)) {
557 return Status;
558 }
559
560 Status = gBS->SetTimer (
561 Timer,
564 );
565
566 if (EFI_ERROR (Status)) {
567 gBS->CloseEvent (Timer);
568 return Status;
569 }
570
571 do {
572 TimerStatus = gBS->CheckEvent (Timer);
573
574 if (!EFI_ERROR (TimerStatus)) {
575 Status = IScsiSessionLogin (Session);
576 }
577 } while (TimerStatus == EFI_NOT_READY);
578
579 gBS->CloseEvent (Timer);
580 return Status;
581}
582
597 IN ISCSI_CONNECTION *Conn
598 )
599{
600 NET_BUF *Pdu;
601 EFI_STATUS Status;
602
603 //
604 // Build the Login Request PDU.
605 //
606 Pdu = IScsiPrepareLoginReq (Conn);
607 if (Pdu == NULL) {
608 return EFI_DEVICE_ERROR;
609 }
610
611 //
612 // Send it to the iSCSI target.
613 //
614 Status = TcpIoTransmit (&Conn->TcpIo, Pdu);
615
616 NetbufFree (Pdu);
617
618 return Status;
619}
620
632 IN ISCSI_CONNECTION *Conn
633 )
634{
635 EFI_STATUS Status;
636 NET_BUF *Pdu;
637
638 Pdu = NULL;
639
640 //
641 // Receive the iSCSI login response.
642 //
643 Status = IScsiReceivePdu (Conn, &Pdu, NULL, FALSE, FALSE, NULL);
644 if (EFI_ERROR (Status)) {
645 return Status;
646 }
647
648 ASSERT (Pdu != NULL);
649
650 //
651 // A Login Response is received; process it.
652 //
653 Status = IScsiProcessLoginRsp (Conn, Pdu);
654
655 NetbufFree (Pdu);
656
657 return Status;
658}
659
678 IN OUT NET_BUF *Pdu,
679 IN CHAR8 *Key,
680 IN CHAR8 *Value
681 )
682{
683 UINT32 DataSegLen;
684 UINT32 KeyLen;
685 UINT32 ValueLen;
686 UINT32 TotalLen;
687 ISCSI_LOGIN_REQUEST *LoginReq;
688 CHAR8 *Data;
689
690 LoginReq = (ISCSI_LOGIN_REQUEST *)NetbufGetByte (Pdu, 0, NULL);
691 if (LoginReq == NULL) {
692 return EFI_PROTOCOL_ERROR;
693 }
694
695 DataSegLen = NTOH24 (LoginReq->DataSegmentLength);
696
697 KeyLen = (UINT32)AsciiStrLen (Key);
698 ValueLen = (UINT32)AsciiStrLen (Value);
699
700 //
701 // 1 byte for the key value separator '=' and 1 byte for the null
702 // delimiter after the value.
703 //
704 TotalLen = KeyLen + 1 + ValueLen + 1;
705
706 //
707 // Allocate the space for the key-value pair.
708 //
709 Data = (CHAR8 *)NetbufAllocSpace (Pdu, TotalLen, NET_BUF_TAIL);
710 if (Data == NULL) {
711 return EFI_OUT_OF_RESOURCES;
712 }
713
714 //
715 // Add the key.
716 //
717 CopyMem (Data, Key, KeyLen);
718 Data += KeyLen;
719
720 *Data = '=';
721 Data++;
722
723 //
724 // Add the value.
725 //
726 CopyMem (Data, Value, ValueLen);
727 Data += ValueLen;
728
729 *Data = '\0';
730
731 //
732 // Update the DataSegmentLength
733 //
734 ISCSI_SET_DATASEG_LEN (LoginReq, DataSegLen + TotalLen);
735
736 return EFI_SUCCESS;
737}
738
748NET_BUF *
751 )
752{
753 ISCSI_SESSION *Session;
754 NET_BUF *Nbuf;
755 ISCSI_LOGIN_REQUEST *LoginReq;
756 EFI_STATUS Status;
757
758 Session = Conn->Session;
759
760 Nbuf = NetbufAlloc (sizeof (ISCSI_LOGIN_REQUEST) + DEFAULT_MAX_RECV_DATA_SEG_LEN);
761 if (Nbuf == NULL) {
762 return NULL;
763 }
764
765 LoginReq = (ISCSI_LOGIN_REQUEST *)NetbufAllocSpace (Nbuf, sizeof (ISCSI_LOGIN_REQUEST), NET_BUF_TAIL);
766 if (LoginReq == NULL) {
767 NetbufFree (Nbuf);
768 return NULL;
769 }
770
771 ZeroMem (LoginReq, sizeof (ISCSI_LOGIN_REQUEST));
772
773 //
774 // Init the login request pdu
775 //
776 ISCSI_SET_OPCODE (LoginReq, ISCSI_OPCODE_LOGIN_REQ, ISCSI_REQ_IMMEDIATE);
777 ISCSI_SET_STAGES (LoginReq, Conn->CurrentStage, Conn->NextStage);
778 LoginReq->VersionMax = ISCSI_VERSION_MAX;
779 LoginReq->VersionMin = ISCSI_VERSION_MIN;
780 LoginReq->Tsih = HTONS (Session->Tsih);
781 LoginReq->InitiatorTaskTag = HTONL (Session->InitiatorTaskTag);
782 LoginReq->Cid = HTONS (Conn->Cid);
783 LoginReq->CmdSN = HTONL (Session->CmdSN);
784
785 //
786 // For the first Login Request on a connection this is ExpStatSN for the
787 // old connection, and this field is only valid if the Login Request restarts
788 // a connection.
789 // For subsequent Login Requests it is used to acknowledge the Login Responses
790 // with their increasing StatSN values.
791 //
792 LoginReq->ExpStatSN = HTONL (Conn->ExpStatSN);
793 CopyMem (LoginReq->Isid, Session->Isid, sizeof (LoginReq->Isid));
794
795 if (Conn->PartialRspRcvd) {
796 //
797 // A partial response. The initiator must send an empty Login Request.
798 //
799 return Nbuf;
800 }
801
802 Status = EFI_SUCCESS;
803
804 switch (Conn->CurrentStage) {
805 case ISCSI_SECURITY_NEGOTIATION:
806 //
807 // Both none authentication and CHAP authentication share the CHAP path.
808 //
809 //
810 if (Session->AuthType != ISCSI_AUTH_TYPE_KRB) {
811 Status = IScsiCHAPToSendReq (Conn, Nbuf);
812 }
813
814 break;
815
816 case ISCSI_LOGIN_OPERATIONAL_NEGOTIATION:
817 //
818 // Only negotiate the parameter once.
819 //
820 if (!Conn->ParamNegotiated) {
821 IScsiFillOpParams (Conn, Nbuf);
822 }
823
824 ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);
825 break;
826
827 default:
828 //
829 // An error occurs...
830 //
831 Status = EFI_DEVICE_ERROR;
832 break;
833 }
834
835 if (EFI_ERROR (Status)) {
836 NetbufFree (Nbuf);
837 Nbuf = NULL;
838 } else {
839 //
840 // Pad the data segment if needed.
841 //
842 IScsiPadSegment (Nbuf, ISCSI_GET_DATASEG_LEN (LoginReq));
843 //
844 // Check whether we will issue the stage transition signal?
845 //
846 Conn->TransitInitiated = ISCSI_FLAG_ON (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);
847 }
848
849 return Nbuf;
850}
851
866 IN OUT ISCSI_CONNECTION *Conn,
867 IN OUT NET_BUF *Pdu
868 )
869{
870 EFI_STATUS Status;
871 ISCSI_SESSION *Session;
872 ISCSI_LOGIN_RESPONSE *LoginRsp;
873 BOOLEAN Transit;
874 BOOLEAN Continue;
875 UINT8 CurrentStage;
876 UINT8 NextStage;
877 UINT8 *DataSeg;
878 UINT32 DataSegLen;
879
880 Status = EFI_SUCCESS;
881 Session = Conn->Session;
882
883 LoginRsp = (ISCSI_LOGIN_RESPONSE *)NetbufGetByte (Pdu, 0, NULL);
884 if (LoginRsp == NULL) {
885 return EFI_PROTOCOL_ERROR;
886 }
887
888 if (!ISCSI_CHECK_OPCODE (LoginRsp, ISCSI_OPCODE_LOGIN_RSP)) {
889 //
890 // It is not a Login Response.
891 //
892 return EFI_PROTOCOL_ERROR;
893 }
894
895 //
896 // Get the data segment, if any.
897 //
898 DataSegLen = ISCSI_GET_DATASEG_LEN (LoginRsp);
899 if (DataSegLen != 0) {
900 DataSeg = NetbufGetByte (Pdu, sizeof (ISCSI_LOGIN_RESPONSE), NULL);
901 } else {
902 DataSeg = NULL;
903 }
904
905 //
906 // Check the status class in the login response PDU.
907 //
908 switch (LoginRsp->StatusClass) {
909 case ISCSI_LOGIN_STATUS_SUCCESS:
910 //
911 // Just break here; the response and the data segment will be processed later.
912 //
913 break;
914
915 case ISCSI_LOGIN_STATUS_REDIRECTION:
916 //
917 // The target may be moved to a different address.
918 //
919 if (DataSeg == NULL) {
920 return EFI_PROTOCOL_ERROR;
921 }
922
923 //
924 // Process the TargetAddress key-value strings in the data segment to update the
925 // target address info.
926 //
927 Status = IScsiUpdateTargetAddress (Session, (CHAR8 *)DataSeg, DataSegLen);
928 if (EFI_ERROR (Status)) {
929 return Status;
930 }
931
932 //
933 // Session will be restarted on this error status because the Target is
934 // redirected by this Login Response.
935 //
936 return EFI_MEDIA_CHANGED;
937
938 default:
939 //
940 // Initiator Error, Target Error, or any other undefined error code.
941 //
942 return EFI_PROTOCOL_ERROR;
943 }
944
945 //
946 // The status is success; extract the wanted fields from the header segment.
947 //
948 Transit = ISCSI_FLAG_ON (LoginRsp, ISCSI_LOGIN_RSP_PDU_FLAG_TRANSIT);
949 Continue = ISCSI_FLAG_ON (LoginRsp, ISCSI_LOGIN_RSP_PDU_FLAG_CONTINUE);
950
951 CurrentStage = ISCSI_GET_CURRENT_STAGE (LoginRsp);
952 NextStage = ISCSI_GET_NEXT_STAGE (LoginRsp);
953
954 LoginRsp->InitiatorTaskTag = NTOHL (LoginRsp->InitiatorTaskTag);
955
956 if ((Transit && Continue) ||
957 (CurrentStage != Conn->CurrentStage) ||
958 (!Conn->TransitInitiated && Transit) ||
959 (Transit && (NextStage != Conn->NextStage)) ||
960 (CompareMem (Session->Isid, LoginRsp->Isid, sizeof (LoginRsp->Isid)) != 0) ||
961 (LoginRsp->InitiatorTaskTag != Session->InitiatorTaskTag)
962 )
963 {
964 //
965 // A Login Response with the C bit set to 1 MUST have the T bit set to 0.
966 // The CSG in the Login Response MUST be the same with the I-end of this connection.
967 // The T bit can't be 1 if the last Login Response sent by the initiator doesn't
968 // initiate the transition.
969 // The NSG MUST be the same with the I-end of this connection if Transit is required.
970 // The ISID in the Login Response MUST be the same with this session.
971 //
972 return EFI_PROTOCOL_ERROR;
973 }
974
975 LoginRsp->StatSN = NTOHL (LoginRsp->StatSN);
976 LoginRsp->ExpCmdSN = NTOHL (LoginRsp->ExpCmdSN);
977 LoginRsp->MaxCmdSN = NTOHL (LoginRsp->MaxCmdSN);
978
979 if ((Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION) && (Conn->AuthStep == ISCSI_AUTH_INITIAL)) {
980 //
981 // If the Login Request is a leading Login Request, the target MUST use
982 // the value presented in CmdSN as the target value for ExpCmdSN.
983 //
984 if ((Session->State == SESSION_STATE_FREE) && (Session->CmdSN != LoginRsp->ExpCmdSN)) {
985 return EFI_PROTOCOL_ERROR;
986 }
987
988 //
989 // It's the initial Login Response, initialize the local ExpStatSN, MaxCmdSN
990 // and ExpCmdSN.
991 //
992 Conn->ExpStatSN = LoginRsp->StatSN + 1;
993 Session->MaxCmdSN = LoginRsp->MaxCmdSN;
994 Session->ExpCmdSN = LoginRsp->ExpCmdSN;
995 } else {
996 //
997 // Check the StatSN of this PDU.
998 //
999 Status = IScsiCheckSN (&Conn->ExpStatSN, LoginRsp->StatSN);
1000 if (!EFI_ERROR (Status)) {
1001 //
1002 // Update the MaxCmdSN and ExpCmdSN.
1003 //
1004 IScsiUpdateCmdSN (Session, LoginRsp->MaxCmdSN, LoginRsp->ExpCmdSN);
1005 } else {
1006 return Status;
1007 }
1008 }
1009
1010 //
1011 // Trim off the header segment.
1012 //
1013 NetbufTrim (Pdu, sizeof (ISCSI_LOGIN_RESPONSE), NET_BUF_HEAD);
1014
1015 //
1016 // Queue this login response first in case it's a partial response so that
1017 // later when the full response list is received we can combine these scattered
1018 // responses' data segment and then process it.
1019 //
1020 NET_GET_REF (Pdu);
1021 NetbufQueAppend (&Conn->RspQue, Pdu);
1022
1023 Conn->PartialRspRcvd = Continue;
1024 if (Continue) {
1025 //
1026 // It is a partial response; must wait for another or more Request/Response
1027 // conversations to get the full response.
1028 //
1029 return EFI_SUCCESS;
1030 }
1031
1032 switch (CurrentStage) {
1033 case ISCSI_SECURITY_NEGOTIATION:
1034 //
1035 // In security negotiation stage, let CHAP module handle it.
1036 //
1037 if (Session->AuthType != ISCSI_AUTH_TYPE_KRB) {
1038 Status = IScsiCHAPOnRspReceived (Conn);
1039 }
1040
1041 break;
1042
1043 case ISCSI_LOGIN_OPERATIONAL_NEGOTIATION:
1044 //
1045 // Response received with negotiation response on iSCSI parameters: check them.
1046 //
1047 Status = IScsiCheckOpParams (Conn);
1048 if (!EFI_ERROR (Status)) {
1049 Conn->ParamNegotiated = TRUE;
1050 }
1051
1052 break;
1053
1054 default:
1055 //
1056 // Should never get here.
1057 //
1058 Status = EFI_PROTOCOL_ERROR;
1059 break;
1060 }
1061
1062 if (Transit && (Status == EFI_SUCCESS)) {
1063 //
1064 // Do the state transition.
1065 //
1066 Conn->CurrentStage = Conn->NextStage;
1067
1068 if (Conn->CurrentStage == ISCSI_LOGIN_OPERATIONAL_NEGOTIATION) {
1069 Conn->NextStage = ISCSI_FULL_FEATURE_PHASE;
1070 } else {
1071 //
1072 // CurrentStage is iSCSI Full Feature. It is the Login-Final Response;
1073 // get the TSIH from the Login Response.
1074 //
1075 Session->Tsih = NTOHS (LoginRsp->Tsih);
1076 }
1077 }
1078
1079 //
1080 // Flush the response(s) received.
1081 //
1082 NetbufQueFlush (&Conn->RspQue);
1083
1084 return Status;
1085}
1086
1104 IN OUT ISCSI_SESSION *Session,
1105 IN CHAR8 *Data,
1106 IN UINT32 Len
1107 )
1108{
1109 LIST_ENTRY *KeyValueList;
1110 CHAR8 *TargetAddress;
1111 CHAR8 *IpStr;
1112 EFI_STATUS Status;
1113 UINTN Number;
1114 UINT8 IpMode;
1116
1117 KeyValueList = IScsiBuildKeyValueList (Data, Len);
1118 if (KeyValueList == NULL) {
1119 return EFI_OUT_OF_RESOURCES;
1120 }
1121
1122 Status = EFI_NOT_FOUND;
1123 NvData = &Session->ConfigData->SessionConfigData;
1124
1125 while (TRUE) {
1126 TargetAddress = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_TARGET_ADDRESS);
1127 if (TargetAddress == NULL) {
1128 break;
1129 }
1130
1131 //
1132 // RFC 3720 defines format of the TargetAddress=domainname[:port][,portal-group-tag]
1133 // The domainname can be specified as either a DNS host name, adotted-decimal IPv4 address,
1134 // or a bracketed IPv6 address as specified in [RFC2732].
1135 //
1136 if (NET_IS_DIGIT (TargetAddress[0])) {
1137 //
1138 // The domainname of the target is presented in a dotted-decimal IPv4 address format.
1139 //
1140 IpStr = TargetAddress;
1141
1142 while ((*TargetAddress != '\0') && (*TargetAddress != ':') && (*TargetAddress != ',')) {
1143 //
1144 // NULL, ':', or ',' ends the IPv4 string.
1145 //
1146 TargetAddress++;
1147 }
1148 } else if (*TargetAddress == ISCSI_REDIRECT_ADDR_START_DELIMITER) {
1149 //
1150 // The domainname of the target is presented in a bracketed IPv6 address format.
1151 //
1152 TargetAddress++;
1153 IpStr = TargetAddress;
1154 while ((*TargetAddress != '\0') && (*TargetAddress != ISCSI_REDIRECT_ADDR_END_DELIMITER)) {
1155 //
1156 // ']' ends the IPv6 string.
1157 //
1158 TargetAddress++;
1159 }
1160
1161 if (*TargetAddress != ISCSI_REDIRECT_ADDR_END_DELIMITER) {
1162 continue;
1163 }
1164
1165 *TargetAddress = '\0';
1166 TargetAddress++;
1167 } else {
1168 //
1169 // The domainname of the target is presented in the format of a DNS host name.
1170 //
1171 IpStr = TargetAddress;
1172
1173 while ((*TargetAddress != '\0') && (*TargetAddress != ':') && (*TargetAddress != ',')) {
1174 TargetAddress++;
1175 }
1176
1177 NvData->DnsMode = TRUE;
1178 }
1179
1180 //
1181 // Save the original user setting which specifies the proxy/virtual iSCSI target.
1182 //
1183 NvData->OriginalTargetPort = NvData->TargetPort;
1184
1185 if (*TargetAddress == ',') {
1186 //
1187 // Comma and the portal group tag MUST be omitted if the TargetAddress is sent
1188 // as the result of a redirection.
1189 //
1190 continue;
1191 } else if (*TargetAddress == ':') {
1192 *TargetAddress = '\0';
1193
1194 TargetAddress++;
1195
1196 Number = AsciiStrDecimalToUintn (TargetAddress);
1197 if (Number > 0xFFFF) {
1198 continue;
1199 } else {
1200 NvData->TargetPort = (UINT16)Number;
1201 }
1202 } else {
1203 //
1204 // The string only contains the Target address. Use the well-known port.
1205 //
1206 NvData->TargetPort = ISCSI_WELL_KNOWN_PORT;
1207 }
1208
1209 //
1210 // Save the original user setting which specifies the proxy/virtual iSCSI target.
1211 //
1212 CopyMem (&NvData->OriginalTargetIp, &NvData->TargetIp, sizeof (EFI_IP_ADDRESS));
1213
1214 //
1215 // Update the target IP address.
1216 //
1217 if (NvData->IpMode < IP_MODE_AUTOCONFIG) {
1218 IpMode = NvData->IpMode;
1219 } else {
1220 IpMode = Session->ConfigData->AutoConfigureMode;
1221 }
1222
1223 if (NvData->DnsMode) {
1224 //
1225 // Target address is expressed as URL format, just save it and
1226 // do DNS resolution when creating a TCP connection.
1227 //
1228 if (AsciiStrSize (IpStr) > sizeof (Session->ConfigData->SessionConfigData.TargetUrl)) {
1229 return EFI_INVALID_PARAMETER;
1230 }
1231
1232 CopyMem (&Session->ConfigData->SessionConfigData.TargetUrl, IpStr, AsciiStrSize (IpStr));
1233 } else {
1234 Status = IScsiAsciiStrToIp (
1235 IpStr,
1236 IpMode,
1237 &Session->ConfigData->SessionConfigData.TargetIp
1238 );
1239
1240 if (EFI_ERROR (Status)) {
1241 continue;
1242 } else {
1243 NvData->RedirectFlag = TRUE;
1244 break;
1245 }
1246 }
1247 }
1248
1249 IScsiFreeKeyValueList (KeyValueList);
1250
1251 return Status;
1252}
1253
1260VOID
1261EFIAPI
1263 VOID *Arg
1264 )
1265{
1266 ASSERT (Arg != NULL);
1267
1268 NetbufFreeList ((LIST_ENTRY *)Arg);
1269 FreePool (Arg);
1270}
1271
1278VOID
1279EFIAPI
1281 VOID *Arg
1282 )
1283{
1284}
1285
1308 IN ISCSI_CONNECTION *Conn,
1309 OUT NET_BUF **Pdu,
1310 IN ISCSI_IN_BUFFER_CONTEXT *Context OPTIONAL,
1311 IN BOOLEAN HeaderDigest,
1312 IN BOOLEAN DataDigest,
1313 IN EFI_EVENT TimeoutEvent OPTIONAL
1314 )
1315{
1316 LIST_ENTRY *NbufList;
1317 UINT32 Len;
1318 NET_BUF *PduHdr;
1319 UINT8 *Header;
1320 EFI_STATUS Status;
1321 UINT32 PadLen;
1322 UINT32 InDataOffset;
1323 NET_FRAGMENT Fragment[2];
1324 UINT32 FragmentCount;
1325 NET_BUF *DataSeg;
1326 UINT32 PadAndCRC32[2];
1327
1328 NbufList = AllocatePool (sizeof (LIST_ENTRY));
1329 if (NbufList == NULL) {
1330 return EFI_OUT_OF_RESOURCES;
1331 }
1332
1333 InitializeListHead (NbufList);
1334
1335 //
1336 // The header digest will be received together with the PDU header, if exists.
1337 //
1338 Len = sizeof (ISCSI_BASIC_HEADER) + (HeaderDigest ? sizeof (UINT32) : 0);
1339 PduHdr = NetbufAlloc (Len);
1340 if (PduHdr == NULL) {
1341 Status = EFI_OUT_OF_RESOURCES;
1342 goto ON_EXIT;
1343 }
1344
1345 Header = NetbufAllocSpace (PduHdr, Len, NET_BUF_TAIL);
1346 if (Header == NULL) {
1347 Status = EFI_OUT_OF_RESOURCES;
1348 goto ON_EXIT;
1349 }
1350
1351 InsertTailList (NbufList, &PduHdr->List);
1352
1353 //
1354 // First step, receive the BHS of the PDU.
1355 //
1356 Status = TcpIoReceive (&Conn->TcpIo, PduHdr, FALSE, TimeoutEvent);
1357
1358 if (EFI_ERROR (Status)) {
1359 goto ON_EXIT;
1360 }
1361
1362 if (HeaderDigest) {
1363 //
1364 // TODO: check the header-digest.
1365 //
1366 //
1367 // Trim off the digest.
1368 //
1369 NetbufTrim (PduHdr, sizeof (UINT32), NET_BUF_TAIL);
1370 }
1371
1372 Len = ISCSI_GET_DATASEG_LEN (Header);
1373 if (Len == 0) {
1374 //
1375 // No data segment.
1376 //
1377 goto FORM_PDU;
1378 }
1379
1380 //
1381 // Get the length of the padding bytes of the data segment.
1382 //
1383 PadLen = ISCSI_GET_PAD_LEN (Len);
1384
1385 switch (ISCSI_GET_OPCODE (Header)) {
1386 case ISCSI_OPCODE_SCSI_DATA_IN:
1387 //
1388 // To reduce memory copy overhead, try to use the buffer described by Context
1389 // if the PDU is an iSCSI SCSI data.
1390 //
1391 InDataOffset = ISCSI_GET_BUFFER_OFFSET (Header);
1392 if ((Context == NULL) || ((InDataOffset + Len) > Context->InDataLen)) {
1393 Status = EFI_PROTOCOL_ERROR;
1394 goto ON_EXIT;
1395 }
1396
1397 Fragment[0].Len = Len;
1398 Fragment[0].Bulk = Context->InData + InDataOffset;
1399
1400 if (DataDigest || (PadLen != 0)) {
1401 //
1402 // The data segment is padded. Use two fragments to receive it:
1403 // the first to receive the useful data; the second to receive the padding.
1404 //
1405 Fragment[1].Len = PadLen + (DataDigest ? sizeof (UINT32) : 0);
1406 Fragment[1].Bulk = (UINT8 *)PadAndCRC32 + (4 - PadLen);
1407
1408 FragmentCount = 2;
1409 } else {
1410 FragmentCount = 1;
1411 }
1412
1413 DataSeg = NetbufFromExt (&Fragment[0], FragmentCount, 0, 0, IScsiNbufExtFree, NULL);
1414 if (DataSeg == NULL) {
1415 Status = EFI_OUT_OF_RESOURCES;
1416 goto ON_EXIT;
1417 }
1418
1419 break;
1420
1421 case ISCSI_OPCODE_SCSI_RSP:
1422 case ISCSI_OPCODE_NOP_IN:
1423 case ISCSI_OPCODE_LOGIN_RSP:
1424 case ISCSI_OPCODE_TEXT_RSP:
1425 case ISCSI_OPCODE_ASYNC_MSG:
1426 case ISCSI_OPCODE_REJECT:
1427 case ISCSI_OPCODE_VENDOR_T0:
1428 case ISCSI_OPCODE_VENDOR_T1:
1429 case ISCSI_OPCODE_VENDOR_T2:
1430 //
1431 // Allocate buffer to receive the data segment.
1432 //
1433 Len += PadLen + (DataDigest ? sizeof (UINT32) : 0);
1434 DataSeg = NetbufAlloc (Len);
1435 if (DataSeg == NULL) {
1436 Status = EFI_OUT_OF_RESOURCES;
1437 goto ON_EXIT;
1438 }
1439
1440 NetbufAllocSpace (DataSeg, Len, NET_BUF_TAIL);
1441 break;
1442
1443 default:
1444 Status = EFI_PROTOCOL_ERROR;
1445 goto ON_EXIT;
1446 }
1447
1448 InsertTailList (NbufList, &DataSeg->List);
1449
1450 //
1451 // Receive the data segment with the data digest, if any.
1452 //
1453 Status = TcpIoReceive (&Conn->TcpIo, DataSeg, FALSE, TimeoutEvent);
1454
1455 if (EFI_ERROR (Status)) {
1456 goto ON_EXIT;
1457 }
1458
1459 if (DataDigest) {
1460 //
1461 // TODO: Check the data digest.
1462 //
1463 NetbufTrim (DataSeg, sizeof (UINT32), NET_BUF_TAIL);
1464 }
1465
1466 if (PadLen != 0) {
1467 //
1468 // Trim off the padding bytes in the data segment.
1469 //
1470 NetbufTrim (DataSeg, PadLen, NET_BUF_TAIL);
1471 }
1472
1473FORM_PDU:
1474 //
1475 // Form the pdu from a list of pdu segments.
1476 //
1477 *Pdu = NetbufFromBufList (NbufList, 0, 0, IScsiFreeNbufList, NbufList);
1478 if (*Pdu == NULL) {
1479 Status = EFI_OUT_OF_RESOURCES;
1480 }
1481
1482ON_EXIT:
1483
1484 if (EFI_ERROR (Status)) {
1485 //
1486 // Free the Nbufs in this NbufList and the NbufList itself.
1487 //
1488 IScsiFreeNbufList (NbufList);
1489 }
1490
1491 return Status;
1492}
1493
1506 IN OUT ISCSI_CONNECTION *Conn
1507 )
1508{
1509 EFI_STATUS Status;
1510 LIST_ENTRY *KeyValueList;
1511 CHAR8 *Data;
1512 UINT32 Len;
1513 ISCSI_SESSION *Session;
1514 CHAR8 *Value;
1515 UINTN NumericValue;
1516
1517 ASSERT (Conn->RspQue.BufNum != 0);
1518
1519 Session = Conn->Session;
1520
1521 Len = Conn->RspQue.BufSize;
1522 Data = AllocatePool (Len);
1523 if (Data == NULL) {
1524 return EFI_OUT_OF_RESOURCES;
1525 }
1526
1527 NetbufQueCopy (&Conn->RspQue, 0, Len, (UINT8 *)Data);
1528
1529 Status = EFI_PROTOCOL_ERROR;
1530
1531 //
1532 // Extract the Key-Value pairs into a list.
1533 //
1534 KeyValueList = IScsiBuildKeyValueList (Data, Len);
1535 if (KeyValueList == NULL) {
1536 FreePool (Data);
1537 return Status;
1538 }
1539
1540 //
1541 // HeaderDigest
1542 //
1543 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_HEADER_DIGEST);
1544 if (Value == NULL) {
1545 goto ON_ERROR;
1546 }
1547
1548 if (AsciiStrCmp (Value, "CRC32") == 0) {
1549 if (Conn->HeaderDigest != IScsiDigestCRC32) {
1550 goto ON_ERROR;
1551 }
1552 } else if (AsciiStrCmp (Value, ISCSI_KEY_VALUE_NONE) == 0) {
1553 Conn->HeaderDigest = IScsiDigestNone;
1554 } else {
1555 goto ON_ERROR;
1556 }
1557
1558 //
1559 // DataDigest
1560 //
1561 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DATA_DIGEST);
1562 if (Value == NULL) {
1563 goto ON_ERROR;
1564 }
1565
1566 if (AsciiStrCmp (Value, "CRC32") == 0) {
1567 if (Conn->DataDigest != IScsiDigestCRC32) {
1568 goto ON_ERROR;
1569 }
1570 } else if (AsciiStrCmp (Value, ISCSI_KEY_VALUE_NONE) == 0) {
1571 Conn->DataDigest = IScsiDigestNone;
1572 } else {
1573 goto ON_ERROR;
1574 }
1575
1576 //
1577 // ErrorRecoveryLevel: result function is Minimum.
1578 //
1579 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_ERROR_RECOVERY_LEVEL);
1580 if (Value == NULL) {
1581 goto ON_ERROR;
1582 }
1583
1584 NumericValue = IScsiNetNtoi (Value);
1585 if (NumericValue > 2) {
1586 goto ON_ERROR;
1587 }
1588
1589 Session->ErrorRecoveryLevel = (UINT8)MIN (Session->ErrorRecoveryLevel, NumericValue);
1590
1591 //
1592 // InitialR2T: result function is OR.
1593 //
1594 if (!Session->InitialR2T) {
1595 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_INITIAL_R2T);
1596 if (Value == NULL) {
1597 goto ON_ERROR;
1598 }
1599
1600 Session->InitialR2T = (BOOLEAN)(AsciiStrCmp (Value, "Yes") == 0);
1601 }
1602
1603 //
1604 // ImmediateData: result function is AND.
1605 //
1606 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_IMMEDIATE_DATA);
1607 if (Value == NULL) {
1608 goto ON_ERROR;
1609 }
1610
1611 Session->ImmediateData = (BOOLEAN)(Session->ImmediateData && (BOOLEAN)(AsciiStrCmp (Value, "Yes") == 0));
1612
1613 //
1614 // MaxRecvDataSegmentLength is declarative.
1615 //
1616 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_MAX_RECV_DATA_SEGMENT_LENGTH);
1617 if (Value != NULL) {
1618 Conn->MaxRecvDataSegmentLength = (UINT32)IScsiNetNtoi (Value);
1619 }
1620
1621 //
1622 // MaxBurstLength: result function is Minimum.
1623 //
1624 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_MAX_BURST_LENGTH);
1625 if (Value == NULL) {
1626 goto ON_ERROR;
1627 }
1628
1629 NumericValue = IScsiNetNtoi (Value);
1630 Session->MaxBurstLength = (UINT32)MIN (Session->MaxBurstLength, NumericValue);
1631
1632 //
1633 // FirstBurstLength: result function is Minimum. Irrelevant when InitialR2T=Yes and
1634 // ImmediateData=No.
1635 //
1636 if (!(Session->InitialR2T && !Session->ImmediateData)) {
1637 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_FIRST_BURST_LENGTH);
1638 if (Value == NULL) {
1639 goto ON_ERROR;
1640 }
1641
1642 NumericValue = IScsiNetNtoi (Value);
1643 Session->FirstBurstLength = (UINT32)MIN (Session->FirstBurstLength, NumericValue);
1644 }
1645
1646 //
1647 // MaxConnections: result function is Minimum.
1648 //
1649 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_MAX_CONNECTIONS);
1650 if (Value == NULL) {
1651 goto ON_ERROR;
1652 }
1653
1654 NumericValue = IScsiNetNtoi (Value);
1655 if ((NumericValue == 0) || (NumericValue > 65535)) {
1656 goto ON_ERROR;
1657 }
1658
1659 Session->MaxConnections = (UINT32)MIN (Session->MaxConnections, NumericValue);
1660
1661 //
1662 // DataPDUInOrder: result function is OR.
1663 //
1664 if (!Session->DataPDUInOrder) {
1665 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DATA_PDU_IN_ORDER);
1666 if (Value == NULL) {
1667 goto ON_ERROR;
1668 }
1669
1670 Session->DataPDUInOrder = (BOOLEAN)(AsciiStrCmp (Value, "Yes") == 0);
1671 }
1672
1673 //
1674 // DataSequenceInorder: result function is OR.
1675 //
1676 if (!Session->DataSequenceInOrder) {
1677 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DATA_SEQUENCE_IN_ORDER);
1678 if (Value == NULL) {
1679 goto ON_ERROR;
1680 }
1681
1682 Session->DataSequenceInOrder = (BOOLEAN)(AsciiStrCmp (Value, "Yes") == 0);
1683 }
1684
1685 //
1686 // DefaultTime2Wait: result function is Maximum.
1687 //
1688 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DEFAULT_TIME2WAIT);
1689 if (Value == NULL) {
1690 goto ON_ERROR;
1691 }
1692
1693 NumericValue = IScsiNetNtoi (Value);
1694 if (NumericValue == 0) {
1695 Session->DefaultTime2Wait = 0;
1696 } else if (NumericValue > 3600) {
1697 goto ON_ERROR;
1698 } else {
1699 Session->DefaultTime2Wait = (UINT32)MAX (Session->DefaultTime2Wait, NumericValue);
1700 }
1701
1702 //
1703 // DefaultTime2Retain: result function is Minimum.
1704 //
1705 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DEFAULT_TIME2RETAIN);
1706 if (Value == NULL) {
1707 goto ON_ERROR;
1708 }
1709
1710 NumericValue = IScsiNetNtoi (Value);
1711 if (NumericValue == 0) {
1712 Session->DefaultTime2Retain = 0;
1713 } else if (NumericValue > 3600) {
1714 goto ON_ERROR;
1715 } else {
1716 Session->DefaultTime2Retain = (UINT32)MIN (Session->DefaultTime2Retain, NumericValue);
1717 }
1718
1719 //
1720 // MaxOutstandingR2T: result function is Minimum.
1721 //
1722 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_MAX_OUTSTANDING_R2T);
1723 if (Value == NULL) {
1724 goto ON_ERROR;
1725 }
1726
1727 NumericValue = IScsiNetNtoi (Value);
1728 if ((NumericValue == 0) || (NumericValue > 65535)) {
1729 goto ON_ERROR;
1730 }
1731
1732 Session->MaxOutstandingR2T = (UINT16)MIN (Session->MaxOutstandingR2T, NumericValue);
1733
1734 //
1735 // Remove declarative key-value pairs, if any.
1736 //
1737 IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_SESSION_TYPE);
1738 IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_TARGET_ALIAS);
1739 IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_TARGET_PORTAL_GROUP_TAG);
1740
1741 //
1742 // Remove the key-value that may not needed for result function is OR.
1743 //
1744 IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_INITIAL_R2T);
1745 IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DATA_PDU_IN_ORDER);
1746 IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DATA_SEQUENCE_IN_ORDER);
1747
1748 //
1749 // Remove irrelevant parameter, if any.
1750 //
1751 if (Session->InitialR2T && !Session->ImmediateData) {
1752 IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_FIRST_BURST_LENGTH);
1753 }
1754
1755 if (IsListEmpty (KeyValueList)) {
1756 //
1757 // Succeed if no more keys in the list.
1758 //
1759 Status = EFI_SUCCESS;
1760 }
1761
1762ON_ERROR:
1763
1764 IScsiFreeKeyValueList (KeyValueList);
1765
1766 FreePool (Data);
1767
1768 return Status;
1769}
1770
1778VOID
1780 IN ISCSI_CONNECTION *Conn,
1781 IN OUT NET_BUF *Pdu
1782 )
1783{
1784 ISCSI_SESSION *Session;
1785 CHAR8 Value[256];
1786
1787 Session = Conn->Session;
1788
1789 AsciiSPrint (Value, sizeof (Value), "%a", (Conn->HeaderDigest == IScsiDigestCRC32) ? "None,CRC32" : "None");
1790 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_HEADER_DIGEST, Value);
1791
1792 AsciiSPrint (Value, sizeof (Value), "%a", (Conn->DataDigest == IScsiDigestCRC32) ? "None,CRC32" : "None");
1793 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_DATA_DIGEST, Value);
1794
1795 AsciiSPrint (Value, sizeof (Value), "%d", Session->ErrorRecoveryLevel);
1796 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_ERROR_RECOVERY_LEVEL, Value);
1797
1798 AsciiSPrint (Value, sizeof (Value), "%a", Session->InitialR2T ? "Yes" : "No");
1799 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_INITIAL_R2T, Value);
1800
1801 AsciiSPrint (Value, sizeof (Value), "%a", Session->ImmediateData ? "Yes" : "No");
1802 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_IMMEDIATE_DATA, Value);
1803
1804 AsciiSPrint (Value, sizeof (Value), "%d", MAX_RECV_DATA_SEG_LEN_IN_FFP);
1805 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_MAX_RECV_DATA_SEGMENT_LENGTH, Value);
1806
1807 AsciiSPrint (Value, sizeof (Value), "%d", Session->MaxBurstLength);
1808 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_MAX_BURST_LENGTH, Value);
1809
1810 AsciiSPrint (Value, sizeof (Value), "%d", Session->FirstBurstLength);
1811 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_FIRST_BURST_LENGTH, Value);
1812
1813 AsciiSPrint (Value, sizeof (Value), "%d", Session->MaxConnections);
1814 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_MAX_CONNECTIONS, Value);
1815
1816 AsciiSPrint (Value, sizeof (Value), "%a", Session->DataPDUInOrder ? "Yes" : "No");
1817 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_DATA_PDU_IN_ORDER, Value);
1818
1819 AsciiSPrint (Value, sizeof (Value), "%a", Session->DataSequenceInOrder ? "Yes" : "No");
1820 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_DATA_SEQUENCE_IN_ORDER, Value);
1821
1822 AsciiSPrint (Value, sizeof (Value), "%d", Session->DefaultTime2Wait);
1823 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_DEFAULT_TIME2WAIT, Value);
1824
1825 AsciiSPrint (Value, sizeof (Value), "%d", Session->DefaultTime2Retain);
1826 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_DEFAULT_TIME2RETAIN, Value);
1827
1828 AsciiSPrint (Value, sizeof (Value), "%d", Session->MaxOutstandingR2T);
1829 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_MAX_OUTSTANDING_R2T, Value);
1830}
1831
1844 IN OUT NET_BUF *Pdu,
1845 IN UINT32 Len
1846 )
1847{
1848 UINT32 PadLen;
1849 UINT8 *Data;
1850
1851 PadLen = ISCSI_GET_PAD_LEN (Len);
1852
1853 if (PadLen != 0) {
1854 Data = NetbufAllocSpace (Pdu, PadLen, NET_BUF_TAIL);
1855 if (Data == NULL) {
1856 return EFI_OUT_OF_RESOURCES;
1857 }
1858
1859 ZeroMem (Data, PadLen);
1860 }
1861
1862 return EFI_SUCCESS;
1863}
1864
1875LIST_ENTRY *
1877 IN CHAR8 *Data,
1878 IN UINT32 Len
1879 )
1880{
1881 LIST_ENTRY *ListHead;
1882 ISCSI_KEY_VALUE_PAIR *KeyValuePair;
1883
1884 ListHead = AllocatePool (sizeof (LIST_ENTRY));
1885 if (ListHead == NULL) {
1886 return NULL;
1887 }
1888
1889 InitializeListHead (ListHead);
1890
1891 while (Len > 0) {
1892 KeyValuePair = AllocatePool (sizeof (ISCSI_KEY_VALUE_PAIR));
1893 if (KeyValuePair == NULL) {
1894 goto ON_ERROR;
1895 }
1896
1897 InitializeListHead (&KeyValuePair->List);
1898
1899 KeyValuePair->Key = Data;
1900
1901 while ((Len > 0) && (*Data != '=')) {
1902 Len--;
1903 Data++;
1904 }
1905
1906 if (*Data == '=') {
1907 *Data = '\0';
1908
1909 Data++;
1910 Len--;
1911 } else {
1912 FreePool (KeyValuePair);
1913 goto ON_ERROR;
1914 }
1915
1916 KeyValuePair->Value = Data;
1917
1918 InsertTailList (ListHead, &KeyValuePair->List);
1919
1920 Data += AsciiStrLen (KeyValuePair->Value) + 1;
1921 Len -= (UINT32)AsciiStrLen (KeyValuePair->Value) + 1;
1922 }
1923
1924 return ListHead;
1925
1926ON_ERROR:
1927
1928 IScsiFreeKeyValueList (ListHead);
1929
1930 return NULL;
1931}
1932
1944CHAR8 *
1946 IN OUT LIST_ENTRY *KeyValueList,
1947 IN CHAR8 *Key
1948 )
1949{
1950 LIST_ENTRY *Entry;
1951 ISCSI_KEY_VALUE_PAIR *KeyValuePair;
1952 CHAR8 *Value;
1953
1954 Value = NULL;
1955
1956 NET_LIST_FOR_EACH (Entry, KeyValueList) {
1957 KeyValuePair = NET_LIST_USER_STRUCT (Entry, ISCSI_KEY_VALUE_PAIR, List);
1958
1959 if (AsciiStrCmp (KeyValuePair->Key, Key) == 0) {
1960 Value = KeyValuePair->Value;
1961
1962 RemoveEntryList (&KeyValuePair->List);
1963 FreePool (KeyValuePair);
1964 break;
1965 }
1966 }
1967
1968 return Value;
1969}
1970
1977VOID
1979 IN LIST_ENTRY *KeyValueList
1980 )
1981{
1982 LIST_ENTRY *Entry;
1983 ISCSI_KEY_VALUE_PAIR *KeyValuePair;
1984
1985 while (!IsListEmpty (KeyValueList)) {
1986 Entry = NetListRemoveHead (KeyValueList);
1987 KeyValuePair = NET_LIST_USER_STRUCT (Entry, ISCSI_KEY_VALUE_PAIR, List);
1988
1989 FreePool (KeyValuePair);
1990 }
1991
1992 FreePool (KeyValueList);
1993}
1994
2007 IN OUT CHAR8 *Name,
2008 IN UINTN Len
2009 )
2010{
2011 UINTN Index;
2012
2013 for (Index = 0; Index < Len; Index++) {
2014 if (NET_IS_UPPER_CASE_CHAR (Name[Index])) {
2015 //
2016 // Convert the upper-case characters to lower-case ones.
2017 //
2018 Name[Index] = (CHAR8)(Name[Index] - 'A' + 'a');
2019 }
2020
2021 if (!NET_IS_LOWER_CASE_CHAR (Name[Index]) &&
2022 !NET_IS_DIGIT (Name[Index]) &&
2023 (Name[Index] != '-') &&
2024 (Name[Index] != '.') &&
2025 (Name[Index] != ':')
2026 )
2027 {
2028 //
2029 // ASCII dash, dot, colon lower-case characters and digit characters
2030 // are allowed.
2031 //
2032 return EFI_PROTOCOL_ERROR;
2033 }
2034 }
2035
2036 if ((Len < 4) || (CompareMem (Name, "iqn.", 4) != 0)) {
2037 //
2038 // Only IQN format is accepted now.
2039 //
2040 return EFI_PROTOCOL_ERROR;
2041 }
2042
2043 return EFI_SUCCESS;
2044}
2045
2059 IN ISCSI_CONNECTION *Conn,
2060 OUT ISCSI_TCB **Tcb
2061 )
2062{
2063 ISCSI_SESSION *Session;
2064 ISCSI_TCB *NewTcb;
2065
2066 ASSERT (Tcb != NULL);
2067
2068 Session = Conn->Session;
2069
2070 if (ISCSI_SEQ_GT (Session->CmdSN, Session->MaxCmdSN)) {
2071 return EFI_NOT_READY;
2072 }
2073
2074 NewTcb = AllocateZeroPool (sizeof (ISCSI_TCB));
2075 if (NewTcb == NULL) {
2076 return EFI_OUT_OF_RESOURCES;
2077 }
2078
2079 InitializeListHead (&NewTcb->Link);
2080
2081 NewTcb->SoFarInOrder = TRUE;
2082 NewTcb->InitiatorTaskTag = Session->InitiatorTaskTag;
2083 NewTcb->CmdSN = Session->CmdSN;
2084 NewTcb->Conn = Conn;
2085
2086 InsertTailList (&Session->TcbList, &NewTcb->Link);
2087
2088 //
2089 // Advance the initiator task tag.
2090 //
2091 Session->InitiatorTaskTag++;
2092 Session->CmdSN++;
2093
2094 *Tcb = NewTcb;
2095
2096 return EFI_SUCCESS;
2097}
2098
2105VOID
2107 IN ISCSI_TCB *Tcb
2108 )
2109{
2110 RemoveEntryList (&Tcb->Link);
2111
2112 FreePool (Tcb);
2113}
2114
2125NET_BUF *
2127 IN UINT8 *Data,
2128 IN UINT32 Len,
2129 IN BOOLEAN DataDigest
2130 )
2131{
2132 NET_FRAGMENT Fragment[2];
2133 UINT32 FragmentCount;
2134 UINT32 PadLen;
2135 NET_BUF *DataSeg;
2136
2137 Fragment[0].Len = Len;
2138 Fragment[0].Bulk = Data;
2139
2140 PadLen = ISCSI_GET_PAD_LEN (Len);
2141 if (PadLen != 0) {
2142 Fragment[1].Len = PadLen;
2143 Fragment[1].Bulk = (UINT8 *)&mDataSegPad;
2144
2145 FragmentCount = 2;
2146 } else {
2147 FragmentCount = 1;
2148 }
2149
2150 DataSeg = NetbufFromExt (&Fragment[0], FragmentCount, 0, 0, IScsiNbufExtFree, NULL);
2151
2152 return DataSeg;
2153}
2154
2167NET_BUF *
2170 IN UINT64 Lun,
2171 IN ISCSI_TCB *Tcb
2172 )
2173{
2174 LIST_ENTRY *NbufList;
2175 NET_BUF *Pdu;
2176 NET_BUF *PduHeader;
2177 NET_BUF *DataSeg;
2178 SCSI_COMMAND *ScsiCmd;
2179 UINT8 AHSLength;
2180 UINT32 Length;
2182 ISCSI_BI_EXP_READ_DATA_LEN_AHS *BiExpReadDataLenAHS;
2183 ISCSI_SESSION *Session;
2184 UINT32 ImmediateDataLen;
2185
2186 AHSLength = 0;
2187
2188 if (Packet->DataDirection == DataBi) {
2189 //
2190 // Bidirectional Read/Write command, the bidirectional expected
2191 // read data length AHS is required.
2192 //
2193 AHSLength += sizeof (ISCSI_BI_EXP_READ_DATA_LEN_AHS);
2194 }
2195
2196 if (Packet->CdbLength > 16) {
2197 //
2198 // The CDB exceeds 16 bytes. An extended CDB AHS is required.
2199 //
2200 AHSLength = (UINT8)(AHSLength + ISCSI_ROUNDUP (Packet->CdbLength - 16) + sizeof (ISCSI_ADDITIONAL_HEADER));
2201 }
2202
2203 Length = sizeof (SCSI_COMMAND) + AHSLength;
2204 PduHeader = NetbufAlloc (Length);
2205 if (PduHeader == NULL) {
2206 return NULL;
2207 }
2208
2209 ScsiCmd = (SCSI_COMMAND *)NetbufAllocSpace (PduHeader, Length, NET_BUF_TAIL);
2210 if (ScsiCmd == NULL) {
2211 NetbufFree (PduHeader);
2212 return NULL;
2213 }
2214
2215 Header = (ISCSI_ADDITIONAL_HEADER *)(ScsiCmd + 1);
2216
2217 ZeroMem (ScsiCmd, Length);
2218
2219 ISCSI_SET_OPCODE (ScsiCmd, ISCSI_OPCODE_SCSI_CMD, 0);
2220 ISCSI_SET_FLAG (ScsiCmd, ISCSI_TASK_ATTR_SIMPLE);
2221
2222 //
2223 // Set the READ/WRITE flags according to the IO type of this request.
2224 //
2225 switch (Packet->DataDirection) {
2226 case DataIn:
2227 ISCSI_SET_FLAG (ScsiCmd, SCSI_CMD_PDU_FLAG_READ);
2228 ScsiCmd->ExpDataXferLength = NTOHL (Packet->InTransferLength);
2229 break;
2230
2231 case DataOut:
2232 ISCSI_SET_FLAG (ScsiCmd, SCSI_CMD_PDU_FLAG_WRITE);
2233 ScsiCmd->ExpDataXferLength = NTOHL (Packet->OutTransferLength);
2234 break;
2235
2236 case DataBi:
2237 ISCSI_SET_FLAG (ScsiCmd, SCSI_CMD_PDU_FLAG_READ | SCSI_CMD_PDU_FLAG_WRITE);
2238 ScsiCmd->ExpDataXferLength = NTOHL (Packet->OutTransferLength);
2239
2240 //
2241 // Fill the bidirectional expected read data length AHS.
2242 //
2243 BiExpReadDataLenAHS = (ISCSI_BI_EXP_READ_DATA_LEN_AHS *)Header;
2244 Header = (ISCSI_ADDITIONAL_HEADER *)(BiExpReadDataLenAHS + 1);
2245
2246 BiExpReadDataLenAHS->Length = NTOHS (5);
2247 BiExpReadDataLenAHS->Type = ISCSI_AHS_TYPE_BI_EXP_READ_DATA_LEN;
2248 BiExpReadDataLenAHS->ExpReadDataLength = NTOHL (Packet->InTransferLength);
2249
2250 break;
2251 }
2252
2253 ScsiCmd->TotalAHSLength = AHSLength;
2254 CopyMem (ScsiCmd->Lun, &Lun, sizeof (ScsiCmd->Lun));
2255 ScsiCmd->InitiatorTaskTag = NTOHL (Tcb->InitiatorTaskTag);
2256 ScsiCmd->CmdSN = NTOHL (Tcb->CmdSN);
2257 ScsiCmd->ExpStatSN = NTOHL (Tcb->Conn->ExpStatSN);
2258
2259 CopyMem (ScsiCmd->Cdb, Packet->Cdb, sizeof (ScsiCmd->Cdb));
2260
2261 if (Packet->CdbLength > 16) {
2262 Header->Length = NTOHS ((UINT16)(Packet->CdbLength - 15));
2263 Header->Type = ISCSI_AHS_TYPE_EXT_CDB;
2264
2265 CopyMem (Header + 1, (UINT8 *)Packet->Cdb + 16, Packet->CdbLength - 16);
2266 }
2267
2268 Pdu = PduHeader;
2269 Session = Tcb->Conn->Session;
2270 ImmediateDataLen = 0;
2271
2272 if (Session->ImmediateData && (Packet->OutTransferLength != 0)) {
2273 //
2274 // Send immediate data in this SCSI Command PDU. The length of the immediate
2275 // data is the minimum of FirstBurstLength, the data length to be xfered, and
2276 // the MaxRecvdataSegmentLength on this connection.
2277 //
2278 ImmediateDataLen = MIN (Session->FirstBurstLength, Packet->OutTransferLength);
2279 ImmediateDataLen = MIN (ImmediateDataLen, Tcb->Conn->MaxRecvDataSegmentLength);
2280
2281 //
2282 // Update the data segment length in the PDU header.
2283 //
2284 ISCSI_SET_DATASEG_LEN (ScsiCmd, ImmediateDataLen);
2285
2286 //
2287 // Create the data segment.
2288 //
2289 DataSeg = IScsiNewDataSegment ((UINT8 *)Packet->OutDataBuffer, ImmediateDataLen, FALSE);
2290 if (DataSeg == NULL) {
2291 NetbufFree (PduHeader);
2292 Pdu = NULL;
2293 goto ON_EXIT;
2294 }
2295
2296 NbufList = AllocatePool (sizeof (LIST_ENTRY));
2297 if (NbufList == NULL) {
2298 NetbufFree (PduHeader);
2299 NetbufFree (DataSeg);
2300
2301 Pdu = NULL;
2302 goto ON_EXIT;
2303 }
2304
2305 InitializeListHead (NbufList);
2306 InsertTailList (NbufList, &PduHeader->List);
2307 InsertTailList (NbufList, &DataSeg->List);
2308
2309 Pdu = NetbufFromBufList (NbufList, 0, 0, IScsiFreeNbufList, NbufList);
2310 if (Pdu == NULL) {
2311 IScsiFreeNbufList (NbufList);
2312 }
2313 }
2314
2315 if (Session->InitialR2T ||
2316 (ImmediateDataLen == Session->FirstBurstLength) ||
2317 (ImmediateDataLen == Packet->OutTransferLength)
2318 )
2319 {
2320 //
2321 // Unsolicited data out sequence is not allowed,
2322 // or FirstBustLength data is already sent out by immediate data,
2323 // or all the OUT data accompany this SCSI packet are sent as
2324 // immediate data. The final flag should be set on this SCSI Command
2325 // PDU.
2326 //
2327 ISCSI_SET_FLAG (ScsiCmd, ISCSI_BHS_FLAG_FINAL);
2328 }
2329
2330ON_EXIT:
2331
2332 return Pdu;
2333}
2334
2348NET_BUF *
2350 IN UINT8 *Data,
2351 IN UINT32 Len,
2352 IN UINT32 DataSN,
2353 IN ISCSI_TCB *Tcb,
2354 IN UINT64 Lun
2355 )
2356{
2357 LIST_ENTRY *NbufList;
2358 NET_BUF *PduHdr;
2359 NET_BUF *DataSeg;
2360 NET_BUF *Pdu;
2361 ISCSI_SCSI_DATA_OUT *DataOutHdr;
2362 ISCSI_XFER_CONTEXT *XferContext;
2363
2364 NbufList = AllocatePool (sizeof (LIST_ENTRY));
2365 if (NbufList == NULL) {
2366 return NULL;
2367 }
2368
2369 InitializeListHead (NbufList);
2370
2371 //
2372 // Allocate memory for the BHS.
2373 //
2374 PduHdr = NetbufAlloc (sizeof (ISCSI_SCSI_DATA_OUT));
2375 if (PduHdr == NULL) {
2376 FreePool (NbufList);
2377 return NULL;
2378 }
2379
2380 //
2381 // Insert the BHS into the buffer list.
2382 //
2383 InsertTailList (NbufList, &PduHdr->List);
2384
2385 DataOutHdr = (ISCSI_SCSI_DATA_OUT *)NetbufAllocSpace (PduHdr, sizeof (ISCSI_SCSI_DATA_OUT), NET_BUF_TAIL);
2386 if (DataOutHdr == NULL) {
2387 IScsiFreeNbufList (NbufList);
2388 return NULL;
2389 }
2390
2391 XferContext = &Tcb->XferContext;
2392
2393 ZeroMem (DataOutHdr, sizeof (ISCSI_SCSI_DATA_OUT));
2394
2395 //
2396 // Set the flags and fields of the Data Out PDU BHS.
2397 //
2398 ISCSI_SET_OPCODE (DataOutHdr, ISCSI_OPCODE_SCSI_DATA_OUT, 0);
2399 ISCSI_SET_DATASEG_LEN (DataOutHdr, Len);
2400
2401 DataOutHdr->InitiatorTaskTag = HTONL (Tcb->InitiatorTaskTag);
2402 DataOutHdr->TargetTransferTag = HTONL (XferContext->TargetTransferTag);
2403 DataOutHdr->ExpStatSN = HTONL (Tcb->Conn->ExpStatSN);
2404 DataOutHdr->DataSN = HTONL (DataSN);
2405 DataOutHdr->BufferOffset = HTONL (XferContext->Offset);
2406
2407 if (XferContext->TargetTransferTag != ISCSI_RESERVED_TAG) {
2408 CopyMem (&DataOutHdr->Lun, &Lun, sizeof (DataOutHdr->Lun));
2409 }
2410
2411 //
2412 // Build the data segment for this Data Out PDU.
2413 //
2414 DataSeg = IScsiNewDataSegment (Data, Len, FALSE);
2415 if (DataSeg == NULL) {
2416 IScsiFreeNbufList (NbufList);
2417 return NULL;
2418 }
2419
2420 //
2421 // Put the data segment into the buffer list and combine it with the BHS
2422 // into a full Data Out PDU.
2423 //
2424 InsertTailList (NbufList, &DataSeg->List);
2425 Pdu = NetbufFromBufList (NbufList, 0, 0, IScsiFreeNbufList, NbufList);
2426 if (Pdu == NULL) {
2427 IScsiFreeNbufList (NbufList);
2428 }
2429
2430 return Pdu;
2431}
2432
2444LIST_ENTRY *
2446 IN UINT8 *Data,
2447 IN ISCSI_TCB *Tcb,
2448 IN UINT64 Lun
2449 )
2450{
2451 LIST_ENTRY *PduList;
2452 UINT32 DataSN;
2453 UINT32 DataLen;
2454 NET_BUF *DataOutPdu;
2455 ISCSI_CONNECTION *Conn;
2456 ISCSI_XFER_CONTEXT *XferContext;
2457 UINT8 *DataOutPacket;
2458
2459 PduList = AllocatePool (sizeof (LIST_ENTRY));
2460 if (PduList == NULL) {
2461 return NULL;
2462 }
2463
2464 InitializeListHead (PduList);
2465
2466 DataSN = 0;
2467 Conn = Tcb->Conn;
2468 DataOutPdu = NULL;
2469 XferContext = &Tcb->XferContext;
2470
2471 while (XferContext->DesiredLength > 0) {
2472 //
2473 // Determine the length of data this Data Out PDU can carry.
2474 //
2475 DataLen = MIN (XferContext->DesiredLength, Conn->MaxRecvDataSegmentLength);
2476
2477 //
2478 // Create a Data Out PDU.
2479 //
2480 DataOutPdu = IScsiNewDataOutPdu (Data, DataLen, DataSN, Tcb, Lun);
2481 if (DataOutPdu == NULL) {
2482 IScsiFreeNbufList (PduList);
2483 PduList = NULL;
2484
2485 goto ON_EXIT;
2486 }
2487
2488 InsertTailList (PduList, &DataOutPdu->List);
2489
2490 //
2491 // Update the context and DataSN.
2492 //
2493 Data += DataLen;
2494 XferContext->Offset += DataLen;
2495 XferContext->DesiredLength -= DataLen;
2496 DataSN++;
2497 }
2498
2499 //
2500 // Set the F bit for the last data out PDU in this sequence.
2501 //
2502 DataOutPacket = NetbufGetByte (DataOutPdu, 0, NULL);
2503 if (DataOutPacket == NULL) {
2504 IScsiFreeNbufList (PduList);
2505 PduList = NULL;
2506 goto ON_EXIT;
2507 }
2508
2509 ISCSI_SET_FLAG (DataOutPacket, ISCSI_BHS_FLAG_FINAL);
2510
2511ON_EXIT:
2512
2513 return PduList;
2514}
2515
2530 IN UINT8 *Data,
2531 IN UINT64 Lun,
2532 IN ISCSI_TCB *Tcb
2533 )
2534{
2535 LIST_ENTRY *DataOutPduList;
2536 LIST_ENTRY *Entry;
2537 NET_BUF *Pdu;
2538 EFI_STATUS Status;
2539
2540 //
2541 // Generate the Data Out PDU sequence.
2542 //
2543 DataOutPduList = IScsiGenerateDataOutPduSequence (Data, Tcb, Lun);
2544 if (DataOutPduList == NULL) {
2545 return EFI_OUT_OF_RESOURCES;
2546 }
2547
2548 Status = EFI_SUCCESS;
2549
2550 //
2551 // Send the Data Out PDU's one by one.
2552 //
2553 NET_LIST_FOR_EACH (Entry, DataOutPduList) {
2554 Pdu = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
2555
2556 Status = TcpIoTransmit (&Tcb->Conn->TcpIo, Pdu);
2557
2558 if (EFI_ERROR (Status)) {
2559 break;
2560 }
2561 }
2562
2563 IScsiFreeNbufList (DataOutPduList);
2564
2565 return Status;
2566}
2567
2584 IN NET_BUF *Pdu,
2585 IN ISCSI_TCB *Tcb,
2587 )
2588{
2589 ISCSI_SCSI_DATA_IN *DataInHdr;
2590 EFI_STATUS Status;
2591
2592 DataInHdr = (ISCSI_SCSI_DATA_IN *)NetbufGetByte (Pdu, 0, NULL);
2593 if (DataInHdr == NULL) {
2594 return EFI_PROTOCOL_ERROR;
2595 }
2596
2597 DataInHdr->InitiatorTaskTag = NTOHL (DataInHdr->InitiatorTaskTag);
2598 DataInHdr->ExpCmdSN = NTOHL (DataInHdr->ExpCmdSN);
2599 DataInHdr->MaxCmdSN = NTOHL (DataInHdr->MaxCmdSN);
2600 DataInHdr->DataSN = NTOHL (DataInHdr->DataSN);
2601
2602 //
2603 // Check the DataSN.
2604 //
2605 Status = IScsiCheckSN (&Tcb->ExpDataSN, DataInHdr->DataSN);
2606 if (EFI_ERROR (Status)) {
2607 return Status;
2608 }
2609
2610 if (DataInHdr->InitiatorTaskTag != Tcb->InitiatorTaskTag) {
2611 return EFI_PROTOCOL_ERROR;
2612 }
2613
2614 //
2615 // Update the command related sequence numbers.
2616 //
2617 IScsiUpdateCmdSN (Tcb->Conn->Session, DataInHdr->MaxCmdSN, DataInHdr->ExpCmdSN);
2618
2619 if (ISCSI_FLAG_ON (DataInHdr, SCSI_DATA_IN_PDU_FLAG_STATUS_VALID)) {
2620 if (!ISCSI_FLAG_ON (DataInHdr, ISCSI_BHS_FLAG_FINAL)) {
2621 //
2622 // The S bit is on but the F bit is off.
2623 //
2624 return EFI_PROTOCOL_ERROR;
2625 }
2626
2627 Tcb->StatusXferd = TRUE;
2628
2629 if (ISCSI_FLAG_ON (DataInHdr, SCSI_DATA_IN_PDU_FLAG_OVERFLOW | SCSI_DATA_IN_PDU_FLAG_UNDERFLOW)) {
2630 //
2631 // Underflow and Overflow are mutual flags.
2632 //
2633 return EFI_PROTOCOL_ERROR;
2634 }
2635
2636 //
2637 // S bit is on, the StatSN is valid.
2638 //
2639 Status = IScsiCheckSN (&Tcb->Conn->ExpStatSN, NTOHL (DataInHdr->StatSN));
2640 if (EFI_ERROR (Status)) {
2641 return Status;
2642 }
2643
2644 Packet->HostAdapterStatus = 0;
2645 Packet->TargetStatus = DataInHdr->Status;
2646
2647 if (ISCSI_FLAG_ON (DataInHdr, SCSI_RSP_PDU_FLAG_OVERFLOW)) {
2648 Packet->InTransferLength += NTOHL (DataInHdr->ResidualCount);
2649 Status = EFI_BAD_BUFFER_SIZE;
2650 }
2651
2652 if (ISCSI_FLAG_ON (DataInHdr, SCSI_RSP_PDU_FLAG_UNDERFLOW)) {
2653 Packet->InTransferLength -= NTOHL (DataInHdr->ResidualCount);
2654 }
2655 }
2656
2657 return Status;
2658}
2659
2675 IN NET_BUF *Pdu,
2676 IN ISCSI_TCB *Tcb,
2677 IN UINT64 Lun,
2679 )
2680{
2682 EFI_STATUS Status;
2683 ISCSI_XFER_CONTEXT *XferContext;
2684 UINT8 *Data;
2685
2686 R2THdr = (ISCSI_READY_TO_TRANSFER *)NetbufGetByte (Pdu, 0, NULL);
2687 if (R2THdr == NULL) {
2688 return EFI_PROTOCOL_ERROR;
2689 }
2690
2691 R2THdr->InitiatorTaskTag = NTOHL (R2THdr->InitiatorTaskTag);
2692 R2THdr->TargetTransferTag = NTOHL (R2THdr->TargetTransferTag);
2693 R2THdr->StatSN = NTOHL (R2THdr->StatSN);
2694 R2THdr->R2TSeqNum = NTOHL (R2THdr->R2TSeqNum);
2695 R2THdr->BufferOffset = NTOHL (R2THdr->BufferOffset);
2696 R2THdr->DesiredDataTransferLength = NTOHL (R2THdr->DesiredDataTransferLength);
2697
2698 if ((R2THdr->InitiatorTaskTag != Tcb->InitiatorTaskTag) || !ISCSI_SEQ_EQ (R2THdr->StatSN, Tcb->Conn->ExpStatSN)) {
2699 return EFI_PROTOCOL_ERROR;
2700 }
2701
2702 //
2703 // Check the sequence number.
2704 //
2705 Status = IScsiCheckSN (&Tcb->ExpDataSN, R2THdr->R2TSeqNum);
2706 if (EFI_ERROR (Status)) {
2707 return Status;
2708 }
2709
2710 XferContext = &Tcb->XferContext;
2711 XferContext->TargetTransferTag = R2THdr->TargetTransferTag;
2712 XferContext->Offset = R2THdr->BufferOffset;
2713 XferContext->DesiredLength = R2THdr->DesiredDataTransferLength;
2714
2715 if (((XferContext->Offset + XferContext->DesiredLength) > Packet->OutTransferLength) ||
2716 (XferContext->DesiredLength > Tcb->Conn->Session->MaxBurstLength)
2717 )
2718 {
2719 return EFI_PROTOCOL_ERROR;
2720 }
2721
2722 //
2723 // Send the data solicited by this R2T.
2724 //
2725 Data = (UINT8 *)Packet->OutDataBuffer + XferContext->Offset;
2726 Status = IScsiSendDataOutPduSequence (Data, Lun, Tcb);
2727
2728 return Status;
2729}
2730
2746 IN NET_BUF *Pdu,
2747 IN ISCSI_TCB *Tcb,
2749 )
2750{
2751 SCSI_RESPONSE *ScsiRspHdr;
2752 ISCSI_SENSE_DATA *SenseData;
2753 EFI_STATUS Status;
2754 UINT32 DataSegLen;
2755
2756 ScsiRspHdr = (SCSI_RESPONSE *)NetbufGetByte (Pdu, 0, NULL);
2757 if (ScsiRspHdr == NULL) {
2758 return EFI_PROTOCOL_ERROR;
2759 }
2760
2761 ScsiRspHdr->InitiatorTaskTag = NTOHL (ScsiRspHdr->InitiatorTaskTag);
2762 if (ScsiRspHdr->InitiatorTaskTag != Tcb->InitiatorTaskTag) {
2763 return EFI_PROTOCOL_ERROR;
2764 }
2765
2766 ScsiRspHdr->StatSN = NTOHL (ScsiRspHdr->StatSN);
2767
2768 Status = IScsiCheckSN (&Tcb->Conn->ExpStatSN, ScsiRspHdr->StatSN);
2769 if (EFI_ERROR (Status)) {
2770 return Status;
2771 }
2772
2773 ScsiRspHdr->MaxCmdSN = NTOHL (ScsiRspHdr->MaxCmdSN);
2774 ScsiRspHdr->ExpCmdSN = NTOHL (ScsiRspHdr->ExpCmdSN);
2775 IScsiUpdateCmdSN (Tcb->Conn->Session, ScsiRspHdr->MaxCmdSN, ScsiRspHdr->ExpCmdSN);
2776
2777 Tcb->StatusXferd = TRUE;
2778
2779 Packet->HostAdapterStatus = ScsiRspHdr->Response;
2780 if (Packet->HostAdapterStatus != ISCSI_SERVICE_RSP_COMMAND_COMPLETE_AT_TARGET) {
2781 return EFI_SUCCESS;
2782 }
2783
2784 Packet->TargetStatus = ScsiRspHdr->Status;
2785
2786 if (ISCSI_FLAG_ON (ScsiRspHdr, SCSI_RSP_PDU_FLAG_BI_READ_OVERFLOW | SCSI_RSP_PDU_FLAG_BI_READ_UNDERFLOW) ||
2787 ISCSI_FLAG_ON (ScsiRspHdr, SCSI_RSP_PDU_FLAG_OVERFLOW | SCSI_RSP_PDU_FLAG_UNDERFLOW)
2788 )
2789 {
2790 return EFI_PROTOCOL_ERROR;
2791 }
2792
2793 if (ISCSI_FLAG_ON (ScsiRspHdr, SCSI_RSP_PDU_FLAG_BI_READ_OVERFLOW)) {
2794 Packet->InTransferLength += NTOHL (ScsiRspHdr->BiReadResidualCount);
2795 Status = EFI_BAD_BUFFER_SIZE;
2796 }
2797
2798 if (ISCSI_FLAG_ON (ScsiRspHdr, SCSI_RSP_PDU_FLAG_BI_READ_UNDERFLOW)) {
2799 Packet->InTransferLength -= NTOHL (ScsiRspHdr->BiReadResidualCount);
2800 }
2801
2802 if (ISCSI_FLAG_ON (ScsiRspHdr, SCSI_RSP_PDU_FLAG_OVERFLOW)) {
2803 if (Packet->DataDirection == DataIn) {
2804 Packet->InTransferLength += NTOHL (ScsiRspHdr->ResidualCount);
2805 } else {
2806 Packet->OutTransferLength += NTOHL (ScsiRspHdr->ResidualCount);
2807 }
2808
2809 Status = EFI_BAD_BUFFER_SIZE;
2810 }
2811
2812 if (ISCSI_FLAG_ON (ScsiRspHdr, SCSI_RSP_PDU_FLAG_UNDERFLOW)) {
2813 if (Packet->DataDirection == DataIn) {
2814 Packet->InTransferLength -= NTOHL (ScsiRspHdr->ResidualCount);
2815 } else {
2816 Packet->OutTransferLength -= NTOHL (ScsiRspHdr->ResidualCount);
2817 }
2818 }
2819
2820 DataSegLen = ISCSI_GET_DATASEG_LEN (ScsiRspHdr);
2821 if (DataSegLen != 0) {
2822 SenseData = (ISCSI_SENSE_DATA *)NetbufGetByte (Pdu, sizeof (SCSI_RESPONSE), NULL);
2823 if (SenseData == NULL) {
2824 return EFI_PROTOCOL_ERROR;
2825 }
2826
2827 SenseData->Length = NTOHS (SenseData->Length);
2828
2829 Packet->SenseDataLength = (UINT8)MIN (SenseData->Length, Packet->SenseDataLength);
2830 if (Packet->SenseDataLength != 0) {
2831 CopyMem (Packet->SenseData, &SenseData->Data[0], Packet->SenseDataLength);
2832 }
2833 } else {
2834 Packet->SenseDataLength = 0;
2835 }
2836
2837 return Status;
2838}
2839
2853 IN NET_BUF *Pdu,
2854 IN ISCSI_TCB *Tcb
2855 )
2856{
2857 ISCSI_NOP_IN *NopInHdr;
2858 EFI_STATUS Status;
2859
2860 NopInHdr = (ISCSI_NOP_IN *)NetbufGetByte (Pdu, 0, NULL);
2861 if (NopInHdr == NULL) {
2862 return EFI_PROTOCOL_ERROR;
2863 }
2864
2865 NopInHdr->StatSN = NTOHL (NopInHdr->StatSN);
2866 NopInHdr->ExpCmdSN = NTOHL (NopInHdr->ExpCmdSN);
2867 NopInHdr->MaxCmdSN = NTOHL (NopInHdr->MaxCmdSN);
2868
2869 if (NopInHdr->InitiatorTaskTag == ISCSI_RESERVED_TAG) {
2870 if (NopInHdr->StatSN != Tcb->Conn->ExpStatSN) {
2871 return EFI_PROTOCOL_ERROR;
2872 }
2873 } else {
2874 Status = IScsiCheckSN (&Tcb->Conn->ExpStatSN, NopInHdr->StatSN);
2875 if (EFI_ERROR (Status)) {
2876 return Status;
2877 }
2878 }
2879
2880 IScsiUpdateCmdSN (Tcb->Conn->Session, NopInHdr->MaxCmdSN, NopInHdr->ExpCmdSN);
2881
2882 return EFI_SUCCESS;
2883}
2884
2906 IN UINT8 *Target,
2907 IN UINT64 Lun,
2909 )
2910{
2911 EFI_STATUS Status;
2912 ISCSI_DRIVER_DATA *Private;
2913 ISCSI_SESSION *Session;
2914 EFI_EVENT TimeoutEvent;
2915 ISCSI_CONNECTION *Conn;
2916 ISCSI_TCB *Tcb;
2917 NET_BUF *Pdu;
2918 ISCSI_XFER_CONTEXT *XferContext;
2919 UINT8 *Data;
2920 ISCSI_IN_BUFFER_CONTEXT InBufferContext;
2921 UINT64 Timeout;
2922 UINT8 *PduHdr;
2923
2924 Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (PassThru);
2925 Session = Private->Session;
2926 Status = EFI_SUCCESS;
2927 Tcb = NULL;
2928 TimeoutEvent = NULL;
2929 Timeout = 0;
2930
2931 if (Session->State != SESSION_STATE_LOGGED_IN) {
2932 Status = EFI_DEVICE_ERROR;
2933 goto ON_EXIT;
2934 }
2935
2936 Conn = NET_LIST_USER_STRUCT_S (
2937 Session->Conns.ForwardLink,
2939 Link,
2940 ISCSI_CONNECTION_SIGNATURE
2941 );
2942
2943 if (Packet->Timeout != 0) {
2944 Timeout = MultU64x32 (Packet->Timeout, 4);
2945 }
2946
2947 Status = IScsiNewTcb (Conn, &Tcb);
2948 if (EFI_ERROR (Status)) {
2949 goto ON_EXIT;
2950 }
2951
2952 //
2953 // Encapsulate the SCSI request packet into an iSCSI SCSI Command PDU.
2954 //
2955 Pdu = IScsiNewScsiCmdPdu (Packet, Lun, Tcb);
2956 if (Pdu == NULL) {
2957 Status = EFI_OUT_OF_RESOURCES;
2958 goto ON_EXIT;
2959 }
2960
2961 XferContext = &Tcb->XferContext;
2962 PduHdr = NetbufGetByte (Pdu, 0, NULL);
2963 if (PduHdr == NULL) {
2964 Status = EFI_PROTOCOL_ERROR;
2965 NetbufFree (Pdu);
2966 goto ON_EXIT;
2967 }
2968
2969 XferContext->Offset = ISCSI_GET_DATASEG_LEN (PduHdr);
2970
2971 //
2972 // Transmit the SCSI Command PDU.
2973 //
2974 Status = TcpIoTransmit (&Conn->TcpIo, Pdu);
2975
2976 NetbufFree (Pdu);
2977
2978 if (EFI_ERROR (Status)) {
2979 goto ON_EXIT;
2980 }
2981
2982 if (!Session->InitialR2T &&
2983 (XferContext->Offset < Session->FirstBurstLength) &&
2984 (XferContext->Offset < Packet->OutTransferLength)
2985 )
2986 {
2987 //
2988 // Unsolicited Data-Out sequence is allowed. There is remaining SCSI
2989 // OUT data, and the limit of FirstBurstLength is not reached.
2990 //
2991 XferContext->TargetTransferTag = ISCSI_RESERVED_TAG;
2992 XferContext->DesiredLength = MIN (
2993 Session->FirstBurstLength,
2994 Packet->OutTransferLength - XferContext->Offset
2995 );
2996
2997 Data = (UINT8 *)Packet->OutDataBuffer + XferContext->Offset;
2998 Status = IScsiSendDataOutPduSequence (Data, Lun, Tcb);
2999 if (EFI_ERROR (Status)) {
3000 goto ON_EXIT;
3001 }
3002 }
3003
3004 InBufferContext.InData = (UINT8 *)Packet->InDataBuffer;
3005 InBufferContext.InDataLen = Packet->InTransferLength;
3006
3007 while (!Tcb->StatusXferd) {
3008 //
3009 // Start the timeout timer.
3010 //
3011 if (Timeout != 0) {
3012 Status = gBS->SetTimer (Conn->TimeoutEvent, TimerRelative, Timeout);
3013 if (EFI_ERROR (Status)) {
3014 goto ON_EXIT;
3015 }
3016
3017 TimeoutEvent = Conn->TimeoutEvent;
3018 }
3019
3020 //
3021 // Try to receive PDU from target.
3022 //
3023 Status = IScsiReceivePdu (Conn, &Pdu, &InBufferContext, FALSE, FALSE, TimeoutEvent);
3024 if (EFI_ERROR (Status)) {
3025 goto ON_EXIT;
3026 }
3027
3028 PduHdr = NetbufGetByte (Pdu, 0, NULL);
3029 if (PduHdr == NULL) {
3030 Status = EFI_PROTOCOL_ERROR;
3031 NetbufFree (Pdu);
3032 goto ON_EXIT;
3033 }
3034
3035 switch (ISCSI_GET_OPCODE (PduHdr)) {
3036 case ISCSI_OPCODE_SCSI_DATA_IN:
3037 Status = IScsiOnDataInRcvd (Pdu, Tcb, Packet);
3038 break;
3039
3040 case ISCSI_OPCODE_R2T:
3041 Status = IScsiOnR2TRcvd (Pdu, Tcb, Lun, Packet);
3042 break;
3043
3044 case ISCSI_OPCODE_SCSI_RSP:
3045 Status = IScsiOnScsiRspRcvd (Pdu, Tcb, Packet);
3046 break;
3047
3048 case ISCSI_OPCODE_NOP_IN:
3049 Status = IScsiOnNopInRcvd (Pdu, Tcb);
3050 break;
3051
3052 case ISCSI_OPCODE_VENDOR_T0:
3053 case ISCSI_OPCODE_VENDOR_T1:
3054 case ISCSI_OPCODE_VENDOR_T2:
3055 //
3056 // These messages are vendor specific. Skip them.
3057 //
3058 break;
3059
3060 default:
3061 Status = EFI_PROTOCOL_ERROR;
3062 break;
3063 }
3064
3065 NetbufFree (Pdu);
3066
3067 if (EFI_ERROR (Status)) {
3068 break;
3069 }
3070 }
3071
3072ON_EXIT:
3073
3074 if (TimeoutEvent != NULL) {
3075 gBS->SetTimer (TimeoutEvent, TimerCancel, 0);
3076 }
3077
3078 if (Tcb != NULL) {
3079 IScsiDelTcb (Tcb);
3080 }
3081
3082 return Status;
3083}
3084
3096 IN ISCSI_SESSION *Session
3097 )
3098{
3099 EFI_STATUS Status;
3100
3101 ASSERT (Session->State != SESSION_STATE_FREE);
3102
3103 //
3104 // Abort the session and re-init it.
3105 //
3106 IScsiSessionAbort (Session);
3107 IScsiSessionInit (Session, TRUE);
3108
3109 //
3110 // Login again.
3111 //
3112 Status = IScsiSessionLogin (Session);
3113
3114 return Status;
3115}
3116
3124VOID
3126 IN OUT ISCSI_SESSION *Session,
3127 IN BOOLEAN Recovery
3128 )
3129{
3130 if (!Recovery) {
3131 Session->Signature = ISCSI_SESSION_SIGNATURE;
3132 Session->State = SESSION_STATE_FREE;
3133
3134 InitializeListHead (&Session->Conns);
3135 InitializeListHead (&Session->TcbList);
3136 }
3137
3138 Session->Tsih = 0;
3139
3140 Session->CmdSN = 1;
3141 Session->InitiatorTaskTag = 1;
3142 Session->NextCid = 1;
3143
3144 Session->TargetPortalGroupTag = 0;
3145 Session->MaxConnections = ISCSI_MAX_CONNS_PER_SESSION;
3146 Session->InitialR2T = FALSE;
3147 Session->ImmediateData = TRUE;
3148 Session->MaxBurstLength = 262144;
3149 Session->FirstBurstLength = MAX_RECV_DATA_SEG_LEN_IN_FFP;
3150 Session->DefaultTime2Wait = 2;
3151 Session->DefaultTime2Retain = 20;
3152 Session->MaxOutstandingR2T = DEFAULT_MAX_OUTSTANDING_R2T;
3153 Session->DataPDUInOrder = TRUE;
3154 Session->DataSequenceInOrder = TRUE;
3155 Session->ErrorRecoveryLevel = 0;
3156}
3157
3165VOID
3167 IN OUT ISCSI_SESSION *Session
3168 )
3169{
3170 ISCSI_CONNECTION *Conn;
3171 EFI_GUID *ProtocolGuid;
3172
3173 if (Session->State != SESSION_STATE_LOGGED_IN) {
3174 return;
3175 }
3176
3177 ASSERT (!IsListEmpty (&Session->Conns));
3178
3179 while (!IsListEmpty (&Session->Conns)) {
3180 Conn = NET_LIST_USER_STRUCT_S (
3181 Session->Conns.ForwardLink,
3183 Link,
3184 ISCSI_CONNECTION_SIGNATURE
3185 );
3186 if (!Conn->Ipv6Flag) {
3187 ProtocolGuid = &gEfiTcp4ProtocolGuid;
3188 } else {
3189 ProtocolGuid = &gEfiTcp6ProtocolGuid;
3190 }
3191
3192 gBS->CloseProtocol (
3193 Conn->TcpIo.Handle,
3194 ProtocolGuid,
3195 Session->Private->Image,
3196 Session->Private->ExtScsiPassThruHandle
3197 );
3198
3199 IScsiConnReset (Conn);
3200
3203 }
3204
3205 Session->State = SESSION_STATE_FAILED;
3206
3207 return;
3208}
UINT64 UINTN
BOOLEAN EFIAPI IsListEmpty(IN CONST LIST_ENTRY *ListHead)
Definition: LinkedList.c:403
UINTN EFIAPI AsciiStrLen(IN CONST CHAR8 *String)
Definition: String.c:641
INTN EFIAPI AsciiStrCmp(IN CONST CHAR8 *FirstString, IN CONST CHAR8 *SecondString)
Definition: String.c:716
UINTN EFIAPI AsciiStrDecimalToUintn(IN CONST CHAR8 *String)
Definition: String.c:1006
LIST_ENTRY *EFIAPI RemoveEntryList(IN CONST LIST_ENTRY *Entry)
Definition: LinkedList.c:590
UINT64 EFIAPI MultU64x32(IN UINT64 Multiplicand, IN UINT32 Multiplier)
Definition: MultU64x32.c:27
LIST_ENTRY *EFIAPI InitializeListHead(IN OUT LIST_ENTRY *ListHead)
Definition: LinkedList.c:182
UINTN EFIAPI AsciiStrSize(IN CONST CHAR8 *String)
Definition: String.c:681
LIST_ENTRY *EFIAPI InsertTailList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:259
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
EFI_STATUS IScsiCHAPToSendReq(IN ISCSI_CONNECTION *Conn, IN OUT NET_BUF *Pdu)
Definition: IScsiCHAP.c:470
EFI_STATUS IScsiCHAPOnRspReceived(IN ISCSI_CONNECTION *Conn)
Definition: IScsiCHAP.c:215
EFI_STATUS IScsiDns4(IN EFI_HANDLE Image, IN EFI_HANDLE Controller, IN OUT ISCSI_SESSION_CONFIG_NVDATA *NvData)
Definition: IScsiDns.c:42
EFI_STATUS IScsiDns6(IN EFI_HANDLE Image, IN EFI_HANDLE Controller, IN OUT ISCSI_SESSION_CONFIG_NVDATA *NvData)
Definition: IScsiDns.c:249
#define ISCSI_WAIT_IPSEC_TIMEOUT
Definition: IScsiImpl.h:80
UINTN IScsiNetNtoi(IN CHAR8 *Str)
Definition: IScsiMisc.c:459
EFI_STATUS IScsiAsciiStrToIp(IN CHAR8 *Str, IN UINT8 IpMode, OUT EFI_IP_ADDRESS *Ip)
Definition: IScsiMisc.c:248
EFI_STATUS IScsiSessionReinstatement(IN ISCSI_SESSION *Session)
Definition: IScsiProto.c:3095
VOID IScsiDelTcb(IN ISCSI_TCB *Tcb)
Definition: IScsiProto.c:2106
EFI_STATUS IScsiOnDataInRcvd(IN NET_BUF *Pdu, IN ISCSI_TCB *Tcb, IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet)
Definition: IScsiProto.c:2583
EFI_STATUS IScsiCheckSN(IN OUT UINT32 *ExpSN, IN UINT32 NewSN)
Definition: IScsiProto.c:59
EFI_STATUS IScsiSendLoginReq(IN ISCSI_CONNECTION *Conn)
Definition: IScsiProto.c:596
EFI_STATUS IScsiReceiveLoginRsp(IN ISCSI_CONNECTION *Conn)
Definition: IScsiProto.c:631
EFI_STATUS IScsiNewTcb(IN ISCSI_CONNECTION *Conn, OUT ISCSI_TCB **Tcb)
Definition: IScsiProto.c:2058
VOID EFIAPI IScsiFreeNbufList(VOID *Arg)
Definition: IScsiProto.c:1262
VOID IScsiAttatchConnection(IN OUT ISCSI_SESSION *Session, IN OUT ISCSI_CONNECTION *Conn)
Definition: IScsiProto.c:21
STATIC VOID IScsiSessionResetAuthData(IN OUT ISCSI_SESSION *Session)
Definition: IScsiProto.c:431
EFI_STATUS IScsiExecuteScsiCommand(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *PassThru, IN UINT8 *Target, IN UINT64 Lun, IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet)
Definition: IScsiProto.c:2904
VOID IScsiUpdateCmdSN(IN OUT ISCSI_SESSION *Session, IN UINT32 MaxCmdSN, IN UINT32 ExpCmdSN)
Definition: IScsiProto.c:91
VOID IScsiSessionAbort(IN OUT ISCSI_SESSION *Session)
Definition: IScsiProto.c:3166
NET_BUF * IScsiPrepareLoginReq(IN OUT ISCSI_CONNECTION *Conn)
Definition: IScsiProto.c:749
EFI_STATUS IScsiProcessLoginRsp(IN OUT ISCSI_CONNECTION *Conn, IN OUT NET_BUF *Pdu)
Definition: IScsiProto.c:865
EFI_STATUS IScsiOnNopInRcvd(IN NET_BUF *Pdu, IN ISCSI_TCB *Tcb)
Definition: IScsiProto.c:2852
VOID IScsiFillOpParams(IN ISCSI_CONNECTION *Conn, IN OUT NET_BUF *Pdu)
Definition: IScsiProto.c:1779
NET_BUF * IScsiNewDataOutPdu(IN UINT8 *Data, IN UINT32 Len, IN UINT32 DataSN, IN ISCSI_TCB *Tcb, IN UINT64 Lun)
Definition: IScsiProto.c:2349
EFI_STATUS IScsiGetIp6NicInfo(IN ISCSI_CONNECTION *Conn)
Definition: IScsiProto.c:332
VOID IScsiDestroyConnection(IN ISCSI_CONNECTION *Conn)
Definition: IScsiProto.c:310
VOID IScsiFreeKeyValueList(IN LIST_ENTRY *KeyValueList)
Definition: IScsiProto.c:1978
NET_BUF * IScsiNewScsiCmdPdu(IN EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet, IN UINT64 Lun, IN ISCSI_TCB *Tcb)
Definition: IScsiProto.c:2168
CHAR8 * IScsiGetValueByKeyFromList(IN OUT LIST_ENTRY *KeyValueList, IN CHAR8 *Key)
Definition: IScsiProto.c:1945
EFI_STATUS IScsiUpdateTargetAddress(IN OUT ISCSI_SESSION *Session, IN CHAR8 *Data, IN UINT32 Len)
Definition: IScsiProto.c:1103
EFI_STATUS IScsiSendDataOutPduSequence(IN UINT8 *Data, IN UINT64 Lun, IN ISCSI_TCB *Tcb)
Definition: IScsiProto.c:2529
EFI_STATUS IScsiPadSegment(IN OUT NET_BUF *Pdu, IN UINT32 Len)
Definition: IScsiProto.c:1843
VOID IScsiDetatchConnection(IN OUT ISCSI_CONNECTION *Conn)
Definition: IScsiProto.c:38
EFI_STATUS IScsiCheckOpParams(IN OUT ISCSI_CONNECTION *Conn)
Definition: IScsiProto.c:1505
EFI_STATUS IScsiConnLogin(IN OUT ISCSI_CONNECTION *Conn, IN UINT16 Timeout)
Definition: IScsiProto.c:122
EFI_STATUS IScsiSessionLogin(IN ISCSI_SESSION *Session)
Definition: IScsiProto.c:452
EFI_STATUS IScsiNormalizeName(IN OUT CHAR8 *Name, IN UINTN Len)
Definition: IScsiProto.c:2006
LIST_ENTRY * IScsiBuildKeyValueList(IN CHAR8 *Data, IN UINT32 Len)
Definition: IScsiProto.c:1876
VOID EFIAPI IScsiNbufExtFree(VOID *Arg)
Definition: IScsiProto.c:1280
LIST_ENTRY * IScsiGenerateDataOutPduSequence(IN UINT8 *Data, IN ISCSI_TCB *Tcb, IN UINT64 Lun)
Definition: IScsiProto.c:2445
EFI_STATUS IScsiAddKeyValuePair(IN OUT NET_BUF *Pdu, IN CHAR8 *Key, IN CHAR8 *Value)
Definition: IScsiProto.c:677
EFI_STATUS IScsiOnR2TRcvd(IN NET_BUF *Pdu, IN ISCSI_TCB *Tcb, IN UINT64 Lun, IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet)
Definition: IScsiProto.c:2674
EFI_STATUS IScsiSessionReLogin(IN ISCSI_SESSION *Session)
Definition: IScsiProto.c:547
ISCSI_CONNECTION * IScsiCreateConnection(IN ISCSI_SESSION *Session)
Definition: IScsiProto.c:194
VOID IScsiSessionInit(IN OUT ISCSI_SESSION *Session, IN BOOLEAN Recovery)
Definition: IScsiProto.c:3125
NET_BUF * IScsiNewDataSegment(IN UINT8 *Data, IN UINT32 Len, IN BOOLEAN DataDigest)
Definition: IScsiProto.c:2126
VOID IScsiConnReset(IN OUT ISCSI_CONNECTION *Conn)
Definition: IScsiProto.c:178
EFI_STATUS IScsiReceivePdu(IN ISCSI_CONNECTION *Conn, OUT NET_BUF **Pdu, IN ISCSI_IN_BUFFER_CONTEXT *Context OPTIONAL, IN BOOLEAN HeaderDigest, IN BOOLEAN DataDigest, IN EFI_EVENT TimeoutEvent OPTIONAL)
Definition: IScsiProto.c:1307
EFI_STATUS IScsiOnScsiRspRcvd(IN NET_BUF *Pdu, IN ISCSI_TCB *Tcb, IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet)
Definition: IScsiProto.c:2745
#define SESSION_STATE_FREE
Definition: IScsiProto.h:84
struct _ISCSI_BASIC_HEADER ISCSI_BASIC_HEADER
#define CONN_STATE_FREE
Definition: IScsiProto.h:72
struct _SCSI_COMMAND SCSI_COMMAND
UINTN EFIAPI AsciiSPrint(OUT CHAR8 *StartOfBuffer, IN UINTN BufferSize, IN CONST CHAR8 *FormatString,...)
Definition: PrintLib.c:813
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define MIN(a, b)
Definition: Base.h:1007
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define MAX(a, b)
Definition: Base.h:992
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
VOID EFIAPI NetbufFree(IN NET_BUF *Nbuf)
Definition: NetBuffer.c:195
VOID EFIAPI NetbufQueInit(IN OUT NET_BUF_QUEUE *NbufQue)
Definition: NetBuffer.c:1300
LIST_ENTRY *EFIAPI NetListRemoveHead(IN OUT LIST_ENTRY *Head)
Definition: DxeNetLib.c:1090
UINT32 EFIAPI NetbufTrim(IN OUT NET_BUF *Nbuf, IN UINT32 Len, IN BOOLEAN FromHead)
Definition: NetBuffer.c:1134
UINT32 EFIAPI NetbufQueCopy(IN NET_BUF_QUEUE *NbufQue, IN UINT32 Offset, IN UINT32 Len, OUT UINT8 *Dest)
Definition: NetBuffer.c:1438
VOID EFIAPI NetbufQueFlush(IN OUT NET_BUF_QUEUE *NbufQue)
Definition: NetBuffer.c:1592
BOOLEAN EFIAPI NetIp6IsNetEqual(EFI_IPv6_ADDRESS *Ip1, EFI_IPv6_ADDRESS *Ip2, UINT8 PrefixLength)
Definition: DxeNetLib.c:837
NET_BUF *EFIAPI NetbufAlloc(IN UINT32 Len)
Definition: NetBuffer.c:89
NET_BUF *EFIAPI NetbufFromExt(IN NET_FRAGMENT *ExtFragment, IN UINT32 ExtNum, IN UINT32 HeadSpace, IN UINT32 HeadLen, IN NET_VECTOR_EXT_FREE ExtFree, IN VOID *Arg OPTIONAL)
Definition: NetBuffer.c:693
NET_BUF *EFIAPI NetbufFromBufList(IN LIST_ENTRY *BufList, IN UINT32 HeadSpace, IN UINT32 HeaderLen, IN NET_VECTOR_EXT_FREE ExtFree, IN VOID *Arg OPTIONAL)
Definition: NetBuffer.c:914
EFI_STATUS EFIAPI NetLibDetectMediaWaitTimeout(IN EFI_HANDLE ServiceHandle, IN UINT64 Timeout, OUT EFI_STATUS *MediaState)
Definition: DxeNetLib.c:2683
UINT8 *EFIAPI NetbufAllocSpace(IN OUT NET_BUF *Nbuf, IN UINT32 Len, IN BOOLEAN FromHead)
Definition: NetBuffer.c:1015
VOID EFIAPI NetbufFreeList(IN OUT LIST_ENTRY *Head)
Definition: NetBuffer.c:319
UINT8 *EFIAPI NetbufGetByte(IN NET_BUF *Nbuf, IN UINT32 Offset, OUT UINT32 *Index OPTIONAL)
Definition: NetBuffer.c:359
VOID EFIAPI NetbufQueAppend(IN OUT NET_BUF_QUEUE *NbufQue, IN OUT NET_BUF *Nbuf)
Definition: NetBuffer.c:1374
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
EFI_STATUS EFIAPI TcpIoCreateSocket(IN EFI_HANDLE Image, IN EFI_HANDLE Controller, IN UINT8 TcpVersion, IN TCP_IO_CONFIG_DATA *ConfigData, OUT TCP_IO *TcpIo)
Definition: DxeTcpIoLib.c:125
EFI_STATUS EFIAPI TcpIoReceive(IN OUT TCP_IO *TcpIo, IN NET_BUF *Packet, IN BOOLEAN AsyncMode, IN EFI_EVENT Timeout OPTIONAL)
Definition: DxeTcpIoLib.c:872
EFI_STATUS EFIAPI TcpIoConnect(IN OUT TCP_IO *TcpIo, IN EFI_EVENT Timeout OPTIONAL)
Definition: DxeTcpIoLib.c:534
EFI_STATUS EFIAPI TcpIoTransmit(IN TCP_IO *TcpIo, IN NET_BUF *Packet)
Definition: DxeTcpIoLib.c:752
VOID EFIAPI TcpIoDestroySocket(IN TCP_IO *TcpIo)
Definition: DxeTcpIoLib.c:397
VOID EFIAPI TcpIoReset(IN OUT TCP_IO *TcpIo)
Definition: DxeTcpIoLib.c:694
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
@ TimerCancel
Definition: UefiSpec.h:531
@ TimerRelative
Definition: UefiSpec.h:539
UINT8 PrefixLength
The length of the prefix associated with the Address.
Definition: Ip6.h:222
EFI_IPv6_ADDRESS Address
The IPv6 address.
Definition: Ip6.h:221
EFI_IPv6_ADDRESS StationAddress
Definition: Ip6.h:188
EFI_IP6_NEIGHBOR_CACHE * NeighborCache
Definition: Ip6.h:366
EFI_IP6_ICMP_TYPE * IcmpTypeList
Definition: Ip6.h:386
UINT32 RouteCount
Definition: Ip6.h:352
EFI_IP6_ADDRESS_INFO * AddressList
Definition: Ip6.h:336
EFI_IP6_ROUTE_TABLE * RouteTable
Definition: Ip6.h:356
EFI_IPv6_ADDRESS * GroupTable
Definition: Ip6.h:347
EFI_IP6_CONFIG_DATA ConfigData
Definition: Ip6.h:319
EFI_IP6_ADDRESS_INFO * PrefixTable
Definition: Ip6.h:376
UINT32 AddressCount
Definition: Ip6.h:330
BOOLEAN IsConfigured
Definition: Ip6.h:326
UINT8 PrefixLength
Definition: Ip6.h:243
EFI_IPv6_ADDRESS Gateway
Definition: Ip6.h:235
EFI_IPv6_ADDRESS Destination
Definition: Ip6.h:239
Definition: Base.h:213