patch-2.1.15 linux/drivers/net/new_tunnel.c
Next file: linux/drivers/net/plip.c
Previous file: linux/drivers/net/net_init.c
Back to the patch index
Back to the overall index
- Lines: 435
- Date:
Thu Jan 1 02:00:00 1970
- Orig file:
v2.1.14/linux/drivers/net/new_tunnel.c
- Orig date:
Fri Jul 19 08:24:05 1996
diff -u --recursive --new-file v2.1.14/linux/drivers/net/new_tunnel.c linux/drivers/net/new_tunnel.c
@@ -1,434 +0,0 @@
-/* tunnel.c: an IP tunnel driver
-
- The purpose of this driver is to provide an IP tunnel through
- which you can tunnel network traffic transparently across subnets.
-
- This was written by looking at Nick Holloway's dummy driver
- Thanks for the great code!
-
- -Sam Lantinga (slouken@cs.ucdavis.edu) 02/01/95
-
- Minor tweaks:
- Cleaned up the code a little and added some pre-1.3.0 tweaks.
- dev->hard_header/hard_header_len changed to use no headers.
- Comments/bracketing tweaked.
- Made the tunnels use dev->name not tunnel: when error reporting.
- Added tx_dropped stat
-
- -Alan Cox (Alan.Cox@linux.org) 21 March 95
-
- Reworked:
- Changed to tunnel to destination gateway in addition to the
- tunnel's pointopoint address
- Almost completely rewritten
- Note: There is currently no firewall or ICMP handling done.
-
- -Sam Lantinga (slouken@cs.ucdavis.edu) 02/13/96
-
- Note:
- The old driver is in tunnel.c if you have funnies with the
- new one.
-*/
-
-/* Things I wish I had known when writing the tunnel driver:
-
- When the tunnel_xmit() function is called, the skb contains the
- packet to be sent (plus a great deal of extra info), and dev
- contains the tunnel device that _we_ are.
-
- When we are passed a packet, we are expected to fill in the
- source address with our source IP address.
-
- What is the proper way to allocate, copy and free a buffer?
- After you allocate it, it is a "0 length" chunk of memory
- starting at zero. If you want to add headers to the buffer
- later, you'll have to call "skb_reserve(skb, amount)" with
- the amount of memory you want reserved. Then, you call
- "skb_put(skb, amount)" with the amount of space you want in
- the buffer. skb_put() returns a pointer to the top (#0) of
- that buffer. skb->len is set to the amount of space you have
- "allocated" with skb_put(). You can then write up to skb->len
- bytes to that buffer. If you need more, you can call skb_put()
- again with the additional amount of space you need. You can
- find out how much more space you can allocate by calling
- "skb_tailroom(skb)".
- Now, to add header space, call "skb_push(skb, header_len)".
- This creates space at the beginning of the buffer and returns
- a pointer to this new space. If later you need to strip a
- header from a buffer, call "skb_pull(skb, header_len)".
- skb_headroom() will return how much space is left at the top
- of the buffer (before the main data). Remember, this headroom
- space must be reserved before the skb_put() function is called.
-*/
-
-#include <linux/module.h>
-#include <linux/config.h> /* for CONFIG_IP_FORWARD */
-
-/* Only two headers!! :-) */
-#include <net/ip.h>
-#include <linux/if_arp.h>
-
-
-/*#define TUNNEL_DEBUG*/
-
-/*
- * Our header is a simple IP packet with no options
- */
-
-#define tunnel_hlen sizeof(struct iphdr)
-
-/*
- * Okay, this needs to be high enough that we can fit a "standard"
- * ethernet header and an IP tunnel header into the outgoing packet.
- * [36 bytes]
- */
-
-#define TUNL_HLEN (((ETH_HLEN+15)&~15)+tunnel_hlen)
-
-
-static int tunnel_open(struct device *dev)
-{
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-static int tunnel_close(struct device *dev)
-{
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-#ifdef TUNNEL_DEBUG
-void print_ip(struct iphdr *ip)
-{
- unsigned char *ipaddr;
-
- printk("IP packet:\n");
- printk("--- header len = %d\n", ip->ihl*4);
- printk("--- ip version: %d\n", ip->version);
- printk("--- ip protocol: %d\n", ip->protocol);
- ipaddr=(unsigned char *)&ip->saddr;
- printk("--- source address: %u.%u.%u.%u\n",
- *ipaddr, *(ipaddr+1), *(ipaddr+2), *(ipaddr+3));
- ipaddr=(unsigned char *)&ip->daddr;
- printk("--- destination address: %u.%u.%u.%u\n",
- *ipaddr, *(ipaddr+1), *(ipaddr+2), *(ipaddr+3));
- printk("--- total packet len: %d\n", ntohs(ip->tot_len));
-}
-#endif
-
-/*
- * This function assumes it is being called from dev_queue_xmit()
- * and that skb is filled properly by that function.
- */
-
-static int tunnel_xmit(struct sk_buff *skb, struct device *dev)
-{
- struct enet_statistics *stats; /* This device's statistics */
- struct rtable *rt; /* Route to the other host */
- struct device *tdev; /* Device to other host */
- struct iphdr *iph; /* Our new IP header */
- __u32 target; /* The other host's IP address */
- int max_headroom; /* The extra header space needed */
-
- /*
- * Return if there is nothing to do. (Does this ever happen?)
- */
- if (skb == NULL || dev == NULL) {
-#ifdef TUNNEL_DEBUG
- printk ( KERN_INFO "tunnel: Nothing to do!\n" );
-#endif
- return 0;
- }
-
- /*
- * Make sure we are not busy (check lock variable)
- */
-
- stats = (struct enet_statistics *)dev->priv;
- cli();
- if (dev->tbusy != 0)
- {
- sti();
- stats->tx_errors++;
- return(1);
- }
- dev->tbusy = 1;
- sti();
-
- /*printk("-");*/
- /*
- * First things first. Look up the destination address in the
- * routing tables
- */
- iph = (struct iphdr *) skb->data;
- if ((rt = ip_rt_route(iph->daddr, 0)) == NULL)
- {
- /* No route to host */
- /* Where did the packet come from? */
- /*icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_UNREACH, 0, dev);*/
- printk ( KERN_INFO "%s: Packet with no route!\n", dev->name);
- dev->tbusy=0;
- stats->tx_errors++;
- dev_kfree_skb(skb, FREE_WRITE);
- return 0;
- }
-
- /*
- * Get the target address (other end of IP tunnel)
- */
- if (rt->rt_flags & RTF_GATEWAY)
- target = rt->rt_gateway;
- else
- target = dev->pa_dstaddr;
-
- if ( ! target )
- { /* No gateway to tunnel through? */
- /* Where did the packet come from? */
- /*icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_UNREACH, 0, dev);*/
- printk ( KERN_INFO "%s: Packet with no target gateway!\n", dev->name);
- ip_rt_put(rt);
- dev->tbusy=0;
- stats->tx_errors++;
- dev_kfree_skb(skb, FREE_WRITE);
- return 0;
- }
- ip_rt_put(rt);
-
- if ((rt = ip_rt_route(target, 0)) == NULL)
- {
- /* No route to host */
- /* Where did the packet come from? */
- /*icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_UNREACH, 0, dev);*/
- printk ( KERN_INFO "%s: Can't reach target gateway!\n", dev->name);
- dev->tbusy=0;
- stats->tx_errors++;
- dev_kfree_skb(skb, FREE_WRITE);
- return 0;
- }
- tdev = rt->rt_dev;
-
- if (tdev == dev)
- {
- /* Tunnel to ourselves? -- I don't think so. */
- printk ( KERN_INFO "%s: Packet targetted at myself!\n" , dev->name);
- ip_rt_put(rt);
- dev->tbusy=0;
- stats->tx_errors++;
- dev_kfree_skb(skb, FREE_WRITE);
- return 0;
- }
-
-#ifdef TUNNEL_DEBUG
- printk("Old IP Header....\n");
- print_ip(iph);
-#endif
-
- /*
- * Okay, now see if we can stuff it in the buffer as-is.
- */
- max_headroom = (((tdev->hard_header_len+15)&~15)+tunnel_hlen);
-#ifdef TUNNEL_DEBUG
-printk("Room left at head: %d\n", skb_headroom(skb));
-printk("Room left at tail: %d\n", skb_tailroom(skb));
-printk("Required room: %d, Tunnel hlen: %d\n", max_headroom, TUNL_HLEN);
-#endif
- if (skb_headroom(skb) >= max_headroom && skb->free) {
- skb->h.iph = (struct iphdr *) skb_push(skb, tunnel_hlen);
- skb_device_unlock(skb);
- } else {
- struct sk_buff *new_skb;
-
- if ( !(new_skb = dev_alloc_skb(skb->len+max_headroom)) )
- {
- printk( KERN_INFO "%s: Out of memory, dropped packet\n",
- dev->name);
- ip_rt_put(rt);
- dev->tbusy = 0;
- stats->tx_dropped++;
- dev_kfree_skb(skb, FREE_WRITE);
- return 0;
- }
- new_skb->free = 1;
-
- /*
- * Reserve space for our header and the lower device header
- */
- skb_reserve(new_skb, max_headroom);
-
- /*
- * Copy the old packet to the new buffer.
- * Note that new_skb->h.iph will be our (tunnel driver's) header
- * and new_skb->ip_hdr is the IP header of the old packet.
- */
- new_skb->ip_hdr = (struct iphdr *) skb_put(new_skb, skb->len);
- new_skb->dev = skb->dev;
- memcpy(new_skb->ip_hdr, skb->data, skb->len);
- memset(new_skb->proto_priv, 0, sizeof(skb->proto_priv));
-
- /* Tack on our header */
- new_skb->h.iph = (struct iphdr *) skb_push(new_skb, tunnel_hlen);
-
- /* Free the old packet, we no longer need it */
- dev_kfree_skb(skb, FREE_WRITE);
- skb = new_skb;
- }
-
- /*
- * Push down and install the IPIP header.
- */
-
- iph = skb->h.iph;
- iph->version = 4;
- iph->tos = skb->ip_hdr->tos;
- iph->ttl = skb->ip_hdr->ttl;
- iph->frag_off = 0;
- iph->daddr = target;
- iph->saddr = tdev->pa_addr;
- iph->protocol = IPPROTO_IPIP;
- iph->ihl = 5;
- iph->tot_len = htons(skb->len);
- iph->id = htons(ip_id_count++); /* Race condition here? */
- ip_send_check(iph);
- skb->ip_hdr = skb->h.iph;
- skb->protocol = htons(ETH_P_IP);
-#ifdef TUNNEL_DEBUG
- printk("New IP Header....\n");
- print_ip(iph);
-#endif
-
- /*
- * Send the packet on its way!
- * Note that dev_queue_xmit() will eventually free the skb.
- * If ip_forward() made a copy, it will return 1 so we can free.
- */
-
-#ifdef CONFIG_IP_FORWARD
- if (ip_forward(skb, dev, IPFWD_NOTTLDEC, target))
-#endif
- kfree_skb(skb, FREE_WRITE);
-
- /*
- * Clean up: We're done with the route and the packet
- */
-
- ip_rt_put(rt);
-
-#ifdef TUNNEL_DEBUG
- printk("Packet sent through tunnel interface!\n");
-#endif
-/*printk(">");*/
- /* Record statistics and return */
- stats->tx_packets++;
- dev->tbusy=0;
- return 0;
-}
-
-static struct enet_statistics *tunnel_get_stats(struct device *dev)
-{
- return((struct enet_statistics*) dev->priv);
-}
-
-/*
- * Called when a new tunnel device is initialized.
- * The new tunnel device structure is passed to us.
- */
-
-int tunnel_init(struct device *dev)
-{
- int i;
-
- /* Oh, just say we're here, in case anyone cares */
- static int tun_msg=0;
- if(!tun_msg)
- {
- printk ( KERN_INFO "tunnel: version v0.2b2\n" );
- tun_msg=1;
- }
-
- /* Add our tunnel functions to the device */
- dev->open = tunnel_open;
- dev->stop = tunnel_close;
- dev->hard_start_xmit = tunnel_xmit;
- dev->get_stats = tunnel_get_stats;
- dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
- if (dev->priv == NULL)
- return -ENOMEM;
- memset(dev->priv, 0, sizeof(struct enet_statistics));
-
- /* Initialize the tunnel device structure */
- for (i = 0; i < DEV_NUMBUFFS; i++)
- skb_queue_head_init(&dev->buffs[i]);
-
- dev->hard_header = NULL;
- dev->rebuild_header = NULL;
- dev->set_mac_address = NULL;
- dev->header_cache_bind = NULL;
- dev->header_cache_update= NULL;
-
- dev->type = ARPHRD_TUNNEL;
- dev->hard_header_len = TUNL_HLEN;
- dev->mtu = 1500-tunnel_hlen; /* eth_mtu */
- dev->addr_len = 0; /* Is this only for ARP? */
- dev->tx_queue_len = 2; /* Small queue */
- memset(dev->broadcast,0xFF, ETH_ALEN);
-
- /* New-style flags. */
- dev->flags = IFF_NOARP; /* Don't use ARP on this device */
- /* No broadcasting through a tunnel */
- dev->family = AF_INET;
- dev->pa_addr = 0;
- dev->pa_brdaddr = 0;
- dev->pa_mask = 0;
- dev->pa_alen = 4;
-
- /* We're done. Have I forgotten anything? */
- return 0;
-}
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-/* Module specific interface */
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-#ifdef MODULE
-
-static int tunnel_probe(struct device *dev)
-{
- tunnel_init(dev);
- return 0;
-}
-
-static struct device dev_tunnel =
-{
- "tunl0\0 ",
- 0, 0, 0, 0,
- 0x0, 0,
- 0, 0, 0, NULL, tunnel_probe
- };
-
-int init_module(void)
-{
- /* Find a name for this unit */
- int ct= 1;
-
- while(dev_get(dev_tunnel.name)!=NULL && ct<100)
- {
- sprintf(dev_tunnel.name,"tunl%d",ct);
- ct++;
- }
-
-#ifdef TUNNEL_DEBUG
- printk("tunnel: registering device %s\n", dev_tunnel.name);
-#endif
- if (register_netdev(&dev_tunnel) != 0)
- return -EIO;
- return 0;
-}
-
-void cleanup_module(void)
-{
- unregister_netdev(&dev_tunnel);
- kfree_s(dev_tunnel.priv,sizeof(struct enet_statistics));
- dev_tunnel.priv=NULL;
-}
-#endif /* MODULE */
-
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov