]> err.no Git - linux-2.6/blobdiff - net/netlink/genetlink.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6] / net / netlink / genetlink.c
index a298f77cc3e38dc2d4d7997d1ae977622ec6c746..6e31234a41966e0df32becfe61613036ac6fd2bd 100644 (file)
@@ -143,6 +143,13 @@ int genl_register_ops(struct genl_family *family, struct genl_ops *ops)
                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();
@@ -288,66 +295,46 @@ int genl_unregister_family(struct genl_family *family)
        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;
@@ -357,15 +344,7 @@ static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
        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)
@@ -384,18 +363,52 @@ 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);
 
@@ -411,6 +424,9 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
        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;
@@ -428,6 +444,9 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
        }
 
 errout:
+       if (chains_to_skip != 0)
+               genl_unlock();
+
        cb->args[0] = i;
        cb->args[1] = n;
 
@@ -440,7 +459,7 @@ static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid,
        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);
 
@@ -455,7 +474,8 @@ static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid,
 
 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)
@@ -470,12 +490,9 @@ 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);
        }
 
@@ -491,7 +508,7 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
                goto errout;
        }
 
-       err = genlmsg_unicast(msg, info->snd_pid);
+       err = genlmsg_reply(msg, info);
 errout:
        return err;
 }
@@ -510,7 +527,7 @@ static int genl_ctrl_event(int event, void *data)
                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;
        }
 
@@ -524,13 +541,6 @@ static struct genl_ops genl_ctrl_ops = {
        .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;
@@ -548,7 +558,7 @@ static int __init genl_init(void)
 
        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");