1 /* 2 * xfrm_output.c - Common IPsec encapsulation code. 3 * 4 * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 12 #include <linux/errno.h> 13 #include <linux/module.h> 14 #include <linux/netdevice.h> 15 #include <linux/skbuff.h> 16 #include <linux/spinlock.h> 17 #include <linux/time.h> 18 #include <net/dst.h> 19 #include <net/xfrm.h> 20 21 int xfrm_output(struct sk_buff *skb) 22 { 23 struct dst_entry *dst = skb->dst; 24 struct xfrm_state *x = dst->xfrm; 25 int err; 26 27 if (skb->ip_summed == CHECKSUM_PARTIAL) { 28 err = skb_checksum_help(skb); 29 if (err) 30 goto error_nolock; 31 } 32 33 do { 34 spin_lock_bh(&x->lock); 35 err = xfrm_state_check(x, skb); 36 if (err) 37 goto error; 38 39 err = x->mode->output(x, skb); 40 if (err) 41 goto error; 42 43 err = x->type->output(x, skb); 44 if (err) 45 goto error; 46 47 x->curlft.bytes += skb->len; 48 x->curlft.packets++; 49 50 if (x->props.mode == XFRM_MODE_ROUTEOPTIMIZATION) 51 x->lastused = get_seconds(); 52 53 spin_unlock_bh(&x->lock); 54 55 skb_reset_network_header(skb); 56 57 if (!(skb->dst = dst_pop(dst))) { 58 err = -EHOSTUNREACH; 59 goto error_nolock; 60 } 61 dst = skb->dst; 62 x = dst->xfrm; 63 } while (x && (x->props.mode != XFRM_MODE_TUNNEL)); 64 65 err = 0; 66 67 error_nolock: 68 return err; 69 error: 70 spin_unlock_bh(&x->lock); 71 goto error_nolock; 72 } 73 EXPORT_SYMBOL_GPL(xfrm_output); 74