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