A new netlink API for tipc that can disable or enable a tipc bearer.
The new API is separated from the old API because of a bug in the
user space client (tipc-config). The problem is that older versions
of tipc-config has a very low receive limit and adding commands to
the legacy genl_opts struct causes the ctrl_getfamily() response
message to grow, subsequently breaking the tool.
The new API utilizes netlink policies for input validation. Where the
top-level netlink attributes are tipc-logical entities, like bearer.
The top level entities then contain nested attributes. In this case
a name, nested link properties and a domain.
Netlink commands implemented in this patch:
TIPC_NL_BEARER_ENABLE
TIPC_NL_BEARER_DISABLE
Netlink logical layout of bearer enable message:
-> bearer
    -> name
    [ -> domain ]
    [
    -> properties
        -> priority
    ]
Netlink logical layout of bearer disable message:
-> bearer
    -> name
Signed-off-by: Richard Alpe <richard.alpe@ericsson.com>
Reviewed-by: Erik Hugne <erik.hugne@ericsson.com>
Reviewed-by: Jon Maloy <jon.maloy@ericsson.com>
Acked-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
--- /dev/null
+/*
+ * Copyright (c) 2014, Ericsson AB
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LINUX_TIPC_NETLINK_H_
+#define _LINUX_TIPC_NETLINK_H_
+
+#define TIPC_GENL_V2_NAME      "TIPCv2"
+#define TIPC_GENL_V2_VERSION   0x1
+
+/* Netlink commands */
+enum {
+       TIPC_NL_UNSPEC,
+       TIPC_NL_LEGACY,
+       TIPC_NL_BEARER_DISABLE,
+       TIPC_NL_BEARER_ENABLE,
+
+       __TIPC_NL_CMD_MAX,
+       TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1
+};
+
+/* Top level netlink attributes */
+enum {
+       TIPC_NLA_UNSPEC,
+       TIPC_NLA_BEARER,                /* nest */
+
+       __TIPC_NLA_MAX,
+       TIPC_NLA_MAX = __TIPC_NLA_MAX - 1
+};
+
+/* Bearer info */
+enum {
+       TIPC_NLA_BEARER_UNSPEC,
+       TIPC_NLA_BEARER_NAME,           /* string */
+       TIPC_NLA_BEARER_PROP,           /* nest */
+       TIPC_NLA_BEARER_DOMAIN,         /* u32 */
+
+       __TIPC_NLA_BEARER_MAX,
+       TIPC_NLA_BEARER_MAX = __TIPC_NLA_BEARER_MAX - 1
+};
+
+/* Nest, link propreties. Valid for link, media and bearer */
+enum {
+       TIPC_NLA_PROP_UNSPEC,
+
+       TIPC_NLA_PROP_PRIO,             /* u32 */
+       TIPC_NLA_PROP_TOL,              /* u32 */
+       TIPC_NLA_PROP_WIN,              /* u32 */
+
+       __TIPC_NLA_PROP_MAX,
+       TIPC_NLA_PROP_MAX = __TIPC_NLA_PROP_MAX - 1
+};
+
+#endif
 
 /*
  * net/tipc/bearer.c: TIPC bearer code
  *
- * Copyright (c) 1996-2006, 2013, Ericsson AB
+ * Copyright (c) 1996-2006, 2013-2014, Ericsson AB
  * Copyright (c) 2004-2006, 2010-2013, Wind River Systems
  * All rights reserved.
  *
 #include "core.h"
 #include "config.h"
 #include "bearer.h"
+#include "link.h"
 #include "discover.h"
 
 #define MAX_ADDR_STR 60
        NULL
 };
 
+static const struct nla_policy
+tipc_nl_bearer_policy[TIPC_NLA_BEARER_MAX + 1] = {
+       [TIPC_NLA_BEARER_UNSPEC]                = { .type = NLA_UNSPEC },
+       [TIPC_NLA_BEARER_NAME] = {
+               .type = NLA_STRING,
+               .len = TIPC_MAX_BEARER_NAME
+       },
+       [TIPC_NLA_BEARER_PROP]                  = { .type = NLA_NESTED },
+       [TIPC_NLA_BEARER_DOMAIN]                = { .type = NLA_U32 }
+};
+
 struct tipc_bearer __rcu *bearer_list[MAX_BEARERS + 1];
 
 static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down);
                }
        }
 }
+
+int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
+{
+       int err;
+       char *name;
+       struct tipc_bearer *bearer;
+       struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
+
+       if (!info->attrs[TIPC_NLA_BEARER])
+               return -EINVAL;
+
+       err = nla_parse_nested(attrs, TIPC_NLA_BEARER_MAX,
+                              info->attrs[TIPC_NLA_BEARER],
+                              tipc_nl_bearer_policy);
+       if (err)
+               return err;
+
+       if (!attrs[TIPC_NLA_BEARER_NAME])
+               return -EINVAL;
+
+       name = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
+
+       rtnl_lock();
+       bearer = tipc_bearer_find(name);
+       if (!bearer) {
+               rtnl_unlock();
+               return -EINVAL;
+       }
+
+       bearer_disable(bearer, false);
+       rtnl_unlock();
+
+       return 0;
+}
+
+int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
+{
+       int err;
+       char *bearer;
+       struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
+       u32 domain;
+       u32 prio;
+
+       prio = TIPC_MEDIA_LINK_PRI;
+       domain = tipc_own_addr & TIPC_CLUSTER_MASK;
+
+       if (!info->attrs[TIPC_NLA_BEARER])
+               return -EINVAL;
+
+       err = nla_parse_nested(attrs, TIPC_NLA_BEARER_MAX,
+                              info->attrs[TIPC_NLA_BEARER],
+                              tipc_nl_bearer_policy);
+       if (err)
+               return err;
+
+       if (!attrs[TIPC_NLA_BEARER_NAME])
+               return -EINVAL;
+
+       bearer = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
+
+       if (attrs[TIPC_NLA_BEARER_DOMAIN])
+               domain = nla_get_u32(attrs[TIPC_NLA_BEARER_DOMAIN]);
+
+       if (attrs[TIPC_NLA_BEARER_PROP]) {
+               struct nlattr *props[TIPC_NLA_PROP_MAX + 1];
+
+               err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_BEARER_PROP],
+                                             props);
+               if (err)
+                       return err;
+
+               if (props[TIPC_NLA_PROP_PRIO])
+                       prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]);
+       }
+
+       rtnl_lock();
+       err = tipc_enable_bearer(bearer, domain, prio);
+       if (err) {
+               rtnl_unlock();
+               return err;
+       }
+       rtnl_unlock();
+
+       return 0;
+}
 
 /*
  * net/tipc/bearer.h: Include file for TIPC bearer code
  *
- * Copyright (c) 1996-2006, 2013, Ericsson AB
+ * Copyright (c) 1996-2006, 2013-2014, Ericsson AB
  * Copyright (c) 2005, 2010-2011, Wind River Systems
  * All rights reserved.
  *
 #define _TIPC_BEARER_H
 
 #include "bcast.h"
+#include "netlink.h"
+#include <net/genetlink.h>
 
 #define MAX_BEARERS    2
 #define MAX_MEDIA      2
 extern struct tipc_media ib_media_info;
 #endif
 
+int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info);
+int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info);
+
 int tipc_media_set_priority(const char *name, u32 new_value);
 int tipc_media_set_window(const char *name, u32 new_value);
 void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a);
 
 
 #include <linux/tipc.h>
 #include <linux/tipc_config.h>
+#include <linux/tipc_netlink.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 
 #include "name_distr.h"
 #include "discover.h"
 #include "config.h"
+#include "netlink.h"
 
 #include <linux/pkt_sched.h>
 
 static const char *link_rst_msg = "Resetting link ";
 static const char *link_unk_evt = "Unknown link event ";
 
+/* Properties valid for media, bearar and link */
+static const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = {
+       [TIPC_NLA_PROP_UNSPEC]          = { .type = NLA_UNSPEC },
+       [TIPC_NLA_PROP_PRIO]            = { .type = NLA_U32 },
+       [TIPC_NLA_PROP_TOL]             = { .type = NLA_U32 },
+       [TIPC_NLA_PROP_WIN]             = { .type = NLA_U32 }
+};
+
 /*
  * Out-of-range value for link session numbers
  */
        else
                pr_cont("\n");
 }
+
+/* Parse and validate nested (link) properties valid for media, bearer and link
+ */
+int tipc_nl_parse_link_prop(struct nlattr *prop, struct nlattr *props[])
+{
+       int err;
+
+       err = nla_parse_nested(props, TIPC_NLA_PROP_MAX, prop,
+                              tipc_nl_prop_policy);
+       if (err)
+               return err;
+
+       if (props[TIPC_NLA_PROP_PRIO]) {
+               u32 prio;
+
+               prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]);
+               if (prio > TIPC_MAX_LINK_PRI)
+                       return -EINVAL;
+       }
+
+       if (props[TIPC_NLA_PROP_TOL]) {
+               u32 tol;
+
+               tol = nla_get_u32(props[TIPC_NLA_PROP_TOL]);
+               if ((tol < TIPC_MIN_LINK_TOL) || (tol > TIPC_MAX_LINK_TOL))
+                       return -EINVAL;
+       }
+
+       if (props[TIPC_NLA_PROP_WIN]) {
+               u32 win;
+
+               win = nla_get_u32(props[TIPC_NLA_PROP_WIN]);
+               if ((win < TIPC_MIN_LINK_WIN) || (win > TIPC_MAX_LINK_WIN))
+                       return -EINVAL;
+       }
+
+       return 0;
+}
 
 #ifndef _TIPC_LINK_H
 #define _TIPC_LINK_H
 
+#include <net/genetlink.h>
 #include "msg.h"
 #include "node.h"
 
 void tipc_link_retransmit(struct tipc_link *l_ptr,
                          struct sk_buff *start, u32 retransmits);
 
+int tipc_nl_parse_link_prop(struct nlattr *prop, struct nlattr *props[]);
+
 /*
  * Link sequence number manipulation routines (uses modulo 2**16 arithmetic)
  */
 
 /*
  * net/tipc/netlink.c: TIPC configuration handling
  *
- * Copyright (c) 2005-2006, Ericsson AB
+ * Copyright (c) 2005-2006, 2014, Ericsson AB
  * Copyright (c) 2005-2007, Wind River Systems
  * All rights reserved.
  *
 
 #include "core.h"
 #include "config.h"
+#include "bearer.h"
 #include <net/genetlink.h>
 
 static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
        return 0;
 }
 
+static const struct nla_policy tipc_nl_policy[TIPC_NLA_MAX + 1] = {
+       [TIPC_NLA_UNSPEC]       = { .type = NLA_UNSPEC, },
+       [TIPC_NLA_BEARER]       = { .type = NLA_NESTED, },
+};
+
+/* Legacy ASCII API */
 static struct genl_family tipc_genl_family = {
        .id             = GENL_ID_GENERATE,
        .name           = TIPC_GENL_NAME,
        .maxattr        = 0,
 };
 
+/* Legacy ASCII API */
 static struct genl_ops tipc_genl_ops[] = {
        {
                .cmd            = TIPC_GENL_CMD,
        },
 };
 
+/* Users of the legacy API (tipc-config) can't handle that we add operations,
+ * so we have a separate genl handling for the new API.
+ */
+struct genl_family tipc_genl_v2_family = {
+       .id             = GENL_ID_GENERATE,
+       .name           = TIPC_GENL_V2_NAME,
+       .version        = TIPC_GENL_V2_VERSION,
+       .hdrsize        = 0,
+       .maxattr        = TIPC_NLA_MAX,
+};
+
+static const struct genl_ops tipc_genl_v2_ops[] = {
+       {
+               .cmd    = TIPC_NL_BEARER_DISABLE,
+               .doit   = tipc_nl_bearer_disable,
+               .policy = tipc_nl_policy,
+       },
+       {
+               .cmd    = TIPC_NL_BEARER_ENABLE,
+               .doit   = tipc_nl_bearer_enable,
+               .policy = tipc_nl_policy,
+       }
+};
+
 int tipc_netlink_start(void)
 {
        int res;
 
        res = genl_register_family_with_ops(&tipc_genl_family, tipc_genl_ops);
+       if (res) {
+               pr_err("Failed to register legacy interface\n");
+               return res;
+       }
+
+       res = genl_register_family_with_ops(&tipc_genl_v2_family,
+                                           tipc_genl_v2_ops);
        if (res) {
                pr_err("Failed to register netlink interface\n");
                return res;
 void tipc_netlink_stop(void)
 {
        genl_unregister_family(&tipc_genl_family);
+       genl_unregister_family(&tipc_genl_v2_family);
 }
 
--- /dev/null
+/*
+ * net/tipc/netlink.h: Include file for TIPC netlink code
+ *
+ * Copyright (c) 2014, Ericsson AB
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_NETLINK_H
+#define _TIPC_NETLINK_H
+
+extern struct genl_family tipc_genl_v2_family;
+
+#endif