Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0+ */
0002 /*
0003  * SSH message builder functions.
0004  *
0005  * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com>
0006  */
0007 
0008 #ifndef _SURFACE_AGGREGATOR_SSH_MSGB_H
0009 #define _SURFACE_AGGREGATOR_SSH_MSGB_H
0010 
0011 #include <asm/unaligned.h>
0012 #include <linux/types.h>
0013 
0014 #include <linux/surface_aggregator/controller.h>
0015 #include <linux/surface_aggregator/serial_hub.h>
0016 
0017 /**
0018  * struct msgbuf - Buffer struct to construct SSH messages.
0019  * @begin: Pointer to the beginning of the allocated buffer space.
0020  * @end:   Pointer to the end (one past last element) of the allocated buffer
0021  *         space.
0022  * @ptr:   Pointer to the first free element in the buffer.
0023  */
0024 struct msgbuf {
0025     u8 *begin;
0026     u8 *end;
0027     u8 *ptr;
0028 };
0029 
0030 /**
0031  * msgb_init() - Initialize the given message buffer struct.
0032  * @msgb: The buffer struct to initialize
0033  * @ptr:  Pointer to the underlying memory by which the buffer will be backed.
0034  * @cap:  Size of the underlying memory.
0035  *
0036  * Initialize the given message buffer struct using the provided memory as
0037  * backing.
0038  */
0039 static inline void msgb_init(struct msgbuf *msgb, u8 *ptr, size_t cap)
0040 {
0041     msgb->begin = ptr;
0042     msgb->end = ptr + cap;
0043     msgb->ptr = ptr;
0044 }
0045 
0046 /**
0047  * msgb_bytes_used() - Return the current number of bytes used in the buffer.
0048  * @msgb: The message buffer.
0049  */
0050 static inline size_t msgb_bytes_used(const struct msgbuf *msgb)
0051 {
0052     return msgb->ptr - msgb->begin;
0053 }
0054 
0055 static inline void __msgb_push_u8(struct msgbuf *msgb, u8 value)
0056 {
0057     *msgb->ptr = value;
0058     msgb->ptr += sizeof(u8);
0059 }
0060 
0061 static inline void __msgb_push_u16(struct msgbuf *msgb, u16 value)
0062 {
0063     put_unaligned_le16(value, msgb->ptr);
0064     msgb->ptr += sizeof(u16);
0065 }
0066 
0067 /**
0068  * msgb_push_u16() - Push a u16 value to the buffer.
0069  * @msgb:  The message buffer.
0070  * @value: The value to push to the buffer.
0071  */
0072 static inline void msgb_push_u16(struct msgbuf *msgb, u16 value)
0073 {
0074     if (WARN_ON(msgb->ptr + sizeof(u16) > msgb->end))
0075         return;
0076 
0077     __msgb_push_u16(msgb, value);
0078 }
0079 
0080 /**
0081  * msgb_push_syn() - Push SSH SYN bytes to the buffer.
0082  * @msgb: The message buffer.
0083  */
0084 static inline void msgb_push_syn(struct msgbuf *msgb)
0085 {
0086     msgb_push_u16(msgb, SSH_MSG_SYN);
0087 }
0088 
0089 /**
0090  * msgb_push_buf() - Push raw data to the buffer.
0091  * @msgb: The message buffer.
0092  * @buf:  The data to push to the buffer.
0093  * @len:  The length of the data to push to the buffer.
0094  */
0095 static inline void msgb_push_buf(struct msgbuf *msgb, const u8 *buf, size_t len)
0096 {
0097     msgb->ptr = memcpy(msgb->ptr, buf, len) + len;
0098 }
0099 
0100 /**
0101  * msgb_push_crc() - Compute CRC and push it to the buffer.
0102  * @msgb: The message buffer.
0103  * @buf:  The data for which the CRC should be computed.
0104  * @len:  The length of the data for which the CRC should be computed.
0105  */
0106 static inline void msgb_push_crc(struct msgbuf *msgb, const u8 *buf, size_t len)
0107 {
0108     msgb_push_u16(msgb, ssh_crc(buf, len));
0109 }
0110 
0111 /**
0112  * msgb_push_frame() - Push a SSH message frame header to the buffer.
0113  * @msgb: The message buffer
0114  * @ty:   The type of the frame.
0115  * @len:  The length of the payload of the frame.
0116  * @seq:  The sequence ID of the frame/packet.
0117  */
0118 static inline void msgb_push_frame(struct msgbuf *msgb, u8 ty, u16 len, u8 seq)
0119 {
0120     u8 *const begin = msgb->ptr;
0121 
0122     if (WARN_ON(msgb->ptr + sizeof(struct ssh_frame) > msgb->end))
0123         return;
0124 
0125     __msgb_push_u8(msgb, ty);   /* Frame type. */
0126     __msgb_push_u16(msgb, len); /* Frame payload length. */
0127     __msgb_push_u8(msgb, seq);  /* Frame sequence ID. */
0128 
0129     msgb_push_crc(msgb, begin, msgb->ptr - begin);
0130 }
0131 
0132 /**
0133  * msgb_push_ack() - Push a SSH ACK frame to the buffer.
0134  * @msgb: The message buffer
0135  * @seq:  The sequence ID of the frame/packet to be ACKed.
0136  */
0137 static inline void msgb_push_ack(struct msgbuf *msgb, u8 seq)
0138 {
0139     /* SYN. */
0140     msgb_push_syn(msgb);
0141 
0142     /* ACK-type frame + CRC. */
0143     msgb_push_frame(msgb, SSH_FRAME_TYPE_ACK, 0x00, seq);
0144 
0145     /* Payload CRC (ACK-type frames do not have a payload). */
0146     msgb_push_crc(msgb, msgb->ptr, 0);
0147 }
0148 
0149 /**
0150  * msgb_push_nak() - Push a SSH NAK frame to the buffer.
0151  * @msgb: The message buffer
0152  */
0153 static inline void msgb_push_nak(struct msgbuf *msgb)
0154 {
0155     /* SYN. */
0156     msgb_push_syn(msgb);
0157 
0158     /* NAK-type frame + CRC. */
0159     msgb_push_frame(msgb, SSH_FRAME_TYPE_NAK, 0x00, 0x00);
0160 
0161     /* Payload CRC (ACK-type frames do not have a payload). */
0162     msgb_push_crc(msgb, msgb->ptr, 0);
0163 }
0164 
0165 /**
0166  * msgb_push_cmd() - Push a SSH command frame with payload to the buffer.
0167  * @msgb: The message buffer.
0168  * @seq:  The sequence ID (SEQ) of the frame/packet.
0169  * @rqid: The request ID (RQID) of the request contained in the frame.
0170  * @rqst: The request to wrap in the frame.
0171  */
0172 static inline void msgb_push_cmd(struct msgbuf *msgb, u8 seq, u16 rqid,
0173                  const struct ssam_request *rqst)
0174 {
0175     const u8 type = SSH_FRAME_TYPE_DATA_SEQ;
0176     u8 *cmd;
0177 
0178     /* SYN. */
0179     msgb_push_syn(msgb);
0180 
0181     /* Command frame + CRC. */
0182     msgb_push_frame(msgb, type, sizeof(struct ssh_command) + rqst->length, seq);
0183 
0184     /* Frame payload: Command struct + payload. */
0185     if (WARN_ON(msgb->ptr + sizeof(struct ssh_command) > msgb->end))
0186         return;
0187 
0188     cmd = msgb->ptr;
0189 
0190     __msgb_push_u8(msgb, SSH_PLD_TYPE_CMD);     /* Payload type. */
0191     __msgb_push_u8(msgb, rqst->target_category);    /* Target category. */
0192     __msgb_push_u8(msgb, rqst->target_id);      /* Target ID (out). */
0193     __msgb_push_u8(msgb, 0x00);         /* Target ID (in). */
0194     __msgb_push_u8(msgb, rqst->instance_id);    /* Instance ID. */
0195     __msgb_push_u16(msgb, rqid);            /* Request ID. */
0196     __msgb_push_u8(msgb, rqst->command_id);     /* Command ID. */
0197 
0198     /* Command payload. */
0199     msgb_push_buf(msgb, rqst->payload, rqst->length);
0200 
0201     /* CRC for command struct + payload. */
0202     msgb_push_crc(msgb, cmd, msgb->ptr - cmd);
0203 }
0204 
0205 #endif /* _SURFACE_AGGREGATOR_SSH_MSGB_H */