1 /*
2 * Copyright (c) 2023, Google Inc. All rights reserved.
3 * Author: codycswong@google.com (Cody Wong)
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files
7 * (the "Software"), to deal in the Software without restriction,
8 * including without limitation the rights to use, copy, modify, merge,
9 * publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so,
11 * subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24 #include "protocol.h"
25
26 #include <dev/virtio/9p.h>
27 #include <inttypes.h>
28 #include <lk/err.h>
29 #include <lk/trace.h>
30 #include <stdlib.h>
31
32 #define LOCAL_TRACE 0
33
34 /*
35 * read/write of basic type APIs
36 */
37
pdu_read(struct p9_fcall * pdu,void * data,size_t size)38 size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
39 {
40 size_t len = MIN(pdu->size - pdu->offset, size);
41
42 memcpy(data, &pdu->sdata[pdu->offset], len);
43 pdu->offset += len;
44 return len;
45 }
46
pdu_write(struct p9_fcall * pdu,void * data,size_t size)47 size_t pdu_write(struct p9_fcall *pdu, void *data, size_t size)
48 {
49 size_t len = MIN(pdu->capacity - pdu->offset, size);
50
51 memcpy(&pdu->sdata[pdu->size], data, len);
52 pdu->size += len;
53 return len;
54 }
55
pdu_writeb(struct p9_fcall * pdu,uint8_t byte)56 status_t pdu_writeb(struct p9_fcall *pdu, uint8_t byte)
57 {
58 return pdu_write(pdu, &byte, 1) == 1 ? NO_ERROR : ERR_IO;
59 }
60
pdu_readb(struct p9_fcall * pdu)61 uint8_t pdu_readb(struct p9_fcall *pdu)
62 {
63 uint8_t byte;
64 ASSERT(pdu_read(pdu, &byte, 1) == 1);
65 return byte;
66 }
67
pdu_writew(struct p9_fcall * pdu,uint16_t word)68 status_t pdu_writew(struct p9_fcall *pdu, uint16_t word)
69 {
70 word = LE16(word);
71 return pdu_write(pdu, &word, 2) == 2 ? NO_ERROR : ERR_IO;
72 }
73
pdu_readw(struct p9_fcall * pdu)74 uint16_t pdu_readw(struct p9_fcall *pdu)
75 {
76 uint16_t word;
77 ASSERT(pdu_read(pdu, &word, 2) == 2);
78 return LE16(word);
79 }
80
pdu_writed(struct p9_fcall * pdu,uint32_t dword)81 status_t pdu_writed(struct p9_fcall *pdu, uint32_t dword)
82 {
83 dword = LE32(dword);
84 return pdu_write(pdu, &dword, 4) == 4 ? NO_ERROR : ERR_IO;
85 }
86
pdu_readd(struct p9_fcall * pdu)87 uint32_t pdu_readd(struct p9_fcall *pdu)
88 {
89 uint32_t dword;
90 ASSERT(pdu_read(pdu, &dword, 4) == 4);
91 return LE32(dword);
92 }
93
pdu_writeq(struct p9_fcall * pdu,uint64_t qword)94 status_t pdu_writeq(struct p9_fcall *pdu, uint64_t qword)
95 {
96 qword = LE64(qword);
97 return pdu_write(pdu, &qword, 8) == 8 ? NO_ERROR : ERR_IO;
98 }
99
pdu_readq(struct p9_fcall * pdu)100 uint64_t pdu_readq(struct p9_fcall *pdu)
101 {
102 uint64_t qword;
103 ASSERT(pdu_read(pdu, &qword, 8) == 8);
104 return LE64(qword);
105 }
106
pdu_writestr(struct p9_fcall * pdu,const char * str)107 status_t pdu_writestr(struct p9_fcall *pdu, const char *str)
108 {
109 uint16_t len = strlen(str);
110 status_t ret;
111
112 if ((ret = pdu_writew(pdu, len)) != NO_ERROR)
113 return ret;
114
115 return pdu_write(pdu, (void *)str, len) == len ? NO_ERROR : ERR_IO;
116 }
117
pdu_readstr(struct p9_fcall * pdu)118 char *pdu_readstr(struct p9_fcall *pdu)
119 {
120 uint16_t len;
121 char *str = NULL;
122
123 len = pdu_readw(pdu);
124 if (!len) {
125 return NULL;
126 }
127
128 str = calloc(len + 1, sizeof(char));
129 if (!str) {
130 return NULL;
131 }
132
133 ASSERT(pdu_read(pdu, str, len) == len);
134 return str;
135 }
136
pdu_readqid(struct p9_fcall * pdu)137 virtio_9p_qid_t pdu_readqid(struct p9_fcall *pdu)
138 {
139 virtio_9p_qid_t qid;
140 qid.type = pdu_readb(pdu);
141 qid.version = pdu_readd(pdu);
142 qid.path = pdu_readq(pdu);
143 return qid;
144 }
145
pdu_writedata(struct p9_fcall * pdu,const uint8_t * data,uint32_t count)146 status_t pdu_writedata(struct p9_fcall *pdu, const uint8_t *data,
147 uint32_t count)
148 {
149 status_t ret;
150 #if LOCAL_TRACE >= 2
151 LTRACEF("count (%u) data (%p)\n", count, data);
152 hexdump8(data, count);
153 #endif
154
155 if ((ret = pdu_writed(pdu, count)) != NO_ERROR)
156 return ret;
157
158 return pdu_write(pdu, (void *)data, count) == count ? NO_ERROR : ERR_IO;
159 }
160
pdu_readdata(struct p9_fcall * pdu,uint32_t * count)161 uint8_t *pdu_readdata(struct p9_fcall *pdu, uint32_t *count)
162 {
163 uint8_t *data = NULL;
164
165 *count = pdu_readd(pdu);
166 if (*count == 0)
167 return NULL;
168
169 data = calloc(*count, sizeof(uint8_t));
170 if (!data)
171 return NULL;
172
173 ASSERT(pdu_read(pdu, data, *count) == *count);
174 #if LOCAL_TRACE >= 2
175 LTRACEF("count (%u) data (%p)\n", *count, data);
176 hexdump8(data, *count);
177 #endif
178 return data;
179 }
180
p9_dirent_read(uint8_t * data,uint32_t size,p9_dirent_t * ent)181 ssize_t p9_dirent_read(uint8_t *data, uint32_t size, p9_dirent_t *ent)
182 {
183 struct p9_fcall fake_pdu;
184
185 fake_pdu.sdata = data;
186 fake_pdu.size = size;
187 fake_pdu.capacity = size;
188 fake_pdu.offset = 0;
189
190 // Rreaddir pattern: qid[13] offset[8] type[1] name[s]
191 ent->qid = pdu_readqid(&fake_pdu);
192 ent->offset = pdu_readq(&fake_pdu);
193 ent->type = pdu_readb(&fake_pdu);
194 ent->name = pdu_readstr(&fake_pdu);
195
196 LTRACEF(
197 "9p read_dirent: qid.type (0x%x) qid.version (%u) qid.path (%llu) "
198 "offset (%llu) type (0x%x) name (%s)\n",
199 ent->qid.type, ent->qid.version, ent->qid.path, ent->offset, ent->type,
200 ent->name);
201
202 return fake_pdu.offset;
203 }
204
p9_dirent_destroy(p9_dirent_t * ent)205 void p9_dirent_destroy(p9_dirent_t *ent)
206 {
207 if (ent) {
208 if (ent->name) {
209 free(ent->name);
210 ent->name = NULL;
211 }
212 }
213 }
214
215 /*
216 * Plan 9 File Protocol APIs
217 */
218
p9_proto_tversion(struct p9_req * req,const virtio_9p_msg_t * tmsg)219 status_t p9_proto_tversion(struct p9_req *req, const virtio_9p_msg_t *tmsg)
220 {
221 status_t ret;
222
223 // Tversion pattern: msize[4] version[s]
224 if ((ret = pdu_writed(&req->tc, tmsg->msg.tversion.msize)) != NO_ERROR)
225 return ret;
226 if ((ret = pdu_writestr(&req->tc, tmsg->msg.tversion.version)) != NO_ERROR)
227 return ret;
228
229 return NO_ERROR;
230 }
231
p9_proto_rversion(struct p9_req * req,virtio_9p_msg_t * rmsg)232 status_t p9_proto_rversion(struct p9_req *req, virtio_9p_msg_t *rmsg)
233 {
234 // Rversion pattern: msize[4] version[s]
235 rmsg->msg.rversion.msize = pdu_readd(&req->rc);
236 rmsg->msg.rversion.version = pdu_readstr(&req->rc);
237
238 LTRACEF("9p version: msize (%u), version (%s)\n", rmsg->msg.rversion.msize,
239 rmsg->msg.rversion.version);
240
241 return NO_ERROR;
242 }
243
p9_proto_tattach(struct p9_req * req,const virtio_9p_msg_t * tmsg)244 status_t p9_proto_tattach(struct p9_req *req, const virtio_9p_msg_t *tmsg)
245 {
246 status_t ret;
247
248 // Tattach pattern: fid[4] afid[4] uname[s] aname[s] n_uname[4]
249 if ((ret = pdu_writed(&req->tc, tmsg->msg.tattach.fid)) != NO_ERROR)
250 return ret;
251 if ((ret = pdu_writed(&req->tc, tmsg->msg.tattach.afid)) != NO_ERROR)
252 return ret;
253 if ((ret = pdu_writestr(&req->tc, tmsg->msg.tattach.uname)) != NO_ERROR)
254 return ret;
255 if ((ret = pdu_writestr(&req->tc, tmsg->msg.tattach.aname)) != NO_ERROR)
256 return ret;
257 if ((ret = pdu_writed(&req->tc, tmsg->msg.tattach.n_uname)) != NO_ERROR)
258 return ret;
259
260 return NO_ERROR;
261 }
262
p9_proto_rattach(struct p9_req * req,virtio_9p_msg_t * rmsg)263 status_t p9_proto_rattach(struct p9_req *req, virtio_9p_msg_t *rmsg)
264 {
265 // Rattach pattern: qid[13]
266 rmsg->msg.rattach.qid = pdu_readqid(&req->rc);
267
268 LTRACEF("9p attach: type (0x%x), version (%u), path (%llu)\n",
269 rmsg->msg.rattach.qid.type, rmsg->msg.rattach.qid.version,
270 rmsg->msg.rattach.qid.path);
271
272 return NO_ERROR;
273 }
274
p9_proto_twalk(struct p9_req * req,const virtio_9p_msg_t * tmsg)275 status_t p9_proto_twalk(struct p9_req *req, const virtio_9p_msg_t *tmsg)
276 {
277 status_t ret;
278
279 // Twalk pattern: fid[4] newfid[4] nwname[2] nwname*(wname[s])
280 if ((ret = pdu_writed(&req->tc, tmsg->msg.twalk.fid)) != NO_ERROR)
281 return ret;
282 if ((ret = pdu_writed(&req->tc, tmsg->msg.twalk.newfid)) != NO_ERROR)
283 return ret;
284 if ((ret = pdu_writew(&req->tc, tmsg->msg.twalk.nwname)) != NO_ERROR)
285 return ret;
286 for (int i = 0; i < tmsg->msg.twalk.nwname; i++) {
287 if ((ret = pdu_writestr(&req->tc, tmsg->msg.twalk.wname[i])) != NO_ERROR)
288 return ret;
289 }
290
291 return NO_ERROR;
292 }
293
p9_proto_rwalk(struct p9_req * req,virtio_9p_msg_t * rmsg)294 status_t p9_proto_rwalk(struct p9_req *req, virtio_9p_msg_t *rmsg)
295 {
296 // Rwalk pattern: nwqid[2] nwqid*(qid[13])
297 rmsg->msg.rwalk.nwqid = pdu_readw(&req->rc);
298
299 for (int i = 0; i < rmsg->msg.rwalk.nwqid; i++) {
300 rmsg->msg.rwalk.qid[i] = pdu_readqid(&req->rc);
301 LTRACEF("9p walk: type (0x%x), version (%u), path (%llu)\n",
302 rmsg->msg.rwalk.qid[i].type, rmsg->msg.rwalk.qid[i].version,
303 rmsg->msg.rwalk.qid[i].path);
304 }
305
306 return NO_ERROR;
307 }
308
p9_proto_topen(struct p9_req * req,const virtio_9p_msg_t * tmsg)309 status_t p9_proto_topen(struct p9_req *req, const virtio_9p_msg_t *tmsg)
310 {
311 status_t ret;
312
313 // Topen pattern: fid[4] mode[1]
314 if ((ret = pdu_writed(&req->tc, tmsg->msg.topen.fid)) != NO_ERROR)
315 return ret;
316 if ((ret = pdu_writeb(&req->tc, tmsg->msg.topen.mode)) != NO_ERROR)
317 return ret;
318
319 return NO_ERROR;
320 }
321
p9_proto_ropen(struct p9_req * req,virtio_9p_msg_t * rmsg)322 status_t p9_proto_ropen(struct p9_req *req, virtio_9p_msg_t *rmsg)
323 {
324 // Ropen pattern: qid[13] iounit[4]
325 rmsg->msg.ropen.qid = pdu_readqid(&req->rc);
326 rmsg->msg.ropen.iounit = pdu_readd(&req->rc);
327
328 LTRACEF("9p open: type (0x%x), version (%u), path (%llu), iounit (%u)\n",
329 rmsg->msg.ropen.qid.type, rmsg->msg.ropen.qid.version,
330 rmsg->msg.ropen.qid.path, rmsg->msg.ropen.iounit);
331
332 return NO_ERROR;
333 }
334
p9_proto_tlopen(struct p9_req * req,const virtio_9p_msg_t * tmsg)335 status_t p9_proto_tlopen(struct p9_req *req, const virtio_9p_msg_t *tmsg)
336 {
337 status_t ret;
338
339 // Tlopen pattern: fid[4] flags[4]
340 if ((ret = pdu_writed(&req->tc, tmsg->msg.tlopen.fid)) != NO_ERROR)
341 return ret;
342 if ((ret = pdu_writed(&req->tc, tmsg->msg.tlopen.flags)) != NO_ERROR)
343 return ret;
344
345 return NO_ERROR;
346 }
347
p9_proto_rlopen(struct p9_req * req,virtio_9p_msg_t * rmsg)348 status_t p9_proto_rlopen(struct p9_req *req, virtio_9p_msg_t *rmsg)
349 {
350 // Rlopen pattern: qid[13] iounit[4]
351 rmsg->msg.rlopen.qid = pdu_readqid(&req->rc);
352 rmsg->msg.rlopen.iounit = pdu_readd(&req->rc);
353
354 LTRACEF("9p lopen: type (0x%x), version (%u), path (%llu), iounit (%u)\n",
355 rmsg->msg.rlopen.qid.type, rmsg->msg.rlopen.qid.version,
356 rmsg->msg.rlopen.qid.path, rmsg->msg.rlopen.iounit);
357
358 return NO_ERROR;
359 }
360
p9_proto_tgetattr(struct p9_req * req,const virtio_9p_msg_t * tmsg)361 status_t p9_proto_tgetattr(struct p9_req *req, const virtio_9p_msg_t *tmsg)
362 {
363 status_t ret;
364
365 // Tgetattr pattern: fid[4] request_mask[8]
366 if ((ret = pdu_writed(&req->tc, tmsg->msg.tgetattr.fid)) != NO_ERROR)
367 return ret;
368 if ((ret = pdu_writeq(&req->tc, tmsg->msg.tgetattr.request_mask)) != NO_ERROR)
369 return ret;
370
371 return NO_ERROR;
372 }
373
p9_proto_rgetattr(struct p9_req * req,virtio_9p_msg_t * rmsg)374 status_t p9_proto_rgetattr(struct p9_req *req, virtio_9p_msg_t *rmsg)
375 {
376 // Rgetattr pattern: valid[8] qid[13] mode[4] uid[4] gid[4] nlink[8]
377 // rdev[8] size[8] blksize[8] blocks[8]
378 // atime_sec[8] atime_nsec[8] mtime_sec[8] mtime_nsec[8]
379 // ctime_sec[8] ctime_nsec[8] btime_sec[8] btime_nsec[8]
380 // gen[8] data_version[8]
381
382 rmsg->msg.rgetattr.valid = pdu_readq(&req->rc);
383 rmsg->msg.rgetattr.qid = pdu_readqid(&req->rc);
384 rmsg->msg.rgetattr.mode = pdu_readd(&req->rc);
385 rmsg->msg.rgetattr.uid = pdu_readd(&req->rc);
386 rmsg->msg.rgetattr.gid = pdu_readd(&req->rc);
387 rmsg->msg.rgetattr.nlink = pdu_readq(&req->rc);
388 rmsg->msg.rgetattr.rdev = pdu_readq(&req->rc);
389 rmsg->msg.rgetattr.size = pdu_readq(&req->rc);
390 rmsg->msg.rgetattr.blksize = pdu_readq(&req->rc);
391 rmsg->msg.rgetattr.blocks = pdu_readq(&req->rc);
392 rmsg->msg.rgetattr.atime_sec = pdu_readq(&req->rc);
393 rmsg->msg.rgetattr.atime_nsec = pdu_readq(&req->rc);
394 rmsg->msg.rgetattr.mtime_sec = pdu_readq(&req->rc);
395 rmsg->msg.rgetattr.mtime_nsec = pdu_readq(&req->rc);
396 rmsg->msg.rgetattr.ctime_sec = pdu_readq(&req->rc);
397 rmsg->msg.rgetattr.ctime_nsec = pdu_readq(&req->rc);
398 rmsg->msg.rgetattr.btime_sec = pdu_readq(&req->rc);
399 rmsg->msg.rgetattr.btime_nsec = pdu_readq(&req->rc);
400 rmsg->msg.rgetattr.gen = pdu_readq(&req->rc);
401 rmsg->msg.rgetattr.data_version = pdu_readq(&req->rc);
402
403 LTRACEF(
404 "9p getattr: valid (0x%llx), qid.type (0x%x), qid.version (%u), "
405 "qid.path (%llu), mode (0x%x), uid (%u), gid (%u), nlink (%llu), rdev "
406 "(%llu), size (%llu), blksize (%llu), blocks (%llu), atime_sec (%llu), "
407 "atime_nsec (%llu), mtime_sec (%llu), mtime_nsec (%llu), ctime_sec "
408 "(%llu), ctime_nsec (%llu), btime_sec (%llu), btime_nsec (%llu), gen "
409 "(%llu), data_version (%llu)\n",
410 rmsg->msg.rgetattr.valid, rmsg->msg.rgetattr.qid.type,
411 rmsg->msg.rgetattr.qid.version, rmsg->msg.rgetattr.qid.path,
412 rmsg->msg.rgetattr.mode, rmsg->msg.rgetattr.uid, rmsg->msg.rgetattr.gid,
413 rmsg->msg.rgetattr.nlink, rmsg->msg.rgetattr.rdev,
414 rmsg->msg.rgetattr.size, rmsg->msg.rgetattr.blksize,
415 rmsg->msg.rgetattr.blocks, rmsg->msg.rgetattr.atime_sec,
416 rmsg->msg.rgetattr.atime_nsec, rmsg->msg.rgetattr.mtime_sec,
417 rmsg->msg.rgetattr.mtime_nsec, rmsg->msg.rgetattr.ctime_sec,
418 rmsg->msg.rgetattr.ctime_nsec, rmsg->msg.rgetattr.btime_sec,
419 rmsg->msg.rgetattr.btime_nsec, rmsg->msg.rgetattr.gen,
420 rmsg->msg.rgetattr.data_version);
421
422 return NO_ERROR;
423 }
424
p9_proto_tread(struct p9_req * req,const virtio_9p_msg_t * tmsg)425 status_t p9_proto_tread(struct p9_req *req, const virtio_9p_msg_t *tmsg)
426 {
427 status_t ret;
428
429 // Tread pattern: fid[4] offset[8] count[4]
430 if ((ret = pdu_writed(&req->tc, tmsg->msg.tread.fid)) != NO_ERROR)
431 return ret;
432 if ((ret = pdu_writeq(&req->tc, tmsg->msg.tread.offset)) != NO_ERROR)
433 return ret;
434 if ((ret = pdu_writed(&req->tc, tmsg->msg.tread.count)) != NO_ERROR)
435 return ret;
436
437 return NO_ERROR;
438 }
439
p9_proto_rread(struct p9_req * req,virtio_9p_msg_t * rmsg)440 status_t p9_proto_rread(struct p9_req *req, virtio_9p_msg_t *rmsg)
441 {
442 // Rread pattern: count[4] data[count]
443 rmsg->msg.rread.data = pdu_readdata(&req->rc, &rmsg->msg.rread.count);
444
445 LTRACEF("9p read: count (%u) data (%p)\n", rmsg->msg.rread.count, rmsg->msg.rread.data);
446
447 return NO_ERROR;
448 }
449
p9_proto_twrite(struct p9_req * req,const virtio_9p_msg_t * tmsg)450 status_t p9_proto_twrite(struct p9_req *req, const virtio_9p_msg_t *tmsg)
451 {
452 status_t ret;
453
454 // Twrite pattern: fid[4] offset[8] count[4] data[count]
455 if ((ret = pdu_writed(&req->tc, tmsg->msg.twrite.fid)) != NO_ERROR)
456 return ret;
457 if ((ret = pdu_writeq(&req->tc, tmsg->msg.twrite.offset)) != NO_ERROR)
458 return ret;
459 if ((ret = pdu_writedata(&req->tc, tmsg->msg.twrite.data, tmsg->msg.twrite.count)) != NO_ERROR)
460 return ret;
461
462 return NO_ERROR;
463 }
464
p9_proto_rwrite(struct p9_req * req,virtio_9p_msg_t * rmsg)465 status_t p9_proto_rwrite(struct p9_req *req, virtio_9p_msg_t *rmsg)
466 {
467 // Rwrite pattern: count[4]
468 rmsg->msg.rwrite.count = pdu_readd(&req->rc);
469
470 LTRACEF("9p write: count %u\n", rmsg->msg.rwrite.count);
471
472 return NO_ERROR;
473 }
474
p9_proto_tclunk(struct p9_req * req,const virtio_9p_msg_t * tmsg)475 status_t p9_proto_tclunk(struct p9_req *req, const virtio_9p_msg_t *tmsg)
476 {
477 status_t ret;
478
479 // Tclunk pattern: fid[4]
480 if ((ret = pdu_writed(&req->tc, tmsg->msg.tclunk.fid)) != NO_ERROR)
481 return ret;
482
483 return NO_ERROR;
484 }
485
p9_proto_rclunk(struct p9_req * req,virtio_9p_msg_t * rmsg)486 status_t p9_proto_rclunk(struct p9_req *req, virtio_9p_msg_t *rmsg)
487 {
488 // Rclunk pattern:
489
490 return NO_ERROR;
491 }
492
p9_proto_tremove(struct p9_req * req,const virtio_9p_msg_t * tmsg)493 status_t p9_proto_tremove(struct p9_req *req, const virtio_9p_msg_t *tmsg)
494 {
495 status_t ret;
496
497 // Tremove pattern: fid[4]
498 if ((ret = pdu_writed(&req->tc, tmsg->msg.tremove.fid)) != NO_ERROR)
499 return ret;
500
501 return NO_ERROR;
502 }
503
p9_proto_rremove(struct p9_req * req,virtio_9p_msg_t * rmsg)504 status_t p9_proto_rremove(struct p9_req *req, virtio_9p_msg_t *rmsg)
505 {
506 // Rremove pattern:
507
508 return NO_ERROR;
509 }
510
p9_proto_rlerror(struct p9_req * req,virtio_9p_msg_t * rmsg)511 status_t p9_proto_rlerror(struct p9_req *req, virtio_9p_msg_t *rmsg)
512 {
513 // Rlerror pattern: ecode[4]
514 rmsg->msg.rlerror.ecode = pdu_readd(&req->rc);
515
516 LTRACEF("9p lerror: ecode %u\n", rmsg->msg.rlerror.ecode);
517
518 return NO_ERROR;
519 }
520
p9_proto_tlcreate(struct p9_req * req,const virtio_9p_msg_t * tmsg)521 status_t p9_proto_tlcreate(struct p9_req *req, const virtio_9p_msg_t *tmsg)
522 {
523 status_t ret;
524
525 // Tlcreate pattern: fid[4] name[s] flags[4] mode[4] gid[4]
526 if ((ret = pdu_writed(&req->tc, tmsg->msg.tlcreate.fid)) != NO_ERROR)
527 return ret;
528 if ((ret = pdu_writestr(&req->tc, tmsg->msg.tlcreate.name)) != NO_ERROR)
529 return ret;
530 if ((ret = pdu_writed(&req->tc, tmsg->msg.tlcreate.flags)) != NO_ERROR)
531 return ret;
532 if ((ret = pdu_writed(&req->tc, tmsg->msg.tlcreate.mode)) != NO_ERROR)
533 return ret;
534 if ((ret = pdu_writed(&req->tc, tmsg->msg.tlcreate.gid)) != NO_ERROR)
535 return ret;
536
537 return NO_ERROR;
538 }
539
p9_proto_rlcreate(struct p9_req * req,virtio_9p_msg_t * rmsg)540 status_t p9_proto_rlcreate(struct p9_req *req, virtio_9p_msg_t *rmsg)
541 {
542 // Rlcreate pattern: qid[13] iounit[4]
543 rmsg->msg.rlcreate.qid = pdu_readqid(&req->rc);
544 rmsg->msg.rlcreate.iounit = pdu_readd(&req->rc);
545
546 LTRACEF("9p lcreate: type (0x%x), version (%u), path (%llu), iounit (%u)\n",
547 rmsg->msg.rlcreate.qid.type, rmsg->msg.rlcreate.qid.version,
548 rmsg->msg.rlcreate.qid.path, rmsg->msg.rlcreate.iounit);
549
550 return NO_ERROR;
551 }
552
p9_proto_treaddir(struct p9_req * req,const virtio_9p_msg_t * tmsg)553 status_t p9_proto_treaddir(struct p9_req *req, const virtio_9p_msg_t *tmsg)
554 {
555 status_t ret;
556
557 // Treaddir pattern: fid[4] offset[8] count[4]
558 if ((ret = pdu_writed(&req->tc, tmsg->msg.treaddir.fid)) != NO_ERROR)
559 return ret;
560 if ((ret = pdu_writeq(&req->tc, tmsg->msg.treaddir.offset)) != NO_ERROR)
561 return ret;
562 if ((ret = pdu_writed(&req->tc, tmsg->msg.treaddir.count)) != NO_ERROR)
563 return ret;
564
565 return NO_ERROR;
566 }
567
p9_proto_rreaddir(struct p9_req * req,virtio_9p_msg_t * rmsg)568 status_t p9_proto_rreaddir(struct p9_req *req, virtio_9p_msg_t *rmsg)
569 {
570 // Rreaddir pattern: count[4] data[count]
571 rmsg->msg.rreaddir.data = pdu_readdata(&req->rc, &rmsg->msg.rreaddir.count);
572
573 LTRACEF("9p readdir: count (%u) data (%p)\n", rmsg->msg.rreaddir.count,
574 rmsg->msg.rreaddir.data);
575
576 return NO_ERROR;
577 }
578
p9_proto_tmkdir(struct p9_req * req,const virtio_9p_msg_t * tmsg)579 status_t p9_proto_tmkdir(struct p9_req *req, const virtio_9p_msg_t *tmsg)
580 {
581 status_t ret;
582
583 // Tmkdir pattern: dfid[4] name[s] mode[4] gid[4]
584 if ((ret = pdu_writed(&req->tc, tmsg->msg.tmkdir.dfid)) != NO_ERROR)
585 return ret;
586 if ((ret = pdu_writestr(&req->tc, tmsg->msg.tmkdir.name)) != NO_ERROR)
587 return ret;
588 if ((ret = pdu_writed(&req->tc, tmsg->msg.tmkdir.mode)) != NO_ERROR)
589 return ret;
590 if ((ret = pdu_writed(&req->tc, tmsg->msg.tmkdir.gid)) != NO_ERROR)
591 return ret;
592
593 return NO_ERROR;
594 }
595
p9_proto_rmkdir(struct p9_req * req,virtio_9p_msg_t * rmsg)596 status_t p9_proto_rmkdir(struct p9_req *req, virtio_9p_msg_t *rmsg)
597 {
598 // Rmkdir pattern: qid[13]
599 rmsg->msg.rmkdir.qid = pdu_readqid(&req->rc);
600
601 LTRACEF("9p mkdir: type (0x%x), version (%u), path (%llu)\n",
602 rmsg->msg.rmkdir.qid.type, rmsg->msg.rmkdir.qid.version,
603 rmsg->msg.rmkdir.qid.path);
604
605 return NO_ERROR;
606 }
607