162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * net/tipc/crypto.c: TIPC crypto for key handling & packet en/decryption 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2019, Ericsson AB 662306a36Sopenharmony_ci * All rights reserved. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 962306a36Sopenharmony_ci * modification, are permitted provided that the following conditions are met: 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 1262306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 1362306a36Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 1462306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 1562306a36Sopenharmony_ci * documentation and/or other materials provided with the distribution. 1662306a36Sopenharmony_ci * 3. Neither the names of the copyright holders nor the names of its 1762306a36Sopenharmony_ci * contributors may be used to endorse or promote products derived from 1862306a36Sopenharmony_ci * this software without specific prior written permission. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the 2162306a36Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free 2262306a36Sopenharmony_ci * Software Foundation. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2562306a36Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2662306a36Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2762306a36Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 2862306a36Sopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2962306a36Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3062306a36Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3162306a36Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3262306a36Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3362306a36Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3462306a36Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGE. 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include <crypto/aead.h> 3862306a36Sopenharmony_ci#include <crypto/aes.h> 3962306a36Sopenharmony_ci#include <crypto/rng.h> 4062306a36Sopenharmony_ci#include "crypto.h" 4162306a36Sopenharmony_ci#include "msg.h" 4262306a36Sopenharmony_ci#include "bcast.h" 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define TIPC_TX_GRACE_PERIOD msecs_to_jiffies(5000) /* 5s */ 4562306a36Sopenharmony_ci#define TIPC_TX_LASTING_TIME msecs_to_jiffies(10000) /* 10s */ 4662306a36Sopenharmony_ci#define TIPC_RX_ACTIVE_LIM msecs_to_jiffies(3000) /* 3s */ 4762306a36Sopenharmony_ci#define TIPC_RX_PASSIVE_LIM msecs_to_jiffies(15000) /* 15s */ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define TIPC_MAX_TFMS_DEF 10 5062306a36Sopenharmony_ci#define TIPC_MAX_TFMS_LIM 1000 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define TIPC_REKEYING_INTV_DEF (60 * 24) /* default: 1 day */ 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* 5562306a36Sopenharmony_ci * TIPC Key ids 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_cienum { 5862306a36Sopenharmony_ci KEY_MASTER = 0, 5962306a36Sopenharmony_ci KEY_MIN = KEY_MASTER, 6062306a36Sopenharmony_ci KEY_1 = 1, 6162306a36Sopenharmony_ci KEY_2, 6262306a36Sopenharmony_ci KEY_3, 6362306a36Sopenharmony_ci KEY_MAX = KEY_3, 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/* 6762306a36Sopenharmony_ci * TIPC Crypto statistics 6862306a36Sopenharmony_ci */ 6962306a36Sopenharmony_cienum { 7062306a36Sopenharmony_ci STAT_OK, 7162306a36Sopenharmony_ci STAT_NOK, 7262306a36Sopenharmony_ci STAT_ASYNC, 7362306a36Sopenharmony_ci STAT_ASYNC_OK, 7462306a36Sopenharmony_ci STAT_ASYNC_NOK, 7562306a36Sopenharmony_ci STAT_BADKEYS, /* tx only */ 7662306a36Sopenharmony_ci STAT_BADMSGS = STAT_BADKEYS, /* rx only */ 7762306a36Sopenharmony_ci STAT_NOKEYS, 7862306a36Sopenharmony_ci STAT_SWITCHES, 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci MAX_STATS, 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* TIPC crypto statistics' header */ 8462306a36Sopenharmony_cistatic const char *hstats[MAX_STATS] = {"ok", "nok", "async", "async_ok", 8562306a36Sopenharmony_ci "async_nok", "badmsgs", "nokeys", 8662306a36Sopenharmony_ci "switches"}; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci/* Max TFMs number per key */ 8962306a36Sopenharmony_ciint sysctl_tipc_max_tfms __read_mostly = TIPC_MAX_TFMS_DEF; 9062306a36Sopenharmony_ci/* Key exchange switch, default: on */ 9162306a36Sopenharmony_ciint sysctl_tipc_key_exchange_enabled __read_mostly = 1; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/* 9462306a36Sopenharmony_ci * struct tipc_key - TIPC keys' status indicator 9562306a36Sopenharmony_ci * 9662306a36Sopenharmony_ci * 7 6 5 4 3 2 1 0 9762306a36Sopenharmony_ci * +-----+-----+-----+-----+-----+-----+-----+-----+ 9862306a36Sopenharmony_ci * key: | (reserved)|passive idx| active idx|pending idx| 9962306a36Sopenharmony_ci * +-----+-----+-----+-----+-----+-----+-----+-----+ 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_cistruct tipc_key { 10262306a36Sopenharmony_ci#define KEY_BITS (2) 10362306a36Sopenharmony_ci#define KEY_MASK ((1 << KEY_BITS) - 1) 10462306a36Sopenharmony_ci union { 10562306a36Sopenharmony_ci struct { 10662306a36Sopenharmony_ci#if defined(__LITTLE_ENDIAN_BITFIELD) 10762306a36Sopenharmony_ci u8 pending:2, 10862306a36Sopenharmony_ci active:2, 10962306a36Sopenharmony_ci passive:2, /* rx only */ 11062306a36Sopenharmony_ci reserved:2; 11162306a36Sopenharmony_ci#elif defined(__BIG_ENDIAN_BITFIELD) 11262306a36Sopenharmony_ci u8 reserved:2, 11362306a36Sopenharmony_ci passive:2, /* rx only */ 11462306a36Sopenharmony_ci active:2, 11562306a36Sopenharmony_ci pending:2; 11662306a36Sopenharmony_ci#else 11762306a36Sopenharmony_ci#error "Please fix <asm/byteorder.h>" 11862306a36Sopenharmony_ci#endif 11962306a36Sopenharmony_ci } __packed; 12062306a36Sopenharmony_ci u8 keys; 12162306a36Sopenharmony_ci }; 12262306a36Sopenharmony_ci}; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/** 12562306a36Sopenharmony_ci * struct tipc_tfm - TIPC TFM structure to form a list of TFMs 12662306a36Sopenharmony_ci * @tfm: cipher handle/key 12762306a36Sopenharmony_ci * @list: linked list of TFMs 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_cistruct tipc_tfm { 13062306a36Sopenharmony_ci struct crypto_aead *tfm; 13162306a36Sopenharmony_ci struct list_head list; 13262306a36Sopenharmony_ci}; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci/** 13562306a36Sopenharmony_ci * struct tipc_aead - TIPC AEAD key structure 13662306a36Sopenharmony_ci * @tfm_entry: per-cpu pointer to one entry in TFM list 13762306a36Sopenharmony_ci * @crypto: TIPC crypto owns this key 13862306a36Sopenharmony_ci * @cloned: reference to the source key in case cloning 13962306a36Sopenharmony_ci * @users: the number of the key users (TX/RX) 14062306a36Sopenharmony_ci * @salt: the key's SALT value 14162306a36Sopenharmony_ci * @authsize: authentication tag size (max = 16) 14262306a36Sopenharmony_ci * @mode: crypto mode is applied to the key 14362306a36Sopenharmony_ci * @hint: a hint for user key 14462306a36Sopenharmony_ci * @rcu: struct rcu_head 14562306a36Sopenharmony_ci * @key: the aead key 14662306a36Sopenharmony_ci * @gen: the key's generation 14762306a36Sopenharmony_ci * @seqno: the key seqno (cluster scope) 14862306a36Sopenharmony_ci * @refcnt: the key reference counter 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_cistruct tipc_aead { 15162306a36Sopenharmony_ci#define TIPC_AEAD_HINT_LEN (5) 15262306a36Sopenharmony_ci struct tipc_tfm * __percpu *tfm_entry; 15362306a36Sopenharmony_ci struct tipc_crypto *crypto; 15462306a36Sopenharmony_ci struct tipc_aead *cloned; 15562306a36Sopenharmony_ci atomic_t users; 15662306a36Sopenharmony_ci u32 salt; 15762306a36Sopenharmony_ci u8 authsize; 15862306a36Sopenharmony_ci u8 mode; 15962306a36Sopenharmony_ci char hint[2 * TIPC_AEAD_HINT_LEN + 1]; 16062306a36Sopenharmony_ci struct rcu_head rcu; 16162306a36Sopenharmony_ci struct tipc_aead_key *key; 16262306a36Sopenharmony_ci u16 gen; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci atomic64_t seqno ____cacheline_aligned; 16562306a36Sopenharmony_ci refcount_t refcnt ____cacheline_aligned; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci} ____cacheline_aligned; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/** 17062306a36Sopenharmony_ci * struct tipc_crypto_stats - TIPC Crypto statistics 17162306a36Sopenharmony_ci * @stat: array of crypto statistics 17262306a36Sopenharmony_ci */ 17362306a36Sopenharmony_cistruct tipc_crypto_stats { 17462306a36Sopenharmony_ci unsigned int stat[MAX_STATS]; 17562306a36Sopenharmony_ci}; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci/** 17862306a36Sopenharmony_ci * struct tipc_crypto - TIPC TX/RX crypto structure 17962306a36Sopenharmony_ci * @net: struct net 18062306a36Sopenharmony_ci * @node: TIPC node (RX) 18162306a36Sopenharmony_ci * @aead: array of pointers to AEAD keys for encryption/decryption 18262306a36Sopenharmony_ci * @peer_rx_active: replicated peer RX active key index 18362306a36Sopenharmony_ci * @key_gen: TX/RX key generation 18462306a36Sopenharmony_ci * @key: the key states 18562306a36Sopenharmony_ci * @skey_mode: session key's mode 18662306a36Sopenharmony_ci * @skey: received session key 18762306a36Sopenharmony_ci * @wq: common workqueue on TX crypto 18862306a36Sopenharmony_ci * @work: delayed work sched for TX/RX 18962306a36Sopenharmony_ci * @key_distr: key distributing state 19062306a36Sopenharmony_ci * @rekeying_intv: rekeying interval (in minutes) 19162306a36Sopenharmony_ci * @stats: the crypto statistics 19262306a36Sopenharmony_ci * @name: the crypto name 19362306a36Sopenharmony_ci * @sndnxt: the per-peer sndnxt (TX) 19462306a36Sopenharmony_ci * @timer1: general timer 1 (jiffies) 19562306a36Sopenharmony_ci * @timer2: general timer 2 (jiffies) 19662306a36Sopenharmony_ci * @working: the crypto is working or not 19762306a36Sopenharmony_ci * @key_master: flag indicates if master key exists 19862306a36Sopenharmony_ci * @legacy_user: flag indicates if a peer joins w/o master key (for bwd comp.) 19962306a36Sopenharmony_ci * @nokey: no key indication 20062306a36Sopenharmony_ci * @flags: combined flags field 20162306a36Sopenharmony_ci * @lock: tipc_key lock 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_cistruct tipc_crypto { 20462306a36Sopenharmony_ci struct net *net; 20562306a36Sopenharmony_ci struct tipc_node *node; 20662306a36Sopenharmony_ci struct tipc_aead __rcu *aead[KEY_MAX + 1]; 20762306a36Sopenharmony_ci atomic_t peer_rx_active; 20862306a36Sopenharmony_ci u16 key_gen; 20962306a36Sopenharmony_ci struct tipc_key key; 21062306a36Sopenharmony_ci u8 skey_mode; 21162306a36Sopenharmony_ci struct tipc_aead_key *skey; 21262306a36Sopenharmony_ci struct workqueue_struct *wq; 21362306a36Sopenharmony_ci struct delayed_work work; 21462306a36Sopenharmony_ci#define KEY_DISTR_SCHED 1 21562306a36Sopenharmony_ci#define KEY_DISTR_COMPL 2 21662306a36Sopenharmony_ci atomic_t key_distr; 21762306a36Sopenharmony_ci u32 rekeying_intv; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci struct tipc_crypto_stats __percpu *stats; 22062306a36Sopenharmony_ci char name[48]; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci atomic64_t sndnxt ____cacheline_aligned; 22362306a36Sopenharmony_ci unsigned long timer1; 22462306a36Sopenharmony_ci unsigned long timer2; 22562306a36Sopenharmony_ci union { 22662306a36Sopenharmony_ci struct { 22762306a36Sopenharmony_ci u8 working:1; 22862306a36Sopenharmony_ci u8 key_master:1; 22962306a36Sopenharmony_ci u8 legacy_user:1; 23062306a36Sopenharmony_ci u8 nokey: 1; 23162306a36Sopenharmony_ci }; 23262306a36Sopenharmony_ci u8 flags; 23362306a36Sopenharmony_ci }; 23462306a36Sopenharmony_ci spinlock_t lock; /* crypto lock */ 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci} ____cacheline_aligned; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci/* struct tipc_crypto_tx_ctx - TX context for callbacks */ 23962306a36Sopenharmony_cistruct tipc_crypto_tx_ctx { 24062306a36Sopenharmony_ci struct tipc_aead *aead; 24162306a36Sopenharmony_ci struct tipc_bearer *bearer; 24262306a36Sopenharmony_ci struct tipc_media_addr dst; 24362306a36Sopenharmony_ci}; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci/* struct tipc_crypto_rx_ctx - RX context for callbacks */ 24662306a36Sopenharmony_cistruct tipc_crypto_rx_ctx { 24762306a36Sopenharmony_ci struct tipc_aead *aead; 24862306a36Sopenharmony_ci struct tipc_bearer *bearer; 24962306a36Sopenharmony_ci}; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic struct tipc_aead *tipc_aead_get(struct tipc_aead __rcu *aead); 25262306a36Sopenharmony_cistatic inline void tipc_aead_put(struct tipc_aead *aead); 25362306a36Sopenharmony_cistatic void tipc_aead_free(struct rcu_head *rp); 25462306a36Sopenharmony_cistatic int tipc_aead_users(struct tipc_aead __rcu *aead); 25562306a36Sopenharmony_cistatic void tipc_aead_users_inc(struct tipc_aead __rcu *aead, int lim); 25662306a36Sopenharmony_cistatic void tipc_aead_users_dec(struct tipc_aead __rcu *aead, int lim); 25762306a36Sopenharmony_cistatic void tipc_aead_users_set(struct tipc_aead __rcu *aead, int val); 25862306a36Sopenharmony_cistatic struct crypto_aead *tipc_aead_tfm_next(struct tipc_aead *aead); 25962306a36Sopenharmony_cistatic int tipc_aead_init(struct tipc_aead **aead, struct tipc_aead_key *ukey, 26062306a36Sopenharmony_ci u8 mode); 26162306a36Sopenharmony_cistatic int tipc_aead_clone(struct tipc_aead **dst, struct tipc_aead *src); 26262306a36Sopenharmony_cistatic void *tipc_aead_mem_alloc(struct crypto_aead *tfm, 26362306a36Sopenharmony_ci unsigned int crypto_ctx_size, 26462306a36Sopenharmony_ci u8 **iv, struct aead_request **req, 26562306a36Sopenharmony_ci struct scatterlist **sg, int nsg); 26662306a36Sopenharmony_cistatic int tipc_aead_encrypt(struct tipc_aead *aead, struct sk_buff *skb, 26762306a36Sopenharmony_ci struct tipc_bearer *b, 26862306a36Sopenharmony_ci struct tipc_media_addr *dst, 26962306a36Sopenharmony_ci struct tipc_node *__dnode); 27062306a36Sopenharmony_cistatic void tipc_aead_encrypt_done(void *data, int err); 27162306a36Sopenharmony_cistatic int tipc_aead_decrypt(struct net *net, struct tipc_aead *aead, 27262306a36Sopenharmony_ci struct sk_buff *skb, struct tipc_bearer *b); 27362306a36Sopenharmony_cistatic void tipc_aead_decrypt_done(void *data, int err); 27462306a36Sopenharmony_cistatic inline int tipc_ehdr_size(struct tipc_ehdr *ehdr); 27562306a36Sopenharmony_cistatic int tipc_ehdr_build(struct net *net, struct tipc_aead *aead, 27662306a36Sopenharmony_ci u8 tx_key, struct sk_buff *skb, 27762306a36Sopenharmony_ci struct tipc_crypto *__rx); 27862306a36Sopenharmony_cistatic inline void tipc_crypto_key_set_state(struct tipc_crypto *c, 27962306a36Sopenharmony_ci u8 new_passive, 28062306a36Sopenharmony_ci u8 new_active, 28162306a36Sopenharmony_ci u8 new_pending); 28262306a36Sopenharmony_cistatic int tipc_crypto_key_attach(struct tipc_crypto *c, 28362306a36Sopenharmony_ci struct tipc_aead *aead, u8 pos, 28462306a36Sopenharmony_ci bool master_key); 28562306a36Sopenharmony_cistatic bool tipc_crypto_key_try_align(struct tipc_crypto *rx, u8 new_pending); 28662306a36Sopenharmony_cistatic struct tipc_aead *tipc_crypto_key_pick_tx(struct tipc_crypto *tx, 28762306a36Sopenharmony_ci struct tipc_crypto *rx, 28862306a36Sopenharmony_ci struct sk_buff *skb, 28962306a36Sopenharmony_ci u8 tx_key); 29062306a36Sopenharmony_cistatic void tipc_crypto_key_synch(struct tipc_crypto *rx, struct sk_buff *skb); 29162306a36Sopenharmony_cistatic int tipc_crypto_key_revoke(struct net *net, u8 tx_key); 29262306a36Sopenharmony_cistatic inline void tipc_crypto_clone_msg(struct net *net, struct sk_buff *_skb, 29362306a36Sopenharmony_ci struct tipc_bearer *b, 29462306a36Sopenharmony_ci struct tipc_media_addr *dst, 29562306a36Sopenharmony_ci struct tipc_node *__dnode, u8 type); 29662306a36Sopenharmony_cistatic void tipc_crypto_rcv_complete(struct net *net, struct tipc_aead *aead, 29762306a36Sopenharmony_ci struct tipc_bearer *b, 29862306a36Sopenharmony_ci struct sk_buff **skb, int err); 29962306a36Sopenharmony_cistatic void tipc_crypto_do_cmd(struct net *net, int cmd); 30062306a36Sopenharmony_cistatic char *tipc_crypto_key_dump(struct tipc_crypto *c, char *buf); 30162306a36Sopenharmony_cistatic char *tipc_key_change_dump(struct tipc_key old, struct tipc_key new, 30262306a36Sopenharmony_ci char *buf); 30362306a36Sopenharmony_cistatic int tipc_crypto_key_xmit(struct net *net, struct tipc_aead_key *skey, 30462306a36Sopenharmony_ci u16 gen, u8 mode, u32 dnode); 30562306a36Sopenharmony_cistatic bool tipc_crypto_key_rcv(struct tipc_crypto *rx, struct tipc_msg *hdr); 30662306a36Sopenharmony_cistatic void tipc_crypto_work_tx(struct work_struct *work); 30762306a36Sopenharmony_cistatic void tipc_crypto_work_rx(struct work_struct *work); 30862306a36Sopenharmony_cistatic int tipc_aead_key_generate(struct tipc_aead_key *skey); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci#define is_tx(crypto) (!(crypto)->node) 31162306a36Sopenharmony_ci#define is_rx(crypto) (!is_tx(crypto)) 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci#define key_next(cur) ((cur) % KEY_MAX + 1) 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci#define tipc_aead_rcu_ptr(rcu_ptr, lock) \ 31662306a36Sopenharmony_ci rcu_dereference_protected((rcu_ptr), lockdep_is_held(lock)) 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci#define tipc_aead_rcu_replace(rcu_ptr, ptr, lock) \ 31962306a36Sopenharmony_cido { \ 32062306a36Sopenharmony_ci struct tipc_aead *__tmp = rcu_dereference_protected((rcu_ptr), \ 32162306a36Sopenharmony_ci lockdep_is_held(lock)); \ 32262306a36Sopenharmony_ci rcu_assign_pointer((rcu_ptr), (ptr)); \ 32362306a36Sopenharmony_ci tipc_aead_put(__tmp); \ 32462306a36Sopenharmony_ci} while (0) 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci#define tipc_crypto_key_detach(rcu_ptr, lock) \ 32762306a36Sopenharmony_ci tipc_aead_rcu_replace((rcu_ptr), NULL, lock) 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci/** 33062306a36Sopenharmony_ci * tipc_aead_key_validate - Validate a AEAD user key 33162306a36Sopenharmony_ci * @ukey: pointer to user key data 33262306a36Sopenharmony_ci * @info: netlink info pointer 33362306a36Sopenharmony_ci */ 33462306a36Sopenharmony_ciint tipc_aead_key_validate(struct tipc_aead_key *ukey, struct genl_info *info) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci int keylen; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* Check if algorithm exists */ 33962306a36Sopenharmony_ci if (unlikely(!crypto_has_alg(ukey->alg_name, 0, 0))) { 34062306a36Sopenharmony_ci GENL_SET_ERR_MSG(info, "unable to load the algorithm (module existed?)"); 34162306a36Sopenharmony_ci return -ENODEV; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* Currently, we only support the "gcm(aes)" cipher algorithm */ 34562306a36Sopenharmony_ci if (strcmp(ukey->alg_name, "gcm(aes)")) { 34662306a36Sopenharmony_ci GENL_SET_ERR_MSG(info, "not supported yet the algorithm"); 34762306a36Sopenharmony_ci return -ENOTSUPP; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci /* Check if key size is correct */ 35162306a36Sopenharmony_ci keylen = ukey->keylen - TIPC_AES_GCM_SALT_SIZE; 35262306a36Sopenharmony_ci if (unlikely(keylen != TIPC_AES_GCM_KEY_SIZE_128 && 35362306a36Sopenharmony_ci keylen != TIPC_AES_GCM_KEY_SIZE_192 && 35462306a36Sopenharmony_ci keylen != TIPC_AES_GCM_KEY_SIZE_256)) { 35562306a36Sopenharmony_ci GENL_SET_ERR_MSG(info, "incorrect key length (20, 28 or 36 octets?)"); 35662306a36Sopenharmony_ci return -EKEYREJECTED; 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci return 0; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci/** 36362306a36Sopenharmony_ci * tipc_aead_key_generate - Generate new session key 36462306a36Sopenharmony_ci * @skey: input/output key with new content 36562306a36Sopenharmony_ci * 36662306a36Sopenharmony_ci * Return: 0 in case of success, otherwise < 0 36762306a36Sopenharmony_ci */ 36862306a36Sopenharmony_cistatic int tipc_aead_key_generate(struct tipc_aead_key *skey) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci int rc = 0; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* Fill the key's content with a random value via RNG cipher */ 37362306a36Sopenharmony_ci rc = crypto_get_default_rng(); 37462306a36Sopenharmony_ci if (likely(!rc)) { 37562306a36Sopenharmony_ci rc = crypto_rng_get_bytes(crypto_default_rng, skey->key, 37662306a36Sopenharmony_ci skey->keylen); 37762306a36Sopenharmony_ci crypto_put_default_rng(); 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci return rc; 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic struct tipc_aead *tipc_aead_get(struct tipc_aead __rcu *aead) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct tipc_aead *tmp; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci rcu_read_lock(); 38862306a36Sopenharmony_ci tmp = rcu_dereference(aead); 38962306a36Sopenharmony_ci if (unlikely(!tmp || !refcount_inc_not_zero(&tmp->refcnt))) 39062306a36Sopenharmony_ci tmp = NULL; 39162306a36Sopenharmony_ci rcu_read_unlock(); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci return tmp; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic inline void tipc_aead_put(struct tipc_aead *aead) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci if (aead && refcount_dec_and_test(&aead->refcnt)) 39962306a36Sopenharmony_ci call_rcu(&aead->rcu, tipc_aead_free); 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci/** 40362306a36Sopenharmony_ci * tipc_aead_free - Release AEAD key incl. all the TFMs in the list 40462306a36Sopenharmony_ci * @rp: rcu head pointer 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_cistatic void tipc_aead_free(struct rcu_head *rp) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci struct tipc_aead *aead = container_of(rp, struct tipc_aead, rcu); 40962306a36Sopenharmony_ci struct tipc_tfm *tfm_entry, *head, *tmp; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (aead->cloned) { 41262306a36Sopenharmony_ci tipc_aead_put(aead->cloned); 41362306a36Sopenharmony_ci } else { 41462306a36Sopenharmony_ci head = *get_cpu_ptr(aead->tfm_entry); 41562306a36Sopenharmony_ci put_cpu_ptr(aead->tfm_entry); 41662306a36Sopenharmony_ci list_for_each_entry_safe(tfm_entry, tmp, &head->list, list) { 41762306a36Sopenharmony_ci crypto_free_aead(tfm_entry->tfm); 41862306a36Sopenharmony_ci list_del(&tfm_entry->list); 41962306a36Sopenharmony_ci kfree(tfm_entry); 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci /* Free the head */ 42262306a36Sopenharmony_ci crypto_free_aead(head->tfm); 42362306a36Sopenharmony_ci list_del(&head->list); 42462306a36Sopenharmony_ci kfree(head); 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci free_percpu(aead->tfm_entry); 42762306a36Sopenharmony_ci kfree_sensitive(aead->key); 42862306a36Sopenharmony_ci kfree(aead); 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic int tipc_aead_users(struct tipc_aead __rcu *aead) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci struct tipc_aead *tmp; 43462306a36Sopenharmony_ci int users = 0; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci rcu_read_lock(); 43762306a36Sopenharmony_ci tmp = rcu_dereference(aead); 43862306a36Sopenharmony_ci if (tmp) 43962306a36Sopenharmony_ci users = atomic_read(&tmp->users); 44062306a36Sopenharmony_ci rcu_read_unlock(); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci return users; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic void tipc_aead_users_inc(struct tipc_aead __rcu *aead, int lim) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci struct tipc_aead *tmp; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci rcu_read_lock(); 45062306a36Sopenharmony_ci tmp = rcu_dereference(aead); 45162306a36Sopenharmony_ci if (tmp) 45262306a36Sopenharmony_ci atomic_add_unless(&tmp->users, 1, lim); 45362306a36Sopenharmony_ci rcu_read_unlock(); 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic void tipc_aead_users_dec(struct tipc_aead __rcu *aead, int lim) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci struct tipc_aead *tmp; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci rcu_read_lock(); 46162306a36Sopenharmony_ci tmp = rcu_dereference(aead); 46262306a36Sopenharmony_ci if (tmp) 46362306a36Sopenharmony_ci atomic_add_unless(&rcu_dereference(aead)->users, -1, lim); 46462306a36Sopenharmony_ci rcu_read_unlock(); 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic void tipc_aead_users_set(struct tipc_aead __rcu *aead, int val) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci struct tipc_aead *tmp; 47062306a36Sopenharmony_ci int cur; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci rcu_read_lock(); 47362306a36Sopenharmony_ci tmp = rcu_dereference(aead); 47462306a36Sopenharmony_ci if (tmp) { 47562306a36Sopenharmony_ci do { 47662306a36Sopenharmony_ci cur = atomic_read(&tmp->users); 47762306a36Sopenharmony_ci if (cur == val) 47862306a36Sopenharmony_ci break; 47962306a36Sopenharmony_ci } while (atomic_cmpxchg(&tmp->users, cur, val) != cur); 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci rcu_read_unlock(); 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci/** 48562306a36Sopenharmony_ci * tipc_aead_tfm_next - Move TFM entry to the next one in list and return it 48662306a36Sopenharmony_ci * @aead: the AEAD key pointer 48762306a36Sopenharmony_ci */ 48862306a36Sopenharmony_cistatic struct crypto_aead *tipc_aead_tfm_next(struct tipc_aead *aead) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci struct tipc_tfm **tfm_entry; 49162306a36Sopenharmony_ci struct crypto_aead *tfm; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci tfm_entry = get_cpu_ptr(aead->tfm_entry); 49462306a36Sopenharmony_ci *tfm_entry = list_next_entry(*tfm_entry, list); 49562306a36Sopenharmony_ci tfm = (*tfm_entry)->tfm; 49662306a36Sopenharmony_ci put_cpu_ptr(tfm_entry); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci return tfm; 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci/** 50262306a36Sopenharmony_ci * tipc_aead_init - Initiate TIPC AEAD 50362306a36Sopenharmony_ci * @aead: returned new TIPC AEAD key handle pointer 50462306a36Sopenharmony_ci * @ukey: pointer to user key data 50562306a36Sopenharmony_ci * @mode: the key mode 50662306a36Sopenharmony_ci * 50762306a36Sopenharmony_ci * Allocate a (list of) new cipher transformation (TFM) with the specific user 50862306a36Sopenharmony_ci * key data if valid. The number of the allocated TFMs can be set via the sysfs 50962306a36Sopenharmony_ci * "net/tipc/max_tfms" first. 51062306a36Sopenharmony_ci * Also, all the other AEAD data are also initialized. 51162306a36Sopenharmony_ci * 51262306a36Sopenharmony_ci * Return: 0 if the initiation is successful, otherwise: < 0 51362306a36Sopenharmony_ci */ 51462306a36Sopenharmony_cistatic int tipc_aead_init(struct tipc_aead **aead, struct tipc_aead_key *ukey, 51562306a36Sopenharmony_ci u8 mode) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci struct tipc_tfm *tfm_entry, *head; 51862306a36Sopenharmony_ci struct crypto_aead *tfm; 51962306a36Sopenharmony_ci struct tipc_aead *tmp; 52062306a36Sopenharmony_ci int keylen, err, cpu; 52162306a36Sopenharmony_ci int tfm_cnt = 0; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (unlikely(*aead)) 52462306a36Sopenharmony_ci return -EEXIST; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci /* Allocate a new AEAD */ 52762306a36Sopenharmony_ci tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC); 52862306a36Sopenharmony_ci if (unlikely(!tmp)) 52962306a36Sopenharmony_ci return -ENOMEM; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci /* The key consists of two parts: [AES-KEY][SALT] */ 53262306a36Sopenharmony_ci keylen = ukey->keylen - TIPC_AES_GCM_SALT_SIZE; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci /* Allocate per-cpu TFM entry pointer */ 53562306a36Sopenharmony_ci tmp->tfm_entry = alloc_percpu(struct tipc_tfm *); 53662306a36Sopenharmony_ci if (!tmp->tfm_entry) { 53762306a36Sopenharmony_ci kfree_sensitive(tmp); 53862306a36Sopenharmony_ci return -ENOMEM; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci /* Make a list of TFMs with the user key data */ 54262306a36Sopenharmony_ci do { 54362306a36Sopenharmony_ci tfm = crypto_alloc_aead(ukey->alg_name, 0, 0); 54462306a36Sopenharmony_ci if (IS_ERR(tfm)) { 54562306a36Sopenharmony_ci err = PTR_ERR(tfm); 54662306a36Sopenharmony_ci break; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (unlikely(!tfm_cnt && 55062306a36Sopenharmony_ci crypto_aead_ivsize(tfm) != TIPC_AES_GCM_IV_SIZE)) { 55162306a36Sopenharmony_ci crypto_free_aead(tfm); 55262306a36Sopenharmony_ci err = -ENOTSUPP; 55362306a36Sopenharmony_ci break; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci err = crypto_aead_setauthsize(tfm, TIPC_AES_GCM_TAG_SIZE); 55762306a36Sopenharmony_ci err |= crypto_aead_setkey(tfm, ukey->key, keylen); 55862306a36Sopenharmony_ci if (unlikely(err)) { 55962306a36Sopenharmony_ci crypto_free_aead(tfm); 56062306a36Sopenharmony_ci break; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci tfm_entry = kmalloc(sizeof(*tfm_entry), GFP_KERNEL); 56462306a36Sopenharmony_ci if (unlikely(!tfm_entry)) { 56562306a36Sopenharmony_ci crypto_free_aead(tfm); 56662306a36Sopenharmony_ci err = -ENOMEM; 56762306a36Sopenharmony_ci break; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci INIT_LIST_HEAD(&tfm_entry->list); 57062306a36Sopenharmony_ci tfm_entry->tfm = tfm; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* First entry? */ 57362306a36Sopenharmony_ci if (!tfm_cnt) { 57462306a36Sopenharmony_ci head = tfm_entry; 57562306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 57662306a36Sopenharmony_ci *per_cpu_ptr(tmp->tfm_entry, cpu) = head; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci } else { 57962306a36Sopenharmony_ci list_add_tail(&tfm_entry->list, &head->list); 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci } while (++tfm_cnt < sysctl_tipc_max_tfms); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* Not any TFM is allocated? */ 58562306a36Sopenharmony_ci if (!tfm_cnt) { 58662306a36Sopenharmony_ci free_percpu(tmp->tfm_entry); 58762306a36Sopenharmony_ci kfree_sensitive(tmp); 58862306a36Sopenharmony_ci return err; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* Form a hex string of some last bytes as the key's hint */ 59262306a36Sopenharmony_ci bin2hex(tmp->hint, ukey->key + keylen - TIPC_AEAD_HINT_LEN, 59362306a36Sopenharmony_ci TIPC_AEAD_HINT_LEN); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci /* Initialize the other data */ 59662306a36Sopenharmony_ci tmp->mode = mode; 59762306a36Sopenharmony_ci tmp->cloned = NULL; 59862306a36Sopenharmony_ci tmp->authsize = TIPC_AES_GCM_TAG_SIZE; 59962306a36Sopenharmony_ci tmp->key = kmemdup(ukey, tipc_aead_key_size(ukey), GFP_KERNEL); 60062306a36Sopenharmony_ci if (!tmp->key) { 60162306a36Sopenharmony_ci tipc_aead_free(&tmp->rcu); 60262306a36Sopenharmony_ci return -ENOMEM; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci memcpy(&tmp->salt, ukey->key + keylen, TIPC_AES_GCM_SALT_SIZE); 60562306a36Sopenharmony_ci atomic_set(&tmp->users, 0); 60662306a36Sopenharmony_ci atomic64_set(&tmp->seqno, 0); 60762306a36Sopenharmony_ci refcount_set(&tmp->refcnt, 1); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci *aead = tmp; 61062306a36Sopenharmony_ci return 0; 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci/** 61462306a36Sopenharmony_ci * tipc_aead_clone - Clone a TIPC AEAD key 61562306a36Sopenharmony_ci * @dst: dest key for the cloning 61662306a36Sopenharmony_ci * @src: source key to clone from 61762306a36Sopenharmony_ci * 61862306a36Sopenharmony_ci * Make a "copy" of the source AEAD key data to the dest, the TFMs list is 61962306a36Sopenharmony_ci * common for the keys. 62062306a36Sopenharmony_ci * A reference to the source is hold in the "cloned" pointer for the later 62162306a36Sopenharmony_ci * freeing purposes. 62262306a36Sopenharmony_ci * 62362306a36Sopenharmony_ci * Note: this must be done in cluster-key mode only! 62462306a36Sopenharmony_ci * Return: 0 in case of success, otherwise < 0 62562306a36Sopenharmony_ci */ 62662306a36Sopenharmony_cistatic int tipc_aead_clone(struct tipc_aead **dst, struct tipc_aead *src) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci struct tipc_aead *aead; 62962306a36Sopenharmony_ci int cpu; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci if (!src) 63262306a36Sopenharmony_ci return -ENOKEY; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci if (src->mode != CLUSTER_KEY) 63562306a36Sopenharmony_ci return -EINVAL; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (unlikely(*dst)) 63862306a36Sopenharmony_ci return -EEXIST; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci aead = kzalloc(sizeof(*aead), GFP_ATOMIC); 64162306a36Sopenharmony_ci if (unlikely(!aead)) 64262306a36Sopenharmony_ci return -ENOMEM; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci aead->tfm_entry = alloc_percpu_gfp(struct tipc_tfm *, GFP_ATOMIC); 64562306a36Sopenharmony_ci if (unlikely(!aead->tfm_entry)) { 64662306a36Sopenharmony_ci kfree_sensitive(aead); 64762306a36Sopenharmony_ci return -ENOMEM; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 65162306a36Sopenharmony_ci *per_cpu_ptr(aead->tfm_entry, cpu) = 65262306a36Sopenharmony_ci *per_cpu_ptr(src->tfm_entry, cpu); 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci memcpy(aead->hint, src->hint, sizeof(src->hint)); 65662306a36Sopenharmony_ci aead->mode = src->mode; 65762306a36Sopenharmony_ci aead->salt = src->salt; 65862306a36Sopenharmony_ci aead->authsize = src->authsize; 65962306a36Sopenharmony_ci atomic_set(&aead->users, 0); 66062306a36Sopenharmony_ci atomic64_set(&aead->seqno, 0); 66162306a36Sopenharmony_ci refcount_set(&aead->refcnt, 1); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci WARN_ON(!refcount_inc_not_zero(&src->refcnt)); 66462306a36Sopenharmony_ci aead->cloned = src; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci *dst = aead; 66762306a36Sopenharmony_ci return 0; 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci/** 67162306a36Sopenharmony_ci * tipc_aead_mem_alloc - Allocate memory for AEAD request operations 67262306a36Sopenharmony_ci * @tfm: cipher handle to be registered with the request 67362306a36Sopenharmony_ci * @crypto_ctx_size: size of crypto context for callback 67462306a36Sopenharmony_ci * @iv: returned pointer to IV data 67562306a36Sopenharmony_ci * @req: returned pointer to AEAD request data 67662306a36Sopenharmony_ci * @sg: returned pointer to SG lists 67762306a36Sopenharmony_ci * @nsg: number of SG lists to be allocated 67862306a36Sopenharmony_ci * 67962306a36Sopenharmony_ci * Allocate memory to store the crypto context data, AEAD request, IV and SG 68062306a36Sopenharmony_ci * lists, the memory layout is as follows: 68162306a36Sopenharmony_ci * crypto_ctx || iv || aead_req || sg[] 68262306a36Sopenharmony_ci * 68362306a36Sopenharmony_ci * Return: the pointer to the memory areas in case of success, otherwise NULL 68462306a36Sopenharmony_ci */ 68562306a36Sopenharmony_cistatic void *tipc_aead_mem_alloc(struct crypto_aead *tfm, 68662306a36Sopenharmony_ci unsigned int crypto_ctx_size, 68762306a36Sopenharmony_ci u8 **iv, struct aead_request **req, 68862306a36Sopenharmony_ci struct scatterlist **sg, int nsg) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci unsigned int iv_size, req_size; 69162306a36Sopenharmony_ci unsigned int len; 69262306a36Sopenharmony_ci u8 *mem; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci iv_size = crypto_aead_ivsize(tfm); 69562306a36Sopenharmony_ci req_size = sizeof(**req) + crypto_aead_reqsize(tfm); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci len = crypto_ctx_size; 69862306a36Sopenharmony_ci len += iv_size; 69962306a36Sopenharmony_ci len += crypto_aead_alignmask(tfm) & ~(crypto_tfm_ctx_alignment() - 1); 70062306a36Sopenharmony_ci len = ALIGN(len, crypto_tfm_ctx_alignment()); 70162306a36Sopenharmony_ci len += req_size; 70262306a36Sopenharmony_ci len = ALIGN(len, __alignof__(struct scatterlist)); 70362306a36Sopenharmony_ci len += nsg * sizeof(**sg); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci mem = kmalloc(len, GFP_ATOMIC); 70662306a36Sopenharmony_ci if (!mem) 70762306a36Sopenharmony_ci return NULL; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci *iv = (u8 *)PTR_ALIGN(mem + crypto_ctx_size, 71062306a36Sopenharmony_ci crypto_aead_alignmask(tfm) + 1); 71162306a36Sopenharmony_ci *req = (struct aead_request *)PTR_ALIGN(*iv + iv_size, 71262306a36Sopenharmony_ci crypto_tfm_ctx_alignment()); 71362306a36Sopenharmony_ci *sg = (struct scatterlist *)PTR_ALIGN((u8 *)*req + req_size, 71462306a36Sopenharmony_ci __alignof__(struct scatterlist)); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci return (void *)mem; 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci/** 72062306a36Sopenharmony_ci * tipc_aead_encrypt - Encrypt a message 72162306a36Sopenharmony_ci * @aead: TIPC AEAD key for the message encryption 72262306a36Sopenharmony_ci * @skb: the input/output skb 72362306a36Sopenharmony_ci * @b: TIPC bearer where the message will be delivered after the encryption 72462306a36Sopenharmony_ci * @dst: the destination media address 72562306a36Sopenharmony_ci * @__dnode: TIPC dest node if "known" 72662306a36Sopenharmony_ci * 72762306a36Sopenharmony_ci * Return: 72862306a36Sopenharmony_ci * * 0 : if the encryption has completed 72962306a36Sopenharmony_ci * * -EINPROGRESS/-EBUSY : if a callback will be performed 73062306a36Sopenharmony_ci * * < 0 : the encryption has failed 73162306a36Sopenharmony_ci */ 73262306a36Sopenharmony_cistatic int tipc_aead_encrypt(struct tipc_aead *aead, struct sk_buff *skb, 73362306a36Sopenharmony_ci struct tipc_bearer *b, 73462306a36Sopenharmony_ci struct tipc_media_addr *dst, 73562306a36Sopenharmony_ci struct tipc_node *__dnode) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci struct crypto_aead *tfm = tipc_aead_tfm_next(aead); 73862306a36Sopenharmony_ci struct tipc_crypto_tx_ctx *tx_ctx; 73962306a36Sopenharmony_ci struct aead_request *req; 74062306a36Sopenharmony_ci struct sk_buff *trailer; 74162306a36Sopenharmony_ci struct scatterlist *sg; 74262306a36Sopenharmony_ci struct tipc_ehdr *ehdr; 74362306a36Sopenharmony_ci int ehsz, len, tailen, nsg, rc; 74462306a36Sopenharmony_ci void *ctx; 74562306a36Sopenharmony_ci u32 salt; 74662306a36Sopenharmony_ci u8 *iv; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci /* Make sure message len at least 4-byte aligned */ 74962306a36Sopenharmony_ci len = ALIGN(skb->len, 4); 75062306a36Sopenharmony_ci tailen = len - skb->len + aead->authsize; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci /* Expand skb tail for authentication tag: 75362306a36Sopenharmony_ci * As for simplicity, we'd have made sure skb having enough tailroom 75462306a36Sopenharmony_ci * for authentication tag @skb allocation. Even when skb is nonlinear 75562306a36Sopenharmony_ci * but there is no frag_list, it should be still fine! 75662306a36Sopenharmony_ci * Otherwise, we must cow it to be a writable buffer with the tailroom. 75762306a36Sopenharmony_ci */ 75862306a36Sopenharmony_ci SKB_LINEAR_ASSERT(skb); 75962306a36Sopenharmony_ci if (tailen > skb_tailroom(skb)) { 76062306a36Sopenharmony_ci pr_debug("TX(): skb tailroom is not enough: %d, requires: %d\n", 76162306a36Sopenharmony_ci skb_tailroom(skb), tailen); 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci nsg = skb_cow_data(skb, tailen, &trailer); 76562306a36Sopenharmony_ci if (unlikely(nsg < 0)) { 76662306a36Sopenharmony_ci pr_err("TX: skb_cow_data() returned %d\n", nsg); 76762306a36Sopenharmony_ci return nsg; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci pskb_put(skb, trailer, tailen); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci /* Allocate memory for the AEAD operation */ 77362306a36Sopenharmony_ci ctx = tipc_aead_mem_alloc(tfm, sizeof(*tx_ctx), &iv, &req, &sg, nsg); 77462306a36Sopenharmony_ci if (unlikely(!ctx)) 77562306a36Sopenharmony_ci return -ENOMEM; 77662306a36Sopenharmony_ci TIPC_SKB_CB(skb)->crypto_ctx = ctx; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci /* Map skb to the sg lists */ 77962306a36Sopenharmony_ci sg_init_table(sg, nsg); 78062306a36Sopenharmony_ci rc = skb_to_sgvec(skb, sg, 0, skb->len); 78162306a36Sopenharmony_ci if (unlikely(rc < 0)) { 78262306a36Sopenharmony_ci pr_err("TX: skb_to_sgvec() returned %d, nsg %d!\n", rc, nsg); 78362306a36Sopenharmony_ci goto exit; 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci /* Prepare IV: [SALT (4 octets)][SEQNO (8 octets)] 78762306a36Sopenharmony_ci * In case we're in cluster-key mode, SALT is varied by xor-ing with 78862306a36Sopenharmony_ci * the source address (or w0 of id), otherwise with the dest address 78962306a36Sopenharmony_ci * if dest is known. 79062306a36Sopenharmony_ci */ 79162306a36Sopenharmony_ci ehdr = (struct tipc_ehdr *)skb->data; 79262306a36Sopenharmony_ci salt = aead->salt; 79362306a36Sopenharmony_ci if (aead->mode == CLUSTER_KEY) 79462306a36Sopenharmony_ci salt ^= __be32_to_cpu(ehdr->addr); 79562306a36Sopenharmony_ci else if (__dnode) 79662306a36Sopenharmony_ci salt ^= tipc_node_get_addr(__dnode); 79762306a36Sopenharmony_ci memcpy(iv, &salt, 4); 79862306a36Sopenharmony_ci memcpy(iv + 4, (u8 *)&ehdr->seqno, 8); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci /* Prepare request */ 80162306a36Sopenharmony_ci ehsz = tipc_ehdr_size(ehdr); 80262306a36Sopenharmony_ci aead_request_set_tfm(req, tfm); 80362306a36Sopenharmony_ci aead_request_set_ad(req, ehsz); 80462306a36Sopenharmony_ci aead_request_set_crypt(req, sg, sg, len - ehsz, iv); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci /* Set callback function & data */ 80762306a36Sopenharmony_ci aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, 80862306a36Sopenharmony_ci tipc_aead_encrypt_done, skb); 80962306a36Sopenharmony_ci tx_ctx = (struct tipc_crypto_tx_ctx *)ctx; 81062306a36Sopenharmony_ci tx_ctx->aead = aead; 81162306a36Sopenharmony_ci tx_ctx->bearer = b; 81262306a36Sopenharmony_ci memcpy(&tx_ctx->dst, dst, sizeof(*dst)); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci /* Hold bearer */ 81562306a36Sopenharmony_ci if (unlikely(!tipc_bearer_hold(b))) { 81662306a36Sopenharmony_ci rc = -ENODEV; 81762306a36Sopenharmony_ci goto exit; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci /* Now, do encrypt */ 82162306a36Sopenharmony_ci rc = crypto_aead_encrypt(req); 82262306a36Sopenharmony_ci if (rc == -EINPROGRESS || rc == -EBUSY) 82362306a36Sopenharmony_ci return rc; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci tipc_bearer_put(b); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ciexit: 82862306a36Sopenharmony_ci kfree(ctx); 82962306a36Sopenharmony_ci TIPC_SKB_CB(skb)->crypto_ctx = NULL; 83062306a36Sopenharmony_ci return rc; 83162306a36Sopenharmony_ci} 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_cistatic void tipc_aead_encrypt_done(void *data, int err) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci struct sk_buff *skb = data; 83662306a36Sopenharmony_ci struct tipc_crypto_tx_ctx *tx_ctx = TIPC_SKB_CB(skb)->crypto_ctx; 83762306a36Sopenharmony_ci struct tipc_bearer *b = tx_ctx->bearer; 83862306a36Sopenharmony_ci struct tipc_aead *aead = tx_ctx->aead; 83962306a36Sopenharmony_ci struct tipc_crypto *tx = aead->crypto; 84062306a36Sopenharmony_ci struct net *net = tx->net; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci switch (err) { 84362306a36Sopenharmony_ci case 0: 84462306a36Sopenharmony_ci this_cpu_inc(tx->stats->stat[STAT_ASYNC_OK]); 84562306a36Sopenharmony_ci rcu_read_lock(); 84662306a36Sopenharmony_ci if (likely(test_bit(0, &b->up))) 84762306a36Sopenharmony_ci b->media->send_msg(net, skb, b, &tx_ctx->dst); 84862306a36Sopenharmony_ci else 84962306a36Sopenharmony_ci kfree_skb(skb); 85062306a36Sopenharmony_ci rcu_read_unlock(); 85162306a36Sopenharmony_ci break; 85262306a36Sopenharmony_ci case -EINPROGRESS: 85362306a36Sopenharmony_ci return; 85462306a36Sopenharmony_ci default: 85562306a36Sopenharmony_ci this_cpu_inc(tx->stats->stat[STAT_ASYNC_NOK]); 85662306a36Sopenharmony_ci kfree_skb(skb); 85762306a36Sopenharmony_ci break; 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci kfree(tx_ctx); 86162306a36Sopenharmony_ci tipc_bearer_put(b); 86262306a36Sopenharmony_ci tipc_aead_put(aead); 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci/** 86662306a36Sopenharmony_ci * tipc_aead_decrypt - Decrypt an encrypted message 86762306a36Sopenharmony_ci * @net: struct net 86862306a36Sopenharmony_ci * @aead: TIPC AEAD for the message decryption 86962306a36Sopenharmony_ci * @skb: the input/output skb 87062306a36Sopenharmony_ci * @b: TIPC bearer where the message has been received 87162306a36Sopenharmony_ci * 87262306a36Sopenharmony_ci * Return: 87362306a36Sopenharmony_ci * * 0 : if the decryption has completed 87462306a36Sopenharmony_ci * * -EINPROGRESS/-EBUSY : if a callback will be performed 87562306a36Sopenharmony_ci * * < 0 : the decryption has failed 87662306a36Sopenharmony_ci */ 87762306a36Sopenharmony_cistatic int tipc_aead_decrypt(struct net *net, struct tipc_aead *aead, 87862306a36Sopenharmony_ci struct sk_buff *skb, struct tipc_bearer *b) 87962306a36Sopenharmony_ci{ 88062306a36Sopenharmony_ci struct tipc_crypto_rx_ctx *rx_ctx; 88162306a36Sopenharmony_ci struct aead_request *req; 88262306a36Sopenharmony_ci struct crypto_aead *tfm; 88362306a36Sopenharmony_ci struct sk_buff *unused; 88462306a36Sopenharmony_ci struct scatterlist *sg; 88562306a36Sopenharmony_ci struct tipc_ehdr *ehdr; 88662306a36Sopenharmony_ci int ehsz, nsg, rc; 88762306a36Sopenharmony_ci void *ctx; 88862306a36Sopenharmony_ci u32 salt; 88962306a36Sopenharmony_ci u8 *iv; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci if (unlikely(!aead)) 89262306a36Sopenharmony_ci return -ENOKEY; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci nsg = skb_cow_data(skb, 0, &unused); 89562306a36Sopenharmony_ci if (unlikely(nsg < 0)) { 89662306a36Sopenharmony_ci pr_err("RX: skb_cow_data() returned %d\n", nsg); 89762306a36Sopenharmony_ci return nsg; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci /* Allocate memory for the AEAD operation */ 90162306a36Sopenharmony_ci tfm = tipc_aead_tfm_next(aead); 90262306a36Sopenharmony_ci ctx = tipc_aead_mem_alloc(tfm, sizeof(*rx_ctx), &iv, &req, &sg, nsg); 90362306a36Sopenharmony_ci if (unlikely(!ctx)) 90462306a36Sopenharmony_ci return -ENOMEM; 90562306a36Sopenharmony_ci TIPC_SKB_CB(skb)->crypto_ctx = ctx; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci /* Map skb to the sg lists */ 90862306a36Sopenharmony_ci sg_init_table(sg, nsg); 90962306a36Sopenharmony_ci rc = skb_to_sgvec(skb, sg, 0, skb->len); 91062306a36Sopenharmony_ci if (unlikely(rc < 0)) { 91162306a36Sopenharmony_ci pr_err("RX: skb_to_sgvec() returned %d, nsg %d\n", rc, nsg); 91262306a36Sopenharmony_ci goto exit; 91362306a36Sopenharmony_ci } 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci /* Reconstruct IV: */ 91662306a36Sopenharmony_ci ehdr = (struct tipc_ehdr *)skb->data; 91762306a36Sopenharmony_ci salt = aead->salt; 91862306a36Sopenharmony_ci if (aead->mode == CLUSTER_KEY) 91962306a36Sopenharmony_ci salt ^= __be32_to_cpu(ehdr->addr); 92062306a36Sopenharmony_ci else if (ehdr->destined) 92162306a36Sopenharmony_ci salt ^= tipc_own_addr(net); 92262306a36Sopenharmony_ci memcpy(iv, &salt, 4); 92362306a36Sopenharmony_ci memcpy(iv + 4, (u8 *)&ehdr->seqno, 8); 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci /* Prepare request */ 92662306a36Sopenharmony_ci ehsz = tipc_ehdr_size(ehdr); 92762306a36Sopenharmony_ci aead_request_set_tfm(req, tfm); 92862306a36Sopenharmony_ci aead_request_set_ad(req, ehsz); 92962306a36Sopenharmony_ci aead_request_set_crypt(req, sg, sg, skb->len - ehsz, iv); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci /* Set callback function & data */ 93262306a36Sopenharmony_ci aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, 93362306a36Sopenharmony_ci tipc_aead_decrypt_done, skb); 93462306a36Sopenharmony_ci rx_ctx = (struct tipc_crypto_rx_ctx *)ctx; 93562306a36Sopenharmony_ci rx_ctx->aead = aead; 93662306a36Sopenharmony_ci rx_ctx->bearer = b; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci /* Hold bearer */ 93962306a36Sopenharmony_ci if (unlikely(!tipc_bearer_hold(b))) { 94062306a36Sopenharmony_ci rc = -ENODEV; 94162306a36Sopenharmony_ci goto exit; 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci /* Now, do decrypt */ 94562306a36Sopenharmony_ci rc = crypto_aead_decrypt(req); 94662306a36Sopenharmony_ci if (rc == -EINPROGRESS || rc == -EBUSY) 94762306a36Sopenharmony_ci return rc; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci tipc_bearer_put(b); 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ciexit: 95262306a36Sopenharmony_ci kfree(ctx); 95362306a36Sopenharmony_ci TIPC_SKB_CB(skb)->crypto_ctx = NULL; 95462306a36Sopenharmony_ci return rc; 95562306a36Sopenharmony_ci} 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_cistatic void tipc_aead_decrypt_done(void *data, int err) 95862306a36Sopenharmony_ci{ 95962306a36Sopenharmony_ci struct sk_buff *skb = data; 96062306a36Sopenharmony_ci struct tipc_crypto_rx_ctx *rx_ctx = TIPC_SKB_CB(skb)->crypto_ctx; 96162306a36Sopenharmony_ci struct tipc_bearer *b = rx_ctx->bearer; 96262306a36Sopenharmony_ci struct tipc_aead *aead = rx_ctx->aead; 96362306a36Sopenharmony_ci struct tipc_crypto_stats __percpu *stats = aead->crypto->stats; 96462306a36Sopenharmony_ci struct net *net = aead->crypto->net; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci switch (err) { 96762306a36Sopenharmony_ci case 0: 96862306a36Sopenharmony_ci this_cpu_inc(stats->stat[STAT_ASYNC_OK]); 96962306a36Sopenharmony_ci break; 97062306a36Sopenharmony_ci case -EINPROGRESS: 97162306a36Sopenharmony_ci return; 97262306a36Sopenharmony_ci default: 97362306a36Sopenharmony_ci this_cpu_inc(stats->stat[STAT_ASYNC_NOK]); 97462306a36Sopenharmony_ci break; 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci kfree(rx_ctx); 97862306a36Sopenharmony_ci tipc_crypto_rcv_complete(net, aead, b, &skb, err); 97962306a36Sopenharmony_ci if (likely(skb)) { 98062306a36Sopenharmony_ci if (likely(test_bit(0, &b->up))) 98162306a36Sopenharmony_ci tipc_rcv(net, skb, b); 98262306a36Sopenharmony_ci else 98362306a36Sopenharmony_ci kfree_skb(skb); 98462306a36Sopenharmony_ci } 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci tipc_bearer_put(b); 98762306a36Sopenharmony_ci} 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_cistatic inline int tipc_ehdr_size(struct tipc_ehdr *ehdr) 99062306a36Sopenharmony_ci{ 99162306a36Sopenharmony_ci return (ehdr->user != LINK_CONFIG) ? EHDR_SIZE : EHDR_CFG_SIZE; 99262306a36Sopenharmony_ci} 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci/** 99562306a36Sopenharmony_ci * tipc_ehdr_validate - Validate an encryption message 99662306a36Sopenharmony_ci * @skb: the message buffer 99762306a36Sopenharmony_ci * 99862306a36Sopenharmony_ci * Return: "true" if this is a valid encryption message, otherwise "false" 99962306a36Sopenharmony_ci */ 100062306a36Sopenharmony_cibool tipc_ehdr_validate(struct sk_buff *skb) 100162306a36Sopenharmony_ci{ 100262306a36Sopenharmony_ci struct tipc_ehdr *ehdr; 100362306a36Sopenharmony_ci int ehsz; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci if (unlikely(!pskb_may_pull(skb, EHDR_MIN_SIZE))) 100662306a36Sopenharmony_ci return false; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci ehdr = (struct tipc_ehdr *)skb->data; 100962306a36Sopenharmony_ci if (unlikely(ehdr->version != TIPC_EVERSION)) 101062306a36Sopenharmony_ci return false; 101162306a36Sopenharmony_ci ehsz = tipc_ehdr_size(ehdr); 101262306a36Sopenharmony_ci if (unlikely(!pskb_may_pull(skb, ehsz))) 101362306a36Sopenharmony_ci return false; 101462306a36Sopenharmony_ci if (unlikely(skb->len <= ehsz + TIPC_AES_GCM_TAG_SIZE)) 101562306a36Sopenharmony_ci return false; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci return true; 101862306a36Sopenharmony_ci} 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci/** 102162306a36Sopenharmony_ci * tipc_ehdr_build - Build TIPC encryption message header 102262306a36Sopenharmony_ci * @net: struct net 102362306a36Sopenharmony_ci * @aead: TX AEAD key to be used for the message encryption 102462306a36Sopenharmony_ci * @tx_key: key id used for the message encryption 102562306a36Sopenharmony_ci * @skb: input/output message skb 102662306a36Sopenharmony_ci * @__rx: RX crypto handle if dest is "known" 102762306a36Sopenharmony_ci * 102862306a36Sopenharmony_ci * Return: the header size if the building is successful, otherwise < 0 102962306a36Sopenharmony_ci */ 103062306a36Sopenharmony_cistatic int tipc_ehdr_build(struct net *net, struct tipc_aead *aead, 103162306a36Sopenharmony_ci u8 tx_key, struct sk_buff *skb, 103262306a36Sopenharmony_ci struct tipc_crypto *__rx) 103362306a36Sopenharmony_ci{ 103462306a36Sopenharmony_ci struct tipc_msg *hdr = buf_msg(skb); 103562306a36Sopenharmony_ci struct tipc_ehdr *ehdr; 103662306a36Sopenharmony_ci u32 user = msg_user(hdr); 103762306a36Sopenharmony_ci u64 seqno; 103862306a36Sopenharmony_ci int ehsz; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci /* Make room for encryption header */ 104162306a36Sopenharmony_ci ehsz = (user != LINK_CONFIG) ? EHDR_SIZE : EHDR_CFG_SIZE; 104262306a36Sopenharmony_ci WARN_ON(skb_headroom(skb) < ehsz); 104362306a36Sopenharmony_ci ehdr = (struct tipc_ehdr *)skb_push(skb, ehsz); 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci /* Obtain a seqno first: 104662306a36Sopenharmony_ci * Use the key seqno (= cluster wise) if dest is unknown or we're in 104762306a36Sopenharmony_ci * cluster key mode, otherwise it's better for a per-peer seqno! 104862306a36Sopenharmony_ci */ 104962306a36Sopenharmony_ci if (!__rx || aead->mode == CLUSTER_KEY) 105062306a36Sopenharmony_ci seqno = atomic64_inc_return(&aead->seqno); 105162306a36Sopenharmony_ci else 105262306a36Sopenharmony_ci seqno = atomic64_inc_return(&__rx->sndnxt); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci /* Revoke the key if seqno is wrapped around */ 105562306a36Sopenharmony_ci if (unlikely(!seqno)) 105662306a36Sopenharmony_ci return tipc_crypto_key_revoke(net, tx_key); 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci /* Word 1-2 */ 105962306a36Sopenharmony_ci ehdr->seqno = cpu_to_be64(seqno); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci /* Words 0, 3- */ 106262306a36Sopenharmony_ci ehdr->version = TIPC_EVERSION; 106362306a36Sopenharmony_ci ehdr->user = 0; 106462306a36Sopenharmony_ci ehdr->keepalive = 0; 106562306a36Sopenharmony_ci ehdr->tx_key = tx_key; 106662306a36Sopenharmony_ci ehdr->destined = (__rx) ? 1 : 0; 106762306a36Sopenharmony_ci ehdr->rx_key_active = (__rx) ? __rx->key.active : 0; 106862306a36Sopenharmony_ci ehdr->rx_nokey = (__rx) ? __rx->nokey : 0; 106962306a36Sopenharmony_ci ehdr->master_key = aead->crypto->key_master; 107062306a36Sopenharmony_ci ehdr->reserved_1 = 0; 107162306a36Sopenharmony_ci ehdr->reserved_2 = 0; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci switch (user) { 107462306a36Sopenharmony_ci case LINK_CONFIG: 107562306a36Sopenharmony_ci ehdr->user = LINK_CONFIG; 107662306a36Sopenharmony_ci memcpy(ehdr->id, tipc_own_id(net), NODE_ID_LEN); 107762306a36Sopenharmony_ci break; 107862306a36Sopenharmony_ci default: 107962306a36Sopenharmony_ci if (user == LINK_PROTOCOL && msg_type(hdr) == STATE_MSG) { 108062306a36Sopenharmony_ci ehdr->user = LINK_PROTOCOL; 108162306a36Sopenharmony_ci ehdr->keepalive = msg_is_keepalive(hdr); 108262306a36Sopenharmony_ci } 108362306a36Sopenharmony_ci ehdr->addr = hdr->hdr[3]; 108462306a36Sopenharmony_ci break; 108562306a36Sopenharmony_ci } 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci return ehsz; 108862306a36Sopenharmony_ci} 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_cistatic inline void tipc_crypto_key_set_state(struct tipc_crypto *c, 109162306a36Sopenharmony_ci u8 new_passive, 109262306a36Sopenharmony_ci u8 new_active, 109362306a36Sopenharmony_ci u8 new_pending) 109462306a36Sopenharmony_ci{ 109562306a36Sopenharmony_ci struct tipc_key old = c->key; 109662306a36Sopenharmony_ci char buf[32]; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci c->key.keys = ((new_passive & KEY_MASK) << (KEY_BITS * 2)) | 109962306a36Sopenharmony_ci ((new_active & KEY_MASK) << (KEY_BITS)) | 110062306a36Sopenharmony_ci ((new_pending & KEY_MASK)); 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci pr_debug("%s: key changing %s ::%pS\n", c->name, 110362306a36Sopenharmony_ci tipc_key_change_dump(old, c->key, buf), 110462306a36Sopenharmony_ci __builtin_return_address(0)); 110562306a36Sopenharmony_ci} 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci/** 110862306a36Sopenharmony_ci * tipc_crypto_key_init - Initiate a new user / AEAD key 110962306a36Sopenharmony_ci * @c: TIPC crypto to which new key is attached 111062306a36Sopenharmony_ci * @ukey: the user key 111162306a36Sopenharmony_ci * @mode: the key mode (CLUSTER_KEY or PER_NODE_KEY) 111262306a36Sopenharmony_ci * @master_key: specify this is a cluster master key 111362306a36Sopenharmony_ci * 111462306a36Sopenharmony_ci * A new TIPC AEAD key will be allocated and initiated with the specified user 111562306a36Sopenharmony_ci * key, then attached to the TIPC crypto. 111662306a36Sopenharmony_ci * 111762306a36Sopenharmony_ci * Return: new key id in case of success, otherwise: < 0 111862306a36Sopenharmony_ci */ 111962306a36Sopenharmony_ciint tipc_crypto_key_init(struct tipc_crypto *c, struct tipc_aead_key *ukey, 112062306a36Sopenharmony_ci u8 mode, bool master_key) 112162306a36Sopenharmony_ci{ 112262306a36Sopenharmony_ci struct tipc_aead *aead = NULL; 112362306a36Sopenharmony_ci int rc = 0; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci /* Initiate with the new user key */ 112662306a36Sopenharmony_ci rc = tipc_aead_init(&aead, ukey, mode); 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci /* Attach it to the crypto */ 112962306a36Sopenharmony_ci if (likely(!rc)) { 113062306a36Sopenharmony_ci rc = tipc_crypto_key_attach(c, aead, 0, master_key); 113162306a36Sopenharmony_ci if (rc < 0) 113262306a36Sopenharmony_ci tipc_aead_free(&aead->rcu); 113362306a36Sopenharmony_ci } 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci return rc; 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci/** 113962306a36Sopenharmony_ci * tipc_crypto_key_attach - Attach a new AEAD key to TIPC crypto 114062306a36Sopenharmony_ci * @c: TIPC crypto to which the new AEAD key is attached 114162306a36Sopenharmony_ci * @aead: the new AEAD key pointer 114262306a36Sopenharmony_ci * @pos: desired slot in the crypto key array, = 0 if any! 114362306a36Sopenharmony_ci * @master_key: specify this is a cluster master key 114462306a36Sopenharmony_ci * 114562306a36Sopenharmony_ci * Return: new key id in case of success, otherwise: -EBUSY 114662306a36Sopenharmony_ci */ 114762306a36Sopenharmony_cistatic int tipc_crypto_key_attach(struct tipc_crypto *c, 114862306a36Sopenharmony_ci struct tipc_aead *aead, u8 pos, 114962306a36Sopenharmony_ci bool master_key) 115062306a36Sopenharmony_ci{ 115162306a36Sopenharmony_ci struct tipc_key key; 115262306a36Sopenharmony_ci int rc = -EBUSY; 115362306a36Sopenharmony_ci u8 new_key; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci spin_lock_bh(&c->lock); 115662306a36Sopenharmony_ci key = c->key; 115762306a36Sopenharmony_ci if (master_key) { 115862306a36Sopenharmony_ci new_key = KEY_MASTER; 115962306a36Sopenharmony_ci goto attach; 116062306a36Sopenharmony_ci } 116162306a36Sopenharmony_ci if (key.active && key.passive) 116262306a36Sopenharmony_ci goto exit; 116362306a36Sopenharmony_ci if (key.pending) { 116462306a36Sopenharmony_ci if (tipc_aead_users(c->aead[key.pending]) > 0) 116562306a36Sopenharmony_ci goto exit; 116662306a36Sopenharmony_ci /* if (pos): ok with replacing, will be aligned when needed */ 116762306a36Sopenharmony_ci /* Replace it */ 116862306a36Sopenharmony_ci new_key = key.pending; 116962306a36Sopenharmony_ci } else { 117062306a36Sopenharmony_ci if (pos) { 117162306a36Sopenharmony_ci if (key.active && pos != key_next(key.active)) { 117262306a36Sopenharmony_ci key.passive = pos; 117362306a36Sopenharmony_ci new_key = pos; 117462306a36Sopenharmony_ci goto attach; 117562306a36Sopenharmony_ci } else if (!key.active && !key.passive) { 117662306a36Sopenharmony_ci key.pending = pos; 117762306a36Sopenharmony_ci new_key = pos; 117862306a36Sopenharmony_ci goto attach; 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci } 118162306a36Sopenharmony_ci key.pending = key_next(key.active ?: key.passive); 118262306a36Sopenharmony_ci new_key = key.pending; 118362306a36Sopenharmony_ci } 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ciattach: 118662306a36Sopenharmony_ci aead->crypto = c; 118762306a36Sopenharmony_ci aead->gen = (is_tx(c)) ? ++c->key_gen : c->key_gen; 118862306a36Sopenharmony_ci tipc_aead_rcu_replace(c->aead[new_key], aead, &c->lock); 118962306a36Sopenharmony_ci if (likely(c->key.keys != key.keys)) 119062306a36Sopenharmony_ci tipc_crypto_key_set_state(c, key.passive, key.active, 119162306a36Sopenharmony_ci key.pending); 119262306a36Sopenharmony_ci c->working = 1; 119362306a36Sopenharmony_ci c->nokey = 0; 119462306a36Sopenharmony_ci c->key_master |= master_key; 119562306a36Sopenharmony_ci rc = new_key; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ciexit: 119862306a36Sopenharmony_ci spin_unlock_bh(&c->lock); 119962306a36Sopenharmony_ci return rc; 120062306a36Sopenharmony_ci} 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_civoid tipc_crypto_key_flush(struct tipc_crypto *c) 120362306a36Sopenharmony_ci{ 120462306a36Sopenharmony_ci struct tipc_crypto *tx, *rx; 120562306a36Sopenharmony_ci int k; 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci spin_lock_bh(&c->lock); 120862306a36Sopenharmony_ci if (is_rx(c)) { 120962306a36Sopenharmony_ci /* Try to cancel pending work */ 121062306a36Sopenharmony_ci rx = c; 121162306a36Sopenharmony_ci tx = tipc_net(rx->net)->crypto_tx; 121262306a36Sopenharmony_ci if (cancel_delayed_work(&rx->work)) { 121362306a36Sopenharmony_ci kfree(rx->skey); 121462306a36Sopenharmony_ci rx->skey = NULL; 121562306a36Sopenharmony_ci atomic_xchg(&rx->key_distr, 0); 121662306a36Sopenharmony_ci tipc_node_put(rx->node); 121762306a36Sopenharmony_ci } 121862306a36Sopenharmony_ci /* RX stopping => decrease TX key users if any */ 121962306a36Sopenharmony_ci k = atomic_xchg(&rx->peer_rx_active, 0); 122062306a36Sopenharmony_ci if (k) { 122162306a36Sopenharmony_ci tipc_aead_users_dec(tx->aead[k], 0); 122262306a36Sopenharmony_ci /* Mark the point TX key users changed */ 122362306a36Sopenharmony_ci tx->timer1 = jiffies; 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci c->flags = 0; 122862306a36Sopenharmony_ci tipc_crypto_key_set_state(c, 0, 0, 0); 122962306a36Sopenharmony_ci for (k = KEY_MIN; k <= KEY_MAX; k++) 123062306a36Sopenharmony_ci tipc_crypto_key_detach(c->aead[k], &c->lock); 123162306a36Sopenharmony_ci atomic64_set(&c->sndnxt, 0); 123262306a36Sopenharmony_ci spin_unlock_bh(&c->lock); 123362306a36Sopenharmony_ci} 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci/** 123662306a36Sopenharmony_ci * tipc_crypto_key_try_align - Align RX keys if possible 123762306a36Sopenharmony_ci * @rx: RX crypto handle 123862306a36Sopenharmony_ci * @new_pending: new pending slot if aligned (= TX key from peer) 123962306a36Sopenharmony_ci * 124062306a36Sopenharmony_ci * Peer has used an unknown key slot, this only happens when peer has left and 124162306a36Sopenharmony_ci * rejoned, or we are newcomer. 124262306a36Sopenharmony_ci * That means, there must be no active key but a pending key at unaligned slot. 124362306a36Sopenharmony_ci * If so, we try to move the pending key to the new slot. 124462306a36Sopenharmony_ci * Note: A potential passive key can exist, it will be shifted correspondingly! 124562306a36Sopenharmony_ci * 124662306a36Sopenharmony_ci * Return: "true" if key is successfully aligned, otherwise "false" 124762306a36Sopenharmony_ci */ 124862306a36Sopenharmony_cistatic bool tipc_crypto_key_try_align(struct tipc_crypto *rx, u8 new_pending) 124962306a36Sopenharmony_ci{ 125062306a36Sopenharmony_ci struct tipc_aead *tmp1, *tmp2 = NULL; 125162306a36Sopenharmony_ci struct tipc_key key; 125262306a36Sopenharmony_ci bool aligned = false; 125362306a36Sopenharmony_ci u8 new_passive = 0; 125462306a36Sopenharmony_ci int x; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci spin_lock(&rx->lock); 125762306a36Sopenharmony_ci key = rx->key; 125862306a36Sopenharmony_ci if (key.pending == new_pending) { 125962306a36Sopenharmony_ci aligned = true; 126062306a36Sopenharmony_ci goto exit; 126162306a36Sopenharmony_ci } 126262306a36Sopenharmony_ci if (key.active) 126362306a36Sopenharmony_ci goto exit; 126462306a36Sopenharmony_ci if (!key.pending) 126562306a36Sopenharmony_ci goto exit; 126662306a36Sopenharmony_ci if (tipc_aead_users(rx->aead[key.pending]) > 0) 126762306a36Sopenharmony_ci goto exit; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci /* Try to "isolate" this pending key first */ 127062306a36Sopenharmony_ci tmp1 = tipc_aead_rcu_ptr(rx->aead[key.pending], &rx->lock); 127162306a36Sopenharmony_ci if (!refcount_dec_if_one(&tmp1->refcnt)) 127262306a36Sopenharmony_ci goto exit; 127362306a36Sopenharmony_ci rcu_assign_pointer(rx->aead[key.pending], NULL); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci /* Move passive key if any */ 127662306a36Sopenharmony_ci if (key.passive) { 127762306a36Sopenharmony_ci tmp2 = rcu_replace_pointer(rx->aead[key.passive], tmp2, lockdep_is_held(&rx->lock)); 127862306a36Sopenharmony_ci x = (key.passive - key.pending + new_pending) % KEY_MAX; 127962306a36Sopenharmony_ci new_passive = (x <= 0) ? x + KEY_MAX : x; 128062306a36Sopenharmony_ci } 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci /* Re-allocate the key(s) */ 128362306a36Sopenharmony_ci tipc_crypto_key_set_state(rx, new_passive, 0, new_pending); 128462306a36Sopenharmony_ci rcu_assign_pointer(rx->aead[new_pending], tmp1); 128562306a36Sopenharmony_ci if (new_passive) 128662306a36Sopenharmony_ci rcu_assign_pointer(rx->aead[new_passive], tmp2); 128762306a36Sopenharmony_ci refcount_set(&tmp1->refcnt, 1); 128862306a36Sopenharmony_ci aligned = true; 128962306a36Sopenharmony_ci pr_info_ratelimited("%s: key[%d] -> key[%d]\n", rx->name, key.pending, 129062306a36Sopenharmony_ci new_pending); 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ciexit: 129362306a36Sopenharmony_ci spin_unlock(&rx->lock); 129462306a36Sopenharmony_ci return aligned; 129562306a36Sopenharmony_ci} 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci/** 129862306a36Sopenharmony_ci * tipc_crypto_key_pick_tx - Pick one TX key for message decryption 129962306a36Sopenharmony_ci * @tx: TX crypto handle 130062306a36Sopenharmony_ci * @rx: RX crypto handle (can be NULL) 130162306a36Sopenharmony_ci * @skb: the message skb which will be decrypted later 130262306a36Sopenharmony_ci * @tx_key: peer TX key id 130362306a36Sopenharmony_ci * 130462306a36Sopenharmony_ci * This function looks up the existing TX keys and pick one which is suitable 130562306a36Sopenharmony_ci * for the message decryption, that must be a cluster key and not used before 130662306a36Sopenharmony_ci * on the same message (i.e. recursive). 130762306a36Sopenharmony_ci * 130862306a36Sopenharmony_ci * Return: the TX AEAD key handle in case of success, otherwise NULL 130962306a36Sopenharmony_ci */ 131062306a36Sopenharmony_cistatic struct tipc_aead *tipc_crypto_key_pick_tx(struct tipc_crypto *tx, 131162306a36Sopenharmony_ci struct tipc_crypto *rx, 131262306a36Sopenharmony_ci struct sk_buff *skb, 131362306a36Sopenharmony_ci u8 tx_key) 131462306a36Sopenharmony_ci{ 131562306a36Sopenharmony_ci struct tipc_skb_cb *skb_cb = TIPC_SKB_CB(skb); 131662306a36Sopenharmony_ci struct tipc_aead *aead = NULL; 131762306a36Sopenharmony_ci struct tipc_key key = tx->key; 131862306a36Sopenharmony_ci u8 k, i = 0; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci /* Initialize data if not yet */ 132162306a36Sopenharmony_ci if (!skb_cb->tx_clone_deferred) { 132262306a36Sopenharmony_ci skb_cb->tx_clone_deferred = 1; 132362306a36Sopenharmony_ci memset(&skb_cb->tx_clone_ctx, 0, sizeof(skb_cb->tx_clone_ctx)); 132462306a36Sopenharmony_ci } 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci skb_cb->tx_clone_ctx.rx = rx; 132762306a36Sopenharmony_ci if (++skb_cb->tx_clone_ctx.recurs > 2) 132862306a36Sopenharmony_ci return NULL; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci /* Pick one TX key */ 133162306a36Sopenharmony_ci spin_lock(&tx->lock); 133262306a36Sopenharmony_ci if (tx_key == KEY_MASTER) { 133362306a36Sopenharmony_ci aead = tipc_aead_rcu_ptr(tx->aead[KEY_MASTER], &tx->lock); 133462306a36Sopenharmony_ci goto done; 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci do { 133762306a36Sopenharmony_ci k = (i == 0) ? key.pending : 133862306a36Sopenharmony_ci ((i == 1) ? key.active : key.passive); 133962306a36Sopenharmony_ci if (!k) 134062306a36Sopenharmony_ci continue; 134162306a36Sopenharmony_ci aead = tipc_aead_rcu_ptr(tx->aead[k], &tx->lock); 134262306a36Sopenharmony_ci if (!aead) 134362306a36Sopenharmony_ci continue; 134462306a36Sopenharmony_ci if (aead->mode != CLUSTER_KEY || 134562306a36Sopenharmony_ci aead == skb_cb->tx_clone_ctx.last) { 134662306a36Sopenharmony_ci aead = NULL; 134762306a36Sopenharmony_ci continue; 134862306a36Sopenharmony_ci } 134962306a36Sopenharmony_ci /* Ok, found one cluster key */ 135062306a36Sopenharmony_ci skb_cb->tx_clone_ctx.last = aead; 135162306a36Sopenharmony_ci WARN_ON(skb->next); 135262306a36Sopenharmony_ci skb->next = skb_clone(skb, GFP_ATOMIC); 135362306a36Sopenharmony_ci if (unlikely(!skb->next)) 135462306a36Sopenharmony_ci pr_warn("Failed to clone skb for next round if any\n"); 135562306a36Sopenharmony_ci break; 135662306a36Sopenharmony_ci } while (++i < 3); 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_cidone: 135962306a36Sopenharmony_ci if (likely(aead)) 136062306a36Sopenharmony_ci WARN_ON(!refcount_inc_not_zero(&aead->refcnt)); 136162306a36Sopenharmony_ci spin_unlock(&tx->lock); 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci return aead; 136462306a36Sopenharmony_ci} 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci/** 136762306a36Sopenharmony_ci * tipc_crypto_key_synch: Synch own key data according to peer key status 136862306a36Sopenharmony_ci * @rx: RX crypto handle 136962306a36Sopenharmony_ci * @skb: TIPCv2 message buffer (incl. the ehdr from peer) 137062306a36Sopenharmony_ci * 137162306a36Sopenharmony_ci * This function updates the peer node related data as the peer RX active key 137262306a36Sopenharmony_ci * has changed, so the number of TX keys' users on this node are increased and 137362306a36Sopenharmony_ci * decreased correspondingly. 137462306a36Sopenharmony_ci * 137562306a36Sopenharmony_ci * It also considers if peer has no key, then we need to make own master key 137662306a36Sopenharmony_ci * (if any) taking over i.e. starting grace period and also trigger key 137762306a36Sopenharmony_ci * distributing process. 137862306a36Sopenharmony_ci * 137962306a36Sopenharmony_ci * The "per-peer" sndnxt is also reset when the peer key has switched. 138062306a36Sopenharmony_ci */ 138162306a36Sopenharmony_cistatic void tipc_crypto_key_synch(struct tipc_crypto *rx, struct sk_buff *skb) 138262306a36Sopenharmony_ci{ 138362306a36Sopenharmony_ci struct tipc_ehdr *ehdr = (struct tipc_ehdr *)skb_network_header(skb); 138462306a36Sopenharmony_ci struct tipc_crypto *tx = tipc_net(rx->net)->crypto_tx; 138562306a36Sopenharmony_ci struct tipc_msg *hdr = buf_msg(skb); 138662306a36Sopenharmony_ci u32 self = tipc_own_addr(rx->net); 138762306a36Sopenharmony_ci u8 cur, new; 138862306a36Sopenharmony_ci unsigned long delay; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci /* Update RX 'key_master' flag according to peer, also mark "legacy" if 139162306a36Sopenharmony_ci * a peer has no master key. 139262306a36Sopenharmony_ci */ 139362306a36Sopenharmony_ci rx->key_master = ehdr->master_key; 139462306a36Sopenharmony_ci if (!rx->key_master) 139562306a36Sopenharmony_ci tx->legacy_user = 1; 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci /* For later cases, apply only if message is destined to this node */ 139862306a36Sopenharmony_ci if (!ehdr->destined || msg_short(hdr) || msg_destnode(hdr) != self) 139962306a36Sopenharmony_ci return; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci /* Case 1: Peer has no keys, let's make master key take over */ 140262306a36Sopenharmony_ci if (ehdr->rx_nokey) { 140362306a36Sopenharmony_ci /* Set or extend grace period */ 140462306a36Sopenharmony_ci tx->timer2 = jiffies; 140562306a36Sopenharmony_ci /* Schedule key distributing for the peer if not yet */ 140662306a36Sopenharmony_ci if (tx->key.keys && 140762306a36Sopenharmony_ci !atomic_cmpxchg(&rx->key_distr, 0, KEY_DISTR_SCHED)) { 140862306a36Sopenharmony_ci get_random_bytes(&delay, 2); 140962306a36Sopenharmony_ci delay %= 5; 141062306a36Sopenharmony_ci delay = msecs_to_jiffies(500 * ++delay); 141162306a36Sopenharmony_ci if (queue_delayed_work(tx->wq, &rx->work, delay)) 141262306a36Sopenharmony_ci tipc_node_get(rx->node); 141362306a36Sopenharmony_ci } 141462306a36Sopenharmony_ci } else { 141562306a36Sopenharmony_ci /* Cancel a pending key distributing if any */ 141662306a36Sopenharmony_ci atomic_xchg(&rx->key_distr, 0); 141762306a36Sopenharmony_ci } 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci /* Case 2: Peer RX active key has changed, let's update own TX users */ 142062306a36Sopenharmony_ci cur = atomic_read(&rx->peer_rx_active); 142162306a36Sopenharmony_ci new = ehdr->rx_key_active; 142262306a36Sopenharmony_ci if (tx->key.keys && 142362306a36Sopenharmony_ci cur != new && 142462306a36Sopenharmony_ci atomic_cmpxchg(&rx->peer_rx_active, cur, new) == cur) { 142562306a36Sopenharmony_ci if (new) 142662306a36Sopenharmony_ci tipc_aead_users_inc(tx->aead[new], INT_MAX); 142762306a36Sopenharmony_ci if (cur) 142862306a36Sopenharmony_ci tipc_aead_users_dec(tx->aead[cur], 0); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci atomic64_set(&rx->sndnxt, 0); 143162306a36Sopenharmony_ci /* Mark the point TX key users changed */ 143262306a36Sopenharmony_ci tx->timer1 = jiffies; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci pr_debug("%s: key users changed %d-- %d++, peer %s\n", 143562306a36Sopenharmony_ci tx->name, cur, new, rx->name); 143662306a36Sopenharmony_ci } 143762306a36Sopenharmony_ci} 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_cistatic int tipc_crypto_key_revoke(struct net *net, u8 tx_key) 144062306a36Sopenharmony_ci{ 144162306a36Sopenharmony_ci struct tipc_crypto *tx = tipc_net(net)->crypto_tx; 144262306a36Sopenharmony_ci struct tipc_key key; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci spin_lock_bh(&tx->lock); 144562306a36Sopenharmony_ci key = tx->key; 144662306a36Sopenharmony_ci WARN_ON(!key.active || tx_key != key.active); 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci /* Free the active key */ 144962306a36Sopenharmony_ci tipc_crypto_key_set_state(tx, key.passive, 0, key.pending); 145062306a36Sopenharmony_ci tipc_crypto_key_detach(tx->aead[key.active], &tx->lock); 145162306a36Sopenharmony_ci spin_unlock_bh(&tx->lock); 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci pr_warn("%s: key is revoked\n", tx->name); 145462306a36Sopenharmony_ci return -EKEYREVOKED; 145562306a36Sopenharmony_ci} 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ciint tipc_crypto_start(struct tipc_crypto **crypto, struct net *net, 145862306a36Sopenharmony_ci struct tipc_node *node) 145962306a36Sopenharmony_ci{ 146062306a36Sopenharmony_ci struct tipc_crypto *c; 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci if (*crypto) 146362306a36Sopenharmony_ci return -EEXIST; 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci /* Allocate crypto */ 146662306a36Sopenharmony_ci c = kzalloc(sizeof(*c), GFP_ATOMIC); 146762306a36Sopenharmony_ci if (!c) 146862306a36Sopenharmony_ci return -ENOMEM; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci /* Allocate workqueue on TX */ 147162306a36Sopenharmony_ci if (!node) { 147262306a36Sopenharmony_ci c->wq = alloc_ordered_workqueue("tipc_crypto", 0); 147362306a36Sopenharmony_ci if (!c->wq) { 147462306a36Sopenharmony_ci kfree(c); 147562306a36Sopenharmony_ci return -ENOMEM; 147662306a36Sopenharmony_ci } 147762306a36Sopenharmony_ci } 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci /* Allocate statistic structure */ 148062306a36Sopenharmony_ci c->stats = alloc_percpu_gfp(struct tipc_crypto_stats, GFP_ATOMIC); 148162306a36Sopenharmony_ci if (!c->stats) { 148262306a36Sopenharmony_ci if (c->wq) 148362306a36Sopenharmony_ci destroy_workqueue(c->wq); 148462306a36Sopenharmony_ci kfree_sensitive(c); 148562306a36Sopenharmony_ci return -ENOMEM; 148662306a36Sopenharmony_ci } 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci c->flags = 0; 148962306a36Sopenharmony_ci c->net = net; 149062306a36Sopenharmony_ci c->node = node; 149162306a36Sopenharmony_ci get_random_bytes(&c->key_gen, 2); 149262306a36Sopenharmony_ci tipc_crypto_key_set_state(c, 0, 0, 0); 149362306a36Sopenharmony_ci atomic_set(&c->key_distr, 0); 149462306a36Sopenharmony_ci atomic_set(&c->peer_rx_active, 0); 149562306a36Sopenharmony_ci atomic64_set(&c->sndnxt, 0); 149662306a36Sopenharmony_ci c->timer1 = jiffies; 149762306a36Sopenharmony_ci c->timer2 = jiffies; 149862306a36Sopenharmony_ci c->rekeying_intv = TIPC_REKEYING_INTV_DEF; 149962306a36Sopenharmony_ci spin_lock_init(&c->lock); 150062306a36Sopenharmony_ci scnprintf(c->name, 48, "%s(%s)", (is_rx(c)) ? "RX" : "TX", 150162306a36Sopenharmony_ci (is_rx(c)) ? tipc_node_get_id_str(c->node) : 150262306a36Sopenharmony_ci tipc_own_id_string(c->net)); 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci if (is_rx(c)) 150562306a36Sopenharmony_ci INIT_DELAYED_WORK(&c->work, tipc_crypto_work_rx); 150662306a36Sopenharmony_ci else 150762306a36Sopenharmony_ci INIT_DELAYED_WORK(&c->work, tipc_crypto_work_tx); 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci *crypto = c; 151062306a36Sopenharmony_ci return 0; 151162306a36Sopenharmony_ci} 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_civoid tipc_crypto_stop(struct tipc_crypto **crypto) 151462306a36Sopenharmony_ci{ 151562306a36Sopenharmony_ci struct tipc_crypto *c = *crypto; 151662306a36Sopenharmony_ci u8 k; 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci if (!c) 151962306a36Sopenharmony_ci return; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci /* Flush any queued works & destroy wq */ 152262306a36Sopenharmony_ci if (is_tx(c)) { 152362306a36Sopenharmony_ci c->rekeying_intv = 0; 152462306a36Sopenharmony_ci cancel_delayed_work_sync(&c->work); 152562306a36Sopenharmony_ci destroy_workqueue(c->wq); 152662306a36Sopenharmony_ci } 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci /* Release AEAD keys */ 152962306a36Sopenharmony_ci rcu_read_lock(); 153062306a36Sopenharmony_ci for (k = KEY_MIN; k <= KEY_MAX; k++) 153162306a36Sopenharmony_ci tipc_aead_put(rcu_dereference(c->aead[k])); 153262306a36Sopenharmony_ci rcu_read_unlock(); 153362306a36Sopenharmony_ci pr_debug("%s: has been stopped\n", c->name); 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci /* Free this crypto statistics */ 153662306a36Sopenharmony_ci free_percpu(c->stats); 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci *crypto = NULL; 153962306a36Sopenharmony_ci kfree_sensitive(c); 154062306a36Sopenharmony_ci} 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_civoid tipc_crypto_timeout(struct tipc_crypto *rx) 154362306a36Sopenharmony_ci{ 154462306a36Sopenharmony_ci struct tipc_net *tn = tipc_net(rx->net); 154562306a36Sopenharmony_ci struct tipc_crypto *tx = tn->crypto_tx; 154662306a36Sopenharmony_ci struct tipc_key key; 154762306a36Sopenharmony_ci int cmd; 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci /* TX pending: taking all users & stable -> active */ 155062306a36Sopenharmony_ci spin_lock(&tx->lock); 155162306a36Sopenharmony_ci key = tx->key; 155262306a36Sopenharmony_ci if (key.active && tipc_aead_users(tx->aead[key.active]) > 0) 155362306a36Sopenharmony_ci goto s1; 155462306a36Sopenharmony_ci if (!key.pending || tipc_aead_users(tx->aead[key.pending]) <= 0) 155562306a36Sopenharmony_ci goto s1; 155662306a36Sopenharmony_ci if (time_before(jiffies, tx->timer1 + TIPC_TX_LASTING_TIME)) 155762306a36Sopenharmony_ci goto s1; 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci tipc_crypto_key_set_state(tx, key.passive, key.pending, 0); 156062306a36Sopenharmony_ci if (key.active) 156162306a36Sopenharmony_ci tipc_crypto_key_detach(tx->aead[key.active], &tx->lock); 156262306a36Sopenharmony_ci this_cpu_inc(tx->stats->stat[STAT_SWITCHES]); 156362306a36Sopenharmony_ci pr_info("%s: key[%d] is activated\n", tx->name, key.pending); 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_cis1: 156662306a36Sopenharmony_ci spin_unlock(&tx->lock); 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci /* RX pending: having user -> active */ 156962306a36Sopenharmony_ci spin_lock(&rx->lock); 157062306a36Sopenharmony_ci key = rx->key; 157162306a36Sopenharmony_ci if (!key.pending || tipc_aead_users(rx->aead[key.pending]) <= 0) 157262306a36Sopenharmony_ci goto s2; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci if (key.active) 157562306a36Sopenharmony_ci key.passive = key.active; 157662306a36Sopenharmony_ci key.active = key.pending; 157762306a36Sopenharmony_ci rx->timer2 = jiffies; 157862306a36Sopenharmony_ci tipc_crypto_key_set_state(rx, key.passive, key.active, 0); 157962306a36Sopenharmony_ci this_cpu_inc(rx->stats->stat[STAT_SWITCHES]); 158062306a36Sopenharmony_ci pr_info("%s: key[%d] is activated\n", rx->name, key.pending); 158162306a36Sopenharmony_ci goto s5; 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_cis2: 158462306a36Sopenharmony_ci /* RX pending: not working -> remove */ 158562306a36Sopenharmony_ci if (!key.pending || tipc_aead_users(rx->aead[key.pending]) > -10) 158662306a36Sopenharmony_ci goto s3; 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci tipc_crypto_key_set_state(rx, key.passive, key.active, 0); 158962306a36Sopenharmony_ci tipc_crypto_key_detach(rx->aead[key.pending], &rx->lock); 159062306a36Sopenharmony_ci pr_debug("%s: key[%d] is removed\n", rx->name, key.pending); 159162306a36Sopenharmony_ci goto s5; 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_cis3: 159462306a36Sopenharmony_ci /* RX active: timed out or no user -> pending */ 159562306a36Sopenharmony_ci if (!key.active) 159662306a36Sopenharmony_ci goto s4; 159762306a36Sopenharmony_ci if (time_before(jiffies, rx->timer1 + TIPC_RX_ACTIVE_LIM) && 159862306a36Sopenharmony_ci tipc_aead_users(rx->aead[key.active]) > 0) 159962306a36Sopenharmony_ci goto s4; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci if (key.pending) 160262306a36Sopenharmony_ci key.passive = key.active; 160362306a36Sopenharmony_ci else 160462306a36Sopenharmony_ci key.pending = key.active; 160562306a36Sopenharmony_ci rx->timer2 = jiffies; 160662306a36Sopenharmony_ci tipc_crypto_key_set_state(rx, key.passive, 0, key.pending); 160762306a36Sopenharmony_ci tipc_aead_users_set(rx->aead[key.pending], 0); 160862306a36Sopenharmony_ci pr_debug("%s: key[%d] is deactivated\n", rx->name, key.active); 160962306a36Sopenharmony_ci goto s5; 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_cis4: 161262306a36Sopenharmony_ci /* RX passive: outdated or not working -> free */ 161362306a36Sopenharmony_ci if (!key.passive) 161462306a36Sopenharmony_ci goto s5; 161562306a36Sopenharmony_ci if (time_before(jiffies, rx->timer2 + TIPC_RX_PASSIVE_LIM) && 161662306a36Sopenharmony_ci tipc_aead_users(rx->aead[key.passive]) > -10) 161762306a36Sopenharmony_ci goto s5; 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci tipc_crypto_key_set_state(rx, 0, key.active, key.pending); 162062306a36Sopenharmony_ci tipc_crypto_key_detach(rx->aead[key.passive], &rx->lock); 162162306a36Sopenharmony_ci pr_debug("%s: key[%d] is freed\n", rx->name, key.passive); 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_cis5: 162462306a36Sopenharmony_ci spin_unlock(&rx->lock); 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci /* Relax it here, the flag will be set again if it really is, but only 162762306a36Sopenharmony_ci * when we are not in grace period for safety! 162862306a36Sopenharmony_ci */ 162962306a36Sopenharmony_ci if (time_after(jiffies, tx->timer2 + TIPC_TX_GRACE_PERIOD)) 163062306a36Sopenharmony_ci tx->legacy_user = 0; 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci /* Limit max_tfms & do debug commands if needed */ 163362306a36Sopenharmony_ci if (likely(sysctl_tipc_max_tfms <= TIPC_MAX_TFMS_LIM)) 163462306a36Sopenharmony_ci return; 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci cmd = sysctl_tipc_max_tfms; 163762306a36Sopenharmony_ci sysctl_tipc_max_tfms = TIPC_MAX_TFMS_DEF; 163862306a36Sopenharmony_ci tipc_crypto_do_cmd(rx->net, cmd); 163962306a36Sopenharmony_ci} 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_cistatic inline void tipc_crypto_clone_msg(struct net *net, struct sk_buff *_skb, 164262306a36Sopenharmony_ci struct tipc_bearer *b, 164362306a36Sopenharmony_ci struct tipc_media_addr *dst, 164462306a36Sopenharmony_ci struct tipc_node *__dnode, u8 type) 164562306a36Sopenharmony_ci{ 164662306a36Sopenharmony_ci struct sk_buff *skb; 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci skb = skb_clone(_skb, GFP_ATOMIC); 164962306a36Sopenharmony_ci if (skb) { 165062306a36Sopenharmony_ci TIPC_SKB_CB(skb)->xmit_type = type; 165162306a36Sopenharmony_ci tipc_crypto_xmit(net, &skb, b, dst, __dnode); 165262306a36Sopenharmony_ci if (skb) 165362306a36Sopenharmony_ci b->media->send_msg(net, skb, b, dst); 165462306a36Sopenharmony_ci } 165562306a36Sopenharmony_ci} 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci/** 165862306a36Sopenharmony_ci * tipc_crypto_xmit - Build & encrypt TIPC message for xmit 165962306a36Sopenharmony_ci * @net: struct net 166062306a36Sopenharmony_ci * @skb: input/output message skb pointer 166162306a36Sopenharmony_ci * @b: bearer used for xmit later 166262306a36Sopenharmony_ci * @dst: destination media address 166362306a36Sopenharmony_ci * @__dnode: destination node for reference if any 166462306a36Sopenharmony_ci * 166562306a36Sopenharmony_ci * First, build an encryption message header on the top of the message, then 166662306a36Sopenharmony_ci * encrypt the original TIPC message by using the pending, master or active 166762306a36Sopenharmony_ci * key with this preference order. 166862306a36Sopenharmony_ci * If the encryption is successful, the encrypted skb is returned directly or 166962306a36Sopenharmony_ci * via the callback. 167062306a36Sopenharmony_ci * Otherwise, the skb is freed! 167162306a36Sopenharmony_ci * 167262306a36Sopenharmony_ci * Return: 167362306a36Sopenharmony_ci * * 0 : the encryption has succeeded (or no encryption) 167462306a36Sopenharmony_ci * * -EINPROGRESS/-EBUSY : the encryption is ongoing, a callback will be made 167562306a36Sopenharmony_ci * * -ENOKEK : the encryption has failed due to no key 167662306a36Sopenharmony_ci * * -EKEYREVOKED : the encryption has failed due to key revoked 167762306a36Sopenharmony_ci * * -ENOMEM : the encryption has failed due to no memory 167862306a36Sopenharmony_ci * * < 0 : the encryption has failed due to other reasons 167962306a36Sopenharmony_ci */ 168062306a36Sopenharmony_ciint tipc_crypto_xmit(struct net *net, struct sk_buff **skb, 168162306a36Sopenharmony_ci struct tipc_bearer *b, struct tipc_media_addr *dst, 168262306a36Sopenharmony_ci struct tipc_node *__dnode) 168362306a36Sopenharmony_ci{ 168462306a36Sopenharmony_ci struct tipc_crypto *__rx = tipc_node_crypto_rx(__dnode); 168562306a36Sopenharmony_ci struct tipc_crypto *tx = tipc_net(net)->crypto_tx; 168662306a36Sopenharmony_ci struct tipc_crypto_stats __percpu *stats = tx->stats; 168762306a36Sopenharmony_ci struct tipc_msg *hdr = buf_msg(*skb); 168862306a36Sopenharmony_ci struct tipc_key key = tx->key; 168962306a36Sopenharmony_ci struct tipc_aead *aead = NULL; 169062306a36Sopenharmony_ci u32 user = msg_user(hdr); 169162306a36Sopenharmony_ci u32 type = msg_type(hdr); 169262306a36Sopenharmony_ci int rc = -ENOKEY; 169362306a36Sopenharmony_ci u8 tx_key = 0; 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci /* No encryption? */ 169662306a36Sopenharmony_ci if (!tx->working) 169762306a36Sopenharmony_ci return 0; 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci /* Pending key if peer has active on it or probing time */ 170062306a36Sopenharmony_ci if (unlikely(key.pending)) { 170162306a36Sopenharmony_ci tx_key = key.pending; 170262306a36Sopenharmony_ci if (!tx->key_master && !key.active) 170362306a36Sopenharmony_ci goto encrypt; 170462306a36Sopenharmony_ci if (__rx && atomic_read(&__rx->peer_rx_active) == tx_key) 170562306a36Sopenharmony_ci goto encrypt; 170662306a36Sopenharmony_ci if (TIPC_SKB_CB(*skb)->xmit_type == SKB_PROBING) { 170762306a36Sopenharmony_ci pr_debug("%s: probing for key[%d]\n", tx->name, 170862306a36Sopenharmony_ci key.pending); 170962306a36Sopenharmony_ci goto encrypt; 171062306a36Sopenharmony_ci } 171162306a36Sopenharmony_ci if (user == LINK_CONFIG || user == LINK_PROTOCOL) 171262306a36Sopenharmony_ci tipc_crypto_clone_msg(net, *skb, b, dst, __dnode, 171362306a36Sopenharmony_ci SKB_PROBING); 171462306a36Sopenharmony_ci } 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci /* Master key if this is a *vital* message or in grace period */ 171762306a36Sopenharmony_ci if (tx->key_master) { 171862306a36Sopenharmony_ci tx_key = KEY_MASTER; 171962306a36Sopenharmony_ci if (!key.active) 172062306a36Sopenharmony_ci goto encrypt; 172162306a36Sopenharmony_ci if (TIPC_SKB_CB(*skb)->xmit_type == SKB_GRACING) { 172262306a36Sopenharmony_ci pr_debug("%s: gracing for msg (%d %d)\n", tx->name, 172362306a36Sopenharmony_ci user, type); 172462306a36Sopenharmony_ci goto encrypt; 172562306a36Sopenharmony_ci } 172662306a36Sopenharmony_ci if (user == LINK_CONFIG || 172762306a36Sopenharmony_ci (user == LINK_PROTOCOL && type == RESET_MSG) || 172862306a36Sopenharmony_ci (user == MSG_CRYPTO && type == KEY_DISTR_MSG) || 172962306a36Sopenharmony_ci time_before(jiffies, tx->timer2 + TIPC_TX_GRACE_PERIOD)) { 173062306a36Sopenharmony_ci if (__rx && __rx->key_master && 173162306a36Sopenharmony_ci !atomic_read(&__rx->peer_rx_active)) 173262306a36Sopenharmony_ci goto encrypt; 173362306a36Sopenharmony_ci if (!__rx) { 173462306a36Sopenharmony_ci if (likely(!tx->legacy_user)) 173562306a36Sopenharmony_ci goto encrypt; 173662306a36Sopenharmony_ci tipc_crypto_clone_msg(net, *skb, b, dst, 173762306a36Sopenharmony_ci __dnode, SKB_GRACING); 173862306a36Sopenharmony_ci } 173962306a36Sopenharmony_ci } 174062306a36Sopenharmony_ci } 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci /* Else, use the active key if any */ 174362306a36Sopenharmony_ci if (likely(key.active)) { 174462306a36Sopenharmony_ci tx_key = key.active; 174562306a36Sopenharmony_ci goto encrypt; 174662306a36Sopenharmony_ci } 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci goto exit; 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ciencrypt: 175162306a36Sopenharmony_ci aead = tipc_aead_get(tx->aead[tx_key]); 175262306a36Sopenharmony_ci if (unlikely(!aead)) 175362306a36Sopenharmony_ci goto exit; 175462306a36Sopenharmony_ci rc = tipc_ehdr_build(net, aead, tx_key, *skb, __rx); 175562306a36Sopenharmony_ci if (likely(rc > 0)) 175662306a36Sopenharmony_ci rc = tipc_aead_encrypt(aead, *skb, b, dst, __dnode); 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ciexit: 175962306a36Sopenharmony_ci switch (rc) { 176062306a36Sopenharmony_ci case 0: 176162306a36Sopenharmony_ci this_cpu_inc(stats->stat[STAT_OK]); 176262306a36Sopenharmony_ci break; 176362306a36Sopenharmony_ci case -EINPROGRESS: 176462306a36Sopenharmony_ci case -EBUSY: 176562306a36Sopenharmony_ci this_cpu_inc(stats->stat[STAT_ASYNC]); 176662306a36Sopenharmony_ci *skb = NULL; 176762306a36Sopenharmony_ci return rc; 176862306a36Sopenharmony_ci default: 176962306a36Sopenharmony_ci this_cpu_inc(stats->stat[STAT_NOK]); 177062306a36Sopenharmony_ci if (rc == -ENOKEY) 177162306a36Sopenharmony_ci this_cpu_inc(stats->stat[STAT_NOKEYS]); 177262306a36Sopenharmony_ci else if (rc == -EKEYREVOKED) 177362306a36Sopenharmony_ci this_cpu_inc(stats->stat[STAT_BADKEYS]); 177462306a36Sopenharmony_ci kfree_skb(*skb); 177562306a36Sopenharmony_ci *skb = NULL; 177662306a36Sopenharmony_ci break; 177762306a36Sopenharmony_ci } 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci tipc_aead_put(aead); 178062306a36Sopenharmony_ci return rc; 178162306a36Sopenharmony_ci} 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci/** 178462306a36Sopenharmony_ci * tipc_crypto_rcv - Decrypt an encrypted TIPC message from peer 178562306a36Sopenharmony_ci * @net: struct net 178662306a36Sopenharmony_ci * @rx: RX crypto handle 178762306a36Sopenharmony_ci * @skb: input/output message skb pointer 178862306a36Sopenharmony_ci * @b: bearer where the message has been received 178962306a36Sopenharmony_ci * 179062306a36Sopenharmony_ci * If the decryption is successful, the decrypted skb is returned directly or 179162306a36Sopenharmony_ci * as the callback, the encryption header and auth tag will be trimed out 179262306a36Sopenharmony_ci * before forwarding to tipc_rcv() via the tipc_crypto_rcv_complete(). 179362306a36Sopenharmony_ci * Otherwise, the skb will be freed! 179462306a36Sopenharmony_ci * Note: RX key(s) can be re-aligned, or in case of no key suitable, TX 179562306a36Sopenharmony_ci * cluster key(s) can be taken for decryption (- recursive). 179662306a36Sopenharmony_ci * 179762306a36Sopenharmony_ci * Return: 179862306a36Sopenharmony_ci * * 0 : the decryption has successfully completed 179962306a36Sopenharmony_ci * * -EINPROGRESS/-EBUSY : the decryption is ongoing, a callback will be made 180062306a36Sopenharmony_ci * * -ENOKEY : the decryption has failed due to no key 180162306a36Sopenharmony_ci * * -EBADMSG : the decryption has failed due to bad message 180262306a36Sopenharmony_ci * * -ENOMEM : the decryption has failed due to no memory 180362306a36Sopenharmony_ci * * < 0 : the decryption has failed due to other reasons 180462306a36Sopenharmony_ci */ 180562306a36Sopenharmony_ciint tipc_crypto_rcv(struct net *net, struct tipc_crypto *rx, 180662306a36Sopenharmony_ci struct sk_buff **skb, struct tipc_bearer *b) 180762306a36Sopenharmony_ci{ 180862306a36Sopenharmony_ci struct tipc_crypto *tx = tipc_net(net)->crypto_tx; 180962306a36Sopenharmony_ci struct tipc_crypto_stats __percpu *stats; 181062306a36Sopenharmony_ci struct tipc_aead *aead = NULL; 181162306a36Sopenharmony_ci struct tipc_key key; 181262306a36Sopenharmony_ci int rc = -ENOKEY; 181362306a36Sopenharmony_ci u8 tx_key, n; 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci tx_key = ((struct tipc_ehdr *)(*skb)->data)->tx_key; 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci /* New peer? 181862306a36Sopenharmony_ci * Let's try with TX key (i.e. cluster mode) & verify the skb first! 181962306a36Sopenharmony_ci */ 182062306a36Sopenharmony_ci if (unlikely(!rx || tx_key == KEY_MASTER)) 182162306a36Sopenharmony_ci goto pick_tx; 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci /* Pick RX key according to TX key if any */ 182462306a36Sopenharmony_ci key = rx->key; 182562306a36Sopenharmony_ci if (tx_key == key.active || tx_key == key.pending || 182662306a36Sopenharmony_ci tx_key == key.passive) 182762306a36Sopenharmony_ci goto decrypt; 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ci /* Unknown key, let's try to align RX key(s) */ 183062306a36Sopenharmony_ci if (tipc_crypto_key_try_align(rx, tx_key)) 183162306a36Sopenharmony_ci goto decrypt; 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_cipick_tx: 183462306a36Sopenharmony_ci /* No key suitable? Try to pick one from TX... */ 183562306a36Sopenharmony_ci aead = tipc_crypto_key_pick_tx(tx, rx, *skb, tx_key); 183662306a36Sopenharmony_ci if (aead) 183762306a36Sopenharmony_ci goto decrypt; 183862306a36Sopenharmony_ci goto exit; 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_cidecrypt: 184162306a36Sopenharmony_ci rcu_read_lock(); 184262306a36Sopenharmony_ci if (!aead) 184362306a36Sopenharmony_ci aead = tipc_aead_get(rx->aead[tx_key]); 184462306a36Sopenharmony_ci rc = tipc_aead_decrypt(net, aead, *skb, b); 184562306a36Sopenharmony_ci rcu_read_unlock(); 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ciexit: 184862306a36Sopenharmony_ci stats = ((rx) ?: tx)->stats; 184962306a36Sopenharmony_ci switch (rc) { 185062306a36Sopenharmony_ci case 0: 185162306a36Sopenharmony_ci this_cpu_inc(stats->stat[STAT_OK]); 185262306a36Sopenharmony_ci break; 185362306a36Sopenharmony_ci case -EINPROGRESS: 185462306a36Sopenharmony_ci case -EBUSY: 185562306a36Sopenharmony_ci this_cpu_inc(stats->stat[STAT_ASYNC]); 185662306a36Sopenharmony_ci *skb = NULL; 185762306a36Sopenharmony_ci return rc; 185862306a36Sopenharmony_ci default: 185962306a36Sopenharmony_ci this_cpu_inc(stats->stat[STAT_NOK]); 186062306a36Sopenharmony_ci if (rc == -ENOKEY) { 186162306a36Sopenharmony_ci kfree_skb(*skb); 186262306a36Sopenharmony_ci *skb = NULL; 186362306a36Sopenharmony_ci if (rx) { 186462306a36Sopenharmony_ci /* Mark rx->nokey only if we dont have a 186562306a36Sopenharmony_ci * pending received session key, nor a newer 186662306a36Sopenharmony_ci * one i.e. in the next slot. 186762306a36Sopenharmony_ci */ 186862306a36Sopenharmony_ci n = key_next(tx_key); 186962306a36Sopenharmony_ci rx->nokey = !(rx->skey || 187062306a36Sopenharmony_ci rcu_access_pointer(rx->aead[n])); 187162306a36Sopenharmony_ci pr_debug_ratelimited("%s: nokey %d, key %d/%x\n", 187262306a36Sopenharmony_ci rx->name, rx->nokey, 187362306a36Sopenharmony_ci tx_key, rx->key.keys); 187462306a36Sopenharmony_ci tipc_node_put(rx->node); 187562306a36Sopenharmony_ci } 187662306a36Sopenharmony_ci this_cpu_inc(stats->stat[STAT_NOKEYS]); 187762306a36Sopenharmony_ci return rc; 187862306a36Sopenharmony_ci } else if (rc == -EBADMSG) { 187962306a36Sopenharmony_ci this_cpu_inc(stats->stat[STAT_BADMSGS]); 188062306a36Sopenharmony_ci } 188162306a36Sopenharmony_ci break; 188262306a36Sopenharmony_ci } 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci tipc_crypto_rcv_complete(net, aead, b, skb, rc); 188562306a36Sopenharmony_ci return rc; 188662306a36Sopenharmony_ci} 188762306a36Sopenharmony_ci 188862306a36Sopenharmony_cistatic void tipc_crypto_rcv_complete(struct net *net, struct tipc_aead *aead, 188962306a36Sopenharmony_ci struct tipc_bearer *b, 189062306a36Sopenharmony_ci struct sk_buff **skb, int err) 189162306a36Sopenharmony_ci{ 189262306a36Sopenharmony_ci struct tipc_skb_cb *skb_cb = TIPC_SKB_CB(*skb); 189362306a36Sopenharmony_ci struct tipc_crypto *rx = aead->crypto; 189462306a36Sopenharmony_ci struct tipc_aead *tmp = NULL; 189562306a36Sopenharmony_ci struct tipc_ehdr *ehdr; 189662306a36Sopenharmony_ci struct tipc_node *n; 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci /* Is this completed by TX? */ 189962306a36Sopenharmony_ci if (unlikely(is_tx(aead->crypto))) { 190062306a36Sopenharmony_ci rx = skb_cb->tx_clone_ctx.rx; 190162306a36Sopenharmony_ci pr_debug("TX->RX(%s): err %d, aead %p, skb->next %p, flags %x\n", 190262306a36Sopenharmony_ci (rx) ? tipc_node_get_id_str(rx->node) : "-", err, aead, 190362306a36Sopenharmony_ci (*skb)->next, skb_cb->flags); 190462306a36Sopenharmony_ci pr_debug("skb_cb [recurs %d, last %p], tx->aead [%p %p %p]\n", 190562306a36Sopenharmony_ci skb_cb->tx_clone_ctx.recurs, skb_cb->tx_clone_ctx.last, 190662306a36Sopenharmony_ci aead->crypto->aead[1], aead->crypto->aead[2], 190762306a36Sopenharmony_ci aead->crypto->aead[3]); 190862306a36Sopenharmony_ci if (unlikely(err)) { 190962306a36Sopenharmony_ci if (err == -EBADMSG && (*skb)->next) 191062306a36Sopenharmony_ci tipc_rcv(net, (*skb)->next, b); 191162306a36Sopenharmony_ci goto free_skb; 191262306a36Sopenharmony_ci } 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci if (likely((*skb)->next)) { 191562306a36Sopenharmony_ci kfree_skb((*skb)->next); 191662306a36Sopenharmony_ci (*skb)->next = NULL; 191762306a36Sopenharmony_ci } 191862306a36Sopenharmony_ci ehdr = (struct tipc_ehdr *)(*skb)->data; 191962306a36Sopenharmony_ci if (!rx) { 192062306a36Sopenharmony_ci WARN_ON(ehdr->user != LINK_CONFIG); 192162306a36Sopenharmony_ci n = tipc_node_create(net, 0, ehdr->id, 0xffffu, 0, 192262306a36Sopenharmony_ci true); 192362306a36Sopenharmony_ci rx = tipc_node_crypto_rx(n); 192462306a36Sopenharmony_ci if (unlikely(!rx)) 192562306a36Sopenharmony_ci goto free_skb; 192662306a36Sopenharmony_ci } 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci /* Ignore cloning if it was TX master key */ 192962306a36Sopenharmony_ci if (ehdr->tx_key == KEY_MASTER) 193062306a36Sopenharmony_ci goto rcv; 193162306a36Sopenharmony_ci if (tipc_aead_clone(&tmp, aead) < 0) 193262306a36Sopenharmony_ci goto rcv; 193362306a36Sopenharmony_ci WARN_ON(!refcount_inc_not_zero(&tmp->refcnt)); 193462306a36Sopenharmony_ci if (tipc_crypto_key_attach(rx, tmp, ehdr->tx_key, false) < 0) { 193562306a36Sopenharmony_ci tipc_aead_free(&tmp->rcu); 193662306a36Sopenharmony_ci goto rcv; 193762306a36Sopenharmony_ci } 193862306a36Sopenharmony_ci tipc_aead_put(aead); 193962306a36Sopenharmony_ci aead = tmp; 194062306a36Sopenharmony_ci } 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci if (unlikely(err)) { 194362306a36Sopenharmony_ci tipc_aead_users_dec((struct tipc_aead __force __rcu *)aead, INT_MIN); 194462306a36Sopenharmony_ci goto free_skb; 194562306a36Sopenharmony_ci } 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci /* Set the RX key's user */ 194862306a36Sopenharmony_ci tipc_aead_users_set((struct tipc_aead __force __rcu *)aead, 1); 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci /* Mark this point, RX works */ 195162306a36Sopenharmony_ci rx->timer1 = jiffies; 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_circv: 195462306a36Sopenharmony_ci /* Remove ehdr & auth. tag prior to tipc_rcv() */ 195562306a36Sopenharmony_ci ehdr = (struct tipc_ehdr *)(*skb)->data; 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci /* Mark this point, RX passive still works */ 195862306a36Sopenharmony_ci if (rx->key.passive && ehdr->tx_key == rx->key.passive) 195962306a36Sopenharmony_ci rx->timer2 = jiffies; 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci skb_reset_network_header(*skb); 196262306a36Sopenharmony_ci skb_pull(*skb, tipc_ehdr_size(ehdr)); 196362306a36Sopenharmony_ci if (pskb_trim(*skb, (*skb)->len - aead->authsize)) 196462306a36Sopenharmony_ci goto free_skb; 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci /* Validate TIPCv2 message */ 196762306a36Sopenharmony_ci if (unlikely(!tipc_msg_validate(skb))) { 196862306a36Sopenharmony_ci pr_err_ratelimited("Packet dropped after decryption!\n"); 196962306a36Sopenharmony_ci goto free_skb; 197062306a36Sopenharmony_ci } 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci /* Ok, everything's fine, try to synch own keys according to peers' */ 197362306a36Sopenharmony_ci tipc_crypto_key_synch(rx, *skb); 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ci /* Re-fetch skb cb as skb might be changed in tipc_msg_validate */ 197662306a36Sopenharmony_ci skb_cb = TIPC_SKB_CB(*skb); 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci /* Mark skb decrypted */ 197962306a36Sopenharmony_ci skb_cb->decrypted = 1; 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci /* Clear clone cxt if any */ 198262306a36Sopenharmony_ci if (likely(!skb_cb->tx_clone_deferred)) 198362306a36Sopenharmony_ci goto exit; 198462306a36Sopenharmony_ci skb_cb->tx_clone_deferred = 0; 198562306a36Sopenharmony_ci memset(&skb_cb->tx_clone_ctx, 0, sizeof(skb_cb->tx_clone_ctx)); 198662306a36Sopenharmony_ci goto exit; 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_cifree_skb: 198962306a36Sopenharmony_ci kfree_skb(*skb); 199062306a36Sopenharmony_ci *skb = NULL; 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_ciexit: 199362306a36Sopenharmony_ci tipc_aead_put(aead); 199462306a36Sopenharmony_ci if (rx) 199562306a36Sopenharmony_ci tipc_node_put(rx->node); 199662306a36Sopenharmony_ci} 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_cistatic void tipc_crypto_do_cmd(struct net *net, int cmd) 199962306a36Sopenharmony_ci{ 200062306a36Sopenharmony_ci struct tipc_net *tn = tipc_net(net); 200162306a36Sopenharmony_ci struct tipc_crypto *tx = tn->crypto_tx, *rx; 200262306a36Sopenharmony_ci struct list_head *p; 200362306a36Sopenharmony_ci unsigned int stat; 200462306a36Sopenharmony_ci int i, j, cpu; 200562306a36Sopenharmony_ci char buf[200]; 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci /* Currently only one command is supported */ 200862306a36Sopenharmony_ci switch (cmd) { 200962306a36Sopenharmony_ci case 0xfff1: 201062306a36Sopenharmony_ci goto print_stats; 201162306a36Sopenharmony_ci default: 201262306a36Sopenharmony_ci return; 201362306a36Sopenharmony_ci } 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ciprint_stats: 201662306a36Sopenharmony_ci /* Print a header */ 201762306a36Sopenharmony_ci pr_info("\n=============== TIPC Crypto Statistics ===============\n\n"); 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ci /* Print key status */ 202062306a36Sopenharmony_ci pr_info("Key status:\n"); 202162306a36Sopenharmony_ci pr_info("TX(%7.7s)\n%s", tipc_own_id_string(net), 202262306a36Sopenharmony_ci tipc_crypto_key_dump(tx, buf)); 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci rcu_read_lock(); 202562306a36Sopenharmony_ci for (p = tn->node_list.next; p != &tn->node_list; p = p->next) { 202662306a36Sopenharmony_ci rx = tipc_node_crypto_rx_by_list(p); 202762306a36Sopenharmony_ci pr_info("RX(%7.7s)\n%s", tipc_node_get_id_str(rx->node), 202862306a36Sopenharmony_ci tipc_crypto_key_dump(rx, buf)); 202962306a36Sopenharmony_ci } 203062306a36Sopenharmony_ci rcu_read_unlock(); 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci /* Print crypto statistics */ 203362306a36Sopenharmony_ci for (i = 0, j = 0; i < MAX_STATS; i++) 203462306a36Sopenharmony_ci j += scnprintf(buf + j, 200 - j, "|%11s ", hstats[i]); 203562306a36Sopenharmony_ci pr_info("Counter %s", buf); 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci memset(buf, '-', 115); 203862306a36Sopenharmony_ci buf[115] = '\0'; 203962306a36Sopenharmony_ci pr_info("%s\n", buf); 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_ci j = scnprintf(buf, 200, "TX(%7.7s) ", tipc_own_id_string(net)); 204262306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 204362306a36Sopenharmony_ci for (i = 0; i < MAX_STATS; i++) { 204462306a36Sopenharmony_ci stat = per_cpu_ptr(tx->stats, cpu)->stat[i]; 204562306a36Sopenharmony_ci j += scnprintf(buf + j, 200 - j, "|%11d ", stat); 204662306a36Sopenharmony_ci } 204762306a36Sopenharmony_ci pr_info("%s", buf); 204862306a36Sopenharmony_ci j = scnprintf(buf, 200, "%12s", " "); 204962306a36Sopenharmony_ci } 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci rcu_read_lock(); 205262306a36Sopenharmony_ci for (p = tn->node_list.next; p != &tn->node_list; p = p->next) { 205362306a36Sopenharmony_ci rx = tipc_node_crypto_rx_by_list(p); 205462306a36Sopenharmony_ci j = scnprintf(buf, 200, "RX(%7.7s) ", 205562306a36Sopenharmony_ci tipc_node_get_id_str(rx->node)); 205662306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 205762306a36Sopenharmony_ci for (i = 0; i < MAX_STATS; i++) { 205862306a36Sopenharmony_ci stat = per_cpu_ptr(rx->stats, cpu)->stat[i]; 205962306a36Sopenharmony_ci j += scnprintf(buf + j, 200 - j, "|%11d ", 206062306a36Sopenharmony_ci stat); 206162306a36Sopenharmony_ci } 206262306a36Sopenharmony_ci pr_info("%s", buf); 206362306a36Sopenharmony_ci j = scnprintf(buf, 200, "%12s", " "); 206462306a36Sopenharmony_ci } 206562306a36Sopenharmony_ci } 206662306a36Sopenharmony_ci rcu_read_unlock(); 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci pr_info("\n======================== Done ========================\n"); 206962306a36Sopenharmony_ci} 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_cistatic char *tipc_crypto_key_dump(struct tipc_crypto *c, char *buf) 207262306a36Sopenharmony_ci{ 207362306a36Sopenharmony_ci struct tipc_key key = c->key; 207462306a36Sopenharmony_ci struct tipc_aead *aead; 207562306a36Sopenharmony_ci int k, i = 0; 207662306a36Sopenharmony_ci char *s; 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci for (k = KEY_MIN; k <= KEY_MAX; k++) { 207962306a36Sopenharmony_ci if (k == KEY_MASTER) { 208062306a36Sopenharmony_ci if (is_rx(c)) 208162306a36Sopenharmony_ci continue; 208262306a36Sopenharmony_ci if (time_before(jiffies, 208362306a36Sopenharmony_ci c->timer2 + TIPC_TX_GRACE_PERIOD)) 208462306a36Sopenharmony_ci s = "ACT"; 208562306a36Sopenharmony_ci else 208662306a36Sopenharmony_ci s = "PAS"; 208762306a36Sopenharmony_ci } else { 208862306a36Sopenharmony_ci if (k == key.passive) 208962306a36Sopenharmony_ci s = "PAS"; 209062306a36Sopenharmony_ci else if (k == key.active) 209162306a36Sopenharmony_ci s = "ACT"; 209262306a36Sopenharmony_ci else if (k == key.pending) 209362306a36Sopenharmony_ci s = "PEN"; 209462306a36Sopenharmony_ci else 209562306a36Sopenharmony_ci s = "-"; 209662306a36Sopenharmony_ci } 209762306a36Sopenharmony_ci i += scnprintf(buf + i, 200 - i, "\tKey%d: %s", k, s); 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci rcu_read_lock(); 210062306a36Sopenharmony_ci aead = rcu_dereference(c->aead[k]); 210162306a36Sopenharmony_ci if (aead) 210262306a36Sopenharmony_ci i += scnprintf(buf + i, 200 - i, 210362306a36Sopenharmony_ci "{\"0x...%s\", \"%s\"}/%d:%d", 210462306a36Sopenharmony_ci aead->hint, 210562306a36Sopenharmony_ci (aead->mode == CLUSTER_KEY) ? "c" : "p", 210662306a36Sopenharmony_ci atomic_read(&aead->users), 210762306a36Sopenharmony_ci refcount_read(&aead->refcnt)); 210862306a36Sopenharmony_ci rcu_read_unlock(); 210962306a36Sopenharmony_ci i += scnprintf(buf + i, 200 - i, "\n"); 211062306a36Sopenharmony_ci } 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci if (is_rx(c)) 211362306a36Sopenharmony_ci i += scnprintf(buf + i, 200 - i, "\tPeer RX active: %d\n", 211462306a36Sopenharmony_ci atomic_read(&c->peer_rx_active)); 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci return buf; 211762306a36Sopenharmony_ci} 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_cistatic char *tipc_key_change_dump(struct tipc_key old, struct tipc_key new, 212062306a36Sopenharmony_ci char *buf) 212162306a36Sopenharmony_ci{ 212262306a36Sopenharmony_ci struct tipc_key *key = &old; 212362306a36Sopenharmony_ci int k, i = 0; 212462306a36Sopenharmony_ci char *s; 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci /* Output format: "[%s %s %s] -> [%s %s %s]", max len = 32 */ 212762306a36Sopenharmony_ciagain: 212862306a36Sopenharmony_ci i += scnprintf(buf + i, 32 - i, "["); 212962306a36Sopenharmony_ci for (k = KEY_1; k <= KEY_3; k++) { 213062306a36Sopenharmony_ci if (k == key->passive) 213162306a36Sopenharmony_ci s = "pas"; 213262306a36Sopenharmony_ci else if (k == key->active) 213362306a36Sopenharmony_ci s = "act"; 213462306a36Sopenharmony_ci else if (k == key->pending) 213562306a36Sopenharmony_ci s = "pen"; 213662306a36Sopenharmony_ci else 213762306a36Sopenharmony_ci s = "-"; 213862306a36Sopenharmony_ci i += scnprintf(buf + i, 32 - i, 213962306a36Sopenharmony_ci (k != KEY_3) ? "%s " : "%s", s); 214062306a36Sopenharmony_ci } 214162306a36Sopenharmony_ci if (key != &new) { 214262306a36Sopenharmony_ci i += scnprintf(buf + i, 32 - i, "] -> "); 214362306a36Sopenharmony_ci key = &new; 214462306a36Sopenharmony_ci goto again; 214562306a36Sopenharmony_ci } 214662306a36Sopenharmony_ci i += scnprintf(buf + i, 32 - i, "]"); 214762306a36Sopenharmony_ci return buf; 214862306a36Sopenharmony_ci} 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci/** 215162306a36Sopenharmony_ci * tipc_crypto_msg_rcv - Common 'MSG_CRYPTO' processing point 215262306a36Sopenharmony_ci * @net: the struct net 215362306a36Sopenharmony_ci * @skb: the receiving message buffer 215462306a36Sopenharmony_ci */ 215562306a36Sopenharmony_civoid tipc_crypto_msg_rcv(struct net *net, struct sk_buff *skb) 215662306a36Sopenharmony_ci{ 215762306a36Sopenharmony_ci struct tipc_crypto *rx; 215862306a36Sopenharmony_ci struct tipc_msg *hdr; 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci if (unlikely(skb_linearize(skb))) 216162306a36Sopenharmony_ci goto exit; 216262306a36Sopenharmony_ci 216362306a36Sopenharmony_ci hdr = buf_msg(skb); 216462306a36Sopenharmony_ci rx = tipc_node_crypto_rx_by_addr(net, msg_prevnode(hdr)); 216562306a36Sopenharmony_ci if (unlikely(!rx)) 216662306a36Sopenharmony_ci goto exit; 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci switch (msg_type(hdr)) { 216962306a36Sopenharmony_ci case KEY_DISTR_MSG: 217062306a36Sopenharmony_ci if (tipc_crypto_key_rcv(rx, hdr)) 217162306a36Sopenharmony_ci goto exit; 217262306a36Sopenharmony_ci break; 217362306a36Sopenharmony_ci default: 217462306a36Sopenharmony_ci break; 217562306a36Sopenharmony_ci } 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci tipc_node_put(rx->node); 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_ciexit: 218062306a36Sopenharmony_ci kfree_skb(skb); 218162306a36Sopenharmony_ci} 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci/** 218462306a36Sopenharmony_ci * tipc_crypto_key_distr - Distribute a TX key 218562306a36Sopenharmony_ci * @tx: the TX crypto 218662306a36Sopenharmony_ci * @key: the key's index 218762306a36Sopenharmony_ci * @dest: the destination tipc node, = NULL if distributing to all nodes 218862306a36Sopenharmony_ci * 218962306a36Sopenharmony_ci * Return: 0 in case of success, otherwise < 0 219062306a36Sopenharmony_ci */ 219162306a36Sopenharmony_ciint tipc_crypto_key_distr(struct tipc_crypto *tx, u8 key, 219262306a36Sopenharmony_ci struct tipc_node *dest) 219362306a36Sopenharmony_ci{ 219462306a36Sopenharmony_ci struct tipc_aead *aead; 219562306a36Sopenharmony_ci u32 dnode = tipc_node_get_addr(dest); 219662306a36Sopenharmony_ci int rc = -ENOKEY; 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci if (!sysctl_tipc_key_exchange_enabled) 219962306a36Sopenharmony_ci return 0; 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_ci if (key) { 220262306a36Sopenharmony_ci rcu_read_lock(); 220362306a36Sopenharmony_ci aead = tipc_aead_get(tx->aead[key]); 220462306a36Sopenharmony_ci if (likely(aead)) { 220562306a36Sopenharmony_ci rc = tipc_crypto_key_xmit(tx->net, aead->key, 220662306a36Sopenharmony_ci aead->gen, aead->mode, 220762306a36Sopenharmony_ci dnode); 220862306a36Sopenharmony_ci tipc_aead_put(aead); 220962306a36Sopenharmony_ci } 221062306a36Sopenharmony_ci rcu_read_unlock(); 221162306a36Sopenharmony_ci } 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci return rc; 221462306a36Sopenharmony_ci} 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_ci/** 221762306a36Sopenharmony_ci * tipc_crypto_key_xmit - Send a session key 221862306a36Sopenharmony_ci * @net: the struct net 221962306a36Sopenharmony_ci * @skey: the session key to be sent 222062306a36Sopenharmony_ci * @gen: the key's generation 222162306a36Sopenharmony_ci * @mode: the key's mode 222262306a36Sopenharmony_ci * @dnode: the destination node address, = 0 if broadcasting to all nodes 222362306a36Sopenharmony_ci * 222462306a36Sopenharmony_ci * The session key 'skey' is packed in a TIPC v2 'MSG_CRYPTO/KEY_DISTR_MSG' 222562306a36Sopenharmony_ci * as its data section, then xmit-ed through the uc/bc link. 222662306a36Sopenharmony_ci * 222762306a36Sopenharmony_ci * Return: 0 in case of success, otherwise < 0 222862306a36Sopenharmony_ci */ 222962306a36Sopenharmony_cistatic int tipc_crypto_key_xmit(struct net *net, struct tipc_aead_key *skey, 223062306a36Sopenharmony_ci u16 gen, u8 mode, u32 dnode) 223162306a36Sopenharmony_ci{ 223262306a36Sopenharmony_ci struct sk_buff_head pkts; 223362306a36Sopenharmony_ci struct tipc_msg *hdr; 223462306a36Sopenharmony_ci struct sk_buff *skb; 223562306a36Sopenharmony_ci u16 size, cong_link_cnt; 223662306a36Sopenharmony_ci u8 *data; 223762306a36Sopenharmony_ci int rc; 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_ci size = tipc_aead_key_size(skey); 224062306a36Sopenharmony_ci skb = tipc_buf_acquire(INT_H_SIZE + size, GFP_ATOMIC); 224162306a36Sopenharmony_ci if (!skb) 224262306a36Sopenharmony_ci return -ENOMEM; 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci hdr = buf_msg(skb); 224562306a36Sopenharmony_ci tipc_msg_init(tipc_own_addr(net), hdr, MSG_CRYPTO, KEY_DISTR_MSG, 224662306a36Sopenharmony_ci INT_H_SIZE, dnode); 224762306a36Sopenharmony_ci msg_set_size(hdr, INT_H_SIZE + size); 224862306a36Sopenharmony_ci msg_set_key_gen(hdr, gen); 224962306a36Sopenharmony_ci msg_set_key_mode(hdr, mode); 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci data = msg_data(hdr); 225262306a36Sopenharmony_ci *((__be32 *)(data + TIPC_AEAD_ALG_NAME)) = htonl(skey->keylen); 225362306a36Sopenharmony_ci memcpy(data, skey->alg_name, TIPC_AEAD_ALG_NAME); 225462306a36Sopenharmony_ci memcpy(data + TIPC_AEAD_ALG_NAME + sizeof(__be32), skey->key, 225562306a36Sopenharmony_ci skey->keylen); 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci __skb_queue_head_init(&pkts); 225862306a36Sopenharmony_ci __skb_queue_tail(&pkts, skb); 225962306a36Sopenharmony_ci if (dnode) 226062306a36Sopenharmony_ci rc = tipc_node_xmit(net, &pkts, dnode, 0); 226162306a36Sopenharmony_ci else 226262306a36Sopenharmony_ci rc = tipc_bcast_xmit(net, &pkts, &cong_link_cnt); 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_ci return rc; 226562306a36Sopenharmony_ci} 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci/** 226862306a36Sopenharmony_ci * tipc_crypto_key_rcv - Receive a session key 226962306a36Sopenharmony_ci * @rx: the RX crypto 227062306a36Sopenharmony_ci * @hdr: the TIPC v2 message incl. the receiving session key in its data 227162306a36Sopenharmony_ci * 227262306a36Sopenharmony_ci * This function retrieves the session key in the message from peer, then 227362306a36Sopenharmony_ci * schedules a RX work to attach the key to the corresponding RX crypto. 227462306a36Sopenharmony_ci * 227562306a36Sopenharmony_ci * Return: "true" if the key has been scheduled for attaching, otherwise 227662306a36Sopenharmony_ci * "false". 227762306a36Sopenharmony_ci */ 227862306a36Sopenharmony_cistatic bool tipc_crypto_key_rcv(struct tipc_crypto *rx, struct tipc_msg *hdr) 227962306a36Sopenharmony_ci{ 228062306a36Sopenharmony_ci struct tipc_crypto *tx = tipc_net(rx->net)->crypto_tx; 228162306a36Sopenharmony_ci struct tipc_aead_key *skey = NULL; 228262306a36Sopenharmony_ci u16 key_gen = msg_key_gen(hdr); 228362306a36Sopenharmony_ci u32 size = msg_data_sz(hdr); 228462306a36Sopenharmony_ci u8 *data = msg_data(hdr); 228562306a36Sopenharmony_ci unsigned int keylen; 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci /* Verify whether the size can exist in the packet */ 228862306a36Sopenharmony_ci if (unlikely(size < sizeof(struct tipc_aead_key) + TIPC_AEAD_KEYLEN_MIN)) { 228962306a36Sopenharmony_ci pr_debug("%s: message data size is too small\n", rx->name); 229062306a36Sopenharmony_ci goto exit; 229162306a36Sopenharmony_ci } 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci keylen = ntohl(*((__be32 *)(data + TIPC_AEAD_ALG_NAME))); 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ci /* Verify the supplied size values */ 229662306a36Sopenharmony_ci if (unlikely(size != keylen + sizeof(struct tipc_aead_key) || 229762306a36Sopenharmony_ci keylen > TIPC_AEAD_KEY_SIZE_MAX)) { 229862306a36Sopenharmony_ci pr_debug("%s: invalid MSG_CRYPTO key size\n", rx->name); 229962306a36Sopenharmony_ci goto exit; 230062306a36Sopenharmony_ci } 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci spin_lock(&rx->lock); 230362306a36Sopenharmony_ci if (unlikely(rx->skey || (key_gen == rx->key_gen && rx->key.keys))) { 230462306a36Sopenharmony_ci pr_err("%s: key existed <%p>, gen %d vs %d\n", rx->name, 230562306a36Sopenharmony_ci rx->skey, key_gen, rx->key_gen); 230662306a36Sopenharmony_ci goto exit_unlock; 230762306a36Sopenharmony_ci } 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci /* Allocate memory for the key */ 231062306a36Sopenharmony_ci skey = kmalloc(size, GFP_ATOMIC); 231162306a36Sopenharmony_ci if (unlikely(!skey)) { 231262306a36Sopenharmony_ci pr_err("%s: unable to allocate memory for skey\n", rx->name); 231362306a36Sopenharmony_ci goto exit_unlock; 231462306a36Sopenharmony_ci } 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci /* Copy key from msg data */ 231762306a36Sopenharmony_ci skey->keylen = keylen; 231862306a36Sopenharmony_ci memcpy(skey->alg_name, data, TIPC_AEAD_ALG_NAME); 231962306a36Sopenharmony_ci memcpy(skey->key, data + TIPC_AEAD_ALG_NAME + sizeof(__be32), 232062306a36Sopenharmony_ci skey->keylen); 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci rx->key_gen = key_gen; 232362306a36Sopenharmony_ci rx->skey_mode = msg_key_mode(hdr); 232462306a36Sopenharmony_ci rx->skey = skey; 232562306a36Sopenharmony_ci rx->nokey = 0; 232662306a36Sopenharmony_ci mb(); /* for nokey flag */ 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ciexit_unlock: 232962306a36Sopenharmony_ci spin_unlock(&rx->lock); 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_ciexit: 233262306a36Sopenharmony_ci /* Schedule the key attaching on this crypto */ 233362306a36Sopenharmony_ci if (likely(skey && queue_delayed_work(tx->wq, &rx->work, 0))) 233462306a36Sopenharmony_ci return true; 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci return false; 233762306a36Sopenharmony_ci} 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci/** 234062306a36Sopenharmony_ci * tipc_crypto_work_rx - Scheduled RX works handler 234162306a36Sopenharmony_ci * @work: the struct RX work 234262306a36Sopenharmony_ci * 234362306a36Sopenharmony_ci * The function processes the previous scheduled works i.e. distributing TX key 234462306a36Sopenharmony_ci * or attaching a received session key on RX crypto. 234562306a36Sopenharmony_ci */ 234662306a36Sopenharmony_cistatic void tipc_crypto_work_rx(struct work_struct *work) 234762306a36Sopenharmony_ci{ 234862306a36Sopenharmony_ci struct delayed_work *dwork = to_delayed_work(work); 234962306a36Sopenharmony_ci struct tipc_crypto *rx = container_of(dwork, struct tipc_crypto, work); 235062306a36Sopenharmony_ci struct tipc_crypto *tx = tipc_net(rx->net)->crypto_tx; 235162306a36Sopenharmony_ci unsigned long delay = msecs_to_jiffies(5000); 235262306a36Sopenharmony_ci bool resched = false; 235362306a36Sopenharmony_ci u8 key; 235462306a36Sopenharmony_ci int rc; 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci /* Case 1: Distribute TX key to peer if scheduled */ 235762306a36Sopenharmony_ci if (atomic_cmpxchg(&rx->key_distr, 235862306a36Sopenharmony_ci KEY_DISTR_SCHED, 235962306a36Sopenharmony_ci KEY_DISTR_COMPL) == KEY_DISTR_SCHED) { 236062306a36Sopenharmony_ci /* Always pick the newest one for distributing */ 236162306a36Sopenharmony_ci key = tx->key.pending ?: tx->key.active; 236262306a36Sopenharmony_ci rc = tipc_crypto_key_distr(tx, key, rx->node); 236362306a36Sopenharmony_ci if (unlikely(rc)) 236462306a36Sopenharmony_ci pr_warn("%s: unable to distr key[%d] to %s, err %d\n", 236562306a36Sopenharmony_ci tx->name, key, tipc_node_get_id_str(rx->node), 236662306a36Sopenharmony_ci rc); 236762306a36Sopenharmony_ci 236862306a36Sopenharmony_ci /* Sched for key_distr releasing */ 236962306a36Sopenharmony_ci resched = true; 237062306a36Sopenharmony_ci } else { 237162306a36Sopenharmony_ci atomic_cmpxchg(&rx->key_distr, KEY_DISTR_COMPL, 0); 237262306a36Sopenharmony_ci } 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci /* Case 2: Attach a pending received session key from peer if any */ 237562306a36Sopenharmony_ci if (rx->skey) { 237662306a36Sopenharmony_ci rc = tipc_crypto_key_init(rx, rx->skey, rx->skey_mode, false); 237762306a36Sopenharmony_ci if (unlikely(rc < 0)) 237862306a36Sopenharmony_ci pr_warn("%s: unable to attach received skey, err %d\n", 237962306a36Sopenharmony_ci rx->name, rc); 238062306a36Sopenharmony_ci switch (rc) { 238162306a36Sopenharmony_ci case -EBUSY: 238262306a36Sopenharmony_ci case -ENOMEM: 238362306a36Sopenharmony_ci /* Resched the key attaching */ 238462306a36Sopenharmony_ci resched = true; 238562306a36Sopenharmony_ci break; 238662306a36Sopenharmony_ci default: 238762306a36Sopenharmony_ci synchronize_rcu(); 238862306a36Sopenharmony_ci kfree(rx->skey); 238962306a36Sopenharmony_ci rx->skey = NULL; 239062306a36Sopenharmony_ci break; 239162306a36Sopenharmony_ci } 239262306a36Sopenharmony_ci } 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_ci if (resched && queue_delayed_work(tx->wq, &rx->work, delay)) 239562306a36Sopenharmony_ci return; 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_ci tipc_node_put(rx->node); 239862306a36Sopenharmony_ci} 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci/** 240162306a36Sopenharmony_ci * tipc_crypto_rekeying_sched - (Re)schedule rekeying w/o new interval 240262306a36Sopenharmony_ci * @tx: TX crypto 240362306a36Sopenharmony_ci * @changed: if the rekeying needs to be rescheduled with new interval 240462306a36Sopenharmony_ci * @new_intv: new rekeying interval (when "changed" = true) 240562306a36Sopenharmony_ci */ 240662306a36Sopenharmony_civoid tipc_crypto_rekeying_sched(struct tipc_crypto *tx, bool changed, 240762306a36Sopenharmony_ci u32 new_intv) 240862306a36Sopenharmony_ci{ 240962306a36Sopenharmony_ci unsigned long delay; 241062306a36Sopenharmony_ci bool now = false; 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci if (changed) { 241362306a36Sopenharmony_ci if (new_intv == TIPC_REKEYING_NOW) 241462306a36Sopenharmony_ci now = true; 241562306a36Sopenharmony_ci else 241662306a36Sopenharmony_ci tx->rekeying_intv = new_intv; 241762306a36Sopenharmony_ci cancel_delayed_work_sync(&tx->work); 241862306a36Sopenharmony_ci } 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ci if (tx->rekeying_intv || now) { 242162306a36Sopenharmony_ci delay = (now) ? 0 : tx->rekeying_intv * 60 * 1000; 242262306a36Sopenharmony_ci queue_delayed_work(tx->wq, &tx->work, msecs_to_jiffies(delay)); 242362306a36Sopenharmony_ci } 242462306a36Sopenharmony_ci} 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ci/** 242762306a36Sopenharmony_ci * tipc_crypto_work_tx - Scheduled TX works handler 242862306a36Sopenharmony_ci * @work: the struct TX work 242962306a36Sopenharmony_ci * 243062306a36Sopenharmony_ci * The function processes the previous scheduled work, i.e. key rekeying, by 243162306a36Sopenharmony_ci * generating a new session key based on current one, then attaching it to the 243262306a36Sopenharmony_ci * TX crypto and finally distributing it to peers. It also re-schedules the 243362306a36Sopenharmony_ci * rekeying if needed. 243462306a36Sopenharmony_ci */ 243562306a36Sopenharmony_cistatic void tipc_crypto_work_tx(struct work_struct *work) 243662306a36Sopenharmony_ci{ 243762306a36Sopenharmony_ci struct delayed_work *dwork = to_delayed_work(work); 243862306a36Sopenharmony_ci struct tipc_crypto *tx = container_of(dwork, struct tipc_crypto, work); 243962306a36Sopenharmony_ci struct tipc_aead_key *skey = NULL; 244062306a36Sopenharmony_ci struct tipc_key key = tx->key; 244162306a36Sopenharmony_ci struct tipc_aead *aead; 244262306a36Sopenharmony_ci int rc = -ENOMEM; 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci if (unlikely(key.pending)) 244562306a36Sopenharmony_ci goto resched; 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_ci /* Take current key as a template */ 244862306a36Sopenharmony_ci rcu_read_lock(); 244962306a36Sopenharmony_ci aead = rcu_dereference(tx->aead[key.active ?: KEY_MASTER]); 245062306a36Sopenharmony_ci if (unlikely(!aead)) { 245162306a36Sopenharmony_ci rcu_read_unlock(); 245262306a36Sopenharmony_ci /* At least one key should exist for securing */ 245362306a36Sopenharmony_ci return; 245462306a36Sopenharmony_ci } 245562306a36Sopenharmony_ci 245662306a36Sopenharmony_ci /* Lets duplicate it first */ 245762306a36Sopenharmony_ci skey = kmemdup(aead->key, tipc_aead_key_size(aead->key), GFP_ATOMIC); 245862306a36Sopenharmony_ci rcu_read_unlock(); 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_ci /* Now, generate new key, initiate & distribute it */ 246162306a36Sopenharmony_ci if (likely(skey)) { 246262306a36Sopenharmony_ci rc = tipc_aead_key_generate(skey) ?: 246362306a36Sopenharmony_ci tipc_crypto_key_init(tx, skey, PER_NODE_KEY, false); 246462306a36Sopenharmony_ci if (likely(rc > 0)) 246562306a36Sopenharmony_ci rc = tipc_crypto_key_distr(tx, rc, NULL); 246662306a36Sopenharmony_ci kfree_sensitive(skey); 246762306a36Sopenharmony_ci } 246862306a36Sopenharmony_ci 246962306a36Sopenharmony_ci if (unlikely(rc)) 247062306a36Sopenharmony_ci pr_warn_ratelimited("%s: rekeying returns %d\n", tx->name, rc); 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ciresched: 247362306a36Sopenharmony_ci /* Re-schedule rekeying if any */ 247462306a36Sopenharmony_ci tipc_crypto_rekeying_sched(tx, false, 0); 247562306a36Sopenharmony_ci} 2476