Search code examples
cnetwork-programmingudpuefi

UEFI UDP Receive token


Sample code such as that provided by MiSimon in Send TCP or UDP packets from efi application shows how to send and receive a single packet. I have successfully been able to send multiple packets, but I'm having difficulties on the receive side.

The documentation for the UEFI UDP Protocol EFI_UDP4_PROTOCOL.Receive() function says that it

Places an asynchronous receive request into the receiving queue.

Based on the EDK2 source code, one might infer this does something like NetMapInsertTail() placing the new token on the RxTokens list. According to the same source, it would appear that when a datagram is delivered, this token is removed with NetMapRemoveHead(). However, empirically after I successfully receive one packet, return from the callback and signal the RecycleSignal, my next call to Receive() fails with EFI_ACCESS_DENIED, described in this context as:

A receive completion token with the same Token.Event was already in the receive queue.

The interface does not provide any API to determine what is in the "receive queue", so it's not easy to investigate whether the 'remove' operation simply isn't doing what I think it is, or whether it's getting requeued, etc.

So the crux of my question is: how do I arrange to receive multiple datagrams from the same UDP port?

  • Is the token on the receive queue something that should be reusable many times without multiple calls to Receive()? (If so, what has to be done to prepare it for reuse?)
  • Or is it something that needs to be created anew for each incoming packet? (And if so, then when and how are they freed?)

Solution

  • The event in the token is only called once, the specification says (Spec 2.9, Chapter 30.1.2 Receive):

    "Providing a proper notification function and context for the event will enable the user to receive the notification and receiving status. That notification function is guaranteed to not be re-entered."

    You need to allocate a new event for every token. If you want to listen for more then one datagram at the same time you can use unique contexts for each event but the same notify function.

    For each token you have to:

    Create event and token -> call receive -> handle datagram or error -> signal the recycle event -> free the token event