fou6.c 2.8 KB

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