Add new extended match files.
diff --git a/tc/em_u32.c b/tc/em_u32.c
new file mode 100644
index 0000000..b8857f1
--- /dev/null
+++ b/tc/em_u32.c
@@ -0,0 +1,178 @@
+/*
+ * em_u32.c		U32 Ematch
+ *
+ *		This program is free software; you can distribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ *
+ * Authors:	Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <errno.h>
+
+#include "m_ematch.h"
+
+extern struct ematch_util u32_ematch_util;
+
+static void u32_print_usage(FILE *fd)
+{
+	fprintf(fd,
+	    "Usage: u32(ALIGN VALUE MASK at [ nexthdr+ ] OFFSET)\n" \
+	    "where: ALIGN  := { u8 | u16 | u32 }\n" \
+	    "\n" \
+	    "Example: u32(u16 0x1122 0xffff at nexthdr+4)\n");
+}
+
+static int u32_parse_eopt(struct nlmsghdr *n, struct tcf_ematch_hdr *hdr,
+			  struct bstr *args)
+{
+	struct bstr *a;
+	int align, nh_len;
+	unsigned long key, mask, offmask = 0, offset;
+	struct tc_u32_key u_key;
+
+	memset(&u_key, 0, sizeof(u_key));
+
+#define PARSE_ERR(CARG, FMT, ARGS...) \
+	em_parse_error(EINVAL, args, CARG, &u32_ematch_util, FMT ,##ARGS)
+
+	if (args == NULL)
+		return PARSE_ERR(args, "u32: missing arguments");
+
+	if (!bstrcmp(args, "u8"))
+		align = 1;
+	else if (!bstrcmp(args, "u16"))
+		align = 2;
+	else if (!bstrcmp(args, "u32"))
+		align = 4;
+	else
+		return PARSE_ERR(args, "u32: invalid alignment");
+
+	a = bstr_next(args);
+	if (a == NULL)
+		return PARSE_ERR(a, "u32: missing key");
+
+	key = bstrtoul(a);
+	if (key == ULONG_MAX)
+		return PARSE_ERR(a, "u32: invalid key, must be numeric");
+
+	a = bstr_next(a);
+	if (a == NULL)
+		return PARSE_ERR(a, "u32: missing mask");
+
+	mask = bstrtoul(a);
+	if (mask == ULONG_MAX)
+		return PARSE_ERR(a, "u32: invalid mask, must be numeric");
+
+	a = bstr_next(a);
+	if (a == NULL || bstrcmp(a, "at") != 0)
+		return PARSE_ERR(a, "u32: missing \"at\"");
+
+	a = bstr_next(a);
+	if (a == NULL)
+		return PARSE_ERR(a, "u32: missing offset");
+
+	nh_len = strlen("nexthdr+");
+	if (a->len > nh_len && !memcmp(a->data, "nexthdr+", nh_len)) {
+		char buf[a->len - nh_len + 1];
+		offmask = -1;
+		memcpy(buf, a->data + nh_len, a->len - nh_len);
+		offset = strtoul(buf, NULL, 0);
+	} else if (!bstrcmp(a, "nexthdr+")) {
+		a = bstr_next(a);
+		if (a == NULL)
+			return PARSE_ERR(a, "u32: missing offset");
+		offset = bstrtoul(a);
+	} else
+		offset = bstrtoul(a);
+		
+	if (offset == ULONG_MAX)
+		return PARSE_ERR(a, "u32: invalid offset");
+
+	if (a->next)
+		return PARSE_ERR(a->next, "u32: unexpected trailer");
+
+	switch (align) {
+		case 1:
+			if (key > 0xFF)
+				return PARSE_ERR(a, "Illegal key (>0xFF)");
+			if (mask > 0xFF)
+				return PARSE_ERR(a, "Illegal mask (>0xFF)");
+
+			key <<= 24 - ((offset & 3) * 8);
+			mask <<= 24 - ((offset & 3) * 8);
+			offset &= ~3;
+			break;
+
+		case 2:
+			if (key > 0xFFFF)
+				return PARSE_ERR(a, "Illegal key (>0xFFFF)");
+			if (mask > 0xFFFF)
+				return PARSE_ERR(a, "Illegal mask (>0xFFFF)");
+
+			if ((offset & 3) == 0) {
+				key <<= 16;
+				mask <<= 16;
+			}
+			offset &= ~3;
+			break;
+	}
+
+	key = htonl(key);
+	mask = htonl(mask);
+
+	if (offset % 4)
+		return PARSE_ERR(a, "u32: invalid offset alignment, " \
+		    "must be aligned to 4.");
+
+	key &= mask;
+
+	u_key.mask = mask;
+	u_key.val = key;
+	u_key.off = offset;
+	u_key.offmask = offmask;
+
+	addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
+	addraw_l(n, MAX_MSG, &u_key, sizeof(u_key));
+
+#undef PARSE_ERR
+	return 0;
+}
+
+static int u32_print_eopt(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
+			  int data_len)
+{
+	struct tc_u32_key *u_key = data;
+
+	if (data_len < sizeof(*u_key)) {
+		fprintf(stderr, "U32 header size mismatch\n");
+		return -1;
+	}
+
+	fprintf(fd, "%08x/%08x at %s%d",
+	    (unsigned int) ntohl(u_key->val),
+	    (unsigned int) ntohl(u_key->mask),
+	    u_key->offmask ? "nexthdr+" : "",
+	    u_key->off);
+
+	return 0;
+}
+
+struct ematch_util u32_ematch_util = {
+	.kind = "u32",
+	.kind_num = TCF_EM_U32,
+	.parse_eopt = u32_parse_eopt,
+	.print_eopt = u32_print_eopt,
+	.print_usage = u32_print_usage
+};