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