4 * 9P protocol conversion functions
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
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.
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.
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
27 #include <linux/config.h>
28 #include <linux/module.h>
29 #include <linux/errno.h>
31 #include <linux/idr.h>
39 * Buffer to help with string parsing
47 static inline void buf_init(struct cbuf
*buf
, void *data
, int datalen
)
49 buf
->sp
= buf
->p
= data
;
50 buf
->ep
= data
+ datalen
;
53 static inline int buf_check_overflow(struct cbuf
*buf
)
55 return buf
->p
> buf
->ep
;
58 static inline void buf_check_size(struct cbuf
*buf
, int len
)
60 if (buf
->p
+len
> buf
->ep
) {
61 if (buf
->p
< buf
->ep
) {
62 eprintk(KERN_ERR
, "buffer overflow\n");
68 static inline void *buf_alloc(struct cbuf
*buf
, int len
)
72 buf_check_size(buf
, len
);
79 static inline void buf_put_int8(struct cbuf
*buf
, u8 val
)
81 buf_check_size(buf
, 1);
87 static inline void buf_put_int16(struct cbuf
*buf
, u16 val
)
89 buf_check_size(buf
, 2);
91 *(__le16
*) buf
->p
= cpu_to_le16(val
);
95 static inline void buf_put_int32(struct cbuf
*buf
, u32 val
)
97 buf_check_size(buf
, 4);
99 *(__le32
*)buf
->p
= cpu_to_le32(val
);
103 static inline void buf_put_int64(struct cbuf
*buf
, u64 val
)
105 buf_check_size(buf
, 8);
107 *(__le64
*)buf
->p
= cpu_to_le64(val
);
111 static inline void buf_put_stringn(struct cbuf
*buf
, const char *s
, u16 slen
)
113 buf_check_size(buf
, slen
+ 2);
115 buf_put_int16(buf
, slen
);
116 memcpy(buf
->p
, s
, slen
);
120 static inline void buf_put_string(struct cbuf
*buf
, const char *s
)
122 buf_put_stringn(buf
, s
, strlen(s
));
125 static inline void buf_put_data(struct cbuf
*buf
, void *data
, u32 datalen
)
127 buf_check_size(buf
, datalen
);
129 memcpy(buf
->p
, data
, datalen
);
133 static inline u8
buf_get_int8(struct cbuf
*buf
)
137 buf_check_size(buf
, 1);
145 static inline u16
buf_get_int16(struct cbuf
*buf
)
149 buf_check_size(buf
, 2);
150 ret
= le16_to_cpu(*(__le16
*)buf
->p
);
157 static inline u32
buf_get_int32(struct cbuf
*buf
)
161 buf_check_size(buf
, 4);
162 ret
= le32_to_cpu(*(__le32
*)buf
->p
);
169 static inline u64
buf_get_int64(struct cbuf
*buf
)
173 buf_check_size(buf
, 8);
174 ret
= le64_to_cpu(*(__le64
*)buf
->p
);
182 buf_get_string(struct cbuf
*buf
, char *data
, unsigned int datalen
)
185 u16 len
= buf_get_int16(buf
);
186 buf_check_size(buf
, len
);
187 if (len
+ 1 > datalen
)
190 memcpy(data
, buf
->p
, len
);
197 static inline char *buf_get_stringb(struct cbuf
*buf
, struct cbuf
*sbuf
)
200 int n
= buf_get_string(buf
, sbuf
->p
, sbuf
->ep
- sbuf
->p
);
210 static inline int buf_get_data(struct cbuf
*buf
, void *data
, int datalen
)
212 buf_check_size(buf
, datalen
);
214 memcpy(data
, buf
->p
, datalen
);
220 static inline void *buf_get_datab(struct cbuf
*buf
, struct cbuf
*dbuf
,
226 buf_check_size(dbuf
, datalen
);
228 n
= buf_get_data(buf
, dbuf
->p
, datalen
);
239 * v9fs_size_stat - calculate the size of a variable length stat struct
240 * @v9ses: session information
241 * @stat: metadata (stat) structure
245 static int v9fs_size_stat(struct v9fs_session_info
*v9ses
,
246 struct v9fs_stat
*stat
)
251 eprintk(KERN_ERR
, "v9fs_size_stat: got a NULL stat pointer\n");
255 size
= /* 2 + *//* size[2] */
258 1 + /* qid.type[1] */
259 4 + /* qid.vers[4] */
260 8 + /* qid.path[8] */
265 8; /* minimum sum of string lengths */
268 size
+= strlen(stat
->name
);
270 size
+= strlen(stat
->uid
);
272 size
+= strlen(stat
->gid
);
274 size
+= strlen(stat
->muid
);
276 if (v9ses
->extended
) {
277 size
+= 4 + /* n_uid[4] */
280 2; /* string length of extension[4] */
282 size
+= strlen(stat
->extension
);
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
297 serialize_stat(struct v9fs_session_info
*v9ses
, struct v9fs_stat
*stat
,
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
);
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
);
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
);
323 if (buf_check_overflow(bufp
))
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
339 deserialize_stat(struct v9fs_session_info
*v9ses
, struct cbuf
*bufp
,
340 struct v9fs_stat
*stat
, struct cbuf
*dbufp
)
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
);
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
);
365 if (buf_check_overflow(bufp
) || buf_check_overflow(dbufp
))
368 return stat
->size
+ 2;
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
379 static inline struct v9fs_stat
*deserialize_statb(struct v9fs_session_info
380 *v9ses
, struct cbuf
*bufp
,
383 struct v9fs_stat
*ret
= buf_alloc(dbufp
, sizeof(struct v9fs_stat
));
386 int n
= deserialize_stat(v9ses
, bufp
, ret
, dbufp
);
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
405 v9fs_deserialize_stat(struct v9fs_session_info
*v9ses
, void *buf
,
406 u32 buflen
, struct v9fs_stat
*stat
, u32 statlen
)
409 struct cbuf
*bufp
= &buffer
;
411 struct cbuf
*dbufp
= &dbuffer
;
413 buf_init(bufp
, buf
, buflen
);
414 buf_init(dbufp
, (char *)stat
+ sizeof(struct v9fs_stat
),
415 statlen
- sizeof(struct v9fs_stat
));
417 return deserialize_stat(v9ses
, bufp
, stat
, dbufp
);
421 v9fs_size_fcall(struct v9fs_session_info
*v9ses
, struct v9fs_fcall
*fcall
)
423 int size
= 4 + 1 + 2; /* size[4] msg[1] tag[2] */
428 eprintk(KERN_ERR
, "bad msg type %d\n", fcall
->id
);
430 case TVERSION
: /* msize[4] version[s] */
431 size
+= 4 + 2 + strlen(fcall
->params
.tversion
.version
);
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
);
437 case TFLUSH
: /* oldtag[2] */
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
);
444 case TWALK
: /* fid[4] newfid[4] nwname[2] nwname*(wname[s]) */
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
]);
450 case TOPEN
: /* fid[4] mode[1] */
453 case TCREATE
: /* fid[4] name[s] perm[4] mode[1] */
454 size
+= 4 + 2 + strlen(fcall
->params
.tcreate
.name
) + 4 + 1;
456 case TREAD
: /* fid[4] offset[8] count[4] */
459 case TWRITE
: /* fid[4] offset[8] count[4] data[count] */
460 size
+= 4 + 8 + 4 + fcall
->params
.twrite
.count
;
462 case TCLUNK
: /* fid[4] */
465 case TREMOVE
: /* fid[4] */
468 case TSTAT
: /* fid[4] */
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
;
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
489 v9fs_serialize_fcall(struct v9fs_session_info
*v9ses
, struct v9fs_fcall
*fcall
,
490 void *data
, u32 datalen
)
493 struct v9fs_stat
*stat
= NULL
;
495 struct cbuf
*bufp
= &buffer
;
497 buf_init(bufp
, data
, datalen
);
500 eprintk(KERN_ERR
, "no fcall\n");
504 fcall
->size
= v9fs_size_fcall(v9ses
, fcall
);
506 buf_put_int32(bufp
, fcall
->size
);
507 buf_put_int8(bufp
, fcall
->id
);
508 buf_put_int16(bufp
, fcall
->tag
);
510 dprintk(DEBUG_CONV
, "size %d id %d tag %d\n", fcall
->size
, fcall
->id
,
516 eprintk(KERN_ERR
, "bad msg type: %d\n", fcall
->id
);
519 buf_put_int32(bufp
, fcall
->params
.tversion
.msize
);
520 buf_put_string(bufp
, fcall
->params
.tversion
.version
);
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
);
528 buf_put_int16(bufp
, fcall
->params
.tflush
.oldtag
);
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
);
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
]);
544 buf_put_int32(bufp
, fcall
->params
.topen
.fid
);
545 buf_put_int8(bufp
, fcall
->params
.topen
.mode
);
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
);
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
);
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
);
566 buf_put_int32(bufp
, fcall
->params
.tclunk
.fid
);
569 buf_put_int32(bufp
, fcall
->params
.tremove
.fid
);
572 buf_put_int32(bufp
, fcall
->params
.tstat
.fid
);
575 buf_put_int32(bufp
, fcall
->params
.twstat
.fid
);
576 stat
= fcall
->params
.twstat
.stat
;
578 buf_put_int16(bufp
, stat
->size
+ 2);
579 serialize_stat(v9ses
, stat
, bufp
);
583 if (buf_check_overflow(bufp
))
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
601 v9fs_deserialize_fcall(struct v9fs_session_info
*v9ses
, u32 msgsize
,
602 void *buf
, u32 buflen
, struct v9fs_fcall
*rcall
,
607 struct cbuf
*bufp
= &buffer
;
609 struct cbuf
*dbufp
= &dbuffer
;
612 buf_init(bufp
, buf
, buflen
);
613 buf_init(dbufp
, (char *)rcall
+ sizeof(struct v9fs_fcall
),
614 rcalllen
- sizeof(struct v9fs_fcall
));
616 rcall
->size
= msgsize
;
617 rcall
->id
= buf_get_int8(bufp
);
618 rcall
->tag
= buf_get_int16(bufp
);
620 dprintk(DEBUG_CONV
, "size %d id %d tag %d\n", rcall
->size
, rcall
->id
,
624 eprintk(KERN_ERR
, "unknown message type: %d\n", rcall
->id
);
627 rcall
->params
.rversion
.msize
= buf_get_int32(bufp
);
628 rcall
->params
.rversion
.version
= buf_get_stringb(bufp
, dbufp
);
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
);
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
=
645 rcall
->params
.rwalk
.wqids
[i
].version
=
647 rcall
->params
.rwalk
.wqids
[i
].path
=
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
);
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
);
664 rcall
->params
.rread
.count
= buf_get_int32(bufp
);
665 rcall
->params
.rread
.data
= buf_get_datab(bufp
, dbufp
,
666 rcall
->params
.rread
.count
);
669 rcall
->params
.rwrite
.count
= buf_get_int32(bufp
);
677 rcall
->params
.rstat
.stat
=
678 deserialize_statb(v9ses
, bufp
, dbufp
);
683 rcall
->params
.rerror
.error
= buf_get_stringb(bufp
, dbufp
);
685 rcall
->params
.rerror
.errno
= buf_get_int16(bufp
);
689 if (buf_check_overflow(bufp
) || buf_check_overflow(dbufp
))