1195972f6Sopenharmony_ci/** 2195972f6Sopenharmony_ci * @file 3195972f6Sopenharmony_ci * User Datagram Protocol module\n 4195972f6Sopenharmony_ci * The code for the User Datagram Protocol UDP & UDPLite (RFC 3828).\n 5195972f6Sopenharmony_ci * See also @ref udp_raw 6195972f6Sopenharmony_ci * 7195972f6Sopenharmony_ci * @defgroup udp_raw UDP 8195972f6Sopenharmony_ci * @ingroup callbackstyle_api 9195972f6Sopenharmony_ci * User Datagram Protocol module\n 10195972f6Sopenharmony_ci * @see @ref api 11195972f6Sopenharmony_ci */ 12195972f6Sopenharmony_ci 13195972f6Sopenharmony_ci/* 14195972f6Sopenharmony_ci * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 15195972f6Sopenharmony_ci * All rights reserved. 16195972f6Sopenharmony_ci * 17195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification, 18195972f6Sopenharmony_ci * are permitted provided that the following conditions are met: 19195972f6Sopenharmony_ci * 20195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, 21195972f6Sopenharmony_ci * this list of conditions and the following disclaimer. 22195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, 23195972f6Sopenharmony_ci * this list of conditions and the following disclaimer in the documentation 24195972f6Sopenharmony_ci * and/or other materials provided with the distribution. 25195972f6Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products 26195972f6Sopenharmony_ci * derived from this software without specific prior written permission. 27195972f6Sopenharmony_ci * 28195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 29195972f6Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 30195972f6Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 31195972f6Sopenharmony_ci * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 32195972f6Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 33195972f6Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34195972f6Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35195972f6Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 36195972f6Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 37195972f6Sopenharmony_ci * OF SUCH DAMAGE. 38195972f6Sopenharmony_ci * 39195972f6Sopenharmony_ci * This file is part of the lwIP TCP/IP stack. 40195972f6Sopenharmony_ci * 41195972f6Sopenharmony_ci * Author: Adam Dunkels <adam@sics.se> 42195972f6Sopenharmony_ci * 43195972f6Sopenharmony_ci */ 44195972f6Sopenharmony_ci 45195972f6Sopenharmony_ci/* @todo Check the use of '(struct udp_pcb).chksum_len_rx'! 46195972f6Sopenharmony_ci */ 47195972f6Sopenharmony_ci 48195972f6Sopenharmony_ci#include "lwip/opt.h" 49195972f6Sopenharmony_ci 50195972f6Sopenharmony_ci#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ 51195972f6Sopenharmony_ci 52195972f6Sopenharmony_ci#include "lwip/udp.h" 53195972f6Sopenharmony_ci#include "lwip/def.h" 54195972f6Sopenharmony_ci#include "lwip/memp.h" 55195972f6Sopenharmony_ci#include "lwip/inet_chksum.h" 56195972f6Sopenharmony_ci#include "lwip/ip_addr.h" 57195972f6Sopenharmony_ci#include "lwip/ip6.h" 58195972f6Sopenharmony_ci#include "lwip/ip6_addr.h" 59195972f6Sopenharmony_ci#include "lwip/netif.h" 60195972f6Sopenharmony_ci#include "lwip/icmp.h" 61195972f6Sopenharmony_ci#include "lwip/icmp6.h" 62195972f6Sopenharmony_ci#include "lwip/stats.h" 63195972f6Sopenharmony_ci#include "lwip/snmp.h" 64195972f6Sopenharmony_ci#include "lwip/dhcp.h" 65195972f6Sopenharmony_ci 66195972f6Sopenharmony_ci#include <string.h> 67195972f6Sopenharmony_ci 68195972f6Sopenharmony_ci#ifndef UDP_LOCAL_PORT_RANGE_START 69195972f6Sopenharmony_ci/* From http://www.iana.org/assignments/port-numbers: 70195972f6Sopenharmony_ci "The Dynamic and/or Private Ports are those from 49152 through 65535" */ 71195972f6Sopenharmony_ci#define UDP_LOCAL_PORT_RANGE_START 0xc000 72195972f6Sopenharmony_ci#define UDP_LOCAL_PORT_RANGE_END 0xffff 73195972f6Sopenharmony_ci#define UDP_ENSURE_LOCAL_PORT_RANGE(port) ((u16_t)(((port) & (u16_t)~UDP_LOCAL_PORT_RANGE_START) + UDP_LOCAL_PORT_RANGE_START)) 74195972f6Sopenharmony_ci#endif 75195972f6Sopenharmony_ci 76195972f6Sopenharmony_ci/* last local UDP port */ 77195972f6Sopenharmony_cistatic u16_t udp_port = UDP_LOCAL_PORT_RANGE_START; 78195972f6Sopenharmony_ci 79195972f6Sopenharmony_ci/* The list of UDP PCBs */ 80195972f6Sopenharmony_ci/* exported in udp.h (was static) */ 81195972f6Sopenharmony_cistruct udp_pcb *udp_pcbs; 82195972f6Sopenharmony_ci 83195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 84195972f6Sopenharmony_civoid set_udp_pcb_net_group(struct udp_pcb *pcb, struct net_group *group) 85195972f6Sopenharmony_ci{ 86195972f6Sopenharmony_ci set_ippcb_net_group((struct ip_pcb *)pcb, group); 87195972f6Sopenharmony_ci} 88195972f6Sopenharmony_ci 89195972f6Sopenharmony_cistruct net_group *get_net_group_from_udp_pcb(struct udp_pcb *pcb) 90195972f6Sopenharmony_ci{ 91195972f6Sopenharmony_ci return get_net_group_from_ippcb((struct ip_pcb *)pcb); 92195972f6Sopenharmony_ci} 93195972f6Sopenharmony_ci#endif 94195972f6Sopenharmony_ci/** 95195972f6Sopenharmony_ci * Initialize this module. 96195972f6Sopenharmony_ci */ 97195972f6Sopenharmony_civoid 98195972f6Sopenharmony_ciudp_init(void) 99195972f6Sopenharmony_ci{ 100195972f6Sopenharmony_ci#ifdef LWIP_RAND 101195972f6Sopenharmony_ci udp_port = UDP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); 102195972f6Sopenharmony_ci#endif /* LWIP_RAND */ 103195972f6Sopenharmony_ci} 104195972f6Sopenharmony_ci 105195972f6Sopenharmony_ci/** 106195972f6Sopenharmony_ci * Allocate a new local UDP port. 107195972f6Sopenharmony_ci * 108195972f6Sopenharmony_ci * @return a new (free) local UDP port number 109195972f6Sopenharmony_ci */ 110195972f6Sopenharmony_cistatic u16_t 111195972f6Sopenharmony_ciudp_new_port(void) 112195972f6Sopenharmony_ci{ 113195972f6Sopenharmony_ci u16_t n = 0; 114195972f6Sopenharmony_ci struct udp_pcb *pcb; 115195972f6Sopenharmony_ci 116195972f6Sopenharmony_ciagain: 117195972f6Sopenharmony_ci if (udp_port++ == UDP_LOCAL_PORT_RANGE_END) { 118195972f6Sopenharmony_ci udp_port = UDP_LOCAL_PORT_RANGE_START; 119195972f6Sopenharmony_ci } 120195972f6Sopenharmony_ci /* Check all PCBs. */ 121195972f6Sopenharmony_ci for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { 122195972f6Sopenharmony_ci if (pcb->local_port == udp_port) { 123195972f6Sopenharmony_ci if (++n > (UDP_LOCAL_PORT_RANGE_END - UDP_LOCAL_PORT_RANGE_START)) { 124195972f6Sopenharmony_ci return 0; 125195972f6Sopenharmony_ci } 126195972f6Sopenharmony_ci goto again; 127195972f6Sopenharmony_ci } 128195972f6Sopenharmony_ci } 129195972f6Sopenharmony_ci return udp_port; 130195972f6Sopenharmony_ci} 131195972f6Sopenharmony_ci 132195972f6Sopenharmony_ci/** Common code to see if the current input packet matches the pcb 133195972f6Sopenharmony_ci * (current input packet is accessed via ip(4/6)_current_* macros) 134195972f6Sopenharmony_ci * 135195972f6Sopenharmony_ci * @param pcb pcb to check 136195972f6Sopenharmony_ci * @param inp network interface on which the datagram was received (only used for IPv4) 137195972f6Sopenharmony_ci * @param broadcast 1 if his is an IPv4 broadcast (global or subnet-only), 0 otherwise (only used for IPv4) 138195972f6Sopenharmony_ci * @return 1 on match, 0 otherwise 139195972f6Sopenharmony_ci */ 140195972f6Sopenharmony_cistatic u8_t 141195972f6Sopenharmony_ciudp_input_local_match(struct udp_pcb *pcb, struct netif *inp, u8_t broadcast) 142195972f6Sopenharmony_ci{ 143195972f6Sopenharmony_ci LWIP_UNUSED_ARG(inp); /* in IPv6 only case */ 144195972f6Sopenharmony_ci LWIP_UNUSED_ARG(broadcast); /* in IPv6 only case */ 145195972f6Sopenharmony_ci 146195972f6Sopenharmony_ci LWIP_ASSERT("udp_input_local_match: invalid pcb", pcb != NULL); 147195972f6Sopenharmony_ci LWIP_ASSERT("udp_input_local_match: invalid netif", inp != NULL); 148195972f6Sopenharmony_ci 149195972f6Sopenharmony_ci /* check if PCB is bound to specific netif */ 150195972f6Sopenharmony_ci if ((pcb->netif_idx != NETIF_NO_INDEX) && 151195972f6Sopenharmony_ci (pcb->netif_idx != netif_get_index(ip_data.current_input_netif))) { 152195972f6Sopenharmony_ci return 0; 153195972f6Sopenharmony_ci } 154195972f6Sopenharmony_ci 155195972f6Sopenharmony_ci /* Dual-stack: PCBs listening to any IP type also listen to any IP address */ 156195972f6Sopenharmony_ci if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { 157195972f6Sopenharmony_ci#if LWIP_IPV4 && IP_SOF_BROADCAST_RECV 158195972f6Sopenharmony_ci if ((broadcast != 0) && !ip_get_option(pcb, SOF_BROADCAST)) { 159195972f6Sopenharmony_ci return 0; 160195972f6Sopenharmony_ci } 161195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && IP_SOF_BROADCAST_RECV */ 162195972f6Sopenharmony_ci return 1; 163195972f6Sopenharmony_ci } 164195972f6Sopenharmony_ci 165195972f6Sopenharmony_ci /* Only need to check PCB if incoming IP version matches PCB IP version */ 166195972f6Sopenharmony_ci if (IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ip_current_dest_addr())) { 167195972f6Sopenharmony_ci#if LWIP_IPV4 168195972f6Sopenharmony_ci /* Special case: IPv4 broadcast: all or broadcasts in my subnet 169195972f6Sopenharmony_ci * Note: broadcast variable can only be 1 if it is an IPv4 broadcast */ 170195972f6Sopenharmony_ci if (broadcast != 0) { 171195972f6Sopenharmony_ci#if IP_SOF_BROADCAST_RECV 172195972f6Sopenharmony_ci if (ip_get_option(pcb, SOF_BROADCAST)) 173195972f6Sopenharmony_ci#endif /* IP_SOF_BROADCAST_RECV */ 174195972f6Sopenharmony_ci { 175195972f6Sopenharmony_ci if (ip4_addr_isany(ip_2_ip4(&pcb->local_ip)) || 176195972f6Sopenharmony_ci ((ip4_current_dest_addr()->addr == IPADDR_BROADCAST)) || 177195972f6Sopenharmony_ci ip4_addr_netcmp(ip_2_ip4(&pcb->local_ip), ip4_current_dest_addr(), netif_ip4_netmask(inp))) { 178195972f6Sopenharmony_ci return 1; 179195972f6Sopenharmony_ci } 180195972f6Sopenharmony_ci } 181195972f6Sopenharmony_ci } else 182195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */ 183195972f6Sopenharmony_ci /* Handle IPv4 and IPv6: all or exact match */ 184195972f6Sopenharmony_ci if (ip_addr_isany(&pcb->local_ip) || ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { 185195972f6Sopenharmony_ci return 1; 186195972f6Sopenharmony_ci } 187195972f6Sopenharmony_ci } 188195972f6Sopenharmony_ci 189195972f6Sopenharmony_ci return 0; 190195972f6Sopenharmony_ci} 191195972f6Sopenharmony_ci 192195972f6Sopenharmony_ci/** 193195972f6Sopenharmony_ci * Process an incoming UDP datagram. 194195972f6Sopenharmony_ci * 195195972f6Sopenharmony_ci * Given an incoming UDP datagram (as a chain of pbufs) this function 196195972f6Sopenharmony_ci * finds a corresponding UDP PCB and hands over the pbuf to the pcbs 197195972f6Sopenharmony_ci * recv function. If no pcb is found or the datagram is incorrect, the 198195972f6Sopenharmony_ci * pbuf is freed. 199195972f6Sopenharmony_ci * 200195972f6Sopenharmony_ci * @param p pbuf to be demultiplexed to a UDP PCB (p->payload pointing to the UDP header) 201195972f6Sopenharmony_ci * @param inp network interface on which the datagram was received. 202195972f6Sopenharmony_ci * 203195972f6Sopenharmony_ci */ 204195972f6Sopenharmony_civoid 205195972f6Sopenharmony_ciudp_input(struct pbuf *p, struct netif *inp) 206195972f6Sopenharmony_ci{ 207195972f6Sopenharmony_ci struct udp_hdr *udphdr; 208195972f6Sopenharmony_ci struct udp_pcb *pcb, *prev; 209195972f6Sopenharmony_ci struct udp_pcb *uncon_pcb; 210195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 211195972f6Sopenharmony_ci struct net_group *inp_net_group = get_net_group_from_netif(inp); 212195972f6Sopenharmony_ci#endif 213195972f6Sopenharmony_ci u16_t src, dest; 214195972f6Sopenharmony_ci u8_t broadcast; 215195972f6Sopenharmony_ci u8_t for_us = 0; 216195972f6Sopenharmony_ci 217195972f6Sopenharmony_ci LWIP_UNUSED_ARG(inp); 218195972f6Sopenharmony_ci 219195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 220195972f6Sopenharmony_ci 221195972f6Sopenharmony_ci LWIP_ASSERT("udp_input: invalid pbuf", p != NULL); 222195972f6Sopenharmony_ci LWIP_ASSERT("udp_input: invalid netif", inp != NULL); 223195972f6Sopenharmony_ci 224195972f6Sopenharmony_ci PERF_START; 225195972f6Sopenharmony_ci 226195972f6Sopenharmony_ci UDP_STATS_INC(udp.recv); 227195972f6Sopenharmony_ci 228195972f6Sopenharmony_ci /* Check minimum length (UDP header) */ 229195972f6Sopenharmony_ci if (p->len < UDP_HLEN) { 230195972f6Sopenharmony_ci /* drop short packets */ 231195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, 232195972f6Sopenharmony_ci ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len)); 233195972f6Sopenharmony_ci UDP_STATS_INC(udp.lenerr); 234195972f6Sopenharmony_ci UDP_STATS_INC(udp.drop); 235195972f6Sopenharmony_ci MIB2_STATS_INC(mib2.udpinerrors); 236195972f6Sopenharmony_ci pbuf_free(p); 237195972f6Sopenharmony_ci goto end; 238195972f6Sopenharmony_ci } 239195972f6Sopenharmony_ci 240195972f6Sopenharmony_ci udphdr = (struct udp_hdr *)p->payload; 241195972f6Sopenharmony_ci 242195972f6Sopenharmony_ci /* is broadcast packet ? */ 243195972f6Sopenharmony_ci broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()); 244195972f6Sopenharmony_ci 245195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len)); 246195972f6Sopenharmony_ci 247195972f6Sopenharmony_ci /* convert src and dest ports to host byte order */ 248195972f6Sopenharmony_ci src = lwip_ntohs(udphdr->src); 249195972f6Sopenharmony_ci dest = lwip_ntohs(udphdr->dest); 250195972f6Sopenharmony_ci 251195972f6Sopenharmony_ci udp_debug_print(udphdr); 252195972f6Sopenharmony_ci 253195972f6Sopenharmony_ci /* print the UDP source and destination */ 254195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, ("udp (")); 255195972f6Sopenharmony_ci ip_addr_debug_print_val(UDP_DEBUG, *ip_current_dest_addr()); 256195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", lwip_ntohs(udphdr->dest))); 257195972f6Sopenharmony_ci ip_addr_debug_print_val(UDP_DEBUG, *ip_current_src_addr()); 258195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", lwip_ntohs(udphdr->src))); 259195972f6Sopenharmony_ci 260195972f6Sopenharmony_ci pcb = NULL; 261195972f6Sopenharmony_ci prev = NULL; 262195972f6Sopenharmony_ci uncon_pcb = NULL; 263195972f6Sopenharmony_ci /* Iterate through the UDP pcb list for a matching pcb. 264195972f6Sopenharmony_ci * 'Perfect match' pcbs (connected to the remote port & ip address) are 265195972f6Sopenharmony_ci * preferred. If no perfect match is found, the first unconnected pcb that 266195972f6Sopenharmony_ci * matches the local port and ip address gets the datagram. */ 267195972f6Sopenharmony_ci for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { 268195972f6Sopenharmony_ci /* print the PCB local and remote address */ 269195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, ("pcb (")); 270195972f6Sopenharmony_ci ip_addr_debug_print_val(UDP_DEBUG, pcb->local_ip); 271195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", pcb->local_port)); 272195972f6Sopenharmony_ci ip_addr_debug_print_val(UDP_DEBUG, pcb->remote_ip); 273195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", pcb->remote_port)); 274195972f6Sopenharmony_ci 275195972f6Sopenharmony_ci /* compare PCB local addr+port to UDP destination addr+port */ 276195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 277195972f6Sopenharmony_ci if (inp_net_group == get_net_group_from_udp_pcb(pcb) && (pcb->local_port == dest) && 278195972f6Sopenharmony_ci#else 279195972f6Sopenharmony_ci if ((pcb->local_port == dest) && 280195972f6Sopenharmony_ci#endif 281195972f6Sopenharmony_ci (udp_input_local_match(pcb, inp, broadcast) != 0)) { 282195972f6Sopenharmony_ci if ((pcb->flags & UDP_FLAGS_CONNECTED) == 0) { 283195972f6Sopenharmony_ci if (uncon_pcb == NULL) { 284195972f6Sopenharmony_ci /* the first unconnected matching PCB */ 285195972f6Sopenharmony_ci uncon_pcb = pcb; 286195972f6Sopenharmony_ci#if LWIP_IPV4 287195972f6Sopenharmony_ci } else if (broadcast && ip4_current_dest_addr()->addr == IPADDR_BROADCAST) { 288195972f6Sopenharmony_ci /* global broadcast address (only valid for IPv4; match was checked before) */ 289195972f6Sopenharmony_ci if (!IP_IS_V4_VAL(uncon_pcb->local_ip) || !ip4_addr_cmp(ip_2_ip4(&uncon_pcb->local_ip), netif_ip4_addr(inp))) { 290195972f6Sopenharmony_ci /* uncon_pcb does not match the input netif, check this pcb */ 291195972f6Sopenharmony_ci if (IP_IS_V4_VAL(pcb->local_ip) && ip4_addr_cmp(ip_2_ip4(&pcb->local_ip), netif_ip4_addr(inp))) { 292195972f6Sopenharmony_ci /* better match */ 293195972f6Sopenharmony_ci uncon_pcb = pcb; 294195972f6Sopenharmony_ci } 295195972f6Sopenharmony_ci } 296195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */ 297195972f6Sopenharmony_ci } 298195972f6Sopenharmony_ci#if SO_REUSE 299195972f6Sopenharmony_ci else if (!ip_addr_isany(&pcb->local_ip)) { 300195972f6Sopenharmony_ci /* prefer specific IPs over catch-all */ 301195972f6Sopenharmony_ci uncon_pcb = pcb; 302195972f6Sopenharmony_ci } 303195972f6Sopenharmony_ci#endif /* SO_REUSE */ 304195972f6Sopenharmony_ci } 305195972f6Sopenharmony_ci 306195972f6Sopenharmony_ci /* compare PCB remote addr+port to UDP source addr+port */ 307195972f6Sopenharmony_ci if ((pcb->remote_port == src) && 308195972f6Sopenharmony_ci (ip_addr_isany_val(pcb->remote_ip) || 309195972f6Sopenharmony_ci ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()))) { 310195972f6Sopenharmony_ci /* the first fully matching PCB */ 311195972f6Sopenharmony_ci if (prev != NULL) { 312195972f6Sopenharmony_ci /* move the pcb to the front of udp_pcbs so that is 313195972f6Sopenharmony_ci found faster next time */ 314195972f6Sopenharmony_ci prev->next = pcb->next; 315195972f6Sopenharmony_ci pcb->next = udp_pcbs; 316195972f6Sopenharmony_ci udp_pcbs = pcb; 317195972f6Sopenharmony_ci } else { 318195972f6Sopenharmony_ci UDP_STATS_INC(udp.cachehit); 319195972f6Sopenharmony_ci } 320195972f6Sopenharmony_ci break; 321195972f6Sopenharmony_ci } 322195972f6Sopenharmony_ci } 323195972f6Sopenharmony_ci 324195972f6Sopenharmony_ci prev = pcb; 325195972f6Sopenharmony_ci } 326195972f6Sopenharmony_ci /* no fully matching pcb found? then look for an unconnected pcb */ 327195972f6Sopenharmony_ci if (pcb == NULL) { 328195972f6Sopenharmony_ci pcb = uncon_pcb; 329195972f6Sopenharmony_ci } 330195972f6Sopenharmony_ci 331195972f6Sopenharmony_ci /* Check checksum if this is a match or if it was directed at us. */ 332195972f6Sopenharmony_ci if (pcb != NULL) { 333195972f6Sopenharmony_ci for_us = 1; 334195972f6Sopenharmony_ci } else { 335195972f6Sopenharmony_ci#if LWIP_IPV6 336195972f6Sopenharmony_ci if (ip_current_is_v6()) { 337195972f6Sopenharmony_ci for_us = netif_get_ip6_addr_match(inp, ip6_current_dest_addr()) >= 0; 338195972f6Sopenharmony_ci } 339195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */ 340195972f6Sopenharmony_ci#if LWIP_IPV4 341195972f6Sopenharmony_ci if (!ip_current_is_v6()) { 342195972f6Sopenharmony_ci for_us = ip4_addr_cmp(netif_ip4_addr(inp), ip4_current_dest_addr()); 343195972f6Sopenharmony_ci } 344195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */ 345195972f6Sopenharmony_ci } 346195972f6Sopenharmony_ci 347195972f6Sopenharmony_ci if (for_us) { 348195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n")); 349195972f6Sopenharmony_ci#if CHECKSUM_CHECK_UDP 350195972f6Sopenharmony_ci IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_UDP) { 351195972f6Sopenharmony_ci#if LWIP_UDPLITE 352195972f6Sopenharmony_ci if (ip_current_header_proto() == IP_PROTO_UDPLITE) { 353195972f6Sopenharmony_ci /* Do the UDP Lite checksum */ 354195972f6Sopenharmony_ci u16_t chklen = lwip_ntohs(udphdr->len); 355195972f6Sopenharmony_ci if (chklen < sizeof(struct udp_hdr)) { 356195972f6Sopenharmony_ci if (chklen == 0) { 357195972f6Sopenharmony_ci /* For UDP-Lite, checksum length of 0 means checksum 358195972f6Sopenharmony_ci over the complete packet (See RFC 3828 chap. 3.1) */ 359195972f6Sopenharmony_ci chklen = p->tot_len; 360195972f6Sopenharmony_ci } else { 361195972f6Sopenharmony_ci /* At least the UDP-Lite header must be covered by the 362195972f6Sopenharmony_ci checksum! (Again, see RFC 3828 chap. 3.1) */ 363195972f6Sopenharmony_ci goto chkerr; 364195972f6Sopenharmony_ci } 365195972f6Sopenharmony_ci } 366195972f6Sopenharmony_ci if (ip_chksum_pseudo_partial(p, IP_PROTO_UDPLITE, 367195972f6Sopenharmony_ci p->tot_len, chklen, 368195972f6Sopenharmony_ci ip_current_src_addr(), ip_current_dest_addr()) != 0) { 369195972f6Sopenharmony_ci goto chkerr; 370195972f6Sopenharmony_ci } 371195972f6Sopenharmony_ci } else 372195972f6Sopenharmony_ci#endif /* LWIP_UDPLITE */ 373195972f6Sopenharmony_ci { 374195972f6Sopenharmony_ci if (udphdr->chksum != 0) { 375195972f6Sopenharmony_ci if (ip_chksum_pseudo(p, IP_PROTO_UDP, p->tot_len, 376195972f6Sopenharmony_ci ip_current_src_addr(), 377195972f6Sopenharmony_ci ip_current_dest_addr()) != 0) { 378195972f6Sopenharmony_ci goto chkerr; 379195972f6Sopenharmony_ci } 380195972f6Sopenharmony_ci } 381195972f6Sopenharmony_ci } 382195972f6Sopenharmony_ci } 383195972f6Sopenharmony_ci#endif /* CHECKSUM_CHECK_UDP */ 384195972f6Sopenharmony_ci if (pbuf_remove_header(p, UDP_HLEN)) { 385195972f6Sopenharmony_ci /* Can we cope with this failing? Just assert for now */ 386195972f6Sopenharmony_ci LWIP_ASSERT("pbuf_remove_header failed\n", 0); 387195972f6Sopenharmony_ci UDP_STATS_INC(udp.drop); 388195972f6Sopenharmony_ci MIB2_STATS_INC(mib2.udpinerrors); 389195972f6Sopenharmony_ci pbuf_free(p); 390195972f6Sopenharmony_ci goto end; 391195972f6Sopenharmony_ci } 392195972f6Sopenharmony_ci 393195972f6Sopenharmony_ci if (pcb != NULL) { 394195972f6Sopenharmony_ci MIB2_STATS_INC(mib2.udpindatagrams); 395195972f6Sopenharmony_ci#if SO_REUSE && SO_REUSE_RXTOALL 396195972f6Sopenharmony_ci if (ip_get_option(pcb, SOF_REUSEADDR) && 397195972f6Sopenharmony_ci (broadcast || ip_addr_ismulticast(ip_current_dest_addr()))) { 398195972f6Sopenharmony_ci /* pass broadcast- or multicast packets to all multicast pcbs 399195972f6Sopenharmony_ci if SOF_REUSEADDR is set on the first match */ 400195972f6Sopenharmony_ci struct udp_pcb *mpcb; 401195972f6Sopenharmony_ci for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) { 402195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 403195972f6Sopenharmony_ci if (mpcb != pcb && inp_net_group == get_net_group_from_udp_pcb(mpcb)) { 404195972f6Sopenharmony_ci#else 405195972f6Sopenharmony_ci if (mpcb != pcb) { 406195972f6Sopenharmony_ci#endif 407195972f6Sopenharmony_ci /* compare PCB local addr+port to UDP destination addr+port */ 408195972f6Sopenharmony_ci if ((mpcb->local_port == dest) && 409195972f6Sopenharmony_ci (udp_input_local_match(mpcb, inp, broadcast) != 0)) { 410195972f6Sopenharmony_ci /* pass a copy of the packet to all local matches */ 411195972f6Sopenharmony_ci if (mpcb->recv != NULL) { 412195972f6Sopenharmony_ci struct pbuf *q; 413195972f6Sopenharmony_ci#if USE_PBUF_RAM_UDP_INPUT 414195972f6Sopenharmony_ci q = pbuf_clone(PBUF_RAW, PBUF_RAM, p); 415195972f6Sopenharmony_ci#else 416195972f6Sopenharmony_ci q = pbuf_clone(PBUF_RAW, PBUF_POOL, p); 417195972f6Sopenharmony_ci#endif 418195972f6Sopenharmony_ci if (q != NULL) { 419195972f6Sopenharmony_ci mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src); 420195972f6Sopenharmony_ci } 421195972f6Sopenharmony_ci } 422195972f6Sopenharmony_ci } 423195972f6Sopenharmony_ci } 424195972f6Sopenharmony_ci } 425195972f6Sopenharmony_ci } 426195972f6Sopenharmony_ci#endif /* SO_REUSE && SO_REUSE_RXTOALL */ 427195972f6Sopenharmony_ci /* callback */ 428195972f6Sopenharmony_ci if (pcb->recv != NULL) { 429195972f6Sopenharmony_ci /* now the recv function is responsible for freeing p */ 430195972f6Sopenharmony_ci pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src); 431195972f6Sopenharmony_ci } else { 432195972f6Sopenharmony_ci /* no recv function registered? then we have to free the pbuf! */ 433195972f6Sopenharmony_ci pbuf_free(p); 434195972f6Sopenharmony_ci goto end; 435195972f6Sopenharmony_ci } 436195972f6Sopenharmony_ci } else { 437195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n")); 438195972f6Sopenharmony_ci 439195972f6Sopenharmony_ci#if LWIP_ICMP || LWIP_ICMP6 440195972f6Sopenharmony_ci /* No match was found, send ICMP destination port unreachable unless 441195972f6Sopenharmony_ci destination address was broadcast/multicast. */ 442195972f6Sopenharmony_ci if (!broadcast && !ip_addr_ismulticast(ip_current_dest_addr())) { 443195972f6Sopenharmony_ci /* move payload pointer back to ip header */ 444195972f6Sopenharmony_ci pbuf_header_force(p, (s16_t)(ip_current_header_tot_len() + UDP_HLEN)); 445195972f6Sopenharmony_ci icmp_port_unreach(ip_current_is_v6(), p); 446195972f6Sopenharmony_ci } 447195972f6Sopenharmony_ci#endif /* LWIP_ICMP || LWIP_ICMP6 */ 448195972f6Sopenharmony_ci UDP_STATS_INC(udp.proterr); 449195972f6Sopenharmony_ci UDP_STATS_INC(udp.drop); 450195972f6Sopenharmony_ci MIB2_STATS_INC(mib2.udpnoports); 451195972f6Sopenharmony_ci pbuf_free(p); 452195972f6Sopenharmony_ci } 453195972f6Sopenharmony_ci } else { 454195972f6Sopenharmony_ci pbuf_free(p); 455195972f6Sopenharmony_ci } 456195972f6Sopenharmony_ciend: 457195972f6Sopenharmony_ci PERF_STOP("udp_input"); 458195972f6Sopenharmony_ci return; 459195972f6Sopenharmony_ci#if CHECKSUM_CHECK_UDP 460195972f6Sopenharmony_cichkerr: 461195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, 462195972f6Sopenharmony_ci ("udp_input: UDP (or UDP Lite) datagram discarded due to failing checksum\n")); 463195972f6Sopenharmony_ci UDP_STATS_INC(udp.chkerr); 464195972f6Sopenharmony_ci UDP_STATS_INC(udp.drop); 465195972f6Sopenharmony_ci MIB2_STATS_INC(mib2.udpinerrors); 466195972f6Sopenharmony_ci pbuf_free(p); 467195972f6Sopenharmony_ci PERF_STOP("udp_input"); 468195972f6Sopenharmony_ci#endif /* CHECKSUM_CHECK_UDP */ 469195972f6Sopenharmony_ci} 470195972f6Sopenharmony_ci 471195972f6Sopenharmony_ci/** 472195972f6Sopenharmony_ci * @ingroup udp_raw 473195972f6Sopenharmony_ci * Sends the pbuf p using UDP. The pbuf is not deallocated. 474195972f6Sopenharmony_ci * 475195972f6Sopenharmony_ci * 476195972f6Sopenharmony_ci * @param pcb UDP PCB used to send the data. 477195972f6Sopenharmony_ci * @param p chain of pbuf's to be sent. 478195972f6Sopenharmony_ci * 479195972f6Sopenharmony_ci * The datagram will be sent to the current remote_ip & remote_port 480195972f6Sopenharmony_ci * stored in pcb. If the pcb is not bound to a port, it will 481195972f6Sopenharmony_ci * automatically be bound to a random port. 482195972f6Sopenharmony_ci * 483195972f6Sopenharmony_ci * @return lwIP error code. 484195972f6Sopenharmony_ci * - ERR_OK. Successful. No error occurred. 485195972f6Sopenharmony_ci * - ERR_MEM. Out of memory. 486195972f6Sopenharmony_ci * - ERR_RTE. Could not find route to destination address. 487195972f6Sopenharmony_ci * - ERR_VAL. No PCB or PCB is dual-stack 488195972f6Sopenharmony_ci * - More errors could be returned by lower protocol layers. 489195972f6Sopenharmony_ci * 490195972f6Sopenharmony_ci * @see udp_disconnect() udp_sendto() 491195972f6Sopenharmony_ci */ 492195972f6Sopenharmony_cierr_t 493195972f6Sopenharmony_ciudp_send(struct udp_pcb *pcb, struct pbuf *p) 494195972f6Sopenharmony_ci{ 495195972f6Sopenharmony_ci LWIP_ERROR("udp_send: invalid pcb", pcb != NULL, return ERR_ARG); 496195972f6Sopenharmony_ci LWIP_ERROR("udp_send: invalid pbuf", p != NULL, return ERR_ARG); 497195972f6Sopenharmony_ci 498195972f6Sopenharmony_ci if (IP_IS_ANY_TYPE_VAL(pcb->remote_ip)) { 499195972f6Sopenharmony_ci return ERR_VAL; 500195972f6Sopenharmony_ci } 501195972f6Sopenharmony_ci 502195972f6Sopenharmony_ci /* send to the packet using remote ip and port stored in the pcb */ 503195972f6Sopenharmony_ci return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port); 504195972f6Sopenharmony_ci} 505195972f6Sopenharmony_ci 506195972f6Sopenharmony_ci#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP 507195972f6Sopenharmony_ci/** @ingroup udp_raw 508195972f6Sopenharmony_ci * Same as udp_send() but with checksum 509195972f6Sopenharmony_ci */ 510195972f6Sopenharmony_cierr_t 511195972f6Sopenharmony_ciudp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, 512195972f6Sopenharmony_ci u8_t have_chksum, u16_t chksum) 513195972f6Sopenharmony_ci{ 514195972f6Sopenharmony_ci LWIP_ERROR("udp_send_chksum: invalid pcb", pcb != NULL, return ERR_ARG); 515195972f6Sopenharmony_ci LWIP_ERROR("udp_send_chksum: invalid pbuf", p != NULL, return ERR_ARG); 516195972f6Sopenharmony_ci 517195972f6Sopenharmony_ci if (IP_IS_ANY_TYPE_VAL(pcb->remote_ip)) { 518195972f6Sopenharmony_ci return ERR_VAL; 519195972f6Sopenharmony_ci } 520195972f6Sopenharmony_ci 521195972f6Sopenharmony_ci /* send to the packet using remote ip and port stored in the pcb */ 522195972f6Sopenharmony_ci return udp_sendto_chksum(pcb, p, &pcb->remote_ip, pcb->remote_port, 523195972f6Sopenharmony_ci have_chksum, chksum); 524195972f6Sopenharmony_ci} 525195972f6Sopenharmony_ci#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ 526195972f6Sopenharmony_ci 527195972f6Sopenharmony_ci/** 528195972f6Sopenharmony_ci * @ingroup udp_raw 529195972f6Sopenharmony_ci * Send data to a specified address using UDP. 530195972f6Sopenharmony_ci * 531195972f6Sopenharmony_ci * @param pcb UDP PCB used to send the data. 532195972f6Sopenharmony_ci * @param p chain of pbuf's to be sent. 533195972f6Sopenharmony_ci * @param dst_ip Destination IP address. 534195972f6Sopenharmony_ci * @param dst_port Destination UDP port. 535195972f6Sopenharmony_ci * 536195972f6Sopenharmony_ci * dst_ip & dst_port are expected to be in the same byte order as in the pcb. 537195972f6Sopenharmony_ci * 538195972f6Sopenharmony_ci * If the PCB already has a remote address association, it will 539195972f6Sopenharmony_ci * be restored after the data is sent. 540195972f6Sopenharmony_ci * 541195972f6Sopenharmony_ci * @return lwIP error code (@see udp_send for possible error codes) 542195972f6Sopenharmony_ci * 543195972f6Sopenharmony_ci * @see udp_disconnect() udp_send() 544195972f6Sopenharmony_ci */ 545195972f6Sopenharmony_cierr_t 546195972f6Sopenharmony_ciudp_sendto(struct udp_pcb *pcb, struct pbuf *p, 547195972f6Sopenharmony_ci const ip_addr_t *dst_ip, u16_t dst_port) 548195972f6Sopenharmony_ci{ 549195972f6Sopenharmony_ci#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP 550195972f6Sopenharmony_ci return udp_sendto_chksum(pcb, p, dst_ip, dst_port, 0, 0); 551195972f6Sopenharmony_ci} 552195972f6Sopenharmony_ci 553195972f6Sopenharmony_ci/** @ingroup udp_raw 554195972f6Sopenharmony_ci * Same as udp_sendto(), but with checksum */ 555195972f6Sopenharmony_cierr_t 556195972f6Sopenharmony_ciudp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, 557195972f6Sopenharmony_ci u16_t dst_port, u8_t have_chksum, u16_t chksum) 558195972f6Sopenharmony_ci{ 559195972f6Sopenharmony_ci#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ 560195972f6Sopenharmony_ci struct netif *netif; 561195972f6Sopenharmony_ci 562195972f6Sopenharmony_ci LWIP_ERROR("udp_sendto: invalid pcb", pcb != NULL, return ERR_ARG); 563195972f6Sopenharmony_ci LWIP_ERROR("udp_sendto: invalid pbuf", p != NULL, return ERR_ARG); 564195972f6Sopenharmony_ci LWIP_ERROR("udp_sendto: invalid dst_ip", dst_ip != NULL, return ERR_ARG); 565195972f6Sopenharmony_ci 566195972f6Sopenharmony_ci if (!IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) { 567195972f6Sopenharmony_ci return ERR_VAL; 568195972f6Sopenharmony_ci } 569195972f6Sopenharmony_ci 570195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); 571195972f6Sopenharmony_ci 572195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 573195972f6Sopenharmony_ci struct net_group *group = get_net_group_from_udp_pcb(pcb); 574195972f6Sopenharmony_ci LWIP_ERROR("udp_sendto: invalid net group", group != NULL, return ERR_VAL); 575195972f6Sopenharmony_ci#endif 576195972f6Sopenharmony_ci if (pcb->netif_idx != NETIF_NO_INDEX) { 577195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 578195972f6Sopenharmony_ci netif = netif_get_by_index(pcb->netif_idx, group); 579195972f6Sopenharmony_ci#else 580195972f6Sopenharmony_ci netif = netif_get_by_index(pcb->netif_idx); 581195972f6Sopenharmony_ci#endif 582195972f6Sopenharmony_ci } else { 583195972f6Sopenharmony_ci#if LWIP_MULTICAST_TX_OPTIONS 584195972f6Sopenharmony_ci netif = NULL; 585195972f6Sopenharmony_ci if (ip_addr_ismulticast(dst_ip)) { 586195972f6Sopenharmony_ci /* For IPv6, the interface to use for packets with a multicast destination 587195972f6Sopenharmony_ci * is specified using an interface index. The same approach may be used for 588195972f6Sopenharmony_ci * IPv4 as well, in which case it overrides the IPv4 multicast override 589195972f6Sopenharmony_ci * address below. Here we have to look up the netif by going through the 590195972f6Sopenharmony_ci * list, but by doing so we skip a route lookup. If the interface index has 591195972f6Sopenharmony_ci * gone stale, we fall through and do the regular route lookup after all. */ 592195972f6Sopenharmony_ci if (pcb->mcast_ifindex != NETIF_NO_INDEX) { 593195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 594195972f6Sopenharmony_ci netif = netif_get_by_index(pcb->mcast_ifindex, group); 595195972f6Sopenharmony_ci#else 596195972f6Sopenharmony_ci netif = netif_get_by_index(pcb->mcast_ifindex); 597195972f6Sopenharmony_ci#endif 598195972f6Sopenharmony_ci } 599195972f6Sopenharmony_ci#if LWIP_IPV4 600195972f6Sopenharmony_ci else 601195972f6Sopenharmony_ci#if LWIP_IPV6 602195972f6Sopenharmony_ci if (IP_IS_V4(dst_ip)) 603195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */ 604195972f6Sopenharmony_ci { 605195972f6Sopenharmony_ci /* IPv4 does not use source-based routing by default, so we use an 606195972f6Sopenharmony_ci administratively selected interface for multicast by default. 607195972f6Sopenharmony_ci However, this can be overridden by setting an interface address 608195972f6Sopenharmony_ci in pcb->mcast_ip4 that is used for routing. If this routing lookup 609195972f6Sopenharmony_ci fails, we try regular routing as though no override was set. */ 610195972f6Sopenharmony_ci if (!ip4_addr_isany_val(pcb->mcast_ip4) && 611195972f6Sopenharmony_ci !ip4_addr_cmp(&pcb->mcast_ip4, IP4_ADDR_BROADCAST)) { 612195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 613195972f6Sopenharmony_ci netif = ip4_route_src(ip_2_ip4(&pcb->local_ip), &pcb->mcast_ip4, group); 614195972f6Sopenharmony_ci#else 615195972f6Sopenharmony_ci netif = ip4_route_src(ip_2_ip4(&pcb->local_ip), &pcb->mcast_ip4); 616195972f6Sopenharmony_ci#endif 617195972f6Sopenharmony_ci } 618195972f6Sopenharmony_ci } 619195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */ 620195972f6Sopenharmony_ci } 621195972f6Sopenharmony_ci 622195972f6Sopenharmony_ci if (netif == NULL) 623195972f6Sopenharmony_ci#endif /* LWIP_MULTICAST_TX_OPTIONS */ 624195972f6Sopenharmony_ci { 625195972f6Sopenharmony_ci /* find the outgoing network interface for this packet */ 626195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 627195972f6Sopenharmony_ci netif = ip_route(&pcb->local_ip, dst_ip, group); 628195972f6Sopenharmony_ci#else 629195972f6Sopenharmony_ci netif = ip_route(&pcb->local_ip, dst_ip); 630195972f6Sopenharmony_ci#endif 631195972f6Sopenharmony_ci } 632195972f6Sopenharmony_ci } 633195972f6Sopenharmony_ci 634195972f6Sopenharmony_ci /* no outgoing network interface could be found? */ 635195972f6Sopenharmony_ci if (netif == NULL) { 636195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to ")); 637195972f6Sopenharmony_ci ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, dst_ip); 638195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, ("\n")); 639195972f6Sopenharmony_ci UDP_STATS_INC(udp.rterr); 640195972f6Sopenharmony_ci return ERR_RTE; 641195972f6Sopenharmony_ci } 642195972f6Sopenharmony_ci#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP 643195972f6Sopenharmony_ci return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum); 644195972f6Sopenharmony_ci#else /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ 645195972f6Sopenharmony_ci return udp_sendto_if(pcb, p, dst_ip, dst_port, netif); 646195972f6Sopenharmony_ci#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ 647195972f6Sopenharmony_ci} 648195972f6Sopenharmony_ci 649195972f6Sopenharmony_ci/** 650195972f6Sopenharmony_ci * @ingroup udp_raw 651195972f6Sopenharmony_ci * Send data to a specified address using UDP. 652195972f6Sopenharmony_ci * The netif used for sending can be specified. 653195972f6Sopenharmony_ci * 654195972f6Sopenharmony_ci * This function exists mainly for DHCP, to be able to send UDP packets 655195972f6Sopenharmony_ci * on a netif that is still down. 656195972f6Sopenharmony_ci * 657195972f6Sopenharmony_ci * @param pcb UDP PCB used to send the data. 658195972f6Sopenharmony_ci * @param p chain of pbuf's to be sent. 659195972f6Sopenharmony_ci * @param dst_ip Destination IP address. 660195972f6Sopenharmony_ci * @param dst_port Destination UDP port. 661195972f6Sopenharmony_ci * @param netif the netif used for sending. 662195972f6Sopenharmony_ci * 663195972f6Sopenharmony_ci * dst_ip & dst_port are expected to be in the same byte order as in the pcb. 664195972f6Sopenharmony_ci * 665195972f6Sopenharmony_ci * @return lwIP error code (@see udp_send for possible error codes) 666195972f6Sopenharmony_ci * 667195972f6Sopenharmony_ci * @see udp_disconnect() udp_send() 668195972f6Sopenharmony_ci */ 669195972f6Sopenharmony_cierr_t 670195972f6Sopenharmony_ciudp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, 671195972f6Sopenharmony_ci const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif) 672195972f6Sopenharmony_ci{ 673195972f6Sopenharmony_ci#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP 674195972f6Sopenharmony_ci return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0); 675195972f6Sopenharmony_ci} 676195972f6Sopenharmony_ci 677195972f6Sopenharmony_ci/** Same as udp_sendto_if(), but with checksum */ 678195972f6Sopenharmony_cierr_t 679195972f6Sopenharmony_ciudp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, 680195972f6Sopenharmony_ci u16_t dst_port, struct netif *netif, u8_t have_chksum, 681195972f6Sopenharmony_ci u16_t chksum) 682195972f6Sopenharmony_ci{ 683195972f6Sopenharmony_ci#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ 684195972f6Sopenharmony_ci const ip_addr_t *src_ip; 685195972f6Sopenharmony_ci 686195972f6Sopenharmony_ci LWIP_ERROR("udp_sendto_if: invalid pcb", pcb != NULL, return ERR_ARG); 687195972f6Sopenharmony_ci LWIP_ERROR("udp_sendto_if: invalid pbuf", p != NULL, return ERR_ARG); 688195972f6Sopenharmony_ci LWIP_ERROR("udp_sendto_if: invalid dst_ip", dst_ip != NULL, return ERR_ARG); 689195972f6Sopenharmony_ci LWIP_ERROR("udp_sendto_if: invalid netif", netif != NULL, return ERR_ARG); 690195972f6Sopenharmony_ci 691195972f6Sopenharmony_ci if (!IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) { 692195972f6Sopenharmony_ci return ERR_VAL; 693195972f6Sopenharmony_ci } 694195972f6Sopenharmony_ci 695195972f6Sopenharmony_ci /* PCB local address is IP_ANY_ADDR or multicast? */ 696195972f6Sopenharmony_ci#if LWIP_IPV6 697195972f6Sopenharmony_ci if (IP_IS_V6(dst_ip)) { 698195972f6Sopenharmony_ci if (ip6_addr_isany(ip_2_ip6(&pcb->local_ip)) || 699195972f6Sopenharmony_ci ip6_addr_ismulticast(ip_2_ip6(&pcb->local_ip))) { 700195972f6Sopenharmony_ci src_ip = ip6_select_source_address(netif, ip_2_ip6(dst_ip)); 701195972f6Sopenharmony_ci if (src_ip == NULL) { 702195972f6Sopenharmony_ci /* No suitable source address was found. */ 703195972f6Sopenharmony_ci return ERR_RTE; 704195972f6Sopenharmony_ci } 705195972f6Sopenharmony_ci } else { 706195972f6Sopenharmony_ci /* use UDP PCB local IPv6 address as source address, if still valid. */ 707195972f6Sopenharmony_ci if (netif_get_ip6_addr_match(netif, ip_2_ip6(&pcb->local_ip)) < 0) { 708195972f6Sopenharmony_ci /* Address isn't valid anymore. */ 709195972f6Sopenharmony_ci return ERR_RTE; 710195972f6Sopenharmony_ci } 711195972f6Sopenharmony_ci src_ip = &pcb->local_ip; 712195972f6Sopenharmony_ci } 713195972f6Sopenharmony_ci } 714195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */ 715195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6 716195972f6Sopenharmony_ci else 717195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && LWIP_IPV6 */ 718195972f6Sopenharmony_ci#if LWIP_IPV4 719195972f6Sopenharmony_ci if (ip4_addr_isany(ip_2_ip4(&pcb->local_ip)) || 720195972f6Sopenharmony_ci ip4_addr_ismulticast(ip_2_ip4(&pcb->local_ip))) { 721195972f6Sopenharmony_ci /* if the local_ip is any or multicast 722195972f6Sopenharmony_ci * use the outgoing network interface IP address as source address */ 723195972f6Sopenharmony_ci src_ip = netif_ip_addr4(netif); 724195972f6Sopenharmony_ci } else { 725195972f6Sopenharmony_ci /* check if UDP PCB local IP address is correct 726195972f6Sopenharmony_ci * this could be an old address if netif->ip_addr has changed */ 727195972f6Sopenharmony_ci if (!ip4_addr_cmp(ip_2_ip4(&(pcb->local_ip)), netif_ip4_addr(netif))) { 728195972f6Sopenharmony_ci /* local_ip doesn't match, drop the packet */ 729195972f6Sopenharmony_ci return ERR_RTE; 730195972f6Sopenharmony_ci } 731195972f6Sopenharmony_ci /* use UDP PCB local IP address as source address */ 732195972f6Sopenharmony_ci src_ip = &pcb->local_ip; 733195972f6Sopenharmony_ci } 734195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */ 735195972f6Sopenharmony_ci#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP 736195972f6Sopenharmony_ci return udp_sendto_if_src_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum, src_ip); 737195972f6Sopenharmony_ci#else /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ 738195972f6Sopenharmony_ci return udp_sendto_if_src(pcb, p, dst_ip, dst_port, netif, src_ip); 739195972f6Sopenharmony_ci#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ 740195972f6Sopenharmony_ci} 741195972f6Sopenharmony_ci 742195972f6Sopenharmony_ci/** @ingroup udp_raw 743195972f6Sopenharmony_ci * Same as @ref udp_sendto_if, but with source address */ 744195972f6Sopenharmony_cierr_t 745195972f6Sopenharmony_ciudp_sendto_if_src(struct udp_pcb *pcb, struct pbuf *p, 746195972f6Sopenharmony_ci const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, const ip_addr_t *src_ip) 747195972f6Sopenharmony_ci{ 748195972f6Sopenharmony_ci#if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP 749195972f6Sopenharmony_ci return udp_sendto_if_src_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0, src_ip); 750195972f6Sopenharmony_ci} 751195972f6Sopenharmony_ci 752195972f6Sopenharmony_ci/** Same as udp_sendto_if_src(), but with checksum */ 753195972f6Sopenharmony_cierr_t 754195972f6Sopenharmony_ciudp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, 755195972f6Sopenharmony_ci u16_t dst_port, struct netif *netif, u8_t have_chksum, 756195972f6Sopenharmony_ci u16_t chksum, const ip_addr_t *src_ip) 757195972f6Sopenharmony_ci{ 758195972f6Sopenharmony_ci#endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ 759195972f6Sopenharmony_ci struct udp_hdr *udphdr; 760195972f6Sopenharmony_ci err_t err; 761195972f6Sopenharmony_ci struct pbuf *q; /* q will be sent down the stack */ 762195972f6Sopenharmony_ci u8_t ip_proto; 763195972f6Sopenharmony_ci u8_t ttl; 764195972f6Sopenharmony_ci 765195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 766195972f6Sopenharmony_ci 767195972f6Sopenharmony_ci LWIP_ERROR("udp_sendto_if_src: invalid pcb", pcb != NULL, return ERR_ARG); 768195972f6Sopenharmony_ci LWIP_ERROR("udp_sendto_if_src: invalid pbuf", p != NULL, return ERR_ARG); 769195972f6Sopenharmony_ci LWIP_ERROR("udp_sendto_if_src: invalid dst_ip", dst_ip != NULL, return ERR_ARG); 770195972f6Sopenharmony_ci LWIP_ERROR("udp_sendto_if_src: invalid src_ip", src_ip != NULL, return ERR_ARG); 771195972f6Sopenharmony_ci LWIP_ERROR("udp_sendto_if_src: invalid netif", netif != NULL, return ERR_ARG); 772195972f6Sopenharmony_ci 773195972f6Sopenharmony_ci if (!IP_ADDR_PCB_VERSION_MATCH(pcb, src_ip) || 774195972f6Sopenharmony_ci !IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)) { 775195972f6Sopenharmony_ci return ERR_VAL; 776195972f6Sopenharmony_ci } 777195972f6Sopenharmony_ci 778195972f6Sopenharmony_ci#if LWIP_IPV4 && IP_SOF_BROADCAST 779195972f6Sopenharmony_ci /* broadcast filter? */ 780195972f6Sopenharmony_ci if (!ip_get_option(pcb, SOF_BROADCAST) && 781195972f6Sopenharmony_ci#if LWIP_IPV6 782195972f6Sopenharmony_ci IP_IS_V4(dst_ip) && 783195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */ 784195972f6Sopenharmony_ci ip_addr_isbroadcast(dst_ip, netif)) { 785195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, 786195972f6Sopenharmony_ci ("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); 787195972f6Sopenharmony_ci return ERR_VAL; 788195972f6Sopenharmony_ci } 789195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && IP_SOF_BROADCAST */ 790195972f6Sopenharmony_ci 791195972f6Sopenharmony_ci /* if the PCB is not yet bound to a port, bind it here */ 792195972f6Sopenharmony_ci if (pcb->local_port == 0) { 793195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send: not yet bound to a port, binding now\n")); 794195972f6Sopenharmony_ci err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); 795195972f6Sopenharmony_ci if (err != ERR_OK) { 796195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n")); 797195972f6Sopenharmony_ci return err; 798195972f6Sopenharmony_ci } 799195972f6Sopenharmony_ci } 800195972f6Sopenharmony_ci 801195972f6Sopenharmony_ci /* packet too large to add a UDP header without causing an overflow? */ 802195972f6Sopenharmony_ci if ((u16_t)(p->tot_len + UDP_HLEN) < p->tot_len) { 803195972f6Sopenharmony_ci return ERR_MEM; 804195972f6Sopenharmony_ci } 805195972f6Sopenharmony_ci /* not enough space to add an UDP header to first pbuf in given p chain? */ 806195972f6Sopenharmony_ci if (pbuf_add_header(p, UDP_HLEN)) { 807195972f6Sopenharmony_ci /* allocate header in a separate new pbuf */ 808195972f6Sopenharmony_ci q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM); 809195972f6Sopenharmony_ci /* new header pbuf could not be allocated? */ 810195972f6Sopenharmony_ci if (q == NULL) { 811195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n")); 812195972f6Sopenharmony_ci return ERR_MEM; 813195972f6Sopenharmony_ci } 814195972f6Sopenharmony_ci if (p->tot_len != 0) { 815195972f6Sopenharmony_ci /* chain header q in front of given pbuf p (only if p contains data) */ 816195972f6Sopenharmony_ci pbuf_chain(q, p); 817195972f6Sopenharmony_ci } 818195972f6Sopenharmony_ci /* first pbuf q points to header pbuf */ 819195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, 820195972f6Sopenharmony_ci ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); 821195972f6Sopenharmony_ci } else { 822195972f6Sopenharmony_ci /* adding space for header within p succeeded */ 823195972f6Sopenharmony_ci /* first pbuf q equals given pbuf */ 824195972f6Sopenharmony_ci q = p; 825195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p)); 826195972f6Sopenharmony_ci } 827195972f6Sopenharmony_ci LWIP_ASSERT("check that first pbuf can hold struct udp_hdr", 828195972f6Sopenharmony_ci (q->len >= sizeof(struct udp_hdr))); 829195972f6Sopenharmony_ci /* q now represents the packet to be sent */ 830195972f6Sopenharmony_ci udphdr = (struct udp_hdr *)q->payload; 831195972f6Sopenharmony_ci udphdr->src = lwip_htons(pcb->local_port); 832195972f6Sopenharmony_ci udphdr->dest = lwip_htons(dst_port); 833195972f6Sopenharmony_ci /* in UDP, 0 checksum means 'no checksum' */ 834195972f6Sopenharmony_ci udphdr->chksum = 0x0000; 835195972f6Sopenharmony_ci 836195972f6Sopenharmony_ci /* Multicast Loop? */ 837195972f6Sopenharmony_ci#if LWIP_MULTICAST_TX_OPTIONS 838195972f6Sopenharmony_ci if (((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) && ip_addr_ismulticast(dst_ip)) { 839195972f6Sopenharmony_ci q->flags |= PBUF_FLAG_MCASTLOOP; 840195972f6Sopenharmony_ci } 841195972f6Sopenharmony_ci#endif /* LWIP_MULTICAST_TX_OPTIONS */ 842195972f6Sopenharmony_ci 843195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len)); 844195972f6Sopenharmony_ci 845195972f6Sopenharmony_ci#if LWIP_UDPLITE 846195972f6Sopenharmony_ci /* UDP Lite protocol? */ 847195972f6Sopenharmony_ci if (pcb->flags & UDP_FLAGS_UDPLITE) { 848195972f6Sopenharmony_ci u16_t chklen, chklen_hdr; 849195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len)); 850195972f6Sopenharmony_ci /* set UDP message length in UDP header */ 851195972f6Sopenharmony_ci chklen_hdr = chklen = pcb->chksum_len_tx; 852195972f6Sopenharmony_ci if ((chklen < sizeof(struct udp_hdr)) || (chklen > q->tot_len)) { 853195972f6Sopenharmony_ci if (chklen != 0) { 854195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE pcb->chksum_len is illegal: %"U16_F"\n", chklen)); 855195972f6Sopenharmony_ci } 856195972f6Sopenharmony_ci /* For UDP-Lite, checksum length of 0 means checksum 857195972f6Sopenharmony_ci over the complete packet. (See RFC 3828 chap. 3.1) 858195972f6Sopenharmony_ci At least the UDP-Lite header must be covered by the 859195972f6Sopenharmony_ci checksum, therefore, if chksum_len has an illegal 860195972f6Sopenharmony_ci value, we generate the checksum over the complete 861195972f6Sopenharmony_ci packet to be safe. */ 862195972f6Sopenharmony_ci chklen_hdr = 0; 863195972f6Sopenharmony_ci chklen = q->tot_len; 864195972f6Sopenharmony_ci } 865195972f6Sopenharmony_ci udphdr->len = lwip_htons(chklen_hdr); 866195972f6Sopenharmony_ci /* calculate checksum */ 867195972f6Sopenharmony_ci#if CHECKSUM_GEN_UDP 868195972f6Sopenharmony_ci IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_UDP) { 869195972f6Sopenharmony_ci#if LWIP_CHECKSUM_ON_COPY 870195972f6Sopenharmony_ci if (have_chksum) { 871195972f6Sopenharmony_ci chklen = UDP_HLEN; 872195972f6Sopenharmony_ci } 873195972f6Sopenharmony_ci#endif /* LWIP_CHECKSUM_ON_COPY */ 874195972f6Sopenharmony_ci udphdr->chksum = ip_chksum_pseudo_partial(q, IP_PROTO_UDPLITE, 875195972f6Sopenharmony_ci q->tot_len, chklen, src_ip, dst_ip); 876195972f6Sopenharmony_ci#if LWIP_CHECKSUM_ON_COPY 877195972f6Sopenharmony_ci if (have_chksum) { 878195972f6Sopenharmony_ci u32_t acc; 879195972f6Sopenharmony_ci acc = udphdr->chksum + (u16_t)~(chksum); 880195972f6Sopenharmony_ci udphdr->chksum = FOLD_U32T(acc); 881195972f6Sopenharmony_ci } 882195972f6Sopenharmony_ci#endif /* LWIP_CHECKSUM_ON_COPY */ 883195972f6Sopenharmony_ci 884195972f6Sopenharmony_ci /* chksum zero must become 0xffff, as zero means 'no checksum' */ 885195972f6Sopenharmony_ci if (udphdr->chksum == 0x0000) { 886195972f6Sopenharmony_ci udphdr->chksum = 0xffff; 887195972f6Sopenharmony_ci } 888195972f6Sopenharmony_ci } 889195972f6Sopenharmony_ci#endif /* CHECKSUM_GEN_UDP */ 890195972f6Sopenharmony_ci 891195972f6Sopenharmony_ci ip_proto = IP_PROTO_UDPLITE; 892195972f6Sopenharmony_ci } else 893195972f6Sopenharmony_ci#endif /* LWIP_UDPLITE */ 894195972f6Sopenharmony_ci { /* UDP */ 895195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len)); 896195972f6Sopenharmony_ci udphdr->len = lwip_htons(q->tot_len); 897195972f6Sopenharmony_ci /* calculate checksum */ 898195972f6Sopenharmony_ci#if CHECKSUM_GEN_UDP 899195972f6Sopenharmony_ci IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_UDP) { 900195972f6Sopenharmony_ci /* Checksum is mandatory over IPv6. */ 901195972f6Sopenharmony_ci if (IP_IS_V6(dst_ip) || (pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { 902195972f6Sopenharmony_ci u16_t udpchksum; 903195972f6Sopenharmony_ci#if LWIP_CHECKSUM_ON_COPY 904195972f6Sopenharmony_ci if (have_chksum) { 905195972f6Sopenharmony_ci u32_t acc; 906195972f6Sopenharmony_ci udpchksum = ip_chksum_pseudo_partial(q, IP_PROTO_UDP, 907195972f6Sopenharmony_ci q->tot_len, UDP_HLEN, src_ip, dst_ip); 908195972f6Sopenharmony_ci acc = udpchksum + (u16_t)~(chksum); 909195972f6Sopenharmony_ci udpchksum = FOLD_U32T(acc); 910195972f6Sopenharmony_ci } else 911195972f6Sopenharmony_ci#endif /* LWIP_CHECKSUM_ON_COPY */ 912195972f6Sopenharmony_ci { 913195972f6Sopenharmony_ci udpchksum = ip_chksum_pseudo(q, IP_PROTO_UDP, q->tot_len, 914195972f6Sopenharmony_ci src_ip, dst_ip); 915195972f6Sopenharmony_ci } 916195972f6Sopenharmony_ci 917195972f6Sopenharmony_ci /* chksum zero must become 0xffff, as zero means 'no checksum' */ 918195972f6Sopenharmony_ci if (udpchksum == 0x0000) { 919195972f6Sopenharmony_ci udpchksum = 0xffff; 920195972f6Sopenharmony_ci } 921195972f6Sopenharmony_ci udphdr->chksum = udpchksum; 922195972f6Sopenharmony_ci } 923195972f6Sopenharmony_ci } 924195972f6Sopenharmony_ci#endif /* CHECKSUM_GEN_UDP */ 925195972f6Sopenharmony_ci ip_proto = IP_PROTO_UDP; 926195972f6Sopenharmony_ci } 927195972f6Sopenharmony_ci 928195972f6Sopenharmony_ci /* Determine TTL to use */ 929195972f6Sopenharmony_ci#if LWIP_MULTICAST_TX_OPTIONS 930195972f6Sopenharmony_ci ttl = (ip_addr_ismulticast(dst_ip) ? udp_get_multicast_ttl(pcb) : pcb->ttl); 931195972f6Sopenharmony_ci#else /* LWIP_MULTICAST_TX_OPTIONS */ 932195972f6Sopenharmony_ci ttl = pcb->ttl; 933195972f6Sopenharmony_ci#endif /* LWIP_MULTICAST_TX_OPTIONS */ 934195972f6Sopenharmony_ci 935195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum)); 936195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,0x%02"X16_F",)\n", (u16_t)ip_proto)); 937195972f6Sopenharmony_ci /* output to IP */ 938195972f6Sopenharmony_ci NETIF_SET_HINTS(netif, &(pcb->netif_hints)); 939195972f6Sopenharmony_ci err = ip_output_if_src(q, src_ip, dst_ip, ttl, pcb->tos, ip_proto, netif); 940195972f6Sopenharmony_ci NETIF_RESET_HINTS(netif); 941195972f6Sopenharmony_ci 942195972f6Sopenharmony_ci /* @todo: must this be increased even if error occurred? */ 943195972f6Sopenharmony_ci MIB2_STATS_INC(mib2.udpoutdatagrams); 944195972f6Sopenharmony_ci 945195972f6Sopenharmony_ci /* did we chain a separate header pbuf earlier? */ 946195972f6Sopenharmony_ci if (q != p) { 947195972f6Sopenharmony_ci /* free the header pbuf */ 948195972f6Sopenharmony_ci pbuf_free(q); 949195972f6Sopenharmony_ci q = NULL; 950195972f6Sopenharmony_ci /* p is still referenced by the caller, and will live on */ 951195972f6Sopenharmony_ci } 952195972f6Sopenharmony_ci 953195972f6Sopenharmony_ci UDP_STATS_INC(udp.xmit); 954195972f6Sopenharmony_ci return err; 955195972f6Sopenharmony_ci} 956195972f6Sopenharmony_ci 957195972f6Sopenharmony_ci/** 958195972f6Sopenharmony_ci * @ingroup udp_raw 959195972f6Sopenharmony_ci * Bind an UDP PCB. 960195972f6Sopenharmony_ci * 961195972f6Sopenharmony_ci * @param pcb UDP PCB to be bound with a local address ipaddr and port. 962195972f6Sopenharmony_ci * @param ipaddr local IP address to bind with. Use IP_ANY_TYPE to 963195972f6Sopenharmony_ci * bind to all local interfaces. 964195972f6Sopenharmony_ci * @param port local UDP port to bind with. Use 0 to automatically bind 965195972f6Sopenharmony_ci * to a random port between UDP_LOCAL_PORT_RANGE_START and 966195972f6Sopenharmony_ci * UDP_LOCAL_PORT_RANGE_END. 967195972f6Sopenharmony_ci * 968195972f6Sopenharmony_ci * ipaddr & port are expected to be in the same byte order as in the pcb. 969195972f6Sopenharmony_ci * 970195972f6Sopenharmony_ci * @return lwIP error code. 971195972f6Sopenharmony_ci * - ERR_OK. Successful. No error occurred. 972195972f6Sopenharmony_ci * - ERR_USE. The specified ipaddr and port are already bound to by 973195972f6Sopenharmony_ci * another UDP PCB. 974195972f6Sopenharmony_ci * 975195972f6Sopenharmony_ci * @see udp_disconnect() 976195972f6Sopenharmony_ci */ 977195972f6Sopenharmony_cierr_t 978195972f6Sopenharmony_ciudp_bind(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) 979195972f6Sopenharmony_ci{ 980195972f6Sopenharmony_ci struct udp_pcb *ipcb; 981195972f6Sopenharmony_ci u8_t rebind; 982195972f6Sopenharmony_ci#if LWIP_IPV6 && LWIP_IPV6_SCOPES 983195972f6Sopenharmony_ci ip_addr_t zoned_ipaddr; 984195972f6Sopenharmony_ci#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ 985195972f6Sopenharmony_ci 986195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 987195972f6Sopenharmony_ci 988195972f6Sopenharmony_ci#if LWIP_IPV4 989195972f6Sopenharmony_ci /* Don't propagate NULL pointer (IPv4 ANY) to subsequent functions */ 990195972f6Sopenharmony_ci if (ipaddr == NULL) { 991195972f6Sopenharmony_ci ipaddr = IP4_ADDR_ANY; 992195972f6Sopenharmony_ci } 993195972f6Sopenharmony_ci#else /* LWIP_IPV4 */ 994195972f6Sopenharmony_ci LWIP_ERROR("udp_bind: invalid ipaddr", ipaddr != NULL, return ERR_ARG); 995195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */ 996195972f6Sopenharmony_ci 997195972f6Sopenharmony_ci LWIP_ERROR("udp_bind: invalid pcb", pcb != NULL, return ERR_ARG); 998195972f6Sopenharmony_ci 999195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = ")); 1000195972f6Sopenharmony_ci ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE, ipaddr); 1001195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port)); 1002195972f6Sopenharmony_ci 1003195972f6Sopenharmony_ci rebind = 0; 1004195972f6Sopenharmony_ci /* Check for double bind and rebind of the same pcb */ 1005195972f6Sopenharmony_ci for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { 1006195972f6Sopenharmony_ci /* is this UDP PCB already on active list? */ 1007195972f6Sopenharmony_ci if (pcb == ipcb) { 1008195972f6Sopenharmony_ci rebind = 1; 1009195972f6Sopenharmony_ci break; 1010195972f6Sopenharmony_ci } 1011195972f6Sopenharmony_ci } 1012195972f6Sopenharmony_ci 1013195972f6Sopenharmony_ci#if LWIP_IPV6 && LWIP_IPV6_SCOPES 1014195972f6Sopenharmony_ci /* If the given IP address should have a zone but doesn't, assign one now. 1015195972f6Sopenharmony_ci * This is legacy support: scope-aware callers should always provide properly 1016195972f6Sopenharmony_ci * zoned source addresses. Do the zone selection before the address-in-use 1017195972f6Sopenharmony_ci * check below; as such we have to make a temporary copy of the address. */ 1018195972f6Sopenharmony_ci if (IP_IS_V6(ipaddr) && ip6_addr_lacks_zone(ip_2_ip6(ipaddr), IP6_UNKNOWN)) { 1019195972f6Sopenharmony_ci ip_addr_copy(zoned_ipaddr, *ipaddr); 1020195972f6Sopenharmony_ci ip6_addr_select_zone(ip_2_ip6(&zoned_ipaddr), ip_2_ip6(&zoned_ipaddr)); 1021195972f6Sopenharmony_ci ipaddr = &zoned_ipaddr; 1022195972f6Sopenharmony_ci } 1023195972f6Sopenharmony_ci#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ 1024195972f6Sopenharmony_ci 1025195972f6Sopenharmony_ci /* no port specified? */ 1026195972f6Sopenharmony_ci if (port == 0) { 1027195972f6Sopenharmony_ci port = udp_new_port(); 1028195972f6Sopenharmony_ci if (port == 0) { 1029195972f6Sopenharmony_ci /* no more ports available in local range */ 1030195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n")); 1031195972f6Sopenharmony_ci return ERR_USE; 1032195972f6Sopenharmony_ci } 1033195972f6Sopenharmony_ci } else { 1034195972f6Sopenharmony_ci for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { 1035195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 1036195972f6Sopenharmony_ci if (pcb != ipcb && (get_net_group_from_udp_pcb(pcb) == get_net_group_from_udp_pcb(ipcb))) { 1037195972f6Sopenharmony_ci#else 1038195972f6Sopenharmony_ci if (pcb != ipcb) { 1039195972f6Sopenharmony_ci#endif 1040195972f6Sopenharmony_ci /* By default, we don't allow to bind to a port that any other udp 1041195972f6Sopenharmony_ci PCB is already bound to, unless *all* PCBs with that port have tha 1042195972f6Sopenharmony_ci REUSEADDR flag set. */ 1043195972f6Sopenharmony_ci#if SO_REUSE 1044195972f6Sopenharmony_ci if (!ip_get_option(pcb, SOF_REUSEADDR) || 1045195972f6Sopenharmony_ci !ip_get_option(ipcb, SOF_REUSEADDR)) 1046195972f6Sopenharmony_ci#endif /* SO_REUSE */ 1047195972f6Sopenharmony_ci { 1048195972f6Sopenharmony_ci /* port matches that of PCB in list and REUSEADDR not set -> reject */ 1049195972f6Sopenharmony_ci if ((ipcb->local_port == port) && 1050195972f6Sopenharmony_ci (((IP_GET_TYPE(&ipcb->local_ip) == IP_GET_TYPE(ipaddr)) && 1051195972f6Sopenharmony_ci /* IP address matches or any IP used? */ 1052195972f6Sopenharmony_ci (ip_addr_cmp(&ipcb->local_ip, ipaddr) || 1053195972f6Sopenharmony_ci ip_addr_isany(ipaddr) || 1054195972f6Sopenharmony_ci ip_addr_isany(&ipcb->local_ip))) || 1055195972f6Sopenharmony_ci (IP_GET_TYPE(&ipcb->local_ip) == IPADDR_TYPE_ANY) || 1056195972f6Sopenharmony_ci (IP_GET_TYPE(ipaddr) == IPADDR_TYPE_ANY))) { 1057195972f6Sopenharmony_ci /* other PCB already binds to this local IP and port */ 1058195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, 1059195972f6Sopenharmony_ci ("udp_bind: local port %"U16_F" already bound by another pcb\n", port)); 1060195972f6Sopenharmony_ci return ERR_USE; 1061195972f6Sopenharmony_ci } 1062195972f6Sopenharmony_ci } 1063195972f6Sopenharmony_ci } 1064195972f6Sopenharmony_ci } 1065195972f6Sopenharmony_ci } 1066195972f6Sopenharmony_ci 1067195972f6Sopenharmony_ci ip_addr_set_ipaddr(&pcb->local_ip, ipaddr); 1068195972f6Sopenharmony_ci 1069195972f6Sopenharmony_ci pcb->local_port = port; 1070195972f6Sopenharmony_ci mib2_udp_bind(pcb); 1071195972f6Sopenharmony_ci /* pcb not active yet? */ 1072195972f6Sopenharmony_ci if (rebind == 0) { 1073195972f6Sopenharmony_ci /* place the PCB on the active list if not already there */ 1074195972f6Sopenharmony_ci pcb->next = udp_pcbs; 1075195972f6Sopenharmony_ci udp_pcbs = pcb; 1076195972f6Sopenharmony_ci } 1077195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_bind: bound to ")); 1078195972f6Sopenharmony_ci ip_addr_debug_print_val(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, pcb->local_ip); 1079195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->local_port)); 1080195972f6Sopenharmony_ci return ERR_OK; 1081195972f6Sopenharmony_ci} 1082195972f6Sopenharmony_ci 1083195972f6Sopenharmony_ci/** 1084195972f6Sopenharmony_ci * @ingroup udp_raw 1085195972f6Sopenharmony_ci * Bind an UDP PCB to a specific netif. 1086195972f6Sopenharmony_ci * After calling this function, all packets received via this PCB 1087195972f6Sopenharmony_ci * are guaranteed to have come in via the specified netif, and all 1088195972f6Sopenharmony_ci * outgoing packets will go out via the specified netif. 1089195972f6Sopenharmony_ci * 1090195972f6Sopenharmony_ci * @param pcb UDP PCB to be bound. 1091195972f6Sopenharmony_ci * @param netif netif to bind udp pcb to. Can be NULL. 1092195972f6Sopenharmony_ci * 1093195972f6Sopenharmony_ci * @see udp_disconnect() 1094195972f6Sopenharmony_ci */ 1095195972f6Sopenharmony_civoid 1096195972f6Sopenharmony_ciudp_bind_netif(struct udp_pcb *pcb, const struct netif *netif) 1097195972f6Sopenharmony_ci{ 1098195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 1099195972f6Sopenharmony_ci 1100195972f6Sopenharmony_ci if (netif != NULL) { 1101195972f6Sopenharmony_ci pcb->netif_idx = netif_get_index(netif); 1102195972f6Sopenharmony_ci } else { 1103195972f6Sopenharmony_ci pcb->netif_idx = NETIF_NO_INDEX; 1104195972f6Sopenharmony_ci } 1105195972f6Sopenharmony_ci} 1106195972f6Sopenharmony_ci 1107195972f6Sopenharmony_ci/** 1108195972f6Sopenharmony_ci * @ingroup udp_raw 1109195972f6Sopenharmony_ci * Sets the remote end of the pcb. This function does not generate any 1110195972f6Sopenharmony_ci * network traffic, but only sets the remote address of the pcb. 1111195972f6Sopenharmony_ci * 1112195972f6Sopenharmony_ci * @param pcb UDP PCB to be connected with remote address ipaddr and port. 1113195972f6Sopenharmony_ci * @param ipaddr remote IP address to connect with. 1114195972f6Sopenharmony_ci * @param port remote UDP port to connect with. 1115195972f6Sopenharmony_ci * 1116195972f6Sopenharmony_ci * @return lwIP error code 1117195972f6Sopenharmony_ci * 1118195972f6Sopenharmony_ci * ipaddr & port are expected to be in the same byte order as in the pcb. 1119195972f6Sopenharmony_ci * 1120195972f6Sopenharmony_ci * The udp pcb is bound to a random local port if not already bound. 1121195972f6Sopenharmony_ci * 1122195972f6Sopenharmony_ci * @see udp_disconnect() 1123195972f6Sopenharmony_ci */ 1124195972f6Sopenharmony_cierr_t 1125195972f6Sopenharmony_ciudp_connect(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) 1126195972f6Sopenharmony_ci{ 1127195972f6Sopenharmony_ci struct udp_pcb *ipcb; 1128195972f6Sopenharmony_ci 1129195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 1130195972f6Sopenharmony_ci 1131195972f6Sopenharmony_ci LWIP_ERROR("udp_connect: invalid pcb", pcb != NULL, return ERR_ARG); 1132195972f6Sopenharmony_ci LWIP_ERROR("udp_connect: invalid ipaddr", ipaddr != NULL, return ERR_ARG); 1133195972f6Sopenharmony_ci 1134195972f6Sopenharmony_ci if (pcb->local_port == 0) { 1135195972f6Sopenharmony_ci err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); 1136195972f6Sopenharmony_ci if (err != ERR_OK) { 1137195972f6Sopenharmony_ci return err; 1138195972f6Sopenharmony_ci } 1139195972f6Sopenharmony_ci } 1140195972f6Sopenharmony_ci 1141195972f6Sopenharmony_ci ip_addr_set_ipaddr(&pcb->remote_ip, ipaddr); 1142195972f6Sopenharmony_ci#if LWIP_IPV6 && LWIP_IPV6_SCOPES 1143195972f6Sopenharmony_ci /* If the given IP address should have a zone but doesn't, assign one now, 1144195972f6Sopenharmony_ci * using the bound address to make a more informed decision when possible. */ 1145195972f6Sopenharmony_ci if (IP_IS_V6(&pcb->remote_ip) && 1146195972f6Sopenharmony_ci ip6_addr_lacks_zone(ip_2_ip6(&pcb->remote_ip), IP6_UNKNOWN)) { 1147195972f6Sopenharmony_ci ip6_addr_select_zone(ip_2_ip6(&pcb->remote_ip), ip_2_ip6(&pcb->local_ip)); 1148195972f6Sopenharmony_ci } 1149195972f6Sopenharmony_ci#endif /* LWIP_IPV6 && LWIP_IPV6_SCOPES */ 1150195972f6Sopenharmony_ci 1151195972f6Sopenharmony_ci pcb->remote_port = port; 1152195972f6Sopenharmony_ci pcb->flags |= UDP_FLAGS_CONNECTED; 1153195972f6Sopenharmony_ci 1154195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_connect: connected to ")); 1155195972f6Sopenharmony_ci ip_addr_debug_print_val(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, 1156195972f6Sopenharmony_ci pcb->remote_ip); 1157195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->remote_port)); 1158195972f6Sopenharmony_ci 1159195972f6Sopenharmony_ci /* Insert UDP PCB into the list of active UDP PCBs. */ 1160195972f6Sopenharmony_ci for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { 1161195972f6Sopenharmony_ci if (pcb == ipcb) { 1162195972f6Sopenharmony_ci /* already on the list, just return */ 1163195972f6Sopenharmony_ci return ERR_OK; 1164195972f6Sopenharmony_ci } 1165195972f6Sopenharmony_ci } 1166195972f6Sopenharmony_ci /* PCB not yet on the list, add PCB now */ 1167195972f6Sopenharmony_ci pcb->next = udp_pcbs; 1168195972f6Sopenharmony_ci udp_pcbs = pcb; 1169195972f6Sopenharmony_ci return ERR_OK; 1170195972f6Sopenharmony_ci} 1171195972f6Sopenharmony_ci 1172195972f6Sopenharmony_ci/** 1173195972f6Sopenharmony_ci * @ingroup udp_raw 1174195972f6Sopenharmony_ci * Remove the remote end of the pcb. This function does not generate 1175195972f6Sopenharmony_ci * any network traffic, but only removes the remote address of the pcb. 1176195972f6Sopenharmony_ci * 1177195972f6Sopenharmony_ci * @param pcb the udp pcb to disconnect. 1178195972f6Sopenharmony_ci */ 1179195972f6Sopenharmony_civoid 1180195972f6Sopenharmony_ciudp_disconnect(struct udp_pcb *pcb) 1181195972f6Sopenharmony_ci{ 1182195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 1183195972f6Sopenharmony_ci 1184195972f6Sopenharmony_ci LWIP_ERROR("udp_disconnect: invalid pcb", pcb != NULL, return); 1185195972f6Sopenharmony_ci 1186195972f6Sopenharmony_ci /* reset remote address association */ 1187195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6 1188195972f6Sopenharmony_ci if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { 1189195972f6Sopenharmony_ci ip_addr_copy(pcb->remote_ip, *IP_ANY_TYPE); 1190195972f6Sopenharmony_ci } else { 1191195972f6Sopenharmony_ci#endif 1192195972f6Sopenharmony_ci ip_addr_set_any(IP_IS_V6_VAL(pcb->remote_ip), &pcb->remote_ip); 1193195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6 1194195972f6Sopenharmony_ci } 1195195972f6Sopenharmony_ci#endif 1196195972f6Sopenharmony_ci pcb->remote_port = 0; 1197195972f6Sopenharmony_ci pcb->netif_idx = NETIF_NO_INDEX; 1198195972f6Sopenharmony_ci /* mark PCB as unconnected */ 1199195972f6Sopenharmony_ci udp_clear_flags(pcb, UDP_FLAGS_CONNECTED); 1200195972f6Sopenharmony_ci} 1201195972f6Sopenharmony_ci 1202195972f6Sopenharmony_ci/** 1203195972f6Sopenharmony_ci * @ingroup udp_raw 1204195972f6Sopenharmony_ci * Set a receive callback for a UDP PCB. 1205195972f6Sopenharmony_ci * This callback will be called when receiving a datagram for the pcb. 1206195972f6Sopenharmony_ci * 1207195972f6Sopenharmony_ci * @param pcb the pcb for which to set the recv callback 1208195972f6Sopenharmony_ci * @param recv function pointer of the callback function 1209195972f6Sopenharmony_ci * @param recv_arg additional argument to pass to the callback function 1210195972f6Sopenharmony_ci */ 1211195972f6Sopenharmony_civoid 1212195972f6Sopenharmony_ciudp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg) 1213195972f6Sopenharmony_ci{ 1214195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 1215195972f6Sopenharmony_ci 1216195972f6Sopenharmony_ci LWIP_ERROR("udp_recv: invalid pcb", pcb != NULL, return); 1217195972f6Sopenharmony_ci 1218195972f6Sopenharmony_ci /* remember recv() callback and user data */ 1219195972f6Sopenharmony_ci pcb->recv = recv; 1220195972f6Sopenharmony_ci pcb->recv_arg = recv_arg; 1221195972f6Sopenharmony_ci} 1222195972f6Sopenharmony_ci 1223195972f6Sopenharmony_ci/** 1224195972f6Sopenharmony_ci * @ingroup udp_raw 1225195972f6Sopenharmony_ci * Removes and deallocates the pcb. 1226195972f6Sopenharmony_ci * 1227195972f6Sopenharmony_ci * @param pcb UDP PCB to be removed. The PCB is removed from the list of 1228195972f6Sopenharmony_ci * UDP PCB's and the data structure is freed from memory. 1229195972f6Sopenharmony_ci * 1230195972f6Sopenharmony_ci * @see udp_new() 1231195972f6Sopenharmony_ci */ 1232195972f6Sopenharmony_civoid 1233195972f6Sopenharmony_ciudp_remove(struct udp_pcb *pcb) 1234195972f6Sopenharmony_ci{ 1235195972f6Sopenharmony_ci struct udp_pcb *pcb2; 1236195972f6Sopenharmony_ci 1237195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 1238195972f6Sopenharmony_ci 1239195972f6Sopenharmony_ci LWIP_ERROR("udp_remove: invalid pcb", pcb != NULL, return); 1240195972f6Sopenharmony_ci 1241195972f6Sopenharmony_ci mib2_udp_unbind(pcb); 1242195972f6Sopenharmony_ci /* pcb to be removed is first in list? */ 1243195972f6Sopenharmony_ci if (udp_pcbs == pcb) { 1244195972f6Sopenharmony_ci /* make list start at 2nd pcb */ 1245195972f6Sopenharmony_ci udp_pcbs = udp_pcbs->next; 1246195972f6Sopenharmony_ci /* pcb not 1st in list */ 1247195972f6Sopenharmony_ci } else { 1248195972f6Sopenharmony_ci for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { 1249195972f6Sopenharmony_ci /* find pcb in udp_pcbs list */ 1250195972f6Sopenharmony_ci if (pcb2->next != NULL && pcb2->next == pcb) { 1251195972f6Sopenharmony_ci /* remove pcb from list */ 1252195972f6Sopenharmony_ci pcb2->next = pcb->next; 1253195972f6Sopenharmony_ci break; 1254195972f6Sopenharmony_ci } 1255195972f6Sopenharmony_ci } 1256195972f6Sopenharmony_ci } 1257195972f6Sopenharmony_ci memp_free(MEMP_UDP_PCB, pcb); 1258195972f6Sopenharmony_ci} 1259195972f6Sopenharmony_ci 1260195972f6Sopenharmony_ci/** 1261195972f6Sopenharmony_ci * @ingroup udp_raw 1262195972f6Sopenharmony_ci * Creates a new UDP pcb which can be used for UDP communication. The 1263195972f6Sopenharmony_ci * pcb is not active until it has either been bound to a local address 1264195972f6Sopenharmony_ci * or connected to a remote address. 1265195972f6Sopenharmony_ci * @see MEMP_NUM_UDP_PCB 1266195972f6Sopenharmony_ci * 1267195972f6Sopenharmony_ci * @return The UDP PCB which was created. NULL if the PCB data structure 1268195972f6Sopenharmony_ci * could not be allocated. 1269195972f6Sopenharmony_ci * 1270195972f6Sopenharmony_ci * @see udp_remove() 1271195972f6Sopenharmony_ci */ 1272195972f6Sopenharmony_cistruct udp_pcb * 1273195972f6Sopenharmony_ciudp_new(void) 1274195972f6Sopenharmony_ci{ 1275195972f6Sopenharmony_ci struct udp_pcb *pcb; 1276195972f6Sopenharmony_ci 1277195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 1278195972f6Sopenharmony_ci 1279195972f6Sopenharmony_ci pcb = (struct udp_pcb *)memp_malloc(MEMP_UDP_PCB); 1280195972f6Sopenharmony_ci /* could allocate UDP PCB? */ 1281195972f6Sopenharmony_ci if (pcb != NULL) { 1282195972f6Sopenharmony_ci /* UDP Lite: by initializing to all zeroes, chksum_len is set to 0 1283195972f6Sopenharmony_ci * which means checksum is generated over the whole datagram per default 1284195972f6Sopenharmony_ci * (recommended as default by RFC 3828). */ 1285195972f6Sopenharmony_ci /* initialize PCB to all zeroes */ 1286195972f6Sopenharmony_ci memset(pcb, 0, sizeof(struct udp_pcb)); 1287195972f6Sopenharmony_ci pcb->ttl = UDP_TTL; 1288195972f6Sopenharmony_ci#if LWIP_MULTICAST_TX_OPTIONS 1289195972f6Sopenharmony_ci udp_set_multicast_ttl(pcb, UDP_TTL); 1290195972f6Sopenharmony_ci#endif /* LWIP_MULTICAST_TX_OPTIONS */ 1291195972f6Sopenharmony_ci } 1292195972f6Sopenharmony_ci return pcb; 1293195972f6Sopenharmony_ci} 1294195972f6Sopenharmony_ci 1295195972f6Sopenharmony_ci/** 1296195972f6Sopenharmony_ci * @ingroup udp_raw 1297195972f6Sopenharmony_ci * Create a UDP PCB for specific IP type. 1298195972f6Sopenharmony_ci * The pcb is not active until it has either been bound to a local address 1299195972f6Sopenharmony_ci * or connected to a remote address. 1300195972f6Sopenharmony_ci * @see MEMP_NUM_UDP_PCB 1301195972f6Sopenharmony_ci * 1302195972f6Sopenharmony_ci * @param type IP address type, see @ref lwip_ip_addr_type definitions. 1303195972f6Sopenharmony_ci * If you want to listen to IPv4 and IPv6 (dual-stack) packets, 1304195972f6Sopenharmony_ci * supply @ref IPADDR_TYPE_ANY as argument and bind to @ref IP_ANY_TYPE. 1305195972f6Sopenharmony_ci * @return The UDP PCB which was created. NULL if the PCB data structure 1306195972f6Sopenharmony_ci * could not be allocated. 1307195972f6Sopenharmony_ci * 1308195972f6Sopenharmony_ci * @see udp_remove() 1309195972f6Sopenharmony_ci */ 1310195972f6Sopenharmony_cistruct udp_pcb * 1311195972f6Sopenharmony_ciudp_new_ip_type(u8_t type) 1312195972f6Sopenharmony_ci{ 1313195972f6Sopenharmony_ci struct udp_pcb *pcb; 1314195972f6Sopenharmony_ci 1315195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 1316195972f6Sopenharmony_ci 1317195972f6Sopenharmony_ci pcb = udp_new(); 1318195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6 1319195972f6Sopenharmony_ci if (pcb != NULL) { 1320195972f6Sopenharmony_ci IP_SET_TYPE_VAL(pcb->local_ip, type); 1321195972f6Sopenharmony_ci IP_SET_TYPE_VAL(pcb->remote_ip, type); 1322195972f6Sopenharmony_ci } 1323195972f6Sopenharmony_ci#else 1324195972f6Sopenharmony_ci LWIP_UNUSED_ARG(type); 1325195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && LWIP_IPV6 */ 1326195972f6Sopenharmony_ci return pcb; 1327195972f6Sopenharmony_ci} 1328195972f6Sopenharmony_ci 1329195972f6Sopenharmony_ci/** This function is called from netif.c when address is changed 1330195972f6Sopenharmony_ci * 1331195972f6Sopenharmony_ci * @param old_addr IP address of the netif before change 1332195972f6Sopenharmony_ci * @param new_addr IP address of the netif after change 1333195972f6Sopenharmony_ci */ 1334195972f6Sopenharmony_civoid udp_netif_ip_addr_changed(const ip_addr_t *old_addr, const ip_addr_t *new_addr) 1335195972f6Sopenharmony_ci{ 1336195972f6Sopenharmony_ci struct udp_pcb *upcb; 1337195972f6Sopenharmony_ci 1338195972f6Sopenharmony_ci if (!ip_addr_isany(old_addr) && !ip_addr_isany(new_addr)) { 1339195972f6Sopenharmony_ci for (upcb = udp_pcbs; upcb != NULL; upcb = upcb->next) { 1340195972f6Sopenharmony_ci /* PCB bound to current local interface address? */ 1341195972f6Sopenharmony_ci if (ip_addr_cmp(&upcb->local_ip, old_addr)) { 1342195972f6Sopenharmony_ci /* The PCB is bound to the old ipaddr and 1343195972f6Sopenharmony_ci * is set to bound to the new one instead */ 1344195972f6Sopenharmony_ci ip_addr_copy(upcb->local_ip, *new_addr); 1345195972f6Sopenharmony_ci } 1346195972f6Sopenharmony_ci } 1347195972f6Sopenharmony_ci } 1348195972f6Sopenharmony_ci} 1349195972f6Sopenharmony_ci 1350195972f6Sopenharmony_ci#if UDP_DEBUG 1351195972f6Sopenharmony_ci/** 1352195972f6Sopenharmony_ci * Print UDP header information for debug purposes. 1353195972f6Sopenharmony_ci * 1354195972f6Sopenharmony_ci * @param udphdr pointer to the udp header in memory. 1355195972f6Sopenharmony_ci */ 1356195972f6Sopenharmony_civoid 1357195972f6Sopenharmony_ciudp_debug_print(struct udp_hdr *udphdr) 1358195972f6Sopenharmony_ci{ 1359195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n")); 1360195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); 1361195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n", 1362195972f6Sopenharmony_ci lwip_ntohs(udphdr->src), lwip_ntohs(udphdr->dest))); 1363195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); 1364195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | 0x%04"X16_F" | (len, chksum)\n", 1365195972f6Sopenharmony_ci lwip_ntohs(udphdr->len), lwip_ntohs(udphdr->chksum))); 1366195972f6Sopenharmony_ci LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); 1367195972f6Sopenharmony_ci} 1368195972f6Sopenharmony_ci#endif /* UDP_DEBUG */ 1369195972f6Sopenharmony_ci 1370195972f6Sopenharmony_ci#endif /* LWIP_UDP */ 1371