1 /* SPDX-License-Identifier: GPL-2.0+ */ 2 /* 3 * SSH message builder functions. 4 * 5 * Copyright (C) 2019-2020 Maximilian Luz <luzmaximilian@gmail.com> 6 */ 7 8 #ifndef _SURFACE_AGGREGATOR_SSH_MSGB_H 9 #define _SURFACE_AGGREGATOR_SSH_MSGB_H 10 11 #include <asm/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 buffer 21 * space. 22 * @ptr: Pointer to the first free element in the buffer. 23 */ 24 struct 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 initialize 33 * @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 as 37 * backing. 38 */ 39 static 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 */ 50 static inline size_t msgb_bytes_used(const struct msgbuf *msgb) 51 { 52 return msgb->ptr - msgb->begin; 53 } 54 55 static inline void __msgb_push_u8(struct msgbuf *msgb, u8 value) 56 { 57 *msgb->ptr = value; 58 msgb->ptr += sizeof(u8); 59 } 60 61 static 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 */ 72 static 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 */ 84 static 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 */ 95 static 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 */ 106 static 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 buffer 114 * @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 */ 118 static 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 buffer 135 * @seq: The sequence ID of the frame/packet to be ACKed. 136 */ 137 static 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 buffer 152 */ 153 static 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 */ 172 static 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 (out). */ 193 __msgb_push_u8(msgb, 0x00); /* Target ID (in). */ 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