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 /* Add encapsulation header.
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:
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.
30 static int xfrm4_beet_output(struct xfrm_state
*x
, struct sk_buff
*skb
)
32 struct iphdr
*iph
, *top_iph
= NULL
;
39 optlen
= iph
->ihl
* 4 - sizeof(*iph
);
41 hdrlen
+= IPV4_BEET_PHMAXLEN
- (optlen
& 4);
43 skb
->nh
.raw
= skb_push(skb
, x
->props
.header_len
+ hdrlen
);
44 top_iph
= skb
->nh
.iph
;
45 hdrlen
= iph
->ihl
* 4 - optlen
;
48 memmove(top_iph
, iph
, hdrlen
);
49 if (unlikely(optlen
)) {
50 struct ip_beet_phdr
*ph
;
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
;
59 top_iph
->protocol
= IPPROTO_BEETPH
;
60 top_iph
->ihl
= sizeof(struct iphdr
) / 4;
63 top_iph
->saddr
= x
->props
.saddr
.a4
;
64 top_iph
->daddr
= x
->id
.daddr
.a4
;
69 static int xfrm4_beet_input(struct xfrm_state
*x
, struct sk_buff
*skb
)
71 struct iphdr
*iph
= skb
->nh
.iph
;
74 __u8 ph_nexthdr
= 0, protocol
= 0;
77 protocol
= iph
->protocol
;
79 if (unlikely(iph
->protocol
== IPPROTO_BEETPH
)) {
80 struct ip_beet_phdr
*ph
= (struct ip_beet_phdr
*)(iph
+ 1);
82 if (!pskb_may_pull(skb
, sizeof(*ph
)))
85 phlen
= ph
->hdrlen
* 8;
86 optlen
= phlen
- ph
->padlen
- sizeof(*ph
);
87 if (optlen
< 0 || optlen
& 3 || optlen
> 250)
90 if (!pskb_may_pull(skb
, phlen
))
93 ph_nexthdr
= ph
->nexthdr
;
96 skb_push(skb
, sizeof(*iph
) - phlen
+ optlen
);
97 memmove(skb
->data
, skb
->nh
.raw
, sizeof(*iph
));
98 skb
->nh
.raw
= skb
->data
;
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
;
106 iph
->protocol
= ph_nexthdr
;
108 iph
->protocol
= protocol
;
110 iph
->check
= ip_fast_csum(skb
->nh
.raw
, iph
->ihl
);
116 static 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
,
123 static int __init
xfrm4_beet_init(void)
125 return xfrm_register_mode(&xfrm4_beet_mode
, AF_INET
);
128 static void __exit
xfrm4_beet_exit(void)
132 err
= xfrm_unregister_mode(&xfrm4_beet_mode
, AF_INET
);
136 module_init(xfrm4_beet_init
);
137 module_exit(xfrm4_beet_exit
);
138 MODULE_LICENSE("GPL");
139 MODULE_ALIAS_XFRM_MODE(AF_INET
, XFRM_MODE_BEET
);