Ejemplo n.º 1
0
int ip_send_packet(struct sr_packet * packet)
{
    struct ip * ip_hdr = IP_HDR(packet);
    uint32_t next_hop;
    char thru_interface[SR_NAMELEN];
    if(forwarding_table_lookup_next_hop(ROUTER(packet->sr)->fwd_table,
                                        ip_hdr->ip_dst.s_addr, &next_hop, thru_interface, 0))
    {
        if(next_hop == 0)
        {
            next_hop = ip_hdr->ip_dst.s_addr;
        }
        ip_send(packet,next_hop,thru_interface);
        return 1;
    }
    return 0;
}
Ejemplo n.º 2
0
// ------------------------------------------------
// Function:        icmp_parse()
// ------------------------------------------------
// Input:           Message buffer
// Output:          -
// ------------------------------------------------
// Description:     Parse a ICMP message
// ------------------------------------------------
void icmp_parse(PPBUF pbuf)
{
    // ---------------------
    // checksum verification
    // ---------------------
    icmp_checksum(pbuf->data, pbuf->size);
    if(chk_H != 0xff) return;
    if(chk_L != 0xff) return;

    // -------------------------------
    // checks recognized message types
    // -------------------------------
    switch(ICMP(pbuf->data)->type) {
        case PING_REQUEST:
            // ---------
            // answer it
            // ---------
            retain_buffer(pbuf);
            ip_answer(pbuf);
            ICMP(pbuf->data)->type = PING_REPLY;

            // ---------------
            // update checksum
            // ---------------
            ICMP(pbuf->data)->checksum = 0;
            icmp_checksum(pbuf->data, pbuf->size);
            ICMP(pbuf->data)->checksum = HTONS(~WORDOF(chk_H, chk_L));

            // ----------------------------
            // sends answer to IP interface
            // ----------------------------
            ip_send(pbuf);
            release_buffer(pbuf);
            break;

        case PING_REPLY:
            // --------------------------------------
            // answer received, signal waiting thread
            // --------------------------------------
            os_signal(SIG_ICMP);
            break;
    }
}
Ejemplo n.º 3
0
int udp_send(struct netdev *nd, struct sin *from, struct sin *to, struct buflist *data)
{
	struct buflist bl, *blp;
	struct udphdr udp;
	int size = 0;

	bl.data = &udp;
	bl.size = sizeof(udp);
	bl.next = data;

	for (blp = &bl; blp; blp = blp->next)
		size += blp->size;

	udp.udp_source = from->sin_port;
	udp.udp_dest   = to->sin_port;
	udp.udp_length = htons(size);
	udp.udp_check  = 0;
	udp.udp_check  = udp_check(&udp, from, to, &bl, size);

	return ip_send(nd, 0x11, from->sin_addr, to->sin_addr, &bl);
}
Ejemplo n.º 4
0
static void raw_send(const struct send_pkt *s, unsigned int len)
{
	static char ip_buf[2048];
	static ip_t *ip_p = NULL;
	int n;
	unsigned int i;

	if (!ip_p) {
		ip_p = ip_open();
		if (!ip_p)
			err(1, "ip_open");
	}
	for (i = 0 ; i < len; ++i) {
		memset(ip_buf, 0, sizeof(ip_buf));
		n = build_buf(&s[i], ip_buf, sizeof(ip_buf));
		ip_checksum(ip_buf, n);
		ip_send(ip_p, ip_buf, n);
	}

	return;
}
Ejemplo n.º 5
0
static void ip_loopback(struct device *old_dev, struct sk_buff *skb)
{
	struct device *dev=&loopback_dev;
	int len=ntohs(skb->ip_hdr->tot_len);
	struct sk_buff *newskb=dev_alloc_skb(len+dev->hard_header_len+15);
	
	if(newskb==NULL)
		return;
		
	newskb->link3=NULL;
	newskb->sk=NULL;
	newskb->dev=dev;
	newskb->saddr=skb->saddr;
	newskb->daddr=skb->daddr;
	newskb->raddr=skb->raddr;
	newskb->free=1;
	newskb->lock=0;
	newskb->users=0;
	newskb->pkt_type=skb->pkt_type;
	
	/*
	 *	Put a MAC header on the packet
	 */
	ip_send(NULL,newskb, skb->ip_hdr->daddr, len, dev, skb->ip_hdr->saddr);
	/*
	 *	Add the rest of the data space.	
	 */
	newskb->ip_hdr=(struct iphdr *)skb_put(newskb, len);
	memcpy(newskb->proto_priv, skb->proto_priv, sizeof(skb->proto_priv));

	/*
	 *	Copy the data
	 */
	memcpy(newskb->ip_hdr,skb->ip_hdr,len);

	/* Recurse. The device check against IFF_LOOPBACK will stop infinite recursion */
		
	/*printk("Loopback output queued [%lX to %lX].\n", newskb->ip_hdr->saddr,newskb->ip_hdr->daddr);*/
	ip_queue_xmit(NULL, dev, newskb, 2);
}
Ejemplo n.º 6
0
static int ipq_daq_inject (
    void* handle, const DAQ_PktHdr_t* hdr, const uint8_t* buf, uint32_t len,
    int reverse)
{
    IpqImpl* impl = (IpqImpl*)handle;
    ssize_t sent = 0;

    if ( impl->link )
        sent = eth_send(impl->link, buf, len);

    else if ( impl->net )
        sent = ip_send(impl->net, buf, len);

    if ( (uint32_t)sent != len )
    {
        DPE(impl->error, "%s: failed to send",
            __FUNCTION__);
        return DAQ_ERROR;
    }
    impl->stats.packets_injected++;
    return DAQ_SUCCESS;
}
Ejemplo n.º 7
0
/*
 * Send a RST to destip, from port srcport to port dstport, acking seqnum.
 */
static int tcp_send_rst(unsigned long destip, unsigned short dstport, unsigned short srcport, unsigned long seqnum)
{
    unsigned char pkt[20];
    struct tcphdr *hdr = (struct tcphdr *)pkt;

    hdr->srcport = srcport;
    hdr->dstport = dstport;
    hdr->seqnum = 0; /* not used in this, right? */
    hdr->acknum = htonl(ntohl(seqnum)+1);
    hdr->hdrlen = 5; /* 20 / 4 = 5 */
    hdr->reserved1 = hdr->reserved2 = 0;
    hdr->cntrlbits = TCPBIT_RST | TCPBIT_ACK;
    hdr->window = 0;
    hdr->csum = 0;
    hdr->urgptr = 0;

    hdr->csum = tcp_checksum(pkt, hdr->hdrlen*4, htonl(INTERMOBI_OURIP), destip);

    ip_send(destip, IPPROTO_TCP, pkt, 20);

    return 0;
}
Ejemplo n.º 8
0
/* if packet->interface = NULL then the packet has been generated by the router  */
void ip_forward(struct sr_packet * packet)
{
    struct ip * ip_hdr = IP_HDR(packet);
    uint32_t next_hop;
    char thru_interface[SR_NAMELEN];

    /* if the destination is to one of our ports, then just forward it there  */
    if(interface_list_get_interface_by_ip(INTERFACE_LIST(packet->sr), ip_hdr->ip_dst.s_addr))
    {
        ip_handle_incoming_packet(packet);
    }
    else
    {
        if(forwarding_table_lookup_next_hop(ROUTER(packet->sr)->fwd_table,
                                            ip_hdr->ip_dst.s_addr, &next_hop, thru_interface,
                                            interface_list_inbound(packet->sr, packet->interface)) &&
           interface_list_forward_packet(packet->sr, packet->interface, thru_interface))
        {
            if(next_hop == 0)
            {
                next_hop = ip_hdr->ip_dst.s_addr;
            }
            ip_hdr->ip_ttl --;
            ip_hdr->ip_sum = checksum_ipheader(ip_hdr);
            ip_send(packet,next_hop,thru_interface);
        }
        else
        {
            if(forwarding_table_lookup_next_hop(ROUTER(packet->sr)->fwd_table,
                                                ip_hdr->ip_src.s_addr, 0,0,
                                                interface_list_inbound(packet->sr, packet->interface)))
            {
                icmp_send_host_unreachable(packet);
            }
        }
    }
}
Ejemplo n.º 9
0
/*------------------------------------------------------------------------
 * udp_sendto  -  Send a UDP packet to a specified destination
 *------------------------------------------------------------------------
 */
status	udp_sendto (
	 uid32	slot,			/* UDP table slot to use	*/
	 uint32	remip,			/* Remote IP address to use	*/
	 uint16	remport,		/* Remote protocol port to use	*/
	 char   *buff,			/* Buffer of UDP data		*/
	 int32	len			/* Length of data in buffer	*/
	)
{
	intmask	mask;			/* Saved interrupt mask		*/
	struct	netpacket *pkt;		/* Pointer to a packet buffer	*/
	int32	pktlen;			/* Total packet length		*/
	static	uint16 ident = 1;	/* Datagram IDENT field		*/
	struct	udpentry *udptr;	/* Pointer to a UDP table entry	*/
	char	*udataptr;		/* Pointer to UDP data		*/

	/* Ensure only one process can access the UDP table at a time	*/

	mask = disable();

	/* Verify that the slot is valid */

	if ( (slot < 0) || (slot >= UDP_SLOTS) ) {
		restore(mask);
		return SYSERR;
	}

	/* Get pointer to table entry */

	udptr = &udptab[slot];

	/* Verify that the slot has been registered and is valid */

	if (udptr->udstate == UDP_FREE) {
		restore(mask);
		return SYSERR;
	}

	/* Allocate a network buffer to hold the packet */

	pkt = (struct netpacket *)getbuf(netbufpool);

	if ((int32)pkt == SYSERR) {
		restore(mask);
		return SYSERR;
	}

	/* Compute packet length as UDP data size + fixed header size	*/

	pktlen = ((char *)&pkt->net_udpdata - (char *)pkt) + len;

	/* Create UDP packet in pkt */

	memcpy((char *)pkt->net_ethsrc,NetData.ethucast,ETH_ADDR_LEN);
        pkt->net_ethtype = 0x0800;	/* Type is IP */
	pkt->net_ipvh = 0x45;		/* IP version and hdr length	*/
	pkt->net_iptos = 0x00;		/* Type of service		*/
	pkt->net_iplen= pktlen - ETH_HDR_LEN;/* total IP datagram length*/
	pkt->net_ipid = ident++;	/* Datagram gets next IDENT	*/
	pkt->net_ipfrag = 0x0000;	/* IP flags & fragment offset	*/
	pkt->net_ipttl = 0xff;		/* IP time-to-live		*/
	pkt->net_ipproto = IP_UDP;	/* Datagram carries UDP		*/
	pkt->net_ipcksum = 0x0000;	/* Initial checksum		*/
	pkt->net_ipsrc = NetData.ipucast;/* IP source address		*/
	pkt->net_ipdst = remip;		/* IP destination address	*/
	pkt->net_udpsport = udptr->udlocport;/* local UDP protocol port	*/
	pkt->net_udpdport = remport;	/* Remote UDP protocol port	*/
	pkt->net_udplen = (uint16)(UDP_HDR_LEN+len); /* UDP length	*/
	pkt->net_udpcksum = 0x0000;	/* Ignore UDP checksum		*/
	udataptr = (char *) pkt->net_udpdata;
	for (; len>0; len--) {
		*udataptr++ = *buff++;
	}

	/* Call ipsend to send the datagram */

	ip_send(pkt);
	restore(mask);
	return OK;
}
Ejemplo n.º 10
0
/*
 *	Handle ICMP messages in the outside-to-inside direction (incoming)
 *	and sometimes in outgoing direction from ip_vs_forward_icmp.
 *	Find any that might be relevant, check against existing connections,
 *	forward to the right destination host if relevant.
 *	Currently handles error types - unreachable, quench, ttl exceeded.
 */
static int ip_vs_in_icmp(struct sk_buff **skb_p)
{
	struct sk_buff	*skb   = *skb_p;
	struct iphdr    *iph;
	struct icmphdr  *icmph;
	struct iphdr    *ciph;	/* The ip header contained within the ICMP */
	__u16	        *pptr;	/* port numbers from TCP/UDP contained header */
	unsigned short   len;
	unsigned short	clen, csize;
	struct ip_vs_conn *cp;
	struct rtable *rt;			/* Route to the other host */
	int    mtu;

	if (skb_is_nonlinear(skb)) {
		if (skb_linearize(skb, GFP_ATOMIC) != 0)
			return NF_DROP;
	}

	iph = skb->nh.iph;
	ip_send_check(iph);
	icmph = (struct icmphdr *)((char *)iph + (iph->ihl << 2));
	len = ntohs(iph->tot_len) - (iph->ihl<<2);
	if (len < sizeof(struct icmphdr))
		return NF_DROP;

	IP_VS_DBG(12, "icmp in (%d,%d) %u.%u.%u.%u -> %u.%u.%u.%u\n",
		  icmph->type, ntohs(icmp_id(icmph)),
		  NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));

	if ((icmph->type != ICMP_DEST_UNREACH) &&
	    (icmph->type != ICMP_SOURCE_QUENCH) &&
	    (icmph->type != ICMP_TIME_EXCEEDED))
		return NF_ACCEPT;

	/*
	 * If we get here we have an ICMP error of one of the above 3 types
	 * Now find the contained IP header
	 */
	clen = len - sizeof(struct icmphdr);
	if (clen < sizeof(struct iphdr))
		return NF_DROP;
	ciph = (struct iphdr *) (icmph + 1);
	csize = ciph->ihl << 2;
	if (clen < csize)
		return NF_DROP;

	/* We are only interested ICMPs generated from TCP or UDP packets */
	if (ciph->protocol != IPPROTO_UDP && ciph->protocol != IPPROTO_TCP)
		return NF_ACCEPT;

	/* Skip non-first embedded TCP/UDP fragments */
	if (ciph->frag_off & __constant_htons(IP_OFFSET))
		return NF_ACCEPT;

	/* We need at least TCP/UDP ports here */
	if (clen < csize + sizeof(struct udphdr))
		return NF_DROP;

	/* Ensure the checksum is correct */
	if (ip_compute_csum((unsigned char *) icmph, len)) {
		/* Failed checksum! */
		IP_VS_ERR_RL("incoming ICMP: failed checksum from "
			     "%d.%d.%d.%d!\n", NIPQUAD(iph->saddr));
		return NF_DROP;
	}

	pptr = (__u16 *)&(((char *)ciph)[csize]);

	IP_VS_DBG(11, "Handling incoming ICMP for "
		  "%u.%u.%u.%u:%d -> %u.%u.%u.%u:%d\n",
		  NIPQUAD(ciph->saddr), ntohs(pptr[0]),
		  NIPQUAD(ciph->daddr), ntohs(pptr[1]));

	/* This is pretty much what ip_vs_conn_in_get() does,
	   except parameters are in the reverse order */
	cp = ip_vs_conn_in_get(ciph->protocol,
			       ciph->daddr, pptr[1],
			       ciph->saddr, pptr[0]);
	if (cp == NULL)
		return NF_ACCEPT;

	ip_vs_in_stats(cp, skb);

	/* The ICMP packet for VS/TUN, VS/DR and LOCALNODE will be
	   forwarded directly here, because there is no need to
	   translate address/port back */
	if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) {
		int ret;
		if (cp->packet_xmit)
			ret = cp->packet_xmit(skb, cp);
		else
			ret = NF_ACCEPT;
		atomic_inc(&cp->in_pkts);
		ip_vs_conn_put(cp);
		return ret;
	}

	/*
	 * mangle and send the packet here
	 */
	if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(iph->tos))))
		goto tx_error_icmp;

	/* MTU checking */
	mtu = rt->u.dst.pmtu;
	if ((skb->len > mtu) && (iph->frag_off&__constant_htons(IP_DF))) {
		ip_rt_put(rt);
		icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu));
		IP_VS_DBG_RL("ip_vs_in_icmp(): frag needed\n");
		goto tx_error;
	}

	/* drop old route */
	dst_release(skb->dst);
	skb->dst = &rt->u.dst;

	/* copy-on-write the packet before mangling it */
	if (ip_vs_skb_cow(skb, rt->u.dst.dev->hard_header_len,
			  &iph, (unsigned char**)&icmph)) {
		ip_vs_conn_put(cp);
		return NF_DROP;
	}
	ciph = (struct iphdr *) (icmph + 1);
	pptr = (__u16 *)&(((char *)ciph)[csize]);

	/* The ICMP packet for VS/NAT must be written to correct addresses
	   before being forwarded to the right server */

	/* First change the dest IP address, and recalc checksum */
	iph->daddr = cp->daddr;
	ip_send_check(iph);

	/* Now change the *source* address in the contained IP */
	ciph->saddr = cp->daddr;
	ip_send_check(ciph);

	/* the TCP/UDP source port - cannot redo check */
	pptr[0] = cp->dport;

	/* And finally the ICMP checksum */
	icmph->checksum = 0;
	icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
	skb->ip_summed = CHECKSUM_UNNECESSARY;

	IP_VS_DBG(11, "Forwarding incoming ICMP to "
		  "%u.%u.%u.%u:%d -> %u.%u.%u.%u:%d\n",
		  NIPQUAD(ciph->saddr), ntohs(pptr[0]),
		  NIPQUAD(ciph->daddr), ntohs(pptr[1]));

#ifdef CONFIG_NETFILTER_DEBUG
	skb->nf_debug = 1 << NF_IP_LOCAL_OUT;
#endif /* CONFIG_NETFILTER_DEBUG */
	ip_send(skb);
	ip_vs_conn_put(cp);
	return NF_STOLEN;

  tx_error_icmp:
	dst_link_failure(skb);
  tx_error:
	dev_kfree_skb(skb);
	ip_vs_conn_put(cp);
	return NF_STOLEN;
}
Ejemplo n.º 11
0
//------------------------------------------------------------------------
// This handles incoming ARP messages
// See "TCP/IP Illustrated, Volume 1" Sect 4.4
// Todo:  Resolve problem of trying to add to a full cache
//------------------------------------------------------------------------
void arp_rcve(UCHAR xdata * inbuf)
{
   UCHAR idata i, cached, oldest;
   UINT idata minimum;
   ARP_HEADER xdata * arp;
      
   arp = (ARP_HEADER xdata *)(inbuf + 14);
   cached = FALSE;
   
   // Print message
   if (debug)
   {
      if (arp->message_type == ARP_REQUEST)
         serial_send("ARP: Request rcvd\r");
      else serial_send("ARP: Response rcvd\r");
   }
         
   // Validate incoming frame
   if ((arp->hardware_type != DIX_ETHERNET) ||
       (arp->protocol_type != IP_PACKET)) return;

   // Search ARP cache for senders IP address
   // If found, update entry and restart timer
   for (i=0; i < CACHESIZE; i++)
   {
      if (arp_cache[i].ipaddr == arp->source_ipaddr)
      {
         memcpy(&arp_cache[i].hwaddr[0], &arp->source_hwaddr[0], 6);
         arp_cache[i].timer = CACHETIME;		
         cached = TRUE;
         if (debug) serial_send("ARP: Cache entry updated\r");
                  
         break;  
      }
   }
   
   if (arp->dest_ipaddr != my_ipaddr) return;
   
   // At this point we know the the frame is addressed to me
   // If not already in cache then add entry and start timer
   if (cached == FALSE)
   {
      // Find first blank space and add entry
		// Blank entries are indicated by ip addr = 0
      for (i=0; i < CACHESIZE; i++)
      {
         if (arp_cache[i].ipaddr == 0) 
         {
            arp_cache[i].ipaddr = arp->source_ipaddr;
            memcpy(&arp_cache[i].hwaddr[0], &arp->source_hwaddr[0], 6);   
            arp_cache[i].timer = CACHETIME;
         	if (debug) serial_send("ARP: New cache entry added\r");
         	break;
         }
      }

		// If no blank entries in arp cache	then sort cache
		// to find oldest entry and replace it
		if (i == CACHESIZE)
		{
			// Oldest entry is the one with lowest timer value			
			minimum = 0xFFFF;
			for (i=0; i < CACHESIZE; i++)
      	{
				if (arp_cache[i].timer < minimum) 
				{
					minimum = arp_cache[i].timer;
					oldest = i;
				}
			}
      	
			// "oldest" is now index of oldest entry, so replace it
			arp_cache[oldest].ipaddr = arp->source_ipaddr;
         memcpy(&arp_cache[oldest].hwaddr[0], &arp->source_hwaddr[0], 6);   
         arp_cache[oldest].timer = CACHETIME;
        if (debug) serial_send("ARP: Cache full, so replaced oldest\r");
   	}
	}

   
   // If we are waiting for an arp response and the arp response
  	// that just came in is addressed to me and is from the host
  	// we are waiting for, then send	the message-in-waiting
   if (arp->message_type == ARP_RESPONSE)
   {
   	if ((waiting_for_arp) && (wait.ipaddr == arp->source_ipaddr))
   	{
   		waiting_for_arp = FALSE;
		  	ip_send(wait.buf, wait.ipaddr, wait.proto_id, wait.len);
		}
	}
	else if (arp->message_type == ARP_REQUEST)
   {
    	// Send ARP response 
    	if (debug) serial_send("ARP: Sending response\r");
    	arp_send(arp->source_hwaddr, arp->source_ipaddr, ARP_RESPONSE);
	}
}
Ejemplo n.º 12
0
/*
 * This is a bit complicated because we attempt to stuff everything
 * we've already sent that hasn't been acked into this packet, along
 * with the new data.
 *
 * XXX check the endpoint window and MSS to make sure we don't overflow it.
 *
 */
static int tcp_send_data(struct tcp_socket *sk, const unsigned char *data, int datalen)
{
    unsigned char *pkt;
    struct tcphdr *hdr;
    struct tcpvec *cur;
    unsigned short flags = 0;
    unsigned long seqnum;

    /* First, enqueue the new data and increment the next seqnum */
    if (data && datalen)
        tcp_txenqueue(sk, 0, sk->snd_nxt, bufdup(data, datalen), datalen);

    for (cur = sk->txqueue, datalen = 0, seqnum = sk->snd_nxt;
            cur && (datalen < sk->rcv_max); cur = cur->next) {

        if (cur->txcount >= TCP_MAX_RETRIES) {
            tcp_changestate(sk, STATE_TIME_WAIT);
            tcp_send_fin(sk);
            return -1;
        }

        flags |= cur->flags;
        if (cur->seqnum < seqnum)
            seqnum = cur->seqnum; /* get the lowest seqnum queued */
        datalen += cur->len;
    }

    dprintf("tcp_send_data: procesing %d queued bytes\n", datalen);

    if (!(pkt = RimMalloc(20+datalen)))
        return -1;

    hdr = (struct tcphdr *)pkt;

    hdr->srcport = htons(sk->localport);
    hdr->dstport = htons(sk->remoteport);

    if (sk->snd_nxt < sk->snd_una)
        sk->snd_una = sk->snd_nxt;

    hdr->seqnum = htonl(seqnum);
    hdr->acknum = htonl(sk->rcv_nxt);

    hdr->hdrlen = 5; /* 20 / 4 = 5 */
    hdr->reserved1 = hdr->reserved2 = 0;
    hdr->cntrlbits = TCPBIT_ACK | flags | (!flags ? TCPBIT_PSH : 0);
    hdr->window = htons(TCP_DEFAULT_WINDOW);
    hdr->csum = 0;
    hdr->urgptr = 0;

    for (cur = sk->txqueue, flags = 20; cur; cur = cur->next) {
        memcpy(pkt+flags, cur->buf+cur->start, cur->len);
        flags += cur->len;
        cur->lasttx = RimGetTicks();
        cur->txcount++;
    }

    hdr->csum = tcp_checksum(pkt, (hdr->hdrlen*4)+datalen,
                             htonl(INTERMOBI_OURIP), htonl(sk->remoteaddr));

    ip_send(htonl(sk->remoteaddr), IPPROTO_TCP, pkt, 20+datalen);

    RimFree(pkt);

    return 0;
}
Ejemplo n.º 13
0
/*
 * This routine builds the appropriate hardware/IP headers for
 * the routine.  It assumes that if *dev != NULL then the
 * protocol knows what it's doing, otherwise it uses the
 * routing/ARP tables to select a device struct.
 */
int ip_build_header(struct sk_buff *skb, __u32 saddr, __u32 daddr,
		struct device **dev, int type, struct options *opt,
		int len, int tos, int ttl, struct rtable ** rp)
{
	struct rtable *rt;
	__u32 raddr;
	int tmp;
	struct iphdr *iph;
	__u32 final_daddr = daddr;


	if (opt && opt->srr)
		daddr = opt->faddr;

	/*
	 *	See if we need to look up the device.
	 */

#ifdef CONFIG_IP_MULTICAST	
	if(MULTICAST(daddr) && *dev==NULL && skb->sk && *skb->sk->ip_mc_name)
		*dev=dev_get(skb->sk->ip_mc_name);
#endif
	if (rp)
	{
		rt = ip_check_route(rp, daddr, skb->localroute, *dev);
		/*
		 * If rp != NULL rt_put following below should not
		 * release route, so that...
		 */
		if (rt)
			atomic_inc(&rt->rt_refcnt);
	}
	else
		rt = ip_rt_route(daddr, skb->localroute, *dev);


	if (*dev == NULL)
	{
		if (rt == NULL)
		{
			ip_statistics.IpOutNoRoutes++;
			return(-ENETUNREACH);
		}

		*dev = rt->rt_dev;
	}

	if ((LOOPBACK(saddr) && !LOOPBACK(daddr)) || !saddr)
		saddr = rt ? rt->rt_src : (*dev)->pa_addr;

	raddr = rt ? rt->rt_gateway : daddr;

	if (opt && opt->is_strictroute && rt && (rt->rt_flags & RTF_GATEWAY))
	{
		ip_rt_put(rt);
		ip_statistics.IpOutNoRoutes++;
		return -ENETUNREACH;
	}

	/*
	 *	Now build the MAC header.
	 */

	if (type==IPPROTO_TCP)
		tmp = ip_send_room(rt, skb, raddr, len, *dev, saddr);
	else
		tmp = ip_send(rt, skb, raddr, len, *dev, saddr);

	ip_rt_put(rt);

	/*
	 *	Book keeping
	 */

	skb->dev = *dev;
	skb->saddr = saddr;
	
	/*
	 *	Now build the IP header.
	 */

	/*
	 *	If we are using IPPROTO_RAW, then we don't need an IP header, since
	 *	one is being supplied to us by the user
	 */

	if(type == IPPROTO_RAW)
		return (tmp);

	/*
	 *	Build the IP addresses
	 */
	 
	if (opt)
		iph=(struct iphdr *)skb_put(skb,sizeof(struct iphdr) + opt->optlen);
	else
		iph=(struct iphdr *)skb_put(skb,sizeof(struct iphdr));

	iph->version  = 4;
	iph->ihl      = 5;
	iph->tos      = tos;
	iph->frag_off = 0;
	iph->ttl      = ttl;
	iph->daddr    = daddr;
	iph->saddr    = saddr;
	iph->protocol = type;
	skb->ip_hdr   = iph;

	if (!opt || !opt->optlen)
		return sizeof(struct iphdr) + tmp;
	iph->ihl += opt->optlen>>2;
	ip_options_build(skb, opt, final_daddr, (*dev)->pa_addr, 0);
	return iph->ihl*4 + tmp;
}
Ejemplo n.º 14
0
static inline int ipsec_mast_xmit2(struct sk_buff *skb)
{
	return ip_send(skb);
}
Ejemplo n.º 15
0
/*
 * This routine builds the appropriate hardware/IP headers for
 * the routine.  It assumes that if *dev != NULL then the
 * protocol knows what it's doing, otherwise it uses the
 * routing/ARP tables to select a device struct.
 */
int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr,
		struct device **dev, int type, struct options *opt, int len, int tos, int ttl)
{
	static struct options optmem;
	struct iphdr *iph;
	struct rtable *rt;
	unsigned char *buff;
	unsigned long raddr;
	int tmp;
	unsigned long src;

	/*
	 *	If there is no 'from' address as yet, then make it our loopback
	 */

	if (saddr == 0)
		saddr = ip_my_addr();

	buff = skb->data;

	/*
	 *	See if we need to look up the device.
	 */

	if (*dev == NULL)
	{
		if(skb->localroute)
			rt = ip_rt_local(daddr, &optmem, &src);
		else
			rt = ip_rt_route(daddr, &optmem, &src);
		if (rt == NULL)
		{
			ip_statistics.IpOutNoRoutes++;
			return(-ENETUNREACH);
		}

		*dev = rt->rt_dev;
		/*
		 *	If the frame is from us and going off machine it MUST MUST MUST
		 *	have the output device ip address and never the loopback
		 */
		if (LOOPBACK(saddr) && !LOOPBACK(daddr))
			saddr = src;/*rt->rt_dev->pa_addr;*/
		raddr = rt->rt_gateway;

		opt = &optmem;
	}
	else
	{
		/*
		 *	We still need the address of the first hop.
		 */
		if(skb->localroute)
			rt = ip_rt_local(daddr, &optmem, &src);
		else
			rt = ip_rt_route(daddr, &optmem, &src);
		/*
		 *	If the frame is from us and going off machine it MUST MUST MUST
		 *	have the output device ip address and never the loopback
		 */
		if (LOOPBACK(saddr) && !LOOPBACK(daddr))
			saddr = src;/*rt->rt_dev->pa_addr;*/

		raddr = (rt == NULL) ? 0 : rt->rt_gateway;
	}

	/*
	 *	No gateway so aim at the real destination
	 */
	if (raddr == 0)
		raddr = daddr;

	/*
	 *	Now build the MAC header.
	 */

	tmp = ip_send(skb, raddr, len, *dev, saddr);
	buff += tmp;
	len -= tmp;

	/*
	 *	Book keeping
	 */

	skb->dev = *dev;
	skb->saddr = saddr;
	if (skb->sk)
		skb->sk->saddr = saddr;

	/*
	 *	Now build the IP header.
	 */

	/*
	 *	If we are using IPPROTO_RAW, then we don't need an IP header, since
	 *	one is being supplied to us by the user
	 */

	if(type == IPPROTO_RAW)
		return (tmp);

	iph = (struct iphdr *)buff;
	iph->version  = 4;
	iph->tos      = tos;
	iph->frag_off = 0;
	iph->ttl      = ttl;
	iph->daddr    = daddr;
	iph->saddr    = saddr;
	iph->protocol = type;
	iph->ihl      = 5;

	/* Setup the IP options. */
#ifdef Not_Yet_Avail
	build_options(iph, opt);
#endif

	return(20 + tmp);	/* IP header plus MAC header size */
}
Ejemplo n.º 16
0
/* Need this wrapper because NF_HOOK takes the function address */
static inline int do_ip_send(struct sk_buff *skb)
{
	return ip_send(skb);
}
Ejemplo n.º 17
0
static int ipip_tunnel_xmit(struct sk_buff *skb, struct device *dev)
{
	struct ip_tunnel *tunnel = (struct ip_tunnel*)dev->priv;
	struct net_device_stats *stats = &tunnel->stat;
	struct iphdr  *tiph = &tunnel->parms.iph;
	u8     tos = tunnel->parms.iph.tos;
	u16    df = tiph->frag_off;
	struct rtable *rt;     			/* Route to the other host */
	struct device *tdev;			/* Device to other host */
	struct iphdr  *old_iph = skb->nh.iph;
	struct iphdr  *iph;			/* Our new IP header */
	int    max_headroom;			/* The extra header space needed */
	u32    dst = tiph->daddr;
	int    mtu;

	if (tunnel->recursion++) {
		tunnel->stat.collisions++;
		goto tx_error;
	}

	if (skb->protocol != __constant_htons(ETH_P_IP))
		goto tx_error;

	if (tos&1)
		tos = old_iph->tos;

	if (!dst) {
		/* NBMA tunnel */
		if ((rt = (struct rtable*)skb->dst) == NULL) {
			tunnel->stat.tx_fifo_errors++;
			goto tx_error;
		}
		if ((dst = rt->rt_gateway) == 0)
			goto tx_error_icmp;
	}

	if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.link)) {
		tunnel->stat.tx_carrier_errors++;
		goto tx_error_icmp;
	}
	tdev = rt->u.dst.dev;

	if (tdev == dev) {
		ip_rt_put(rt);
		tunnel->stat.collisions++;
		goto tx_error;
	}

	mtu = rt->u.dst.pmtu - sizeof(struct iphdr);
	if (mtu < 68) {
		tunnel->stat.collisions++;
		ip_rt_put(rt);
		goto tx_error;
	}
	if (skb->dst && mtu < skb->dst->pmtu)
		skb->dst->pmtu = mtu;

	df |= (old_iph->frag_off&__constant_htons(IP_DF));

	if ((old_iph->frag_off&__constant_htons(IP_DF)) && mtu < ntohs(old_iph->tot_len)) {
		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
		ip_rt_put(rt);
		goto tx_error;
	}

	if (tunnel->err_count > 0) {
		if (jiffies - tunnel->err_time < IPTUNNEL_ERR_TIMEO) {
			tunnel->err_count--;
			dst_link_failure(skb);
		} else
			tunnel->err_count = 0;
	}

	skb->h.raw = skb->nh.raw;

	/*
	 * Okay, now see if we can stuff it in the buffer as-is.
	 */
	max_headroom = (((tdev->hard_header_len+15)&~15)+sizeof(struct iphdr));

	if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) {
		struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
		if (!new_skb) {
			ip_rt_put(rt);
  			stats->tx_dropped++;
			dev_kfree_skb(skb);
			tunnel->recursion--;
			return 0;
		}
		if (skb->sk)
			skb_set_owner_w(new_skb, skb->sk);
		dev_kfree_skb(skb);
		skb = new_skb;
	}

	skb->nh.raw = skb_push(skb, sizeof(struct iphdr));
	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
	dst_release(skb->dst);
	skb->dst = &rt->u.dst;

	/*
	 *	Push down and install the IPIP header.
	 */

	iph 			=	skb->nh.iph;
	iph->version		=	4;
	iph->ihl		=	sizeof(struct iphdr)>>2;
	iph->frag_off		=	df;
	iph->protocol		=	IPPROTO_IPIP;
	iph->tos		=	tos;
	iph->daddr		=	rt->rt_dst;
	iph->saddr		=	rt->rt_src;

	if ((iph->ttl = tiph->ttl) == 0)
		iph->ttl	=	old_iph->ttl;

	iph->tot_len		=	htons(skb->len);
	iph->id			=	htons(ip_id_count++);
	ip_send_check(iph);

	stats->tx_bytes += skb->len;
	stats->tx_packets++;
	ip_send(skb);
	tunnel->recursion--;
	return 0;

tx_error_icmp:
	dst_link_failure(skb);
tx_error:
	stats->tx_errors++;
	dev_kfree_skb(skb);
	tunnel->recursion--;
	return 0;
}
Ejemplo n.º 18
0
/* Return an ICMP response to the sender of a datagram.
 * Unlike most routines, the callER frees the mbuf.
 */
int
icmp_output(
struct ip *ip,          /* Header of offending datagram */
struct mbuf *data,      /* Data portion of datagram - FREED BY CALLER */
uint8 type,             /* Codes to send */
uint8 code,
union icmp_args *args
){
	struct mbuf *bp;
	struct icmp icmp;       /* ICMP protocol header */
	uint dlen;              /* Length of data portion of offending pkt */
	uint length;            /* Total length of reply */

	if(ip == NULL)
		return -1;
	if(ip->protocol == ICMP_PTCL){
		/* Peek at type field of ICMP header to see if it's safe to
		 * return an ICMP message
		 */
		switch(data->data[0]){
		case ICMP_ECHO_REPLY:
		case ICMP_ECHO:
		case ICMP_TIMESTAMP:
		case ICMP_TIME_REPLY:
		case ICMP_INFO_RQST:
		case ICMP_INFO_REPLY:
			break;  /* These are all safe */
		default:
			/* Never send an ICMP error message about another
			 * ICMP error message!
			 */
			return -1;
		}
	}
	/* Compute amount of original datagram to return.
	 * We return the original IP header, and up to 8 bytes past that.
	 */
	dlen = min(8,len_p(data));
	length = dlen + ICMPLEN + IPLEN + ip->optlen;
	/* Take excerpt from data portion */
	if(data != NULL && dup_p(&bp,data,0,dlen) == 0)
		return -1;      /* The caller will free data */

	/* Recreate and tack on offending IP header */
	htonip(ip,&bp,IP_CS_NEW);
	icmp.type = type;
	icmp.code = code;
	icmp.args.unused = 0;
	switch(icmp.type){
	case ICMP_PARAM_PROB:
		icmpOutParmProbs++;
		icmp.args.pointer = args->pointer;
		break;
	case ICMP_REDIRECT:
		icmpOutRedirects++;
		icmp.args.address = args->address;
		break;
	case ICMP_ECHO:
		icmpOutEchos++;
		break;
	case ICMP_ECHO_REPLY:
		icmpOutEchoReps++;
		break;
	case ICMP_INFO_RQST:
		break;
	case ICMP_INFO_REPLY:
		break;
	case ICMP_TIMESTAMP:
		icmpOutTimestamps++;
		break;
	case ICMP_TIME_REPLY:
		icmpOutTimestampReps++;
		icmp.args.echo.id = args->echo.id;
		icmp.args.echo.seq = args->echo.seq;
		break;
	case ICMP_ADDR_MASK:
		icmpOutAddrMasks++;
		break;
	case ICMP_ADDR_MASK_REPLY:
		icmpOutAddrMaskReps++;
		break;
	case ICMP_DEST_UNREACH:
		if(icmp.code == ICMP_FRAG_NEEDED)
			icmp.args.mtu = args->mtu;
		icmpOutDestUnreachs++;
		break;
	case ICMP_TIME_EXCEED:
		icmpOutTimeExcds++;
		break;
	case ICMP_QUENCH:
		icmpOutSrcQuenchs++;
		break;
	}
	icmpOutMsgs++;
	/* Now stick on the ICMP header */
	htonicmp(&icmp,&bp);
	return ip_send(INADDR_ANY,ip->source,ICMP_PTCL,ip->tos,0,&bp,length,0,0);
}