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>
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 inline 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\n");
72 static inline void *buf_alloc(struct cbuf
*buf
, int len
)
76 if (buf_check_size(buf
, len
)) {
84 static inline void buf_put_int8(struct cbuf
*buf
, u8 val
)
86 if (buf_check_size(buf
, 1)) {
92 static inline void buf_put_int16(struct cbuf
*buf
, u16 val
)
94 if (buf_check_size(buf
, 2)) {
95 *(__le16
*) buf
->p
= cpu_to_le16(val
);
100 static inline void buf_put_int32(struct cbuf
*buf
, u32 val
)
102 if (buf_check_size(buf
, 4)) {
103 *(__le32
*)buf
->p
= cpu_to_le32(val
);
108 static inline void buf_put_int64(struct cbuf
*buf
, u64 val
)
110 if (buf_check_size(buf
, 8)) {
111 *(__le64
*)buf
->p
= cpu_to_le64(val
);
116 static inline void buf_put_stringn(struct cbuf
*buf
, const char *s
, u16 slen
)
118 if (buf_check_size(buf
, slen
+ 2)) {
119 buf_put_int16(buf
, slen
);
120 memcpy(buf
->p
, s
, slen
);
125 static inline void buf_put_string(struct cbuf
*buf
, const char *s
)
127 buf_put_stringn(buf
, s
, strlen(s
));
130 static inline void buf_put_data(struct cbuf
*buf
, void *data
, u32 datalen
)
132 if (buf_check_size(buf
, datalen
)) {
133 memcpy(buf
->p
, data
, datalen
);
138 static inline u8
buf_get_int8(struct cbuf
*buf
)
142 if (buf_check_size(buf
, 1)) {
150 static inline u16
buf_get_int16(struct cbuf
*buf
)
154 if (buf_check_size(buf
, 2)) {
155 ret
= le16_to_cpu(*(__le16
*)buf
->p
);
162 static inline u32
buf_get_int32(struct cbuf
*buf
)
166 if (buf_check_size(buf
, 4)) {
167 ret
= le32_to_cpu(*(__le32
*)buf
->p
);
174 static inline u64
buf_get_int64(struct cbuf
*buf
)
178 if (buf_check_size(buf
, 8)) {
179 ret
= le64_to_cpu(*(__le64
*)buf
->p
);
187 buf_get_string(struct cbuf
*buf
, char *data
, unsigned int datalen
)
191 len
= buf_get_int16(buf
);
192 if (!buf_check_overflow(buf
) && buf_check_size(buf
, len
) && len
+1>datalen
) {
193 memcpy(data
, buf
->p
, len
);
202 static inline char *buf_get_stringb(struct cbuf
*buf
, struct cbuf
*sbuf
)
208 len
= buf_get_int16(buf
);
210 if (!buf_check_overflow(buf
) && buf_check_size(buf
, len
) &&
211 buf_check_size(sbuf
, len
+1)) {
213 memcpy(sbuf
->p
, buf
->p
, len
);
223 static inline int buf_get_data(struct cbuf
*buf
, void *data
, int datalen
)
227 if (buf_check_size(buf
, datalen
)) {
228 memcpy(data
, buf
->p
, datalen
);
236 static inline void *buf_get_datab(struct cbuf
*buf
, struct cbuf
*dbuf
,
242 if (buf_check_size(dbuf
, datalen
)) {
243 n
= buf_get_data(buf
, dbuf
->p
, datalen
);
254 * v9fs_size_stat - calculate the size of a variable length stat struct
255 * @v9ses: session information
256 * @stat: metadata (stat) structure
260 static int v9fs_size_stat(struct v9fs_session_info
*v9ses
,
261 struct v9fs_stat
*stat
)
266 eprintk(KERN_ERR
, "v9fs_size_stat: got a NULL stat pointer\n");
270 size
= /* 2 + *//* size[2] */
273 1 + /* qid.type[1] */
274 4 + /* qid.vers[4] */
275 8 + /* qid.path[8] */
280 8; /* minimum sum of string lengths */
283 size
+= strlen(stat
->name
);
285 size
+= strlen(stat
->uid
);
287 size
+= strlen(stat
->gid
);
289 size
+= strlen(stat
->muid
);
291 if (v9ses
->extended
) {
292 size
+= 4 + /* n_uid[4] */
295 2; /* string length of extension[4] */
297 size
+= strlen(stat
->extension
);
304 * serialize_stat - safely format a stat structure for transmission
305 * @v9ses: session info
306 * @stat: metadata (stat) structure
307 * @bufp: buffer to serialize structure into
312 serialize_stat(struct v9fs_session_info
*v9ses
, struct v9fs_stat
*stat
,
315 buf_put_int16(bufp
, stat
->size
);
316 buf_put_int16(bufp
, stat
->type
);
317 buf_put_int32(bufp
, stat
->dev
);
318 buf_put_int8(bufp
, stat
->qid
.type
);
319 buf_put_int32(bufp
, stat
->qid
.version
);
320 buf_put_int64(bufp
, stat
->qid
.path
);
321 buf_put_int32(bufp
, stat
->mode
);
322 buf_put_int32(bufp
, stat
->atime
);
323 buf_put_int32(bufp
, stat
->mtime
);
324 buf_put_int64(bufp
, stat
->length
);
326 buf_put_string(bufp
, stat
->name
);
327 buf_put_string(bufp
, stat
->uid
);
328 buf_put_string(bufp
, stat
->gid
);
329 buf_put_string(bufp
, stat
->muid
);
331 if (v9ses
->extended
) {
332 buf_put_string(bufp
, stat
->extension
);
333 buf_put_int32(bufp
, stat
->n_uid
);
334 buf_put_int32(bufp
, stat
->n_gid
);
335 buf_put_int32(bufp
, stat
->n_muid
);
338 if (buf_check_overflow(bufp
))
345 * deserialize_stat - safely decode a recieved metadata (stat) structure
346 * @v9ses: session info
347 * @bufp: buffer to deserialize
348 * @stat: metadata (stat) structure
349 * @dbufp: buffer to deserialize variable strings into
354 deserialize_stat(struct v9fs_session_info
*v9ses
, struct cbuf
*bufp
,
355 struct v9fs_stat
*stat
, struct cbuf
*dbufp
)
358 stat
->size
= buf_get_int16(bufp
);
359 stat
->type
= buf_get_int16(bufp
);
360 stat
->dev
= buf_get_int32(bufp
);
361 stat
->qid
.type
= buf_get_int8(bufp
);
362 stat
->qid
.version
= buf_get_int32(bufp
);
363 stat
->qid
.path
= buf_get_int64(bufp
);
364 stat
->mode
= buf_get_int32(bufp
);
365 stat
->atime
= buf_get_int32(bufp
);
366 stat
->mtime
= buf_get_int32(bufp
);
367 stat
->length
= buf_get_int64(bufp
);
368 stat
->name
= buf_get_stringb(bufp
, dbufp
);
369 stat
->uid
= buf_get_stringb(bufp
, dbufp
);
370 stat
->gid
= buf_get_stringb(bufp
, dbufp
);
371 stat
->muid
= buf_get_stringb(bufp
, dbufp
);
373 if (v9ses
->extended
) {
374 stat
->extension
= buf_get_stringb(bufp
, dbufp
);
375 stat
->n_uid
= buf_get_int32(bufp
);
376 stat
->n_gid
= buf_get_int32(bufp
);
377 stat
->n_muid
= buf_get_int32(bufp
);
380 if (buf_check_overflow(bufp
) || buf_check_overflow(dbufp
))
383 return stat
->size
+ 2;
387 * deserialize_statb - wrapper for decoding a received metadata structure
388 * @v9ses: session info
389 * @bufp: buffer to deserialize
390 * @dbufp: buffer to deserialize variable strings into
394 static inline struct v9fs_stat
*deserialize_statb(struct v9fs_session_info
395 *v9ses
, struct cbuf
*bufp
,
398 struct v9fs_stat
*ret
= buf_alloc(dbufp
, sizeof(struct v9fs_stat
));
401 int n
= deserialize_stat(v9ses
, bufp
, ret
, dbufp
);
410 * v9fs_deserialize_stat - decode a received metadata structure
411 * @v9ses: session info
412 * @buf: buffer to deserialize
413 * @buflen: length of received buffer
414 * @stat: metadata structure to decode into
415 * @statlen: length of destination metadata structure
420 v9fs_deserialize_stat(struct v9fs_session_info
*v9ses
, void *buf
,
421 u32 buflen
, struct v9fs_stat
*stat
, u32 statlen
)
424 struct cbuf
*bufp
= &buffer
;
426 struct cbuf
*dbufp
= &dbuffer
;
428 buf_init(bufp
, buf
, buflen
);
429 buf_init(dbufp
, (char *)stat
+ sizeof(struct v9fs_stat
),
430 statlen
- sizeof(struct v9fs_stat
));
432 return deserialize_stat(v9ses
, bufp
, stat
, dbufp
);
436 v9fs_size_fcall(struct v9fs_session_info
*v9ses
, struct v9fs_fcall
*fcall
)
438 int size
= 4 + 1 + 2; /* size[4] msg[1] tag[2] */
443 eprintk(KERN_ERR
, "bad msg type %d\n", fcall
->id
);
445 case TVERSION
: /* msize[4] version[s] */
446 size
+= 4 + 2 + strlen(fcall
->params
.tversion
.version
);
448 case TAUTH
: /* afid[4] uname[s] aname[s] */
449 size
+= 4 + 2 + strlen(fcall
->params
.tauth
.uname
) +
450 2 + strlen(fcall
->params
.tauth
.aname
);
452 case TFLUSH
: /* oldtag[2] */
455 case TATTACH
: /* fid[4] afid[4] uname[s] aname[s] */
456 size
+= 4 + 4 + 2 + strlen(fcall
->params
.tattach
.uname
) +
457 2 + strlen(fcall
->params
.tattach
.aname
);
459 case TWALK
: /* fid[4] newfid[4] nwname[2] nwname*(wname[s]) */
461 /* now compute total for the array of names */
462 for (i
= 0; i
< fcall
->params
.twalk
.nwname
; i
++)
463 size
+= 2 + strlen(fcall
->params
.twalk
.wnames
[i
]);
465 case TOPEN
: /* fid[4] mode[1] */
468 case TCREATE
: /* fid[4] name[s] perm[4] mode[1] */
469 size
+= 4 + 2 + strlen(fcall
->params
.tcreate
.name
) + 4 + 1;
471 case TREAD
: /* fid[4] offset[8] count[4] */
474 case TWRITE
: /* fid[4] offset[8] count[4] data[count] */
475 size
+= 4 + 8 + 4 + fcall
->params
.twrite
.count
;
477 case TCLUNK
: /* fid[4] */
480 case TREMOVE
: /* fid[4] */
483 case TSTAT
: /* fid[4] */
486 case TWSTAT
: /* fid[4] stat[n] */
487 fcall
->params
.twstat
.stat
->size
=
488 v9fs_size_stat(v9ses
, fcall
->params
.twstat
.stat
);
489 size
+= 4 + 2 + 2 + fcall
->params
.twstat
.stat
->size
;
495 * v9fs_serialize_fcall - marshall fcall struct into a packet
496 * @v9ses: session information
497 * @fcall: structure to convert
498 * @data: buffer to serialize fcall into
499 * @datalen: length of buffer to serialize fcall into
504 v9fs_serialize_fcall(struct v9fs_session_info
*v9ses
, struct v9fs_fcall
*fcall
,
505 void *data
, u32 datalen
)
508 struct v9fs_stat
*stat
= NULL
;
510 struct cbuf
*bufp
= &buffer
;
512 buf_init(bufp
, data
, datalen
);
515 eprintk(KERN_ERR
, "no fcall\n");
519 fcall
->size
= v9fs_size_fcall(v9ses
, fcall
);
521 buf_put_int32(bufp
, fcall
->size
);
522 buf_put_int8(bufp
, fcall
->id
);
523 buf_put_int16(bufp
, fcall
->tag
);
525 dprintk(DEBUG_CONV
, "size %d id %d tag %d\n", fcall
->size
, fcall
->id
,
531 eprintk(KERN_ERR
, "bad msg type: %d\n", fcall
->id
);
534 buf_put_int32(bufp
, fcall
->params
.tversion
.msize
);
535 buf_put_string(bufp
, fcall
->params
.tversion
.version
);
538 buf_put_int32(bufp
, fcall
->params
.tauth
.afid
);
539 buf_put_string(bufp
, fcall
->params
.tauth
.uname
);
540 buf_put_string(bufp
, fcall
->params
.tauth
.aname
);
543 buf_put_int16(bufp
, fcall
->params
.tflush
.oldtag
);
546 buf_put_int32(bufp
, fcall
->params
.tattach
.fid
);
547 buf_put_int32(bufp
, fcall
->params
.tattach
.afid
);
548 buf_put_string(bufp
, fcall
->params
.tattach
.uname
);
549 buf_put_string(bufp
, fcall
->params
.tattach
.aname
);
552 buf_put_int32(bufp
, fcall
->params
.twalk
.fid
);
553 buf_put_int32(bufp
, fcall
->params
.twalk
.newfid
);
554 buf_put_int16(bufp
, fcall
->params
.twalk
.nwname
);
555 for (i
= 0; i
< fcall
->params
.twalk
.nwname
; i
++)
556 buf_put_string(bufp
, fcall
->params
.twalk
.wnames
[i
]);
559 buf_put_int32(bufp
, fcall
->params
.topen
.fid
);
560 buf_put_int8(bufp
, fcall
->params
.topen
.mode
);
563 buf_put_int32(bufp
, fcall
->params
.tcreate
.fid
);
564 buf_put_string(bufp
, fcall
->params
.tcreate
.name
);
565 buf_put_int32(bufp
, fcall
->params
.tcreate
.perm
);
566 buf_put_int8(bufp
, fcall
->params
.tcreate
.mode
);
569 buf_put_int32(bufp
, fcall
->params
.tread
.fid
);
570 buf_put_int64(bufp
, fcall
->params
.tread
.offset
);
571 buf_put_int32(bufp
, fcall
->params
.tread
.count
);
574 buf_put_int32(bufp
, fcall
->params
.twrite
.fid
);
575 buf_put_int64(bufp
, fcall
->params
.twrite
.offset
);
576 buf_put_int32(bufp
, fcall
->params
.twrite
.count
);
577 buf_put_data(bufp
, fcall
->params
.twrite
.data
,
578 fcall
->params
.twrite
.count
);
581 buf_put_int32(bufp
, fcall
->params
.tclunk
.fid
);
584 buf_put_int32(bufp
, fcall
->params
.tremove
.fid
);
587 buf_put_int32(bufp
, fcall
->params
.tstat
.fid
);
590 buf_put_int32(bufp
, fcall
->params
.twstat
.fid
);
591 stat
= fcall
->params
.twstat
.stat
;
593 buf_put_int16(bufp
, stat
->size
+ 2);
594 serialize_stat(v9ses
, stat
, bufp
);
598 if (buf_check_overflow(bufp
))
605 * deserialize_fcall - unmarshal a response
606 * @v9ses: session information
607 * @msgsize: size of rcall message
608 * @buf: recieved buffer
609 * @buflen: length of received buffer
610 * @rcall: fcall structure to populate
611 * @rcalllen: length of fcall structure to populate
616 v9fs_deserialize_fcall(struct v9fs_session_info
*v9ses
, u32 msgsize
,
617 void *buf
, u32 buflen
, struct v9fs_fcall
*rcall
,
622 struct cbuf
*bufp
= &buffer
;
624 struct cbuf
*dbufp
= &dbuffer
;
627 buf_init(bufp
, buf
, buflen
);
628 buf_init(dbufp
, (char *)rcall
+ sizeof(struct v9fs_fcall
),
629 rcalllen
- sizeof(struct v9fs_fcall
));
631 rcall
->size
= msgsize
;
632 rcall
->id
= buf_get_int8(bufp
);
633 rcall
->tag
= buf_get_int16(bufp
);
635 dprintk(DEBUG_CONV
, "size %d id %d tag %d\n", rcall
->size
, rcall
->id
,
639 eprintk(KERN_ERR
, "unknown message type: %d\n", rcall
->id
);
642 rcall
->params
.rversion
.msize
= buf_get_int32(bufp
);
643 rcall
->params
.rversion
.version
= buf_get_stringb(bufp
, dbufp
);
648 rcall
->params
.rattach
.qid
.type
= buf_get_int8(bufp
);
649 rcall
->params
.rattach
.qid
.version
= buf_get_int32(bufp
);
650 rcall
->params
.rattach
.qid
.path
= buf_get_int64(bufp
);
653 rcall
->params
.rwalk
.nwqid
= buf_get_int16(bufp
);
654 rcall
->params
.rwalk
.wqids
= buf_alloc(dbufp
,
655 rcall
->params
.rwalk
.nwqid
* sizeof(struct v9fs_qid
));
656 if (rcall
->params
.rwalk
.wqids
)
657 for (i
= 0; i
< rcall
->params
.rwalk
.nwqid
; i
++) {
658 rcall
->params
.rwalk
.wqids
[i
].type
=
660 rcall
->params
.rwalk
.wqids
[i
].version
=
662 rcall
->params
.rwalk
.wqids
[i
].path
=
667 rcall
->params
.ropen
.qid
.type
= buf_get_int8(bufp
);
668 rcall
->params
.ropen
.qid
.version
= buf_get_int32(bufp
);
669 rcall
->params
.ropen
.qid
.path
= buf_get_int64(bufp
);
670 rcall
->params
.ropen
.iounit
= buf_get_int32(bufp
);
673 rcall
->params
.rcreate
.qid
.type
= buf_get_int8(bufp
);
674 rcall
->params
.rcreate
.qid
.version
= buf_get_int32(bufp
);
675 rcall
->params
.rcreate
.qid
.path
= buf_get_int64(bufp
);
676 rcall
->params
.rcreate
.iounit
= buf_get_int32(bufp
);
679 rcall
->params
.rread
.count
= buf_get_int32(bufp
);
680 rcall
->params
.rread
.data
= buf_get_datab(bufp
, dbufp
,
681 rcall
->params
.rread
.count
);
684 rcall
->params
.rwrite
.count
= buf_get_int32(bufp
);
692 rcall
->params
.rstat
.stat
=
693 deserialize_statb(v9ses
, bufp
, dbufp
);
698 rcall
->params
.rerror
.error
= buf_get_stringb(bufp
, dbufp
);
700 rcall
->params
.rerror
.errno
= buf_get_int16(bufp
);
704 if (buf_check_overflow(bufp
) || buf_check_overflow(dbufp
))