1#include <linux/module.h> 2#include <linux/errno.h> 3#include <linux/socket.h> 4#include <linux/skbuff.h> 5#include <linux/ip.h> 6#include <linux/udp.h> 7#include <linux/types.h> 8#include <linux/kernel.h> 9#include <net/fou.h> 10#include <net/ip.h> 11#include <net/ip6_tunnel.h> 12#include <net/ip6_checksum.h> 13#include <net/protocol.h> 14#include <net/udp.h> 15#include <net/udp_tunnel.h> 16 17#if IS_ENABLED(CONFIG_IPV6_FOU_TUNNEL) 18 19static void fou6_build_udp(struct sk_buff *skb, struct ip_tunnel_encap *e, 20 struct flowi6 *fl6, u8 *protocol, __be16 sport) 21{ 22 struct udphdr *uh; 23 24 skb_push(skb, sizeof(struct udphdr)); 25 skb_reset_transport_header(skb); 26 27 uh = udp_hdr(skb); 28 29 uh->dest = e->dport; 30 uh->source = sport; 31 uh->len = htons(skb->len); 32 udp6_set_csum(!(e->flags & TUNNEL_ENCAP_FLAG_CSUM6), skb, 33 &fl6->saddr, &fl6->daddr, skb->len); 34 35 *protocol = IPPROTO_UDP; 36} 37 38static int fou6_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, 39 u8 *protocol, struct flowi6 *fl6) 40{ 41 __be16 sport; 42 int err; 43 int type = e->flags & TUNNEL_ENCAP_FLAG_CSUM6 ? 44 SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; 45 46 err = __fou_build_header(skb, e, protocol, &sport, type); 47 if (err) 48 return err; 49 50 fou6_build_udp(skb, e, fl6, protocol, sport); 51 52 return 0; 53} 54 55static int gue6_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, 56 u8 *protocol, struct flowi6 *fl6) 57{ 58 __be16 sport; 59 int err; 60 int type = e->flags & TUNNEL_ENCAP_FLAG_CSUM6 ? 61 SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; 62 63 err = __gue_build_header(skb, e, protocol, &sport, type); 64 if (err) 65 return err; 66 67 fou6_build_udp(skb, e, fl6, protocol, sport); 68 69 return 0; 70} 71 72static const struct ip6_tnl_encap_ops fou_ip6tun_ops = { 73 .encap_hlen = fou_encap_hlen, 74 .build_header = fou6_build_header, 75}; 76 77static const struct ip6_tnl_encap_ops gue_ip6tun_ops = { 78 .encap_hlen = gue_encap_hlen, 79 .build_header = gue6_build_header, 80}; 81 82static int ip6_tnl_encap_add_fou_ops(void) 83{ 84 int ret; 85 86 ret = ip6_tnl_encap_add_ops(&fou_ip6tun_ops, TUNNEL_ENCAP_FOU); 87 if (ret < 0) { 88 pr_err("can't add fou6 ops\n"); 89 return ret; 90 } 91 92 ret = ip6_tnl_encap_add_ops(&gue_ip6tun_ops, TUNNEL_ENCAP_GUE); 93 if (ret < 0) { 94 pr_err("can't add gue6 ops\n"); 95 ip6_tnl_encap_del_ops(&fou_ip6tun_ops, TUNNEL_ENCAP_FOU); 96 return ret; 97 } 98 99 return 0; 100} 101 102static void ip6_tnl_encap_del_fou_ops(void) 103{ 104 ip6_tnl_encap_del_ops(&fou_ip6tun_ops, TUNNEL_ENCAP_FOU); 105 ip6_tnl_encap_del_ops(&gue_ip6tun_ops, TUNNEL_ENCAP_GUE); 106} 107 108#else 109 110static int ip6_tnl_encap_add_fou_ops(void) 111{ 112 return 0; 113} 114 115static void ip6_tnl_encap_del_fou_ops(void) 116{ 117} 118 119#endif 120 121static int __init fou6_init(void) 122{ 123 int ret; 124 125 ret = ip6_tnl_encap_add_fou_ops(); 126 127 return ret; 128} 129 130static void __exit fou6_fini(void) 131{ 132 ip6_tnl_encap_del_fou_ops(); 133} 134 135module_init(fou6_init); 136module_exit(fou6_fini); 137MODULE_AUTHOR("Tom Herbert <therbert@google.com>"); 138MODULE_LICENSE("GPL"); 139