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