コード例 #1
0
ファイル: sr_router.c プロジェクト: c2birlar/yah
/*Does all handling of incoming ARP packets, returns 1 if successful*/
int handle_ARP_packet(struct sr_instance* sr, 
		      uint8_t* packet,
		      int len, 
		      char* interface){
  int minLenARP = sizeof(struct sr_ethernet_hdr) + sizeof(struct sr_arp_hdr); 
  if (len < minLenARP){
      fprintf(stderr, "Failed to access ARP header, too small\n");
      drop_packet = 1;
      //return;
    }
    if (drop_packet == 0){
      if (destinedToRouter(dest_ip)){
	sr_ethernet_hdr_t* ethernet_hdr = (sr_ethernet_hdr_t*)packet;
	sr_arp_hdr_t* arp_header = (sr_arp_hdr_t*)(packet + (uint8_t) eth_size);

	if (ntohl(arp_header->ar_op) == arp_op_reply){//We have a ARP reply
	  //process reply
	  //move entries from ARP request queue to ARP cache
	  struct sr_arpreq* req;
	  req = sr_arpcache_insert(&(sr->cache), arp_header->ar_sha,
				   ntohl(arp_header->ar_sip));
	  if (req!=NULL){
	     struct sr_packet* traverser = req->packets;
	     while(traverser != NULL){
	       //normal IP forward, no errors detected
	       //change old contents
	       struct sr_arpentry *arp_entry;
	       arp_entry = sr_arpcache_lookup(&(sr->cache),dest_ip);
	       sr_ip_hdr_t* ip_header = (sr_ip_hdr_t*)(packet + (uint8_t) eth_size);
	       sr_ethernet_hdr_t* out_eth = (sr_ethernet_hdr_t*)packet;
	       uint16_t modCksum = cksum(ip_header, sizeof(struct sr_ip_hdr));
	       int ret = ip_forward(sr,packet,len,out_eth,arp_entry->mac,
				    dest_ip, modCksum,interface);
	       if (ret!= 0){
		 fprintf(stderr, "Didn't send ip packet properly\n");

	       }

	       traverser = traverser->next;
	     }
	     sr_arpreq_destroy(&(sr->cache), req);
	  }
	}else{
	  //process ARP request and send reply 
	  //(they want our MAC address) so sends reply packet
	  int ret =  arp_send(sr,packet,len,
			      ethernet_hdr,arp_header,dest_ip);
	  if (ret!= 0){
	    fprintf(stderr, "Didn't send arp packet properly\n");

	  }
	}
      }else{
	//pass
	//forward packet
      }
    }
    return 1;
}
コード例 #2
0
ファイル: ip.c プロジェクト: alexanderkatovsky/bir
void ip_handle_incoming_packet(struct sr_packet * packet)
{
    struct ip * ip_hdr = IP_HDR(packet);

    if(ip_hdr->ip_sum != checksum_ipheader(ip_hdr))
    {
        printf("\nchecksums differ %x, %x\n", ip_hdr->ip_sum, checksum_ipheader(ip_hdr));
    }
    else if(ip_hdr->ip_v != 4)
    {
        printf("\nip version is %d; only accepting 4\n",ip_hdr->ip_v);
    }
    else
    {
        if(dhcp_packet(packet))
        {
            dhcp_handle_incoming(packet);
        }
        /* if packet is not for one of our interfaces then forward */
        else if(!interface_list_ip_exists(ROUTER(packet->sr)->iflist, ip_hdr->ip_dst.s_addr) &&
                ntohl(ip_hdr->ip_dst.s_addr) != OSPF_AllSPFRouters)
        {
            if(ip_hdr->ip_ttl <= 1)
            {
                icmp_send_time_exceeded(packet);
            }
            else
            {
                if(ip_hdr->ip_p == IP_P_TCP || ip_hdr->ip_p == IP_P_UDP)
                {
                    tcp_handle_incoming_not_for_us(packet);
                }
                else
                {
                    ip_forward(packet);
                }
            }
        }
        else
        {
            switch(ip_hdr->ip_p)
            {
            case IP_P_ICMP:
                icmp_handle_incoming_packet(packet);
                break;
            case IP_P_TCP: case IP_P_UDP:
                tcp_handle_incoming_for_us(packet);
                break;
            case IP_P_OSPF:
                ospf_handle_incoming_packet(packet);
                break;
            default:
                icmp_send_port_unreachable(packet);
            }
        }
    }    
}
コード例 #3
0
ファイル: ip_input.c プロジェクト: tongsucn/ip_stack
int ip_rcv(void *data)
{
	ip_fragment_t *frag = data;

	if (iphdr_check(data) == -1)
		return -1;
	else if (ip_dest_check(frag))
		return ip_defrag(frag);
	else
		return ip_forward(frag);
}
コード例 #4
0
ファイル: ip_modelnet.c プロジェクト: arjunroy/modelnet-core
/*
 * [forward_packet] called when emulation of all hops in path is complete 
 */
static void
forward_packet(struct packet *pkt)
{
    struct mbuf    *m;

    if (pkt->m == NULL) {
	    /*
	     * return remote packet home when cached 
	     */
	    remote_hop(pkt, pkt->cachehost);	    
	    return;
    }

    if (pkt->cachehost) { /* re-mbuf-headerizing packet */
        MGETHDR(m, M_DONTWAIT, MT_DATA);
        if (!m) {
            /*
             * pkt and pkt->m freed on return 
             */
            printf("forward_packet: unable to allocate mhdr!\n");
            return;
        }
        MN_DUMP_PKT(pkt);
        m->m_pkthdr.rcvif = NULL;       /* unknown */
        m->m_nextpkt = 0;
        m->m_pkthdr.len = pkt->info.len;
        m->m_len = 0;
        m_cat(m, pkt->m);
        m = m_pullup(m, sizeof(struct ip));
        pkt->m = m;
    }

    if (xcp_initialized){  /* see code in filter_ipinput */
	    xcp_set_xcpinfo(pkt);
    }

    Dprintf(("forward_packet: calling ip_forward\n"), MN_P_PKTS);

    ip_forward(pkt->m, 0, NULL);
    /*
     * we lose this mbuf, IP output owns it now 
     */
    pkt->m = NULL;
    pktcount[(ticks / hz) % (sizeof(pktcount) / sizeof(*pktcount))]++;
}
コード例 #5
0
ファイル: IFFI.c プロジェクト: calvinmetcalf/intercal
void ick_iffi_interpreter_one_iteration(void)
{
	funge_cell opcode;
	opcode = fungespace_get(&iffiIP->position);

	if (setting_trace_level > 8) {
		fprintf(stderr, "x=%" FUNGECELLPRI " y=%" FUNGECELLPRI
				": %c (%" FUNGECELLPRI ")\n",
				iffiIP->position.x, iffiIP->position.y, (char)opcode, opcode);
		stack_print_top(iffiIP->stack);
	} else if (setting_trace_level > 3) {
		fprintf(stderr, "x=%" FUNGECELLPRI " y=%" FUNGECELLPRI
				": %c (%" FUNGECELLPRI ")\n",
				iffiIP->position.x, iffiIP->position.y, (char)opcode, opcode);
	} else if (setting_trace_level > 2)
		fprintf(stderr, "%c", (char)opcode);

	execute_instruction(opcode, iffiIP);
	if (iffiIP->needMove)
		ip_forward(iffiIP);
	else
		iffiIP->needMove = true;
}
コード例 #6
0
ファイル: ip_input.c プロジェクト: Kefir0192/embox
static int ip_rcv(struct sk_buff *skb, struct net_device *dev) {
	net_device_stats_t *stats = &dev->stats;
	const struct net_proto *nproto;
	iphdr_t *iph = ip_hdr(skb);
	__u16 old_check;
	size_t ip_len;
	int optlen;
	sk_buff_t *complete_skb;

	/**
	 *   RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.
	 *   Is the datagram acceptable?
	 *   1.  Length at least the size of an ip header
	 *   2.  Version of 4
	 *   3.  Checksums correctly. [Speed optimisation for later, skip loopback checksums]
	 *   4.  Doesn't have a bogus length
	 */
	if (skb->len < dev->hdr_len + IP_MIN_HEADER_SIZE
			|| IP_HEADER_SIZE(iph) < IP_MIN_HEADER_SIZE
			|| skb->len < dev->hdr_len + IP_HEADER_SIZE(iph)) {
		DBG(printk("ip_rcv: invalid IPv4 header length\n"));
		stats->rx_length_errors++;
		skb_free(skb);
		return 0; /* error: invalid header length */
	}


	if (iph->version != 4) {
		DBG(printk("ip_rcv: invalid IPv4 version\n"));
		stats->rx_err++;
		skb_free(skb);
		return 0; /* error: not ipv4 */
	}

	old_check = iph->check;
	ip_set_check_field(iph);
	if (old_check != iph->check) {
		DBG(printk("ip_rcv: invalid checksum %hx(%hx)\n",
				ntohs(old_check), ntohs(iph->check)));
		stats->rx_crc_errors++;
		skb_free(skb);
		return 0; /* error: invalid crc */
	}

	ip_len = ntohs(iph->tot_len);
	if (ip_len < IP_HEADER_SIZE(iph)
			|| skb->len < dev->hdr_len + ip_len) {
		DBG(printk("ip_rcv: invalid IPv4 length\n"));
		stats->rx_length_errors++;
		skb_free(skb);
		return 0; /* error: invalid length */
	}

	/* Setup transport layer (L4) header */
	skb->h.raw = skb->nh.raw + IP_HEADER_SIZE(iph);

	/* Validating */
	if (0 != nf_test_skb(NF_CHAIN_INPUT, NF_TARGET_ACCEPT, skb)) {
		DBG(printk("ip_rcv: dropped by input netfilter\n"));
		stats->rx_dropped++;
		skb_free(skb);
		return 0; /* error: dropped */
	}

	/* Forwarding */
	assert(skb->dev);
	assert(inetdev_get_by_dev(skb->dev));
	if (inetdev_get_by_dev(skb->dev)->ifa_address != 0) {
		/**
		 * FIXME
		 * This check needed for BOOTP protocol
		 * disable forwarding if interface is not set yet
		 */
		/**
		 * Check the destination address, and if it doesn't match
		 * any of own addresses, retransmit packet according to the routing table.
		 */
		if (!ip_is_local(iph->daddr, IP_LOCAL_BROADCAST)) {
			if (0 != nf_test_skb(NF_CHAIN_FORWARD, NF_TARGET_ACCEPT, skb)) {
				DBG(printk("ip_rcv: dropped by forward netfilter\n"));
				stats->rx_dropped++;
				skb_free(skb);
				return 0; /* error: dropped */
			}
			return ip_forward(skb);
		}
	}

	memset(skb->cb, 0, sizeof(skb->cb));
	optlen = IP_HEADER_SIZE(iph) - IP_MIN_HEADER_SIZE;
	if (optlen > 0) {
		/* NOTE : maybe it'd be better to copy skb here,
		 * 'cause options may cause modifications
		 * but smart people who wrote linux kernel
		 * say that this is extremely rarely needed
		 */
		ip_options_t *opts = (ip_options_t*)(skb->cb);

		memset(skb->cb, 0, sizeof(skb->cb));
		opts->optlen = optlen;
		if (ip_options_compile(skb, opts)) {
			DBG(printk("ip_rcv: invalid options\n"));
			stats->rx_err++;
			skb_free(skb);
			return 0; /* error: bad ops */
		}
		if (ip_options_handle_srr(skb)) {
			DBG(printk("ip_rcv: can't handle options\n"));
			stats->tx_err++;
			skb_free(skb);
			return 0; /* error: can't handle ops */
		}
	}

	/* It's very useful for us to have complete packet even for forwarding
	 * (we may apply any filter, we may perform NAT etc),
	 * but it'll break routing if different parts of a fragmented
	 * packet will use different routes. So they can't be assembled.
	 * See RFC 1812 for details
	 */
	if (ntohs(skb->nh.iph->frag_off) & (IP_MF | IP_OFFSET)) {
		if ((complete_skb = ip_defrag(skb)) == NULL) {
			if (skb == NULL) {
				return 0; /* error: */
			}
			return 0;
		} else {
			skb = complete_skb;
			iph = ip_hdr(complete_skb);
		}
	}

	/* When a packet is received, it is passed to any raw sockets
	 * which have been bound to its protocol or to socket with concrete protocol */
	raw_rcv(skb);

	nproto = net_proto_lookup(ETH_P_IP, iph->proto);
	if (nproto != NULL) {
		return nproto->handle(skb);
	}

	DBG(printk("ip_rcv: unknown protocol\n"));
	skb_free(skb);
	return 0; /* error: nobody wants this packet */
}
コード例 #7
0
ファイル: ip.c プロジェクト: ChijunShen/wildfire_stm32_iso
/**
 * 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.
 * 
 * @param p the received IP packet (p->payload points to IP header)
 * @param inp the netif on which this packet was received
 * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't
 *         processed, but currently always returns ERR_OK)
 */
err_t
ip_input(struct pbuf *p, struct netif *inp)
{
  struct ip_hdr *iphdr;
  struct netif *netif;
  u16_t iphdr_hlen;
  u16_t iphdr_len;
#if LWIP_DHCP
  int check_ip_src=1;
#endif /* LWIP_DHCP */

  IP_STATS_INC(ip.recv);
  snmp_inc_ipinreceives();

  /* identify the IP header */
  iphdr = p->payload;
  if (IPH_V(iphdr) != 4) {
    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
    ip_debug_print(p);
    pbuf_free(p);
    IP_STATS_INC(ip.err);
    IP_STATS_INC(ip.drop);
    snmp_inc_ipinhdrerrors();
    return ERR_OK;
  }

  /* obtain IP header length in number of 32-bit words */
  iphdr_hlen = IPH_HL(iphdr);
  /* calculate IP header length in bytes */
  iphdr_hlen *= 4;
  /* obtain ip length in bytes */
  iphdr_len = ntohs(IPH_LEN(iphdr));

  /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
  if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
    if (iphdr_hlen > p->len) {
      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
        ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
        iphdr_hlen, p->len));
    }
    if (iphdr_len > p->tot_len) {
      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
        ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n",
        iphdr_len, p->tot_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, iphdr_hlen) != 0) {

    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
      ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
    ip_debug_print(p);
    pbuf_free(p);
    IP_STATS_INC(ip.chkerr);
    IP_STATS_INC(ip.drop);
    snmp_inc_ipinhdrerrors();
    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, iphdr_len);

  /* match packet against an interface, i.e. is this packet for us? */
#if LWIP_IGMP
  if (ip_addr_ismulticast(&(iphdr->dest))) {
    if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &(iphdr->dest)))) {
      netif = inp;
    } else {
      netif = NULL;
    }
  } else
#endif /* LWIP_IGMP */
  {
    /* start trying with inp. if that's not acceptable, start walking the
       list of configured netifs.
       'first' is used as a boolean to mark whether we started walking the list */
    int first = 1;
    netif = inp;
    do {
      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",
          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)));

      /* interface is up and configured? */
      if ((netif_is_up(netif)) && (!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), netif)) {
          LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
              netif->name[0], netif->name[1]));
          /* break out of for loop */
          break;
        }
      }
      if (first) {
        first = 0;
        netif = netif_list;
      } else {
        netif = netif->next;
      }
      if (netif == inp) {
        netif = netif->next;
      }
    } while(netif != NULL);
  }

#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 (netif == NULL) {
    /* remote port is DHCP server? */
    if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
        ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest)));
      if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest) == DHCP_CLIENT_PORT) {
        LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n"));
        netif = inp;
        check_ip_src = 0;
      }
    }
  }
#endif /* LWIP_DHCP */

  /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */
#if LWIP_DHCP
  /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */
  if (check_ip_src && (iphdr->src.addr != 0))
#endif /* LWIP_DHCP */
  {  if ((ip_addr_isbroadcast(&(iphdr->src), inp)) ||
         (ip_addr_ismulticast(&(iphdr->src)))) {
      /* packet source is not valid */
      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n"));
      /* free (drop) packet pbufs */
      pbuf_free(p);
      IP_STATS_INC(ip.drop);
      snmp_inc_ipinaddrerrors();
      snmp_inc_ipindiscards();
      return ERR_OK;
    }
  }

  /* packet not for us? */
  if (netif == NULL) {
    /* packet not for us, route or discard */
    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n"));
#if IP_FORWARD
    /* non-broadcast packet? */
    if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) {
      /* try to forward IP packet on (other) interfaces */
      ip_forward(p, iphdr, inp);
    } else
#endif /* IP_FORWARD */
    {
      snmp_inc_ipinaddrerrors();
      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? */
    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 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));
    /* 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);
    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
      ntohs(IPH_OFFSET(iphdr))));
    IP_STATS_INC(ip.opterr);
    IP_STATS_INC(ip.drop);
    /* unsupported protocol feature */
    snmp_inc_ipinunknownprotos();
    return ERR_OK;
#endif /* IP_REASSEMBLY */
  }

#if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */

#if LWIP_IGMP
  /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */
  if((iphdr_hlen > IP_HLEN &&  (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {
#else
  if (iphdr_hlen > IP_HLEN) {
#endif /* LWIP_IGMP */
    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
    pbuf_free(p);
    IP_STATS_INC(ip.opterr);
    IP_STATS_INC(ip.drop);
    /* unsupported protocol feature */
    snmp_inc_ipinunknownprotos();
    return ERR_OK;
  }
#endif /* IP_OPTIONS_ALLOWED == 0 */

  /* send to upper layers */
  LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n"));
  ip_debug_print(p);
  LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));

  current_netif = inp;
  current_header = iphdr;

#if LWIP_RAW
  /* raw input did not eat the packet? */
  if (raw_input(p, inp) == 0)
#endif /* LWIP_RAW */
  {

    switch (IPH_PROTO(iphdr)) {
#if LWIP_UDP
    case IP_PROTO_UDP:
#if LWIP_UDPLITE
    case IP_PROTO_UDPLITE:
#endif /* LWIP_UDPLITE */
      snmp_inc_ipindelivers();
      udp_input(p, inp);
      break;
#endif /* LWIP_UDP */
#if LWIP_TCP
    case IP_PROTO_TCP:
      snmp_inc_ipindelivers();
      tcp_input(p, inp);
      break;
#endif /* LWIP_TCP */
#if LWIP_ICMP
    case IP_PROTO_ICMP:
      snmp_inc_ipindelivers();
      icmp_input(p, inp);
      break;
#endif /* LWIP_ICMP */
#if LWIP_IGMP
    case IP_PROTO_IGMP:
      igmp_input(p,inp,&(iphdr->dest));
      break;
#endif /* LWIP_IGMP */
    default:
#if LWIP_ICMP
      /* send ICMP destination protocol unreachable unless is was a broadcast */
      if (!ip_addr_isbroadcast(&(iphdr->dest), inp) &&
          !ip_addr_ismulticast(&(iphdr->dest))) {
        p->payload = iphdr;
        icmp_dest_unreach(p, ICMP_DUR_PROTO);
      }
#endif /* LWIP_ICMP */
      pbuf_free(p);

      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));

      IP_STATS_INC(ip.proterr);
      IP_STATS_INC(ip.drop);
      snmp_inc_ipinunknownprotos();
    }
  }

  current_netif = NULL;
  current_header = NULL;

  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.
 * If the destination IP address is IP_HDRINCL, p is assumed to already
 * include an IP header and p->payload points to it instead of the data.
 *
 * @param p the packet to send (p->payload points to the data, e.g. next
            protocol header; if dest == IP_HDRINCL, p already includes an IP
            header and p->payload points to that IP header)
 * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
 *         IP  address of the netif used to send is used as source address)
 * @param dest the destination IP address to send the packet to
 * @param ttl the TTL value to be set in the IP header
 * @param tos the TOS value to be set in the IP header
 * @param proto the PROTOCOL to be set in the IP header
 * @param netif the netif on which to send this packet
 * @return ERR_OK if the packet was sent OK
 *         ERR_BUF if p doesn't have enough space for IP/LINK headers
 *         returns errors returned by netif->output
 *
 * @note ip_id: RFC791 "some host may be able to simply use
 *  unique identifiers independent of destination"
 */
err_t
ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
             u8_t ttl, u8_t tos,
             u8_t proto, struct netif *netif)
{
#if IP_OPTIONS_SEND
  return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0);
}

/**
 * Same as ip_output_if() but with the possibility to include IP options:
 *
 * @ param ip_options pointer to the IP options, copied into the IP header
 * @ param optlen length of ip_options
 */
err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
       u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
       u16_t optlen)
{
#endif /* IP_OPTIONS_SEND */
  struct ip_hdr *iphdr;
  static u16_t ip_id = 0;

  snmp_inc_ipoutrequests();

  /* Should the IP header be generated or is it already included in p? */
  if (dest != IP_HDRINCL) {
    u16_t ip_hlen = IP_HLEN;
#if IP_OPTIONS_SEND
    u16_t optlen_aligned = 0;
    if (optlen != 0) {
      /* round up to a multiple of 4 */
      optlen_aligned = ((optlen + 3) & ~3);
      ip_hlen += optlen_aligned;
      /* First write in the IP options */
      if (pbuf_header(p, optlen_aligned)) {
        LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output_if_opt: not enough room for IP options in pbuf\n"));
        IP_STATS_INC(ip.err);
        snmp_inc_ipoutdiscards();
        return ERR_BUF;
      }
      MEMCPY(p->payload, ip_options, optlen);
      if (optlen < optlen_aligned) {
        /* zero the remaining bytes */
        memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen);
      }
    }
#endif /* IP_OPTIONS_SEND */
    /* generate IP header */
    if (pbuf_header(p, IP_HLEN)) {
      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("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;
    LWIP_ASSERT("check that first pbuf can hold struct ip_hdr",
               (p->len >= sizeof(struct ip_hdr)));

    IPH_TTL_SET(iphdr, ttl);
    IPH_PROTO_SET(iphdr, proto);

    ip_addr_set(&(iphdr->dest), dest);

    IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos);
    IPH_LEN_SET(iphdr, htons(p->tot_len));
    IPH_OFFSET_SET(iphdr, 0);
    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 {
    /* IP header already included in p */
    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);

#if ENABLE_LOOPBACK
  if (ip_addr_cmp(dest, &netif->ip_addr)) {
    /* Packet to self, enqueue it for loopback */
    LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()"));
    return netif_loop_output(netif, p, dest);
  }
#endif /* ENABLE_LOOPBACK */
#if IP_FRAG
  /* don't fragment if interface has mtu set to 0 [loopif] */
  if (netif->mtu && (p->tot_len > netif->mtu)) {
    return ip_frag(p,netif,dest);
  }
#endif

  LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
  return netif->output(netif, p, dest);
}

/**
 * Simple interface to ip_output_if. It finds the outgoing network
 * interface and calls upon ip_output_if to do the actual work.
 *
 * @param p the packet to send (p->payload points to the data, e.g. next
            protocol header; if dest == IP_HDRINCL, p already includes an IP
            header and p->payload points to that IP header)
 * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
 *         IP  address of the netif used to send is used as source address)
 * @param dest the destination IP address to send the packet to
 * @param ttl the TTL value to be set in the IP header
 * @param tos the TOS value to be set in the IP header
 * @param proto the PROTOCOL to be set in the IP header
 *
 * @return ERR_RTE if no route is found
 *         see ip_output_if() for more return values
 */
err_t
ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
          u8_t ttl, u8_t tos, u8_t proto)
{
  struct netif *netif;

  if ((netif = ip_route(dest)) == NULL) {
    LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));
    IP_STATS_INC(ip.rterr);
    return ERR_RTE;
  }

  return ip_output_if(p, src, dest, ttl, tos, proto, netif);
}

#if LWIP_NETIF_HWADDRHINT
/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint
 *  before calling ip_output_if.
 *
 * @param p the packet to send (p->payload points to the data, e.g. next
            protocol header; if dest == IP_HDRINCL, p already includes an IP
            header and p->payload points to that IP header)
 * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
 *         IP  address of the netif used to send is used as source address)
 * @param dest the destination IP address to send the packet to
 * @param ttl the TTL value to be set in the IP header
 * @param tos the TOS value to be set in the IP header
 * @param proto the PROTOCOL to be set in the IP header
 * @param addr_hint address hint pointer set to netif->addr_hint before
 *        calling ip_output_if()
 *
 * @return ERR_RTE if no route is found
 *         see ip_output_if() for more return values
 */
err_t
ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
          u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)
{
  struct netif *netif;
  err_t err;

  if ((netif = ip_route(dest)) == NULL) {
    LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));
    IP_STATS_INC(ip.rterr);
    return ERR_RTE;
  }

  netif->addr_hint = addr_hint;
  err = ip_output_if(p, src, dest, ttl, tos, proto, netif);
  netif->addr_hint = NULL;

  return err;
}
#endif /* LWIP_NETIF_HWADDRHINT*/

#if IP_DEBUG
/* Print an IP header by using LWIP_DEBUGF
 * @param p an IP packet, p->payload pointing to the IP header
 */
void
ip_debug_print(struct pbuf *p)
{
  struct ip_hdr *iphdr = p->payload;
  u8_t *payload;

  payload = (u8_t *)iphdr + IP_HLEN;

  LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));
  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
  LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" |  0x%02"X16_F" |     %5"U16_F"     | (v, hl, tos, len)\n",
                    IPH_V(iphdr),
                    IPH_HL(iphdr),
                    IPH_TOS(iphdr),
                    ntohs(IPH_LEN(iphdr))));
  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
  LWIP_DEBUGF(IP_DEBUG, ("|    %5"U16_F"      |%"U16_F"%"U16_F"%"U16_F"|    %4"U16_F"   | (id, flags, offset)\n",
                    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));
  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |    0x%04"X16_F"     | (ttl, proto, chksum)\n",
                    IPH_TTL(iphdr),
                    IPH_PROTO(iphdr),
                    ntohs(IPH_CHKSUM(iphdr))));
  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (src)\n",
                    ip4_addr1(&iphdr->src),
                    ip4_addr2(&iphdr->src),
                    ip4_addr3(&iphdr->src),
                    ip4_addr4(&iphdr->src)));
  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (dest)\n",
                    ip4_addr1(&iphdr->dest),
                    ip4_addr2(&iphdr->dest),
                    ip4_addr3(&iphdr->dest),
                    ip4_addr4(&iphdr->dest)));
  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
}
コード例 #8
0
ファイル: sr_router.c プロジェクト: c2birlar/yah
/*Handles all incoming IP packets, returns 1 if successful*/
int handle_IP_packet(struct sr_instance* sr, 
		      uint8_t* packet,
		      int len, 
		      char* interface){
  int normal_ip_forward = 0;
  int icmp_send = 0;
  struct sr_ethernet_hdr* ethernet_hdr =  (sr_ethernet_hdr_t*)packet;
  sr_ip_hdr_t* ip_header = (sr_ip_hdr_t*)(packet + (uint8_t) eth_size);
  int minLenIP = eth_size + sizeof(struct sr_ip_hdr);
  
  //1. Basic Standards: Make  sure it meets min len of packet,
  //   check checksum correct; set drop_packet if necessary
  if (len < minLenIP){
    fprintf(stderr, "Failed to access IP header, too small\n");
    drop_packet = 1;
    //return;
  }
  uint16_t initCksum = cksum(ip_header, sizeof(struct sr_ip_hdr));
  if (ntohl(ip_header->ip_sum) != initCksum){
    drop_packet = 1;
    icmp_type_code = -1;
  }

  //2. Figure out if either drop packet, or ICMP neccessary, 
  //   or just IP forward
  if (drop_packet == 0){
    dest_ip = ntohl(ip_header->ip_dst);
    if (destinedToRouter(dest_ip)){
      //destined for us
      icmp_type_code = icmp(sr,packet);
      if (icmp_type_code == -1){
	//unknown
	drop_packet = 1;
      }else{
	icmp_send = 1;
      }
    }else{//not destined to us
      icmp_type_code = icmp(sr,packet);
      if (icmp_type_code == -1){
	normal_ip_forward = 1;//good to forward
      }else{
	icmp_send = 1;
      }
    }
  }
   
  //if going to ip forward -> recompute ttl
  if (normal_ip_forward == 1){
    //ttl--, recompute checksum over modifified header
    ip_header->ip_ttl = htonl(ntohs(ip_header->ip_ttl) - 1);
    modCksum = cksum(ip_header, sizeof(struct sr_ip_hdr));
  }

  //if not dropping
  if (drop_packet == 0){
    //check arp cache for mac address
    struct sr_arpentry *arp_entry;
    arp_entry = sr_arpcache_lookup(&(sr->cache),
				   htonl(ip_header->ip_dst));

    //Means we found the ARP entry
    if (arp_entry != NULL){
      uint8_t dest_mac[ETHER_ADDR_LEN];
      convertMAC(dest_mac, arp_entry->mac);

      //use this to send to next hop ip, free entry
      free(arp_entry);
	
      //ICMP
      if (icmp_send == 1){
	//send back to source IP
	//Create Ethernet header, IP header and ICMP header
	int buff_size = minLenIP 
	  + sizeof(struct sr_icmp_t3_hdr) + ICMP_DATA_SIZE;//plus more?
	uint8_t* buf = (uint8_t*)malloc(buff_size);
	  
	setIcmpHeaders(buf, icmp_type_code, sr);
	sendPacket(sr,buf, interface, buff_size); //????????

      }else{
	if (normal_ip_forward == 1){
	  //means no errors detected; thus send packet
	  int ret = ip_forward(sr,packet,len,ethernet_hdr,
			       dest_mac,dest_ip,modCksum,interface);
	  if (ret!= 0){
	    fprintf(stderr, "Didn't send ip packet properly\n");
	    //return;
	  }
	}
      }
    }else{
      //entry not found ARP cache
      struct sr_arpreq* req1;
      req1 = (struct sr_arpreq*)(arpcache_queuereq(htonl(dest_ip),packet,len));
      free(req1);
      //rest done by arp_cahce. functions
      //ARP reply process code handles this
    }
  }//else packets are ignored (drop packet)
  return 1;
}
コード例 #9
0
/*
 * Do option processing on a datagram, possibly discarding it if bad options
 * are encountered, or forwarding it if source-routed.
 *
 * The pass argument is used when operating in the IPSTEALTH mode to tell
 * what options to process: [LS]SRR (pass 0) or the others (pass 1).  The
 * reason for as many as two passes is that when doing IPSTEALTH, non-routing
 * options should be processed only if the packet is for us.
 *
 * Returns 1 if packet has been forwarded/freed, 0 if the packet should be
 * processed further.
 */
int
ip_dooptions(struct mbuf *m, int pass)
{
	struct ip *ip = mtod(m, struct ip *);
	u_char *cp;
	struct in_ifaddr *ia;
	int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
	struct in_addr *sin, dst;
	uint32_t ntime;
	struct	sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET };

	/* Ignore or reject packets with IP options. */
	if (ip_doopts == 0)
		return 0;
	else if (ip_doopts == 2) {
		type = ICMP_UNREACH;
		code = ICMP_UNREACH_FILTER_PROHIB;
		goto bad;
	}

	dst = ip->ip_dst;
	cp = (u_char *)(ip + 1);
	cnt = (ip->ip_hl << 2) - sizeof (struct ip);
	for (; cnt > 0; cnt -= optlen, cp += optlen) {
		opt = cp[IPOPT_OPTVAL];
		if (opt == IPOPT_EOL)
			break;
		if (opt == IPOPT_NOP)
			optlen = 1;
		else {
			if (cnt < IPOPT_OLEN + sizeof(*cp)) {
				code = &cp[IPOPT_OLEN] - (u_char *)ip;
				goto bad;
			}
			optlen = cp[IPOPT_OLEN];
			if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) {
				code = &cp[IPOPT_OLEN] - (u_char *)ip;
				goto bad;
			}
		}
		switch (opt) {

		default:
			break;

		/*
		 * Source routing with record.  Find interface with current
		 * destination address.  If none on this machine then drop if
		 * strictly routed, or do nothing if loosely routed.  Record
		 * interface address and bring up next address component.  If
		 * strictly routed make sure next address is on directly
		 * accessible net.
		 */
		case IPOPT_LSRR:
		case IPOPT_SSRR:
#ifdef IPSTEALTH
			if (V_ipstealth && pass > 0)
				break;
#endif
			if (optlen < IPOPT_OFFSET + sizeof(*cp)) {
				code = &cp[IPOPT_OLEN] - (u_char *)ip;
				goto bad;
			}
			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
				goto bad;
			}
			ipaddr.sin_addr = ip->ip_dst;
			if (ifa_ifwithaddr_check((struct sockaddr *)&ipaddr)
			    == 0) {
				if (opt == IPOPT_SSRR) {
					type = ICMP_UNREACH;
					code = ICMP_UNREACH_SRCFAIL;
					goto bad;
				}
				if (!ip_dosourceroute)
					goto nosourcerouting;
				/*
				 * Loose routing, and not at next destination
				 * yet; nothing to do except forward.
				 */
				break;
			}
			off--;			/* 0 origin */
			if (off > optlen - (int)sizeof(struct in_addr)) {
				/*
				 * End of source route.  Should be for us.
				 */
				if (!ip_acceptsourceroute)
					goto nosourcerouting;
				save_rte(m, cp, ip->ip_src);
				break;
			}
#ifdef IPSTEALTH
			if (V_ipstealth)
				goto dropit;
#endif
			if (!ip_dosourceroute) {
				if (V_ipforwarding) {
					char buf[16]; /* aaa.bbb.ccc.ddd\0 */
					/*
					 * Acting as a router, so generate
					 * ICMP
					 */
nosourcerouting:
					strcpy(buf, inet_ntoa(ip->ip_dst));
					log(LOG_WARNING, 
					    "attempted source route from %s to %s\n",
					    inet_ntoa(ip->ip_src), buf);
					type = ICMP_UNREACH;
					code = ICMP_UNREACH_SRCFAIL;
					goto bad;
				} else {
					/*
					 * Not acting as a router, so
					 * silently drop.
					 */
#ifdef IPSTEALTH
dropit:
#endif
					IPSTAT_INC(ips_cantforward);
					m_freem(m);
					return (1);
				}
			}

			/*
			 * locate outgoing interface
			 */
			(void)memcpy(&ipaddr.sin_addr, cp + off,
			    sizeof(ipaddr.sin_addr));

			if (opt == IPOPT_SSRR) {
#define	INA	struct in_ifaddr *
#define	SA	struct sockaddr *
			    if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == NULL)
				    ia = (INA)ifa_ifwithnet((SA)&ipaddr, 0);
			} else
/* XXX MRT 0 for routing */
				ia = ip_rtaddr(ipaddr.sin_addr, M_GETFIB(m));
			if (ia == NULL) {
				type = ICMP_UNREACH;
				code = ICMP_UNREACH_SRCFAIL;
				goto bad;
			}
			ip->ip_dst = ipaddr.sin_addr;
			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
			    sizeof(struct in_addr));
			ifa_free(&ia->ia_ifa);
			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
			/*
			 * Let ip_intr's mcast routing check handle mcast pkts
			 */
			forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr));
			break;

		case IPOPT_RR:
#ifdef IPSTEALTH
			if (V_ipstealth && pass == 0)
				break;
#endif
			if (optlen < IPOPT_OFFSET + sizeof(*cp)) {
				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
				goto bad;
			}
			if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) {
				code = &cp[IPOPT_OFFSET] - (u_char *)ip;
				goto bad;
			}
			/*
			 * If no space remains, ignore.
			 */
			off--;			/* 0 origin */
			if (off > optlen - (int)sizeof(struct in_addr))
				break;
			(void)memcpy(&ipaddr.sin_addr, &ip->ip_dst,
			    sizeof(ipaddr.sin_addr));
			/*
			 * Locate outgoing interface; if we're the
			 * destination, use the incoming interface (should be
			 * same).
			 */
			if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == NULL &&
			    (ia = ip_rtaddr(ipaddr.sin_addr, M_GETFIB(m))) == NULL) {
				type = ICMP_UNREACH;
				code = ICMP_UNREACH_HOST;
				goto bad;
			}
			(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
			    sizeof(struct in_addr));
			ifa_free(&ia->ia_ifa);
			cp[IPOPT_OFFSET] += sizeof(struct in_addr);
			break;

		case IPOPT_TS:
#ifdef IPSTEALTH
			if (V_ipstealth && pass == 0)
				break;
#endif
			code = cp - (u_char *)ip;
			if (optlen < 4 || optlen > 40) {
				code = &cp[IPOPT_OLEN] - (u_char *)ip;
				goto bad;
			}
			if ((off = cp[IPOPT_OFFSET]) < 5) {
				code = &cp[IPOPT_OLEN] - (u_char *)ip;
				goto bad;
			}
			if (off > optlen - (int)sizeof(int32_t)) {
				cp[IPOPT_OFFSET + 1] += (1 << 4);
				if ((cp[IPOPT_OFFSET + 1] & 0xf0) == 0) {
					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
					goto bad;
				}
				break;
			}
			off--;				/* 0 origin */
			sin = (struct in_addr *)(cp + off);
			switch (cp[IPOPT_OFFSET + 1] & 0x0f) {

			case IPOPT_TS_TSONLY:
				break;

			case IPOPT_TS_TSANDADDR:
				if (off + sizeof(uint32_t) +
				    sizeof(struct in_addr) > optlen) {
					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
					goto bad;
				}
				ipaddr.sin_addr = dst;
				ia = (INA)ifaof_ifpforaddr((SA)&ipaddr,
							    m->m_pkthdr.rcvif);
				if (ia == NULL)
					continue;
				(void)memcpy(sin, &IA_SIN(ia)->sin_addr,
				    sizeof(struct in_addr));
				ifa_free(&ia->ia_ifa);
				cp[IPOPT_OFFSET] += sizeof(struct in_addr);
				off += sizeof(struct in_addr);
				break;

			case IPOPT_TS_PRESPEC:
				if (off + sizeof(uint32_t) +
				    sizeof(struct in_addr) > optlen) {
					code = &cp[IPOPT_OFFSET] - (u_char *)ip;
					goto bad;
				}
				(void)memcpy(&ipaddr.sin_addr, sin,
				    sizeof(struct in_addr));
				if (ifa_ifwithaddr_check((SA)&ipaddr) == 0)
					continue;
				cp[IPOPT_OFFSET] += sizeof(struct in_addr);
				off += sizeof(struct in_addr);
				break;

			default:
				code = &cp[IPOPT_OFFSET + 1] - (u_char *)ip;
				goto bad;
			}
			ntime = iptime();
			(void)memcpy(cp + off, &ntime, sizeof(uint32_t));
			cp[IPOPT_OFFSET] += sizeof(uint32_t);
		}
	}
	if (forward && V_ipforwarding) {
		ip_forward(m, 1);
		return (1);
	}
	return (0);
bad:
	icmp_error(m, type, code, 0, 0);
	IPSTAT_INC(ips_badoptions);
	return (1);
}
コード例 #10
0
err_t
ip_input(struct pbuf *p, struct netif *inp) {
  struct ip_hdr *iphdr;
  struct netif *netif;
  u16_t iphdrlen;

  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)));
    ip_debug_print(p);
    pbuf_free(p);
    IP_STATS_INC(ip.err);
    IP_STATS_INC(ip.drop);
    snmp_inc_ipinhdrerrors();
    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_ipinhdrerrors();
    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)));

  /* match packet against an interface, i.e. is this packet for us? */
  for (netif = netif_list; netif != NULL; netif = netif->next) {

    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",
      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)));

    /* interface is up and configured? */
    if ((netif_is_up(netif)) && (!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), netif)) {
        LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
          netif->name[0], netif->name[1]));
        /* break out of for loop */
        break;
      }
    }
  }
#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 (netif == NULL) {
    /* remote port is DHCP server? */
    if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
      LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
        ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdrlen))->dest)));
      if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdrlen))->dest) == DHCP_CLIENT_PORT) {
        LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: DHCP packet accepted.\n"));
        netif = inp;
      }
    }
  }
#endif /* LWIP_DHCP */
  /* packet not for us? */
  if (netif == NULL) {
    /* packet not for us, route or discard */
    LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: packet not for us.\n"));
#if IP_FORWARD
    /* non-broadcast packet? */
    if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) {
      /* try to forward IP packet on (other) interfaces */
      ip_forward(p, iphdr, inp);
    }
    else
#endif /* IP_FORWARD */
    {
      snmp_inc_ipinaddrerrors();
      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? */
    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 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));
    /* 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);
    LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
      ntohs(IPH_OFFSET(iphdr))));
    IP_STATS_INC(ip.opterr);
    IP_STATS_INC(ip.drop);
    /* unsupported protocol feature */
    snmp_inc_ipinunknownprotos();
    return ERR_OK;
#endif /* IP_REASSEMBLY */
  }

#if IP_OPTIONS == 0 /* no support for IP options in the IP header? */
  if (iphdrlen > IP_HLEN) {
    LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS == 0).\n"));
    pbuf_free(p);
    IP_STATS_INC(ip.opterr);
    IP_STATS_INC(ip.drop);
    /* unsupported protocol feature */
    snmp_inc_ipinunknownprotos();
    return ERR_OK;
  }
#endif /* IP_OPTIONS == 0 */

  /* send to upper layers */
  LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n"));
  ip_debug_print(p);
  LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));

#if LWIP_RAW
  /* raw input did not eat the packet? */
  if (raw_input(p, inp) == 0) {
#endif /* LWIP_RAW */

  switch (IPH_PROTO(iphdr)) {
#if LWIP_UDP
  case IP_PROTO_UDP:
  case IP_PROTO_UDPLITE:
    snmp_inc_ipindelivers();
    udp_input(p, inp);
    break;
#endif /* LWIP_UDP */
#if LWIP_TCP
  case IP_PROTO_TCP:
    snmp_inc_ipindelivers();
    tcp_input(p, inp);
    break;
#endif /* LWIP_TCP */
  case IP_PROTO_ICMP:
    snmp_inc_ipindelivers();
    icmp_input(p, inp);
    break;
  default:
    /* send ICMP destination protocol unreachable unless is was a broadcast */
    if (!ip_addr_isbroadcast(&(iphdr->dest), inp) &&
        !ip_addr_ismulticast(&(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_ipinunknownprotos();
  }
#if LWIP_RAW
  } /* LWIP_RAW */
#endif
  return ERR_OK;
}
コード例 #11
0
ファイル: ip6.c プロジェクト: 0xBADCA7/lk
void
ip_input(struct pbuf *p, struct netif *inp) {
  struct ip_hdr *iphdr;
  struct netif *netif;


  PERF_START;

#if IP_DEBUG
  ip_debug_print(p);
#endif /* IP_DEBUG */


  IP_STATS_INC(ip.recv);

  /* identify the IP header */
  iphdr = p->payload;


  if (iphdr->v != 6) {
    LWIP_DEBUGF(IP_DEBUG, ("IP packet dropped due to bad version number\n"));
#if IP_DEBUG
    ip_debug_print(p);
#endif /* IP_DEBUG */
    pbuf_free(p);
    IP_STATS_INC(ip.err);
    IP_STATS_INC(ip.drop);
    return;
  }

  /* is this packet for us? */
  for(netif = netif_list; netif != NULL; netif = netif->next) {
#if IP_DEBUG
    LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest "));
    ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest)));
    LWIP_DEBUGF(IP_DEBUG, ("netif->ip_addr "));
    ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest)));
    LWIP_DEBUGF(IP_DEBUG, ("\n"));
#endif /* IP_DEBUG */
    if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr))) {
      break;
    }
  }


  if (netif == NULL) {
    /* packet not for us, route or discard */
#if IP_FORWARD
    ip_forward(p, iphdr);
#endif
    pbuf_free(p);
    return;
  }

  pbuf_realloc(p, IP_HLEN + ntohs(iphdr->len));

  /* send to upper layers */
#if IP_DEBUG
  /*  LWIP_DEBUGF("ip_input: \n");
  ip_debug_print(p);
  LWIP_DEBUGF("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/
#endif /* IP_DEBUG */

  if(pbuf_header(p, -IP_HLEN)) {
    LWIP_ASSERT("Can't move over header in packet", 0);
    return;
  }

  switch (iphdr->nexthdr) {
  case IP_PROTO_UDP:
    udp_input(p, inp);
    break;
  case IP_PROTO_TCP:
    tcp_input(p, inp);
    break;
#if LWIP_ICMP
  case IP_PROTO_ICMP:
    icmp_input(p, inp);
    break;
#endif /* LWIP_ICMP */
  default:
#if LWIP_ICMP
    /* send ICMP destination protocol unreachable */
    icmp_dest_unreach(p, ICMP_DUR_PROTO);
#endif /* LWIP_ICMP */
    pbuf_free(p);
    LWIP_DEBUGF(IP_DEBUG, ("Unsupported transport protocol %"U16_F"\n",
          iphdr->nexthdr));

    IP_STATS_INC(ip.proterr);
    IP_STATS_INC(ip.drop);
  }
  PERF_STOP("ip_input");
}
コード例 #12
0
ファイル: ip_input.c プロジェクト: Scarletts/LiteBSD
/*
 * Ip input routine.  Checksum and byte swap header.  If fragmented
 * try to reassemble.  Process options.  Pass to next level.
 */
void
ipintr()
{
    register struct ip *ip;
    register struct mbuf *m;
    register struct ipq *fp;
    register struct in_ifaddr *ia;
    int hlen, s;

next:
    /*
     * Get next datagram off input queue and get IP header
     * in first mbuf.
     */
    s = splimp();
    IF_DEQUEUE(&ipintrq, m);
    splx(s);
    if (m == 0)
        return;
#ifdef  DIAGNOSTIC
    if ((m->m_flags & M_PKTHDR) == 0)
        panic("ipintr no HDR");
#endif
    /*
     * If no IP addresses have been set yet but the interfaces
     * are receiving, can't do anything with incoming packets yet.
     */
    if (in_ifaddr == NULL)
        goto bad;
    ipstat.ips_total++;
    if (m->m_len < sizeof (struct ip) &&
        (m = m_pullup(m, sizeof (struct ip))) == 0) {
        ipstat.ips_toosmall++;
        goto next;
    }
    ip = mtod(m, struct ip *);
    if (ip->ip_v != IPVERSION) {
        ipstat.ips_badvers++;
        goto bad;
    }
    hlen = ip->ip_hl << 2;
    if (hlen < sizeof(struct ip)) { /* minimum header length */
        ipstat.ips_badhlen++;
        goto bad;
    }
    if (hlen > m->m_len) {
        if ((m = m_pullup(m, hlen)) == 0) {
            ipstat.ips_badhlen++;
            goto next;
        }
        ip = mtod(m, struct ip *);
    }
    ip->ip_sum = in_cksum(m, hlen);
    if (ip->ip_sum) {
        ipstat.ips_badsum++;
        goto bad;
    }

    /*
     * Convert fields to host representation.
     */
    NTOHS(ip->ip_len);
    if (ip->ip_len < hlen) {
        ipstat.ips_badlen++;
        goto bad;
    }
    NTOHS(ip->ip_id);
    NTOHS(ip->ip_off);

    /*
     * Check that the amount of data in the buffers
     * is as at least much as the IP header would have us expect.
     * Trim mbufs if longer than we expect.
     * Drop packet if shorter than we expect.
     */
    if (m->m_pkthdr.len < ip->ip_len) {
        ipstat.ips_tooshort++;
        goto bad;
    }
    if (m->m_pkthdr.len > ip->ip_len) {
        if (m->m_len == m->m_pkthdr.len) {
            m->m_len = ip->ip_len;
            m->m_pkthdr.len = ip->ip_len;
        } else
            m_adj(m, ip->ip_len - m->m_pkthdr.len);
    }

    /*
     * Process options and, if not destined for us,
     * ship it on.  ip_dooptions returns 1 when an
     * error was detected (causing an icmp message
     * to be sent and the original packet to be freed).
     */
    ip_nhops = 0;       /* for source routed packets */
    if (hlen > sizeof (struct ip) && ip_dooptions(m))
        goto next;

    /*
     * Check our list of addresses, to see if the packet is for us.
     */
    for (ia = in_ifaddr; ia; ia = ia->ia_next) {
#define satosin(sa) ((struct sockaddr_in *)(sa))

        if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
            goto ours;
        if (
#ifdef  DIRECTED_BROADCAST
            ia->ia_ifp == m->m_pkthdr.rcvif &&
#endif
            (ia->ia_ifp->if_flags & IFF_BROADCAST)) {
            u_long t;

            if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
                ip->ip_dst.s_addr)
                goto ours;
            if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr)
                goto ours;
            /*
             * Look for all-0's host part (old broadcast addr),
             * either for subnet or net.
             */
            t = ntohl(ip->ip_dst.s_addr);
            if (t == ia->ia_subnet)
                goto ours;
            if (t == ia->ia_net)
                goto ours;
        }
    }
    if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
        struct in_multi *inm;
#ifdef MROUTING
        extern struct socket *ip_mrouter;

        if (ip_mrouter) {
            /*
             * If we are acting as a multicast router, all
             * incoming multicast packets are passed to the
             * kernel-level multicast forwarding function.
             * The packet is returned (relatively) intact; if
             * ip_mforward() returns a non-zero value, the packet
             * must be discarded, else it may be accepted below.
             *
             * (The IP ident field is put in the same byte order
             * as expected when ip_mforward() is called from
             * ip_output().)
             */
            ip->ip_id = htons(ip->ip_id);
            if (ip_mforward(m, m->m_pkthdr.rcvif) != 0) {
                ipstat.ips_cantforward++;
                m_freem(m);
                goto next;
            }
            ip->ip_id = ntohs(ip->ip_id);

            /*
             * The process-level routing demon needs to receive
             * all multicast IGMP packets, whether or not this
             * host belongs to their destination groups.
             */
            if (ip->ip_p == IPPROTO_IGMP)
                goto ours;
            ipstat.ips_forward++;
        }
#endif
        /*
         * See if we belong to the destination multicast group on the
         * arrival interface.
         */
        IN_LOOKUP_MULTI(ip->ip_dst, m->m_pkthdr.rcvif, inm);
        if (inm == NULL) {
            ipstat.ips_cantforward++;
            m_freem(m);
            goto next;
        }
        goto ours;
    }
    if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
        goto ours;
    if (ip->ip_dst.s_addr == INADDR_ANY)
        goto ours;

    /*
     * Not for us; forward if possible and desirable.
     */
    if (ipforwarding == 0) {
        ipstat.ips_cantforward++;
        m_freem(m);
    } else
        ip_forward(m, 0);
    goto next;

ours:
    /*
     * If offset or IP_MF are set, must reassemble.
     * Otherwise, nothing need be done.
     * (We could look in the reassembly queue to see
     * if the packet was previously fragmented,
     * but it's not worth the time; just let them time out.)
     */
    if (ip->ip_off &~ IP_DF) {
        if (m->m_flags & M_EXT) {       /* XXX */
            if ((m = m_pullup(m, sizeof (struct ip))) == 0) {
                ipstat.ips_toosmall++;
                goto next;
            }
            ip = mtod(m, struct ip *);
        }
        /*
         * Look for queue of fragments
         * of this datagram.
         */
        for (fp = ipq.next; fp != &ipq; fp = fp->next)
            if (ip->ip_id == fp->ipq_id &&
                ip->ip_src.s_addr == fp->ipq_src.s_addr &&
                ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
                ip->ip_p == fp->ipq_p)
                goto found;
        fp = 0;
found:

        /*
         * Adjust ip_len to not reflect header,
         * set ip_mff if more fragments are expected,
         * convert offset of this to bytes.
         */
        ip->ip_len -= hlen;
        ((struct ipasfrag *)ip)->ipf_mff &= ~1;
        if (ip->ip_off & IP_MF)
            ((struct ipasfrag *)ip)->ipf_mff |= 1;
        ip->ip_off <<= 3;

        /*
         * If datagram marked as having more fragments
         * or if this is not the first fragment,
         * attempt reassembly; if it succeeds, proceed.
         */
        if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) {
            ipstat.ips_fragments++;
            ip = ip_reass((struct ipasfrag *)ip, fp);
            if (ip == 0)
                goto next;
            ipstat.ips_reassembled++;
            m = dtom(ip);
        } else
            if (fp)
                ip_freef(fp);
    } else
コード例 #13
0
ファイル: ip.c プロジェクト: Joel397/Ongoing_work_files
/*-----------------------------------------------------------------------------------*/
err_t
ip_input(struct pbuf *p, struct netif *inp) {
    static struct ip_hdr *iphdr;
    static struct netif *netif;
    static u8_t hl;



#ifdef IP_STATS
    ++stats.ip.recv;
#endif /* IP_STATS */

    /* identify the IP header */
    iphdr = p->payload;
    if(IPH_V(iphdr) != 4) {
        DEBUGF(IP_DEBUG, ("IP packet dropped due to bad version number %d\n", IPH_V(iphdr)));
#if IP_DEBUG
        ip_debug_print(p);
#endif /* IP_DEBUG */
        pbuf_free(p);
#ifdef IP_STATS
        ++stats.ip.err;
        ++stats.ip.drop;
#endif /* IP_STATS */
        return ERR_OK;
    }

    hl = IPH_HL(iphdr);

    if(hl * 4 > p->len) {
        DEBUGF(IP_DEBUG, ("IP packet dropped due to too short packet %d\n", p->len));

        pbuf_free(p);
#ifdef IP_STATS
        ++stats.ip.lenerr;
        ++stats.ip.drop;
#endif /* IP_STATS */
        return ERR_OK;
    }

    /* verify checksum */
    if(inet_chksum(iphdr, hl * 4) != 0) {

        DEBUGF(IP_DEBUG, ("IP packet dropped due to failing checksum 0x%x\n", inet_chksum(iphdr, hl * 4)));
#if IP_DEBUG
        ip_debug_print(p);
#endif /* IP_DEBUG */
        pbuf_free(p);
#ifdef IP_STATS
        ++stats.ip.chkerr;
        ++stats.ip.drop;
#endif /* IP_STATS */
        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",
                          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)));

        if(ip_addr_isany(&(netif->ip_addr)) ||
                ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) ||
                (ip_addr_isbroadcast(&(iphdr->dest), &(netif->netmask)) &&
                 ip_addr_maskcmp(&(iphdr->dest), &(netif->ip_addr), &(netif->netmask))) ||
                ip_addr_cmp(&(iphdr->dest), IP_ADDR_BROADCAST)) {
            break;
        }
    }

#if LWIP_DHCP
    /* If a DHCP packet has arrived on the interface, we pass it up the
       stack regardless of destination IP address. The reason is that
       DHCP replies are sent to the IP adress that will be given to this
       node (as recommended by RFC 1542 section 3.1.1, referred by RFC
       2131). */
    if(IPH_PROTO(iphdr) == IP_PROTO_UDP &&
            ((struct udp_hdr *)((u8_t *)iphdr + IPH_HL(iphdr) * 4/sizeof(u8_t)))->src ==
            DHCP_SERVER_PORT) {
        netif = inp;
    }
#endif /* LWIP_DHCP */

    if(netif == NULL) {
        /* packet not for us, route or discard */
        DEBUGF(IP_DEBUG, ("ip_input: packet not for us.\n"));
#if IP_FORWARD
        if(!ip_addr_isbroadcast(&(iphdr->dest), &(inp->netmask))) {
            ip_forward(p, iphdr, inp);
        }
#endif /* IP_FORWARD */
        pbuf_free(p);
        return ERR_OK;
    }

#if IP_REASSEMBLY
    if((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
        p = ip_reass(p);
        if(p == NULL) {
            return ERR_OK;
        }
        iphdr = p->payload;
    }
#else /* IP_REASSEMBLY */
    if((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
        pbuf_free(p);
        DEBUGF(IP_DEBUG, ("IP packet dropped since it was fragmented (0x%x).\n",
                          ntohs(IPH_OFFSET(iphdr))));
#ifdef IP_STATS
        ++stats.ip.opterr;
        ++stats.ip.drop;
#endif /* IP_STATS */
        return ERR_OK;
    }
#endif /* IP_REASSEMBLY */

#if IP_OPTIONS == 0
    if(hl * 4 > IP_HLEN) {
        DEBUGF(IP_DEBUG, ("IP packet dropped since there were IP options.\n"));

        pbuf_free(p);
#ifdef IP_STATS
        ++stats.ip.opterr;
        ++stats.ip.drop;
#endif /* IP_STATS */
        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 */

    switch(IPH_PROTO(iphdr)) {
#if LWIP_UDP > 0
    case IP_PROTO_UDP:
        udp_input(p, inp);
        break;
#endif /* LWIP_UDP */
#if LWIP_TCP > 0
    case IP_PROTO_TCP:
        tcp_input(p, inp);
        break;
#endif /* LWIP_TCP */
    case IP_PROTO_ICMP:
        icmp_input(p, inp);
        break;
    default:
        /* send ICMP destination protocol unreachable unless is was a broadcast */
        if(!ip_addr_isbroadcast(&(iphdr->dest), &(inp->netmask)) &&
                !ip_addr_ismulticast(&(iphdr->dest))) {
            p->payload = iphdr;
            icmp_dest_unreach(p, ICMP_DUR_PROTO);
        }
        pbuf_free(p);

        DEBUGF(IP_DEBUG, ("Unsupported transportation protocol %d\n", IPH_PROTO(iphdr)));

#ifdef IP_STATS
        ++stats.ip.proterr;
        ++stats.ip.drop;
#endif /* IP_STATS */

    }
    return ERR_OK;
}
コード例 #14
0
ファイル: ip_input.c プロジェクト: shattered/linux-m68k
int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
	struct iphdr *iph = skb->h.iph;
	struct sock *raw_sk=NULL;
	unsigned char hash;
	unsigned char flag = 0;
	struct inet_protocol *ipprot;
	int brd=IS_MYADDR;
	struct options * opt = NULL;
	int is_frag=0;
	__u32 daddr;

#ifdef CONFIG_FIREWALL
	int fwres;
	__u16 rport;
#endif	
#ifdef CONFIG_IP_MROUTE
	int mroute_pkt=0;
#endif	

#ifdef CONFIG_NET_IPV6
	/* 
	 *	Intercept IPv6 frames. We dump ST-II and invalid types just below..
	 */
	 
	if(iph->version == 6)
		return ipv6_rcv(skb,dev,pt);
#endif		

	ip_statistics.IpInReceives++;


	/*
	 *	Tag the ip header of this packet so we can find it
	 */

	skb->ip_hdr = iph;

	/*
	 *	RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.
	 *	RFC1122: 3.1.2.3 MUST discard a frame with invalid source address [NEEDS FIXING].
	 *
	 *	Is the datagram acceptable?
	 *
	 *	1.	Length at least the size of an ip header
	 *	2.	Version of 4
	 *	3.	Checksums correctly. [Speed optimisation for later, skip loopback checksums]
	 *	4.	Doesn't have a bogus length
	 *	(5.	We ought to check for IP multicast addresses and undefined types.. does this matter ?)
	 */

	if (skb->len<sizeof(struct iphdr) || iph->ihl<5 || iph->version != 4 || ip_fast_csum((unsigned char *)iph, iph->ihl) !=0
		|| skb->len < ntohs(iph->tot_len))
	{
		ip_statistics.IpInHdrErrors++;
		kfree_skb(skb, FREE_WRITE);
		return(0);
	}

	/*
	 *	Our transport medium may have padded the buffer out. Now we know it
	 *	is IP we can trim to the true length of the frame.
	 *	Note this now means skb->len holds ntohs(iph->tot_len).
	 */

	skb_trim(skb,ntohs(iph->tot_len));
	
	if(skb->len < (iph->ihl<<2))
	{
		ip_statistics.IpInHdrErrors++;
		kfree_skb(skb, FREE_WRITE);
		return 0;
	}

	/*
	 *	Account for the packet (even if the packet is
	 *	not accepted by the firewall!). We do this after
	 *	the sanity checks and the additional ihl check
	 *	so we dont account garbage as we might do before.
	 */

#ifdef CONFIG_IP_ACCT
	ip_fw_chk(iph,dev,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_IN);
#endif	

	/*
	 *	Try to select closest <src,dst> alias device, if any.
	 *	net_alias_dev_rx32 returns main device if it 
	 *	fails to found other.
 	 *  	If successful, also incr. alias rx count.
	 *
	 *	Only makes sense for unicasts - Thanks ANK.
	 */

#ifdef CONFIG_NET_ALIAS
	if (skb->pkt_type == PACKET_HOST && iph->daddr != skb->dev->pa_addr && net_alias_has(skb->dev)) {
		skb->dev = dev = net_alias_dev_rx32(skb->dev, AF_INET, iph->saddr, iph->daddr);
	}
#endif

	if (iph->ihl > 5) 
	{
		skb->ip_summed = 0;
		if (ip_options_compile(NULL, skb))
			return(0);
		opt = (struct options*)skb->proto_priv;
#ifdef CONFIG_IP_NOSR
		if (opt->srr) 
		{
			kfree_skb(skb, FREE_READ);
			return -EINVAL;
		}
#endif					
	}
	
#if defined(CONFIG_IP_TRANSPARENT_PROXY) && !defined(CONFIG_IP_ALWAYS_DEFRAG)
#define CONFIG_IP_ALWAYS_DEFRAG 1
#endif
#ifdef CONFIG_IP_ALWAYS_DEFRAG
	/*
	 * Defragment all incoming traffic before even looking at it.
	 * If you have forwarding enabled, this makes the system a
	 * defragmenting router.  Not a common thing.
	 * You probably DON'T want to enable this unless you have to.
	 * You NEED to use this if you want to use transparent proxying,
	 * otherwise, we can't vouch for your sanity.
	 */

	/*
	 *	See if the frame is fragmented.
	 */
	 
	if(iph->frag_off)
	{
		if (iph->frag_off & htons(IP_MF))
			is_frag|=IPFWD_FRAGMENT;
		/*
		 *	Last fragment ?
		 */
	
		if (iph->frag_off & htons(IP_OFFSET))
			is_frag|=IPFWD_LASTFRAG;
	
		/*
		 *	Reassemble IP fragments.
		 */

		if(is_frag)
		{
			/* Defragment. Obtain the complete packet if there is one */
			skb=ip_defrag(iph,skb,dev);
			if(skb==NULL)
				return 0;
			skb->dev = dev;
			iph=skb->h.iph;
			is_frag = 0;
			/*
			 * When the reassembled packet gets forwarded, the ip
			 * header checksum should be correct.
			 * For better performance, this should actually only
			 * be done in that particular case, i.e. set a flag
			 * here and calculate the checksum in ip_forward.
			 */
			ip_send_check(iph);
		}
	}

#endif
	/*
	 *	See if the firewall wants to dispose of the packet. 
	 */
	
#ifdef	CONFIG_FIREWALL

	if ((fwres=call_in_firewall(PF_INET, skb->dev, iph, &rport))<FW_ACCEPT)
	{
		if(fwres==FW_REJECT)
			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0, dev);
		kfree_skb(skb, FREE_WRITE);
		return 0;	
	}

#ifdef	CONFIG_IP_TRANSPARENT_PROXY
	if (fwres==FW_REDIRECT)
		skb->redirport = rport;
	else
#endif
		skb->redirport = 0;
#endif
	
#ifndef CONFIG_IP_ALWAYS_DEFRAG
	/*
	 *	Remember if the frame is fragmented.
	 */
	 
	if(iph->frag_off)
	{
		if (iph->frag_off & htons(IP_MF))
			is_frag|=IPFWD_FRAGMENT;
		/*
		 *	Last fragment ?
		 */
	
		if (iph->frag_off & htons(IP_OFFSET))
			is_frag|=IPFWD_LASTFRAG;
	}
	
#endif
	/*
	 *	Do any IP forwarding required.  chk_addr() is expensive -- avoid it someday.
	 *
	 *	This is inefficient. While finding out if it is for us we could also compute
	 *	the routing table entry. This is where the great unified cache theory comes
	 *	in as and when someone implements it
	 *
	 *	For most hosts over 99% of packets match the first conditional
	 *	and don't go via ip_chk_addr. Note: brd is set to IS_MYADDR at
	 *	function entry.
	 */
	daddr = iph->daddr;
#ifdef CONFIG_IP_TRANSPARENT_PROXY
	/*
	 *	ip_chksock adds still more overhead for forwarded traffic...
	 */
	if ( iph->daddr == skb->dev->pa_addr || skb->redirport || (brd = ip_chk_addr(iph->daddr)) != 0 || ip_chksock(skb))
#else
	if ( iph->daddr == skb->dev->pa_addr || (brd = ip_chk_addr(iph->daddr)) != 0)
#endif
	{
		if (opt && opt->srr) 
	        {
			int srrspace, srrptr;
			__u32 nexthop;
			unsigned char * optptr = ((unsigned char *)iph) + opt->srr;

			if (brd != IS_MYADDR || skb->pkt_type != PACKET_HOST) 
			{
				kfree_skb(skb, FREE_WRITE);
				return 0;
			}

			for ( srrptr=optptr[2], srrspace = optptr[1];
			      srrptr <= srrspace;
			      srrptr += 4
			     ) 
			{
				int brd2;
				if (srrptr + 3 > srrspace) 
				{
					icmp_send(skb, ICMP_PARAMETERPROB, 0, opt->srr+2,
						  skb->dev);
					kfree_skb(skb, FREE_WRITE);
					return 0;
				}
				memcpy(&nexthop, &optptr[srrptr-1], 4);
				if ((brd2 = ip_chk_addr(nexthop)) == 0)
					break;
				if (brd2 != IS_MYADDR) 
				{

					/*
					 *	ANK: should we implement weak tunneling of multicasts?
					 *	Are they obsolete? DVMRP specs (RFC-1075) is old enough...
					 *	[They are obsolete]
					 */
					kfree_skb(skb, FREE_WRITE);
					return -EINVAL;
				}
				memcpy(&daddr, &optptr[srrptr-1], 4);
			}
			if (srrptr <= srrspace) 
			{
				opt->srr_is_hit = 1;
				opt->is_changed = 1;
				if (sysctl_ip_forward) {
					if (ip_forward(skb, dev, is_frag, nexthop))
						kfree_skb(skb, FREE_WRITE);
				} else {
					ip_statistics.IpInAddrErrors++;
					kfree_skb(skb, FREE_WRITE);
				}
				return 0;
			}
		}

#ifdef CONFIG_IP_MULTICAST	
		if(!(dev->flags&IFF_ALLMULTI) && brd==IS_MULTICAST && iph->daddr!=IGMP_ALL_HOSTS && !(dev->flags&IFF_LOOPBACK))
		{
			/*
			 *	Check it is for one of our groups
			 */
			struct ip_mc_list *ip_mc=dev->ip_mc_list;
			do
			{
				if(ip_mc==NULL)
				{	
					kfree_skb(skb, FREE_WRITE);
					return 0;
				}
				if(ip_mc->multiaddr==iph->daddr)
					break;
				ip_mc=ip_mc->next;
			}
			while(1);
		}
#endif

#ifndef CONFIG_IP_ALWAYS_DEFRAG
		/*
		 *	Reassemble IP fragments.
		 */

		if(is_frag)
		{
			/* Defragment. Obtain the complete packet if there is one */
			skb=ip_defrag(iph,skb,dev);
			if(skb==NULL)
				return 0;
			skb->dev = dev;
			iph=skb->h.iph;
		}

#endif

#ifdef CONFIG_IP_MASQUERADE
		/*
		 * Do we need to de-masquerade this packet?
		 */
		{
			int ret = ip_fw_demasquerade(&skb,dev);
			if (ret < 0) {
				kfree_skb(skb, FREE_WRITE);
				return 0;
			}

			if (ret)
			{
				struct iphdr *iph=skb->h.iph;
				if (ip_forward(skb, dev, IPFWD_MASQUERADED, iph->daddr))
					kfree_skb(skb, FREE_WRITE);
				return 0;
			}
		}
#endif

		/*
		 *	Point into the IP datagram, just past the header.
		 */

		skb->ip_hdr = iph;
		skb->h.raw += iph->ihl*4;

#ifdef CONFIG_IP_MROUTE		
		/*
		 *	Check the state on multicast routing (multicast and not 224.0.0.z)
		 */
		 
		if(brd==IS_MULTICAST && (iph->daddr&htonl(0xFFFFFF00))!=htonl(0xE0000000))
			mroute_pkt=1;

#endif
		/*
		 *	Deliver to raw sockets. This is fun as to avoid copies we want to make no surplus copies.
		 *
		 *	RFC 1122: SHOULD pass TOS value up to the transport layer.
		 */
 
		/* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
		hash = iph->protocol & (MAX_INET_PROTOS - 1);

		/* 
		 *	If there maybe a raw socket we must check - if not we don't care less 
		 */
		 
		if((raw_sk = raw_v4_htable[hash]) != NULL) {
			struct sock *sknext = NULL;
			struct sk_buff *skb1;

			raw_sk = raw_v4_lookup(raw_sk, iph->protocol,
					       iph->saddr, iph->daddr);
			if(raw_sk) {	/* Any raw sockets */
				do {
					/* Find the next */
					sknext = raw_v4_lookup(raw_sk->next,
							       iph->protocol,
							       iph->saddr,
							       iph->daddr);
					if(sknext)
						skb1 = skb_clone(skb, GFP_ATOMIC);
					else
						break;	/* One pending raw socket left */
					if(skb1)
						raw_rcv(raw_sk, skb1, dev, iph->saddr,daddr);
					raw_sk = sknext;
				} while(raw_sk!=NULL);
				
				/*
				 *	Here either raw_sk is the last raw socket, or NULL if none 
				 */
				 
				/*
				 *	We deliver to the last raw socket AFTER the protocol checks as it avoids a surplus copy 
				 */
			}
		}
	
		/*
		 *	skb->h.raw now points at the protocol beyond the IP header.
		 */
	
		for (ipprot = (struct inet_protocol *)inet_protos[hash];ipprot != NULL;ipprot=(struct inet_protocol *)ipprot->next)
		{
			struct sk_buff *skb2;
	
			if (ipprot->protocol != iph->protocol)
				continue;
		       /*
			* 	See if we need to make a copy of it.  This will
			* 	only be set if more than one protocol wants it.
			* 	and then not for the last one. If there is a pending
			*	raw delivery wait for that
			*/
	
#ifdef CONFIG_IP_MROUTE
			if (ipprot->copy || raw_sk || mroute_pkt)
#else	
			if (ipprot->copy || raw_sk)
#endif			
			{
				skb2 = skb_clone(skb, GFP_ATOMIC);
				if(skb2==NULL)
					continue;
			}
			else
			{
				skb2 = skb;
			}
			flag = 1;

		       /*
			*	Pass on the datagram to each protocol that wants it,
			*	based on the datagram protocol.  We should really
			*	check the protocol handler's return values here...
			*/

			ipprot->handler(skb2, dev, opt, daddr,
				(ntohs(iph->tot_len) - (iph->ihl * 4)),
				iph->saddr, 0, ipprot);
		}

		/*
		 *	All protocols checked.
		 *	If this packet was a broadcast, we may *not* reply to it, since that
		 *	causes (proven, grin) ARP storms and a leakage of memory (i.e. all
		 *	ICMP reply messages get queued up for transmission...)
		 */

#ifdef CONFIG_IP_MROUTE		 
		/*
		 *	Forward the last copy to the multicast router. If
		 *	there is a pending raw delivery however make a copy
		 *	and forward that.
		 */
		 
		if(mroute_pkt)
		{
			flag=1;
			if(raw_sk==NULL)
				ipmr_forward(skb, is_frag);
			else
			{
				struct sk_buff *skb2=skb_clone(skb, GFP_ATOMIC);
				if(skb2)
				{
					skb2->free=1;
					ipmr_forward(skb2, is_frag);
				}
			}
		}
#endif		

		if(raw_sk!=NULL)	/* Shift to last raw user */
			raw_rcv(raw_sk, skb, dev, iph->saddr, daddr);
		else if (!flag)		/* Free and report errors */
		{
			if (brd != IS_BROADCAST && brd!=IS_MULTICAST)
				icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0, dev);	
			kfree_skb(skb, FREE_WRITE);
		}

		return(0);
	}

	/*
	 *	Do any unicast IP forwarding required.
	 */
	
	/*
	 *	Don't forward multicast or broadcast frames.
	 */

	if(skb->pkt_type!=PACKET_HOST || brd==IS_BROADCAST)
	{
		kfree_skb(skb,FREE_WRITE);
		return 0;
	}

	/*
	 *	The packet is for another target. Forward the frame
	 */

	if (sysctl_ip_forward) {
		if (opt && opt->is_strictroute) 
		{
			icmp_send(skb, ICMP_PARAMETERPROB, 0, 16, skb->dev);
			kfree_skb(skb, FREE_WRITE);
			return -1;
		}
		if (ip_forward(skb, dev, is_frag, iph->daddr))
			kfree_skb(skb, FREE_WRITE);
	} else {
/*	printk("Machine %lx tried to use us as a forwarder to %lx but we have forwarding disabled!\n",
			iph->saddr,iph->daddr);*/
		ip_statistics.IpInAddrErrors++;
		kfree_skb(skb, FREE_WRITE);
	}
	return(0);
}
コード例 #15
0
/*
 * READ/WRITE ip group.
 */
int
op_ip(struct snmp_context *ctx, struct snmp_value *value,
    u_int sub, u_int idx __unused, enum snmp_op op)
{
	int old;

	switch (op) {

	  case SNMP_OP_GETNEXT:
		abort();

	  case SNMP_OP_GET:
		break;

	  case SNMP_OP_SET:
		if (ip_tick < this_tick)
			if (fetch_ip() == -1)
				return (SNMP_ERR_GENERR);

		switch (value->var.subs[sub - 1]) {

		  case LEAF_ipForwarding:
			ctx->scratch->int1 = ip_forwarding ? 1 : 2;
			ctx->scratch->int2 = value->v.integer;
			if (value->v.integer == 1) {
				if (!ip_forwarding && ip_forward(1, &old))
					return (SNMP_ERR_GENERR);
				ctx->scratch->int1 = old ? 1 : 2;
			} else if (value->v.integer == 2) {
				if (ip_forwarding && ip_forward(0, &old))
					return (SNMP_ERR_GENERR);
				ctx->scratch->int1 = old;
			} else
				return (SNMP_ERR_WRONG_VALUE);
			break;

		  case LEAF_ipDefaultTTL:
			ctx->scratch->int1 = ip_defttl;
			ctx->scratch->int2 = value->v.integer;
			if (value->v.integer < 1 || value->v.integer > 255)
				return (SNMP_ERR_WRONG_VALUE);
			if (ip_defttl != value->v.integer &&
			    ip_setttl(value->v.integer, &old))
				return (SNMP_ERR_GENERR);
			ctx->scratch->int1 = old;
			break;
		}
		return (SNMP_ERR_NOERROR);

	  case SNMP_OP_ROLLBACK:
		switch (value->var.subs[sub - 1]) {

		  case LEAF_ipForwarding:
			if (ctx->scratch->int1 == 1) {
				if (ctx->scratch->int2 == 2)
					(void)ip_forward(1, NULL);
			} else {
				if (ctx->scratch->int2 == 1)
					(void)ip_forward(0, NULL);
			}
			break;

		  case LEAF_ipDefaultTTL:
			if (ctx->scratch->int1 != ctx->scratch->int2)
				(void)ip_setttl(ctx->scratch->int1, NULL);
			break;
		}
		return (SNMP_ERR_NOERROR);

	  case SNMP_OP_COMMIT:
		return (SNMP_ERR_NOERROR);
	}

	if (ip_tick < this_tick)
		if (fetch_ip() == -1)
			return (SNMP_ERR_GENERR);

	switch (value->var.subs[sub - 1]) {

	  case LEAF_ipForwarding:
		value->v.integer = ip_forwarding ? 1 : 2;
		break;

	  case LEAF_ipDefaultTTL:
		value->v.integer = ip_defttl;
		break;
	}
	return (SNMP_ERR_NOERROR);
}
コード例 #16
0
ファイル: tmp.c プロジェクト: jamjr/Helios-NG
/*
 * Ip input routine.  Checksum and byte swap header.  If fragmented
 * try to reassamble.  If complete and fragment queue exists, discard.
 * Process options.  Pass to next level.
 */
ipintr()
{
	register struct ip *ip;
	register struct mbuf *m;
	struct mbuf *m0;
	register int i;
	register struct ipq *fp;
	register struct in_ifaddr *ia;
	struct ifnet *ifp;
	int hlen, s;

	
	/* IOdebug( "ipintr: called" ); */
next:
	/*
	 * Get next datagram off input queue and get IP header
	 * in first mbuf.
	 */
	s = splimp();
	
	IF_DEQUEUEIF(&ipintrq, m, ifp);
	
	splx(s);
	
	if (m == NULL)
	  {
	    /* IOdebug( "ipintr: no more mbufs" ); */
	    
	    return;
	  }

	/*
	 * If no IP addresses have been set yet but the interfaces
	 * are receiving, can't do anything with incoming packets yet.
	 */
	if (in_ifaddr == NULL)
		goto bad;
	ipstat.ips_total++;
	if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct ip)) &&
	    (m = m_pullup(m, sizeof (struct ip))) == 0) {
		ipstat.ips_toosmall++;
		goto next;
	}
	ip = mtod(m, struct ip *);
	hlen = ip->ip_hl << 2;
	if (hlen < sizeof(struct ip)) {	/* minimum header length */
		ipstat.ips_badhlen++;
		goto bad;
	}
	if (hlen > m->m_len) {
		if ((m = m_pullup(m, hlen)) == 0) {
			ipstat.ips_badhlen++;
			goto next;
		}
		ip = mtod(m, struct ip *);
	}
	if (ipcksum)
		if (ip->ip_sum = in_cksum(m, hlen)) {
			ipstat.ips_badsum++;
			/* IOdebug( "ipintr: bad checksum" ); */
			goto bad;
		}

	/*
	 * Convert fields to host representation.
	 */
	ip->ip_len = ntohs((u_short)ip->ip_len);
	if (ip->ip_len < hlen) {
		ipstat.ips_badlen++;
		goto bad;
	}
	ip->ip_id = ntohs(ip->ip_id);
	ip->ip_off = ntohs((u_short)ip->ip_off);

	/*
	 * Check that the amount of data in the buffers
	 * is as at least much as the IP header would have us expect.
	 * Trim mbufs if longer than we expect.
	 * Drop packet if shorter than we expect.
	 */
	i = -(u_short)ip->ip_len;
	m0 = m;
	for (;;) {
		i += m->m_len;
		if (m->m_next == 0)
			break;
		m = m->m_next;
	}
	if (i != 0) {
		if (i < 0) {
			ipstat.ips_tooshort++;
			m = m0;
			goto bad;
		}
		if (i <= m->m_len)
			m->m_len -= i;
		else
			m_adj(m0, -i);
	}
	m = m0;

	/*
	 * Process options and, if not destined for us,
	 * ship it on.  ip_dooptions returns 1 when an
	 * error was detected (causing an icmp message
	 * to be sent and the original packet to be freed).
	 */
	ip_nhops = 0;		/* for source routed packets */
	if (hlen > sizeof (struct ip) && ip_dooptions(ip, ifp))
		goto next;

	/*
	 * Check our list of addresses, to see if the packet is for us.
	 */
	
	/* IOdebug( "ipintr: checking address" ); */
	
	for (ia = in_ifaddr; ia; ia = ia->ia_next) {
#define	satosin(sa)	((struct sockaddr_in *)(sa))

		if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
			goto ours;
		if (
#ifdef	DIRECTED_BROADCAST
		    ia->ia_ifp == ifp &&
#endif
		    (ia->ia_ifp->if_flags & IFF_BROADCAST)) {
			u_long t;

			if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
			    ip->ip_dst.s_addr)
				goto ours;
			if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr)
				goto ours;
			/*
			 * Look for all-0's host part (old broadcast addr),
			 * either for subnet or net.
			 */
			t = ntohl(ip->ip_dst.s_addr);
			if (t == ia->ia_subnet)
				goto ours;
			if (t == ia->ia_net)
				goto ours;
		}
	}
	if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST)
		goto ours;
	if (ip->ip_dst.s_addr == INADDR_ANY)
		goto ours;

	/*
	 * Not for us; forward if possible and desirable.
	 */
	ip_forward(ip, ifp);
	
	/* IOdebug( "ipintr: not for us" ); */
	
	goto next;

ours:
	/* IOdebug( "ipintr: ours" ); */
	
	/*
	 * If offset or IP_MF are set, must reassemble.
	 * Otherwise, nothing need be done.
	 * (We could look in the reassembly queue to see
	 * if the packet was previously fragmented,
	 * but it's not worth the time; just let them time out.)
	 */
	if (ip->ip_off &~ IP_DF) {
		/*
		 * Look for queue of fragments
		 * of this datagram.
		 */
	    
		for (fp = ipq.next; fp != &ipq; fp = fp->next)
			if (ip->ip_id == fp->ipq_id &&
			    ip->ip_src.s_addr == fp->ipq_src.s_addr &&
			    ip->ip_dst.s_addr == fp->ipq_dst.s_addr &&
			    ip->ip_p == fp->ipq_p)
				goto found;
		fp = 0;
found:

		/*
		 * Adjust ip_len to not reflect header,
		 * set ip_mff if more fragments are expected,
		 * convert offset of this to bytes.
		 */
		
		ip->ip_len -= hlen;
		
		((struct ipasfrag *)ip)->ipf_mff = 0;
		
		if (ip->ip_off & IP_MF)
			((struct ipasfrag *)ip)->ipf_mff = 1;
		
		ip->ip_off <<= 3;

		/*
		 * If datagram marked as having more fragments
		 * or if this is not the first fragment,
		 * attempt reassembly; if it succeeds, proceed.
		 */
		
		if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off)
		  {
		    /* IOdebug( "ipintr: attempting reassembly" ); */
		    
			ipstat.ips_fragments++;
			
			ip = ip_reass((struct ipasfrag *)ip, fp);
			
			if (ip == NULL)
			  {
			    /* IOdebug( "ipintr: attempt failed" ); */
			    
			    goto next;
			  }			
			
			m = dtom(ip);
		  }
		else
			if (fp)
				ip_freef(fp);
	} else
		ip->ip_len -= hlen;
	/*
	 * Switch out to protocol's input routine.
	 */
	
	/* IOdebug( "ipintr: handling packet of len %d", ip->ip_len ); */
	
	(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, ifp);

	/* IOdebug( "ipintr: handled" ); */
	
	goto next;
bad:
	/* IOdebug( "ipintr: bad input" ); */
	
	m_freem(m);
	goto next;
}