aboutsummaryrefslogtreecommitdiffstats
path: root/net
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 /net
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>
Diffstat (limited to 'net')
-rw-r--r--net/core/filter.c17
1 files changed, 17 insertions, 0 deletions
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 }