summaryrefslogtreecommitdiffstats
path: root/net/ipv4/ipip.c
blob: 31e1258e88120a577c80efde9e6ba48d932eb4cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
 *	Linux NET3:	IP/IP protocol decoder. 
 *
 *	Authors:
 *		Sam Lantinga (slouken@cs.ucdavis.edu)  02/01/95
 *
 *	Fixes:
 *		Alan Cox	:	Merged and made usable non modular (its so tiny its silly as
 *					a module taking up 2 pages).
 *		Alan Cox	: 	Fixed bug with 1.3.18 and IPIP not working (now needs to set skb->h.iph)
 *					to keep ip_forward happy.
 *		Alan Cox	:	More fixes for 1.3.21, and firewall fix. Maybe this will work soon 8).
 *		Kai Schulte	:	Fixed #defines for IP_FIREWALL->FIREWALL
 *
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License
 *	as published by the Free Software Foundation; either version
 *	2 of the License, or (at your option) any later version.
 *
 */
 
#include <linux/module.h>
#include <linux/config.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/in.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/if_arp.h>
#include <linux/mroute.h>

#include <net/datalink.h>
#include <net/sock.h>
#include <net/ip.h>
#include <net/icmp.h>
#include <net/protocol.h>
#include <net/ipip.h>

void ipip_err(struct sk_buff *skb, unsigned char *dp)
{
	/* NI */
	return;
}

/*
 *	The IPIP protocol driver.
 *
 *	On entry here
 *		skb->data is the original IP header
 *		skb->nh points to the initial IP header.
 *		skb->h points at the new header.
 */

int ipip_rcv(struct sk_buff *skb, unsigned short len)
{
	struct device *dev;
	struct iphdr *iph;

#ifdef TUNNEL_DEBUG
	printk("ipip_rcv: got a packet!\n");
#endif
	/*
	 *	Discard the original IP header
	 */

	skb->mac.raw = skb->data;	 
	skb_pull(skb, skb->h.raw - skb->nh.raw);
	
	/*
	 *	Adjust pointers
	 */
	 
	iph = skb->nh.iph;
	skb->nh.iph = skb->h.ipiph;
	memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));

	/*
	 *	If you want to add LZ compressed IP or things like that here,
	 *	and in drivers/net/tunnel.c are the places to add.
	 */
	
	skb->protocol = htons(ETH_P_IP);
	skb->ip_summed = 0;
	skb->pkt_type = PACKET_HOST;

	/*
	 * Is it draconic? I do not think so. --ANK
	 */
	dev = ip_dev_find_tunnel(iph->daddr, iph->saddr);
	if (dev == NULL) {
#ifdef CONFIG_IP_MROUTE
		int vif;

		if (!MULTICAST(skb->nh.iph->daddr) ||
		    !ipv4_config.multicast_route ||
		    LOCAL_MCAST(skb->nh.iph->daddr) ||
		    (vif=ip_mr_find_tunnel(iph->daddr, iph->saddr)) < 0)
		{
#endif
			kfree_skb(skb, FREE_READ);
			return -EINVAL;
#ifdef CONFIG_IP_MROUTE
		}
		IPCB(skb)->flags |= IPSKB_TUNNELED;
		IPCB(skb)->vif = vif;
		dev = skb->dev;
#endif
	}
	skb->dev = dev;
	dst_release(skb->dst);
	skb->dst = NULL;
	netif_rx(skb);
	return(0);
}

#ifdef MODULE

static struct inet_protocol ipip_protocol = {
  ipip_rcv,             /* IPIP handler          */
  ipip_err,             /* TUNNEL error control */
  0,                    /* next                 */
  IPPROTO_IPIP,         /* protocol ID          */
  0,                    /* copy                 */
  NULL,                 /* data                 */
  "IPIP"                /* name                 */
};


/*
 *	And now the modules code and kernel interface.
 */

int init_module( void) 
{
	inet_add_protocol(&ipip_protocol);
	return 0;
}

void cleanup_module( void) 
{
	if ( inet_del_protocol(&ipip_protocol) < 0 )
		printk(KERN_INFO "ipip close: can't remove protocol\n");
}

#endif