My fork of the HTTPServer (working)

Dependents:   DGWWebServer LAN2

Committer:
screamer
Date:
Tue Nov 20 12:18:53 2012 +0000
Revision:
1:284f2df30cf9
Parent:
0:7a64fbb4069d
local changes

Who changed what in which revision?

UserRevisionLine numberNew contents of line
screamer 0:7a64fbb4069d 1 /**
screamer 0:7a64fbb4069d 2 * @file
screamer 0:7a64fbb4069d 3 * User Datagram Protocol module
screamer 0:7a64fbb4069d 4 *
screamer 0:7a64fbb4069d 5 */
screamer 0:7a64fbb4069d 6
screamer 0:7a64fbb4069d 7 /*
screamer 0:7a64fbb4069d 8 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
screamer 0:7a64fbb4069d 9 * All rights reserved.
screamer 0:7a64fbb4069d 10 *
screamer 0:7a64fbb4069d 11 * Redistribution and use in source and binary forms, with or without modification,
screamer 0:7a64fbb4069d 12 * are permitted provided that the following conditions are met:
screamer 0:7a64fbb4069d 13 *
screamer 0:7a64fbb4069d 14 * 1. Redistributions of source code must retain the above copyright notice,
screamer 0:7a64fbb4069d 15 * this list of conditions and the following disclaimer.
screamer 0:7a64fbb4069d 16 * 2. Redistributions in binary form must reproduce the above copyright notice,
screamer 0:7a64fbb4069d 17 * this list of conditions and the following disclaimer in the documentation
screamer 0:7a64fbb4069d 18 * and/or other materials provided with the distribution.
screamer 0:7a64fbb4069d 19 * 3. The name of the author may not be used to endorse or promote products
screamer 0:7a64fbb4069d 20 * derived from this software without specific prior written permission.
screamer 0:7a64fbb4069d 21 *
screamer 0:7a64fbb4069d 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
screamer 0:7a64fbb4069d 23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
screamer 0:7a64fbb4069d 24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
screamer 0:7a64fbb4069d 25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
screamer 0:7a64fbb4069d 26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
screamer 0:7a64fbb4069d 27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
screamer 0:7a64fbb4069d 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
screamer 0:7a64fbb4069d 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
screamer 0:7a64fbb4069d 30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
screamer 0:7a64fbb4069d 31 * OF SUCH DAMAGE.
screamer 0:7a64fbb4069d 32 *
screamer 0:7a64fbb4069d 33 * This file is part of the lwIP TCP/IP stack.
screamer 0:7a64fbb4069d 34 *
screamer 0:7a64fbb4069d 35 * Author: Adam Dunkels <adam@sics.se>
screamer 0:7a64fbb4069d 36 *
screamer 0:7a64fbb4069d 37 */
screamer 0:7a64fbb4069d 38
screamer 0:7a64fbb4069d 39
screamer 0:7a64fbb4069d 40 /* udp.c
screamer 0:7a64fbb4069d 41 *
screamer 0:7a64fbb4069d 42 * The code for the User Datagram Protocol UDP & UDPLite (RFC 3828).
screamer 0:7a64fbb4069d 43 *
screamer 0:7a64fbb4069d 44 */
screamer 0:7a64fbb4069d 45
screamer 0:7a64fbb4069d 46 /* @todo Check the use of '(struct udp_pcb).chksum_len_rx'!
screamer 0:7a64fbb4069d 47 */
screamer 0:7a64fbb4069d 48
screamer 0:7a64fbb4069d 49 #include "lwip/opt.h"
screamer 0:7a64fbb4069d 50
screamer 0:7a64fbb4069d 51 #if LWIP_UDP /* don't build if not configured for use in lwipopts.h */
screamer 0:7a64fbb4069d 52
screamer 0:7a64fbb4069d 53 #include "lwip/udp.h"
screamer 0:7a64fbb4069d 54 #include "lwip/def.h"
screamer 0:7a64fbb4069d 55 #include "lwip/memp.h"
screamer 0:7a64fbb4069d 56 #include "lwip/inet.h"
screamer 0:7a64fbb4069d 57 #include "lwip/inet_chksum.h"
screamer 0:7a64fbb4069d 58 #include "lwip/ip_addr.h"
screamer 0:7a64fbb4069d 59 #include "lwip/netif.h"
screamer 0:7a64fbb4069d 60 #include "lwip/icmp.h"
screamer 0:7a64fbb4069d 61 #include "lwip/stats.h"
screamer 0:7a64fbb4069d 62 #include "lwip/snmp.h"
screamer 0:7a64fbb4069d 63 #include "arch/perf.h"
screamer 0:7a64fbb4069d 64 #include "lwip/dhcp.h"
screamer 0:7a64fbb4069d 65
screamer 0:7a64fbb4069d 66 #include <string.h>
screamer 0:7a64fbb4069d 67
screamer 0:7a64fbb4069d 68 /* The list of UDP PCBs */
screamer 0:7a64fbb4069d 69 /* exported in udp.h (was static) */
screamer 0:7a64fbb4069d 70 struct udp_pcb *udp_pcbs;
screamer 0:7a64fbb4069d 71
screamer 0:7a64fbb4069d 72 /**
screamer 0:7a64fbb4069d 73 * Process an incoming UDP datagram.
screamer 0:7a64fbb4069d 74 *
screamer 0:7a64fbb4069d 75 * Given an incoming UDP datagram (as a chain of pbufs) this function
screamer 0:7a64fbb4069d 76 * finds a corresponding UDP PCB and hands over the pbuf to the pcbs
screamer 0:7a64fbb4069d 77 * recv function. If no pcb is found or the datagram is incorrect, the
screamer 0:7a64fbb4069d 78 * pbuf is freed.
screamer 0:7a64fbb4069d 79 *
screamer 0:7a64fbb4069d 80 * @param p pbuf to be demultiplexed to a UDP PCB.
screamer 0:7a64fbb4069d 81 * @param inp network interface on which the datagram was received.
screamer 0:7a64fbb4069d 82 *
screamer 0:7a64fbb4069d 83 */
screamer 0:7a64fbb4069d 84 void
screamer 0:7a64fbb4069d 85 udp_input(struct pbuf *p, struct netif *inp)
screamer 0:7a64fbb4069d 86 {
screamer 0:7a64fbb4069d 87 struct udp_hdr *udphdr;
screamer 0:7a64fbb4069d 88 struct udp_pcb *pcb, *prev;
screamer 0:7a64fbb4069d 89 struct udp_pcb *uncon_pcb;
screamer 0:7a64fbb4069d 90 struct ip_hdr *iphdr;
screamer 0:7a64fbb4069d 91 u16_t src, dest;
screamer 0:7a64fbb4069d 92 u8_t local_match;
screamer 0:7a64fbb4069d 93
screamer 0:7a64fbb4069d 94 PERF_START;
screamer 0:7a64fbb4069d 95
screamer 0:7a64fbb4069d 96 UDP_STATS_INC(udp.recv);
screamer 0:7a64fbb4069d 97
screamer 0:7a64fbb4069d 98 iphdr = (struct ip_hdr *)(p->payload);
screamer 0:7a64fbb4069d 99
screamer 0:7a64fbb4069d 100 /* Check minimum length (IP header + UDP header)
screamer 0:7a64fbb4069d 101 * and move payload pointer to UDP header */
screamer 0:7a64fbb4069d 102 if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) {
screamer 0:7a64fbb4069d 103 /* drop short packets */
screamer 0:7a64fbb4069d 104 LWIP_DEBUGF(UDP_DEBUG,
screamer 0:7a64fbb4069d 105 ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len));
screamer 0:7a64fbb4069d 106 UDP_STATS_INC(udp.lenerr);
screamer 0:7a64fbb4069d 107 UDP_STATS_INC(udp.drop);
screamer 0:7a64fbb4069d 108 snmp_inc_udpinerrors();
screamer 0:7a64fbb4069d 109 pbuf_free(p);
screamer 0:7a64fbb4069d 110 goto end;
screamer 0:7a64fbb4069d 111 }
screamer 0:7a64fbb4069d 112
screamer 0:7a64fbb4069d 113 udphdr = (struct udp_hdr *)p->payload;
screamer 0:7a64fbb4069d 114
screamer 0:7a64fbb4069d 115 LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len));
screamer 0:7a64fbb4069d 116
screamer 0:7a64fbb4069d 117 /* convert src and dest ports to host byte order */
screamer 0:7a64fbb4069d 118 src = ntohs(udphdr->src);
screamer 0:7a64fbb4069d 119 dest = ntohs(udphdr->dest);
screamer 0:7a64fbb4069d 120
screamer 0:7a64fbb4069d 121 udp_debug_print(udphdr);
screamer 0:7a64fbb4069d 122
screamer 0:7a64fbb4069d 123 /* print the UDP source and destination */
screamer 0:7a64fbb4069d 124 LWIP_DEBUGF(UDP_DEBUG,
screamer 0:7a64fbb4069d 125 ("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- "
screamer 0:7a64fbb4069d 126 "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
screamer 0:7a64fbb4069d 127 ip4_addr1(&iphdr->dest), ip4_addr2(&iphdr->dest),
screamer 0:7a64fbb4069d 128 ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest),
screamer 0:7a64fbb4069d 129 ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src),
screamer 0:7a64fbb4069d 130 ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src)));
screamer 0:7a64fbb4069d 131
screamer 0:7a64fbb4069d 132 #if LWIP_DHCP
screamer 0:7a64fbb4069d 133 pcb = NULL;
screamer 0:7a64fbb4069d 134 /* when LWIP_DHCP is active, packets to DHCP_CLIENT_PORT may only be processed by
screamer 0:7a64fbb4069d 135 the dhcp module, no other UDP pcb may use the local UDP port DHCP_CLIENT_PORT */
screamer 0:7a64fbb4069d 136 if (dest == DHCP_CLIENT_PORT) {
screamer 0:7a64fbb4069d 137 /* all packets for DHCP_CLIENT_PORT not coming from DHCP_SERVER_PORT are dropped! */
screamer 0:7a64fbb4069d 138 if (src == DHCP_SERVER_PORT) {
screamer 0:7a64fbb4069d 139 if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) {
screamer 0:7a64fbb4069d 140 /* accept the packe if
screamer 0:7a64fbb4069d 141 (- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY!
screamer 0:7a64fbb4069d 142 - inp->dhcp->pcb->remote == ANY or iphdr->src */
screamer 0:7a64fbb4069d 143 if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) ||
screamer 0:7a64fbb4069d 144 ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), &(iphdr->src)))) {
screamer 0:7a64fbb4069d 145 pcb = inp->dhcp->pcb;
screamer 0:7a64fbb4069d 146 }
screamer 0:7a64fbb4069d 147 }
screamer 0:7a64fbb4069d 148 }
screamer 0:7a64fbb4069d 149 } else
screamer 0:7a64fbb4069d 150 #endif /* LWIP_DHCP */
screamer 0:7a64fbb4069d 151 {
screamer 0:7a64fbb4069d 152 prev = NULL;
screamer 0:7a64fbb4069d 153 local_match = 0;
screamer 0:7a64fbb4069d 154 uncon_pcb = NULL;
screamer 0:7a64fbb4069d 155 /* Iterate through the UDP pcb list for a matching pcb.
screamer 0:7a64fbb4069d 156 * 'Perfect match' pcbs (connected to the remote port & ip address) are
screamer 0:7a64fbb4069d 157 * preferred. If no perfect match is found, the first unconnected pcb that
screamer 0:7a64fbb4069d 158 * matches the local port and ip address gets the datagram. */
screamer 0:7a64fbb4069d 159 for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
screamer 0:7a64fbb4069d 160 local_match = 0;
screamer 0:7a64fbb4069d 161 /* print the PCB local and remote address */
screamer 0:7a64fbb4069d 162 LWIP_DEBUGF(UDP_DEBUG,
screamer 0:7a64fbb4069d 163 ("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- "
screamer 0:7a64fbb4069d 164 "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
screamer 0:7a64fbb4069d 165 ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip),
screamer 0:7a64fbb4069d 166 ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port,
screamer 0:7a64fbb4069d 167 ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
screamer 0:7a64fbb4069d 168 ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip), pcb->remote_port));
screamer 0:7a64fbb4069d 169
screamer 0:7a64fbb4069d 170 /* compare PCB local addr+port to UDP destination addr+port */
screamer 0:7a64fbb4069d 171 if ((pcb->local_port == dest) &&
screamer 0:7a64fbb4069d 172 (ip_addr_isany(&pcb->local_ip) ||
screamer 0:7a64fbb4069d 173 ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) ||
screamer 0:7a64fbb4069d 174 #if LWIP_IGMP
screamer 0:7a64fbb4069d 175 ip_addr_ismulticast(&(iphdr->dest)) ||
screamer 0:7a64fbb4069d 176 #endif /* LWIP_IGMP */
screamer 0:7a64fbb4069d 177 ip_addr_isbroadcast(&(iphdr->dest), inp))) {
screamer 0:7a64fbb4069d 178 local_match = 1;
screamer 0:7a64fbb4069d 179 if ((uncon_pcb == NULL) &&
screamer 0:7a64fbb4069d 180 ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {
screamer 0:7a64fbb4069d 181 /* the first unconnected matching PCB */
screamer 0:7a64fbb4069d 182 uncon_pcb = pcb;
screamer 0:7a64fbb4069d 183 }
screamer 0:7a64fbb4069d 184 }
screamer 0:7a64fbb4069d 185 /* compare PCB remote addr+port to UDP source addr+port */
screamer 0:7a64fbb4069d 186 if ((local_match != 0) &&
screamer 0:7a64fbb4069d 187 (pcb->remote_port == src) &&
screamer 0:7a64fbb4069d 188 (ip_addr_isany(&pcb->remote_ip) ||
screamer 0:7a64fbb4069d 189 ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)))) {
screamer 0:7a64fbb4069d 190 /* the first fully matching PCB */
screamer 0:7a64fbb4069d 191 if (prev != NULL) {
screamer 0:7a64fbb4069d 192 /* move the pcb to the front of udp_pcbs so that is
screamer 0:7a64fbb4069d 193 found faster next time */
screamer 0:7a64fbb4069d 194 prev->next = pcb->next;
screamer 0:7a64fbb4069d 195 pcb->next = udp_pcbs;
screamer 0:7a64fbb4069d 196 udp_pcbs = pcb;
screamer 0:7a64fbb4069d 197 } else {
screamer 0:7a64fbb4069d 198 UDP_STATS_INC(udp.cachehit);
screamer 0:7a64fbb4069d 199 }
screamer 0:7a64fbb4069d 200 break;
screamer 0:7a64fbb4069d 201 }
screamer 0:7a64fbb4069d 202 prev = pcb;
screamer 0:7a64fbb4069d 203 }
screamer 0:7a64fbb4069d 204 /* no fully matching pcb found? then look for an unconnected pcb */
screamer 0:7a64fbb4069d 205 if (pcb == NULL) {
screamer 0:7a64fbb4069d 206 pcb = uncon_pcb;
screamer 0:7a64fbb4069d 207 }
screamer 0:7a64fbb4069d 208 }
screamer 0:7a64fbb4069d 209
screamer 0:7a64fbb4069d 210 /* Check checksum if this is a match or if it was directed at us. */
screamer 0:7a64fbb4069d 211 if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &iphdr->dest)) {
screamer 0:7a64fbb4069d 212 LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n"));
screamer 0:7a64fbb4069d 213 #if LWIP_UDPLITE
screamer 0:7a64fbb4069d 214 if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {
screamer 0:7a64fbb4069d 215 /* Do the UDP Lite checksum */
screamer 0:7a64fbb4069d 216 #if CHECKSUM_CHECK_UDP
screamer 0:7a64fbb4069d 217 u16_t chklen = ntohs(udphdr->len);
screamer 0:7a64fbb4069d 218 if (chklen < sizeof(struct udp_hdr)) {
screamer 0:7a64fbb4069d 219 if (chklen == 0) {
screamer 0:7a64fbb4069d 220 /* For UDP-Lite, checksum length of 0 means checksum
screamer 0:7a64fbb4069d 221 over the complete packet (See RFC 3828 chap. 3.1) */
screamer 0:7a64fbb4069d 222 chklen = p->tot_len;
screamer 0:7a64fbb4069d 223 } else {
screamer 0:7a64fbb4069d 224 /* At least the UDP-Lite header must be covered by the
screamer 0:7a64fbb4069d 225 checksum! (Again, see RFC 3828 chap. 3.1) */
screamer 0:7a64fbb4069d 226 UDP_STATS_INC(udp.chkerr);
screamer 0:7a64fbb4069d 227 UDP_STATS_INC(udp.drop);
screamer 0:7a64fbb4069d 228 snmp_inc_udpinerrors();
screamer 0:7a64fbb4069d 229 pbuf_free(p);
screamer 0:7a64fbb4069d 230 goto end;
screamer 0:7a64fbb4069d 231 }
screamer 0:7a64fbb4069d 232 }
screamer 0:7a64fbb4069d 233 if (inet_chksum_pseudo_partial(p, (struct ip_addr *)&(iphdr->src),
screamer 0:7a64fbb4069d 234 (struct ip_addr *)&(iphdr->dest),
screamer 0:7a64fbb4069d 235 IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) {
screamer 0:7a64fbb4069d 236 LWIP_DEBUGF(UDP_DEBUG | 2,
screamer 0:7a64fbb4069d 237 ("udp_input: UDP Lite datagram discarded due to failing checksum\n"));
screamer 0:7a64fbb4069d 238 UDP_STATS_INC(udp.chkerr);
screamer 0:7a64fbb4069d 239 UDP_STATS_INC(udp.drop);
screamer 0:7a64fbb4069d 240 snmp_inc_udpinerrors();
screamer 0:7a64fbb4069d 241 pbuf_free(p);
screamer 0:7a64fbb4069d 242 goto end;
screamer 0:7a64fbb4069d 243 }
screamer 0:7a64fbb4069d 244 #endif /* CHECKSUM_CHECK_UDP */
screamer 0:7a64fbb4069d 245 } else
screamer 0:7a64fbb4069d 246 #endif /* LWIP_UDPLITE */
screamer 0:7a64fbb4069d 247 {
screamer 0:7a64fbb4069d 248 #if CHECKSUM_CHECK_UDP
screamer 0:7a64fbb4069d 249 if (udphdr->chksum != 0) {
screamer 0:7a64fbb4069d 250 if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
screamer 0:7a64fbb4069d 251 (struct ip_addr *)&(iphdr->dest),
screamer 0:7a64fbb4069d 252 IP_PROTO_UDP, p->tot_len) != 0) {
screamer 0:7a64fbb4069d 253 LWIP_DEBUGF(UDP_DEBUG | 2,
screamer 0:7a64fbb4069d 254 ("udp_input: UDP datagram discarded due to failing checksum\n"));
screamer 0:7a64fbb4069d 255 UDP_STATS_INC(udp.chkerr);
screamer 0:7a64fbb4069d 256 UDP_STATS_INC(udp.drop);
screamer 0:7a64fbb4069d 257 snmp_inc_udpinerrors();
screamer 0:7a64fbb4069d 258 pbuf_free(p);
screamer 0:7a64fbb4069d 259 goto end;
screamer 0:7a64fbb4069d 260 }
screamer 0:7a64fbb4069d 261 }
screamer 0:7a64fbb4069d 262 #endif /* CHECKSUM_CHECK_UDP */
screamer 0:7a64fbb4069d 263 }
screamer 0:7a64fbb4069d 264 if(pbuf_header(p, -UDP_HLEN)) {
screamer 0:7a64fbb4069d 265 /* Can we cope with this failing? Just assert for now */
screamer 0:7a64fbb4069d 266 LWIP_ASSERT("pbuf_header failed\n", 0);
screamer 0:7a64fbb4069d 267 UDP_STATS_INC(udp.drop);
screamer 0:7a64fbb4069d 268 snmp_inc_udpinerrors();
screamer 0:7a64fbb4069d 269 pbuf_free(p);
screamer 0:7a64fbb4069d 270 goto end;
screamer 0:7a64fbb4069d 271 }
screamer 0:7a64fbb4069d 272 if (pcb != NULL) {
screamer 0:7a64fbb4069d 273 snmp_inc_udpindatagrams();
screamer 0:7a64fbb4069d 274 /* callback */
screamer 0:7a64fbb4069d 275 if (pcb->recv != NULL) {
screamer 0:7a64fbb4069d 276 /* now the recv function is responsible for freeing p */
screamer 0:7a64fbb4069d 277 struct ip_addr iphdrsrc; // __packed hack
screamer 0:7a64fbb4069d 278 iphdrsrc.addr = iphdr->src.addr;
screamer 0:7a64fbb4069d 279 pcb->recv(pcb->recv_arg, pcb, p, &iphdrsrc, src);
screamer 0:7a64fbb4069d 280 } else {
screamer 0:7a64fbb4069d 281 /* no recv function registered? then we have to free the pbuf! */
screamer 0:7a64fbb4069d 282 pbuf_free(p);
screamer 0:7a64fbb4069d 283 goto end;
screamer 0:7a64fbb4069d 284 }
screamer 0:7a64fbb4069d 285 } else {
screamer 0:7a64fbb4069d 286 LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n"));
screamer 0:7a64fbb4069d 287
screamer 0:7a64fbb4069d 288 #if LWIP_ICMP
screamer 0:7a64fbb4069d 289 /* No match was found, send ICMP destination port unreachable unless
screamer 0:7a64fbb4069d 290 destination address was broadcast/multicast. */
screamer 0:7a64fbb4069d 291 if (!ip_addr_isbroadcast(&(iphdr->dest), inp) &&
screamer 0:7a64fbb4069d 292 !ip_addr_ismulticast(&iphdr->dest)) {
screamer 0:7a64fbb4069d 293 /* move payload pointer back to ip header */
screamer 0:7a64fbb4069d 294 pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN);
screamer 0:7a64fbb4069d 295 LWIP_ASSERT("p->payload == iphdr", (p->payload == iphdr));
screamer 0:7a64fbb4069d 296 icmp_dest_unreach(p, ICMP_DUR_PORT);
screamer 0:7a64fbb4069d 297 }
screamer 0:7a64fbb4069d 298 #endif /* LWIP_ICMP */
screamer 0:7a64fbb4069d 299 UDP_STATS_INC(udp.proterr);
screamer 0:7a64fbb4069d 300 UDP_STATS_INC(udp.drop);
screamer 0:7a64fbb4069d 301 snmp_inc_udpnoports();
screamer 0:7a64fbb4069d 302 pbuf_free(p);
screamer 0:7a64fbb4069d 303 }
screamer 0:7a64fbb4069d 304 } else {
screamer 0:7a64fbb4069d 305 pbuf_free(p);
screamer 0:7a64fbb4069d 306 }
screamer 0:7a64fbb4069d 307 end:
screamer 0:7a64fbb4069d 308 PERF_STOP("udp_input");
screamer 0:7a64fbb4069d 309 }
screamer 0:7a64fbb4069d 310
screamer 0:7a64fbb4069d 311 /**
screamer 0:7a64fbb4069d 312 * Send data using UDP.
screamer 0:7a64fbb4069d 313 *
screamer 0:7a64fbb4069d 314 * @param pcb UDP PCB used to send the data.
screamer 0:7a64fbb4069d 315 * @param p chain of pbuf's to be sent.
screamer 0:7a64fbb4069d 316 *
screamer 0:7a64fbb4069d 317 * The datagram will be sent to the current remote_ip & remote_port
screamer 0:7a64fbb4069d 318 * stored in pcb. If the pcb is not bound to a port, it will
screamer 0:7a64fbb4069d 319 * automatically be bound to a random port.
screamer 0:7a64fbb4069d 320 *
screamer 0:7a64fbb4069d 321 * @return lwIP error code.
screamer 0:7a64fbb4069d 322 * - ERR_OK. Successful. No error occured.
screamer 0:7a64fbb4069d 323 * - ERR_MEM. Out of memory.
screamer 0:7a64fbb4069d 324 * - ERR_RTE. Could not find route to destination address.
screamer 0:7a64fbb4069d 325 * - More errors could be returned by lower protocol layers.
screamer 0:7a64fbb4069d 326 *
screamer 0:7a64fbb4069d 327 * @see udp_disconnect() udp_sendto()
screamer 0:7a64fbb4069d 328 */
screamer 0:7a64fbb4069d 329 err_t
screamer 0:7a64fbb4069d 330 udp_send(struct udp_pcb *pcb, struct pbuf *p)
screamer 0:7a64fbb4069d 331 {
screamer 0:7a64fbb4069d 332 /* send to the packet using remote ip and port stored in the pcb */
screamer 0:7a64fbb4069d 333 return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port);
screamer 0:7a64fbb4069d 334 }
screamer 0:7a64fbb4069d 335
screamer 0:7a64fbb4069d 336 /**
screamer 0:7a64fbb4069d 337 * Send data to a specified address using UDP.
screamer 0:7a64fbb4069d 338 *
screamer 0:7a64fbb4069d 339 * @param pcb UDP PCB used to send the data.
screamer 0:7a64fbb4069d 340 * @param p chain of pbuf's to be sent.
screamer 0:7a64fbb4069d 341 * @param dst_ip Destination IP address.
screamer 0:7a64fbb4069d 342 * @param dst_port Destination UDP port.
screamer 0:7a64fbb4069d 343 *
screamer 0:7a64fbb4069d 344 * dst_ip & dst_port are expected to be in the same byte order as in the pcb.
screamer 0:7a64fbb4069d 345 *
screamer 0:7a64fbb4069d 346 * If the PCB already has a remote address association, it will
screamer 0:7a64fbb4069d 347 * be restored after the data is sent.
screamer 0:7a64fbb4069d 348 *
screamer 0:7a64fbb4069d 349 * @return lwIP error code (@see udp_send for possible error codes)
screamer 0:7a64fbb4069d 350 *
screamer 0:7a64fbb4069d 351 * @see udp_disconnect() udp_send()
screamer 0:7a64fbb4069d 352 */
screamer 0:7a64fbb4069d 353 err_t
screamer 0:7a64fbb4069d 354 udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
screamer 0:7a64fbb4069d 355 struct ip_addr *dst_ip, u16_t dst_port)
screamer 0:7a64fbb4069d 356 {
screamer 0:7a64fbb4069d 357 struct netif *netif;
screamer 0:7a64fbb4069d 358
screamer 0:7a64fbb4069d 359 LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, ("udp_send\n"));
screamer 0:7a64fbb4069d 360
screamer 0:7a64fbb4069d 361 /* find the outgoing network interface for this packet */
screamer 0:7a64fbb4069d 362 #if LWIP_IGMP
screamer 0:7a64fbb4069d 363 netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip));
screamer 0:7a64fbb4069d 364 #else
screamer 0:7a64fbb4069d 365 netif = ip_route(dst_ip);
screamer 0:7a64fbb4069d 366 #endif /* LWIP_IGMP */
screamer 0:7a64fbb4069d 367
screamer 0:7a64fbb4069d 368 /* no outgoing network interface could be found? */
screamer 0:7a64fbb4069d 369 if (netif == NULL) {
screamer 0:7a64fbb4069d 370 LWIP_DEBUGF(UDP_DEBUG | 1, ("udp_send: No route to 0x%"X32_F"\n", dst_ip->addr));
screamer 0:7a64fbb4069d 371 UDP_STATS_INC(udp.rterr);
screamer 0:7a64fbb4069d 372 return ERR_RTE;
screamer 0:7a64fbb4069d 373 }
screamer 0:7a64fbb4069d 374 return udp_sendto_if(pcb, p, dst_ip, dst_port, netif);
screamer 0:7a64fbb4069d 375 }
screamer 0:7a64fbb4069d 376
screamer 0:7a64fbb4069d 377 /**
screamer 0:7a64fbb4069d 378 * Send data to a specified address using UDP.
screamer 0:7a64fbb4069d 379 * The netif used for sending can be specified.
screamer 0:7a64fbb4069d 380 *
screamer 0:7a64fbb4069d 381 * This function exists mainly for DHCP, to be able to send UDP packets
screamer 0:7a64fbb4069d 382 * on a netif that is still down.
screamer 0:7a64fbb4069d 383 *
screamer 0:7a64fbb4069d 384 * @param pcb UDP PCB used to send the data.
screamer 0:7a64fbb4069d 385 * @param p chain of pbuf's to be sent.
screamer 0:7a64fbb4069d 386 * @param dst_ip Destination IP address.
screamer 0:7a64fbb4069d 387 * @param dst_port Destination UDP port.
screamer 0:7a64fbb4069d 388 * @param netif the netif used for sending.
screamer 0:7a64fbb4069d 389 *
screamer 0:7a64fbb4069d 390 * dst_ip & dst_port are expected to be in the same byte order as in the pcb.
screamer 0:7a64fbb4069d 391 *
screamer 0:7a64fbb4069d 392 * @return lwIP error code (@see udp_send for possible error codes)
screamer 0:7a64fbb4069d 393 *
screamer 0:7a64fbb4069d 394 * @see udp_disconnect() udp_send()
screamer 0:7a64fbb4069d 395 */
screamer 0:7a64fbb4069d 396 err_t
screamer 0:7a64fbb4069d 397 udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
screamer 0:7a64fbb4069d 398 struct ip_addr *dst_ip, u16_t dst_port, struct netif *netif)
screamer 0:7a64fbb4069d 399 {
screamer 0:7a64fbb4069d 400 struct udp_hdr *udphdr;
screamer 0:7a64fbb4069d 401 struct ip_addr *src_ip;
screamer 0:7a64fbb4069d 402 err_t err;
screamer 0:7a64fbb4069d 403 struct pbuf *q; /* q will be sent down the stack */
screamer 0:7a64fbb4069d 404
screamer 0:7a64fbb4069d 405 /* if the PCB is not yet bound to a port, bind it here */
screamer 0:7a64fbb4069d 406 if (pcb->local_port == 0) {
screamer 0:7a64fbb4069d 407 LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: not yet bound to a port, binding now\n"));
screamer 0:7a64fbb4069d 408 err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
screamer 0:7a64fbb4069d 409 if (err != ERR_OK) {
screamer 0:7a64fbb4069d 410 LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: forced port bind failed\n"));
screamer 0:7a64fbb4069d 411 return err;
screamer 0:7a64fbb4069d 412 }
screamer 0:7a64fbb4069d 413 }
screamer 0:7a64fbb4069d 414
screamer 0:7a64fbb4069d 415 /* not enough space to add an UDP header to first pbuf in given p chain? */
screamer 0:7a64fbb4069d 416 if (pbuf_header(p, UDP_HLEN)) {
screamer 0:7a64fbb4069d 417 /* allocate header in a separate new pbuf */
screamer 0:7a64fbb4069d 418 q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);
screamer 0:7a64fbb4069d 419 /* new header pbuf could not be allocated? */
screamer 0:7a64fbb4069d 420 if (q == NULL) {
screamer 0:7a64fbb4069d 421 LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: could not allocate header\n"));
screamer 0:7a64fbb4069d 422 return ERR_MEM;
screamer 0:7a64fbb4069d 423 }
screamer 0:7a64fbb4069d 424 /* chain header q in front of given pbuf p */
screamer 0:7a64fbb4069d 425 pbuf_chain(q, p);
screamer 0:7a64fbb4069d 426 /* first pbuf q points to header pbuf */
screamer 0:7a64fbb4069d 427 LWIP_DEBUGF(UDP_DEBUG,
screamer 0:7a64fbb4069d 428 ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
screamer 0:7a64fbb4069d 429 } else {
screamer 0:7a64fbb4069d 430 /* adding space for header within p succeeded */
screamer 0:7a64fbb4069d 431 /* first pbuf q equals given pbuf */
screamer 0:7a64fbb4069d 432 q = p;
screamer 0:7a64fbb4069d 433 LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p));
screamer 0:7a64fbb4069d 434 }
screamer 0:7a64fbb4069d 435 LWIP_ASSERT("check that first pbuf can hold struct udp_hdr",
screamer 0:7a64fbb4069d 436 (q->len >= sizeof(struct udp_hdr)));
screamer 0:7a64fbb4069d 437 /* q now represents the packet to be sent */
screamer 0:7a64fbb4069d 438 udphdr = (struct udp_hdr *)(q->payload);
screamer 0:7a64fbb4069d 439 udphdr->src = htons(pcb->local_port);
screamer 0:7a64fbb4069d 440 udphdr->dest = htons(dst_port);
screamer 0:7a64fbb4069d 441 /* in UDP, 0 checksum means 'no checksum' */
screamer 0:7a64fbb4069d 442 udphdr->chksum = 0x0000;
screamer 0:7a64fbb4069d 443
screamer 0:7a64fbb4069d 444 /* PCB local address is IP_ANY_ADDR? */
screamer 0:7a64fbb4069d 445 if (ip_addr_isany(&pcb->local_ip)) {
screamer 0:7a64fbb4069d 446 /* use outgoing network interface IP address as source address */
screamer 0:7a64fbb4069d 447 src_ip = &(netif->ip_addr);
screamer 0:7a64fbb4069d 448 } else {
screamer 0:7a64fbb4069d 449 /* check if UDP PCB local IP address is correct
screamer 0:7a64fbb4069d 450 * this could be an old address if netif->ip_addr has changed */
screamer 0:7a64fbb4069d 451 if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {
screamer 0:7a64fbb4069d 452 /* local_ip doesn't match, drop the packet */
screamer 0:7a64fbb4069d 453 if (q != p) {
screamer 0:7a64fbb4069d 454 /* free the header pbuf */
screamer 0:7a64fbb4069d 455 pbuf_free(q);
screamer 0:7a64fbb4069d 456 q = NULL;
screamer 0:7a64fbb4069d 457 /* p is still referenced by the caller, and will live on */
screamer 0:7a64fbb4069d 458 }
screamer 0:7a64fbb4069d 459 return ERR_VAL;
screamer 0:7a64fbb4069d 460 }
screamer 0:7a64fbb4069d 461 /* use UDP PCB local IP address as source address */
screamer 0:7a64fbb4069d 462 src_ip = &(pcb->local_ip);
screamer 0:7a64fbb4069d 463 }
screamer 0:7a64fbb4069d 464
screamer 0:7a64fbb4069d 465 LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len));
screamer 0:7a64fbb4069d 466
screamer 0:7a64fbb4069d 467 #if LWIP_UDPLITE
screamer 0:7a64fbb4069d 468 /* UDP Lite protocol? */
screamer 0:7a64fbb4069d 469 if (pcb->flags & UDP_FLAGS_UDPLITE) {
screamer 0:7a64fbb4069d 470 u16_t chklen, chklen_hdr;
screamer 0:7a64fbb4069d 471 LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len));
screamer 0:7a64fbb4069d 472 /* set UDP message length in UDP header */
screamer 0:7a64fbb4069d 473 chklen_hdr = chklen = pcb->chksum_len_tx;
screamer 0:7a64fbb4069d 474 if ((chklen < sizeof(struct udp_hdr)) || (chklen > q->tot_len)) {
screamer 0:7a64fbb4069d 475 if (chklen != 0) {
screamer 0:7a64fbb4069d 476 LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE pcb->chksum_len is illegal: %"U16_F"\n", chklen));
screamer 0:7a64fbb4069d 477 }
screamer 0:7a64fbb4069d 478 /* For UDP-Lite, checksum length of 0 means checksum
screamer 0:7a64fbb4069d 479 over the complete packet. (See RFC 3828 chap. 3.1)
screamer 0:7a64fbb4069d 480 At least the UDP-Lite header must be covered by the
screamer 0:7a64fbb4069d 481 checksum, therefore, if chksum_len has an illegal
screamer 0:7a64fbb4069d 482 value, we generate the checksum over the complete
screamer 0:7a64fbb4069d 483 packet to be safe. */
screamer 0:7a64fbb4069d 484 chklen_hdr = 0;
screamer 0:7a64fbb4069d 485 chklen = q->tot_len;
screamer 0:7a64fbb4069d 486 }
screamer 0:7a64fbb4069d 487 udphdr->len = htons(chklen_hdr);
screamer 0:7a64fbb4069d 488 /* calculate checksum */
screamer 0:7a64fbb4069d 489 #if CHECKSUM_GEN_UDP
screamer 0:7a64fbb4069d 490 udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip,
screamer 0:7a64fbb4069d 491 IP_PROTO_UDPLITE, q->tot_len, chklen);
screamer 0:7a64fbb4069d 492 /* chksum zero must become 0xffff, as zero means 'no checksum' */
screamer 0:7a64fbb4069d 493 if (udphdr->chksum == 0x0000)
screamer 0:7a64fbb4069d 494 udphdr->chksum = 0xffff;
screamer 0:7a64fbb4069d 495 #endif /* CHECKSUM_CHECK_UDP */
screamer 0:7a64fbb4069d 496 /* output to IP */
screamer 0:7a64fbb4069d 497 LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n"));
screamer 0:7a64fbb4069d 498 #if LWIP_NETIF_HWADDRHINT
screamer 0:7a64fbb4069d 499 netif->addr_hint = &(pcb->addr_hint);
screamer 0:7a64fbb4069d 500 #endif /* LWIP_NETIF_HWADDRHINT*/
screamer 0:7a64fbb4069d 501 err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);
screamer 0:7a64fbb4069d 502 #if LWIP_NETIF_HWADDRHINT
screamer 0:7a64fbb4069d 503 netif->addr_hint = NULL;
screamer 0:7a64fbb4069d 504 #endif /* LWIP_NETIF_HWADDRHINT*/
screamer 0:7a64fbb4069d 505 } else
screamer 0:7a64fbb4069d 506 #endif /* LWIP_UDPLITE */
screamer 0:7a64fbb4069d 507 { /* UDP */
screamer 0:7a64fbb4069d 508 LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len));
screamer 0:7a64fbb4069d 509 udphdr->len = htons(q->tot_len);
screamer 0:7a64fbb4069d 510 /* calculate checksum */
screamer 0:7a64fbb4069d 511 #if CHECKSUM_GEN_UDP
screamer 0:7a64fbb4069d 512 if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
screamer 0:7a64fbb4069d 513 udphdr->chksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len);
screamer 0:7a64fbb4069d 514 /* chksum zero must become 0xffff, as zero means 'no checksum' */
screamer 0:7a64fbb4069d 515 if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff;
screamer 0:7a64fbb4069d 516 }
screamer 0:7a64fbb4069d 517 #endif /* CHECKSUM_CHECK_UDP */
screamer 0:7a64fbb4069d 518 LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum));
screamer 0:7a64fbb4069d 519 LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n"));
screamer 0:7a64fbb4069d 520 /* output to IP */
screamer 0:7a64fbb4069d 521 #if LWIP_NETIF_HWADDRHINT
screamer 0:7a64fbb4069d 522 netif->addr_hint = &(pcb->addr_hint);
screamer 0:7a64fbb4069d 523 #endif /* LWIP_NETIF_HWADDRHINT*/
screamer 0:7a64fbb4069d 524 err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);
screamer 0:7a64fbb4069d 525 #if LWIP_NETIF_HWADDRHINT
screamer 0:7a64fbb4069d 526 netif->addr_hint = NULL;
screamer 0:7a64fbb4069d 527 #endif /* LWIP_NETIF_HWADDRHINT*/
screamer 0:7a64fbb4069d 528 }
screamer 0:7a64fbb4069d 529 /* TODO: must this be increased even if error occured? */
screamer 0:7a64fbb4069d 530 snmp_inc_udpoutdatagrams();
screamer 0:7a64fbb4069d 531
screamer 0:7a64fbb4069d 532 /* did we chain a separate header pbuf earlier? */
screamer 0:7a64fbb4069d 533 if (q != p) {
screamer 0:7a64fbb4069d 534 /* free the header pbuf */
screamer 0:7a64fbb4069d 535 pbuf_free(q);
screamer 0:7a64fbb4069d 536 q = NULL;
screamer 0:7a64fbb4069d 537 /* p is still referenced by the caller, and will live on */
screamer 0:7a64fbb4069d 538 }
screamer 0:7a64fbb4069d 539
screamer 0:7a64fbb4069d 540 UDP_STATS_INC(udp.xmit);
screamer 0:7a64fbb4069d 541 return err;
screamer 0:7a64fbb4069d 542 }
screamer 0:7a64fbb4069d 543
screamer 0:7a64fbb4069d 544 /**
screamer 0:7a64fbb4069d 545 * Bind an UDP PCB.
screamer 0:7a64fbb4069d 546 *
screamer 0:7a64fbb4069d 547 * @param pcb UDP PCB to be bound with a local address ipaddr and port.
screamer 0:7a64fbb4069d 548 * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
screamer 0:7a64fbb4069d 549 * bind to all local interfaces.
screamer 0:7a64fbb4069d 550 * @param port local UDP port to bind with. Use 0 to automatically bind
screamer 0:7a64fbb4069d 551 * to a random port between UDP_LOCAL_PORT_RANGE_START and
screamer 0:7a64fbb4069d 552 * UDP_LOCAL_PORT_RANGE_END.
screamer 0:7a64fbb4069d 553 *
screamer 0:7a64fbb4069d 554 * ipaddr & port are expected to be in the same byte order as in the pcb.
screamer 0:7a64fbb4069d 555 *
screamer 0:7a64fbb4069d 556 * @return lwIP error code.
screamer 0:7a64fbb4069d 557 * - ERR_OK. Successful. No error occured.
screamer 0:7a64fbb4069d 558 * - ERR_USE. The specified ipaddr and port are already bound to by
screamer 0:7a64fbb4069d 559 * another UDP PCB.
screamer 0:7a64fbb4069d 560 *
screamer 0:7a64fbb4069d 561 * @see udp_disconnect()
screamer 0:7a64fbb4069d 562 */
screamer 0:7a64fbb4069d 563 err_t
screamer 0:7a64fbb4069d 564 udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
screamer 0:7a64fbb4069d 565 {
screamer 0:7a64fbb4069d 566 struct udp_pcb *ipcb;
screamer 0:7a64fbb4069d 567 u8_t rebind;
screamer 0:7a64fbb4069d 568
screamer 0:7a64fbb4069d 569 LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, ("udp_bind(ipaddr = "));
screamer 0:7a64fbb4069d 570 ip_addr_debug_print(UDP_DEBUG, ipaddr);
screamer 0:7a64fbb4069d 571 LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, (", port = %"U16_F")\n", port));
screamer 0:7a64fbb4069d 572
screamer 0:7a64fbb4069d 573 rebind = 0;
screamer 0:7a64fbb4069d 574 /* Check for double bind and rebind of the same pcb */
screamer 0:7a64fbb4069d 575 for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
screamer 0:7a64fbb4069d 576 /* is this UDP PCB already on active list? */
screamer 0:7a64fbb4069d 577 if (pcb == ipcb) {
screamer 0:7a64fbb4069d 578 /* pcb may occur at most once in active list */
screamer 0:7a64fbb4069d 579 LWIP_ASSERT("rebind == 0", rebind == 0);
screamer 0:7a64fbb4069d 580 /* pcb already in list, just rebind */
screamer 0:7a64fbb4069d 581 rebind = 1;
screamer 0:7a64fbb4069d 582 }
screamer 0:7a64fbb4069d 583
screamer 0:7a64fbb4069d 584 /* this code does not allow upper layer to share a UDP port for
screamer 0:7a64fbb4069d 585 listening to broadcast or multicast traffic (See SO_REUSE_ADDR and
screamer 0:7a64fbb4069d 586 SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR
screamer 0:7a64fbb4069d 587 combine with implementation of UDP PCB flags. Leon Woestenberg. */
screamer 0:7a64fbb4069d 588 #ifdef LWIP_UDP_TODO
screamer 0:7a64fbb4069d 589 /* port matches that of PCB in list? */
screamer 0:7a64fbb4069d 590 else
screamer 0:7a64fbb4069d 591 if ((ipcb->local_port == port) &&
screamer 0:7a64fbb4069d 592 /* IP address matches, or one is IP_ADDR_ANY? */
screamer 0:7a64fbb4069d 593 (ip_addr_isany(&(ipcb->local_ip)) ||
screamer 0:7a64fbb4069d 594 ip_addr_isany(ipaddr) ||
screamer 0:7a64fbb4069d 595 ip_addr_cmp(&(ipcb->local_ip), ipaddr))) {
screamer 0:7a64fbb4069d 596 /* other PCB already binds to this local IP and port */
screamer 0:7a64fbb4069d 597 LWIP_DEBUGF(UDP_DEBUG,
screamer 0:7a64fbb4069d 598 ("udp_bind: local port %"U16_F" already bound by another pcb\n", port));
screamer 0:7a64fbb4069d 599 return ERR_USE;
screamer 0:7a64fbb4069d 600 }
screamer 0:7a64fbb4069d 601 #endif
screamer 0:7a64fbb4069d 602 }
screamer 0:7a64fbb4069d 603
screamer 0:7a64fbb4069d 604 ip_addr_set(&pcb->local_ip, ipaddr);
screamer 0:7a64fbb4069d 605
screamer 0:7a64fbb4069d 606 /* no port specified? */
screamer 0:7a64fbb4069d 607 if (port == 0) {
screamer 0:7a64fbb4069d 608 #ifndef UDP_LOCAL_PORT_RANGE_START
screamer 0:7a64fbb4069d 609 #define UDP_LOCAL_PORT_RANGE_START 4096
screamer 0:7a64fbb4069d 610 #define UDP_LOCAL_PORT_RANGE_END 0x7fff
screamer 0:7a64fbb4069d 611 #endif
screamer 0:7a64fbb4069d 612 port = UDP_LOCAL_PORT_RANGE_START;
screamer 0:7a64fbb4069d 613 ipcb = udp_pcbs;
screamer 0:7a64fbb4069d 614 while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) {
screamer 0:7a64fbb4069d 615 if (ipcb->local_port == port) {
screamer 0:7a64fbb4069d 616 /* port is already used by another udp_pcb */
screamer 0:7a64fbb4069d 617 port++;
screamer 0:7a64fbb4069d 618 /* restart scanning all udp pcbs */
screamer 0:7a64fbb4069d 619 ipcb = udp_pcbs;
screamer 0:7a64fbb4069d 620 } else
screamer 0:7a64fbb4069d 621 /* go on with next udp pcb */
screamer 0:7a64fbb4069d 622 ipcb = ipcb->next;
screamer 0:7a64fbb4069d 623 }
screamer 0:7a64fbb4069d 624 if (ipcb != NULL) {
screamer 0:7a64fbb4069d 625 /* no more ports available in local range */
screamer 0:7a64fbb4069d 626 LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n"));
screamer 0:7a64fbb4069d 627 return ERR_USE;
screamer 0:7a64fbb4069d 628 }
screamer 0:7a64fbb4069d 629 }
screamer 0:7a64fbb4069d 630 pcb->local_port = port;
screamer 0:7a64fbb4069d 631 snmp_insert_udpidx_tree(pcb);
screamer 0:7a64fbb4069d 632 /* pcb not active yet? */
screamer 0:7a64fbb4069d 633 if (rebind == 0) {
screamer 0:7a64fbb4069d 634 /* place the PCB on the active list if not already there */
screamer 0:7a64fbb4069d 635 pcb->next = udp_pcbs;
screamer 0:7a64fbb4069d 636 udp_pcbs = pcb;
screamer 0:7a64fbb4069d 637 }
screamer 0:7a64fbb4069d 638 LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
screamer 0:7a64fbb4069d 639 ("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n",
screamer 0:7a64fbb4069d 640 (u16_t)((ntohl(pcb->local_ip.addr) >> 24) & 0xff),
screamer 0:7a64fbb4069d 641 (u16_t)((ntohl(pcb->local_ip.addr) >> 16) & 0xff),
screamer 0:7a64fbb4069d 642 (u16_t)((ntohl(pcb->local_ip.addr) >> 8) & 0xff),
screamer 0:7a64fbb4069d 643 (u16_t)(ntohl(pcb->local_ip.addr) & 0xff), pcb->local_port));
screamer 0:7a64fbb4069d 644 return ERR_OK;
screamer 0:7a64fbb4069d 645 }
screamer 0:7a64fbb4069d 646 /**
screamer 0:7a64fbb4069d 647 * Connect an UDP PCB.
screamer 0:7a64fbb4069d 648 *
screamer 0:7a64fbb4069d 649 * This will associate the UDP PCB with the remote address.
screamer 0:7a64fbb4069d 650 *
screamer 0:7a64fbb4069d 651 * @param pcb UDP PCB to be connected with remote address ipaddr and port.
screamer 0:7a64fbb4069d 652 * @param ipaddr remote IP address to connect with.
screamer 0:7a64fbb4069d 653 * @param port remote UDP port to connect with.
screamer 0:7a64fbb4069d 654 *
screamer 0:7a64fbb4069d 655 * @return lwIP error code
screamer 0:7a64fbb4069d 656 *
screamer 0:7a64fbb4069d 657 * ipaddr & port are expected to be in the same byte order as in the pcb.
screamer 0:7a64fbb4069d 658 *
screamer 0:7a64fbb4069d 659 * The udp pcb is bound to a random local port if not already bound.
screamer 0:7a64fbb4069d 660 *
screamer 0:7a64fbb4069d 661 * @see udp_disconnect()
screamer 0:7a64fbb4069d 662 */
screamer 0:7a64fbb4069d 663 err_t
screamer 0:7a64fbb4069d 664 udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
screamer 0:7a64fbb4069d 665 {
screamer 0:7a64fbb4069d 666 struct udp_pcb *ipcb;
screamer 0:7a64fbb4069d 667
screamer 0:7a64fbb4069d 668 if (pcb->local_port == 0) {
screamer 0:7a64fbb4069d 669 err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
screamer 0:7a64fbb4069d 670 if (err != ERR_OK)
screamer 0:7a64fbb4069d 671 return err;
screamer 0:7a64fbb4069d 672 }
screamer 0:7a64fbb4069d 673
screamer 0:7a64fbb4069d 674 ip_addr_set(&pcb->remote_ip, ipaddr);
screamer 0:7a64fbb4069d 675 pcb->remote_port = port;
screamer 0:7a64fbb4069d 676 pcb->flags |= UDP_FLAGS_CONNECTED;
screamer 0:7a64fbb4069d 677 /** TODO: this functionality belongs in upper layers */
screamer 0:7a64fbb4069d 678 #ifdef LWIP_UDP_TODO
screamer 0:7a64fbb4069d 679 /* Nail down local IP for netconn_addr()/getsockname() */
screamer 0:7a64fbb4069d 680 if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) {
screamer 0:7a64fbb4069d 681 struct netif *netif;
screamer 0:7a64fbb4069d 682
screamer 0:7a64fbb4069d 683 if ((netif = ip_route(&(pcb->remote_ip))) == NULL) {
screamer 0:7a64fbb4069d 684 LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr));
screamer 0:7a64fbb4069d 685 UDP_STATS_INC(udp.rterr);
screamer 0:7a64fbb4069d 686 return ERR_RTE;
screamer 0:7a64fbb4069d 687 }
screamer 0:7a64fbb4069d 688 /** TODO: this will bind the udp pcb locally, to the interface which
screamer 0:7a64fbb4069d 689 is used to route output packets to the remote address. However, we
screamer 0:7a64fbb4069d 690 might want to accept incoming packets on any interface! */
screamer 0:7a64fbb4069d 691 pcb->local_ip = netif->ip_addr;
screamer 0:7a64fbb4069d 692 } else if (ip_addr_isany(&pcb->remote_ip)) {
screamer 0:7a64fbb4069d 693 pcb->local_ip.addr = 0;
screamer 0:7a64fbb4069d 694 }
screamer 0:7a64fbb4069d 695 #endif
screamer 0:7a64fbb4069d 696 LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
screamer 0:7a64fbb4069d 697 ("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n",
screamer 0:7a64fbb4069d 698 (u16_t)((ntohl(pcb->remote_ip.addr) >> 24) & 0xff),
screamer 0:7a64fbb4069d 699 (u16_t)((ntohl(pcb->remote_ip.addr) >> 16) & 0xff),
screamer 0:7a64fbb4069d 700 (u16_t)((ntohl(pcb->remote_ip.addr) >> 8) & 0xff),
screamer 0:7a64fbb4069d 701 (u16_t)(ntohl(pcb->remote_ip.addr) & 0xff), pcb->remote_port));
screamer 0:7a64fbb4069d 702
screamer 0:7a64fbb4069d 703 /* Insert UDP PCB into the list of active UDP PCBs. */
screamer 0:7a64fbb4069d 704 for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
screamer 0:7a64fbb4069d 705 if (pcb == ipcb) {
screamer 0:7a64fbb4069d 706 /* already on the list, just return */
screamer 0:7a64fbb4069d 707 return ERR_OK;
screamer 0:7a64fbb4069d 708 }
screamer 0:7a64fbb4069d 709 }
screamer 0:7a64fbb4069d 710 /* PCB not yet on the list, add PCB now */
screamer 0:7a64fbb4069d 711 pcb->next = udp_pcbs;
screamer 0:7a64fbb4069d 712 udp_pcbs = pcb;
screamer 0:7a64fbb4069d 713 return ERR_OK;
screamer 0:7a64fbb4069d 714 }
screamer 0:7a64fbb4069d 715
screamer 0:7a64fbb4069d 716 /**
screamer 0:7a64fbb4069d 717 * Disconnect a UDP PCB
screamer 0:7a64fbb4069d 718 *
screamer 0:7a64fbb4069d 719 * @param pcb the udp pcb to disconnect.
screamer 0:7a64fbb4069d 720 */
screamer 0:7a64fbb4069d 721 void
screamer 0:7a64fbb4069d 722 udp_disconnect(struct udp_pcb *pcb)
screamer 0:7a64fbb4069d 723 {
screamer 0:7a64fbb4069d 724 /* reset remote address association */
screamer 0:7a64fbb4069d 725 ip_addr_set(&pcb->remote_ip, IP_ADDR_ANY);
screamer 0:7a64fbb4069d 726 pcb->remote_port = 0;
screamer 0:7a64fbb4069d 727 /* mark PCB as unconnected */
screamer 0:7a64fbb4069d 728 pcb->flags &= ~UDP_FLAGS_CONNECTED;
screamer 0:7a64fbb4069d 729 }
screamer 0:7a64fbb4069d 730
screamer 0:7a64fbb4069d 731 /**
screamer 0:7a64fbb4069d 732 * Set a receive callback for a UDP PCB
screamer 0:7a64fbb4069d 733 *
screamer 0:7a64fbb4069d 734 * This callback will be called when receiving a datagram for the pcb.
screamer 0:7a64fbb4069d 735 *
screamer 0:7a64fbb4069d 736 * @param pcb the pcb for wich to set the recv callback
screamer 0:7a64fbb4069d 737 * @param recv function pointer of the callback function
screamer 0:7a64fbb4069d 738 * @param recv_arg additional argument to pass to the callback function
screamer 0:7a64fbb4069d 739 */
screamer 0:7a64fbb4069d 740 void
screamer 0:7a64fbb4069d 741 udp_recv(struct udp_pcb *pcb,
screamer 0:7a64fbb4069d 742 void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p,
screamer 0:7a64fbb4069d 743 struct ip_addr *addr, u16_t port),
screamer 0:7a64fbb4069d 744 void *recv_arg)
screamer 0:7a64fbb4069d 745 {
screamer 0:7a64fbb4069d 746 /* remember recv() callback and user data */
screamer 0:7a64fbb4069d 747 pcb->recv = recv;
screamer 0:7a64fbb4069d 748 pcb->recv_arg = recv_arg;
screamer 0:7a64fbb4069d 749 }
screamer 0:7a64fbb4069d 750
screamer 0:7a64fbb4069d 751 /**
screamer 0:7a64fbb4069d 752 * Remove an UDP PCB.
screamer 0:7a64fbb4069d 753 *
screamer 0:7a64fbb4069d 754 * @param pcb UDP PCB to be removed. The PCB is removed from the list of
screamer 0:7a64fbb4069d 755 * UDP PCB's and the data structure is freed from memory.
screamer 0:7a64fbb4069d 756 *
screamer 0:7a64fbb4069d 757 * @see udp_new()
screamer 0:7a64fbb4069d 758 */
screamer 0:7a64fbb4069d 759 void
screamer 0:7a64fbb4069d 760 udp_remove(struct udp_pcb *pcb)
screamer 0:7a64fbb4069d 761 {
screamer 0:7a64fbb4069d 762 struct udp_pcb *pcb2;
screamer 0:7a64fbb4069d 763
screamer 0:7a64fbb4069d 764 snmp_delete_udpidx_tree(pcb);
screamer 0:7a64fbb4069d 765 /* pcb to be removed is first in list? */
screamer 0:7a64fbb4069d 766 if (udp_pcbs == pcb) {
screamer 0:7a64fbb4069d 767 /* make list start at 2nd pcb */
screamer 0:7a64fbb4069d 768 udp_pcbs = udp_pcbs->next;
screamer 0:7a64fbb4069d 769 /* pcb not 1st in list */
screamer 0:7a64fbb4069d 770 } else
screamer 0:7a64fbb4069d 771 for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
screamer 0:7a64fbb4069d 772 /* find pcb in udp_pcbs list */
screamer 0:7a64fbb4069d 773 if (pcb2->next != NULL && pcb2->next == pcb) {
screamer 0:7a64fbb4069d 774 /* remove pcb from list */
screamer 0:7a64fbb4069d 775 pcb2->next = pcb->next;
screamer 0:7a64fbb4069d 776 }
screamer 0:7a64fbb4069d 777 }
screamer 0:7a64fbb4069d 778 memp_free(MEMP_UDP_PCB, pcb);
screamer 0:7a64fbb4069d 779 }
screamer 0:7a64fbb4069d 780
screamer 0:7a64fbb4069d 781 /**
screamer 0:7a64fbb4069d 782 * Create a UDP PCB.
screamer 0:7a64fbb4069d 783 *
screamer 0:7a64fbb4069d 784 * @return The UDP PCB which was created. NULL if the PCB data structure
screamer 0:7a64fbb4069d 785 * could not be allocated.
screamer 0:7a64fbb4069d 786 *
screamer 0:7a64fbb4069d 787 * @see udp_remove()
screamer 0:7a64fbb4069d 788 */
screamer 0:7a64fbb4069d 789 struct udp_pcb *
screamer 0:7a64fbb4069d 790 udp_new(void)
screamer 0:7a64fbb4069d 791 {
screamer 0:7a64fbb4069d 792 struct udp_pcb *pcb;
screamer 0:7a64fbb4069d 793 pcb = (struct udp_pcb *)(memp_malloc(MEMP_UDP_PCB));
screamer 0:7a64fbb4069d 794 /* could allocate UDP PCB? */
screamer 0:7a64fbb4069d 795 if (pcb != NULL) {
screamer 0:7a64fbb4069d 796 /* UDP Lite: by initializing to all zeroes, chksum_len is set to 0
screamer 0:7a64fbb4069d 797 * which means checksum is generated over the whole datagram per default
screamer 0:7a64fbb4069d 798 * (recommended as default by RFC 3828). */
screamer 0:7a64fbb4069d 799 /* initialize PCB to all zeroes */
screamer 0:7a64fbb4069d 800 memset(pcb, 0, sizeof(struct udp_pcb));
screamer 0:7a64fbb4069d 801 pcb->ttl = UDP_TTL;
screamer 0:7a64fbb4069d 802 }
screamer 0:7a64fbb4069d 803 return pcb;
screamer 0:7a64fbb4069d 804 }
screamer 0:7a64fbb4069d 805
screamer 0:7a64fbb4069d 806 #if UDP_DEBUG
screamer 0:7a64fbb4069d 807 /**
screamer 0:7a64fbb4069d 808 * Print UDP header information for debug purposes.
screamer 0:7a64fbb4069d 809 *
screamer 0:7a64fbb4069d 810 * @param udphdr pointer to the udp header in memory.
screamer 0:7a64fbb4069d 811 */
screamer 0:7a64fbb4069d 812 void
screamer 0:7a64fbb4069d 813 udp_debug_print(struct udp_hdr *udphdr)
screamer 0:7a64fbb4069d 814 {
screamer 0:7a64fbb4069d 815 LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n"));
screamer 0:7a64fbb4069d 816 LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
screamer 0:7a64fbb4069d 817 LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n",
screamer 0:7a64fbb4069d 818 ntohs(udphdr->src), ntohs(udphdr->dest)));
screamer 0:7a64fbb4069d 819 LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
screamer 0:7a64fbb4069d 820 LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | 0x%04"X16_F" | (len, chksum)\n",
screamer 0:7a64fbb4069d 821 ntohs(udphdr->len), ntohs(udphdr->chksum)));
screamer 0:7a64fbb4069d 822 LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
screamer 0:7a64fbb4069d 823 }
screamer 0:7a64fbb4069d 824 #endif /* UDP_DEBUG */
screamer 0:7a64fbb4069d 825
screamer 0:7a64fbb4069d 826 #endif /* LWIP_UDP */