aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/9p/9p.c359
-rw-r--r--fs/9p/9p.h341
-rw-r--r--fs/9p/conv.c693
-rw-r--r--fs/9p/conv.h36
4 files changed, 1429 insertions, 0 deletions
diff --git a/fs/9p/9p.c b/fs/9p/9p.c
new file mode 100644
index 000000000000..e847f504a47c
--- /dev/null
+++ b/fs/9p/9p.c
@@ -0,0 +1,359 @@
1/*
2 * linux/fs/9p/9p.c
3 *
4 * This file contains functions 9P2000 functions
5 *
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
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 "mux.h"
37
38/**
39 * v9fs_t_version - negotiate protocol parameters with sever
40 * @v9ses: 9P2000 session information
41 * @msize: requested max size packet
42 * @version: requested version.extension string
43 * @fcall: pointer to response fcall pointer
44 *
45 */
46
47int
48v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
49 char *version, struct v9fs_fcall **fcall)
50{
51 struct v9fs_fcall msg;
52
53 dprintk(DEBUG_9P, "msize: %d version: %s\n", msize, version);
54 msg.id = TVERSION;
55 msg.params.tversion.msize = msize;
56 msg.params.tversion.version = version;
57
58 return v9fs_mux_rpc(v9ses, &msg, fcall);
59}
60
61/**
62 * v9fs_t_attach - mount the server
63 * @v9ses: 9P2000 session information
64 * @uname: user name doing the attach
65 * @aname: remote name being attached to
66 * @fid: mount fid to attatch to root node
67 * @afid: authentication fid (in this case result key)
68 * @fcall: pointer to response fcall pointer
69 *
70 */
71
72int
73v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname,
74 u32 fid, u32 afid, struct v9fs_fcall **fcall)
75{
76 struct v9fs_fcall msg;
77
78 dprintk(DEBUG_9P, "uname '%s' aname '%s' fid %d afid %d\n", uname,
79 aname, fid, afid);
80 msg.id = TATTACH;
81 msg.params.tattach.fid = fid;
82 msg.params.tattach.afid = afid;
83 msg.params.tattach.uname = uname;
84 msg.params.tattach.aname = aname;
85
86 return v9fs_mux_rpc(v9ses, &msg, fcall);
87}
88
89/**
90 * v9fs_t_clunk - release a fid (finish a transaction)
91 * @v9ses: 9P2000 session information
92 * @fid: fid to release
93 * @fcall: pointer to response fcall pointer
94 *
95 */
96
97int
98v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid,
99 struct v9fs_fcall **fcall)
100{
101 struct v9fs_fcall msg;
102
103 dprintk(DEBUG_9P, "fid %d\n", fid);
104 msg.id = TCLUNK;
105 msg.params.tclunk.fid = fid;
106
107 return v9fs_mux_rpc(v9ses, &msg, fcall);
108}
109
110/**
111 * v9fs_v9fs_t_flush - flush a pending transaction
112 * @v9ses: 9P2000 session information
113 * @tag: tid to release
114 *
115 */
116
117int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 tag)
118{
119 struct v9fs_fcall msg;
120
121 dprintk(DEBUG_9P, "oldtag %d\n", tag);
122 msg.id = TFLUSH;
123 msg.params.tflush.oldtag = tag;
124 return v9fs_mux_rpc(v9ses, &msg, NULL);
125}
126
127/**
128 * v9fs_t_stat - read a file's meta-data
129 * @v9ses: 9P2000 session information
130 * @fid: fid pointing to file or directory to get info about
131 * @fcall: pointer to response fcall
132 *
133 */
134
135int
136v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **fcall)
137{
138 struct v9fs_fcall msg;
139
140 dprintk(DEBUG_9P, "fid %d\n", fid);
141 if (fcall)
142 *fcall = NULL;
143
144 msg.id = TSTAT;
145 msg.params.tstat.fid = fid;
146 return v9fs_mux_rpc(v9ses, &msg, fcall);
147}
148
149/**
150 * v9fs_t_wstat - write a file's meta-data
151 * @v9ses: 9P2000 session information
152 * @fid: fid pointing to file or directory to write info about
153 * @stat: metadata
154 * @fcall: pointer to response fcall
155 *
156 */
157
158int
159v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
160 struct v9fs_stat *stat, struct v9fs_fcall **fcall)
161{
162 struct v9fs_fcall msg;
163
164 dprintk(DEBUG_9P, "fid %d length %d\n", fid, (int)stat->length);
165 msg.id = TWSTAT;
166 msg.params.twstat.fid = fid;
167 msg.params.twstat.stat = stat;
168
169 return v9fs_mux_rpc(v9ses, &msg, fcall);
170}
171
172/**
173 * v9fs_t_walk - walk a fid to a new file or directory
174 * @v9ses: 9P2000 session information
175 * @fid: fid to walk
176 * @newfid: new fid (for clone operations)
177 * @name: path to walk fid to
178 * @fcall: pointer to response fcall
179 *
180 */
181
182/* TODO: support multiple walk */
183
184int
185v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
186 char *name, struct v9fs_fcall **fcall)
187{
188 struct v9fs_fcall msg;
189
190 dprintk(DEBUG_9P, "fid %d newfid %d wname '%s'\n", fid, newfid, name);
191 msg.id = TWALK;
192 msg.params.twalk.fid = fid;
193 msg.params.twalk.newfid = newfid;
194
195 if (name) {
196 msg.params.twalk.nwname = 1;
197 msg.params.twalk.wnames = &name;
198 } else {
199 msg.params.twalk.nwname = 0;
200 }
201
202 return v9fs_mux_rpc(v9ses, &msg, fcall);
203}
204
205/**
206 * v9fs_t_open - open a file
207 *
208 * @v9ses - 9P2000 session information
209 * @fid - fid to open
210 * @mode - mode to open file (R, RW, etc)
211 * @fcall - pointer to response fcall
212 *
213 */
214
215int
216v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode,
217 struct v9fs_fcall **fcall)
218{
219 struct v9fs_fcall msg;
220 long errorno = -1;
221
222 dprintk(DEBUG_9P, "fid %d mode %d\n", fid, mode);
223 msg.id = TOPEN;
224 msg.params.topen.fid = fid;
225 msg.params.topen.mode = mode;
226
227 errorno = v9fs_mux_rpc(v9ses, &msg, fcall);
228
229 return errorno;
230}
231
232/**
233 * v9fs_t_remove - remove a file or directory
234 * @v9ses: 9P2000 session information
235 * @fid: fid to remove
236 * @fcall: pointer to response fcall
237 *
238 */
239
240int
241v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid,
242 struct v9fs_fcall **fcall)
243{
244 struct v9fs_fcall msg;
245
246 dprintk(DEBUG_9P, "fid %d\n", fid);
247 msg.id = TREMOVE;
248 msg.params.tremove.fid = fid;
249 return v9fs_mux_rpc(v9ses, &msg, fcall);
250}
251
252/**
253 * v9fs_t_create - create a file or directory
254 * @v9ses: 9P2000 session information
255 * @fid: fid to create
256 * @name: name of the file or directory to create
257 * @perm: permissions to create with
258 * @mode: mode to open file (R, RW, etc)
259 * @fcall: pointer to response fcall
260 *
261 */
262
263int
264v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name,
265 u32 perm, u8 mode, struct v9fs_fcall **fcall)
266{
267 struct v9fs_fcall msg;
268
269 dprintk(DEBUG_9P, "fid %d name '%s' perm %x mode %d\n",
270 fid, name, perm, mode);
271
272 msg.id = TCREATE;
273 msg.params.tcreate.fid = fid;
274 msg.params.tcreate.name = name;
275 msg.params.tcreate.perm = perm;
276 msg.params.tcreate.mode = mode;
277
278 return v9fs_mux_rpc(v9ses, &msg, fcall);
279}
280
281/**
282 * v9fs_t_read - read data
283 * @v9ses: 9P2000 session information
284 * @fid: fid to read from
285 * @offset: offset to start read at
286 * @count: how many bytes to read
287 * @fcall: pointer to response fcall (with data)
288 *
289 */
290
291int
292v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
293 u32 count, struct v9fs_fcall **fcall)
294{
295 struct v9fs_fcall msg;
296 struct v9fs_fcall *rc = NULL;
297 long errorno = -1;
298
299 dprintk(DEBUG_9P, "fid %d offset 0x%lx count 0x%x\n", fid,
300 (long unsigned int)offset, count);
301 msg.id = TREAD;
302 msg.params.tread.fid = fid;
303 msg.params.tread.offset = offset;
304 msg.params.tread.count = count;
305 errorno = v9fs_mux_rpc(v9ses, &msg, &rc);
306
307 if (!errorno) {
308 errorno = rc->params.rread.count;
309 dump_data(rc->params.rread.data, rc->params.rread.count);
310 }
311
312 if (fcall)
313 *fcall = rc;
314 else
315 kfree(rc);
316
317 return errorno;
318}
319
320/**
321 * v9fs_t_write - write data
322 * @v9ses: 9P2000 session information
323 * @fid: fid to write to
324 * @offset: offset to start write at
325 * @count: how many bytes to write
326 * @fcall: pointer to response fcall
327 *
328 */
329
330int
331v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid,
332 u64 offset, u32 count, void *data, struct v9fs_fcall **fcall)
333{
334 struct v9fs_fcall msg;
335 struct v9fs_fcall *rc = NULL;
336 long errorno = -1;
337
338 dprintk(DEBUG_9P, "fid %d offset 0x%llx count 0x%x\n", fid,
339 (unsigned long long)offset, count);
340 dump_data(data, count);
341
342 msg.id = TWRITE;
343 msg.params.twrite.fid = fid;
344 msg.params.twrite.offset = offset;
345 msg.params.twrite.count = count;
346 msg.params.twrite.data = data;
347
348 errorno = v9fs_mux_rpc(v9ses, &msg, &rc);
349
350 if (!errorno)
351 errorno = rc->params.rwrite.count;
352
353 if (fcall)
354 *fcall = rc;
355 else
356 kfree(rc);
357
358 return errorno;
359}
diff --git a/fs/9p/9p.h b/fs/9p/9p.h
new file mode 100644
index 000000000000..f55424216be2
--- /dev/null
+++ b/fs/9p/9p.h
@@ -0,0 +1,341 @@
1/*
2 * linux/fs/9p/9p.h
3 *
4 * 9P protocol definitions.
5 *
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
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/* Message Types */
28enum {
29 TVERSION = 100,
30 RVERSION,
31 TAUTH = 102,
32 RAUTH,
33 TATTACH = 104,
34 RATTACH,
35 TERROR = 106,
36 RERROR,
37 TFLUSH = 108,
38 RFLUSH,
39 TWALK = 110,
40 RWALK,
41 TOPEN = 112,
42 ROPEN,
43 TCREATE = 114,
44 RCREATE,
45 TREAD = 116,
46 RREAD,
47 TWRITE = 118,
48 RWRITE,
49 TCLUNK = 120,
50 RCLUNK,
51 TREMOVE = 122,
52 RREMOVE,
53 TSTAT = 124,
54 RSTAT,
55 TWSTAT = 126,
56 RWSTAT,
57};
58
59/* modes */
60enum {
61 V9FS_OREAD = 0x00,
62 V9FS_OWRITE = 0x01,
63 V9FS_ORDWR = 0x02,
64 V9FS_OEXEC = 0x03,
65 V9FS_OEXCL = 0x04,
66 V9FS_OTRUNC = 0x10,
67 V9FS_OREXEC = 0x20,
68 V9FS_ORCLOSE = 0x40,
69 V9FS_OAPPEND = 0x80,
70};
71
72/* permissions */
73enum {
74 V9FS_DMDIR = 0x80000000,
75 V9FS_DMAPPEND = 0x40000000,
76 V9FS_DMEXCL = 0x20000000,
77 V9FS_DMMOUNT = 0x10000000,
78 V9FS_DMAUTH = 0x08000000,
79 V9FS_DMTMP = 0x04000000,
80 V9FS_DMSYMLINK = 0x02000000,
81 V9FS_DMLINK = 0x01000000,
82 /* 9P2000.u extensions */
83 V9FS_DMDEVICE = 0x00800000,
84 V9FS_DMNAMEDPIPE = 0x00200000,
85 V9FS_DMSOCKET = 0x00100000,
86 V9FS_DMSETUID = 0x00080000,
87 V9FS_DMSETGID = 0x00040000,
88};
89
90/* qid.types */
91enum {
92 V9FS_QTDIR = 0x80,
93 V9FS_QTAPPEND = 0x40,
94 V9FS_QTEXCL = 0x20,
95 V9FS_QTMOUNT = 0x10,
96 V9FS_QTAUTH = 0x08,
97 V9FS_QTTMP = 0x04,
98 V9FS_QTSYMLINK = 0x02,
99 V9FS_QTLINK = 0x01,
100 V9FS_QTFILE = 0x00,
101};
102
103/* ample room for Twrite/Rread header (iounit) */
104#define V9FS_IOHDRSZ 24
105
106/* qids are the unique ID for a file (like an inode */
107struct v9fs_qid {
108 u8 type;
109 u32 version;
110 u64 path;
111};
112
113/* Plan 9 file metadata (stat) structure */
114struct v9fs_stat {
115 u16 size;
116 u16 type;
117 u32 dev;
118 struct v9fs_qid qid;
119 u32 mode;
120 u32 atime;
121 u32 mtime;
122 u64 length;
123 char *name;
124 char *uid;
125 char *gid;
126 char *muid;
127 char *extension; /* 9p2000.u extensions */
128 u32 n_uid; /* 9p2000.u extensions */
129 u32 n_gid; /* 9p2000.u extensions */
130 u32 n_muid; /* 9p2000.u extensions */
131 char data[0];
132};
133
134/* Structures for Protocol Operations */
135
136struct Tversion {
137 u32 msize;
138 char *version;
139};
140
141struct Rversion {
142 u32 msize;
143 char *version;
144};
145
146struct Tauth {
147 u32 afid;
148 char *uname;
149 char *aname;
150};
151
152struct Rauth {
153 struct v9fs_qid qid;
154};
155
156struct Rerror {
157 char *error;
158 u32 errno; /* 9p2000.u extension */
159};
160
161struct Tflush {
162 u32 oldtag;
163};
164
165struct Rflush {
166};
167
168struct Tattach {
169 u32 fid;
170 u32 afid;
171 char *uname;
172 char *aname;
173};
174
175struct Rattach {
176 struct v9fs_qid qid;
177};
178
179struct Twalk {
180 u32 fid;
181 u32 newfid;
182 u32 nwname;
183 char **wnames;
184};
185
186struct Rwalk {
187 u32 nwqid;
188 struct v9fs_qid *wqids;
189};
190
191struct Topen {
192 u32 fid;
193 u8 mode;
194};
195
196struct Ropen {
197 struct v9fs_qid qid;
198 u32 iounit;
199};
200
201struct Tcreate {
202 u32 fid;
203 char *name;
204 u32 perm;
205 u8 mode;
206};
207
208struct Rcreate {
209 struct v9fs_qid qid;
210 u32 iounit;
211};
212
213struct Tread {
214 u32 fid;
215 u64 offset;
216 u32 count;
217};
218
219struct Rread {
220 u32 count;
221 u8 *data;
222};
223
224struct Twrite {
225 u32 fid;
226 u64 offset;
227 u32 count;
228 u8 *data;
229};
230
231struct Rwrite {
232 u32 count;
233};
234
235struct Tclunk {
236 u32 fid;
237};
238
239struct Rclunk {
240};
241
242struct Tremove {
243 u32 fid;
244};
245
246struct Rremove {
247};
248
249struct Tstat {
250 u32 fid;
251};
252
253struct Rstat {
254 struct v9fs_stat *stat;
255};
256
257struct Twstat {
258 u32 fid;
259 struct v9fs_stat *stat;
260};
261
262struct Rwstat {
263};
264
265/*
266 * fcall is the primary packet structure
267 *
268 */
269
270struct v9fs_fcall {
271 u32 size;
272 u8 id;
273 u16 tag;
274
275 union {
276 struct Tversion tversion;
277 struct Rversion rversion;
278 struct Tauth tauth;
279 struct Rauth rauth;
280 struct Rerror rerror;
281 struct Tflush tflush;
282 struct Rflush rflush;
283 struct Tattach tattach;
284 struct Rattach rattach;
285 struct Twalk twalk;
286 struct Rwalk rwalk;
287 struct Topen topen;
288 struct Ropen ropen;
289 struct Tcreate tcreate;
290 struct Rcreate rcreate;
291 struct Tread tread;
292 struct Rread rread;
293 struct Twrite twrite;
294 struct Rwrite rwrite;
295 struct Tclunk tclunk;
296 struct Rclunk rclunk;
297 struct Tremove tremove;
298 struct Rremove rremove;
299 struct Tstat tstat;
300 struct Rstat rstat;
301 struct Twstat twstat;
302 struct Rwstat rwstat;
303 } params;
304};
305
306#define FCALL_ERROR(fcall) (fcall ? fcall->params.rerror.error : "")
307
308int v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
309 char *version, struct v9fs_fcall **rcall);
310
311int v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname,
312 u32 fid, u32 afid, struct v9fs_fcall **rcall);
313
314int v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid,
315 struct v9fs_fcall **rcall);
316
317int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 oldtag);
318
319int v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid,
320 struct v9fs_fcall **rcall);
321
322int v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
323 struct v9fs_stat *stat, struct v9fs_fcall **rcall);
324
325int v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
326 char *name, struct v9fs_fcall **rcall);
327
328int v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode,
329 struct v9fs_fcall **rcall);
330
331int v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid,
332 struct v9fs_fcall **rcall);
333
334int v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name,
335 u32 perm, u8 mode, struct v9fs_fcall **rcall);
336
337int v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid,
338 u64 offset, u32 count, struct v9fs_fcall **rcall);
339
340int v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
341 u32 count, void *data, struct v9fs_fcall **rcall);
diff --git a/fs/9p/conv.c b/fs/9p/conv.c
new file mode 100644
index 000000000000..1554731bd653
--- /dev/null
+++ b/fs/9p/conv.c
@@ -0,0 +1,693 @@
1/*
2 * linux/fs/9p/conv.c
3 *
4 * 9P protocol conversion functions
5 *
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
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 */
41struct cbuf {
42 unsigned char *sp;
43 unsigned char *p;
44 unsigned char *ep;
45};
46
47static 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
53static inline int buf_check_overflow(struct cbuf *buf)
54{
55 return buf->p > buf->ep;
56}
57
58static 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
68static 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
79static 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
87static 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
95static 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
103static 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
111static 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
120static inline void buf_put_string(struct cbuf *buf, const char *s)
121{
122 buf_put_stringn(buf, s, strlen(s));
123}
124
125static 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
133static 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
145static 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
157static 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
169static 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
181static inline int
182buf_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
197static 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
210static 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
220static 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
245static 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
296static int
297serialize_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
338static inline int
339deserialize_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
379static 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
404int
405v9fs_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
420static inline int
421v9fs_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
488int
489v9fs_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
600int
601v9fs_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}
diff --git a/fs/9p/conv.h b/fs/9p/conv.h
new file mode 100644
index 000000000000..ee849613c61a
--- /dev/null
+++ b/fs/9p/conv.h
@@ -0,0 +1,36 @@
1/*
2 * linux/fs/9p/conv.h
3 *
4 * 9P protocol conversion definitions
5 *
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
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
27int v9fs_deserialize_stat(struct v9fs_session_info *, void *buf,
28 u32 buflen, struct v9fs_stat *stat, u32 statlen);
29int v9fs_serialize_fcall(struct v9fs_session_info *, struct v9fs_fcall *tcall,
30 void *buf, u32 buflen);
31int v9fs_deserialize_fcall(struct v9fs_session_info *, u32 msglen,
32 void *buf, u32 buflen, struct v9fs_fcall *rcall,
33 int rcalllen);
34
35/* this one is actually in error.c right now */
36int v9fs_errstr2errno(char *errstr);