ソースを参照

[NETFILTER] nfnetlink: use highest bit of nfa_type to indicate nested TLV

As Henrik Nordstrom pointed out, all our efforts with "split endian" (i.e.
host byte order tags, net byte order values) are useless, unless a parser
can determine whether an attribute is nested or not.

This patch steals the highest bit of nfattr.nfa_type to indicate whether
the data payload contains a nested nfattr (1) or not (0).

This will break userspace compatibility, but luckily no kernel with
nfnetlink was released so far.

Signed-off-by: Harald Welte <laforge@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Harald Welte 19 年 前
コミット
ebe0bbf06c
2 ファイル変更10 行追加6 行削除
  1. 8 4
      include/linux/netfilter/nfnetlink.h
  2. 2 2
      net/netfilter/nfnetlink.c

+ 8 - 4
include/linux/netfilter/nfnetlink.h

@@ -41,11 +41,15 @@ enum nfnetlink_groups {
 struct nfattr
 struct nfattr
 {
 {
 	u_int16_t nfa_len;
 	u_int16_t nfa_len;
-	u_int16_t nfa_type;
+	u_int16_t nfa_type;	/* we use 15 bits for the type, and the highest
+				 * bit to indicate whether the payload is nested */
 } __attribute__ ((packed));
 } __attribute__ ((packed));
 
 
-/* FIXME: Shamelessly copy and pasted from rtnetlink.h, it's time
- * 	  to put this in a generic file */
+/* FIXME: Apart from NFNL_NFA_NESTED shamelessly copy and pasted from
+ * rtnetlink.h, it's time to put this in a generic file */
+
+#define NFNL_NFA_NEST	0x8000
+#define NFA_TYPE(attr) 	((attr)->nfa_type & 0x7fff)
 
 
 #define NFA_ALIGNTO     4
 #define NFA_ALIGNTO     4
 #define NFA_ALIGN(len)	(((len) + NFA_ALIGNTO - 1) & ~(NFA_ALIGNTO - 1))
 #define NFA_ALIGN(len)	(((len) + NFA_ALIGNTO - 1) & ~(NFA_ALIGNTO - 1))
@@ -59,7 +63,7 @@ struct nfattr
 #define NFA_PAYLOAD(nfa) ((int)((nfa)->nfa_len) - NFA_LENGTH(0))
 #define NFA_PAYLOAD(nfa) ((int)((nfa)->nfa_len) - NFA_LENGTH(0))
 #define NFA_NEST(skb, type) \
 #define NFA_NEST(skb, type) \
 ({	struct nfattr *__start = (struct nfattr *) (skb)->tail; \
 ({	struct nfattr *__start = (struct nfattr *) (skb)->tail; \
-	NFA_PUT(skb, type, 0, NULL); \
+	NFA_PUT(skb, (NFNL_NFA_NEST | type), 0, NULL); \
 	__start;  })
 	__start;  })
 #define NFA_NEST_END(skb, start) \
 #define NFA_NEST_END(skb, start) \
 ({      (start)->nfa_len = ((skb)->tail - (unsigned char *) (start)); \
 ({      (start)->nfa_len = ((skb)->tail - (unsigned char *) (start)); \

+ 2 - 2
net/netfilter/nfnetlink.c

@@ -133,7 +133,7 @@ int nfattr_parse(struct nfattr *tb[], int maxattr, struct nfattr *nfa, int len)
 	memset(tb, 0, sizeof(struct nfattr *) * maxattr);
 	memset(tb, 0, sizeof(struct nfattr *) * maxattr);
 
 
 	while (NFA_OK(nfa, len)) {
 	while (NFA_OK(nfa, len)) {
-		unsigned flavor = nfa->nfa_type;
+		unsigned flavor = NFA_TYPE(nfa);
 		if (flavor && flavor <= maxattr)
 		if (flavor && flavor <= maxattr)
 			tb[flavor-1] = nfa;
 			tb[flavor-1] = nfa;
 		nfa = NFA_NEXT(nfa, len);
 		nfa = NFA_NEXT(nfa, len);
@@ -177,7 +177,7 @@ nfnetlink_check_attributes(struct nfnetlink_subsystem *subsys,
 		int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
 		int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
 
 
 		while (NFA_OK(attr, attrlen)) {
 		while (NFA_OK(attr, attrlen)) {
-			unsigned flavor = attr->nfa_type;
+			unsigned flavor = NFA_TYPE(attr);
 			if (flavor) {
 			if (flavor) {
 				if (flavor > attr_count)
 				if (flavor > attr_count)
 					return -EINVAL;
 					return -EINVAL;