xref: /kernel/linux/linux-5.10/fs/dlm/midcomms.c (revision 8c2ecf20)
1// SPDX-License-Identifier: GPL-2.0-only
2/******************************************************************************
3*******************************************************************************
4**
5**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
6**  Copyright (C) 2004-2008 Red Hat, Inc.  All rights reserved.
7**
8**
9*******************************************************************************
10******************************************************************************/
11
12/*
13 * midcomms.c
14 *
15 * This is the appallingly named "mid-level" comms layer.
16 *
17 * Its purpose is to take packets from the "real" comms layer,
18 * split them up into packets and pass them to the interested
19 * part of the locking mechanism.
20 *
21 * It also takes messages from the locking layer, formats them
22 * into packets and sends them to the comms layer.
23 */
24
25#include <asm/unaligned.h>
26
27#include "dlm_internal.h"
28#include "lowcomms.h"
29#include "config.h"
30#include "lock.h"
31#include "midcomms.h"
32
33/*
34 * Called from the low-level comms layer to process a buffer of
35 * commands.
36 */
37
38int dlm_process_incoming_buffer(int nodeid, unsigned char *buf, int len)
39{
40	const unsigned char *ptr = buf;
41	const struct dlm_header *hd;
42	uint16_t msglen;
43	int ret = 0;
44
45	while (len >= sizeof(struct dlm_header)) {
46		hd = (struct dlm_header *)ptr;
47
48		/* no message should be more than this otherwise we
49		 * cannot deliver this message to upper layers
50		 */
51		msglen = get_unaligned_le16(&hd->h_length);
52		if (msglen > DEFAULT_BUFFER_SIZE ||
53		    msglen < sizeof(struct dlm_header)) {
54			log_print("received invalid length header: %u from node %d, will abort message parsing",
55				  msglen, nodeid);
56			return -EBADMSG;
57		}
58
59		/* caller will take care that leftover
60		 * will be parsed next call with more data
61		 */
62		if (msglen > len)
63			break;
64
65		switch (hd->h_cmd) {
66		case DLM_MSG:
67			if (msglen < sizeof(struct dlm_message)) {
68				log_print("dlm msg too small: %u, will skip this message",
69					  msglen);
70				goto skip;
71			}
72
73			break;
74		case DLM_RCOM:
75			if (msglen < sizeof(struct dlm_rcom)) {
76				log_print("dlm rcom msg too small: %u, will skip this message",
77					  msglen);
78				goto skip;
79			}
80
81			break;
82		default:
83			log_print("unsupported h_cmd received: %u, will skip this message",
84				  hd->h_cmd);
85			goto skip;
86		}
87
88		/* for aligned memory access, we just copy current message
89		 * to begin of the buffer which contains already parsed buffer
90		 * data and should provide align access for upper layers
91		 * because the start address of the buffer has a aligned
92		 * address. This memmove can be removed when the upperlayer
93		 * is capable of unaligned memory access.
94		 */
95		memmove(buf, ptr, msglen);
96		dlm_receive_buffer((union dlm_packet *)buf, nodeid);
97
98skip:
99		ret += msglen;
100		len -= msglen;
101		ptr += msglen;
102	}
103
104	return ret;
105}
106
107