1 /** @file
2 The wrap of TCP/IP Socket interface.
3
4 Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "IScsiImpl.h"
16
17 /**
18 The common notify function associated with various Tcp4Io events.
19
20 @param[in] Event The event signaled.
21 @param[in] Context The context.
22 **/
23 VOID
24 EFIAPI
Tcp4IoCommonNotify(IN EFI_EVENT Event,IN VOID * Context)25 Tcp4IoCommonNotify (
26 IN EFI_EVENT Event,
27 IN VOID *Context
28 )
29 {
30 *((BOOLEAN *) Context) = TRUE;
31 }
32
33 /**
34 Create a TCP socket with the specified configuration data.
35
36 @param[in] Image The handle of the driver image.
37 @param[in] Controller The handle of the controller.
38 @param[in] ConfigData The Tcp4 configuration data.
39 @param[in] Tcp4Io The Tcp4Io.
40
41 @retval EFI_SUCCESS The TCP socket is created and configured.
42 @retval Others Failed to create the TCP socket or configure it.
43 **/
44 EFI_STATUS
Tcp4IoCreateSocket(IN EFI_HANDLE Image,IN EFI_HANDLE Controller,IN TCP4_IO_CONFIG_DATA * ConfigData,IN TCP4_IO * Tcp4Io)45 Tcp4IoCreateSocket (
46 IN EFI_HANDLE Image,
47 IN EFI_HANDLE Controller,
48 IN TCP4_IO_CONFIG_DATA *ConfigData,
49 IN TCP4_IO *Tcp4Io
50 )
51 {
52 EFI_STATUS Status;
53 EFI_TCP4_PROTOCOL *Tcp4;
54 EFI_TCP4_CONFIG_DATA Tcp4ConfigData;
55 EFI_TCP4_OPTION ControlOption;
56 EFI_TCP4_ACCESS_POINT *AccessPoint;
57
58 Tcp4Io->Handle = NULL;
59 Tcp4Io->ConnToken.CompletionToken.Event = NULL;
60 Tcp4Io->TxToken.CompletionToken.Event = NULL;
61 Tcp4Io->RxToken.CompletionToken.Event = NULL;
62 Tcp4Io->CloseToken.CompletionToken.Event = NULL;
63 Tcp4 = NULL;
64
65 //
66 // Create the TCP4 child instance and get the TCP4 protocol.
67 //
68 Status = NetLibCreateServiceChild (
69 Controller,
70 Image,
71 &gEfiTcp4ServiceBindingProtocolGuid,
72 &Tcp4Io->Handle
73 );
74 if (EFI_ERROR (Status)) {
75 return Status;
76 }
77
78 Status = gBS->OpenProtocol (
79 Tcp4Io->Handle,
80 &gEfiTcp4ProtocolGuid,
81 (VOID **)&Tcp4Io->Tcp4,
82 Image,
83 Controller,
84 EFI_OPEN_PROTOCOL_BY_DRIVER
85 );
86 if (EFI_ERROR (Status)) {
87 goto ON_ERROR;
88 }
89
90 Tcp4Io->Image = Image;
91 Tcp4Io->Controller = Controller;
92 Tcp4 = Tcp4Io->Tcp4;
93
94 //
95 // Set the configuration parameters.
96 //
97 ControlOption.ReceiveBufferSize = 0x200000;
98 ControlOption.SendBufferSize = 0x200000;
99 ControlOption.MaxSynBackLog = 0;
100 ControlOption.ConnectionTimeout = 0;
101 ControlOption.DataRetries = 6;
102 ControlOption.FinTimeout = 0;
103 ControlOption.TimeWaitTimeout = 0;
104 ControlOption.KeepAliveProbes = 4;
105 ControlOption.KeepAliveTime = 0;
106 ControlOption.KeepAliveInterval = 0;
107 ControlOption.EnableNagle = FALSE;
108 ControlOption.EnableTimeStamp = FALSE;
109 ControlOption.EnableWindowScaling = TRUE;
110 ControlOption.EnableSelectiveAck = FALSE;
111 ControlOption.EnablePathMtuDiscovery = FALSE;
112
113 Tcp4ConfigData.TypeOfService = 8;
114 Tcp4ConfigData.TimeToLive = 255;
115 Tcp4ConfigData.ControlOption = &ControlOption;
116
117 AccessPoint = &Tcp4ConfigData.AccessPoint;
118
119 AccessPoint->UseDefaultAddress = FALSE;
120 AccessPoint->StationPort = 0;
121 AccessPoint->RemotePort = ConfigData->RemotePort;
122 AccessPoint->ActiveFlag = TRUE;
123
124 CopyMem (&AccessPoint->StationAddress, &ConfigData->LocalIp, sizeof (EFI_IPv4_ADDRESS));
125 CopyMem (&AccessPoint->SubnetMask, &ConfigData->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
126 CopyMem (&AccessPoint->RemoteAddress, &ConfigData->RemoteIp, sizeof (EFI_IPv4_ADDRESS));
127
128 //
129 // Configure the TCP4 protocol.
130 //
131 Status = Tcp4->Configure (Tcp4, &Tcp4ConfigData);
132 if (EFI_ERROR (Status)) {
133 goto ON_ERROR;
134 }
135
136 if (!EFI_IP4_EQUAL (&ConfigData->Gateway, &mZeroIp4Addr)) {
137 //
138 // the gateway is not zero, add the default route by hand
139 //
140 Status = Tcp4->Routes (Tcp4, FALSE, &mZeroIp4Addr, &mZeroIp4Addr, &ConfigData->Gateway);
141 if (EFI_ERROR (Status)) {
142 goto ON_ERROR;
143 }
144 }
145 //
146 // Create events for variuos asynchronous operations.
147 //
148 Status = gBS->CreateEvent (
149 EVT_NOTIFY_SIGNAL,
150 TPL_NOTIFY,
151 Tcp4IoCommonNotify,
152 &Tcp4Io->IsConnDone,
153 &Tcp4Io->ConnToken.CompletionToken.Event
154 );
155 if (EFI_ERROR (Status)) {
156 goto ON_ERROR;
157 }
158
159 Status = gBS->CreateEvent (
160 EVT_NOTIFY_SIGNAL,
161 TPL_NOTIFY,
162 Tcp4IoCommonNotify,
163 &Tcp4Io->IsTxDone,
164 &Tcp4Io->TxToken.CompletionToken.Event
165 );
166 if (EFI_ERROR (Status)) {
167 goto ON_ERROR;
168 }
169
170 Status = gBS->CreateEvent (
171 EVT_NOTIFY_SIGNAL,
172 TPL_NOTIFY,
173 Tcp4IoCommonNotify,
174 &Tcp4Io->IsRxDone,
175 &Tcp4Io->RxToken.CompletionToken.Event
176 );
177 if (EFI_ERROR (Status)) {
178 goto ON_ERROR;
179 }
180
181 Status = gBS->CreateEvent (
182 EVT_NOTIFY_SIGNAL,
183 TPL_NOTIFY,
184 Tcp4IoCommonNotify,
185 &Tcp4Io->IsCloseDone,
186 &Tcp4Io->CloseToken.CompletionToken.Event
187 );
188 if (EFI_ERROR (Status)) {
189 goto ON_ERROR;
190 }
191
192 Tcp4Io->IsTxDone = FALSE;
193 Tcp4Io->IsRxDone = FALSE;
194
195 return EFI_SUCCESS;
196
197 ON_ERROR:
198
199 if (Tcp4Io->RxToken.CompletionToken.Event != NULL) {
200 gBS->CloseEvent (Tcp4Io->RxToken.CompletionToken.Event);
201 }
202
203 if (Tcp4Io->TxToken.CompletionToken.Event != NULL) {
204 gBS->CloseEvent (Tcp4Io->TxToken.CompletionToken.Event);
205 }
206
207 if (Tcp4Io->ConnToken.CompletionToken.Event != NULL) {
208 gBS->CloseEvent (Tcp4Io->ConnToken.CompletionToken.Event);
209 }
210
211 if (Tcp4 != NULL) {
212 Tcp4->Configure (Tcp4, NULL);
213
214 gBS->CloseProtocol (
215 Tcp4Io->Handle,
216 &gEfiTcp4ProtocolGuid,
217 Image,
218 Controller
219 );
220 }
221
222 NetLibDestroyServiceChild (
223 Controller,
224 Image,
225 &gEfiTcp4ServiceBindingProtocolGuid,
226 Tcp4Io->Handle
227 );
228
229 return Status;
230 }
231
232 /**
233 Destroy the socket.
234
235 @param[in] Tcp4Io The Tcp4Io which wraps the socket to be destroyeds.
236 **/
237 VOID
Tcp4IoDestroySocket(IN TCP4_IO * Tcp4Io)238 Tcp4IoDestroySocket (
239 IN TCP4_IO *Tcp4Io
240 )
241 {
242 EFI_TCP4_PROTOCOL *Tcp4;
243
244 Tcp4 = Tcp4Io->Tcp4;
245
246 Tcp4->Configure (Tcp4, NULL);
247
248 gBS->CloseEvent (Tcp4Io->TxToken.CompletionToken.Event);
249 gBS->CloseEvent (Tcp4Io->RxToken.CompletionToken.Event);
250 gBS->CloseEvent (Tcp4Io->ConnToken.CompletionToken.Event);
251
252 gBS->CloseProtocol (
253 Tcp4Io->Handle,
254 &gEfiTcp4ProtocolGuid,
255 Tcp4Io->Image,
256 Tcp4Io->Controller
257 );
258
259 NetLibDestroyServiceChild (
260 Tcp4Io->Controller,
261 Tcp4Io->Image,
262 &gEfiTcp4ServiceBindingProtocolGuid,
263 Tcp4Io->Handle
264 );
265 }
266
267 /**
268 Connect to the other endpoint of the TCP socket.
269
270 @param[in, out] Tcp4Io The Tcp4Io wrapping the TCP socket.
271 @param[in] Timeout The time to wait for connection done.
272
273 @retval EFI_SUCCESS Connect to the other endpoint of the TCP socket successfully.
274 @retval EFI_TIMEOUT Failed to connect to the other endpoint of the TCP socket in the specified time period.
275 @retval Others Other errors as indicated.
276 **/
277 EFI_STATUS
Tcp4IoConnect(IN OUT TCP4_IO * Tcp4Io,IN EFI_EVENT Timeout)278 Tcp4IoConnect (
279 IN OUT TCP4_IO *Tcp4Io,
280 IN EFI_EVENT Timeout
281 )
282 {
283 EFI_TCP4_PROTOCOL *Tcp4;
284 EFI_STATUS Status;
285
286 Tcp4Io->IsConnDone = FALSE;
287 Tcp4 = Tcp4Io->Tcp4;
288 Status = Tcp4->Connect (Tcp4, &Tcp4Io->ConnToken);
289 if (EFI_ERROR (Status)) {
290 return Status;
291 }
292
293 while (!Tcp4Io->IsConnDone && EFI_ERROR (gBS->CheckEvent (Timeout))) {
294 Tcp4->Poll (Tcp4);
295 }
296
297 if (!Tcp4Io->IsConnDone) {
298 Status = EFI_TIMEOUT;
299 } else {
300 Status = Tcp4Io->ConnToken.CompletionToken.Status;
301 }
302
303 return Status;
304 }
305
306 /**
307 Reset the socket.
308
309 @param[in, out] Tcp4Io The Tcp4Io wrapping the TCP socket.
310 **/
311 VOID
Tcp4IoReset(IN OUT TCP4_IO * Tcp4Io)312 Tcp4IoReset (
313 IN OUT TCP4_IO *Tcp4Io
314 )
315 {
316 EFI_STATUS Status;
317 EFI_TCP4_PROTOCOL *Tcp4;
318
319 Tcp4Io->CloseToken.AbortOnClose = TRUE;
320 Tcp4Io->IsCloseDone = FALSE;
321
322 Tcp4 = Tcp4Io->Tcp4;
323 Status = Tcp4->Close (Tcp4, &Tcp4Io->CloseToken);
324 if (EFI_ERROR (Status)) {
325 return ;
326 }
327
328 while (!Tcp4Io->IsCloseDone) {
329 Tcp4->Poll (Tcp4);
330 }
331 }
332
333 /**
334 Transmit the Packet to the other endpoint of the socket.
335
336 @param[in] Tcp4Io The Tcp4Io wrapping the TCP socket.
337 @param[in] Packet The packet to transmit.
338
339 @retval EFI_SUCCESS The packet is trasmitted.
340 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
341 @retval Others Other errors as indicated.
342 **/
343 EFI_STATUS
Tcp4IoTransmit(IN TCP4_IO * Tcp4Io,IN NET_BUF * Packet)344 Tcp4IoTransmit (
345 IN TCP4_IO *Tcp4Io,
346 IN NET_BUF *Packet
347 )
348 {
349 EFI_TCP4_TRANSMIT_DATA *TxData;
350 EFI_TCP4_PROTOCOL *Tcp4;
351 EFI_STATUS Status;
352
353 TxData = AllocatePool (sizeof (EFI_TCP4_TRANSMIT_DATA) + (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA));
354 if (TxData == NULL) {
355 return EFI_OUT_OF_RESOURCES;
356 }
357
358 TxData->Push = TRUE;
359 TxData->Urgent = FALSE;
360 TxData->DataLength = Packet->TotalSize;
361
362 //
363 // Build the fragment table.
364 //
365 TxData->FragmentCount = Packet->BlockOpNum;
366 NetbufBuildExt (Packet, (NET_FRAGMENT *) &TxData->FragmentTable[0], &TxData->FragmentCount);
367
368 Tcp4Io->TxToken.Packet.TxData = TxData;
369
370 //
371 // Trasnmit the packet.
372 //
373 Tcp4 = Tcp4Io->Tcp4;
374 Status = Tcp4->Transmit (Tcp4, &Tcp4Io->TxToken);
375 if (EFI_ERROR (Status)) {
376 goto ON_EXIT;
377 }
378
379 while (!Tcp4Io->IsTxDone) {
380 Tcp4->Poll (Tcp4);
381 }
382
383 Tcp4Io->IsTxDone = FALSE;
384
385 Status = Tcp4Io->TxToken.CompletionToken.Status;
386
387 ON_EXIT:
388
389 FreePool (TxData);
390
391 return Status;
392 }
393
394 /**
395 Receive data from the socket.
396
397 @param[in] Tcp4Io The Tcp4Io which wraps the socket to be destroyed.
398 @param[in] Packet The buffer to hold the data copy from the soket rx buffer.
399 @param[in] AsyncMode Is this receive asyncronous or not.
400 @param[in] Timeout The time to wait for receiving the amount of data the Packet
401 can hold.
402
403 @retval EFI_SUCCESS The required amount of data is received from the socket.
404 @retval EFI_OUT_OF_RESOURCES Failed to allocate momery.
405 @retval EFI_TIMEOUT Failed to receive the required amount of data in the
406 specified time period.
407 @retval Others Other errors as indicated.
408 **/
409 EFI_STATUS
Tcp4IoReceive(IN TCP4_IO * Tcp4Io,IN NET_BUF * Packet,IN BOOLEAN AsyncMode,IN EFI_EVENT Timeout)410 Tcp4IoReceive (
411 IN TCP4_IO *Tcp4Io,
412 IN NET_BUF *Packet,
413 IN BOOLEAN AsyncMode,
414 IN EFI_EVENT Timeout
415 )
416 {
417 EFI_TCP4_PROTOCOL *Tcp4;
418 EFI_TCP4_RECEIVE_DATA RxData;
419 EFI_STATUS Status;
420 NET_FRAGMENT *Fragment;
421 UINT32 FragmentCount;
422 UINT32 CurrentFragment;
423
424 FragmentCount = Packet->BlockOpNum;
425 Fragment = AllocatePool (FragmentCount * sizeof (NET_FRAGMENT));
426 if (Fragment == NULL) {
427 return EFI_OUT_OF_RESOURCES;
428 }
429 //
430 // Build the fragment table.
431 //
432 NetbufBuildExt (Packet, Fragment, &FragmentCount);
433
434 RxData.FragmentCount = 1;
435 Tcp4Io->RxToken.Packet.RxData = &RxData;
436 CurrentFragment = 0;
437 Tcp4 = Tcp4Io->Tcp4;
438 Status = EFI_SUCCESS;
439
440 while (CurrentFragment < FragmentCount) {
441 RxData.DataLength = Fragment[CurrentFragment].Len;
442 RxData.FragmentTable[0].FragmentLength = Fragment[CurrentFragment].Len;
443 RxData.FragmentTable[0].FragmentBuffer = Fragment[CurrentFragment].Bulk;
444
445 Status = Tcp4->Receive (Tcp4, &Tcp4Io->RxToken);
446 if (EFI_ERROR (Status)) {
447 goto ON_EXIT;
448 }
449
450 while (!Tcp4Io->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
451 //
452 // Poll until some data is received or something error happens.
453 //
454 Tcp4->Poll (Tcp4);
455 }
456
457 if (!Tcp4Io->IsRxDone) {
458 //
459 // Timeout occurs, cancel the receive request.
460 //
461 Tcp4->Cancel (Tcp4, &Tcp4Io->RxToken.CompletionToken);
462
463 Status = EFI_TIMEOUT;
464 goto ON_EXIT;
465 } else {
466 Tcp4Io->IsRxDone = FALSE;
467 }
468
469 if (EFI_ERROR (Tcp4Io->RxToken.CompletionToken.Status)) {
470 Status = Tcp4Io->RxToken.CompletionToken.Status;
471 goto ON_EXIT;
472 }
473
474 Fragment[CurrentFragment].Len -= RxData.FragmentTable[0].FragmentLength;
475 if (Fragment[CurrentFragment].Len == 0) {
476 CurrentFragment++;
477 } else {
478 Fragment[CurrentFragment].Bulk += RxData.FragmentTable[0].FragmentLength;
479 }
480 }
481
482 ON_EXIT:
483 Tcp4Io->RxToken.Packet.RxData = NULL;
484 FreePool (Fragment);
485
486 return Status;
487 }
488