aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/xfrm4_output.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-11-14 00:43:11 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:53:48 -0500
commit862b82c6f960cc61274d370aa78ce1112f92a83e (patch)
tree51e252e1525dd7d02a695d428890a4c37fae2442 /net/ipv4/xfrm4_output.c
parentef76bc23ef2acf20c8f7f841a542d8ab74c827c6 (diff)
[IPSEC]: Merge most of the output path
As part of the work on asynchrnous cryptographic operations, we need to be able to resume from the spot where they occur. As such, it helps if we isolate them to one spot. This patch moves most of the remaining family-specific processing into the common output code. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/xfrm4_output.c')
-rw-r--r--net/ipv4/xfrm4_output.c76
1 files changed, 4 insertions, 72 deletions
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
index 0ffc3d078489..2fb4efa3ff2c 100644
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -59,7 +59,7 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
59 return err; 59 return err;
60 60
61 memset(IPCB(skb), 0, sizeof(*IPCB(skb))); 61 memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
62 IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE; 62 IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED;
63 63
64 skb->protocol = htons(ETH_P_IP); 64 skb->protocol = htons(ETH_P_IP);
65 65
@@ -67,87 +67,19 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
67} 67}
68EXPORT_SYMBOL(xfrm4_prepare_output); 68EXPORT_SYMBOL(xfrm4_prepare_output);
69 69
70static inline int xfrm4_output_one(struct sk_buff *skb)
71{
72 int err;
73
74 err = xfrm_output(skb);
75 if (err)
76 goto error_nolock;
77
78 IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
79 err = 0;
80
81out_exit:
82 return err;
83error_nolock:
84 kfree_skb(skb);
85 goto out_exit;
86}
87
88static int xfrm4_output_finish2(struct sk_buff *skb)
89{
90 int err;
91
92 while (likely((err = xfrm4_output_one(skb)) == 0)) {
93 nf_reset(skb);
94
95 err = __ip_local_out(skb);
96 if (unlikely(err != 1))
97 break;
98
99 if (!skb->dst->xfrm)
100 return dst_output(skb);
101
102 err = nf_hook(PF_INET, NF_IP_POST_ROUTING, skb, NULL,
103 skb->dst->dev, xfrm4_output_finish2);
104 if (unlikely(err != 1))
105 break;
106 }
107
108 return err;
109}
110
111static int xfrm4_output_finish(struct sk_buff *skb) 70static int xfrm4_output_finish(struct sk_buff *skb)
112{ 71{
113 struct sk_buff *segs;
114
115#ifdef CONFIG_NETFILTER 72#ifdef CONFIG_NETFILTER
116 if (!skb->dst->xfrm) { 73 if (!skb->dst->xfrm) {
117 IPCB(skb)->flags |= IPSKB_REROUTED; 74 IPCB(skb)->flags |= IPSKB_REROUTED;
118 return dst_output(skb); 75 return dst_output(skb);
119 } 76 }
120#endif
121 77
122 if (!skb_is_gso(skb)) 78 IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
123 return xfrm4_output_finish2(skb); 79#endif
124 80
125 skb->protocol = htons(ETH_P_IP); 81 skb->protocol = htons(ETH_P_IP);
126 segs = skb_gso_segment(skb, 0); 82 return xfrm_output(skb);
127 kfree_skb(skb);
128 if (unlikely(IS_ERR(segs)))
129 return PTR_ERR(segs);
130
131 do {
132 struct sk_buff *nskb = segs->next;
133 int err;
134
135 segs->next = NULL;
136 err = xfrm4_output_finish2(segs);
137
138 if (unlikely(err)) {
139 while ((segs = nskb)) {
140 nskb = segs->next;
141 segs->next = NULL;
142 kfree_skb(segs);
143 }
144 return err;
145 }
146
147 segs = nskb;
148 } while (segs);
149
150 return 0;
151} 83}
152 84
153int xfrm4_output(struct sk_buff *skb) 85int xfrm4_output(struct sk_buff *skb)