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 version 2
12 * as published by the Free Software Foundation.
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/module.h>
28 #include <linux/errno.h>
30 #include <linux/idr.h>
31 #include <asm/uaccess.h>
38 * Buffer to help with string parsing
46 static inline void buf_init(struct cbuf *buf, void *data, int datalen)
48 buf->sp = buf->p = data;
49 buf->ep = data + datalen;
52 static inline int buf_check_overflow(struct cbuf *buf)
54 return buf->p > buf->ep;
57 static int buf_check_size(struct cbuf *buf, int len)
59 if (buf->p + len > buf->ep) {
60 if (buf->p < buf->ep) {
61 eprintk(KERN_ERR, "buffer overflow: want %d has %d\n",
62 len, (int)(buf->ep - buf->p));
73 static void *buf_alloc(struct cbuf *buf, int len)
77 if (buf_check_size(buf, len)) {
85 static void buf_put_int8(struct cbuf *buf, u8 val)
87 if (buf_check_size(buf, 1)) {
93 static void buf_put_int16(struct cbuf *buf, u16 val)
95 if (buf_check_size(buf, 2)) {
96 *(__le16 *) buf->p = cpu_to_le16(val);
101 static void buf_put_int32(struct cbuf *buf, u32 val)
103 if (buf_check_size(buf, 4)) {
104 *(__le32 *)buf->p = cpu_to_le32(val);
109 static void buf_put_int64(struct cbuf *buf, u64 val)
111 if (buf_check_size(buf, 8)) {
112 *(__le64 *)buf->p = cpu_to_le64(val);
117 static char *buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
122 if (buf_check_size(buf, slen + 2)) {
123 buf_put_int16(buf, slen);
125 memcpy(buf->p, s, slen);
132 static inline void buf_put_string(struct cbuf *buf, const char *s)
134 buf_put_stringn(buf, s, strlen(s));
137 static u8 buf_get_int8(struct cbuf *buf)
141 if (buf_check_size(buf, 1)) {
149 static u16 buf_get_int16(struct cbuf *buf)
153 if (buf_check_size(buf, 2)) {
154 ret = le16_to_cpu(*(__le16 *)buf->p);
161 static u32 buf_get_int32(struct cbuf *buf)
165 if (buf_check_size(buf, 4)) {
166 ret = le32_to_cpu(*(__le32 *)buf->p);
173 static u64 buf_get_int64(struct cbuf *buf)
177 if (buf_check_size(buf, 8)) {
178 ret = le64_to_cpu(*(__le64 *)buf->p);
185 static void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr)
187 vstr->len = buf_get_int16(buf);
188 if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) {
197 static void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid)
199 qid->type = buf_get_int8(bufp);
200 qid->version = buf_get_int32(bufp);
201 qid->path = buf_get_int64(bufp);
205 * v9fs_size_wstat - calculate the size of a variable length stat struct
206 * @stat: metadata (stat) structure
207 * @extended: non-zero if 9P2000.u
211 static int v9fs_size_wstat(struct v9fs_wstat *wstat, int extended)
216 eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n");
220 size = /* 2 + *//* size[2] */
223 1 + /* qid.type[1] */
224 4 + /* qid.vers[4] */
225 8 + /* qid.path[8] */
230 8; /* minimum sum of string lengths */
233 size += strlen(wstat->name);
235 size += strlen(wstat->uid);
237 size += strlen(wstat->gid);
239 size += strlen(wstat->muid);
242 size += 4 + /* n_uid[4] */
245 2; /* string length of extension[4] */
246 if (wstat->extension)
247 size += strlen(wstat->extension);
254 * buf_get_stat - safely decode a recieved metadata (stat) structure
255 * @bufp: buffer to deserialize
256 * @stat: metadata (stat) structure
257 * @extended: non-zero if 9P2000.u
262 buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended)
264 stat->size = buf_get_int16(bufp);
265 stat->type = buf_get_int16(bufp);
266 stat->dev = buf_get_int32(bufp);
267 stat->qid.type = buf_get_int8(bufp);
268 stat->qid.version = buf_get_int32(bufp);
269 stat->qid.path = buf_get_int64(bufp);
270 stat->mode = buf_get_int32(bufp);
271 stat->atime = buf_get_int32(bufp);
272 stat->mtime = buf_get_int32(bufp);
273 stat->length = buf_get_int64(bufp);
274 buf_get_str(bufp, &stat->name);
275 buf_get_str(bufp, &stat->uid);
276 buf_get_str(bufp, &stat->gid);
277 buf_get_str(bufp, &stat->muid);
280 buf_get_str(bufp, &stat->extension);
281 stat->n_uid = buf_get_int32(bufp);
282 stat->n_gid = buf_get_int32(bufp);
283 stat->n_muid = buf_get_int32(bufp);
288 * v9fs_deserialize_stat - decode a received metadata structure
289 * @buf: buffer to deserialize
290 * @buflen: length of received buffer
291 * @stat: metadata structure to decode into
292 * @extended: non-zero if 9P2000.u
294 * Note: stat will point to the buf region.
298 v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat,
302 struct cbuf *bufp = &buffer;
305 buf_init(bufp, buf, buflen);
307 buf_get_stat(bufp, stat, extended);
309 if (buf_check_overflow(bufp))
316 * deserialize_fcall - unmarshal a response
317 * @buf: recieved buffer
318 * @buflen: length of received buffer
319 * @rcall: fcall structure to populate
320 * @rcalllen: length of fcall structure to populate
321 * @extended: non-zero if 9P2000.u
326 v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall,
331 struct cbuf *bufp = &buffer;
334 buf_init(bufp, buf, buflen);
336 rcall->size = buf_get_int32(bufp);
337 rcall->id = buf_get_int8(bufp);
338 rcall->tag = buf_get_int16(bufp);
340 dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id,
345 eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id);
348 rcall->params.rversion.msize = buf_get_int32(bufp);
349 buf_get_str(bufp, &rcall->params.rversion.version);
354 rcall->params.rattach.qid.type = buf_get_int8(bufp);
355 rcall->params.rattach.qid.version = buf_get_int32(bufp);
356 rcall->params.rattach.qid.path = buf_get_int64(bufp);
359 rcall->params.rwalk.nwqid = buf_get_int16(bufp);
360 if (rcall->params.rwalk.nwqid > V9FS_MAXWELEM) {
361 eprintk(KERN_ERR, "Rwalk with more than %d qids: %d\n",
362 V9FS_MAXWELEM, rcall->params.rwalk.nwqid);
366 for (i = 0; i < rcall->params.rwalk.nwqid; i++)
367 buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]);
370 buf_get_qid(bufp, &rcall->params.ropen.qid);
371 rcall->params.ropen.iounit = buf_get_int32(bufp);
374 buf_get_qid(bufp, &rcall->params.rcreate.qid);
375 rcall->params.rcreate.iounit = buf_get_int32(bufp);
378 rcall->params.rread.count = buf_get_int32(bufp);
379 rcall->params.rread.data = bufp->p;
380 buf_check_size(bufp, rcall->params.rread.count);
383 rcall->params.rwrite.count = buf_get_int32(bufp);
391 buf_get_stat(bufp, &rcall->params.rstat.stat, extended);
396 buf_get_str(bufp, &rcall->params.rerror.error);
398 rcall->params.rerror.errno = buf_get_int16(bufp);
402 if (buf_check_overflow(bufp)) {
403 dprintk(DEBUG_ERROR, "buffer overflow\n");
407 return bufp->p - bufp->sp;
410 static inline void v9fs_put_int8(struct cbuf *bufp, u8 val, u8 * p)
413 buf_put_int8(bufp, val);
416 static inline void v9fs_put_int16(struct cbuf *bufp, u16 val, u16 * p)
419 buf_put_int16(bufp, val);
422 static inline void v9fs_put_int32(struct cbuf *bufp, u32 val, u32 * p)
425 buf_put_int32(bufp, val);
428 static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p)
431 buf_put_int64(bufp, val);
435 v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str)
445 s = buf_put_stringn(bufp, data, len);
453 v9fs_put_user_data(struct cbuf *bufp, const char __user * data, int count,
454 unsigned char **pdata)
456 *pdata = buf_alloc(bufp, count);
457 return copy_from_user(*pdata, data, count);
461 v9fs_put_wstat(struct cbuf *bufp, struct v9fs_wstat *wstat,
462 struct v9fs_stat *stat, int statsz, int extended)
464 v9fs_put_int16(bufp, statsz, &stat->size);
465 v9fs_put_int16(bufp, wstat->type, &stat->type);
466 v9fs_put_int32(bufp, wstat->dev, &stat->dev);
467 v9fs_put_int8(bufp, wstat->qid.type, &stat->qid.type);
468 v9fs_put_int32(bufp, wstat->qid.version, &stat->qid.version);
469 v9fs_put_int64(bufp, wstat->qid.path, &stat->qid.path);
470 v9fs_put_int32(bufp, wstat->mode, &stat->mode);
471 v9fs_put_int32(bufp, wstat->atime, &stat->atime);
472 v9fs_put_int32(bufp, wstat->mtime, &stat->mtime);
473 v9fs_put_int64(bufp, wstat->length, &stat->length);
475 v9fs_put_str(bufp, wstat->name, &stat->name);
476 v9fs_put_str(bufp, wstat->uid, &stat->uid);
477 v9fs_put_str(bufp, wstat->gid, &stat->gid);
478 v9fs_put_str(bufp, wstat->muid, &stat->muid);
481 v9fs_put_str(bufp, wstat->extension, &stat->extension);
482 v9fs_put_int32(bufp, wstat->n_uid, &stat->n_uid);
483 v9fs_put_int32(bufp, wstat->n_gid, &stat->n_gid);
484 v9fs_put_int32(bufp, wstat->n_muid, &stat->n_muid);
488 static struct v9fs_fcall *
489 v9fs_create_common(struct cbuf *bufp, u32 size, u8 id)
491 struct v9fs_fcall *fc;
493 size += 4 + 1 + 2; /* size[4] id[1] tag[2] */
494 fc = kmalloc(sizeof(struct v9fs_fcall) + size, GFP_KERNEL);
496 return ERR_PTR(-ENOMEM);
498 fc->sdata = (char *)fc + sizeof(*fc);
500 buf_init(bufp, (char *)fc->sdata, size);
501 v9fs_put_int32(bufp, size, &fc->size);
502 v9fs_put_int8(bufp, id, &fc->id);
503 v9fs_put_int16(bufp, V9FS_NOTAG, &fc->tag);
508 void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag)
511 *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag);
514 struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version)
517 struct v9fs_fcall *fc;
519 struct cbuf *bufp = &buffer;
521 size = 4 + 2 + strlen(version); /* msize[4] version[s] */
522 fc = v9fs_create_common(bufp, size, TVERSION);
526 v9fs_put_int32(bufp, msize, &fc->params.tversion.msize);
527 v9fs_put_str(bufp, version, &fc->params.tversion.version);
529 if (buf_check_overflow(bufp)) {
531 fc = ERR_PTR(-ENOMEM);
538 struct v9fs_fcall *v9fs_create_tauth(u32 afid, char *uname, char *aname)
541 struct v9fs_fcall *fc;
543 struct cbuf *bufp = &buffer;
545 size = 4 + 2 + strlen(uname) + 2 + strlen(aname); /* afid[4] uname[s] aname[s] */
546 fc = v9fs_create_common(bufp, size, TAUTH);
550 v9fs_put_int32(bufp, afid, &fc->params.tauth.afid);
551 v9fs_put_str(bufp, uname, &fc->params.tauth.uname);
552 v9fs_put_str(bufp, aname, &fc->params.tauth.aname);
554 if (buf_check_overflow(bufp)) {
556 fc = ERR_PTR(-ENOMEM);
564 v9fs_create_tattach(u32 fid, u32 afid, char *uname, char *aname)
567 struct v9fs_fcall *fc;
569 struct cbuf *bufp = &buffer;
571 size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname); /* fid[4] afid[4] uname[s] aname[s] */
572 fc = v9fs_create_common(bufp, size, TATTACH);
576 v9fs_put_int32(bufp, fid, &fc->params.tattach.fid);
577 v9fs_put_int32(bufp, afid, &fc->params.tattach.afid);
578 v9fs_put_str(bufp, uname, &fc->params.tattach.uname);
579 v9fs_put_str(bufp, aname, &fc->params.tattach.aname);
585 struct v9fs_fcall *v9fs_create_tflush(u16 oldtag)
588 struct v9fs_fcall *fc;
590 struct cbuf *bufp = &buffer;
592 size = 2; /* oldtag[2] */
593 fc = v9fs_create_common(bufp, size, TFLUSH);
597 v9fs_put_int16(bufp, oldtag, &fc->params.tflush.oldtag);
599 if (buf_check_overflow(bufp)) {
601 fc = ERR_PTR(-ENOMEM);
607 struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname,
611 struct v9fs_fcall *fc;
613 struct cbuf *bufp = &buffer;
615 if (nwname > V9FS_MAXWELEM) {
616 dprintk(DEBUG_ERROR, "nwname > %d\n", V9FS_MAXWELEM);
620 size = 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */
621 for (i = 0; i < nwname; i++) {
622 size += 2 + strlen(wnames[i]); /* wname[s] */
625 fc = v9fs_create_common(bufp, size, TWALK);
629 v9fs_put_int32(bufp, fid, &fc->params.twalk.fid);
630 v9fs_put_int32(bufp, newfid, &fc->params.twalk.newfid);
631 v9fs_put_int16(bufp, nwname, &fc->params.twalk.nwname);
632 for (i = 0; i < nwname; i++) {
633 v9fs_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]);
636 if (buf_check_overflow(bufp)) {
638 fc = ERR_PTR(-ENOMEM);
644 struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode)
647 struct v9fs_fcall *fc;
649 struct cbuf *bufp = &buffer;
651 size = 4 + 1; /* fid[4] mode[1] */
652 fc = v9fs_create_common(bufp, size, TOPEN);
656 v9fs_put_int32(bufp, fid, &fc->params.topen.fid);
657 v9fs_put_int8(bufp, mode, &fc->params.topen.mode);
659 if (buf_check_overflow(bufp)) {
661 fc = ERR_PTR(-ENOMEM);
667 struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode,
668 char *extension, int extended)
671 struct v9fs_fcall *fc;
673 struct cbuf *bufp = &buffer;
675 size = 4 + 2 + strlen(name) + 4 + 1; /* fid[4] name[s] perm[4] mode[1] */
676 if (extended && extension!=NULL)
677 size += 2 + strlen(extension); /* extension[s] */
679 fc = v9fs_create_common(bufp, size, TCREATE);
683 v9fs_put_int32(bufp, fid, &fc->params.tcreate.fid);
684 v9fs_put_str(bufp, name, &fc->params.tcreate.name);
685 v9fs_put_int32(bufp, perm, &fc->params.tcreate.perm);
686 v9fs_put_int8(bufp, mode, &fc->params.tcreate.mode);
688 v9fs_put_str(bufp, extension, &fc->params.tcreate.extension);
690 if (buf_check_overflow(bufp)) {
692 fc = ERR_PTR(-ENOMEM);
698 struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count)
701 struct v9fs_fcall *fc;
703 struct cbuf *bufp = &buffer;
705 size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */
706 fc = v9fs_create_common(bufp, size, TREAD);
710 v9fs_put_int32(bufp, fid, &fc->params.tread.fid);
711 v9fs_put_int64(bufp, offset, &fc->params.tread.offset);
712 v9fs_put_int32(bufp, count, &fc->params.tread.count);
714 if (buf_check_overflow(bufp)) {
716 fc = ERR_PTR(-ENOMEM);
722 struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count,
723 const char __user * data)
726 struct v9fs_fcall *fc;
728 struct cbuf *bufp = &buffer;
730 size = 4 + 8 + 4 + count; /* fid[4] offset[8] count[4] data[count] */
731 fc = v9fs_create_common(bufp, size, TWRITE);
735 v9fs_put_int32(bufp, fid, &fc->params.twrite.fid);
736 v9fs_put_int64(bufp, offset, &fc->params.twrite.offset);
737 v9fs_put_int32(bufp, count, &fc->params.twrite.count);
738 err = v9fs_put_user_data(bufp, data, count, &fc->params.twrite.data);
744 if (buf_check_overflow(bufp)) {
746 fc = ERR_PTR(-ENOMEM);
752 struct v9fs_fcall *v9fs_create_tclunk(u32 fid)
755 struct v9fs_fcall *fc;
757 struct cbuf *bufp = &buffer;
759 size = 4; /* fid[4] */
760 fc = v9fs_create_common(bufp, size, TCLUNK);
764 v9fs_put_int32(bufp, fid, &fc->params.tclunk.fid);
766 if (buf_check_overflow(bufp)) {
768 fc = ERR_PTR(-ENOMEM);
774 struct v9fs_fcall *v9fs_create_tremove(u32 fid)
777 struct v9fs_fcall *fc;
779 struct cbuf *bufp = &buffer;
781 size = 4; /* fid[4] */
782 fc = v9fs_create_common(bufp, size, TREMOVE);
786 v9fs_put_int32(bufp, fid, &fc->params.tremove.fid);
788 if (buf_check_overflow(bufp)) {
790 fc = ERR_PTR(-ENOMEM);
796 struct v9fs_fcall *v9fs_create_tstat(u32 fid)
799 struct v9fs_fcall *fc;
801 struct cbuf *bufp = &buffer;
803 size = 4; /* fid[4] */
804 fc = v9fs_create_common(bufp, size, TSTAT);
808 v9fs_put_int32(bufp, fid, &fc->params.tstat.fid);
810 if (buf_check_overflow(bufp)) {
812 fc = ERR_PTR(-ENOMEM);
818 struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat,
822 struct v9fs_fcall *fc;
824 struct cbuf *bufp = &buffer;
826 statsz = v9fs_size_wstat(wstat, extended);
827 size = 4 + 2 + 2 + statsz; /* fid[4] stat[n] */
828 fc = v9fs_create_common(bufp, size, TWSTAT);
832 v9fs_put_int32(bufp, fid, &fc->params.twstat.fid);
833 buf_put_int16(bufp, statsz + 2);
834 v9fs_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, extended);
836 if (buf_check_overflow(bufp)) {
838 fc = ERR_PTR(-ENOMEM);