diff options
| author | Herbert Xu <herbert@gondor.apana.org.au> | 2007-11-14 00:43:43 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:53:49 -0500 |
| commit | c6581a457e661b7070e484ad723bbf555b17aca2 (patch) | |
| tree | 8562bded99fdee996e6b147d938057caf154f25b | |
| parent | 862b82c6f960cc61274d370aa78ce1112f92a83e (diff) | |
[IPSEC]: Add async resume support on output
This patch adds support for async resumptions on output. To do so,
the transform would return -EINPROGRESS and subsequently invoke the
function xfrm_output_resume to resume processing.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | include/net/xfrm.h | 1 | ||||
| -rw-r--r-- | net/xfrm/xfrm_output.c | 57 |
2 files changed, 41 insertions, 17 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index ab9e747340b4..99677207a4ce 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
| @@ -1119,6 +1119,7 @@ extern void xfrm_replay_notify(struct xfrm_state *x, int event); | |||
| 1119 | extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); | 1119 | extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); |
| 1120 | extern int xfrm_init_state(struct xfrm_state *x); | 1120 | extern int xfrm_init_state(struct xfrm_state *x); |
| 1121 | extern int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb); | 1121 | extern int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb); |
| 1122 | extern int xfrm_output_resume(struct sk_buff *skb, int err); | ||
| 1122 | extern int xfrm_output(struct sk_buff *skb); | 1123 | extern int xfrm_output(struct sk_buff *skb); |
| 1123 | extern int xfrm4_extract_header(struct sk_buff *skb); | 1124 | extern int xfrm4_extract_header(struct sk_buff *skb); |
| 1124 | extern int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb); | 1125 | extern int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb); |
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index bcb3701c5cf3..048d240c3e15 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c | |||
| @@ -18,6 +18,8 @@ | |||
| 18 | #include <net/dst.h> | 18 | #include <net/dst.h> |
| 19 | #include <net/xfrm.h> | 19 | #include <net/xfrm.h> |
| 20 | 20 | ||
| 21 | static int xfrm_output2(struct sk_buff *skb); | ||
| 22 | |||
| 21 | static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb) | 23 | static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb) |
| 22 | { | 24 | { |
| 23 | struct dst_entry *dst = skb->dst; | 25 | struct dst_entry *dst = skb->dst; |
| @@ -41,17 +43,13 @@ err: | |||
| 41 | return err; | 43 | return err; |
| 42 | } | 44 | } |
| 43 | 45 | ||
| 44 | static int xfrm_output_one(struct sk_buff *skb) | 46 | static int xfrm_output_one(struct sk_buff *skb, int err) |
| 45 | { | 47 | { |
| 46 | struct dst_entry *dst = skb->dst; | 48 | struct dst_entry *dst = skb->dst; |
| 47 | struct xfrm_state *x = dst->xfrm; | 49 | struct xfrm_state *x = dst->xfrm; |
| 48 | int err; | ||
| 49 | 50 | ||
| 50 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 51 | if (err <= 0) |
| 51 | err = skb_checksum_help(skb); | 52 | goto resume; |
| 52 | if (err) | ||
| 53 | goto error_nolock; | ||
| 54 | } | ||
| 55 | 53 | ||
| 56 | do { | 54 | do { |
| 57 | err = x->outer_mode->output(x, skb); | 55 | err = x->outer_mode->output(x, skb); |
| @@ -75,6 +73,8 @@ static int xfrm_output_one(struct sk_buff *skb) | |||
| 75 | spin_unlock_bh(&x->lock); | 73 | spin_unlock_bh(&x->lock); |
| 76 | 74 | ||
| 77 | err = x->type->output(x, skb); | 75 | err = x->type->output(x, skb); |
| 76 | |||
| 77 | resume: | ||
| 78 | if (err) | 78 | if (err) |
| 79 | goto error_nolock; | 79 | goto error_nolock; |
| 80 | 80 | ||
| @@ -97,18 +97,16 @@ error_nolock: | |||
| 97 | goto out_exit; | 97 | goto out_exit; |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | static int xfrm_output2(struct sk_buff *skb) | 100 | int xfrm_output_resume(struct sk_buff *skb, int err) |
| 101 | { | 101 | { |
| 102 | int err; | 102 | while (likely((err = xfrm_output_one(skb, err)) == 0)) { |
| 103 | |||
| 104 | while (likely((err = xfrm_output_one(skb)) == 0)) { | ||
| 105 | struct xfrm_state *x; | 103 | struct xfrm_state *x; |
| 106 | 104 | ||
| 107 | nf_reset(skb); | 105 | nf_reset(skb); |
| 108 | 106 | ||
| 109 | err = skb->dst->ops->local_out(skb); | 107 | err = skb->dst->ops->local_out(skb); |
| 110 | if (unlikely(err != 1)) | 108 | if (unlikely(err != 1)) |
| 111 | break; | 109 | goto out; |
| 112 | 110 | ||
| 113 | x = skb->dst->xfrm; | 111 | x = skb->dst->xfrm; |
| 114 | if (!x) | 112 | if (!x) |
| @@ -118,18 +116,25 @@ static int xfrm_output2(struct sk_buff *skb) | |||
| 118 | x->inner_mode->afinfo->nf_post_routing, skb, | 116 | x->inner_mode->afinfo->nf_post_routing, skb, |
| 119 | NULL, skb->dst->dev, xfrm_output2); | 117 | NULL, skb->dst->dev, xfrm_output2); |
| 120 | if (unlikely(err != 1)) | 118 | if (unlikely(err != 1)) |
| 121 | break; | 119 | goto out; |
| 122 | } | 120 | } |
| 123 | 121 | ||
| 122 | if (err == -EINPROGRESS) | ||
| 123 | err = 0; | ||
| 124 | |||
| 125 | out: | ||
| 124 | return err; | 126 | return err; |
| 125 | } | 127 | } |
| 128 | EXPORT_SYMBOL_GPL(xfrm_output_resume); | ||
| 126 | 129 | ||
| 127 | int xfrm_output(struct sk_buff *skb) | 130 | static int xfrm_output2(struct sk_buff *skb) |
| 128 | { | 131 | { |
| 129 | struct sk_buff *segs; | 132 | return xfrm_output_resume(skb, 1); |
| 133 | } | ||
| 130 | 134 | ||
| 131 | if (!skb_is_gso(skb)) | 135 | static int xfrm_output_gso(struct sk_buff *skb) |
| 132 | return xfrm_output2(skb); | 136 | { |
| 137 | struct sk_buff *segs; | ||
| 133 | 138 | ||
| 134 | segs = skb_gso_segment(skb, 0); | 139 | segs = skb_gso_segment(skb, 0); |
| 135 | kfree_skb(skb); | 140 | kfree_skb(skb); |
| @@ -157,4 +162,22 @@ int xfrm_output(struct sk_buff *skb) | |||
| 157 | 162 | ||
| 158 | return 0; | 163 | return 0; |
| 159 | } | 164 | } |
| 165 | |||
| 166 | int xfrm_output(struct sk_buff *skb) | ||
| 167 | { | ||
| 168 | int err; | ||
| 169 | |||
| 170 | if (skb_is_gso(skb)) | ||
| 171 | return xfrm_output_gso(skb); | ||
| 172 | |||
| 173 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | ||
| 174 | err = skb_checksum_help(skb); | ||
| 175 | if (err) { | ||
| 176 | kfree_skb(skb); | ||
| 177 | return err; | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | return xfrm_output2(skb); | ||
| 182 | } | ||
| 160 | EXPORT_SYMBOL_GPL(xfrm_output); | 183 | EXPORT_SYMBOL_GPL(xfrm_output); |
