Sergey Pastor / 1

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers udp.c Source File

udp.c

Go to the documentation of this file.
00001 /**
00002  * @file udp.c
00003  * @brief UDP (User Datagram Protocol)
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL UDP_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include <string.h>
00034 #include "core/net.h"
00035 #include "core/ip.h"
00036 #include "core/udp.h"
00037 #include "core/socket.h"
00038 #include "ipv4/ipv4.h"
00039 #include "ipv6/ipv6.h"
00040 #include "ipv6/ipv6_misc.h"
00041 #include "mibs/mib2_module.h"
00042 #include "debug.h"
00043 
00044 //Check TCP/IP stack configuration
00045 #if (UDP_SUPPORT == ENABLED)
00046 
00047 //Ephemeral ports are used for dynamic port assignment
00048 static uint16_t udpDynamicPort;
00049 //Mutex to prevent simultaneous access to the callback table
00050 OsMutex udpCallbackMutex;
00051 //Table that holds the registered user callbacks
00052 UdpRxCallbackDesc udpCallbackTable[UDP_CALLBACK_TABLE_SIZE];
00053 
00054 
00055 /**
00056  * @brief UDP related initialization
00057  * @return Error code
00058  **/
00059 
00060 error_t udpInit(void)
00061 {
00062    //Reset ephemeral port number
00063    udpDynamicPort = 0;
00064 
00065    //Create a mutex to prevent simultaneous access to the callback table
00066    if(!osCreateMutex(&udpCallbackMutex))
00067    {
00068       //Failed to create mutex
00069       return ERROR_OUT_OF_RESOURCES;
00070    }
00071 
00072    //Initialize callback table
00073    memset(udpCallbackTable, 0, sizeof(udpCallbackTable));
00074 
00075    //Successful initialization
00076    return NO_ERROR;
00077 }
00078 
00079 
00080 /**
00081  * @brief Get an ephemeral port number
00082  * @return Ephemeral port
00083  **/
00084 
00085 uint16_t udpGetDynamicPort(void)
00086 {
00087    uint_t port;
00088 
00089    //Retrieve current port number
00090    port = udpDynamicPort;
00091 
00092    //Invalid port number?
00093    if(port < SOCKET_EPHEMERAL_PORT_MIN || port > SOCKET_EPHEMERAL_PORT_MAX)
00094    {
00095       //Generate a random port number
00096       port = SOCKET_EPHEMERAL_PORT_MIN + netGetRand() %
00097          (SOCKET_EPHEMERAL_PORT_MAX - SOCKET_EPHEMERAL_PORT_MIN + 1);
00098    }
00099 
00100    //Next dynamic port to use
00101    if(port < SOCKET_EPHEMERAL_PORT_MAX)
00102    {
00103       //Increment port number
00104       udpDynamicPort = port + 1;
00105    }
00106    else
00107    {
00108       //Wrap around if necessary
00109       udpDynamicPort = SOCKET_EPHEMERAL_PORT_MIN;
00110    }
00111 
00112    //Return an ephemeral port number
00113    return port;
00114 }
00115 
00116 
00117 /**
00118  * @brief Incoming UDP datagram processing
00119  * @param[in] interface Underlying network interface
00120  * @param[in] pseudoHeader UDP pseudo header
00121  * @param[in] buffer Multi-part buffer containing the incoming UDP datagram
00122  * @param[in] offset Offset to the first byte of the UDP header
00123  * @return Error code
00124  **/
00125 
00126 error_t udpProcessDatagram(NetInterface *interface,
00127    IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset)
00128 {
00129    error_t error;
00130    uint_t i;
00131    size_t length;
00132    UdpHeader *header;
00133    Socket *socket;
00134    SocketQueueItem *queueItem;
00135    NetBuffer *p;
00136 
00137    //Retrieve the length of the UDP datagram
00138    length = netBufferGetLength(buffer) - offset;
00139 
00140    //Ensure the UDP header is valid
00141    if(length < sizeof(UdpHeader))
00142    {
00143       //Number of received UDP datagrams that could not be delivered for
00144       //reasons other than the lack of an application at the destination port
00145       MIB2_INC_COUNTER32(mib2Base.udpGroup.udpInErrors, 1);
00146 
00147       //Report an error
00148       return ERROR_INVALID_HEADER;
00149    }
00150 
00151    //Point to the UDP header
00152    header = netBufferAt(buffer, offset);
00153    //Sanity check
00154    if(header == NULL)
00155       return ERROR_FAILURE;
00156 
00157    //Debug message
00158    TRACE_INFO("UDP datagram received (%" PRIuSIZE " bytes)...\r\n", length);
00159    //Dump UDP header contents for debugging purpose
00160    udpDumpHeader(header);
00161 
00162    //When UDP runs over IPv6, the checksum is mandatory
00163    if(header->checksum != 0x0000 || pseudoHeader->length == sizeof(Ipv6PseudoHeader))
00164    {
00165       //Verify UDP checksum
00166       if(ipCalcUpperLayerChecksumEx(pseudoHeader->data,
00167          pseudoHeader->length, buffer, offset, length) != 0x0000)
00168       {
00169          //Debug message
00170          TRACE_WARNING("Wrong UDP header checksum!\r\n");
00171 
00172          //Number of received UDP datagrams that could not be delivered for
00173          //reasons other than the lack of an application at the destination port
00174          MIB2_INC_COUNTER32(mib2Base.udpGroup.udpInErrors, 1);
00175 
00176          //Report an error
00177          return ERROR_WRONG_CHECKSUM;
00178       }
00179    }
00180 
00181    //Loop through opened sockets
00182    for(i = 0; i < SOCKET_MAX_COUNT; i++)
00183    {
00184       //Point to the current socket
00185       socket = socketTable + i;
00186 
00187       //UDP socket found?
00188       if(socket->type != SOCKET_TYPE_DGRAM)
00189          continue;
00190       //Check whether the socket is bound to a particular interface
00191       if(socket->interface && socket->interface != interface)
00192          continue;
00193       //Check destination port number
00194       if(socket->localPort != ntohs(header->destPort))
00195          continue;
00196       //Source port number filtering
00197       if(socket->remotePort && socket->remotePort != ntohs(header->srcPort))
00198          continue;
00199 
00200 #if (IPV4_SUPPORT == ENABLED)
00201       //An IPv4 packet was received?
00202       if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
00203       {
00204          //Destination IP address filtering
00205          if(socket->localIpAddr.length)
00206          {
00207             //An IPv4 address is expected
00208             if(socket->localIpAddr.length != sizeof(Ipv4Addr))
00209                continue;
00210             //Filter out non-matching addresses
00211             if(socket->localIpAddr.ipv4Addr != pseudoHeader->ipv4Data.destAddr)
00212                continue;
00213          }
00214 
00215          //Source IP address filtering
00216          if(socket->remoteIpAddr.length)
00217          {
00218             //An IPv4 address is expected
00219             if(socket->remoteIpAddr.length != sizeof(Ipv4Addr))
00220                continue;
00221             //Filter out non-matching addresses
00222             if(socket->remoteIpAddr.ipv4Addr != pseudoHeader->ipv4Data.srcAddr)
00223                continue;
00224          }
00225       }
00226       else
00227 #endif
00228 #if (IPV6_SUPPORT == ENABLED)
00229       //An IPv6 packet was received?
00230       if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
00231       {
00232          //Destination IP address filtering
00233          if(socket->localIpAddr.length)
00234          {
00235             //An IPv6 address is expected
00236             if(socket->localIpAddr.length != sizeof(Ipv6Addr))
00237                continue;
00238             //Filter out non-matching addresses
00239             if(!ipv6CompAddr(&socket->localIpAddr.ipv6Addr, &pseudoHeader->ipv6Data.destAddr))
00240                continue;
00241          }
00242 
00243          //Source IP address filtering
00244          if(socket->remoteIpAddr.length)
00245          {
00246             //An IPv6 address is expected
00247             if(socket->remoteIpAddr.length != sizeof(Ipv6Addr))
00248                continue;
00249             //Filter out non-matching addresses
00250             if(!ipv6CompAddr(&socket->remoteIpAddr.ipv6Addr, &pseudoHeader->ipv6Data.srcAddr))
00251                continue;
00252          }
00253       }
00254       else
00255 #endif
00256       //An invalid packet was received?
00257       {
00258          //This should never occur...
00259          continue;
00260       }
00261 
00262       //The current socket meets all the criteria
00263       break;
00264    }
00265 
00266    //Point to the payload
00267    offset += sizeof(UdpHeader);
00268    length -= sizeof(UdpHeader);
00269 
00270    //No matching socket found?
00271    if(i >= SOCKET_MAX_COUNT)
00272    {
00273       //Invoke user callback, if any
00274       error = udpInvokeRxCallback(interface, pseudoHeader, header, buffer, offset);
00275       //Return status code
00276       return error;
00277    }
00278 
00279    //Empty receive queue?
00280    if(!socket->receiveQueue)
00281    {
00282       //Allocate a memory buffer to hold the data and the associated descriptor
00283       p = netBufferAlloc(sizeof(SocketQueueItem) + length);
00284 
00285       //Successful memory allocation?
00286       if(p != NULL)
00287       {
00288          //Point to the newly created item
00289          queueItem = netBufferAt(p, 0);
00290          queueItem->buffer = p;
00291          //Add the newly created item to the queue
00292          socket->receiveQueue = queueItem;
00293       }
00294       else
00295       {
00296          //Memory allocation failed
00297          queueItem = NULL;
00298       }
00299    }
00300    else
00301    {
00302       //Point to the very first item
00303       queueItem = socket->receiveQueue;
00304       //Reach the last item in the receive queue
00305       for(i = 1; queueItem->next; i++)
00306          queueItem = queueItem->next;
00307 
00308       //Make sure the receive queue is not full
00309       if(i >= UDP_RX_QUEUE_SIZE)
00310          return ERROR_RECEIVE_QUEUE_FULL;
00311 
00312       //Allocate a memory buffer to hold the data and the associated descriptor
00313       p = netBufferAlloc(sizeof(SocketQueueItem) + length);
00314 
00315       //Successful memory allocation?
00316       if(p != NULL)
00317       {
00318          //Add the newly created item to the queue
00319          queueItem->next = netBufferAt(p, 0);
00320          //Point to the newly created item
00321          queueItem = queueItem->next;
00322          queueItem->buffer = p;
00323       }
00324       else
00325       {
00326          //Memory allocation failed
00327          queueItem = NULL;
00328       }
00329    }
00330 
00331    //Failed to allocate memory?
00332    if(queueItem == NULL)
00333       return ERROR_OUT_OF_MEMORY;
00334 
00335    //Initialize next field
00336    queueItem->next = NULL;
00337    //Record the source port number
00338    queueItem->srcPort = ntohs(header->srcPort);
00339 
00340 #if (IPV4_SUPPORT == ENABLED)
00341    //IPv4 remote address?
00342    if(pseudoHeader->length == sizeof(Ipv4PseudoHeader))
00343    {
00344       //Save the source IPv4 address
00345       queueItem->srcIpAddr.length = sizeof(Ipv4Addr);
00346       queueItem->srcIpAddr.ipv4Addr = pseudoHeader->ipv4Data.srcAddr;
00347       //Save the destination IPv4 address
00348       queueItem->destIpAddr.length = sizeof(Ipv4Addr);
00349       queueItem->destIpAddr.ipv4Addr = pseudoHeader->ipv4Data.destAddr;
00350    }
00351 #endif
00352 #if (IPV6_SUPPORT == ENABLED)
00353    //IPv6 remote address?
00354    if(pseudoHeader->length == sizeof(Ipv6PseudoHeader))
00355    {
00356       //Save the source IPv6 address
00357       queueItem->srcIpAddr.length = sizeof(Ipv6Addr);
00358       queueItem->srcIpAddr.ipv6Addr = pseudoHeader->ipv6Data.srcAddr;
00359       //Save the destination IPv6 address
00360       queueItem->destIpAddr.length = sizeof(Ipv6Addr);
00361       queueItem->destIpAddr.ipv6Addr = pseudoHeader->ipv6Data.destAddr;
00362    }
00363 #endif
00364 
00365    //Offset to the payload
00366    queueItem->offset = sizeof(SocketQueueItem);
00367    //Copy the payload
00368    netBufferCopy(queueItem->buffer, queueItem->offset, buffer, offset, length);
00369 
00370    //Notify user that data is available
00371    udpUpdateEvents(socket);
00372 
00373    //Total number of UDP datagrams delivered to UDP users
00374    MIB2_INC_COUNTER32(mib2Base.udpGroup.udpInDatagrams, 1);
00375    MIB2_INC_COUNTER64(mib2Base.udpGroup.udpHCInDatagrams, 1);
00376 
00377    //Successful processing
00378    return NO_ERROR;
00379 }
00380 
00381 
00382 /**
00383  * @brief Send a UDP datagram
00384  * @param[in] socket Handle referencing the socket
00385  * @param[in] destIpAddr IP address of the target host
00386  * @param[in] destPort Target port number
00387  * @param[in] data Pointer to data payload
00388  * @param[in] length Length of the payload data
00389  * @param[out] written Actual number of bytes written (optional parameter)
00390  * @return Error code
00391  **/
00392 
00393 error_t udpSendDatagram(Socket *socket, const IpAddr *destIpAddr,
00394    uint16_t destPort, const void *data, size_t length, size_t *written)
00395 {
00396    error_t error;
00397    size_t offset;
00398    NetBuffer *buffer;
00399 
00400    //Allocate a memory buffer to hold the UDP datagram
00401    buffer = udpAllocBuffer(0, &offset);
00402    //Failed to allocate buffer?
00403    if(buffer == NULL)
00404       return ERROR_OUT_OF_MEMORY;
00405 
00406    //Copy data payload
00407    error = netBufferAppend(buffer, data, length);
00408 
00409    //Successful processing?
00410    if(!error)
00411    {
00412       //Send UDP datagram
00413       error = udpSendDatagramEx(socket->interface, socket->localPort,
00414          destIpAddr, destPort, buffer, offset, socket->ttl);
00415    }
00416 
00417    //Successful processing?
00418    if(!error)
00419    {
00420       //Total number of data bytes successfully transmitted
00421       if(written != NULL)
00422          *written = length;
00423    }
00424 
00425    //Free previously allocated memory
00426    netBufferFree(buffer);
00427    //Return status code
00428    return error;
00429 }
00430 
00431 
00432 /**
00433  * @brief Send a UDP datagram (raw interface)
00434  * @param[in] interface Underlying network interface
00435  * @param[in] srcPort Source port
00436  * @param[in] destIpAddr IP address of the target host
00437  * @param[in] destPort Target port number
00438  * @param[in] buffer Multi-part buffer containing the payload
00439  * @param[in] offset Offset to the first payload byte
00440  * @param[in] ttl TTL value. Default Time-To-Live is used when this parameter is zero
00441  * @return Error code
00442  **/
00443 
00444 error_t udpSendDatagramEx(NetInterface *interface, uint16_t srcPort, const IpAddr *destIpAddr,
00445    uint16_t destPort, NetBuffer *buffer, size_t offset, uint8_t ttl)
00446 {
00447    error_t error;
00448    size_t length;
00449    UdpHeader *header;
00450    IpPseudoHeader pseudoHeader;
00451 
00452    //Make room for the UDP header
00453    offset -= sizeof(UdpHeader);
00454    //Retrieve the length of the datagram
00455    length = netBufferGetLength(buffer) - offset;
00456 
00457    //Point to the UDP header
00458    header = netBufferAt(buffer, offset);
00459    //Sanity check
00460    if(header == NULL)
00461       return ERROR_FAILURE;
00462 
00463    //Format UDP header
00464    header->srcPort = htons(srcPort);
00465    header->destPort = htons(destPort);
00466    header->length = htons(length);
00467    header->checksum = 0;
00468 
00469 #if (IPV4_SUPPORT == ENABLED)
00470    //Destination address is an IPv4 address?
00471    if(destIpAddr->length == sizeof(Ipv4Addr))
00472    {
00473       Ipv4Addr srcIpAddr;
00474 
00475       //Select the source IPv4 address and the relevant network interface
00476       //to use when sending data to the specified destination host
00477       error = ipv4SelectSourceAddr(&interface, destIpAddr->ipv4Addr, &srcIpAddr);
00478 
00479       //Check status code
00480       if(error)
00481       {
00482          //Handle the special case where the destination address is the
00483          //broadcast address
00484          if(destIpAddr->ipv4Addr == IPV4_BROADCAST_ADDR)
00485          {
00486             //Use the unspecified address as source address
00487             srcIpAddr = IPV4_UNSPECIFIED_ADDR;
00488          }
00489          else
00490          {
00491             //Source address selection failed
00492             return error;
00493          }
00494       }
00495 
00496       //Format IPv4 pseudo header
00497       pseudoHeader.length = sizeof(Ipv4PseudoHeader);
00498       pseudoHeader.ipv4Data.srcAddr = srcIpAddr;
00499       pseudoHeader.ipv4Data.destAddr = destIpAddr->ipv4Addr;
00500       pseudoHeader.ipv4Data.reserved = 0;
00501       pseudoHeader.ipv4Data.protocol = IPV4_PROTOCOL_UDP;
00502       pseudoHeader.ipv4Data.length = htons(length);
00503 
00504       //Calculate UDP header checksum
00505       header->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader.ipv4Data,
00506          sizeof(Ipv4PseudoHeader), buffer, offset, length);
00507    }
00508    else
00509 #endif
00510 #if (IPV6_SUPPORT == ENABLED)
00511    //Destination address is an IPv6 address?
00512    if(destIpAddr->length == sizeof(Ipv6Addr))
00513    {
00514       //Select the source IPv6 address and the relevant network interface
00515       //to use when sending data to the specified destination host
00516       error = ipv6SelectSourceAddr(&interface,
00517          &destIpAddr->ipv6Addr, &pseudoHeader.ipv6Data.srcAddr);
00518       //Any error to report?
00519       if(error)
00520          return error;
00521 
00522       //Format IPv6 pseudo header
00523       pseudoHeader.length = sizeof(Ipv6PseudoHeader);
00524       pseudoHeader.ipv6Data.destAddr = destIpAddr->ipv6Addr;
00525       pseudoHeader.ipv6Data.length = htonl(length);
00526       pseudoHeader.ipv6Data.reserved = 0;
00527       pseudoHeader.ipv6Data.nextHeader = IPV6_UDP_HEADER;
00528 
00529       //Calculate UDP header checksum
00530       header->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader.ipv6Data,
00531          sizeof(Ipv6PseudoHeader), buffer, offset, length);
00532    }
00533    else
00534 #endif
00535    //Invalid destination address?
00536    {
00537       //An internal error has occurred
00538       return ERROR_FAILURE;
00539    }
00540 
00541    //If the computed checksum is zero, it is transmitted as all ones. An all
00542    //zero transmitted checksum value means that the transmitter generated no
00543    //checksum
00544    if(header->checksum == 0x0000)
00545       header->checksum = 0xFFFF;
00546 
00547    //Total number of UDP datagrams sent from this entity
00548    MIB2_INC_COUNTER32(mib2Base.udpGroup.udpOutDatagrams, 1);
00549    MIB2_INC_COUNTER64(mib2Base.udpGroup.udpHCOutDatagrams, 1);
00550 
00551    //Debug message
00552    TRACE_INFO("Sending UDP datagram (%" PRIuSIZE " bytes)\r\n", length);
00553    //Dump UDP header contents for debugging purpose
00554    udpDumpHeader(header);
00555 
00556    //Send UDP datagram
00557    error = ipSendDatagram(interface, &pseudoHeader, buffer, offset, ttl);
00558    //Return status code
00559    return error;
00560 }
00561 
00562 
00563 /**
00564  * @brief Receive data from a UDP socket
00565  * @param[in] socket Handle referencing the socket
00566  * @param[out] srcIpAddr Source IP address (optional)
00567  * @param[out] srcPort Source port number (optional)
00568  * @param[out] destIpAddr Destination IP address (optional)
00569  * @param[out] data Buffer where to store the incoming data
00570  * @param[in] size Maximum number of bytes that can be received
00571  * @param[out] received Number of bytes that have been received
00572  * @param[in] flags Set of flags that influences the behavior of this function
00573  * @return Error code
00574  **/
00575 
00576 error_t udpReceiveDatagram(Socket *socket, IpAddr *srcIpAddr, uint16_t *srcPort,
00577    IpAddr *destIpAddr, void *data, size_t size, size_t *received, uint_t flags)
00578 {
00579    SocketQueueItem *queueItem;
00580 
00581    //The SOCKET_FLAG_DONT_WAIT enables non-blocking operation
00582    if(!(flags & SOCKET_FLAG_DONT_WAIT))
00583    {
00584       //The receive queue is empty?
00585       if(!socket->receiveQueue)
00586       {
00587          //Set the events the application is interested in
00588          socket->eventMask = SOCKET_EVENT_RX_READY;
00589          //Reset the event object
00590          osResetEvent(&socket->event);
00591 
00592          //Release exclusive access
00593          osReleaseMutex(&netMutex);
00594          //Wait until an event is triggered
00595          osWaitForEvent(&socket->event, socket->timeout);
00596          //Get exclusive access
00597          osAcquireMutex(&netMutex);
00598       }
00599    }
00600 
00601    //Check whether the read operation timed out
00602    if(!socket->receiveQueue)
00603    {
00604       //No data can be read
00605       *received = 0;
00606       //Report a timeout error
00607       return ERROR_TIMEOUT;
00608    }
00609 
00610    //Point to the first item in the receive queue
00611    queueItem = socket->receiveQueue;
00612    //Copy data to user buffer
00613    *received = netBufferRead(data, queueItem->buffer, queueItem->offset, size);
00614 
00615    //Save the source IP address
00616    if(srcIpAddr)
00617       *srcIpAddr = queueItem->srcIpAddr;
00618    //Save the source port number
00619    if(srcPort)
00620       *srcPort = queueItem->srcPort;
00621    //Save the destination IP address
00622    if(destIpAddr)
00623       *destIpAddr = queueItem->destIpAddr;
00624 
00625    //If the SOCKET_FLAG_PEEK flag is set, the data is copied
00626    //into the buffer but is not removed from the input queue
00627    if(!(flags & SOCKET_FLAG_PEEK))
00628    {
00629       //Remove the item from the receive queue
00630       socket->receiveQueue = queueItem->next;
00631       //Deallocate memory buffer
00632       netBufferFree(queueItem->buffer);
00633    }
00634 
00635    //Update the state of events
00636    udpUpdateEvents(socket);
00637 
00638    //Successful read operation
00639    return NO_ERROR;
00640 }
00641 
00642 
00643 /**
00644  * @brief Allocate a buffer to hold a UDP packet
00645  * @param[in] length Desired payload length
00646  * @param[out] offset Offset to the first byte of the payload
00647  * @return The function returns a pointer to the newly allocated
00648  *   buffer. If the system is out of resources, NULL is returned
00649  **/
00650 
00651 NetBuffer *udpAllocBuffer(size_t length, size_t *offset)
00652 {
00653    NetBuffer *buffer;
00654 
00655    //Allocate a buffer to hold the UDP header and the payload
00656    buffer = ipAllocBuffer(length + sizeof(UdpHeader), offset);
00657    //Failed to allocate buffer?
00658    if(buffer == NULL)
00659       return NULL;
00660 
00661    //Offset to the first byte of the payload
00662    *offset += sizeof(UdpHeader);
00663 
00664    //Return a pointer to the freshly allocated buffer
00665    return buffer;
00666 }
00667 
00668 
00669 /**
00670  * @brief Update UDP related events
00671  * @param[in] socket Handle referencing the socket
00672  **/
00673 
00674 void udpUpdateEvents(Socket *socket)
00675 {
00676    //Clear event flags
00677    socket->eventFlags = 0;
00678 
00679    //The socket is marked as readable if a datagram is pending in the queue
00680    if(socket->receiveQueue)
00681       socket->eventFlags |= SOCKET_EVENT_RX_READY;
00682 
00683    //Check whether the socket is bound to a particular network interface
00684    if(socket->interface != NULL)
00685    {
00686       //Handle link up and link down events
00687       if(socket->interface->linkState)
00688          socket->eventFlags |= SOCKET_EVENT_LINK_UP;
00689       else
00690          socket->eventFlags |= SOCKET_EVENT_LINK_DOWN;
00691    }
00692 
00693    //Mask unused events
00694    socket->eventFlags &= socket->eventMask;
00695 
00696    //Any event to signal?
00697    if(socket->eventFlags)
00698    {
00699       //Unblock I/O operations currently in waiting state
00700       osSetEvent(&socket->event);
00701 
00702       //Set user event to signaled state if necessary
00703       if(socket->userEvent != NULL)
00704          osSetEvent(socket->userEvent);
00705    }
00706 }
00707 
00708 
00709 /**
00710  * @brief Register user callback
00711  * @param[in] interface Underlying network interface
00712  * @param[in] port UDP port number
00713  * @param[in] callback Callback function to be called when a datagram is received
00714  * @param[in] params Callback function parameter (optional)
00715  * @return Error code
00716  **/
00717 
00718 error_t udpAttachRxCallback(NetInterface *interface,
00719    uint16_t port, UdpRxCallback callback, void *params)
00720 {
00721    uint_t i;
00722    UdpRxCallbackDesc *entry;
00723 
00724    //Acquire exclusive access to the callback table
00725    osAcquireMutex(&udpCallbackMutex);
00726 
00727    //Loop through the table
00728    for(i = 0; i < UDP_CALLBACK_TABLE_SIZE; i++)
00729    {
00730       //Point to the current entry
00731       entry = &udpCallbackTable[i];
00732 
00733       //Check whether the entry is currently in used
00734       if(entry->callback == NULL)
00735       {
00736          //Create a new entry
00737          entry->interface = interface;
00738          entry->port = port;
00739          entry->callback = callback;
00740          entry->params = params;
00741          //We are done
00742          break;
00743       }
00744    }
00745 
00746    //Release exclusive access to the callback table
00747    osReleaseMutex(&udpCallbackMutex);
00748 
00749    //Failed to attach the specified user callback?
00750    if(i >= UDP_CALLBACK_TABLE_SIZE)
00751       return ERROR_OUT_OF_RESOURCES;
00752 
00753    //Successful processing
00754    return NO_ERROR;
00755 }
00756 
00757 
00758 /**
00759  * @brief Unregister user callback
00760  * @param[in] interface Underlying network interface
00761  * @param[in] port UDP port number
00762  * @return Error code
00763  **/
00764 
00765 error_t udpDetachRxCallback(NetInterface *interface, uint16_t port)
00766 {
00767    error_t error;
00768    uint_t i;
00769    UdpRxCallbackDesc *entry;
00770 
00771    //Initialize status code
00772    error = ERROR_FAILURE;
00773 
00774    //Acquire exclusive access to the callback table
00775    osAcquireMutex(&udpCallbackMutex);
00776 
00777    //Loop through the table
00778    for(i = 0; i < UDP_CALLBACK_TABLE_SIZE; i++)
00779    {
00780       //Point to the current entry
00781       entry = &udpCallbackTable[i];
00782 
00783       //Check whether the entry is currently in used
00784       if(entry->callback != NULL)
00785       {
00786          //Does the specified port number match the current entry?
00787          if(entry->port == port && entry->interface == interface)
00788          {
00789             //Unregister user callback
00790             entry->callback = NULL;
00791             //A matching entry has been found
00792             error = NO_ERROR;
00793          }
00794       }
00795    }
00796 
00797    //Release exclusive access to the callback table
00798    osReleaseMutex(&udpCallbackMutex);
00799 
00800    //Return status code
00801    return error;
00802 }
00803 
00804 
00805 /**
00806  * @brief Invoke user callback
00807  * @param[in] interface Underlying network interface
00808  * @param[in] pseudoHeader UDP pseudo header
00809  * @param[in] header UDP header
00810  * @param[in] buffer Multi-part buffer containing the payload
00811  * @param[in] offset Offset to the first byte of the payload
00812  * @return Error code
00813  **/
00814 
00815 error_t udpInvokeRxCallback(NetInterface *interface, const IpPseudoHeader *pseudoHeader,
00816    const UdpHeader *header, const NetBuffer *buffer, size_t offset)
00817 {
00818    error_t error;
00819    uint_t i;
00820    void *params;
00821    UdpRxCallbackDesc *entry;
00822 
00823    //Initialize status code
00824    error = ERROR_PORT_UNREACHABLE;
00825 
00826    //Acquire exclusive access to the callback table
00827    osAcquireMutex(&udpCallbackMutex);
00828 
00829    //Loop through the table
00830    for(i = 0; i < UDP_CALLBACK_TABLE_SIZE; i++)
00831    {
00832       //Point to the current entry
00833       entry = &udpCallbackTable[i];
00834 
00835       //Check whether the entry is currently in used
00836       if(entry->callback != NULL)
00837       {
00838          //Bound to a particular interface?
00839          if(entry->interface == NULL || entry->interface == interface)
00840          {
00841             //Does the specified port number match the current entry?
00842             if(entry->port == ntohs(header->destPort))
00843             {
00844                //Retrieve callback parameters
00845                params = entry->params;
00846 
00847                //Release mutex to prevent any deadlock
00848                if(params == NULL)
00849                   osReleaseMutex(&udpCallbackMutex);
00850 
00851                //Invoke user callback function
00852                entry->callback(interface, pseudoHeader,
00853                   header, buffer, offset, params);
00854 
00855                //Acquire mutex
00856                if(params == NULL)
00857                   osAcquireMutex(&udpCallbackMutex);
00858 
00859                //A matching entry has been found
00860                error = NO_ERROR;
00861             }
00862          }
00863       }
00864    }
00865 
00866    //Release exclusive access to the callback table
00867    osReleaseMutex(&udpCallbackMutex);
00868 
00869    //Check status code
00870    if(error)
00871    {
00872       //Total number of received UDP datagrams for which there was
00873       //no application at the destination port
00874       MIB2_INC_COUNTER32(mib2Base.udpGroup.udpNoPorts, 1);
00875    }
00876    else
00877    {
00878       //Total number of UDP datagrams delivered to UDP users
00879       MIB2_INC_COUNTER32(mib2Base.udpGroup.udpInDatagrams, 1);
00880       MIB2_INC_COUNTER64(mib2Base.udpGroup.udpHCInDatagrams, 1);
00881    }
00882 
00883    //Return status code
00884    return error;
00885 }
00886 
00887 
00888 /**
00889  * @brief Dump UDP header for debugging purpose
00890  * @param[in] datagram Pointer to the UDP header
00891  **/
00892 
00893 void udpDumpHeader(const UdpHeader *datagram)
00894 {
00895    //Dump UDP header contents
00896    TRACE_DEBUG("  Source Port = %" PRIu16 "\r\n", ntohs(datagram->srcPort));
00897    TRACE_DEBUG("  Destination Port = %" PRIu16 "\r\n", ntohs(datagram->destPort));
00898    TRACE_DEBUG("  Length = %" PRIu16 "\r\n", ntohs(datagram->length));
00899    TRACE_DEBUG("  Checksum = 0x%04" PRIX16 "\r\n", ntohs(datagram->checksum));
00900 }
00901 
00902 #endif
00903