• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * xfrm4_mode_tunnel.c - Tunnel mode encapsulation for IPv4.
3  *
4  * Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au>
5  */
6 
7 #include <linux/gfp.h>
8 #include <linux/init.h>
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/skbuff.h>
12 #include <linux/stringify.h>
13 #include <net/dst.h>
14 #include <net/inet_ecn.h>
15 #include <net/ip.h>
16 #include <net/xfrm.h>
17 
18 /* Informational hook. The decap is still done here. */
19 static struct xfrm_tunnel __rcu *rcv_notify_handlers __read_mostly;
20 static DEFINE_MUTEX(xfrm4_mode_tunnel_input_mutex);
21 
xfrm4_mode_tunnel_input_register(struct xfrm_tunnel * handler)22 int xfrm4_mode_tunnel_input_register(struct xfrm_tunnel *handler)
23 {
24 	struct xfrm_tunnel __rcu **pprev;
25 	struct xfrm_tunnel *t;
26 	int ret = -EEXIST;
27 	int priority = handler->priority;
28 
29 	mutex_lock(&xfrm4_mode_tunnel_input_mutex);
30 
31 	for (pprev = &rcv_notify_handlers;
32 	     (t = rcu_dereference_protected(*pprev,
33 	     lockdep_is_held(&xfrm4_mode_tunnel_input_mutex))) != NULL;
34 	     pprev = &t->next) {
35 		if (t->priority > priority)
36 			break;
37 		if (t->priority == priority)
38 			goto err;
39 
40 	}
41 
42 	handler->next = *pprev;
43 	rcu_assign_pointer(*pprev, handler);
44 
45 	ret = 0;
46 
47 err:
48 	mutex_unlock(&xfrm4_mode_tunnel_input_mutex);
49 	return ret;
50 }
51 EXPORT_SYMBOL_GPL(xfrm4_mode_tunnel_input_register);
52 
xfrm4_mode_tunnel_input_deregister(struct xfrm_tunnel * handler)53 int xfrm4_mode_tunnel_input_deregister(struct xfrm_tunnel *handler)
54 {
55 	struct xfrm_tunnel __rcu **pprev;
56 	struct xfrm_tunnel *t;
57 	int ret = -ENOENT;
58 
59 	mutex_lock(&xfrm4_mode_tunnel_input_mutex);
60 	for (pprev = &rcv_notify_handlers;
61 	     (t = rcu_dereference_protected(*pprev,
62 	     lockdep_is_held(&xfrm4_mode_tunnel_input_mutex))) != NULL;
63 	     pprev = &t->next) {
64 		if (t == handler) {
65 			*pprev = handler->next;
66 			ret = 0;
67 			break;
68 		}
69 	}
70 	mutex_unlock(&xfrm4_mode_tunnel_input_mutex);
71 	synchronize_net();
72 
73 	return ret;
74 }
75 EXPORT_SYMBOL_GPL(xfrm4_mode_tunnel_input_deregister);
76 
ipip_ecn_decapsulate(struct sk_buff * skb)77 static inline void ipip_ecn_decapsulate(struct sk_buff *skb)
78 {
79 	struct iphdr *inner_iph = ipip_hdr(skb);
80 
81 	if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos))
82 		IP_ECN_set_ce(inner_iph);
83 }
84 
85 /* Add encapsulation header.
86  *
87  * The top IP header will be constructed per RFC 2401.
88  */
xfrm4_mode_tunnel_output(struct xfrm_state * x,struct sk_buff * skb)89 static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
90 {
91 	struct dst_entry *dst = skb_dst(skb);
92 	struct iphdr *top_iph;
93 	int flags;
94 
95 	skb_set_network_header(skb, -x->props.header_len);
96 	skb->mac_header = skb->network_header +
97 			  offsetof(struct iphdr, protocol);
98 	skb->transport_header = skb->network_header + sizeof(*top_iph);
99 	top_iph = ip_hdr(skb);
100 
101 	top_iph->ihl = 5;
102 	top_iph->version = 4;
103 
104 	top_iph->protocol = xfrm_af2proto(skb_dst(skb)->ops->family);
105 
106 	/* DS disclosing depends on XFRM_SA_XFLAG_DONT_ENCAP_DSCP */
107 	if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP)
108 		top_iph->tos = 0;
109 	else
110 		top_iph->tos = XFRM_MODE_SKB_CB(skb)->tos;
111 	top_iph->tos = INET_ECN_encapsulate(top_iph->tos,
112 					    XFRM_MODE_SKB_CB(skb)->tos);
113 
114 	flags = x->props.flags;
115 	if (flags & XFRM_STATE_NOECN)
116 		IP_ECN_clear(top_iph);
117 
118 	top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ?
119 		0 : (XFRM_MODE_SKB_CB(skb)->frag_off & htons(IP_DF));
120 	ip_select_ident(top_iph, dst->child, NULL);
121 
122 	top_iph->ttl = ip4_dst_hoplimit(dst->child);
123 
124 	top_iph->saddr = x->props.saddr.a4;
125 	top_iph->daddr = x->id.daddr.a4;
126 
127 	return 0;
128 }
129 
130 #define for_each_input_rcu(head, handler)	\
131 	for (handler = rcu_dereference(head);	\
132 	     handler != NULL;			\
133 	     handler = rcu_dereference(handler->next))
134 
xfrm4_mode_tunnel_input(struct xfrm_state * x,struct sk_buff * skb)135 static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
136 {
137 	struct xfrm_tunnel *handler;
138 	int err = -EINVAL;
139 
140 	if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP)
141 		goto out;
142 
143 	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
144 		goto out;
145 
146 	for_each_input_rcu(rcv_notify_handlers, handler)
147 		handler->handler(skb);
148 
149 	err = skb_unclone(skb, GFP_ATOMIC);
150 	if (err)
151 		goto out;
152 
153 	if (x->props.flags & XFRM_STATE_DECAP_DSCP)
154 		ipv4_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipip_hdr(skb));
155 	if (!(x->props.flags & XFRM_STATE_NOECN))
156 		ipip_ecn_decapsulate(skb);
157 
158 	skb_reset_network_header(skb);
159 	skb_mac_header_rebuild(skb);
160 
161 	err = 0;
162 
163 out:
164 	return err;
165 }
166 
167 static struct xfrm_mode xfrm4_tunnel_mode = {
168 	.input2 = xfrm4_mode_tunnel_input,
169 	.input = xfrm_prepare_input,
170 	.output2 = xfrm4_mode_tunnel_output,
171 	.output = xfrm4_prepare_output,
172 	.owner = THIS_MODULE,
173 	.encap = XFRM_MODE_TUNNEL,
174 	.flags = XFRM_MODE_FLAG_TUNNEL,
175 };
176 
xfrm4_mode_tunnel_init(void)177 static int __init xfrm4_mode_tunnel_init(void)
178 {
179 	return xfrm_register_mode(&xfrm4_tunnel_mode, AF_INET);
180 }
181 
xfrm4_mode_tunnel_exit(void)182 static void __exit xfrm4_mode_tunnel_exit(void)
183 {
184 	int err;
185 
186 	err = xfrm_unregister_mode(&xfrm4_tunnel_mode, AF_INET);
187 	BUG_ON(err);
188 }
189 
190 module_init(xfrm4_mode_tunnel_init);
191 module_exit(xfrm4_mode_tunnel_exit);
192 MODULE_LICENSE("GPL");
193 MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_TUNNEL);
194