1 /* 2 * xfrm4_output.c - Common IPsec encapsulation code for IPv4. 3 * Copyright (c) 2004 Herbert Xu <herbert@gondor.apana.org.au> 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License 7 * as published by the Free Software Foundation; either version 8 * 2 of the License, or (at your option) any later version. 9 */ 10 11 #include <linux/skbuff.h> 12 #include <linux/spinlock.h> 13 #include <net/inet_ecn.h> 14 #include <net/ip.h> 15 #include <net/xfrm.h> 16 #include <net/icmp.h> 17 18 /* Add encapsulation header. 19 * 20 * In transport mode, the IP header will be moved forward to make space 21 * for the encapsulation header. 22 * 23 * In tunnel mode, the top IP header will be constructed per RFC 2401. 24 * The following fields in it shall be filled in by x->type->output: 25 * tot_len 26 * check 27 * 28 * On exit, skb->h will be set to the start of the payload to be processed 29 * by x->type->output and skb->nh will be set to the top IP header. 30 */ 31 static void xfrm4_encap(struct sk_buff *skb) 32 { 33 struct dst_entry *dst = skb->dst; 34 struct xfrm_state *x = dst->xfrm; 35 struct iphdr *iph, *top_iph; 36 int flags; 37 38 iph = skb->nh.iph; 39 skb->h.ipiph = iph; 40 41 skb->nh.raw = skb_push(skb, x->props.header_len); 42 top_iph = skb->nh.iph; 43 44 if (!x->props.mode) { 45 skb->h.raw += iph->ihl*4; 46 memmove(top_iph, iph, iph->ihl*4); 47 return; 48 } 49 50 top_iph->ihl = 5; 51 top_iph->version = 4; 52 53 /* DS disclosed */ 54 top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos); 55 56 flags = x->props.flags; 57 if (flags & XFRM_STATE_NOECN) 58 IP_ECN_clear(top_iph); 59 60 top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? 61 0 : (iph->frag_off & htons(IP_DF)); 62 if (!top_iph->frag_off) 63 __ip_select_ident(top_iph, dst, 0); 64 65 top_iph->ttl = dst_metric(dst->child, RTAX_HOPLIMIT); 66 67 top_iph->saddr = x->props.saddr.a4; 68 top_iph->daddr = x->id.daddr.a4; 69 top_iph->protocol = IPPROTO_IPIP; 70 71 memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); 72 } 73 74 static int xfrm4_tunnel_check_size(struct sk_buff *skb) 75 { 76 int mtu, ret = 0; 77 struct dst_entry *dst; 78 struct iphdr *iph = skb->nh.iph; 79 80 if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE) 81 goto out; 82 83 IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE; 84 85 if (!(iph->frag_off & htons(IP_DF)) || skb->local_df) 86 goto out; 87 88 dst = skb->dst; 89 mtu = dst_mtu(dst); 90 if (skb->len > mtu) { 91 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); 92 ret = -EMSGSIZE; 93 } 94 out: 95 return ret; 96 } 97 98 int xfrm4_output(struct sk_buff *skb) 99 { 100 struct dst_entry *dst = skb->dst; 101 struct xfrm_state *x = dst->xfrm; 102 int err; 103 104 if (skb->ip_summed == CHECKSUM_HW) { 105 err = skb_checksum_help(skb, 0); 106 if (err) 107 goto error_nolock; 108 } 109 110 if (x->props.mode) { 111 err = xfrm4_tunnel_check_size(skb); 112 if (err) 113 goto error_nolock; 114 } 115 116 spin_lock_bh(&x->lock); 117 err = xfrm_state_check(x, skb); 118 if (err) 119 goto error; 120 121 xfrm4_encap(skb); 122 123 err = x->type->output(x, skb); 124 if (err) 125 goto error; 126 127 x->curlft.bytes += skb->len; 128 x->curlft.packets++; 129 130 spin_unlock_bh(&x->lock); 131 132 if (!(skb->dst = dst_pop(dst))) { 133 err = -EHOSTUNREACH; 134 goto error_nolock; 135 } 136 err = NET_XMIT_BYPASS; 137 138 out_exit: 139 return err; 140 error: 141 spin_unlock_bh(&x->lock); 142 error_nolock: 143 kfree_skb(skb); 144 goto out_exit; 145 } 146