www.pudn.com > TCPmodbushy.rar > ip.c


/* @file 
 * 
 * This is the IP layer implementation for incoming and outgoing IP traffic. 
 *  
 * @see ip_frag.c 
 * 
 */ 
/* 
 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 
 * 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  
 * 
 */ 
 
#include "o:/lwip/opt.h" 
 
#include "o:/lwip/def.h" 
#include "o:/lwip/mem.h" 
#include "o:/IPV4/lwip/ip.h" 
#include "o:/IPV4/lwip/ip_frag.h" 
#include "o:/IPV4/lwip/inet.h" 
#include "o:/lwip/netif.h" 
#include "o:/IPV4/lwip/icmp.h" 
//#include "o:/lwip/raw.h" 
#include "o:/lwip/udp.h" 
#include "o:/lwip/tcp.h" 
 
#include "o:/lwip/stats.h" 
 
#include "o:/arch/perf.h" 
 
#include "o:/netif/ethernetif.h" 
 
#include "o:/lwip/snmp.h" 
#if LWIP_DHCP 
#  include "o:/lwip/dhcp.h" 
#endif /* LWIP_DHCP */ 
 
 
/** 
 * Initializes the IP layer. 
 */ 
 
//void 
//ip_init(void) 
//{ 
  /* no initializations as of yet */ 
//} 
 
/** 
 * 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) 
 
/** 
 * 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 xdata *p) { 
  struct ip_hdr xdata *iphdr; 
  u8_t iphdrlen; 
  unsigned char IsForMe = 0; 
 
  IP_STATS_INC(ip.recv); 
  snmp_inc_ipinreceives(); 
 
  /* identify the IP header */ 
  iphdr = p->payload; 
  if (IPH_V(iphdr) != 4) { 
    LWIP_DEBUGF(IP_DEBUG | 1, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr))); 
    pbuf_free(p); 
    snmp_inc_ipunknownprotos(); 
    return ERR_OK; 
  } 
  /* 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? */ 
  if (iphdrlen > p->len) { 
    LWIP_DEBUGF(IP_DEBUG | 2, ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet droppped.\n", 
      iphdrlen, p->len)); 
    /* free (drop) packet pbufs */ 
    pbuf_free(p); 
    IP_STATS_INC(ip.lenerr); 
    IP_STATS_INC(ip.drop); 
    snmp_inc_ipindiscards(); 
    return ERR_OK; 
  } 
 
  /* verify checksum */ 
#if CHECKSUM_CHECK_IP 
  if (inet_chksum(iphdr, iphdrlen) != 0) { 
 
    LWIP_DEBUGF(IP_DEBUG | 2, ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdrlen))); 
    ip_debug_print(p); 
    pbuf_free(p); 
    IP_STATS_INC(ip.chkerr); 
    IP_STATS_INC(ip.drop); 
    snmp_inc_ipindiscards(); 
    return ERR_OK; 
  } 
#endif 
 
  /* 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))); 
 
  /* interface is up and configured? */ 
  if ((netif_is_up()) && (!ip_addr_isany(&(netif->ip_addr)))) 
  { 
    /* unicast to this interface address? */ 
    if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) || 
       /* or broadcast on this interface network address? */ 
       ip_addr_isbroadcast(&(iphdr->dest)))  
    { 
       /* break out of for loop */ 
	   IsForMe = 1; 
    } 
  } 
 
#if LWIP_DHCP 
  /* 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). 
   */ 
  if (IsForMe == 0) { 
    /* remote port is DHCP server? */ 
    if (IPH_PROTO(iphdr) == IP_PROTO_UDP) { 
      //ip_input: UDP packet to DHCP client port 
      if (ntohs(((struct udp_hdr xdata *)((u8_t xdata *)iphdr + iphdrlen))->dest) == DHCP_CLIENT_PORT) { 
        //ip_input: DHCP packet accepted 
        IsForMe = 1; 
      } 
    } 
  } 
#endif /* LWIP_DHCP */ 
  /* packet not for us? */ 
  if (IsForMe == 0) { 
    /* packet not for us, route or discard */ 
    LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: packet not for us.\n")); 
    { 
      snmp_inc_ipindiscards(); 
    } 
    pbuf_free(p); 
    return ERR_OK; 
  } 
  /* packet consists of multiple fragments? */ 
  if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) { 
#if IP_REASSEMBLY /* packet fragment reassembly code present? */ 
    /* reassemble the packet*/ 
    p = ip_reass(p); 
    /* packet not fully reassembled yet? */ 
    if (p == NULL) { 
      return ERR_OK; 
    } 
    iphdr = p->payload; 
#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */ 
    pbuf_free(p); 
    return ERR_OK; 
#endif /* IP_REASSEMBLY */ 
  } 
 
  /* send to upper layers */ 
  switch (IPH_PROTO(iphdr)) { 
#if LWIP_UDP 
  case IP_PROTO_UDP: 
  case IP_PROTO_UDPLITE: 
    snmp_inc_ipindelivers(); 
    udp_input(p); 
    break; 
#endif /* LWIP_UDP */ 
#if LWIP_TCP 
  case IP_PROTO_TCP: 
    snmp_inc_ipindelivers(); 
    tcp_input(p); 
    break; 
#endif /* LWIP_TCP */ 
  case IP_PROTO_ICMP: 
    snmp_inc_ipindelivers(); 
    icmp_input(p); 
    break; 
  default: 
    /* send ICMP destination protocol unreachable unless is was a broadcast */ 
    if (!ip_addr_isbroadcast(&(iphdr->dest))) { 
      p->payload = iphdr; 
      icmp_dest_unreach(p, ICMP_DUR_PROTO); 
    } 
    pbuf_free(p); 
 
    LWIP_DEBUGF(IP_DEBUG | 2, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr))); 
 
    IP_STATS_INC(ip.proterr); 
    IP_STATS_INC(ip.drop); 
    snmp_inc_ipunknownprotos(); 
  } 
  return ERR_OK; 
} 
 
/** 
 * 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 ip_output_if(struct pbuf xdata *p, struct ip_addr xdata *src, struct ip_addr xdata *dest, 
             u8_t ttl, u8_t proto) 
{ 
  struct ip_hdr xdata *iphdr; 
static  u16_t data ip_id = 0; 
 
  snmp_inc_ipoutrequests(); 
 
  if (dest != IP_HDRINCL) { 
    if (pbuf_header(p, IP_HLEN)) { 
      LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n")); 
 
      IP_STATS_INC(ip.err); 
      snmp_inc_ipoutdiscards(); 
      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); 
    IPH_LEN_SET(iphdr, htons(p->tot_len)); 
    IPH_OFFSET_SET(iphdr, htons(IP_DF)); 
    IPH_ID_SET(iphdr, htons(ip_id)); 
    ++ip_id; 
 
    if (ip_addr_isany(src)) { 
      ip_addr_set(&(iphdr->src), &(netif->ip_addr)); 
    } else { 
      ip_addr_set(&(iphdr->src), src); 
    } 
 
    IPH_CHKSUM_SET(iphdr, 0); 
#if CHECKSUM_GEN_IP 
    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); 
#endif 
  } else { 
    iphdr = p->payload; 
    dest = &(iphdr->dest); 
  } 
 
  IP_STATS_INC(ip.xmit); 
 
  LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num)); 
  ip_debug_print(p); 
 
  LWIP_DEBUGF(IP_DEBUG, ("netif->output()")); 
 
//  return netif->output(netif, p, dest); 
    return ( ethernetif_output(p, dest) ); 
}