diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/9p/Makefile | 1 | ||||
-rw-r--r-- | net/9p/conv.c | 1054 | ||||
-rw-r--r-- | net/9p/protocol.c | 13 |
3 files changed, 13 insertions, 1055 deletions
diff --git a/net/9p/Makefile b/net/9p/Makefile index c3302d88b808..1041b7bd12e2 100644 --- a/net/9p/Makefile +++ b/net/9p/Makefile | |||
@@ -4,7 +4,6 @@ obj-$(CONFIG_NET_9P_VIRTIO) += 9pnet_virtio.o | |||
4 | 9pnet-objs := \ | 4 | 9pnet-objs := \ |
5 | mod.o \ | 5 | mod.o \ |
6 | client.o \ | 6 | client.o \ |
7 | conv.o \ | ||
8 | error.o \ | 7 | error.o \ |
9 | util.o \ | 8 | util.o \ |
10 | protocol.o \ | 9 | protocol.o \ |
diff --git a/net/9p/conv.c b/net/9p/conv.c deleted file mode 100644 index 5ad3a3bd73b2..000000000000 --- a/net/9p/conv.c +++ /dev/null | |||
@@ -1,1054 +0,0 @@ | |||
1 | /* | ||
2 | * net/9p/conv.c | ||
3 | * | ||
4 | * 9P protocol conversion functions | ||
5 | * | ||
6 | * Copyright (C) 2004, 2005 by Latchesar Ionkov <lucho@ionkov.net> | ||
7 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> | ||
8 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 | ||
12 | * as published by the Free Software Foundation. | ||
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/module.h> | ||
28 | #include <linux/errno.h> | ||
29 | #include <linux/fs.h> | ||
30 | #include <linux/sched.h> | ||
31 | #include <linux/idr.h> | ||
32 | #include <linux/uaccess.h> | ||
33 | #include <net/9p/9p.h> | ||
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 | |||
55 | static int buf_check_size(struct cbuf *buf, int len) | ||
56 | { | ||
57 | if (buf->p + len > buf->ep) { | ||
58 | if (buf->p < buf->ep) { | ||
59 | P9_EPRINTK(KERN_ERR, | ||
60 | "buffer overflow: want %d has %d\n", len, | ||
61 | (int)(buf->ep - buf->p)); | ||
62 | dump_stack(); | ||
63 | buf->p = buf->ep + 1; | ||
64 | } | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | return 1; | ||
70 | } | ||
71 | |||
72 | static void *buf_alloc(struct cbuf *buf, int len) | ||
73 | { | ||
74 | void *ret = NULL; | ||
75 | |||
76 | if (buf_check_size(buf, len)) { | ||
77 | ret = buf->p; | ||
78 | buf->p += len; | ||
79 | } | ||
80 | |||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | static void buf_put_int8(struct cbuf *buf, u8 val) | ||
85 | { | ||
86 | if (buf_check_size(buf, 1)) { | ||
87 | buf->p[0] = val; | ||
88 | buf->p++; | ||
89 | } | ||
90 | } | ||
91 | |||
92 | static void buf_put_int16(struct cbuf *buf, u16 val) | ||
93 | { | ||
94 | if (buf_check_size(buf, 2)) { | ||
95 | *(__le16 *) buf->p = cpu_to_le16(val); | ||
96 | buf->p += 2; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | static void buf_put_int32(struct cbuf *buf, u32 val) | ||
101 | { | ||
102 | if (buf_check_size(buf, 4)) { | ||
103 | *(__le32 *)buf->p = cpu_to_le32(val); | ||
104 | buf->p += 4; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | static void buf_put_int64(struct cbuf *buf, u64 val) | ||
109 | { | ||
110 | if (buf_check_size(buf, 8)) { | ||
111 | *(__le64 *)buf->p = cpu_to_le64(val); | ||
112 | buf->p += 8; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | static char *buf_put_stringn(struct cbuf *buf, const char *s, u16 slen) | ||
117 | { | ||
118 | char *ret; | ||
119 | |||
120 | ret = NULL; | ||
121 | if (buf_check_size(buf, slen + 2)) { | ||
122 | buf_put_int16(buf, slen); | ||
123 | ret = buf->p; | ||
124 | memcpy(buf->p, s, slen); | ||
125 | buf->p += slen; | ||
126 | } | ||
127 | |||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | static u8 buf_get_int8(struct cbuf *buf) | ||
132 | { | ||
133 | u8 ret = 0; | ||
134 | |||
135 | if (buf_check_size(buf, 1)) { | ||
136 | ret = buf->p[0]; | ||
137 | buf->p++; | ||
138 | } | ||
139 | |||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | static u16 buf_get_int16(struct cbuf *buf) | ||
144 | { | ||
145 | u16 ret = 0; | ||
146 | |||
147 | if (buf_check_size(buf, 2)) { | ||
148 | ret = le16_to_cpu(*(__le16 *)buf->p); | ||
149 | buf->p += 2; | ||
150 | } | ||
151 | |||
152 | return ret; | ||
153 | } | ||
154 | |||
155 | static u32 buf_get_int32(struct cbuf *buf) | ||
156 | { | ||
157 | u32 ret = 0; | ||
158 | |||
159 | if (buf_check_size(buf, 4)) { | ||
160 | ret = le32_to_cpu(*(__le32 *)buf->p); | ||
161 | buf->p += 4; | ||
162 | } | ||
163 | |||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | static u64 buf_get_int64(struct cbuf *buf) | ||
168 | { | ||
169 | u64 ret = 0; | ||
170 | |||
171 | if (buf_check_size(buf, 8)) { | ||
172 | ret = le64_to_cpu(*(__le64 *)buf->p); | ||
173 | buf->p += 8; | ||
174 | } | ||
175 | |||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | static void buf_get_str(struct cbuf *buf, struct p9_str *vstr) | ||
180 | { | ||
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; | ||
188 | } | ||
189 | } | ||
190 | |||
191 | static void buf_get_qid(struct cbuf *bufp, struct p9_qid *qid) | ||
192 | { | ||
193 | qid->type = buf_get_int8(bufp); | ||
194 | qid->version = buf_get_int32(bufp); | ||
195 | qid->path = buf_get_int64(bufp); | ||
196 | } | ||
197 | |||
198 | /** | ||
199 | * p9_size_wstat - calculate the size of a variable length stat struct | ||
200 | * @wstat: metadata (stat) structure | ||
201 | * @dotu: non-zero if 9P2000.u | ||
202 | * | ||
203 | */ | ||
204 | |||
205 | static int p9_size_wstat(struct p9_wstat *wstat, int dotu) | ||
206 | { | ||
207 | int size = 0; | ||
208 | |||
209 | if (wstat == NULL) { | ||
210 | P9_EPRINTK(KERN_ERR, "p9_size_stat: got a NULL stat pointer\n"); | ||
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 | |||
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); | ||
234 | |||
235 | if (dotu) { | ||
236 | size += 4 + /* n_uid[4] */ | ||
237 | 4 + /* n_gid[4] */ | ||
238 | 4 + /* n_muid[4] */ | ||
239 | 2; /* string length of extension[4] */ | ||
240 | if (wstat->extension) | ||
241 | size += strlen(wstat->extension); | ||
242 | } | ||
243 | |||
244 | return size; | ||
245 | } | ||
246 | |||
247 | /** | ||
248 | * buf_get_stat - safely decode a recieved metadata (stat) structure | ||
249 | * @bufp: buffer to deserialize | ||
250 | * @stat: metadata (stat) structure | ||
251 | * @dotu: non-zero if 9P2000.u | ||
252 | * | ||
253 | */ | ||
254 | |||
255 | static void | ||
256 | buf_get_stat(struct cbuf *bufp, struct p9_stat *stat, int dotu) | ||
257 | { | ||
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); | ||
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); | ||
272 | |||
273 | if (dotu) { | ||
274 | buf_get_str(bufp, &stat->extension); | ||
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 | } | ||
279 | } | ||
280 | |||
281 | /** | ||
282 | * p9_deserialize_stat - decode a received metadata structure | ||
283 | * @buf: buffer to deserialize | ||
284 | * @buflen: length of received buffer | ||
285 | * @stat: metadata structure to decode into | ||
286 | * @dotu: non-zero if 9P2000.u | ||
287 | * | ||
288 | * Note: stat will point to the buf region. | ||
289 | */ | ||
290 | |||
291 | int | ||
292 | p9_deserialize_stat(void *buf, u32 buflen, struct p9_stat *stat, | ||
293 | int dotu) | ||
294 | { | ||
295 | struct cbuf buffer; | ||
296 | struct cbuf *bufp = &buffer; | ||
297 | unsigned char *p; | ||
298 | |||
299 | buf_init(bufp, buf, buflen); | ||
300 | p = bufp->p; | ||
301 | buf_get_stat(bufp, stat, dotu); | ||
302 | |||
303 | if (buf_check_overflow(bufp)) | ||
304 | return 0; | ||
305 | else | ||
306 | return bufp->p - p; | ||
307 | } | ||
308 | EXPORT_SYMBOL(p9_deserialize_stat); | ||
309 | |||
310 | /** | ||
311 | * deserialize_fcall - unmarshal a response | ||
312 | * @buf: recieved buffer | ||
313 | * @buflen: length of received buffer | ||
314 | * @rcall: fcall structure to populate | ||
315 | * @rcalllen: length of fcall structure to populate | ||
316 | * @dotu: non-zero if 9P2000.u | ||
317 | * | ||
318 | */ | ||
319 | |||
320 | int | ||
321 | p9_deserialize_fcall(void *buf, u32 buflen, struct p9_fcall *rcall, | ||
322 | int dotu) | ||
323 | { | ||
324 | |||
325 | struct cbuf buffer; | ||
326 | struct cbuf *bufp = &buffer; | ||
327 | int i = 0; | ||
328 | |||
329 | buf_init(bufp, buf, buflen); | ||
330 | |||
331 | rcall->size = buf_get_int32(bufp); | ||
332 | rcall->id = buf_get_int8(bufp); | ||
333 | rcall->tag = buf_get_int16(bufp); | ||
334 | |||
335 | P9_DPRINTK(P9_DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, | ||
336 | rcall->id, rcall->tag); | ||
337 | |||
338 | switch (rcall->id) { | ||
339 | default: | ||
340 | P9_EPRINTK(KERN_ERR, "unknown message type: %d\n", rcall->id); | ||
341 | return -EPROTO; | ||
342 | case P9_RVERSION: | ||
343 | rcall->params.rversion.msize = buf_get_int32(bufp); | ||
344 | buf_get_str(bufp, &rcall->params.rversion.version); | ||
345 | break; | ||
346 | case P9_RFLUSH: | ||
347 | break; | ||
348 | case P9_RATTACH: | ||
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; | ||
353 | case P9_RWALK: | ||
354 | rcall->params.rwalk.nwqid = buf_get_int16(bufp); | ||
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); | ||
359 | return -EPROTO; | ||
360 | } | ||
361 | |||
362 | for (i = 0; i < rcall->params.rwalk.nwqid; i++) | ||
363 | buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]); | ||
364 | break; | ||
365 | case P9_ROPEN: | ||
366 | buf_get_qid(bufp, &rcall->params.ropen.qid); | ||
367 | rcall->params.ropen.iounit = buf_get_int32(bufp); | ||
368 | break; | ||
369 | case P9_RCREATE: | ||
370 | buf_get_qid(bufp, &rcall->params.rcreate.qid); | ||
371 | rcall->params.rcreate.iounit = buf_get_int32(bufp); | ||
372 | break; | ||
373 | case P9_RREAD: | ||
374 | rcall->params.rread.count = buf_get_int32(bufp); | ||
375 | rcall->params.rread.data = bufp->p; | ||
376 | buf_check_size(bufp, rcall->params.rread.count); | ||
377 | break; | ||
378 | case P9_RWRITE: | ||
379 | rcall->params.rwrite.count = buf_get_int32(bufp); | ||
380 | break; | ||
381 | case P9_RCLUNK: | ||
382 | break; | ||
383 | case P9_RREMOVE: | ||
384 | break; | ||
385 | case P9_RSTAT: | ||
386 | buf_get_int16(bufp); | ||
387 | buf_get_stat(bufp, &rcall->params.rstat.stat, dotu); | ||
388 | break; | ||
389 | case P9_RWSTAT: | ||
390 | break; | ||
391 | case P9_RERROR: | ||
392 | buf_get_str(bufp, &rcall->params.rerror.error); | ||
393 | if (dotu) | ||
394 | rcall->params.rerror.errno = buf_get_int16(bufp); | ||
395 | break; | ||
396 | } | ||
397 | |||
398 | if (buf_check_overflow(bufp)) { | ||
399 | P9_DPRINTK(P9_DEBUG_ERROR, "buffer overflow\n"); | ||
400 | return -EIO; | ||
401 | } | ||
402 | |||
403 | return bufp->p - bufp->sp; | ||
404 | } | ||
405 | EXPORT_SYMBOL(p9_deserialize_fcall); | ||
406 | |||
407 | static inline void p9_put_int8(struct cbuf *bufp, u8 val, u8 * p) | ||
408 | { | ||
409 | *p = val; | ||
410 | buf_put_int8(bufp, val); | ||
411 | } | ||
412 | |||
413 | static inline void p9_put_int16(struct cbuf *bufp, u16 val, u16 * p) | ||
414 | { | ||
415 | *p = val; | ||
416 | buf_put_int16(bufp, val); | ||
417 | } | ||
418 | |||
419 | static inline void p9_put_int32(struct cbuf *bufp, u32 val, u32 * p) | ||
420 | { | ||
421 | *p = val; | ||
422 | buf_put_int32(bufp, val); | ||
423 | } | ||
424 | |||
425 | static inline void p9_put_int64(struct cbuf *bufp, u64 val, u64 * p) | ||
426 | { | ||
427 | *p = val; | ||
428 | buf_put_int64(bufp, val); | ||
429 | } | ||
430 | |||
431 | static void | ||
432 | p9_put_str(struct cbuf *bufp, char *data, struct p9_str *str) | ||
433 | { | ||
434 | int len; | ||
435 | char *s; | ||
436 | |||
437 | if (data) | ||
438 | len = strlen(data); | ||
439 | else | ||
440 | len = 0; | ||
441 | |||
442 | s = buf_put_stringn(bufp, data, len); | ||
443 | if (str) { | ||
444 | str->len = len; | ||
445 | str->str = s; | ||
446 | } | ||
447 | } | ||
448 | |||
449 | static int | ||
450 | p9_put_data(struct cbuf *bufp, const char *data, int count, | ||
451 | unsigned char **pdata) | ||
452 | { | ||
453 | *pdata = buf_alloc(bufp, count); | ||
454 | if (*pdata == NULL) | ||
455 | return -ENOMEM; | ||
456 | memmove(*pdata, data, count); | ||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | static int | ||
461 | p9_put_user_data(struct cbuf *bufp, const char __user *data, int count, | ||
462 | unsigned char **pdata) | ||
463 | { | ||
464 | *pdata = buf_alloc(bufp, count); | ||
465 | if (*pdata == NULL) | ||
466 | return -ENOMEM; | ||
467 | return copy_from_user(*pdata, data, count); | ||
468 | } | ||
469 | |||
470 | static void | ||
471 | p9_put_wstat(struct cbuf *bufp, struct p9_wstat *wstat, | ||
472 | struct p9_stat *stat, int statsz, int dotu) | ||
473 | { | ||
474 | p9_put_int16(bufp, statsz, &stat->size); | ||
475 | p9_put_int16(bufp, wstat->type, &stat->type); | ||
476 | p9_put_int32(bufp, wstat->dev, &stat->dev); | ||
477 | p9_put_int8(bufp, wstat->qid.type, &stat->qid.type); | ||
478 | p9_put_int32(bufp, wstat->qid.version, &stat->qid.version); | ||
479 | p9_put_int64(bufp, wstat->qid.path, &stat->qid.path); | ||
480 | p9_put_int32(bufp, wstat->mode, &stat->mode); | ||
481 | p9_put_int32(bufp, wstat->atime, &stat->atime); | ||
482 | p9_put_int32(bufp, wstat->mtime, &stat->mtime); | ||
483 | p9_put_int64(bufp, wstat->length, &stat->length); | ||
484 | |||
485 | p9_put_str(bufp, wstat->name, &stat->name); | ||
486 | p9_put_str(bufp, wstat->uid, &stat->uid); | ||
487 | p9_put_str(bufp, wstat->gid, &stat->gid); | ||
488 | p9_put_str(bufp, wstat->muid, &stat->muid); | ||
489 | |||
490 | if (dotu) { | ||
491 | p9_put_str(bufp, wstat->extension, &stat->extension); | ||
492 | p9_put_int32(bufp, wstat->n_uid, &stat->n_uid); | ||
493 | p9_put_int32(bufp, wstat->n_gid, &stat->n_gid); | ||
494 | p9_put_int32(bufp, wstat->n_muid, &stat->n_muid); | ||
495 | } | ||
496 | } | ||
497 | |||
498 | static struct p9_fcall * | ||
499 | p9_create_common(struct cbuf *bufp, u32 size, u8 id) | ||
500 | { | ||
501 | struct p9_fcall *fc; | ||
502 | |||
503 | size += 4 + 1 + 2; /* size[4] id[1] tag[2] */ | ||
504 | fc = kmalloc(sizeof(struct p9_fcall) + size, GFP_KERNEL); | ||
505 | if (!fc) | ||
506 | return ERR_PTR(-ENOMEM); | ||
507 | |||
508 | fc->sdata = (char *)fc + sizeof(*fc); | ||
509 | |||
510 | buf_init(bufp, (char *)fc->sdata, size); | ||
511 | p9_put_int32(bufp, size, &fc->size); | ||
512 | p9_put_int8(bufp, id, &fc->id); | ||
513 | p9_put_int16(bufp, P9_NOTAG, &fc->tag); | ||
514 | |||
515 | return fc; | ||
516 | } | ||
517 | |||
518 | /** | ||
519 | * p9_set_tag - set the tag field of an &p9_fcall structure | ||
520 | * @fc: fcall structure to set tag within | ||
521 | * @tag: tag id to set | ||
522 | */ | ||
523 | |||
524 | void p9_set_tag(struct p9_fcall *fc, u16 tag) | ||
525 | { | ||
526 | fc->tag = tag; | ||
527 | *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag); | ||
528 | } | ||
529 | EXPORT_SYMBOL(p9_set_tag); | ||
530 | |||
531 | /** | ||
532 | * p9_create_tversion - allocates and creates a T_VERSION request | ||
533 | * @msize: requested maximum data size | ||
534 | * @version: version string to negotiate | ||
535 | * | ||
536 | */ | ||
537 | struct p9_fcall *p9_create_tversion(u32 msize, char *version) | ||
538 | { | ||
539 | int size; | ||
540 | struct p9_fcall *fc; | ||
541 | struct cbuf buffer; | ||
542 | struct cbuf *bufp = &buffer; | ||
543 | |||
544 | size = 4 + 2 + strlen(version); /* msize[4] version[s] */ | ||
545 | fc = p9_create_common(bufp, size, P9_TVERSION); | ||
546 | if (IS_ERR(fc)) | ||
547 | goto error; | ||
548 | |||
549 | p9_put_int32(bufp, msize, &fc->params.tversion.msize); | ||
550 | p9_put_str(bufp, version, &fc->params.tversion.version); | ||
551 | |||
552 | if (buf_check_overflow(bufp)) { | ||
553 | kfree(fc); | ||
554 | fc = ERR_PTR(-ENOMEM); | ||
555 | } | ||
556 | error: | ||
557 | return fc; | ||
558 | } | ||
559 | EXPORT_SYMBOL(p9_create_tversion); | ||
560 | |||
561 | /** | ||
562 | * p9_create_tauth - allocates and creates a T_AUTH request | ||
563 | * @afid: handle to use for authentication protocol | ||
564 | * @uname: user name attempting to authenticate | ||
565 | * @aname: mount specifier for remote server | ||
566 | * @n_uname: numeric id for user attempting to authneticate | ||
567 | * @dotu: 9P2000.u extension flag | ||
568 | * | ||
569 | */ | ||
570 | |||
571 | struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname, | ||
572 | u32 n_uname, int dotu) | ||
573 | { | ||
574 | int size; | ||
575 | struct p9_fcall *fc; | ||
576 | struct cbuf buffer; | ||
577 | struct cbuf *bufp = &buffer; | ||
578 | |||
579 | /* afid[4] uname[s] aname[s] */ | ||
580 | size = 4 + 2 + 2; | ||
581 | if (uname) | ||
582 | size += strlen(uname); | ||
583 | |||
584 | if (aname) | ||
585 | size += strlen(aname); | ||
586 | |||
587 | if (dotu) | ||
588 | size += 4; /* n_uname */ | ||
589 | |||
590 | fc = p9_create_common(bufp, size, P9_TAUTH); | ||
591 | if (IS_ERR(fc)) | ||
592 | goto error; | ||
593 | |||
594 | p9_put_int32(bufp, afid, &fc->params.tauth.afid); | ||
595 | p9_put_str(bufp, uname, &fc->params.tauth.uname); | ||
596 | p9_put_str(bufp, aname, &fc->params.tauth.aname); | ||
597 | if (dotu) | ||
598 | p9_put_int32(bufp, n_uname, &fc->params.tauth.n_uname); | ||
599 | |||
600 | if (buf_check_overflow(bufp)) { | ||
601 | kfree(fc); | ||
602 | fc = ERR_PTR(-ENOMEM); | ||
603 | } | ||
604 | error: | ||
605 | return fc; | ||
606 | } | ||
607 | EXPORT_SYMBOL(p9_create_tauth); | ||
608 | |||
609 | /** | ||
610 | * p9_create_tattach - allocates and creates a T_ATTACH request | ||
611 | * @fid: handle to use for the new mount point | ||
612 | * @afid: handle to use for authentication protocol | ||
613 | * @uname: user name attempting to attach | ||
614 | * @aname: mount specifier for remote server | ||
615 | * @n_uname: numeric id for user attempting to attach | ||
616 | * @n_uname: numeric id for user attempting to attach | ||
617 | * @dotu: 9P2000.u extension flag | ||
618 | * | ||
619 | */ | ||
620 | |||
621 | struct p9_fcall * | ||
622 | p9_create_tattach(u32 fid, u32 afid, char *uname, char *aname, | ||
623 | u32 n_uname, int dotu) | ||
624 | { | ||
625 | int size; | ||
626 | struct p9_fcall *fc; | ||
627 | struct cbuf buffer; | ||
628 | struct cbuf *bufp = &buffer; | ||
629 | |||
630 | /* fid[4] afid[4] uname[s] aname[s] */ | ||
631 | size = 4 + 4 + 2 + 2; | ||
632 | if (uname) | ||
633 | size += strlen(uname); | ||
634 | |||
635 | if (aname) | ||
636 | size += strlen(aname); | ||
637 | |||
638 | if (dotu) | ||
639 | size += 4; /* n_uname */ | ||
640 | |||
641 | fc = p9_create_common(bufp, size, P9_TATTACH); | ||
642 | if (IS_ERR(fc)) | ||
643 | goto error; | ||
644 | |||
645 | p9_put_int32(bufp, fid, &fc->params.tattach.fid); | ||
646 | p9_put_int32(bufp, afid, &fc->params.tattach.afid); | ||
647 | p9_put_str(bufp, uname, &fc->params.tattach.uname); | ||
648 | p9_put_str(bufp, aname, &fc->params.tattach.aname); | ||
649 | if (dotu) | ||
650 | p9_put_int32(bufp, n_uname, &fc->params.tattach.n_uname); | ||
651 | |||
652 | error: | ||
653 | return fc; | ||
654 | } | ||
655 | EXPORT_SYMBOL(p9_create_tattach); | ||
656 | |||
657 | /** | ||
658 | * p9_create_tflush - allocates and creates a T_FLUSH request | ||
659 | * @oldtag: tag id for the transaction we are attempting to cancel | ||
660 | * | ||
661 | */ | ||
662 | |||
663 | struct p9_fcall *p9_create_tflush(u16 oldtag) | ||
664 | { | ||
665 | int size; | ||
666 | struct p9_fcall *fc; | ||
667 | struct cbuf buffer; | ||
668 | struct cbuf *bufp = &buffer; | ||
669 | |||
670 | size = 2; /* oldtag[2] */ | ||
671 | fc = p9_create_common(bufp, size, P9_TFLUSH); | ||
672 | if (IS_ERR(fc)) | ||
673 | goto error; | ||
674 | |||
675 | p9_put_int16(bufp, oldtag, &fc->params.tflush.oldtag); | ||
676 | |||
677 | if (buf_check_overflow(bufp)) { | ||
678 | kfree(fc); | ||
679 | fc = ERR_PTR(-ENOMEM); | ||
680 | } | ||
681 | error: | ||
682 | return fc; | ||
683 | } | ||
684 | EXPORT_SYMBOL(p9_create_tflush); | ||
685 | |||
686 | /** | ||
687 | * p9_create_twalk - allocates and creates a T_FLUSH request | ||
688 | * @fid: handle we are traversing from | ||
689 | * @newfid: a new handle for this transaction | ||
690 | * @nwname: number of path elements to traverse | ||
691 | * @wnames: array of path elements | ||
692 | * | ||
693 | */ | ||
694 | |||
695 | struct p9_fcall *p9_create_twalk(u32 fid, u32 newfid, u16 nwname, | ||
696 | char **wnames) | ||
697 | { | ||
698 | int i, size; | ||
699 | struct p9_fcall *fc; | ||
700 | struct cbuf buffer; | ||
701 | struct cbuf *bufp = &buffer; | ||
702 | |||
703 | if (nwname > P9_MAXWELEM) { | ||
704 | P9_DPRINTK(P9_DEBUG_ERROR, "nwname > %d\n", P9_MAXWELEM); | ||
705 | return NULL; | ||
706 | } | ||
707 | |||
708 | size = 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */ | ||
709 | for (i = 0; i < nwname; i++) { | ||
710 | size += 2 + strlen(wnames[i]); /* wname[s] */ | ||
711 | } | ||
712 | |||
713 | fc = p9_create_common(bufp, size, P9_TWALK); | ||
714 | if (IS_ERR(fc)) | ||
715 | goto error; | ||
716 | |||
717 | p9_put_int32(bufp, fid, &fc->params.twalk.fid); | ||
718 | p9_put_int32(bufp, newfid, &fc->params.twalk.newfid); | ||
719 | p9_put_int16(bufp, nwname, &fc->params.twalk.nwname); | ||
720 | for (i = 0; i < nwname; i++) { | ||
721 | p9_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]); | ||
722 | } | ||
723 | |||
724 | if (buf_check_overflow(bufp)) { | ||
725 | kfree(fc); | ||
726 | fc = ERR_PTR(-ENOMEM); | ||
727 | } | ||
728 | error: | ||
729 | return fc; | ||
730 | } | ||
731 | EXPORT_SYMBOL(p9_create_twalk); | ||
732 | |||
733 | /** | ||
734 | * p9_create_topen - allocates and creates a T_OPEN request | ||
735 | * @fid: handle we are trying to open | ||
736 | * @mode: what mode we are trying to open the file in | ||
737 | * | ||
738 | */ | ||
739 | |||
740 | struct p9_fcall *p9_create_topen(u32 fid, u8 mode) | ||
741 | { | ||
742 | int size; | ||
743 | struct p9_fcall *fc; | ||
744 | struct cbuf buffer; | ||
745 | struct cbuf *bufp = &buffer; | ||
746 | |||
747 | size = 4 + 1; /* fid[4] mode[1] */ | ||
748 | fc = p9_create_common(bufp, size, P9_TOPEN); | ||
749 | if (IS_ERR(fc)) | ||
750 | goto error; | ||
751 | |||
752 | p9_put_int32(bufp, fid, &fc->params.topen.fid); | ||
753 | p9_put_int8(bufp, mode, &fc->params.topen.mode); | ||
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_topen); | ||
763 | |||
764 | /** | ||
765 | * p9_create_tcreate - allocates and creates a T_CREATE request | ||
766 | * @fid: handle of directory we are trying to create in | ||
767 | * @name: name of the file we are trying to create | ||
768 | * @perm: permissions for the file we are trying to create | ||
769 | * @mode: what mode we are trying to open the file in | ||
770 | * @extension: 9p2000.u extension string (for special files) | ||
771 | * @dotu: 9p2000.u enabled flag | ||
772 | * | ||
773 | * Note: Plan 9 create semantics include opening the resulting file | ||
774 | * which is why mode is included. | ||
775 | */ | ||
776 | |||
777 | struct p9_fcall *p9_create_tcreate(u32 fid, char *name, u32 perm, u8 mode, | ||
778 | char *extension, int dotu) | ||
779 | { | ||
780 | int size; | ||
781 | struct p9_fcall *fc; | ||
782 | struct cbuf buffer; | ||
783 | struct cbuf *bufp = &buffer; | ||
784 | |||
785 | /* fid[4] name[s] perm[4] mode[1] */ | ||
786 | size = 4 + 2 + strlen(name) + 4 + 1; | ||
787 | if (dotu) { | ||
788 | size += 2 + /* extension[s] */ | ||
789 | (extension == NULL ? 0 : strlen(extension)); | ||
790 | } | ||
791 | |||
792 | fc = p9_create_common(bufp, size, P9_TCREATE); | ||
793 | if (IS_ERR(fc)) | ||
794 | goto error; | ||
795 | |||
796 | p9_put_int32(bufp, fid, &fc->params.tcreate.fid); | ||
797 | p9_put_str(bufp, name, &fc->params.tcreate.name); | ||
798 | p9_put_int32(bufp, perm, &fc->params.tcreate.perm); | ||
799 | p9_put_int8(bufp, mode, &fc->params.tcreate.mode); | ||
800 | if (dotu) | ||
801 | p9_put_str(bufp, extension, &fc->params.tcreate.extension); | ||
802 | |||
803 | if (buf_check_overflow(bufp)) { | ||
804 | kfree(fc); | ||
805 | fc = ERR_PTR(-ENOMEM); | ||
806 | } | ||
807 | error: | ||
808 | return fc; | ||
809 | } | ||
810 | EXPORT_SYMBOL(p9_create_tcreate); | ||
811 | |||
812 | /** | ||
813 | * p9_create_tread - allocates and creates a T_READ request | ||
814 | * @fid: handle of the file we are trying to read | ||
815 | * @offset: offset to start reading from | ||
816 | * @count: how many bytes to read | ||
817 | */ | ||
818 | |||
819 | struct p9_fcall *p9_create_tread(u32 fid, u64 offset, u32 count) | ||
820 | { | ||
821 | int size; | ||
822 | struct p9_fcall *fc; | ||
823 | struct cbuf buffer; | ||
824 | struct cbuf *bufp = &buffer; | ||
825 | |||
826 | size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */ | ||
827 | fc = p9_create_common(bufp, size, P9_TREAD); | ||
828 | if (IS_ERR(fc)) | ||
829 | goto error; | ||
830 | |||
831 | p9_put_int32(bufp, fid, &fc->params.tread.fid); | ||
832 | p9_put_int64(bufp, offset, &fc->params.tread.offset); | ||
833 | p9_put_int32(bufp, count, &fc->params.tread.count); | ||
834 | |||
835 | if (buf_check_overflow(bufp)) { | ||
836 | kfree(fc); | ||
837 | fc = ERR_PTR(-ENOMEM); | ||
838 | } | ||
839 | error: | ||
840 | return fc; | ||
841 | } | ||
842 | EXPORT_SYMBOL(p9_create_tread); | ||
843 | |||
844 | /** | ||
845 | * p9_create_twrite - allocates and creates a T_WRITE request from the kernel | ||
846 | * @fid: handle of the file we are trying to write | ||
847 | * @offset: offset to start writing at | ||
848 | * @count: how many bytes to write | ||
849 | * @data: data to write | ||
850 | * | ||
851 | * This function will create a requst with data buffers from the kernel | ||
852 | * such as the page cache. | ||
853 | */ | ||
854 | |||
855 | struct p9_fcall *p9_create_twrite(u32 fid, u64 offset, u32 count, | ||
856 | const char *data) | ||
857 | { | ||
858 | int size, err; | ||
859 | struct p9_fcall *fc; | ||
860 | struct cbuf buffer; | ||
861 | struct cbuf *bufp = &buffer; | ||
862 | |||
863 | /* fid[4] offset[8] count[4] data[count] */ | ||
864 | size = 4 + 8 + 4 + count; | ||
865 | fc = p9_create_common(bufp, size, P9_TWRITE); | ||
866 | if (IS_ERR(fc)) | ||
867 | goto error; | ||
868 | |||
869 | p9_put_int32(bufp, fid, &fc->params.twrite.fid); | ||
870 | p9_put_int64(bufp, offset, &fc->params.twrite.offset); | ||
871 | p9_put_int32(bufp, count, &fc->params.twrite.count); | ||
872 | err = p9_put_data(bufp, data, count, &fc->params.twrite.data); | ||
873 | if (err) { | ||
874 | kfree(fc); | ||
875 | fc = ERR_PTR(err); | ||
876 | goto error; | ||
877 | } | ||
878 | |||
879 | if (buf_check_overflow(bufp)) { | ||
880 | kfree(fc); | ||
881 | fc = ERR_PTR(-ENOMEM); | ||
882 | } | ||
883 | error: | ||
884 | return fc; | ||
885 | } | ||
886 | EXPORT_SYMBOL(p9_create_twrite); | ||
887 | |||
888 | /** | ||
889 | * p9_create_twrite_u - allocates and creates a T_WRITE request from userspace | ||
890 | * @fid: handle of the file we are trying to write | ||
891 | * @offset: offset to start writing at | ||
892 | * @count: how many bytes to write | ||
893 | * @data: data to write | ||
894 | * | ||
895 | * This function will create a request with data buffers from userspace | ||
896 | */ | ||
897 | |||
898 | struct p9_fcall *p9_create_twrite_u(u32 fid, u64 offset, u32 count, | ||
899 | const char __user *data) | ||
900 | { | ||
901 | int size, err; | ||
902 | struct p9_fcall *fc; | ||
903 | struct cbuf buffer; | ||
904 | struct cbuf *bufp = &buffer; | ||
905 | |||
906 | /* fid[4] offset[8] count[4] data[count] */ | ||
907 | size = 4 + 8 + 4 + count; | ||
908 | fc = p9_create_common(bufp, size, P9_TWRITE); | ||
909 | if (IS_ERR(fc)) | ||
910 | goto error; | ||
911 | |||
912 | p9_put_int32(bufp, fid, &fc->params.twrite.fid); | ||
913 | p9_put_int64(bufp, offset, &fc->params.twrite.offset); | ||
914 | p9_put_int32(bufp, count, &fc->params.twrite.count); | ||
915 | err = p9_put_user_data(bufp, data, count, &fc->params.twrite.data); | ||
916 | if (err) { | ||
917 | kfree(fc); | ||
918 | fc = ERR_PTR(err); | ||
919 | goto error; | ||
920 | } | ||
921 | |||
922 | if (buf_check_overflow(bufp)) { | ||
923 | kfree(fc); | ||
924 | fc = ERR_PTR(-ENOMEM); | ||
925 | } | ||
926 | error: | ||
927 | return fc; | ||
928 | } | ||
929 | EXPORT_SYMBOL(p9_create_twrite_u); | ||
930 | |||
931 | /** | ||
932 | * p9_create_tclunk - allocate a request to forget about a file handle | ||
933 | * @fid: handle of the file we closing or forgetting about | ||
934 | * | ||
935 | * clunk is used both to close open files and to discard transient handles | ||
936 | * which may be created during meta-data operations and hierarchy traversal. | ||
937 | */ | ||
938 | |||
939 | struct p9_fcall *p9_create_tclunk(u32 fid) | ||
940 | { | ||
941 | int size; | ||
942 | struct p9_fcall *fc; | ||
943 | struct cbuf buffer; | ||
944 | struct cbuf *bufp = &buffer; | ||
945 | |||
946 | size = 4; /* fid[4] */ | ||
947 | fc = p9_create_common(bufp, size, P9_TCLUNK); | ||
948 | if (IS_ERR(fc)) | ||
949 | goto error; | ||
950 | |||
951 | p9_put_int32(bufp, fid, &fc->params.tclunk.fid); | ||
952 | |||
953 | if (buf_check_overflow(bufp)) { | ||
954 | kfree(fc); | ||
955 | fc = ERR_PTR(-ENOMEM); | ||
956 | } | ||
957 | error: | ||
958 | return fc; | ||
959 | } | ||
960 | EXPORT_SYMBOL(p9_create_tclunk); | ||
961 | |||
962 | /** | ||
963 | * p9_create_tremove - allocate and create a request to remove a file | ||
964 | * @fid: handle of the file or directory we are removing | ||
965 | * | ||
966 | */ | ||
967 | |||
968 | struct p9_fcall *p9_create_tremove(u32 fid) | ||
969 | { | ||
970 | int size; | ||
971 | struct p9_fcall *fc; | ||
972 | struct cbuf buffer; | ||
973 | struct cbuf *bufp = &buffer; | ||
974 | |||
975 | size = 4; /* fid[4] */ | ||
976 | fc = p9_create_common(bufp, size, P9_TREMOVE); | ||
977 | if (IS_ERR(fc)) | ||
978 | goto error; | ||
979 | |||
980 | p9_put_int32(bufp, fid, &fc->params.tremove.fid); | ||
981 | |||
982 | if (buf_check_overflow(bufp)) { | ||
983 | kfree(fc); | ||
984 | fc = ERR_PTR(-ENOMEM); | ||
985 | } | ||
986 | error: | ||
987 | return fc; | ||
988 | } | ||
989 | EXPORT_SYMBOL(p9_create_tremove); | ||
990 | |||
991 | /** | ||
992 | * p9_create_tstat - allocate and populate a request for attributes | ||
993 | * @fid: handle of the file or directory we are trying to get the attributes of | ||
994 | * | ||
995 | */ | ||
996 | |||
997 | struct p9_fcall *p9_create_tstat(u32 fid) | ||
998 | { | ||
999 | int size; | ||
1000 | struct p9_fcall *fc; | ||
1001 | struct cbuf buffer; | ||
1002 | struct cbuf *bufp = &buffer; | ||
1003 | |||
1004 | size = 4; /* fid[4] */ | ||
1005 | fc = p9_create_common(bufp, size, P9_TSTAT); | ||
1006 | if (IS_ERR(fc)) | ||
1007 | goto error; | ||
1008 | |||
1009 | p9_put_int32(bufp, fid, &fc->params.tstat.fid); | ||
1010 | |||
1011 | if (buf_check_overflow(bufp)) { | ||
1012 | kfree(fc); | ||
1013 | fc = ERR_PTR(-ENOMEM); | ||
1014 | } | ||
1015 | error: | ||
1016 | return fc; | ||
1017 | } | ||
1018 | EXPORT_SYMBOL(p9_create_tstat); | ||
1019 | |||
1020 | /** | ||
1021 | * p9_create_tstat - allocate and populate a request to change attributes | ||
1022 | * @fid: handle of the file or directory we are trying to change | ||
1023 | * @wstat: &p9_stat structure with attributes we wish to set | ||
1024 | * @dotu: 9p2000.u enabled flag | ||
1025 | * | ||
1026 | */ | ||
1027 | |||
1028 | struct p9_fcall *p9_create_twstat(u32 fid, struct p9_wstat *wstat, | ||
1029 | int dotu) | ||
1030 | { | ||
1031 | int size, statsz; | ||
1032 | struct p9_fcall *fc; | ||
1033 | struct cbuf buffer; | ||
1034 | struct cbuf *bufp = &buffer; | ||
1035 | |||
1036 | statsz = p9_size_wstat(wstat, dotu); | ||
1037 | size = 4 + 2 + 2 + statsz; /* fid[4] stat[n] */ | ||
1038 | fc = p9_create_common(bufp, size, P9_TWSTAT); | ||
1039 | if (IS_ERR(fc)) | ||
1040 | goto error; | ||
1041 | |||
1042 | p9_put_int32(bufp, fid, &fc->params.twstat.fid); | ||
1043 | buf_put_int16(bufp, statsz + 2); | ||
1044 | p9_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, dotu); | ||
1045 | |||
1046 | if (buf_check_overflow(bufp)) { | ||
1047 | kfree(fc); | ||
1048 | fc = ERR_PTR(-ENOMEM); | ||
1049 | } | ||
1050 | error: | ||
1051 | return fc; | ||
1052 | } | ||
1053 | EXPORT_SYMBOL(p9_create_twstat); | ||
1054 | |||
diff --git a/net/9p/protocol.c b/net/9p/protocol.c index 4ebeffd21d3d..92cb60bb191b 100644 --- a/net/9p/protocol.c +++ b/net/9p/protocol.c | |||
@@ -509,6 +509,19 @@ p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...) | |||
509 | return ret; | 509 | return ret; |
510 | } | 510 | } |
511 | 511 | ||
512 | int p9stat_read(char *buf, int len, struct p9_wstat *st, int dotu) | ||
513 | { | ||
514 | struct p9_fcall fake_pdu; | ||
515 | |||
516 | fake_pdu.size = len; | ||
517 | fake_pdu.capacity = len; | ||
518 | fake_pdu.sdata = buf; | ||
519 | fake_pdu.offset = 0; | ||
520 | |||
521 | return p9pdu_readf(&fake_pdu, dotu, "S", st); | ||
522 | } | ||
523 | EXPORT_SYMBOL(p9stat_read); | ||
524 | |||
512 | int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type) | 525 | int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type) |
513 | { | 526 | { |
514 | return p9pdu_writef(pdu, 0, "dbw", 0, type, tag); | 527 | return p9pdu_writef(pdu, 0, "dbw", 0, type, tag); |