Blame view
net/ipv4/xfrm4_policy.c
7.17 KB
e905a9eda [NET] IPV4: Fix w... |
1 |
/* |
1da177e4c Linux-2.6.12-rc2 |
2 3 4 5 6 7 |
* xfrm4_policy.c * * Changes: * Kazunori MIYAZAWA @USAGI * YOSHIFUJI Hideaki @USAGI * Split up af-specific portion |
e905a9eda [NET] IPV4: Fix w... |
8 |
* |
1da177e4c Linux-2.6.12-rc2 |
9 |
*/ |
66cdb3ca2 [IPSEC]: Move flo... |
10 11 |
#include <linux/err.h> #include <linux/kernel.h> |
aabc9761b [IPSEC]: Store id... |
12 |
#include <linux/inetdevice.h> |
cc9ff19da xfrm: use gre key... |
13 |
#include <linux/if_tunnel.h> |
45ff5a3f9 [IPSEC]: Set dst-... |
14 |
#include <net/dst.h> |
1da177e4c Linux-2.6.12-rc2 |
15 16 |
#include <net/xfrm.h> #include <net/ip.h> |
1da177e4c Linux-2.6.12-rc2 |
17 |
static struct xfrm_policy_afinfo xfrm4_policy_afinfo; |
8f01cb082 ipv4: xfrm: Elimi... |
18 19 20 21 |
static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4, int tos, const xfrm_address_t *saddr, const xfrm_address_t *daddr) |
1da177e4c Linux-2.6.12-rc2 |
22 |
{ |
66cdb3ca2 [IPSEC]: Move flo... |
23 |
struct rtable *rt; |
a1e59abf8 [XFRM]: Fix wildc... |
24 |
|
8f01cb082 ipv4: xfrm: Elimi... |
25 26 27 |
memset(fl4, 0, sizeof(*fl4)); fl4->daddr = daddr->a4; fl4->flowi4_tos = tos; |
66cdb3ca2 [IPSEC]: Move flo... |
28 |
if (saddr) |
8f01cb082 ipv4: xfrm: Elimi... |
29 |
fl4->saddr = saddr->a4; |
66cdb3ca2 [IPSEC]: Move flo... |
30 |
|
8f01cb082 ipv4: xfrm: Elimi... |
31 |
rt = __ip_route_output_key(net, fl4); |
b23dd4fe4 ipv4: Make output... |
32 33 34 35 |
if (!IS_ERR(rt)) return &rt->dst; return ERR_CAST(rt); |
66cdb3ca2 [IPSEC]: Move flo... |
36 |
} |
8f01cb082 ipv4: xfrm: Elimi... |
37 38 39 40 41 42 43 44 |
static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, const xfrm_address_t *saddr, const xfrm_address_t *daddr) { struct flowi4 fl4; return __xfrm4_dst_lookup(net, &fl4, tos, saddr, daddr); } |
fbda33b2b netns xfrm: ->get... |
45 46 |
static int xfrm4_get_saddr(struct net *net, xfrm_address_t *saddr, xfrm_address_t *daddr) |
66cdb3ca2 [IPSEC]: Move flo... |
47 48 |
{ struct dst_entry *dst; |
8f01cb082 ipv4: xfrm: Elimi... |
49 |
struct flowi4 fl4; |
66cdb3ca2 [IPSEC]: Move flo... |
50 |
|
8f01cb082 ipv4: xfrm: Elimi... |
51 |
dst = __xfrm4_dst_lookup(net, &fl4, 0, NULL, daddr); |
66cdb3ca2 [IPSEC]: Move flo... |
52 53 |
if (IS_ERR(dst)) return -EHOSTUNREACH; |
8f01cb082 ipv4: xfrm: Elimi... |
54 |
saddr->a4 = fl4.saddr; |
66cdb3ca2 [IPSEC]: Move flo... |
55 56 |
dst_release(dst); return 0; |
a1e59abf8 [XFRM]: Fix wildc... |
57 |
} |
05d840257 xfrm: Mark flowi ... |
58 |
static int xfrm4_get_tos(const struct flowi *fl) |
1da177e4c Linux-2.6.12-rc2 |
59 |
{ |
7e1dc7b6f net: Use flowi4 a... |
60 |
return IPTOS_RT_MASK & fl->u.ip4.flowi4_tos; /* Strip ECN bits */ |
25ee3286d [IPSEC]: Merge co... |
61 |
} |
1da177e4c Linux-2.6.12-rc2 |
62 |
|
a1b051405 [XFRM] IPv6: Fix ... |
63 64 65 66 67 |
static int xfrm4_init_path(struct xfrm_dst *path, struct dst_entry *dst, int nfheader_len) { return 0; } |
87c1e12b5 ipsec: Fix bogus ... |
68 |
static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, |
0c7b3eefb xfrm: Mark flowi ... |
69 |
const struct flowi *fl) |
25ee3286d [IPSEC]: Merge co... |
70 71 |
{ struct rtable *rt = (struct rtable *)xdst->route; |
7e1dc7b6f net: Use flowi4 a... |
72 |
const struct flowi4 *fl4 = &fl->u.ip4; |
1da177e4c Linux-2.6.12-rc2 |
73 |
|
b73233960 ipv4: fix ipsec f... |
74 75 76 77 78 79 80 |
xdst->u.rt.rt_key_dst = fl4->daddr; xdst->u.rt.rt_key_src = fl4->saddr; xdst->u.rt.rt_key_tos = fl4->flowi4_tos; xdst->u.rt.rt_route_iif = fl4->flowi4_iif; xdst->u.rt.rt_iif = fl4->flowi4_iif; xdst->u.rt.rt_oif = fl4->flowi4_oif; xdst->u.rt.rt_mark = fl4->flowi4_mark; |
1da177e4c Linux-2.6.12-rc2 |
81 |
|
25ee3286d [IPSEC]: Merge co... |
82 83 |
xdst->u.dst.dev = dev; dev_hold(dev); |
433722622 [IPSEC]: IPv4 ove... |
84 |
|
25ee3286d [IPSEC]: Merge co... |
85 86 87 |
xdst->u.rt.peer = rt->peer; if (rt->peer) atomic_inc(&rt->peer->refcnt); |
66cdb3ca2 [IPSEC]: Move flo... |
88 |
|
25ee3286d [IPSEC]: Merge co... |
89 90 91 92 93 94 95 96 97 |
/* Sheit... I remember I did this right. Apparently, * it was magically lost, so this code needs audit */ xdst->u.rt.rt_flags = rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST | RTCF_LOCAL); xdst->u.rt.rt_type = rt->rt_type; xdst->u.rt.rt_src = rt->rt_src; xdst->u.rt.rt_dst = rt->rt_dst; xdst->u.rt.rt_gateway = rt->rt_gateway; xdst->u.rt.rt_spec_dst = rt->rt_spec_dst; |
1da177e4c Linux-2.6.12-rc2 |
98 |
|
1da177e4c Linux-2.6.12-rc2 |
99 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
100 101 102 |
} static void |
d5422efe6 [IPSEC]: Added xf... |
103 |
_decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse) |
1da177e4c Linux-2.6.12-rc2 |
104 |
{ |
b71d1d426 inet: constify ip... |
105 |
const struct iphdr *iph = ip_hdr(skb); |
d56f90a7c [SK_BUFF]: Introd... |
106 |
u8 *xprth = skb_network_header(skb) + iph->ihl * 4; |
7e1dc7b6f net: Use flowi4 a... |
107 |
struct flowi4 *fl4 = &fl->u.ip4; |
1da177e4c Linux-2.6.12-rc2 |
108 |
|
7e1dc7b6f net: Use flowi4 a... |
109 110 |
memset(fl4, 0, sizeof(struct flowi4)); fl4->flowi4_mark = skb->mark; |
44b451f16 xfrm: fix xfrm by... |
111 |
|
56f8a75c1 ip: introduce ip_... |
112 |
if (!ip_is_fragment(iph)) { |
1da177e4c Linux-2.6.12-rc2 |
113 114 |
switch (iph->protocol) { case IPPROTO_UDP: |
ba4e58eca [NET]: Supporting... |
115 |
case IPPROTO_UDPLITE: |
1da177e4c Linux-2.6.12-rc2 |
116 117 |
case IPPROTO_TCP: case IPPROTO_SCTP: |
9e999993c [XFRM]: Handle DC... |
118 |
case IPPROTO_DCCP: |
c615c9f3f xfrm4: fix the po... |
119 120 |
if (xprth + 4 < skb->data || pskb_may_pull(skb, xprth + 4 - skb->data)) { |
8c689a6ea [XFRM]: misc anno... |
121 |
__be16 *ports = (__be16 *)xprth; |
1da177e4c Linux-2.6.12-rc2 |
122 |
|
9cce96df5 net: Put fl4_* ma... |
123 124 |
fl4->fl4_sport = ports[!!reverse]; fl4->fl4_dport = ports[!reverse]; |
1da177e4c Linux-2.6.12-rc2 |
125 126 127 128 129 130 |
} break; case IPPROTO_ICMP: if (pskb_may_pull(skb, xprth + 2 - skb->data)) { u8 *icmp = xprth; |
9cce96df5 net: Put fl4_* ma... |
131 132 |
fl4->fl4_icmp_type = icmp[0]; fl4->fl4_icmp_code = icmp[1]; |
1da177e4c Linux-2.6.12-rc2 |
133 134 135 136 137 |
} break; case IPPROTO_ESP: if (pskb_may_pull(skb, xprth + 4 - skb->data)) { |
4324a1743 [XFRM]: fl_ipsec_... |
138 |
__be32 *ehdr = (__be32 *)xprth; |
1da177e4c Linux-2.6.12-rc2 |
139 |
|
9cce96df5 net: Put fl4_* ma... |
140 |
fl4->fl4_ipsec_spi = ehdr[0]; |
1da177e4c Linux-2.6.12-rc2 |
141 142 143 144 145 |
} break; case IPPROTO_AH: if (pskb_may_pull(skb, xprth + 8 - skb->data)) { |
4324a1743 [XFRM]: fl_ipsec_... |
146 |
__be32 *ah_hdr = (__be32*)xprth; |
1da177e4c Linux-2.6.12-rc2 |
147 |
|
9cce96df5 net: Put fl4_* ma... |
148 |
fl4->fl4_ipsec_spi = ah_hdr[1]; |
1da177e4c Linux-2.6.12-rc2 |
149 150 151 152 153 |
} break; case IPPROTO_COMP: if (pskb_may_pull(skb, xprth + 4 - skb->data)) { |
4324a1743 [XFRM]: fl_ipsec_... |
154 |
__be16 *ipcomp_hdr = (__be16 *)xprth; |
1da177e4c Linux-2.6.12-rc2 |
155 |
|
9cce96df5 net: Put fl4_* ma... |
156 |
fl4->fl4_ipsec_spi = htonl(ntohs(ipcomp_hdr[1])); |
1da177e4c Linux-2.6.12-rc2 |
157 158 |
} break; |
cc9ff19da xfrm: use gre key... |
159 160 161 162 163 164 165 166 167 |
case IPPROTO_GRE: if (pskb_may_pull(skb, xprth + 12 - skb->data)) { __be16 *greflags = (__be16 *)xprth; __be32 *gre_hdr = (__be32 *)xprth; if (greflags[0] & GRE_KEY) { if (greflags[0] & GRE_CSUM) gre_hdr++; |
9cce96df5 net: Put fl4_* ma... |
168 |
fl4->fl4_gre_key = gre_hdr[1]; |
cc9ff19da xfrm: use gre key... |
169 170 171 |
} } break; |
1da177e4c Linux-2.6.12-rc2 |
172 |
default: |
9cce96df5 net: Put fl4_* ma... |
173 |
fl4->fl4_ipsec_spi = 0; |
1da177e4c Linux-2.6.12-rc2 |
174 |
break; |
3ff50b799 [NET]: cleanup ex... |
175 |
} |
1da177e4c Linux-2.6.12-rc2 |
176 |
} |
7e1dc7b6f net: Use flowi4 a... |
177 178 179 180 |
fl4->flowi4_proto = iph->protocol; fl4->daddr = reverse ? iph->saddr : iph->daddr; fl4->saddr = reverse ? iph->daddr : iph->saddr; fl4->flowi4_tos = iph->tos; |
1da177e4c Linux-2.6.12-rc2 |
181 |
} |
569d36452 [NETNS][DST] dst:... |
182 |
static inline int xfrm4_garbage_collect(struct dst_ops *ops) |
1da177e4c Linux-2.6.12-rc2 |
183 |
{ |
d7c7544c3 netns xfrm: deal ... |
184 185 186 |
struct net *net = container_of(ops, struct net, xfrm.xfrm4_dst_ops); xfrm4_policy_afinfo.garbage_collect(net); |
fc66f95c6 net dst: use a pe... |
187 |
return (dst_entries_get_slow(ops) > ops->gc_thresh * 2); |
1da177e4c Linux-2.6.12-rc2 |
188 189 190 191 192 193 194 195 196 |
} static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu) { struct xfrm_dst *xdst = (struct xfrm_dst *)dst; struct dst_entry *path = xdst->route; path->ops->update_pmtu(path, mtu); } |
aabc9761b [IPSEC]: Store id... |
197 198 199 |
static void xfrm4_dst_destroy(struct dst_entry *dst) { struct xfrm_dst *xdst = (struct xfrm_dst *)dst; |
62fa8a846 net: Implement re... |
200 |
dst_destroy_metrics_generic(dst); |
ed3e37ddb [IPSEC]: Use the ... |
201 |
if (likely(xdst->u.rt.peer)) |
26db16770 [IPSEC]: Fix inet... |
202 |
inet_putpeer(xdst->u.rt.peer); |
62fa8a846 net: Implement re... |
203 |
|
aabc9761b [IPSEC]: Store id... |
204 205 206 207 208 209 |
xfrm_dst_destroy(xdst); } static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, int unregister) { |
aabc9761b [IPSEC]: Store id... |
210 211 |
if (!unregister) return; |
aabc9761b [IPSEC]: Store id... |
212 213 |
xfrm_dst_ifdown(dst, dev); } |
1da177e4c Linux-2.6.12-rc2 |
214 215 |
static struct dst_ops xfrm4_dst_ops = { .family = AF_INET, |
09640e636 net: replace uses... |
216 |
.protocol = cpu_to_be16(ETH_P_IP), |
1da177e4c Linux-2.6.12-rc2 |
217 218 |
.gc = xfrm4_garbage_collect, .update_pmtu = xfrm4_update_pmtu, |
62fa8a846 net: Implement re... |
219 |
.cow_metrics = dst_cow_metrics_generic, |
aabc9761b [IPSEC]: Store id... |
220 221 |
.destroy = xfrm4_dst_destroy, .ifdown = xfrm4_dst_ifdown, |
862b82c6f [IPSEC]: Merge mo... |
222 |
.local_out = __ip_local_out, |
1da177e4c Linux-2.6.12-rc2 |
223 |
.gc_thresh = 1024, |
1da177e4c Linux-2.6.12-rc2 |
224 225 226 227 |
}; static struct xfrm_policy_afinfo xfrm4_policy_afinfo = { .family = AF_INET, |
1da177e4c Linux-2.6.12-rc2 |
228 229 |
.dst_ops = &xfrm4_dst_ops, .dst_lookup = xfrm4_dst_lookup, |
a1e59abf8 [XFRM]: Fix wildc... |
230 |
.get_saddr = xfrm4_get_saddr, |
1da177e4c Linux-2.6.12-rc2 |
231 |
.decode_session = _decode_session4, |
25ee3286d [IPSEC]: Merge co... |
232 |
.get_tos = xfrm4_get_tos, |
a1b051405 [XFRM] IPv6: Fix ... |
233 |
.init_path = xfrm4_init_path, |
25ee3286d [IPSEC]: Merge co... |
234 |
.fill_dst = xfrm4_fill_dst, |
2774c131b xfrm: Handle blac... |
235 |
.blackhole_route = ipv4_blackhole_route, |
1da177e4c Linux-2.6.12-rc2 |
236 |
}; |
f816700aa xfrm4: fix build ... |
237 |
#ifdef CONFIG_SYSCTL |
a44a4a006 xfrm: export xfrm... |
238 239 |
static struct ctl_table xfrm4_policy_table[] = { { |
a44a4a006 xfrm: export xfrm... |
240 |
.procname = "xfrm4_gc_thresh", |
d7c7544c3 netns xfrm: deal ... |
241 |
.data = &init_net.xfrm.xfrm4_dst_ops.gc_thresh, |
a44a4a006 xfrm: export xfrm... |
242 243 244 245 246 247 248 249 |
.maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, }, { } }; static struct ctl_table_header *sysctl_hdr; |
f816700aa xfrm4: fix build ... |
250 |
#endif |
a44a4a006 xfrm: export xfrm... |
251 |
|
1da177e4c Linux-2.6.12-rc2 |
252 253 254 255 256 257 258 |
static void __init xfrm4_policy_init(void) { xfrm_policy_register_afinfo(&xfrm4_policy_afinfo); } static void __exit xfrm4_policy_fini(void) { |
f816700aa xfrm4: fix build ... |
259 |
#ifdef CONFIG_SYSCTL |
a44a4a006 xfrm: export xfrm... |
260 261 |
if (sysctl_hdr) unregister_net_sysctl_table(sysctl_hdr); |
f816700aa xfrm4: fix build ... |
262 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
263 264 |
xfrm_policy_unregister_afinfo(&xfrm4_policy_afinfo); } |
a33bc5c15 xfrm: select sane... |
265 |
void __init xfrm4_init(int rt_max_size) |
1da177e4c Linux-2.6.12-rc2 |
266 |
{ |
a33bc5c15 xfrm: select sane... |
267 268 269 270 271 272 273 274 275 276 277 |
/* * Select a default value for the gc_thresh based on the main route * table hash size. It seems to me the worst case scenario is when * we have ipsec operating in transport mode, in which we create a * dst_entry per socket. The xfrm gc algorithm starts trying to remove * entries at gc_thresh, and prevents new allocations as 2*gc_thresh * so lets set an initial xfrm gc_thresh value at the rt_max_size/2. * That will let us store an ipsec connection per route table entry, * and start cleaning when were 1/2 full */ xfrm4_dst_ops.gc_thresh = rt_max_size/2; |
fc66f95c6 net dst: use a pe... |
278 |
dst_entries_init(&xfrm4_dst_ops); |
d7c7544c3 netns xfrm: deal ... |
279 280 281 |
xfrm4_state_init(); xfrm4_policy_init(); |
f816700aa xfrm4: fix build ... |
282 |
#ifdef CONFIG_SYSCTL |
a44a4a006 xfrm: export xfrm... |
283 284 |
sysctl_hdr = register_net_sysctl_table(&init_net, net_ipv4_ctl_path, xfrm4_policy_table); |
f816700aa xfrm4: fix build ... |
285 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
286 |
} |