2 * xfrm4_mode_beet.c - BEET mode encapsulation for IPv4.
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>
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>
20 static void xfrm4_beet_make_header(struct sk_buff
*skb
)
22 struct iphdr
*iph
= ip_hdr(skb
);
27 iph
->protocol
= XFRM_MODE_SKB_CB(skb
)->protocol
;
28 iph
->tos
= XFRM_MODE_SKB_CB(skb
)->tos
;
30 iph
->id
= XFRM_MODE_SKB_CB(skb
)->id
;
31 iph
->frag_off
= XFRM_MODE_SKB_CB(skb
)->frag_off
;
32 iph
->ttl
= XFRM_MODE_SKB_CB(skb
)->ttl
;
35 /* Add encapsulation header.
37 * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt.
39 static int xfrm4_beet_output(struct xfrm_state
*x
, struct sk_buff
*skb
)
41 struct ip_beet_phdr
*ph
;
42 struct iphdr
*top_iph
;
46 optlen
= XFRM_MODE_SKB_CB(skb
)->optlen
;
48 hdrlen
+= IPV4_BEET_PHMAXLEN
- (optlen
& 4);
50 skb_set_network_header(skb
, -x
->props
.header_len
-
51 hdrlen
+ (XFRM_MODE_SKB_CB(skb
)->ihl
- sizeof(*top_iph
)));
52 if (x
->sel
.family
!= AF_INET6
)
53 skb
->network_header
+= IPV4_BEET_PHMAXLEN
;
54 skb
->mac_header
= skb
->network_header
+
55 offsetof(struct iphdr
, protocol
);
56 skb
->transport_header
= skb
->network_header
+ sizeof(*top_iph
);
58 xfrm4_beet_make_header(skb
);
60 ph
= (struct ip_beet_phdr
*)
61 __skb_pull(skb
, XFRM_MODE_SKB_CB(skb
)->ihl
- hdrlen
);
63 top_iph
= ip_hdr(skb
);
65 if (unlikely(optlen
)) {
68 ph
->padlen
= 4 - (optlen
& 4);
69 ph
->hdrlen
= optlen
/ 8;
70 ph
->nexthdr
= top_iph
->protocol
;
72 memset(ph
+ 1, IPOPT_NOP
, ph
->padlen
);
74 top_iph
->protocol
= IPPROTO_BEETPH
;
75 top_iph
->ihl
= sizeof(struct iphdr
) / 4;
78 top_iph
->saddr
= x
->props
.saddr
.a4
;
79 top_iph
->daddr
= x
->id
.daddr
.a4
;
84 static int xfrm4_beet_input(struct xfrm_state
*x
, struct sk_buff
*skb
)
90 if (unlikely(XFRM_MODE_SKB_CB(skb
)->protocol
== IPPROTO_BEETPH
)) {
91 struct ip_beet_phdr
*ph
;
94 if (!pskb_may_pull(skb
, sizeof(*ph
)))
97 ph
= (struct ip_beet_phdr
*)skb
->data
;
99 phlen
= sizeof(*ph
) + ph
->padlen
;
100 optlen
= ph
->hdrlen
* 8 + (IPV4_BEET_PHMAXLEN
- phlen
);
101 if (optlen
< 0 || optlen
& 3 || optlen
> 250)
104 XFRM_MODE_SKB_CB(skb
)->protocol
= ph
->nexthdr
;
106 if (!pskb_may_pull(skb
, phlen
))
108 __skb_pull(skb
, phlen
);
111 skb_push(skb
, sizeof(*iph
));
112 skb_reset_network_header(skb
);
114 memmove(skb
->data
- skb
->mac_len
, skb_mac_header(skb
),
116 skb_set_mac_header(skb
, -skb
->mac_len
);
118 xfrm4_beet_make_header(skb
);
122 iph
->ihl
+= optlen
/ 4;
123 iph
->tot_len
= htons(skb
->len
);
124 iph
->daddr
= x
->sel
.daddr
.a4
;
125 iph
->saddr
= x
->sel
.saddr
.a4
;
127 iph
->check
= ip_fast_csum(skb_network_header(skb
), iph
->ihl
);
133 static struct xfrm_mode xfrm4_beet_mode
= {
134 .input2
= xfrm4_beet_input
,
135 .input
= xfrm_prepare_input
,
136 .output2
= xfrm4_beet_output
,
137 .output
= xfrm4_prepare_output
,
138 .owner
= THIS_MODULE
,
139 .encap
= XFRM_MODE_BEET
,
140 .flags
= XFRM_MODE_FLAG_TUNNEL
,
143 static int __init
xfrm4_beet_init(void)
145 return xfrm_register_mode(&xfrm4_beet_mode
, AF_INET
);
148 static void __exit
xfrm4_beet_exit(void)
152 err
= xfrm_unregister_mode(&xfrm4_beet_mode
, AF_INET
);
156 module_init(xfrm4_beet_init
);
157 module_exit(xfrm4_beet_exit
);
158 MODULE_LICENSE("GPL");
159 MODULE_ALIAS_XFRM_MODE(AF_INET
, XFRM_MODE_BEET
);