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