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