Branch data Line data Source code
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 : : static void xfrm4_beet_make_header(struct sk_buff *skb)
21 : : {
22 : : struct iphdr *iph = ip_hdr(skb);
23 : :
24 : 0 : iph->ihl = 5;
25 : 0 : iph->version = 4;
26 : :
27 : 0 : iph->protocol = XFRM_MODE_SKB_CB(skb)->protocol;
28 : 0 : iph->tos = XFRM_MODE_SKB_CB(skb)->tos;
29 : :
30 : 0 : iph->id = XFRM_MODE_SKB_CB(skb)->id;
31 : 0 : iph->frag_off = XFRM_MODE_SKB_CB(skb)->frag_off;
32 : 0 : iph->ttl = XFRM_MODE_SKB_CB(skb)->ttl;
33 : : }
34 : :
35 : : /* Add encapsulation header.
36 : : *
37 : : * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt.
38 : : */
39 : 0 : static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb)
40 : : {
41 : : struct ip_beet_phdr *ph;
42 : : struct iphdr *top_iph;
43 : : int hdrlen, optlen;
44 : :
45 : : hdrlen = 0;
46 : 0 : optlen = XFRM_MODE_SKB_CB(skb)->optlen;
47 [ # # ]: 0 : if (unlikely(optlen))
48 : 0 : hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4);
49 : :
50 : 0 : skb_set_network_header(skb, -x->props.header_len -
51 : 0 : hdrlen + (XFRM_MODE_SKB_CB(skb)->ihl - sizeof(*top_iph)));
52 [ # # ]: 0 : if (x->sel.family != AF_INET6)
53 : 0 : skb->network_header += IPV4_BEET_PHMAXLEN;
54 : 0 : skb->mac_header = skb->network_header +
55 : : offsetof(struct iphdr, protocol);
56 : 0 : skb->transport_header = skb->network_header + sizeof(*top_iph);
57 : :
58 : : xfrm4_beet_make_header(skb);
59 : :
60 : : ph = (struct ip_beet_phdr *)
61 : 0 : __skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl - hdrlen);
62 : :
63 : : top_iph = ip_hdr(skb);
64 : :
65 [ # # ]: 0 : if (unlikely(optlen)) {
66 [ # # ]: 0 : BUG_ON(optlen < 0);
67 : :
68 : 0 : ph->padlen = 4 - (optlen & 4);
69 : 0 : ph->hdrlen = optlen / 8;
70 : 0 : ph->nexthdr = top_iph->protocol;
71 [ # # ]: 0 : if (ph->padlen)
72 [ # # ]: 0 : memset(ph + 1, IPOPT_NOP, ph->padlen);
73 : :
74 : 0 : top_iph->protocol = IPPROTO_BEETPH;
75 : 0 : top_iph->ihl = sizeof(struct iphdr) / 4;
76 : : }
77 : :
78 : 0 : top_iph->saddr = x->props.saddr.a4;
79 : 0 : top_iph->daddr = x->id.daddr.a4;
80 : :
81 : 0 : return 0;
82 : : }
83 : :
84 : 0 : static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb)
85 : : {
86 : : struct iphdr *iph;
87 : : int optlen = 0;
88 : : int err = -EINVAL;
89 : :
90 [ # # ]: 0 : if (unlikely(XFRM_MODE_SKB_CB(skb)->protocol == IPPROTO_BEETPH)) {
91 : : struct ip_beet_phdr *ph;
92 : : int phlen;
93 : :
94 [ # # ]: 0 : if (!pskb_may_pull(skb, sizeof(*ph)))
95 : : goto out;
96 : :
97 : 0 : ph = (struct ip_beet_phdr *)skb->data;
98 : :
99 : 0 : phlen = sizeof(*ph) + ph->padlen;
100 : 0 : optlen = ph->hdrlen * 8 + (IPV4_BEET_PHMAXLEN - phlen);
101 [ # # ][ # # ]: 0 : if (optlen < 0 || optlen & 3 || optlen > 250)
[ # # ]
102 : : goto out;
103 : :
104 : 0 : XFRM_MODE_SKB_CB(skb)->protocol = ph->nexthdr;
105 : :
106 [ # # ]: 0 : if (!pskb_may_pull(skb, phlen))
107 : : goto out;
108 : : __skb_pull(skb, phlen);
109 : : }
110 : :
111 : 0 : skb_push(skb, sizeof(*iph));
112 : : skb_reset_network_header(skb);
113 : : skb_mac_header_rebuild(skb);
114 : :
115 : : xfrm4_beet_make_header(skb);
116 : :
117 : : iph = ip_hdr(skb);
118 : :
119 : 0 : iph->ihl += optlen / 4;
120 [ # # ]: 0 : iph->tot_len = htons(skb->len);
121 : 0 : iph->daddr = x->sel.daddr.a4;
122 : 0 : iph->saddr = x->sel.saddr.a4;
123 : 0 : iph->check = 0;
124 : 0 : iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl);
125 : : err = 0;
126 : : out:
127 : 0 : return err;
128 : : }
129 : :
130 : : static struct xfrm_mode xfrm4_beet_mode = {
131 : : .input2 = xfrm4_beet_input,
132 : : .input = xfrm_prepare_input,
133 : : .output2 = xfrm4_beet_output,
134 : : .output = xfrm4_prepare_output,
135 : : .owner = THIS_MODULE,
136 : : .encap = XFRM_MODE_BEET,
137 : : .flags = XFRM_MODE_FLAG_TUNNEL,
138 : : };
139 : :
140 : 0 : static int __init xfrm4_beet_init(void)
141 : : {
142 : 0 : return xfrm_register_mode(&xfrm4_beet_mode, AF_INET);
143 : : }
144 : :
145 : 0 : static void __exit xfrm4_beet_exit(void)
146 : : {
147 : : int err;
148 : :
149 : 0 : err = xfrm_unregister_mode(&xfrm4_beet_mode, AF_INET);
150 [ # # ]: 0 : BUG_ON(err);
151 : 0 : }
152 : :
153 : : module_init(xfrm4_beet_init);
154 : : module_exit(xfrm4_beet_exit);
155 : : MODULE_LICENSE("GPL");
156 : : MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_BEET);
|