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