Commit | Line | Data |
---|---|---|
b8cf945b | 1 | /* |
bd238fb4 | 2 | * net/9p/conv.c |
b8cf945b EVH |
3 | * |
4 | * 9P protocol conversion functions | |
5 | * | |
d06a8fb1 | 6 | * Copyright (C) 2004, 2005 by Latchesar Ionkov <lucho@ionkov.net> |
b8cf945b EVH |
7 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> |
8 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
42e8c509 EVH |
11 | * it under the terms of the GNU General Public License version 2 |
12 | * as published by the Free Software Foundation. | |
b8cf945b EVH |
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 | ||
b8cf945b EVH |
27 | #include <linux/module.h> |
28 | #include <linux/errno.h> | |
29 | #include <linux/fs.h> | |
914e2637 | 30 | #include <linux/sched.h> |
b8cf945b | 31 | #include <linux/idr.h> |
bd238fb4 LI |
32 | #include <linux/uaccess.h> |
33 | #include <net/9p/9p.h> | |
b8cf945b EVH |
34 | |
35 | /* | |
36 | * Buffer to help with string parsing | |
37 | */ | |
38 | struct cbuf { | |
39 | unsigned char *sp; | |
40 | unsigned char *p; | |
41 | unsigned char *ep; | |
42 | }; | |
43 | ||
44 | static inline void buf_init(struct cbuf *buf, void *data, int datalen) | |
45 | { | |
46 | buf->sp = buf->p = data; | |
47 | buf->ep = data + datalen; | |
48 | } | |
49 | ||
50 | static inline int buf_check_overflow(struct cbuf *buf) | |
51 | { | |
52 | return buf->p > buf->ep; | |
53 | } | |
54 | ||
858119e1 | 55 | static int buf_check_size(struct cbuf *buf, int len) |
b8cf945b | 56 | { |
1dac06b2 LI |
57 | if (buf->p + len > buf->ep) { |
58 | if (buf->p < buf->ep) { | |
bd238fb4 LI |
59 | P9_EPRINTK(KERN_ERR, |
60 | "buffer overflow: want %d has %d\n", len, | |
61 | (int)(buf->ep - buf->p)); | |
1dac06b2 LI |
62 | dump_stack(); |
63 | buf->p = buf->ep + 1; | |
64 | } | |
65 | ||
531b1094 | 66 | return 0; |
b8cf945b | 67 | } |
d06a8fb1 LI |
68 | |
69 | return 1; | |
b8cf945b EVH |
70 | } |
71 | ||
858119e1 | 72 | static void *buf_alloc(struct cbuf *buf, int len) |
b8cf945b EVH |
73 | { |
74 | void *ret = NULL; | |
75 | ||
d06a8fb1 LI |
76 | if (buf_check_size(buf, len)) { |
77 | ret = buf->p; | |
78 | buf->p += len; | |
79 | } | |
b8cf945b EVH |
80 | |
81 | return ret; | |
82 | } | |
83 | ||
858119e1 | 84 | static void buf_put_int8(struct cbuf *buf, u8 val) |
b8cf945b | 85 | { |
d06a8fb1 LI |
86 | if (buf_check_size(buf, 1)) { |
87 | buf->p[0] = val; | |
88 | buf->p++; | |
89 | } | |
b8cf945b EVH |
90 | } |
91 | ||
858119e1 | 92 | static void buf_put_int16(struct cbuf *buf, u16 val) |
b8cf945b | 93 | { |
d06a8fb1 LI |
94 | if (buf_check_size(buf, 2)) { |
95 | *(__le16 *) buf->p = cpu_to_le16(val); | |
96 | buf->p += 2; | |
97 | } | |
b8cf945b EVH |
98 | } |
99 | ||
858119e1 | 100 | static void buf_put_int32(struct cbuf *buf, u32 val) |
b8cf945b | 101 | { |
d06a8fb1 LI |
102 | if (buf_check_size(buf, 4)) { |
103 | *(__le32 *)buf->p = cpu_to_le32(val); | |
104 | buf->p += 4; | |
105 | } | |
b8cf945b EVH |
106 | } |
107 | ||
858119e1 | 108 | static void buf_put_int64(struct cbuf *buf, u64 val) |
b8cf945b | 109 | { |
d06a8fb1 LI |
110 | if (buf_check_size(buf, 8)) { |
111 | *(__le64 *)buf->p = cpu_to_le64(val); | |
112 | buf->p += 8; | |
113 | } | |
b8cf945b EVH |
114 | } |
115 | ||
05818a00 | 116 | static char *buf_put_stringn(struct cbuf *buf, const char *s, u16 slen) |
b8cf945b | 117 | { |
05818a00 LI |
118 | char *ret; |
119 | ||
120 | ret = NULL; | |
d06a8fb1 LI |
121 | if (buf_check_size(buf, slen + 2)) { |
122 | buf_put_int16(buf, slen); | |
05818a00 | 123 | ret = buf->p; |
d06a8fb1 LI |
124 | memcpy(buf->p, s, slen); |
125 | buf->p += slen; | |
126 | } | |
05818a00 LI |
127 | |
128 | return ret; | |
b8cf945b EVH |
129 | } |
130 | ||
131 | static inline void buf_put_string(struct cbuf *buf, const char *s) | |
132 | { | |
133 | buf_put_stringn(buf, s, strlen(s)); | |
134 | } | |
135 | ||
858119e1 | 136 | static u8 buf_get_int8(struct cbuf *buf) |
b8cf945b EVH |
137 | { |
138 | u8 ret = 0; | |
139 | ||
d06a8fb1 LI |
140 | if (buf_check_size(buf, 1)) { |
141 | ret = buf->p[0]; | |
142 | buf->p++; | |
143 | } | |
b8cf945b EVH |
144 | |
145 | return ret; | |
146 | } | |
147 | ||
858119e1 | 148 | static u16 buf_get_int16(struct cbuf *buf) |
b8cf945b EVH |
149 | { |
150 | u16 ret = 0; | |
151 | ||
d06a8fb1 LI |
152 | if (buf_check_size(buf, 2)) { |
153 | ret = le16_to_cpu(*(__le16 *)buf->p); | |
154 | buf->p += 2; | |
155 | } | |
b8cf945b EVH |
156 | |
157 | return ret; | |
158 | } | |
159 | ||
858119e1 | 160 | static u32 buf_get_int32(struct cbuf *buf) |
b8cf945b EVH |
161 | { |
162 | u32 ret = 0; | |
163 | ||
d06a8fb1 LI |
164 | if (buf_check_size(buf, 4)) { |
165 | ret = le32_to_cpu(*(__le32 *)buf->p); | |
166 | buf->p += 4; | |
167 | } | |
b8cf945b EVH |
168 | |
169 | return ret; | |
170 | } | |
171 | ||
858119e1 | 172 | static u64 buf_get_int64(struct cbuf *buf) |
b8cf945b EVH |
173 | { |
174 | u64 ret = 0; | |
175 | ||
d06a8fb1 LI |
176 | if (buf_check_size(buf, 8)) { |
177 | ret = le64_to_cpu(*(__le64 *)buf->p); | |
178 | buf->p += 8; | |
179 | } | |
b8cf945b EVH |
180 | |
181 | return ret; | |
182 | } | |
183 | ||
bd238fb4 | 184 | static void buf_get_str(struct cbuf *buf, struct p9_str *vstr) |
b8cf945b | 185 | { |
531b1094 LI |
186 | vstr->len = buf_get_int16(buf); |
187 | if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) { | |
188 | vstr->str = buf->p; | |
189 | buf->p += vstr->len; | |
190 | } else { | |
191 | vstr->len = 0; | |
192 | vstr->str = NULL; | |
d06a8fb1 | 193 | } |
b8cf945b EVH |
194 | } |
195 | ||
bd238fb4 | 196 | static void buf_get_qid(struct cbuf *bufp, struct p9_qid *qid) |
b8cf945b | 197 | { |
531b1094 LI |
198 | qid->type = buf_get_int8(bufp); |
199 | qid->version = buf_get_int32(bufp); | |
200 | qid->path = buf_get_int64(bufp); | |
b8cf945b EVH |
201 | } |
202 | ||
203 | /** | |
bd238fb4 | 204 | * p9_size_wstat - calculate the size of a variable length stat struct |
b8cf945b | 205 | * @stat: metadata (stat) structure |
bd238fb4 | 206 | * @dotu: non-zero if 9P2000.u |
b8cf945b EVH |
207 | * |
208 | */ | |
209 | ||
bd238fb4 | 210 | static int p9_size_wstat(struct p9_wstat *wstat, int dotu) |
b8cf945b EVH |
211 | { |
212 | int size = 0; | |
213 | ||
531b1094 | 214 | if (wstat == NULL) { |
bd238fb4 | 215 | P9_EPRINTK(KERN_ERR, "p9_size_stat: got a NULL stat pointer\n"); |
b8cf945b EVH |
216 | return 0; |
217 | } | |
218 | ||
219 | size = /* 2 + *//* size[2] */ | |
220 | 2 + /* type[2] */ | |
221 | 4 + /* dev[4] */ | |
222 | 1 + /* qid.type[1] */ | |
223 | 4 + /* qid.vers[4] */ | |
224 | 8 + /* qid.path[8] */ | |
225 | 4 + /* mode[4] */ | |
226 | 4 + /* atime[4] */ | |
227 | 4 + /* mtime[4] */ | |
228 | 8 + /* length[8] */ | |
229 | 8; /* minimum sum of string lengths */ | |
230 | ||
531b1094 LI |
231 | if (wstat->name) |
232 | size += strlen(wstat->name); | |
233 | if (wstat->uid) | |
234 | size += strlen(wstat->uid); | |
235 | if (wstat->gid) | |
236 | size += strlen(wstat->gid); | |
237 | if (wstat->muid) | |
238 | size += strlen(wstat->muid); | |
b8cf945b | 239 | |
bd238fb4 | 240 | if (dotu) { |
b8cf945b EVH |
241 | size += 4 + /* n_uid[4] */ |
242 | 4 + /* n_gid[4] */ | |
243 | 4 + /* n_muid[4] */ | |
244 | 2; /* string length of extension[4] */ | |
531b1094 LI |
245 | if (wstat->extension) |
246 | size += strlen(wstat->extension); | |
b8cf945b EVH |
247 | } |
248 | ||
249 | return size; | |
250 | } | |
251 | ||
252 | /** | |
531b1094 | 253 | * buf_get_stat - safely decode a recieved metadata (stat) structure |
b8cf945b EVH |
254 | * @bufp: buffer to deserialize |
255 | * @stat: metadata (stat) structure | |
bd238fb4 | 256 | * @dotu: non-zero if 9P2000.u |
b8cf945b EVH |
257 | * |
258 | */ | |
259 | ||
858119e1 | 260 | static void |
bd238fb4 | 261 | buf_get_stat(struct cbuf *bufp, struct p9_stat *stat, int dotu) |
b8cf945b | 262 | { |
b8cf945b EVH |
263 | stat->size = buf_get_int16(bufp); |
264 | stat->type = buf_get_int16(bufp); | |
265 | stat->dev = buf_get_int32(bufp); | |
266 | stat->qid.type = buf_get_int8(bufp); | |
267 | stat->qid.version = buf_get_int32(bufp); | |
268 | stat->qid.path = buf_get_int64(bufp); | |
269 | stat->mode = buf_get_int32(bufp); | |
270 | stat->atime = buf_get_int32(bufp); | |
271 | stat->mtime = buf_get_int32(bufp); | |
272 | stat->length = buf_get_int64(bufp); | |
531b1094 LI |
273 | buf_get_str(bufp, &stat->name); |
274 | buf_get_str(bufp, &stat->uid); | |
275 | buf_get_str(bufp, &stat->gid); | |
276 | buf_get_str(bufp, &stat->muid); | |
b8cf945b | 277 | |
bd238fb4 | 278 | if (dotu) { |
531b1094 | 279 | buf_get_str(bufp, &stat->extension); |
b8cf945b EVH |
280 | stat->n_uid = buf_get_int32(bufp); |
281 | stat->n_gid = buf_get_int32(bufp); | |
282 | stat->n_muid = buf_get_int32(bufp); | |
283 | } | |
b8cf945b EVH |
284 | } |
285 | ||
286 | /** | |
bd238fb4 | 287 | * p9_deserialize_stat - decode a received metadata structure |
b8cf945b EVH |
288 | * @buf: buffer to deserialize |
289 | * @buflen: length of received buffer | |
290 | * @stat: metadata structure to decode into | |
bd238fb4 | 291 | * @dotu: non-zero if 9P2000.u |
b8cf945b | 292 | * |
531b1094 | 293 | * Note: stat will point to the buf region. |
b8cf945b EVH |
294 | */ |
295 | ||
531b1094 | 296 | int |
bd238fb4 LI |
297 | p9_deserialize_stat(void *buf, u32 buflen, struct p9_stat *stat, |
298 | int dotu) | |
b8cf945b EVH |
299 | { |
300 | struct cbuf buffer; | |
301 | struct cbuf *bufp = &buffer; | |
531b1094 | 302 | unsigned char *p; |
b8cf945b EVH |
303 | |
304 | buf_init(bufp, buf, buflen); | |
531b1094 | 305 | p = bufp->p; |
bd238fb4 | 306 | buf_get_stat(bufp, stat, dotu); |
b8cf945b | 307 | |
531b1094 | 308 | if (buf_check_overflow(bufp)) |
b8cf945b | 309 | return 0; |
531b1094 LI |
310 | else |
311 | return bufp->p - p; | |
b8cf945b | 312 | } |
bd238fb4 | 313 | EXPORT_SYMBOL(p9_deserialize_stat); |
b8cf945b EVH |
314 | |
315 | /** | |
316 | * deserialize_fcall - unmarshal a response | |
b8cf945b EVH |
317 | * @buf: recieved buffer |
318 | * @buflen: length of received buffer | |
319 | * @rcall: fcall structure to populate | |
320 | * @rcalllen: length of fcall structure to populate | |
bd238fb4 | 321 | * @dotu: non-zero if 9P2000.u |
b8cf945b EVH |
322 | * |
323 | */ | |
324 | ||
325 | int | |
bd238fb4 LI |
326 | p9_deserialize_fcall(void *buf, u32 buflen, struct p9_fcall *rcall, |
327 | int dotu) | |
b8cf945b EVH |
328 | { |
329 | ||
330 | struct cbuf buffer; | |
331 | struct cbuf *bufp = &buffer; | |
b8cf945b EVH |
332 | int i = 0; |
333 | ||
334 | buf_init(bufp, buf, buflen); | |
b8cf945b | 335 | |
3cf6429a | 336 | rcall->size = buf_get_int32(bufp); |
b8cf945b EVH |
337 | rcall->id = buf_get_int8(bufp); |
338 | rcall->tag = buf_get_int16(bufp); | |
339 | ||
bd238fb4 LI |
340 | P9_DPRINTK(P9_DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, |
341 | rcall->id, rcall->tag); | |
531b1094 | 342 | |
b8cf945b EVH |
343 | switch (rcall->id) { |
344 | default: | |
bd238fb4 | 345 | P9_EPRINTK(KERN_ERR, "unknown message type: %d\n", rcall->id); |
b8cf945b | 346 | return -EPROTO; |
bd238fb4 | 347 | case P9_RVERSION: |
b8cf945b | 348 | rcall->params.rversion.msize = buf_get_int32(bufp); |
531b1094 | 349 | buf_get_str(bufp, &rcall->params.rversion.version); |
b8cf945b | 350 | break; |
bd238fb4 | 351 | case P9_RFLUSH: |
b8cf945b | 352 | break; |
bd238fb4 | 353 | case P9_RATTACH: |
b8cf945b EVH |
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); | |
357 | break; | |
bd238fb4 | 358 | case P9_RWALK: |
b8cf945b | 359 | rcall->params.rwalk.nwqid = buf_get_int16(bufp); |
bd238fb4 LI |
360 | if (rcall->params.rwalk.nwqid > P9_MAXWELEM) { |
361 | P9_EPRINTK(KERN_ERR, | |
362 | "Rwalk with more than %d qids: %d\n", | |
363 | P9_MAXWELEM, rcall->params.rwalk.nwqid); | |
3cf6429a LI |
364 | return -EPROTO; |
365 | } | |
366 | ||
531b1094 LI |
367 | for (i = 0; i < rcall->params.rwalk.nwqid; i++) |
368 | buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]); | |
b8cf945b | 369 | break; |
bd238fb4 | 370 | case P9_ROPEN: |
531b1094 | 371 | buf_get_qid(bufp, &rcall->params.ropen.qid); |
b8cf945b EVH |
372 | rcall->params.ropen.iounit = buf_get_int32(bufp); |
373 | break; | |
bd238fb4 | 374 | case P9_RCREATE: |
531b1094 | 375 | buf_get_qid(bufp, &rcall->params.rcreate.qid); |
b8cf945b EVH |
376 | rcall->params.rcreate.iounit = buf_get_int32(bufp); |
377 | break; | |
bd238fb4 | 378 | case P9_RREAD: |
b8cf945b | 379 | rcall->params.rread.count = buf_get_int32(bufp); |
531b1094 LI |
380 | rcall->params.rread.data = bufp->p; |
381 | buf_check_size(bufp, rcall->params.rread.count); | |
b8cf945b | 382 | break; |
bd238fb4 | 383 | case P9_RWRITE: |
b8cf945b EVH |
384 | rcall->params.rwrite.count = buf_get_int32(bufp); |
385 | break; | |
bd238fb4 | 386 | case P9_RCLUNK: |
b8cf945b | 387 | break; |
bd238fb4 | 388 | case P9_RREMOVE: |
b8cf945b | 389 | break; |
bd238fb4 | 390 | case P9_RSTAT: |
b8cf945b | 391 | buf_get_int16(bufp); |
bd238fb4 | 392 | buf_get_stat(bufp, &rcall->params.rstat.stat, dotu); |
b8cf945b | 393 | break; |
bd238fb4 | 394 | case P9_RWSTAT: |
b8cf945b | 395 | break; |
bd238fb4 | 396 | case P9_RERROR: |
531b1094 | 397 | buf_get_str(bufp, &rcall->params.rerror.error); |
bd238fb4 | 398 | if (dotu) |
b8cf945b EVH |
399 | rcall->params.rerror.errno = buf_get_int16(bufp); |
400 | break; | |
401 | } | |
402 | ||
531b1094 | 403 | if (buf_check_overflow(bufp)) { |
bd238fb4 | 404 | P9_DPRINTK(P9_DEBUG_ERROR, "buffer overflow\n"); |
b8cf945b | 405 | return -EIO; |
3cf6429a | 406 | } |
b8cf945b | 407 | |
531b1094 LI |
408 | return bufp->p - bufp->sp; |
409 | } | |
bd238fb4 | 410 | EXPORT_SYMBOL(p9_deserialize_fcall); |
531b1094 | 411 | |
bd238fb4 | 412 | static inline void p9_put_int8(struct cbuf *bufp, u8 val, u8 * p) |
531b1094 LI |
413 | { |
414 | *p = val; | |
415 | buf_put_int8(bufp, val); | |
416 | } | |
417 | ||
bd238fb4 | 418 | static inline void p9_put_int16(struct cbuf *bufp, u16 val, u16 * p) |
531b1094 LI |
419 | { |
420 | *p = val; | |
421 | buf_put_int16(bufp, val); | |
422 | } | |
423 | ||
bd238fb4 | 424 | static inline void p9_put_int32(struct cbuf *bufp, u32 val, u32 * p) |
531b1094 LI |
425 | { |
426 | *p = val; | |
427 | buf_put_int32(bufp, val); | |
428 | } | |
429 | ||
bd238fb4 | 430 | static inline void p9_put_int64(struct cbuf *bufp, u64 val, u64 * p) |
531b1094 LI |
431 | { |
432 | *p = val; | |
433 | buf_put_int64(bufp, val); | |
434 | } | |
435 | ||
858119e1 | 436 | static void |
bd238fb4 | 437 | p9_put_str(struct cbuf *bufp, char *data, struct p9_str *str) |
531b1094 | 438 | { |
05818a00 LI |
439 | int len; |
440 | char *s; | |
441 | ||
442 | if (data) | |
443 | len = strlen(data); | |
444 | else | |
445 | len = 0; | |
531b1094 | 446 | |
05818a00 LI |
447 | s = buf_put_stringn(bufp, data, len); |
448 | if (str) { | |
449 | str->len = len; | |
450 | str->str = s; | |
451 | } | |
531b1094 LI |
452 | } |
453 | ||
858119e1 | 454 | static int |
bd238fb4 LI |
455 | p9_put_data(struct cbuf *bufp, const char *data, int count, |
456 | unsigned char **pdata) | |
457 | { | |
458 | *pdata = buf_alloc(bufp, count); | |
459 | memmove(*pdata, data, count); | |
460 | return count; | |
461 | } | |
462 | ||
463 | static int | |
464 | p9_put_user_data(struct cbuf *bufp, const char __user *data, int count, | |
531b1094 LI |
465 | unsigned char **pdata) |
466 | { | |
467 | *pdata = buf_alloc(bufp, count); | |
468 | return copy_from_user(*pdata, data, count); | |
469 | } | |
470 | ||
471 | static void | |
bd238fb4 LI |
472 | p9_put_wstat(struct cbuf *bufp, struct p9_wstat *wstat, |
473 | struct p9_stat *stat, int statsz, int dotu) | |
531b1094 | 474 | { |
bd238fb4 LI |
475 | p9_put_int16(bufp, statsz, &stat->size); |
476 | p9_put_int16(bufp, wstat->type, &stat->type); | |
477 | p9_put_int32(bufp, wstat->dev, &stat->dev); | |
478 | p9_put_int8(bufp, wstat->qid.type, &stat->qid.type); | |
479 | p9_put_int32(bufp, wstat->qid.version, &stat->qid.version); | |
480 | p9_put_int64(bufp, wstat->qid.path, &stat->qid.path); | |
481 | p9_put_int32(bufp, wstat->mode, &stat->mode); | |
482 | p9_put_int32(bufp, wstat->atime, &stat->atime); | |
483 | p9_put_int32(bufp, wstat->mtime, &stat->mtime); | |
484 | p9_put_int64(bufp, wstat->length, &stat->length); | |
531b1094 | 485 | |
bd238fb4 LI |
486 | p9_put_str(bufp, wstat->name, &stat->name); |
487 | p9_put_str(bufp, wstat->uid, &stat->uid); | |
488 | p9_put_str(bufp, wstat->gid, &stat->gid); | |
489 | p9_put_str(bufp, wstat->muid, &stat->muid); | |
531b1094 | 490 | |
bd238fb4 LI |
491 | if (dotu) { |
492 | p9_put_str(bufp, wstat->extension, &stat->extension); | |
493 | p9_put_int32(bufp, wstat->n_uid, &stat->n_uid); | |
494 | p9_put_int32(bufp, wstat->n_gid, &stat->n_gid); | |
495 | p9_put_int32(bufp, wstat->n_muid, &stat->n_muid); | |
531b1094 LI |
496 | } |
497 | } | |
498 | ||
bd238fb4 LI |
499 | static struct p9_fcall * |
500 | p9_create_common(struct cbuf *bufp, u32 size, u8 id) | |
531b1094 | 501 | { |
bd238fb4 | 502 | struct p9_fcall *fc; |
531b1094 LI |
503 | |
504 | size += 4 + 1 + 2; /* size[4] id[1] tag[2] */ | |
bd238fb4 | 505 | fc = kmalloc(sizeof(struct p9_fcall) + size, GFP_KERNEL); |
531b1094 LI |
506 | if (!fc) |
507 | return ERR_PTR(-ENOMEM); | |
508 | ||
509 | fc->sdata = (char *)fc + sizeof(*fc); | |
510 | ||
511 | buf_init(bufp, (char *)fc->sdata, size); | |
bd238fb4 LI |
512 | p9_put_int32(bufp, size, &fc->size); |
513 | p9_put_int8(bufp, id, &fc->id); | |
514 | p9_put_int16(bufp, P9_NOTAG, &fc->tag); | |
531b1094 LI |
515 | |
516 | return fc; | |
517 | } | |
518 | ||
bd238fb4 | 519 | void p9_set_tag(struct p9_fcall *fc, u16 tag) |
531b1094 | 520 | { |
1dac06b2 | 521 | fc->tag = tag; |
531b1094 LI |
522 | *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag); |
523 | } | |
bd238fb4 | 524 | EXPORT_SYMBOL(p9_set_tag); |
531b1094 | 525 | |
bd238fb4 | 526 | struct p9_fcall *p9_create_tversion(u32 msize, char *version) |
531b1094 LI |
527 | { |
528 | int size; | |
bd238fb4 | 529 | struct p9_fcall *fc; |
531b1094 LI |
530 | struct cbuf buffer; |
531 | struct cbuf *bufp = &buffer; | |
532 | ||
533 | size = 4 + 2 + strlen(version); /* msize[4] version[s] */ | |
bd238fb4 | 534 | fc = p9_create_common(bufp, size, P9_TVERSION); |
531b1094 LI |
535 | if (IS_ERR(fc)) |
536 | goto error; | |
537 | ||
bd238fb4 LI |
538 | p9_put_int32(bufp, msize, &fc->params.tversion.msize); |
539 | p9_put_str(bufp, version, &fc->params.tversion.version); | |
531b1094 LI |
540 | |
541 | if (buf_check_overflow(bufp)) { | |
542 | kfree(fc); | |
543 | fc = ERR_PTR(-ENOMEM); | |
544 | } | |
bd238fb4 | 545 | error: |
531b1094 LI |
546 | return fc; |
547 | } | |
bd238fb4 | 548 | EXPORT_SYMBOL(p9_create_tversion); |
531b1094 | 549 | |
bd238fb4 | 550 | struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname) |
531b1094 LI |
551 | { |
552 | int size; | |
bd238fb4 | 553 | struct p9_fcall *fc; |
531b1094 LI |
554 | struct cbuf buffer; |
555 | struct cbuf *bufp = &buffer; | |
556 | ||
bd238fb4 LI |
557 | /* afid[4] uname[s] aname[s] */ |
558 | size = 4 + 2 + strlen(uname) + 2 + strlen(aname); | |
559 | fc = p9_create_common(bufp, size, P9_TAUTH); | |
531b1094 LI |
560 | if (IS_ERR(fc)) |
561 | goto error; | |
562 | ||
bd238fb4 LI |
563 | p9_put_int32(bufp, afid, &fc->params.tauth.afid); |
564 | p9_put_str(bufp, uname, &fc->params.tauth.uname); | |
565 | p9_put_str(bufp, aname, &fc->params.tauth.aname); | |
531b1094 LI |
566 | |
567 | if (buf_check_overflow(bufp)) { | |
568 | kfree(fc); | |
569 | fc = ERR_PTR(-ENOMEM); | |
570 | } | |
bd238fb4 | 571 | error: |
531b1094 LI |
572 | return fc; |
573 | } | |
bd238fb4 | 574 | EXPORT_SYMBOL(p9_create_tauth); |
531b1094 | 575 | |
bd238fb4 LI |
576 | struct p9_fcall * |
577 | p9_create_tattach(u32 fid, u32 afid, char *uname, char *aname) | |
531b1094 LI |
578 | { |
579 | int size; | |
bd238fb4 | 580 | struct p9_fcall *fc; |
531b1094 LI |
581 | struct cbuf buffer; |
582 | struct cbuf *bufp = &buffer; | |
583 | ||
bd238fb4 LI |
584 | /* fid[4] afid[4] uname[s] aname[s] */ |
585 | size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname); | |
586 | fc = p9_create_common(bufp, size, P9_TATTACH); | |
531b1094 LI |
587 | if (IS_ERR(fc)) |
588 | goto error; | |
589 | ||
bd238fb4 LI |
590 | p9_put_int32(bufp, fid, &fc->params.tattach.fid); |
591 | p9_put_int32(bufp, afid, &fc->params.tattach.afid); | |
592 | p9_put_str(bufp, uname, &fc->params.tattach.uname); | |
593 | p9_put_str(bufp, aname, &fc->params.tattach.aname); | |
531b1094 | 594 | |
bd238fb4 | 595 | error: |
531b1094 LI |
596 | return fc; |
597 | } | |
bd238fb4 | 598 | EXPORT_SYMBOL(p9_create_tattach); |
531b1094 | 599 | |
bd238fb4 | 600 | struct p9_fcall *p9_create_tflush(u16 oldtag) |
531b1094 LI |
601 | { |
602 | int size; | |
bd238fb4 | 603 | struct p9_fcall *fc; |
531b1094 LI |
604 | struct cbuf buffer; |
605 | struct cbuf *bufp = &buffer; | |
606 | ||
607 | size = 2; /* oldtag[2] */ | |
bd238fb4 | 608 | fc = p9_create_common(bufp, size, P9_TFLUSH); |
531b1094 LI |
609 | if (IS_ERR(fc)) |
610 | goto error; | |
611 | ||
bd238fb4 | 612 | p9_put_int16(bufp, oldtag, &fc->params.tflush.oldtag); |
531b1094 LI |
613 | |
614 | if (buf_check_overflow(bufp)) { | |
615 | kfree(fc); | |
616 | fc = ERR_PTR(-ENOMEM); | |
617 | } | |
bd238fb4 | 618 | error: |
531b1094 LI |
619 | return fc; |
620 | } | |
bd238fb4 | 621 | EXPORT_SYMBOL(p9_create_tflush); |
531b1094 | 622 | |
bd238fb4 | 623 | struct p9_fcall *p9_create_twalk(u32 fid, u32 newfid, u16 nwname, |
531b1094 LI |
624 | char **wnames) |
625 | { | |
626 | int i, size; | |
bd238fb4 | 627 | struct p9_fcall *fc; |
531b1094 LI |
628 | struct cbuf buffer; |
629 | struct cbuf *bufp = &buffer; | |
630 | ||
bd238fb4 LI |
631 | if (nwname > P9_MAXWELEM) { |
632 | P9_DPRINTK(P9_DEBUG_ERROR, "nwname > %d\n", P9_MAXWELEM); | |
531b1094 LI |
633 | return NULL; |
634 | } | |
635 | ||
636 | size = 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */ | |
637 | for (i = 0; i < nwname; i++) { | |
638 | size += 2 + strlen(wnames[i]); /* wname[s] */ | |
639 | } | |
640 | ||
bd238fb4 | 641 | fc = p9_create_common(bufp, size, P9_TWALK); |
531b1094 LI |
642 | if (IS_ERR(fc)) |
643 | goto error; | |
644 | ||
bd238fb4 LI |
645 | p9_put_int32(bufp, fid, &fc->params.twalk.fid); |
646 | p9_put_int32(bufp, newfid, &fc->params.twalk.newfid); | |
647 | p9_put_int16(bufp, nwname, &fc->params.twalk.nwname); | |
531b1094 | 648 | for (i = 0; i < nwname; i++) { |
bd238fb4 | 649 | p9_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]); |
531b1094 LI |
650 | } |
651 | ||
652 | if (buf_check_overflow(bufp)) { | |
653 | kfree(fc); | |
654 | fc = ERR_PTR(-ENOMEM); | |
655 | } | |
bd238fb4 | 656 | error: |
531b1094 LI |
657 | return fc; |
658 | } | |
bd238fb4 | 659 | EXPORT_SYMBOL(p9_create_twalk); |
531b1094 | 660 | |
bd238fb4 | 661 | struct p9_fcall *p9_create_topen(u32 fid, u8 mode) |
531b1094 LI |
662 | { |
663 | int size; | |
bd238fb4 | 664 | struct p9_fcall *fc; |
531b1094 LI |
665 | struct cbuf buffer; |
666 | struct cbuf *bufp = &buffer; | |
667 | ||
668 | size = 4 + 1; /* fid[4] mode[1] */ | |
bd238fb4 | 669 | fc = p9_create_common(bufp, size, P9_TOPEN); |
531b1094 LI |
670 | if (IS_ERR(fc)) |
671 | goto error; | |
672 | ||
bd238fb4 LI |
673 | p9_put_int32(bufp, fid, &fc->params.topen.fid); |
674 | p9_put_int8(bufp, mode, &fc->params.topen.mode); | |
531b1094 LI |
675 | |
676 | if (buf_check_overflow(bufp)) { | |
677 | kfree(fc); | |
678 | fc = ERR_PTR(-ENOMEM); | |
679 | } | |
bd238fb4 | 680 | error: |
531b1094 LI |
681 | return fc; |
682 | } | |
bd238fb4 | 683 | EXPORT_SYMBOL(p9_create_topen); |
531b1094 | 684 | |
bd238fb4 LI |
685 | struct p9_fcall *p9_create_tcreate(u32 fid, char *name, u32 perm, u8 mode, |
686 | char *extension, int dotu) | |
531b1094 LI |
687 | { |
688 | int size; | |
bd238fb4 | 689 | struct p9_fcall *fc; |
531b1094 LI |
690 | struct cbuf buffer; |
691 | struct cbuf *bufp = &buffer; | |
692 | ||
bd238fb4 LI |
693 | /* fid[4] name[s] perm[4] mode[1] */ |
694 | size = 4 + 2 + strlen(name) + 4 + 1; | |
695 | if (dotu) { | |
4c90c68a RR |
696 | size += 2 + /* extension[s] */ |
697 | (extension == NULL ? 0 : strlen(extension)); | |
698 | } | |
16cce6d2 | 699 | |
bd238fb4 | 700 | fc = p9_create_common(bufp, size, P9_TCREATE); |
531b1094 LI |
701 | if (IS_ERR(fc)) |
702 | goto error; | |
703 | ||
bd238fb4 LI |
704 | p9_put_int32(bufp, fid, &fc->params.tcreate.fid); |
705 | p9_put_str(bufp, name, &fc->params.tcreate.name); | |
706 | p9_put_int32(bufp, perm, &fc->params.tcreate.perm); | |
707 | p9_put_int8(bufp, mode, &fc->params.tcreate.mode); | |
708 | if (dotu) | |
709 | p9_put_str(bufp, extension, &fc->params.tcreate.extension); | |
531b1094 LI |
710 | |
711 | if (buf_check_overflow(bufp)) { | |
712 | kfree(fc); | |
713 | fc = ERR_PTR(-ENOMEM); | |
714 | } | |
bd238fb4 | 715 | error: |
531b1094 LI |
716 | return fc; |
717 | } | |
bd238fb4 | 718 | EXPORT_SYMBOL(p9_create_tcreate); |
531b1094 | 719 | |
bd238fb4 | 720 | struct p9_fcall *p9_create_tread(u32 fid, u64 offset, u32 count) |
531b1094 LI |
721 | { |
722 | int size; | |
bd238fb4 | 723 | struct p9_fcall *fc; |
531b1094 LI |
724 | struct cbuf buffer; |
725 | struct cbuf *bufp = &buffer; | |
726 | ||
727 | size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */ | |
bd238fb4 LI |
728 | fc = p9_create_common(bufp, size, P9_TREAD); |
729 | if (IS_ERR(fc)) | |
730 | goto error; | |
731 | ||
732 | p9_put_int32(bufp, fid, &fc->params.tread.fid); | |
733 | p9_put_int64(bufp, offset, &fc->params.tread.offset); | |
734 | p9_put_int32(bufp, count, &fc->params.tread.count); | |
735 | ||
736 | if (buf_check_overflow(bufp)) { | |
737 | kfree(fc); | |
738 | fc = ERR_PTR(-ENOMEM); | |
739 | } | |
740 | error: | |
741 | return fc; | |
742 | } | |
743 | EXPORT_SYMBOL(p9_create_tread); | |
744 | ||
745 | struct p9_fcall *p9_create_twrite(u32 fid, u64 offset, u32 count, | |
746 | const char *data) | |
747 | { | |
748 | int size, err; | |
749 | struct p9_fcall *fc; | |
750 | struct cbuf buffer; | |
751 | struct cbuf *bufp = &buffer; | |
752 | ||
753 | /* fid[4] offset[8] count[4] data[count] */ | |
754 | size = 4 + 8 + 4 + count; | |
755 | fc = p9_create_common(bufp, size, P9_TWRITE); | |
531b1094 LI |
756 | if (IS_ERR(fc)) |
757 | goto error; | |
758 | ||
bd238fb4 LI |
759 | p9_put_int32(bufp, fid, &fc->params.twrite.fid); |
760 | p9_put_int64(bufp, offset, &fc->params.twrite.offset); | |
761 | p9_put_int32(bufp, count, &fc->params.twrite.count); | |
762 | err = p9_put_data(bufp, data, count, &fc->params.twrite.data); | |
763 | if (err) { | |
764 | kfree(fc); | |
765 | fc = ERR_PTR(err); | |
bbe06f6b | 766 | goto error; |
bd238fb4 | 767 | } |
531b1094 LI |
768 | |
769 | if (buf_check_overflow(bufp)) { | |
770 | kfree(fc); | |
771 | fc = ERR_PTR(-ENOMEM); | |
772 | } | |
bd238fb4 | 773 | error: |
531b1094 LI |
774 | return fc; |
775 | } | |
bd238fb4 | 776 | EXPORT_SYMBOL(p9_create_twrite); |
531b1094 | 777 | |
bd238fb4 LI |
778 | struct p9_fcall *p9_create_twrite_u(u32 fid, u64 offset, u32 count, |
779 | const char __user *data) | |
531b1094 LI |
780 | { |
781 | int size, err; | |
bd238fb4 | 782 | struct p9_fcall *fc; |
531b1094 LI |
783 | struct cbuf buffer; |
784 | struct cbuf *bufp = &buffer; | |
785 | ||
bd238fb4 LI |
786 | /* fid[4] offset[8] count[4] data[count] */ |
787 | size = 4 + 8 + 4 + count; | |
788 | fc = p9_create_common(bufp, size, P9_TWRITE); | |
531b1094 LI |
789 | if (IS_ERR(fc)) |
790 | goto error; | |
791 | ||
bd238fb4 LI |
792 | p9_put_int32(bufp, fid, &fc->params.twrite.fid); |
793 | p9_put_int64(bufp, offset, &fc->params.twrite.offset); | |
794 | p9_put_int32(bufp, count, &fc->params.twrite.count); | |
795 | err = p9_put_user_data(bufp, data, count, &fc->params.twrite.data); | |
531b1094 LI |
796 | if (err) { |
797 | kfree(fc); | |
798 | fc = ERR_PTR(err); | |
02881d94 | 799 | goto error; |
531b1094 LI |
800 | } |
801 | ||
802 | if (buf_check_overflow(bufp)) { | |
803 | kfree(fc); | |
804 | fc = ERR_PTR(-ENOMEM); | |
805 | } | |
bd238fb4 | 806 | error: |
531b1094 LI |
807 | return fc; |
808 | } | |
bd238fb4 | 809 | EXPORT_SYMBOL(p9_create_twrite_u); |
531b1094 | 810 | |
bd238fb4 | 811 | struct p9_fcall *p9_create_tclunk(u32 fid) |
531b1094 LI |
812 | { |
813 | int size; | |
bd238fb4 | 814 | struct p9_fcall *fc; |
531b1094 LI |
815 | struct cbuf buffer; |
816 | struct cbuf *bufp = &buffer; | |
817 | ||
818 | size = 4; /* fid[4] */ | |
bd238fb4 | 819 | fc = p9_create_common(bufp, size, P9_TCLUNK); |
531b1094 LI |
820 | if (IS_ERR(fc)) |
821 | goto error; | |
822 | ||
bd238fb4 | 823 | p9_put_int32(bufp, fid, &fc->params.tclunk.fid); |
531b1094 LI |
824 | |
825 | if (buf_check_overflow(bufp)) { | |
826 | kfree(fc); | |
827 | fc = ERR_PTR(-ENOMEM); | |
828 | } | |
bd238fb4 | 829 | error: |
531b1094 LI |
830 | return fc; |
831 | } | |
bd238fb4 | 832 | EXPORT_SYMBOL(p9_create_tclunk); |
531b1094 | 833 | |
bd238fb4 | 834 | struct p9_fcall *p9_create_tremove(u32 fid) |
531b1094 LI |
835 | { |
836 | int size; | |
bd238fb4 | 837 | struct p9_fcall *fc; |
531b1094 LI |
838 | struct cbuf buffer; |
839 | struct cbuf *bufp = &buffer; | |
840 | ||
841 | size = 4; /* fid[4] */ | |
bd238fb4 | 842 | fc = p9_create_common(bufp, size, P9_TREMOVE); |
531b1094 LI |
843 | if (IS_ERR(fc)) |
844 | goto error; | |
845 | ||
bd238fb4 | 846 | p9_put_int32(bufp, fid, &fc->params.tremove.fid); |
531b1094 LI |
847 | |
848 | if (buf_check_overflow(bufp)) { | |
849 | kfree(fc); | |
850 | fc = ERR_PTR(-ENOMEM); | |
851 | } | |
bd238fb4 | 852 | error: |
531b1094 LI |
853 | return fc; |
854 | } | |
bd238fb4 | 855 | EXPORT_SYMBOL(p9_create_tremove); |
531b1094 | 856 | |
bd238fb4 | 857 | struct p9_fcall *p9_create_tstat(u32 fid) |
531b1094 LI |
858 | { |
859 | int size; | |
bd238fb4 | 860 | struct p9_fcall *fc; |
531b1094 LI |
861 | struct cbuf buffer; |
862 | struct cbuf *bufp = &buffer; | |
863 | ||
864 | size = 4; /* fid[4] */ | |
bd238fb4 | 865 | fc = p9_create_common(bufp, size, P9_TSTAT); |
531b1094 LI |
866 | if (IS_ERR(fc)) |
867 | goto error; | |
868 | ||
bd238fb4 | 869 | p9_put_int32(bufp, fid, &fc->params.tstat.fid); |
531b1094 LI |
870 | |
871 | if (buf_check_overflow(bufp)) { | |
872 | kfree(fc); | |
873 | fc = ERR_PTR(-ENOMEM); | |
874 | } | |
bd238fb4 | 875 | error: |
531b1094 LI |
876 | return fc; |
877 | } | |
bd238fb4 | 878 | EXPORT_SYMBOL(p9_create_tstat); |
531b1094 | 879 | |
bd238fb4 LI |
880 | struct p9_fcall *p9_create_twstat(u32 fid, struct p9_wstat *wstat, |
881 | int dotu) | |
531b1094 LI |
882 | { |
883 | int size, statsz; | |
bd238fb4 | 884 | struct p9_fcall *fc; |
531b1094 LI |
885 | struct cbuf buffer; |
886 | struct cbuf *bufp = &buffer; | |
887 | ||
bd238fb4 | 888 | statsz = p9_size_wstat(wstat, dotu); |
531b1094 | 889 | size = 4 + 2 + 2 + statsz; /* fid[4] stat[n] */ |
bd238fb4 | 890 | fc = p9_create_common(bufp, size, P9_TWSTAT); |
531b1094 LI |
891 | if (IS_ERR(fc)) |
892 | goto error; | |
893 | ||
bd238fb4 | 894 | p9_put_int32(bufp, fid, &fc->params.twstat.fid); |
531b1094 | 895 | buf_put_int16(bufp, statsz + 2); |
bd238fb4 | 896 | p9_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, dotu); |
531b1094 LI |
897 | |
898 | if (buf_check_overflow(bufp)) { | |
899 | kfree(fc); | |
900 | fc = ERR_PTR(-ENOMEM); | |
901 | } | |
bd238fb4 | 902 | error: |
531b1094 | 903 | return fc; |
b8cf945b | 904 | } |
bd238fb4 | 905 | EXPORT_SYMBOL(p9_create_twstat); |