aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/Kconfig9
-rw-r--r--net/ipv4/Makefile1
-rw-r--r--net/ipv4/esp4.c26
-rw-r--r--net/ipv4/ipcomp.c5
-rw-r--r--net/ipv4/ipvs/ip_vs_core.c10
-rw-r--r--net/ipv4/netfilter.c9
-rw-r--r--net/ipv4/netfilter/ip_nat_standalone.c3
-rw-r--r--net/ipv4/netfilter/ipt_REJECT.c97
-rw-r--r--net/ipv4/netfilter/iptable_mangle.c3
-rw-r--r--net/ipv4/tcp_input.c2
-rw-r--r--net/ipv4/udp.c2
-rw-r--r--net/ipv4/xfrm4_mode_beet.c139
12 files changed, 214 insertions, 92 deletions
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index d172a9804448..5572071af735 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -434,6 +434,15 @@ config INET_XFRM_MODE_TUNNEL
434 434
435 If unsure, say Y. 435 If unsure, say Y.
436 436
437config INET_XFRM_MODE_BEET
438 tristate "IP: IPsec BEET mode"
439 default y
440 select XFRM
441 ---help---
442 Support for IPsec BEET mode.
443
444 If unsure, say Y.
445
437config INET_DIAG 446config INET_DIAG
438 tristate "INET: socket monitoring interface" 447 tristate "INET: socket monitoring interface"
439 default y 448 default y
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index f66049e28aeb..15645c51520c 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_INET_AH) += ah4.o
23obj-$(CONFIG_INET_ESP) += esp4.o 23obj-$(CONFIG_INET_ESP) += esp4.o
24obj-$(CONFIG_INET_IPCOMP) += ipcomp.o 24obj-$(CONFIG_INET_IPCOMP) += ipcomp.o
25obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o 25obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o
26obj-$(CONFIG_INET_XFRM_MODE_BEET) += xfrm4_mode_beet.o
26obj-$(CONFIG_INET_TUNNEL) += tunnel4.o 27obj-$(CONFIG_INET_TUNNEL) += tunnel4.o
27obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o 28obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o
28obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o 29obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 13b29360d102..b5c205b57669 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -253,7 +253,8 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
253 * as per draft-ietf-ipsec-udp-encaps-06, 253 * as per draft-ietf-ipsec-udp-encaps-06,
254 * section 3.1.2 254 * section 3.1.2
255 */ 255 */
256 if (x->props.mode == XFRM_MODE_TRANSPORT) 256 if (x->props.mode == XFRM_MODE_TRANSPORT ||
257 x->props.mode == XFRM_MODE_BEET)
257 skb->ip_summed = CHECKSUM_UNNECESSARY; 258 skb->ip_summed = CHECKSUM_UNNECESSARY;
258 } 259 }
259 260
@@ -271,17 +272,28 @@ static u32 esp4_get_max_size(struct xfrm_state *x, int mtu)
271{ 272{
272 struct esp_data *esp = x->data; 273 struct esp_data *esp = x->data;
273 u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4); 274 u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4);
274 275 int enclen = 0;
275 if (x->props.mode == XFRM_MODE_TUNNEL) { 276
276 mtu = ALIGN(mtu + 2, blksize); 277 switch (x->props.mode) {
277 } else { 278 case XFRM_MODE_TUNNEL:
278 /* The worst case. */ 279 mtu = ALIGN(mtu +2, blksize);
280 break;
281 default:
282 case XFRM_MODE_TRANSPORT:
283 /* The worst case */
279 mtu = ALIGN(mtu + 2, 4) + blksize - 4; 284 mtu = ALIGN(mtu + 2, 4) + blksize - 4;
285 break;
286 case XFRM_MODE_BEET:
287 /* The worst case. */
288 enclen = IPV4_BEET_PHMAXLEN;
289 mtu = ALIGN(mtu + enclen + 2, blksize);
290 break;
280 } 291 }
292
281 if (esp->conf.padlen) 293 if (esp->conf.padlen)
282 mtu = ALIGN(mtu, esp->conf.padlen); 294 mtu = ALIGN(mtu, esp->conf.padlen);
283 295
284 return mtu + x->props.header_len + esp->auth.icv_trunc_len; 296 return mtu + x->props.header_len + esp->auth.icv_trunc_len - enclen;
285} 297}
286 298
287static void esp4_err(struct sk_buff *skb, u32 info) 299static void esp4_err(struct sk_buff *skb, u32 info)
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index 2017d36024d4..3839b706142e 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -206,6 +206,7 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)
206static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x) 206static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
207{ 207{
208 struct xfrm_state *t; 208 struct xfrm_state *t;
209 u8 mode = XFRM_MODE_TUNNEL;
209 210
210 t = xfrm_state_alloc(); 211 t = xfrm_state_alloc();
211 if (t == NULL) 212 if (t == NULL)
@@ -216,7 +217,9 @@ static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
216 t->id.daddr.a4 = x->id.daddr.a4; 217 t->id.daddr.a4 = x->id.daddr.a4;
217 memcpy(&t->sel, &x->sel, sizeof(t->sel)); 218 memcpy(&t->sel, &x->sel, sizeof(t->sel));
218 t->props.family = AF_INET; 219 t->props.family = AF_INET;
219 t->props.mode = XFRM_MODE_TUNNEL; 220 if (x->props.mode == XFRM_MODE_BEET)
221 mode = x->props.mode;
222 t->props.mode = mode;
220 t->props.saddr.a4 = x->props.saddr.a4; 223 t->props.saddr.a4 = x->props.saddr.a4;
221 t->props.flags = x->props.flags; 224 t->props.flags = x->props.flags;
222 225
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 6dee03935f78..1445bb47fea4 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -813,6 +813,16 @@ ip_vs_out(unsigned int hooknum, struct sk_buff **pskb,
813 skb->nh.iph->saddr = cp->vaddr; 813 skb->nh.iph->saddr = cp->vaddr;
814 ip_send_check(skb->nh.iph); 814 ip_send_check(skb->nh.iph);
815 815
816 /* For policy routing, packets originating from this
817 * machine itself may be routed differently to packets
818 * passing through. We want this packet to be routed as
819 * if it came from this machine itself. So re-compute
820 * the routing information.
821 */
822 if (ip_route_me_harder(pskb, RTN_LOCAL) != 0)
823 goto drop;
824 skb = *pskb;
825
816 IP_VS_DBG_PKT(10, pp, skb, 0, "After SNAT"); 826 IP_VS_DBG_PKT(10, pp, skb, 0, "After SNAT");
817 827
818 ip_vs_out_stats(cp, skb); 828 ip_vs_out_stats(cp, skb);
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index 5ac15379a0cf..e2005c6810a4 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -8,7 +8,7 @@
8#include <net/ip.h> 8#include <net/ip.h>
9 9
10/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */ 10/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
11int ip_route_me_harder(struct sk_buff **pskb) 11int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type)
12{ 12{
13 struct iphdr *iph = (*pskb)->nh.iph; 13 struct iphdr *iph = (*pskb)->nh.iph;
14 struct rtable *rt; 14 struct rtable *rt;
@@ -16,10 +16,13 @@ int ip_route_me_harder(struct sk_buff **pskb)
16 struct dst_entry *odst; 16 struct dst_entry *odst;
17 unsigned int hh_len; 17 unsigned int hh_len;
18 18
19 if (addr_type == RTN_UNSPEC)
20 addr_type = inet_addr_type(iph->saddr);
21
19 /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause 22 /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
20 * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook. 23 * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook.
21 */ 24 */
22 if (inet_addr_type(iph->saddr) == RTN_LOCAL) { 25 if (addr_type == RTN_LOCAL) {
23 fl.nl_u.ip4_u.daddr = iph->daddr; 26 fl.nl_u.ip4_u.daddr = iph->daddr;
24 fl.nl_u.ip4_u.saddr = iph->saddr; 27 fl.nl_u.ip4_u.saddr = iph->saddr;
25 fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); 28 fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
@@ -156,7 +159,7 @@ static int nf_ip_reroute(struct sk_buff **pskb, const struct nf_info *info)
156 if (!(iph->tos == rt_info->tos 159 if (!(iph->tos == rt_info->tos
157 && iph->daddr == rt_info->daddr 160 && iph->daddr == rt_info->daddr
158 && iph->saddr == rt_info->saddr)) 161 && iph->saddr == rt_info->saddr))
159 return ip_route_me_harder(pskb); 162 return ip_route_me_harder(pskb, RTN_UNSPEC);
160 } 163 }
161 return 0; 164 return 0;
162} 165}
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index 021395b67463..d85d2de50449 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -265,7 +265,8 @@ ip_nat_local_fn(unsigned int hooknum,
265 ct->tuplehash[!dir].tuple.src.u.all 265 ct->tuplehash[!dir].tuple.src.u.all
266#endif 266#endif
267 ) 267 )
268 return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; 268 if (ip_route_me_harder(pskb, RTN_UNSPEC))
269 ret = NF_DROP;
269 } 270 }
270 return ret; 271 return ret;
271} 272}
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index fd0c05efed8a..ad0312d0e4fd 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -38,76 +38,16 @@ MODULE_DESCRIPTION("iptables REJECT target module");
38#define DEBUGP(format, args...) 38#define DEBUGP(format, args...)
39#endif 39#endif
40 40
41static inline struct rtable *route_reverse(struct sk_buff *skb,
42 struct tcphdr *tcph, int hook)
43{
44 struct iphdr *iph = skb->nh.iph;
45 struct dst_entry *odst;
46 struct flowi fl = {};
47 struct rtable *rt;
48
49 /* We don't require ip forwarding to be enabled to be able to
50 * send a RST reply for bridged traffic. */
51 if (hook != NF_IP_FORWARD
52#ifdef CONFIG_BRIDGE_NETFILTER
53 || (skb->nf_bridge && skb->nf_bridge->mask & BRNF_BRIDGED)
54#endif
55 ) {
56 fl.nl_u.ip4_u.daddr = iph->saddr;
57 if (hook == NF_IP_LOCAL_IN)
58 fl.nl_u.ip4_u.saddr = iph->daddr;
59 fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
60
61 if (ip_route_output_key(&rt, &fl) != 0)
62 return NULL;
63 } else {
64 /* non-local src, find valid iif to satisfy
65 * rp-filter when calling ip_route_input. */
66 fl.nl_u.ip4_u.daddr = iph->daddr;
67 if (ip_route_output_key(&rt, &fl) != 0)
68 return NULL;
69
70 odst = skb->dst;
71 if (ip_route_input(skb, iph->saddr, iph->daddr,
72 RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
73 dst_release(&rt->u.dst);
74 return NULL;
75 }
76 dst_release(&rt->u.dst);
77 rt = (struct rtable *)skb->dst;
78 skb->dst = odst;
79
80 fl.nl_u.ip4_u.daddr = iph->saddr;
81 fl.nl_u.ip4_u.saddr = iph->daddr;
82 fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
83 }
84
85 if (rt->u.dst.error) {
86 dst_release(&rt->u.dst);
87 return NULL;
88 }
89
90 fl.proto = IPPROTO_TCP;
91 fl.fl_ip_sport = tcph->dest;
92 fl.fl_ip_dport = tcph->source;
93 security_skb_classify_flow(skb, &fl);
94
95 xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0);
96
97 return rt;
98}
99
100/* Send RST reply */ 41/* Send RST reply */
101static void send_reset(struct sk_buff *oldskb, int hook) 42static void send_reset(struct sk_buff *oldskb, int hook)
102{ 43{
103 struct sk_buff *nskb; 44 struct sk_buff *nskb;
104 struct iphdr *iph = oldskb->nh.iph; 45 struct iphdr *iph = oldskb->nh.iph;
105 struct tcphdr _otcph, *oth, *tcph; 46 struct tcphdr _otcph, *oth, *tcph;
106 struct rtable *rt;
107 __be16 tmp_port; 47 __be16 tmp_port;
108 __be32 tmp_addr; 48 __be32 tmp_addr;
109 int needs_ack; 49 int needs_ack;
110 int hh_len; 50 unsigned int addr_type;
111 51
112 /* IP header checks: fragment. */ 52 /* IP header checks: fragment. */
113 if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)) 53 if (oldskb->nh.iph->frag_off & htons(IP_OFFSET))
@@ -126,23 +66,13 @@ static void send_reset(struct sk_buff *oldskb, int hook)
126 if (nf_ip_checksum(oldskb, hook, iph->ihl * 4, IPPROTO_TCP)) 66 if (nf_ip_checksum(oldskb, hook, iph->ihl * 4, IPPROTO_TCP))
127 return; 67 return;
128 68
129 if ((rt = route_reverse(oldskb, oth, hook)) == NULL)
130 return;
131
132 hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
133
134 /* We need a linear, writeable skb. We also need to expand 69 /* We need a linear, writeable skb. We also need to expand
135 headroom in case hh_len of incoming interface < hh_len of 70 headroom in case hh_len of incoming interface < hh_len of
136 outgoing interface */ 71 outgoing interface */
137 nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb), 72 nskb = skb_copy_expand(oldskb, LL_MAX_HEADER, skb_tailroom(oldskb),
138 GFP_ATOMIC); 73 GFP_ATOMIC);
139 if (!nskb) { 74 if (!nskb)
140 dst_release(&rt->u.dst);
141 return; 75 return;
142 }
143
144 dst_release(nskb->dst);
145 nskb->dst = &rt->u.dst;
146 76
147 /* This packet will not be the same as the other: clear nf fields */ 77 /* This packet will not be the same as the other: clear nf fields */
148 nf_reset(nskb); 78 nf_reset(nskb);
@@ -184,6 +114,21 @@ static void send_reset(struct sk_buff *oldskb, int hook)
184 tcph->window = 0; 114 tcph->window = 0;
185 tcph->urg_ptr = 0; 115 tcph->urg_ptr = 0;
186 116
117 /* Set DF, id = 0 */
118 nskb->nh.iph->frag_off = htons(IP_DF);
119 nskb->nh.iph->id = 0;
120
121 addr_type = RTN_UNSPEC;
122 if (hook != NF_IP_FORWARD
123#ifdef CONFIG_BRIDGE_NETFILTER
124 || (nskb->nf_bridge && nskb->nf_bridge->mask & BRNF_BRIDGED)
125#endif
126 )
127 addr_type = RTN_LOCAL;
128
129 if (ip_route_me_harder(&nskb, addr_type))
130 goto free_nskb;
131
187 /* Adjust TCP checksum */ 132 /* Adjust TCP checksum */
188 nskb->ip_summed = CHECKSUM_NONE; 133 nskb->ip_summed = CHECKSUM_NONE;
189 tcph->check = 0; 134 tcph->check = 0;
@@ -192,12 +137,8 @@ static void send_reset(struct sk_buff *oldskb, int hook)
192 nskb->nh.iph->daddr, 137 nskb->nh.iph->daddr,
193 csum_partial((char *)tcph, 138 csum_partial((char *)tcph,
194 sizeof(struct tcphdr), 0)); 139 sizeof(struct tcphdr), 0));
195 140 /* Adjust IP TTL */
196 /* Adjust IP TTL, DF */
197 nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT); 141 nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
198 /* Set DF, id = 0 */
199 nskb->nh.iph->frag_off = htons(IP_DF);
200 nskb->nh.iph->id = 0;
201 142
202 /* Adjust IP checksum */ 143 /* Adjust IP checksum */
203 nskb->nh.iph->check = 0; 144 nskb->nh.iph->check = 0;
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index e62ea2bb9c0a..b91f3582359b 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -157,7 +157,8 @@ ipt_local_hook(unsigned int hook,
157 || (*pskb)->nfmark != nfmark 157 || (*pskb)->nfmark != nfmark
158#endif 158#endif
159 || (*pskb)->nh.iph->tos != tos)) 159 || (*pskb)->nh.iph->tos != tos))
160 return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; 160 if (ip_route_me_harder(pskb, RTN_UNSPEC))
161 ret = NF_DROP;
161 162
162 return ret; 163 return ret;
163} 164}
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 3f884cea14ff..cf06accbe687 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -2259,7 +2259,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p)
2259 u32 pkts_acked = 0; 2259 u32 pkts_acked = 0;
2260 void (*rtt_sample)(struct sock *sk, u32 usrtt) 2260 void (*rtt_sample)(struct sock *sk, u32 usrtt)
2261 = icsk->icsk_ca_ops->rtt_sample; 2261 = icsk->icsk_ca_ops->rtt_sample;
2262 struct timeval tv; 2262 struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };
2263 2263
2264 while ((skb = skb_peek(&sk->sk_write_queue)) && 2264 while ((skb = skb_peek(&sk->sk_write_queue)) &&
2265 skb != sk->sk_send_head) { 2265 skb != sk->sk_send_head) {
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 6d6142f9c478..865d75214a9a 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -675,6 +675,8 @@ do_append_data:
675 udp_flush_pending_frames(sk); 675 udp_flush_pending_frames(sk);
676 else if (!corkreq) 676 else if (!corkreq)
677 err = udp_push_pending_frames(sk, up); 677 err = udp_push_pending_frames(sk, up);
678 else if (unlikely(skb_queue_empty(&sk->sk_write_queue)))
679 up->pending = 0;
678 release_sock(sk); 680 release_sock(sk);
679 681
680out: 682out:
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c
new file mode 100644
index 000000000000..89cf59ea7bbe
--- /dev/null
+++ b/net/ipv4/xfrm4_mode_beet.c
@@ -0,0 +1,139 @@
1/*
2 * xfrm4_mode_beet.c - BEET mode encapsulation for IPv4.
3 *
4 * Copyright (c) 2006 Diego Beltrami <diego.beltrami@gmail.com>
5 * Miika Komu <miika@iki.fi>
6 * Herbert Xu <herbert@gondor.apana.org.au>
7 * Abhinav Pathak <abhinav.pathak@hiit.fi>
8 * Jeff Ahrenholz <ahrenholz@gmail.com>
9 */
10
11#include <linux/init.h>
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/skbuff.h>
15#include <linux/stringify.h>
16#include <net/dst.h>
17#include <net/ip.h>
18#include <net/xfrm.h>
19
20/* Add encapsulation header.
21 *
22 * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt.
23 * The following fields in it shall be filled in by x->type->output:
24 * tot_len
25 * check
26 *
27 * On exit, skb->h will be set to the start of the payload to be processed
28 * by x->type->output and skb->nh will be set to the top IP header.
29 */
30static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb)
31{
32 struct iphdr *iph, *top_iph = NULL;
33 int hdrlen, optlen;
34
35 iph = skb->nh.iph;
36 skb->h.ipiph = iph;
37
38 hdrlen = 0;
39 optlen = iph->ihl * 4 - sizeof(*iph);
40 if (unlikely(optlen))
41 hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4);
42
43 skb->nh.raw = skb_push(skb, x->props.header_len + hdrlen);
44 top_iph = skb->nh.iph;
45 hdrlen = iph->ihl * 4 - optlen;
46 skb->h.raw += hdrlen;
47
48 memmove(top_iph, iph, hdrlen);
49 if (unlikely(optlen)) {
50 struct ip_beet_phdr *ph;
51
52 BUG_ON(optlen < 0);
53
54 ph = (struct ip_beet_phdr *)skb->h.raw;
55 ph->padlen = 4 - (optlen & 4);
56 ph->hdrlen = (optlen + ph->padlen + sizeof(*ph)) / 8;
57 ph->nexthdr = top_iph->protocol;
58
59 top_iph->protocol = IPPROTO_BEETPH;
60 top_iph->ihl = sizeof(struct iphdr) / 4;
61 }
62
63 top_iph->saddr = x->props.saddr.a4;
64 top_iph->daddr = x->id.daddr.a4;
65
66 return 0;
67}
68
69static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb)
70{
71 struct iphdr *iph = skb->nh.iph;
72 int phlen = 0;
73 int optlen = 0;
74 __u8 ph_nexthdr = 0, protocol = 0;
75 int err = -EINVAL;
76
77 protocol = iph->protocol;
78
79 if (unlikely(iph->protocol == IPPROTO_BEETPH)) {
80 struct ip_beet_phdr *ph = (struct ip_beet_phdr*)(iph + 1);
81
82 if (!pskb_may_pull(skb, sizeof(*ph)))
83 goto out;
84
85 phlen = ph->hdrlen * 8;
86 optlen = phlen - ph->padlen - sizeof(*ph);
87 if (optlen < 0 || optlen & 3 || optlen > 250)
88 goto out;
89
90 if (!pskb_may_pull(skb, phlen))
91 goto out;
92
93 ph_nexthdr = ph->nexthdr;
94 }
95
96 skb_push(skb, sizeof(*iph) - phlen + optlen);
97 memmove(skb->data, skb->nh.raw, sizeof(*iph));
98 skb->nh.raw = skb->data;
99
100 iph = skb->nh.iph;
101 iph->ihl = (sizeof(*iph) + optlen) / 4;
102 iph->tot_len = htons(skb->len);
103 iph->daddr = x->sel.daddr.a4;
104 iph->saddr = x->sel.saddr.a4;
105 if (ph_nexthdr)
106 iph->protocol = ph_nexthdr;
107 else
108 iph->protocol = protocol;
109 iph->check = 0;
110 iph->check = ip_fast_csum(skb->nh.raw, iph->ihl);
111 err = 0;
112out:
113 return err;
114}
115
116static struct xfrm_mode xfrm4_beet_mode = {
117 .input = xfrm4_beet_input,
118 .output = xfrm4_beet_output,
119 .owner = THIS_MODULE,
120 .encap = XFRM_MODE_BEET,
121};
122
123static int __init xfrm4_beet_init(void)
124{
125 return xfrm_register_mode(&xfrm4_beet_mode, AF_INET);
126}
127
128static void __exit xfrm4_beet_exit(void)
129{
130 int err;
131
132 err = xfrm_unregister_mode(&xfrm4_beet_mode, AF_INET);
133 BUG_ON(err);
134}
135
136module_init(xfrm4_beet_init);
137module_exit(xfrm4_beet_exit);
138MODULE_LICENSE("GPL");
139MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_BEET);