1 /** @file
2 Implementation of I/O interfaces between TCP and IpIoLib.
3
4 Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "TcpMain.h"
17
18 /**
19 Packet receive callback function provided to IP_IO, used to call
20 the proper function to handle the packet received by IP.
21
22 @param[in] Status Result of the receive request.
23 @param[in] IcmpErr Valid when Status is EFI_ICMP_ERROR.
24 @param[in] NetSession The IP session for the received packet.
25 @param[in] Pkt Packet received.
26 @param[in] Context The data provided by the user for the received packet when
27 the callback is registered in IP_IO_OPEN_DATA::RcvdContext.
28 This is an optional parameter that may be NULL.
29
30 **/
31 VOID
32 EFIAPI
TcpRxCallback(IN EFI_STATUS Status,IN UINT8 IcmpErr,IN EFI_NET_SESSION_DATA * NetSession,IN NET_BUF * Pkt,IN VOID * Context OPTIONAL)33 TcpRxCallback (
34 IN EFI_STATUS Status,
35 IN UINT8 IcmpErr,
36 IN EFI_NET_SESSION_DATA *NetSession,
37 IN NET_BUF *Pkt,
38 IN VOID *Context OPTIONAL
39 )
40 {
41 if (EFI_SUCCESS == Status) {
42 TcpInput (Pkt, &NetSession->Source, &NetSession->Dest, NetSession->IpVersion);
43 } else {
44 TcpIcmpInput (
45 Pkt,
46 IcmpErr,
47 &NetSession->Source,
48 &NetSession->Dest,
49 NetSession->IpVersion
50 );
51 }
52 }
53
54 /**
55 Send the segment to IP via IpIo function.
56
57 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
58 @param[in] Nbuf Pointer to the TCP segment to be sent.
59 @param[in] Src Source address of the TCP segment.
60 @param[in] Dest Destination address of the TCP segment.
61 @param[in] Version IP_VERSION_4 or IP_VERSION_6
62
63 @retval 0 The segment was sent out successfully.
64 @retval -1 The segment failed to send.
65
66 **/
67 INTN
TcpSendIpPacket(IN TCP_CB * Tcb,IN NET_BUF * Nbuf,IN EFI_IP_ADDRESS * Src,IN EFI_IP_ADDRESS * Dest,IN UINT8 Version)68 TcpSendIpPacket (
69 IN TCP_CB *Tcb,
70 IN NET_BUF *Nbuf,
71 IN EFI_IP_ADDRESS *Src,
72 IN EFI_IP_ADDRESS *Dest,
73 IN UINT8 Version
74 )
75 {
76 EFI_STATUS Status;
77 IP_IO *IpIo;
78 IP_IO_OVERRIDE Override;
79 SOCKET *Sock;
80 VOID *IpSender;
81 TCP_PROTO_DATA *TcpProto;
82
83 if (NULL == Tcb) {
84
85 IpIo = NULL;
86 IpSender = IpIoFindSender (&IpIo, Version, Src);
87
88 if (IpSender == NULL) {
89 DEBUG ((EFI_D_WARN, "TcpSendIpPacket: No appropriate IpSender.\n"));
90 return -1;
91 }
92
93 if (Version == IP_VERSION_6) {
94 //
95 // It's tricky here. EFI IPv6 Spec don't allow an instance overriding the
96 // destination address if the dest is already specified through the
97 // configuration data. Here we get the IpIo we need and use the default IP
98 // instance in this IpIo to send the packet. The dest address is configured
99 // to be the unspecified address for the default IP instance.
100 //
101 IpSender = NULL;
102 }
103 } else {
104
105 Sock = Tcb->Sk;
106 TcpProto = (TCP_PROTO_DATA *) Sock->ProtoReserved;
107 IpIo = TcpProto->TcpService->IpIo;
108 IpSender = Tcb->IpInfo;
109
110 if (Version == IP_VERSION_6) {
111 //
112 // It's IPv6 and this TCP segment belongs to a solid TCB, in such case
113 // the destination address can't be overridden, so reset the Dest to NULL.
114 //
115 if (!Tcb->RemoteIpZero) {
116 Dest = NULL;
117 }
118 }
119 }
120
121 ASSERT (Version == IpIo->IpVersion);
122
123 if (Version == IP_VERSION_4) {
124 Override.Ip4OverrideData.TypeOfService = 0;
125 Override.Ip4OverrideData.TimeToLive = 255;
126 Override.Ip4OverrideData.DoNotFragment = FALSE;
127 Override.Ip4OverrideData.Protocol = EFI_IP_PROTO_TCP;
128 ZeroMem (&Override.Ip4OverrideData.GatewayAddress, sizeof (EFI_IPv4_ADDRESS));
129 CopyMem (&Override.Ip4OverrideData.SourceAddress, Src, sizeof (EFI_IPv4_ADDRESS));
130 } else {
131 Override.Ip6OverrideData.Protocol = EFI_IP_PROTO_TCP;
132 Override.Ip6OverrideData.HopLimit = 255;
133 Override.Ip6OverrideData.FlowLabel = 0;
134 }
135
136 Status = IpIoSend (IpIo, Nbuf, IpSender, NULL, NULL, Dest, &Override);
137
138 if (EFI_ERROR (Status)) {
139 DEBUG ((EFI_D_ERROR, "TcpSendIpPacket: return %r error\n", Status));
140 return -1;
141 }
142
143 return 0;
144 }
145
146 /**
147 Refresh the remote peer's Neighbor Cache State if already exists.
148
149 @param[in] Tcb Pointer to the TCP_CB of this TCP instance.
150 @param[in] Neighbor Source address of the TCP segment.
151 @param[in] Timeout Time in 100-ns units that this entry will remain
152 in the neighbor cache. A value of zero means that
153 the entry is permanent. A value of non-zero means
154 that the entry is dynamic and will be deleted
155 after Timeout.
156
157 @retval EFI_SUCCESS Successfully updated the neighbor relationship.
158 @retval EFI_NOT_STARTED The IpIo is not configured.
159 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
160 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resources.
161 @retval EFI_NOT_FOUND This entry is not in the neighbor table.
162
163 **/
164 EFI_STATUS
Tcp6RefreshNeighbor(IN TCP_CB * Tcb,IN EFI_IP_ADDRESS * Neighbor,IN UINT32 Timeout)165 Tcp6RefreshNeighbor (
166 IN TCP_CB *Tcb,
167 IN EFI_IP_ADDRESS *Neighbor,
168 IN UINT32 Timeout
169 )
170 {
171 IP_IO *IpIo;
172 SOCKET *Sock;
173 TCP_PROTO_DATA *TcpProto;
174
175 if (NULL == Tcb) {
176 IpIo = NULL;
177 IpIoFindSender (&IpIo, IP_VERSION_6, Neighbor);
178
179 if (IpIo == NULL) {
180 DEBUG ((EFI_D_WARN, "Tcp6AddNeighbor: No appropriate IpIo.\n"));
181 return EFI_NOT_STARTED;
182 }
183
184 } else {
185 Sock = Tcb->Sk;
186 TcpProto = (TCP_PROTO_DATA *) Sock->ProtoReserved;
187 IpIo = TcpProto->TcpService->IpIo;
188 }
189
190 return IpIoRefreshNeighbor (IpIo, Neighbor, Timeout);
191 }
192
193