/* Process one complete nfnetlink message. */ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { struct nfnl_callback *nc; struct nfnetlink_subsystem *ss; int type, err; if (security_netlink_recv(skb, CAP_NET_ADMIN)) return -EPERM; /* All the messages must at least contain nfgenmsg */ if (nlh->nlmsg_len < NLMSG_SPACE(sizeof(struct nfgenmsg))) return 0; type = nlh->nlmsg_type; ss = nfnetlink_get_subsys(type); if (!ss) { #ifdef CONFIG_KMOD /* don't call nfnl_unlock, since it would reenter * with further packet processing */ __nfnl_unlock(); request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type)); nfnl_lock(); ss = nfnetlink_get_subsys(type); if (!ss) #endif return -EINVAL; } nc = nfnetlink_find_client(type, ss); if (!nc) return -EINVAL; { u_int16_t attr_count = ss->cb[NFNL_MSG_TYPE(nlh->nlmsg_type)].attr_count; struct nfattr *cda[attr_count]; memset(cda, 0, sizeof(struct nfattr *) * attr_count); err = nfnetlink_check_attributes(ss, nlh, cda); if (err < 0) return err; return nc->call(nfnl, skb, nlh, cda); } }
/* Process one complete nfnetlink message. */ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) { struct nfnl_callback *nc; struct nfnetlink_subsystem *ss; int type, err = 0; DEBUGP("entered; subsys=%u, msgtype=%u\n", NFNL_SUBSYS_ID(nlh->nlmsg_type), NFNL_MSG_TYPE(nlh->nlmsg_type)); if (security_netlink_recv(skb, CAP_NET_ADMIN)) { DEBUGP("missing CAP_NET_ADMIN\n"); *errp = -EPERM; return -1; } /* Only requests are handled by kernel now. */ if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) { DEBUGP("received non-request message\n"); return 0; } /* All the messages must at least contain nfgenmsg */ if (nlh->nlmsg_len < NLMSG_SPACE(sizeof(struct nfgenmsg))) { DEBUGP("received message was too short\n"); return 0; } type = nlh->nlmsg_type; ss = nfnetlink_get_subsys(type); if (!ss) { #ifdef CONFIG_KMOD /* don't call nfnl_shunlock, since it would reenter * with further packet processing */ up(&nfnl_sem); request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type)); nfnl_shlock(); ss = nfnetlink_get_subsys(type); if (!ss) #endif goto err_inval; } nc = nfnetlink_find_client(type, ss); if (!nc) { DEBUGP("unable to find client for type %d\n", type); goto err_inval; } { u_int16_t attr_count = ss->cb[NFNL_MSG_TYPE(nlh->nlmsg_type)].attr_count; struct nfattr *cda[attr_count]; memset(cda, 0, sizeof(struct nfattr *) * attr_count); err = nfnetlink_check_attributes(ss, nlh, cda); if (err < 0) goto err_inval; DEBUGP("calling handler\n"); err = nc->call(nfnl, skb, nlh, cda, errp); *errp = err; return err; } err_inval: DEBUGP("returning -EINVAL\n"); *errp = -EINVAL; return -1; }