summaryrefslogtreecommitdiffstats
path: root/tests/test_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_api.c')
-rw-r--r--tests/test_api.c751
1 files changed, 751 insertions, 0 deletions
diff --git a/tests/test_api.c b/tests/test_api.c
new file mode 100644
index 0000000..57fdb90
--- /dev/null
+++ b/tests/test_api.c
@@ -0,0 +1,751 @@
+/*
+ * Run this after adding a new attribute to the nf_conntrack object
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <errno.h>
+
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+
+/*
+ * this file contains a test to check the set/get/copy/cmp APIs.
+ */
+
+static void eval_sigterm(int status)
+{
+ switch(WTERMSIG(status)) {
+ case SIGSEGV:
+ printf("received SIGSEV\n");
+ break;
+ case 0:
+ printf("OK\n");
+ break;
+ default:
+ printf("exited with signal: %d\n", WTERMSIG(status));
+ break;
+ }
+}
+
+static void test_nfct_bitmask(void)
+{
+ struct nfct_bitmask *a, *b;
+ unsigned short int maxb, i;
+ struct nf_conntrack *ct1, *ct2;
+
+ printf("== test nfct_bitmask_* API ==\n");
+
+ maxb = rand() & 0xffff;
+
+ a = nfct_bitmask_new(maxb);
+
+ assert(!nfct_bitmask_test_bit(a, maxb + 32));
+ nfct_bitmask_set_bit(a, maxb + 32);
+ assert(!nfct_bitmask_test_bit(a, maxb + 32));
+
+ for (i = 0; i <= maxb; i++)
+ assert(!nfct_bitmask_test_bit(a, i));
+
+ for (i = 0; i <= maxb; i++) {
+ if (rand() & 1) {
+ assert(!nfct_bitmask_test_bit(a, i));
+ continue;
+ }
+ nfct_bitmask_set_bit(a, i);
+ assert(nfct_bitmask_test_bit(a, i));
+ }
+
+ b = nfct_bitmask_clone(a);
+ assert(b);
+
+ for (i = 0; i <= maxb; i++) {
+ if (nfct_bitmask_test_bit(a, i))
+ assert(nfct_bitmask_test_bit(b, i));
+ else
+ assert(!nfct_bitmask_test_bit(b, i));
+ }
+
+ nfct_bitmask_destroy(a);
+
+ for (i = 0; i <= maxb; i++) {
+ if (rand() & 1)
+ continue;
+ nfct_bitmask_unset_bit(b, i);
+ assert(!nfct_bitmask_test_bit(b, i));
+ }
+
+ /* nfct_bitmask_clear() */
+ for (i = 0; i < maxb; i++) {
+ nfct_bitmask_set_bit(b, i);
+ assert(nfct_bitmask_test_bit(b, i));
+ nfct_bitmask_clear(b);
+ assert(!nfct_bitmask_test_bit(b, i));
+ }
+
+ for (i = 0; i < maxb; i++)
+ nfct_bitmask_set_bit(b, i);
+ nfct_bitmask_clear(b);
+ for (i = 0; i < maxb; i++)
+ assert(!nfct_bitmask_test_bit(b, i));
+
+ /* nfct_bitmask_equal() */
+ for (i = 0; i < maxb / 32 * 32; i += 32) {
+ a = nfct_bitmask_new(i);
+ assert(!nfct_bitmask_equal(a, b));
+ nfct_bitmask_destroy(a);
+ }
+
+ a = nfct_bitmask_clone(b);
+ assert(nfct_bitmask_equal(a, b));
+ for (i = 0; i < maxb; i++) {
+ if (nfct_bitmask_test_bit(a, i)) {
+ nfct_bitmask_unset_bit(a, i);
+ assert(!nfct_bitmask_equal(a, b));
+ nfct_bitmask_set_bit(a, i);
+ } else {
+ nfct_bitmask_set_bit(a, i);
+ assert(!nfct_bitmask_equal(a, b));
+ nfct_bitmask_unset_bit(a, i);
+ }
+ assert(nfct_bitmask_equal(a, b));
+ }
+
+ nfct_bitmask_destroy(a);
+ nfct_bitmask_destroy(b);
+
+ ct1 = nfct_new();
+ ct2 = nfct_new();
+
+ maxb = rand() & 0xff;
+ maxb += 128;
+ maxb /= 2;
+ a = nfct_bitmask_new(maxb * 2);
+ b = nfct_bitmask_new(maxb);
+ nfct_set_attr(ct1, ATTR_CONNLABELS, a);
+ nfct_set_attr(ct2, ATTR_CONNLABELS, b);
+
+ assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1);
+
+ nfct_bitmask_set_bit(a, maxb);
+ nfct_bitmask_set_bit(b, maxb);
+ assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1);
+
+ nfct_bitmask_set_bit(a, maxb * 2);
+ assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 0);
+ nfct_destroy(ct1);
+ nfct_destroy(ct2);
+ printf("OK\n");
+}
+
+/* These attributes cannot be set, ignore them. */
+static int attr_is_readonly(int attr)
+{
+ switch (attr) {
+ case ATTR_ORIG_COUNTER_PACKETS:
+ case ATTR_REPL_COUNTER_PACKETS:
+ case ATTR_ORIG_COUNTER_BYTES:
+ case ATTR_REPL_COUNTER_BYTES:
+ case ATTR_USE:
+ case ATTR_SECCTX:
+ case ATTR_TIMESTAMP_START:
+ case ATTR_TIMESTAMP_STOP:
+ return 1;
+ }
+ return 0;
+}
+
+
+static int test_nfct_cmp_api_single(struct nf_conntrack *ct1,
+ struct nf_conntrack *ct2, int attr)
+{
+ char data[256];
+ struct nfct_bitmask *b;
+ int bit;
+
+ if (attr_is_readonly(attr))
+ return 0;
+
+ switch (attr) {
+ case ATTR_SECMARK: /* obsolete */
+ return 0;
+
+ /* FIXME: not implemented comparators: */
+ case ATTR_SNAT_IPV4:
+ case ATTR_DNAT_IPV4:
+ case ATTR_SNAT_IPV6:
+ case ATTR_DNAT_IPV6:
+ case ATTR_SNAT_PORT:
+ case ATTR_DNAT_PORT:
+
+ case ATTR_TCP_FLAGS_ORIG:
+ case ATTR_TCP_FLAGS_REPL:
+ case ATTR_TCP_MASK_ORIG:
+ case ATTR_TCP_MASK_REPL:
+
+ case ATTR_MASTER_IPV4_SRC:
+ case ATTR_MASTER_IPV4_DST:
+ case ATTR_MASTER_IPV6_SRC:
+ case ATTR_MASTER_IPV6_DST:
+ case ATTR_MASTER_PORT_SRC:
+ case ATTR_MASTER_PORT_DST:
+ case ATTR_MASTER_L3PROTO:
+ case ATTR_MASTER_L4PROTO:
+
+ case ATTR_ORIG_NAT_SEQ_CORRECTION_POS:
+ case ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE:
+ case ATTR_ORIG_NAT_SEQ_OFFSET_AFTER:
+ case ATTR_REPL_NAT_SEQ_CORRECTION_POS:
+ case ATTR_REPL_NAT_SEQ_OFFSET_BEFORE:
+ case ATTR_REPL_NAT_SEQ_OFFSET_AFTER:
+
+ case ATTR_SCTP_VTAG_ORIG:
+ case ATTR_SCTP_VTAG_REPL:
+
+ case ATTR_HELPER_NAME:
+
+ case ATTR_DCCP_ROLE:
+ case ATTR_DCCP_HANDSHAKE_SEQ:
+
+ case ATTR_TCP_WSCALE_ORIG:
+ case ATTR_TCP_WSCALE_REPL:
+
+ case ATTR_SYNPROXY_ISN:
+ case ATTR_SYNPROXY_ITS:
+ case ATTR_SYNPROXY_TSOFF:
+
+ case ATTR_HELPER_INFO:
+ return 0; /* XXX */
+
+ default:
+ break;
+ }
+
+ if (attr >= ATTR_SCTP_STATE) {
+ nfct_set_attr_u8(ct1, ATTR_REPL_L4PROTO, IPPROTO_SCTP);
+ nfct_set_attr_u8(ct1, ATTR_L4PROTO, IPPROTO_SCTP);
+ } else if (attr >= ATTR_TCP_FLAGS_ORIG) {
+ nfct_set_attr_u8(ct1, ATTR_REPL_L4PROTO, IPPROTO_TCP);
+ nfct_set_attr_u8(ct1, ATTR_L4PROTO, IPPROTO_TCP);
+ } else if (attr >= ATTR_ICMP_CODE) {
+ nfct_set_attr_u8(ct1, ATTR_REPL_L4PROTO, IPPROTO_ICMP);
+ nfct_set_attr_u8(ct1, ATTR_L4PROTO, IPPROTO_ICMP);
+ } else if (attr >= ATTR_ORIG_PORT_SRC) {
+ nfct_set_attr_u8(ct1, ATTR_REPL_L4PROTO, IPPROTO_TCP);
+ nfct_set_attr_u8(ct1, ATTR_L4PROTO, IPPROTO_TCP);
+ }
+
+ nfct_copy(ct2, ct1, NFCT_CP_OVERRIDE);
+ memset(data, 42, sizeof(data));
+
+ assert(nfct_attr_is_set(ct1, attr));
+ assert(nfct_attr_is_set(ct2, attr));
+
+ switch (attr) {
+ case ATTR_CONNLABELS:
+ case ATTR_CONNLABELS_MASK:
+ b = (void *) nfct_get_attr(ct1, attr);
+ assert(b);
+ b = nfct_bitmask_clone(b);
+ assert(b);
+ bit = nfct_bitmask_maxbit(b);
+ if (nfct_bitmask_test_bit(b, bit)) {
+ nfct_bitmask_unset_bit(b, bit);
+ assert(!nfct_bitmask_test_bit(b, bit));
+ } else {
+ nfct_bitmask_set_bit(b, bit);
+ assert(nfct_bitmask_test_bit(b, bit));
+ }
+ assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1);
+ nfct_set_attr(ct2, attr, b);
+ break;
+ case ATTR_HELPER_INFO:
+ nfct_set_attr_l(ct2, attr, "test", 4);
+ break;
+ default:
+ nfct_set_attr(ct2, attr, data);
+ break;
+ }
+
+ if (nfct_cmp(ct1, ct2, NFCT_CMP_ALL) != 0) {
+ fprintf(stderr, "nfct_cmp assert failure for attr %d\n", attr);
+ fprintf(stderr, "%p, %p, %x, %x\n", nfct_get_attr(ct1, attr),
+ nfct_get_attr(ct2, attr),
+ nfct_get_attr_u32(ct1, attr), nfct_get_attr_u32(ct2, attr));
+ return -1;
+ }
+ if (nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) != 0) {
+ fprintf(stderr, "nfct_cmp strict assert failure for attr %d\n", attr);
+ return -1;
+ }
+ return 0;
+}
+
+static int test_cmp_attr32(int attr, bool at1, bool at2,
+ uint32_t v1, uint32_t v2, unsigned int flags)
+{
+ struct nf_conntrack *ct1 = nfct_new();
+ struct nf_conntrack *ct2 = nfct_new();
+ int ret;
+
+ if (at1)
+ nfct_set_attr_u32(ct1, attr, v1);
+ if (at2)
+ nfct_set_attr_u32(ct2, attr, v2);
+
+ ret = nfct_cmp(ct1, ct2, NFCT_CMP_ALL | flags);
+
+ nfct_destroy(ct1);
+ nfct_destroy(ct2);
+
+ return ret;
+}
+
+static void test_nfct_cmp_attr(int attr)
+{
+ unsigned int flags = 0;
+
+ /* 0000, 1000, 1100, 0010, 1010... */
+ /* attr at1 at2 v1 v2 */
+ assert(test_cmp_attr32(attr, false, false, 0, 0, flags) == 1);
+ assert(test_cmp_attr32(attr, true, false, 0, 0, flags) == 1);
+ assert(test_cmp_attr32(attr, false, true, 0, 0, flags) == 1);
+ assert(test_cmp_attr32(attr, true, true, 0, 0, flags) == 1);
+ assert(test_cmp_attr32(attr, false, false, 1, 0, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, true, false, 1, 0, flags) == 1);
+ assert(test_cmp_attr32(attr, false, true, 1, 0, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, true, true, 1, 0, flags) == 0);
+ assert(test_cmp_attr32(attr, false, false, 0, 1, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, true, false, 0, 1, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, false, true, 0, 1, flags) == 1);
+ assert(test_cmp_attr32(attr, true, true, 0, 1, flags) == 0);
+ assert(test_cmp_attr32(attr, false, false, 1, 1, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, true, false, 1, 1, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, false, true, 1, 1, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, true, true, 1, 1, flags) == 1);
+
+ flags = NFCT_CMP_STRICT;
+ assert(test_cmp_attr32(attr, false, false, 0, 0, flags) == 1);
+ assert(test_cmp_attr32(attr, true, false, 0, 0, flags) == 1);
+ assert(test_cmp_attr32(attr, false, true, 0, 0, flags) == 1);
+ assert(test_cmp_attr32(attr, true, true, 0, 0, flags) == 1);
+ assert(test_cmp_attr32(attr, false, false, 1, 0, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, true, false, 1, 0, flags) == 0);
+ assert(test_cmp_attr32(attr, false, true, 1, 0, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, true, true, 1, 0, flags) == 0);
+ assert(test_cmp_attr32(attr, false, false, 0, 1, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, true, false, 0, 1, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, false, true, 0, 1, flags) == 0);
+ assert(test_cmp_attr32(attr, true, true, 0, 1, flags) == 0);
+ assert(test_cmp_attr32(attr, false, false, 1, 1, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, true, false, 1, 1, flags) == 0); /* verbose */
+ assert(test_cmp_attr32(attr, false, true, 1, 1, flags) == 0); /* verbose */
+ assert(test_cmp_attr32(attr, true, true, 1, 1, flags) == 1);
+
+ flags = NFCT_CMP_MASK;
+ assert(test_cmp_attr32(attr, false, false, 0, 0, flags) == 1);
+ assert(test_cmp_attr32(attr, true, false, 0, 0, flags) == 1);
+ assert(test_cmp_attr32(attr, false, true, 0, 0, flags) == 1);
+ assert(test_cmp_attr32(attr, true, true, 0, 0, flags) == 1);
+ assert(test_cmp_attr32(attr, false, false, 1, 0, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, true, false, 1, 0, flags) == 0);
+ assert(test_cmp_attr32(attr, false, true, 1, 0, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, true, true, 1, 0, flags) == 0);
+ assert(test_cmp_attr32(attr, false, false, 0, 1, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, true, false, 0, 1, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, false, true, 0, 1, flags) == 1);
+ assert(test_cmp_attr32(attr, true, true, 0, 1, flags) == 0);
+ assert(test_cmp_attr32(attr, false, false, 1, 1, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, true, false, 1, 1, flags) == 0); /* verbose */
+ assert(test_cmp_attr32(attr, false, true, 1, 1, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, true, true, 1, 1, flags) == 1);
+
+ flags = NFCT_CMP_STRICT|NFCT_CMP_MASK;
+ assert(test_cmp_attr32(attr, false, false, 0, 0, flags) == 1);
+ assert(test_cmp_attr32(attr, true, false, 0, 0, flags) == 1);
+ assert(test_cmp_attr32(attr, false, true, 0, 0, flags) == 1);
+ assert(test_cmp_attr32(attr, true, true, 0, 0, flags) == 1);
+ assert(test_cmp_attr32(attr, false, false, 1, 0, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, true, false, 1, 0, flags) == 0);
+ assert(test_cmp_attr32(attr, false, true, 1, 0, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, true, true, 1, 0, flags) == 0);
+ assert(test_cmp_attr32(attr, false, false, 0, 1, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, true, false, 0, 1, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, false, true, 0, 1, flags) == 0);
+ assert(test_cmp_attr32(attr, true, true, 0, 1, flags) == 0);
+ assert(test_cmp_attr32(attr, false, false, 1, 1, flags) == 1); /* verbose */
+ assert(test_cmp_attr32(attr, true, false, 1, 1, flags) == 0); /* verbose */
+ assert(test_cmp_attr32(attr, false, true, 1, 1, flags) == 0); /* verbose */
+ assert(test_cmp_attr32(attr, true, true, 1, 1, flags) == 1);
+}
+
+static void test_nfct_cmp_api(struct nf_conntrack *ct1, struct nf_conntrack *ct2)
+{
+ int i;
+
+ printf("== test cmp API ==\n");
+
+ test_nfct_cmp_attr(ATTR_ZONE);
+ test_nfct_cmp_attr(ATTR_ORIG_ZONE);
+ test_nfct_cmp_attr(ATTR_REPL_ZONE);
+ test_nfct_cmp_attr(ATTR_MARK);
+
+ assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1);
+ assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) == 0);
+
+ nfct_copy(ct1, ct2, NFCT_CP_OVERRIDE);
+
+ assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1);
+ assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) == 1);
+
+ for (i=0; i < ATTR_MAX ; i++) {
+ nfct_attr_unset(ct1, i);
+
+ assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1);
+ assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) == 0);
+ assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_MASK) == 1);
+ }
+ nfct_copy(ct1, ct2, NFCT_CP_OVERRIDE);
+ for (i=0; i < ATTR_MAX ; i++) {
+ nfct_attr_unset(ct2, i);
+
+ assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1);
+ assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) == 0);
+ assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_MASK) == 0);
+ }
+
+ for (i=0; i < ATTR_MAX ; i++)
+ assert(test_nfct_cmp_api_single(ct1, ct2, i) == 0);
+
+ nfct_copy(ct2, ct1, NFCT_CP_OVERRIDE);
+ for (i=0; i < ATTR_MAX ; i++) {
+ nfct_attr_unset(ct1, i);
+ nfct_attr_unset(ct2, i);
+
+ assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL) == 1);
+ assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_STRICT) == 1);
+ assert(nfct_cmp(ct1, ct2, NFCT_CMP_ALL|NFCT_CMP_MASK) == 1);
+ }
+ nfct_destroy(ct1);
+ nfct_destroy(ct2);
+}
+
+static void test_nfexp_cmp_api(struct nf_expect *ex1, struct nf_expect *ex2)
+{
+ int i;
+
+ printf("== test expect cmp API ==\n");
+
+ /* XXX: missing nfexp_copy API. */
+ memcpy(ex1, ex2, nfexp_maxsize());
+
+ assert(nfexp_cmp(ex1, ex2, 0) == 1);
+ assert(nfexp_cmp(ex1, ex2, NFCT_CMP_STRICT) == 1);
+
+ assert(nfexp_attr_is_set(ex1, 0) == 1);
+ nfexp_attr_unset(ex1, 0);
+ assert(nfexp_attr_is_set(ex1, 0) == 0);
+
+ memcpy(ex1, ex2, nfexp_maxsize());
+ for (i=0; i < ATTR_EXP_MAX; i++) {
+ nfexp_attr_unset(ex1, i);
+
+ assert(nfexp_cmp(ex1, ex2, 0) == 1);
+ assert(nfexp_cmp(ex1, ex2, NFCT_CMP_STRICT) == 0);
+ assert(nfexp_cmp(ex1, ex2, NFCT_CMP_MASK) == 1);
+ }
+ memcpy(ex1, ex2, nfexp_maxsize());
+ for (i=0; i < ATTR_EXP_MAX; i++) {
+ nfexp_attr_unset(ex2, i);
+
+ assert(nfexp_cmp(ex1, ex2, 0) == 1);
+ assert(nfexp_cmp(ex1, ex2, NFCT_CMP_MASK) == 0);
+ }
+ memcpy(ex1, ex2, nfexp_maxsize());
+ for (i=0; i < ATTR_EXP_MAX; i++) {
+ nfexp_attr_unset(ex1, i);
+ nfexp_attr_unset(ex2, i);
+
+ assert(nfexp_cmp(ex1, ex2, 0) == 1);
+ assert(nfexp_cmp(ex1, ex2, NFCT_CMP_STRICT) == 1);
+ assert(nfexp_cmp(ex1, ex2, NFCT_CMP_MASK) == 1);
+ }
+ nfexp_destroy(ex1);
+ nfexp_destroy(ex2);
+}
+
+int main(void)
+{
+ int ret, i;
+ struct nf_conntrack *ct, *ct2, *tmp;
+ struct nf_expect *exp, *tmp_exp;
+ char data[256];
+ const char *val;
+ int status;
+ struct nfct_bitmask *b, *b2;
+
+ srand(time(NULL));
+
+ /* initialize fake data for testing purposes */
+ for (i=0; i<sizeof(data); i++)
+ data[i] = 0x01;
+
+ ct = nfct_new();
+ if (!ct) {
+ perror("nfct_new");
+ return 0;
+ }
+ tmp = nfct_new();
+ if (!tmp) {
+ perror("nfct_new");
+ return 0;
+ }
+
+ printf("== test set API ==\n");
+ ret = fork();
+ if (ret == 0) {
+ for (i=0; i<ATTR_MAX; i++)
+ nfct_set_attr(ct, i, data);
+ exit(0);
+ } else {
+ wait(&status);
+ eval_sigterm(status);
+ }
+
+ b = nfct_bitmask_new(rand() & 0xffff);
+ assert(b);
+ b2 = nfct_bitmask_new(rand() & 0xffff);
+ assert(b2);
+
+ for (i=0; i<ATTR_MAX; i++) {
+ switch (i) {
+ case ATTR_CONNLABELS:
+ nfct_set_attr(ct, i, b);
+ break;
+ case ATTR_CONNLABELS_MASK:
+ nfct_set_attr(ct, i, b2);
+ break;
+ default:
+ nfct_set_attr(ct, i, data);
+ break;
+ }
+ }
+
+ printf("== test get API ==\n");
+ ret = fork();
+ if (ret == 0) {
+ for (i=0; i<ATTR_MAX; i++)
+ nfct_get_attr(ct, i);
+ exit(0);
+ } else {
+ wait(&status);
+ eval_sigterm(status);
+ }
+
+ printf("== validate set API ==\n");
+ ret = fork();
+ if (ret == 0) {
+ for (i=0; i<ATTR_MAX; i++) {
+ if (attr_is_readonly(i))
+ continue;
+ switch(i) {
+ /* These attributes require special handling */
+ case ATTR_HELPER_INFO:
+ nfct_set_attr_l(ct, i, data, sizeof(data));
+ break;
+ case ATTR_CONNLABELS:
+ case ATTR_CONNLABELS_MASK:
+ /* already set above */
+ break;
+ default:
+ data[0] = (uint8_t) i;
+ nfct_set_attr(ct, i, data);
+ }
+ val = nfct_get_attr(ct, i);
+ switch (i) {
+ case ATTR_CONNLABELS:
+ assert((void *) val == b);
+ continue;
+ case ATTR_CONNLABELS_MASK:
+ assert((void *) val == b2);
+ continue;
+ }
+
+ if (val[0] != data[0]) {
+ printf("ERROR: set/get operations don't match "
+ "for attribute %d (%x != %x)\n",
+ i, val[0], data[0]);
+ }
+ }
+ exit(0);
+ } else {
+ wait(&status);
+ eval_sigterm(status);
+ }
+
+ printf("== test copy API ==\n");
+ ret = fork();
+ if (ret == 0) {
+ for (i=0; i<ATTR_MAX; i++)
+ nfct_copy_attr(tmp, ct, i);
+ exit(0);
+ } else {
+ wait(&status);
+ eval_sigterm(status);
+ }
+
+ ret = fork();
+ if (ret == 0) {
+ test_nfct_cmp_api(tmp, ct);
+ exit(0);
+ } else {
+ wait(&status);
+ eval_sigterm(status);
+ }
+
+ exp = nfexp_new();
+ if (!exp) {
+ perror("nfexp_new");
+ return 0;
+ }
+ tmp_exp = nfexp_new();
+ if (!tmp_exp) {
+ perror("nfexp_new");
+ return 0;
+ }
+
+ printf("== test expect set API ==\n");
+ ret = fork();
+ if (ret == 0) {
+ for (i=0; i<ATTR_EXP_MAX; i++)
+ nfexp_set_attr(exp, i, data);
+ exit(0);
+ } else {
+ wait(&status);
+ eval_sigterm(status);
+ }
+
+ for (i=0; i<ATTR_EXP_MAX; i++)
+ nfexp_set_attr(exp, i, data);
+
+ printf("== test expect get API ==\n");
+ ret = fork();
+ if (ret == 0) {
+ for (i=0; i<ATTR_EXP_MAX; i++)
+ nfexp_get_attr(exp, i);
+ exit(0);
+ } else {
+ wait(&status);
+ eval_sigterm(status);
+ }
+
+ printf("== validate expect set API ==\n");
+ ret = fork();
+ if (ret == 0) {
+ for (i=0; i<ATTR_EXP_MAX; i++) {
+ data[0] = (uint8_t) i;
+ nfexp_set_attr(exp, i, data);
+ val = nfexp_get_attr(exp, i);
+ if (val[0] != data[0]) {
+ printf("ERROR: set/get operations don't match "
+ "for attribute %d (%x != %x)\n",
+ i, val[0], data[0]);
+ }
+ }
+ exit(0);
+ } else {
+ wait(&status);
+ eval_sigterm(status);
+ }
+
+ ret = fork();
+ if (ret == 0) {
+ test_nfexp_cmp_api(tmp_exp, exp);
+ exit(0);
+ } else {
+ wait(&status);
+ eval_sigterm(status);
+ }
+
+ ct2 = nfct_new();
+ if (!ct2) {
+ perror("nfct_new");
+ return 0;
+ }
+
+ printf("== test set grp API ==\n");
+ ret = fork();
+ if (ret == 0) {
+ for (i=0; i<ATTR_GRP_MAX; i++)
+ nfct_set_attr_grp(ct2, i, data);
+ exit(0);
+ } else {
+ wait(&status);
+ eval_sigterm(status);
+ }
+
+ for (i=0; i<ATTR_GRP_MAX; i++)
+ nfct_set_attr_grp(ct2, i, data);
+
+ printf("== test get grp API ==\n");
+ ret = fork();
+ if (ret == 0) {
+ char buf[32]; /* IPv6 group address is 16 bytes * 2 */
+
+ for (i=0; i<ATTR_GRP_MAX; i++)
+ nfct_get_attr_grp(ct2, i, buf);
+ exit(0);
+ } else {
+ wait(&status);
+ eval_sigterm(status);
+ }
+
+ printf("== validate set grp API ==\n");
+ ret = fork();
+ if (ret == 0) {
+ for (i=0; i<ATTR_GRP_MAX; i++) {
+ char buf[32]; /* IPv6 group address is 16 bytes */
+
+ data[0] = (uint8_t) i;
+ nfct_set_attr_grp(ct2, i, data);
+ nfct_get_attr_grp(ct2, i, buf);
+ /* These attributes cannot be set, ignore them. */
+ switch(i) {
+ case ATTR_GRP_ORIG_COUNTERS:
+ case ATTR_GRP_REPL_COUNTERS:
+ case ATTR_GRP_ORIG_ADDR_SRC:
+ case ATTR_GRP_ORIG_ADDR_DST:
+ case ATTR_GRP_REPL_ADDR_SRC:
+ case ATTR_GRP_REPL_ADDR_DST:
+ continue;
+ }
+ if (buf[0] != data[0]) {
+ printf("ERROR: set/get operations don't match "
+ "for attribute %d (%x != %x)\n",
+ i, buf[0], data[0]);
+ }
+ }
+ exit(0);
+ } else {
+ wait(&status);
+ eval_sigterm(status);
+ }
+
+ nfct_destroy(ct2);
+ printf("== destroy cloned ct entry ==\n");
+ nfct_destroy(ct);
+ nfct_destroy(tmp);
+ nfexp_destroy(exp);
+ nfexp_destroy(tmp_exp);
+
+ printf("OK\n");
+
+ test_nfct_bitmask();
+
+ return EXIT_SUCCESS;
+}