nf_sockopt.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. #include <linux/kernel.h>
  2. #include <linux/init.h>
  3. #include <linux/module.h>
  4. #include <linux/skbuff.h>
  5. #include <linux/netfilter.h>
  6. #include <linux/mutex.h>
  7. #include <net/sock.h>
  8. #include "nf_internals.h"
  9. /* Sockopts only registered and called from user context, so
  10. net locking would be overkill. Also, [gs]etsockopt calls may
  11. sleep. */
  12. static DEFINE_MUTEX(nf_sockopt_mutex);
  13. static LIST_HEAD(nf_sockopts);
  14. /* Do exclusive ranges overlap? */
  15. static inline int overlap(int min1, int max1, int min2, int max2)
  16. {
  17. return max1 > min2 && min1 < max2;
  18. }
  19. /* Functions to register sockopt ranges (exclusive). */
  20. int nf_register_sockopt(struct nf_sockopt_ops *reg)
  21. {
  22. struct nf_sockopt_ops *ops;
  23. int ret = 0;
  24. mutex_lock(&nf_sockopt_mutex);
  25. list_for_each_entry(ops, &nf_sockopts, list) {
  26. if (ops->pf == reg->pf
  27. && (overlap(ops->set_optmin, ops->set_optmax,
  28. reg->set_optmin, reg->set_optmax)
  29. || overlap(ops->get_optmin, ops->get_optmax,
  30. reg->get_optmin, reg->get_optmax))) {
  31. NFDEBUG("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n",
  32. ops->set_optmin, ops->set_optmax,
  33. ops->get_optmin, ops->get_optmax,
  34. reg->set_optmin, reg->set_optmax,
  35. reg->get_optmin, reg->get_optmax);
  36. ret = -EBUSY;
  37. goto out;
  38. }
  39. }
  40. list_add(&reg->list, &nf_sockopts);
  41. out:
  42. mutex_unlock(&nf_sockopt_mutex);
  43. return ret;
  44. }
  45. EXPORT_SYMBOL(nf_register_sockopt);
  46. void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
  47. {
  48. mutex_lock(&nf_sockopt_mutex);
  49. list_del(&reg->list);
  50. mutex_unlock(&nf_sockopt_mutex);
  51. }
  52. EXPORT_SYMBOL(nf_unregister_sockopt);
  53. static struct nf_sockopt_ops *nf_sockopt_find(struct sock *sk, u_int8_t pf,
  54. int val, int get)
  55. {
  56. struct nf_sockopt_ops *ops;
  57. mutex_lock(&nf_sockopt_mutex);
  58. list_for_each_entry(ops, &nf_sockopts, list) {
  59. if (ops->pf == pf) {
  60. if (!try_module_get(ops->owner))
  61. goto out_nosup;
  62. if (get) {
  63. if (val >= ops->get_optmin &&
  64. val < ops->get_optmax)
  65. goto out;
  66. } else {
  67. if (val >= ops->set_optmin &&
  68. val < ops->set_optmax)
  69. goto out;
  70. }
  71. module_put(ops->owner);
  72. }
  73. }
  74. out_nosup:
  75. ops = ERR_PTR(-ENOPROTOOPT);
  76. out:
  77. mutex_unlock(&nf_sockopt_mutex);
  78. return ops;
  79. }
  80. /* Call get/setsockopt() */
  81. static int nf_sockopt(struct sock *sk, u_int8_t pf, int val,
  82. char __user *opt, int *len, int get)
  83. {
  84. struct nf_sockopt_ops *ops;
  85. int ret;
  86. ops = nf_sockopt_find(sk, pf, val, get);
  87. if (IS_ERR(ops))
  88. return PTR_ERR(ops);
  89. if (get)
  90. ret = ops->get(sk, val, opt, len);
  91. else
  92. ret = ops->set(sk, val, opt, *len);
  93. module_put(ops->owner);
  94. return ret;
  95. }
  96. int nf_setsockopt(struct sock *sk, u_int8_t pf, int val, char __user *opt,
  97. unsigned int len)
  98. {
  99. return nf_sockopt(sk, pf, val, opt, &len, 0);
  100. }
  101. EXPORT_SYMBOL(nf_setsockopt);
  102. int nf_getsockopt(struct sock *sk, u_int8_t pf, int val, char __user *opt,
  103. int *len)
  104. {
  105. return nf_sockopt(sk, pf, val, opt, len, 1);
  106. }
  107. EXPORT_SYMBOL(nf_getsockopt);
  108. #ifdef CONFIG_COMPAT
  109. static int compat_nf_sockopt(struct sock *sk, u_int8_t pf, int val,
  110. char __user *opt, int *len, int get)
  111. {
  112. struct nf_sockopt_ops *ops;
  113. int ret;
  114. ops = nf_sockopt_find(sk, pf, val, get);
  115. if (IS_ERR(ops))
  116. return PTR_ERR(ops);
  117. if (get) {
  118. if (ops->compat_get)
  119. ret = ops->compat_get(sk, val, opt, len);
  120. else
  121. ret = ops->get(sk, val, opt, len);
  122. } else {
  123. if (ops->compat_set)
  124. ret = ops->compat_set(sk, val, opt, *len);
  125. else
  126. ret = ops->set(sk, val, opt, *len);
  127. }
  128. module_put(ops->owner);
  129. return ret;
  130. }
  131. int compat_nf_setsockopt(struct sock *sk, u_int8_t pf,
  132. int val, char __user *opt, unsigned int len)
  133. {
  134. return compat_nf_sockopt(sk, pf, val, opt, &len, 0);
  135. }
  136. EXPORT_SYMBOL(compat_nf_setsockopt);
  137. int compat_nf_getsockopt(struct sock *sk, u_int8_t pf,
  138. int val, char __user *opt, int *len)
  139. {
  140. return compat_nf_sockopt(sk, pf, val, opt, len, 1);
  141. }
  142. EXPORT_SYMBOL(compat_nf_getsockopt);
  143. #endif