TIPC_NLA_NET_UNSPEC,
        TIPC_NLA_NET_ID,                /* u32 */
        TIPC_NLA_NET_ADDR,              /* u32 */
+       TIPC_NLA_NET_NODEID,            /* u64 */
+       TIPC_NLA_NET_NODEID_W1,         /* u64 */
 
        __TIPC_NLA_NET_MAX,
        TIPC_NLA_NET_MAX = __TIPC_NLA_NET_MAX - 1
 
 /*
  * net/tipc/addr.c: TIPC address utility routines
  *
- * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2000-2006, 2018, Ericsson AB
  * Copyright (c) 2004-2005, 2010-2011, Wind River Systems
  * All rights reserved.
  *
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <linux/kernel.h>
 #include "addr.h"
 #include "core.h"
 
-/**
- * in_own_node - test for node inclusion; <0.0.0> always matches
- */
-int in_own_node(struct net *net, u32 addr)
-{
-       return addr == tipc_own_addr(net) || !addr;
-}
-
 bool tipc_in_scope(bool legacy_format, u32 domain, u32 addr)
 {
        if (!domain || (domain == addr))
        return false;
 }
 
-char *tipc_addr_string_fill(char *string, u32 addr)
+void tipc_set_node_id(struct net *net, u8 *id)
+{
+       struct tipc_net *tn = tipc_net(net);
+       u32 *tmp = (u32 *)id;
+
+       memcpy(tn->node_id, id, NODE_ID_LEN);
+       tipc_nodeid2string(tn->node_id_string, id);
+       tn->node_addr = tmp[0] ^ tmp[1] ^ tmp[2] ^ tmp[3];
+       pr_info("Own node identity %s, cluster identity %u\n",
+               tipc_own_id_string(net), tn->net_id);
+}
+
+void tipc_set_node_addr(struct net *net, u32 addr)
 {
-       snprintf(string, 16, "<%u.%u.%u>",
-                tipc_zone(addr), tipc_cluster(addr), tipc_node(addr));
-       return string;
+       struct tipc_net *tn = tipc_net(net);
+       u8 node_id[NODE_ID_LEN] = {0,};
+
+       tn->node_addr = addr;
+       if (!tipc_own_id(net)) {
+               sprintf(node_id, "%x", addr);
+               tipc_set_node_id(net, node_id);
+       }
+       pr_info("32-bit node address hash set to %x\n", addr);
+}
+
+char *tipc_nodeid2string(char *str, u8 *id)
+{
+       int i;
+       u8 c;
+
+       /* Already a string ? */
+       for (i = 0; i < NODE_ID_LEN; i++) {
+               c = id[i];
+               if (c >= '0' && c <= '9')
+                       continue;
+               if (c >= 'A' && c <= 'Z')
+                       continue;
+               if (c >= 'a' && c <= 'z')
+                       continue;
+               if (c == '.')
+                       continue;
+               if (c == ':')
+                       continue;
+               if (c == '_')
+                       continue;
+               if (c == '-')
+                       continue;
+               if (c == '@')
+                       continue;
+               if (c != 0)
+                       break;
+       }
+       if (i == NODE_ID_LEN) {
+               memcpy(str, id, NODE_ID_LEN);
+               str[NODE_ID_LEN] = 0;
+               return str;
+       }
+
+       /* Translate to hex string */
+       for (i = 0; i < NODE_ID_LEN; i++)
+               sprintf(&str[2 * i], "%02x", id[i]);
+
+       /* Strip off trailing zeroes */
+       for (i = NODE_ID_STR_LEN - 2; str[i] == '0'; i--)
+               str[i] = 0;
+
+       return str;
 }
 
 /*
  * net/tipc/addr.h: Include file for TIPC address utility routines
  *
- * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2000-2006, 2018, Ericsson AB
  * Copyright (c) 2004-2005, Wind River Systems
  * All rights reserved.
  *
 #include "core.h"
 
 static inline u32 tipc_own_addr(struct net *net)
+{
+       return tipc_net(net)->node_addr;
+}
+
+static inline u8 *tipc_own_id(struct net *net)
 {
        struct tipc_net *tn = tipc_net(net);
 
-       return tn->own_addr;
+       if (!strlen(tn->node_id_string))
+               return NULL;
+       return tn->node_id;
+}
+
+static inline char *tipc_own_id_string(struct net *net)
+{
+       return tipc_net(net)->node_id_string;
 }
 
 static inline u32 tipc_cluster_mask(u32 addr)
        return sc != TIPC_NODE_SCOPE ? 0 : tipc_own_addr(net);
 }
 
-u32 tipc_own_addr(struct net *net);
-int in_own_node(struct net *net, u32 addr);
+static inline int in_own_node(struct net *net, u32 addr)
+{
+       return addr == tipc_own_addr(net) || !addr;
+}
+
 bool tipc_in_scope(bool legacy_format, u32 domain, u32 addr);
-char *tipc_addr_string_fill(char *string, u32 addr);
+void tipc_set_node_id(struct net *net, u8 *id);
+void tipc_set_node_addr(struct net *net, u32 addr);
+char *tipc_nodeid2string(char *str, u8 *id);
+u32 tipc_node_id2hash(u8 *id128);
 
 #endif
 
        int err;
 
        tn->net_id = 4711;
-       tn->own_addr = 0;
+       tn->node_addr = 0;
+       memset(tn->node_id, 0, sizeof(tn->node_id));
+       memset(tn->node_id_string, 0, sizeof(tn->node_id_string));
        tn->mon_threshold = TIPC_DEF_MON_THRESHOLD;
        get_random_bytes(&tn->random, sizeof(int));
        INIT_LIST_HEAD(&tn->node_list);
 
 #define NODE_HTABLE_SIZE       512
 #define MAX_BEARERS             3
 #define TIPC_DEF_MON_THRESHOLD  32
+#define NODE_ID_LEN             16
+#define NODE_ID_STR_LEN        (NODE_ID_LEN * 2 + 1)
 
 extern unsigned int tipc_net_id __read_mostly;
 extern int sysctl_tipc_rmem[3] __read_mostly;
 extern int sysctl_tipc_named_timeout __read_mostly;
 
 struct tipc_net {
-       u32 own_addr;
+       u8  node_id[NODE_ID_LEN];
+       u32 node_addr;
+       char node_id_string[NODE_ID_STR_LEN];
        int net_id;
        int random;
        bool legacy_addr_format;
 
 static void disc_dupl_alert(struct tipc_bearer *b, u32 node_addr,
                            struct tipc_media_addr *media_addr)
 {
-       char node_addr_str[16];
        char media_addr_str[64];
 
-       tipc_addr_string_fill(node_addr_str, node_addr);
        tipc_media_addr_printf(media_addr_str, sizeof(media_addr_str),
                               media_addr);
-       pr_warn("Duplicate %s using %s seen on <%s>\n", node_addr_str,
+       pr_warn("Duplicate %x using %s seen on <%s>\n", node_addr,
                media_addr_str, b->name);
 }
 
 
                      struct sk_buff_head *namedq,
                      struct tipc_link **link)
 {
+       char *self_str = tipc_own_id_string(net);
        struct tipc_link *l;
 
        l = kzalloc(sizeof(*l), GFP_ATOMIC);
        l->session = session;
 
        /* Note: peer i/f name is completed by reset/activate message */
-       sprintf(l->name, "%x:%s-%x:unknown", self, if_name, peer);
+       if (strlen(self_str) > 16)
+               sprintf(l->name, "%x:%s-%x:unknown", self, if_name, peer);
+       else
+               sprintf(l->name, "%s:%s-%x:unknown", self_str, if_name, peer);
        strcpy(l->if_name, if_name);
        l->addr = peer;
        l->peer_caps = peer_caps;
 
 {
        struct distr_queue_item *e, *tmp;
        struct tipc_net *tn = net_generic(net, tipc_net_id);
-       char addr[16];
        unsigned long now = get_jiffies_64();
 
        list_for_each_entry_safe(e, tmp, &tn->dist_queue, next) {
                        if (!tipc_update_nametbl(net, &e->i, e->node, e->dtype))
                                continue;
                } else {
-                       tipc_addr_string_fill(addr, e->node);
-                       pr_warn_ratelimited("Dropping name table update (%d) of {%u, %u, %u} from %s key=%u\n",
+                       pr_warn_ratelimited("Dropping name table update (%d) of {%u, %u, %u} from %x key=%u\n",
                                            e->dtype, ntohl(e->i.type),
                                            ntohl(e->i.lower),
                                            ntohl(e->i.upper),
-                                           addr, ntohl(e->i.key));
+                                           e->node, ntohl(e->i.key));
                }
                list_del(&e->next);
                kfree(e);
 
  *     - A local spin_lock protecting the queue of subscriber events.
 */
 
-int tipc_net_start(struct net *net, u32 addr)
+int tipc_net_init(struct net *net, u8 *node_id, u32 addr)
 {
-       struct tipc_net *tn = tipc_net(net);
-       char addr_string[16];
+       if (tipc_own_id(net)) {
+               pr_info("Cannot configure node identity twice\n");
+               return -1;
+       }
+       pr_info("Started in network mode\n");
 
-       tn->own_addr = addr;
+       if (node_id) {
+               tipc_set_node_id(net, node_id);
+               tipc_net_finalize(net, tipc_own_addr(net));
+       }
+       if (addr)
+               tipc_net_finalize(net, addr);
+       return 0;
+}
 
-       /* Ensure that the new address is visible before we reinit. */
+void tipc_net_finalize(struct net *net, u32 addr)
+{
+       tipc_set_node_addr(net, addr);
        smp_mb();
-
        tipc_named_reinit(net);
        tipc_sk_reinit(net);
-
        tipc_nametbl_publish(net, TIPC_CFG_SRV, addr, addr,
                             TIPC_CLUSTER_SCOPE, 0, addr);
-
-       pr_info("Started in network mode\n");
-       pr_info("Own node address %s, cluster identity %u\n",
-               tipc_addr_string_fill(addr_string, addr),
-               tn->net_id);
-       return 0;
 }
 
 void tipc_net_stop(struct net *net)
 static int __tipc_nl_add_net(struct net *net, struct tipc_nl_msg *msg)
 {
        struct tipc_net *tn = net_generic(net, tipc_net_id);
-       void *hdr;
+       u64 *w0 = (u64 *)&tn->node_id[0];
+       u64 *w1 = (u64 *)&tn->node_id[8];
        struct nlattr *attrs;
+       void *hdr;
 
        hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
                          NLM_F_MULTI, TIPC_NL_NET_GET);
 
        if (nla_put_u32(msg->skb, TIPC_NLA_NET_ID, tn->net_id))
                goto attr_msg_full;
-
+       if (nla_put_u64_64bit(msg->skb, TIPC_NLA_NET_NODEID, *w0, 0))
+               goto attr_msg_full;
+       if (nla_put_u64_64bit(msg->skb, TIPC_NLA_NET_NODEID_W1, *w1, 0))
+               goto attr_msg_full;
        nla_nest_end(msg->skb, attrs);
        genlmsg_end(msg->skb, hdr);
 
        err = nla_parse_nested(attrs, TIPC_NLA_NET_MAX,
                               info->attrs[TIPC_NLA_NET], tipc_nl_net_policy,
                               info->extack);
+
        if (err)
                return err;
 
                if (!addr)
                        return -EINVAL;
                tn->legacy_addr_format = true;
-               tipc_net_start(net, addr);
+               tipc_net_init(net, NULL, addr);
        }
 
+       if (attrs[TIPC_NLA_NET_NODEID]) {
+               u8 node_id[NODE_ID_LEN];
+               u64 *w0 = (u64 *)&node_id[0];
+               u64 *w1 = (u64 *)&node_id[8];
+
+               *w0 = nla_get_u64(attrs[TIPC_NLA_NET_NODEID]);
+               *w1 = nla_get_u64(attrs[TIPC_NLA_NET_NODEID_W1]);
+               tipc_net_init(net, node_id, 0);
+       }
        return 0;
 }
 
 
 
 extern const struct nla_policy tipc_nl_net_policy[];
 
-int tipc_net_start(struct net *net, u32 addr);
-
+void tipc_net_finalize(struct net *net, u32 addr);
 void tipc_net_stop(struct net *net);
-
 int tipc_nl_net_dump(struct sk_buff *skb, struct netlink_callback *cb);
 int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info);
 int __tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info);
 
 
 static void tipc_node_reset_links(struct tipc_node *n)
 {
-       char addr_string[16];
        int i;
 
-       pr_warn("Resetting all links to %s\n",
-               tipc_addr_string_fill(addr_string, n->addr));
+       pr_warn("Resetting all links to %x\n", n->addr);
 
        for (i = 0; i < MAX_BEARERS; i++) {
                tipc_node_link_down(n, i, false);
 static void node_lost_contact(struct tipc_node *n,
                              struct sk_buff_head *inputq)
 {
-       char addr_string[16];
        struct tipc_sock_conn *conn, *safe;
        struct tipc_link *l;
        struct list_head *conns = &n->conn_sks;
        struct sk_buff *skb;
        uint i;
 
-       pr_debug("Lost contact with %s\n",
-                tipc_addr_string_fill(addr_string, n->addr));
+       pr_debug("Lost contact with %x\n", n->addr);
 
        /* Clean up broadcast state */
        tipc_bcast_remove_peer(n->net, n->bc_entry.link);
 
        TIPC_BCAST_STATE_NACK = (1 << 2),
        TIPC_BLOCK_FLOWCTL    = (1 << 3),
        TIPC_BCAST_RCAST      = (1 << 4),
-       TIPC_NODE_ID32        = (1 << 5)
+       TIPC_NODE_ID128       = (1 << 5)
 };
 
 #define TIPC_NODE_CAPABILITIES (TIPC_BCAST_SYNCH | \
                                TIPC_BCAST_STATE_NACK | \
                                TIPC_BCAST_RCAST | \
                                TIPC_BLOCK_FLOWCTL | \
-                               TIPC_NODE_ID32)
+                               TIPC_NODE_ID128)
 #define INVALID_BEARER_ID -1
 
 void tipc_node_stop(struct net *net);