struct nfnl_callback
 {
-       kernel_cap_t cap_required; /* capabilities required for this msg */
        int (*call)(struct sock *nl, struct sk_buff *skb, 
                struct nlmsghdr *nlh, struct nfattr *cda[], int *errp);
+       kernel_cap_t cap_required; /* capabilities required for this msg */
+       u_int16_t attr_count;   /* number of nfattr's */
 };
 
 struct nfnetlink_subsystem
        const char *name;
        __u8 subsys_id;         /* nfnetlink subsystem ID */
        __u8 cb_count;          /* number of callbacks */
-       u_int32_t attr_count;   /* number of nfattr's */
        struct nfnl_callback *cb; /* callback for individual types */
 };
 
 
 
 static struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
        [IPCTNL_MSG_CT_NEW]             = { .call = ctnetlink_new_conntrack,
+                                           .attr_count = CTA_MAX,
                                            .cap_required = CAP_NET_ADMIN },
        [IPCTNL_MSG_CT_GET]             = { .call = ctnetlink_get_conntrack,
+                                           .attr_count = CTA_MAX,
                                            .cap_required = CAP_NET_ADMIN },
        [IPCTNL_MSG_CT_DELETE]          = { .call = ctnetlink_del_conntrack,
+                                           .attr_count = CTA_MAX,
                                            .cap_required = CAP_NET_ADMIN },
        [IPCTNL_MSG_CT_GET_CTRZERO]     = { .call = ctnetlink_get_conntrack,
+                                           .attr_count = CTA_MAX,
                                            .cap_required = CAP_NET_ADMIN },
 };
 
 static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_MAX] = {
        [IPCTNL_MSG_EXP_GET]            = { .call = ctnetlink_get_expect,
+                                           .attr_count = CTA_EXPECT_MAX,
                                            .cap_required = CAP_NET_ADMIN },
        [IPCTNL_MSG_EXP_NEW]            = { .call = ctnetlink_new_expect,
+                                           .attr_count = CTA_EXPECT_MAX,
                                            .cap_required = CAP_NET_ADMIN },
        [IPCTNL_MSG_EXP_DELETE]         = { .call = ctnetlink_del_expect,
+                                           .attr_count = CTA_EXPECT_MAX,
                                            .cap_required = CAP_NET_ADMIN },
 };
 
        .name                           = "conntrack",
        .subsys_id                      = NFNL_SUBSYS_CTNETLINK,
        .cb_count                       = IPCTNL_MSG_MAX,
-       .attr_count                     = CTA_MAX,
        .cb                             = ctnl_cb,
 };
 
        .name                           = "conntrack_expect",
        .subsys_id                      = NFNL_SUBSYS_CTNETLINK_EXP,
        .cb_count                       = IPCTNL_MSG_EXP_MAX,
-       .attr_count                     = CTA_MAX,
        .cb                             = ctnl_exp_cb,
 };
 
 
                           struct nlmsghdr *nlh, struct nfattr *cda[])
 {
        int min_len;
+       u_int16_t attr_count;
+       u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
 
-       memset(cda, 0, sizeof(struct nfattr *) * subsys->attr_count);
+       if (unlikely(cb_id >= subsys->cb_count)) {
+               DEBUGP("msgtype %u >= %u, returning\n",
+                       cb_id, subsys->cb_count);
+               return -EINVAL;
+       }
+       
+       attr_count = subsys->cb[cb_id].attr_count;
+
+       memset(cda, 0, sizeof(struct nfattr *) * attr_count);
 
        /* check attribute lengths. */
        min_len = NLMSG_ALIGN(sizeof(struct nfgenmsg));
                while (NFA_OK(attr, attrlen)) {
                        unsigned flavor = attr->nfa_type;
                        if (flavor) {
-                               if (flavor > subsys->attr_count)
+                               if (flavor > attr_count)
                                        return -EINVAL;
                                cda[flavor - 1] = attr;
                        }
        }
 
        {
-               struct nfattr *cda[ss->attr_count];
+               u_int16_t attr_count = 
+                       ss->cb[NFNL_MSG_TYPE(nlh->nlmsg_type)].attr_count;
+               struct nfattr *cda[attr_count];
 
-               memset(cda, 0, ss->attr_count*sizeof(struct nfattr *));
+               memset(cda, 0, sizeof(struct nfattr *) * attr_count);
                
                err = nfnetlink_check_attributes(ss, nlh, cda);
                if (err < 0)
 
 
 static struct nfnl_callback nfulnl_cb[NFULNL_MSG_MAX] = {
        [NFULNL_MSG_PACKET]     = { .call = nfulnl_recv_unsupp,
-                                   .cap_required = CAP_NET_ADMIN },
+                                   .attr_count = NFULA_MAX,
+                                   .cap_required = CAP_NET_ADMIN, },
        [NFULNL_MSG_CONFIG]     = { .call = nfulnl_recv_config,
+                                   .attr_count = NFULA_CFG_MAX,
                                    .cap_required = CAP_NET_ADMIN },
 };
 
        .name           = "log",
        .subsys_id      = NFNL_SUBSYS_ULOG,
        .cb_count       = NFULNL_MSG_MAX,
-       .attr_count     = NFULA_MAX,
        .cb             = nfulnl_cb,
 };
 
 
 
 static struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = {
        [NFQNL_MSG_PACKET]      = { .call = nfqnl_recv_unsupp,
+                                   .attr_count = NFQA_MAX,
                                    .cap_required = CAP_NET_ADMIN },
        [NFQNL_MSG_VERDICT]     = { .call = nfqnl_recv_verdict,
+                                   .attr_count = NFQA_MAX,
                                    .cap_required = CAP_NET_ADMIN },
        [NFQNL_MSG_CONFIG]      = { .call = nfqnl_recv_config,
+                                   .attr_count = NFQA_CFG_MAX,
                                    .cap_required = CAP_NET_ADMIN },
 };
 
        .name           = "nf_queue",
        .subsys_id      = NFNL_SUBSYS_QUEUE,
        .cb_count       = NFQNL_MSG_MAX,
-       .attr_count     = NFQA_MAX,
        .cb             = nfqnl_cb,
 };