Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.23-rc6 201 lines 4.9 kB view raw
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 9#include "nf_internals.h" 10 11/* Sockopts only registered and called from user context, so 12 net locking would be overkill. Also, [gs]etsockopt calls may 13 sleep. */ 14static DEFINE_MUTEX(nf_sockopt_mutex); 15static LIST_HEAD(nf_sockopts); 16 17/* Do exclusive ranges overlap? */ 18static inline int overlap(int min1, int max1, int min2, int max2) 19{ 20 return max1 > min2 && min1 < max2; 21} 22 23/* Functions to register sockopt ranges (exclusive). */ 24int nf_register_sockopt(struct nf_sockopt_ops *reg) 25{ 26 struct list_head *i; 27 int ret = 0; 28 29 if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) 30 return -EINTR; 31 32 list_for_each(i, &nf_sockopts) { 33 struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i; 34 if (ops->pf == reg->pf 35 && (overlap(ops->set_optmin, ops->set_optmax, 36 reg->set_optmin, reg->set_optmax) 37 || overlap(ops->get_optmin, ops->get_optmax, 38 reg->get_optmin, reg->get_optmax))) { 39 NFDEBUG("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n", 40 ops->set_optmin, ops->set_optmax, 41 ops->get_optmin, ops->get_optmax, 42 reg->set_optmin, reg->set_optmax, 43 reg->get_optmin, reg->get_optmax); 44 ret = -EBUSY; 45 goto out; 46 } 47 } 48 49 list_add(&reg->list, &nf_sockopts); 50out: 51 mutex_unlock(&nf_sockopt_mutex); 52 return ret; 53} 54EXPORT_SYMBOL(nf_register_sockopt); 55 56void nf_unregister_sockopt(struct nf_sockopt_ops *reg) 57{ 58 /* No point being interruptible: we're probably in cleanup_module() */ 59 restart: 60 mutex_lock(&nf_sockopt_mutex); 61 if (reg->use != 0) { 62 /* To be woken by nf_sockopt call... */ 63 /* FIXME: Stuart Young's name appears gratuitously. */ 64 set_current_state(TASK_UNINTERRUPTIBLE); 65 reg->cleanup_task = current; 66 mutex_unlock(&nf_sockopt_mutex); 67 schedule(); 68 goto restart; 69 } 70 list_del(&reg->list); 71 mutex_unlock(&nf_sockopt_mutex); 72} 73EXPORT_SYMBOL(nf_unregister_sockopt); 74 75/* Call get/setsockopt() */ 76static int nf_sockopt(struct sock *sk, int pf, int val, 77 char __user *opt, int *len, int get) 78{ 79 struct list_head *i; 80 struct nf_sockopt_ops *ops; 81 int ret; 82 83 if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) 84 return -EINTR; 85 86 list_for_each(i, &nf_sockopts) { 87 ops = (struct nf_sockopt_ops *)i; 88 if (ops->pf == pf) { 89 if (get) { 90 if (val >= ops->get_optmin 91 && val < ops->get_optmax) { 92 ops->use++; 93 mutex_unlock(&nf_sockopt_mutex); 94 ret = ops->get(sk, val, opt, len); 95 goto out; 96 } 97 } else { 98 if (val >= ops->set_optmin 99 && val < ops->set_optmax) { 100 ops->use++; 101 mutex_unlock(&nf_sockopt_mutex); 102 ret = ops->set(sk, val, opt, *len); 103 goto out; 104 } 105 } 106 } 107 } 108 mutex_unlock(&nf_sockopt_mutex); 109 return -ENOPROTOOPT; 110 111 out: 112 mutex_lock(&nf_sockopt_mutex); 113 ops->use--; 114 if (ops->cleanup_task) 115 wake_up_process(ops->cleanup_task); 116 mutex_unlock(&nf_sockopt_mutex); 117 return ret; 118} 119 120int nf_setsockopt(struct sock *sk, int pf, int val, char __user *opt, 121 int len) 122{ 123 return nf_sockopt(sk, pf, val, opt, &len, 0); 124} 125EXPORT_SYMBOL(nf_setsockopt); 126 127int nf_getsockopt(struct sock *sk, int pf, int val, char __user *opt, int *len) 128{ 129 return nf_sockopt(sk, pf, val, opt, len, 1); 130} 131EXPORT_SYMBOL(nf_getsockopt); 132 133#ifdef CONFIG_COMPAT 134static int compat_nf_sockopt(struct sock *sk, int pf, int val, 135 char __user *opt, int *len, int get) 136{ 137 struct list_head *i; 138 struct nf_sockopt_ops *ops; 139 int ret; 140 141 if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) 142 return -EINTR; 143 144 list_for_each(i, &nf_sockopts) { 145 ops = (struct nf_sockopt_ops *)i; 146 if (ops->pf == pf) { 147 if (get) { 148 if (val >= ops->get_optmin 149 && val < ops->get_optmax) { 150 ops->use++; 151 mutex_unlock(&nf_sockopt_mutex); 152 if (ops->compat_get) 153 ret = ops->compat_get(sk, 154 val, opt, len); 155 else 156 ret = ops->get(sk, 157 val, opt, len); 158 goto out; 159 } 160 } else { 161 if (val >= ops->set_optmin 162 && val < ops->set_optmax) { 163 ops->use++; 164 mutex_unlock(&nf_sockopt_mutex); 165 if (ops->compat_set) 166 ret = ops->compat_set(sk, 167 val, opt, *len); 168 else 169 ret = ops->set(sk, 170 val, opt, *len); 171 goto out; 172 } 173 } 174 } 175 } 176 mutex_unlock(&nf_sockopt_mutex); 177 return -ENOPROTOOPT; 178 179 out: 180 mutex_lock(&nf_sockopt_mutex); 181 ops->use--; 182 if (ops->cleanup_task) 183 wake_up_process(ops->cleanup_task); 184 mutex_unlock(&nf_sockopt_mutex); 185 return ret; 186} 187 188int compat_nf_setsockopt(struct sock *sk, int pf, 189 int val, char __user *opt, int len) 190{ 191 return compat_nf_sockopt(sk, pf, val, opt, &len, 0); 192} 193EXPORT_SYMBOL(compat_nf_setsockopt); 194 195int compat_nf_getsockopt(struct sock *sk, int pf, 196 int val, char __user *opt, int *len) 197{ 198 return compat_nf_sockopt(sk, pf, val, opt, len, 1); 199} 200EXPORT_SYMBOL(compat_nf_getsockopt); 201#endif