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