4 * 9P protocol conversion functions
6 * Copyright (C) 2004, 2005 by Latchesar Ionkov <lucho@ionkov.net>
7 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
8 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to:
22 * Free Software Foundation
23 * 51 Franklin Street, Fifth Floor
24 * Boston, MA 02111-1301 USA
28 #include <linux/config.h>
29 #include <linux/module.h>
30 #include <linux/errno.h>
32 #include <linux/idr.h>
33 #include <asm/uaccess.h>
40 * Buffer to help with string parsing
48 static inline void buf_init(struct cbuf
*buf
, void *data
, int datalen
)
50 buf
->sp
= buf
->p
= data
;
51 buf
->ep
= data
+ datalen
;
54 static inline int buf_check_overflow(struct cbuf
*buf
)
56 return buf
->p
> buf
->ep
;
59 static int buf_check_size(struct cbuf
*buf
, int len
)
61 if (buf
->p
+ len
> buf
->ep
) {
62 if (buf
->p
< buf
->ep
) {
63 eprintk(KERN_ERR
, "buffer overflow: want %d has %d\n",
64 len
, (int)(buf
->ep
- buf
->p
));
75 static void *buf_alloc(struct cbuf
*buf
, int len
)
79 if (buf_check_size(buf
, len
)) {
87 static void buf_put_int8(struct cbuf
*buf
, u8 val
)
89 if (buf_check_size(buf
, 1)) {
95 static void buf_put_int16(struct cbuf
*buf
, u16 val
)
97 if (buf_check_size(buf
, 2)) {
98 *(__le16
*) buf
->p
= cpu_to_le16(val
);
103 static void buf_put_int32(struct cbuf
*buf
, u32 val
)
105 if (buf_check_size(buf
, 4)) {
106 *(__le32
*)buf
->p
= cpu_to_le32(val
);
111 static void buf_put_int64(struct cbuf
*buf
, u64 val
)
113 if (buf_check_size(buf
, 8)) {
114 *(__le64
*)buf
->p
= cpu_to_le64(val
);
119 static void buf_put_stringn(struct cbuf
*buf
, const char *s
, u16 slen
)
121 if (buf_check_size(buf
, slen
+ 2)) {
122 buf_put_int16(buf
, slen
);
123 memcpy(buf
->p
, s
, slen
);
128 static inline void buf_put_string(struct cbuf
*buf
, const char *s
)
130 buf_put_stringn(buf
, s
, strlen(s
));
133 static u8
buf_get_int8(struct cbuf
*buf
)
137 if (buf_check_size(buf
, 1)) {
145 static u16
buf_get_int16(struct cbuf
*buf
)
149 if (buf_check_size(buf
, 2)) {
150 ret
= le16_to_cpu(*(__le16
*)buf
->p
);
157 static u32
buf_get_int32(struct cbuf
*buf
)
161 if (buf_check_size(buf
, 4)) {
162 ret
= le32_to_cpu(*(__le32
*)buf
->p
);
169 static u64
buf_get_int64(struct cbuf
*buf
)
173 if (buf_check_size(buf
, 8)) {
174 ret
= le64_to_cpu(*(__le64
*)buf
->p
);
181 static void buf_get_str(struct cbuf
*buf
, struct v9fs_str
*vstr
)
183 vstr
->len
= buf_get_int16(buf
);
184 if (!buf_check_overflow(buf
) && buf_check_size(buf
, vstr
->len
)) {
193 static void buf_get_qid(struct cbuf
*bufp
, struct v9fs_qid
*qid
)
195 qid
->type
= buf_get_int8(bufp
);
196 qid
->version
= buf_get_int32(bufp
);
197 qid
->path
= buf_get_int64(bufp
);
201 * v9fs_size_wstat - calculate the size of a variable length stat struct
202 * @stat: metadata (stat) structure
203 * @extended: non-zero if 9P2000.u
207 static int v9fs_size_wstat(struct v9fs_wstat
*wstat
, int extended
)
212 eprintk(KERN_ERR
, "v9fs_size_stat: got a NULL stat pointer\n");
216 size
= /* 2 + *//* size[2] */
219 1 + /* qid.type[1] */
220 4 + /* qid.vers[4] */
221 8 + /* qid.path[8] */
226 8; /* minimum sum of string lengths */
229 size
+= strlen(wstat
->name
);
231 size
+= strlen(wstat
->uid
);
233 size
+= strlen(wstat
->gid
);
235 size
+= strlen(wstat
->muid
);
238 size
+= 4 + /* n_uid[4] */
241 2; /* string length of extension[4] */
242 if (wstat
->extension
)
243 size
+= strlen(wstat
->extension
);
250 * buf_get_stat - safely decode a recieved metadata (stat) structure
251 * @bufp: buffer to deserialize
252 * @stat: metadata (stat) structure
253 * @extended: non-zero if 9P2000.u
258 buf_get_stat(struct cbuf
*bufp
, struct v9fs_stat
*stat
, int extended
)
260 stat
->size
= buf_get_int16(bufp
);
261 stat
->type
= buf_get_int16(bufp
);
262 stat
->dev
= buf_get_int32(bufp
);
263 stat
->qid
.type
= buf_get_int8(bufp
);
264 stat
->qid
.version
= buf_get_int32(bufp
);
265 stat
->qid
.path
= buf_get_int64(bufp
);
266 stat
->mode
= buf_get_int32(bufp
);
267 stat
->atime
= buf_get_int32(bufp
);
268 stat
->mtime
= buf_get_int32(bufp
);
269 stat
->length
= buf_get_int64(bufp
);
270 buf_get_str(bufp
, &stat
->name
);
271 buf_get_str(bufp
, &stat
->uid
);
272 buf_get_str(bufp
, &stat
->gid
);
273 buf_get_str(bufp
, &stat
->muid
);
276 buf_get_str(bufp
, &stat
->extension
);
277 stat
->n_uid
= buf_get_int32(bufp
);
278 stat
->n_gid
= buf_get_int32(bufp
);
279 stat
->n_muid
= buf_get_int32(bufp
);
284 * v9fs_deserialize_stat - decode a received metadata structure
285 * @buf: buffer to deserialize
286 * @buflen: length of received buffer
287 * @stat: metadata structure to decode into
288 * @extended: non-zero if 9P2000.u
290 * Note: stat will point to the buf region.
294 v9fs_deserialize_stat(void *buf
, u32 buflen
, struct v9fs_stat
*stat
,
298 struct cbuf
*bufp
= &buffer
;
301 buf_init(bufp
, buf
, buflen
);
303 buf_get_stat(bufp
, stat
, extended
);
305 if (buf_check_overflow(bufp
))
312 * deserialize_fcall - unmarshal a response
313 * @buf: recieved buffer
314 * @buflen: length of received buffer
315 * @rcall: fcall structure to populate
316 * @rcalllen: length of fcall structure to populate
317 * @extended: non-zero if 9P2000.u
322 v9fs_deserialize_fcall(void *buf
, u32 buflen
, struct v9fs_fcall
*rcall
,
327 struct cbuf
*bufp
= &buffer
;
330 buf_init(bufp
, buf
, buflen
);
332 rcall
->size
= buf_get_int32(bufp
);
333 rcall
->id
= buf_get_int8(bufp
);
334 rcall
->tag
= buf_get_int16(bufp
);
336 dprintk(DEBUG_CONV
, "size %d id %d tag %d\n", rcall
->size
, rcall
->id
,
341 eprintk(KERN_ERR
, "unknown message type: %d\n", rcall
->id
);
344 rcall
->params
.rversion
.msize
= buf_get_int32(bufp
);
345 buf_get_str(bufp
, &rcall
->params
.rversion
.version
);
350 rcall
->params
.rattach
.qid
.type
= buf_get_int8(bufp
);
351 rcall
->params
.rattach
.qid
.version
= buf_get_int32(bufp
);
352 rcall
->params
.rattach
.qid
.path
= buf_get_int64(bufp
);
355 rcall
->params
.rwalk
.nwqid
= buf_get_int16(bufp
);
356 if (rcall
->params
.rwalk
.nwqid
> V9FS_MAXWELEM
) {
357 eprintk(KERN_ERR
, "Rwalk with more than %d qids: %d\n",
358 V9FS_MAXWELEM
, rcall
->params
.rwalk
.nwqid
);
362 for (i
= 0; i
< rcall
->params
.rwalk
.nwqid
; i
++)
363 buf_get_qid(bufp
, &rcall
->params
.rwalk
.wqids
[i
]);
366 buf_get_qid(bufp
, &rcall
->params
.ropen
.qid
);
367 rcall
->params
.ropen
.iounit
= buf_get_int32(bufp
);
370 buf_get_qid(bufp
, &rcall
->params
.rcreate
.qid
);
371 rcall
->params
.rcreate
.iounit
= buf_get_int32(bufp
);
374 rcall
->params
.rread
.count
= buf_get_int32(bufp
);
375 rcall
->params
.rread
.data
= bufp
->p
;
376 buf_check_size(bufp
, rcall
->params
.rread
.count
);
379 rcall
->params
.rwrite
.count
= buf_get_int32(bufp
);
387 buf_get_stat(bufp
, &rcall
->params
.rstat
.stat
, extended
);
392 buf_get_str(bufp
, &rcall
->params
.rerror
.error
);
394 rcall
->params
.rerror
.errno
= buf_get_int16(bufp
);
398 if (buf_check_overflow(bufp
)) {
399 dprintk(DEBUG_ERROR
, "buffer overflow\n");
403 return bufp
->p
- bufp
->sp
;
406 static inline void v9fs_put_int8(struct cbuf
*bufp
, u8 val
, u8
* p
)
409 buf_put_int8(bufp
, val
);
412 static inline void v9fs_put_int16(struct cbuf
*bufp
, u16 val
, u16
* p
)
415 buf_put_int16(bufp
, val
);
418 static inline void v9fs_put_int32(struct cbuf
*bufp
, u32 val
, u32
* p
)
421 buf_put_int32(bufp
, val
);
424 static inline void v9fs_put_int64(struct cbuf
*bufp
, u64 val
, u64
* p
)
427 buf_put_int64(bufp
, val
);
431 v9fs_put_str(struct cbuf
*bufp
, char *data
, struct v9fs_str
*str
)
434 str
->len
= strlen(data
);
441 buf_put_stringn(bufp
, data
, str
->len
);
445 v9fs_put_user_data(struct cbuf
*bufp
, const char __user
* data
, int count
,
446 unsigned char **pdata
)
448 *pdata
= buf_alloc(bufp
, count
);
449 return copy_from_user(*pdata
, data
, count
);
453 v9fs_put_wstat(struct cbuf
*bufp
, struct v9fs_wstat
*wstat
,
454 struct v9fs_stat
*stat
, int statsz
, int extended
)
456 v9fs_put_int16(bufp
, statsz
, &stat
->size
);
457 v9fs_put_int16(bufp
, wstat
->type
, &stat
->type
);
458 v9fs_put_int32(bufp
, wstat
->dev
, &stat
->dev
);
459 v9fs_put_int8(bufp
, wstat
->qid
.type
, &stat
->qid
.type
);
460 v9fs_put_int32(bufp
, wstat
->qid
.version
, &stat
->qid
.version
);
461 v9fs_put_int64(bufp
, wstat
->qid
.path
, &stat
->qid
.path
);
462 v9fs_put_int32(bufp
, wstat
->mode
, &stat
->mode
);
463 v9fs_put_int32(bufp
, wstat
->atime
, &stat
->atime
);
464 v9fs_put_int32(bufp
, wstat
->mtime
, &stat
->mtime
);
465 v9fs_put_int64(bufp
, wstat
->length
, &stat
->length
);
467 v9fs_put_str(bufp
, wstat
->name
, &stat
->name
);
468 v9fs_put_str(bufp
, wstat
->uid
, &stat
->uid
);
469 v9fs_put_str(bufp
, wstat
->gid
, &stat
->gid
);
470 v9fs_put_str(bufp
, wstat
->muid
, &stat
->muid
);
473 v9fs_put_str(bufp
, wstat
->extension
, &stat
->extension
);
474 v9fs_put_int32(bufp
, wstat
->n_uid
, &stat
->n_uid
);
475 v9fs_put_int32(bufp
, wstat
->n_gid
, &stat
->n_gid
);
476 v9fs_put_int32(bufp
, wstat
->n_muid
, &stat
->n_muid
);
480 static struct v9fs_fcall
*
481 v9fs_create_common(struct cbuf
*bufp
, u32 size
, u8 id
)
483 struct v9fs_fcall
*fc
;
485 size
+= 4 + 1 + 2; /* size[4] id[1] tag[2] */
486 fc
= kmalloc(sizeof(struct v9fs_fcall
) + size
, GFP_KERNEL
);
488 return ERR_PTR(-ENOMEM
);
490 fc
->sdata
= (char *)fc
+ sizeof(*fc
);
492 buf_init(bufp
, (char *)fc
->sdata
, size
);
493 v9fs_put_int32(bufp
, size
, &fc
->size
);
494 v9fs_put_int8(bufp
, id
, &fc
->id
);
495 v9fs_put_int16(bufp
, V9FS_NOTAG
, &fc
->tag
);
500 void v9fs_set_tag(struct v9fs_fcall
*fc
, u16 tag
)
503 *(__le16
*) (fc
->sdata
+ 5) = cpu_to_le16(tag
);
506 struct v9fs_fcall
*v9fs_create_tversion(u32 msize
, char *version
)
509 struct v9fs_fcall
*fc
;
511 struct cbuf
*bufp
= &buffer
;
513 size
= 4 + 2 + strlen(version
); /* msize[4] version[s] */
514 fc
= v9fs_create_common(bufp
, size
, TVERSION
);
518 v9fs_put_int32(bufp
, msize
, &fc
->params
.tversion
.msize
);
519 v9fs_put_str(bufp
, version
, &fc
->params
.tversion
.version
);
521 if (buf_check_overflow(bufp
)) {
523 fc
= ERR_PTR(-ENOMEM
);
529 struct v9fs_fcall
*v9fs_create_tauth(u32 afid
, char *uname
, char *aname
)
532 struct v9fs_fcall
*fc
;
534 struct cbuf
*bufp
= &buffer
;
536 size
= 4 + 2 + strlen(uname
) + 2 + strlen(aname
); /* afid[4] uname[s] aname[s] */
537 fc
= v9fs_create_common(bufp
, size
, TAUTH
);
541 v9fs_put_int32(bufp
, afid
, &fc
->params
.tauth
.afid
);
542 v9fs_put_str(bufp
, uname
, &fc
->params
.tauth
.uname
);
543 v9fs_put_str(bufp
, aname
, &fc
->params
.tauth
.aname
);
545 if (buf_check_overflow(bufp
)) {
547 fc
= ERR_PTR(-ENOMEM
);
554 v9fs_create_tattach(u32 fid
, u32 afid
, char *uname
, char *aname
)
557 struct v9fs_fcall
*fc
;
559 struct cbuf
*bufp
= &buffer
;
561 size
= 4 + 4 + 2 + strlen(uname
) + 2 + strlen(aname
); /* fid[4] afid[4] uname[s] aname[s] */
562 fc
= v9fs_create_common(bufp
, size
, TATTACH
);
566 v9fs_put_int32(bufp
, fid
, &fc
->params
.tattach
.fid
);
567 v9fs_put_int32(bufp
, afid
, &fc
->params
.tattach
.afid
);
568 v9fs_put_str(bufp
, uname
, &fc
->params
.tattach
.uname
);
569 v9fs_put_str(bufp
, aname
, &fc
->params
.tattach
.aname
);
575 struct v9fs_fcall
*v9fs_create_tflush(u16 oldtag
)
578 struct v9fs_fcall
*fc
;
580 struct cbuf
*bufp
= &buffer
;
582 size
= 2; /* oldtag[2] */
583 fc
= v9fs_create_common(bufp
, size
, TFLUSH
);
587 v9fs_put_int16(bufp
, oldtag
, &fc
->params
.tflush
.oldtag
);
589 if (buf_check_overflow(bufp
)) {
591 fc
= ERR_PTR(-ENOMEM
);
597 struct v9fs_fcall
*v9fs_create_twalk(u32 fid
, u32 newfid
, u16 nwname
,
601 struct v9fs_fcall
*fc
;
603 struct cbuf
*bufp
= &buffer
;
605 if (nwname
> V9FS_MAXWELEM
) {
606 dprintk(DEBUG_ERROR
, "nwname > %d\n", V9FS_MAXWELEM
);
610 size
= 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */
611 for (i
= 0; i
< nwname
; i
++) {
612 size
+= 2 + strlen(wnames
[i
]); /* wname[s] */
615 fc
= v9fs_create_common(bufp
, size
, TWALK
);
619 v9fs_put_int32(bufp
, fid
, &fc
->params
.twalk
.fid
);
620 v9fs_put_int32(bufp
, newfid
, &fc
->params
.twalk
.newfid
);
621 v9fs_put_int16(bufp
, nwname
, &fc
->params
.twalk
.nwname
);
622 for (i
= 0; i
< nwname
; i
++) {
623 v9fs_put_str(bufp
, wnames
[i
], &fc
->params
.twalk
.wnames
[i
]);
626 if (buf_check_overflow(bufp
)) {
628 fc
= ERR_PTR(-ENOMEM
);
634 struct v9fs_fcall
*v9fs_create_topen(u32 fid
, u8 mode
)
637 struct v9fs_fcall
*fc
;
639 struct cbuf
*bufp
= &buffer
;
641 size
= 4 + 1; /* fid[4] mode[1] */
642 fc
= v9fs_create_common(bufp
, size
, TOPEN
);
646 v9fs_put_int32(bufp
, fid
, &fc
->params
.topen
.fid
);
647 v9fs_put_int8(bufp
, mode
, &fc
->params
.topen
.mode
);
649 if (buf_check_overflow(bufp
)) {
651 fc
= ERR_PTR(-ENOMEM
);
657 struct v9fs_fcall
*v9fs_create_tcreate(u32 fid
, char *name
, u32 perm
, u8 mode
)
660 struct v9fs_fcall
*fc
;
662 struct cbuf
*bufp
= &buffer
;
664 size
= 4 + 2 + strlen(name
) + 4 + 1; /* fid[4] name[s] perm[4] mode[1] */
665 fc
= v9fs_create_common(bufp
, size
, TCREATE
);
669 v9fs_put_int32(bufp
, fid
, &fc
->params
.tcreate
.fid
);
670 v9fs_put_str(bufp
, name
, &fc
->params
.tcreate
.name
);
671 v9fs_put_int32(bufp
, perm
, &fc
->params
.tcreate
.perm
);
672 v9fs_put_int8(bufp
, mode
, &fc
->params
.tcreate
.mode
);
674 if (buf_check_overflow(bufp
)) {
676 fc
= ERR_PTR(-ENOMEM
);
682 struct v9fs_fcall
*v9fs_create_tread(u32 fid
, u64 offset
, u32 count
)
685 struct v9fs_fcall
*fc
;
687 struct cbuf
*bufp
= &buffer
;
689 size
= 4 + 8 + 4; /* fid[4] offset[8] count[4] */
690 fc
= v9fs_create_common(bufp
, size
, TREAD
);
694 v9fs_put_int32(bufp
, fid
, &fc
->params
.tread
.fid
);
695 v9fs_put_int64(bufp
, offset
, &fc
->params
.tread
.offset
);
696 v9fs_put_int32(bufp
, count
, &fc
->params
.tread
.count
);
698 if (buf_check_overflow(bufp
)) {
700 fc
= ERR_PTR(-ENOMEM
);
706 struct v9fs_fcall
*v9fs_create_twrite(u32 fid
, u64 offset
, u32 count
,
707 const char __user
* data
)
710 struct v9fs_fcall
*fc
;
712 struct cbuf
*bufp
= &buffer
;
714 size
= 4 + 8 + 4 + count
; /* fid[4] offset[8] count[4] data[count] */
715 fc
= v9fs_create_common(bufp
, size
, TWRITE
);
719 v9fs_put_int32(bufp
, fid
, &fc
->params
.twrite
.fid
);
720 v9fs_put_int64(bufp
, offset
, &fc
->params
.twrite
.offset
);
721 v9fs_put_int32(bufp
, count
, &fc
->params
.twrite
.count
);
722 err
= v9fs_put_user_data(bufp
, data
, count
, &fc
->params
.twrite
.data
);
728 if (buf_check_overflow(bufp
)) {
730 fc
= ERR_PTR(-ENOMEM
);
736 struct v9fs_fcall
*v9fs_create_tclunk(u32 fid
)
739 struct v9fs_fcall
*fc
;
741 struct cbuf
*bufp
= &buffer
;
743 size
= 4; /* fid[4] */
744 fc
= v9fs_create_common(bufp
, size
, TCLUNK
);
748 v9fs_put_int32(bufp
, fid
, &fc
->params
.tclunk
.fid
);
750 if (buf_check_overflow(bufp
)) {
752 fc
= ERR_PTR(-ENOMEM
);
758 struct v9fs_fcall
*v9fs_create_tremove(u32 fid
)
761 struct v9fs_fcall
*fc
;
763 struct cbuf
*bufp
= &buffer
;
765 size
= 4; /* fid[4] */
766 fc
= v9fs_create_common(bufp
, size
, TREMOVE
);
770 v9fs_put_int32(bufp
, fid
, &fc
->params
.tremove
.fid
);
772 if (buf_check_overflow(bufp
)) {
774 fc
= ERR_PTR(-ENOMEM
);
780 struct v9fs_fcall
*v9fs_create_tstat(u32 fid
)
783 struct v9fs_fcall
*fc
;
785 struct cbuf
*bufp
= &buffer
;
787 size
= 4; /* fid[4] */
788 fc
= v9fs_create_common(bufp
, size
, TSTAT
);
792 v9fs_put_int32(bufp
, fid
, &fc
->params
.tstat
.fid
);
794 if (buf_check_overflow(bufp
)) {
796 fc
= ERR_PTR(-ENOMEM
);
802 struct v9fs_fcall
*v9fs_create_twstat(u32 fid
, struct v9fs_wstat
*wstat
,
806 struct v9fs_fcall
*fc
;
808 struct cbuf
*bufp
= &buffer
;
810 statsz
= v9fs_size_wstat(wstat
, extended
);
811 size
= 4 + 2 + 2 + statsz
; /* fid[4] stat[n] */
812 fc
= v9fs_create_common(bufp
, size
, TWSTAT
);
816 v9fs_put_int32(bufp
, fid
, &fc
->params
.twstat
.fid
);
817 buf_put_int16(bufp
, statsz
+ 2);
818 v9fs_put_wstat(bufp
, wstat
, &fc
->params
.twstat
.stat
, statsz
, extended
);
820 if (buf_check_overflow(bufp
)) {
822 fc
= ERR_PTR(-ENOMEM
);