goto errout;
}
+ if (ops->dumpit)
+ ops->flags |= GENL_CMD_CAP_DUMP;
+ if (ops->doit)
+ ops->flags |= GENL_CMD_CAP_DO;
+ if (ops->policy)
+ ops->flags |= GENL_CMD_CAP_HASPOL;
+
genl_lock();
list_add_tail(&ops->ops_list, &family->ops_list);
genl_unlock();
return -ENOENT;
}
-static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
- int *errp)
+static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct genl_ops *ops;
struct genl_family *family;
struct genl_info info;
struct genlmsghdr *hdr = nlmsg_data(nlh);
- int hdrlen, err = -EINVAL;
-
- if (!(nlh->nlmsg_flags & NLM_F_REQUEST))
- goto ignore;
-
- if (nlh->nlmsg_type < NLMSG_MIN_TYPE)
- goto ignore;
+ int hdrlen, err;
- family = genl_family_find_byid(nlh->nlmsg_type);
- if (family == NULL) {
- err = -ENOENT;
- goto errout;
- }
+ family = genl_family_find_byid(nlh->nlmsg_type);
+ if (family == NULL)
+ return -ENOENT;
hdrlen = GENL_HDRLEN + family->hdrsize;
if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
- goto errout;
+ return -EINVAL;
ops = genl_get_cmd(hdr->cmd, family);
- if (ops == NULL) {
- err = -EOPNOTSUPP;
- goto errout;
- }
+ if (ops == NULL)
+ return -EOPNOTSUPP;
- if ((ops->flags & GENL_ADMIN_PERM) && security_netlink_recv(skb, CAP_NET_ADMIN)) {
- err = -EPERM;
- goto errout;
- }
+ if ((ops->flags & GENL_ADMIN_PERM) &&
+ security_netlink_recv(skb, CAP_NET_ADMIN))
+ return -EPERM;
if (nlh->nlmsg_flags & NLM_F_DUMP) {
- if (ops->dumpit == NULL) {
- err = -EOPNOTSUPP;
- goto errout;
- }
+ if (ops->dumpit == NULL)
+ return -EOPNOTSUPP;
- *errp = err = netlink_dump_start(genl_sock, skb, nlh,
- ops->dumpit, NULL);
- if (err == 0)
- skb_pull(skb, min(NLMSG_ALIGN(nlh->nlmsg_len),
- skb->len));
- return -1;
+ return netlink_dump_start(genl_sock, skb, nlh,
+ ops->dumpit, ops->done);
}
- if (ops->doit == NULL) {
- err = -EOPNOTSUPP;
- goto errout;
- }
+ if (ops->doit == NULL)
+ return -EOPNOTSUPP;
if (family->attrbuf) {
err = nlmsg_parse(nlh, hdrlen, family->attrbuf, family->maxattr,
ops->policy);
if (err < 0)
- goto errout;
+ return err;
}
info.snd_seq = nlh->nlmsg_seq;
info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN;
info.attrs = family->attrbuf;
- *errp = err = ops->doit(skb, &info);
- return err;
-
-ignore:
- return 0;
-
-errout:
- *errp = err;
- return -1;
+ return ops->doit(skb, &info);
}
static void genl_rcv(struct sock *sk, int len)
* Controller
**************************************************************************/
+static struct genl_family genl_ctrl = {
+ .id = GENL_ID_CTRL,
+ .name = "nlctrl",
+ .version = 0x2,
+ .maxattr = CTRL_ATTR_MAX,
+};
+
static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq,
u32 flags, struct sk_buff *skb, u8 cmd)
{
void *hdr;
- hdr = genlmsg_put(skb, pid, seq, GENL_ID_CTRL, 0, flags, cmd,
- family->version);
+ hdr = genlmsg_put(skb, pid, seq, &genl_ctrl, flags, cmd);
if (hdr == NULL)
return -1;
NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, family->name);
NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, family->id);
+ NLA_PUT_U32(skb, CTRL_ATTR_VERSION, family->version);
+ NLA_PUT_U32(skb, CTRL_ATTR_HDRSIZE, family->hdrsize);
+ NLA_PUT_U32(skb, CTRL_ATTR_MAXATTR, family->maxattr);
+
+ if (!list_empty(&family->ops_list)) {
+ struct nlattr *nla_ops;
+ struct genl_ops *ops;
+ int idx = 1;
+
+ nla_ops = nla_nest_start(skb, CTRL_ATTR_OPS);
+ if (nla_ops == NULL)
+ goto nla_put_failure;
+
+ list_for_each_entry(ops, &family->ops_list, ops_list) {
+ struct nlattr *nest;
+
+ nest = nla_nest_start(skb, idx++);
+ if (nest == NULL)
+ goto nla_put_failure;
+
+ NLA_PUT_U32(skb, CTRL_ATTR_OP_ID, ops->cmd);
+ NLA_PUT_U32(skb, CTRL_ATTR_OP_FLAGS, ops->flags);
+
+ nla_nest_end(skb, nest);
+ }
+
+ nla_nest_end(skb, nla_ops);
+ }
return genlmsg_end(skb, hdr);
int chains_to_skip = cb->args[0];
int fams_to_skip = cb->args[1];
+ if (chains_to_skip != 0)
+ genl_lock();
+
for (i = 0; i < GENL_FAM_TAB_SIZE; i++) {
if (i < chains_to_skip)
continue;
}
errout:
+ if (chains_to_skip != 0)
+ genl_unlock();
+
cb->args[0] = i;
cb->args[1] = n;
struct sk_buff *skb;
int err;
- skb = nlmsg_new(NLMSG_GOODSIZE);
+ skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (skb == NULL)
return ERR_PTR(-ENOBUFS);
static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] __read_mostly = {
[CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 },
- [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING },
+ [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING,
+ .len = GENL_NAMSIZ - 1 },
};
static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
}
if (info->attrs[CTRL_ATTR_FAMILY_NAME]) {
- char name[GENL_NAMSIZ];
-
- if (nla_strlcpy(name, info->attrs[CTRL_ATTR_FAMILY_NAME],
- GENL_NAMSIZ) >= GENL_NAMSIZ)
- goto errout;
+ char *name;
+ name = nla_data(info->attrs[CTRL_ATTR_FAMILY_NAME]);
res = genl_family_find_byname(name);
}
goto errout;
}
- err = genlmsg_unicast(msg, info->snd_pid);
+ err = genlmsg_reply(msg, info);
errout:
return err;
}
if (IS_ERR(msg))
return PTR_ERR(msg);
- genlmsg_multicast(msg, 0, GENL_ID_CTRL);
+ genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL);
break;
}
.policy = ctrl_policy,
};
-static struct genl_family genl_ctrl = {
- .id = GENL_ID_CTRL,
- .name = "nlctrl",
- .version = 0x1,
- .maxattr = CTRL_ATTR_MAX,
-};
-
static int __init genl_init(void)
{
int i, err;
netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV);
genl_sock = netlink_kernel_create(NETLINK_GENERIC, GENL_MAX_ID,
- genl_rcv, THIS_MODULE);
+ genl_rcv, NULL, THIS_MODULE);
if (genl_sock == NULL)
panic("GENL: Cannot initialize generic netlink\n");