2002-10-19 12:59:30 +00:00
/*
2003-01-08 10:09:39 +00:00
* Copyright ( c ) 2001 - 2003 Swedish Institute of Computer Science .
2002-10-19 12:59:30 +00:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without modification ,
* are permitted provided that the following conditions are met :
*
* 1. Redistributions of source code must retain the above copyright notice ,
* this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright notice ,
* this list of conditions and the following disclaimer in the documentation
* and / or other materials provided with the distribution .
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR IMPLIED
* WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL ,
* EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS
* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN
* CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE .
*
* This file is part of the lwIP TCP / IP stack .
*
* Author : Adam Dunkels < adam @ sics . se >
*
*/
/*-----------------------------------------------------------------------------------*/
/* ip.c
*
* This is the code for the IP layer .
*
*/
/*-----------------------------------------------------------------------------------*/
2003-02-21 16:43:46 +00:00
# include "lwip/opt.h"
2002-10-19 12:59:30 +00:00
# include "lwip/def.h"
# include "lwip/mem.h"
# include "lwip/ip.h"
2002-11-22 15:46:50 +00:00
# include "lwip/ip_frag.h"
2002-10-19 12:59:30 +00:00
# include "lwip/inet.h"
# include "lwip/netif.h"
# include "lwip/icmp.h"
# include "lwip/udp.h"
# include "lwip/tcp.h"
# include "lwip/stats.h"
# include "arch/perf.h"
2003-02-10 21:58:34 +00:00
# include "lwip/snmp.h"
2002-10-19 12:59:30 +00:00
# if LWIP_DHCP
2003-02-20 08:41:59 +00:00
# include "lwip / dhcp.h"
2002-10-19 12:59:30 +00:00
# endif /* LWIP_DHCP */
/*-----------------------------------------------------------------------------------*/
/* ip_init:
*
* Initializes the IP layer .
*/
/*-----------------------------------------------------------------------------------*/
void
ip_init ( void )
{
}
/*-----------------------------------------------------------------------------------*/
/* ip_lookup:
*
* An experimental feature that will be changed in future versions . Do
* not depend on it yet . . .
*/
/*-----------------------------------------------------------------------------------*/
# ifdef LWIP_DEBUG
u8_t
ip_lookup ( void * header , struct netif * inp )
{
struct ip_hdr * iphdr ;
iphdr = header ;
2003-01-30 10:18:40 +00:00
/* not IP v4? */
2003-05-01 13:24:01 +00:00
if ( IPH_V ( iphdr ) ! = 4 ) {
2002-10-19 12:59:30 +00:00
return 0 ;
}
/* Immediately accept/decline packets that are fragments or has
options . */
# if IP_REASSEMBLY == 0
2003-05-01 13:24:01 +00:00
/* if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
2002-10-19 12:59:30 +00:00
return 0 ;
} */
# endif /* IP_REASSEMBLY == 0 */
# if IP_OPTIONS == 0
2003-05-01 13:24:01 +00:00
if ( IPH_HL ( iphdr ) ! = 5 ) {
2002-10-19 12:59:30 +00:00
return 0 ;
}
# endif /* IP_OPTIONS == 0 */
2003-05-01 13:24:01 +00:00
switch ( IPH_PROTO ( iphdr ) ) {
2002-10-19 12:59:30 +00:00
# if LWIP_UDP > 0
case IP_PROTO_UDP :
return udp_lookup ( iphdr , inp ) ;
# endif /* LWIP_UDP */
# if LWIP_TCP > 0
case IP_PROTO_TCP :
return 1 ;
# endif /* LWIP_TCP */
case IP_PROTO_ICMP :
return 1 ;
default :
return 0 ;
}
}
# endif /* LWIP_DEBUG */
/*-----------------------------------------------------------------------------------*/
/* ip_route:
*
* Finds the appropriate network interface for a given IP address . It
* searches the list of network interfaces linearly . A match is found
* if the masked IP address of the network interface equals the masked
* IP address given to the function .
*/
/*-----------------------------------------------------------------------------------*/
struct netif *
ip_route ( struct ip_addr * dest )
{
struct netif * netif ;
2003-01-30 10:18:40 +00:00
/* iterate through netifs */
2002-10-19 12:59:30 +00:00
for ( netif = netif_list ; netif ! = NULL ; netif = netif - > next ) {
2003-01-30 10:18:40 +00:00
/* network mask matches? */
2003-05-01 13:24:01 +00:00
if ( ip_addr_maskcmp ( dest , & ( netif - > ip_addr ) , & ( netif - > netmask ) ) ) {
2003-01-30 10:18:40 +00:00
/* return netif on which to forward IP packet */
2002-10-19 12:59:30 +00:00
return netif ;
}
}
2003-01-30 10:18:40 +00:00
/* no matching netif found, use default netif */
2002-10-19 12:59:30 +00:00
return netif_default ;
}
# if IP_FORWARD
/*-----------------------------------------------------------------------------------*/
/* ip_forward:
*
* Forwards an IP packet . It finds an appropriate route for the
* packet , decrements the TTL value of the packet , adjusts the
* checksum and outputs the packet on the appropriate interface .
*/
/*-----------------------------------------------------------------------------------*/
static void
ip_forward ( struct pbuf * p , struct ip_hdr * iphdr , struct netif * inp )
{
2002-12-18 11:53:26 +00:00
struct netif * netif ;
2002-10-19 12:59:30 +00:00
PERF_START ;
2003-01-30 10:18:40 +00:00
/* Find network interface where to forward this IP packet to. */
netif = ip_route ( ( struct ip_addr * ) & ( iphdr - > dest ) ) ;
2003-05-01 13:24:01 +00:00
if ( netif = = NULL ) {
2002-10-19 12:59:30 +00:00
DEBUGF ( IP_DEBUG , ( " ip_forward: no forwarding route for 0x%lx found \n " ,
2003-02-18 21:14:16 +00:00
iphdr - > dest . addr ) ) ;
2002-11-21 10:32:19 +00:00
snmp_inc_ipnoroutes ( ) ;
2002-10-19 12:59:30 +00:00
return ;
}
2003-01-30 10:18:40 +00:00
/* Do not forward packets onto the same network interface on which
2002-10-19 12:59:30 +00:00
they arrived . */
2003-05-01 13:24:01 +00:00
if ( netif = = inp ) {
2003-01-30 10:18:40 +00:00
DEBUGF ( IP_DEBUG , ( " ip_forward: not bouncing packets back on incoming interface. \n " ) ) ;
2002-11-21 10:32:19 +00:00
snmp_inc_ipnoroutes ( ) ;
2002-10-19 12:59:30 +00:00
return ;
}
2003-01-30 10:18:40 +00:00
/* decrement TTL */
2002-10-19 12:59:30 +00:00
IPH_TTL_SET ( iphdr , IPH_TTL ( iphdr ) - 1 ) ;
2003-01-30 10:18:40 +00:00
/* send ICMP if TTL == 0 */
2003-05-01 13:24:01 +00:00
if ( IPH_TTL ( iphdr ) = = 0 ) {
2002-10-19 12:59:30 +00:00
/* Don't send ICMP messages in response to ICMP messages */
2003-05-01 13:24:01 +00:00
if ( IPH_PROTO ( iphdr ) ! = IP_PROTO_ICMP ) {
2002-10-19 12:59:30 +00:00
icmp_time_exceeded ( p , ICMP_TE_TTL ) ;
2002-11-21 10:32:19 +00:00
snmp_inc_icmpouttimeexcds ( ) ;
2002-10-19 12:59:30 +00:00
}
return ;
}
2003-01-30 10:18:40 +00:00
/* Incrementally update the IP checksum. */
2003-05-01 13:24:01 +00:00
if ( IPH_CHKSUM ( iphdr ) > = htons ( 0xffff - 0x100 ) ) {
2002-10-19 12:59:30 +00:00
IPH_CHKSUM_SET ( iphdr , IPH_CHKSUM ( iphdr ) + htons ( 0x100 ) + 1 ) ;
} else {
IPH_CHKSUM_SET ( iphdr , IPH_CHKSUM ( iphdr ) + htons ( 0x100 ) ) ;
}
DEBUGF ( IP_DEBUG , ( " ip_forward: forwarding packet to 0x%lx \n " ,
2003-02-18 21:14:16 +00:00
iphdr - > dest . addr ) ) ;
2002-10-19 12:59:30 +00:00
# ifdef IP_STATS
2002-12-18 12:49:01 +00:00
+ + lwip_stats . ip . fw ;
+ + lwip_stats . ip . xmit ;
2002-10-19 12:59:30 +00:00
# endif /* IP_STATS */
2002-11-21 10:32:19 +00:00
snmp_inc_ipforwdatagrams ( ) ;
2002-10-19 12:59:30 +00:00
PERF_STOP ( " ip_forward " ) ;
2003-01-30 10:18:40 +00:00
/* transmit pbuf on chosen interface */
2002-10-19 12:59:30 +00:00
netif - > output ( netif , p , ( struct ip_addr * ) & ( iphdr - > dest ) ) ;
}
# endif /* IP_FORWARD */
/*-----------------------------------------------------------------------------------*/
/* ip_input:
*
* This function is called by the network interface device driver when
* an IP packet is received . The function does the basic checks of the
* IP header such as packet size being at least larger than the header
* size etc . If the packet was not destined for us , the packet is
* forwarded ( using ip_forward ) . The IP checksum is always checked .
*
* Finally , the packet is sent to the upper layer protocol input function .
*/
/*-----------------------------------------------------------------------------------*/
err_t
ip_input ( struct pbuf * p , struct netif * inp ) {
static struct ip_hdr * iphdr ;
static struct netif * netif ;
2003-01-30 10:18:40 +00:00
static u16_t iphdrlen ;
2002-10-19 12:59:30 +00:00
# ifdef IP_STATS
2002-12-18 12:49:01 +00:00
+ + lwip_stats . ip . recv ;
2002-10-19 12:59:30 +00:00
# endif /* IP_STATS */
2003-02-10 13:47:47 +00:00
snmp_inc_ipinreceives ( ) ;
2002-10-19 12:59:30 +00:00
/* identify the IP header */
iphdr = p - > payload ;
2003-05-01 13:24:01 +00:00
if ( IPH_V ( iphdr ) ! = 4 ) {
2003-03-25 12:59:42 +00:00
DEBUGF ( IP_DEBUG | 1 , ( " IP packet dropped due to bad version number %d \n " , IPH_V ( iphdr ) ) ) ;
2002-10-19 12:59:30 +00:00
# if IP_DEBUG
ip_debug_print ( p ) ;
# endif /* IP_DEBUG */
pbuf_free ( p ) ;
# ifdef IP_STATS
2002-12-18 12:49:01 +00:00
+ + lwip_stats . ip . err ;
+ + lwip_stats . ip . drop ;
2002-10-19 12:59:30 +00:00
# endif /* IP_STATS */
2002-11-21 10:32:19 +00:00
snmp_inc_ipunknownprotos ( ) ;
2002-10-19 12:59:30 +00:00
return ERR_OK ;
}
2003-01-30 10:18:40 +00:00
/* obtain IP header length in number of 32-bit words */
iphdrlen = IPH_HL ( iphdr ) ;
/* calculate IP header length in bytes */
iphdrlen * = 4 ;
/* header length exceeds first pbuf length? */
2003-05-01 13:24:01 +00:00
if ( iphdrlen > p - > len ) {
2003-03-25 12:59:42 +00:00
DEBUGF ( IP_DEBUG | 2 , ( " IP header (len %u) does not fit in first pbuf (len %u), IP packet droppped. \n " ,
2003-01-30 10:18:40 +00:00
iphdrlen , p - > len ) ) ;
/* free (drop) packet pbufs */
2002-10-19 12:59:30 +00:00
pbuf_free ( p ) ;
# ifdef IP_STATS
2002-12-18 12:49:01 +00:00
+ + lwip_stats . ip . lenerr ;
+ + lwip_stats . ip . drop ;
2002-10-19 12:59:30 +00:00
# endif /* IP_STATS */
2002-11-21 10:32:19 +00:00
snmp_inc_ipindiscards ( ) ;
2002-10-19 12:59:30 +00:00
return ERR_OK ;
}
/* verify checksum */
2003-05-01 13:24:01 +00:00
if ( inet_chksum ( iphdr , iphdrlen ) ! = 0 ) {
2002-10-19 12:59:30 +00:00
2003-03-25 12:59:42 +00:00
DEBUGF ( IP_DEBUG | 2 , ( " Checksum (0x%x) failed, IP packet dropped. \n " , inet_chksum ( iphdr , iphdrlen ) ) ) ;
2002-10-19 12:59:30 +00:00
# if IP_DEBUG
ip_debug_print ( p ) ;
# endif /* IP_DEBUG */
pbuf_free ( p ) ;
# ifdef IP_STATS
2002-12-18 12:49:01 +00:00
+ + lwip_stats . ip . chkerr ;
+ + lwip_stats . ip . drop ;
2002-10-19 12:59:30 +00:00
# endif /* IP_STATS */
2002-11-21 10:32:19 +00:00
snmp_inc_ipindiscards ( ) ;
2002-10-19 12:59:30 +00:00
return ERR_OK ;
}
/* Trim pbuf. This should have been done at the netif layer,
but we ' ll do it anyway just to be sure that its done . */
pbuf_realloc ( p , ntohs ( IPH_LEN ( iphdr ) ) ) ;
/* is this packet for us? */
for ( netif = netif_list ; netif ! = NULL ; netif = netif - > next ) {
DEBUGF ( IP_DEBUG , ( " ip_input: iphdr->dest 0x%lx netif->ip_addr 0x%lx (0x%lx, 0x%lx, 0x%lx) \n " ,
2003-02-18 21:14:16 +00:00
iphdr - > dest . addr , netif - > ip_addr . addr ,
iphdr - > dest . addr & netif - > netmask . addr ,
netif - > ip_addr . addr & netif - > netmask . addr ,
iphdr - > dest . addr & ~ ( netif - > netmask . addr ) ) ) ;
2002-10-19 12:59:30 +00:00
2003-01-28 18:24:25 +00:00
/* interface configured? */
2003-05-01 13:24:01 +00:00
if ( ! ip_addr_isany ( & ( netif - > ip_addr ) ) )
2003-01-28 18:24:25 +00:00
{
/* unicast to this interface address? */
2003-05-01 13:24:01 +00:00
if ( ip_addr_cmp ( & ( iphdr - > dest ) , & ( netif - > ip_addr ) ) | |
2003-01-30 10:18:40 +00:00
/* or broadcast matching this interface network address? */
2003-01-28 18:24:25 +00:00
( ip_addr_isbroadcast ( & ( iphdr - > dest ) , & ( netif - > netmask ) ) & &
ip_addr_maskcmp ( & ( iphdr - > dest ) , & ( netif - > ip_addr ) , & ( netif - > netmask ) ) ) | |
/* or restricted broadcast? */
ip_addr_cmp ( & ( iphdr - > dest ) , IP_ADDR_BROADCAST ) ) {
2003-01-30 10:18:40 +00:00
DEBUGF ( IP_DEBUG , ( " ip_input: packet accepted on interface %c%c \n " ,
2003-02-18 21:14:16 +00:00
netif - > name [ 0 ] , netif - > name [ 1 ] ) ) ;
2003-01-28 18:24:25 +00:00
/* break out of for loop */
break ;
}
2002-10-19 12:59:30 +00:00
}
2003-01-30 10:18:40 +00:00
}
2002-10-19 12:59:30 +00:00
# if LWIP_DHCP
2003-01-30 10:18:40 +00:00
/* Pass DHCP messages regardless of destination address. DHCP traffic is addressed
using link layer addressing ( such as Ethernet MAC ) so we must not filter on IP .
According to RFC 1542 section 3.1 .1 , referred by RFC 2131 ) . */
2003-05-01 13:24:01 +00:00
if ( netif = = NULL ) {
2003-01-30 10:18:40 +00:00
/* remote port is DHCP server? */
2003-05-01 13:24:01 +00:00
if ( IPH_PROTO ( iphdr ) = = IP_PROTO_UDP ) {
2003-03-25 12:59:42 +00:00
DEBUGF ( IP_DEBUG | DBG_TRACE | 1 , ( " ip_input: UDP packet to DHCP client port %u \n " ,
2003-03-31 10:32:35 +00:00
ntohs ( ( ( struct udp_hdr * ) ( ( u8_t * ) iphdr + iphdrlen ) ) - > dest ) ) ) ;
2003-01-30 10:18:40 +00:00
if ( ntohs ( ( ( struct udp_hdr * ) ( ( u8_t * ) iphdr + iphdrlen ) ) - > dest ) = = DHCP_CLIENT_PORT ) {
2003-03-25 12:59:42 +00:00
DEBUGF ( IP_DEBUG | DBG_TRACE | 1 , ( " ip_input: DHCP packet accepted. \n " ) ) ;
2003-01-30 10:18:40 +00:00
netif = inp ;
2003-01-28 18:24:25 +00:00
}
}
}
2003-01-30 10:18:40 +00:00
# endif /* LWIP_DHCP */
2003-02-18 21:14:16 +00:00
/* packet not for us? */
2003-05-01 13:24:01 +00:00
if ( netif = = NULL ) {
2002-10-19 12:59:30 +00:00
/* packet not for us, route or discard */
2003-03-25 12:59:42 +00:00
DEBUGF ( IP_DEBUG | DBG_TRACE | 1 , ( " ip_input: packet not for us. \n " ) ) ;
2002-10-19 12:59:30 +00:00
# if IP_FORWARD
2003-01-30 10:18:40 +00:00
/* non-broadcast packet? */
2003-05-01 13:24:01 +00:00
if ( ! ip_addr_isbroadcast ( & ( iphdr - > dest ) , & ( inp - > netmask ) ) ) {
2003-01-30 10:18:40 +00:00
/* try to forward IP packet on (other) interfaces */
2002-10-19 12:59:30 +00:00
ip_forward ( p , iphdr , inp ) ;
}
2002-11-21 10:32:19 +00:00
else
2002-10-19 12:59:30 +00:00
# endif /* IP_FORWARD */
2002-11-21 10:32:19 +00:00
{
snmp_inc_ipindiscards ( ) ;
}
2002-10-19 12:59:30 +00:00
pbuf_free ( p ) ;
return ERR_OK ;
}
# if IP_REASSEMBLY
2003-05-01 13:24:01 +00:00
if ( ( IPH_OFFSET ( iphdr ) & htons ( IP_OFFMASK | IP_MF ) ) ! = 0 ) {
2003-02-18 21:14:16 +00:00
DEBUGF ( IP_DEBUG , ( " IP packet is a fragment (id=0x%04x tot_len=%u len=%u MF=%u offset=%u), calling ip_reass() \n " , ntohs ( IPH_ID ( iphdr ) ) , p - > tot_len , ntohs ( IPH_LEN ( iphdr ) ) , ! ! ( IPH_OFFSET ( iphdr ) & htons ( IP_MF ) ) , ( ntohs ( IPH_OFFSET ( iphdr ) ) & IP_OFFMASK ) * 8 ) ) ;
2002-10-19 12:59:30 +00:00
p = ip_reass ( p ) ;
2003-05-01 13:24:01 +00:00
if ( p = = NULL ) {
2002-10-19 12:59:30 +00:00
return ERR_OK ;
}
iphdr = p - > payload ;
}
# else /* IP_REASSEMBLY */
2003-05-01 13:24:01 +00:00
if ( ( IPH_OFFSET ( iphdr ) & htons ( IP_OFFMASK | IP_MF ) ) ! = 0 ) {
2002-10-19 12:59:30 +00:00
pbuf_free ( p ) ;
2003-03-25 12:59:42 +00:00
DEBUGF ( IP_DEBUG | 2 , ( " IP packet dropped since it was fragmented (0x%x) (while IP_REASSEMBLY == 0). \n " ,
2003-02-18 21:14:16 +00:00
ntohs ( IPH_OFFSET ( iphdr ) ) ) ) ;
2002-10-19 12:59:30 +00:00
# ifdef IP_STATS
2002-12-18 12:49:01 +00:00
+ + lwip_stats . ip . opterr ;
+ + lwip_stats . ip . drop ;
2002-10-19 12:59:30 +00:00
# endif /* IP_STATS */
2002-11-21 10:32:19 +00:00
snmp_inc_ipunknownprotos ( ) ;
2002-10-19 12:59:30 +00:00
return ERR_OK ;
}
# endif /* IP_REASSEMBLY */
# if IP_OPTIONS == 0
2003-03-25 12:59:42 +00:00
if ( iphdrlen > IP_HLEN ) {
DEBUGF ( IP_DEBUG | 2 , ( " IP packet dropped since there were IP options (while IP_OPTIONS == 0). \n " ) ) ;
2002-10-19 12:59:30 +00:00
pbuf_free ( p ) ;
# ifdef IP_STATS
2002-12-18 12:49:01 +00:00
+ + lwip_stats . ip . opterr ;
+ + lwip_stats . ip . drop ;
2002-10-19 12:59:30 +00:00
# endif /* IP_STATS */
2002-11-21 10:32:19 +00:00
snmp_inc_ipunknownprotos ( ) ;
2002-10-19 12:59:30 +00:00
return ERR_OK ;
}
# endif /* IP_OPTIONS == 0 */
/* send to upper layers */
# if IP_DEBUG
DEBUGF ( IP_DEBUG , ( " ip_input: \n " ) ) ;
ip_debug_print ( p ) ;
DEBUGF ( IP_DEBUG , ( " ip_input: p->len %d p->tot_len %d \n " , p - > len , p - > tot_len ) ) ;
# endif /* IP_DEBUG */
2003-05-01 13:24:01 +00:00
switch ( IPH_PROTO ( iphdr ) ) {
2002-10-19 12:59:30 +00:00
# if LWIP_UDP > 0
case IP_PROTO_UDP :
2002-11-21 10:32:19 +00:00
snmp_inc_ipindelivers ( ) ;
2002-10-19 12:59:30 +00:00
udp_input ( p , inp ) ;
break ;
# endif /* LWIP_UDP */
# if LWIP_TCP > 0
case IP_PROTO_TCP :
2002-11-21 10:32:19 +00:00
snmp_inc_ipindelivers ( ) ;
2002-10-19 12:59:30 +00:00
tcp_input ( p , inp ) ;
break ;
# endif /* LWIP_TCP */
case IP_PROTO_ICMP :
2002-11-21 10:32:19 +00:00
snmp_inc_ipindelivers ( ) ;
2002-10-19 12:59:30 +00:00
icmp_input ( p , inp ) ;
break ;
default :
/* send ICMP destination protocol unreachable unless is was a broadcast */
2003-05-01 13:24:01 +00:00
if ( ! ip_addr_isbroadcast ( & ( iphdr - > dest ) , & ( inp - > netmask ) ) & &
2002-10-19 12:59:30 +00:00
! ip_addr_ismulticast ( & ( iphdr - > dest ) ) ) {
p - > payload = iphdr ;
icmp_dest_unreach ( p , ICMP_DUR_PROTO ) ;
}
pbuf_free ( p ) ;
2003-03-25 12:59:42 +00:00
DEBUGF ( IP_DEBUG | 2 , ( " Unsupported transport protocol %d \n " , IPH_PROTO ( iphdr ) ) ) ;
2002-10-19 12:59:30 +00:00
# ifdef IP_STATS
2002-12-18 12:49:01 +00:00
+ + lwip_stats . ip . proterr ;
+ + lwip_stats . ip . drop ;
2002-10-19 12:59:30 +00:00
# endif /* IP_STATS */
2002-11-21 10:32:19 +00:00
snmp_inc_ipunknownprotos ( ) ;
2002-10-19 12:59:30 +00:00
}
return ERR_OK ;
}
/*-----------------------------------------------------------------------------------*/
/* ip_output_if:
*
* Sends an IP packet on a network interface . This function constructs
* the IP header and calculates the IP header checksum . If the source
* IP address is NULL , the IP address of the outgoing network
* interface is filled in as source address .
*/
/*-----------------------------------------------------------------------------------*/
err_t
2003-05-01 13:24:01 +00:00
ip_output_if ( struct pbuf * p , struct ip_addr * src , struct ip_addr * dest ,
2003-02-18 21:14:16 +00:00
u8_t ttl ,
u8_t proto , struct netif * netif )
2002-10-19 12:59:30 +00:00
{
static struct ip_hdr * iphdr ;
static u16_t ip_id = 0 ;
2003-02-10 13:47:47 +00:00
snmp_inc_ipoutrequests ( ) ;
2002-10-19 12:59:30 +00:00
2003-05-01 13:24:01 +00:00
if ( dest ! = IP_HDRINCL ) {
if ( pbuf_header ( p , IP_HLEN ) ) {
2003-03-25 12:59:42 +00:00
DEBUGF ( IP_DEBUG | 2 , ( " ip_output: not enough room for IP header in pbuf \n " ) ) ;
2002-10-19 12:59:30 +00:00
# ifdef IP_STATS
2002-12-18 12:49:01 +00:00
+ + lwip_stats . ip . err ;
2002-10-19 12:59:30 +00:00
# endif /* IP_STATS */
2003-02-10 13:47:47 +00:00
snmp_inc_ipoutdiscards ( ) ;
2002-10-19 12:59:30 +00:00
return ERR_BUF ;
}
iphdr = p - > payload ;
IPH_TTL_SET ( iphdr , ttl ) ;
IPH_PROTO_SET ( iphdr , proto ) ;
ip_addr_set ( & ( iphdr - > dest ) , dest ) ;
IPH_VHLTOS_SET ( iphdr , 4 , IP_HLEN / 4 , 0 ) ;
IPH_LEN_SET ( iphdr , htons ( p - > tot_len ) ) ;
IPH_OFFSET_SET ( iphdr , htons ( IP_DF ) ) ;
IPH_ID_SET ( iphdr , htons ( ip_id ) ) ;
+ + ip_id ;
2003-05-01 13:24:01 +00:00
if ( ip_addr_isany ( src ) ) {
2002-10-19 12:59:30 +00:00
ip_addr_set ( & ( iphdr - > src ) , & ( netif - > ip_addr ) ) ;
} else {
ip_addr_set ( & ( iphdr - > src ) , src ) ;
}
IPH_CHKSUM_SET ( iphdr , 0 ) ;
IPH_CHKSUM_SET ( iphdr , inet_chksum ( iphdr , IP_HLEN ) ) ;
} else {
iphdr = p - > payload ;
dest = & ( iphdr - > dest ) ;
}
2003-02-18 21:14:16 +00:00
# if IP_FRAG
2003-02-06 22:18:56 +00:00
/* don't fragment if interface has mtu set to 0 [loopif] */
if ( netif - > mtu & & ( p - > tot_len > netif - > mtu ) )
2002-11-22 15:46:50 +00:00
return ip_frag ( p , netif , dest ) ;
# endif
2002-10-19 12:59:30 +00:00
# ifdef IP_STATS
2002-12-18 12:49:01 +00:00
lwip_stats . ip . xmit + + ;
2002-10-19 12:59:30 +00:00
# endif /* IP_STATS */
2003-04-01 14:02:50 +00:00
DEBUGF ( IP_DEBUG , ( " ip_output_if: %c%c%u \n " , netif - > name [ 0 ] , netif - > name [ 1 ] , netif - > num ) ) ;
2002-10-19 12:59:30 +00:00
# if IP_DEBUG
ip_debug_print ( p ) ;
# endif /* IP_DEBUG */
2003-01-30 10:18:40 +00:00
DEBUGF ( IP_DEBUG , ( " netif->output() " ) ) ;
2002-10-19 12:59:30 +00:00
return netif - > output ( netif , p , dest ) ;
}
/*-----------------------------------------------------------------------------------*/
/* ip_output:
*
* Simple interface to ip_output_if . It finds the outgoing network
* interface and calls upon ip_output_if to do the actual work .
*/
/*-----------------------------------------------------------------------------------*/
err_t
ip_output ( struct pbuf * p , struct ip_addr * src , struct ip_addr * dest ,
2003-02-18 21:14:16 +00:00
u8_t ttl , u8_t proto )
2002-10-19 12:59:30 +00:00
{
2002-12-18 11:53:26 +00:00
struct netif * netif ;
2002-10-19 12:59:30 +00:00
2003-05-01 13:24:01 +00:00
if ( ( netif = ip_route ( dest ) ) = = NULL ) {
2003-03-25 12:59:42 +00:00
DEBUGF ( IP_DEBUG | 2 , ( " ip_output: No route to 0x%lx \n " , dest - > addr ) ) ;
2002-10-19 12:59:30 +00:00
# ifdef IP_STATS
2002-12-18 12:49:01 +00:00
+ + lwip_stats . ip . rterr ;
2002-10-19 12:59:30 +00:00
# endif /* IP_STATS */
2002-11-21 10:32:19 +00:00
snmp_inc_ipoutdiscards ( ) ;
2002-10-19 12:59:30 +00:00
return ERR_RTE ;
}
2003-05-01 13:24:01 +00:00
return ip_output_if ( p , src , dest , ttl , proto , netif ) ;
2002-10-19 12:59:30 +00:00
}
/*-----------------------------------------------------------------------------------*/
# if IP_DEBUG
void
ip_debug_print ( struct pbuf * p )
{
struct ip_hdr * iphdr = p - > payload ;
u8_t * payload ;
2002-12-19 09:04:58 +00:00
payload = ( u8_t * ) iphdr + IP_HLEN ;
2002-10-19 12:59:30 +00:00
DEBUGF ( IP_DEBUG , ( " IP header: \n " ) ) ;
DEBUGF ( IP_DEBUG , ( " +-------------------------------+ \n " ) ) ;
2003-05-01 08:37:24 +00:00
DEBUGF ( IP_DEBUG , ( " |%2d |%2d | 0x%02x | %5u | (v, hl, tos, len) \n " ,
2003-02-18 21:14:16 +00:00
IPH_V ( iphdr ) ,
IPH_HL ( iphdr ) ,
IPH_TOS ( iphdr ) ,
ntohs ( IPH_LEN ( iphdr ) ) ) ) ;
2002-10-19 12:59:30 +00:00
DEBUGF ( IP_DEBUG , ( " +-------------------------------+ \n " ) ) ;
2003-02-06 22:18:56 +00:00
DEBUGF ( IP_DEBUG , ( " | %5u |%u%u%u| %4u | (id, flags, offset) \n " ,
2003-02-18 21:14:16 +00:00
ntohs ( IPH_ID ( iphdr ) ) ,
ntohs ( IPH_OFFSET ( iphdr ) ) > > 15 & 1 ,
ntohs ( IPH_OFFSET ( iphdr ) ) > > 14 & 1 ,
ntohs ( IPH_OFFSET ( iphdr ) ) > > 13 & 1 ,
ntohs ( IPH_OFFSET ( iphdr ) ) & IP_OFFMASK ) ) ;
2002-10-19 12:59:30 +00:00
DEBUGF ( IP_DEBUG , ( " +-------------------------------+ \n " ) ) ;
2003-05-01 08:37:24 +00:00
DEBUGF ( IP_DEBUG , ( " | %3u | %3u | 0x%04x | (ttl, proto, chksum) \n " ,
2003-02-18 21:14:16 +00:00
IPH_TTL ( iphdr ) ,
IPH_PROTO ( iphdr ) ,
ntohs ( IPH_CHKSUM ( iphdr ) ) ) ) ;
2002-10-19 12:59:30 +00:00
DEBUGF ( IP_DEBUG , ( " +-------------------------------+ \n " ) ) ;
DEBUGF ( IP_DEBUG , ( " | %3ld | %3ld | %3ld | %3ld | (src) \n " ,
2003-02-18 21:14:16 +00:00
ntohl ( iphdr - > src . addr ) > > 24 & 0xff ,
ntohl ( iphdr - > src . addr ) > > 16 & 0xff ,
ntohl ( iphdr - > src . addr ) > > 8 & 0xff ,
ntohl ( iphdr - > src . addr ) & 0xff ) ) ;
2002-10-19 12:59:30 +00:00
DEBUGF ( IP_DEBUG , ( " +-------------------------------+ \n " ) ) ;
DEBUGF ( IP_DEBUG , ( " | %3ld | %3ld | %3ld | %3ld | (dest) \n " ,
2003-02-18 21:14:16 +00:00
ntohl ( iphdr - > dest . addr ) > > 24 & 0xff ,
ntohl ( iphdr - > dest . addr ) > > 16 & 0xff ,
ntohl ( iphdr - > dest . addr ) > > 8 & 0xff ,
ntohl ( iphdr - > dest . addr ) & 0xff ) ) ;
2002-10-19 12:59:30 +00:00
DEBUGF ( IP_DEBUG , ( " +-------------------------------+ \n " ) ) ;
}
# endif /* IP_DEBUG */
/*-----------------------------------------------------------------------------------*/