ip4input.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,332 行 · 第 1/3 页
C
1,332 行
in the IP4_RXDATA_WRAP. The IP4_RXDATA_WRAP->RxData is passed
to the upper layer. Upper layer will signal the recycle event in
it when it is done with the packet.
Arguments:
IpInstance - The IP4 child to receive the packet
Packet - The packet to deliver up.
Returns:
NULL if failed to wrap the packet, otherwise the wrapper.
--*/
{
IP4_RXDATA_WRAP *Wrap;
EFI_IP4_RECEIVE_DATA *RxData;
EFI_STATUS Status;
Wrap = NetAllocatePool (IP4_RXDATA_WRAP_SIZE (Packet->BlockOpNum));
if (Wrap == NULL) {
return NULL;
}
NetListInit (&Wrap->Link);
Wrap->IpInstance = IpInstance;
Wrap->Packet = Packet;
RxData = &Wrap->RxData;
NetZeroMem (&RxData->TimeStamp, sizeof (EFI_TIME));
Status = gBS->CreateEvent (
EFI_EVENT_NOTIFY_SIGNAL,
NET_TPL_RECYCLE,
Ip4OnRecyclePacket,
Wrap,
&RxData->RecycleSignal
);
if (EFI_ERROR (Status)) {
NetFreePool (Wrap);
return NULL;
}
ASSERT (Packet->Ip != NULL);
//
// The application expects a network byte order header.
//
RxData->HeaderLength = (Packet->Ip->HeadLen << 2);
RxData->Header = (EFI_IP4_HEADER *) Ip4NtohHead (Packet->Ip);
RxData->OptionsLength = RxData->HeaderLength - IP4_MIN_HEADLEN;
RxData->Options = NULL;
if (RxData->OptionsLength != 0) {
RxData->Options = (VOID *) (RxData->Header + 1);
}
RxData->DataLength = Packet->TotalSize;
//
// Build the fragment table to be delivered up.
//
RxData->FragmentCount = Packet->BlockOpNum;
NetbufBuildExt (Packet, (NET_FRAGMENT *) RxData->FragmentTable, &RxData->FragmentCount);
return Wrap;
}
EFI_STATUS
Ip4InstanceDeliverPacket (
IN IP4_PROTOCOL *IpInstance
)
/*++
Routine Description:
Deliver the received packets to upper layer if there are both received
requests and enqueued packets. If the enqueued packet is shared, it will
duplicate it to a non-shared packet, release the shared packet, then
deliver the non-shared packet up.
Arguments:
IpInstance - The IP child to deliver the packet up.
Returns:
EFI_OUT_OF_RESOURCES - Failed to allocate resources to deliver the packets.
EFI_SUCCESS - All the enqueued packets that can be delivered
are delivered up.
--*/
{
EFI_IP4_COMPLETION_TOKEN *Token;
IP4_RXDATA_WRAP *Wrap;
NET_BUF *Packet;
NET_BUF *Dup;
UINT8 *Head;
//
// Deliver a packet if there are both a packet and a receive token.
//
while (!NetListIsEmpty (&IpInstance->Received) &&
!NetMapIsEmpty (&IpInstance->RxTokens)) {
Packet = NET_LIST_HEAD (&IpInstance->Received, NET_BUF, List);
if (!NET_BUF_SHARED (Packet)) {
//
// If this is the only instance that wants the packet, wrap it up.
//
Wrap = Ip4WrapRxData (IpInstance, Packet);
if (Wrap == NULL) {
return EFI_OUT_OF_RESOURCES;
}
NetListRemoveEntry (&Packet->List);
} else {
//
// Create a duplicated packet if this packet is shared
//
Dup = NetbufDuplicate (Packet, NULL, IP4_MAX_HEADLEN);
if (Dup == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Copy the IP head over. The packet to deliver up is
// headless. Trim the head off after copy. The IP head
// may be not continuous before the data.
//
Head = NetbufAllocSpace (Dup, IP4_MAX_HEADLEN, NET_BUF_HEAD);
Dup->Ip = (IP4_HEAD *) Head;
NetCopyMem (Head, Packet->Ip, Packet->Ip->HeadLen << 2);
NetbufTrim (Dup, IP4_MAX_HEADLEN, TRUE);
Wrap = Ip4WrapRxData (IpInstance, Dup);
if (Wrap == NULL) {
NetbufFree (Dup);
return EFI_OUT_OF_RESOURCES;
}
NetListRemoveEntry (&Packet->List);
NetbufFree (Packet);
Packet = Dup;
}
//
// Insert it into the delivered packet, then get a user's
// receive token, pass the wrapped packet up.
//
NET_TRYLOCK (&IpInstance->RecycleLock);
NetListInsertHead (&IpInstance->Delivered, &Wrap->Link);
NET_UNLOCK (&IpInstance->RecycleLock);
Token = NetMapRemoveHead (&IpInstance->RxTokens, NULL);
Token->Status = IP4_GET_CLIP_INFO (Packet)->Status;
Token->Packet.RxData = &Wrap->RxData;
gBS->SignalEvent (Token->Event);
}
return EFI_SUCCESS;
}
INTN
Ip4InterfaceEnquePacket (
IN IP4_SERVICE *IpSb,
IN IP4_HEAD *Head,
IN NET_BUF *Packet,
IN IP4_INTERFACE *IpIf
)
/*++
Routine Description:
Enqueue a received packet to all the IP children that share
the same interface.
Arguments:
IpSb - The IP4 service instance that receive the packet
Head - The header of the received packet
Packet - The data of the received packet
IpIf - The interface to enqueue the packet to
Returns:
The number of the IP4 children that accepts the packet
--*/
{
IP4_PROTOCOL *IpInstance;
IP4_CLIP_INFO *Info;
NET_LIST_ENTRY *Entry;
INTN Enqueued;
INTN LocalType;
INTN SavedType;
//
// First, check that the packet is acceptable to this interface
// and find the local cast type for the interface. A packet sent
// to say 192.168.1.1 should NOT be delliever to 10.0.0.1 unless
// promiscuous receiving.
//
LocalType = 0;
Info = IP4_GET_CLIP_INFO (Packet);
if ((Info->CastType == IP4_MULTICAST) || (Info->CastType == IP4_LOCAL_BROADCAST)) {
//
// If the CastType is multicast, don't need to filter against
// the group address here, Ip4InstanceFrameAcceptable will do
// that later.
//
LocalType = Info->CastType;
} else {
//
// Check the destination againist local IP. If the station
// address is 0.0.0.0, it means receiving all the IP destined
// to local non-zero IP. Otherwise, it is necessary to compare
// the destination to the interface's IP address.
//
if (IpIf->Ip == IP4_ALLZERO_ADDRESS) {
LocalType = IP4_LOCAL_HOST;
} else {
LocalType = Ip4GetNetCast (Head->Dst, IpIf);
if ((LocalType == 0) && IpIf->PromiscRecv) {
LocalType = IP4_PROMISCUOUS;
}
}
}
if (LocalType == 0) {
return 0;
}
//
// Iterate through the ip instances on the interface, enqueue
// the packet if filter passed. Save the original cast type,
// and pass the local cast type to the IP children on the
// interface. The global cast type will be restored later.
//
SavedType = Info->CastType;
Info->CastType = LocalType;
Enqueued = 0;
NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {
IpInstance = NET_LIST_USER_STRUCT (Entry, IP4_PROTOCOL, AddrLink);
NET_CHECK_SIGNATURE (IpInstance, IP4_PROTOCOL_SIGNATURE);
if (Ip4InstanceEnquePacket (IpInstance, Head, Packet) == EFI_SUCCESS) {
Enqueued++;
}
}
Info->CastType = SavedType;
return Enqueued;
}
EFI_STATUS
Ip4InterfaceDeliverPacket (
IN IP4_SERVICE *IpSb,
IN IP4_INTERFACE *IpIf
)
/*++
Routine Description:
Deliver the packet for each IP4 child on the interface.
Arguments:
IpSb - The IP4 service instance that received the packet
IpIf - The IP4 interface to deliver the packet.
Returns:
EFI_SUCCESS - It always returns EFI_SUCCESS now
--*/
{
IP4_PROTOCOL *Ip4Instance;
NET_LIST_ENTRY *Entry;
NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {
Ip4Instance = NET_LIST_USER_STRUCT (Entry, IP4_PROTOCOL, AddrLink);
Ip4InstanceDeliverPacket (Ip4Instance);
}
return EFI_SUCCESS;
}
EFI_STATUS
Ip4Demultiplex (
IN IP4_SERVICE *IpSb,
IN IP4_HEAD *Head,
IN NET_BUF *Packet
)
/*++
Routine Description:
Demultiple the packet. the packet delivery is processed in two
passes. The first pass will enque a shared copy of the packet
to each IP4 child that accepts the packet. The second pass will
deliver a non-shared copy of the packet to each IP4 child that
has pending receive requests. Data is copied if more than one
child wants to consume the packet bacause each IP child need
its own copy of the packet to make changes.
Arguments:
IpSb - The IP4 service instance that received the packet
Head - The header of the received packet
Packet - The data of the received packet
Returns:
EFI_NOT_FOUND - No IP child accepts the packet
EFI_SUCCESS - The packet is enqueued or delivered to some IP children.
--*/
{
NET_LIST_ENTRY *Entry;
IP4_INTERFACE *IpIf;
INTN Enqueued;
//
// Two pass delivery: first, enque a shared copy of the packet
// to each instance that accept the packet.
//
Enqueued = 0;
NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
if (IpIf->Configured) {
Enqueued += Ip4InterfaceEnquePacket (IpSb, Head, Packet, IpIf);
}
}
//
// Second: deliver a duplicate of the packet to each instance.
// Release the local reference first, so that the last instance
// getting the packet will not copy the data.
//
NetbufFree (Packet);
if (Enqueued == 0) {
return EFI_NOT_FOUND;
}
NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
if (IpIf->Configured) {
Ip4InterfaceDeliverPacket (IpSb, IpIf);
}
}
return EFI_SUCCESS;
}
VOID
Ip4PacketTimerTicking (
IN IP4_SERVICE *IpSb
)
/*++
Routine Description:
Timeout the fragment and enqueued packets.
Arguments:
IpSb - The IP4 service instance to timeout
Returns:
None
--*/
{
NET_LIST_ENTRY *InstanceEntry;
NET_LIST_ENTRY *Entry;
NET_LIST_ENTRY *Next;
IP4_PROTOCOL *IpInstance;
IP4_ASSEMBLE_ENTRY *Assemble;
NET_BUF *Packet;
IP4_CLIP_INFO *Info;
UINT32 Index;
//
// First, time out the fragments. The packet's life is counting down
// once the first-arrived fragment was received.
//
for (Index = 0; Index < IP4_ASSEMLE_HASH_SIZE; Index++) {
NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->Assemble.Bucket[Index]) {
Assemble = NET_LIST_USER_STRUCT (Entry, IP4_ASSEMBLE_ENTRY, Link);
if ((Assemble->Life > 0) && (--Assemble->Life == 0)) {
NetListRemoveEntry (Entry);
Ip4FreeAssembleEntry (Assemble);
}
}
}
NET_LIST_FOR_EACH (InstanceEntry, &IpSb->Children) {
IpInstance = NET_LIST_USER_STRUCT (InstanceEntry, IP4_PROTOCOL, Link);
//
// Second, time out the assembled packets enqueued on each IP child.
//
NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpInstance->Received) {
Packet = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
Info = IP4_GET_CLIP_INFO (Packet);
if ((Info->Life > 0) && (--Info->Life == 0)) {
NetListRemoveEntry (Entry);
NetbufFree (Packet);
}
}
//
// Third: time out the transmitted packets.
//
NetMapIterate (&IpInstance->TxTokens, Ip4SentPacketTicking, NULL);
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?