X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=NetworkPkg%2FIScsiDxe%2FIScsiProto.c;h=29b3c24997ea7231c8ea06005ffebf0e0a534820;hp=2ab4da8cdac22fa9330f3f44f9a5d98b8d7b319e;hb=0b10bb6f4387fd0587329d43e768a90371d63491;hpb=4c5a5e0cfecf23526493bf9a05c0530805bf10ec diff --git a/NetworkPkg/IScsiDxe/IScsiProto.c b/NetworkPkg/IScsiDxe/IScsiProto.c index 2ab4da8cda..29b3c24997 100644 --- a/NetworkPkg/IScsiDxe/IScsiProto.c +++ b/NetworkPkg/IScsiDxe/IScsiProto.c @@ -1,7 +1,7 @@ /** @file The implementation of iSCSI protocol based on RFC3720. -Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.
+Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -228,7 +228,7 @@ IScsiCreateConnection ( Conn->PartialRspRcvd = FALSE; Conn->ParamNegotiated = FALSE; Conn->Cid = Session->NextCid++; - Conn->Ipv6Flag = mPrivate->Ipv6Flag; + Conn->Ipv6Flag = NvData->IpMode == IP_MODE_IP6 || Session->ConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6; Status = gBS->CreateEvent ( EVT_TIMER, @@ -259,15 +259,16 @@ IScsiCreateConnection ( CopyMem (&Tcp4IoConfig->Gateway, &NvData->Gateway, sizeof (EFI_IPv4_ADDRESS)); CopyMem (&Tcp4IoConfig->RemoteIp, &NvData->TargetIp, sizeof (EFI_IPv4_ADDRESS)); - Tcp4IoConfig->RemotePort = NvData->TargetPort; - Tcp4IoConfig->ActiveFlag = TRUE; - + Tcp4IoConfig->RemotePort = NvData->TargetPort; + Tcp4IoConfig->ActiveFlag = TRUE; + Tcp4IoConfig->StationPort = 0; } else { Tcp6IoConfig = &TcpIoConfig.Tcp6IoConfigData; CopyMem (&Tcp6IoConfig->RemoteIp, &NvData->TargetIp, sizeof (EFI_IPv6_ADDRESS)); - Tcp6IoConfig->RemotePort = NvData->TargetPort; - Tcp6IoConfig->ActiveFlag = TRUE; + Tcp6IoConfig->RemotePort = NvData->TargetPort; + Tcp6IoConfig->ActiveFlag = TRUE; + Tcp6IoConfig->StationPort = 0; } // @@ -308,6 +309,98 @@ IScsiDestroyConnection ( FreePool (Conn); } +/** + Retrieve the IPv6 Address/Prefix/Gateway from the established TCP connection, these informations + will be filled in the iSCSI Boot Firmware Table. + + @param[in] Conn The connection used in the iSCSI login phase. + + @retval EFI_SUCCESS Get the NIC information successfully. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +IScsiGetIp6NicInfo ( + IN ISCSI_CONNECTION *Conn + ) +{ + ISCSI_SESSION_CONFIG_NVDATA *NvData; + EFI_TCP6_PROTOCOL *Tcp6; + EFI_IP6_MODE_DATA Ip6ModeData; + EFI_STATUS Status; + EFI_IPv6_ADDRESS *TargetIp; + UINTN Index; + UINT8 SubnetPrefixLength; + UINTN RouteEntry; + + NvData = &Conn->Session->ConfigData->SessionConfigData; + TargetIp = &NvData->TargetIp.v6; + Tcp6 = Conn->TcpIo.Tcp.Tcp6; + + ZeroMem (&Ip6ModeData, sizeof (EFI_IP6_MODE_DATA)); + Status = Tcp6->GetModeData ( + Tcp6, + NULL, + NULL, + &Ip6ModeData, + NULL, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (!Ip6ModeData.IsConfigured) { + Status = EFI_ABORTED; + goto ON_EXIT; + } + + IP6_COPY_ADDRESS (&NvData->LocalIp, &Ip6ModeData.ConfigData.StationAddress); + + NvData->PrefixLength = 0; + for (Index = 0; Index < Ip6ModeData.AddressCount; Index++) { + if (EFI_IP6_EQUAL (&NvData->LocalIp.v6, &Ip6ModeData.AddressList[Index].Address)) { + NvData->PrefixLength = Ip6ModeData.AddressList[Index].PrefixLength; + break; + } + } + + SubnetPrefixLength = 0; + RouteEntry = Ip6ModeData.RouteCount; + for (Index = 0; Index < Ip6ModeData.RouteCount; Index++) { + if (NetIp6IsNetEqual (TargetIp, &Ip6ModeData.RouteTable[Index].Destination, Ip6ModeData.RouteTable[Index].PrefixLength)) { + if (SubnetPrefixLength < Ip6ModeData.RouteTable[Index].PrefixLength) { + SubnetPrefixLength = Ip6ModeData.RouteTable[Index].PrefixLength; + RouteEntry = Index; + } + } + } + if (RouteEntry != Ip6ModeData.RouteCount) { + IP6_COPY_ADDRESS (&NvData->Gateway, &Ip6ModeData.RouteTable[RouteEntry].Gateway); + } + +ON_EXIT: + if (Ip6ModeData.AddressList != NULL) { + FreePool (Ip6ModeData.AddressList); + } + if (Ip6ModeData.GroupTable!= NULL) { + FreePool (Ip6ModeData.GroupTable); + } + if (Ip6ModeData.RouteTable!= NULL) { + FreePool (Ip6ModeData.RouteTable); + } + if (Ip6ModeData.NeighborCache!= NULL) { + FreePool (Ip6ModeData.NeighborCache); + } + if (Ip6ModeData.PrefixTable!= NULL) { + FreePool (Ip6ModeData.PrefixTable); + } + if (Ip6ModeData.IcmpTypeList!= NULL) { + FreePool (Ip6ModeData.IcmpTypeList); + } + + return Status; +} /** Login the iSCSI session. @@ -379,7 +472,7 @@ IScsiSessionLogin ( if (!EFI_ERROR (Status)) { Session->State = SESSION_STATE_LOGGED_IN; - if (!mPrivate->Ipv6Flag) { + if (!Conn->Ipv6Flag) { ProtocolGuid = &gEfiTcp4ProtocolGuid; } else { ProtocolGuid = &gEfiTcp6ProtocolGuid; @@ -395,6 +488,10 @@ IScsiSessionLogin ( ); ASSERT_EFI_ERROR (Status); + + if (Conn->Ipv6Flag) { + Status = IScsiGetIp6NicInfo (Conn); + } } return Status; @@ -514,6 +611,8 @@ IScsiReceiveLoginRsp ( if (EFI_ERROR (Status)) { return Status; } + ASSERT (Pdu != NULL); + // // A Login Response is received; process it. // @@ -539,6 +638,7 @@ IScsiReceiveLoginRsp ( the correspondence length fields are updated. @retval EFI_OUT_OF_RESOURCES There is not enough space in the PDU to add the key-value pair. + @retval EFI_PROTOCOL_ERROR There is no such data in the net buffer. **/ EFI_STATUS IScsiAddKeyValuePair ( @@ -555,6 +655,9 @@ IScsiAddKeyValuePair ( CHAR8 *Data; LoginReq = (ISCSI_LOGIN_REQUEST *) NetbufGetByte (Pdu, 0, NULL); + if (LoginReq == NULL) { + return EFI_PROTOCOL_ERROR; + } DataSegLen = NTOH24 (LoginReq->DataSegmentLength); KeyLen = (UINT32) AsciiStrLen (Key); @@ -741,6 +844,9 @@ IScsiProcessLoginRsp ( Session = Conn->Session; LoginRsp = (ISCSI_LOGIN_RESPONSE *) NetbufGetByte (Pdu, 0, NULL); + if (LoginRsp == NULL) { + return EFI_PROTOCOL_ERROR; + } if (!ISCSI_CHECK_OPCODE (LoginRsp, ISCSI_OPCODE_LOGIN_RSP)) { // // It is not a Login Response. @@ -1282,7 +1388,7 @@ ON_EXIT: /** - Check and get the result of the prameter negotiation. + Check and get the result of the parameter negotiation. @param[in, out] Conn The connection in iSCSI login. @@ -1530,6 +1636,12 @@ IScsiCheckOpParams ( IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DATA_PDU_IN_ORDER); IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_DATA_SEQUENCE_IN_ORDER); + // + // Remove irrelevant parameter, if any. + // + if (Session->InitialR2T && !Session->ImmediateData) { + IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_FIRST_BURST_LENGTH); + } if (IsListEmpty (KeyValueList)) { // @@ -1549,7 +1661,7 @@ ON_ERROR: /** - Fill the oprational parameters. + Fill the operational parameters. @param[in] Conn The connection in iSCSI login. @param[in, out] Pdu The iSCSI login request PDU to fill the parameters. @@ -2268,6 +2380,7 @@ IScsiGenerateDataOutPduSequence ( NET_BUF *DataOutPdu; ISCSI_CONNECTION *Conn; ISCSI_XFER_CONTEXT *XferContext; + UINT8 *DataOutPacket; PduList = AllocatePool (sizeof (LIST_ENTRY)); if (PduList == NULL) { @@ -2311,7 +2424,14 @@ IScsiGenerateDataOutPduSequence ( // // Set the F bit for the last data out PDU in this sequence. // - ISCSI_SET_FLAG (NetbufGetByte (DataOutPdu, 0, NULL), ISCSI_BHS_FLAG_FINAL); + DataOutPacket = NetbufGetByte (DataOutPdu, 0, NULL); + if (DataOutPacket == NULL) { + IScsiFreeNbufList (PduList); + PduList = NULL; + goto ON_EXIT; + } + + ISCSI_SET_FLAG (DataOutPacket, ISCSI_BHS_FLAG_FINAL); ON_EXIT: @@ -2396,6 +2516,9 @@ IScsiOnDataInRcvd ( EFI_STATUS Status; DataInHdr = (ISCSI_SCSI_DATA_IN *) NetbufGetByte (Pdu, 0, NULL); + if (DataInHdr == NULL) { + return EFI_PROTOCOL_ERROR; + } DataInHdr->InitiatorTaskTag = NTOHL (DataInHdr->InitiatorTaskTag); DataInHdr->ExpCmdSN = NTOHL (DataInHdr->ExpCmdSN); @@ -2486,6 +2609,9 @@ IScsiOnR2TRcvd ( UINT8 *Data; R2THdr = (ISCSI_READY_TO_TRANSFER *) NetbufGetByte (Pdu, 0, NULL); + if (R2THdr == NULL) { + return EFI_PROTOCOL_ERROR; + } R2THdr->InitiatorTaskTag = NTOHL (R2THdr->InitiatorTaskTag); R2THdr->TargetTransferTag = NTOHL (R2THdr->TargetTransferTag); @@ -2551,6 +2677,9 @@ IScsiOnScsiRspRcvd ( UINT32 DataSegLen; ScsiRspHdr = (SCSI_RESPONSE *) NetbufGetByte (Pdu, 0, NULL); + if (ScsiRspHdr == NULL) { + return EFI_PROTOCOL_ERROR; + } ScsiRspHdr->InitiatorTaskTag = NTOHL (ScsiRspHdr->InitiatorTaskTag); if (ScsiRspHdr->InitiatorTaskTag != Tcb->InitiatorTaskTag) { @@ -2613,6 +2742,9 @@ IScsiOnScsiRspRcvd ( DataSegLen = ISCSI_GET_DATASEG_LEN (ScsiRspHdr); if (DataSegLen != 0) { SenseData = (ISCSI_SENSE_DATA *) NetbufGetByte (Pdu, sizeof (SCSI_RESPONSE), NULL); + if (SenseData == NULL) { + return EFI_PROTOCOL_ERROR; + } SenseData->Length = NTOHS (SenseData->Length); @@ -2649,6 +2781,9 @@ IScsiOnNopInRcvd ( EFI_STATUS Status; NopInHdr = (ISCSI_NOP_IN *) NetbufGetByte (Pdu, 0, NULL); + if (NopInHdr == NULL) { + return EFI_PROTOCOL_ERROR; + } NopInHdr->StatSN = NTOHL (NopInHdr->StatSN); NopInHdr->ExpCmdSN = NTOHL (NopInHdr->ExpCmdSN); @@ -2684,6 +2819,7 @@ IScsiOnNopInRcvd ( the Packet. @retval EFI_DEVICE_ERROR Session state was not as required. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. + @retval EFI_PROTOCOL_ERROR There is no such data in the net buffer. @retval Others Other errors as indicated. **/ @@ -2716,7 +2852,8 @@ IScsiExecuteScsiCommand ( Timeout = 0; if (Session->State != SESSION_STATE_LOGGED_IN) { - return EFI_DEVICE_ERROR; + Status = EFI_DEVICE_ERROR; + goto ON_EXIT; } Conn = NET_LIST_USER_STRUCT_S ( @@ -2745,6 +2882,11 @@ IScsiExecuteScsiCommand ( XferContext = &Tcb->XferContext; PduHdr = NetbufGetByte (Pdu, 0, NULL); + if (PduHdr == NULL) { + Status = EFI_PROTOCOL_ERROR; + NetbufFree (Pdu); + goto ON_EXIT; + } XferContext->Offset = ISCSI_GET_DATASEG_LEN (PduHdr); // @@ -2803,7 +2945,13 @@ IScsiExecuteScsiCommand ( goto ON_EXIT; } - switch (ISCSI_GET_OPCODE (NetbufGetByte (Pdu, 0, NULL))) { + PduHdr = NetbufGetByte (Pdu, 0, NULL); + if (PduHdr == NULL) { + Status = EFI_PROTOCOL_ERROR; + NetbufFree (Pdu); + goto ON_EXIT; + } + switch (ISCSI_GET_OPCODE (PduHdr)) { case ISCSI_OPCODE_SCSI_DATA_IN: Status = IScsiOnDataInRcvd (Pdu, Tcb, Packet); break; @@ -2879,7 +3027,7 @@ IScsiSessionReinstatement ( { EFI_STATUS Status; - ASSERT (Session->State == SESSION_STATE_LOGGED_IN); + ASSERT (Session->State != SESSION_STATE_FREE); // // Abort the session and re-init it.