diff options
Diffstat (limited to 'net/tipc/node.c')
| -rw-r--r-- | net/tipc/node.c | 96 | 
1 files changed, 66 insertions, 30 deletions
| diff --git a/net/tipc/node.c b/net/tipc/node.c index 4edcee3088da..d269ebe382e1 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -278,6 +278,14 @@ struct tipc_crypto *tipc_node_crypto_rx_by_list(struct list_head *pos)  {  	return container_of(pos, struct tipc_node, list)->crypto_rx;  } + +struct tipc_crypto *tipc_node_crypto_rx_by_addr(struct net *net, u32 addr) +{ +	struct tipc_node *n; + +	n = tipc_node_find(net, addr); +	return (n) ? n->crypto_rx : NULL; +}  #endif  static void tipc_node_free(struct rcu_head *rp) @@ -303,7 +311,7 @@ void tipc_node_put(struct tipc_node *node)  	kref_put(&node->kref, tipc_node_kref_release);  } -static void tipc_node_get(struct tipc_node *node) +void tipc_node_get(struct tipc_node *node)  {  	kref_get(&node->kref);  } @@ -584,6 +592,9 @@ static void tipc_node_calculate_timer(struct tipc_node *n, struct tipc_link *l)  static void tipc_node_delete_from_list(struct tipc_node *node)  { +#ifdef CONFIG_TIPC_CRYPTO +	tipc_crypto_key_flush(node->crypto_rx); +#endif  	list_del_rcu(&node->list);  	hlist_del_rcu(&node->hash);  	tipc_node_put(node); @@ -1485,7 +1496,7 @@ static void node_lost_contact(struct tipc_node *n,  	/* Clean up broadcast state */  	tipc_bcast_remove_peer(n->net, n->bc_entry.link); -	__skb_queue_purge(&n->bc_entry.namedq); +	skb_queue_purge(&n->bc_entry.namedq);  	/* Abort any ongoing link failover */  	for (i = 0; i < MAX_BEARERS; i++) { @@ -2868,15 +2879,27 @@ static int tipc_nl_retrieve_nodeid(struct nlattr **attrs, u8 **node_id)  	return 0;  } +static int tipc_nl_retrieve_rekeying(struct nlattr **attrs, u32 *intv) +{ +	struct nlattr *attr = attrs[TIPC_NLA_NODE_REKEYING]; + +	if (!attr) +		return -ENODATA; + +	*intv = nla_get_u32(attr); +	return 0; +} +  static int __tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info)  {  	struct nlattr *attrs[TIPC_NLA_NODE_MAX + 1];  	struct net *net = sock_net(skb->sk); -	struct tipc_net *tn = tipc_net(net); +	struct tipc_crypto *tx = tipc_net(net)->crypto_tx, *c = tx;  	struct tipc_node *n = NULL;  	struct tipc_aead_key *ukey; -	struct tipc_crypto *c; -	u8 *id, *own_id; +	bool rekeying = true, master_key = false; +	u8 *id, *own_id, mode; +	u32 intv = 0;  	int rc = 0;  	if (!info->attrs[TIPC_NLA_NODE]) @@ -2886,52 +2909,66 @@ static int __tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info)  			      info->attrs[TIPC_NLA_NODE],  			      tipc_nl_node_policy, info->extack);  	if (rc) -		goto exit; +		return rc;  	own_id = tipc_own_id(net);  	if (!own_id) { -		rc = -EPERM; -		goto exit; +		GENL_SET_ERR_MSG(info, "not found own node identity (set id?)"); +		return -EPERM;  	} +	rc = tipc_nl_retrieve_rekeying(attrs, &intv); +	if (rc == -ENODATA) +		rekeying = false; +  	rc = tipc_nl_retrieve_key(attrs, &ukey); -	if (rc) -		goto exit; +	if (rc == -ENODATA && rekeying) +		goto rekeying; +	else if (rc) +		return rc; -	rc = tipc_aead_key_validate(ukey); +	rc = tipc_aead_key_validate(ukey, info);  	if (rc) -		goto exit; +		return rc;  	rc = tipc_nl_retrieve_nodeid(attrs, &id);  	switch (rc) {  	case -ENODATA: -		/* Cluster key mode */ -		rc = tipc_crypto_key_init(tn->crypto_tx, ukey, CLUSTER_KEY); +		mode = CLUSTER_KEY; +		master_key = !!(attrs[TIPC_NLA_NODE_KEY_MASTER]);  		break;  	case 0: -		/* Per-node key mode */ -		if (!memcmp(id, own_id, NODE_ID_LEN)) { -			c = tn->crypto_tx; -		} else { +		mode = PER_NODE_KEY; +		if (memcmp(id, own_id, NODE_ID_LEN)) {  			n = tipc_node_find_by_id(net, id) ?:  				tipc_node_create(net, 0, id, 0xffffu, 0, true); -			if (unlikely(!n)) { -				rc = -ENOMEM; -				break; -			} +			if (unlikely(!n)) +				return -ENOMEM;  			c = n->crypto_rx;  		} - -		rc = tipc_crypto_key_init(c, ukey, PER_NODE_KEY); -		if (n) -			tipc_node_put(n);  		break;  	default: -		break; +		return rc;  	} -exit: -	return (rc < 0) ? rc : 0; +	/* Initiate the TX/RX key */ +	rc = tipc_crypto_key_init(c, ukey, mode, master_key); +	if (n) +		tipc_node_put(n); + +	if (unlikely(rc < 0)) { +		GENL_SET_ERR_MSG(info, "unable to initiate or attach new key"); +		return rc; +	} else if (c == tx) { +		/* Distribute TX key but not master one */ +		if (!master_key && tipc_crypto_key_distr(tx, rc, NULL)) +			GENL_SET_ERR_MSG(info, "failed to replicate new key"); +rekeying: +		/* Schedule TX rekeying if needed */ +		tipc_crypto_rekeying_sched(tx, rekeying, intv); +	} + +	return 0;  }  int tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info) @@ -2958,7 +2995,6 @@ static int __tipc_nl_node_flush_key(struct sk_buff *skb,  		tipc_crypto_key_flush(n->crypto_rx);  	rcu_read_unlock(); -	pr_info("All keys are flushed!\n");  	return 0;  } |