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