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