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