0001
0002 #include <linux/module.h>
0003 #include <linux/errno.h>
0004 #include <linux/socket.h>
0005 #include <linux/skbuff.h>
0006 #include <linux/ip.h>
0007 #include <linux/udp.h>
0008 #include <linux/icmpv6.h>
0009 #include <linux/types.h>
0010 #include <linux/kernel.h>
0011 #include <net/fou.h>
0012 #include <net/ip.h>
0013 #include <net/ip6_tunnel.h>
0014 #include <net/ip6_checksum.h>
0015 #include <net/protocol.h>
0016 #include <net/udp.h>
0017 #include <net/udp_tunnel.h>
0018
0019 #if IS_ENABLED(CONFIG_IPV6_FOU_TUNNEL)
0020
0021 static void fou6_build_udp(struct sk_buff *skb, struct ip_tunnel_encap *e,
0022 struct flowi6 *fl6, u8 *protocol, __be16 sport)
0023 {
0024 struct udphdr *uh;
0025
0026 skb_push(skb, sizeof(struct udphdr));
0027 skb_reset_transport_header(skb);
0028
0029 uh = udp_hdr(skb);
0030
0031 uh->dest = e->dport;
0032 uh->source = sport;
0033 uh->len = htons(skb->len);
0034 udp6_set_csum(!(e->flags & TUNNEL_ENCAP_FLAG_CSUM6), skb,
0035 &fl6->saddr, &fl6->daddr, skb->len);
0036
0037 *protocol = IPPROTO_UDP;
0038 }
0039
0040 static int fou6_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
0041 u8 *protocol, struct flowi6 *fl6)
0042 {
0043 __be16 sport;
0044 int err;
0045 int type = e->flags & TUNNEL_ENCAP_FLAG_CSUM6 ?
0046 SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL;
0047
0048 err = __fou_build_header(skb, e, protocol, &sport, type);
0049 if (err)
0050 return err;
0051
0052 fou6_build_udp(skb, e, fl6, protocol, sport);
0053
0054 return 0;
0055 }
0056
0057 static int gue6_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e,
0058 u8 *protocol, struct flowi6 *fl6)
0059 {
0060 __be16 sport;
0061 int err;
0062 int type = e->flags & TUNNEL_ENCAP_FLAG_CSUM6 ?
0063 SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL;
0064
0065 err = __gue_build_header(skb, e, protocol, &sport, type);
0066 if (err)
0067 return err;
0068
0069 fou6_build_udp(skb, e, fl6, protocol, sport);
0070
0071 return 0;
0072 }
0073
0074 static int gue6_err_proto_handler(int proto, struct sk_buff *skb,
0075 struct inet6_skb_parm *opt,
0076 u8 type, u8 code, int offset, __be32 info)
0077 {
0078 const struct inet6_protocol *ipprot;
0079
0080 ipprot = rcu_dereference(inet6_protos[proto]);
0081 if (ipprot && ipprot->err_handler) {
0082 if (!ipprot->err_handler(skb, opt, type, code, offset, info))
0083 return 0;
0084 }
0085
0086 return -ENOENT;
0087 }
0088
0089 static int gue6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
0090 u8 type, u8 code, int offset, __be32 info)
0091 {
0092 int transport_offset = skb_transport_offset(skb);
0093 struct guehdr *guehdr;
0094 size_t len, optlen;
0095 int ret;
0096
0097 len = sizeof(struct udphdr) + sizeof(struct guehdr);
0098 if (!pskb_may_pull(skb, transport_offset + len))
0099 return -EINVAL;
0100
0101 guehdr = (struct guehdr *)&udp_hdr(skb)[1];
0102
0103 switch (guehdr->version) {
0104 case 0:
0105 break;
0106 case 1: {
0107
0108 skb_set_transport_header(skb, -(int)sizeof(struct icmp6hdr));
0109
0110 switch (((struct iphdr *)guehdr)->version) {
0111 case 4:
0112 ret = gue6_err_proto_handler(IPPROTO_IPIP, skb, opt,
0113 type, code, offset, info);
0114 goto out;
0115 case 6:
0116 ret = gue6_err_proto_handler(IPPROTO_IPV6, skb, opt,
0117 type, code, offset, info);
0118 goto out;
0119 default:
0120 ret = -EOPNOTSUPP;
0121 goto out;
0122 }
0123 }
0124 default:
0125 return -EOPNOTSUPP;
0126 }
0127
0128 if (guehdr->control)
0129 return -ENOENT;
0130
0131 optlen = guehdr->hlen << 2;
0132
0133 if (!pskb_may_pull(skb, transport_offset + len + optlen))
0134 return -EINVAL;
0135
0136 guehdr = (struct guehdr *)&udp_hdr(skb)[1];
0137 if (validate_gue_flags(guehdr, optlen))
0138 return -EINVAL;
0139
0140
0141
0142
0143
0144 if (guehdr->proto_ctype == IPPROTO_UDP ||
0145 guehdr->proto_ctype == IPPROTO_UDPLITE)
0146 return -EOPNOTSUPP;
0147
0148 skb_set_transport_header(skb, -(int)sizeof(struct icmp6hdr));
0149 ret = gue6_err_proto_handler(guehdr->proto_ctype, skb,
0150 opt, type, code, offset, info);
0151
0152 out:
0153 skb_set_transport_header(skb, transport_offset);
0154 return ret;
0155 }
0156
0157
0158 static const struct ip6_tnl_encap_ops fou_ip6tun_ops = {
0159 .encap_hlen = fou_encap_hlen,
0160 .build_header = fou6_build_header,
0161 .err_handler = gue6_err,
0162 };
0163
0164 static const struct ip6_tnl_encap_ops gue_ip6tun_ops = {
0165 .encap_hlen = gue_encap_hlen,
0166 .build_header = gue6_build_header,
0167 .err_handler = gue6_err,
0168 };
0169
0170 static int ip6_tnl_encap_add_fou_ops(void)
0171 {
0172 int ret;
0173
0174 ret = ip6_tnl_encap_add_ops(&fou_ip6tun_ops, TUNNEL_ENCAP_FOU);
0175 if (ret < 0) {
0176 pr_err("can't add fou6 ops\n");
0177 return ret;
0178 }
0179
0180 ret = ip6_tnl_encap_add_ops(&gue_ip6tun_ops, TUNNEL_ENCAP_GUE);
0181 if (ret < 0) {
0182 pr_err("can't add gue6 ops\n");
0183 ip6_tnl_encap_del_ops(&fou_ip6tun_ops, TUNNEL_ENCAP_FOU);
0184 return ret;
0185 }
0186
0187 return 0;
0188 }
0189
0190 static void ip6_tnl_encap_del_fou_ops(void)
0191 {
0192 ip6_tnl_encap_del_ops(&fou_ip6tun_ops, TUNNEL_ENCAP_FOU);
0193 ip6_tnl_encap_del_ops(&gue_ip6tun_ops, TUNNEL_ENCAP_GUE);
0194 }
0195
0196 #else
0197
0198 static int ip6_tnl_encap_add_fou_ops(void)
0199 {
0200 return 0;
0201 }
0202
0203 static void ip6_tnl_encap_del_fou_ops(void)
0204 {
0205 }
0206
0207 #endif
0208
0209 static int __init fou6_init(void)
0210 {
0211 int ret;
0212
0213 ret = ip6_tnl_encap_add_fou_ops();
0214
0215 return ret;
0216 }
0217
0218 static void __exit fou6_fini(void)
0219 {
0220 ip6_tnl_encap_del_fou_ops();
0221 }
0222
0223 module_init(fou6_init);
0224 module_exit(fou6_fini);
0225 MODULE_AUTHOR("Tom Herbert <therbert@google.com>");
0226 MODULE_LICENSE("GPL");
0227 MODULE_DESCRIPTION("Foo over UDP (IPv6)");