e2a78b7a9dd25c229e6c1202435caf7c587f7a24
[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 Tcp4Dispatcher,
55 NULL,
56 };
57
58 EFI_DRIVER_BINDING_PROTOCOL mTcp4DriverBinding = {
59 Tcp4DriverBindingSupported,
60 Tcp4DriverBindingStart,
61 Tcp4DriverBindingStop,
62 0xa,
63 NULL,
64 NULL
65 };
66
67 EFI_SERVICE_BINDING_PROTOCOL mTcp4ServiceBinding = {
68 Tcp4ServiceBindingCreateChild,
69 Tcp4ServiceBindingDestroyChild
70 };
71
72
73 /**
74 Create and start the heartbeat timer for TCP driver.
75
76 None.
77
78 @retval EFI_SUCCESS The timer is successfully created and started.
79 @retval other The timer is not created.
80
81 **/
82 STATIC
83 EFI_STATUS
84 Tcp4CreateTimer (
85 VOID
86 )
87 {
88 EFI_STATUS Status;
89
90 Status = EFI_SUCCESS;
91
92 if (mTcp4Timer.RefCnt == 0) {
93
94 Status = gBS->CreateEvent (
95 EVT_TIMER | EVT_NOTIFY_SIGNAL,
96 NET_TPL_EVENT,
97 TcpTicking,
98 NULL,
99 &mTcp4Timer.TimerEvent
100 );
101 if (!EFI_ERROR (Status)) {
102
103 Status = gBS->SetTimer (
104 mTcp4Timer.TimerEvent,
105 TimerPeriodic,
106 (UINT64) (TICKS_PER_SECOND / TCP_TICK_HZ)
107 );
108 }
109 }
110
111 if (!EFI_ERROR (Status)) {
112
113 mTcp4Timer.RefCnt++;
114 }
115
116 return Status;
117 }
118
119
120 /**
121 Stop and destroy the heartbeat timer for TCP driver.
122
123 None.
124
125 @return None.
126
127 **/
128 STATIC
129 VOID
130 Tcp4DestroyTimer (
131 VOID
132 )
133 {
134 ASSERT (mTcp4Timer.RefCnt > 0);
135
136 mTcp4Timer.RefCnt--;
137
138 if (mTcp4Timer.RefCnt > 0) {
139 return;
140 }
141
142 gBS->SetTimer (mTcp4Timer.TimerEvent, TimerCancel, 0);
143 gBS->CloseEvent (mTcp4Timer.TimerEvent);
144 mTcp4Timer.TimerEvent = NULL;
145 }
146
147
148 EFI_STATUS
149 EFIAPI
150 Tcp4DriverEntryPoint (
151 IN EFI_HANDLE ImageHandle,
152 IN EFI_SYSTEM_TABLE *SystemTable
153 )
154 /*++
155
156 Routine Description:
157
158 The entry point for Tcp4 driver. used to install
159 Tcp4 driver on the ImageHandle.
160
161 Arguments:
162
163 ImageHandle - The firmware allocated handle for this
164 driver image.
165 SystemTable - Pointer to the EFI system table.
166
167 Returns:
168
169 EFI_SUCCESS - Driver loaded.
170 other - Driver not loaded.
171
172 --*/
173 {
174 EFI_STATUS Status;
175 UINT32 Seed;
176
177 //
178 // Install the TCP4 Driver Binding Protocol
179 //
180 Status = EfiLibInstallDriverBindingComponentName2 (
181 ImageHandle,
182 SystemTable,
183 &mTcp4DriverBinding,
184 ImageHandle,
185 &gTcp4ComponentName,
186 &gTcp4ComponentName2
187 );
188 ASSERT_EFI_ERROR (Status);
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 ON_ERROR;
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 ON_ERROR;
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 ON_ERROR;
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 Tcp4DestroyTimer ();
348 goto ON_ERROR;
349 }
350
351 //
352 // Initialize member in TcpServiceData
353 //
354 TcpServiceData->ControllerHandle = ControllerHandle;
355 TcpServiceData->Signature = TCP4_DRIVER_SIGNATURE;
356 TcpServiceData->DriverBindingHandle = This->DriverBindingHandle;
357
358 NetListInit (&TcpServiceData->SocketList);
359
360 TcpSetVariableData (TcpServiceData);
361
362 return EFI_SUCCESS;
363
364 ON_ERROR:
365
366 if (TcpServiceData->IpIo != NULL) {
367 IpIoDestroy (TcpServiceData->IpIo);
368 }
369
370 NetFreePool (TcpServiceData);
371
372 return Status;
373 }
374
375
376 /**
377 Stop this driver on ControllerHandle.
378
379 @param This Protocol instance pointer.
380 @param ControllerHandle Handle of device to stop driver on.
381 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number
382 of children is zero stop the entire bus driver.
383 @param ChildHandleBuffer List of Child Handles to Stop.
384
385 @retval EFI_SUCCESS This driver is removed from ControllerHandle.
386 @retval other This driver is not removed from ControllerHandle.
387
388 **/
389 EFI_STATUS
390 EFIAPI
391 Tcp4DriverBindingStop (
392 IN EFI_DRIVER_BINDING_PROTOCOL *This,
393 IN EFI_HANDLE ControllerHandle,
394 IN UINTN NumberOfChildren,
395 IN EFI_HANDLE *ChildHandleBuffer
396 )
397 {
398 EFI_STATUS Status;
399 EFI_HANDLE NicHandle;
400 EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding;
401 TCP4_SERVICE_DATA *TcpServiceData;
402 SOCKET *Sock;
403
404 // Find the NicHandle where Tcp4 ServiceBinding Protocol is installed.
405 //
406 NicHandle = NetLibGetNicHandle (ControllerHandle, &gEfiIp4ProtocolGuid);
407 if (NicHandle == NULL) {
408 return EFI_DEVICE_ERROR;
409 }
410
411 //
412 // Retrieve the TCP driver Data Structure
413 //
414 Status = gBS->OpenProtocol (
415 NicHandle,
416 &gEfiTcp4ServiceBindingProtocolGuid,
417 (VOID **) &ServiceBinding,
418 This->DriverBindingHandle,
419 ControllerHandle,
420 EFI_OPEN_PROTOCOL_GET_PROTOCOL
421 );
422 if (EFI_ERROR (Status)) {
423
424 TCP4_DEBUG_ERROR (("Tcp4DriverBindingStop: Locate Tcp4 Service "
425 " Binding Protocol failed with %r\n", Status));
426
427 return EFI_DEVICE_ERROR;
428 }
429
430 TcpServiceData = TCP4_FROM_THIS (ServiceBinding);
431
432 if (NumberOfChildren == 0) {
433 //
434 // Uninstall TCP servicebinding protocol
435 //
436 gBS->UninstallMultipleProtocolInterfaces (
437 NicHandle,
438 &gEfiTcp4ServiceBindingProtocolGuid,
439 ServiceBinding,
440 NULL
441 );
442
443 //
444 // Destroy the IpIO consumed by TCP driver
445 //
446 IpIoDestroy (TcpServiceData->IpIo);
447
448 //
449 // Destroy the heartbeat timer.
450 //
451 Tcp4DestroyTimer ();
452
453 //
454 // Clear the variable.
455 //
456 TcpClearVariableData (TcpServiceData);
457
458 //
459 // Release the TCP service data
460 //
461 NetFreePool (TcpServiceData);
462 } else {
463
464 while (!NetListIsEmpty (&TcpServiceData->SocketList)) {
465 Sock = NET_LIST_HEAD (&TcpServiceData->SocketList, SOCKET, Link);
466
467 ServiceBinding->DestroyChild (ServiceBinding, Sock->SockHandle);
468 }
469 }
470
471 return Status;
472 }
473
474 /**
475 Creates a child handle with a set of TCP4 services.
476
477 @param This Protocol instance pointer.
478 @param ChildHandle Pointer to the handle of the child to create. If
479 it is NULL, then a new handle is created. If it is
480 not NULL, then the I/O services are added to the
481 existing child handle.
482
483 @retval EFI_SUCCESS The child handle is created.
484 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
485 @retval EFI_OUT_OF_RESOURCES There are not enough resources to create the
486 child.
487
488 **/
489 EFI_STATUS
490 EFIAPI
491 Tcp4ServiceBindingCreateChild (
492 IN EFI_SERVICE_BINDING_PROTOCOL *This,
493 IN EFI_HANDLE *ChildHandle
494 )
495 {
496 SOCKET *Sock;
497 TCP4_SERVICE_DATA *TcpServiceData;
498 TCP4_PROTO_DATA TcpProto;
499 EFI_STATUS Status;
500 VOID *Ip4;
501 EFI_TPL OldTpl;
502
503 if (NULL == This || NULL == ChildHandle) {
504 return EFI_INVALID_PARAMETER;
505 }
506
507 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
508 TcpServiceData = TCP4_FROM_THIS (This);
509 TcpProto.TcpService = TcpServiceData;
510 TcpProto.TcpPcb = NULL;
511
512 //
513 // Create a tcp instance with defualt Tcp default
514 // sock init data and TcpProto
515 //
516 mTcp4DefaultSockData.DriverBinding = TcpServiceData->DriverBindingHandle;
517
518 Sock = SockCreateChild (&mTcp4DefaultSockData, &TcpProto, sizeof (TCP4_PROTO_DATA));
519 if (NULL == Sock) {
520 TCP4_DEBUG_ERROR (("Tcp4DriverBindingCreateChild: "
521 "No resource to create a Tcp Child\n"));
522
523 Status = EFI_OUT_OF_RESOURCES;
524 goto ON_EXIT;
525 }
526
527 *ChildHandle = Sock->SockHandle;
528
529 //
530 // Open the default Ip4 protocol of IP_IO BY_DRIVER.
531 //
532 Status = gBS->OpenProtocol (
533 TcpServiceData->IpIo->ChildHandle,
534 &gEfiIp4ProtocolGuid,
535 (VOID **) &Ip4,
536 TcpServiceData->DriverBindingHandle,
537 Sock->SockHandle,
538 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
539 );
540 if (EFI_ERROR (Status)) {
541 SockDestroyChild (Sock);
542 goto ON_EXIT;
543 }
544
545 //
546 // Open the device path on the handle where service binding resides on.
547 //
548 Status = gBS->OpenProtocol (
549 TcpServiceData->ControllerHandle,
550 &gEfiDevicePathProtocolGuid,
551 (VOID **) &Sock->ParentDevicePath,
552 TcpServiceData->DriverBindingHandle,
553 Sock->SockHandle,
554 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
555 );
556 if (EFI_ERROR (Status)) {
557 gBS->CloseProtocol (
558 TcpServiceData->IpIo->ChildHandle,
559 &gEfiIp4ProtocolGuid,
560 TcpServiceData->DriverBindingHandle,
561 Sock->SockHandle
562 );
563 SockDestroyChild (Sock);
564 } else {
565 NetListInsertTail (&TcpServiceData->SocketList, &Sock->Link);
566 }
567
568 ON_EXIT:
569
570 NET_RESTORE_TPL (OldTpl);
571 return Status;
572 }
573
574
575 /**
576 Destroys a child handle with a set of UDP4 services.
577
578 @param This Protocol instance pointer.
579 @param ChildHandle Handle of the child to be destroyed.
580
581 @retval EFI_SUCCESS The TCP4 services are removed from the child
582 handle.
583 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
584 @retval other The child handle is not destroyed.
585
586 **/
587 EFI_STATUS
588 EFIAPI
589 Tcp4ServiceBindingDestroyChild (
590 IN EFI_SERVICE_BINDING_PROTOCOL *This,
591 IN EFI_HANDLE ChildHandle
592 )
593 {
594 EFI_STATUS Status;
595 EFI_TCP4_PROTOCOL *Tcp4;
596 SOCKET *Sock;
597 TCP4_PROTO_DATA *TcpProtoData;
598 TCP4_SERVICE_DATA *TcpServiceData;
599 EFI_TPL OldTpl;
600
601 if (NULL == This || NULL == ChildHandle) {
602 return EFI_INVALID_PARAMETER;
603 }
604
605 OldTpl = NET_RAISE_TPL (NET_TPL_LOCK);
606
607 //
608 // retrieve the Tcp4 protocol from ChildHandle
609 //
610 Status = gBS->OpenProtocol (
611 ChildHandle,
612 &gEfiTcp4ProtocolGuid,
613 (VOID **) &Tcp4,
614 mTcp4DriverBinding.DriverBindingHandle,
615 ChildHandle,
616 EFI_OPEN_PROTOCOL_GET_PROTOCOL
617 );
618 if (EFI_ERROR (Status)) {
619 Status = EFI_UNSUPPORTED;
620 goto ON_EXIT;
621 }
622
623 //
624 // destroy this sock and related Tcp protocol control
625 // block
626 //
627 Sock = SOCK_FROM_THIS (Tcp4);
628 TcpProtoData = (TCP4_PROTO_DATA *) Sock->ProtoReserved;
629 TcpServiceData = TcpProtoData->TcpService;
630
631 NetListRemoveEntry (&Sock->Link);
632
633 SockDestroyChild (Sock);
634
635 //
636 // Close the device path protocol
637 //
638 gBS->CloseProtocol (
639 TcpServiceData->ControllerHandle,
640 &gEfiDevicePathProtocolGuid,
641 TcpServiceData->DriverBindingHandle,
642 ChildHandle
643 );
644
645 //
646 // Close the Ip4 protocol.
647 //
648 gBS->CloseProtocol (
649 TcpServiceData->IpIo->ChildHandle,
650 &gEfiIp4ProtocolGuid,
651 TcpServiceData->DriverBindingHandle,
652 ChildHandle
653 );
654
655 ON_EXIT:
656 NET_RESTORE_TPL (OldTpl);
657 return Status;
658 }