/** Check whether the DestinationAddress is an anycast address. @param[in] IpSb The IP service that received the packet. @param[in] DestinationAddress Points to the Destination Address of the packet. @retval TRUE The DestinationAddress is anycast address. @retval FALSE The DestinationAddress is not anycast address. **/ BOOLEAN Ip6IsAnycast ( IN IP6_SERVICE *IpSb, IN EFI_IPv6_ADDRESS *DestinationAddress ) { IP6_PREFIX_LIST_ENTRY *PrefixEntry; EFI_IPv6_ADDRESS Prefix; BOOLEAN Flag; ZeroMem (&Prefix, sizeof (EFI_IPv6_ADDRESS)); Flag = FALSE; // // If the address is known as on-link or autonomous prefix, record it as // anycast address. // do { PrefixEntry = Ip6FindPrefixListEntry (IpSb, Flag, 255, DestinationAddress); if (PrefixEntry != NULL) { IP6_COPY_ADDRESS (&Prefix, &PrefixEntry->Prefix); Ip6GetPrefix (PrefixEntry->PrefixLength, &Prefix); if (EFI_IP6_EQUAL (&Prefix, DestinationAddress)) { return TRUE; } } Flag = (BOOLEAN) !Flag; } while (Flag); return FALSE; }
/** Create a HTTP_IO to access the HTTP service. It will create and configure a HTTP child handle. @param[in] Image The handle of the driver image. @param[in] Controller The handle of the controller. @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. @param[in] ConfigData The HTTP_IO configuration data. @param[in] Callback Callback function which will be invoked when specified HTTP_IO_CALLBACK_EVENT happened. @param[in] Context The Context data which will be passed to the Callback function. @param[out] HttpIo The HTTP_IO. @retval EFI_SUCCESS The HTTP_IO is created and configured. @retval EFI_INVALID_PARAMETER One or more parameters are invalid. @retval EFI_UNSUPPORTED One or more of the control options are not supported in the implementation. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. @retval Others Failed to create the HTTP_IO or configure it. **/ EFI_STATUS HttpIoCreateIo ( IN EFI_HANDLE Image, IN EFI_HANDLE Controller, IN UINT8 IpVersion, IN HTTP_IO_CONFIG_DATA *ConfigData, IN HTTP_IO_CALLBACK Callback, IN VOID *Context, OUT HTTP_IO *HttpIo ) { EFI_STATUS Status; EFI_HTTP_CONFIG_DATA HttpConfigData; EFI_HTTPv4_ACCESS_POINT Http4AccessPoint; EFI_HTTPv6_ACCESS_POINT Http6AccessPoint; EFI_HTTP_PROTOCOL *Http; EFI_EVENT Event; if ((Image == NULL) || (Controller == NULL) || (ConfigData == NULL) || (HttpIo == NULL)) { return EFI_INVALID_PARAMETER; } if (IpVersion != IP_VERSION_4 && IpVersion != IP_VERSION_6) { return EFI_UNSUPPORTED; } ZeroMem (HttpIo, sizeof (HTTP_IO)); // // Create the HTTP child instance and get the HTTP protocol. // Status = NetLibCreateServiceChild ( Controller, Image, &gEfiHttpServiceBindingProtocolGuid, &HttpIo->Handle ); if (EFI_ERROR (Status)) { return Status; } Status = gBS->OpenProtocol ( HttpIo->Handle, &gEfiHttpProtocolGuid, (VOID **) &Http, Image, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status) || (Http == NULL)) { goto ON_ERROR; } // // Init the configuration data and configure the HTTP child. // HttpIo->Image = Image; HttpIo->Controller = Controller; HttpIo->IpVersion = IpVersion; HttpIo->Http = Http; HttpIo->Callback = Callback; HttpIo->Context = Context; ZeroMem (&HttpConfigData, sizeof (EFI_HTTP_CONFIG_DATA)); HttpConfigData.HttpVersion = HttpVersion11; HttpConfigData.TimeOutMillisec = ConfigData->Config4.RequestTimeOut; if (HttpIo->IpVersion == IP_VERSION_4) { HttpConfigData.LocalAddressIsIPv6 = FALSE; Http4AccessPoint.UseDefaultAddress = ConfigData->Config4.UseDefaultAddress; Http4AccessPoint.LocalPort = ConfigData->Config4.LocalPort; IP4_COPY_ADDRESS (&Http4AccessPoint.LocalAddress, &ConfigData->Config4.LocalIp); IP4_COPY_ADDRESS (&Http4AccessPoint.LocalSubnet, &ConfigData->Config4.SubnetMask); HttpConfigData.AccessPoint.IPv4Node = &Http4AccessPoint; } else { HttpConfigData.LocalAddressIsIPv6 = TRUE; Http6AccessPoint.LocalPort = ConfigData->Config6.LocalPort; IP6_COPY_ADDRESS (&Http6AccessPoint.LocalAddress, &ConfigData->Config6.LocalIp); HttpConfigData.AccessPoint.IPv6Node = &Http6AccessPoint; } Status = Http->Configure (Http, &HttpConfigData); if (EFI_ERROR (Status)) { goto ON_ERROR; } // // Create events for variuos asynchronous operations. // Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, HttpIoNotify, &HttpIo->IsTxDone, &Event ); if (EFI_ERROR (Status)) { goto ON_ERROR; } HttpIo->ReqToken.Event = Event; HttpIo->ReqToken.Message = &HttpIo->ReqMessage; Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, HttpIoNotify, &HttpIo->IsRxDone, &Event ); if (EFI_ERROR (Status)) { goto ON_ERROR; } HttpIo->RspToken.Event = Event; HttpIo->RspToken.Message = &HttpIo->RspMessage; // // Create TimeoutEvent for response // Status = gBS->CreateEvent ( EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Event ); if (EFI_ERROR (Status)) { goto ON_ERROR; } HttpIo->TimeoutEvent = Event; return EFI_SUCCESS; ON_ERROR: HttpIoDestroyIo (HttpIo); return Status; }
/** Retrieve the host address using the EFI_DNS6_PROTOCOL. @param[in] Private The pointer to the driver's private data. @param[in] HostName Pointer to buffer containing hostname. @param[out] IpAddress On output, pointer to buffer containing IPv6 address. @retval EFI_SUCCESS Operation succeeded. @retval EFI_DEVICE_ERROR An unexpected network error occurred. @retval Others Other errors as indicated. **/ EFI_STATUS HttpBootDns ( IN HTTP_BOOT_PRIVATE_DATA *Private, IN CHAR16 *HostName, OUT EFI_IPv6_ADDRESS *IpAddress ) { EFI_STATUS Status; EFI_DNS6_PROTOCOL *Dns6; EFI_DNS6_CONFIG_DATA Dns6ConfigData; EFI_DNS6_COMPLETION_TOKEN Token; EFI_HANDLE Dns6Handle; EFI_IP6_CONFIG_PROTOCOL *Ip6Config; EFI_IPv6_ADDRESS *DnsServerList; UINTN DnsServerListCount; UINTN DataSize; BOOLEAN IsDone; DnsServerList = NULL; DnsServerListCount = 0; Dns6 = NULL; Dns6Handle = NULL; ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN)); // // Get DNS server list from EFI IPv6 Configuration protocol. // Status = gBS->HandleProtocol (Private->Controller, &gEfiIp6ConfigProtocolGuid, (VOID **) &Ip6Config); if (!EFI_ERROR (Status)) { // // Get the required size. // DataSize = 0; Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, NULL); if (Status == EFI_BUFFER_TOO_SMALL) { DnsServerList = AllocatePool (DataSize); if (DnsServerList == NULL) { return EFI_OUT_OF_RESOURCES; } Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, DnsServerList); if (EFI_ERROR (Status)) { FreePool (DnsServerList); DnsServerList = NULL; } else { DnsServerListCount = DataSize / sizeof (EFI_IPv6_ADDRESS); } } } // // Create a DNSv6 child instance and get the protocol. // Status = NetLibCreateServiceChild ( Private->Controller, Private->Ip6Nic->ImageHandle, &gEfiDns6ServiceBindingProtocolGuid, &Dns6Handle ); if (EFI_ERROR (Status)) { goto Exit; } Status = gBS->OpenProtocol ( Dns6Handle, &gEfiDns6ProtocolGuid, (VOID **) &Dns6, Private->Ip6Nic->ImageHandle, Private->Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status)) { goto Exit; } // // Configure DNS6 instance for the DNS server address and protocol. // ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA)); Dns6ConfigData.DnsServerCount = (UINT32)DnsServerListCount; Dns6ConfigData.DnsServerList = DnsServerList; Dns6ConfigData.EnableDnsCache = TRUE; Dns6ConfigData.Protocol = EFI_IP_PROTO_UDP; IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp,&Private->StationIp.v6); Status = Dns6->Configure ( Dns6, &Dns6ConfigData ); if (EFI_ERROR (Status)) { goto Exit; } Token.Status = EFI_NOT_READY; IsDone = FALSE; // // Create event to set the IsDone flag when name resolution is finished. // Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, HttpBootCommonNotify, &IsDone, &Token.Event ); if (EFI_ERROR (Status)) { goto Exit; } // // Start asynchronous name resolution. // Status = Dns6->HostNameToIp (Dns6, HostName, &Token); if (EFI_ERROR (Status)) { goto Exit; } while (!IsDone) { Dns6->Poll (Dns6); } // // Name resolution is done, check result. // Status = Token.Status; if (!EFI_ERROR (Status)) { if (Token.RspData.H2AData == NULL) { Status = EFI_DEVICE_ERROR; goto Exit; } if (Token.RspData.H2AData->IpCount == 0 || Token.RspData.H2AData->IpList == NULL) { Status = EFI_DEVICE_ERROR; goto Exit; } // // We just return the first IPv6 address from DNS protocol. // IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList); Status = EFI_SUCCESS; } Exit: if (Token.Event != NULL) { gBS->CloseEvent (Token.Event); } if (Token.RspData.H2AData != NULL) { if (Token.RspData.H2AData->IpList != NULL) { FreePool (Token.RspData.H2AData->IpList); } FreePool (Token.RspData.H2AData); } if (Dns6 != NULL) { Dns6->Configure (Dns6, NULL); gBS->CloseProtocol ( Dns6Handle, &gEfiDns6ProtocolGuid, Private->Ip6Nic->ImageHandle, Private->Controller ); } if (Dns6Handle != NULL) { NetLibDestroyServiceChild ( Private->Controller, Private->Ip6Nic->ImageHandle, &gEfiDns6ServiceBindingProtocolGuid, Dns6Handle ); } if (DnsServerList != NULL) { FreePool (DnsServerList); } return Status; }
/** Pick up gw/dns IPv6 address in string format from Args with "-s" option and convert it to EFI_IPv6_ADDRESS format. @param[in, out] Arg The pointer of the address of ARG_LIST that save Args with the "-s" option. @param[out] Buf The pointer of the address of EFI_IPv6_ADDRESS. @param[out] BufSize The pointer of BufSize that describes the size of Buf in bytes. @retval EFI_SUCCESS The conversion is successful. @retval Others Doesn't find the host address, or it is an invalid IPv6 address in string format. **/ EFI_STATUS IfConfig6ParseGwDnsAddressList ( IN OUT ARG_LIST **Arg, OUT EFI_IPv6_ADDRESS **Buf, OUT UINTN *BufSize ) { EFI_STATUS Status; EFI_IPv6_ADDRESS *AddrBuf; ARG_LIST *VarArg; EFI_IPv6_ADDRESS Address; UINT8 Prefix; UINT8 AddrCnt; AddrCnt = 0; *BufSize = 0; *Buf = NULL; VarArg = *Arg; Status = EFI_SUCCESS; // // Go through the list to check the correctness of input gw/dns address. // while ((!EFI_ERROR (Status)) && (VarArg != NULL)) { Status = NetLibStrToIp6andPrefix (VarArg->Arg, &Address, &Prefix); if (EFI_ERROR (Status)) { // // gw ip ip ... host // break; } VarArg = VarArg->Next; AddrCnt++; } if (AddrCnt == 0) { return EFI_INVALID_PARAMETER; } AddrBuf = AllocateZeroPool (AddrCnt * sizeof (EFI_IPv6_ADDRESS)); ASSERT (AddrBuf != NULL); AddrCnt = 0; VarArg = *Arg; Status = EFI_SUCCESS; // // Go through the list to fill in the EFI_IPv6_ADDRESS structure. // while ((!EFI_ERROR (Status)) && (VarArg != NULL)) { Status = NetLibStrToIp6andPrefix (VarArg->Arg, &Address, &Prefix); if (EFI_ERROR (Status)) { break; } IP6_COPY_ADDRESS (&AddrBuf[AddrCnt], &Address); VarArg = VarArg->Next; AddrCnt++; } *Arg = VarArg; if (EFI_ERROR (Status) && (Status != EFI_INVALID_PARAMETER)) { goto ON_ERROR; } *Buf = AddrBuf; *BufSize = AddrCnt * sizeof (EFI_IPv6_ADDRESS); return EFI_SUCCESS; ON_ERROR: FreePool (AddrBuf); return Status; }
/** Pick up host IPv6 address in string format from Args with "-s" option and convert it to EFI_IP6_CONFIG_MANUAL_ADDRESS format. @param[in, out] Arg The pointer of the address of ARG_LIST which save Args with the "-s" option. @param[out] Buf The pointer of the address of EFI_IP6_CONFIG_MANUAL_ADDRESS. @param[out] BufSize The pointer of BufSize that describes the size of Buf in bytes. @retval EFI_SUCCESS The convertion is successful. @retval Others Does't find the host address, or it is an invalid IPv6 address in string format. **/ EFI_STATUS IfConfig6ParseManualAddressList ( IN OUT ARG_LIST **Arg, OUT EFI_IP6_CONFIG_MANUAL_ADDRESS **Buf, OUT UINTN *BufSize ) { EFI_STATUS Status; EFI_IP6_CONFIG_MANUAL_ADDRESS *AddrBuf; ARG_LIST *VarArg; EFI_IPv6_ADDRESS Address; UINT8 Prefix; UINT8 AddrCnt; Prefix = 0; AddrCnt = 0; *BufSize = 0; *Buf = NULL; VarArg = *Arg; Status = EFI_SUCCESS; // // Go through the list to check the correctness of input host ip6 address. // while ((!EFI_ERROR (Status)) && (VarArg != NULL)) { Status = NetLibStrToIp6andPrefix (VarArg->Arg, &Address, &Prefix); if (EFI_ERROR (Status)) { // // host ip ip ... gw // break; } VarArg = VarArg->Next; AddrCnt++; } if (AddrCnt == 0) { return EFI_INVALID_PARAMETER; } AddrBuf = AllocateZeroPool (AddrCnt * sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)); ASSERT (AddrBuf != NULL); AddrCnt = 0; VarArg = *Arg; Status = EFI_SUCCESS; // // Go through the list to fill in the EFI_IP6_CONFIG_MANUAL_ADDRESS structure. // while ((!EFI_ERROR (Status)) && (VarArg != NULL)) { Status = NetLibStrToIp6andPrefix (VarArg->Arg, &Address, &Prefix); if (EFI_ERROR (Status)) { break; } // // If prefix length is not set, set it as Zero here. In the IfConfigSetInterfaceInfo() // Zero prefix, length will be transfered to default prefix length. // if (Prefix == 0xFF) { Prefix = 0; } AddrBuf[AddrCnt].IsAnycast = FALSE; AddrBuf[AddrCnt].PrefixLength = Prefix; IP6_COPY_ADDRESS (&AddrBuf[AddrCnt].Address, &Address); VarArg = VarArg->Next; AddrCnt++; } *Arg = VarArg; if (EFI_ERROR (Status) && (Status != EFI_INVALID_PARAMETER)) { goto ON_ERROR; } *Buf = AddrBuf; *BufSize = AddrCnt * sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS); return EFI_SUCCESS; ON_ERROR: FreePool (AddrBuf); return Status; }
/** Create a TCP socket with the specified configuration data. @param[in] Image The handle of the driver image. @param[in] Controller The handle of the controller. @param[in] TcpVersion The version of Tcp, TCP_VERSION_4 or TCP_VERSION_6. @param[in] ConfigData The Tcp configuration data. @param[out] TcpIo The TcpIo. @retval EFI_SUCCESS The TCP socket is created and configured. @retval EFI_INVALID_PARAMETER One or more parameters are invalid. @retval EFI_UNSUPPORTED One or more of the control options are not supported in the implementation. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. @retval Others Failed to create the TCP socket or configure it. **/ 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 ) { EFI_STATUS Status; EFI_EVENT Event; EFI_GUID *ServiceBindingGuid; EFI_GUID *ProtocolGuid; VOID **Interface; EFI_TCP4_OPTION ControlOption; EFI_TCP4_CONFIG_DATA Tcp4ConfigData; EFI_TCP4_ACCESS_POINT *AccessPoint4; EFI_TCP4_PROTOCOL *Tcp4; EFI_TCP6_CONFIG_DATA Tcp6ConfigData; EFI_TCP6_ACCESS_POINT *AccessPoint6; EFI_TCP6_PROTOCOL *Tcp6; EFI_TCP4_RECEIVE_DATA *RxData; if ((Image == NULL) || (Controller == NULL) || (ConfigData == NULL) || (TcpIo == NULL)) { return EFI_INVALID_PARAMETER; } Tcp4 = NULL; Tcp6 = NULL; ZeroMem (TcpIo, sizeof (TCP_IO)); if (TcpVersion == TCP_VERSION_4) { ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid; ProtocolGuid = &gEfiTcp4ProtocolGuid; Interface = (VOID **) (&TcpIo->Tcp.Tcp4); } else if (TcpVersion == TCP_VERSION_6) { ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid; ProtocolGuid = &gEfiTcp6ProtocolGuid; Interface = (VOID **) (&TcpIo->Tcp.Tcp6); } else { return EFI_UNSUPPORTED; } TcpIo->TcpVersion = TcpVersion; // // Create the TCP child instance and get the TCP protocol. // Status = NetLibCreateServiceChild ( Controller, Image, ServiceBindingGuid, &TcpIo->Handle ); if (EFI_ERROR (Status)) { return Status; } Status = gBS->OpenProtocol ( TcpIo->Handle, ProtocolGuid, Interface, Image, Controller, EFI_OPEN_PROTOCOL_BY_DRIVER ); if (EFI_ERROR (Status) || (*Interface == NULL)) { goto ON_ERROR; } if (TcpVersion == TCP_VERSION_4) { Tcp4 = TcpIo->Tcp.Tcp4; } else { Tcp6 = TcpIo->Tcp.Tcp6; } TcpIo->Image = Image; TcpIo->Controller = Controller; // // Set the configuration parameters. // ControlOption.ReceiveBufferSize = 0x200000; ControlOption.SendBufferSize = 0x200000; ControlOption.MaxSynBackLog = 0; ControlOption.ConnectionTimeout = 0; ControlOption.DataRetries = 6; ControlOption.FinTimeout = 0; ControlOption.TimeWaitTimeout = 0; ControlOption.KeepAliveProbes = 4; ControlOption.KeepAliveTime = 0; ControlOption.KeepAliveInterval = 0; ControlOption.EnableNagle = FALSE; ControlOption.EnableTimeStamp = FALSE; ControlOption.EnableWindowScaling = TRUE; ControlOption.EnableSelectiveAck = FALSE; ControlOption.EnablePathMtuDiscovery = FALSE; if (TcpVersion == TCP_VERSION_4) { Tcp4ConfigData.TypeOfService = 8; Tcp4ConfigData.TimeToLive = 255; Tcp4ConfigData.ControlOption = &ControlOption; AccessPoint4 = &Tcp4ConfigData.AccessPoint; ZeroMem (AccessPoint4, sizeof (EFI_TCP4_ACCESS_POINT)); AccessPoint4->StationPort = ConfigData->Tcp4IoConfigData.StationPort; AccessPoint4->RemotePort = ConfigData->Tcp4IoConfigData.RemotePort; AccessPoint4->ActiveFlag = ConfigData->Tcp4IoConfigData.ActiveFlag; CopyMem ( &AccessPoint4->StationAddress, &ConfigData->Tcp4IoConfigData.LocalIp, sizeof (EFI_IPv4_ADDRESS) ); CopyMem ( &AccessPoint4->SubnetMask, &ConfigData->Tcp4IoConfigData.SubnetMask, sizeof (EFI_IPv4_ADDRESS) ); CopyMem ( &AccessPoint4->RemoteAddress, &ConfigData->Tcp4IoConfigData.RemoteIp, sizeof (EFI_IPv4_ADDRESS) ); ASSERT (Tcp4 != NULL); // // Configure the TCP4 protocol. // Status = Tcp4->Configure (Tcp4, &Tcp4ConfigData); if (EFI_ERROR (Status)) { goto ON_ERROR; } if (!EFI_IP4_EQUAL (&ConfigData->Tcp4IoConfigData.Gateway, &mZeroIp4Addr)) { // // The gateway is not zero. Add the default route manually. // Status = Tcp4->Routes ( Tcp4, FALSE, &mZeroIp4Addr, &mZeroIp4Addr, &ConfigData->Tcp4IoConfigData.Gateway ); if (EFI_ERROR (Status)) { goto ON_ERROR; } } } else { Tcp6ConfigData.TrafficClass = 0; Tcp6ConfigData.HopLimit = 255; Tcp6ConfigData.ControlOption = (EFI_TCP6_OPTION *) &ControlOption; AccessPoint6 = &Tcp6ConfigData.AccessPoint; ZeroMem (AccessPoint6, sizeof (EFI_TCP6_ACCESS_POINT)); AccessPoint6->StationPort = ConfigData->Tcp6IoConfigData.StationPort; AccessPoint6->RemotePort = ConfigData->Tcp6IoConfigData.RemotePort; AccessPoint6->ActiveFlag = ConfigData->Tcp6IoConfigData.ActiveFlag; IP6_COPY_ADDRESS (&AccessPoint6->RemoteAddress, &ConfigData->Tcp6IoConfigData.RemoteIp); ASSERT (Tcp6 != NULL); // // Configure the TCP6 protocol. // Status = Tcp6->Configure (Tcp6, &Tcp6ConfigData); if (Status == EFI_NO_MAPPING) { Status = TcpIoGetMapping (Tcp6, &Tcp6ConfigData); } if (EFI_ERROR (Status)) { goto ON_ERROR; } } // // Create events for variuos asynchronous operations. // Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, TcpIoCommonNotify, &TcpIo->IsConnDone, &Event ); if (EFI_ERROR (Status)) { goto ON_ERROR; } TcpIo->ConnToken.Tcp4Token.CompletionToken.Event = Event; Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, TcpIoCommonNotify, &TcpIo->IsListenDone, &Event ); if (EFI_ERROR (Status)) { goto ON_ERROR; } TcpIo->ListenToken.Tcp4Token.CompletionToken.Event = Event; Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, TcpIoCommonNotify, &TcpIo->IsTxDone, &Event ); if (EFI_ERROR (Status)) { goto ON_ERROR; } TcpIo->TxToken.Tcp4Token.CompletionToken.Event = Event; Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, TcpIoCommonNotify, &TcpIo->IsRxDone, &Event ); if (EFI_ERROR (Status)) { goto ON_ERROR; } TcpIo->RxToken.Tcp4Token.CompletionToken.Event = Event; RxData = (EFI_TCP4_RECEIVE_DATA *) AllocateZeroPool (sizeof (EFI_TCP4_RECEIVE_DATA)); if (RxData == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ON_ERROR; } TcpIo->RxToken.Tcp4Token.Packet.RxData = RxData; Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, TcpIoCommonNotify, &TcpIo->IsCloseDone, &Event ); if (EFI_ERROR (Status)) { goto ON_ERROR; } TcpIo->CloseToken.Tcp4Token.CompletionToken.Event = Event; return EFI_SUCCESS; ON_ERROR: TcpIoDestroySocket (TcpIo); return Status; }
/** Configure the Pcb using CfgData. @param[in] Sk Pointer to the socket of this TCP instance. @param[in] CfgData Pointer to the TCP configuration data. @retval EFI_SUCCESS The operation completed successfully. @retval EFI_INVALID_PARAMETER A same access point has been configured in another TCP instance. @retval EFI_OUT_OF_RESOURCES Failed due to resource limits. **/ EFI_STATUS TcpConfigurePcb ( IN SOCKET *Sk, IN TCP_CONFIG_DATA *CfgData ) { IP_IO_IP_CONFIG_DATA IpCfgData; EFI_STATUS Status; EFI_TCP4_OPTION *Option; TCP_PROTO_DATA *TcpProto; TCP_CB *Tcb; TCP_ACCESS_POINT *TcpAp; ASSERT ((CfgData != NULL) && (Sk != NULL) && (Sk->SockHandle != NULL)); TcpProto = (TCP_PROTO_DATA *) Sk->ProtoReserved; Tcb = TcpProto->TcpPcb; ASSERT (Tcb != NULL); if (Sk->IpVersion == IP_VERSION_4) { // // Add Ip for send pkt to the peer // CopyMem (&IpCfgData.Ip4CfgData, &mIp4IoDefaultIpConfigData, sizeof (EFI_IP4_CONFIG_DATA)); IpCfgData.Ip4CfgData.DefaultProtocol = EFI_IP_PROTO_TCP; IpCfgData.Ip4CfgData.TypeOfService = CfgData->Tcp4CfgData.TypeOfService; IpCfgData.Ip4CfgData.TimeToLive = CfgData->Tcp4CfgData.TimeToLive; IpCfgData.Ip4CfgData.UseDefaultAddress = CfgData->Tcp4CfgData.AccessPoint.UseDefaultAddress; IP4_COPY_ADDRESS ( &IpCfgData.Ip4CfgData.SubnetMask, &CfgData->Tcp4CfgData.AccessPoint.SubnetMask ); IpCfgData.Ip4CfgData.ReceiveTimeout = (UINT32) (-1); IP4_COPY_ADDRESS ( &IpCfgData.Ip4CfgData.StationAddress, &CfgData->Tcp4CfgData.AccessPoint.StationAddress ); } else { ASSERT (Sk->IpVersion == IP_VERSION_6); CopyMem (&IpCfgData.Ip6CfgData, &mIp6IoDefaultIpConfigData, sizeof (EFI_IP6_CONFIG_DATA)); IpCfgData.Ip6CfgData.DefaultProtocol = EFI_IP_PROTO_TCP; IpCfgData.Ip6CfgData.TrafficClass = CfgData->Tcp6CfgData.TrafficClass; IpCfgData.Ip6CfgData.HopLimit = CfgData->Tcp6CfgData.HopLimit; IpCfgData.Ip6CfgData.ReceiveTimeout = (UINT32) (-1); IP6_COPY_ADDRESS ( &IpCfgData.Ip6CfgData.StationAddress, &CfgData->Tcp6CfgData.AccessPoint.StationAddress ); IP6_COPY_ADDRESS ( &IpCfgData.Ip6CfgData.DestinationAddress, &CfgData->Tcp6CfgData.AccessPoint.RemoteAddress ); } // // Configure the IP instance this Tcb consumes. // Status = IpIoConfigIp (Tcb->IpInfo, &IpCfgData); if (EFI_ERROR (Status)) { goto OnExit; } if (Sk->IpVersion == IP_VERSION_4) { // // Get the default address information if the instance is configured to use default address. // IP4_COPY_ADDRESS ( &CfgData->Tcp4CfgData.AccessPoint.StationAddress, &IpCfgData.Ip4CfgData.StationAddress ); IP4_COPY_ADDRESS ( &CfgData->Tcp4CfgData.AccessPoint.SubnetMask, &IpCfgData.Ip4CfgData.SubnetMask ); TcpAp = (TCP_ACCESS_POINT *) &CfgData->Tcp4CfgData.AccessPoint; } else { IP6_COPY_ADDRESS ( &CfgData->Tcp6CfgData.AccessPoint.StationAddress, &IpCfgData.Ip6CfgData.StationAddress ); TcpAp = (TCP_ACCESS_POINT *) &CfgData->Tcp6CfgData.AccessPoint; } // // check if we can bind this endpoint in CfgData // Status = TcpBind (TcpAp, Sk->IpVersion); if (EFI_ERROR (Status)) { DEBUG ( (EFI_D_ERROR, "TcpConfigurePcb: Bind endpoint failed with %r\n", Status) ); goto OnExit; } // // Initalize the operating information in this Tcb // ASSERT (Tcb->State == TCP_CLOSED && IsListEmpty (&Tcb->SndQue) && IsListEmpty (&Tcb->RcvQue)); TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE); Tcb->State = TCP_CLOSED; Tcb->SndMss = 536; Tcb->RcvMss = TcpGetRcvMss (Sk); Tcb->SRtt = 0; Tcb->Rto = 3 * TCP_TICK_HZ; Tcb->CWnd = Tcb->SndMss; Tcb->Ssthresh = 0xffffffff; Tcb->CongestState = TCP_CONGEST_OPEN; Tcb->KeepAliveIdle = TCP_KEEPALIVE_IDLE_MIN; Tcb->KeepAlivePeriod = TCP_KEEPALIVE_PERIOD; Tcb->MaxKeepAlive = TCP_MAX_KEEPALIVE; Tcb->MaxRexmit = TCP_MAX_LOSS; Tcb->FinWait2Timeout = TCP_FIN_WAIT2_TIME; Tcb->TimeWaitTimeout = TCP_TIME_WAIT_TIME; Tcb->ConnectTimeout = TCP_CONNECT_TIME; if (Sk->IpVersion == IP_VERSION_4) { // // initialize Tcb in the light of CfgData // Tcb->Ttl = CfgData->Tcp4CfgData.TimeToLive; Tcb->Tos = CfgData->Tcp4CfgData.TypeOfService; Tcb->UseDefaultAddr = CfgData->Tcp4CfgData.AccessPoint.UseDefaultAddress; CopyMem (&Tcb->LocalEnd.Ip, &CfgData->Tcp4CfgData.AccessPoint.StationAddress, sizeof (IP4_ADDR)); Tcb->LocalEnd.Port = HTONS (CfgData->Tcp4CfgData.AccessPoint.StationPort); IP4_COPY_ADDRESS (&Tcb->SubnetMask, &CfgData->Tcp4CfgData.AccessPoint.SubnetMask); CopyMem (&Tcb->RemoteEnd.Ip, &CfgData->Tcp4CfgData.AccessPoint.RemoteAddress, sizeof (IP4_ADDR)); Tcb->RemoteEnd.Port = HTONS (CfgData->Tcp4CfgData.AccessPoint.RemotePort); Option = CfgData->Tcp4CfgData.ControlOption; } else { Tcb->Ttl = CfgData->Tcp6CfgData.HopLimit; Tcb->Tos = CfgData->Tcp6CfgData.TrafficClass; IP6_COPY_ADDRESS (&Tcb->LocalEnd.Ip, &CfgData->Tcp6CfgData.AccessPoint.StationAddress); Tcb->LocalEnd.Port = HTONS (CfgData->Tcp6CfgData.AccessPoint.StationPort); IP6_COPY_ADDRESS (&Tcb->RemoteEnd.Ip, &CfgData->Tcp6CfgData.AccessPoint.RemoteAddress); Tcb->RemoteEnd.Port = HTONS (CfgData->Tcp6CfgData.AccessPoint.RemotePort); // // Type EFI_TCP4_OPTION and EFI_TCP6_OPTION are the same. // Option = (EFI_TCP4_OPTION *) CfgData->Tcp6CfgData.ControlOption; } if (Option != NULL) { SET_RCV_BUFFSIZE ( Sk, (UINT32) (TCP_COMP_VAL ( TCP_RCV_BUF_SIZE_MIN, TCP_RCV_BUF_SIZE, TCP_RCV_BUF_SIZE, Option->ReceiveBufferSize ) ) ); SET_SND_BUFFSIZE ( Sk, (UINT32) (TCP_COMP_VAL ( TCP_SND_BUF_SIZE_MIN, TCP_SND_BUF_SIZE, TCP_SND_BUF_SIZE, Option->SendBufferSize ) ) ); SET_BACKLOG ( Sk, (UINT32) (TCP_COMP_VAL ( TCP_BACKLOG_MIN, TCP_BACKLOG, TCP_BACKLOG, Option->MaxSynBackLog ) ) ); Tcb->MaxRexmit = (UINT16) TCP_COMP_VAL ( TCP_MAX_LOSS_MIN, TCP_MAX_LOSS, TCP_MAX_LOSS, Option->DataRetries ); Tcb->FinWait2Timeout = TCP_COMP_VAL ( TCP_FIN_WAIT2_TIME, TCP_FIN_WAIT2_TIME_MAX, TCP_FIN_WAIT2_TIME, (UINT32) (Option->FinTimeout * TCP_TICK_HZ) ); if (Option->TimeWaitTimeout != 0) { Tcb->TimeWaitTimeout = TCP_COMP_VAL ( TCP_TIME_WAIT_TIME, TCP_TIME_WAIT_TIME_MAX, TCP_TIME_WAIT_TIME, (UINT32) (Option->TimeWaitTimeout * TCP_TICK_HZ) ); } else { Tcb->TimeWaitTimeout = 0; } if (Option->KeepAliveProbes != 0) { TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_KEEPALIVE); Tcb->MaxKeepAlive = (UINT8) TCP_COMP_VAL ( TCP_MAX_KEEPALIVE_MIN, TCP_MAX_KEEPALIVE, TCP_MAX_KEEPALIVE, Option->KeepAliveProbes ); Tcb->KeepAliveIdle = TCP_COMP_VAL ( TCP_KEEPALIVE_IDLE_MIN, TCP_KEEPALIVE_IDLE_MAX, TCP_KEEPALIVE_IDLE_MIN, (UINT32) (Option->KeepAliveTime * TCP_TICK_HZ) ); Tcb->KeepAlivePeriod = TCP_COMP_VAL ( TCP_KEEPALIVE_PERIOD_MIN, TCP_KEEPALIVE_PERIOD, TCP_KEEPALIVE_PERIOD, (UINT32) (Option->KeepAliveInterval * TCP_TICK_HZ) ); } Tcb->ConnectTimeout = TCP_COMP_VAL ( TCP_CONNECT_TIME_MIN, TCP_CONNECT_TIME, TCP_CONNECT_TIME, (UINT32) (Option->ConnectionTimeout * TCP_TICK_HZ) ); if (!Option->EnableNagle) { TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE); } if (!Option->EnableTimeStamp) { TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_TS); } if (!Option->EnableWindowScaling) { TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_NO_WS); } } // // The socket is bound, the <SrcIp, SrcPort, DstIp, DstPort> is // determined, construct the IP device path and install it. // Status = TcpInstallDevicePath (Sk); if (EFI_ERROR (Status)) { goto OnExit; } // // update state of Tcb and socket // if (((Sk->IpVersion == IP_VERSION_4) && !CfgData->Tcp4CfgData.AccessPoint.ActiveFlag) || ((Sk->IpVersion == IP_VERSION_6) && !CfgData->Tcp6CfgData.AccessPoint.ActiveFlag) ) { TcpSetState (Tcb, TCP_LISTEN); SockSetState (Sk, SO_LISTENING); Sk->ConfigureState = SO_CONFIGURED_PASSIVE; } else { Sk->ConfigureState = SO_CONFIGURED_ACTIVE; } if (Sk->IpVersion == IP_VERSION_6) { Tcb->Tick = TCP6_REFRESH_NEIGHBOR_TICK; if (NetIp6IsUnspecifiedAddr (&Tcb->RemoteEnd.Ip.v6)) { Tcb->RemoteIpZero = TRUE; } } TcpInsertTcb (Tcb); OnExit: return Status; }
/** If TcpAp->StationPort isn't zero, check whether the access point is registered, else generate a random station port for this access point. @param[in] TcpAp Pointer to the access point. @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6 @retval EFI_SUCCESS The check passed or the port is assigned. @retval EFI_INVALID_PARAMETER The non-zero station port is already used. @retval EFI_OUT_OF_RESOURCES No port can be allocated. **/ EFI_STATUS TcpBind ( IN TCP_ACCESS_POINT *TcpAp, IN UINT8 IpVersion ) { BOOLEAN Cycle; EFI_IP_ADDRESS Local; UINT16 *Port; UINT16 *RandomPort; if (IpVersion == IP_VERSION_4) { IP4_COPY_ADDRESS (&Local, &TcpAp->Tcp4Ap.StationAddress); Port = &TcpAp->Tcp4Ap.StationPort; RandomPort = &mTcp4RandomPort; } else { IP6_COPY_ADDRESS (&Local, &TcpAp->Tcp6Ap.StationAddress); Port = &TcpAp->Tcp6Ap.StationPort; RandomPort = &mTcp6RandomPort; } if (0 != *Port) { // // Check if a same endpoing is bound. // if (TcpFindTcbByPeer (&Local, *Port, IpVersion)) { return EFI_INVALID_PARAMETER; } } else { // // generate a random port // Cycle = FALSE; if (TCP_PORT_USER_RESERVED == *RandomPort) { *RandomPort = TCP_PORT_KNOWN; } (*RandomPort)++; while (TcpFindTcbByPeer (&Local, *RandomPort, IpVersion)) { (*RandomPort)++; if (*RandomPort <= TCP_PORT_KNOWN) { if (Cycle) { DEBUG ( (EFI_D_ERROR, "TcpBind: no port can be allocated for this pcb\n") ); return EFI_OUT_OF_RESOURCES; } *RandomPort = TCP_PORT_KNOWN + 1; Cycle = TRUE; } } *Port = *RandomPort; } return EFI_SUCCESS; }
/** Get the operational settings of this TCPv6 instance. @param[in] Tcb Pointer to the TCP_CB of this TCP instance. @param[in, out] Mode Pointer to the buffer to store the operational settings. @retval EFI_SUCCESS The mode data was read. @retval EFI_NOT_STARTED No configuration data is available because this instance hasn't been started. **/ EFI_STATUS Tcp6GetMode ( IN TCP_CB *Tcb, IN OUT TCP6_MODE_DATA *Mode ) { SOCKET *Sock; EFI_TCP6_CONFIG_DATA *ConfigData; EFI_TCP6_ACCESS_POINT *AccessPoint; EFI_TCP6_OPTION *Option; EFI_IP6_PROTOCOL *Ip; Sock = Tcb->Sk; if (!SOCK_IS_CONFIGURED (Sock) && (Mode->Tcp6ConfigData != NULL)) { return EFI_NOT_STARTED; } if (Mode->Tcp6State != NULL) { *(Mode->Tcp6State) = (EFI_TCP6_CONNECTION_STATE) (Tcb->State); } if (Mode->Tcp6ConfigData != NULL) { ConfigData = Mode->Tcp6ConfigData; AccessPoint = &(ConfigData->AccessPoint); Option = ConfigData->ControlOption; ConfigData->TrafficClass = Tcb->Tos; ConfigData->HopLimit = Tcb->Ttl; AccessPoint->StationPort = NTOHS (Tcb->LocalEnd.Port); AccessPoint->RemotePort = NTOHS (Tcb->RemoteEnd.Port); AccessPoint->ActiveFlag = (BOOLEAN) (Tcb->State != TCP_LISTEN); IP6_COPY_ADDRESS (&AccessPoint->StationAddress, &Tcb->LocalEnd.Ip); IP6_COPY_ADDRESS (&AccessPoint->RemoteAddress, &Tcb->RemoteEnd.Ip); if (Option != NULL) { Option->ReceiveBufferSize = GET_RCV_BUFFSIZE (Tcb->Sk); Option->SendBufferSize = GET_SND_BUFFSIZE (Tcb->Sk); Option->MaxSynBackLog = GET_BACKLOG (Tcb->Sk); Option->ConnectionTimeout = Tcb->ConnectTimeout / TCP_TICK_HZ; Option->DataRetries = Tcb->MaxRexmit; Option->FinTimeout = Tcb->FinWait2Timeout / TCP_TICK_HZ; Option->TimeWaitTimeout = Tcb->TimeWaitTimeout / TCP_TICK_HZ; Option->KeepAliveProbes = Tcb->MaxKeepAlive; Option->KeepAliveTime = Tcb->KeepAliveIdle / TCP_TICK_HZ; Option->KeepAliveInterval = Tcb->KeepAlivePeriod / TCP_TICK_HZ; Option->EnableNagle = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE)); Option->EnableTimeStamp = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS)); Option->EnableWindowScaling = (BOOLEAN) (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS)); Option->EnableSelectiveAck = FALSE; Option->EnablePathMtuDiscovery = FALSE; } } Ip = Tcb->IpInfo->Ip.Ip6; ASSERT (Ip != NULL); return Ip->GetModeData (Ip, Mode->Ip6ModeData, Mode->MnpConfigData, Mode->SnpModeData); }
/** Reply an ICMPv6 echo request. @param[in] IpSb The IP service that received the packet. @param[in] Head The IP head of the ICMPv6 informational message. @param[in] Packet The content of the ICMPv6 message with the IP head removed. @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. @retval EFI_SUCCESS Successfully answered the ICMPv6 Echo request. @retval Others Failed to answer the ICMPv6 Echo request. **/ EFI_STATUS Ip6IcmpReplyEcho ( IN IP6_SERVICE *IpSb, IN EFI_IP6_HEADER *Head, IN NET_BUF *Packet ) { IP6_ICMP_INFORMATION_HEAD *Icmp; NET_BUF *Data; EFI_STATUS Status; EFI_IP6_HEADER ReplyHead; Status = EFI_OUT_OF_RESOURCES; // // make a copy the packet, it is really a bad idea to // send the MNP's buffer back to MNP. // Data = NetbufDuplicate (Packet, NULL, IP6_MAX_HEADLEN); if (Data == NULL) { goto Exit; } // // Change the ICMP type to echo reply, exchange the source // and destination, then send it. The source is updated to // use specific destination. See RFC1122. SRR/RR option // update is omitted. // Icmp = (IP6_ICMP_INFORMATION_HEAD *) NetbufGetByte (Data, 0, NULL); if (Icmp == NULL) { NetbufFree (Data); goto Exit; } Icmp->Head.Type = ICMP_V6_ECHO_REPLY; Icmp->Head.Checksum = 0; // // Generate the IPv6 basic header // If the Echo Reply is a response to a Echo Request sent to one of the node's unicast address, // the Source address of the Echo Reply must be the same address. // ZeroMem (&ReplyHead, sizeof (EFI_IP6_HEADER)); ReplyHead.PayloadLength = HTONS ((UINT16) (Packet->TotalSize)); ReplyHead.NextHeader = IP6_ICMP; ReplyHead.HopLimit = IpSb->CurHopLimit; IP6_COPY_ADDRESS (&ReplyHead.DestinationAddress, &Head->SourceAddress); if (Ip6IsOneOfSetAddress (IpSb, &Head->DestinationAddress, NULL, NULL)) { IP6_COPY_ADDRESS (&ReplyHead.SourceAddress, &Head->DestinationAddress); } // // If source is unspecified, Ip6Output will select a source for us // Status = Ip6Output ( IpSb, NULL, NULL, Data, &ReplyHead, NULL, 0, Ip6SysPacketSent, NULL ); Exit: NetbufFree (Packet); return Status; }