aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2008-04-10 05:02:28 -0400
committerDavid S. Miller <davem@davemloft.net>2008-04-10 05:02:28 -0400
commit4738c1db1593687713869fa69e733eebc7b0d6d8 (patch)
tree4da848f5944f89cc5393f173d95227c3e76423f2
parent3cccd6078413e9707f0ef3652b4e6e9cb84e9fa0 (diff)
[SKFILTER]: Add SKF_ADF_NLATTR instruction
SKF_ADF_NLATTR searches for a netlink attribute, which avoids manually parsing and walking attributes. It takes the offset at which to start searching in the 'A' register and the attribute type in the 'X' register and returns the offset in the 'A' register. When the attribute is not found it returns zero. A top-level attribute can be located using a filter like this (example for nfnetlink, using struct nfgenmsg): ... { /* A = offset of first attribute */ .code = BPF_LD | BPF_IMM, .k = sizeof(struct nlmsghdr) + sizeof(struct nfgenmsg) }, { /* X = CTA_PROTOINFO */ .code = BPF_LDX | BPF_IMM, .k = CTA_PROTOINFO, }, { /* A = netlink attribute offset */ .code = BPF_LD | BPF_B | BPF_ABS, .k = SKF_AD_OFF + SKF_AD_NLATTR }, { /* Exit if not found */ .code = BPF_JMP | BPF_JEQ | BPF_K, .k = 0, .jt = <error> }, ... A nested attribute below the CTA_PROTOINFO attribute would then be parsed like this: ... { /* A += sizeof(struct nlattr) */ .code = BPF_ALU | BPF_ADD | BPF_K, .k = sizeof(struct nlattr), }, { /* X = CTA_PROTOINFO_TCP */ .code = BPF_LDX | BPF_IMM, .k = CTA_PROTOINFO_TCP, }, { /* A = netlink attribute offset */ .code = BPF_LD | BPF_B | BPF_ABS, .k = SKF_AD_OFF + SKF_AD_NLATTR }, ... The data of an attribute can be loaded into 'A' like this: ... { /* X = A (attribute offset) */ .code = BPF_MISC | BPF_TAX, }, { /* A = skb->data[X + k] */ .code = BPF_LD | BPF_B | BPF_IND, .k = sizeof(struct nlattr), }, ... Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/filter.h3
-rw-r--r--net/core/filter.c17
2 files changed, 19 insertions, 1 deletions
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 673e5677ebcc..b6ea9aa9e853 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -121,7 +121,8 @@ struct sock_fprog /* Required for SO_ATTACH_FILTER. */
121#define SKF_AD_PROTOCOL 0 121#define SKF_AD_PROTOCOL 0
122#define SKF_AD_PKTTYPE 4 122#define SKF_AD_PKTTYPE 4
123#define SKF_AD_IFINDEX 8 123#define SKF_AD_IFINDEX 8
124#define SKF_AD_MAX 12 124#define SKF_AD_NLATTR 12
125#define SKF_AD_MAX 16
125#define SKF_NET_OFF (-0x100000) 126#define SKF_NET_OFF (-0x100000)
126#define SKF_LL_OFF (-0x200000) 127#define SKF_LL_OFF (-0x200000)
127 128
diff --git a/net/core/filter.c b/net/core/filter.c
index bbb53c69857c..f5f3cf603064 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -27,6 +27,7 @@
27#include <linux/if_packet.h> 27#include <linux/if_packet.h>
28#include <net/ip.h> 28#include <net/ip.h>
29#include <net/protocol.h> 29#include <net/protocol.h>
30#include <net/netlink.h>
30#include <linux/skbuff.h> 31#include <linux/skbuff.h>
31#include <net/sock.h> 32#include <net/sock.h>
32#include <linux/errno.h> 33#include <linux/errno.h>
@@ -303,6 +304,22 @@ load_b:
303 case SKF_AD_IFINDEX: 304 case SKF_AD_IFINDEX:
304 A = skb->dev->ifindex; 305 A = skb->dev->ifindex;
305 continue; 306 continue;
307 case SKF_AD_NLATTR: {
308 struct nlattr *nla;
309
310 if (skb_is_nonlinear(skb))
311 return 0;
312 if (A > skb->len - sizeof(struct nlattr))
313 return 0;
314
315 nla = nla_find((struct nlattr *)&skb->data[A],
316 skb->len - A, X);
317 if (nla)
318 A = (void *)nla - (void *)skb->data;
319 else
320 A = 0;
321 continue;
322 }
306 default: 323 default:
307 return 0; 324 return 0;
308 } 325 }