]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/MnpDxe/MnpIo.c
Import SnpDxe, Tcp4Dxe, Udp4Dxe and MnpDxe.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / MnpDxe / MnpIo.c
CommitLineData
8a67d61d 1/** @file\r
2\r
3Copyright (c) 2005 - 2007, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 MnpIo.c\r
15\r
16Abstract:\r
17\r
18 Implementation of Managed Network Protocol I/O functions.\r
19\r
20\r
21**/\r
22\r
23#include <Library/NetLib.h>\r
24#include <Library/BaseMemoryLib.h>\r
25#include <Library/BaseLib.h>\r
26#include <Library/MemoryAllocationLib.h>\r
27#include "MnpImpl.h"\r
28\r
29\r
30/**\r
31 Validates the Mnp transmit token.\r
32\r
33 @param Instance Pointer to the Mnp instance context data.\r
34 @param Token Pointer to the transmit token to check.\r
35\r
36 @return The Token is valid or not.\r
37\r
38**/\r
39BOOLEAN\r
40MnpIsValidTxToken (\r
41 IN MNP_INSTANCE_DATA *Instance,\r
42 IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token\r
43 )\r
44{\r
45 MNP_SERVICE_DATA *MnpServiceData;\r
46 EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
47 EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData;\r
48 UINT32 Index;\r
49 UINT32 TotalLength;\r
50 EFI_MANAGED_NETWORK_FRAGMENT_DATA *FragmentTable;\r
51\r
52 MnpServiceData = Instance->MnpServiceData;\r
53 NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
54\r
55 SnpMode = MnpServiceData->Snp->Mode;\r
56 TxData = Token->Packet.TxData;\r
57\r
58 if ((Token->Event == NULL) || (TxData == NULL) || (TxData->FragmentCount == 0)) {\r
59 //\r
60 // The token is invalid if the Event is NULL, or the TxData is NULL, or\r
61 // the fragment count is zero.\r
62 //\r
63 MNP_DEBUG_WARN (("MnpIsValidTxToken: Invalid Token.\n"));\r
64 return FALSE;\r
65 }\r
66\r
67 if ((TxData->DestinationAddress != NULL) && (TxData->HeaderLength != 0)) {\r
68 //\r
69 // The token is invalid if the HeaderLength isn't zero while the DestinationAddress\r
70 // is NULL (The destination address is already put into the packet).\r
71 //\r
72 MNP_DEBUG_WARN (("MnpIsValidTxToken: DestinationAddress isn't NULL, HeaderLength must be 0.\n"));\r
73 return FALSE;\r
74 }\r
75\r
76 TotalLength = 0;\r
77 FragmentTable = TxData->FragmentTable;\r
78 for (Index = 0; Index < TxData->FragmentCount; Index++) {\r
79\r
80 if ((FragmentTable[Index].FragmentLength == 0) || (FragmentTable[Index].FragmentBuffer == NULL)) {\r
81 //\r
82 // The token is invalid if any FragmentLength is zero or any FragmentBuffer is NULL.\r
83 //\r
84 MNP_DEBUG_WARN (("MnpIsValidTxToken: Invalid FragmentLength or FragmentBuffer.\n"));\r
85 return FALSE;\r
86 }\r
87\r
88 TotalLength += FragmentTable[Index].FragmentLength;\r
89 }\r
90\r
91 if ((TxData->DestinationAddress == NULL) && (FragmentTable[0].FragmentLength < TxData->HeaderLength)) {\r
92 //\r
93 // Media header is split between fragments.\r
94 //\r
95 return FALSE;\r
96 }\r
97\r
98 if (TotalLength != (TxData->DataLength + TxData->HeaderLength)) {\r
99 //\r
100 // The length calculated from the fragment information doesn't equal to the\r
101 // sum of the DataLength and the HeaderLength.\r
102 //\r
103 MNP_DEBUG_WARN (("MnpIsValidTxData: Invalid Datalength compared with the sum of fragment length.\n"));\r
104 return FALSE;\r
105 }\r
106\r
107 if (TxData->DataLength > MnpServiceData->Mtu) {\r
108 //\r
109 // The total length is larger than the MTU.\r
110 //\r
111 MNP_DEBUG_WARN (("MnpIsValidTxData: TxData->DataLength exceeds Mtu.\n"));\r
112 return FALSE;\r
113 }\r
114\r
115 return TRUE;\r
116}\r
117\r
118\r
119/**\r
120 Build the packet to transmit from the TxData passed in.\r
121\r
122 @param MnpServiceData Pointer to the mnp service context data.\r
123 @param TxData Pointer to the transmit data containing the\r
124 information to build the packet.\r
125 @param PktBuf Pointer to record the address of the packet.\r
126 @param PktLen Pointer to a UINT32 variable used to record the\r
127 packet's length.\r
128\r
129 @return None.\r
130\r
131**/\r
132VOID\r
133MnpBuildTxPacket (\r
134 IN MNP_SERVICE_DATA *MnpServiceData,\r
135 IN EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData,\r
136 OUT UINT8 **PktBuf,\r
137 OUT UINT32 *PktLen\r
138 )\r
139{\r
140 EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
141 UINT8 *DstPos;\r
142 UINT16 Index;\r
143\r
144 if ((TxData->DestinationAddress == NULL) && (TxData->FragmentCount == 1)) {\r
145 //\r
146 // Media header is in FragmentTable and there is only one fragment,\r
147 // use fragment buffer directly.\r
148 //\r
149 *PktBuf = TxData->FragmentTable[0].FragmentBuffer;\r
150 *PktLen = TxData->FragmentTable[0].FragmentLength;\r
151 } else {\r
152 //\r
153 // Either media header isn't in FragmentTable or there is more than\r
154 // one fragment, copy the data into the packet buffer. Reserve the\r
155 // media header space if necessary.\r
156 //\r
157 SnpMode = MnpServiceData->Snp->Mode;\r
158 DstPos = MnpServiceData->TxBuf;\r
159\r
160 *PktLen = 0;\r
161 if (TxData->DestinationAddress != NULL) {\r
162 //\r
163 // If dest address is not NULL, move DstPos to reserve space for the\r
164 // media header. Add the media header length to buflen.\r
165 //\r
166 DstPos += SnpMode->MediaHeaderSize;\r
167 *PktLen += SnpMode->MediaHeaderSize;\r
168 }\r
169\r
170 for (Index = 0; Index < TxData->FragmentCount; Index++) {\r
171 //\r
172 // Copy the data.\r
173 //\r
174 NetCopyMem (\r
175 DstPos,\r
176 TxData->FragmentTable[Index].FragmentBuffer,\r
177 TxData->FragmentTable[Index].FragmentLength\r
178 );\r
179 DstPos += TxData->FragmentTable[Index].FragmentLength;\r
180 }\r
181\r
182 //\r
183 // Set the buffer pointer and the buffer length.\r
184 //\r
185 *PktBuf = MnpServiceData->TxBuf;\r
186 *PktLen += TxData->DataLength + TxData->HeaderLength;\r
187 }\r
188}\r
189\r
190\r
191/**\r
192 Synchronously send out the packet.\r
193\r
194 @param MnpServiceData Pointer to the mnp service context data.\r
195 @param Packet Pointer to the pakcet buffer.\r
196 @param Length The length of the packet.\r
197 @param Token Pointer to the token the packet generated from.\r
198\r
199 @retval EFI_SUCCESS The packet is sent out.\r
200 @retval EFI_TIMEOUT Time out occurs, the packet isn't sent.\r
201 @retval EFI_DEVICE_ERROR An unexpected network error occurs.\r
202\r
203**/\r
204EFI_STATUS\r
205MnpSyncSendPacket (\r
206 IN MNP_SERVICE_DATA *MnpServiceData,\r
207 IN UINT8 *Packet,\r
208 IN UINT32 Length,\r
209 IN EFI_MANAGED_NETWORK_COMPLETION_TOKEN *Token\r
210 )\r
211{\r
212 EFI_STATUS Status;\r
213 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
214 EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData;\r
215 UINT32 HeaderSize;\r
216 UINT8 *TxBuf;\r
217\r
218 Snp = MnpServiceData->Snp;\r
219 TxData = Token->Packet.TxData;\r
220\r
221 HeaderSize = Snp->Mode->MediaHeaderSize - TxData->HeaderLength;\r
222\r
223 //\r
224 // Start the timeout event.\r
225 //\r
226 Status = gBS->SetTimer (\r
227 MnpServiceData->TxTimeoutEvent,\r
228 TimerRelative,\r
229 MNP_TX_TIMEOUT_TIME\r
230 );\r
231 if (EFI_ERROR (Status)) {\r
232\r
233 goto SIGNAL_TOKEN;\r
234 }\r
235\r
236 for (;;) {\r
237 //\r
238 // Transmit the packet through SNP.\r
239 //\r
240 Status = Snp->Transmit (\r
241 Snp,\r
242 HeaderSize,\r
243 Length,\r
244 Packet,\r
245 TxData->SourceAddress,\r
246 TxData->DestinationAddress,\r
247 &TxData->ProtocolType\r
248 );\r
249 if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) {\r
250\r
251 Status = EFI_DEVICE_ERROR;\r
252 break;\r
253 }\r
254\r
255 //\r
256 // If Status is EFI_SUCCESS, the packet is put in the transmit queue.\r
257 // if Status is EFI_NOT_READY, the transmit engine of the network interface is busy.\r
258 // Both need to sync SNP.\r
259 //\r
260 TxBuf = NULL;\r
261 do {\r
262 //\r
263 // Get the recycled transmit buffer status.\r
264 //\r
265 Snp->GetStatus (Snp, NULL, &TxBuf);\r
266\r
267 if (!EFI_ERROR (gBS->CheckEvent (MnpServiceData->TxTimeoutEvent))) {\r
268\r
269 Status = EFI_TIMEOUT;\r
270 break;\r
271 }\r
272 } while (TxBuf == NULL);\r
273\r
274 if ((Status == EFI_SUCCESS) || (Status == EFI_TIMEOUT)) {\r
275\r
276 break;\r
277 } else {\r
278 //\r
279 // Status is EFI_NOT_READY. Restart the timer event and call Snp->Transmit again.\r
280 //\r
281 gBS->SetTimer (\r
282 MnpServiceData->TxTimeoutEvent,\r
283 TimerRelative,\r
284 MNP_TX_TIMEOUT_TIME\r
285 );\r
286 }\r
287 }\r
288\r
289 //\r
290 // Cancel the timer event.\r
291 //\r
292 gBS->SetTimer (MnpServiceData->TxTimeoutEvent, TimerCancel, 0);\r
293\r
294SIGNAL_TOKEN:\r
295\r
296 Token->Status = Status;\r
297 gBS->SignalEvent (Token->Event);\r
298\r
299 return EFI_SUCCESS;\r
300}\r
301\r
302\r
303/**\r
304 Try to deliver the received packet to the instance.\r
305\r
306 @param Instance Pointer to the mnp instance context data.\r
307\r
308 @retval EFI_SUCCESS The received packet is delivered, or there is no\r
309 packet to deliver, or there is no available receive\r
310 token.\r
311 @retval EFI_OUT_OF_RESOURCES The deliver fails due to lack of memory resource.\r
312\r
313**/\r
314EFI_STATUS\r
315MnpInstanceDeliverPacket (\r
316 IN MNP_INSTANCE_DATA *Instance\r
317 )\r
318{\r
319 MNP_SERVICE_DATA *MnpServiceData;\r
320 MNP_RXDATA_WRAP *RxDataWrap;\r
321 NET_BUF *DupNbuf;\r
322 EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData;\r
323 EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
324 EFI_MANAGED_NETWORK_COMPLETION_TOKEN *RxToken;\r
325\r
326 MnpServiceData = Instance->MnpServiceData;\r
327 NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
328\r
329 if (NetMapIsEmpty (&Instance->RxTokenMap) || NetListIsEmpty (&Instance->RcvdPacketQueue)) {\r
330 //\r
331 // No pending received data or no available receive token, return.\r
332 //\r
333 return EFI_SUCCESS;\r
334 }\r
335\r
336 ASSERT (Instance->RcvdPacketQueueSize != 0);\r
337\r
338 RxDataWrap = NET_LIST_HEAD (&Instance->RcvdPacketQueue, MNP_RXDATA_WRAP, WrapEntry);\r
339 if (RxDataWrap->Nbuf->RefCnt > 2) {\r
340 //\r
341 // There are other instances share this Nbuf, duplicate to get a\r
342 // copy to allow the instance to do R/W operations.\r
343 //\r
344 DupNbuf = MnpAllocNbuf (MnpServiceData);\r
345 if (DupNbuf == NULL) {\r
346 MNP_DEBUG_WARN (("MnpDeliverPacket: Failed to allocate a free Nbuf.\n"));\r
347\r
348 return EFI_OUT_OF_RESOURCES;\r
349 }\r
350\r
351 //\r
352 // Duplicate the net buffer.\r
353 //\r
354 NetbufDuplicate (RxDataWrap->Nbuf, DupNbuf, 0);\r
355 MnpFreeNbuf (MnpServiceData, RxDataWrap->Nbuf);\r
356 RxDataWrap->Nbuf = DupNbuf;\r
357 }\r
358\r
359 //\r
360 // All resources are OK, remove the packet from the queue.\r
361 //\r
362 NetListRemoveHead (&Instance->RcvdPacketQueue);\r
363 Instance->RcvdPacketQueueSize--;\r
364\r
365 RxData = &RxDataWrap->RxData;\r
366 SnpMode = MnpServiceData->Snp->Mode;\r
367\r
368 //\r
369 // Set all the buffer pointers.\r
370 //\r
371 RxData->MediaHeader = NetbufGetByte (RxDataWrap->Nbuf, 0, NULL);\r
372 RxData->DestinationAddress = RxData->MediaHeader;\r
373 RxData->SourceAddress = (UINT8 *) RxData->MediaHeader + SnpMode->HwAddressSize;\r
374 RxData->PacketData = (UINT8 *) RxData->MediaHeader + SnpMode->MediaHeaderSize;\r
375\r
376 //\r
377 // Insert this RxDataWrap into the delivered queue.\r
378 //\r
379 NetListInsertTail (&Instance->RxDeliveredPacketQueue, &RxDataWrap->WrapEntry);\r
380\r
381 //\r
382 // Get the receive token from the RxTokenMap.\r
383 //\r
384 RxToken = NetMapRemoveHead (&Instance->RxTokenMap, NULL);\r
385\r
386 //\r
387 // Signal this token's event.\r
388 //\r
389 RxToken->Packet.RxData = &RxDataWrap->RxData;\r
390 RxToken->Status = EFI_SUCCESS;\r
391 gBS->SignalEvent (RxToken->Event);\r
392\r
393 return EFI_SUCCESS;\r
394}\r
395\r
396\r
397/**\r
398 Deliver the received packet for the instances belonging to the MnpServiceData.\r
399\r
400 @param MnpServiceData Pointer to the mnp service context data.\r
401\r
402 @return None.\r
403\r
404**/\r
405STATIC\r
406VOID\r
407MnpDeliverPacket (\r
408 IN MNP_SERVICE_DATA *MnpServiceData\r
409 )\r
410{\r
411 NET_LIST_ENTRY *Entry;\r
412 MNP_INSTANCE_DATA *Instance;\r
413\r
414 NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
415\r
416 NET_LIST_FOR_EACH (Entry, &MnpServiceData->ChildrenList) {\r
417 Instance = NET_LIST_USER_STRUCT (Entry, MNP_INSTANCE_DATA, InstEntry);\r
418 NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
419\r
420 //\r
421 // Try to deliver packet for this instance.\r
422 //\r
423 MnpInstanceDeliverPacket (Instance);\r
424 }\r
425}\r
426\r
427\r
428/**\r
429 Recycle the RxData and other resources used to hold and deliver the received\r
430 packet.\r
431\r
432 @param Event The event this notify function registered to.\r
433 @param Context Pointer to the context data registerd to the Event.\r
434\r
435 @return None.\r
436\r
437**/\r
438VOID\r
439EFIAPI\r
440MnpRecycleRxData (\r
441 IN EFI_EVENT Event,\r
442 IN VOID *Context\r
443 )\r
444{\r
445 MNP_RXDATA_WRAP *RxDataWrap;\r
446 MNP_SERVICE_DATA *MnpServiceData;\r
447\r
448 ASSERT (Context != NULL);\r
449\r
450 RxDataWrap = (MNP_RXDATA_WRAP *) Context;\r
451 NET_CHECK_SIGNATURE (RxDataWrap->Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
452\r
453 ASSERT (RxDataWrap->Nbuf != NULL);\r
454\r
455 MnpServiceData = RxDataWrap->Instance->MnpServiceData;\r
456 NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
457\r
458 //\r
459 // Free this Nbuf.\r
460 //\r
461 MnpFreeNbuf (MnpServiceData, RxDataWrap->Nbuf);\r
462 RxDataWrap->Nbuf = NULL;\r
463\r
464 //\r
465 // Close the recycle event.\r
466 //\r
467 gBS->CloseEvent (RxDataWrap->RxData.RecycleEvent);\r
468\r
469 //\r
470 // Remove this Wrap entry from the list.\r
471 //\r
472 NetListRemoveEntry (&RxDataWrap->WrapEntry);\r
473\r
474 NetFreePool (RxDataWrap);\r
475}\r
476\r
477\r
478/**\r
479 Queue the received packet into instance's receive queue.\r
480\r
481 @param Instance Pointer to the mnp instance context data.\r
482 @param RxDataWrap Pointer to the Wrap structure containing the\r
483 received data and other information.\r
484\r
485 @return None.\r
486\r
487**/\r
488STATIC\r
489VOID\r
490MnpQueueRcvdPacket (\r
491 IN MNP_INSTANCE_DATA *Instance,\r
492 IN MNP_RXDATA_WRAP *RxDataWrap\r
493 )\r
494{\r
495 MNP_RXDATA_WRAP *OldRxDataWrap;\r
496\r
497 NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
498\r
499 //\r
500 // Check the queue size. If it exceeds the limit, drop one packet\r
501 // from the head.\r
502 //\r
503 if (Instance->RcvdPacketQueueSize == MNP_MAX_RCVD_PACKET_QUE_SIZE) {\r
504\r
505 MNP_DEBUG_WARN (("MnpQueueRcvdPacket: Drop one packet bcz queue size limit reached.\n"));\r
506\r
507 //\r
508 // Get the oldest packet.\r
509 //\r
510 OldRxDataWrap = NET_LIST_HEAD (\r
511 &Instance->RcvdPacketQueue,\r
512 MNP_RXDATA_WRAP,\r
513 WrapEntry\r
514 );\r
515\r
516 //\r
517 // Recycle this OldRxDataWrap, this entry will be removed by the callee.\r
518 //\r
519 MnpRecycleRxData (NULL, (VOID *) OldRxDataWrap);\r
520 Instance->RcvdPacketQueueSize--;\r
521 }\r
522\r
523 //\r
524 // Update the timeout tick using the configured parameter.\r
525 //\r
526 RxDataWrap->TimeoutTick = Instance->ConfigData.ReceivedQueueTimeoutValue;\r
527\r
528 //\r
529 // Insert this Wrap into the instance queue.\r
530 //\r
531 NetListInsertTail (&Instance->RcvdPacketQueue, &RxDataWrap->WrapEntry);\r
532 Instance->RcvdPacketQueueSize++;\r
533}\r
534\r
535\r
536/**\r
537 Match the received packet with the instance receive filters.\r
538\r
539 @param Instance Pointer to the mnp instance context data.\r
540 @param RxData Pointer to the EFI_MANAGED_NETWORK_RECEIVE_DATA.\r
541 @param GroupAddress Pointer to the GroupAddress, the GroupAddress is\r
542 non-NULL and it contains the destination multicast\r
543 mac address of the received packet if the packet\r
544 destinated to a multicast mac address.\r
545 @param PktAttr The received packets attribute.\r
546\r
547 @return The received packet matches the instance's receive filters or not.\r
548\r
549**/\r
550STATIC\r
551BOOLEAN\r
552MnpMatchPacket (\r
553 IN MNP_INSTANCE_DATA *Instance,\r
554 IN EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData,\r
555 IN MNP_GROUP_ADDRESS *GroupAddress OPTIONAL,\r
556 IN UINT8 PktAttr\r
557 )\r
558{\r
559 EFI_MANAGED_NETWORK_CONFIG_DATA *ConfigData;\r
560 NET_LIST_ENTRY *Entry;\r
561 MNP_GROUP_CONTROL_BLOCK *GroupCtrlBlk;\r
562\r
563 NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
564\r
565 ConfigData = &Instance->ConfigData;\r
566\r
567 if (ConfigData->EnablePromiscuousReceive) {\r
568 //\r
569 // Always match if this instance is configured to be promiscuous.\r
570 //\r
571 return TRUE;\r
572 }\r
573 //\r
574 // Check the protocol type.\r
575 //\r
576 if ((ConfigData->ProtocolTypeFilter != 0) && (ConfigData->ProtocolTypeFilter != RxData->ProtocolType)) {\r
577 return FALSE;\r
578 }\r
579\r
580 //\r
581 // The protocol type is matched, check receive filter, include unicast and broadcast.\r
582 //\r
583 if ((Instance->ReceiveFilter & PktAttr) != 0) {\r
584 return TRUE;\r
585 }\r
586\r
587 //\r
588 // Check multicast addresses.\r
589 //\r
590 if (ConfigData->EnableMulticastReceive && RxData->MulticastFlag) {\r
591\r
592 ASSERT (GroupAddress != NULL);\r
593\r
594 NET_LIST_FOR_EACH (Entry, &Instance->GroupCtrlBlkList) {\r
595\r
596 GroupCtrlBlk = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_CONTROL_BLOCK, CtrlBlkEntry);\r
597 if (GroupCtrlBlk->GroupAddress == GroupAddress) {\r
598 //\r
599 // The instance is configured to receiveing packets destinated to this\r
600 // multicast address.\r
601 //\r
602 return TRUE;\r
603 }\r
604 }\r
605 }\r
606\r
607 //\r
608 // No match.\r
609 //\r
610 return FALSE;\r
611}\r
612\r
613\r
614/**\r
615 Analyse the received packets.\r
616\r
617 @param MnpServiceData Pointer to the mnp service context data.\r
618 @param Nbuf Pointer to the net buffer holding the received\r
619 packet.\r
620 @param RxData Pointer to the buffer used to save the analysed\r
621 result in EFI_MANAGED_NETWORK_RECEIVE_DATA.\r
622 @param GroupAddress Pointer to pointer to a MNP_GROUP_ADDRESS used to\r
623 pass out the address of the multicast address the\r
624 received packet destinated to.\r
625 @param PktAttr Pointer to the buffer used to save the analysed\r
626 packet attribute.\r
627\r
628 @return None.\r
629\r
630**/\r
631STATIC\r
632VOID\r
633MnpAnalysePacket (\r
634 IN MNP_SERVICE_DATA *MnpServiceData,\r
635 IN NET_BUF *Nbuf,\r
636 IN EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData,\r
637 OUT MNP_GROUP_ADDRESS **GroupAddress,\r
638 OUT UINT8 *PktAttr\r
639 )\r
640{\r
641 EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
642 UINT8 *BufPtr;\r
643 NET_LIST_ENTRY *Entry;\r
644\r
645 SnpMode = MnpServiceData->Snp->Mode;\r
646\r
647 //\r
648 // Get the packet buffer.\r
649 //\r
650 BufPtr = NetbufGetByte (Nbuf, 0, NULL);\r
651 ASSERT (BufPtr != NULL);\r
652\r
653 //\r
654 // Set the initial values.\r
655 //\r
656 RxData->BroadcastFlag = FALSE;\r
657 RxData->MulticastFlag = FALSE;\r
658 RxData->PromiscuousFlag = FALSE;\r
659 *PktAttr = UNICAST_PACKET;\r
660\r
661 if (!NET_MAC_EQUAL (&SnpMode->CurrentAddress, BufPtr, SnpMode->HwAddressSize)) {\r
662 //\r
663 // This packet isn't destinated to our current mac address, it't not unicast.\r
664 //\r
665 *PktAttr = 0;\r
666\r
667 if (NET_MAC_EQUAL (&SnpMode->BroadcastAddress, BufPtr, SnpMode->HwAddressSize)) {\r
668 //\r
669 // It's broadcast.\r
670 //\r
671 RxData->BroadcastFlag = TRUE;\r
672 *PktAttr = BROADCAST_PACKET;\r
673 } else if ((*BufPtr & 0x01) == 0x1) {\r
674 //\r
675 // It's multicast, try to match the multicast filters.\r
676 //\r
677 NET_LIST_FOR_EACH (Entry, &MnpServiceData->GroupAddressList) {\r
678\r
679 *GroupAddress = NET_LIST_USER_STRUCT (Entry, MNP_GROUP_ADDRESS, AddrEntry);\r
680 if (NET_MAC_EQUAL (BufPtr, &((*GroupAddress)->Address), SnpMode->HwAddressSize)) {\r
681 RxData->MulticastFlag = TRUE;\r
682 break;\r
683 }\r
684 }\r
685\r
686 if (!RxData->MulticastFlag) {\r
687 //\r
688 // No match, set GroupAddress to NULL. This multicast packet must\r
689 // be the result of PROMISUCOUS or PROMISUCOUS_MULTICAST flag is on.\r
690 //\r
691 *GroupAddress = NULL;\r
692 RxData->PromiscuousFlag = TRUE;\r
693\r
694 if (MnpServiceData->PromiscuousCount == 0) {\r
695 //\r
696 // Skip the below code, there is no receiver of this packet.\r
697 //\r
698 return ;\r
699 }\r
700 }\r
701 } else {\r
702 RxData->PromiscuousFlag = TRUE;\r
703 }\r
704 }\r
705\r
706 NetZeroMem (&RxData->Timestamp, sizeof (EFI_TIME));\r
707\r
708 //\r
709 // Fill the common parts of RxData.\r
710 //\r
711 RxData->PacketLength = Nbuf->TotalSize;\r
712 RxData->HeaderLength = SnpMode->MediaHeaderSize;\r
713 RxData->AddressLength = SnpMode->HwAddressSize;\r
714 RxData->DataLength = RxData->PacketLength - RxData->HeaderLength;\r
715 RxData->ProtocolType = NTOHS (*(UINT16 *) (BufPtr + 2 * SnpMode->HwAddressSize));\r
716}\r
717\r
718\r
719/**\r
720 Wrap the RxData.\r
721\r
722 @param Instance Pointer to the mnp instance context data.\r
723 @param RxData Pointer to the receive data to wrap.\r
724\r
725 @return Pointer to a MNP_RXDATA_WRAP which wraps the RxData.\r
726\r
727**/\r
728STATIC\r
729MNP_RXDATA_WRAP *\r
730MnpWrapRxData (\r
731 IN MNP_INSTANCE_DATA *Instance,\r
732 IN EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData\r
733 )\r
734{\r
735 EFI_STATUS Status;\r
736 MNP_RXDATA_WRAP *RxDataWrap;\r
737\r
738 //\r
739 // Allocate memory.\r
740 //\r
741 RxDataWrap = NetAllocatePool (sizeof (MNP_RXDATA_WRAP));\r
742 if (RxDataWrap == NULL) {\r
743 MNP_DEBUG_ERROR (("MnpDispatchPacket: Failed to allocate a MNP_RXDATA_WRAP.\n"));\r
744 return NULL;\r
745 }\r
746\r
747 RxDataWrap->Instance = Instance;\r
748\r
749 //\r
750 // Fill the RxData in RxDataWrap,\r
751 //\r
752 RxDataWrap->RxData = *RxData;\r
753\r
754 //\r
755 // Create the recycle event.\r
756 //\r
757 Status = gBS->CreateEvent (\r
758 EVT_NOTIFY_SIGNAL,\r
759 NET_TPL_RECYCLE,\r
760 MnpRecycleRxData,\r
761 RxDataWrap,\r
762 &RxDataWrap->RxData.RecycleEvent\r
763 );\r
764 if (EFI_ERROR (Status)) {\r
765\r
766 MNP_DEBUG_ERROR (("MnpDispatchPacket: gBS->CreateEvent failed, %r.\n", Status));\r
767 NetFreePool (RxDataWrap);\r
768 return NULL;\r
769 }\r
770\r
771 return RxDataWrap;\r
772}\r
773\r
774\r
775/**\r
776 Enqueue the received the packets to the instances belonging to the\r
777 MnpServiceData.\r
778\r
779 @param MnpServiceData Pointer to the mnp service context data.\r
780 @param Nbuf Pointer to the net buffer representing the received\r
781 packet.\r
782\r
783 @return None.\r
784\r
785**/\r
786STATIC\r
787VOID\r
788MnpEnqueuePacket (\r
789 IN MNP_SERVICE_DATA *MnpServiceData,\r
790 IN NET_BUF *Nbuf\r
791 )\r
792{\r
793 NET_LIST_ENTRY *Entry;\r
794 MNP_INSTANCE_DATA *Instance;\r
795 EFI_MANAGED_NETWORK_RECEIVE_DATA RxData;\r
796 UINT8 PktAttr;\r
797 MNP_GROUP_ADDRESS *GroupAddress;\r
798 MNP_RXDATA_WRAP *RxDataWrap;\r
799\r
800 //\r
801 // First, analyse the packet header.\r
802 //\r
803 MnpAnalysePacket (MnpServiceData, Nbuf, &RxData, &GroupAddress, &PktAttr);\r
804\r
805 if (RxData.PromiscuousFlag && (MnpServiceData->PromiscuousCount == 0)) {\r
806 //\r
807 // No receivers, no more action need.\r
808 //\r
809 return ;\r
810 }\r
811\r
812 //\r
813 // Iterate the children to find match.\r
814 //\r
815 NET_LIST_FOR_EACH (Entry, &MnpServiceData->ChildrenList) {\r
816\r
817 Instance = NET_LIST_USER_STRUCT (Entry, MNP_INSTANCE_DATA, InstEntry);\r
818 NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
819\r
820 if (!Instance->Configured) {\r
821 continue;\r
822 }\r
823\r
824 //\r
825 // Check the packet against the instance receive filters.\r
826 //\r
827 if (MnpMatchPacket (Instance, &RxData, GroupAddress, PktAttr)) {\r
828\r
829 //\r
830 // Wrap the RxData.\r
831 //\r
832 RxDataWrap = MnpWrapRxData (Instance, &RxData);\r
833 if (RxDataWrap == NULL) {\r
834 continue;\r
835 }\r
836\r
837 //\r
838 // Associate RxDataWrap with Nbuf and increase the RefCnt.\r
839 //\r
840 RxDataWrap->Nbuf = Nbuf;\r
841 NET_GET_REF (RxDataWrap->Nbuf);\r
842\r
843 //\r
844 // Queue the packet into the instance queue.\r
845 //\r
846 MnpQueueRcvdPacket (Instance, RxDataWrap);\r
847 }\r
848 }\r
849}\r
850\r
851\r
852/**\r
853 Try to receive a packet and deliver it.\r
854\r
855 @param MnpServiceData Pointer to the mnp service context data.\r
856\r
857 @retval EFI_SUCCESS add return value to function comment\r
858 @retval EFI_NOT_STARTED The simple network protocol is not started.\r
859 @retval EFI_NOT_READY No packet received.\r
860 @retval EFI_DEVICE_ERROR An unexpected error occurs.\r
861\r
862**/\r
863EFI_STATUS\r
864MnpReceivePacket (\r
865 IN MNP_SERVICE_DATA *MnpServiceData\r
866 )\r
867{\r
868 EFI_STATUS Status;\r
869 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
870 NET_BUF *Nbuf;\r
871 UINT8 *BufPtr;\r
872 UINTN BufLen;\r
873 UINTN HeaderSize;\r
874 UINT32 Trimmed;\r
875\r
876 NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
877\r
878 Snp = MnpServiceData->Snp;\r
879 if (Snp->Mode->State != EfiSimpleNetworkInitialized) {\r
880 //\r
881 // The simple network protocol is not started.\r
882 //\r
883 return EFI_NOT_STARTED;\r
884 }\r
885\r
886 if (NetListIsEmpty (&MnpServiceData->ChildrenList)) {\r
887 //\r
888 // There is no child, no need to receive packets.\r
889 //\r
890 return EFI_SUCCESS;\r
891 }\r
892\r
893 if (MnpServiceData->RxNbufCache == NULL) {\r
894 //\r
895 // Try to get a new buffer as there may be buffers recycled.\r
896 //\r
897 MnpServiceData->RxNbufCache = MnpAllocNbuf (MnpServiceData);\r
898\r
899 if (MnpServiceData->RxNbufCache == NULL) {\r
900 //\r
901 // No availabe buffer in the buffer pool.\r
902 //\r
903 return EFI_DEVICE_ERROR;\r
904 }\r
905\r
906 NetbufAllocSpace (\r
907 MnpServiceData->RxNbufCache,\r
908 MnpServiceData->BufferLength,\r
909 NET_BUF_TAIL\r
910 );\r
911 }\r
912\r
913 Nbuf = MnpServiceData->RxNbufCache;\r
914 BufLen = Nbuf->TotalSize;\r
915 BufPtr = NetbufGetByte (Nbuf, 0, NULL);\r
916 ASSERT (BufPtr != NULL);\r
917\r
918 //\r
919 // Receive packet through Snp.\r
920 //\r
921 Status = Snp->Receive (Snp, &HeaderSize, &BufLen, BufPtr, NULL, NULL, NULL);\r
922 if (EFI_ERROR (Status)) {\r
923\r
924 DEBUG_CODE (\r
925 if (Status != EFI_NOT_READY) {\r
926 MNP_DEBUG_ERROR (("MnpReceivePacket: Snp->Receive() = %r.\n", Status));\r
927 }\r
928 );\r
929\r
930 return Status;\r
931 }\r
932\r
933 //\r
934 // Sanity check.\r
935 //\r
936 if ((HeaderSize != Snp->Mode->MediaHeaderSize) || (BufLen < HeaderSize)) {\r
937\r
938 MNP_DEBUG_WARN (\r
939 ("MnpReceivePacket: Size error, HL:TL = %d:%d.\n",\r
940 HeaderSize,\r
941 BufLen)\r
942 );\r
943 return EFI_DEVICE_ERROR;\r
944 }\r
945\r
946 Trimmed = 0;\r
947 if (Nbuf->TotalSize != BufLen) {\r
948 //\r
949 // Trim the packet from tail.\r
950 //\r
951 Trimmed = NetbufTrim (Nbuf, Nbuf->TotalSize - (UINT32) BufLen, NET_BUF_TAIL);\r
952 ASSERT (Nbuf->TotalSize == BufLen);\r
953 }\r
954\r
955 //\r
956 // Enqueue the packet to the matched instances.\r
957 //\r
958 MnpEnqueuePacket (MnpServiceData, Nbuf);\r
959\r
960 if (Nbuf->RefCnt > 2) {\r
961 //\r
962 // RefCnt > 2 indicates there is at least one receiver of this packet.\r
963 // Free the current RxNbufCache and allocate a new one.\r
964 //\r
965 MnpFreeNbuf (MnpServiceData, Nbuf);\r
966\r
967 Nbuf = MnpAllocNbuf (MnpServiceData);\r
968 MnpServiceData->RxNbufCache = Nbuf;\r
969 if (Nbuf == NULL) {\r
970 MNP_DEBUG_ERROR (("MnpReceivePacket: Alloc packet for receiving cache failed.\n"));\r
971 return EFI_DEVICE_ERROR;\r
972 }\r
973\r
974 NetbufAllocSpace (Nbuf, MnpServiceData->BufferLength, NET_BUF_TAIL);\r
975 } else {\r
976 //\r
977 // No receiver for this packet.\r
978 //\r
979 NetbufAllocSpace (Nbuf, Trimmed, NET_BUF_TAIL);\r
980 goto EXIT;\r
981 }\r
982 //\r
983 // Deliver the queued packets.\r
984 //\r
985 MnpDeliverPacket (MnpServiceData);\r
986\r
987EXIT:\r
988\r
989 ASSERT (Nbuf->TotalSize == MnpServiceData->BufferLength);\r
990\r
991 return Status;\r
992}\r
993\r
994\r
995/**\r
996 Remove the received packets if timeout occurs.\r
997\r
998 @param Event The event this notify function registered to.\r
999 @param Context Pointer to the context data registered to the\r
1000 event.\r
1001\r
1002 @return None.\r
1003\r
1004**/\r
1005VOID\r
1006EFIAPI\r
1007MnpCheckPacketTimeout (\r
1008 IN EFI_EVENT Event,\r
1009 IN VOID *Context\r
1010 )\r
1011{\r
1012 MNP_SERVICE_DATA *MnpServiceData;\r
1013 NET_LIST_ENTRY *Entry;\r
1014 NET_LIST_ENTRY *RxEntry;\r
1015 NET_LIST_ENTRY *NextEntry;\r
1016 MNP_INSTANCE_DATA *Instance;\r
1017 MNP_RXDATA_WRAP *RxDataWrap;\r
1018 EFI_TPL OldTpl;\r
1019\r
1020 MnpServiceData = (MNP_SERVICE_DATA *) Context;\r
1021 NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
1022\r
1023 NET_LIST_FOR_EACH (Entry, &MnpServiceData->ChildrenList) {\r
1024\r
1025 Instance = NET_LIST_USER_STRUCT (Entry, MNP_INSTANCE_DATA, InstEntry);\r
1026 NET_CHECK_SIGNATURE (Instance, MNP_INSTANCE_DATA_SIGNATURE);\r
1027\r
1028 if (!Instance->Configured || (Instance->ConfigData.ReceivedQueueTimeoutValue == 0)) {\r
1029 //\r
1030 // This instance is not configured or there is no receive time out,\r
1031 // just skip to the next instance.\r
1032 //\r
1033 continue;\r
1034 }\r
1035\r
1036 OldTpl = NET_RAISE_TPL (NET_TPL_RECYCLE);\r
1037\r
1038 NET_LIST_FOR_EACH_SAFE (RxEntry, NextEntry, &Instance->RcvdPacketQueue) {\r
1039\r
1040 RxDataWrap = NET_LIST_USER_STRUCT (RxEntry, MNP_RXDATA_WRAP, WrapEntry);\r
1041\r
1042 if (RxDataWrap->TimeoutTick >= MNP_TIMEOUT_CHECK_INTERVAL) {\r
1043\r
1044 RxDataWrap->TimeoutTick -= MNP_TIMEOUT_CHECK_INTERVAL;\r
1045 } else {\r
1046 //\r
1047 // Drop the timeout packet.\r
1048 //\r
1049 MNP_DEBUG_WARN (("MnpCheckPacketTimeout: Received packet timeout.\n"));\r
1050 MnpRecycleRxData (NULL, RxDataWrap);\r
1051 Instance->RcvdPacketQueueSize--;\r
1052 }\r
1053 }\r
1054\r
1055 NET_RESTORE_TPL (OldTpl);\r
1056 }\r
1057}\r
1058\r
1059\r
1060/**\r
1061 Poll to receive the packets from Snp. This function is either called by upperlayer\r
1062 protocols/applications or the system poll timer notify mechanism.\r
1063\r
1064 @param Event The event this notify function registered to.\r
1065 @param Context Pointer to the context data registered to the\r
1066 event.\r
1067\r
1068 @return None.\r
1069\r
1070**/\r
1071VOID\r
1072EFIAPI\r
1073MnpSystemPoll (\r
1074 IN EFI_EVENT Event,\r
1075 IN VOID *Context\r
1076 )\r
1077{\r
1078 MNP_SERVICE_DATA *MnpServiceData;\r
1079\r
1080 MnpServiceData = (MNP_SERVICE_DATA *) Context;\r
1081 NET_CHECK_SIGNATURE (MnpServiceData, MNP_SERVICE_DATA_SIGNATURE);\r
1082\r
1083 //\r
1084 // Try to receive packets from Snp.\r
1085 //\r
1086 MnpReceivePacket (MnpServiceData);\r
1087}\r