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