]>
Commit | Line | Data |
---|---|---|
b8cf945b EVH |
1 | /* |
2 | * linux/fs/9p/conv.c | |
3 | * | |
4 | * 9P protocol conversion functions | |
5 | * | |
6 | * Copyright (C) 2004 by Eric Van Hensbergen <[email protected]> | |
7 | * Copyright (C) 2002 by Ron Minnich <[email protected]> | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to: | |
21 | * Free Software Foundation | |
22 | * 51 Franklin Street, Fifth Floor | |
23 | * Boston, MA 02111-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | #include <linux/config.h> | |
28 | #include <linux/module.h> | |
29 | #include <linux/errno.h> | |
30 | #include <linux/fs.h> | |
31 | #include <linux/idr.h> | |
32 | ||
33 | #include "debug.h" | |
34 | #include "v9fs.h" | |
35 | #include "9p.h" | |
36 | #include "conv.h" | |
37 | ||
38 | /* | |
39 | * Buffer to help with string parsing | |
40 | */ | |
41 | struct cbuf { | |
42 | unsigned char *sp; | |
43 | unsigned char *p; | |
44 | unsigned char *ep; | |
45 | }; | |
46 | ||
47 | static inline void buf_init(struct cbuf *buf, void *data, int datalen) | |
48 | { | |
49 | buf->sp = buf->p = data; | |
50 | buf->ep = data + datalen; | |
51 | } | |
52 | ||
53 | static inline int buf_check_overflow(struct cbuf *buf) | |
54 | { | |
55 | return buf->p > buf->ep; | |
56 | } | |
57 | ||
58 | static inline void buf_check_size(struct cbuf *buf, int len) | |
59 | { | |
60 | if (buf->p+len > buf->ep) { | |
61 | if (buf->p < buf->ep) { | |
62 | eprintk(KERN_ERR, "buffer overflow\n"); | |
63 | buf->p = buf->ep + 1; | |
64 | } | |
65 | } | |
66 | } | |
67 | ||
68 | static inline void *buf_alloc(struct cbuf *buf, int len) | |
69 | { | |
70 | void *ret = NULL; | |
71 | ||
72 | buf_check_size(buf, len); | |
73 | ret = buf->p; | |
74 | buf->p += len; | |
75 | ||
76 | return ret; | |
77 | } | |
78 | ||
79 | static inline void buf_put_int8(struct cbuf *buf, u8 val) | |
80 | { | |
81 | buf_check_size(buf, 1); | |
82 | ||
83 | buf->p[0] = val; | |
84 | buf->p++; | |
85 | } | |
86 | ||
87 | static inline void buf_put_int16(struct cbuf *buf, u16 val) | |
88 | { | |
89 | buf_check_size(buf, 2); | |
90 | ||
91 | *(__le16 *) buf->p = cpu_to_le16(val); | |
92 | buf->p += 2; | |
93 | } | |
94 | ||
95 | static inline void buf_put_int32(struct cbuf *buf, u32 val) | |
96 | { | |
97 | buf_check_size(buf, 4); | |
98 | ||
99 | *(__le32 *)buf->p = cpu_to_le32(val); | |
100 | buf->p += 4; | |
101 | } | |
102 | ||
103 | static inline void buf_put_int64(struct cbuf *buf, u64 val) | |
104 | { | |
105 | buf_check_size(buf, 8); | |
106 | ||
107 | *(__le64 *)buf->p = cpu_to_le64(val); | |
108 | buf->p += 8; | |
109 | } | |
110 | ||
111 | static inline void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen) | |
112 | { | |
113 | buf_check_size(buf, slen + 2); | |
114 | ||
115 | buf_put_int16(buf, slen); | |
116 | memcpy(buf->p, s, slen); | |
117 | buf->p += slen; | |
118 | } | |
119 | ||
120 | static inline void buf_put_string(struct cbuf *buf, const char *s) | |
121 | { | |
122 | buf_put_stringn(buf, s, strlen(s)); | |
123 | } | |
124 | ||
125 | static inline void buf_put_data(struct cbuf *buf, void *data, u32 datalen) | |
126 | { | |
127 | buf_check_size(buf, datalen); | |
128 | ||
129 | memcpy(buf->p, data, datalen); | |
130 | buf->p += datalen; | |
131 | } | |
132 | ||
133 | static inline u8 buf_get_int8(struct cbuf *buf) | |
134 | { | |
135 | u8 ret = 0; | |
136 | ||
137 | buf_check_size(buf, 1); | |
138 | ret = buf->p[0]; | |
139 | ||
140 | buf->p++; | |
141 | ||
142 | return ret; | |
143 | } | |
144 | ||
145 | static inline u16 buf_get_int16(struct cbuf *buf) | |
146 | { | |
147 | u16 ret = 0; | |
148 | ||
149 | buf_check_size(buf, 2); | |
150 | ret = le16_to_cpu(*(__le16 *)buf->p); | |
151 | ||
152 | buf->p += 2; | |
153 | ||
154 | return ret; | |
155 | } | |
156 | ||
157 | static inline u32 buf_get_int32(struct cbuf *buf) | |
158 | { | |
159 | u32 ret = 0; | |
160 | ||
161 | buf_check_size(buf, 4); | |
162 | ret = le32_to_cpu(*(__le32 *)buf->p); | |
163 | ||
164 | buf->p += 4; | |
165 | ||
166 | return ret; | |
167 | } | |
168 | ||
169 | static inline u64 buf_get_int64(struct cbuf *buf) | |
170 | { | |
171 | u64 ret = 0; | |
172 | ||
173 | buf_check_size(buf, 8); | |
174 | ret = le64_to_cpu(*(__le64 *)buf->p); | |
175 | ||
176 | buf->p += 8; | |
177 | ||
178 | return ret; | |
179 | } | |
180 | ||
181 | static inline int | |
182 | buf_get_string(struct cbuf *buf, char *data, unsigned int datalen) | |
183 | { | |
184 | ||
185 | u16 len = buf_get_int16(buf); | |
186 | buf_check_size(buf, len); | |
187 | if (len + 1 > datalen) | |
188 | return 0; | |
189 | ||
190 | memcpy(data, buf->p, len); | |
191 | data[len] = 0; | |
192 | buf->p += len; | |
193 | ||
194 | return len + 1; | |
195 | } | |
196 | ||
197 | static inline char *buf_get_stringb(struct cbuf *buf, struct cbuf *sbuf) | |
198 | { | |
199 | char *ret = NULL; | |
200 | int n = buf_get_string(buf, sbuf->p, sbuf->ep - sbuf->p); | |
201 | ||
202 | if (n > 0) { | |
203 | ret = sbuf->p; | |
204 | sbuf->p += n; | |
205 | } | |
206 | ||
207 | return ret; | |
208 | } | |
209 | ||
210 | static inline int buf_get_data(struct cbuf *buf, void *data, int datalen) | |
211 | { | |
212 | buf_check_size(buf, datalen); | |
213 | ||
214 | memcpy(data, buf->p, datalen); | |
215 | buf->p += datalen; | |
216 | ||
217 | return datalen; | |
218 | } | |
219 | ||
220 | static inline void *buf_get_datab(struct cbuf *buf, struct cbuf *dbuf, | |
221 | int datalen) | |
222 | { | |
223 | char *ret = NULL; | |
224 | int n = 0; | |
225 | ||
226 | buf_check_size(dbuf, datalen); | |
227 | ||
228 | n = buf_get_data(buf, dbuf->p, datalen); | |
229 | ||
230 | if (n > 0) { | |
231 | ret = dbuf->p; | |
232 | dbuf->p += n; | |
233 | } | |
234 | ||
235 | return ret; | |
236 | } | |
237 | ||
238 | /** | |
239 | * v9fs_size_stat - calculate the size of a variable length stat struct | |
240 | * @v9ses: session information | |
241 | * @stat: metadata (stat) structure | |
242 | * | |
243 | */ | |
244 | ||
245 | static int v9fs_size_stat(struct v9fs_session_info *v9ses, | |
246 | struct v9fs_stat *stat) | |
247 | { | |
248 | int size = 0; | |
249 | ||
250 | if (stat == NULL) { | |
251 | eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n"); | |
252 | return 0; | |
253 | } | |
254 | ||
255 | size = /* 2 + *//* size[2] */ | |
256 | 2 + /* type[2] */ | |
257 | 4 + /* dev[4] */ | |
258 | 1 + /* qid.type[1] */ | |
259 | 4 + /* qid.vers[4] */ | |
260 | 8 + /* qid.path[8] */ | |
261 | 4 + /* mode[4] */ | |
262 | 4 + /* atime[4] */ | |
263 | 4 + /* mtime[4] */ | |
264 | 8 + /* length[8] */ | |
265 | 8; /* minimum sum of string lengths */ | |
266 | ||
267 | if (stat->name) | |
268 | size += strlen(stat->name); | |
269 | if (stat->uid) | |
270 | size += strlen(stat->uid); | |
271 | if (stat->gid) | |
272 | size += strlen(stat->gid); | |
273 | if (stat->muid) | |
274 | size += strlen(stat->muid); | |
275 | ||
276 | if (v9ses->extended) { | |
277 | size += 4 + /* n_uid[4] */ | |
278 | 4 + /* n_gid[4] */ | |
279 | 4 + /* n_muid[4] */ | |
280 | 2; /* string length of extension[4] */ | |
281 | if (stat->extension) | |
282 | size += strlen(stat->extension); | |
283 | } | |
284 | ||
285 | return size; | |
286 | } | |
287 | ||
288 | /** | |
289 | * serialize_stat - safely format a stat structure for transmission | |
290 | * @v9ses: session info | |
291 | * @stat: metadata (stat) structure | |
292 | * @bufp: buffer to serialize structure into | |
293 | * | |
294 | */ | |
295 | ||
296 | static int | |
297 | serialize_stat(struct v9fs_session_info *v9ses, struct v9fs_stat *stat, | |
298 | struct cbuf *bufp) | |
299 | { | |
300 | buf_put_int16(bufp, stat->size); | |
301 | buf_put_int16(bufp, stat->type); | |
302 | buf_put_int32(bufp, stat->dev); | |
303 | buf_put_int8(bufp, stat->qid.type); | |
304 | buf_put_int32(bufp, stat->qid.version); | |
305 | buf_put_int64(bufp, stat->qid.path); | |
306 | buf_put_int32(bufp, stat->mode); | |
307 | buf_put_int32(bufp, stat->atime); | |
308 | buf_put_int32(bufp, stat->mtime); | |
309 | buf_put_int64(bufp, stat->length); | |
310 | ||
311 | buf_put_string(bufp, stat->name); | |
312 | buf_put_string(bufp, stat->uid); | |
313 | buf_put_string(bufp, stat->gid); | |
314 | buf_put_string(bufp, stat->muid); | |
315 | ||
316 | if (v9ses->extended) { | |
317 | buf_put_string(bufp, stat->extension); | |
318 | buf_put_int32(bufp, stat->n_uid); | |
319 | buf_put_int32(bufp, stat->n_gid); | |
320 | buf_put_int32(bufp, stat->n_muid); | |
321 | } | |
322 | ||
323 | if (buf_check_overflow(bufp)) | |
324 | return 0; | |
325 | ||
326 | return stat->size; | |
327 | } | |
328 | ||
329 | /** | |
330 | * deserialize_stat - safely decode a recieved metadata (stat) structure | |
331 | * @v9ses: session info | |
332 | * @bufp: buffer to deserialize | |
333 | * @stat: metadata (stat) structure | |
334 | * @dbufp: buffer to deserialize variable strings into | |
335 | * | |
336 | */ | |
337 | ||
338 | static inline int | |
339 | deserialize_stat(struct v9fs_session_info *v9ses, struct cbuf *bufp, | |
340 | struct v9fs_stat *stat, struct cbuf *dbufp) | |
341 | { | |
342 | ||
343 | stat->size = buf_get_int16(bufp); | |
344 | stat->type = buf_get_int16(bufp); | |
345 | stat->dev = buf_get_int32(bufp); | |
346 | stat->qid.type = buf_get_int8(bufp); | |
347 | stat->qid.version = buf_get_int32(bufp); | |
348 | stat->qid.path = buf_get_int64(bufp); | |
349 | stat->mode = buf_get_int32(bufp); | |
350 | stat->atime = buf_get_int32(bufp); | |
351 | stat->mtime = buf_get_int32(bufp); | |
352 | stat->length = buf_get_int64(bufp); | |
353 | stat->name = buf_get_stringb(bufp, dbufp); | |
354 | stat->uid = buf_get_stringb(bufp, dbufp); | |
355 | stat->gid = buf_get_stringb(bufp, dbufp); | |
356 | stat->muid = buf_get_stringb(bufp, dbufp); | |
357 | ||
358 | if (v9ses->extended) { | |
359 | stat->extension = buf_get_stringb(bufp, dbufp); | |
360 | stat->n_uid = buf_get_int32(bufp); | |
361 | stat->n_gid = buf_get_int32(bufp); | |
362 | stat->n_muid = buf_get_int32(bufp); | |
363 | } | |
364 | ||
365 | if (buf_check_overflow(bufp) || buf_check_overflow(dbufp)) | |
366 | return 0; | |
367 | ||
368 | return stat->size + 2; | |
369 | } | |
370 | ||
371 | /** | |
372 | * deserialize_statb - wrapper for decoding a received metadata structure | |
373 | * @v9ses: session info | |
374 | * @bufp: buffer to deserialize | |
375 | * @dbufp: buffer to deserialize variable strings into | |
376 | * | |
377 | */ | |
378 | ||
379 | static inline struct v9fs_stat *deserialize_statb(struct v9fs_session_info | |
380 | *v9ses, struct cbuf *bufp, | |
381 | struct cbuf *dbufp) | |
382 | { | |
383 | struct v9fs_stat *ret = buf_alloc(dbufp, sizeof(struct v9fs_stat)); | |
384 | ||
385 | if (ret) { | |
386 | int n = deserialize_stat(v9ses, bufp, ret, dbufp); | |
387 | if (n <= 0) | |
388 | return NULL; | |
389 | } | |
390 | ||
391 | return ret; | |
392 | } | |
393 | ||
394 | /** | |
395 | * v9fs_deserialize_stat - decode a received metadata structure | |
396 | * @v9ses: session info | |
397 | * @buf: buffer to deserialize | |
398 | * @buflen: length of received buffer | |
399 | * @stat: metadata structure to decode into | |
400 | * @statlen: length of destination metadata structure | |
401 | * | |
402 | */ | |
403 | ||
404 | int | |
405 | v9fs_deserialize_stat(struct v9fs_session_info *v9ses, void *buf, | |
406 | u32 buflen, struct v9fs_stat *stat, u32 statlen) | |
407 | { | |
408 | struct cbuf buffer; | |
409 | struct cbuf *bufp = &buffer; | |
410 | struct cbuf dbuffer; | |
411 | struct cbuf *dbufp = &dbuffer; | |
412 | ||
413 | buf_init(bufp, buf, buflen); | |
414 | buf_init(dbufp, (char *)stat + sizeof(struct v9fs_stat), | |
415 | statlen - sizeof(struct v9fs_stat)); | |
416 | ||
417 | return deserialize_stat(v9ses, bufp, stat, dbufp); | |
418 | } | |
419 | ||
420 | static inline int | |
421 | v9fs_size_fcall(struct v9fs_session_info *v9ses, struct v9fs_fcall *fcall) | |
422 | { | |
423 | int size = 4 + 1 + 2; /* size[4] msg[1] tag[2] */ | |
424 | int i = 0; | |
425 | ||
426 | switch (fcall->id) { | |
427 | default: | |
428 | eprintk(KERN_ERR, "bad msg type %d\n", fcall->id); | |
429 | return 0; | |
430 | case TVERSION: /* msize[4] version[s] */ | |
431 | size += 4 + 2 + strlen(fcall->params.tversion.version); | |
432 | break; | |
433 | case TAUTH: /* afid[4] uname[s] aname[s] */ | |
434 | size += 4 + 2 + strlen(fcall->params.tauth.uname) + | |
435 | 2 + strlen(fcall->params.tauth.aname); | |
436 | break; | |
437 | case TFLUSH: /* oldtag[2] */ | |
438 | size += 2; | |
439 | break; | |
440 | case TATTACH: /* fid[4] afid[4] uname[s] aname[s] */ | |
441 | size += 4 + 4 + 2 + strlen(fcall->params.tattach.uname) + | |
442 | 2 + strlen(fcall->params.tattach.aname); | |
443 | break; | |
444 | case TWALK: /* fid[4] newfid[4] nwname[2] nwname*(wname[s]) */ | |
445 | size += 4 + 4 + 2; | |
446 | /* now compute total for the array of names */ | |
447 | for (i = 0; i < fcall->params.twalk.nwname; i++) | |
448 | size += 2 + strlen(fcall->params.twalk.wnames[i]); | |
449 | break; | |
450 | case TOPEN: /* fid[4] mode[1] */ | |
451 | size += 4 + 1; | |
452 | break; | |
453 | case TCREATE: /* fid[4] name[s] perm[4] mode[1] */ | |
454 | size += 4 + 2 + strlen(fcall->params.tcreate.name) + 4 + 1; | |
455 | break; | |
456 | case TREAD: /* fid[4] offset[8] count[4] */ | |
457 | size += 4 + 8 + 4; | |
458 | break; | |
459 | case TWRITE: /* fid[4] offset[8] count[4] data[count] */ | |
460 | size += 4 + 8 + 4 + fcall->params.twrite.count; | |
461 | break; | |
462 | case TCLUNK: /* fid[4] */ | |
463 | size += 4; | |
464 | break; | |
465 | case TREMOVE: /* fid[4] */ | |
466 | size += 4; | |
467 | break; | |
468 | case TSTAT: /* fid[4] */ | |
469 | size += 4; | |
470 | break; | |
471 | case TWSTAT: /* fid[4] stat[n] */ | |
472 | fcall->params.twstat.stat->size = | |
473 | v9fs_size_stat(v9ses, fcall->params.twstat.stat); | |
474 | size += 4 + 2 + 2 + fcall->params.twstat.stat->size; | |
475 | } | |
476 | return size; | |
477 | } | |
478 | ||
479 | /* | |
480 | * v9fs_serialize_fcall - marshall fcall struct into a packet | |
481 | * @v9ses: session information | |
482 | * @fcall: structure to convert | |
483 | * @data: buffer to serialize fcall into | |
484 | * @datalen: length of buffer to serialize fcall into | |
485 | * | |
486 | */ | |
487 | ||
488 | int | |
489 | v9fs_serialize_fcall(struct v9fs_session_info *v9ses, struct v9fs_fcall *fcall, | |
490 | void *data, u32 datalen) | |
491 | { | |
492 | int i = 0; | |
493 | struct v9fs_stat *stat = NULL; | |
494 | struct cbuf buffer; | |
495 | struct cbuf *bufp = &buffer; | |
496 | ||
497 | buf_init(bufp, data, datalen); | |
498 | ||
499 | if (!fcall) { | |
500 | eprintk(KERN_ERR, "no fcall\n"); | |
501 | return -EINVAL; | |
502 | } | |
503 | ||
504 | fcall->size = v9fs_size_fcall(v9ses, fcall); | |
505 | ||
506 | buf_put_int32(bufp, fcall->size); | |
507 | buf_put_int8(bufp, fcall->id); | |
508 | buf_put_int16(bufp, fcall->tag); | |
509 | ||
510 | dprintk(DEBUG_CONV, "size %d id %d tag %d\n", fcall->size, fcall->id, | |
511 | fcall->tag); | |
512 | ||
513 | /* now encode it */ | |
514 | switch (fcall->id) { | |
515 | default: | |
516 | eprintk(KERN_ERR, "bad msg type: %d\n", fcall->id); | |
517 | return -EPROTO; | |
518 | case TVERSION: | |
519 | buf_put_int32(bufp, fcall->params.tversion.msize); | |
520 | buf_put_string(bufp, fcall->params.tversion.version); | |
521 | break; | |
522 | case TAUTH: | |
523 | buf_put_int32(bufp, fcall->params.tauth.afid); | |
524 | buf_put_string(bufp, fcall->params.tauth.uname); | |
525 | buf_put_string(bufp, fcall->params.tauth.aname); | |
526 | break; | |
527 | case TFLUSH: | |
528 | buf_put_int16(bufp, fcall->params.tflush.oldtag); | |
529 | break; | |
530 | case TATTACH: | |
531 | buf_put_int32(bufp, fcall->params.tattach.fid); | |
532 | buf_put_int32(bufp, fcall->params.tattach.afid); | |
533 | buf_put_string(bufp, fcall->params.tattach.uname); | |
534 | buf_put_string(bufp, fcall->params.tattach.aname); | |
535 | break; | |
536 | case TWALK: | |
537 | buf_put_int32(bufp, fcall->params.twalk.fid); | |
538 | buf_put_int32(bufp, fcall->params.twalk.newfid); | |
539 | buf_put_int16(bufp, fcall->params.twalk.nwname); | |
540 | for (i = 0; i < fcall->params.twalk.nwname; i++) | |
541 | buf_put_string(bufp, fcall->params.twalk.wnames[i]); | |
542 | break; | |
543 | case TOPEN: | |
544 | buf_put_int32(bufp, fcall->params.topen.fid); | |
545 | buf_put_int8(bufp, fcall->params.topen.mode); | |
546 | break; | |
547 | case TCREATE: | |
548 | buf_put_int32(bufp, fcall->params.tcreate.fid); | |
549 | buf_put_string(bufp, fcall->params.tcreate.name); | |
550 | buf_put_int32(bufp, fcall->params.tcreate.perm); | |
551 | buf_put_int8(bufp, fcall->params.tcreate.mode); | |
552 | break; | |
553 | case TREAD: | |
554 | buf_put_int32(bufp, fcall->params.tread.fid); | |
555 | buf_put_int64(bufp, fcall->params.tread.offset); | |
556 | buf_put_int32(bufp, fcall->params.tread.count); | |
557 | break; | |
558 | case TWRITE: | |
559 | buf_put_int32(bufp, fcall->params.twrite.fid); | |
560 | buf_put_int64(bufp, fcall->params.twrite.offset); | |
561 | buf_put_int32(bufp, fcall->params.twrite.count); | |
562 | buf_put_data(bufp, fcall->params.twrite.data, | |
563 | fcall->params.twrite.count); | |
564 | break; | |
565 | case TCLUNK: | |
566 | buf_put_int32(bufp, fcall->params.tclunk.fid); | |
567 | break; | |
568 | case TREMOVE: | |
569 | buf_put_int32(bufp, fcall->params.tremove.fid); | |
570 | break; | |
571 | case TSTAT: | |
572 | buf_put_int32(bufp, fcall->params.tstat.fid); | |
573 | break; | |
574 | case TWSTAT: | |
575 | buf_put_int32(bufp, fcall->params.twstat.fid); | |
576 | stat = fcall->params.twstat.stat; | |
577 | ||
578 | buf_put_int16(bufp, stat->size + 2); | |
579 | serialize_stat(v9ses, stat, bufp); | |
580 | break; | |
581 | } | |
582 | ||
583 | if (buf_check_overflow(bufp)) | |
584 | return -EIO; | |
585 | ||
586 | return fcall->size; | |
587 | } | |
588 | ||
589 | /** | |
590 | * deserialize_fcall - unmarshal a response | |
591 | * @v9ses: session information | |
592 | * @msgsize: size of rcall message | |
593 | * @buf: recieved buffer | |
594 | * @buflen: length of received buffer | |
595 | * @rcall: fcall structure to populate | |
596 | * @rcalllen: length of fcall structure to populate | |
597 | * | |
598 | */ | |
599 | ||
600 | int | |
601 | v9fs_deserialize_fcall(struct v9fs_session_info *v9ses, u32 msgsize, | |
602 | void *buf, u32 buflen, struct v9fs_fcall *rcall, | |
603 | int rcalllen) | |
604 | { | |
605 | ||
606 | struct cbuf buffer; | |
607 | struct cbuf *bufp = &buffer; | |
608 | struct cbuf dbuffer; | |
609 | struct cbuf *dbufp = &dbuffer; | |
610 | int i = 0; | |
611 | ||
612 | buf_init(bufp, buf, buflen); | |
613 | buf_init(dbufp, (char *)rcall + sizeof(struct v9fs_fcall), | |
614 | rcalllen - sizeof(struct v9fs_fcall)); | |
615 | ||
616 | rcall->size = msgsize; | |
617 | rcall->id = buf_get_int8(bufp); | |
618 | rcall->tag = buf_get_int16(bufp); | |
619 | ||
620 | dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id, | |
621 | rcall->tag); | |
622 | switch (rcall->id) { | |
623 | default: | |
624 | eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id); | |
625 | return -EPROTO; | |
626 | case RVERSION: | |
627 | rcall->params.rversion.msize = buf_get_int32(bufp); | |
628 | rcall->params.rversion.version = buf_get_stringb(bufp, dbufp); | |
629 | break; | |
630 | case RFLUSH: | |
631 | break; | |
632 | case RATTACH: | |
633 | rcall->params.rattach.qid.type = buf_get_int8(bufp); | |
634 | rcall->params.rattach.qid.version = buf_get_int32(bufp); | |
635 | rcall->params.rattach.qid.path = buf_get_int64(bufp); | |
636 | break; | |
637 | case RWALK: | |
638 | rcall->params.rwalk.nwqid = buf_get_int16(bufp); | |
639 | rcall->params.rwalk.wqids = buf_alloc(bufp, | |
640 | rcall->params.rwalk.nwqid * sizeof(struct v9fs_qid)); | |
641 | if (rcall->params.rwalk.wqids) | |
642 | for (i = 0; i < rcall->params.rwalk.nwqid; i++) { | |
643 | rcall->params.rwalk.wqids[i].type = | |
644 | buf_get_int8(bufp); | |
645 | rcall->params.rwalk.wqids[i].version = | |
646 | buf_get_int16(bufp); | |
647 | rcall->params.rwalk.wqids[i].path = | |
648 | buf_get_int64(bufp); | |
649 | } | |
650 | break; | |
651 | case ROPEN: | |
652 | rcall->params.ropen.qid.type = buf_get_int8(bufp); | |
653 | rcall->params.ropen.qid.version = buf_get_int32(bufp); | |
654 | rcall->params.ropen.qid.path = buf_get_int64(bufp); | |
655 | rcall->params.ropen.iounit = buf_get_int32(bufp); | |
656 | break; | |
657 | case RCREATE: | |
658 | rcall->params.rcreate.qid.type = buf_get_int8(bufp); | |
659 | rcall->params.rcreate.qid.version = buf_get_int32(bufp); | |
660 | rcall->params.rcreate.qid.path = buf_get_int64(bufp); | |
661 | rcall->params.rcreate.iounit = buf_get_int32(bufp); | |
662 | break; | |
663 | case RREAD: | |
664 | rcall->params.rread.count = buf_get_int32(bufp); | |
665 | rcall->params.rread.data = buf_get_datab(bufp, dbufp, | |
666 | rcall->params.rread.count); | |
667 | break; | |
668 | case RWRITE: | |
669 | rcall->params.rwrite.count = buf_get_int32(bufp); | |
670 | break; | |
671 | case RCLUNK: | |
672 | break; | |
673 | case RREMOVE: | |
674 | break; | |
675 | case RSTAT: | |
676 | buf_get_int16(bufp); | |
677 | rcall->params.rstat.stat = | |
678 | deserialize_statb(v9ses, bufp, dbufp); | |
679 | break; | |
680 | case RWSTAT: | |
681 | break; | |
682 | case RERROR: | |
683 | rcall->params.rerror.error = buf_get_stringb(bufp, dbufp); | |
684 | if (v9ses->extended) | |
685 | rcall->params.rerror.errno = buf_get_int16(bufp); | |
686 | break; | |
687 | } | |
688 | ||
689 | if (buf_check_overflow(bufp) || buf_check_overflow(dbufp)) | |
690 | return -EIO; | |
691 | ||
692 | return rcall->size; | |
693 | } |