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 + -
显示快捷键?