Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
udp.c
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
Generated on Tue Jul 12 2022 17:10:17 by
