]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Impl.c
0f14021e2397407b9ae63f4103f1dd5ac6311f69
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Udp4Dxe / Udp4Impl.c
1 /** @file
2 The implementation of the Udp4 protocol.
3
4 Copyright (c) 2006 - 2009, Intel Corporation.<BR>
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 **/
14
15
16 #include "Udp4Impl.h"
17
18 UINT16 mUdp4RandomPort;
19
20 /**
21 This function checks and timeouts the I/O datagrams holding by the corresponding
22 service context.
23
24 @param[in] Event The event this function registered to.
25 @param[in] Context The context data registered during the creation of
26 the Event.
27
28 **/
29 VOID
30 EFIAPI
31 Udp4CheckTimeout (
32 IN EFI_EVENT Event,
33 IN VOID *Context
34 );
35
36 /**
37 This function finds the udp instance by the specified <Address, Port> pair.
38
39 @param[in] InstanceList Pointer to the head of the list linking the udp
40 instances.
41 @param[in] Address Pointer to the specified IPv4 address.
42 @param[in] Port The udp port number.
43
44 @retval TRUE The specified <Address, Port> pair is found.
45 @retval FALSE Otherwise.
46
47 **/
48 BOOLEAN
49 Udp4FindInstanceByPort (
50 IN LIST_ENTRY *InstanceList,
51 IN EFI_IPv4_ADDRESS *Address,
52 IN UINT16 Port
53 );
54
55 /**
56 This function is the packet transmitting notify function registered to the IpIo
57 interface. It's called to signal the udp TxToken when IpIo layer completes the
58 transmitting of the udp datagram.
59
60 @param[in] Status The completion status of the output udp datagram.
61 @param[in] Context Pointer to the context data.
62 @param[in] Sender Pointer to the Ip sender of the udp datagram.
63 @param[in] NotifyData Pointer to the notify data.
64
65 **/
66 VOID
67 Udp4DgramSent (
68 IN EFI_STATUS Status,
69 IN VOID *Context,
70 IN VOID *Sender,
71 IN VOID *NotifyData
72 );
73
74 /**
75 This function processes the received datagram passed up by the IpIo layer.
76
77 @param[in] Status The status of this udp datagram.
78 @param[in] IcmpError The IcmpError code, only available when Status is
79 EFI_ICMP_ERROR.
80 @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA.
81 @param[in] Packet Pointer to the NET_BUF containing the received udp
82 datagram.
83 @param[in] Context Pointer to the context data.
84
85 **/
86 VOID
87 Udp4DgramRcvd (
88 IN EFI_STATUS Status,
89 IN ICMP_ERROR IcmpError,
90 IN EFI_NET_SESSION_DATA *NetSession,
91 IN NET_BUF *Packet,
92 IN VOID *Context
93 );
94
95 /**
96 This function cancels the token specified by Arg in the Map. This is a callback
97 used by Udp4InstanceCancelToken().
98
99 @param[in] Map Pointer to the NET_MAP.
100 @param[in] Item Pointer to the NET_MAP_ITEM.
101 @param[in] Arg Pointer to the token to be cancelled, if NULL,
102 the token specified by Item is cancelled.
103
104 @retval EFI_SUCCESS The token is cancelled if Arg is NULL or the token
105 is not the same as that in the Item if Arg is not
106 NULL.
107 @retval EFI_ABORTED Arg is not NULL, and the token specified by Arg is
108 cancelled.
109
110 **/
111 EFI_STATUS
112 Udp4CancelTokens (
113 IN NET_MAP *Map,
114 IN NET_MAP_ITEM *Item,
115 IN VOID *Arg OPTIONAL
116 );
117
118 /**
119 This function matches the received udp datagram with the Instance.
120
121 @param[in] Instance Pointer to the udp instance context data.
122 @param[in] Udp4Session Pointer to the EFI_UDP4_SESSION_DATA abstracted
123 from the received udp datagram.
124
125 @retval TRUE The udp datagram matches the receiving requirments of the
126 udp Instance.
127 @retval FALSE Otherwise.
128
129 **/
130 BOOLEAN
131 Udp4MatchDgram (
132 IN UDP4_INSTANCE_DATA *Instance,
133 IN EFI_UDP4_SESSION_DATA *Udp4Session
134 );
135
136 /**
137 This function removes the Wrap specified by Context and release relevant resources.
138
139 @param[in] Event The Event this notify function registered to.
140 @param[in] Context Pointer to the context data.
141
142 **/
143 VOID
144 EFIAPI
145 Udp4RecycleRxDataWrap (
146 IN EFI_EVENT Event,
147 IN VOID *Context
148 );
149
150 /**
151 This function wraps the Packet and the RxData.
152
153 @param[in] Instance Pointer to the instance context data.
154 @param[in] Packet Pointer to the buffer containing the received
155 datagram.
156 @param[in] RxData Pointer to the EFI_UDP4_RECEIVE_DATA of this
157 datagram.
158
159 @return Pointer to the structure wrapping the RxData and the Packet.
160
161 **/
162 UDP4_RXDATA_WRAP *
163 Udp4WrapRxData (
164 IN UDP4_INSTANCE_DATA *Instance,
165 IN NET_BUF *Packet,
166 IN EFI_UDP4_RECEIVE_DATA *RxData
167 );
168
169 /**
170 This function enqueues the received datagram into the instances' receiving queues.
171
172 @param[in] Udp4Service Pointer to the udp service context data.
173 @param[in] Packet Pointer to the buffer containing the received
174 datagram.
175 @param[in] RxData Pointer to the EFI_UDP4_RECEIVE_DATA of this
176 datagram.
177
178 @return The times this datagram is enqueued.
179
180 **/
181 UINTN
182 Udp4EnqueueDgram (
183 IN UDP4_SERVICE_DATA *Udp4Service,
184 IN NET_BUF *Packet,
185 IN EFI_UDP4_RECEIVE_DATA *RxData
186 );
187
188 /**
189 This function delivers the datagrams enqueued in the instances.
190
191 @param[in] Udp4Service Pointer to the udp service context data.
192
193 **/
194 VOID
195 Udp4DeliverDgram (
196 IN UDP4_SERVICE_DATA *Udp4Service
197 );
198
199 /**
200 This function demultiplexes the received udp datagram to the apropriate instances.
201
202 @param[in] Udp4Service Pointer to the udp service context data.
203 @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA abstrated from
204 the received datagram.
205 @param[in] Packet Pointer to the buffer containing the received udp
206 datagram.
207
208 **/
209 VOID
210 Udp4Demultiplex (
211 IN UDP4_SERVICE_DATA *Udp4Service,
212 IN EFI_NET_SESSION_DATA *NetSession,
213 IN NET_BUF *Packet
214 );
215
216 /**
217 This function handles the received Icmp Error message and demultiplexes it to the
218 instance.
219
220 @param[in] Udp4Service Pointer to the udp service context data.
221 @param[in] IcmpError The icmp error code.
222 @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA abstracted
223 from the received Icmp Error packet.
224 @param[in] Packet Pointer to the Icmp Error packet.
225
226 **/
227 VOID
228 Udp4IcmpHandler (
229 IN UDP4_SERVICE_DATA *Udp4Service,
230 IN ICMP_ERROR IcmpError,
231 IN EFI_NET_SESSION_DATA *NetSession,
232 IN NET_BUF *Packet
233 );
234
235 /**
236 This function builds and sends out a icmp port unreachable message.
237
238 @param[in] IpIo Pointer to the IP_IO instance.
239 @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA of the packet
240 causes this icmp error message.
241 @param[in] Udp4Header Pointer to the udp header of the datagram causes
242 this icmp error message.
243
244 **/
245 VOID
246 Udp4SendPortUnreach (
247 IN IP_IO *IpIo,
248 IN EFI_NET_SESSION_DATA *NetSession,
249 IN VOID *Udp4Header
250 );
251
252
253 /**
254 Create the Udp service context data.
255
256 @param Udp4Service Pointer to the UDP4_SERVICE_DATA.
257 @param ImageHandle The image handle of this udp4 driver.
258 @param ControllerHandle The controller handle this udp4 driver binds on.
259
260 @retval EFI_SUCCESS The udp4 service context data is created and
261 initialized.
262 @retval EFI_OUT_OF_RESOURCES Cannot allocate memory.
263 @retval other Other error occurs.
264
265 **/
266 EFI_STATUS
267 Udp4CreateService (
268 IN OUT UDP4_SERVICE_DATA *Udp4Service,
269 IN EFI_HANDLE ImageHandle,
270 IN EFI_HANDLE ControllerHandle
271 )
272 {
273 EFI_STATUS Status;
274 IP_IO_OPEN_DATA OpenData;
275
276 ZeroMem (Udp4Service, sizeof (UDP4_SERVICE_DATA));
277
278 Udp4Service->Signature = UDP4_SERVICE_DATA_SIGNATURE;
279 Udp4Service->ServiceBinding = mUdp4ServiceBinding;
280 Udp4Service->ImageHandle = ImageHandle;
281 Udp4Service->ControllerHandle = ControllerHandle;
282 Udp4Service->ChildrenNumber = 0;
283
284 InitializeListHead (&Udp4Service->ChildrenList);
285
286 //
287 // Create the IpIo for this service context.
288 //
289 Udp4Service->IpIo = IpIoCreate (ImageHandle, ControllerHandle);
290 if (Udp4Service->IpIo == NULL) {
291 return EFI_OUT_OF_RESOURCES;
292 }
293
294 //
295 // Set the OpenData used to open the IpIo.
296 //
297 CopyMem (&OpenData.IpConfigData, &mIpIoDefaultIpConfigData, sizeof (OpenData.IpConfigData));
298 OpenData.IpConfigData.AcceptBroadcast = TRUE;
299 OpenData.RcvdContext = (VOID *) Udp4Service;
300 OpenData.SndContext = NULL;
301 OpenData.PktRcvdNotify = Udp4DgramRcvd;
302 OpenData.PktSentNotify = Udp4DgramSent;
303
304 //
305 // Configure and start the IpIo.
306 //
307 Status = IpIoOpen (Udp4Service->IpIo, &OpenData);
308 if (EFI_ERROR (Status)) {
309 goto ON_ERROR;
310 }
311
312 //
313 // Create the event for Udp timeout checking.
314 //
315 Status = gBS->CreateEvent (
316 EVT_TIMER | EVT_NOTIFY_SIGNAL,
317 TPL_CALLBACK,
318 Udp4CheckTimeout,
319 Udp4Service,
320 &Udp4Service->TimeoutEvent
321 );
322 if (EFI_ERROR (Status)) {
323 goto ON_ERROR;
324 }
325
326 //
327 // Start the timeout timer event.
328 //
329 Status = gBS->SetTimer (
330 Udp4Service->TimeoutEvent,
331 TimerPeriodic,
332 UDP4_TIMEOUT_INTERVAL
333 );
334 if (EFI_ERROR (Status)) {
335 goto ON_ERROR;
336 }
337
338 return EFI_SUCCESS;
339
340 ON_ERROR:
341
342 if (Udp4Service->TimeoutEvent != NULL) {
343 gBS->CloseEvent (Udp4Service->TimeoutEvent);
344 }
345
346 IpIoDestroy (Udp4Service->IpIo);
347
348 return Status;
349 }
350
351
352 /**
353 Clean the Udp service context data.
354
355 @param[in] Udp4Service Pointer to the UDP4_SERVICE_DATA.
356
357 **/
358 VOID
359 Udp4CleanService (
360 IN UDP4_SERVICE_DATA *Udp4Service
361 )
362 {
363 //
364 // Cancel the TimeoutEvent timer.
365 //
366 gBS->SetTimer (Udp4Service->TimeoutEvent, TimerCancel, 0);
367
368 //
369 // Close the TimeoutEvent timer.
370 //
371 gBS->CloseEvent (Udp4Service->TimeoutEvent);
372
373 //
374 // Destroy the IpIo.
375 //
376 IpIoDestroy (Udp4Service->IpIo);
377 }
378
379
380 /**
381 This function checks and timeouts the I/O datagrams holding by the corresponding
382 service context.
383
384 @param[in] Event The event this function registered to.
385 @param[in] Context The context data registered during the creation of
386 the Event.
387
388 **/
389 VOID
390 EFIAPI
391 Udp4CheckTimeout (
392 IN EFI_EVENT Event,
393 IN VOID *Context
394 )
395 {
396 UDP4_SERVICE_DATA *Udp4Service;
397 LIST_ENTRY *Entry;
398 UDP4_INSTANCE_DATA *Instance;
399 LIST_ENTRY *WrapEntry;
400 LIST_ENTRY *NextEntry;
401 UDP4_RXDATA_WRAP *Wrap;
402
403 Udp4Service = (UDP4_SERVICE_DATA *) Context;
404 NET_CHECK_SIGNATURE (Udp4Service, UDP4_SERVICE_DATA_SIGNATURE);
405
406 NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {
407 //
408 // Iterate all the instances belonging to this service context.
409 //
410 Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);
411 NET_CHECK_SIGNATURE (Instance, UDP4_INSTANCE_DATA_SIGNATURE);
412
413 if (!Instance->Configured || (Instance->ConfigData.ReceiveTimeout == 0)) {
414 //
415 // Skip this instance if it's not configured or no receive timeout.
416 //
417 continue;
418 }
419
420 NET_LIST_FOR_EACH_SAFE (WrapEntry, NextEntry, &Instance->RcvdDgramQue) {
421 //
422 // Iterate all the rxdatas belonging to this udp instance.
423 //
424 Wrap = NET_LIST_USER_STRUCT (WrapEntry, UDP4_RXDATA_WRAP, Link);
425
426 //
427 // TimeoutTick unit is ms, MNP_TIMEOUT_CHECK_INTERVAL unit is 100ns.
428 //
429 if (Wrap->TimeoutTick <= (UDP4_TIMEOUT_INTERVAL / 10)) {
430 //
431 // Remove this RxData if it timeouts.
432 //
433 Udp4RecycleRxDataWrap (NULL, (VOID *) Wrap);
434 } else {
435 Wrap->TimeoutTick -= (UDP4_TIMEOUT_INTERVAL / 10);
436 }
437 }
438 }
439 }
440
441
442 /**
443 This function intializes the new created udp instance.
444
445 @param Udp4Service Pointer to the UDP4_SERVICE_DATA.
446 @param Instance Pointer to the un-initialized UDP4_INSTANCE_DATA.
447
448 **/
449 VOID
450 Udp4InitInstance (
451 IN UDP4_SERVICE_DATA *Udp4Service,
452 IN OUT UDP4_INSTANCE_DATA *Instance
453 )
454 {
455 //
456 // Set the signature.
457 //
458 Instance->Signature = UDP4_INSTANCE_DATA_SIGNATURE;
459
460 //
461 // Init the lists.
462 //
463 InitializeListHead (&Instance->Link);
464 InitializeListHead (&Instance->RcvdDgramQue);
465 InitializeListHead (&Instance->DeliveredDgramQue);
466
467 //
468 // Init the NET_MAPs.
469 //
470 NetMapInit (&Instance->TxTokens);
471 NetMapInit (&Instance->RxTokens);
472 NetMapInit (&Instance->McastIps);
473
474 //
475 // Save the pointer to the UDP4_SERVICE_DATA, and initialize other members.
476 //
477 Instance->Udp4Service = Udp4Service;
478 CopyMem (&Instance->Udp4Proto, &mUdp4Protocol, sizeof (Instance->Udp4Proto));
479 Instance->IcmpError = EFI_SUCCESS;
480 Instance->Configured = FALSE;
481 Instance->IsNoMapping = FALSE;
482 Instance->Destroyed = FALSE;
483 }
484
485
486 /**
487 This function cleans the udp instance.
488
489 @param[in] Instance Pointer to the UDP4_INSTANCE_DATA to clean.
490
491 **/
492 VOID
493 Udp4CleanInstance (
494 IN UDP4_INSTANCE_DATA *Instance
495 )
496 {
497 NetMapClean (&Instance->McastIps);
498 NetMapClean (&Instance->RxTokens);
499 NetMapClean (&Instance->TxTokens);
500 }
501
502
503 /**
504 This function finds the udp instance by the specified <Address, Port> pair.
505
506 @param[in] InstanceList Pointer to the head of the list linking the udp
507 instances.
508 @param[in] Address Pointer to the specified IPv4 address.
509 @param[in] Port The udp port number.
510
511 @retval TRUE The specified <Address, Port> pair is found.
512 @retval FALSE Otherwise.
513
514 **/
515 BOOLEAN
516 Udp4FindInstanceByPort (
517 IN LIST_ENTRY *InstanceList,
518 IN EFI_IPv4_ADDRESS *Address,
519 IN UINT16 Port
520 )
521 {
522 LIST_ENTRY *Entry;
523 UDP4_INSTANCE_DATA *Instance;
524 EFI_UDP4_CONFIG_DATA *ConfigData;
525
526 NET_LIST_FOR_EACH (Entry, InstanceList) {
527 //
528 // Iterate all the udp instances.
529 //
530 Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);
531 ConfigData = &Instance->ConfigData;
532
533 if (!Instance->Configured || ConfigData->AcceptAnyPort) {
534 //
535 // If the instance is not configured or the configdata of the instance indicates
536 // this instance accepts any port, skip it.
537 //
538 continue;
539 }
540
541 if (EFI_IP4_EQUAL (&ConfigData->StationAddress, Address) &&
542 (ConfigData->StationPort == Port)) {
543 //
544 // if both the address and the port are the same, return TRUE.
545 //
546 return TRUE;
547 }
548 }
549
550 //
551 // return FALSE when matching fails.
552 //
553 return FALSE;
554 }
555
556
557 /**
558 This function tries to bind the udp instance according to the configured port
559 allocation strategy.
560
561 @param InstanceList Pointer to the head of the list linking the udp
562 instances.
563 @param ConfigData Pointer to the ConfigData of the instance to be
564 bound. ConfigData->StationPort will be assigned
565 with an available port value on success.
566
567 @retval EFI_SUCCESS The bound operation is completed successfully.
568 @retval EFI_ACCESS_DENIED The <Address, Port> specified by the ConfigData is
569 already used by other instance.
570 @retval EFI_OUT_OF_RESOURCES No available port resources.
571
572 **/
573 EFI_STATUS
574 Udp4Bind (
575 IN LIST_ENTRY *InstanceList,
576 IN OUT EFI_UDP4_CONFIG_DATA *ConfigData
577 )
578 {
579 EFI_IPv4_ADDRESS *StationAddress;
580 UINT16 StartPort;
581
582 if (ConfigData->AcceptAnyPort) {
583 return EFI_SUCCESS;
584 }
585
586 StationAddress = &ConfigData->StationAddress;
587
588 if (ConfigData->StationPort != 0) {
589
590 if (!ConfigData->AllowDuplicatePort &&
591 Udp4FindInstanceByPort (InstanceList, StationAddress, ConfigData->StationPort)) {
592 //
593 // Do not allow duplicate port and the port is already used by other instance.
594 //
595 return EFI_ACCESS_DENIED;
596 }
597 } else {
598 //
599 // select a random port for this instance;
600 //
601
602 if (ConfigData->AllowDuplicatePort) {
603 //
604 // Just pick up the random port if the instance allows duplicate port.
605 //
606 ConfigData->StationPort = mUdp4RandomPort;
607 } else {
608
609 StartPort = mUdp4RandomPort;
610
611 while (Udp4FindInstanceByPort(InstanceList, StationAddress, mUdp4RandomPort)) {
612
613 mUdp4RandomPort++;
614 if (mUdp4RandomPort == 0) {
615 mUdp4RandomPort = UDP4_PORT_KNOWN;
616 }
617
618 if (mUdp4RandomPort == StartPort) {
619 //
620 // No available port.
621 //
622 return EFI_OUT_OF_RESOURCES;
623 }
624 }
625
626 ConfigData->StationPort = mUdp4RandomPort;
627 }
628
629 mUdp4RandomPort++;
630 if (mUdp4RandomPort == 0) {
631 mUdp4RandomPort = UDP4_PORT_KNOWN;
632 }
633 }
634
635 return EFI_SUCCESS;
636 }
637
638
639 /**
640 This function is used to check whether the NewConfigData has any un-reconfigurable
641 parameters changed compared to the OldConfigData.
642
643 @param[in] OldConfigData Pointer to the current ConfigData the udp instance
644 uses.
645 @param[in] NewConfigData Pointer to the new ConfigData.
646
647 @retval TRUE The instance is reconfigurable.
648 @retval FALSE Otherwise.
649
650 **/
651 BOOLEAN
652 Udp4IsReconfigurable (
653 IN EFI_UDP4_CONFIG_DATA *OldConfigData,
654 IN EFI_UDP4_CONFIG_DATA *NewConfigData
655 )
656 {
657 if ((NewConfigData->AcceptAnyPort != OldConfigData->AcceptAnyPort) ||
658 (NewConfigData->AcceptBroadcast != OldConfigData->AcceptBroadcast) ||
659 (NewConfigData->AcceptPromiscuous != OldConfigData->AcceptPromiscuous) ||
660 (NewConfigData->AllowDuplicatePort != OldConfigData->AllowDuplicatePort)
661 ) {
662 //
663 // The receiving filter parameters cannot be changed.
664 //
665 return FALSE;
666 }
667
668 if ((!NewConfigData->AcceptAnyPort) &&
669 (NewConfigData->StationPort != OldConfigData->StationPort)
670 ) {
671 //
672 // The port is not changeable.
673 //
674 return FALSE;
675 }
676
677 if (!NewConfigData->AcceptPromiscuous) {
678
679 if (NewConfigData->UseDefaultAddress != OldConfigData->UseDefaultAddress) {
680 //
681 // The NewConfigData differs to the old one on the UseDefaultAddress.
682 //
683 return FALSE;
684 }
685
686 if (!NewConfigData->UseDefaultAddress &&
687 (!EFI_IP4_EQUAL (&NewConfigData->StationAddress, &OldConfigData->StationAddress) ||
688 !EFI_IP4_EQUAL (&NewConfigData->SubnetMask, &OldConfigData->SubnetMask))
689 ) {
690 //
691 // If the instance doesn't use the default address, and the new address or
692 // new subnet mask is different from the old values.
693 //
694 return FALSE;
695 }
696 }
697
698 if (!EFI_IP4_EQUAL (&NewConfigData->RemoteAddress, &OldConfigData->RemoteAddress)) {
699 //
700 // The remoteaddress is not the same.
701 //
702 return FALSE;
703 }
704
705 if (!EFI_IP4_EQUAL (&NewConfigData->RemoteAddress, &mZeroIp4Addr) &&
706 NewConfigData->RemotePort != OldConfigData->RemotePort
707 ) {
708 //
709 // The RemotePort differs if it's designated in the configdata.
710 //
711 return FALSE;
712 }
713
714 //
715 // All checks pass, return TRUE.
716 //
717 return TRUE;
718 }
719
720
721 /**
722 This function builds the Ip4 configdata from the Udp4ConfigData.
723
724 @param[in] Udp4ConfigData Pointer to the EFI_UDP4_CONFIG_DATA.
725 @param[in, out] Ip4ConfigData Pointer to the EFI_IP4_CONFIG_DATA.
726
727 **/
728 VOID
729 Udp4BuildIp4ConfigData (
730 IN EFI_UDP4_CONFIG_DATA *Udp4ConfigData,
731 IN OUT EFI_IP4_CONFIG_DATA *Ip4ConfigData
732 )
733 {
734 CopyMem (Ip4ConfigData, &mIpIoDefaultIpConfigData, sizeof (*Ip4ConfigData));
735
736 Ip4ConfigData->DefaultProtocol = EFI_IP_PROTO_UDP;
737 Ip4ConfigData->AcceptBroadcast = Udp4ConfigData->AcceptBroadcast;
738 Ip4ConfigData->AcceptPromiscuous = Udp4ConfigData->AcceptPromiscuous;
739 Ip4ConfigData->UseDefaultAddress = Udp4ConfigData->UseDefaultAddress;
740 CopyMem (&Ip4ConfigData->StationAddress, &Udp4ConfigData->StationAddress, sizeof (EFI_IPv4_ADDRESS));
741 CopyMem (&Ip4ConfigData->SubnetMask, &Udp4ConfigData->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
742
743 //
744 // use the -1 magic number to disable the receiving process of the ip instance.
745 //
746 Ip4ConfigData->ReceiveTimeout = (UINT32) (-1);
747 }
748
749
750 /**
751 This function validates the TxToken, it returns the error code according to the spec.
752
753 @param[in] Instance Pointer to the udp instance context data.
754 @param[in] TxToken Pointer to the token to be checked.
755
756 @retval EFI_SUCCESS The TxToken is valid.
757 @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: This is
758 NULL. Token is NULL. Token.Event is NULL.
759 Token.Packet.TxData is NULL.
760 Token.Packet.TxData.FragmentCount is zero.
761 Token.Packet.TxData.DataLength is not equal to the
762 sum of fragment lengths. One or more of the
763 Token.Packet.TxData.FragmentTable[].
764 FragmentLength fields is zero. One or more of the
765 Token.Packet.TxData.FragmentTable[].
766 FragmentBuffer fields is NULL.
767 Token.Packet.TxData. GatewayAddress is not a
768 unicast IPv4 address if it is not NULL. One or
769 more IPv4 addresses in Token.Packet.TxData.
770 UdpSessionData are not valid unicast IPv4
771 addresses if the UdpSessionData is not NULL.
772 @retval EFI_BAD_BUFFER_SIZE The data length is greater than the maximum UDP
773 packet size.
774
775 **/
776 EFI_STATUS
777 Udp4ValidateTxToken (
778 IN UDP4_INSTANCE_DATA *Instance,
779 IN EFI_UDP4_COMPLETION_TOKEN *TxToken
780 )
781 {
782 EFI_UDP4_TRANSMIT_DATA *TxData;
783 UINT32 Index;
784 UINT32 TotalLen;
785 EFI_UDP4_CONFIG_DATA *ConfigData;
786 EFI_UDP4_SESSION_DATA *UdpSessionData;
787 IP4_ADDR SourceAddress;
788 IP4_ADDR GatewayAddress;
789
790 if (TxToken->Event == NULL) {
791 return EFI_INVALID_PARAMETER;
792 }
793
794 TxData = TxToken->Packet.TxData;
795
796 if ((TxData == NULL) || (TxData->FragmentCount == 0)) {
797 return EFI_INVALID_PARAMETER;
798 }
799
800 TotalLen = 0;
801 for (Index = 0; Index < TxData->FragmentCount; Index++) {
802
803 if ((TxData->FragmentTable[Index].FragmentBuffer == NULL) ||
804 (TxData->FragmentTable[Index].FragmentLength == 0)) {
805 //
806 // if the FragmentBuffer is NULL or the FragmentLeng is zero.
807 //
808 return EFI_INVALID_PARAMETER;
809 }
810
811 TotalLen += TxData->FragmentTable[Index].FragmentLength;
812 }
813
814 if (TotalLen != TxData->DataLength) {
815 //
816 // The TotalLen calculated by adding all the FragmentLeng doesn't equal to the
817 // DataLength.
818 //
819 return EFI_INVALID_PARAMETER;
820 }
821
822 if (TxData->GatewayAddress != NULL) {
823 CopyMem (&GatewayAddress, TxData->GatewayAddress, sizeof (IP4_ADDR));
824
825 if (!Ip4IsUnicast (NTOHL (GatewayAddress), 0)) {
826 //
827 // The specified GatewayAddress is not a unicast IPv4 address while it's not 0.
828 //
829 return EFI_INVALID_PARAMETER;
830 }
831 }
832
833 ConfigData = &Instance->ConfigData;
834 UdpSessionData = TxData->UdpSessionData;
835
836 if (UdpSessionData != NULL) {
837
838 CopyMem (&SourceAddress, &UdpSessionData->SourceAddress, sizeof (IP4_ADDR));
839
840 if ((SourceAddress != 0) && !Ip4IsUnicast (HTONL (SourceAddress), 0)) {
841 //
842 // Check whether SourceAddress is a valid IPv4 address in case it's not zero.
843 // The configured station address is used if SourceAddress is zero.
844 //
845 return EFI_INVALID_PARAMETER;
846 }
847
848 if ((UdpSessionData->DestinationPort == 0) && (ConfigData->RemotePort == 0)) {
849 //
850 // Ambiguous, no avalaible DestinationPort for this token.
851 //
852 return EFI_INVALID_PARAMETER;
853 }
854
855 if (EFI_IP4_EQUAL (&UdpSessionData->DestinationAddress, &mZeroIp4Addr)) {
856 //
857 // The DestinationAddress specified in the UdpSessionData is 0.
858 //
859 return EFI_INVALID_PARAMETER;
860 }
861 } else if (EFI_IP4_EQUAL (&ConfigData->RemoteAddress, &mZeroIp4Addr)) {
862 //
863 // the configured RemoteAddress is all zero, and the user doens't override the
864 // destination address.
865 //
866 return EFI_INVALID_PARAMETER;
867 }
868
869 if (TxData->DataLength > UDP4_MAX_DATA_SIZE) {
870 return EFI_BAD_BUFFER_SIZE;
871 }
872
873 return EFI_SUCCESS;
874 }
875
876
877 /**
878 This function checks whether the specified Token duplicates with the one in the Map.
879
880 @param[in] Map Pointer to the NET_MAP.
881 @param[in] Item Pointer to the NET_MAP_ITEM contain the pointer to
882 the Token.
883 @param[in] Context Pointer to the Token to be checked.
884
885 @retval EFI_SUCCESS The Token specified by Context differs from the
886 one in the Item.
887 @retval EFI_ACCESS_DENIED The Token duplicates with the one in the Item.
888
889 **/
890 EFI_STATUS
891 Udp4TokenExist (
892 IN NET_MAP *Map,
893 IN NET_MAP_ITEM *Item,
894 IN VOID *Context
895 )
896 {
897 EFI_UDP4_COMPLETION_TOKEN *Token;
898 EFI_UDP4_COMPLETION_TOKEN *TokenInItem;
899
900 Token = (EFI_UDP4_COMPLETION_TOKEN*) Context;
901 TokenInItem = (EFI_UDP4_COMPLETION_TOKEN*) Item->Key;
902
903 if ((Token == TokenInItem) || (Token->Event == TokenInItem->Event)) {
904 //
905 // The Token duplicates with the TokenInItem in case either the two pointers are the
906 // same or the Events of these two tokens are the same.
907 //
908 return EFI_ACCESS_DENIED;
909 }
910
911 return EFI_SUCCESS;
912 }
913
914
915 /**
916 This function calculates the checksum for the Packet, utilizing the pre-calculated
917 pseudo HeadSum to reduce some overhead.
918
919 @param[in] Packet Pointer to the NET_BUF contains the udp datagram.
920 @param[in] HeadSum Checksum of the pseudo header execpt the length
921 field.
922
923 @retval The 16-bit checksum of this udp datagram.
924
925 **/
926 UINT16
927 Udp4Checksum (
928 IN NET_BUF *Packet,
929 IN UINT16 HeadSum
930 )
931 {
932 UINT16 Checksum;
933
934 Checksum = NetbufChecksum (Packet);
935 Checksum = NetAddChecksum (Checksum, HeadSum);
936
937 Checksum = NetAddChecksum (Checksum, HTONS ((UINT16) Packet->TotalSize));
938
939 return (UINT16) ~Checksum;
940 }
941
942
943 /**
944 This function removes the specified Token from the TokenMap.
945
946 @param TokenMap Pointer to the NET_MAP containing the tokens.
947 @param Token Pointer to the Token to be removed.
948
949 @retval EFI_SUCCESS The specified Token is removed from the TokenMap.
950 @retval EFI_NOT_FOUND The specified Token is not found in the TokenMap.
951
952 **/
953 EFI_STATUS
954 Udp4RemoveToken (
955 IN OUT NET_MAP *TokenMap,
956 IN EFI_UDP4_COMPLETION_TOKEN *Token
957 )
958 {
959 NET_MAP_ITEM *Item;
960
961 //
962 // Find the Token first.
963 //
964 Item = NetMapFindKey (TokenMap, (VOID *) Token);
965
966 if (Item != NULL) {
967 //
968 // Remove the token if it's found in the map.
969 //
970 NetMapRemoveItem (TokenMap, Item, NULL);
971
972 return EFI_SUCCESS;
973 }
974
975 return EFI_NOT_FOUND;
976 }
977
978
979 /**
980 This function is the packet transmitting notify function registered to the IpIo
981 interface. It's called to signal the udp TxToken when IpIo layer completes the
982 transmitting of the udp datagram.
983
984 @param[in] Status The completion status of the output udp datagram.
985 @param[in] Context Pointer to the context data.
986 @param[in] Sender Pointer to the Ip sender of the udp datagram.
987 @param[in] NotifyData Pointer to the notify data.
988
989 **/
990 VOID
991 Udp4DgramSent (
992 IN EFI_STATUS Status,
993 IN VOID *Context,
994 IN VOID *Sender,
995 IN VOID *NotifyData
996 )
997 {
998 UDP4_INSTANCE_DATA *Instance;
999 EFI_UDP4_COMPLETION_TOKEN *Token;
1000
1001 Instance = (UDP4_INSTANCE_DATA *) Context;
1002 Token = (EFI_UDP4_COMPLETION_TOKEN *) NotifyData;
1003
1004 if (Udp4RemoveToken (&Instance->TxTokens, Token) == EFI_SUCCESS) {
1005 //
1006 // The token may be cancelled. Only signal it if the remove operation succeeds.
1007 //
1008 Token->Status = Status;
1009 gBS->SignalEvent (Token->Event);
1010 NetLibDispatchDpc ();
1011 }
1012 }
1013
1014
1015 /**
1016 This function processes the received datagram passed up by the IpIo layer.
1017
1018 @param[in] Status The status of this udp datagram.
1019 @param[in] IcmpError The IcmpError code, only available when Status is
1020 EFI_ICMP_ERROR.
1021 @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA.
1022 @param[in] Packet Pointer to the NET_BUF containing the received udp
1023 datagram.
1024 @param[in] Context Pointer to the context data.
1025
1026 **/
1027 VOID
1028 Udp4DgramRcvd (
1029 IN EFI_STATUS Status,
1030 IN ICMP_ERROR IcmpError,
1031 IN EFI_NET_SESSION_DATA *NetSession,
1032 IN NET_BUF *Packet,
1033 IN VOID *Context
1034 )
1035 {
1036 NET_CHECK_SIGNATURE (Packet, NET_BUF_SIGNATURE);
1037
1038 //
1039 // IpIo only passes received packets with Status EFI_SUCCESS or EFI_ICMP_ERROR.
1040 //
1041 if (Status == EFI_SUCCESS) {
1042 //
1043 // Demultiplex the received datagram.
1044 //
1045 Udp4Demultiplex ((UDP4_SERVICE_DATA *) Context, NetSession, Packet);
1046 } else {
1047 //
1048 // Handle the ICMP_ERROR packet.
1049 //
1050 Udp4IcmpHandler ((UDP4_SERVICE_DATA *) Context, IcmpError, NetSession, Packet);
1051 }
1052
1053 //
1054 // Dispatch the DPC queued by the NotifyFunction of the rx token's events
1055 // which are signaled with received data.
1056 //
1057 NetLibDispatchDpc ();
1058 }
1059
1060
1061 /**
1062 This function removes the multicast group specified by Arg from the Map.
1063
1064 @param Map Pointer to the NET_MAP.
1065 @param Item Pointer to the NET_MAP_ITEM.
1066 @param Arg Pointer to the Arg, it's the pointer to a
1067 multicast IPv4 Address.
1068
1069 @retval EFI_SUCCESS The multicast address is removed.
1070 @retval EFI_ABORTED The specified multicast address is removed and the
1071 Arg is not NULL.
1072
1073 **/
1074 EFI_STATUS
1075 Udp4LeaveGroup (
1076 IN OUT NET_MAP *Map,
1077 IN NET_MAP_ITEM *Item,
1078 IN VOID *Arg OPTIONAL
1079 )
1080 {
1081 EFI_IPv4_ADDRESS *McastIp;
1082
1083 McastIp = Arg;
1084
1085 if ((McastIp != NULL) && (!EFI_IP4_EQUAL (McastIp, &(Item->Key)))) {
1086 //
1087 // McastIp is not NULL and the multicast address contained in the Item
1088 // is not the same as McastIp.
1089 //
1090 return EFI_SUCCESS;
1091 }
1092
1093 //
1094 // Remove this Item.
1095 //
1096 NetMapRemoveItem (Map, Item, NULL);
1097
1098 if (McastIp != NULL) {
1099 //
1100 // Return EFI_ABORTED in case McastIp is not NULL to terminate the iteration.
1101 //
1102 return EFI_ABORTED;
1103 }
1104
1105 return EFI_SUCCESS;
1106 }
1107
1108
1109 /**
1110 This function cancels the token specified by Arg in the Map. This is a callback
1111 used by Udp4InstanceCancelToken().
1112
1113 @param[in] Map Pointer to the NET_MAP.
1114 @param[in] Item Pointer to the NET_MAP_ITEM.
1115 @param[in] Arg Pointer to the token to be cancelled, if NULL,
1116 the token specified by Item is cancelled.
1117
1118 @retval EFI_SUCCESS The token is cancelled if Arg is NULL or the token
1119 is not the same as that in the Item if Arg is not
1120 NULL.
1121 @retval EFI_ABORTED Arg is not NULL, and the token specified by Arg is
1122 cancelled.
1123
1124 **/
1125 EFI_STATUS
1126 Udp4CancelTokens (
1127 IN NET_MAP *Map,
1128 IN NET_MAP_ITEM *Item,
1129 IN VOID *Arg OPTIONAL
1130 )
1131 {
1132 EFI_UDP4_COMPLETION_TOKEN *TokenToCancel;
1133 NET_BUF *Packet;
1134 IP_IO *IpIo;
1135
1136 if ((Arg != NULL) && (Item->Key != Arg)) {
1137 return EFI_SUCCESS;
1138 }
1139
1140 if (Item->Value != NULL) {
1141 //
1142 // If the token is a transmit token, the corresponding Packet is recorded in
1143 // Item->Value, invoke IpIo to cancel this packet first. The IpIoCancelTxToken
1144 // will invoke Udp4DgramSent, the token will be signaled and this Item will
1145 // be removed from the Map there.
1146 //
1147 Packet = (NET_BUF *) (Item->Value);
1148 IpIo = (IP_IO *) (*((UINTN *) &Packet->ProtoData[0]));
1149
1150 IpIoCancelTxToken (IpIo, Packet);
1151 } else {
1152 //
1153 // The token is a receive token. Abort it and remove it from the Map.
1154 //
1155 TokenToCancel = (EFI_UDP4_COMPLETION_TOKEN *) Item->Key;
1156 NetMapRemoveItem (Map, Item, NULL);
1157
1158 TokenToCancel->Status = EFI_ABORTED;
1159 gBS->SignalEvent (TokenToCancel->Event);
1160 }
1161
1162 if (Arg != NULL) {
1163 return EFI_ABORTED;
1164 }
1165
1166 return EFI_SUCCESS;
1167 }
1168
1169
1170 /**
1171 This function removes all the Wrap datas in the RcvdDgramQue.
1172
1173 @param[in] Instance Pointer to the udp instance context data.
1174
1175 **/
1176 VOID
1177 Udp4FlushRcvdDgram (
1178 IN UDP4_INSTANCE_DATA *Instance
1179 )
1180 {
1181 UDP4_RXDATA_WRAP *Wrap;
1182
1183 while (!IsListEmpty (&Instance->RcvdDgramQue)) {
1184 //
1185 // Iterate all the Wraps in the RcvdDgramQue.
1186 //
1187 Wrap = NET_LIST_HEAD (&Instance->RcvdDgramQue, UDP4_RXDATA_WRAP, Link);
1188
1189 //
1190 // The Wrap will be removed from the RcvdDgramQue by this function call.
1191 //
1192 Udp4RecycleRxDataWrap (NULL, (VOID *) Wrap);
1193 }
1194 }
1195
1196
1197
1198 /**
1199 Cancel Udp4 tokens from the Udp4 instance.
1200
1201 @param[in] Instance Pointer to the udp instance context data.
1202 @param[in] Token Pointer to the token to be canceled, if NULL, all
1203 tokens in this instance will be cancelled.
1204
1205 @retval EFI_SUCCESS The Token is cancelled.
1206 @retval EFI_NOT_FOUND The Token is not found.
1207
1208 **/
1209 EFI_STATUS
1210 Udp4InstanceCancelToken (
1211 IN UDP4_INSTANCE_DATA *Instance,
1212 IN EFI_UDP4_COMPLETION_TOKEN *Token OPTIONAL
1213 )
1214 {
1215 EFI_STATUS Status;
1216
1217 //
1218 // Cancel this token from the TxTokens map.
1219 //
1220 Status = NetMapIterate (&Instance->TxTokens, Udp4CancelTokens, Token);
1221
1222 if ((Token != NULL) && (Status == EFI_ABORTED)) {
1223 //
1224 // If Token isn't NULL and Status is EFI_ABORTED, the token is cancelled from
1225 // the TxTokens, just return success.
1226 //
1227 return EFI_SUCCESS;
1228 }
1229
1230 //
1231 // Try to cancel this token from the RxTokens map in condition either the Token
1232 // is NULL or the specified Token is not in TxTokens.
1233 //
1234 Status = NetMapIterate (&Instance->RxTokens, Udp4CancelTokens, Token);
1235
1236 if ((Token != NULL) && (Status == EFI_SUCCESS)) {
1237 //
1238 // If Token isn't NULL and Status is EFI_SUCCESS, the token is neither in the
1239 // TxTokens nor the RxTokens, or say, it's not found.
1240 //
1241 return EFI_NOT_FOUND;
1242 }
1243
1244 ASSERT ((Token != NULL) || ((0 == NetMapGetCount (&Instance->TxTokens))
1245 && (0 == NetMapGetCount (&Instance->RxTokens))));
1246
1247 return EFI_SUCCESS;
1248 }
1249
1250
1251 /**
1252 This function matches the received udp datagram with the Instance.
1253
1254 @param[in] Instance Pointer to the udp instance context data.
1255 @param[in] Udp4Session Pointer to the EFI_UDP4_SESSION_DATA abstracted
1256 from the received udp datagram.
1257
1258 @retval TRUE The udp datagram matches the receiving requirments of the
1259 udp Instance.
1260 @retval FALSE Otherwise.
1261
1262 **/
1263 BOOLEAN
1264 Udp4MatchDgram (
1265 IN UDP4_INSTANCE_DATA *Instance,
1266 IN EFI_UDP4_SESSION_DATA *Udp4Session
1267 )
1268 {
1269 EFI_UDP4_CONFIG_DATA *ConfigData;
1270 IP4_ADDR Destination;
1271
1272 ConfigData = &Instance->ConfigData;
1273
1274 if (ConfigData->AcceptPromiscuous) {
1275 //
1276 // Always matches if this instance is in the promiscuous state.
1277 //
1278 return TRUE;
1279 }
1280
1281 if ((!ConfigData->AcceptAnyPort && (Udp4Session->DestinationPort != ConfigData->StationPort)) ||
1282 ((ConfigData->RemotePort != 0) && (Udp4Session->SourcePort != ConfigData->RemotePort))
1283 ) {
1284 //
1285 // The local port or the remote port doesn't match.
1286 //
1287 return FALSE;
1288 }
1289
1290 if (!EFI_IP4_EQUAL (&ConfigData->RemoteAddress, &mZeroIp4Addr) &&
1291 !EFI_IP4_EQUAL (&ConfigData->RemoteAddress, &Udp4Session->SourceAddress)
1292 ) {
1293 //
1294 // This datagram doesn't come from the instance's specified sender.
1295 //
1296 return FALSE;
1297 }
1298
1299 if (EFI_IP4_EQUAL (&ConfigData->StationAddress, &mZeroIp4Addr) ||
1300 EFI_IP4_EQUAL (&Udp4Session->DestinationAddress, &ConfigData->StationAddress)
1301 ) {
1302 //
1303 // The instance is configured to receive datagrams destined to any station IP or
1304 // the destination address of this datagram matches the configured station IP.
1305 //
1306 return TRUE;
1307 }
1308
1309 CopyMem (&Destination, &Udp4Session->DestinationAddress, sizeof (IP4_ADDR));
1310
1311 if (IP4_IS_LOCAL_BROADCAST (Destination) && ConfigData->AcceptBroadcast) {
1312 //
1313 // The instance is configured to receive broadcast and this is a broadcast packet.
1314 //
1315 return TRUE;
1316 }
1317
1318 if (IP4_IS_MULTICAST (NTOHL (Destination)) &&
1319 NetMapFindKey (&Instance->McastIps, (VOID *) (UINTN) Destination) != NULL
1320 ) {
1321 //
1322 // It's a multicast packet and the multicast address is accepted by this instance.
1323 //
1324 return TRUE;
1325 }
1326
1327 return FALSE;
1328 }
1329
1330
1331 /**
1332 This function removes the Wrap specified by Context and release relevant resources.
1333
1334 @param[in] Event The Event this notify function registered to.
1335 @param[in] Context Pointer to the context data.
1336
1337 **/
1338 VOID
1339 EFIAPI
1340 Udp4RecycleRxDataWrap (
1341 IN EFI_EVENT Event,
1342 IN VOID *Context
1343 )
1344 {
1345 UDP4_RXDATA_WRAP *Wrap;
1346
1347 Wrap = (UDP4_RXDATA_WRAP *) Context;
1348
1349 //
1350 // Remove the Wrap from the list it belongs to.
1351 //
1352 RemoveEntryList (&Wrap->Link);
1353
1354 //
1355 // Free the Packet associated with this Wrap.
1356 //
1357 NetbufFree (Wrap->Packet);
1358
1359 //
1360 // Close the event.
1361 //
1362 gBS->CloseEvent (Wrap->RxData.RecycleSignal);
1363
1364 gBS->FreePool (Wrap);
1365 }
1366
1367
1368 /**
1369 This function wraps the Packet and the RxData.
1370
1371 @param[in] Instance Pointer to the instance context data.
1372 @param[in] Packet Pointer to the buffer containing the received
1373 datagram.
1374 @param[in] RxData Pointer to the EFI_UDP4_RECEIVE_DATA of this
1375 datagram.
1376
1377 @return Pointer to the structure wrapping the RxData and the Packet.
1378
1379 **/
1380 UDP4_RXDATA_WRAP *
1381 Udp4WrapRxData (
1382 IN UDP4_INSTANCE_DATA *Instance,
1383 IN NET_BUF *Packet,
1384 IN EFI_UDP4_RECEIVE_DATA *RxData
1385 )
1386 {
1387 EFI_STATUS Status;
1388 UDP4_RXDATA_WRAP *Wrap;
1389
1390 //
1391 // Allocate buffer for the Wrap.
1392 //
1393 Wrap = AllocatePool (sizeof (UDP4_RXDATA_WRAP) +
1394 (Packet->BlockOpNum - 1) * sizeof (EFI_UDP4_FRAGMENT_DATA));
1395 if (Wrap == NULL) {
1396 return NULL;
1397 }
1398
1399 InitializeListHead (&Wrap->Link);
1400
1401 CopyMem (&Wrap->RxData, RxData, sizeof (Wrap->RxData));
1402
1403 //
1404 // Create the Recycle event.
1405 //
1406 Status = gBS->CreateEvent (
1407 EVT_NOTIFY_SIGNAL,
1408 TPL_NOTIFY,
1409 Udp4RecycleRxDataWrap,
1410 Wrap,
1411 &Wrap->RxData.RecycleSignal
1412 );
1413 if (EFI_ERROR (Status)) {
1414 gBS->FreePool (Wrap);
1415 return NULL;
1416 }
1417
1418 Wrap->Packet = Packet;
1419 Wrap->TimeoutTick = Instance->ConfigData.ReceiveTimeout;
1420
1421 return Wrap;
1422 }
1423
1424
1425 /**
1426 This function enqueues the received datagram into the instances' receiving queues.
1427
1428 @param[in] Udp4Service Pointer to the udp service context data.
1429 @param[in] Packet Pointer to the buffer containing the received
1430 datagram.
1431 @param[in] RxData Pointer to the EFI_UDP4_RECEIVE_DATA of this
1432 datagram.
1433
1434 @return The times this datagram is enqueued.
1435
1436 **/
1437 UINTN
1438 Udp4EnqueueDgram (
1439 IN UDP4_SERVICE_DATA *Udp4Service,
1440 IN NET_BUF *Packet,
1441 IN EFI_UDP4_RECEIVE_DATA *RxData
1442 )
1443 {
1444 LIST_ENTRY *Entry;
1445 UDP4_INSTANCE_DATA *Instance;
1446 UDP4_RXDATA_WRAP *Wrap;
1447 UINTN Enqueued;
1448
1449 Enqueued = 0;
1450
1451 NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {
1452 //
1453 // Iterate the instances.
1454 //
1455 Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);
1456
1457 if (!Instance->Configured) {
1458 continue;
1459 }
1460
1461 if (Udp4MatchDgram (Instance, &RxData->UdpSession)) {
1462 //
1463 // Wrap the RxData and put this Wrap into the instances RcvdDgramQue.
1464 //
1465 Wrap = Udp4WrapRxData (Instance, Packet, RxData);
1466 if (Wrap == NULL) {
1467 continue;
1468 }
1469
1470 NET_GET_REF (Packet);
1471
1472 InsertTailList (&Instance->RcvdDgramQue, &Wrap->Link);
1473
1474 Enqueued++;
1475 }
1476 }
1477
1478 return Enqueued;
1479 }
1480
1481
1482 /**
1483 This function delivers the received datagrams for the specified instance.
1484
1485 @param[in] Instance Pointer to the instance context data.
1486
1487 **/
1488 VOID
1489 Udp4InstanceDeliverDgram (
1490 IN UDP4_INSTANCE_DATA *Instance
1491 )
1492 {
1493 UDP4_RXDATA_WRAP *Wrap;
1494 EFI_UDP4_COMPLETION_TOKEN *Token;
1495 NET_BUF *Dup;
1496 EFI_UDP4_RECEIVE_DATA *RxData;
1497 EFI_TPL OldTpl;
1498
1499 if (!IsListEmpty (&Instance->RcvdDgramQue) &&
1500 !NetMapIsEmpty (&Instance->RxTokens)) {
1501
1502 Wrap = NET_LIST_HEAD (&Instance->RcvdDgramQue, UDP4_RXDATA_WRAP, Link);
1503
1504 if (NET_BUF_SHARED (Wrap->Packet)) {
1505 //
1506 // Duplicate the Packet if it is shared between instances.
1507 //
1508 Dup = NetbufDuplicate (Wrap->Packet, NULL, 0);
1509 if (Dup == NULL) {
1510 return;
1511 }
1512
1513 NetbufFree (Wrap->Packet);
1514
1515 Wrap->Packet = Dup;
1516 }
1517
1518 NetListRemoveHead (&Instance->RcvdDgramQue);
1519
1520 Token = (EFI_UDP4_COMPLETION_TOKEN *) NetMapRemoveHead (&Instance->RxTokens, NULL);
1521
1522 //
1523 // Build the FragmentTable and set the FragmentCount in RxData.
1524 //
1525 RxData = &Wrap->RxData;
1526 RxData->FragmentCount = Wrap->Packet->BlockOpNum;
1527
1528 NetbufBuildExt (
1529 Wrap->Packet,
1530 (NET_FRAGMENT *) RxData->FragmentTable,
1531 &RxData->FragmentCount
1532 );
1533
1534 Token->Status = EFI_SUCCESS;
1535 Token->Packet.RxData = &Wrap->RxData;
1536
1537 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
1538 InsertTailList (&Instance->DeliveredDgramQue, &Wrap->Link);
1539 gBS->RestoreTPL (OldTpl);
1540
1541 gBS->SignalEvent (Token->Event);
1542 }
1543 }
1544
1545
1546 /**
1547 This function delivers the datagrams enqueued in the instances.
1548
1549 @param[in] Udp4Service Pointer to the udp service context data.
1550
1551 **/
1552 VOID
1553 Udp4DeliverDgram (
1554 IN UDP4_SERVICE_DATA *Udp4Service
1555 )
1556 {
1557 LIST_ENTRY *Entry;
1558 UDP4_INSTANCE_DATA *Instance;
1559
1560 NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {
1561 //
1562 // Iterate the instances.
1563 //
1564 Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);
1565
1566 if (!Instance->Configured) {
1567 continue;
1568 }
1569
1570 //
1571 // Deliver the datagrams of this instance.
1572 //
1573 Udp4InstanceDeliverDgram (Instance);
1574 }
1575 }
1576
1577
1578 /**
1579 This function demultiplexes the received udp datagram to the apropriate instances.
1580
1581 @param[in] Udp4Service Pointer to the udp service context data.
1582 @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA abstrated from
1583 the received datagram.
1584 @param[in] Packet Pointer to the buffer containing the received udp
1585 datagram.
1586
1587 **/
1588 VOID
1589 Udp4Demultiplex (
1590 IN UDP4_SERVICE_DATA *Udp4Service,
1591 IN EFI_NET_SESSION_DATA *NetSession,
1592 IN NET_BUF *Packet
1593 )
1594 {
1595 EFI_UDP4_HEADER *Udp4Header;
1596 UINT16 HeadSum;
1597 EFI_UDP4_RECEIVE_DATA RxData;
1598 EFI_UDP4_SESSION_DATA *Udp4Session;
1599 UINTN Enqueued;
1600
1601 //
1602 // Get the datagram header from the packet buffer.
1603 //
1604 Udp4Header = (EFI_UDP4_HEADER *) NetbufGetByte (Packet, 0, NULL);
1605
1606 if (Udp4Header->Checksum != 0) {
1607 //
1608 // check the checksum.
1609 //
1610 HeadSum = NetPseudoHeadChecksum (
1611 NetSession->Source,
1612 NetSession->Dest,
1613 EFI_IP_PROTO_UDP,
1614 0
1615 );
1616
1617 if (Udp4Checksum (Packet, HeadSum) != 0) {
1618 //
1619 // Wrong checksum.
1620 //
1621 return;
1622 }
1623 }
1624
1625 gRT->GetTime (&RxData.TimeStamp, NULL);
1626
1627 Udp4Session = &RxData.UdpSession;
1628 Udp4Session->SourcePort = NTOHS (Udp4Header->SrcPort);
1629 Udp4Session->DestinationPort = NTOHS (Udp4Header->DstPort);
1630
1631 CopyMem (&Udp4Session->SourceAddress, &NetSession->Source, sizeof (EFI_IPv4_ADDRESS));
1632 CopyMem (&Udp4Session->DestinationAddress, &NetSession->Dest, sizeof (EFI_IPv4_ADDRESS));
1633
1634 //
1635 // Trim the UDP header.
1636 //
1637 NetbufTrim (Packet, UDP4_HEADER_SIZE, TRUE);
1638
1639 RxData.DataLength = (UINT32) Packet->TotalSize;
1640
1641 //
1642 // Try to enqueue this datagram into the instances.
1643 //
1644 Enqueued = Udp4EnqueueDgram (Udp4Service, Packet, &RxData);
1645
1646 if (Enqueued == 0) {
1647 //
1648 // Send the port unreachable ICMP packet before we free this NET_BUF
1649 //
1650 Udp4SendPortUnreach (Udp4Service->IpIo, NetSession, Udp4Header);
1651 }
1652
1653 //
1654 // Try to free the packet before deliver it.
1655 //
1656 NetbufFree (Packet);
1657
1658 if (Enqueued > 0) {
1659 //
1660 // Deliver the datagram.
1661 //
1662 Udp4DeliverDgram (Udp4Service);
1663 }
1664 }
1665
1666
1667 /**
1668 This function builds and sends out a icmp port unreachable message.
1669
1670 @param[in] IpIo Pointer to the IP_IO instance.
1671 @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA of the packet
1672 causes this icmp error message.
1673 @param[in] Udp4Header Pointer to the udp header of the datagram causes
1674 this icmp error message.
1675
1676 **/
1677 VOID
1678 Udp4SendPortUnreach (
1679 IN IP_IO *IpIo,
1680 IN EFI_NET_SESSION_DATA *NetSession,
1681 IN VOID *Udp4Header
1682 )
1683 {
1684 NET_BUF *Packet;
1685 UINT32 Len;
1686 IP4_ICMP_ERROR_HEAD *IcmpErrHdr;
1687 EFI_IP4_HEADER *IpHdr;
1688 UINT8 *Ptr;
1689 IP_IO_OVERRIDE Override;
1690 IP_IO_IP_INFO *IpSender;
1691
1692 IpSender = IpIoFindSender (&IpIo, NetSession->Dest);
1693 if (IpSender == NULL) {
1694 //
1695 // No apropriate sender, since we cannot send out the ICMP message through
1696 // the default zero station address IP instance, abort.
1697 //
1698 return;
1699 }
1700
1701 IpHdr = NetSession->IpHdr;
1702
1703 //
1704 // Calculate the requried length of the icmp error message.
1705 //
1706 Len = sizeof (IP4_ICMP_ERROR_HEAD) + (EFI_IP4_HEADER_LEN (IpHdr) -
1707 sizeof (IP4_HEAD)) + ICMP_ERROR_PACKET_LENGTH;
1708
1709 //
1710 // Allocate buffer for the icmp error message.
1711 //
1712 Packet = NetbufAlloc (Len);
1713 if (Packet == NULL) {
1714 return;
1715 }
1716
1717 //
1718 // Allocate space for the IP4_ICMP_ERROR_HEAD.
1719 //
1720 IcmpErrHdr = (IP4_ICMP_ERROR_HEAD *) NetbufAllocSpace (Packet, Len, FALSE);
1721 ASSERT (IcmpErrHdr != NULL);
1722
1723 //
1724 // Set the required fields for the icmp port unreachable message.
1725 //
1726 IcmpErrHdr->Head.Type = ICMP_TYPE_UNREACH;
1727 IcmpErrHdr->Head.Code = ICMP_CODE_UNREACH_PORT;
1728 IcmpErrHdr->Head.Checksum = 0;
1729 IcmpErrHdr->Fourth = 0;
1730
1731 //
1732 // Copy the IP header of the datagram tragged the error.
1733 //
1734 CopyMem (&IcmpErrHdr->IpHead, IpHdr, EFI_IP4_HEADER_LEN (IpHdr));
1735
1736 //
1737 // Copy the UDP header.
1738 //
1739 Ptr = (UINT8 *) &IcmpErrHdr->IpHead + EFI_IP4_HEADER_LEN (IpHdr);
1740 CopyMem (Ptr, Udp4Header, ICMP_ERROR_PACKET_LENGTH);
1741
1742 //
1743 // Calculate the checksum.
1744 //
1745 IcmpErrHdr->Head.Checksum = (UINT16) ~(NetbufChecksum (Packet));
1746
1747 //
1748 // Fill the override data.
1749 //
1750 Override.DoNotFragment = FALSE;
1751 Override.TypeOfService = 0;
1752 Override.TimeToLive = 255;
1753 Override.Protocol = EFI_IP_PROTO_ICMP;
1754
1755 CopyMem (&Override.SourceAddress, &NetSession->Dest, sizeof (EFI_IPv4_ADDRESS));
1756 ZeroMem (&Override.GatewayAddress, sizeof (EFI_IPv4_ADDRESS));
1757
1758 //
1759 // Send out this icmp packet.
1760 //
1761 IpIoSend (IpIo, Packet, IpSender, NULL, NULL, NetSession->Source, &Override);
1762
1763 NetbufFree (Packet);
1764 }
1765
1766
1767 /**
1768 This function handles the received Icmp Error message and demultiplexes it to the
1769 instance.
1770
1771 @param[in] Udp4Service Pointer to the udp service context data.
1772 @param[in] IcmpError The icmp error code.
1773 @param[in] NetSession Pointer to the EFI_NET_SESSION_DATA abstracted
1774 from the received Icmp Error packet.
1775 @param[in] Packet Pointer to the Icmp Error packet.
1776
1777 **/
1778 VOID
1779 Udp4IcmpHandler (
1780 IN UDP4_SERVICE_DATA *Udp4Service,
1781 IN ICMP_ERROR IcmpError,
1782 IN EFI_NET_SESSION_DATA *NetSession,
1783 IN NET_BUF *Packet
1784 )
1785 {
1786 EFI_UDP4_HEADER *Udp4Header;
1787 EFI_UDP4_SESSION_DATA Udp4Session;
1788 LIST_ENTRY *Entry;
1789 UDP4_INSTANCE_DATA *Instance;
1790
1791 Udp4Header = (EFI_UDP4_HEADER *) NetbufGetByte (Packet, 0, NULL);
1792
1793 CopyMem (&Udp4Session.SourceAddress, &NetSession->Source, sizeof (EFI_IPv4_ADDRESS));
1794 CopyMem (&Udp4Session.DestinationAddress, &NetSession->Dest, sizeof (EFI_IPv4_ADDRESS));
1795
1796 Udp4Session.SourcePort = NTOHS (Udp4Header->DstPort);
1797 Udp4Session.DestinationPort = NTOHS (Udp4Header->SrcPort);
1798
1799 NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {
1800 //
1801 // Iterate all the instances.
1802 //
1803 Instance = NET_LIST_USER_STRUCT (Entry, UDP4_INSTANCE_DATA, Link);
1804
1805 if (!Instance->Configured ||
1806 Instance->ConfigData.AcceptPromiscuous ||
1807 Instance->ConfigData.AcceptAnyPort ||
1808 EFI_IP4_EQUAL (&Instance->ConfigData.StationAddress, &mZeroIp4Addr)
1809 ) {
1810 //
1811 // Don't try to deliver the ICMP error to this instance if it is not configured,
1812 // or it's configured to be promiscuous or accept any port or accept all the
1813 // datagrams.
1814 //
1815 continue;
1816 }
1817
1818 if (Udp4MatchDgram (Instance, &Udp4Session)) {
1819 //
1820 // Translate the Icmp Error code according to the udp spec.
1821 //
1822 Instance->IcmpError = IpIoGetIcmpErrStatus (IcmpError, NULL, NULL);
1823
1824 if (IcmpError > ICMP_ERR_UNREACH_PORT) {
1825 Instance->IcmpError = EFI_ICMP_ERROR;
1826 }
1827
1828 //
1829 // Notify the instance with the received Icmp Error.
1830 //
1831 Udp4ReportIcmpError (Instance);
1832
1833 break;
1834 }
1835 }
1836
1837 NetbufFree (Packet);
1838 }
1839
1840
1841 /**
1842 This function reports the received ICMP error.
1843
1844 @param[in] Instance Pointer to the udp instance context data.
1845
1846 **/
1847 VOID
1848 Udp4ReportIcmpError (
1849 IN UDP4_INSTANCE_DATA *Instance
1850 )
1851 {
1852 EFI_UDP4_COMPLETION_TOKEN *Token;
1853
1854 if (NetMapIsEmpty (&Instance->RxTokens)) {
1855 //
1856 // There are no receive tokens to deliver the ICMP error.
1857 //
1858 return;
1859 }
1860
1861 if (EFI_ERROR (Instance->IcmpError)) {
1862 //
1863 // Try to get a RxToken from the RxTokens map.
1864 //
1865 Token = (EFI_UDP4_COMPLETION_TOKEN *) NetMapRemoveHead (&Instance->RxTokens, NULL);
1866
1867 if (Token != NULL) {
1868 //
1869 // Report the error through the Token.
1870 //
1871 Token->Status = Instance->IcmpError;
1872 gBS->SignalEvent (Token->Event);
1873
1874 //
1875 // Clear the IcmpError.
1876 //
1877 Instance->IcmpError = EFI_SUCCESS;
1878 }
1879 }
1880 }
1881
1882
1883 /**
1884 This function is a dummy ext-free function for the NET_BUF created for the output
1885 udp datagram.
1886
1887 @param[in] Context Pointer to the context data.
1888
1889 **/
1890 VOID
1891 Udp4NetVectorExtFree (
1892 VOID *Context
1893 )
1894 {
1895 }
1896
1897
1898 /**
1899 Set the Udp4 variable data.
1900
1901 @param Udp4Service Udp4 service data.
1902
1903 @retval EFI_OUT_OF_RESOURCES There are not enough resources to set the
1904 variable.
1905 @retval EFI_SUCCESS Set variable successfully.
1906 @retval other Set variable failed.
1907
1908 **/
1909 EFI_STATUS
1910 Udp4SetVariableData (
1911 IN UDP4_SERVICE_DATA *Udp4Service
1912 )
1913 {
1914 UINT32 NumConfiguredInstance;
1915 LIST_ENTRY *Entry;
1916 UINTN VariableDataSize;
1917 EFI_UDP4_VARIABLE_DATA *Udp4VariableData;
1918 EFI_UDP4_SERVICE_POINT *Udp4ServicePoint;
1919 UDP4_INSTANCE_DATA *Udp4Instance;
1920 CHAR16 *NewMacString;
1921 EFI_STATUS Status;
1922
1923 NumConfiguredInstance = 0;
1924
1925 //
1926 // Go through the children list to count the configured children.
1927 //
1928 NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {
1929 Udp4Instance = NET_LIST_USER_STRUCT_S (
1930 Entry,
1931 UDP4_INSTANCE_DATA,
1932 Link,
1933 UDP4_INSTANCE_DATA_SIGNATURE
1934 );
1935
1936 if (Udp4Instance->Configured) {
1937 NumConfiguredInstance++;
1938 }
1939 }
1940
1941 //
1942 // Calculate the size of the Udp4VariableData. As there may be no Udp4 child,
1943 // we should add extra buffer for the service points only if the number of configured
1944 // children is more than 1.
1945 //
1946 VariableDataSize = sizeof (EFI_UDP4_VARIABLE_DATA);
1947
1948 if (NumConfiguredInstance > 1) {
1949 VariableDataSize += sizeof (EFI_UDP4_SERVICE_POINT) * (NumConfiguredInstance - 1);
1950 }
1951
1952 Udp4VariableData = AllocatePool (VariableDataSize);
1953 if (Udp4VariableData == NULL) {
1954 return EFI_OUT_OF_RESOURCES;
1955 }
1956
1957 Udp4VariableData->DriverHandle = Udp4Service->ImageHandle;
1958 Udp4VariableData->ServiceCount = NumConfiguredInstance;
1959
1960 Udp4ServicePoint = &Udp4VariableData->Services[0];
1961
1962 //
1963 // Go through the children list to fill the configured children's address pairs.
1964 //
1965 NET_LIST_FOR_EACH (Entry, &Udp4Service->ChildrenList) {
1966 Udp4Instance = NET_LIST_USER_STRUCT_S (
1967 Entry,
1968 UDP4_INSTANCE_DATA,
1969 Link,
1970 UDP4_INSTANCE_DATA_SIGNATURE
1971 );
1972
1973 if (Udp4Instance->Configured) {
1974 Udp4ServicePoint->InstanceHandle = Udp4Instance->ChildHandle;
1975 Udp4ServicePoint->LocalAddress = Udp4Instance->ConfigData.StationAddress;
1976 Udp4ServicePoint->LocalPort = Udp4Instance->ConfigData.StationPort;
1977 Udp4ServicePoint->RemoteAddress = Udp4Instance->ConfigData.RemoteAddress;
1978 Udp4ServicePoint->RemotePort = Udp4Instance->ConfigData.RemotePort;
1979
1980 Udp4ServicePoint++;
1981 }
1982 }
1983
1984 //
1985 // Get the mac string.
1986 //
1987 Status = NetLibGetMacString (
1988 Udp4Service->ControllerHandle,
1989 Udp4Service->ImageHandle,
1990 &NewMacString
1991 );
1992 if (EFI_ERROR (Status)) {
1993 goto ON_ERROR;
1994 }
1995
1996 if (Udp4Service->MacString != NULL) {
1997 //
1998 // The variable is set already, we're going to update it.
1999 //
2000 if (StrCmp (Udp4Service->MacString, NewMacString) != 0) {
2001 //
2002 // The mac address is changed, delete the previous variable first.
2003 //
2004 gRT->SetVariable (
2005 Udp4Service->MacString,
2006 &gEfiUdp4ServiceBindingProtocolGuid,
2007 EFI_VARIABLE_BOOTSERVICE_ACCESS,
2008 0,
2009 NULL
2010 );
2011 }
2012
2013 gBS->FreePool (Udp4Service->MacString);
2014 }
2015
2016 Udp4Service->MacString = NewMacString;
2017
2018 Status = gRT->SetVariable (
2019 Udp4Service->MacString,
2020 &gEfiUdp4ServiceBindingProtocolGuid,
2021 EFI_VARIABLE_BOOTSERVICE_ACCESS,
2022 VariableDataSize,
2023 (VOID *) Udp4VariableData
2024 );
2025
2026 ON_ERROR:
2027
2028 gBS->FreePool (Udp4VariableData);
2029
2030 return Status;
2031 }
2032
2033
2034 /**
2035 Clear the variable and free the resource.
2036
2037 @param[[in] Udp4Service Udp4 service data.
2038
2039 **/
2040 VOID
2041 Udp4ClearVariableData (
2042 IN UDP4_SERVICE_DATA *Udp4Service
2043 )
2044 {
2045 ASSERT (Udp4Service->MacString != NULL);
2046
2047 gRT->SetVariable (
2048 Udp4Service->MacString,
2049 &gEfiUdp4ServiceBindingProtocolGuid,
2050 EFI_VARIABLE_BOOTSERVICE_ACCESS,
2051 0,
2052 NULL
2053 );
2054
2055 gBS->FreePool (Udp4Service->MacString);
2056 Udp4Service->MacString = NULL;
2057 }