/** @file | |
Implementation of I/O interfaces between TCP and IpIoLib. | |
Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR> | |
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 | |
http://opensource.org/licenses/bsd-license.php. | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
**/ | |
#include "TcpMain.h" | |
/** | |
Packet receive callback function provided to IP_IO, used to call | |
the proper function to handle the packet received by IP. | |
@param[in] Status Result of the receive request. | |
@param[in] IcmpErr Valid when Status is EFI_ICMP_ERROR. | |
@param[in] NetSession The IP session for the received packet. | |
@param[in] Pkt Packet received. | |
@param[in] Context The data provided by the user for the received packet when | |
the callback is registered in IP_IO_OPEN_DATA::RcvdContext. | |
This is an optional parameter that may be NULL. | |
**/ | |
VOID | |
EFIAPI | |
TcpRxCallback ( | |
IN EFI_STATUS Status, | |
IN UINT8 IcmpErr, | |
IN EFI_NET_SESSION_DATA *NetSession, | |
IN NET_BUF *Pkt, | |
IN VOID *Context OPTIONAL | |
) | |
{ | |
if (EFI_SUCCESS == Status) { | |
TcpInput (Pkt, &NetSession->Source, &NetSession->Dest, NetSession->IpVersion); | |
} else { | |
TcpIcmpInput ( | |
Pkt, | |
IcmpErr, | |
&NetSession->Source, | |
&NetSession->Dest, | |
NetSession->IpVersion | |
); | |
} | |
} | |
/** | |
Send the segment to IP via IpIo function. | |
@param[in] Tcb Pointer to the TCP_CB of this TCP instance. | |
@param[in] Nbuf Pointer to the TCP segment to be sent. | |
@param[in] Src Source address of the TCP segment. | |
@param[in] Dest Destination address of the TCP segment. | |
@param[in] Version IP_VERSION_4 or IP_VERSION_6 | |
@retval 0 The segment was sent out successfully. | |
@retval -1 The segment failed to send. | |
**/ | |
INTN | |
TcpSendIpPacket ( | |
IN TCP_CB *Tcb, | |
IN NET_BUF *Nbuf, | |
IN EFI_IP_ADDRESS *Src, | |
IN EFI_IP_ADDRESS *Dest, | |
IN UINT8 Version | |
) | |
{ | |
EFI_STATUS Status; | |
IP_IO *IpIo; | |
IP_IO_OVERRIDE Override; | |
SOCKET *Sock; | |
VOID *IpSender; | |
TCP_PROTO_DATA *TcpProto; | |
if (NULL == Tcb) { | |
IpIo = NULL; | |
IpSender = IpIoFindSender (&IpIo, Version, Src); | |
if (IpSender == NULL) { | |
DEBUG ((EFI_D_WARN, "TcpSendIpPacket: No appropriate IpSender.\n")); | |
return -1; | |
} | |
if (Version == IP_VERSION_6) { | |
// | |
// It's tricky here. EFI IPv6 Spec don't allow an instance overriding the | |
// destination address if the dest is already specified through the | |
// configuration data. Here we get the IpIo we need and use the default IP | |
// instance in this IpIo to send the packet. The dest address is configured | |
// to be the unspecified address for the default IP instance. | |
// | |
IpSender = NULL; | |
} | |
} else { | |
Sock = Tcb->Sk; | |
TcpProto = (TCP_PROTO_DATA *) Sock->ProtoReserved; | |
IpIo = TcpProto->TcpService->IpIo; | |
IpSender = Tcb->IpInfo; | |
if (Version == IP_VERSION_6) { | |
// | |
// It's IPv6 and this TCP segment belongs to a solid TCB, in such case | |
// the destination address can't be overridden, so reset the Dest to NULL. | |
// | |
if (!Tcb->RemoteIpZero) { | |
Dest = NULL; | |
} | |
} | |
} | |
ASSERT (Version == IpIo->IpVersion); | |
if (Version == IP_VERSION_4) { | |
Override.Ip4OverrideData.TypeOfService = 0; | |
Override.Ip4OverrideData.TimeToLive = 255; | |
Override.Ip4OverrideData.DoNotFragment = FALSE; | |
Override.Ip4OverrideData.Protocol = EFI_IP_PROTO_TCP; | |
ZeroMem (&Override.Ip4OverrideData.GatewayAddress, sizeof (EFI_IPv4_ADDRESS)); | |
CopyMem (&Override.Ip4OverrideData.SourceAddress, Src, sizeof (EFI_IPv4_ADDRESS)); | |
} else { | |
Override.Ip6OverrideData.Protocol = EFI_IP_PROTO_TCP; | |
Override.Ip6OverrideData.HopLimit = 255; | |
Override.Ip6OverrideData.FlowLabel = 0; | |
} | |
Status = IpIoSend (IpIo, Nbuf, IpSender, NULL, NULL, Dest, &Override); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((EFI_D_ERROR, "TcpSendIpPacket: return %r error\n", Status)); | |
return -1; | |
} | |
return 0; | |
} | |
/** | |
Refresh the remote peer's Neighbor Cache State if already exists. | |
@param[in] Tcb Pointer to the TCP_CB of this TCP instance. | |
@param[in] Neighbor Source address of the TCP segment. | |
@param[in] Timeout Time in 100-ns units that this entry will remain | |
in the neighbor cache. A value of zero means that | |
the entry is permanent. A value of non-zero means | |
that the entry is dynamic and will be deleted | |
after Timeout. | |
@retval EFI_SUCCESS Successfully updated the neighbor relationship. | |
@retval EFI_NOT_STARTED The IpIo is not configured. | |
@retval EFI_INVALID_PARAMETER Any input parameter is invalid. | |
@retval EFI_OUT_OF_RESOURCES Failed to allocate some resources. | |
@retval EFI_NOT_FOUND This entry is not in the neighbor table. | |
**/ | |
EFI_STATUS | |
Tcp6RefreshNeighbor ( | |
IN TCP_CB *Tcb, | |
IN EFI_IP_ADDRESS *Neighbor, | |
IN UINT32 Timeout | |
) | |
{ | |
IP_IO *IpIo; | |
SOCKET *Sock; | |
TCP_PROTO_DATA *TcpProto; | |
if (NULL == Tcb) { | |
IpIo = NULL; | |
IpIoFindSender (&IpIo, IP_VERSION_6, Neighbor); | |
if (IpIo == NULL) { | |
DEBUG ((EFI_D_WARN, "Tcp6AddNeighbor: No appropriate IpIo.\n")); | |
return EFI_NOT_STARTED; | |
} | |
} else { | |
Sock = Tcb->Sk; | |
TcpProto = (TCP_PROTO_DATA *) Sock->ProtoReserved; | |
IpIo = TcpProto->TcpService->IpIo; | |
} | |
return IpIoRefreshNeighbor (IpIo, Neighbor, Timeout); | |
} | |