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