| // SPDX-License-Identifier: GPL-2.0-only | |
| /****************************************************************************** | |
| ******************************************************************************* | |
| ** | |
| ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | |
| ** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. | |
| ** | |
| ** | |
| ******************************************************************************* | |
| ******************************************************************************/ | |
| /* | |
| * midcomms.c | |
| * | |
| * This is the appallingly named "mid-level" comms layer. | |
| * | |
| * Its purpose is to take packets from the "real" comms layer, | |
| * split them up into packets and pass them to the interested | |
| * part of the locking mechanism. | |
| * | |
| * It also takes messages from the locking layer, formats them | |
| * into packets and sends them to the comms layer. | |
| */ | |
| #include <asm/unaligned.h> | |
| #include "dlm_internal.h" | |
| #include "lowcomms.h" | |
| #include "config.h" | |
| #include "lock.h" | |
| #include "midcomms.h" | |
| /* | |
| * Called from the low-level comms layer to process a buffer of | |
| * commands. | |
| */ | |
| int dlm_process_incoming_buffer(int nodeid, unsigned char *buf, int len) | |
| { | |
| const unsigned char *ptr = buf; | |
| const struct dlm_header *hd; | |
| uint16_t msglen; | |
| int ret = 0; | |
| while (len >= sizeof(struct dlm_header)) { | |
| hd = (struct dlm_header *)ptr; | |
| /* no message should be more than this otherwise we | |
| * cannot deliver this message to upper layers | |
| */ | |
| msglen = get_unaligned_le16(&hd->h_length); | |
| if (msglen > DEFAULT_BUFFER_SIZE) { | |
| log_print("received invalid length header: %u, will abort message parsing", | |
| msglen); | |
| return -EBADMSG; | |
| } | |
| /* caller will take care that leftover | |
| * will be parsed next call with more data | |
| */ | |
| if (msglen > len) | |
| break; | |
| switch (hd->h_cmd) { | |
| case DLM_MSG: | |
| if (msglen < sizeof(struct dlm_message)) { | |
| log_print("dlm msg too small: %u, will skip this message", | |
| msglen); | |
| goto skip; | |
| } | |
| break; | |
| case DLM_RCOM: | |
| if (msglen < sizeof(struct dlm_rcom)) { | |
| log_print("dlm rcom msg too small: %u, will skip this message", | |
| msglen); | |
| goto skip; | |
| } | |
| break; | |
| default: | |
| log_print("unsupported h_cmd received: %u, will skip this message", | |
| hd->h_cmd); | |
| goto skip; | |
| } | |
| /* for aligned memory access, we just copy current message | |
| * to begin of the buffer which contains already parsed buffer | |
| * data and should provide align access for upper layers | |
| * because the start address of the buffer has a aligned | |
| * address. This memmove can be removed when the upperlayer | |
| * is capable of unaligned memory access. | |
| */ | |
| memmove(buf, ptr, msglen); | |
| dlm_receive_buffer((union dlm_packet *)buf, nodeid); | |
| skip: | |
| ret += msglen; | |
| len -= msglen; | |
| ptr += msglen; | |
| } | |
| return ret; | |
| } | |