aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netfilter/x_tables.h23
-rw-r--r--net/ipv4/netfilter/arp_tables.c14
-rw-r--r--net/ipv4/netfilter/ip_tables.c23
-rw-r--r--net/ipv6/netfilter/ip6_tables.c23
-rw-r--r--net/netfilter/xt_physdev.c21
5 files changed, 30 insertions, 74 deletions
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index e8e08d036752..72918b7cbe85 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -435,6 +435,29 @@ extern void xt_free_table_info(struct xt_table_info *info);
435extern void xt_table_entry_swap_rcu(struct xt_table_info *old, 435extern void xt_table_entry_swap_rcu(struct xt_table_info *old,
436 struct xt_table_info *new); 436 struct xt_table_info *new);
437 437
438/*
439 * This helper is performance critical and must be inlined
440 */
441static inline unsigned long ifname_compare_aligned(const char *_a,
442 const char *_b,
443 const char *_mask)
444{
445 const unsigned long *a = (const unsigned long *)_a;
446 const unsigned long *b = (const unsigned long *)_b;
447 const unsigned long *mask = (const unsigned long *)_mask;
448 unsigned long ret;
449
450 ret = (a[0] ^ b[0]) & mask[0];
451 if (IFNAMSIZ > sizeof(unsigned long))
452 ret |= (a[1] ^ b[1]) & mask[1];
453 if (IFNAMSIZ > 2 * sizeof(unsigned long))
454 ret |= (a[2] ^ b[2]) & mask[2];
455 if (IFNAMSIZ > 3 * sizeof(unsigned long))
456 ret |= (a[3] ^ b[3]) & mask[3];
457 BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
458 return ret;
459}
460
438#ifdef CONFIG_COMPAT 461#ifdef CONFIG_COMPAT
439#include <net/compat.h> 462#include <net/compat.h>
440 463
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 64a7c6ce0b98..4b35dba7cf7d 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -80,19 +80,7 @@ static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap,
80static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask) 80static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask)
81{ 81{
82#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 82#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
83 const unsigned long *a = (const unsigned long *)_a; 83 unsigned long ret = ifname_compare_aligned(_a, _b, _mask);
84 const unsigned long *b = (const unsigned long *)_b;
85 const unsigned long *mask = (const unsigned long *)_mask;
86 unsigned long ret;
87
88 ret = (a[0] ^ b[0]) & mask[0];
89 if (IFNAMSIZ > sizeof(unsigned long))
90 ret |= (a[1] ^ b[1]) & mask[1];
91 if (IFNAMSIZ > 2 * sizeof(unsigned long))
92 ret |= (a[2] ^ b[2]) & mask[2];
93 if (IFNAMSIZ > 3 * sizeof(unsigned long))
94 ret |= (a[3] ^ b[3]) & mask[3];
95 BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
96#else 84#else
97 unsigned long ret = 0; 85 unsigned long ret = 0;
98 int i; 86 int i;
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index e5294aec967d..41c59e391a6a 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -74,25 +74,6 @@ do { \
74 74
75 Hence the start of any table is given by get_table() below. */ 75 Hence the start of any table is given by get_table() below. */
76 76
77static unsigned long ifname_compare(const char *_a, const char *_b,
78 const unsigned char *_mask)
79{
80 const unsigned long *a = (const unsigned long *)_a;
81 const unsigned long *b = (const unsigned long *)_b;
82 const unsigned long *mask = (const unsigned long *)_mask;
83 unsigned long ret;
84
85 ret = (a[0] ^ b[0]) & mask[0];
86 if (IFNAMSIZ > sizeof(unsigned long))
87 ret |= (a[1] ^ b[1]) & mask[1];
88 if (IFNAMSIZ > 2 * sizeof(unsigned long))
89 ret |= (a[2] ^ b[2]) & mask[2];
90 if (IFNAMSIZ > 3 * sizeof(unsigned long))
91 ret |= (a[3] ^ b[3]) & mask[3];
92 BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
93 return ret;
94}
95
96/* Returns whether matches rule or not. */ 77/* Returns whether matches rule or not. */
97/* Performance critical - called for every packet */ 78/* Performance critical - called for every packet */
98static inline bool 79static inline bool
@@ -121,7 +102,7 @@ ip_packet_match(const struct iphdr *ip,
121 return false; 102 return false;
122 } 103 }
123 104
124 ret = ifname_compare(indev, ipinfo->iniface, ipinfo->iniface_mask); 105 ret = ifname_compare_aligned(indev, ipinfo->iniface, ipinfo->iniface_mask);
125 106
126 if (FWINV(ret != 0, IPT_INV_VIA_IN)) { 107 if (FWINV(ret != 0, IPT_INV_VIA_IN)) {
127 dprintf("VIA in mismatch (%s vs %s).%s\n", 108 dprintf("VIA in mismatch (%s vs %s).%s\n",
@@ -130,7 +111,7 @@ ip_packet_match(const struct iphdr *ip,
130 return false; 111 return false;
131 } 112 }
132 113
133 ret = ifname_compare(outdev, ipinfo->outiface, ipinfo->outiface_mask); 114 ret = ifname_compare_aligned(outdev, ipinfo->outiface, ipinfo->outiface_mask);
134 115
135 if (FWINV(ret != 0, IPT_INV_VIA_OUT)) { 116 if (FWINV(ret != 0, IPT_INV_VIA_OUT)) {
136 dprintf("VIA out mismatch (%s vs %s).%s\n", 117 dprintf("VIA out mismatch (%s vs %s).%s\n",
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 34af7bb8df5f..e59662b3b5b9 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -89,25 +89,6 @@ ip6t_ext_hdr(u8 nexthdr)
89 (nexthdr == IPPROTO_DSTOPTS) ); 89 (nexthdr == IPPROTO_DSTOPTS) );
90} 90}
91 91
92static unsigned long ifname_compare(const char *_a, const char *_b,
93 const unsigned char *_mask)
94{
95 const unsigned long *a = (const unsigned long *)_a;
96 const unsigned long *b = (const unsigned long *)_b;
97 const unsigned long *mask = (const unsigned long *)_mask;
98 unsigned long ret;
99
100 ret = (a[0] ^ b[0]) & mask[0];
101 if (IFNAMSIZ > sizeof(unsigned long))
102 ret |= (a[1] ^ b[1]) & mask[1];
103 if (IFNAMSIZ > 2 * sizeof(unsigned long))
104 ret |= (a[2] ^ b[2]) & mask[2];
105 if (IFNAMSIZ > 3 * sizeof(unsigned long))
106 ret |= (a[3] ^ b[3]) & mask[3];
107 BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
108 return ret;
109}
110
111/* Returns whether matches rule or not. */ 92/* Returns whether matches rule or not. */
112/* Performance critical - called for every packet */ 93/* Performance critical - called for every packet */
113static inline bool 94static inline bool
@@ -138,7 +119,7 @@ ip6_packet_match(const struct sk_buff *skb,
138 return false; 119 return false;
139 } 120 }
140 121
141 ret = ifname_compare(indev, ip6info->iniface, ip6info->iniface_mask); 122 ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask);
142 123
143 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) { 124 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
144 dprintf("VIA in mismatch (%s vs %s).%s\n", 125 dprintf("VIA in mismatch (%s vs %s).%s\n",
@@ -147,7 +128,7 @@ ip6_packet_match(const struct sk_buff *skb,
147 return false; 128 return false;
148 } 129 }
149 130
150 ret = ifname_compare(outdev, ip6info->outiface, ip6info->outiface_mask); 131 ret = ifname_compare_aligned(outdev, ip6info->outiface, ip6info->outiface_mask);
151 132
152 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) { 133 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
153 dprintf("VIA out mismatch (%s vs %s).%s\n", 134 dprintf("VIA out mismatch (%s vs %s).%s\n",
diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c
index 44a234ef4439..8d28ca5848bc 100644
--- a/net/netfilter/xt_physdev.c
+++ b/net/netfilter/xt_physdev.c
@@ -20,23 +20,6 @@ MODULE_DESCRIPTION("Xtables: Bridge physical device match");
20MODULE_ALIAS("ipt_physdev"); 20MODULE_ALIAS("ipt_physdev");
21MODULE_ALIAS("ip6t_physdev"); 21MODULE_ALIAS("ip6t_physdev");
22 22
23static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask)
24{
25 const unsigned long *a = (const unsigned long *)_a;
26 const unsigned long *b = (const unsigned long *)_b;
27 const unsigned long *mask = (const unsigned long *)_mask;
28 unsigned long ret;
29
30 ret = (a[0] ^ b[0]) & mask[0];
31 if (IFNAMSIZ > sizeof(unsigned long))
32 ret |= (a[1] ^ b[1]) & mask[1];
33 if (IFNAMSIZ > 2 * sizeof(unsigned long))
34 ret |= (a[2] ^ b[2]) & mask[2];
35 if (IFNAMSIZ > 3 * sizeof(unsigned long))
36 ret |= (a[3] ^ b[3]) & mask[3];
37 BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
38 return ret;
39}
40 23
41static bool 24static bool
42physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par) 25physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par)
@@ -85,7 +68,7 @@ physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par)
85 if (!(info->bitmask & XT_PHYSDEV_OP_IN)) 68 if (!(info->bitmask & XT_PHYSDEV_OP_IN))
86 goto match_outdev; 69 goto match_outdev;
87 indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname; 70 indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname;
88 ret = ifname_compare(indev, info->physindev, info->in_mask); 71 ret = ifname_compare_aligned(indev, info->physindev, info->in_mask);
89 72
90 if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN)) 73 if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN))
91 return false; 74 return false;
@@ -95,7 +78,7 @@ match_outdev:
95 return true; 78 return true;
96 outdev = nf_bridge->physoutdev ? 79 outdev = nf_bridge->physoutdev ?
97 nf_bridge->physoutdev->name : nulldevname; 80 nf_bridge->physoutdev->name : nulldevname;
98 ret = ifname_compare(outdev, info->physoutdev, info->out_mask); 81 ret = ifname_compare_aligned(outdev, info->physoutdev, info->out_mask);
99 82
100 return (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT)); 83 return (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT));
101} 84}