Blame view
net/ipv4/xfrm4_output.c
3.36 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 |
/* * xfrm4_output.c - Common IPsec encapsulation code for IPv4. * Copyright (c) 2004 Herbert Xu <herbert@gondor.apana.org.au> |
e905a9eda [NET] IPV4: Fix w... |
4 |
* |
1da177e4c Linux-2.6.12-rc2 |
5 6 7 8 9 |
* This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ |
16a6677fd [XFRM]: Netfilter... |
10 |
#include <linux/compiler.h> |
09b8f7a93 [IPSEC]: Handle G... |
11 12 |
#include <linux/if_ether.h> #include <linux/kernel.h> |
1da177e4c Linux-2.6.12-rc2 |
13 14 |
#include <linux/skbuff.h> #include <linux/spinlock.h> |
16a6677fd [XFRM]: Netfilter... |
15 |
#include <linux/netfilter_ipv4.h> |
1da177e4c Linux-2.6.12-rc2 |
16 17 18 |
#include <net/ip.h> #include <net/xfrm.h> #include <net/icmp.h> |
1da177e4c Linux-2.6.12-rc2 |
19 20 21 22 |
static int xfrm4_tunnel_check_size(struct sk_buff *skb) { int mtu, ret = 0; struct dst_entry *dst; |
1da177e4c Linux-2.6.12-rc2 |
23 24 25 26 27 |
if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE) goto out; IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE; |
e905a9eda [NET] IPV4: Fix w... |
28 |
|
eddc9ec53 [SK_BUFF]: Introd... |
29 |
if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->local_df) |
1da177e4c Linux-2.6.12-rc2 |
30 31 32 33 34 35 36 37 38 39 40 |
goto out; dst = skb->dst; mtu = dst_mtu(dst); if (skb->len > mtu) { icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); ret = -EMSGSIZE; } out: return ret; } |
16a6677fd [XFRM]: Netfilter... |
41 |
static int xfrm4_output_one(struct sk_buff *skb) |
1da177e4c Linux-2.6.12-rc2 |
42 43 44 45 |
{ struct dst_entry *dst = skb->dst; struct xfrm_state *x = dst->xfrm; int err; |
e905a9eda [NET] IPV4: Fix w... |
46 |
|
84fa7933a [NET]: Replace CH... |
47 48 |
if (skb->ip_summed == CHECKSUM_PARTIAL) { err = skb_checksum_help(skb); |
1da177e4c Linux-2.6.12-rc2 |
49 50 51 |
if (err) goto error_nolock; } |
7e49e6de3 [XFRM]: Add XFRM_... |
52 |
if (x->props.mode == XFRM_MODE_TUNNEL) { |
1da177e4c Linux-2.6.12-rc2 |
53 54 55 56 |
err = xfrm4_tunnel_check_size(skb); if (err) goto error_nolock; } |
16a6677fd [XFRM]: Netfilter... |
57 58 59 60 61 |
do { spin_lock_bh(&x->lock); err = xfrm_state_check(x, skb); if (err) goto error; |
1da177e4c Linux-2.6.12-rc2 |
62 |
|
eb878e845 [IPSEC]: output m... |
63 |
err = x->mode->output(x, skb); |
b59f45d0b [IPSEC] xfrm: Abs... |
64 65 |
if (err) goto error; |
1da177e4c Linux-2.6.12-rc2 |
66 |
|
16a6677fd [XFRM]: Netfilter... |
67 68 69 |
err = x->type->output(x, skb); if (err) goto error; |
1da177e4c Linux-2.6.12-rc2 |
70 |
|
16a6677fd [XFRM]: Netfilter... |
71 72 |
x->curlft.bytes += skb->len; x->curlft.packets++; |
1da177e4c Linux-2.6.12-rc2 |
73 |
|
16a6677fd [XFRM]: Netfilter... |
74 |
spin_unlock_bh(&x->lock); |
e905a9eda [NET] IPV4: Fix w... |
75 |
|
16a6677fd [XFRM]: Netfilter... |
76 77 78 79 80 81 |
if (!(skb->dst = dst_pop(dst))) { err = -EHOSTUNREACH; goto error_nolock; } dst = skb->dst; x = dst->xfrm; |
7e49e6de3 [XFRM]: Add XFRM_... |
82 |
} while (x && (x->props.mode != XFRM_MODE_TUNNEL)); |
16a6677fd [XFRM]: Netfilter... |
83 |
|
3e3850e98 [NETFILTER]: Fix ... |
84 |
IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED; |
16a6677fd [XFRM]: Netfilter... |
85 |
err = 0; |
1da177e4c Linux-2.6.12-rc2 |
86 87 88 89 90 91 92 93 94 |
out_exit: return err; error: spin_unlock_bh(&x->lock); error_nolock: kfree_skb(skb); goto out_exit; } |
16a6677fd [XFRM]: Netfilter... |
95 |
|
09b8f7a93 [IPSEC]: Handle G... |
96 |
static int xfrm4_output_finish2(struct sk_buff *skb) |
16a6677fd [XFRM]: Netfilter... |
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
{ int err; while (likely((err = xfrm4_output_one(skb)) == 0)) { nf_reset(skb); err = nf_hook(PF_INET, NF_IP_LOCAL_OUT, &skb, NULL, skb->dst->dev, dst_output); if (unlikely(err != 1)) break; if (!skb->dst->xfrm) return dst_output(skb); err = nf_hook(PF_INET, NF_IP_POST_ROUTING, &skb, NULL, |
09b8f7a93 [IPSEC]: Handle G... |
112 |
skb->dst->dev, xfrm4_output_finish2); |
16a6677fd [XFRM]: Netfilter... |
113 114 115 116 117 118 |
if (unlikely(err != 1)) break; } return err; } |
09b8f7a93 [IPSEC]: Handle G... |
119 120 121 122 123 124 125 126 127 128 |
static int xfrm4_output_finish(struct sk_buff *skb) { struct sk_buff *segs; #ifdef CONFIG_NETFILTER if (!skb->dst->xfrm) { IPCB(skb)->flags |= IPSKB_REROUTED; return dst_output(skb); } #endif |
89114afd4 [NET] gso: Add sk... |
129 |
if (!skb_is_gso(skb)) |
09b8f7a93 [IPSEC]: Handle G... |
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
return xfrm4_output_finish2(skb); skb->protocol = htons(ETH_P_IP); segs = skb_gso_segment(skb, 0); kfree_skb(skb); if (unlikely(IS_ERR(segs))) return PTR_ERR(segs); do { struct sk_buff *nskb = segs->next; int err; segs->next = NULL; err = xfrm4_output_finish2(segs); if (unlikely(err)) { while ((segs = nskb)) { nskb = segs->next; segs->next = NULL; kfree_skb(segs); } return err; } segs = nskb; } while (segs); return 0; } |
16a6677fd [XFRM]: Netfilter... |
159 160 |
int xfrm4_output(struct sk_buff *skb) { |
48d5cad87 [XFRM]: Fix SNAT-... |
161 162 163 |
return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dst->dev, xfrm4_output_finish, !(IPCB(skb)->flags & IPSKB_REROUTED)); |
16a6677fd [XFRM]: Netfilter... |
164 |
} |