[NETFILTER]: ip6_queue: deobfuscate entry lookups

A queue entry lookup currently looks like this:

ipq_find_dequeue_entry -> __ipq_find_dequeue_entry ->
	__ipq_find_entry -> cmpfn -> id_cmp

Use simple open-coded list walking and kill the cmpfn for
ipq_find_dequeue_entry. Instead add it to ipq_flush (after
similar cleanups) and use ipq_flush for both complete flushes
and flushing entries related to a device.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Patrick McHardy 2007-12-05 01:26:02 -08:00 коммит произвёл David S. Miller
Родитель 9521409265
Коммит 171b7fc4fc
1 изменённых файлов: 37 добавлений и 64 удалений

Просмотреть файл

@ -75,52 +75,6 @@ __ipq_enqueue_entry(struct ipq_queue_entry *entry)
queue_total++;
}
/*
* Find and return a queued entry matched by cmpfn, or return the last
* entry if cmpfn is NULL.
*/
static inline struct ipq_queue_entry *
__ipq_find_entry(ipq_cmpfn cmpfn, unsigned long data)
{
struct ipq_queue_entry *entry;
list_for_each_entry(entry, &queue_list, list) {
if (!cmpfn || cmpfn(entry, data))
return entry;
}
return NULL;
}
static inline void
__ipq_dequeue_entry(struct ipq_queue_entry *entry)
{
list_del(&entry->list);
queue_total--;
}
static inline struct ipq_queue_entry *
__ipq_find_dequeue_entry(ipq_cmpfn cmpfn, unsigned long data)
{
struct ipq_queue_entry *entry;
entry = __ipq_find_entry(cmpfn, data);
if (entry == NULL)
return NULL;
__ipq_dequeue_entry(entry);
return entry;
}
static inline void
__ipq_flush(int verdict)
{
struct ipq_queue_entry *entry;
while ((entry = __ipq_find_dequeue_entry(NULL, 0)))
ipq_issue_verdict(entry, verdict);
}
static inline int
__ipq_set_mode(unsigned char mode, unsigned int range)
{
@ -147,31 +101,59 @@ __ipq_set_mode(unsigned char mode, unsigned int range)
return status;
}
static void __ipq_flush(ipq_cmpfn cmpfn, unsigned long data);
static inline void
__ipq_reset(void)
{
peer_pid = 0;
net_disable_timestamp();
__ipq_set_mode(IPQ_COPY_NONE, 0);
__ipq_flush(NF_DROP);
__ipq_flush(NULL, 0);
}
static struct ipq_queue_entry *
ipq_find_dequeue_entry(ipq_cmpfn cmpfn, unsigned long data)
ipq_find_dequeue_entry(unsigned long id)
{
struct ipq_queue_entry *entry;
struct ipq_queue_entry *entry = NULL, *i;
write_lock_bh(&queue_lock);
entry = __ipq_find_dequeue_entry(cmpfn, data);
list_for_each_entry(i, &queue_list, list) {
if ((unsigned long)i == id) {
entry = i;
break;
}
}
if (entry) {
list_del(&entry->list);
queue_total--;
}
write_unlock_bh(&queue_lock);
return entry;
}
static void
ipq_flush(int verdict)
__ipq_flush(ipq_cmpfn cmpfn, unsigned long data)
{
struct ipq_queue_entry *entry, *next;
list_for_each_entry_safe(entry, next, &queue_list, list) {
if (!cmpfn || cmpfn(entry, data)) {
list_del(&entry->list);
queue_total--;
ipq_issue_verdict(entry, NF_DROP);
}
}
}
static void
ipq_flush(ipq_cmpfn cmpfn, unsigned long data)
{
write_lock_bh(&queue_lock);
__ipq_flush(verdict);
__ipq_flush(cmpfn, data);
write_unlock_bh(&queue_lock);
}
@ -364,12 +346,6 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
return 0;
}
static inline int
id_cmp(struct ipq_queue_entry *e, unsigned long id)
{
return (id == (unsigned long )e);
}
static int
ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len)
{
@ -378,7 +354,7 @@ ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len)
if (vmsg->value > NF_MAX_VERDICT)
return -EINVAL;
entry = ipq_find_dequeue_entry(id_cmp, vmsg->id);
entry = ipq_find_dequeue_entry(vmsg->id);
if (entry == NULL)
return -ENOENT;
else {
@ -449,10 +425,7 @@ dev_cmp(struct ipq_queue_entry *entry, unsigned long ifindex)
static void
ipq_dev_drop(int ifindex)
{
struct ipq_queue_entry *entry;
while ((entry = ipq_find_dequeue_entry(dev_cmp, ifindex)) != NULL)
ipq_issue_verdict(entry, NF_DROP);
ipq_flush(dev_cmp, ifindex);
}
#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
@ -689,7 +662,7 @@ static void __exit ip6_queue_fini(void)
{
nf_unregister_queue_handlers(&nfqh);
synchronize_net();
ipq_flush(NF_DROP);
ipq_flush(NULL, 0);
unregister_sysctl_table(ipq_sysctl_header);
unregister_netdevice_notifier(&ipq_dev_notifier);