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