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