1bfc15268SAneesh Kumar K.V #include "kvm/util.h"
2bfc15268SAneesh Kumar K.V #include "kvm/virtio-9p.h"
3bfc15268SAneesh Kumar K.V
4bfc15268SAneesh Kumar K.V #include <endian.h>
5bfc15268SAneesh Kumar K.V #include <stdint.h>
6bfc15268SAneesh Kumar K.V
7bfc15268SAneesh Kumar K.V #include <linux/compiler.h>
8*c6cb7c75SAndre Przywara #include <linux/9p.h>
9bfc15268SAneesh Kumar K.V
virtio_p9_pdu_read(struct p9_pdu * pdu,void * data,size_t size)10bfc15268SAneesh Kumar K.V static void virtio_p9_pdu_read(struct p9_pdu *pdu, void *data, size_t size)
11bfc15268SAneesh Kumar K.V {
12bfc15268SAneesh Kumar K.V size_t len;
13bfc15268SAneesh Kumar K.V int i, copied = 0;
14bfc15268SAneesh Kumar K.V u16 iov_cnt = pdu->out_iov_cnt;
15bfc15268SAneesh Kumar K.V size_t offset = pdu->read_offset;
16bfc15268SAneesh Kumar K.V struct iovec *iov = pdu->out_iov;
17bfc15268SAneesh Kumar K.V
18bfc15268SAneesh Kumar K.V for (i = 0; i < iov_cnt && size; i++) {
19bfc15268SAneesh Kumar K.V if (offset >= iov[i].iov_len) {
20bfc15268SAneesh Kumar K.V offset -= iov[i].iov_len;
21bfc15268SAneesh Kumar K.V continue;
22bfc15268SAneesh Kumar K.V } else {
23bfc15268SAneesh Kumar K.V len = MIN(iov[i].iov_len - offset, size);
24bfc15268SAneesh Kumar K.V memcpy(data, iov[i].iov_base + offset, len);
25bfc15268SAneesh Kumar K.V size -= len;
26bfc15268SAneesh Kumar K.V data += len;
27bfc15268SAneesh Kumar K.V offset = 0;
28bfc15268SAneesh Kumar K.V copied += len;
29bfc15268SAneesh Kumar K.V }
30bfc15268SAneesh Kumar K.V }
31bfc15268SAneesh Kumar K.V pdu->read_offset += copied;
32bfc15268SAneesh Kumar K.V }
33bfc15268SAneesh Kumar K.V
virtio_p9_pdu_write(struct p9_pdu * pdu,const void * data,size_t size)34bfc15268SAneesh Kumar K.V static void virtio_p9_pdu_write(struct p9_pdu *pdu,
35bfc15268SAneesh Kumar K.V const void *data, size_t size)
36bfc15268SAneesh Kumar K.V {
37bfc15268SAneesh Kumar K.V size_t len;
38bfc15268SAneesh Kumar K.V int i, copied = 0;
39bfc15268SAneesh Kumar K.V u16 iov_cnt = pdu->in_iov_cnt;
40bfc15268SAneesh Kumar K.V size_t offset = pdu->write_offset;
41bfc15268SAneesh Kumar K.V struct iovec *iov = pdu->in_iov;
42bfc15268SAneesh Kumar K.V
43bfc15268SAneesh Kumar K.V for (i = 0; i < iov_cnt && size; i++) {
44bfc15268SAneesh Kumar K.V if (offset >= iov[i].iov_len) {
45bfc15268SAneesh Kumar K.V offset -= iov[i].iov_len;
46bfc15268SAneesh Kumar K.V continue;
47bfc15268SAneesh Kumar K.V } else {
48bfc15268SAneesh Kumar K.V len = MIN(iov[i].iov_len - offset, size);
49bfc15268SAneesh Kumar K.V memcpy(iov[i].iov_base + offset, data, len);
50bfc15268SAneesh Kumar K.V size -= len;
51bfc15268SAneesh Kumar K.V data += len;
52bfc15268SAneesh Kumar K.V offset = 0;
53bfc15268SAneesh Kumar K.V copied += len;
54bfc15268SAneesh Kumar K.V }
55bfc15268SAneesh Kumar K.V }
56bfc15268SAneesh Kumar K.V pdu->write_offset += copied;
57bfc15268SAneesh Kumar K.V }
58bfc15268SAneesh Kumar K.V
virtio_p9_wstat_free(struct p9_wstat * stbuf)59bfc15268SAneesh Kumar K.V static void virtio_p9_wstat_free(struct p9_wstat *stbuf)
60bfc15268SAneesh Kumar K.V {
61bfc15268SAneesh Kumar K.V free(stbuf->name);
62bfc15268SAneesh Kumar K.V free(stbuf->uid);
63bfc15268SAneesh Kumar K.V free(stbuf->gid);
64bfc15268SAneesh Kumar K.V free(stbuf->muid);
65bfc15268SAneesh Kumar K.V }
66bfc15268SAneesh Kumar K.V
virtio_p9_decode(struct p9_pdu * pdu,const char * fmt,va_list ap)67bfc15268SAneesh Kumar K.V static int virtio_p9_decode(struct p9_pdu *pdu, const char *fmt, va_list ap)
68bfc15268SAneesh Kumar K.V {
69bfc15268SAneesh Kumar K.V int retval = 0;
70bfc15268SAneesh Kumar K.V const char *ptr;
71bfc15268SAneesh Kumar K.V
72bfc15268SAneesh Kumar K.V for (ptr = fmt; *ptr; ptr++) {
73bfc15268SAneesh Kumar K.V switch (*ptr) {
74bfc15268SAneesh Kumar K.V case 'b':
75bfc15268SAneesh Kumar K.V {
76bfc15268SAneesh Kumar K.V int8_t *val = va_arg(ap, int8_t *);
77bfc15268SAneesh Kumar K.V virtio_p9_pdu_read(pdu, val, sizeof(*val));
78bfc15268SAneesh Kumar K.V }
79bfc15268SAneesh Kumar K.V break;
80bfc15268SAneesh Kumar K.V case 'w':
81bfc15268SAneesh Kumar K.V {
82bfc15268SAneesh Kumar K.V int16_t le_val;
83bfc15268SAneesh Kumar K.V int16_t *val = va_arg(ap, int16_t *);
84bfc15268SAneesh Kumar K.V virtio_p9_pdu_read(pdu, &le_val, sizeof(le_val));
85bfc15268SAneesh Kumar K.V *val = le16toh(le_val);
86bfc15268SAneesh Kumar K.V }
87bfc15268SAneesh Kumar K.V break;
88bfc15268SAneesh Kumar K.V case 'd':
89bfc15268SAneesh Kumar K.V {
90bfc15268SAneesh Kumar K.V int32_t le_val;
91bfc15268SAneesh Kumar K.V int32_t *val = va_arg(ap, int32_t *);
92bfc15268SAneesh Kumar K.V virtio_p9_pdu_read(pdu, &le_val, sizeof(le_val));
93bfc15268SAneesh Kumar K.V *val = le32toh(le_val);
94bfc15268SAneesh Kumar K.V }
95bfc15268SAneesh Kumar K.V break;
96bfc15268SAneesh Kumar K.V case 'q':
97bfc15268SAneesh Kumar K.V {
98bfc15268SAneesh Kumar K.V int64_t le_val;
99bfc15268SAneesh Kumar K.V int64_t *val = va_arg(ap, int64_t *);
100bfc15268SAneesh Kumar K.V virtio_p9_pdu_read(pdu, &le_val, sizeof(le_val));
101bfc15268SAneesh Kumar K.V *val = le64toh(le_val);
102bfc15268SAneesh Kumar K.V }
103bfc15268SAneesh Kumar K.V break;
104bfc15268SAneesh Kumar K.V case 's':
105bfc15268SAneesh Kumar K.V {
106bfc15268SAneesh Kumar K.V int16_t len;
107bfc15268SAneesh Kumar K.V char **str = va_arg(ap, char **);
108bfc15268SAneesh Kumar K.V
109bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "w", &len);
110bfc15268SAneesh Kumar K.V *str = malloc(len + 1);
111bfc15268SAneesh Kumar K.V if (*str == NULL) {
112bfc15268SAneesh Kumar K.V retval = ENOMEM;
113bfc15268SAneesh Kumar K.V break;
114bfc15268SAneesh Kumar K.V }
115bfc15268SAneesh Kumar K.V virtio_p9_pdu_read(pdu, *str, len);
116bfc15268SAneesh Kumar K.V (*str)[len] = 0;
117bfc15268SAneesh Kumar K.V }
118bfc15268SAneesh Kumar K.V break;
119bfc15268SAneesh Kumar K.V case 'Q':
120bfc15268SAneesh Kumar K.V {
121bfc15268SAneesh Kumar K.V struct p9_qid *qid = va_arg(ap, struct p9_qid *);
122bfc15268SAneesh Kumar K.V retval = virtio_p9_pdu_readf(pdu, "bdq",
123bfc15268SAneesh Kumar K.V &qid->type, &qid->version,
124bfc15268SAneesh Kumar K.V &qid->path);
125bfc15268SAneesh Kumar K.V }
126bfc15268SAneesh Kumar K.V break;
127bfc15268SAneesh Kumar K.V case 'S':
128bfc15268SAneesh Kumar K.V {
129bfc15268SAneesh Kumar K.V struct p9_wstat *stbuf = va_arg(ap, struct p9_wstat *);
130bfc15268SAneesh Kumar K.V memset(stbuf, 0, sizeof(struct p9_wstat));
131506fd90bSSasha Levin stbuf->n_uid = KUIDT_INIT(-1);
132506fd90bSSasha Levin stbuf->n_gid = KGIDT_INIT(-1);
133506fd90bSSasha Levin stbuf->n_muid = KUIDT_INIT(-1);
134bfc15268SAneesh Kumar K.V retval = virtio_p9_pdu_readf(pdu, "wwdQdddqssss",
135bfc15268SAneesh Kumar K.V &stbuf->size, &stbuf->type,
136bfc15268SAneesh Kumar K.V &stbuf->dev, &stbuf->qid,
137bfc15268SAneesh Kumar K.V &stbuf->mode, &stbuf->atime,
138bfc15268SAneesh Kumar K.V &stbuf->mtime, &stbuf->length,
139bfc15268SAneesh Kumar K.V &stbuf->name, &stbuf->uid,
140bfc15268SAneesh Kumar K.V &stbuf->gid, &stbuf->muid);
141bfc15268SAneesh Kumar K.V if (retval)
142bfc15268SAneesh Kumar K.V virtio_p9_wstat_free(stbuf);
143bfc15268SAneesh Kumar K.V }
144bfc15268SAneesh Kumar K.V break;
145c797b6c6SAneesh Kumar K.V case 'I':
146c797b6c6SAneesh Kumar K.V {
147c797b6c6SAneesh Kumar K.V struct p9_iattr_dotl *p9attr = va_arg(ap,
148c797b6c6SAneesh Kumar K.V struct p9_iattr_dotl *);
149c797b6c6SAneesh Kumar K.V
150c797b6c6SAneesh Kumar K.V retval = virtio_p9_pdu_readf(pdu, "ddddqqqqq",
151c797b6c6SAneesh Kumar K.V &p9attr->valid,
152c797b6c6SAneesh Kumar K.V &p9attr->mode,
153c797b6c6SAneesh Kumar K.V &p9attr->uid,
154c797b6c6SAneesh Kumar K.V &p9attr->gid,
155c797b6c6SAneesh Kumar K.V &p9attr->size,
156c797b6c6SAneesh Kumar K.V &p9attr->atime_sec,
157c797b6c6SAneesh Kumar K.V &p9attr->atime_nsec,
158c797b6c6SAneesh Kumar K.V &p9attr->mtime_sec,
159c797b6c6SAneesh Kumar K.V &p9attr->mtime_nsec);
160c797b6c6SAneesh Kumar K.V }
161c797b6c6SAneesh Kumar K.V break;
162bfc15268SAneesh Kumar K.V default:
163bfc15268SAneesh Kumar K.V retval = EINVAL;
164bfc15268SAneesh Kumar K.V break;
165bfc15268SAneesh Kumar K.V }
166bfc15268SAneesh Kumar K.V }
167bfc15268SAneesh Kumar K.V return retval;
168bfc15268SAneesh Kumar K.V }
169bfc15268SAneesh Kumar K.V
virtio_p9_pdu_encode(struct p9_pdu * pdu,const char * fmt,va_list ap)170bfc15268SAneesh Kumar K.V static int virtio_p9_pdu_encode(struct p9_pdu *pdu, const char *fmt, va_list ap)
171bfc15268SAneesh Kumar K.V {
172bfc15268SAneesh Kumar K.V int retval = 0;
173bfc15268SAneesh Kumar K.V const char *ptr;
174bfc15268SAneesh Kumar K.V
175bfc15268SAneesh Kumar K.V for (ptr = fmt; *ptr; ptr++) {
176bfc15268SAneesh Kumar K.V switch (*ptr) {
177bfc15268SAneesh Kumar K.V case 'b':
178bfc15268SAneesh Kumar K.V {
179bfc15268SAneesh Kumar K.V int8_t val = va_arg(ap, int);
180bfc15268SAneesh Kumar K.V virtio_p9_pdu_write(pdu, &val, sizeof(val));
181bfc15268SAneesh Kumar K.V }
182bfc15268SAneesh Kumar K.V break;
183bfc15268SAneesh Kumar K.V case 'w':
184bfc15268SAneesh Kumar K.V {
185bfc15268SAneesh Kumar K.V int16_t val = htole16(va_arg(ap, int));
186bfc15268SAneesh Kumar K.V virtio_p9_pdu_write(pdu, &val, sizeof(val));
187bfc15268SAneesh Kumar K.V }
188bfc15268SAneesh Kumar K.V break;
189bfc15268SAneesh Kumar K.V case 'd':
190bfc15268SAneesh Kumar K.V {
191bfc15268SAneesh Kumar K.V int32_t val = htole32(va_arg(ap, int32_t));
192bfc15268SAneesh Kumar K.V virtio_p9_pdu_write(pdu, &val, sizeof(val));
193bfc15268SAneesh Kumar K.V }
194bfc15268SAneesh Kumar K.V break;
195bfc15268SAneesh Kumar K.V case 'q':
196bfc15268SAneesh Kumar K.V {
197bfc15268SAneesh Kumar K.V int64_t val = htole64(va_arg(ap, int64_t));
198bfc15268SAneesh Kumar K.V virtio_p9_pdu_write(pdu, &val, sizeof(val));
199bfc15268SAneesh Kumar K.V }
200bfc15268SAneesh Kumar K.V break;
201bfc15268SAneesh Kumar K.V case 's':
202bfc15268SAneesh Kumar K.V {
203bfc15268SAneesh Kumar K.V uint16_t len = 0;
204bfc15268SAneesh Kumar K.V const char *s = va_arg(ap, char *);
205bfc15268SAneesh Kumar K.V if (s)
206bfc15268SAneesh Kumar K.V len = MIN(strlen(s), USHRT_MAX);
207bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "w", len);
208bfc15268SAneesh Kumar K.V virtio_p9_pdu_write(pdu, s, len);
209bfc15268SAneesh Kumar K.V }
210bfc15268SAneesh Kumar K.V break;
211bfc15268SAneesh Kumar K.V case 'Q':
212bfc15268SAneesh Kumar K.V {
213bfc15268SAneesh Kumar K.V struct p9_qid *qid = va_arg(ap, struct p9_qid *);
214bfc15268SAneesh Kumar K.V retval = virtio_p9_pdu_writef(pdu, "bdq",
215bfc15268SAneesh Kumar K.V qid->type, qid->version,
216bfc15268SAneesh Kumar K.V qid->path);
217bfc15268SAneesh Kumar K.V }
218bfc15268SAneesh Kumar K.V break;
219bfc15268SAneesh Kumar K.V case 'S':
220bfc15268SAneesh Kumar K.V {
221bfc15268SAneesh Kumar K.V struct p9_wstat *stbuf = va_arg(ap, struct p9_wstat *);
222c797b6c6SAneesh Kumar K.V retval = virtio_p9_pdu_writef(pdu, "wwdQdddqssss",
223bfc15268SAneesh Kumar K.V stbuf->size, stbuf->type,
224bfc15268SAneesh Kumar K.V stbuf->dev, &stbuf->qid,
225bfc15268SAneesh Kumar K.V stbuf->mode, stbuf->atime,
226bfc15268SAneesh Kumar K.V stbuf->mtime, stbuf->length,
227bfc15268SAneesh Kumar K.V stbuf->name, stbuf->uid,
228c797b6c6SAneesh Kumar K.V stbuf->gid, stbuf->muid);
229c797b6c6SAneesh Kumar K.V }
230c797b6c6SAneesh Kumar K.V break;
231c797b6c6SAneesh Kumar K.V case 'A':
232c797b6c6SAneesh Kumar K.V {
233c797b6c6SAneesh Kumar K.V struct p9_stat_dotl *stbuf = va_arg(ap,
234c797b6c6SAneesh Kumar K.V struct p9_stat_dotl *);
235c797b6c6SAneesh Kumar K.V retval = virtio_p9_pdu_writef(pdu,
236c797b6c6SAneesh Kumar K.V "qQdddqqqqqqqqqqqqqqq",
237c797b6c6SAneesh Kumar K.V stbuf->st_result_mask,
238c797b6c6SAneesh Kumar K.V &stbuf->qid,
239c797b6c6SAneesh Kumar K.V stbuf->st_mode,
240c797b6c6SAneesh Kumar K.V stbuf->st_uid,
241c797b6c6SAneesh Kumar K.V stbuf->st_gid,
242c797b6c6SAneesh Kumar K.V stbuf->st_nlink,
243c797b6c6SAneesh Kumar K.V stbuf->st_rdev,
244c797b6c6SAneesh Kumar K.V stbuf->st_size,
245c797b6c6SAneesh Kumar K.V stbuf->st_blksize,
246c797b6c6SAneesh Kumar K.V stbuf->st_blocks,
247c797b6c6SAneesh Kumar K.V stbuf->st_atime_sec,
248c797b6c6SAneesh Kumar K.V stbuf->st_atime_nsec,
249c797b6c6SAneesh Kumar K.V stbuf->st_mtime_sec,
250c797b6c6SAneesh Kumar K.V stbuf->st_mtime_nsec,
251c797b6c6SAneesh Kumar K.V stbuf->st_ctime_sec,
252c797b6c6SAneesh Kumar K.V stbuf->st_ctime_nsec,
253c797b6c6SAneesh Kumar K.V stbuf->st_btime_sec,
254c797b6c6SAneesh Kumar K.V stbuf->st_btime_nsec,
255c797b6c6SAneesh Kumar K.V stbuf->st_gen,
256c797b6c6SAneesh Kumar K.V stbuf->st_data_version);
257bfc15268SAneesh Kumar K.V }
258bfc15268SAneesh Kumar K.V break;
259bfc15268SAneesh Kumar K.V default:
260bfc15268SAneesh Kumar K.V retval = EINVAL;
261bfc15268SAneesh Kumar K.V break;
262bfc15268SAneesh Kumar K.V }
263bfc15268SAneesh Kumar K.V }
264bfc15268SAneesh Kumar K.V return retval;
265bfc15268SAneesh Kumar K.V }
266bfc15268SAneesh Kumar K.V
virtio_p9_pdu_readf(struct p9_pdu * pdu,const char * fmt,...)267bfc15268SAneesh Kumar K.V int virtio_p9_pdu_readf(struct p9_pdu *pdu, const char *fmt, ...)
268bfc15268SAneesh Kumar K.V {
269bfc15268SAneesh Kumar K.V int ret;
270bfc15268SAneesh Kumar K.V va_list ap;
271bfc15268SAneesh Kumar K.V
272bfc15268SAneesh Kumar K.V va_start(ap, fmt);
273bfc15268SAneesh Kumar K.V ret = virtio_p9_decode(pdu, fmt, ap);
274bfc15268SAneesh Kumar K.V va_end(ap);
275bfc15268SAneesh Kumar K.V
276bfc15268SAneesh Kumar K.V return ret;
277bfc15268SAneesh Kumar K.V }
278bfc15268SAneesh Kumar K.V
virtio_p9_pdu_writef(struct p9_pdu * pdu,const char * fmt,...)279bfc15268SAneesh Kumar K.V int virtio_p9_pdu_writef(struct p9_pdu *pdu, const char *fmt, ...)
280bfc15268SAneesh Kumar K.V {
281bfc15268SAneesh Kumar K.V int ret;
282bfc15268SAneesh Kumar K.V va_list ap;
283bfc15268SAneesh Kumar K.V
284bfc15268SAneesh Kumar K.V va_start(ap, fmt);
285bfc15268SAneesh Kumar K.V ret = virtio_p9_pdu_encode(pdu, fmt, ap);
286bfc15268SAneesh Kumar K.V va_end(ap);
287bfc15268SAneesh Kumar K.V
288bfc15268SAneesh Kumar K.V return ret;
289bfc15268SAneesh Kumar K.V }
290