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