linux/net/ipv6/fou6.c
<<
>>
Prefs
   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