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