utils.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <linux/kernel.h>
  3. #include <linux/netfilter.h>
  4. #include <linux/netfilter_ipv4.h>
  5. #include <linux/netfilter_ipv6.h>
  6. #include <net/netfilter/nf_queue.h>
  7. #ifdef CONFIG_INET
  8. __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
  9. unsigned int dataoff, u8 protocol)
  10. {
  11. const struct iphdr *iph = ip_hdr(skb);
  12. __sum16 csum = 0;
  13. switch (skb->ip_summed) {
  14. case CHECKSUM_COMPLETE:
  15. if (hook != NF_INET_PRE_ROUTING && hook != NF_INET_LOCAL_IN)
  16. break;
  17. if ((protocol == 0 && !csum_fold(skb->csum)) ||
  18. !csum_tcpudp_magic(iph->saddr, iph->daddr,
  19. skb->len - dataoff, protocol,
  20. skb->csum)) {
  21. skb->ip_summed = CHECKSUM_UNNECESSARY;
  22. break;
  23. }
  24. /* fall through */
  25. case CHECKSUM_NONE:
  26. if (protocol == 0)
  27. skb->csum = 0;
  28. else
  29. skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr,
  30. skb->len - dataoff,
  31. protocol, 0);
  32. csum = __skb_checksum_complete(skb);
  33. }
  34. return csum;
  35. }
  36. EXPORT_SYMBOL(nf_ip_checksum);
  37. #endif
  38. static __sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook,
  39. unsigned int dataoff, unsigned int len,
  40. u8 protocol)
  41. {
  42. const struct iphdr *iph = ip_hdr(skb);
  43. __sum16 csum = 0;
  44. switch (skb->ip_summed) {
  45. case CHECKSUM_COMPLETE:
  46. if (len == skb->len - dataoff)
  47. return nf_ip_checksum(skb, hook, dataoff, protocol);
  48. /* fall through */
  49. case CHECKSUM_NONE:
  50. skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, protocol,
  51. skb->len - dataoff, 0);
  52. skb->ip_summed = CHECKSUM_NONE;
  53. return __skb_checksum_complete_head(skb, dataoff + len);
  54. }
  55. return csum;
  56. }
  57. __sum16 nf_checksum(struct sk_buff *skb, unsigned int hook,
  58. unsigned int dataoff, u_int8_t protocol,
  59. unsigned short family)
  60. {
  61. const struct nf_ipv6_ops *v6ops;
  62. __sum16 csum = 0;
  63. switch (family) {
  64. case AF_INET:
  65. csum = nf_ip_checksum(skb, hook, dataoff, protocol);
  66. break;
  67. case AF_INET6:
  68. v6ops = rcu_dereference(nf_ipv6_ops);
  69. if (v6ops)
  70. csum = v6ops->checksum(skb, hook, dataoff, protocol);
  71. break;
  72. }
  73. return csum;
  74. }
  75. EXPORT_SYMBOL_GPL(nf_checksum);
  76. __sum16 nf_checksum_partial(struct sk_buff *skb, unsigned int hook,
  77. unsigned int dataoff, unsigned int len,
  78. u_int8_t protocol, unsigned short family)
  79. {
  80. const struct nf_ipv6_ops *v6ops;
  81. __sum16 csum = 0;
  82. switch (family) {
  83. case AF_INET:
  84. csum = nf_ip_checksum_partial(skb, hook, dataoff, len,
  85. protocol);
  86. break;
  87. case AF_INET6:
  88. v6ops = rcu_dereference(nf_ipv6_ops);
  89. if (v6ops)
  90. csum = v6ops->checksum_partial(skb, hook, dataoff, len,
  91. protocol);
  92. break;
  93. }
  94. return csum;
  95. }
  96. EXPORT_SYMBOL_GPL(nf_checksum_partial);
  97. int nf_route(struct net *net, struct dst_entry **dst, struct flowi *fl,
  98. bool strict, unsigned short family)
  99. {
  100. const struct nf_ipv6_ops *v6ops;
  101. int ret = 0;
  102. switch (family) {
  103. case AF_INET:
  104. ret = nf_ip_route(net, dst, fl, strict);
  105. break;
  106. case AF_INET6:
  107. v6ops = rcu_dereference(nf_ipv6_ops);
  108. if (v6ops)
  109. ret = v6ops->route(net, dst, fl, strict);
  110. break;
  111. }
  112. return ret;
  113. }
  114. EXPORT_SYMBOL_GPL(nf_route);
  115. int nf_reroute(struct sk_buff *skb, struct nf_queue_entry *entry)
  116. {
  117. const struct nf_ipv6_ops *v6ops;
  118. int ret = 0;
  119. switch (entry->state.pf) {
  120. case AF_INET:
  121. ret = nf_ip_reroute(skb, entry);
  122. break;
  123. case AF_INET6:
  124. v6ops = rcu_dereference(nf_ipv6_ops);
  125. if (v6ops)
  126. ret = v6ops->reroute(skb, entry);
  127. break;
  128. }
  129. return ret;
  130. }