2013-06-18 04:49:56 +04:00
/*
* Copyright ( c ) 2013 Nicira , Inc .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA
* 02110 - 1301 , USA
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/skbuff.h>
# include <linux/netdevice.h>
# include <linux/in.h>
# include <linux/if_arp.h>
# include <linux/mroute.h>
# include <linux/init.h>
# include <linux/in6.h>
# include <linux/inetdevice.h>
# include <linux/netfilter_ipv4.h>
# include <linux/etherdevice.h>
# include <linux/if_ether.h>
# include <linux/if_vlan.h>
# include <net/ip.h>
# include <net/icmp.h>
# include <net/protocol.h>
# include <net/ip_tunnels.h>
# include <net/arp.h>
# include <net/checksum.h>
# include <net/dsfield.h>
# include <net/inet_ecn.h>
# include <net/xfrm.h>
# include <net/net_namespace.h>
# include <net/netns/generic.h>
# include <net/rtnetlink.h>
2013-09-02 17:34:54 +04:00
int iptunnel_xmit ( struct rtable * rt , struct sk_buff * skb ,
2013-06-18 04:49:56 +04:00
__be32 src , __be32 dst , __u8 proto ,
2013-09-02 17:34:57 +04:00
__u8 tos , __u8 ttl , __be16 df , bool xnet )
2013-06-18 04:49:56 +04:00
{
int pkt_len = skb - > len ;
struct iphdr * iph ;
int err ;
2013-09-02 17:34:57 +04:00
skb_scrub_packet ( skb , xnet ) ;
2013-06-18 04:49:56 +04:00
skb - > rxhash = 0 ;
skb_dst_set ( skb , & rt - > dst ) ;
memset ( IPCB ( skb ) , 0 , sizeof ( * IPCB ( skb ) ) ) ;
/* Push down and install the IP header. */
2013-10-01 13:35:51 +04:00
skb_push ( skb , sizeof ( struct iphdr ) ) ;
2013-06-18 04:49:56 +04:00
skb_reset_network_header ( skb ) ;
iph = ip_hdr ( skb ) ;
iph - > version = 4 ;
iph - > ihl = sizeof ( struct iphdr ) > > 2 ;
iph - > frag_off = df ;
iph - > protocol = proto ;
iph - > tos = tos ;
iph - > daddr = dst ;
iph - > saddr = src ;
iph - > ttl = ttl ;
2013-08-13 12:41:06 +04:00
__ip_select_ident ( iph , & rt - > dst , ( skb_shinfo ( skb ) - > gso_segs ? : 1 ) - 1 ) ;
2013-06-18 04:49:56 +04:00
err = ip_local_out ( skb ) ;
if ( unlikely ( net_xmit_eval ( err ) ) )
pkt_len = 0 ;
return pkt_len ;
}
EXPORT_SYMBOL_GPL ( iptunnel_xmit ) ;
2013-06-18 04:50:02 +04:00
int iptunnel_pull_header ( struct sk_buff * skb , int hdr_len , __be16 inner_proto )
{
if ( unlikely ( ! pskb_may_pull ( skb , hdr_len ) ) )
return - ENOMEM ;
skb_pull_rcsum ( skb , hdr_len ) ;
if ( inner_proto = = htons ( ETH_P_TEB ) ) {
struct ethhdr * eh = ( struct ethhdr * ) skb - > data ;
if ( unlikely ( ! pskb_may_pull ( skb , ETH_HLEN ) ) )
return - ENOMEM ;
if ( likely ( ntohs ( eh - > h_proto ) > = ETH_P_802_3_MIN ) )
skb - > protocol = eh - > h_proto ;
else
skb - > protocol = htons ( ETH_P_802_2 ) ;
} else {
skb - > protocol = inner_proto ;
}
nf_reset ( skb ) ;
secpath_reset ( skb ) ;
if ( ! skb - > l4_rxhash )
skb - > rxhash = 0 ;
skb_dst_drop ( skb ) ;
skb - > vlan_tci = 0 ;
skb_set_queue_mapping ( skb , 0 ) ;
skb - > pkt_type = PACKET_HOST ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( iptunnel_pull_header ) ;