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