206 lines · c
1/* SPDX-License-Identifier: GPL-2.0+ */2/*3 * SSH message builder functions.4 *5 * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>6 */7 8#ifndef _SURFACE_AGGREGATOR_SSH_MSGB_H9#define _SURFACE_AGGREGATOR_SSH_MSGB_H10 11#include <linux/unaligned.h>12#include <linux/types.h>13 14#include <linux/surface_aggregator/controller.h>15#include <linux/surface_aggregator/serial_hub.h>16 17/**18 * struct msgbuf - Buffer struct to construct SSH messages.19 * @begin: Pointer to the beginning of the allocated buffer space.20 * @end: Pointer to the end (one past last element) of the allocated buffer21 * space.22 * @ptr: Pointer to the first free element in the buffer.23 */24struct msgbuf {25 u8 *begin;26 u8 *end;27 u8 *ptr;28};29 30/**31 * msgb_init() - Initialize the given message buffer struct.32 * @msgb: The buffer struct to initialize33 * @ptr: Pointer to the underlying memory by which the buffer will be backed.34 * @cap: Size of the underlying memory.35 *36 * Initialize the given message buffer struct using the provided memory as37 * backing.38 */39static inline void msgb_init(struct msgbuf *msgb, u8 *ptr, size_t cap)40{41 msgb->begin = ptr;42 msgb->end = ptr + cap;43 msgb->ptr = ptr;44}45 46/**47 * msgb_bytes_used() - Return the current number of bytes used in the buffer.48 * @msgb: The message buffer.49 */50static inline size_t msgb_bytes_used(const struct msgbuf *msgb)51{52 return msgb->ptr - msgb->begin;53}54 55static inline void __msgb_push_u8(struct msgbuf *msgb, u8 value)56{57 *msgb->ptr = value;58 msgb->ptr += sizeof(u8);59}60 61static inline void __msgb_push_u16(struct msgbuf *msgb, u16 value)62{63 put_unaligned_le16(value, msgb->ptr);64 msgb->ptr += sizeof(u16);65}66 67/**68 * msgb_push_u16() - Push a u16 value to the buffer.69 * @msgb: The message buffer.70 * @value: The value to push to the buffer.71 */72static inline void msgb_push_u16(struct msgbuf *msgb, u16 value)73{74 if (WARN_ON(msgb->ptr + sizeof(u16) > msgb->end))75 return;76 77 __msgb_push_u16(msgb, value);78}79 80/**81 * msgb_push_syn() - Push SSH SYN bytes to the buffer.82 * @msgb: The message buffer.83 */84static inline void msgb_push_syn(struct msgbuf *msgb)85{86 msgb_push_u16(msgb, SSH_MSG_SYN);87}88 89/**90 * msgb_push_buf() - Push raw data to the buffer.91 * @msgb: The message buffer.92 * @buf: The data to push to the buffer.93 * @len: The length of the data to push to the buffer.94 */95static inline void msgb_push_buf(struct msgbuf *msgb, const u8 *buf, size_t len)96{97 msgb->ptr = memcpy(msgb->ptr, buf, len) + len;98}99 100/**101 * msgb_push_crc() - Compute CRC and push it to the buffer.102 * @msgb: The message buffer.103 * @buf: The data for which the CRC should be computed.104 * @len: The length of the data for which the CRC should be computed.105 */106static inline void msgb_push_crc(struct msgbuf *msgb, const u8 *buf, size_t len)107{108 msgb_push_u16(msgb, ssh_crc(buf, len));109}110 111/**112 * msgb_push_frame() - Push a SSH message frame header to the buffer.113 * @msgb: The message buffer114 * @ty: The type of the frame.115 * @len: The length of the payload of the frame.116 * @seq: The sequence ID of the frame/packet.117 */118static inline void msgb_push_frame(struct msgbuf *msgb, u8 ty, u16 len, u8 seq)119{120 u8 *const begin = msgb->ptr;121 122 if (WARN_ON(msgb->ptr + sizeof(struct ssh_frame) > msgb->end))123 return;124 125 __msgb_push_u8(msgb, ty); /* Frame type. */126 __msgb_push_u16(msgb, len); /* Frame payload length. */127 __msgb_push_u8(msgb, seq); /* Frame sequence ID. */128 129 msgb_push_crc(msgb, begin, msgb->ptr - begin);130}131 132/**133 * msgb_push_ack() - Push a SSH ACK frame to the buffer.134 * @msgb: The message buffer135 * @seq: The sequence ID of the frame/packet to be ACKed.136 */137static inline void msgb_push_ack(struct msgbuf *msgb, u8 seq)138{139 /* SYN. */140 msgb_push_syn(msgb);141 142 /* ACK-type frame + CRC. */143 msgb_push_frame(msgb, SSH_FRAME_TYPE_ACK, 0x00, seq);144 145 /* Payload CRC (ACK-type frames do not have a payload). */146 msgb_push_crc(msgb, msgb->ptr, 0);147}148 149/**150 * msgb_push_nak() - Push a SSH NAK frame to the buffer.151 * @msgb: The message buffer152 */153static inline void msgb_push_nak(struct msgbuf *msgb)154{155 /* SYN. */156 msgb_push_syn(msgb);157 158 /* NAK-type frame + CRC. */159 msgb_push_frame(msgb, SSH_FRAME_TYPE_NAK, 0x00, 0x00);160 161 /* Payload CRC (ACK-type frames do not have a payload). */162 msgb_push_crc(msgb, msgb->ptr, 0);163}164 165/**166 * msgb_push_cmd() - Push a SSH command frame with payload to the buffer.167 * @msgb: The message buffer.168 * @seq: The sequence ID (SEQ) of the frame/packet.169 * @rqid: The request ID (RQID) of the request contained in the frame.170 * @rqst: The request to wrap in the frame.171 */172static inline void msgb_push_cmd(struct msgbuf *msgb, u8 seq, u16 rqid,173 const struct ssam_request *rqst)174{175 const u8 type = SSH_FRAME_TYPE_DATA_SEQ;176 u8 *cmd;177 178 /* SYN. */179 msgb_push_syn(msgb);180 181 /* Command frame + CRC. */182 msgb_push_frame(msgb, type, sizeof(struct ssh_command) + rqst->length, seq);183 184 /* Frame payload: Command struct + payload. */185 if (WARN_ON(msgb->ptr + sizeof(struct ssh_command) > msgb->end))186 return;187 188 cmd = msgb->ptr;189 190 __msgb_push_u8(msgb, SSH_PLD_TYPE_CMD); /* Payload type. */191 __msgb_push_u8(msgb, rqst->target_category); /* Target category. */192 __msgb_push_u8(msgb, rqst->target_id); /* Target ID. */193 __msgb_push_u8(msgb, SSAM_SSH_TID_HOST); /* Source ID. */194 __msgb_push_u8(msgb, rqst->instance_id); /* Instance ID. */195 __msgb_push_u16(msgb, rqid); /* Request ID. */196 __msgb_push_u8(msgb, rqst->command_id); /* Command ID. */197 198 /* Command payload. */199 msgb_push_buf(msgb, rqst->payload, rqst->length);200 201 /* CRC for command struct + payload. */202 msgb_push_crc(msgb, cmd, msgb->ptr - cmd);203}204 205#endif /* _SURFACE_AGGREGATOR_SSH_MSGB_H */206