nf_conntrack_extend.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /* Structure dynamic extension infrastructure
  2. * Copyright (C) 2004 Rusty Russell IBM Corporation
  3. * Copyright (C) 2007 Netfilter Core Team <coreteam@netfilter.org>
  4. * Copyright (C) 2007 USAGI/WIDE Project <http://www.linux-ipv6.org>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version
  9. * 2 of the License, or (at your option) any later version.
  10. */
  11. #include <linux/kernel.h>
  12. #include <linux/module.h>
  13. #include <linux/mutex.h>
  14. #include <linux/rcupdate.h>
  15. #include <linux/slab.h>
  16. #include <linux/skbuff.h>
  17. #include <net/netfilter/nf_conntrack_extend.h>
  18. static struct nf_ct_ext_type __rcu *nf_ct_ext_types[NF_CT_EXT_NUM];
  19. static DEFINE_MUTEX(nf_ct_ext_type_mutex);
  20. void __nf_ct_ext_destroy(struct nf_conn *ct)
  21. {
  22. unsigned int i;
  23. struct nf_ct_ext_type *t;
  24. struct nf_ct_ext *ext = ct->ext;
  25. for (i = 0; i < NF_CT_EXT_NUM; i++) {
  26. if (!__nf_ct_ext_exist(ext, i))
  27. continue;
  28. rcu_read_lock();
  29. t = rcu_dereference(nf_ct_ext_types[i]);
  30. /* Here the nf_ct_ext_type might have been unregisterd.
  31. * I.e., it has responsible to cleanup private
  32. * area in all conntracks when it is unregisterd.
  33. */
  34. if (t && t->destroy)
  35. t->destroy(ct);
  36. rcu_read_unlock();
  37. }
  38. }
  39. EXPORT_SYMBOL(__nf_ct_ext_destroy);
  40. static void *
  41. nf_ct_ext_create(struct nf_ct_ext **ext, enum nf_ct_ext_id id,
  42. size_t var_alloc_len, gfp_t gfp)
  43. {
  44. unsigned int off, len;
  45. struct nf_ct_ext_type *t;
  46. size_t alloc_size;
  47. rcu_read_lock();
  48. t = rcu_dereference(nf_ct_ext_types[id]);
  49. if (!t) {
  50. rcu_read_unlock();
  51. return NULL;
  52. }
  53. off = ALIGN(sizeof(struct nf_ct_ext), t->align);
  54. len = off + t->len + var_alloc_len;
  55. alloc_size = t->alloc_size + var_alloc_len;
  56. rcu_read_unlock();
  57. *ext = kzalloc(alloc_size, gfp);
  58. if (!*ext)
  59. return NULL;
  60. (*ext)->offset[id] = off;
  61. (*ext)->len = len;
  62. return (void *)(*ext) + off;
  63. }
  64. void *__nf_ct_ext_add_length(struct nf_conn *ct, enum nf_ct_ext_id id,
  65. size_t var_alloc_len, gfp_t gfp)
  66. {
  67. struct nf_ct_ext *old, *new;
  68. int i, newlen, newoff;
  69. struct nf_ct_ext_type *t;
  70. /* Conntrack must not be confirmed to avoid races on reallocation. */
  71. NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
  72. old = ct->ext;
  73. if (!old)
  74. return nf_ct_ext_create(&ct->ext, id, var_alloc_len, gfp);
  75. if (__nf_ct_ext_exist(old, id))
  76. return NULL;
  77. rcu_read_lock();
  78. t = rcu_dereference(nf_ct_ext_types[id]);
  79. if (!t) {
  80. rcu_read_unlock();
  81. return NULL;
  82. }
  83. newoff = ALIGN(old->len, t->align);
  84. newlen = newoff + t->len + var_alloc_len;
  85. rcu_read_unlock();
  86. new = __krealloc(old, newlen, gfp);
  87. if (!new)
  88. return NULL;
  89. if (new != old) {
  90. for (i = 0; i < NF_CT_EXT_NUM; i++) {
  91. if (!__nf_ct_ext_exist(old, i))
  92. continue;
  93. rcu_read_lock();
  94. t = rcu_dereference(nf_ct_ext_types[i]);
  95. if (t && t->move)
  96. t->move((void *)new + new->offset[i],
  97. (void *)old + old->offset[i]);
  98. rcu_read_unlock();
  99. }
  100. kfree_rcu(old, rcu);
  101. ct->ext = new;
  102. }
  103. new->offset[id] = newoff;
  104. new->len = newlen;
  105. memset((void *)new + newoff, 0, newlen - newoff);
  106. return (void *)new + newoff;
  107. }
  108. EXPORT_SYMBOL(__nf_ct_ext_add_length);
  109. static void update_alloc_size(struct nf_ct_ext_type *type)
  110. {
  111. int i, j;
  112. struct nf_ct_ext_type *t1, *t2;
  113. enum nf_ct_ext_id min = 0, max = NF_CT_EXT_NUM - 1;
  114. /* unnecessary to update all types */
  115. if ((type->flags & NF_CT_EXT_F_PREALLOC) == 0) {
  116. min = type->id;
  117. max = type->id;
  118. }
  119. /* This assumes that extended areas in conntrack for the types
  120. whose NF_CT_EXT_F_PREALLOC bit set are allocated in order */
  121. for (i = min; i <= max; i++) {
  122. t1 = rcu_dereference_protected(nf_ct_ext_types[i],
  123. lockdep_is_held(&nf_ct_ext_type_mutex));
  124. if (!t1)
  125. continue;
  126. t1->alloc_size = ALIGN(sizeof(struct nf_ct_ext), t1->align) +
  127. t1->len;
  128. for (j = 0; j < NF_CT_EXT_NUM; j++) {
  129. t2 = rcu_dereference_protected(nf_ct_ext_types[j],
  130. lockdep_is_held(&nf_ct_ext_type_mutex));
  131. if (t2 == NULL || t2 == t1 ||
  132. (t2->flags & NF_CT_EXT_F_PREALLOC) == 0)
  133. continue;
  134. t1->alloc_size = ALIGN(t1->alloc_size, t2->align)
  135. + t2->len;
  136. }
  137. }
  138. }
  139. /* This MUST be called in process context. */
  140. int nf_ct_extend_register(struct nf_ct_ext_type *type)
  141. {
  142. int ret = 0;
  143. mutex_lock(&nf_ct_ext_type_mutex);
  144. if (nf_ct_ext_types[type->id]) {
  145. ret = -EBUSY;
  146. goto out;
  147. }
  148. /* This ensures that nf_ct_ext_create() can allocate enough area
  149. before updating alloc_size */
  150. type->alloc_size = ALIGN(sizeof(struct nf_ct_ext), type->align)
  151. + type->len;
  152. rcu_assign_pointer(nf_ct_ext_types[type->id], type);
  153. update_alloc_size(type);
  154. out:
  155. mutex_unlock(&nf_ct_ext_type_mutex);
  156. return ret;
  157. }
  158. EXPORT_SYMBOL_GPL(nf_ct_extend_register);
  159. /* This MUST be called in process context. */
  160. void nf_ct_extend_unregister(struct nf_ct_ext_type *type)
  161. {
  162. mutex_lock(&nf_ct_ext_type_mutex);
  163. RCU_INIT_POINTER(nf_ct_ext_types[type->id], NULL);
  164. update_alloc_size(type);
  165. mutex_unlock(&nf_ct_ext_type_mutex);
  166. synchronize_rcu();
  167. }
  168. EXPORT_SYMBOL_GPL(nf_ct_extend_unregister);