]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Driver.c
c51962ba9ebaf172f671403139f10a0d05131ee2
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Tcp4Dxe / Tcp4Driver.c
1 /** @file
2
3 Copyright (c) 2005 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 Tcp4Driver.c
15
16 Abstract:
17
18
19 **/
20
21 #include "Tcp4Main.h"
22
23
24 UINT16 mTcp4RandomPort;
25 extern EFI_COMPONENT_NAME_PROTOCOL gTcp4ComponentName;
26 extern EFI_COMPONENT_NAME2_PROTOCOL gTcp4ComponentName2;
27
28 TCP4_HEARTBEAT_TIMER mTcp4Timer = {
29 NULL,
30 0
31 };
32
33 EFI_TCP4_PROTOCOL mTcp4ProtocolTemplate = {
34 Tcp4GetModeData,
35 Tcp4Configure,
36 Tcp4Routes,
37 Tcp4Connect,
38 Tcp4Accept,
39 Tcp4Transmit,
40 Tcp4Receive,
41 Tcp4Close,
42 Tcp4Cancel,
43 Tcp4Poll
44 };
45
46 SOCK_INIT_DATA mTcp4DefaultSockData = {
47 SOCK_STREAM,
48 (SOCK_STATE) 0,
49 NULL,
50 TCP_BACKLOG,
51 TCP_SND_BUF_SIZE,
52 TCP_RCV_BUF_SIZE,
53 &mTcp4ProtocolTemplate,
54 Tcp4CreateSocketCallback,
55 Tcp4DestroySocketCallback,
56 NULL,
57 NULL,
58 0,
59 Tcp4Dispatcher,
60 NULL,
61 };
62
63 EFI_DRIVER_BINDING_PROTOCOL mTcp4DriverBinding = {
64 Tcp4DriverBindingSupported,
65 Tcp4DriverBindingStart,
66 Tcp4DriverBindingStop,
67 0xa,
68 NULL,
69 NULL
70 };
71
72 EFI_SERVICE_BINDING_PROTOCOL mTcp4ServiceBinding = {
73 Tcp4ServiceBindingCreateChild,
74 Tcp4ServiceBindingDestroyChild
75 };
76
77
78 /**
79 Create and start the heartbeat timer for TCP driver.
80
81 @retval EFI_SUCCESS The timer is successfully created and started.
82 @retval other The timer is not created.
83
84 **/
85 EFI_STATUS
86 Tcp4CreateTimer (
87 VOID
88 )
89 {
90 EFI_STATUS Status;
91
92 Status = EFI_SUCCESS;
93
94 if (mTcp4Timer.RefCnt == 0) {
95
96 Status = gBS->CreateEvent (
97 EVT_TIMER | EVT_NOTIFY_SIGNAL,
98 TPL_NOTIFY,
99 TcpTicking,
100 NULL,
101 &mTcp4Timer.TimerEvent
102 );
103 if (!EFI_ERROR (Status)) {
104
105 Status = gBS->SetTimer (
106 mTcp4Timer.TimerEvent,
107 TimerPeriodic,
108 (UINT64) (TICKS_PER_SECOND / TCP_TICK_HZ)
109 );
110 }
111 }
112
113 if (!EFI_ERROR (Status)) {
114
115 mTcp4Timer.RefCnt++;
116 }
117
118 return Status;
119 }
120
121
122 /**
123 Stop and destroy the heartbeat timer for TCP driver.
124
125 **/
126 VOID
127 Tcp4DestroyTimer (
128 VOID
129 )
130 {
131 ASSERT (mTcp4Timer.RefCnt > 0);
132
133 mTcp4Timer.RefCnt--;
134
135 if (mTcp4Timer.RefCnt > 0) {
136 return;
137 }
138
139 gBS->SetTimer (mTcp4Timer.TimerEvent, TimerCancel, 0);
140 gBS->CloseEvent (mTcp4Timer.TimerEvent);
141 mTcp4Timer.TimerEvent = NULL;
142 }
143
144 /**
145 The entry point for Tcp4 driver, used to install Tcp4 driver on the ImageHandle.
146
147 @param ImageHandle The firmware allocated handle for this
148 driver image.
149 @param SystemTable Pointer to the EFI system table.
150
151 @retval EFI_SUCCESS Driver loaded.
152 @retval other Driver not loaded.
153
154 **/
155 EFI_STATUS
156 EFIAPI
157 Tcp4DriverEntryPoint (
158 IN EFI_HANDLE ImageHandle,
159 IN EFI_SYSTEM_TABLE *SystemTable
160 )
161 {
162 EFI_STATUS Status;
163 UINT32 Seed;
164
165 //
166 // Install the TCP4 Driver Binding Protocol
167 //
168 Status = EfiLibInstallDriverBindingComponentName2 (
169 ImageHandle,
170 SystemTable,
171 &mTcp4DriverBinding,
172 ImageHandle,
173 &gTcp4ComponentName,
174 &gTcp4ComponentName2
175 );
176 ASSERT_EFI_ERROR (Status);
177 //
178 // Initialize ISS and random port.
179 //
180 Seed = NetRandomInitSeed ();
181 mTcpGlobalIss = NET_RANDOM (Seed) % mTcpGlobalIss;
182 mTcp4RandomPort = (UINT16) (TCP4_PORT_KNOWN +
183 (UINT16) (NET_RANDOM(Seed) % TCP4_PORT_KNOWN));
184
185 return Status;
186 }
187
188
189 /**
190 Test to see if this driver supports ControllerHandle.
191
192 @param This Protocol instance pointer.
193 @param ControllerHandle Handle of device to test.
194 @param RemainingDevicePath Optional parameter use to pick a specific child
195 device to start.
196
197 @retval EFI_SUCCESS This driver supports this device.
198 @retval EFI_ALREADY_STARTED This driver is already running on this device.
199 @retval other This driver does not support this device.
200
201 **/
202 EFI_STATUS
203 EFIAPI
204 Tcp4DriverBindingSupported (
205 IN EFI_DRIVER_BINDING_PROTOCOL *This,
206 IN EFI_HANDLE ControllerHandle,
207 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
208 )
209 {
210 EFI_STATUS Status;
211
212 //
213 // Test for the Tcp4ServiceBinding Protocol
214 //
215 Status = gBS->OpenProtocol (
216 ControllerHandle,
217 &gEfiTcp4ServiceBindingProtocolGuid,
218 NULL,
219 This->DriverBindingHandle,
220 ControllerHandle,
221 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
222 );
223 if (!EFI_ERROR (Status)) {
224 return EFI_ALREADY_STARTED;
225 }
226
227 //
228 // Test for the Ip4 Protocol
229 //
230 Status = gBS->OpenProtocol (
231 ControllerHandle,
232 &gEfiIp4ServiceBindingProtocolGuid,
233 NULL,
234 This->DriverBindingHandle,
235 ControllerHandle,
236 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
237 );
238
239 return Status;
240 }
241
242
243 /**
244 Start this driver on ControllerHandle.
245
246 @param This Protocol instance pointer.
247 @param ControllerHandle Handle of device to bind driver to.
248 @param RemainingDevicePath Optional parameter use to pick a specific child
249 device to start.
250
251 @retval EFI_SUCCESS The driver is added to ControllerHandle.
252 @retval EFI_OUT_OF_RESOURCES There are not enough resources to start the
253 driver.
254 @retval other The driver cannot be added to ControllerHandle.
255
256 **/
257 EFI_STATUS
258 EFIAPI
259 Tcp4DriverBindingStart (
260 IN EFI_DRIVER_BINDING_PROTOCOL *This,
261 IN EFI_HANDLE ControllerHandle,
262 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
263 )
264 {
265 EFI_STATUS Status;
266 TCP4_SERVICE_DATA *TcpServiceData;
267 IP_IO_OPEN_DATA OpenData;
268
269 TcpServiceData = AllocateZeroPool (sizeof (TCP4_SERVICE_DATA));
270
271 if (NULL == TcpServiceData) {
272 DEBUG ((EFI_D_ERROR, "Tcp4DriverBindingStart: Have no enough"
273 " resource to create a Tcp Servcie Data!\n"));
274
275 return EFI_OUT_OF_RESOURCES;
276 }
277
278 //
279 // Create a new IP IO to Consume it
280 //
281 TcpServiceData->IpIo = IpIoCreate (This->DriverBindingHandle, ControllerHandle);
282 if (NULL == TcpServiceData->IpIo) {
283
284 DEBUG ((EFI_D_ERROR, "Tcp4DriverBindingStart: Have no enough"
285 " resource to create an Ip Io!\n"));
286
287 Status = EFI_OUT_OF_RESOURCES;
288 goto ON_ERROR;
289 }
290
291 //
292 // Configure and start IpIo.
293 //
294 ZeroMem (&OpenData, sizeof (IP_IO_OPEN_DATA));
295
296 CopyMem (&OpenData.IpConfigData, &mIpIoDefaultIpConfigData, sizeof (OpenData.IpConfigData));
297 OpenData.IpConfigData.DefaultProtocol = EFI_IP_PROTO_TCP;
298
299 OpenData.PktRcvdNotify = Tcp4RxCallback;
300 Status = IpIoOpen (TcpServiceData->IpIo, &OpenData);
301
302 if (EFI_ERROR (Status)) {
303 goto ON_ERROR;
304 }
305
306 //
307 // Create the timer event used by TCP driver
308 //
309 Status = Tcp4CreateTimer ();
310 if (EFI_ERROR (Status)) {
311
312 DEBUG ((EFI_D_ERROR, "Tcp4DriverBindingStart: Create TcpTimer"
313 " Event failed with %r\n", Status));
314
315 goto ON_ERROR;
316 }
317
318 //
319 // Install the Tcp4ServiceBinding Protocol on the
320 // controller handle
321 //
322 TcpServiceData->Tcp4ServiceBinding = mTcp4ServiceBinding;
323
324 Status = gBS->InstallMultipleProtocolInterfaces (
325 &ControllerHandle,
326 &gEfiTcp4ServiceBindingProtocolGuid,
327 &TcpServiceData->Tcp4ServiceBinding,
328 NULL
329 );
330 if (EFI_ERROR (Status)) {
331
332 DEBUG ((EFI_D_ERROR, "Tcp4DriverBindingStart: Install Tcp4 Service Binding"
333 " Protocol failed for %r\n", Status));
334
335 Tcp4DestroyTimer ();
336 goto ON_ERROR;
337 }
338
339 //
340 // Initialize member in TcpServiceData
341 //
342 TcpServiceData->ControllerHandle = ControllerHandle;
343 TcpServiceData->Signature = TCP4_DRIVER_SIGNATURE;
344 TcpServiceData->DriverBindingHandle = This->DriverBindingHandle;
345
346 InitializeListHead (&TcpServiceData->SocketList);
347
348 TcpSetVariableData (TcpServiceData);
349
350 return EFI_SUCCESS;
351
352 ON_ERROR:
353
354 if (TcpServiceData->IpIo != NULL) {
355 IpIoDestroy (TcpServiceData->IpIo);
356 }
357
358 gBS->FreePool (TcpServiceData);
359
360 return Status;
361 }
362
363
364 /**
365 Stop this driver on ControllerHandle.
366
367 @param This Protocol instance pointer.
368 @param ControllerHandle Handle of device to stop driver on.
369 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number
370 of children is zero stop the entire bus driver.
371 @param ChildHandleBuffer List of Child Handles to Stop.
372
373 @retval EFI_SUCCESS This driver is removed from ControllerHandle.
374 @retval other This driver is not removed from ControllerHandle.
375
376 **/
377 EFI_STATUS
378 EFIAPI
379 Tcp4DriverBindingStop (
380 IN EFI_DRIVER_BINDING_PROTOCOL *This,
381 IN EFI_HANDLE ControllerHandle,
382 IN UINTN NumberOfChildren,
383 IN EFI_HANDLE *ChildHandleBuffer
384 )
385 {
386 EFI_STATUS Status;
387 EFI_HANDLE NicHandle;
388 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
389 TCP4_SERVICE_DATA *TcpServiceData;
390 SOCKET *Sock;
391
392 // Find the NicHandle where Tcp4 ServiceBinding Protocol is installed.
393 //
394 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiIp4ProtocolGuid);
395 if (NicHandle == NULL) {
396 return EFI_DEVICE_ERROR;
397 }
398
399 //
400 // Retrieve the TCP driver Data Structure
401 //
402 Status = gBS->OpenProtocol (
403 NicHandle,
404 &gEfiTcp4ServiceBindingProtocolGuid,
405 (VOID **) &ServiceBinding,
406 This->DriverBindingHandle,
407 ControllerHandle,
408 EFI_OPEN_PROTOCOL_GET_PROTOCOL
409 );
410 if (EFI_ERROR (Status)) {
411
412 DEBUG ((EFI_D_ERROR, "Tcp4DriverBindingStop: Locate Tcp4 Service "
413 " Binding Protocol failed with %r\n", Status));
414
415 return EFI_DEVICE_ERROR;
416 }
417
418 TcpServiceData = TCP4_FROM_THIS (ServiceBinding);
419
420 if (NumberOfChildren == 0) {
421 //
422 // Uninstall TCP servicebinding protocol
423 //
424 gBS->UninstallMultipleProtocolInterfaces (
425 NicHandle,
426 &gEfiTcp4ServiceBindingProtocolGuid,
427 ServiceBinding,
428 NULL
429 );
430
431 //
432 // Destroy the IpIO consumed by TCP driver
433 //
434 IpIoDestroy (TcpServiceData->IpIo);
435
436 //
437 // Destroy the heartbeat timer.
438 //
439 Tcp4DestroyTimer ();
440
441 //
442 // Clear the variable.
443 //
444 TcpClearVariableData (TcpServiceData);
445
446 //
447 // Release the TCP service data
448 //
449 gBS->FreePool (TcpServiceData);
450 } else {
451
452 while (!IsListEmpty (&TcpServiceData->SocketList)) {
453 Sock = NET_LIST_HEAD (&TcpServiceData->SocketList, SOCKET, Link);
454
455 ServiceBinding->DestroyChild (ServiceBinding, Sock->SockHandle);
456 }
457 }
458
459 return Status;
460 }
461
462 /**
463 Open Ip4 and device path protocols for a created socket, and insert it in
464 socket list.
465
466 @param This Pointer to the socket just created
467 @param Context Context of the socket
468
469 @retval EFI_SUCCESS This protocol is installed successfully.
470 @retval other Some error occured.
471
472 **/
473 EFI_STATUS
474 Tcp4CreateSocketCallback (
475 IN SOCKET *This,
476 IN VOID *Context
477 )
478 {
479 EFI_STATUS Status;
480 TCP4_SERVICE_DATA *TcpServiceData;
481 EFI_IP4_PROTOCOL *Ip4;
482
483 TcpServiceData = ((TCP4_PROTO_DATA *) This->ProtoReserved)->TcpService;
484
485 //
486 // Open the default Ip4 protocol of IP_IO BY_DRIVER.
487 //
488 Status = gBS->OpenProtocol (
489 TcpServiceData->IpIo->ChildHandle,
490 &gEfiIp4ProtocolGuid,
491 (VOID **) &Ip4,
492 TcpServiceData->DriverBindingHandle,
493 This->SockHandle,
494 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
495 );
496 if (EFI_ERROR (Status)) {
497 return Status;
498 }
499
500 //
501 // Open the device path on the handle where service binding resides on.
502 //
503 Status = gBS->OpenProtocol (
504 TcpServiceData->ControllerHandle,
505 &gEfiDevicePathProtocolGuid,
506 (VOID **) &This->ParentDevicePath,
507 TcpServiceData->DriverBindingHandle,
508 This->SockHandle,
509 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
510 );
511 if (EFI_ERROR (Status)) {
512 gBS->CloseProtocol (
513 TcpServiceData->IpIo->ChildHandle,
514 &gEfiIp4ProtocolGuid,
515 TcpServiceData->DriverBindingHandle,
516 This->SockHandle
517 );
518 } else {
519 //
520 // Insert this socket into the SocketList.
521 //
522 InsertTailList (&TcpServiceData->SocketList, &This->Link);
523 }
524
525 return Status;
526 }
527
528 /**
529 Close Ip4 and device path protocols for a socket, and remove it from socket list.
530
531 @param This Pointer to the socket to be removed
532 @param Context Context of the socket
533
534 **/
535 VOID
536 Tcp4DestroySocketCallback (
537 IN SOCKET *This,
538 IN VOID *Context
539 )
540 {
541 TCP4_SERVICE_DATA *TcpServiceData;
542
543 TcpServiceData = ((TCP4_PROTO_DATA *) This->ProtoReserved)->TcpService;
544
545 //
546 // Remove this node from the list.
547 //
548 RemoveEntryList (&This->Link);
549
550 //
551 // Close the device path protocol
552 //
553 gBS->CloseProtocol (
554 TcpServiceData->ControllerHandle,
555 &gEfiDevicePathProtocolGuid,
556 TcpServiceData->DriverBindingHandle,
557 This->SockHandle
558 );
559
560 //
561 // Close the Ip4 protocol.
562 //
563 gBS->CloseProtocol (
564 TcpServiceData->IpIo->ChildHandle,
565 &gEfiIp4ProtocolGuid,
566 TcpServiceData->DriverBindingHandle,
567 This->SockHandle
568 );
569 }
570
571 /**
572 Creates a child handle with a set of TCP4 services.
573
574 @param This Protocol instance pointer.
575 @param ChildHandle Pointer to the handle of the child to create. If
576 it is NULL, then a new handle is created. If it is
577 not NULL, then the I/O services are added to the
578 existing child handle.
579
580 @retval EFI_SUCCESS The child handle is created.
581 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
582 @retval EFI_OUT_OF_RESOURCES There are not enough resources to create the
583 child.
584
585 **/
586 EFI_STATUS
587 EFIAPI
588 Tcp4ServiceBindingCreateChild (
589 IN EFI_SERVICE_BINDING_PROTOCOL *This,
590 IN EFI_HANDLE *ChildHandle
591 )
592 {
593 SOCKET *Sock;
594 TCP4_SERVICE_DATA *TcpServiceData;
595 TCP4_PROTO_DATA TcpProto;
596 EFI_STATUS Status;
597 EFI_TPL OldTpl;
598
599 if (NULL == This || NULL == ChildHandle) {
600 return EFI_INVALID_PARAMETER;
601 }
602
603 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
604 Status = EFI_SUCCESS;
605 TcpServiceData = TCP4_FROM_THIS (This);
606 TcpProto.TcpService = TcpServiceData;
607 TcpProto.TcpPcb = NULL;
608
609 //
610 // Create a tcp instance with defualt Tcp default
611 // sock init data and TcpProto
612 //
613 mTcp4DefaultSockData.ProtoData = &TcpProto;
614 mTcp4DefaultSockData.DataSize = sizeof (TCP4_PROTO_DATA);
615 mTcp4DefaultSockData.DriverBinding = TcpServiceData->DriverBindingHandle;
616
617 Sock = SockCreateChild (&mTcp4DefaultSockData);
618 if (NULL == Sock) {
619 DEBUG ((EFI_D_ERROR, "Tcp4DriverBindingCreateChild: "
620 "No resource to create a Tcp Child\n"));
621
622 Status = EFI_OUT_OF_RESOURCES;
623 } else {
624 *ChildHandle = Sock->SockHandle;
625 }
626
627 gBS->RestoreTPL (OldTpl);
628 return Status;
629 }
630
631
632 /**
633 Destroys a child handle with a set of UDP4 services.
634
635 @param This Protocol instance pointer.
636 @param ChildHandle Handle of the child to be destroyed.
637
638 @retval EFI_SUCCESS The TCP4 services are removed from the child
639 handle.
640 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
641 @retval other The child handle is not destroyed.
642
643 **/
644 EFI_STATUS
645 EFIAPI
646 Tcp4ServiceBindingDestroyChild (
647 IN EFI_SERVICE_BINDING_PROTOCOL *This,
648 IN EFI_HANDLE ChildHandle
649 )
650 {
651 EFI_STATUS Status;
652 EFI_TCP4_PROTOCOL *Tcp4;
653 SOCKET *Sock;
654 EFI_TPL OldTpl;
655
656 if (NULL == This || NULL == ChildHandle) {
657 return EFI_INVALID_PARAMETER;
658 }
659
660 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
661
662 //
663 // retrieve the Tcp4 protocol from ChildHandle
664 //
665 Status = gBS->OpenProtocol (
666 ChildHandle,
667 &gEfiTcp4ProtocolGuid,
668 (VOID **) &Tcp4,
669 mTcp4DriverBinding.DriverBindingHandle,
670 ChildHandle,
671 EFI_OPEN_PROTOCOL_GET_PROTOCOL
672 );
673 if (EFI_ERROR (Status)) {
674 Status = EFI_UNSUPPORTED;
675 } else {
676 //
677 // destroy this sock and related Tcp protocol control
678 // block
679 //
680 Sock = SOCK_FROM_THIS (Tcp4);
681
682 SockDestroyChild (Sock);
683 }
684
685 gBS->RestoreTPL (OldTpl);
686 return Status;
687 }
688