18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * fs/hmdfs/comm/connection.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "connection.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/file.h>
118c2ecf20Sopenharmony_ci#include <linux/freezer.h>
128c2ecf20Sopenharmony_ci#include <linux/fs.h>
138c2ecf20Sopenharmony_ci#include <linux/kthread.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/net.h>
168c2ecf20Sopenharmony_ci#include <linux/tcp.h>
178c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "device_node.h"
208c2ecf20Sopenharmony_ci#include "hmdfs.h"
218c2ecf20Sopenharmony_ci#include "message_verify.h"
228c2ecf20Sopenharmony_ci#include "node_cb.h"
238c2ecf20Sopenharmony_ci#include "protocol.h"
248c2ecf20Sopenharmony_ci#include "socket_adapter.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#ifdef CONFIG_HMDFS_FS_ENCRYPTION
278c2ecf20Sopenharmony_ci#include "crypto.h"
288c2ecf20Sopenharmony_ci#endif
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define HMDFS_WAIT_REQUEST_END_MIN 20
318c2ecf20Sopenharmony_ci#define HMDFS_WAIT_REQUEST_END_MAX 30
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define HMDFS_WAIT_CONN_RELEASE (3 * HZ)
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define HMDFS_RETRY_WB_WQ_MAX_ACTIVE 16
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic void hs_fill_crypto_data(struct connection *conn_impl, __u8 ops,
388c2ecf20Sopenharmony_ci				void *data, __u32 len)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	struct crypto_body *body = NULL;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	if (len < sizeof(struct crypto_body)) {
438c2ecf20Sopenharmony_ci		hmdfs_info("crpto body len %u is err", len);
448c2ecf20Sopenharmony_ci		return;
458c2ecf20Sopenharmony_ci	}
468c2ecf20Sopenharmony_ci	body = (struct crypto_body *)data;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	/* this is only test, later need to fill right algorithm. */
498c2ecf20Sopenharmony_ci	body->crypto |= HMDFS_HS_CRYPTO_KTLS_AES128;
508c2ecf20Sopenharmony_ci	body->crypto = cpu_to_le32(body->crypto);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	hmdfs_info("fill crypto. ccrtypto=0x%08x", body->crypto);
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic int hs_parse_crypto_data(struct connection *conn_impl, __u8 ops,
568c2ecf20Sopenharmony_ci				 void *data, __u32 len)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	struct crypto_body *hs_crypto = NULL;
598c2ecf20Sopenharmony_ci	uint32_t crypto;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	if (len < sizeof(struct crypto_body)) {
628c2ecf20Sopenharmony_ci		hmdfs_info("handshake msg len error, len=%u", len);
638c2ecf20Sopenharmony_ci		return -1;
648c2ecf20Sopenharmony_ci	}
658c2ecf20Sopenharmony_ci	hs_crypto = (struct crypto_body *)data;
668c2ecf20Sopenharmony_ci	crypto = le16_to_cpu(hs_crypto->crypto);
678c2ecf20Sopenharmony_ci	conn_impl->crypto = crypto;
688c2ecf20Sopenharmony_ci	hmdfs_info("ops=%u, len=%u, crypto=0x%08x", ops, len, crypto);
698c2ecf20Sopenharmony_ci	return 0;
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic void hs_fill_case_sense_data(struct connection *conn_impl, __u8 ops,
738c2ecf20Sopenharmony_ci				    void *data, __u32 len)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	struct case_sense_body *body = (struct case_sense_body *)data;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	if (len < sizeof(struct case_sense_body)) {
788c2ecf20Sopenharmony_ci		hmdfs_err("case sensitive len %u is err", len);
798c2ecf20Sopenharmony_ci		return;
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci	body->case_sensitive = conn_impl->node->sbi->s_case_sensitive;
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic int hs_parse_case_sense_data(struct connection *conn_impl, __u8 ops,
858c2ecf20Sopenharmony_ci				     void *data, __u32 len)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	struct case_sense_body *body = (struct case_sense_body *)data;
888c2ecf20Sopenharmony_ci	__u8 sensitive = conn_impl->node->sbi->s_case_sensitive ? 1 : 0;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	if (len < sizeof(struct case_sense_body)) {
918c2ecf20Sopenharmony_ci		hmdfs_info("case sensitive len %u is err", len);
928c2ecf20Sopenharmony_ci		return -1;
938c2ecf20Sopenharmony_ci	}
948c2ecf20Sopenharmony_ci	if (body->case_sensitive != sensitive) {
958c2ecf20Sopenharmony_ci		hmdfs_err("case sensitive inconsistent, server: %u,client: %u, ops: %u",
968c2ecf20Sopenharmony_ci			  body->case_sensitive, sensitive, ops);
978c2ecf20Sopenharmony_ci		return -1;
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci	return 0;
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic void hs_fill_feature_data(struct connection *conn_impl, __u8 ops,
1038c2ecf20Sopenharmony_ci				 void *data, __u32 len)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	struct feature_body *body = (struct feature_body *)data;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	if (len < sizeof(struct feature_body)) {
1088c2ecf20Sopenharmony_ci		hmdfs_err("feature len %u is err", len);
1098c2ecf20Sopenharmony_ci		return;
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci	body->features = cpu_to_le64(conn_impl->node->sbi->s_features);
1128c2ecf20Sopenharmony_ci	body->reserved = cpu_to_le64(0);
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic int hs_parse_feature_data(struct connection *conn_impl, __u8 ops,
1168c2ecf20Sopenharmony_ci				 void *data, __u32 len)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	struct feature_body *body = (struct feature_body *)data;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	if (len < sizeof(struct feature_body)) {
1218c2ecf20Sopenharmony_ci		hmdfs_err("feature len %u is err", len);
1228c2ecf20Sopenharmony_ci		return -1;
1238c2ecf20Sopenharmony_ci	}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	conn_impl->node->features = le64_to_cpu(body->features);
1268c2ecf20Sopenharmony_ci	return 0;
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci/* should ensure len is small than 0xffff. */
1308c2ecf20Sopenharmony_cistatic const struct conn_hs_extend_reg s_hs_extend_reg[HS_EXTEND_CODE_COUNT] = {
1318c2ecf20Sopenharmony_ci	[HS_EXTEND_CODE_CRYPTO] = {
1328c2ecf20Sopenharmony_ci		.len = sizeof(struct crypto_body),
1338c2ecf20Sopenharmony_ci		.resv = 0,
1348c2ecf20Sopenharmony_ci		.filler = hs_fill_crypto_data,
1358c2ecf20Sopenharmony_ci		.parser = hs_parse_crypto_data
1368c2ecf20Sopenharmony_ci	},
1378c2ecf20Sopenharmony_ci	[HS_EXTEND_CODE_CASE_SENSE] = {
1388c2ecf20Sopenharmony_ci		.len = sizeof(struct case_sense_body),
1398c2ecf20Sopenharmony_ci		.resv = 0,
1408c2ecf20Sopenharmony_ci		.filler = hs_fill_case_sense_data,
1418c2ecf20Sopenharmony_ci		.parser = hs_parse_case_sense_data,
1428c2ecf20Sopenharmony_ci	},
1438c2ecf20Sopenharmony_ci	[HS_EXTEND_CODE_FEATURE_SUPPORT] = {
1448c2ecf20Sopenharmony_ci		.len = sizeof(struct feature_body),
1458c2ecf20Sopenharmony_ci		.resv = 0,
1468c2ecf20Sopenharmony_ci		.filler = hs_fill_feature_data,
1478c2ecf20Sopenharmony_ci		.parser = hs_parse_feature_data,
1488c2ecf20Sopenharmony_ci	},
1498c2ecf20Sopenharmony_ci	[HS_EXTEND_CODE_FEATURE_SUPPORT] = {
1508c2ecf20Sopenharmony_ci		.len = sizeof(struct feature_body),
1518c2ecf20Sopenharmony_ci		.resv = 0,
1528c2ecf20Sopenharmony_ci		.filler = hs_fill_feature_data,
1538c2ecf20Sopenharmony_ci		.parser = hs_parse_feature_data,
1548c2ecf20Sopenharmony_ci	},
1558c2ecf20Sopenharmony_ci};
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic __u32 hs_get_extend_data_len(void)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	__u32 len;
1608c2ecf20Sopenharmony_ci	int i;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	len = sizeof(struct conn_hs_extend_head);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	for (i = 0; i < HS_EXTEND_CODE_COUNT; i++) {
1658c2ecf20Sopenharmony_ci		len += sizeof(struct extend_field_head);
1668c2ecf20Sopenharmony_ci		len += s_hs_extend_reg[i].len;
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	hmdfs_info("extend data total len is %u", len);
1708c2ecf20Sopenharmony_ci	return len;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic void hs_fill_extend_data(struct connection *conn_impl, __u8 ops,
1748c2ecf20Sopenharmony_ci				void *extend_data, __u32 len)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	struct conn_hs_extend_head *extend_head = NULL;
1778c2ecf20Sopenharmony_ci	struct extend_field_head *field = NULL;
1788c2ecf20Sopenharmony_ci	uint8_t *body = NULL;
1798c2ecf20Sopenharmony_ci	__u32 offset;
1808c2ecf20Sopenharmony_ci	__u16 i;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	if (sizeof(struct conn_hs_extend_head) > len) {
1838c2ecf20Sopenharmony_ci		hmdfs_info("len error. len=%u", len);
1848c2ecf20Sopenharmony_ci		return;
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci	extend_head = (struct conn_hs_extend_head *)extend_data;
1878c2ecf20Sopenharmony_ci	extend_head->field_cn = 0;
1888c2ecf20Sopenharmony_ci	offset = sizeof(struct conn_hs_extend_head);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	for (i = 0; i < HS_EXTEND_CODE_COUNT; i++) {
1918c2ecf20Sopenharmony_ci		if (sizeof(struct extend_field_head) > (len - offset))
1928c2ecf20Sopenharmony_ci			break;
1938c2ecf20Sopenharmony_ci		field = (struct extend_field_head *)((uint8_t *)extend_data +
1948c2ecf20Sopenharmony_ci						     offset);
1958c2ecf20Sopenharmony_ci		offset += sizeof(struct extend_field_head);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci		if (s_hs_extend_reg[i].len > (len - offset))
1988c2ecf20Sopenharmony_ci			break;
1998c2ecf20Sopenharmony_ci		body = (uint8_t *)extend_data + offset;
2008c2ecf20Sopenharmony_ci		offset += s_hs_extend_reg[i].len;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci		field->code = cpu_to_le16(i);
2038c2ecf20Sopenharmony_ci		field->len = cpu_to_le16(s_hs_extend_reg[i].len);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci		if (s_hs_extend_reg[i].filler)
2068c2ecf20Sopenharmony_ci			s_hs_extend_reg[i].filler(conn_impl, ops,
2078c2ecf20Sopenharmony_ci					body, s_hs_extend_reg[i].len);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci		extend_head->field_cn += 1;
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	extend_head->field_cn = cpu_to_le32(extend_head->field_cn);
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic int hs_parse_extend_data(struct connection *conn_impl, __u8 ops,
2168c2ecf20Sopenharmony_ci				void *extend_data, __u32 extend_len)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	struct conn_hs_extend_head *extend_head = NULL;
2198c2ecf20Sopenharmony_ci	struct extend_field_head *field = NULL;
2208c2ecf20Sopenharmony_ci	uint8_t *body = NULL;
2218c2ecf20Sopenharmony_ci	__u32 offset;
2228c2ecf20Sopenharmony_ci	__u32 field_cnt;
2238c2ecf20Sopenharmony_ci	__u16 code;
2248c2ecf20Sopenharmony_ci	__u16 len;
2258c2ecf20Sopenharmony_ci	int i;
2268c2ecf20Sopenharmony_ci	int ret;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	if (sizeof(struct conn_hs_extend_head) > extend_len) {
2298c2ecf20Sopenharmony_ci		hmdfs_err("ops=%u,extend_len=%u", ops, extend_len);
2308c2ecf20Sopenharmony_ci		return -1;
2318c2ecf20Sopenharmony_ci	}
2328c2ecf20Sopenharmony_ci	extend_head = (struct conn_hs_extend_head *)extend_data;
2338c2ecf20Sopenharmony_ci	field_cnt = le32_to_cpu(extend_head->field_cn);
2348c2ecf20Sopenharmony_ci	hmdfs_info("extend_len=%u,field_cnt=%u", extend_len, field_cnt);
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	offset = sizeof(struct conn_hs_extend_head);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	for (i = 0; i < field_cnt; i++) {
2398c2ecf20Sopenharmony_ci		if (sizeof(struct extend_field_head) > (extend_len - offset)) {
2408c2ecf20Sopenharmony_ci			hmdfs_err("cnt err, op=%u, extend_len=%u, cnt=%u, i=%u",
2418c2ecf20Sopenharmony_ci				  ops, extend_len, field_cnt, i);
2428c2ecf20Sopenharmony_ci			return -1;
2438c2ecf20Sopenharmony_ci		}
2448c2ecf20Sopenharmony_ci		field = (struct extend_field_head *)((uint8_t *)extend_data +
2458c2ecf20Sopenharmony_ci						     offset);
2468c2ecf20Sopenharmony_ci		offset += sizeof(struct extend_field_head);
2478c2ecf20Sopenharmony_ci		code = le16_to_cpu(field->code);
2488c2ecf20Sopenharmony_ci		len = le16_to_cpu(field->len);
2498c2ecf20Sopenharmony_ci		if (len > (extend_len - offset)) {
2508c2ecf20Sopenharmony_ci			hmdfs_err("len err, op=%u, extend_len=%u, cnt=%u, i=%u",
2518c2ecf20Sopenharmony_ci				  ops, extend_len, field_cnt, i);
2528c2ecf20Sopenharmony_ci			hmdfs_err("len err, code=%u, len=%u, offset=%u", code,
2538c2ecf20Sopenharmony_ci				  len, offset);
2548c2ecf20Sopenharmony_ci			return -1;
2558c2ecf20Sopenharmony_ci		}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci		body = (uint8_t *)extend_data + offset;
2588c2ecf20Sopenharmony_ci		offset += len;
2598c2ecf20Sopenharmony_ci		if ((code < HS_EXTEND_CODE_COUNT) &&
2608c2ecf20Sopenharmony_ci		    (s_hs_extend_reg[code].parser)) {
2618c2ecf20Sopenharmony_ci			ret = s_hs_extend_reg[code].parser(conn_impl, ops,
2628c2ecf20Sopenharmony_ci							   body, len);
2638c2ecf20Sopenharmony_ci			if (ret)
2648c2ecf20Sopenharmony_ci				return ret;
2658c2ecf20Sopenharmony_ci		}
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci	return 0;
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cistatic int hs_proc_msg_data(struct connection *conn_impl, __u8 ops, void *data,
2718c2ecf20Sopenharmony_ci			    __u32 data_len)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	struct connection_handshake_req *hs_req = NULL;
2748c2ecf20Sopenharmony_ci	uint8_t *extend_data = NULL;
2758c2ecf20Sopenharmony_ci	__u32 extend_len;
2768c2ecf20Sopenharmony_ci	__u32 req_len;
2778c2ecf20Sopenharmony_ci	int ret;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	if (!data) {
2808c2ecf20Sopenharmony_ci		hmdfs_err("err, msg data is null");
2818c2ecf20Sopenharmony_ci		return -1;
2828c2ecf20Sopenharmony_ci	}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	if (data_len < sizeof(struct connection_handshake_req)) {
2858c2ecf20Sopenharmony_ci		hmdfs_err("ack msg data len error. data_len=%u, device_id=%llu",
2868c2ecf20Sopenharmony_ci			  data_len, conn_impl->node->device_id);
2878c2ecf20Sopenharmony_ci		return -1;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	hs_req = (struct connection_handshake_req *)data;
2918c2ecf20Sopenharmony_ci	req_len = le32_to_cpu(hs_req->len);
2928c2ecf20Sopenharmony_ci	if (req_len > (data_len - sizeof(struct connection_handshake_req))) {
2938c2ecf20Sopenharmony_ci		hmdfs_info(
2948c2ecf20Sopenharmony_ci			"ack msg hs_req len(%u) error. data_len=%u, device_id=%llu",
2958c2ecf20Sopenharmony_ci			req_len, data_len, conn_impl->node->device_id);
2968c2ecf20Sopenharmony_ci		return -1;
2978c2ecf20Sopenharmony_ci	}
2988c2ecf20Sopenharmony_ci	extend_len =
2998c2ecf20Sopenharmony_ci		data_len - sizeof(struct connection_handshake_req) - req_len;
3008c2ecf20Sopenharmony_ci	extend_data = (uint8_t *)data +
3018c2ecf20Sopenharmony_ci		      sizeof(struct connection_handshake_req) + req_len;
3028c2ecf20Sopenharmony_ci	ret = hs_parse_extend_data(conn_impl, ops, extend_data, extend_len);
3038c2ecf20Sopenharmony_ci	if (!ret)
3048c2ecf20Sopenharmony_ci		hmdfs_info(
3058c2ecf20Sopenharmony_ci			"hs msg rcv, ops=%u, data_len=%u, device_id=%llu, req_len=%u",
3068c2ecf20Sopenharmony_ci			ops, data_len, conn_impl->node->device_id, hs_req->len);
3078c2ecf20Sopenharmony_ci	return ret;
3088c2ecf20Sopenharmony_ci}
3098c2ecf20Sopenharmony_ci#ifdef CONFIG_HMDFS_FS_ENCRYPTION
3108c2ecf20Sopenharmony_cistatic int connection_handshake_init_tls(struct connection *conn_impl, __u8 ops)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	// init ktls config, use key1/key2 as init write-key of each direction
3138c2ecf20Sopenharmony_ci	__u8 key1[HMDFS_KEY_SIZE];
3148c2ecf20Sopenharmony_ci	__u8 key2[HMDFS_KEY_SIZE];
3158c2ecf20Sopenharmony_ci	int ret;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	if ((ops != CONNECT_MESG_HANDSHAKE_RESPONSE) &&
3188c2ecf20Sopenharmony_ci	    (ops != CONNECT_MESG_HANDSHAKE_ACK)) {
3198c2ecf20Sopenharmony_ci		hmdfs_err("ops %u is err", ops);
3208c2ecf20Sopenharmony_ci		return -EINVAL;
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	update_key(conn_impl->master_key, key1, HKDF_TYPE_KEY_INITIATOR);
3248c2ecf20Sopenharmony_ci	update_key(conn_impl->master_key, key2, HKDF_TYPE_KEY_ACCEPTER);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	if (ops == CONNECT_MESG_HANDSHAKE_ACK) {
3278c2ecf20Sopenharmony_ci		memcpy(conn_impl->send_key, key1, HMDFS_KEY_SIZE);
3288c2ecf20Sopenharmony_ci		memcpy(conn_impl->recv_key, key2, HMDFS_KEY_SIZE);
3298c2ecf20Sopenharmony_ci	} else {
3308c2ecf20Sopenharmony_ci		memcpy(conn_impl->send_key, key2, HMDFS_KEY_SIZE);
3318c2ecf20Sopenharmony_ci		memcpy(conn_impl->recv_key, key1, HMDFS_KEY_SIZE);
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	memset(key1, 0, HMDFS_KEY_SIZE);
3358c2ecf20Sopenharmony_ci	memset(key2, 0, HMDFS_KEY_SIZE);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	hmdfs_info("hs: ops=%u start set crypto tls", ops);
3388c2ecf20Sopenharmony_ci	ret = tls_crypto_info_init(conn_impl);
3398c2ecf20Sopenharmony_ci	if (ret)
3408c2ecf20Sopenharmony_ci		hmdfs_err("setting tls fail. ops is %u", ops);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	return ret;
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci#endif
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic int do_send_handshake(struct connection *conn_impl, __u8 ops,
3478c2ecf20Sopenharmony_ci			     __le16 request_id)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	int err;
3508c2ecf20Sopenharmony_ci	struct connection_msg_head *hs_head = NULL;
3518c2ecf20Sopenharmony_ci	struct connection_handshake_req *hs_data = NULL;
3528c2ecf20Sopenharmony_ci	uint8_t *hs_extend_data = NULL;
3538c2ecf20Sopenharmony_ci	struct hmdfs_send_data msg;
3548c2ecf20Sopenharmony_ci	__u32 send_len;
3558c2ecf20Sopenharmony_ci	__u32 len;
3568c2ecf20Sopenharmony_ci	__u32 extend_len;
3578c2ecf20Sopenharmony_ci	char buf[HMDFS_CID_SIZE] = { 0 };
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	len = scnprintf(buf, HMDFS_CID_SIZE, "%llu", 0ULL);
3608c2ecf20Sopenharmony_ci	send_len = sizeof(struct connection_msg_head) +
3618c2ecf20Sopenharmony_ci		   sizeof(struct connection_handshake_req) + len;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	if (((ops == CONNECT_MESG_HANDSHAKE_RESPONSE) ||
3648c2ecf20Sopenharmony_ci	     (ops == CONNECT_MESG_HANDSHAKE_ACK))) {
3658c2ecf20Sopenharmony_ci		extend_len = hs_get_extend_data_len();
3668c2ecf20Sopenharmony_ci		send_len += extend_len;
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	hs_head = kzalloc(send_len, GFP_KERNEL);
3708c2ecf20Sopenharmony_ci	if (!hs_head)
3718c2ecf20Sopenharmony_ci		return -ENOMEM;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	hs_data = (struct connection_handshake_req
3748c2ecf20Sopenharmony_ci			   *)((uint8_t *)hs_head +
3758c2ecf20Sopenharmony_ci			      sizeof(struct connection_msg_head));
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	hs_data->len = cpu_to_le32(len);
3788c2ecf20Sopenharmony_ci	memcpy(hs_data->dev_id, buf, len);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	if (((ops == CONNECT_MESG_HANDSHAKE_RESPONSE) ||
3818c2ecf20Sopenharmony_ci	     ops == CONNECT_MESG_HANDSHAKE_ACK)) {
3828c2ecf20Sopenharmony_ci		hs_extend_data = (uint8_t *)hs_data +
3838c2ecf20Sopenharmony_ci				  sizeof(struct connection_handshake_req) + len;
3848c2ecf20Sopenharmony_ci		hs_fill_extend_data(conn_impl, ops, hs_extend_data, extend_len);
3858c2ecf20Sopenharmony_ci	}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	hs_head->magic = HMDFS_MSG_MAGIC;
3888c2ecf20Sopenharmony_ci	hs_head->version = HMDFS_VERSION;
3898c2ecf20Sopenharmony_ci	hs_head->flags |= 0x1;
3908c2ecf20Sopenharmony_ci	hmdfs_info("Send handshake message: ops = %d, fd = %d", ops,
3918c2ecf20Sopenharmony_ci		   ((struct tcp_handle *)(conn_impl->connect_handle))->fd);
3928c2ecf20Sopenharmony_ci	hs_head->operations = ops;
3938c2ecf20Sopenharmony_ci	hs_head->request_id = request_id;
3948c2ecf20Sopenharmony_ci	hs_head->datasize = cpu_to_le32(send_len);
3958c2ecf20Sopenharmony_ci	hs_head->source = 0;
3968c2ecf20Sopenharmony_ci	hs_head->msg_id = 0;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	msg.head = hs_head;
3998c2ecf20Sopenharmony_ci	msg.head_len = sizeof(struct connection_msg_head);
4008c2ecf20Sopenharmony_ci	msg.data = hs_data;
4018c2ecf20Sopenharmony_ci	msg.len = send_len - msg.head_len;
4028c2ecf20Sopenharmony_ci	msg.sdesc = NULL;
4038c2ecf20Sopenharmony_ci	msg.sdesc_len = 0;
4048c2ecf20Sopenharmony_ci	err = conn_impl->send_message(conn_impl, &msg);
4058c2ecf20Sopenharmony_ci	kfree(hs_head);
4068c2ecf20Sopenharmony_ci	return err;
4078c2ecf20Sopenharmony_ci}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_cistatic int hmdfs_node_waiting_evt_sum(const struct hmdfs_peer *node)
4108c2ecf20Sopenharmony_ci{
4118c2ecf20Sopenharmony_ci	int sum = 0;
4128c2ecf20Sopenharmony_ci	int i;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	for (i = 0; i < RAW_NODE_EVT_NR; i++)
4158c2ecf20Sopenharmony_ci		sum += node->waiting_evt[i];
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	return sum;
4188c2ecf20Sopenharmony_ci}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_cistatic int hmdfs_update_node_waiting_evt(struct hmdfs_peer *node, int evt,
4218c2ecf20Sopenharmony_ci					 unsigned int *seq)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	int last;
4248c2ecf20Sopenharmony_ci	int sum;
4258c2ecf20Sopenharmony_ci	unsigned int next;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	sum = hmdfs_node_waiting_evt_sum(node);
4288c2ecf20Sopenharmony_ci	if (sum % RAW_NODE_EVT_NR)
4298c2ecf20Sopenharmony_ci		last = !node->pending_evt;
4308c2ecf20Sopenharmony_ci	else
4318c2ecf20Sopenharmony_ci		last = node->pending_evt;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	/* duplicated event */
4348c2ecf20Sopenharmony_ci	if (evt == last) {
4358c2ecf20Sopenharmony_ci		node->dup_evt[evt]++;
4368c2ecf20Sopenharmony_ci		return 0;
4378c2ecf20Sopenharmony_ci	}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	node->waiting_evt[evt]++;
4408c2ecf20Sopenharmony_ci	hmdfs_debug("add node->waiting_evt[%d]=%d", evt,
4418c2ecf20Sopenharmony_ci		    node->waiting_evt[evt]);
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	/* offline wait + online wait + offline wait = offline wait
4448c2ecf20Sopenharmony_ci	 * online wait + offline wait + online wait != online wait
4458c2ecf20Sopenharmony_ci	 * As the first online related resource (e.g. fd) must be invalidated
4468c2ecf20Sopenharmony_ci	 */
4478c2ecf20Sopenharmony_ci	if (node->waiting_evt[RAW_NODE_EVT_OFF] >= 2 &&
4488c2ecf20Sopenharmony_ci	    node->waiting_evt[RAW_NODE_EVT_ON] >= 1) {
4498c2ecf20Sopenharmony_ci		node->waiting_evt[RAW_NODE_EVT_OFF] -= 1;
4508c2ecf20Sopenharmony_ci		node->waiting_evt[RAW_NODE_EVT_ON] -= 1;
4518c2ecf20Sopenharmony_ci		node->seq_wr_idx -= 2;
4528c2ecf20Sopenharmony_ci		node->merged_evt += 2;
4538c2ecf20Sopenharmony_ci	}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	next = hmdfs_node_inc_evt_seq(node);
4568c2ecf20Sopenharmony_ci	node->seq_tbl[(node->seq_wr_idx++) % RAW_NODE_EVT_MAX_NR] = next;
4578c2ecf20Sopenharmony_ci	*seq = next;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	return 1;
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_cistatic void hmdfs_run_evt_cb_verbosely(struct hmdfs_peer *node, int raw_evt,
4638c2ecf20Sopenharmony_ci				       bool sync, unsigned int seq)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	int evt = (raw_evt == RAW_NODE_EVT_OFF) ? NODE_EVT_OFFLINE :
4668c2ecf20Sopenharmony_ci						  NODE_EVT_ONLINE;
4678c2ecf20Sopenharmony_ci	int cur_evt_idx = sync ? 1 : 0;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	node->cur_evt[cur_evt_idx] = raw_evt;
4708c2ecf20Sopenharmony_ci	node->cur_evt_seq[cur_evt_idx] = seq;
4718c2ecf20Sopenharmony_ci	hmdfs_node_call_evt_cb(node, evt, sync, seq);
4728c2ecf20Sopenharmony_ci	node->cur_evt[cur_evt_idx] = RAW_NODE_EVT_NR;
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_cistatic void hmdfs_node_evt_work(struct work_struct *work)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	struct hmdfs_peer *node =
4788c2ecf20Sopenharmony_ci		container_of(work, struct hmdfs_peer, evt_dwork.work);
4798c2ecf20Sopenharmony_ci	unsigned int seq;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	/*
4828c2ecf20Sopenharmony_ci	 * N-th sync cb completes before N-th async cb,
4838c2ecf20Sopenharmony_ci	 * so use seq_lock as a barrier in read & write path
4848c2ecf20Sopenharmony_ci	 * to ensure we can read the required seq.
4858c2ecf20Sopenharmony_ci	 */
4868c2ecf20Sopenharmony_ci	mutex_lock(&node->seq_lock);
4878c2ecf20Sopenharmony_ci	seq = node->seq_tbl[(node->seq_rd_idx++) % RAW_NODE_EVT_MAX_NR];
4888c2ecf20Sopenharmony_ci	hmdfs_run_evt_cb_verbosely(node, node->pending_evt, false, seq);
4898c2ecf20Sopenharmony_ci	mutex_unlock(&node->seq_lock);
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	mutex_lock(&node->evt_lock);
4928c2ecf20Sopenharmony_ci	if (hmdfs_node_waiting_evt_sum(node)) {
4938c2ecf20Sopenharmony_ci		node->pending_evt = !node->pending_evt;
4948c2ecf20Sopenharmony_ci		node->pending_evt_seq =
4958c2ecf20Sopenharmony_ci			node->seq_tbl[node->seq_rd_idx % RAW_NODE_EVT_MAX_NR];
4968c2ecf20Sopenharmony_ci		node->waiting_evt[node->pending_evt]--;
4978c2ecf20Sopenharmony_ci		/* sync cb has been done */
4988c2ecf20Sopenharmony_ci		schedule_delayed_work(&node->evt_dwork,
4998c2ecf20Sopenharmony_ci				      node->sbi->async_cb_delay * HZ);
5008c2ecf20Sopenharmony_ci	} else {
5018c2ecf20Sopenharmony_ci		node->last_evt = node->pending_evt;
5028c2ecf20Sopenharmony_ci		node->pending_evt = RAW_NODE_EVT_NR;
5038c2ecf20Sopenharmony_ci	}
5048c2ecf20Sopenharmony_ci	mutex_unlock(&node->evt_lock);
5058c2ecf20Sopenharmony_ci}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci/*
5088c2ecf20Sopenharmony_ci * The running orders of cb are:
5098c2ecf20Sopenharmony_ci *
5108c2ecf20Sopenharmony_ci * (1) sync callbacks are invoked according to the queue order of raw events:
5118c2ecf20Sopenharmony_ci *     ensured by seq_lock.
5128c2ecf20Sopenharmony_ci * (2) async callbacks are invoked according to the queue order of raw events:
5138c2ecf20Sopenharmony_ci *     ensured by evt_lock & evt_dwork
5148c2ecf20Sopenharmony_ci * (3) async callback is invoked after sync callback of the same raw event:
5158c2ecf20Sopenharmony_ci *     ensured by seq_lock.
5168c2ecf20Sopenharmony_ci * (4) async callback of N-th raw event and sync callback of (N+x)-th raw
5178c2ecf20Sopenharmony_ci *     event can run concurrently.
5188c2ecf20Sopenharmony_ci */
5198c2ecf20Sopenharmony_cistatic void hmdfs_queue_raw_node_evt(struct hmdfs_peer *node, int evt)
5208c2ecf20Sopenharmony_ci{
5218c2ecf20Sopenharmony_ci	unsigned int seq = 0;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	mutex_lock(&node->evt_lock);
5248c2ecf20Sopenharmony_ci	if (node->pending_evt == RAW_NODE_EVT_NR) {
5258c2ecf20Sopenharmony_ci		if (evt == node->last_evt) {
5268c2ecf20Sopenharmony_ci			node->dup_evt[evt]++;
5278c2ecf20Sopenharmony_ci			mutex_unlock(&node->evt_lock);
5288c2ecf20Sopenharmony_ci			return;
5298c2ecf20Sopenharmony_ci		}
5308c2ecf20Sopenharmony_ci		node->pending_evt = evt;
5318c2ecf20Sopenharmony_ci		seq = hmdfs_node_inc_evt_seq(node);
5328c2ecf20Sopenharmony_ci		node->seq_tbl[(node->seq_wr_idx++) % RAW_NODE_EVT_MAX_NR] = seq;
5338c2ecf20Sopenharmony_ci		node->pending_evt_seq = seq;
5348c2ecf20Sopenharmony_ci		mutex_lock(&node->seq_lock);
5358c2ecf20Sopenharmony_ci		mutex_unlock(&node->evt_lock);
5368c2ecf20Sopenharmony_ci		/* call sync cb, then async cb */
5378c2ecf20Sopenharmony_ci		hmdfs_run_evt_cb_verbosely(node, evt, true, seq);
5388c2ecf20Sopenharmony_ci		mutex_unlock(&node->seq_lock);
5398c2ecf20Sopenharmony_ci		schedule_delayed_work(&node->evt_dwork,
5408c2ecf20Sopenharmony_ci				      node->sbi->async_cb_delay * HZ);
5418c2ecf20Sopenharmony_ci	} else if (hmdfs_update_node_waiting_evt(node, evt, &seq) > 0) {
5428c2ecf20Sopenharmony_ci		/*
5438c2ecf20Sopenharmony_ci		 * Take seq_lock firstly to ensure N-th sync cb
5448c2ecf20Sopenharmony_ci		 * is called before N-th async cb.
5458c2ecf20Sopenharmony_ci		 */
5468c2ecf20Sopenharmony_ci		mutex_lock(&node->seq_lock);
5478c2ecf20Sopenharmony_ci		mutex_unlock(&node->evt_lock);
5488c2ecf20Sopenharmony_ci		hmdfs_run_evt_cb_verbosely(node, evt, true, seq);
5498c2ecf20Sopenharmony_ci		mutex_unlock(&node->seq_lock);
5508c2ecf20Sopenharmony_ci	} else {
5518c2ecf20Sopenharmony_ci		mutex_unlock(&node->evt_lock);
5528c2ecf20Sopenharmony_ci	}
5538c2ecf20Sopenharmony_ci}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_civoid connection_send_handshake(struct connection *conn_impl, __u8 ops,
5568c2ecf20Sopenharmony_ci			       __le16 request_id)
5578c2ecf20Sopenharmony_ci{
5588c2ecf20Sopenharmony_ci	struct tcp_handle *tcp = NULL;
5598c2ecf20Sopenharmony_ci	int err = do_send_handshake(conn_impl, ops, request_id);
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	if (likely(err >= 0))
5628c2ecf20Sopenharmony_ci		return;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	tcp = conn_impl->connect_handle;
5658c2ecf20Sopenharmony_ci	hmdfs_err("Failed to send handshake: err = %d, fd = %d", err, tcp->fd);
5668c2ecf20Sopenharmony_ci	hmdfs_reget_connection(conn_impl);
5678c2ecf20Sopenharmony_ci}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_civoid connection_handshake_notify(struct hmdfs_peer *node, int notify_type)
5708c2ecf20Sopenharmony_ci{
5718c2ecf20Sopenharmony_ci	struct notify_param param;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	param.notify = notify_type;
5748c2ecf20Sopenharmony_ci	param.fd = INVALID_SOCKET_FD;
5758c2ecf20Sopenharmony_ci	memcpy(param.remote_cid, node->cid, HMDFS_CID_SIZE);
5768c2ecf20Sopenharmony_ci	notify(node, &param);
5778c2ecf20Sopenharmony_ci}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_civoid peer_online(struct hmdfs_peer *peer)
5818c2ecf20Sopenharmony_ci{
5828c2ecf20Sopenharmony_ci	// To evaluate if someone else has made the peer online
5838c2ecf20Sopenharmony_ci	u8 prev_stat = xchg(&peer->status, NODE_STAT_ONLINE);
5848c2ecf20Sopenharmony_ci	unsigned long jif_tmp = jiffies;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	if (prev_stat == NODE_STAT_ONLINE)
5878c2ecf20Sopenharmony_ci		return;
5888c2ecf20Sopenharmony_ci	WRITE_ONCE(peer->conn_time, jif_tmp);
5898c2ecf20Sopenharmony_ci	WRITE_ONCE(peer->sbi->connections.recent_ol, jif_tmp);
5908c2ecf20Sopenharmony_ci	hmdfs_queue_raw_node_evt(peer, RAW_NODE_EVT_ON);
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_civoid connection_to_working(struct hmdfs_peer *node)
5948c2ecf20Sopenharmony_ci{
5958c2ecf20Sopenharmony_ci	struct connection *conn_impl = NULL;
5968c2ecf20Sopenharmony_ci	struct tcp_handle *tcp = NULL;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	if (!node)
5998c2ecf20Sopenharmony_ci		return;
6008c2ecf20Sopenharmony_ci	mutex_lock(&node->conn_impl_list_lock);
6018c2ecf20Sopenharmony_ci	list_for_each_entry(conn_impl, &node->conn_impl_list, list) {
6028c2ecf20Sopenharmony_ci		if (conn_impl->type == CONNECT_TYPE_TCP &&
6038c2ecf20Sopenharmony_ci		    conn_impl->status == CONNECT_STAT_WAIT_RESPONSE) {
6048c2ecf20Sopenharmony_ci			tcp = conn_impl->connect_handle;
6058c2ecf20Sopenharmony_ci			hmdfs_info("fd %d to working", tcp->fd);
6068c2ecf20Sopenharmony_ci			conn_impl->status = CONNECT_STAT_WORKING;
6078c2ecf20Sopenharmony_ci		}
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci	mutex_unlock(&node->conn_impl_list_lock);
6108c2ecf20Sopenharmony_ci	peer_online(node);
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_civoid connection_handshake_recv_handler(struct connection *conn_impl, void *buf,
6148c2ecf20Sopenharmony_ci				       void *data, __u32 data_len)
6158c2ecf20Sopenharmony_ci{
6168c2ecf20Sopenharmony_ci	__u8 ops;
6178c2ecf20Sopenharmony_ci	__u8 status;
6188c2ecf20Sopenharmony_ci	int fd = ((struct tcp_handle *)(conn_impl->connect_handle))->fd;
6198c2ecf20Sopenharmony_ci	struct connection_msg_head *head = (struct connection_msg_head *)buf;
6208c2ecf20Sopenharmony_ci	int ret;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	if (head->version != HMDFS_VERSION)
6238c2ecf20Sopenharmony_ci		goto out;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	conn_impl->node->version = head->version;
6268c2ecf20Sopenharmony_ci	ops = head->operations;
6278c2ecf20Sopenharmony_ci	status = conn_impl->status;
6288c2ecf20Sopenharmony_ci	switch (ops) {
6298c2ecf20Sopenharmony_ci	case CONNECT_MESG_HANDSHAKE_REQUEST:
6308c2ecf20Sopenharmony_ci		hmdfs_info(
6318c2ecf20Sopenharmony_ci			"Recved handshake request: device_id = %llu, head->len = %d, tcp->fd = %d",
6328c2ecf20Sopenharmony_ci			conn_impl->node->device_id, head->datasize, fd);
6338c2ecf20Sopenharmony_ci		connection_send_handshake(conn_impl,
6348c2ecf20Sopenharmony_ci					  CONNECT_MESG_HANDSHAKE_RESPONSE,
6358c2ecf20Sopenharmony_ci					  head->msg_id);
6368c2ecf20Sopenharmony_ci		conn_impl->status = CONNECT_STAT_WAIT_ACK;
6378c2ecf20Sopenharmony_ci		conn_impl->node->status = NODE_STAT_SHAKING;
6388c2ecf20Sopenharmony_ci		break;
6398c2ecf20Sopenharmony_ci	case CONNECT_MESG_HANDSHAKE_RESPONSE:
6408c2ecf20Sopenharmony_ci		hmdfs_info(
6418c2ecf20Sopenharmony_ci			"Recved handshake response: device_id = %llu, cmd->status = %hhu, tcp->fd = %d",
6428c2ecf20Sopenharmony_ci			conn_impl->node->device_id, status, fd);
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci		ret = hs_proc_msg_data(conn_impl, ops, data, data_len);
6458c2ecf20Sopenharmony_ci		if (ret)
6468c2ecf20Sopenharmony_ci			goto nego_err;
6478c2ecf20Sopenharmony_ci		connection_send_handshake(conn_impl,
6488c2ecf20Sopenharmony_ci					  CONNECT_MESG_HANDSHAKE_ACK,
6498c2ecf20Sopenharmony_ci					  head->msg_id);
6508c2ecf20Sopenharmony_ci		hmdfs_info("respon rcv handle,conn_impl->crypto=0x%0x",
6518c2ecf20Sopenharmony_ci				conn_impl->crypto);
6528c2ecf20Sopenharmony_ci#ifdef CONFIG_HMDFS_FS_ENCRYPTION
6538c2ecf20Sopenharmony_ci		ret = connection_handshake_init_tls(conn_impl, ops);
6548c2ecf20Sopenharmony_ci		if (ret) {
6558c2ecf20Sopenharmony_ci			hmdfs_err("init_tls_key fail, ops %u", ops);
6568c2ecf20Sopenharmony_ci			goto out;
6578c2ecf20Sopenharmony_ci		}
6588c2ecf20Sopenharmony_ci#endif
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci		conn_impl->status = CONNECT_STAT_WORKING;
6618c2ecf20Sopenharmony_ci		peer_online(conn_impl->node);
6628c2ecf20Sopenharmony_ci		break;
6638c2ecf20Sopenharmony_ci	case CONNECT_MESG_HANDSHAKE_ACK:
6648c2ecf20Sopenharmony_ci		ret = hs_proc_msg_data(conn_impl, ops, data, data_len);
6658c2ecf20Sopenharmony_ci		if (ret)
6668c2ecf20Sopenharmony_ci			goto nego_err;
6678c2ecf20Sopenharmony_ci		hmdfs_info("ack rcv handle, conn_impl->crypto=0x%0x",
6688c2ecf20Sopenharmony_ci				conn_impl->crypto);
6698c2ecf20Sopenharmony_ci#ifdef CONFIG_HMDFS_FS_ENCRYPTION
6708c2ecf20Sopenharmony_ci		ret = connection_handshake_init_tls(conn_impl, ops);
6718c2ecf20Sopenharmony_ci		if (ret) {
6728c2ecf20Sopenharmony_ci			hmdfs_err("init_tls_key fail, ops %u", ops);
6738c2ecf20Sopenharmony_ci			goto out;
6748c2ecf20Sopenharmony_ci		}
6758c2ecf20Sopenharmony_ci#endif
6768c2ecf20Sopenharmony_ci		conn_impl->status = CONNECT_STAT_WORKING;
6778c2ecf20Sopenharmony_ci		peer_online(conn_impl->node);
6788c2ecf20Sopenharmony_ci		break;
6798c2ecf20Sopenharmony_ci		fallthrough;
6808c2ecf20Sopenharmony_ci	default:
6818c2ecf20Sopenharmony_ci		break;
6828c2ecf20Sopenharmony_ci	}
6838c2ecf20Sopenharmony_ciout:
6848c2ecf20Sopenharmony_ci	kfree(data);
6858c2ecf20Sopenharmony_ci	return;
6868c2ecf20Sopenharmony_cinego_err:
6878c2ecf20Sopenharmony_ci	conn_impl->status = CONNECT_STAT_NEGO_FAIL;
6888c2ecf20Sopenharmony_ci	connection_handshake_notify(conn_impl->node, NOTIFY_OFFLINE);
6898c2ecf20Sopenharmony_ci	hmdfs_err("protocol negotiation failed, remote device_id = %llu, tcp->fd = %d",
6908c2ecf20Sopenharmony_ci		  conn_impl->node->device_id, fd);
6918c2ecf20Sopenharmony_ci	goto out;
6928c2ecf20Sopenharmony_ci}
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci#ifdef CONFIG_HMDFS_FS_ENCRYPTION
6958c2ecf20Sopenharmony_cistatic void update_tls_crypto_key(struct connection *conn,
6968c2ecf20Sopenharmony_ci				  struct hmdfs_head_cmd *head, void *data,
6978c2ecf20Sopenharmony_ci				  __u32 data_len)
6988c2ecf20Sopenharmony_ci{
6998c2ecf20Sopenharmony_ci	// rekey message handler
7008c2ecf20Sopenharmony_ci	struct connection_rekey_request *rekey_req = NULL;
7018c2ecf20Sopenharmony_ci	int ret = 0;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	if (hmdfs_message_verify(conn->node, head, data) < 0) {
7048c2ecf20Sopenharmony_ci		hmdfs_err("Rekey msg %d has been abandoned", head->msg_id);
7058c2ecf20Sopenharmony_ci		goto out_err;
7068c2ecf20Sopenharmony_ci	}
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	hmdfs_info("recv REKEY request");
7098c2ecf20Sopenharmony_ci	set_crypto_info(conn, SET_CRYPTO_RECV);
7108c2ecf20Sopenharmony_ci	// update send key if requested
7118c2ecf20Sopenharmony_ci	rekey_req = data;
7128c2ecf20Sopenharmony_ci	if (le32_to_cpu(rekey_req->update_request) == UPDATE_REQUESTED) {
7138c2ecf20Sopenharmony_ci		ret = tcp_send_rekey_request(conn);
7148c2ecf20Sopenharmony_ci		if (ret == 0)
7158c2ecf20Sopenharmony_ci			set_crypto_info(conn, SET_CRYPTO_SEND);
7168c2ecf20Sopenharmony_ci	}
7178c2ecf20Sopenharmony_ciout_err:
7188c2ecf20Sopenharmony_ci	kfree(data);
7198c2ecf20Sopenharmony_ci}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_cistatic bool cmd_update_tls_crypto_key(struct connection *conn,
7228c2ecf20Sopenharmony_ci				      struct hmdfs_head_cmd *head)
7238c2ecf20Sopenharmony_ci{
7248c2ecf20Sopenharmony_ci	struct tcp_handle *tcp = conn->connect_handle;
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	if (conn->type != CONNECT_TYPE_TCP || !tcp)
7278c2ecf20Sopenharmony_ci		return false;
7288c2ecf20Sopenharmony_ci	return head->operations.command == F_CONNECT_REKEY;
7298c2ecf20Sopenharmony_ci}
7308c2ecf20Sopenharmony_ci#endif
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_civoid connection_working_recv_handler(struct connection *conn_impl, void *buf,
7338c2ecf20Sopenharmony_ci				     void *data, __u32 data_len)
7348c2ecf20Sopenharmony_ci{
7358c2ecf20Sopenharmony_ci#ifdef CONFIG_HMDFS_FS_ENCRYPTION
7368c2ecf20Sopenharmony_ci	if (cmd_update_tls_crypto_key(conn_impl, buf)) {
7378c2ecf20Sopenharmony_ci		update_tls_crypto_key(conn_impl, buf, data, data_len);
7388c2ecf20Sopenharmony_ci		return;
7398c2ecf20Sopenharmony_ci	}
7408c2ecf20Sopenharmony_ci#endif
7418c2ecf20Sopenharmony_ci	hmdfs_recv_mesg_callback(conn_impl->node, buf, data);
7428c2ecf20Sopenharmony_ci}
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_cistatic void connection_release(struct kref *ref)
7458c2ecf20Sopenharmony_ci{
7468c2ecf20Sopenharmony_ci	struct tcp_handle *tcp = NULL;
7478c2ecf20Sopenharmony_ci	struct connection *conn = container_of(ref, struct connection, ref_cnt);
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	hmdfs_info("connection release");
7508c2ecf20Sopenharmony_ci	memset(conn->master_key, 0, HMDFS_KEY_SIZE);
7518c2ecf20Sopenharmony_ci	memset(conn->send_key, 0, HMDFS_KEY_SIZE);
7528c2ecf20Sopenharmony_ci	memset(conn->recv_key, 0, HMDFS_KEY_SIZE);
7538c2ecf20Sopenharmony_ci	if (conn->close)
7548c2ecf20Sopenharmony_ci		conn->close(conn);
7558c2ecf20Sopenharmony_ci	tcp = conn->connect_handle;
7568c2ecf20Sopenharmony_ci	crypto_free_aead(conn->tfm);
7578c2ecf20Sopenharmony_ci	// need to check and test: fput(tcp->sock->file);
7588c2ecf20Sopenharmony_ci	if (tcp && tcp->sock) {
7598c2ecf20Sopenharmony_ci		hmdfs_info("connection release: fd = %d, refcount %ld", tcp->fd,
7608c2ecf20Sopenharmony_ci			   file_count(tcp->sock->file));
7618c2ecf20Sopenharmony_ci		sockfd_put(tcp->sock);
7628c2ecf20Sopenharmony_ci	}
7638c2ecf20Sopenharmony_ci	if (tcp && tcp->recv_cache)
7648c2ecf20Sopenharmony_ci		kmem_cache_destroy(tcp->recv_cache);
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	if (!list_empty(&conn->list)) {
7678c2ecf20Sopenharmony_ci		mutex_lock(&conn->node->conn_impl_list_lock);
7688c2ecf20Sopenharmony_ci		list_del(&conn->list);
7698c2ecf20Sopenharmony_ci		mutex_unlock(&conn->node->conn_impl_list_lock);
7708c2ecf20Sopenharmony_ci		/*
7718c2ecf20Sopenharmony_ci		 * wakup hmdfs_disconnect_node to check
7728c2ecf20Sopenharmony_ci		 * conn_deleting_list if empty.
7738c2ecf20Sopenharmony_ci		 */
7748c2ecf20Sopenharmony_ci		wake_up_interruptible(&conn->node->deleting_list_wq);
7758c2ecf20Sopenharmony_ci	}
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	kfree(tcp);
7788c2ecf20Sopenharmony_ci	kfree(conn);
7798c2ecf20Sopenharmony_ci}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_cistatic void hmdfs_peer_release(struct kref *ref)
7828c2ecf20Sopenharmony_ci{
7838c2ecf20Sopenharmony_ci	struct hmdfs_peer *peer = container_of(ref, struct hmdfs_peer, ref_cnt);
7848c2ecf20Sopenharmony_ci	struct mutex *lock = &peer->sbi->connections.node_lock;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	if (!list_empty(&peer->list))
7878c2ecf20Sopenharmony_ci		hmdfs_info("releasing a on-sbi peer: device_id %llu ",
7888c2ecf20Sopenharmony_ci			   peer->device_id);
7898c2ecf20Sopenharmony_ci	else
7908c2ecf20Sopenharmony_ci		hmdfs_info("releasing a redundant peer: device_id %llu ",
7918c2ecf20Sopenharmony_ci			   peer->device_id);
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&peer->evt_dwork);
7948c2ecf20Sopenharmony_ci	list_del(&peer->list);
7958c2ecf20Sopenharmony_ci	idr_destroy(&peer->msg_idr);
7968c2ecf20Sopenharmony_ci	idr_destroy(&peer->file_id_idr);
7978c2ecf20Sopenharmony_ci	flush_workqueue(peer->req_handle_wq);
7988c2ecf20Sopenharmony_ci	flush_workqueue(peer->async_wq);
7998c2ecf20Sopenharmony_ci	flush_workqueue(peer->retry_wb_wq);
8008c2ecf20Sopenharmony_ci	destroy_workqueue(peer->dentry_wq);
8018c2ecf20Sopenharmony_ci	destroy_workqueue(peer->req_handle_wq);
8028c2ecf20Sopenharmony_ci	destroy_workqueue(peer->async_wq);
8038c2ecf20Sopenharmony_ci	destroy_workqueue(peer->retry_wb_wq);
8048c2ecf20Sopenharmony_ci	destroy_workqueue(peer->reget_conn_wq);
8058c2ecf20Sopenharmony_ci	kfree(peer);
8068c2ecf20Sopenharmony_ci	mutex_unlock(lock);
8078c2ecf20Sopenharmony_ci}
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_civoid connection_put(struct connection *conn)
8108c2ecf20Sopenharmony_ci{
8118c2ecf20Sopenharmony_ci	struct mutex *lock = &conn->ref_lock;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	kref_put_mutex(&conn->ref_cnt, connection_release, lock);
8148c2ecf20Sopenharmony_ci}
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_civoid peer_put(struct hmdfs_peer *peer)
8178c2ecf20Sopenharmony_ci{
8188c2ecf20Sopenharmony_ci	struct mutex *lock = &peer->sbi->connections.node_lock;
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	kref_put_mutex(&peer->ref_cnt, hmdfs_peer_release, lock);
8218c2ecf20Sopenharmony_ci}
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_cistatic void hmdfs_dump_deleting_list(struct hmdfs_peer *node)
8248c2ecf20Sopenharmony_ci{
8258c2ecf20Sopenharmony_ci	struct connection *con = NULL;
8268c2ecf20Sopenharmony_ci	struct tcp_handle *tcp = NULL;
8278c2ecf20Sopenharmony_ci	int count = 0;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	mutex_lock(&node->conn_impl_list_lock);
8308c2ecf20Sopenharmony_ci	list_for_each_entry(con, &node->conn_deleting_list, list) {
8318c2ecf20Sopenharmony_ci		tcp = con->connect_handle;
8328c2ecf20Sopenharmony_ci		hmdfs_info("deleting list %d:device_id %llu tcp_fd %d refcnt %d",
8338c2ecf20Sopenharmony_ci			   count, node->device_id, tcp ? tcp->fd : -1,
8348c2ecf20Sopenharmony_ci			   kref_read(&con->ref_cnt));
8358c2ecf20Sopenharmony_ci		count++;
8368c2ecf20Sopenharmony_ci	}
8378c2ecf20Sopenharmony_ci	mutex_unlock(&node->conn_impl_list_lock);
8388c2ecf20Sopenharmony_ci}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_cistatic bool hmdfs_conn_deleting_list_empty(struct hmdfs_peer *node)
8418c2ecf20Sopenharmony_ci{
8428c2ecf20Sopenharmony_ci	bool empty = false;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	mutex_lock(&node->conn_impl_list_lock);
8458c2ecf20Sopenharmony_ci	empty = list_empty(&node->conn_deleting_list);
8468c2ecf20Sopenharmony_ci	mutex_unlock(&node->conn_impl_list_lock);
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	return empty;
8498c2ecf20Sopenharmony_ci}
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_civoid hmdfs_disconnect_node(struct hmdfs_peer *node)
8528c2ecf20Sopenharmony_ci{
8538c2ecf20Sopenharmony_ci	LIST_HEAD(local_conns);
8548c2ecf20Sopenharmony_ci	struct connection *conn_impl = NULL;
8558c2ecf20Sopenharmony_ci	struct connection *next = NULL;
8568c2ecf20Sopenharmony_ci	struct tcp_handle *tcp = NULL;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	if (unlikely(!node))
8598c2ecf20Sopenharmony_ci		return;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	hmdfs_node_inc_evt_seq(node);
8628c2ecf20Sopenharmony_ci	/* Refer to comments in hmdfs_is_node_offlined() */
8638c2ecf20Sopenharmony_ci	smp_mb__after_atomic();
8648c2ecf20Sopenharmony_ci	node->status = NODE_STAT_OFFLINE;
8658c2ecf20Sopenharmony_ci	hmdfs_info("Try to disconnect peer: device_id %llu", node->device_id);
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	mutex_lock(&node->conn_impl_list_lock);
8688c2ecf20Sopenharmony_ci	if (!list_empty(&node->conn_impl_list))
8698c2ecf20Sopenharmony_ci		list_replace_init(&node->conn_impl_list, &local_conns);
8708c2ecf20Sopenharmony_ci	mutex_unlock(&node->conn_impl_list_lock);
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	list_for_each_entry_safe(conn_impl, next, &local_conns, list) {
8738c2ecf20Sopenharmony_ci		tcp = conn_impl->connect_handle;
8748c2ecf20Sopenharmony_ci		if (tcp && tcp->sock) {
8758c2ecf20Sopenharmony_ci			kernel_sock_shutdown(tcp->sock, SHUT_RDWR);
8768c2ecf20Sopenharmony_ci			hmdfs_info("shudown sock: fd = %d, refcount %ld",
8778c2ecf20Sopenharmony_ci				   tcp->fd, file_count(tcp->sock->file));
8788c2ecf20Sopenharmony_ci		}
8798c2ecf20Sopenharmony_ci		if (tcp)
8808c2ecf20Sopenharmony_ci			tcp->fd = INVALID_SOCKET_FD;
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci		tcp_close_socket(tcp);
8838c2ecf20Sopenharmony_ci		list_del_init(&conn_impl->list);
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci		connection_put(conn_impl);
8868c2ecf20Sopenharmony_ci	}
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	if (wait_event_interruptible_timeout(node->deleting_list_wq,
8898c2ecf20Sopenharmony_ci					hmdfs_conn_deleting_list_empty(node),
8908c2ecf20Sopenharmony_ci					HMDFS_WAIT_CONN_RELEASE) <= 0)
8918c2ecf20Sopenharmony_ci		hmdfs_dump_deleting_list(node);
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	/* wait all request process end */
8948c2ecf20Sopenharmony_ci	spin_lock(&node->idr_lock);
8958c2ecf20Sopenharmony_ci	while (node->msg_idr_process) {
8968c2ecf20Sopenharmony_ci		spin_unlock(&node->idr_lock);
8978c2ecf20Sopenharmony_ci		usleep_range(HMDFS_WAIT_REQUEST_END_MIN,
8988c2ecf20Sopenharmony_ci			     HMDFS_WAIT_REQUEST_END_MAX);
8998c2ecf20Sopenharmony_ci		spin_lock(&node->idr_lock);
9008c2ecf20Sopenharmony_ci	}
9018c2ecf20Sopenharmony_ci	spin_unlock(&node->idr_lock);
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	hmdfs_queue_raw_node_evt(node, RAW_NODE_EVT_OFF);
9048c2ecf20Sopenharmony_ci}
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_cistatic void hmdfs_run_simple_evt_cb(struct hmdfs_peer *node, int evt)
9078c2ecf20Sopenharmony_ci{
9088c2ecf20Sopenharmony_ci	unsigned int seq = hmdfs_node_inc_evt_seq(node);
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	mutex_lock(&node->seq_lock);
9118c2ecf20Sopenharmony_ci	hmdfs_node_call_evt_cb(node, evt, true, seq);
9128c2ecf20Sopenharmony_ci	mutex_unlock(&node->seq_lock);
9138c2ecf20Sopenharmony_ci}
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_cistatic void hmdfs_del_peer(struct hmdfs_peer *node)
9168c2ecf20Sopenharmony_ci{
9178c2ecf20Sopenharmony_ci	/*
9188c2ecf20Sopenharmony_ci	 * No need for offline evt cb, because all files must
9198c2ecf20Sopenharmony_ci	 * have been flushed and closed, else the filesystem
9208c2ecf20Sopenharmony_ci	 * will be un-mountable.
9218c2ecf20Sopenharmony_ci	 */
9228c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&node->evt_dwork);
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	hmdfs_run_simple_evt_cb(node, NODE_EVT_DEL);
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	hmdfs_release_peer_sysfs(node);
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	flush_workqueue(node->reget_conn_wq);
9298c2ecf20Sopenharmony_ci	peer_put(node);
9308c2ecf20Sopenharmony_ci}
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_civoid hmdfs_connections_stop(struct hmdfs_sb_info *sbi)
9338c2ecf20Sopenharmony_ci{
9348c2ecf20Sopenharmony_ci	struct hmdfs_peer *node = NULL;
9358c2ecf20Sopenharmony_ci	struct hmdfs_peer *con_tmp = NULL;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	mutex_lock(&sbi->connections.node_lock);
9388c2ecf20Sopenharmony_ci	list_for_each_entry_safe(node, con_tmp, &sbi->connections.node_list,
9398c2ecf20Sopenharmony_ci				  list) {
9408c2ecf20Sopenharmony_ci		mutex_unlock(&sbi->connections.node_lock);
9418c2ecf20Sopenharmony_ci		hmdfs_disconnect_node(node);
9428c2ecf20Sopenharmony_ci		hmdfs_del_peer(node);
9438c2ecf20Sopenharmony_ci		mutex_lock(&sbi->connections.node_lock);
9448c2ecf20Sopenharmony_ci	}
9458c2ecf20Sopenharmony_ci	mutex_unlock(&sbi->connections.node_lock);
9468c2ecf20Sopenharmony_ci}
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_cistruct connection *get_conn_impl(struct hmdfs_peer *node, int connect_type)
9498c2ecf20Sopenharmony_ci{
9508c2ecf20Sopenharmony_ci	struct connection *conn_impl = NULL;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	if (!node)
9538c2ecf20Sopenharmony_ci		return NULL;
9548c2ecf20Sopenharmony_ci	mutex_lock(&node->conn_impl_list_lock);
9558c2ecf20Sopenharmony_ci	list_for_each_entry(conn_impl, &node->conn_impl_list, list) {
9568c2ecf20Sopenharmony_ci		if (conn_impl->type == connect_type &&
9578c2ecf20Sopenharmony_ci		    conn_impl->status == CONNECT_STAT_WORKING) {
9588c2ecf20Sopenharmony_ci			connection_get(conn_impl);
9598c2ecf20Sopenharmony_ci			mutex_unlock(&node->conn_impl_list_lock);
9608c2ecf20Sopenharmony_ci			return conn_impl;
9618c2ecf20Sopenharmony_ci		}
9628c2ecf20Sopenharmony_ci	}
9638c2ecf20Sopenharmony_ci	mutex_unlock(&node->conn_impl_list_lock);
9648c2ecf20Sopenharmony_ci	hmdfs_err_ratelimited("device %llu not find connection, type %d",
9658c2ecf20Sopenharmony_ci			      node->device_id, connect_type);
9668c2ecf20Sopenharmony_ci	return NULL;
9678c2ecf20Sopenharmony_ci}
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_civoid set_conn_sock_quickack(struct hmdfs_peer *node)
9708c2ecf20Sopenharmony_ci{
9718c2ecf20Sopenharmony_ci	struct connection *conn_impl = NULL;
9728c2ecf20Sopenharmony_ci	struct tcp_handle *tcp = NULL;
9738c2ecf20Sopenharmony_ci	int option = 1;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	if (!node)
9768c2ecf20Sopenharmony_ci		return;
9778c2ecf20Sopenharmony_ci	mutex_lock(&node->conn_impl_list_lock);
9788c2ecf20Sopenharmony_ci	list_for_each_entry(conn_impl, &node->conn_impl_list, list) {
9798c2ecf20Sopenharmony_ci		if (conn_impl->type == CONNECT_TYPE_TCP &&
9808c2ecf20Sopenharmony_ci		    conn_impl->status == CONNECT_STAT_WORKING &&
9818c2ecf20Sopenharmony_ci		    conn_impl->connect_handle) {
9828c2ecf20Sopenharmony_ci			tcp = (struct tcp_handle *)(conn_impl->connect_handle);
9838c2ecf20Sopenharmony_ci			tcp_sock_set_quickack(tcp->sock->sk, option);
9848c2ecf20Sopenharmony_ci		}
9858c2ecf20Sopenharmony_ci	}
9868c2ecf20Sopenharmony_ci	mutex_unlock(&node->conn_impl_list_lock);
9878c2ecf20Sopenharmony_ci}
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_cistruct hmdfs_peer *hmdfs_lookup_from_devid(struct hmdfs_sb_info *sbi,
9908c2ecf20Sopenharmony_ci					   uint64_t device_id)
9918c2ecf20Sopenharmony_ci{
9928c2ecf20Sopenharmony_ci	struct hmdfs_peer *con = NULL;
9938c2ecf20Sopenharmony_ci	struct hmdfs_peer *lookup = NULL;
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	if (!sbi)
9968c2ecf20Sopenharmony_ci		return NULL;
9978c2ecf20Sopenharmony_ci	mutex_lock(&sbi->connections.node_lock);
9988c2ecf20Sopenharmony_ci	list_for_each_entry(con, &sbi->connections.node_list, list) {
9998c2ecf20Sopenharmony_ci		if (con->status != NODE_STAT_ONLINE ||
10008c2ecf20Sopenharmony_ci		    con->device_id != device_id)
10018c2ecf20Sopenharmony_ci			continue;
10028c2ecf20Sopenharmony_ci		lookup = con;
10038c2ecf20Sopenharmony_ci		peer_get(lookup);
10048c2ecf20Sopenharmony_ci		break;
10058c2ecf20Sopenharmony_ci	}
10068c2ecf20Sopenharmony_ci	mutex_unlock(&sbi->connections.node_lock);
10078c2ecf20Sopenharmony_ci	return lookup;
10088c2ecf20Sopenharmony_ci}
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_cistruct hmdfs_peer *hmdfs_lookup_from_cid(struct hmdfs_sb_info *sbi,
10118c2ecf20Sopenharmony_ci					 uint8_t *cid)
10128c2ecf20Sopenharmony_ci{
10138c2ecf20Sopenharmony_ci	struct hmdfs_peer *con = NULL;
10148c2ecf20Sopenharmony_ci	struct hmdfs_peer *lookup = NULL;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	if (!sbi)
10178c2ecf20Sopenharmony_ci		return NULL;
10188c2ecf20Sopenharmony_ci	mutex_lock(&sbi->connections.node_lock);
10198c2ecf20Sopenharmony_ci	list_for_each_entry(con, &sbi->connections.node_list, list) {
10208c2ecf20Sopenharmony_ci		if (strncmp(con->cid, cid, HMDFS_CID_SIZE) != 0)
10218c2ecf20Sopenharmony_ci			continue;
10228c2ecf20Sopenharmony_ci		lookup = con;
10238c2ecf20Sopenharmony_ci		peer_get(lookup);
10248c2ecf20Sopenharmony_ci		break;
10258c2ecf20Sopenharmony_ci	}
10268c2ecf20Sopenharmony_ci	mutex_unlock(&sbi->connections.node_lock);
10278c2ecf20Sopenharmony_ci	return lookup;
10288c2ecf20Sopenharmony_ci}
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_cistatic struct hmdfs_peer *lookup_peer_by_cid_unsafe(struct hmdfs_sb_info *sbi,
10318c2ecf20Sopenharmony_ci						    uint8_t *cid)
10328c2ecf20Sopenharmony_ci{
10338c2ecf20Sopenharmony_ci	struct hmdfs_peer *node = NULL;
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	list_for_each_entry(node, &sbi->connections.node_list, list)
10368c2ecf20Sopenharmony_ci		if (!strncmp(node->cid, cid, HMDFS_CID_SIZE)) {
10378c2ecf20Sopenharmony_ci			peer_get(node);
10388c2ecf20Sopenharmony_ci			return node;
10398c2ecf20Sopenharmony_ci		}
10408c2ecf20Sopenharmony_ci	return NULL;
10418c2ecf20Sopenharmony_ci}
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_cistatic struct hmdfs_peer *add_peer_unsafe(struct hmdfs_sb_info *sbi,
10448c2ecf20Sopenharmony_ci					  struct hmdfs_peer *peer2add)
10458c2ecf20Sopenharmony_ci{
10468c2ecf20Sopenharmony_ci	struct hmdfs_peer *peer;
10478c2ecf20Sopenharmony_ci	int err;
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	peer = lookup_peer_by_cid_unsafe(sbi, peer2add->cid);
10508c2ecf20Sopenharmony_ci	if (peer)
10518c2ecf20Sopenharmony_ci		return peer;
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	err = hmdfs_register_peer_sysfs(sbi, peer2add);
10548c2ecf20Sopenharmony_ci	if (err) {
10558c2ecf20Sopenharmony_ci		hmdfs_err("register peer %llu sysfs err %d",
10568c2ecf20Sopenharmony_ci			  peer2add->device_id, err);
10578c2ecf20Sopenharmony_ci		return ERR_PTR(err);
10588c2ecf20Sopenharmony_ci	}
10598c2ecf20Sopenharmony_ci	list_add_tail(&peer2add->list, &sbi->connections.node_list);
10608c2ecf20Sopenharmony_ci	peer_get(peer2add);
10618c2ecf20Sopenharmony_ci	hmdfs_run_simple_evt_cb(peer2add, NODE_EVT_ADD);
10628c2ecf20Sopenharmony_ci	return peer2add;
10638c2ecf20Sopenharmony_ci}
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_cistatic struct hmdfs_peer *alloc_peer(struct hmdfs_sb_info *sbi, uint8_t *cid,
10668c2ecf20Sopenharmony_ci	uint32_t devsl)
10678c2ecf20Sopenharmony_ci{
10688c2ecf20Sopenharmony_ci	struct hmdfs_peer *node = kzalloc(sizeof(*node), GFP_KERNEL);
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	if (!node)
10718c2ecf20Sopenharmony_ci		return NULL;
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	node->device_id = (u32)atomic_inc_return(&sbi->connections.conn_seq);
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	node->async_wq = alloc_workqueue("dfs_async%u_%llu", WQ_MEM_RECLAIM, 0,
10768c2ecf20Sopenharmony_ci					 sbi->seq, node->device_id);
10778c2ecf20Sopenharmony_ci	if (!node->async_wq) {
10788c2ecf20Sopenharmony_ci		hmdfs_err("Failed to alloc async wq");
10798c2ecf20Sopenharmony_ci		goto out_err;
10808c2ecf20Sopenharmony_ci	}
10818c2ecf20Sopenharmony_ci	node->req_handle_wq = alloc_workqueue("dfs_req%u_%llu",
10828c2ecf20Sopenharmony_ci					      WQ_UNBOUND | WQ_MEM_RECLAIM,
10838c2ecf20Sopenharmony_ci					      sbi->async_req_max_active,
10848c2ecf20Sopenharmony_ci					      sbi->seq, node->device_id);
10858c2ecf20Sopenharmony_ci	if (!node->req_handle_wq) {
10868c2ecf20Sopenharmony_ci		hmdfs_err("Failed to alloc req wq");
10878c2ecf20Sopenharmony_ci		goto out_err;
10888c2ecf20Sopenharmony_ci	}
10898c2ecf20Sopenharmony_ci	node->dentry_wq = alloc_workqueue("dfs_dentry%u_%llu",
10908c2ecf20Sopenharmony_ci					   WQ_UNBOUND | WQ_MEM_RECLAIM,
10918c2ecf20Sopenharmony_ci					   0, sbi->seq, node->device_id);
10928c2ecf20Sopenharmony_ci	if (!node->dentry_wq) {
10938c2ecf20Sopenharmony_ci		hmdfs_err("Failed to alloc dentry wq");
10948c2ecf20Sopenharmony_ci		goto out_err;
10958c2ecf20Sopenharmony_ci	}
10968c2ecf20Sopenharmony_ci	node->retry_wb_wq = alloc_workqueue("dfs_rwb%u_%llu",
10978c2ecf20Sopenharmony_ci					   WQ_UNBOUND | WQ_MEM_RECLAIM,
10988c2ecf20Sopenharmony_ci					   HMDFS_RETRY_WB_WQ_MAX_ACTIVE,
10998c2ecf20Sopenharmony_ci					   sbi->seq, node->device_id);
11008c2ecf20Sopenharmony_ci	if (!node->retry_wb_wq) {
11018c2ecf20Sopenharmony_ci		hmdfs_err("Failed to alloc retry writeback wq");
11028c2ecf20Sopenharmony_ci		goto out_err;
11038c2ecf20Sopenharmony_ci	}
11048c2ecf20Sopenharmony_ci	node->reget_conn_wq = alloc_workqueue("dfs_regetcon%u_%llu",
11058c2ecf20Sopenharmony_ci					      WQ_UNBOUND, 0,
11068c2ecf20Sopenharmony_ci					      sbi->seq, node->device_id);
11078c2ecf20Sopenharmony_ci	if (!node->reget_conn_wq) {
11088c2ecf20Sopenharmony_ci		hmdfs_err("Failed to alloc reget conn wq");
11098c2ecf20Sopenharmony_ci		goto out_err;
11108c2ecf20Sopenharmony_ci	}
11118c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&node->conn_impl_list);
11128c2ecf20Sopenharmony_ci	mutex_init(&node->conn_impl_list_lock);
11138c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&node->conn_deleting_list);
11148c2ecf20Sopenharmony_ci	init_waitqueue_head(&node->deleting_list_wq);
11158c2ecf20Sopenharmony_ci	idr_init(&node->msg_idr);
11168c2ecf20Sopenharmony_ci	spin_lock_init(&node->idr_lock);
11178c2ecf20Sopenharmony_ci	idr_init(&node->file_id_idr);
11188c2ecf20Sopenharmony_ci	spin_lock_init(&node->file_id_lock);
11198c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&node->list);
11208c2ecf20Sopenharmony_ci	kref_init(&node->ref_cnt);
11218c2ecf20Sopenharmony_ci	node->owner = sbi->seq;
11228c2ecf20Sopenharmony_ci	node->sbi = sbi;
11238c2ecf20Sopenharmony_ci	node->version = HMDFS_VERSION;
11248c2ecf20Sopenharmony_ci	node->status = NODE_STAT_SHAKING;
11258c2ecf20Sopenharmony_ci	node->conn_time = jiffies;
11268c2ecf20Sopenharmony_ci	memcpy(node->cid, cid, HMDFS_CID_SIZE);
11278c2ecf20Sopenharmony_ci	atomic64_set(&node->sb_dirty_count, 0);
11288c2ecf20Sopenharmony_ci	node->fid_cookie = 0;
11298c2ecf20Sopenharmony_ci	atomic_set(&node->evt_seq, 0);
11308c2ecf20Sopenharmony_ci	mutex_init(&node->seq_lock);
11318c2ecf20Sopenharmony_ci	mutex_init(&node->offline_cb_lock);
11328c2ecf20Sopenharmony_ci	mutex_init(&node->evt_lock);
11338c2ecf20Sopenharmony_ci	node->pending_evt = RAW_NODE_EVT_NR;
11348c2ecf20Sopenharmony_ci	node->last_evt = RAW_NODE_EVT_NR;
11358c2ecf20Sopenharmony_ci	node->cur_evt[0] = RAW_NODE_EVT_NR;
11368c2ecf20Sopenharmony_ci	node->cur_evt[1] = RAW_NODE_EVT_NR;
11378c2ecf20Sopenharmony_ci	node->seq_wr_idx = (unsigned char)UINT_MAX;
11388c2ecf20Sopenharmony_ci	node->seq_rd_idx = node->seq_wr_idx;
11398c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&node->evt_dwork, hmdfs_node_evt_work);
11408c2ecf20Sopenharmony_ci	node->msg_idr_process = 0;
11418c2ecf20Sopenharmony_ci	node->offline_start = false;
11428c2ecf20Sopenharmony_ci	spin_lock_init(&node->wr_opened_inode_lock);
11438c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&node->wr_opened_inode_list);
11448c2ecf20Sopenharmony_ci	spin_lock_init(&node->stashed_inode_lock);
11458c2ecf20Sopenharmony_ci	node->stashed_inode_nr = 0;
11468c2ecf20Sopenharmony_ci	atomic_set(&node->rebuild_inode_status_nr, 0);
11478c2ecf20Sopenharmony_ci	init_waitqueue_head(&node->rebuild_inode_status_wq);
11488c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&node->stashed_inode_list);
11498c2ecf20Sopenharmony_ci	node->need_rebuild_stash_list = false;
11508c2ecf20Sopenharmony_ci	node->devsl = devsl;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	return node;
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ciout_err:
11558c2ecf20Sopenharmony_ci	if (node->async_wq) {
11568c2ecf20Sopenharmony_ci		destroy_workqueue(node->async_wq);
11578c2ecf20Sopenharmony_ci		node->async_wq = NULL;
11588c2ecf20Sopenharmony_ci	}
11598c2ecf20Sopenharmony_ci	if (node->req_handle_wq) {
11608c2ecf20Sopenharmony_ci		destroy_workqueue(node->req_handle_wq);
11618c2ecf20Sopenharmony_ci		node->req_handle_wq = NULL;
11628c2ecf20Sopenharmony_ci	}
11638c2ecf20Sopenharmony_ci	if (node->dentry_wq) {
11648c2ecf20Sopenharmony_ci		destroy_workqueue(node->dentry_wq);
11658c2ecf20Sopenharmony_ci		node->dentry_wq = NULL;
11668c2ecf20Sopenharmony_ci	}
11678c2ecf20Sopenharmony_ci	if (node->retry_wb_wq) {
11688c2ecf20Sopenharmony_ci		destroy_workqueue(node->retry_wb_wq);
11698c2ecf20Sopenharmony_ci		node->retry_wb_wq = NULL;
11708c2ecf20Sopenharmony_ci	}
11718c2ecf20Sopenharmony_ci	if (node->reget_conn_wq) {
11728c2ecf20Sopenharmony_ci		destroy_workqueue(node->reget_conn_wq);
11738c2ecf20Sopenharmony_ci		node->reget_conn_wq = NULL;
11748c2ecf20Sopenharmony_ci	}
11758c2ecf20Sopenharmony_ci	kfree(node);
11768c2ecf20Sopenharmony_ci	return NULL;
11778c2ecf20Sopenharmony_ci}
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_cistruct hmdfs_peer *hmdfs_get_peer(struct hmdfs_sb_info *sbi, uint8_t *cid,
11808c2ecf20Sopenharmony_ci	uint32_t devsl)
11818c2ecf20Sopenharmony_ci{
11828c2ecf20Sopenharmony_ci	struct hmdfs_peer *peer = NULL, *on_sbi_peer = NULL;
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	mutex_lock(&sbi->connections.node_lock);
11858c2ecf20Sopenharmony_ci	peer = lookup_peer_by_cid_unsafe(sbi, cid);
11868c2ecf20Sopenharmony_ci	mutex_unlock(&sbi->connections.node_lock);
11878c2ecf20Sopenharmony_ci	if (peer) {
11888c2ecf20Sopenharmony_ci		hmdfs_info("Got a existing peer: device_id = %llu",
11898c2ecf20Sopenharmony_ci			   peer->device_id);
11908c2ecf20Sopenharmony_ci		goto out;
11918c2ecf20Sopenharmony_ci	}
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	peer = alloc_peer(sbi, cid, devsl);
11948c2ecf20Sopenharmony_ci	if (unlikely(!peer)) {
11958c2ecf20Sopenharmony_ci		hmdfs_info("Failed to alloc a peer");
11968c2ecf20Sopenharmony_ci		goto out;
11978c2ecf20Sopenharmony_ci	}
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	mutex_lock(&sbi->connections.node_lock);
12008c2ecf20Sopenharmony_ci	on_sbi_peer = add_peer_unsafe(sbi, peer);
12018c2ecf20Sopenharmony_ci	mutex_unlock(&sbi->connections.node_lock);
12028c2ecf20Sopenharmony_ci	if (IS_ERR(on_sbi_peer)) {
12038c2ecf20Sopenharmony_ci		peer_put(peer);
12048c2ecf20Sopenharmony_ci		peer = NULL;
12058c2ecf20Sopenharmony_ci		goto out;
12068c2ecf20Sopenharmony_ci	} else if (unlikely(on_sbi_peer != peer)) {
12078c2ecf20Sopenharmony_ci		hmdfs_info("Got a existing peer: device_id = %llu",
12088c2ecf20Sopenharmony_ci			   on_sbi_peer->device_id);
12098c2ecf20Sopenharmony_ci		peer_put(peer);
12108c2ecf20Sopenharmony_ci		peer = on_sbi_peer;
12118c2ecf20Sopenharmony_ci	} else {
12128c2ecf20Sopenharmony_ci		hmdfs_info("Got a newly allocated peer: device_id = %llu",
12138c2ecf20Sopenharmony_ci			   peer->device_id);
12148c2ecf20Sopenharmony_ci	}
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ciout:
12178c2ecf20Sopenharmony_ci	return peer;
12188c2ecf20Sopenharmony_ci}
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_cistatic void head_release(struct kref *kref)
12218c2ecf20Sopenharmony_ci{
12228c2ecf20Sopenharmony_ci	struct hmdfs_msg_idr_head *head;
12238c2ecf20Sopenharmony_ci	struct hmdfs_peer *con;
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	head = (struct hmdfs_msg_idr_head *)container_of(kref,
12268c2ecf20Sopenharmony_ci			struct hmdfs_msg_idr_head, ref);
12278c2ecf20Sopenharmony_ci	con = head->peer;
12288c2ecf20Sopenharmony_ci	idr_remove(&con->msg_idr, head->msg_id);
12298c2ecf20Sopenharmony_ci	spin_unlock(&con->idr_lock);
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	kfree(head);
12328c2ecf20Sopenharmony_ci}
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_civoid head_put(struct hmdfs_msg_idr_head *head)
12358c2ecf20Sopenharmony_ci{
12368c2ecf20Sopenharmony_ci	kref_put_lock(&head->ref, head_release, &head->peer->idr_lock);
12378c2ecf20Sopenharmony_ci}
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_cistruct hmdfs_msg_idr_head *hmdfs_find_msg_head(struct hmdfs_peer *peer,
12408c2ecf20Sopenharmony_ci					int id, struct hmdfs_cmd operations)
12418c2ecf20Sopenharmony_ci{
12428c2ecf20Sopenharmony_ci	struct hmdfs_msg_idr_head *head = NULL;
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci	spin_lock(&peer->idr_lock);
12458c2ecf20Sopenharmony_ci	head = idr_find(&peer->msg_idr, id);
12468c2ecf20Sopenharmony_ci	if (head && head->send_cmd_operations.command == operations.command)
12478c2ecf20Sopenharmony_ci		kref_get(&head->ref);
12488c2ecf20Sopenharmony_ci	else
12498c2ecf20Sopenharmony_ci		head = NULL;
12508c2ecf20Sopenharmony_ci	spin_unlock(&peer->idr_lock);
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	return head;
12538c2ecf20Sopenharmony_ci}
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ciint hmdfs_alloc_msg_idr(struct hmdfs_peer *peer, enum MSG_IDR_TYPE type,
12568c2ecf20Sopenharmony_ci			void *ptr, struct hmdfs_cmd operations)
12578c2ecf20Sopenharmony_ci{
12588c2ecf20Sopenharmony_ci	int ret = -EAGAIN;
12598c2ecf20Sopenharmony_ci	struct hmdfs_msg_idr_head *head = ptr;
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	idr_preload(GFP_KERNEL);
12628c2ecf20Sopenharmony_ci	spin_lock(&peer->idr_lock);
12638c2ecf20Sopenharmony_ci	if (!peer->offline_start)
12648c2ecf20Sopenharmony_ci		ret = idr_alloc_cyclic(&peer->msg_idr, ptr,
12658c2ecf20Sopenharmony_ci				       1, 0, GFP_NOWAIT);
12668c2ecf20Sopenharmony_ci	if (ret >= 0) {
12678c2ecf20Sopenharmony_ci		kref_init(&head->ref);
12688c2ecf20Sopenharmony_ci		head->msg_id = ret;
12698c2ecf20Sopenharmony_ci		head->type = type;
12708c2ecf20Sopenharmony_ci		head->peer = peer;
12718c2ecf20Sopenharmony_ci		head->send_cmd_operations = operations;
12728c2ecf20Sopenharmony_ci		peer->msg_idr_process++;
12738c2ecf20Sopenharmony_ci		ret = 0;
12748c2ecf20Sopenharmony_ci	}
12758c2ecf20Sopenharmony_ci	spin_unlock(&peer->idr_lock);
12768c2ecf20Sopenharmony_ci	idr_preload_end();
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	return ret;
12798c2ecf20Sopenharmony_ci}
1280