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.26-rc1 171 lines 4.0 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 nf_sockopt_ops *ops; 27 int ret = 0; 28 29 if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) 30 return -EINTR; 31 32 list_for_each_entry(ops, &nf_sockopts, list) { 33 if (ops->pf == reg->pf 34 && (overlap(ops->set_optmin, ops->set_optmax, 35 reg->set_optmin, reg->set_optmax) 36 || overlap(ops->get_optmin, ops->get_optmax, 37 reg->get_optmin, reg->get_optmax))) { 38 NFDEBUG("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n", 39 ops->set_optmin, ops->set_optmax, 40 ops->get_optmin, ops->get_optmax, 41 reg->set_optmin, reg->set_optmax, 42 reg->get_optmin, reg->get_optmax); 43 ret = -EBUSY; 44 goto out; 45 } 46 } 47 48 list_add(&reg->list, &nf_sockopts); 49out: 50 mutex_unlock(&nf_sockopt_mutex); 51 return ret; 52} 53EXPORT_SYMBOL(nf_register_sockopt); 54 55void nf_unregister_sockopt(struct nf_sockopt_ops *reg) 56{ 57 mutex_lock(&nf_sockopt_mutex); 58 list_del(&reg->list); 59 mutex_unlock(&nf_sockopt_mutex); 60} 61EXPORT_SYMBOL(nf_unregister_sockopt); 62 63static struct nf_sockopt_ops *nf_sockopt_find(struct sock *sk, int pf, 64 int val, int get) 65{ 66 struct nf_sockopt_ops *ops; 67 68 if (sock_net(sk) != &init_net) 69 return ERR_PTR(-ENOPROTOOPT); 70 71 if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) 72 return ERR_PTR(-EINTR); 73 74 list_for_each_entry(ops, &nf_sockopts, list) { 75 if (ops->pf == pf) { 76 if (!try_module_get(ops->owner)) 77 goto out_nosup; 78 79 if (get) { 80 if (val >= ops->get_optmin && 81 val < ops->get_optmax) 82 goto out; 83 } else { 84 if (val >= ops->set_optmin && 85 val < ops->set_optmax) 86 goto out; 87 } 88 module_put(ops->owner); 89 } 90 } 91out_nosup: 92 ops = ERR_PTR(-ENOPROTOOPT); 93out: 94 mutex_unlock(&nf_sockopt_mutex); 95 return ops; 96} 97 98/* Call get/setsockopt() */ 99static int nf_sockopt(struct sock *sk, int pf, int val, 100 char __user *opt, int *len, int get) 101{ 102 struct nf_sockopt_ops *ops; 103 int ret; 104 105 ops = nf_sockopt_find(sk, pf, val, get); 106 if (IS_ERR(ops)) 107 return PTR_ERR(ops); 108 109 if (get) 110 ret = ops->get(sk, val, opt, len); 111 else 112 ret = ops->set(sk, val, opt, *len); 113 114 module_put(ops->owner); 115 return ret; 116} 117 118int nf_setsockopt(struct sock *sk, int pf, int val, char __user *opt, 119 int len) 120{ 121 return nf_sockopt(sk, pf, val, opt, &len, 0); 122} 123EXPORT_SYMBOL(nf_setsockopt); 124 125int nf_getsockopt(struct sock *sk, int pf, int val, char __user *opt, int *len) 126{ 127 return nf_sockopt(sk, pf, val, opt, len, 1); 128} 129EXPORT_SYMBOL(nf_getsockopt); 130 131#ifdef CONFIG_COMPAT 132static int compat_nf_sockopt(struct sock *sk, int pf, int val, 133 char __user *opt, int *len, int get) 134{ 135 struct nf_sockopt_ops *ops; 136 int ret; 137 138 ops = nf_sockopt_find(sk, pf, val, get); 139 if (IS_ERR(ops)) 140 return PTR_ERR(ops); 141 142 if (get) { 143 if (ops->compat_get) 144 ret = ops->compat_get(sk, val, opt, len); 145 else 146 ret = ops->get(sk, val, opt, len); 147 } else { 148 if (ops->compat_set) 149 ret = ops->compat_set(sk, val, opt, *len); 150 else 151 ret = ops->set(sk, val, opt, *len); 152 } 153 154 module_put(ops->owner); 155 return ret; 156} 157 158int compat_nf_setsockopt(struct sock *sk, int pf, 159 int val, char __user *opt, int len) 160{ 161 return compat_nf_sockopt(sk, pf, val, opt, &len, 0); 162} 163EXPORT_SYMBOL(compat_nf_setsockopt); 164 165int compat_nf_getsockopt(struct sock *sk, int pf, 166 int val, char __user *opt, int *len) 167{ 168 return compat_nf_sockopt(sk, pf, val, opt, len, 1); 169} 170EXPORT_SYMBOL(compat_nf_getsockopt); 171#endif