diff options
Diffstat (limited to 'net/9p/protocol.c')
-rw-r--r-- | net/9p/protocol.c | 85 |
1 files changed, 82 insertions, 3 deletions
diff --git a/net/9p/protocol.c b/net/9p/protocol.c index 43e98220e9a4..4ebeffd21d3d 100644 --- a/net/9p/protocol.c +++ b/net/9p/protocol.c | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/errno.h> | 29 | #include <linux/errno.h> |
30 | #include <linux/uaccess.h> | ||
30 | #include <net/9p/9p.h> | 31 | #include <net/9p/9p.h> |
31 | #include <net/9p/client.h> | 32 | #include <net/9p/client.h> |
32 | #include "protocol.h" | 33 | #include "protocol.h" |
@@ -51,6 +52,38 @@ | |||
51 | static int | 52 | static int |
52 | p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...); | 53 | p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...); |
53 | 54 | ||
55 | #define PACKET_DEBUG 0 | ||
56 | |||
57 | void | ||
58 | p9pdu_dump(int way, struct p9_fcall *pdu) | ||
59 | { | ||
60 | int i, n; | ||
61 | u8 *data = pdu->sdata; | ||
62 | int datalen = pdu->size; | ||
63 | char buf[255]; | ||
64 | int buflen = 255; | ||
65 | |||
66 | i = n = 0; | ||
67 | if (datalen > (buflen-16)) | ||
68 | datalen = buflen-16; | ||
69 | while (i < datalen) { | ||
70 | n += scnprintf(buf + n, buflen - n, "%02x ", data[i]); | ||
71 | if (i%4 == 3) | ||
72 | n += scnprintf(buf + n, buflen - n, " "); | ||
73 | if (i%32 == 31) | ||
74 | n += scnprintf(buf + n, buflen - n, "\n"); | ||
75 | |||
76 | i++; | ||
77 | } | ||
78 | n += scnprintf(buf + n, buflen - n, "\n"); | ||
79 | |||
80 | if (way) | ||
81 | printk(KERN_NOTICE "[[(%d)[ %s\n", datalen, buf); | ||
82 | else | ||
83 | printk(KERN_NOTICE "]](%d)] %s\n", datalen, buf); | ||
84 | } | ||
85 | EXPORT_SYMBOL(p9pdu_dump); | ||
86 | |||
54 | void p9stat_free(struct p9_wstat *stbuf) | 87 | void p9stat_free(struct p9_wstat *stbuf) |
55 | { | 88 | { |
56 | kfree(stbuf->name); | 89 | kfree(stbuf->name); |
@@ -77,6 +110,18 @@ static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size) | |||
77 | return size - len; | 110 | return size - len; |
78 | } | 111 | } |
79 | 112 | ||
113 | static size_t | ||
114 | pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size) | ||
115 | { | ||
116 | size_t len = MIN(pdu->capacity - pdu->size, size); | ||
117 | int err = copy_from_user(&pdu->sdata[pdu->size], udata, len); | ||
118 | if (err) | ||
119 | printk(KERN_WARNING "pdu_write_u returning: %d\n", err); | ||
120 | |||
121 | pdu->size += len; | ||
122 | return size - len; | ||
123 | } | ||
124 | |||
80 | /* | 125 | /* |
81 | b - int8_t | 126 | b - int8_t |
82 | w - int16_t | 127 | w - int16_t |
@@ -174,7 +219,6 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
174 | stbuf->extension = NULL; | 219 | stbuf->extension = NULL; |
175 | stbuf->n_uid = stbuf->n_gid = stbuf->n_muid = | 220 | stbuf->n_uid = stbuf->n_gid = stbuf->n_muid = |
176 | -1; | 221 | -1; |
177 | |||
178 | errcode = | 222 | errcode = |
179 | p9pdu_readf(pdu, optional, | 223 | p9pdu_readf(pdu, optional, |
180 | "wwdQdddqssss?sddd", | 224 | "wwdQdddqssss?sddd", |
@@ -332,7 +376,6 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
332 | case 's':{ | 376 | case 's':{ |
333 | const char *ptr = va_arg(ap, const char *); | 377 | const char *ptr = va_arg(ap, const char *); |
334 | int16_t len = 0; | 378 | int16_t len = 0; |
335 | |||
336 | if (ptr) | 379 | if (ptr) |
337 | len = MIN(strlen(ptr), USHORT_MAX); | 380 | len = MIN(strlen(ptr), USHORT_MAX); |
338 | 381 | ||
@@ -356,7 +399,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
356 | p9pdu_writef(pdu, optional, | 399 | p9pdu_writef(pdu, optional, |
357 | "wwdQdddqssss?sddd", | 400 | "wwdQdddqssss?sddd", |
358 | stbuf->size, stbuf->type, | 401 | stbuf->size, stbuf->type, |
359 | stbuf->dev, stbuf->qid, | 402 | stbuf->dev, &stbuf->qid, |
360 | stbuf->mode, stbuf->atime, | 403 | stbuf->mode, stbuf->atime, |
361 | stbuf->mtime, stbuf->length, | 404 | stbuf->mtime, stbuf->length, |
362 | stbuf->name, stbuf->uid, | 405 | stbuf->name, stbuf->uid, |
@@ -374,6 +417,16 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) | |||
374 | errcode = -EFAULT; | 417 | errcode = -EFAULT; |
375 | } | 418 | } |
376 | break; | 419 | break; |
420 | case 'U':{ | ||
421 | int32_t count = va_arg(ap, int32_t); | ||
422 | const char __user *udata = | ||
423 | va_arg(ap, const void *); | ||
424 | errcode = | ||
425 | p9pdu_writef(pdu, optional, "d", count); | ||
426 | if (!errcode && pdu_write_u(pdu, udata, count)) | ||
427 | errcode = -EFAULT; | ||
428 | } | ||
429 | break; | ||
377 | case 'T':{ | 430 | case 'T':{ |
378 | int16_t nwname = va_arg(ap, int); | 431 | int16_t nwname = va_arg(ap, int); |
379 | const char **wnames = va_arg(ap, const char **); | 432 | const char **wnames = va_arg(ap, const char **); |
@@ -455,3 +508,29 @@ p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...) | |||
455 | 508 | ||
456 | return ret; | 509 | return ret; |
457 | } | 510 | } |
511 | |||
512 | int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type) | ||
513 | { | ||
514 | return p9pdu_writef(pdu, 0, "dbw", 0, type, tag); | ||
515 | } | ||
516 | |||
517 | int p9pdu_finalize(struct p9_fcall *pdu) | ||
518 | { | ||
519 | int size = pdu->size; | ||
520 | int err; | ||
521 | |||
522 | pdu->size = 0; | ||
523 | err = p9pdu_writef(pdu, 0, "d", size); | ||
524 | pdu->size = size; | ||
525 | |||
526 | if (PACKET_DEBUG) | ||
527 | p9pdu_dump(0, pdu); | ||
528 | |||
529 | return err; | ||
530 | } | ||
531 | |||
532 | void p9pdu_reset(struct p9_fcall *pdu) | ||
533 | { | ||
534 | pdu->offset = 0; | ||
535 | pdu->size = 0; | ||
536 | } | ||