ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

Committer:
group-onsemi
Date:
Wed Jan 25 20:34:15 2017 +0000
Revision:
0:098463de4c5d
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
group-onsemi 0:098463de4c5d 1 /**
group-onsemi 0:098463de4c5d 2 * @file
group-onsemi 0:098463de4c5d 3 * This is the IPv4 layer implementation for incoming and outgoing IP traffic.
group-onsemi 0:098463de4c5d 4 *
group-onsemi 0:098463de4c5d 5 * @see ip_frag.c
group-onsemi 0:098463de4c5d 6 *
group-onsemi 0:098463de4c5d 7 */
group-onsemi 0:098463de4c5d 8
group-onsemi 0:098463de4c5d 9 /*
group-onsemi 0:098463de4c5d 10 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
group-onsemi 0:098463de4c5d 11 * All rights reserved.
group-onsemi 0:098463de4c5d 12 *
group-onsemi 0:098463de4c5d 13 * Redistribution and use in source and binary forms, with or without modification,
group-onsemi 0:098463de4c5d 14 * are permitted provided that the following conditions are met:
group-onsemi 0:098463de4c5d 15 *
group-onsemi 0:098463de4c5d 16 * 1. Redistributions of source code must retain the above copyright notice,
group-onsemi 0:098463de4c5d 17 * this list of conditions and the following disclaimer.
group-onsemi 0:098463de4c5d 18 * 2. Redistributions in binary form must reproduce the above copyright notice,
group-onsemi 0:098463de4c5d 19 * this list of conditions and the following disclaimer in the documentation
group-onsemi 0:098463de4c5d 20 * and/or other materials provided with the distribution.
group-onsemi 0:098463de4c5d 21 * 3. The name of the author may not be used to endorse or promote products
group-onsemi 0:098463de4c5d 22 * derived from this software without specific prior written permission.
group-onsemi 0:098463de4c5d 23 *
group-onsemi 0:098463de4c5d 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
group-onsemi 0:098463de4c5d 25 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
group-onsemi 0:098463de4c5d 26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
group-onsemi 0:098463de4c5d 27 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
group-onsemi 0:098463de4c5d 28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
group-onsemi 0:098463de4c5d 29 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
group-onsemi 0:098463de4c5d 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
group-onsemi 0:098463de4c5d 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
group-onsemi 0:098463de4c5d 32 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
group-onsemi 0:098463de4c5d 33 * OF SUCH DAMAGE.
group-onsemi 0:098463de4c5d 34 *
group-onsemi 0:098463de4c5d 35 * This file is part of the lwIP TCP/IP stack.
group-onsemi 0:098463de4c5d 36 *
group-onsemi 0:098463de4c5d 37 * Author: Adam Dunkels <adam@sics.se>
group-onsemi 0:098463de4c5d 38 *
group-onsemi 0:098463de4c5d 39 */
group-onsemi 0:098463de4c5d 40
group-onsemi 0:098463de4c5d 41 #include "lwip/opt.h"
group-onsemi 0:098463de4c5d 42
group-onsemi 0:098463de4c5d 43 #if LWIP_IPV4
group-onsemi 0:098463de4c5d 44
group-onsemi 0:098463de4c5d 45 #include "lwip/ip.h"
group-onsemi 0:098463de4c5d 46 #include "lwip/def.h"
group-onsemi 0:098463de4c5d 47 #include "lwip/mem.h"
group-onsemi 0:098463de4c5d 48 #include "lwip/ip4_frag.h"
group-onsemi 0:098463de4c5d 49 #include "lwip/inet_chksum.h"
group-onsemi 0:098463de4c5d 50 #include "lwip/netif.h"
group-onsemi 0:098463de4c5d 51 #include "lwip/icmp.h"
group-onsemi 0:098463de4c5d 52 #include "lwip/igmp.h"
group-onsemi 0:098463de4c5d 53 #include "lwip/raw.h"
group-onsemi 0:098463de4c5d 54 #include "lwip/udp.h"
group-onsemi 0:098463de4c5d 55 #include "lwip/priv/tcp_priv.h"
group-onsemi 0:098463de4c5d 56 #include "lwip/dhcp.h"
group-onsemi 0:098463de4c5d 57 #include "lwip/autoip.h"
group-onsemi 0:098463de4c5d 58 #include "lwip/stats.h"
group-onsemi 0:098463de4c5d 59
group-onsemi 0:098463de4c5d 60 #include <string.h>
group-onsemi 0:098463de4c5d 61
group-onsemi 0:098463de4c5d 62 /** Set this to 0 in the rare case of wanting to call an extra function to
group-onsemi 0:098463de4c5d 63 * generate the IP checksum (in contrast to calculating it on-the-fly). */
group-onsemi 0:098463de4c5d 64 #ifndef LWIP_INLINE_IP_CHKSUM
group-onsemi 0:098463de4c5d 65 #if LWIP_CHECKSUM_CTRL_PER_NETIF
group-onsemi 0:098463de4c5d 66 #define LWIP_INLINE_IP_CHKSUM 0
group-onsemi 0:098463de4c5d 67 #else /* LWIP_CHECKSUM_CTRL_PER_NETIF */
group-onsemi 0:098463de4c5d 68 #define LWIP_INLINE_IP_CHKSUM 1
group-onsemi 0:098463de4c5d 69 #endif /* LWIP_CHECKSUM_CTRL_PER_NETIF */
group-onsemi 0:098463de4c5d 70 #endif
group-onsemi 0:098463de4c5d 71
group-onsemi 0:098463de4c5d 72 #if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP
group-onsemi 0:098463de4c5d 73 #define CHECKSUM_GEN_IP_INLINE 1
group-onsemi 0:098463de4c5d 74 #else
group-onsemi 0:098463de4c5d 75 #define CHECKSUM_GEN_IP_INLINE 0
group-onsemi 0:098463de4c5d 76 #endif
group-onsemi 0:098463de4c5d 77
group-onsemi 0:098463de4c5d 78 #if LWIP_DHCP || defined(LWIP_IP_ACCEPT_UDP_PORT)
group-onsemi 0:098463de4c5d 79 #define IP_ACCEPT_LINK_LAYER_ADDRESSING 1
group-onsemi 0:098463de4c5d 80
group-onsemi 0:098463de4c5d 81 /** Some defines for DHCP to let link-layer-addressed packets through while the
group-onsemi 0:098463de4c5d 82 * netif is down.
group-onsemi 0:098463de4c5d 83 * To use this in your own application/protocol, define LWIP_IP_ACCEPT_UDP_PORT(port)
group-onsemi 0:098463de4c5d 84 * to return 1 if the port is accepted and 0 if the port is not accepted.
group-onsemi 0:098463de4c5d 85 */
group-onsemi 0:098463de4c5d 86 #if LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT)
group-onsemi 0:098463de4c5d 87 /* accept DHCP client port and custom port */
group-onsemi 0:098463de4c5d 88 #define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (((port) == PP_NTOHS(DHCP_CLIENT_PORT)) \
group-onsemi 0:098463de4c5d 89 || (LWIP_IP_ACCEPT_UDP_PORT(port)))
group-onsemi 0:098463de4c5d 90 #elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
group-onsemi 0:098463de4c5d 91 /* accept custom port only */
group-onsemi 0:098463de4c5d 92 #define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(port))
group-onsemi 0:098463de4c5d 93 #else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
group-onsemi 0:098463de4c5d 94 /* accept DHCP client port only */
group-onsemi 0:098463de4c5d 95 #define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT))
group-onsemi 0:098463de4c5d 96 #endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */
group-onsemi 0:098463de4c5d 97
group-onsemi 0:098463de4c5d 98 #else /* LWIP_DHCP */
group-onsemi 0:098463de4c5d 99 #define IP_ACCEPT_LINK_LAYER_ADDRESSING 0
group-onsemi 0:098463de4c5d 100 #endif /* LWIP_DHCP */
group-onsemi 0:098463de4c5d 101
group-onsemi 0:098463de4c5d 102 /** The IP header ID of the next outgoing IP packet */
group-onsemi 0:098463de4c5d 103 static u16_t ip_id;
group-onsemi 0:098463de4c5d 104
group-onsemi 0:098463de4c5d 105 #if LWIP_MULTICAST_TX_OPTIONS
group-onsemi 0:098463de4c5d 106 /** The default netif used for multicast */
group-onsemi 0:098463de4c5d 107 static struct netif* ip4_default_multicast_netif;
group-onsemi 0:098463de4c5d 108
group-onsemi 0:098463de4c5d 109 /** Set a default netif for IPv4 multicast. */
group-onsemi 0:098463de4c5d 110 void
group-onsemi 0:098463de4c5d 111 ip4_set_default_multicast_netif(struct netif* default_multicast_netif)
group-onsemi 0:098463de4c5d 112 {
group-onsemi 0:098463de4c5d 113 ip4_default_multicast_netif = default_multicast_netif;
group-onsemi 0:098463de4c5d 114 }
group-onsemi 0:098463de4c5d 115 #endif /* LWIP_MULTICAST_TX_OPTIONS */
group-onsemi 0:098463de4c5d 116
group-onsemi 0:098463de4c5d 117 #ifdef LWIP_HOOK_IP4_ROUTE_SRC
group-onsemi 0:098463de4c5d 118 /**
group-onsemi 0:098463de4c5d 119 * Source based IPv4 routing must be fully implemented in
group-onsemi 0:098463de4c5d 120 * LWIP_HOOK_IP4_ROUTE_SRC(). This function only provides he parameters.
group-onsemi 0:098463de4c5d 121 */
group-onsemi 0:098463de4c5d 122 struct netif *
group-onsemi 0:098463de4c5d 123 ip4_route_src(const ip4_addr_t *dest, const ip4_addr_t *src)
group-onsemi 0:098463de4c5d 124 {
group-onsemi 0:098463de4c5d 125 if (src != NULL) {
group-onsemi 0:098463de4c5d 126 /* when src==NULL, the hook is called from ip4_route(dest) */
group-onsemi 0:098463de4c5d 127 struct netif *netif = LWIP_HOOK_IP4_ROUTE_SRC(dest, src);
group-onsemi 0:098463de4c5d 128 if (netif != NULL) {
group-onsemi 0:098463de4c5d 129 return netif;
group-onsemi 0:098463de4c5d 130 }
group-onsemi 0:098463de4c5d 131 }
group-onsemi 0:098463de4c5d 132 return ip4_route(dest);
group-onsemi 0:098463de4c5d 133 }
group-onsemi 0:098463de4c5d 134 #endif /* LWIP_HOOK_IP4_ROUTE_SRC */
group-onsemi 0:098463de4c5d 135
group-onsemi 0:098463de4c5d 136 /**
group-onsemi 0:098463de4c5d 137 * Finds the appropriate network interface for a given IP address. It
group-onsemi 0:098463de4c5d 138 * searches the list of network interfaces linearly. A match is found
group-onsemi 0:098463de4c5d 139 * if the masked IP address of the network interface equals the masked
group-onsemi 0:098463de4c5d 140 * IP address given to the function.
group-onsemi 0:098463de4c5d 141 *
group-onsemi 0:098463de4c5d 142 * @param dest the destination IP address for which to find the route
group-onsemi 0:098463de4c5d 143 * @return the netif on which to send to reach dest
group-onsemi 0:098463de4c5d 144 */
group-onsemi 0:098463de4c5d 145 struct netif *
group-onsemi 0:098463de4c5d 146 ip4_route(const ip4_addr_t *dest)
group-onsemi 0:098463de4c5d 147 {
group-onsemi 0:098463de4c5d 148 struct netif *netif;
group-onsemi 0:098463de4c5d 149
group-onsemi 0:098463de4c5d 150 #if LWIP_MULTICAST_TX_OPTIONS
group-onsemi 0:098463de4c5d 151 /* Use administratively selected interface for multicast by default */
group-onsemi 0:098463de4c5d 152 if (ip4_addr_ismulticast(dest) && ip4_default_multicast_netif) {
group-onsemi 0:098463de4c5d 153 return ip4_default_multicast_netif;
group-onsemi 0:098463de4c5d 154 }
group-onsemi 0:098463de4c5d 155 #endif /* LWIP_MULTICAST_TX_OPTIONS */
group-onsemi 0:098463de4c5d 156
group-onsemi 0:098463de4c5d 157 /* iterate through netifs */
group-onsemi 0:098463de4c5d 158 for (netif = netif_list; netif != NULL; netif = netif->next) {
group-onsemi 0:098463de4c5d 159 /* is the netif up, does it have a link and a valid address? */
group-onsemi 0:098463de4c5d 160 if (netif_is_up(netif) && netif_is_link_up(netif) && !ip4_addr_isany_val(*netif_ip4_addr(netif))) {
group-onsemi 0:098463de4c5d 161 /* network mask matches? */
group-onsemi 0:098463de4c5d 162 if (ip4_addr_netcmp(dest, netif_ip4_addr(netif), netif_ip4_netmask(netif))) {
group-onsemi 0:098463de4c5d 163 /* return netif on which to forward IP packet */
group-onsemi 0:098463de4c5d 164 return netif;
group-onsemi 0:098463de4c5d 165 }
group-onsemi 0:098463de4c5d 166 /* gateway matches on a non broadcast interface? (i.e. peer in a point to point interface) */
group-onsemi 0:098463de4c5d 167 if (((netif->flags & NETIF_FLAG_BROADCAST) == 0) && ip4_addr_cmp(dest, netif_ip4_gw(netif))) {
group-onsemi 0:098463de4c5d 168 /* return netif on which to forward IP packet */
group-onsemi 0:098463de4c5d 169 return netif;
group-onsemi 0:098463de4c5d 170 }
group-onsemi 0:098463de4c5d 171 }
group-onsemi 0:098463de4c5d 172 }
group-onsemi 0:098463de4c5d 173
group-onsemi 0:098463de4c5d 174 #if LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF
group-onsemi 0:098463de4c5d 175 /* loopif is disabled, looopback traffic is passed through any netif */
group-onsemi 0:098463de4c5d 176 if (ip4_addr_isloopback(dest)) {
group-onsemi 0:098463de4c5d 177 /* don't check for link on loopback traffic */
group-onsemi 0:098463de4c5d 178 if (netif_is_up(netif_default)) {
group-onsemi 0:098463de4c5d 179 return netif_default;
group-onsemi 0:098463de4c5d 180 }
group-onsemi 0:098463de4c5d 181 /* default netif is not up, just use any netif for loopback traffic */
group-onsemi 0:098463de4c5d 182 for (netif = netif_list; netif != NULL; netif = netif->next) {
group-onsemi 0:098463de4c5d 183 if (netif_is_up(netif)) {
group-onsemi 0:098463de4c5d 184 return netif;
group-onsemi 0:098463de4c5d 185 }
group-onsemi 0:098463de4c5d 186 }
group-onsemi 0:098463de4c5d 187 return NULL;
group-onsemi 0:098463de4c5d 188 }
group-onsemi 0:098463de4c5d 189 #endif /* LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF */
group-onsemi 0:098463de4c5d 190
group-onsemi 0:098463de4c5d 191 #ifdef LWIP_HOOK_IP4_ROUTE_SRC
group-onsemi 0:098463de4c5d 192 netif = LWIP_HOOK_IP4_ROUTE_SRC(dest, NULL);
group-onsemi 0:098463de4c5d 193 if (netif != NULL) {
group-onsemi 0:098463de4c5d 194 return netif;
group-onsemi 0:098463de4c5d 195 }
group-onsemi 0:098463de4c5d 196 #elif defined(LWIP_HOOK_IP4_ROUTE)
group-onsemi 0:098463de4c5d 197 netif = LWIP_HOOK_IP4_ROUTE(dest);
group-onsemi 0:098463de4c5d 198 if (netif != NULL) {
group-onsemi 0:098463de4c5d 199 return netif;
group-onsemi 0:098463de4c5d 200 }
group-onsemi 0:098463de4c5d 201 #endif
group-onsemi 0:098463de4c5d 202
group-onsemi 0:098463de4c5d 203 if ((netif_default == NULL) || !netif_is_up(netif_default) || !netif_is_link_up(netif_default) ||
group-onsemi 0:098463de4c5d 204 ip4_addr_isany_val(*netif_ip4_addr(netif_default))) {
group-onsemi 0:098463de4c5d 205 /* No matching netif found and default netif is not usable.
group-onsemi 0:098463de4c5d 206 If this is not good enough for you, use LWIP_HOOK_IP4_ROUTE() */
group-onsemi 0:098463de4c5d 207 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
group-onsemi 0:098463de4c5d 208 ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
group-onsemi 0:098463de4c5d 209 IP_STATS_INC(ip.rterr);
group-onsemi 0:098463de4c5d 210 MIB2_STATS_INC(mib2.ipoutnoroutes);
group-onsemi 0:098463de4c5d 211 return NULL;
group-onsemi 0:098463de4c5d 212 }
group-onsemi 0:098463de4c5d 213
group-onsemi 0:098463de4c5d 214 return netif_default;
group-onsemi 0:098463de4c5d 215 }
group-onsemi 0:098463de4c5d 216
group-onsemi 0:098463de4c5d 217 #if IP_FORWARD
group-onsemi 0:098463de4c5d 218 /**
group-onsemi 0:098463de4c5d 219 * Determine whether an IP address is in a reserved set of addresses
group-onsemi 0:098463de4c5d 220 * that may not be forwarded, or whether datagrams to that destination
group-onsemi 0:098463de4c5d 221 * may be forwarded.
group-onsemi 0:098463de4c5d 222 * @param p the packet to forward
group-onsemi 0:098463de4c5d 223 * @param dest the destination IP address
group-onsemi 0:098463de4c5d 224 * @return 1: can forward 0: discard
group-onsemi 0:098463de4c5d 225 */
group-onsemi 0:098463de4c5d 226 static int
group-onsemi 0:098463de4c5d 227 ip4_canforward(struct pbuf *p)
group-onsemi 0:098463de4c5d 228 {
group-onsemi 0:098463de4c5d 229 u32_t addr = htonl(ip4_addr_get_u32(ip4_current_dest_addr()));
group-onsemi 0:098463de4c5d 230
group-onsemi 0:098463de4c5d 231 if (p->flags & PBUF_FLAG_LLBCAST) {
group-onsemi 0:098463de4c5d 232 /* don't route link-layer broadcasts */
group-onsemi 0:098463de4c5d 233 return 0;
group-onsemi 0:098463de4c5d 234 }
group-onsemi 0:098463de4c5d 235 if ((p->flags & PBUF_FLAG_LLMCAST) && !IP_MULTICAST(addr)) {
group-onsemi 0:098463de4c5d 236 /* don't route link-layer multicasts unless the destination address is an IP
group-onsemi 0:098463de4c5d 237 multicast address */
group-onsemi 0:098463de4c5d 238 return 0;
group-onsemi 0:098463de4c5d 239 }
group-onsemi 0:098463de4c5d 240 if (IP_EXPERIMENTAL(addr)) {
group-onsemi 0:098463de4c5d 241 return 0;
group-onsemi 0:098463de4c5d 242 }
group-onsemi 0:098463de4c5d 243 if (IP_CLASSA(addr)) {
group-onsemi 0:098463de4c5d 244 u32_t net = addr & IP_CLASSA_NET;
group-onsemi 0:098463de4c5d 245 if ((net == 0) || (net == ((u32_t)IP_LOOPBACKNET << IP_CLASSA_NSHIFT))) {
group-onsemi 0:098463de4c5d 246 /* don't route loopback packets */
group-onsemi 0:098463de4c5d 247 return 0;
group-onsemi 0:098463de4c5d 248 }
group-onsemi 0:098463de4c5d 249 }
group-onsemi 0:098463de4c5d 250 return 1;
group-onsemi 0:098463de4c5d 251 }
group-onsemi 0:098463de4c5d 252
group-onsemi 0:098463de4c5d 253 /**
group-onsemi 0:098463de4c5d 254 * Forwards an IP packet. It finds an appropriate route for the
group-onsemi 0:098463de4c5d 255 * packet, decrements the TTL value of the packet, adjusts the
group-onsemi 0:098463de4c5d 256 * checksum and outputs the packet on the appropriate interface.
group-onsemi 0:098463de4c5d 257 *
group-onsemi 0:098463de4c5d 258 * @param p the packet to forward (p->payload points to IP header)
group-onsemi 0:098463de4c5d 259 * @param iphdr the IP header of the input packet
group-onsemi 0:098463de4c5d 260 * @param inp the netif on which this packet was received
group-onsemi 0:098463de4c5d 261 */
group-onsemi 0:098463de4c5d 262 static void
group-onsemi 0:098463de4c5d 263 ip4_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
group-onsemi 0:098463de4c5d 264 {
group-onsemi 0:098463de4c5d 265 struct netif *netif;
group-onsemi 0:098463de4c5d 266
group-onsemi 0:098463de4c5d 267 PERF_START;
group-onsemi 0:098463de4c5d 268
group-onsemi 0:098463de4c5d 269 if (!ip4_canforward(p)) {
group-onsemi 0:098463de4c5d 270 goto return_noroute;
group-onsemi 0:098463de4c5d 271 }
group-onsemi 0:098463de4c5d 272
group-onsemi 0:098463de4c5d 273 /* RFC3927 2.7: do not forward link-local addresses */
group-onsemi 0:098463de4c5d 274 if (ip4_addr_islinklocal(ip4_current_dest_addr())) {
group-onsemi 0:098463de4c5d 275 LWIP_DEBUGF(IP_DEBUG, ("ip4_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
group-onsemi 0:098463de4c5d 276 ip4_addr1_16(ip4_current_dest_addr()), ip4_addr2_16(ip4_current_dest_addr()),
group-onsemi 0:098463de4c5d 277 ip4_addr3_16(ip4_current_dest_addr()), ip4_addr4_16(ip4_current_dest_addr())));
group-onsemi 0:098463de4c5d 278 goto return_noroute;
group-onsemi 0:098463de4c5d 279 }
group-onsemi 0:098463de4c5d 280
group-onsemi 0:098463de4c5d 281 /* Find network interface where to forward this IP packet to. */
group-onsemi 0:098463de4c5d 282 netif = ip4_route_src(ip4_current_dest_addr(), ip4_current_src_addr());
group-onsemi 0:098463de4c5d 283 if (netif == NULL) {
group-onsemi 0:098463de4c5d 284 LWIP_DEBUGF(IP_DEBUG, ("ip4_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n",
group-onsemi 0:098463de4c5d 285 ip4_addr1_16(ip4_current_dest_addr()), ip4_addr2_16(ip4_current_dest_addr()),
group-onsemi 0:098463de4c5d 286 ip4_addr3_16(ip4_current_dest_addr()), ip4_addr4_16(ip4_current_dest_addr())));
group-onsemi 0:098463de4c5d 287 /* @todo: send ICMP_DUR_NET? */
group-onsemi 0:098463de4c5d 288 goto return_noroute;
group-onsemi 0:098463de4c5d 289 }
group-onsemi 0:098463de4c5d 290 #if !IP_FORWARD_ALLOW_TX_ON_RX_NETIF
group-onsemi 0:098463de4c5d 291 /* Do not forward packets onto the same network interface on which
group-onsemi 0:098463de4c5d 292 * they arrived. */
group-onsemi 0:098463de4c5d 293 if (netif == inp) {
group-onsemi 0:098463de4c5d 294 LWIP_DEBUGF(IP_DEBUG, ("ip4_forward: not bouncing packets back on incoming interface.\n"));
group-onsemi 0:098463de4c5d 295 goto return_noroute;
group-onsemi 0:098463de4c5d 296 }
group-onsemi 0:098463de4c5d 297 #endif /* IP_FORWARD_ALLOW_TX_ON_RX_NETIF */
group-onsemi 0:098463de4c5d 298
group-onsemi 0:098463de4c5d 299 /* decrement TTL */
group-onsemi 0:098463de4c5d 300 IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);
group-onsemi 0:098463de4c5d 301 /* send ICMP if TTL == 0 */
group-onsemi 0:098463de4c5d 302 if (IPH_TTL(iphdr) == 0) {
group-onsemi 0:098463de4c5d 303 MIB2_STATS_INC(mib2.ipinhdrerrors);
group-onsemi 0:098463de4c5d 304 #if LWIP_ICMP
group-onsemi 0:098463de4c5d 305 /* Don't send ICMP messages in response to ICMP messages */
group-onsemi 0:098463de4c5d 306 if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) {
group-onsemi 0:098463de4c5d 307 icmp_time_exceeded(p, ICMP_TE_TTL);
group-onsemi 0:098463de4c5d 308 }
group-onsemi 0:098463de4c5d 309 #endif /* LWIP_ICMP */
group-onsemi 0:098463de4c5d 310 return;
group-onsemi 0:098463de4c5d 311 }
group-onsemi 0:098463de4c5d 312
group-onsemi 0:098463de4c5d 313 /* Incrementally update the IP checksum. */
group-onsemi 0:098463de4c5d 314 if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffffU - 0x100)) {
group-onsemi 0:098463de4c5d 315 IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1);
group-onsemi 0:098463de4c5d 316 } else {
group-onsemi 0:098463de4c5d 317 IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100));
group-onsemi 0:098463de4c5d 318 }
group-onsemi 0:098463de4c5d 319
group-onsemi 0:098463de4c5d 320 LWIP_DEBUGF(IP_DEBUG, ("ip4_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
group-onsemi 0:098463de4c5d 321 ip4_addr1_16(ip4_current_dest_addr()), ip4_addr2_16(ip4_current_dest_addr()),
group-onsemi 0:098463de4c5d 322 ip4_addr3_16(ip4_current_dest_addr()), ip4_addr4_16(ip4_current_dest_addr())));
group-onsemi 0:098463de4c5d 323
group-onsemi 0:098463de4c5d 324 IP_STATS_INC(ip.fw);
group-onsemi 0:098463de4c5d 325 MIB2_STATS_INC(mib2.ipforwdatagrams);
group-onsemi 0:098463de4c5d 326 IP_STATS_INC(ip.xmit);
group-onsemi 0:098463de4c5d 327
group-onsemi 0:098463de4c5d 328 PERF_STOP("ip4_forward");
group-onsemi 0:098463de4c5d 329 /* don't fragment if interface has mtu set to 0 [loopif] */
group-onsemi 0:098463de4c5d 330 if (netif->mtu && (p->tot_len > netif->mtu)) {
group-onsemi 0:098463de4c5d 331 if ((IPH_OFFSET(iphdr) & PP_NTOHS(IP_DF)) == 0) {
group-onsemi 0:098463de4c5d 332 #if IP_FRAG
group-onsemi 0:098463de4c5d 333 ip4_frag(p, netif, ip4_current_dest_addr());
group-onsemi 0:098463de4c5d 334 #else /* IP_FRAG */
group-onsemi 0:098463de4c5d 335 /* @todo: send ICMP Destination Unreachable code 13 "Communication administratively prohibited"? */
group-onsemi 0:098463de4c5d 336 #endif /* IP_FRAG */
group-onsemi 0:098463de4c5d 337 } else {
group-onsemi 0:098463de4c5d 338 #if LWIP_ICMP
group-onsemi 0:098463de4c5d 339 /* send ICMP Destination Unreachable code 4: "Fragmentation Needed and DF Set" */
group-onsemi 0:098463de4c5d 340 icmp_dest_unreach(p, ICMP_DUR_FRAG);
group-onsemi 0:098463de4c5d 341 #endif /* LWIP_ICMP */
group-onsemi 0:098463de4c5d 342 }
group-onsemi 0:098463de4c5d 343 return;
group-onsemi 0:098463de4c5d 344 }
group-onsemi 0:098463de4c5d 345 /* transmit pbuf on chosen interface */
group-onsemi 0:098463de4c5d 346 netif->output(netif, p, ip4_current_dest_addr());
group-onsemi 0:098463de4c5d 347 return;
group-onsemi 0:098463de4c5d 348 return_noroute:
group-onsemi 0:098463de4c5d 349 MIB2_STATS_INC(mib2.ipoutnoroutes);
group-onsemi 0:098463de4c5d 350 }
group-onsemi 0:098463de4c5d 351 #endif /* IP_FORWARD */
group-onsemi 0:098463de4c5d 352
group-onsemi 0:098463de4c5d 353 /**
group-onsemi 0:098463de4c5d 354 * This function is called by the network interface device driver when
group-onsemi 0:098463de4c5d 355 * an IP packet is received. The function does the basic checks of the
group-onsemi 0:098463de4c5d 356 * IP header such as packet size being at least larger than the header
group-onsemi 0:098463de4c5d 357 * size etc. If the packet was not destined for us, the packet is
group-onsemi 0:098463de4c5d 358 * forwarded (using ip_forward). The IP checksum is always checked.
group-onsemi 0:098463de4c5d 359 *
group-onsemi 0:098463de4c5d 360 * Finally, the packet is sent to the upper layer protocol input function.
group-onsemi 0:098463de4c5d 361 *
group-onsemi 0:098463de4c5d 362 * @param p the received IP packet (p->payload points to IP header)
group-onsemi 0:098463de4c5d 363 * @param inp the netif on which this packet was received
group-onsemi 0:098463de4c5d 364 * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't
group-onsemi 0:098463de4c5d 365 * processed, but currently always returns ERR_OK)
group-onsemi 0:098463de4c5d 366 */
group-onsemi 0:098463de4c5d 367 err_t
group-onsemi 0:098463de4c5d 368 ip4_input(struct pbuf *p, struct netif *inp)
group-onsemi 0:098463de4c5d 369 {
group-onsemi 0:098463de4c5d 370 struct ip_hdr *iphdr;
group-onsemi 0:098463de4c5d 371 struct netif *netif;
group-onsemi 0:098463de4c5d 372 u16_t iphdr_hlen;
group-onsemi 0:098463de4c5d 373 u16_t iphdr_len;
group-onsemi 0:098463de4c5d 374 #if IP_ACCEPT_LINK_LAYER_ADDRESSING || LWIP_IGMP
group-onsemi 0:098463de4c5d 375 int check_ip_src = 1;
group-onsemi 0:098463de4c5d 376 #endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING || LWIP_IGMP */
group-onsemi 0:098463de4c5d 377
group-onsemi 0:098463de4c5d 378 IP_STATS_INC(ip.recv);
group-onsemi 0:098463de4c5d 379 MIB2_STATS_INC(mib2.ipinreceives);
group-onsemi 0:098463de4c5d 380
group-onsemi 0:098463de4c5d 381 /* identify the IP header */
group-onsemi 0:098463de4c5d 382 iphdr = (struct ip_hdr *)p->payload;
group-onsemi 0:098463de4c5d 383 if (IPH_V(iphdr) != 4) {
group-onsemi 0:098463de4c5d 384 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", (u16_t)IPH_V(iphdr)));
group-onsemi 0:098463de4c5d 385 ip4_debug_print(p);
group-onsemi 0:098463de4c5d 386 pbuf_free(p);
group-onsemi 0:098463de4c5d 387 IP_STATS_INC(ip.err);
group-onsemi 0:098463de4c5d 388 IP_STATS_INC(ip.drop);
group-onsemi 0:098463de4c5d 389 MIB2_STATS_INC(mib2.ipinhdrerrors);
group-onsemi 0:098463de4c5d 390 return ERR_OK;
group-onsemi 0:098463de4c5d 391 }
group-onsemi 0:098463de4c5d 392
group-onsemi 0:098463de4c5d 393 #ifdef LWIP_HOOK_IP4_INPUT
group-onsemi 0:098463de4c5d 394 if (LWIP_HOOK_IP4_INPUT(p, inp)) {
group-onsemi 0:098463de4c5d 395 /* the packet has been eaten */
group-onsemi 0:098463de4c5d 396 return ERR_OK;
group-onsemi 0:098463de4c5d 397 }
group-onsemi 0:098463de4c5d 398 #endif
group-onsemi 0:098463de4c5d 399
group-onsemi 0:098463de4c5d 400 /* obtain IP header length in number of 32-bit words */
group-onsemi 0:098463de4c5d 401 iphdr_hlen = IPH_HL(iphdr);
group-onsemi 0:098463de4c5d 402 /* calculate IP header length in bytes */
group-onsemi 0:098463de4c5d 403 iphdr_hlen *= 4;
group-onsemi 0:098463de4c5d 404 /* obtain ip length in bytes */
group-onsemi 0:098463de4c5d 405 iphdr_len = ntohs(IPH_LEN(iphdr));
group-onsemi 0:098463de4c5d 406
group-onsemi 0:098463de4c5d 407 /* Trim pbuf. This is especially required for packets < 60 bytes. */
group-onsemi 0:098463de4c5d 408 if (iphdr_len < p->tot_len) {
group-onsemi 0:098463de4c5d 409 pbuf_realloc(p, iphdr_len);
group-onsemi 0:098463de4c5d 410 }
group-onsemi 0:098463de4c5d 411
group-onsemi 0:098463de4c5d 412 /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
group-onsemi 0:098463de4c5d 413 if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len) || (iphdr_hlen < IP_HLEN)) {
group-onsemi 0:098463de4c5d 414 if (iphdr_hlen < IP_HLEN) {
group-onsemi 0:098463de4c5d 415 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
group-onsemi 0:098463de4c5d 416 ("ip4_input: short IP header (%"U16_F" bytes) received, IP packet dropped\n", iphdr_hlen));
group-onsemi 0:098463de4c5d 417 }
group-onsemi 0:098463de4c5d 418 if (iphdr_hlen > p->len) {
group-onsemi 0:098463de4c5d 419 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
group-onsemi 0:098463de4c5d 420 ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
group-onsemi 0:098463de4c5d 421 iphdr_hlen, p->len));
group-onsemi 0:098463de4c5d 422 }
group-onsemi 0:098463de4c5d 423 if (iphdr_len > p->tot_len) {
group-onsemi 0:098463de4c5d 424 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
group-onsemi 0:098463de4c5d 425 ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n",
group-onsemi 0:098463de4c5d 426 iphdr_len, p->tot_len));
group-onsemi 0:098463de4c5d 427 }
group-onsemi 0:098463de4c5d 428 /* free (drop) packet pbufs */
group-onsemi 0:098463de4c5d 429 pbuf_free(p);
group-onsemi 0:098463de4c5d 430 IP_STATS_INC(ip.lenerr);
group-onsemi 0:098463de4c5d 431 IP_STATS_INC(ip.drop);
group-onsemi 0:098463de4c5d 432 MIB2_STATS_INC(mib2.ipindiscards);
group-onsemi 0:098463de4c5d 433 return ERR_OK;
group-onsemi 0:098463de4c5d 434 }
group-onsemi 0:098463de4c5d 435
group-onsemi 0:098463de4c5d 436 /* verify checksum */
group-onsemi 0:098463de4c5d 437 #if CHECKSUM_CHECK_IP
group-onsemi 0:098463de4c5d 438 IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_IP) {
group-onsemi 0:098463de4c5d 439 if (inet_chksum(iphdr, iphdr_hlen) != 0) {
group-onsemi 0:098463de4c5d 440
group-onsemi 0:098463de4c5d 441 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
group-onsemi 0:098463de4c5d 442 ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
group-onsemi 0:098463de4c5d 443 ip4_debug_print(p);
group-onsemi 0:098463de4c5d 444 pbuf_free(p);
group-onsemi 0:098463de4c5d 445 IP_STATS_INC(ip.chkerr);
group-onsemi 0:098463de4c5d 446 IP_STATS_INC(ip.drop);
group-onsemi 0:098463de4c5d 447 MIB2_STATS_INC(mib2.ipinhdrerrors);
group-onsemi 0:098463de4c5d 448 return ERR_OK;
group-onsemi 0:098463de4c5d 449 }
group-onsemi 0:098463de4c5d 450 }
group-onsemi 0:098463de4c5d 451 #endif
group-onsemi 0:098463de4c5d 452
group-onsemi 0:098463de4c5d 453 /* copy IP addresses to aligned ip_addr_t */
group-onsemi 0:098463de4c5d 454 ip_addr_copy_from_ip4(ip_data.current_iphdr_dest, iphdr->dest);
group-onsemi 0:098463de4c5d 455 ip_addr_copy_from_ip4(ip_data.current_iphdr_src, iphdr->src);
group-onsemi 0:098463de4c5d 456
group-onsemi 0:098463de4c5d 457 /* match packet against an interface, i.e. is this packet for us? */
group-onsemi 0:098463de4c5d 458 if (ip4_addr_ismulticast(ip4_current_dest_addr())) {
group-onsemi 0:098463de4c5d 459 #if LWIP_IGMP
group-onsemi 0:098463de4c5d 460 if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ip4_current_dest_addr()))) {
group-onsemi 0:098463de4c5d 461 /* IGMP snooping switches need 0.0.0.0 to be allowed as source address (RFC 4541) */
group-onsemi 0:098463de4c5d 462 ip4_addr_t allsystems;
group-onsemi 0:098463de4c5d 463 IP4_ADDR(&allsystems, 224, 0, 0, 1);
group-onsemi 0:098463de4c5d 464 if (ip4_addr_cmp(ip4_current_dest_addr(), &allsystems) &&
group-onsemi 0:098463de4c5d 465 ip4_addr_isany(ip4_current_src_addr())) {
group-onsemi 0:098463de4c5d 466 check_ip_src = 0;
group-onsemi 0:098463de4c5d 467 }
group-onsemi 0:098463de4c5d 468 netif = inp;
group-onsemi 0:098463de4c5d 469 } else {
group-onsemi 0:098463de4c5d 470 netif = NULL;
group-onsemi 0:098463de4c5d 471 }
group-onsemi 0:098463de4c5d 472 #else /* LWIP_IGMP */
group-onsemi 0:098463de4c5d 473 if ((netif_is_up(inp)) && (!ip4_addr_isany_val(*netif_ip4_addr(inp)))) {
group-onsemi 0:098463de4c5d 474 netif = inp;
group-onsemi 0:098463de4c5d 475 } else {
group-onsemi 0:098463de4c5d 476 netif = NULL;
group-onsemi 0:098463de4c5d 477 }
group-onsemi 0:098463de4c5d 478 #endif /* LWIP_IGMP */
group-onsemi 0:098463de4c5d 479 } else {
group-onsemi 0:098463de4c5d 480 /* start trying with inp. if that's not acceptable, start walking the
group-onsemi 0:098463de4c5d 481 list of configured netifs.
group-onsemi 0:098463de4c5d 482 'first' is used as a boolean to mark whether we started walking the list */
group-onsemi 0:098463de4c5d 483 int first = 1;
group-onsemi 0:098463de4c5d 484 netif = inp;
group-onsemi 0:098463de4c5d 485 do {
group-onsemi 0:098463de4c5d 486 LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n",
group-onsemi 0:098463de4c5d 487 ip4_addr_get_u32(&iphdr->dest), ip4_addr_get_u32(netif_ip4_addr(netif)),
group-onsemi 0:098463de4c5d 488 ip4_addr_get_u32(&iphdr->dest) & ip4_addr_get_u32(netif_ip4_netmask(netif)),
group-onsemi 0:098463de4c5d 489 ip4_addr_get_u32(netif_ip4_addr(netif)) & ip4_addr_get_u32(netif_ip4_netmask(netif)),
group-onsemi 0:098463de4c5d 490 ip4_addr_get_u32(&iphdr->dest) & ~ip4_addr_get_u32(netif_ip4_netmask(netif))));
group-onsemi 0:098463de4c5d 491
group-onsemi 0:098463de4c5d 492 /* interface is up and configured? */
group-onsemi 0:098463de4c5d 493 if ((netif_is_up(netif)) && (!ip4_addr_isany_val(*netif_ip4_addr(netif)))) {
group-onsemi 0:098463de4c5d 494 /* unicast to this interface address? */
group-onsemi 0:098463de4c5d 495 if (ip4_addr_cmp(ip4_current_dest_addr(), netif_ip4_addr(netif)) ||
group-onsemi 0:098463de4c5d 496 /* or broadcast on this interface network address? */
group-onsemi 0:098463de4c5d 497 ip4_addr_isbroadcast(ip4_current_dest_addr(), netif)
group-onsemi 0:098463de4c5d 498 #if LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF
group-onsemi 0:098463de4c5d 499 || (ip4_addr_get_u32(ip4_current_dest_addr()) == PP_HTONL(IPADDR_LOOPBACK))
group-onsemi 0:098463de4c5d 500 #endif /* LWIP_NETIF_LOOPBACK && !LWIP_HAVE_LOOPIF */
group-onsemi 0:098463de4c5d 501 ) {
group-onsemi 0:098463de4c5d 502 LWIP_DEBUGF(IP_DEBUG, ("ip4_input: packet accepted on interface %c%c\n",
group-onsemi 0:098463de4c5d 503 netif->name[0], netif->name[1]));
group-onsemi 0:098463de4c5d 504 /* break out of for loop */
group-onsemi 0:098463de4c5d 505 break;
group-onsemi 0:098463de4c5d 506 }
group-onsemi 0:098463de4c5d 507 #if LWIP_AUTOIP
group-onsemi 0:098463de4c5d 508 /* connections to link-local addresses must persist after changing
group-onsemi 0:098463de4c5d 509 the netif's address (RFC3927 ch. 1.9) */
group-onsemi 0:098463de4c5d 510 if ((netif->autoip != NULL) &&
group-onsemi 0:098463de4c5d 511 ip4_addr_cmp(ip4_current_dest_addr(), &(netif->autoip->llipaddr))) {
group-onsemi 0:098463de4c5d 512 LWIP_DEBUGF(IP_DEBUG, ("ip4_input: LLA packet accepted on interface %c%c\n",
group-onsemi 0:098463de4c5d 513 netif->name[0], netif->name[1]));
group-onsemi 0:098463de4c5d 514 /* break out of for loop */
group-onsemi 0:098463de4c5d 515 break;
group-onsemi 0:098463de4c5d 516 }
group-onsemi 0:098463de4c5d 517 #endif /* LWIP_AUTOIP */
group-onsemi 0:098463de4c5d 518 }
group-onsemi 0:098463de4c5d 519 if (first) {
group-onsemi 0:098463de4c5d 520 first = 0;
group-onsemi 0:098463de4c5d 521 netif = netif_list;
group-onsemi 0:098463de4c5d 522 } else {
group-onsemi 0:098463de4c5d 523 netif = netif->next;
group-onsemi 0:098463de4c5d 524 }
group-onsemi 0:098463de4c5d 525 if (netif == inp) {
group-onsemi 0:098463de4c5d 526 netif = netif->next;
group-onsemi 0:098463de4c5d 527 }
group-onsemi 0:098463de4c5d 528 } while (netif != NULL);
group-onsemi 0:098463de4c5d 529 }
group-onsemi 0:098463de4c5d 530
group-onsemi 0:098463de4c5d 531 #if IP_ACCEPT_LINK_LAYER_ADDRESSING
group-onsemi 0:098463de4c5d 532 /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed
group-onsemi 0:098463de4c5d 533 * using link layer addressing (such as Ethernet MAC) so we must not filter on IP.
group-onsemi 0:098463de4c5d 534 * According to RFC 1542 section 3.1.1, referred by RFC 2131).
group-onsemi 0:098463de4c5d 535 *
group-onsemi 0:098463de4c5d 536 * If you want to accept private broadcast communication while a netif is down,
group-onsemi 0:098463de4c5d 537 * define LWIP_IP_ACCEPT_UDP_PORT(dst_port), e.g.:
group-onsemi 0:098463de4c5d 538 *
group-onsemi 0:098463de4c5d 539 * #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345))
group-onsemi 0:098463de4c5d 540 */
group-onsemi 0:098463de4c5d 541 if (netif == NULL) {
group-onsemi 0:098463de4c5d 542 /* remote port is DHCP server? */
group-onsemi 0:098463de4c5d 543 if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
group-onsemi 0:098463de4c5d 544 struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen);
group-onsemi 0:098463de4c5d 545 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip4_input: UDP packet to DHCP client port %"U16_F"\n",
group-onsemi 0:098463de4c5d 546 ntohs(udphdr->dest)));
group-onsemi 0:098463de4c5d 547 if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) {
group-onsemi 0:098463de4c5d 548 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip4_input: DHCP packet accepted.\n"));
group-onsemi 0:098463de4c5d 549 netif = inp;
group-onsemi 0:098463de4c5d 550 check_ip_src = 0;
group-onsemi 0:098463de4c5d 551 }
group-onsemi 0:098463de4c5d 552 }
group-onsemi 0:098463de4c5d 553 }
group-onsemi 0:098463de4c5d 554 #endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
group-onsemi 0:098463de4c5d 555
group-onsemi 0:098463de4c5d 556 /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */
group-onsemi 0:098463de4c5d 557 #if LWIP_IGMP || IP_ACCEPT_LINK_LAYER_ADDRESSING
group-onsemi 0:098463de4c5d 558 if (check_ip_src
group-onsemi 0:098463de4c5d 559 #if IP_ACCEPT_LINK_LAYER_ADDRESSING
group-onsemi 0:098463de4c5d 560 /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */
group-onsemi 0:098463de4c5d 561 && !ip4_addr_isany_val(*ip4_current_src_addr())
group-onsemi 0:098463de4c5d 562 #endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
group-onsemi 0:098463de4c5d 563 )
group-onsemi 0:098463de4c5d 564 #endif /* LWIP_IGMP || IP_ACCEPT_LINK_LAYER_ADDRESSING */
group-onsemi 0:098463de4c5d 565 {
group-onsemi 0:098463de4c5d 566 if ((ip4_addr_isbroadcast(ip4_current_src_addr(), inp)) ||
group-onsemi 0:098463de4c5d 567 (ip4_addr_ismulticast(ip4_current_src_addr()))) {
group-onsemi 0:098463de4c5d 568 /* packet source is not valid */
group-onsemi 0:098463de4c5d 569 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip4_input: packet source is not valid.\n"));
group-onsemi 0:098463de4c5d 570 /* free (drop) packet pbufs */
group-onsemi 0:098463de4c5d 571 pbuf_free(p);
group-onsemi 0:098463de4c5d 572 IP_STATS_INC(ip.drop);
group-onsemi 0:098463de4c5d 573 MIB2_STATS_INC(mib2.ipinaddrerrors);
group-onsemi 0:098463de4c5d 574 MIB2_STATS_INC(mib2.ipindiscards);
group-onsemi 0:098463de4c5d 575 return ERR_OK;
group-onsemi 0:098463de4c5d 576 }
group-onsemi 0:098463de4c5d 577 }
group-onsemi 0:098463de4c5d 578
group-onsemi 0:098463de4c5d 579 /* packet not for us? */
group-onsemi 0:098463de4c5d 580 if (netif == NULL) {
group-onsemi 0:098463de4c5d 581 /* packet not for us, route or discard */
group-onsemi 0:098463de4c5d 582 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip4_input: packet not for us.\n"));
group-onsemi 0:098463de4c5d 583 #if IP_FORWARD
group-onsemi 0:098463de4c5d 584 /* non-broadcast packet? */
group-onsemi 0:098463de4c5d 585 if (!ip4_addr_isbroadcast(ip4_current_dest_addr(), inp)) {
group-onsemi 0:098463de4c5d 586 /* try to forward IP packet on (other) interfaces */
group-onsemi 0:098463de4c5d 587 ip4_forward(p, iphdr, inp);
group-onsemi 0:098463de4c5d 588 } else
group-onsemi 0:098463de4c5d 589 #endif /* IP_FORWARD */
group-onsemi 0:098463de4c5d 590 {
group-onsemi 0:098463de4c5d 591 MIB2_STATS_INC(mib2.ipinaddrerrors);
group-onsemi 0:098463de4c5d 592 MIB2_STATS_INC(mib2.ipindiscards);
group-onsemi 0:098463de4c5d 593 }
group-onsemi 0:098463de4c5d 594 pbuf_free(p);
group-onsemi 0:098463de4c5d 595 return ERR_OK;
group-onsemi 0:098463de4c5d 596 }
group-onsemi 0:098463de4c5d 597 /* packet consists of multiple fragments? */
group-onsemi 0:098463de4c5d 598 if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) {
group-onsemi 0:098463de4c5d 599 #if IP_REASSEMBLY /* packet fragment reassembly code present? */
group-onsemi 0:098463de4c5d 600 LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip4_reass()\n",
group-onsemi 0:098463de4c5d 601 ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), (u16_t)!!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (u16_t)((ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8)));
group-onsemi 0:098463de4c5d 602 /* reassemble the packet*/
group-onsemi 0:098463de4c5d 603 p = ip4_reass(p);
group-onsemi 0:098463de4c5d 604 /* packet not fully reassembled yet? */
group-onsemi 0:098463de4c5d 605 if (p == NULL) {
group-onsemi 0:098463de4c5d 606 return ERR_OK;
group-onsemi 0:098463de4c5d 607 }
group-onsemi 0:098463de4c5d 608 iphdr = (struct ip_hdr *)p->payload;
group-onsemi 0:098463de4c5d 609 #else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
group-onsemi 0:098463de4c5d 610 pbuf_free(p);
group-onsemi 0:098463de4c5d 611 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
group-onsemi 0:098463de4c5d 612 ntohs(IPH_OFFSET(iphdr))));
group-onsemi 0:098463de4c5d 613 IP_STATS_INC(ip.opterr);
group-onsemi 0:098463de4c5d 614 IP_STATS_INC(ip.drop);
group-onsemi 0:098463de4c5d 615 /* unsupported protocol feature */
group-onsemi 0:098463de4c5d 616 MIB2_STATS_INC(mib2.ipinunknownprotos);
group-onsemi 0:098463de4c5d 617 return ERR_OK;
group-onsemi 0:098463de4c5d 618 #endif /* IP_REASSEMBLY */
group-onsemi 0:098463de4c5d 619 }
group-onsemi 0:098463de4c5d 620
group-onsemi 0:098463de4c5d 621 #if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */
group-onsemi 0:098463de4c5d 622
group-onsemi 0:098463de4c5d 623 #if LWIP_IGMP
group-onsemi 0:098463de4c5d 624 /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */
group-onsemi 0:098463de4c5d 625 if ((iphdr_hlen > IP_HLEN) && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {
group-onsemi 0:098463de4c5d 626 #else
group-onsemi 0:098463de4c5d 627 if (iphdr_hlen > IP_HLEN) {
group-onsemi 0:098463de4c5d 628 #endif /* LWIP_IGMP */
group-onsemi 0:098463de4c5d 629 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
group-onsemi 0:098463de4c5d 630 pbuf_free(p);
group-onsemi 0:098463de4c5d 631 IP_STATS_INC(ip.opterr);
group-onsemi 0:098463de4c5d 632 IP_STATS_INC(ip.drop);
group-onsemi 0:098463de4c5d 633 /* unsupported protocol feature */
group-onsemi 0:098463de4c5d 634 MIB2_STATS_INC(mib2.ipinunknownprotos);
group-onsemi 0:098463de4c5d 635 return ERR_OK;
group-onsemi 0:098463de4c5d 636 }
group-onsemi 0:098463de4c5d 637 #endif /* IP_OPTIONS_ALLOWED == 0 */
group-onsemi 0:098463de4c5d 638
group-onsemi 0:098463de4c5d 639 /* send to upper layers */
group-onsemi 0:098463de4c5d 640 LWIP_DEBUGF(IP_DEBUG, ("ip4_input: \n"));
group-onsemi 0:098463de4c5d 641 ip4_debug_print(p);
group-onsemi 0:098463de4c5d 642 LWIP_DEBUGF(IP_DEBUG, ("ip4_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));
group-onsemi 0:098463de4c5d 643
group-onsemi 0:098463de4c5d 644 ip_data.current_netif = netif;
group-onsemi 0:098463de4c5d 645 ip_data.current_input_netif = inp;
group-onsemi 0:098463de4c5d 646 ip_data.current_ip4_header = iphdr;
group-onsemi 0:098463de4c5d 647 ip_data.current_ip_header_tot_len = IPH_HL(iphdr) * 4;
group-onsemi 0:098463de4c5d 648
group-onsemi 0:098463de4c5d 649 #if LWIP_RAW
group-onsemi 0:098463de4c5d 650 /* raw input did not eat the packet? */
group-onsemi 0:098463de4c5d 651 if (raw_input(p, inp) == 0)
group-onsemi 0:098463de4c5d 652 #endif /* LWIP_RAW */
group-onsemi 0:098463de4c5d 653 {
group-onsemi 0:098463de4c5d 654 pbuf_header(p, -(s16_t)iphdr_hlen); /* Move to payload, no check necessary. */
group-onsemi 0:098463de4c5d 655
group-onsemi 0:098463de4c5d 656 switch (IPH_PROTO(iphdr)) {
group-onsemi 0:098463de4c5d 657 #if LWIP_UDP
group-onsemi 0:098463de4c5d 658 case IP_PROTO_UDP:
group-onsemi 0:098463de4c5d 659 #if LWIP_UDPLITE
group-onsemi 0:098463de4c5d 660 case IP_PROTO_UDPLITE:
group-onsemi 0:098463de4c5d 661 #endif /* LWIP_UDPLITE */
group-onsemi 0:098463de4c5d 662 MIB2_STATS_INC(mib2.ipindelivers);
group-onsemi 0:098463de4c5d 663 udp_input(p, inp);
group-onsemi 0:098463de4c5d 664 break;
group-onsemi 0:098463de4c5d 665 #endif /* LWIP_UDP */
group-onsemi 0:098463de4c5d 666 #if LWIP_TCP
group-onsemi 0:098463de4c5d 667 case IP_PROTO_TCP:
group-onsemi 0:098463de4c5d 668 MIB2_STATS_INC(mib2.ipindelivers);
group-onsemi 0:098463de4c5d 669 tcp_input(p, inp);
group-onsemi 0:098463de4c5d 670 break;
group-onsemi 0:098463de4c5d 671 #endif /* LWIP_TCP */
group-onsemi 0:098463de4c5d 672 #if LWIP_ICMP
group-onsemi 0:098463de4c5d 673 case IP_PROTO_ICMP:
group-onsemi 0:098463de4c5d 674 MIB2_STATS_INC(mib2.ipindelivers);
group-onsemi 0:098463de4c5d 675 icmp_input(p, inp);
group-onsemi 0:098463de4c5d 676 break;
group-onsemi 0:098463de4c5d 677 #endif /* LWIP_ICMP */
group-onsemi 0:098463de4c5d 678 #if LWIP_IGMP
group-onsemi 0:098463de4c5d 679 case IP_PROTO_IGMP:
group-onsemi 0:098463de4c5d 680 igmp_input(p, inp, ip4_current_dest_addr());
group-onsemi 0:098463de4c5d 681 break;
group-onsemi 0:098463de4c5d 682 #endif /* LWIP_IGMP */
group-onsemi 0:098463de4c5d 683 default:
group-onsemi 0:098463de4c5d 684 #if LWIP_ICMP
group-onsemi 0:098463de4c5d 685 /* send ICMP destination protocol unreachable unless is was a broadcast */
group-onsemi 0:098463de4c5d 686 if (!ip4_addr_isbroadcast(ip4_current_dest_addr(), netif) &&
group-onsemi 0:098463de4c5d 687 !ip4_addr_ismulticast(ip4_current_dest_addr())) {
group-onsemi 0:098463de4c5d 688 pbuf_header_force(p, iphdr_hlen); /* Move to ip header, no check necessary. */
group-onsemi 0:098463de4c5d 689 p->payload = iphdr;
group-onsemi 0:098463de4c5d 690 icmp_dest_unreach(p, ICMP_DUR_PROTO);
group-onsemi 0:098463de4c5d 691 }
group-onsemi 0:098463de4c5d 692 #endif /* LWIP_ICMP */
group-onsemi 0:098463de4c5d 693 pbuf_free(p);
group-onsemi 0:098463de4c5d 694
group-onsemi 0:098463de4c5d 695 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", (u16_t)IPH_PROTO(iphdr)));
group-onsemi 0:098463de4c5d 696
group-onsemi 0:098463de4c5d 697 IP_STATS_INC(ip.proterr);
group-onsemi 0:098463de4c5d 698 IP_STATS_INC(ip.drop);
group-onsemi 0:098463de4c5d 699 MIB2_STATS_INC(mib2.ipinunknownprotos);
group-onsemi 0:098463de4c5d 700 }
group-onsemi 0:098463de4c5d 701 }
group-onsemi 0:098463de4c5d 702
group-onsemi 0:098463de4c5d 703 /* @todo: this is not really necessary... */
group-onsemi 0:098463de4c5d 704 ip_data.current_netif = NULL;
group-onsemi 0:098463de4c5d 705 ip_data.current_input_netif = NULL;
group-onsemi 0:098463de4c5d 706 ip_data.current_ip4_header = NULL;
group-onsemi 0:098463de4c5d 707 ip_data.current_ip_header_tot_len = 0;
group-onsemi 0:098463de4c5d 708 ip4_addr_set_any(ip4_current_src_addr());
group-onsemi 0:098463de4c5d 709 ip4_addr_set_any(ip4_current_dest_addr());
group-onsemi 0:098463de4c5d 710
group-onsemi 0:098463de4c5d 711 return ERR_OK;
group-onsemi 0:098463de4c5d 712 }
group-onsemi 0:098463de4c5d 713
group-onsemi 0:098463de4c5d 714 /**
group-onsemi 0:098463de4c5d 715 * Sends an IP packet on a network interface. This function constructs
group-onsemi 0:098463de4c5d 716 * the IP header and calculates the IP header checksum. If the source
group-onsemi 0:098463de4c5d 717 * IP address is NULL, the IP address of the outgoing network
group-onsemi 0:098463de4c5d 718 * interface is filled in as source address.
group-onsemi 0:098463de4c5d 719 * If the destination IP address is IP_HDRINCL, p is assumed to already
group-onsemi 0:098463de4c5d 720 * include an IP header and p->payload points to it instead of the data.
group-onsemi 0:098463de4c5d 721 *
group-onsemi 0:098463de4c5d 722 * @param p the packet to send (p->payload points to the data, e.g. next
group-onsemi 0:098463de4c5d 723 protocol header; if dest == IP_HDRINCL, p already includes an IP
group-onsemi 0:098463de4c5d 724 header and p->payload points to that IP header)
group-onsemi 0:098463de4c5d 725 * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
group-onsemi 0:098463de4c5d 726 * IP address of the netif used to send is used as source address)
group-onsemi 0:098463de4c5d 727 * @param dest the destination IP address to send the packet to
group-onsemi 0:098463de4c5d 728 * @param ttl the TTL value to be set in the IP header
group-onsemi 0:098463de4c5d 729 * @param tos the TOS value to be set in the IP header
group-onsemi 0:098463de4c5d 730 * @param proto the PROTOCOL to be set in the IP header
group-onsemi 0:098463de4c5d 731 * @param netif the netif on which to send this packet
group-onsemi 0:098463de4c5d 732 * @return ERR_OK if the packet was sent OK
group-onsemi 0:098463de4c5d 733 * ERR_BUF if p doesn't have enough space for IP/LINK headers
group-onsemi 0:098463de4c5d 734 * returns errors returned by netif->output
group-onsemi 0:098463de4c5d 735 *
group-onsemi 0:098463de4c5d 736 * @note ip_id: RFC791 "some host may be able to simply use
group-onsemi 0:098463de4c5d 737 * unique identifiers independent of destination"
group-onsemi 0:098463de4c5d 738 */
group-onsemi 0:098463de4c5d 739 err_t
group-onsemi 0:098463de4c5d 740 ip4_output_if(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest,
group-onsemi 0:098463de4c5d 741 u8_t ttl, u8_t tos,
group-onsemi 0:098463de4c5d 742 u8_t proto, struct netif *netif)
group-onsemi 0:098463de4c5d 743 {
group-onsemi 0:098463de4c5d 744 #if IP_OPTIONS_SEND
group-onsemi 0:098463de4c5d 745 return ip4_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0);
group-onsemi 0:098463de4c5d 746 }
group-onsemi 0:098463de4c5d 747
group-onsemi 0:098463de4c5d 748 /**
group-onsemi 0:098463de4c5d 749 * Same as ip_output_if() but with the possibility to include IP options:
group-onsemi 0:098463de4c5d 750 *
group-onsemi 0:098463de4c5d 751 * @ param ip_options pointer to the IP options, copied into the IP header
group-onsemi 0:098463de4c5d 752 * @ param optlen length of ip_options
group-onsemi 0:098463de4c5d 753 */
group-onsemi 0:098463de4c5d 754 err_t
group-onsemi 0:098463de4c5d 755 ip4_output_if_opt(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest,
group-onsemi 0:098463de4c5d 756 u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
group-onsemi 0:098463de4c5d 757 u16_t optlen)
group-onsemi 0:098463de4c5d 758 {
group-onsemi 0:098463de4c5d 759 #endif /* IP_OPTIONS_SEND */
group-onsemi 0:098463de4c5d 760 const ip4_addr_t *src_used = src;
group-onsemi 0:098463de4c5d 761 if (dest != IP_HDRINCL) {
group-onsemi 0:098463de4c5d 762 if (ip4_addr_isany(src)) {
group-onsemi 0:098463de4c5d 763 src_used = netif_ip4_addr(netif);
group-onsemi 0:098463de4c5d 764 }
group-onsemi 0:098463de4c5d 765 }
group-onsemi 0:098463de4c5d 766
group-onsemi 0:098463de4c5d 767 #if IP_OPTIONS_SEND
group-onsemi 0:098463de4c5d 768 return ip4_output_if_opt_src(p, src_used, dest, ttl, tos, proto, netif,
group-onsemi 0:098463de4c5d 769 ip_options, optlen);
group-onsemi 0:098463de4c5d 770 #else /* IP_OPTIONS_SEND */
group-onsemi 0:098463de4c5d 771 return ip4_output_if_src(p, src_used, dest, ttl, tos, proto, netif);
group-onsemi 0:098463de4c5d 772 #endif /* IP_OPTIONS_SEND */
group-onsemi 0:098463de4c5d 773 }
group-onsemi 0:098463de4c5d 774
group-onsemi 0:098463de4c5d 775 /**
group-onsemi 0:098463de4c5d 776 * Same as ip_output_if() but 'src' address is not replaced by netif address
group-onsemi 0:098463de4c5d 777 * when it is 'any'.
group-onsemi 0:098463de4c5d 778 */
group-onsemi 0:098463de4c5d 779 err_t
group-onsemi 0:098463de4c5d 780 ip4_output_if_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest,
group-onsemi 0:098463de4c5d 781 u8_t ttl, u8_t tos,
group-onsemi 0:098463de4c5d 782 u8_t proto, struct netif *netif)
group-onsemi 0:098463de4c5d 783 {
group-onsemi 0:098463de4c5d 784 #if IP_OPTIONS_SEND
group-onsemi 0:098463de4c5d 785 return ip4_output_if_opt_src(p, src, dest, ttl, tos, proto, netif, NULL, 0);
group-onsemi 0:098463de4c5d 786 }
group-onsemi 0:098463de4c5d 787
group-onsemi 0:098463de4c5d 788 /**
group-onsemi 0:098463de4c5d 789 * Same as ip_output_if_opt() but 'src' address is not replaced by netif address
group-onsemi 0:098463de4c5d 790 * when it is 'any'.
group-onsemi 0:098463de4c5d 791 */
group-onsemi 0:098463de4c5d 792 err_t
group-onsemi 0:098463de4c5d 793 ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest,
group-onsemi 0:098463de4c5d 794 u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
group-onsemi 0:098463de4c5d 795 u16_t optlen)
group-onsemi 0:098463de4c5d 796 {
group-onsemi 0:098463de4c5d 797 #endif /* IP_OPTIONS_SEND */
group-onsemi 0:098463de4c5d 798 struct ip_hdr *iphdr;
group-onsemi 0:098463de4c5d 799 ip4_addr_t dest_addr;
group-onsemi 0:098463de4c5d 800 #if CHECKSUM_GEN_IP_INLINE
group-onsemi 0:098463de4c5d 801 u32_t chk_sum = 0;
group-onsemi 0:098463de4c5d 802 #endif /* CHECKSUM_GEN_IP_INLINE */
group-onsemi 0:098463de4c5d 803
group-onsemi 0:098463de4c5d 804 LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p);
group-onsemi 0:098463de4c5d 805
group-onsemi 0:098463de4c5d 806 MIB2_STATS_INC(mib2.ipoutrequests);
group-onsemi 0:098463de4c5d 807
group-onsemi 0:098463de4c5d 808 /* Should the IP header be generated or is it already included in p? */
group-onsemi 0:098463de4c5d 809 if (dest != IP_HDRINCL) {
group-onsemi 0:098463de4c5d 810 u16_t ip_hlen = IP_HLEN;
group-onsemi 0:098463de4c5d 811 #if IP_OPTIONS_SEND
group-onsemi 0:098463de4c5d 812 u16_t optlen_aligned = 0;
group-onsemi 0:098463de4c5d 813 if (optlen != 0) {
group-onsemi 0:098463de4c5d 814 #if CHECKSUM_GEN_IP_INLINE
group-onsemi 0:098463de4c5d 815 int i;
group-onsemi 0:098463de4c5d 816 #endif /* CHECKSUM_GEN_IP_INLINE */
group-onsemi 0:098463de4c5d 817 /* round up to a multiple of 4 */
group-onsemi 0:098463de4c5d 818 optlen_aligned = ((optlen + 3) & ~3);
group-onsemi 0:098463de4c5d 819 ip_hlen += optlen_aligned;
group-onsemi 0:098463de4c5d 820 /* First write in the IP options */
group-onsemi 0:098463de4c5d 821 if (pbuf_header(p, optlen_aligned)) {
group-onsemi 0:098463de4c5d 822 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_output_if_opt: not enough room for IP options in pbuf\n"));
group-onsemi 0:098463de4c5d 823 IP_STATS_INC(ip.err);
group-onsemi 0:098463de4c5d 824 MIB2_STATS_INC(mib2.ipoutdiscards);
group-onsemi 0:098463de4c5d 825 return ERR_BUF;
group-onsemi 0:098463de4c5d 826 }
group-onsemi 0:098463de4c5d 827 MEMCPY(p->payload, ip_options, optlen);
group-onsemi 0:098463de4c5d 828 if (optlen < optlen_aligned) {
group-onsemi 0:098463de4c5d 829 /* zero the remaining bytes */
group-onsemi 0:098463de4c5d 830 memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen);
group-onsemi 0:098463de4c5d 831 }
group-onsemi 0:098463de4c5d 832 #if CHECKSUM_GEN_IP_INLINE
group-onsemi 0:098463de4c5d 833 for (i = 0; i < optlen_aligned/2; i++) {
group-onsemi 0:098463de4c5d 834 chk_sum += ((u16_t*)p->payload)[i];
group-onsemi 0:098463de4c5d 835 }
group-onsemi 0:098463de4c5d 836 #endif /* CHECKSUM_GEN_IP_INLINE */
group-onsemi 0:098463de4c5d 837 }
group-onsemi 0:098463de4c5d 838 #endif /* IP_OPTIONS_SEND */
group-onsemi 0:098463de4c5d 839 /* generate IP header */
group-onsemi 0:098463de4c5d 840 if (pbuf_header(p, IP_HLEN)) {
group-onsemi 0:098463de4c5d 841 LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip4_output: not enough room for IP header in pbuf\n"));
group-onsemi 0:098463de4c5d 842
group-onsemi 0:098463de4c5d 843 IP_STATS_INC(ip.err);
group-onsemi 0:098463de4c5d 844 MIB2_STATS_INC(mib2.ipoutdiscards);
group-onsemi 0:098463de4c5d 845 return ERR_BUF;
group-onsemi 0:098463de4c5d 846 }
group-onsemi 0:098463de4c5d 847
group-onsemi 0:098463de4c5d 848 iphdr = (struct ip_hdr *)p->payload;
group-onsemi 0:098463de4c5d 849 LWIP_ASSERT("check that first pbuf can hold struct ip_hdr",
group-onsemi 0:098463de4c5d 850 (p->len >= sizeof(struct ip_hdr)));
group-onsemi 0:098463de4c5d 851
group-onsemi 0:098463de4c5d 852 IPH_TTL_SET(iphdr, ttl);
group-onsemi 0:098463de4c5d 853 IPH_PROTO_SET(iphdr, proto);
group-onsemi 0:098463de4c5d 854 #if CHECKSUM_GEN_IP_INLINE
group-onsemi 0:098463de4c5d 855 chk_sum += LWIP_MAKE_U16(proto, ttl);
group-onsemi 0:098463de4c5d 856 #endif /* CHECKSUM_GEN_IP_INLINE */
group-onsemi 0:098463de4c5d 857
group-onsemi 0:098463de4c5d 858 /* dest cannot be NULL here */
group-onsemi 0:098463de4c5d 859 ip4_addr_copy(iphdr->dest, *dest);
group-onsemi 0:098463de4c5d 860 #if CHECKSUM_GEN_IP_INLINE
group-onsemi 0:098463de4c5d 861 chk_sum += ip4_addr_get_u32(&iphdr->dest) & 0xFFFF;
group-onsemi 0:098463de4c5d 862 chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16;
group-onsemi 0:098463de4c5d 863 #endif /* CHECKSUM_GEN_IP_INLINE */
group-onsemi 0:098463de4c5d 864
group-onsemi 0:098463de4c5d 865 IPH_VHL_SET(iphdr, 4, ip_hlen / 4);
group-onsemi 0:098463de4c5d 866 IPH_TOS_SET(iphdr, tos);
group-onsemi 0:098463de4c5d 867 #if CHECKSUM_GEN_IP_INLINE
group-onsemi 0:098463de4c5d 868 chk_sum += LWIP_MAKE_U16(tos, iphdr->_v_hl);
group-onsemi 0:098463de4c5d 869 #endif /* CHECKSUM_GEN_IP_INLINE */
group-onsemi 0:098463de4c5d 870 IPH_LEN_SET(iphdr, htons(p->tot_len));
group-onsemi 0:098463de4c5d 871 #if CHECKSUM_GEN_IP_INLINE
group-onsemi 0:098463de4c5d 872 chk_sum += iphdr->_len;
group-onsemi 0:098463de4c5d 873 #endif /* CHECKSUM_GEN_IP_INLINE */
group-onsemi 0:098463de4c5d 874 IPH_OFFSET_SET(iphdr, 0);
group-onsemi 0:098463de4c5d 875 IPH_ID_SET(iphdr, htons(ip_id));
group-onsemi 0:098463de4c5d 876 #if CHECKSUM_GEN_IP_INLINE
group-onsemi 0:098463de4c5d 877 chk_sum += iphdr->_id;
group-onsemi 0:098463de4c5d 878 #endif /* CHECKSUM_GEN_IP_INLINE */
group-onsemi 0:098463de4c5d 879 ++ip_id;
group-onsemi 0:098463de4c5d 880
group-onsemi 0:098463de4c5d 881 if (src == NULL) {
group-onsemi 0:098463de4c5d 882 ip4_addr_copy(iphdr->src, *IP4_ADDR_ANY);
group-onsemi 0:098463de4c5d 883 } else {
group-onsemi 0:098463de4c5d 884 /* src cannot be NULL here */
group-onsemi 0:098463de4c5d 885 ip4_addr_copy(iphdr->src, *src);
group-onsemi 0:098463de4c5d 886 }
group-onsemi 0:098463de4c5d 887
group-onsemi 0:098463de4c5d 888 #if CHECKSUM_GEN_IP_INLINE
group-onsemi 0:098463de4c5d 889 chk_sum += ip4_addr_get_u32(&iphdr->src) & 0xFFFF;
group-onsemi 0:098463de4c5d 890 chk_sum += ip4_addr_get_u32(&iphdr->src) >> 16;
group-onsemi 0:098463de4c5d 891 chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF);
group-onsemi 0:098463de4c5d 892 chk_sum = (chk_sum >> 16) + chk_sum;
group-onsemi 0:098463de4c5d 893 chk_sum = ~chk_sum;
group-onsemi 0:098463de4c5d 894 IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) {
group-onsemi 0:098463de4c5d 895 iphdr->_chksum = (u16_t)chk_sum; /* network order */
group-onsemi 0:098463de4c5d 896 }
group-onsemi 0:098463de4c5d 897 #if LWIP_CHECKSUM_CTRL_PER_NETIF
group-onsemi 0:098463de4c5d 898 else {
group-onsemi 0:098463de4c5d 899 IPH_CHKSUM_SET(iphdr, 0);
group-onsemi 0:098463de4c5d 900 }
group-onsemi 0:098463de4c5d 901 #endif /* LWIP_CHECKSUM_CTRL_PER_NETIF*/
group-onsemi 0:098463de4c5d 902 #else /* CHECKSUM_GEN_IP_INLINE */
group-onsemi 0:098463de4c5d 903 IPH_CHKSUM_SET(iphdr, 0);
group-onsemi 0:098463de4c5d 904 #if CHECKSUM_GEN_IP
group-onsemi 0:098463de4c5d 905 IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) {
group-onsemi 0:098463de4c5d 906 IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen));
group-onsemi 0:098463de4c5d 907 }
group-onsemi 0:098463de4c5d 908 #endif /* CHECKSUM_GEN_IP */
group-onsemi 0:098463de4c5d 909 #endif /* CHECKSUM_GEN_IP_INLINE */
group-onsemi 0:098463de4c5d 910 } else {
group-onsemi 0:098463de4c5d 911 /* IP header already included in p */
group-onsemi 0:098463de4c5d 912 iphdr = (struct ip_hdr *)p->payload;
group-onsemi 0:098463de4c5d 913 ip4_addr_copy(dest_addr, iphdr->dest);
group-onsemi 0:098463de4c5d 914 dest = &dest_addr;
group-onsemi 0:098463de4c5d 915 }
group-onsemi 0:098463de4c5d 916
group-onsemi 0:098463de4c5d 917 IP_STATS_INC(ip.xmit);
group-onsemi 0:098463de4c5d 918
group-onsemi 0:098463de4c5d 919 LWIP_DEBUGF(IP_DEBUG, ("ip4_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], (u16_t)netif->num));
group-onsemi 0:098463de4c5d 920 ip4_debug_print(p);
group-onsemi 0:098463de4c5d 921
group-onsemi 0:098463de4c5d 922 #if ENABLE_LOOPBACK
group-onsemi 0:098463de4c5d 923 if (ip4_addr_cmp(dest, netif_ip4_addr(netif))
group-onsemi 0:098463de4c5d 924 #if !LWIP_HAVE_LOOPIF
group-onsemi 0:098463de4c5d 925 || ip4_addr_isloopback(dest)
group-onsemi 0:098463de4c5d 926 #endif /* !LWIP_HAVE_LOOPIF */
group-onsemi 0:098463de4c5d 927 ) {
group-onsemi 0:098463de4c5d 928 /* Packet to self, enqueue it for loopback */
group-onsemi 0:098463de4c5d 929 LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()"));
group-onsemi 0:098463de4c5d 930 return netif_loop_output(netif, p);
group-onsemi 0:098463de4c5d 931 }
group-onsemi 0:098463de4c5d 932 #if LWIP_MULTICAST_TX_OPTIONS
group-onsemi 0:098463de4c5d 933 if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) {
group-onsemi 0:098463de4c5d 934 netif_loop_output(netif, p);
group-onsemi 0:098463de4c5d 935 }
group-onsemi 0:098463de4c5d 936 #endif /* LWIP_MULTICAST_TX_OPTIONS */
group-onsemi 0:098463de4c5d 937 #endif /* ENABLE_LOOPBACK */
group-onsemi 0:098463de4c5d 938 #if IP_FRAG
group-onsemi 0:098463de4c5d 939 /* don't fragment if interface has mtu set to 0 [loopif] */
group-onsemi 0:098463de4c5d 940 if (netif->mtu && (p->tot_len > netif->mtu)) {
group-onsemi 0:098463de4c5d 941 return ip4_frag(p, netif, dest);
group-onsemi 0:098463de4c5d 942 }
group-onsemi 0:098463de4c5d 943 #endif /* IP_FRAG */
group-onsemi 0:098463de4c5d 944
group-onsemi 0:098463de4c5d 945 LWIP_DEBUGF(IP_DEBUG, ("ip4_output_if: call netif->output()\n"));
group-onsemi 0:098463de4c5d 946 return netif->output(netif, p, dest);
group-onsemi 0:098463de4c5d 947 }
group-onsemi 0:098463de4c5d 948
group-onsemi 0:098463de4c5d 949 /**
group-onsemi 0:098463de4c5d 950 * Simple interface to ip_output_if. It finds the outgoing network
group-onsemi 0:098463de4c5d 951 * interface and calls upon ip_output_if to do the actual work.
group-onsemi 0:098463de4c5d 952 *
group-onsemi 0:098463de4c5d 953 * @param p the packet to send (p->payload points to the data, e.g. next
group-onsemi 0:098463de4c5d 954 protocol header; if dest == IP_HDRINCL, p already includes an IP
group-onsemi 0:098463de4c5d 955 header and p->payload points to that IP header)
group-onsemi 0:098463de4c5d 956 * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
group-onsemi 0:098463de4c5d 957 * IP address of the netif used to send is used as source address)
group-onsemi 0:098463de4c5d 958 * @param dest the destination IP address to send the packet to
group-onsemi 0:098463de4c5d 959 * @param ttl the TTL value to be set in the IP header
group-onsemi 0:098463de4c5d 960 * @param tos the TOS value to be set in the IP header
group-onsemi 0:098463de4c5d 961 * @param proto the PROTOCOL to be set in the IP header
group-onsemi 0:098463de4c5d 962 *
group-onsemi 0:098463de4c5d 963 * @return ERR_RTE if no route is found
group-onsemi 0:098463de4c5d 964 * see ip_output_if() for more return values
group-onsemi 0:098463de4c5d 965 */
group-onsemi 0:098463de4c5d 966 err_t
group-onsemi 0:098463de4c5d 967 ip4_output(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest,
group-onsemi 0:098463de4c5d 968 u8_t ttl, u8_t tos, u8_t proto)
group-onsemi 0:098463de4c5d 969 {
group-onsemi 0:098463de4c5d 970 struct netif *netif;
group-onsemi 0:098463de4c5d 971
group-onsemi 0:098463de4c5d 972 LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p);
group-onsemi 0:098463de4c5d 973
group-onsemi 0:098463de4c5d 974 if ((netif = ip4_route_src(dest, src)) == NULL) {
group-onsemi 0:098463de4c5d 975 LWIP_DEBUGF(IP_DEBUG, ("ip4_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
group-onsemi 0:098463de4c5d 976 ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
group-onsemi 0:098463de4c5d 977 IP_STATS_INC(ip.rterr);
group-onsemi 0:098463de4c5d 978 return ERR_RTE;
group-onsemi 0:098463de4c5d 979 }
group-onsemi 0:098463de4c5d 980
group-onsemi 0:098463de4c5d 981 return ip4_output_if(p, src, dest, ttl, tos, proto, netif);
group-onsemi 0:098463de4c5d 982 }
group-onsemi 0:098463de4c5d 983
group-onsemi 0:098463de4c5d 984 #if LWIP_NETIF_HWADDRHINT
group-onsemi 0:098463de4c5d 985 /** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint
group-onsemi 0:098463de4c5d 986 * before calling ip_output_if.
group-onsemi 0:098463de4c5d 987 *
group-onsemi 0:098463de4c5d 988 * @param p the packet to send (p->payload points to the data, e.g. next
group-onsemi 0:098463de4c5d 989 protocol header; if dest == IP_HDRINCL, p already includes an IP
group-onsemi 0:098463de4c5d 990 header and p->payload points to that IP header)
group-onsemi 0:098463de4c5d 991 * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
group-onsemi 0:098463de4c5d 992 * IP address of the netif used to send is used as source address)
group-onsemi 0:098463de4c5d 993 * @param dest the destination IP address to send the packet to
group-onsemi 0:098463de4c5d 994 * @param ttl the TTL value to be set in the IP header
group-onsemi 0:098463de4c5d 995 * @param tos the TOS value to be set in the IP header
group-onsemi 0:098463de4c5d 996 * @param proto the PROTOCOL to be set in the IP header
group-onsemi 0:098463de4c5d 997 * @param addr_hint address hint pointer set to netif->addr_hint before
group-onsemi 0:098463de4c5d 998 * calling ip_output_if()
group-onsemi 0:098463de4c5d 999 *
group-onsemi 0:098463de4c5d 1000 * @return ERR_RTE if no route is found
group-onsemi 0:098463de4c5d 1001 * see ip_output_if() for more return values
group-onsemi 0:098463de4c5d 1002 */
group-onsemi 0:098463de4c5d 1003 err_t
group-onsemi 0:098463de4c5d 1004 ip4_output_hinted(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest,
group-onsemi 0:098463de4c5d 1005 u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)
group-onsemi 0:098463de4c5d 1006 {
group-onsemi 0:098463de4c5d 1007 struct netif *netif;
group-onsemi 0:098463de4c5d 1008 err_t err;
group-onsemi 0:098463de4c5d 1009
group-onsemi 0:098463de4c5d 1010 LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p);
group-onsemi 0:098463de4c5d 1011
group-onsemi 0:098463de4c5d 1012 if ((netif = ip4_route_src(dest, src)) == NULL) {
group-onsemi 0:098463de4c5d 1013 LWIP_DEBUGF(IP_DEBUG, ("ip4_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
group-onsemi 0:098463de4c5d 1014 ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));
group-onsemi 0:098463de4c5d 1015 IP_STATS_INC(ip.rterr);
group-onsemi 0:098463de4c5d 1016 return ERR_RTE;
group-onsemi 0:098463de4c5d 1017 }
group-onsemi 0:098463de4c5d 1018
group-onsemi 0:098463de4c5d 1019 NETIF_SET_HWADDRHINT(netif, addr_hint);
group-onsemi 0:098463de4c5d 1020 err = ip4_output_if(p, src, dest, ttl, tos, proto, netif);
group-onsemi 0:098463de4c5d 1021 NETIF_SET_HWADDRHINT(netif, NULL);
group-onsemi 0:098463de4c5d 1022
group-onsemi 0:098463de4c5d 1023 return err;
group-onsemi 0:098463de4c5d 1024 }
group-onsemi 0:098463de4c5d 1025 #endif /* LWIP_NETIF_HWADDRHINT*/
group-onsemi 0:098463de4c5d 1026
group-onsemi 0:098463de4c5d 1027 #if IP_DEBUG
group-onsemi 0:098463de4c5d 1028 /* Print an IP header by using LWIP_DEBUGF
group-onsemi 0:098463de4c5d 1029 * @param p an IP packet, p->payload pointing to the IP header
group-onsemi 0:098463de4c5d 1030 */
group-onsemi 0:098463de4c5d 1031 void
group-onsemi 0:098463de4c5d 1032 ip4_debug_print(struct pbuf *p)
group-onsemi 0:098463de4c5d 1033 {
group-onsemi 0:098463de4c5d 1034 struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
group-onsemi 0:098463de4c5d 1035
group-onsemi 0:098463de4c5d 1036 LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));
group-onsemi 0:098463de4c5d 1037 LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
group-onsemi 0:098463de4c5d 1038 LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" | 0x%02"X16_F" | %5"U16_F" | (v, hl, tos, len)\n",
group-onsemi 0:098463de4c5d 1039 (u16_t)IPH_V(iphdr),
group-onsemi 0:098463de4c5d 1040 (u16_t)IPH_HL(iphdr),
group-onsemi 0:098463de4c5d 1041 (u16_t)IPH_TOS(iphdr),
group-onsemi 0:098463de4c5d 1042 ntohs(IPH_LEN(iphdr))));
group-onsemi 0:098463de4c5d 1043 LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
group-onsemi 0:098463de4c5d 1044 LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" |%"U16_F"%"U16_F"%"U16_F"| %4"U16_F" | (id, flags, offset)\n",
group-onsemi 0:098463de4c5d 1045 ntohs(IPH_ID(iphdr)),
group-onsemi 0:098463de4c5d 1046 (u16_t)(ntohs(IPH_OFFSET(iphdr)) >> 15 & 1),
group-onsemi 0:098463de4c5d 1047 (u16_t)(ntohs(IPH_OFFSET(iphdr)) >> 14 & 1),
group-onsemi 0:098463de4c5d 1048 (u16_t)(ntohs(IPH_OFFSET(iphdr)) >> 13 & 1),
group-onsemi 0:098463de4c5d 1049 (u16_t)(ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)));
group-onsemi 0:098463de4c5d 1050 LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
group-onsemi 0:098463de4c5d 1051 LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | 0x%04"X16_F" | (ttl, proto, chksum)\n",
group-onsemi 0:098463de4c5d 1052 (u16_t)IPH_TTL(iphdr),
group-onsemi 0:098463de4c5d 1053 (u16_t)IPH_PROTO(iphdr),
group-onsemi 0:098463de4c5d 1054 ntohs(IPH_CHKSUM(iphdr))));
group-onsemi 0:098463de4c5d 1055 LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
group-onsemi 0:098463de4c5d 1056 LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n",
group-onsemi 0:098463de4c5d 1057 ip4_addr1_16(&iphdr->src),
group-onsemi 0:098463de4c5d 1058 ip4_addr2_16(&iphdr->src),
group-onsemi 0:098463de4c5d 1059 ip4_addr3_16(&iphdr->src),
group-onsemi 0:098463de4c5d 1060 ip4_addr4_16(&iphdr->src)));
group-onsemi 0:098463de4c5d 1061 LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
group-onsemi 0:098463de4c5d 1062 LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\n",
group-onsemi 0:098463de4c5d 1063 ip4_addr1_16(&iphdr->dest),
group-onsemi 0:098463de4c5d 1064 ip4_addr2_16(&iphdr->dest),
group-onsemi 0:098463de4c5d 1065 ip4_addr3_16(&iphdr->dest),
group-onsemi 0:098463de4c5d 1066 ip4_addr4_16(&iphdr->dest)));
group-onsemi 0:098463de4c5d 1067 LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
group-onsemi 0:098463de4c5d 1068 }
group-onsemi 0:098463de4c5d 1069 #endif /* IP_DEBUG */
group-onsemi 0:098463de4c5d 1070
group-onsemi 0:098463de4c5d 1071 #endif /* LWIP_IPV4 */