]> bbs.cooldavid.org Git - net-next-2.6.git/blame - net/9p/protocol.c
Merge branch 'drm-core-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[net-next-2.6.git] / net / 9p / protocol.c
CommitLineData
ace51c4d
EVH
1/*
2 * net/9p/protocol.c
3 *
4 * 9P Protocol Support Code
5 *
6 * Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com>
7 *
8 * Base on code from Anthony Liguori <aliguori@us.ibm.com>
9 * Copyright (C) 2008 by IBM, Corp.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2
13 * as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to:
22 * Free Software Foundation
23 * 51 Franklin Street, Fifth Floor
24 * Boston, MA 02111-1301 USA
25 *
26 */
27
28#include <linux/module.h>
29#include <linux/errno.h>
51a87c55 30#include <linux/uaccess.h>
5a0e3ad6 31#include <linux/slab.h>
e7f4b8f1 32#include <linux/sched.h>
beeebc92 33#include <linux/types.h>
ace51c4d
EVH
34#include <net/9p/9p.h>
35#include <net/9p/client.h>
36#include "protocol.h"
37
38#ifndef MIN
39#define MIN(a, b) (((a) < (b)) ? (a) : (b))
40#endif
41
42#ifndef MAX
43#define MAX(a, b) (((a) > (b)) ? (a) : (b))
44#endif
45
46#ifndef offset_of
47#define offset_of(type, memb) \
48 ((unsigned long)(&((type *)0)->memb))
49#endif
50#ifndef container_of
51#define container_of(obj, type, memb) \
52 ((type *)(((char *)obj) - offset_of(type, memb)))
53#endif
54
55static int
342fee1d 56p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
ace51c4d 57
0b15a3a5 58#ifdef CONFIG_NET_9P_DEBUG
51a87c55
EVH
59void
60p9pdu_dump(int way, struct p9_fcall *pdu)
61{
62 int i, n;
63 u8 *data = pdu->sdata;
64 int datalen = pdu->size;
65 char buf[255];
66 int buflen = 255;
67
68 i = n = 0;
69 if (datalen > (buflen-16))
70 datalen = buflen-16;
71 while (i < datalen) {
72 n += scnprintf(buf + n, buflen - n, "%02x ", data[i]);
73 if (i%4 == 3)
74 n += scnprintf(buf + n, buflen - n, " ");
75 if (i%32 == 31)
76 n += scnprintf(buf + n, buflen - n, "\n");
77
78 i++;
79 }
80 n += scnprintf(buf + n, buflen - n, "\n");
81
82 if (way)
e7f4b8f1 83 P9_DPRINTK(P9_DEBUG_PKT, "[[[(%d) %s\n", datalen, buf);
51a87c55 84 else
e7f4b8f1 85 P9_DPRINTK(P9_DEBUG_PKT, "]]](%d) %s\n", datalen, buf);
51a87c55 86}
0b15a3a5
EVH
87#else
88void
89p9pdu_dump(int way, struct p9_fcall *pdu)
90{
91}
92#endif
51a87c55
EVH
93EXPORT_SYMBOL(p9pdu_dump);
94
ace51c4d
EVH
95void p9stat_free(struct p9_wstat *stbuf)
96{
97 kfree(stbuf->name);
98 kfree(stbuf->uid);
99 kfree(stbuf->gid);
100 kfree(stbuf->muid);
101 kfree(stbuf->extension);
102}
103EXPORT_SYMBOL(p9stat_free);
104
105static size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
106{
107 size_t len = MIN(pdu->size - pdu->offset, size);
108 memcpy(data, &pdu->sdata[pdu->offset], len);
109 pdu->offset += len;
110 return size - len;
111}
112
113static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
114{
115 size_t len = MIN(pdu->capacity - pdu->size, size);
116 memcpy(&pdu->sdata[pdu->size], data, len);
117 pdu->size += len;
118 return size - len;
119}
120
51a87c55
EVH
121static size_t
122pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
123{
124 size_t len = MIN(pdu->capacity - pdu->size, size);
125 int err = copy_from_user(&pdu->sdata[pdu->size], udata, len);
126 if (err)
127 printk(KERN_WARNING "pdu_write_u returning: %d\n", err);
128
129 pdu->size += len;
130 return size - len;
131}
132
ace51c4d
EVH
133/*
134 b - int8_t
135 w - int16_t
136 d - int32_t
137 q - int64_t
138 s - string
139 S - stat
140 Q - qid
141 D - data blob (int32_t size followed by void *, results are not freed)
142 T - array of strings (int16_t count, followed by strings)
143 R - array of qids (int16_t count, followed by qids)
f0853122 144 A - stat for 9p2000.L (p9_stat_dotl)
ace51c4d
EVH
145 ? - if optional = 1, continue parsing
146*/
147
148static int
342fee1d
SK
149p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
150 va_list ap)
ace51c4d
EVH
151{
152 const char *ptr;
153 int errcode = 0;
154
155 for (ptr = fmt; *ptr; ptr++) {
156 switch (*ptr) {
157 case 'b':{
158 int8_t *val = va_arg(ap, int8_t *);
159 if (pdu_read(pdu, val, sizeof(*val))) {
160 errcode = -EFAULT;
161 break;
162 }
163 }
164 break;
165 case 'w':{
166 int16_t *val = va_arg(ap, int16_t *);
beeebc92
EVH
167 __le16 le_val;
168 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
ace51c4d
EVH
169 errcode = -EFAULT;
170 break;
171 }
beeebc92 172 *val = le16_to_cpu(le_val);
ace51c4d
EVH
173 }
174 break;
175 case 'd':{
176 int32_t *val = va_arg(ap, int32_t *);
beeebc92
EVH
177 __le32 le_val;
178 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
ace51c4d
EVH
179 errcode = -EFAULT;
180 break;
181 }
beeebc92 182 *val = le32_to_cpu(le_val);
ace51c4d
EVH
183 }
184 break;
185 case 'q':{
186 int64_t *val = va_arg(ap, int64_t *);
beeebc92
EVH
187 __le64 le_val;
188 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
ace51c4d
EVH
189 errcode = -EFAULT;
190 break;
191 }
beeebc92 192 *val = le64_to_cpu(le_val);
ace51c4d
EVH
193 }
194 break;
195 case 's':{
e45c5405 196 char **sptr = va_arg(ap, char **);
ace51c4d
EVH
197 int16_t len;
198 int size;
199
342fee1d
SK
200 errcode = p9pdu_readf(pdu, proto_version,
201 "w", &len);
ace51c4d
EVH
202 if (errcode)
203 break;
204
205 size = MAX(len, 0);
206
e45c5405
EVH
207 *sptr = kmalloc(size + 1, GFP_KERNEL);
208 if (*sptr == NULL) {
ace51c4d
EVH
209 errcode = -EFAULT;
210 break;
211 }
e45c5405 212 if (pdu_read(pdu, *sptr, size)) {
ace51c4d 213 errcode = -EFAULT;
e45c5405
EVH
214 kfree(*sptr);
215 *sptr = NULL;
ace51c4d 216 } else
e45c5405 217 (*sptr)[size] = 0;
ace51c4d
EVH
218 }
219 break;
220 case 'Q':{
221 struct p9_qid *qid =
222 va_arg(ap, struct p9_qid *);
223
342fee1d 224 errcode = p9pdu_readf(pdu, proto_version, "bdq",
ace51c4d
EVH
225 &qid->type, &qid->version,
226 &qid->path);
227 }
228 break;
229 case 'S':{
230 struct p9_wstat *stbuf =
231 va_arg(ap, struct p9_wstat *);
232
f0a0ac2e 233 memset(stbuf, 0, sizeof(struct p9_wstat));
ace51c4d 234 stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
f0a0ac2e 235 -1;
ace51c4d 236 errcode =
342fee1d 237 p9pdu_readf(pdu, proto_version,
ace51c4d
EVH
238 "wwdQdddqssss?sddd",
239 &stbuf->size, &stbuf->type,
240 &stbuf->dev, &stbuf->qid,
241 &stbuf->mode, &stbuf->atime,
242 &stbuf->mtime, &stbuf->length,
243 &stbuf->name, &stbuf->uid,
244 &stbuf->gid, &stbuf->muid,
245 &stbuf->extension,
246 &stbuf->n_uid, &stbuf->n_gid,
247 &stbuf->n_muid);
248 if (errcode)
249 p9stat_free(stbuf);
250 }
251 break;
252 case 'D':{
253 int32_t *count = va_arg(ap, int32_t *);
254 void **data = va_arg(ap, void **);
255
256 errcode =
342fee1d 257 p9pdu_readf(pdu, proto_version, "d", count);
ace51c4d
EVH
258 if (!errcode) {
259 *count =
260 MIN(*count,
261 pdu->size - pdu->offset);
262 *data = &pdu->sdata[pdu->offset];
263 }
264 }
265 break;
266 case 'T':{
267 int16_t *nwname = va_arg(ap, int16_t *);
268 char ***wnames = va_arg(ap, char ***);
269
342fee1d
SK
270 errcode = p9pdu_readf(pdu, proto_version,
271 "w", nwname);
ace51c4d
EVH
272 if (!errcode) {
273 *wnames =
274 kmalloc(sizeof(char *) * *nwname,
275 GFP_KERNEL);
276 if (!*wnames)
277 errcode = -ENOMEM;
278 }
279
280 if (!errcode) {
281 int i;
282
283 for (i = 0; i < *nwname; i++) {
284 errcode =
342fee1d
SK
285 p9pdu_readf(pdu,
286 proto_version,
ace51c4d
EVH
287 "s",
288 &(*wnames)[i]);
289 if (errcode)
290 break;
291 }
292 }
293
294 if (errcode) {
295 if (*wnames) {
296 int i;
297
298 for (i = 0; i < *nwname; i++)
299 kfree((*wnames)[i]);
300 }
301 kfree(*wnames);
302 *wnames = NULL;
303 }
304 }
305 break;
306 case 'R':{
307 int16_t *nwqid = va_arg(ap, int16_t *);
308 struct p9_qid **wqids =
309 va_arg(ap, struct p9_qid **);
310
311 *wqids = NULL;
312
313 errcode =
342fee1d 314 p9pdu_readf(pdu, proto_version, "w", nwqid);
ace51c4d
EVH
315 if (!errcode) {
316 *wqids =
317 kmalloc(*nwqid *
318 sizeof(struct p9_qid),
319 GFP_KERNEL);
320 if (*wqids == NULL)
321 errcode = -ENOMEM;
322 }
323
324 if (!errcode) {
325 int i;
326
327 for (i = 0; i < *nwqid; i++) {
328 errcode =
342fee1d
SK
329 p9pdu_readf(pdu,
330 proto_version,
ace51c4d
EVH
331 "Q",
332 &(*wqids)[i]);
333 if (errcode)
334 break;
335 }
336 }
337
338 if (errcode) {
339 kfree(*wqids);
340 *wqids = NULL;
341 }
342 }
343 break;
f0853122
SK
344 case 'A': {
345 struct p9_stat_dotl *stbuf =
346 va_arg(ap, struct p9_stat_dotl *);
347
348 memset(stbuf, 0, sizeof(struct p9_stat_dotl));
349 errcode =
350 p9pdu_readf(pdu, proto_version,
351 "qQdddqqqqqqqqqqqqqqq",
352 &stbuf->st_result_mask,
353 &stbuf->qid,
354 &stbuf->st_mode,
355 &stbuf->st_uid, &stbuf->st_gid,
356 &stbuf->st_nlink,
357 &stbuf->st_rdev, &stbuf->st_size,
358 &stbuf->st_blksize, &stbuf->st_blocks,
359 &stbuf->st_atime_sec,
360 &stbuf->st_atime_nsec,
361 &stbuf->st_mtime_sec,
362 &stbuf->st_mtime_nsec,
363 &stbuf->st_ctime_sec,
364 &stbuf->st_ctime_nsec,
365 &stbuf->st_btime_sec,
366 &stbuf->st_btime_nsec,
367 &stbuf->st_gen,
368 &stbuf->st_data_version);
369 }
370 break;
ace51c4d 371 case '?':
c56e4acf
SK
372 if ((proto_version != p9_proto_2000u) &&
373 (proto_version != p9_proto_2000L))
ace51c4d
EVH
374 return 0;
375 break;
376 default:
377 BUG();
378 break;
379 }
380
381 if (errcode)
382 break;
383 }
384
385 return errcode;
386}
387
388int
342fee1d
SK
389p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
390 va_list ap)
ace51c4d
EVH
391{
392 const char *ptr;
393 int errcode = 0;
394
395 for (ptr = fmt; *ptr; ptr++) {
396 switch (*ptr) {
397 case 'b':{
398 int8_t val = va_arg(ap, int);
399 if (pdu_write(pdu, &val, sizeof(val)))
400 errcode = -EFAULT;
401 }
402 break;
403 case 'w':{
beeebc92 404 __le16 val = cpu_to_le16(va_arg(ap, int));
ace51c4d
EVH
405 if (pdu_write(pdu, &val, sizeof(val)))
406 errcode = -EFAULT;
407 }
408 break;
409 case 'd':{
beeebc92 410 __le32 val = cpu_to_le32(va_arg(ap, int32_t));
ace51c4d
EVH
411 if (pdu_write(pdu, &val, sizeof(val)))
412 errcode = -EFAULT;
413 }
414 break;
415 case 'q':{
beeebc92 416 __le64 val = cpu_to_le64(va_arg(ap, int64_t));
ace51c4d
EVH
417 if (pdu_write(pdu, &val, sizeof(val)))
418 errcode = -EFAULT;
419 }
420 break;
421 case 's':{
e45c5405 422 const char *sptr = va_arg(ap, const char *);
ace51c4d 423 int16_t len = 0;
e45c5405 424 if (sptr)
4be929be 425 len = MIN(strlen(sptr), USHRT_MAX);
ace51c4d 426
342fee1d
SK
427 errcode = p9pdu_writef(pdu, proto_version,
428 "w", len);
e45c5405 429 if (!errcode && pdu_write(pdu, sptr, len))
ace51c4d
EVH
430 errcode = -EFAULT;
431 }
432 break;
433 case 'Q':{
434 const struct p9_qid *qid =
435 va_arg(ap, const struct p9_qid *);
436 errcode =
342fee1d 437 p9pdu_writef(pdu, proto_version, "bdq",
ace51c4d
EVH
438 qid->type, qid->version,
439 qid->path);
440 } break;
441 case 'S':{
442 const struct p9_wstat *stbuf =
443 va_arg(ap, const struct p9_wstat *);
444 errcode =
342fee1d 445 p9pdu_writef(pdu, proto_version,
ace51c4d
EVH
446 "wwdQdddqssss?sddd",
447 stbuf->size, stbuf->type,
51a87c55 448 stbuf->dev, &stbuf->qid,
ace51c4d
EVH
449 stbuf->mode, stbuf->atime,
450 stbuf->mtime, stbuf->length,
451 stbuf->name, stbuf->uid,
452 stbuf->gid, stbuf->muid,
453 stbuf->extension, stbuf->n_uid,
454 stbuf->n_gid, stbuf->n_muid);
455 } break;
456 case 'D':{
457 int32_t count = va_arg(ap, int32_t);
458 const void *data = va_arg(ap, const void *);
459
342fee1d
SK
460 errcode = p9pdu_writef(pdu, proto_version, "d",
461 count);
ace51c4d
EVH
462 if (!errcode && pdu_write(pdu, data, count))
463 errcode = -EFAULT;
464 }
465 break;
51a87c55
EVH
466 case 'U':{
467 int32_t count = va_arg(ap, int32_t);
468 const char __user *udata =
e45c5405 469 va_arg(ap, const void __user *);
342fee1d
SK
470 errcode = p9pdu_writef(pdu, proto_version, "d",
471 count);
51a87c55
EVH
472 if (!errcode && pdu_write_u(pdu, udata, count))
473 errcode = -EFAULT;
474 }
475 break;
ace51c4d
EVH
476 case 'T':{
477 int16_t nwname = va_arg(ap, int);
478 const char **wnames = va_arg(ap, const char **);
479
342fee1d
SK
480 errcode = p9pdu_writef(pdu, proto_version, "w",
481 nwname);
ace51c4d
EVH
482 if (!errcode) {
483 int i;
484
485 for (i = 0; i < nwname; i++) {
486 errcode =
342fee1d
SK
487 p9pdu_writef(pdu,
488 proto_version,
ace51c4d
EVH
489 "s",
490 wnames[i]);
491 if (errcode)
492 break;
493 }
494 }
495 }
496 break;
497 case 'R':{
498 int16_t nwqid = va_arg(ap, int);
499 struct p9_qid *wqids =
500 va_arg(ap, struct p9_qid *);
501
342fee1d
SK
502 errcode = p9pdu_writef(pdu, proto_version, "w",
503 nwqid);
ace51c4d
EVH
504 if (!errcode) {
505 int i;
506
507 for (i = 0; i < nwqid; i++) {
508 errcode =
342fee1d
SK
509 p9pdu_writef(pdu,
510 proto_version,
ace51c4d
EVH
511 "Q",
512 &wqids[i]);
513 if (errcode)
514 break;
515 }
516 }
517 }
518 break;
87d7845a
SK
519 case 'I':{
520 struct p9_iattr_dotl *p9attr = va_arg(ap,
521 struct p9_iattr_dotl *);
522
523 errcode = p9pdu_writef(pdu, proto_version,
524 "ddddqqqqq",
525 p9attr->valid,
526 p9attr->mode,
527 p9attr->uid,
528 p9attr->gid,
529 p9attr->size,
530 p9attr->atime_sec,
531 p9attr->atime_nsec,
532 p9attr->mtime_sec,
533 p9attr->mtime_nsec);
534 }
535 break;
ace51c4d 536 case '?':
c56e4acf
SK
537 if ((proto_version != p9_proto_2000u) &&
538 (proto_version != p9_proto_2000L))
ace51c4d
EVH
539 return 0;
540 break;
541 default:
542 BUG();
543 break;
544 }
545
546 if (errcode)
547 break;
548 }
549
550 return errcode;
551}
552
342fee1d 553int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
ace51c4d
EVH
554{
555 va_list ap;
556 int ret;
557
558 va_start(ap, fmt);
342fee1d 559 ret = p9pdu_vreadf(pdu, proto_version, fmt, ap);
ace51c4d
EVH
560 va_end(ap);
561
562 return ret;
563}
564
565static int
342fee1d 566p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
ace51c4d
EVH
567{
568 va_list ap;
569 int ret;
570
571 va_start(ap, fmt);
342fee1d 572 ret = p9pdu_vwritef(pdu, proto_version, fmt, ap);
ace51c4d
EVH
573 va_end(ap);
574
575 return ret;
576}
51a87c55 577
342fee1d 578int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version)
02da398b
EVH
579{
580 struct p9_fcall fake_pdu;
e7f4b8f1 581 int ret;
02da398b
EVH
582
583 fake_pdu.size = len;
584 fake_pdu.capacity = len;
585 fake_pdu.sdata = buf;
586 fake_pdu.offset = 0;
587
342fee1d 588 ret = p9pdu_readf(&fake_pdu, proto_version, "S", st);
e7f4b8f1
EVH
589 if (ret) {
590 P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
591 p9pdu_dump(1, &fake_pdu);
592 }
593
594 return ret;
02da398b
EVH
595}
596EXPORT_SYMBOL(p9stat_read);
597
51a87c55
EVH
598int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
599{
600 return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
601}
602
603int p9pdu_finalize(struct p9_fcall *pdu)
604{
605 int size = pdu->size;
606 int err;
607
608 pdu->size = 0;
609 err = p9pdu_writef(pdu, 0, "d", size);
610 pdu->size = size;
611
0b15a3a5 612#ifdef CONFIG_NET_9P_DEBUG
e7f4b8f1 613 if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT)
51a87c55 614 p9pdu_dump(0, pdu);
0b15a3a5 615#endif
51a87c55 616
e7f4b8f1
EVH
617 P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size,
618 pdu->id, pdu->tag);
619
51a87c55
EVH
620 return err;
621}
622
623void p9pdu_reset(struct p9_fcall *pdu)
624{
625 pdu->offset = 0;
626 pdu->size = 0;
627}
7751bdb3
SK
628
629int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
630 int proto_version)
631{
632 struct p9_fcall fake_pdu;
633 int ret;
634 char *nameptr;
635
636 fake_pdu.size = len;
637 fake_pdu.capacity = len;
638 fake_pdu.sdata = buf;
639 fake_pdu.offset = 0;
640
641 ret = p9pdu_readf(&fake_pdu, proto_version, "Qqbs", &dirent->qid,
642 &dirent->d_off, &dirent->d_type, &nameptr);
643 if (ret) {
644 P9_DPRINTK(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
645 p9pdu_dump(1, &fake_pdu);
646 goto out;
647 }
648
649 strcpy(dirent->d_name, nameptr);
650
651out:
652 return fake_pdu.offset;
653}
654EXPORT_SYMBOL(p9dirent_read);