utils.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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. #include <net/ip6_checksum.h>
  8. #ifdef CONFIG_INET
  9. __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
  10. unsigned int dataoff, u8 protocol)
  11. {
  12. const struct iphdr *iph = ip_hdr(skb);
  13. __sum16 csum = 0;
  14. switch (skb->ip_summed) {
  15. case CHECKSUM_COMPLETE:
  16. if (hook != NF_INET_PRE_ROUTING && hook != NF_INET_LOCAL_IN)
  17. break;
  18. if ((protocol == 0 && !csum_fold(skb->csum)) ||
  19. !csum_tcpudp_magic(iph->saddr, iph->daddr,
  20. skb->len - dataoff, protocol,
  21. skb->csum)) {
  22. skb->ip_summed = CHECKSUM_UNNECESSARY;
  23. break;
  24. }
  25. /* fall through */
  26. case CHECKSUM_NONE:
  27. if (protocol == 0)
  28. skb->csum = 0;
  29. else
  30. skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr,
  31. skb->len - dataoff,
  32. protocol, 0);
  33. csum = __skb_checksum_complete(skb);
  34. }
  35. return csum;
  36. }
  37. EXPORT_SYMBOL(nf_ip_checksum);
  38. #endif
  39. static __sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook,
  40. unsigned int dataoff, unsigned int len,
  41. u8 protocol)
  42. {
  43. const struct iphdr *iph = ip_hdr(skb);
  44. __sum16 csum = 0;
  45. switch (skb->ip_summed) {
  46. case CHECKSUM_COMPLETE:
  47. if (len == skb->len - dataoff)
  48. return nf_ip_checksum(skb, hook, dataoff, protocol);
  49. /* fall through */
  50. case CHECKSUM_NONE:
  51. skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, protocol,
  52. skb->len - dataoff, 0);
  53. skb->ip_summed = CHECKSUM_NONE;
  54. return __skb_checksum_complete_head(skb, dataoff + len);
  55. }
  56. return csum;
  57. }
  58. __sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook,
  59. unsigned int dataoff, u8 protocol)
  60. {
  61. const struct ipv6hdr *ip6h = ipv6_hdr(skb);
  62. __sum16 csum = 0;
  63. switch (skb->ip_summed) {
  64. case CHECKSUM_COMPLETE:
  65. if (hook != NF_INET_PRE_ROUTING && hook != NF_INET_LOCAL_IN)
  66. break;
  67. if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
  68. skb->len - dataoff, protocol,
  69. csum_sub(skb->csum,
  70. skb_checksum(skb, 0,
  71. dataoff, 0)))) {
  72. skb->ip_summed = CHECKSUM_UNNECESSARY;
  73. break;
  74. }
  75. /* fall through */
  76. case CHECKSUM_NONE:
  77. skb->csum = ~csum_unfold(
  78. csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
  79. skb->len - dataoff,
  80. protocol,
  81. csum_sub(0,
  82. skb_checksum(skb, 0,
  83. dataoff, 0))));
  84. csum = __skb_checksum_complete(skb);
  85. }
  86. return csum;
  87. }
  88. EXPORT_SYMBOL(nf_ip6_checksum);
  89. static __sum16 nf_ip6_checksum_partial(struct sk_buff *skb, unsigned int hook,
  90. unsigned int dataoff, unsigned int len,
  91. u8 protocol)
  92. {
  93. const struct ipv6hdr *ip6h = ipv6_hdr(skb);
  94. __wsum hsum;
  95. __sum16 csum = 0;
  96. switch (skb->ip_summed) {
  97. case CHECKSUM_COMPLETE:
  98. if (len == skb->len - dataoff)
  99. return nf_ip6_checksum(skb, hook, dataoff, protocol);
  100. /* fall through */
  101. case CHECKSUM_NONE:
  102. hsum = skb_checksum(skb, 0, dataoff, 0);
  103. skb->csum = ~csum_unfold(csum_ipv6_magic(&ip6h->saddr,
  104. &ip6h->daddr,
  105. skb->len - dataoff,
  106. protocol,
  107. csum_sub(0, hsum)));
  108. skb->ip_summed = CHECKSUM_NONE;
  109. return __skb_checksum_complete_head(skb, dataoff + len);
  110. }
  111. return csum;
  112. };
  113. __sum16 nf_checksum(struct sk_buff *skb, unsigned int hook,
  114. unsigned int dataoff, u8 protocol,
  115. unsigned short family)
  116. {
  117. __sum16 csum = 0;
  118. switch (family) {
  119. case AF_INET:
  120. csum = nf_ip_checksum(skb, hook, dataoff, protocol);
  121. break;
  122. case AF_INET6:
  123. csum = nf_ip6_checksum(skb, hook, dataoff, protocol);
  124. break;
  125. }
  126. return csum;
  127. }
  128. EXPORT_SYMBOL_GPL(nf_checksum);
  129. __sum16 nf_checksum_partial(struct sk_buff *skb, unsigned int hook,
  130. unsigned int dataoff, unsigned int len,
  131. u8 protocol, unsigned short family)
  132. {
  133. __sum16 csum = 0;
  134. switch (family) {
  135. case AF_INET:
  136. csum = nf_ip_checksum_partial(skb, hook, dataoff, len,
  137. protocol);
  138. break;
  139. case AF_INET6:
  140. csum = nf_ip6_checksum_partial(skb, hook, dataoff, len,
  141. protocol);
  142. break;
  143. }
  144. return csum;
  145. }
  146. EXPORT_SYMBOL_GPL(nf_checksum_partial);
  147. int nf_route(struct net *net, struct dst_entry **dst, struct flowi *fl,
  148. bool strict, unsigned short family)
  149. {
  150. const struct nf_ipv6_ops *v6ops;
  151. int ret = 0;
  152. switch (family) {
  153. case AF_INET:
  154. ret = nf_ip_route(net, dst, fl, strict);
  155. break;
  156. case AF_INET6:
  157. v6ops = rcu_dereference(nf_ipv6_ops);
  158. if (v6ops)
  159. ret = v6ops->route(net, dst, fl, strict);
  160. break;
  161. }
  162. return ret;
  163. }
  164. EXPORT_SYMBOL_GPL(nf_route);
  165. int nf_reroute(struct sk_buff *skb, struct nf_queue_entry *entry)
  166. {
  167. const struct nf_ipv6_ops *v6ops;
  168. int ret = 0;
  169. switch (entry->state.pf) {
  170. case AF_INET:
  171. ret = nf_ip_reroute(skb, entry);
  172. break;
  173. case AF_INET6:
  174. v6ops = rcu_dereference(nf_ipv6_ops);
  175. if (v6ops)
  176. ret = v6ops->reroute(skb, entry);
  177. break;
  178. }
  179. return ret;
  180. }