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 static 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 36 int 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 } 52 EXPORT_SYMBOL(fou6_build_header); 53 54 int 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 } 70 EXPORT_SYMBOL(gue6_build_header); 71 72 #if IS_ENABLED(CONFIG_IPV6_FOU_TUNNEL) 73 74 static const struct ip6_tnl_encap_ops fou_ip6tun_ops = { 75 .encap_hlen = fou_encap_hlen, 76 .build_header = fou6_build_header, 77 }; 78 79 static const struct ip6_tnl_encap_ops gue_ip6tun_ops = { 80 .encap_hlen = gue_encap_hlen, 81 .build_header = gue6_build_header, 82 }; 83 84 static 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 104 static 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 112 static int ip6_tnl_encap_add_fou_ops(void) 113 { 114 return 0; 115 } 116 117 static void ip6_tnl_encap_del_fou_ops(void) 118 { 119 } 120 121 #endif 122 123 static int __init fou6_init(void) 124 { 125 int ret; 126 127 ret = ip6_tnl_encap_add_fou_ops(); 128 129 return ret; 130 } 131 132 static void __exit fou6_fini(void) 133 { 134 ip6_tnl_encap_del_fou_ops(); 135 } 136 137 module_init(fou6_init); 138 module_exit(fou6_fini); 139 MODULE_AUTHOR("Tom Herbert <therbert@google.com>"); 140 MODULE_LICENSE("GPL"); 141