Merge remote-tracking branch 'sysctl/master'
[linux-2.6/next.git] / net / 9p / protocol.c
blobb7d4e8aa5383e7e2022cdcdd92205d0b634fe06e
1 /*
2 * net/9p/protocol.c
4 * 9P Protocol Support Code
6 * Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com>
8 * Base on code from Anthony Liguori <aliguori@us.ibm.com>
9 * Copyright (C) 2008 by IBM, Corp.
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.
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.
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
28 #include <linux/module.h>
29 #include <linux/errno.h>
30 #include <linux/kernel.h>
31 #include <linux/uaccess.h>
32 #include <linux/slab.h>
33 #include <linux/sched.h>
34 #include <linux/stddef.h>
35 #include <linux/types.h>
36 #include <net/9p/9p.h>
37 #include <net/9p/client.h>
38 #include "protocol.h"
40 static int
41 p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
43 #ifdef CONFIG_NET_9P_DEBUG
44 void
45 p9pdu_dump(int way, struct p9_fcall *pdu)
47 int len = pdu->size;
49 if ((p9_debug_level & P9_DEBUG_VPKT) != P9_DEBUG_VPKT) {
50 if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT) {
51 if (len > 32)
52 len = 32;
53 } else {
54 /* shouldn't happen */
55 return;
59 if (way)
60 print_hex_dump_bytes("[9P] ", DUMP_PREFIX_OFFSET, pdu->sdata,
61 len);
62 else
63 print_hex_dump_bytes("]9P[ ", DUMP_PREFIX_OFFSET, pdu->sdata,
64 len);
66 #else
67 void
68 p9pdu_dump(int way, struct p9_fcall *pdu)
71 #endif
72 EXPORT_SYMBOL(p9pdu_dump);
74 void p9stat_free(struct p9_wstat *stbuf)
76 kfree(stbuf->name);
77 kfree(stbuf->uid);
78 kfree(stbuf->gid);
79 kfree(stbuf->muid);
80 kfree(stbuf->extension);
82 EXPORT_SYMBOL(p9stat_free);
84 size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
86 size_t len = min(pdu->size - pdu->offset, size);
87 memcpy(data, &pdu->sdata[pdu->offset], len);
88 pdu->offset += len;
89 return size - len;
92 static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
94 size_t len = min(pdu->capacity - pdu->size, size);
95 memcpy(&pdu->sdata[pdu->size], data, len);
96 pdu->size += len;
97 return size - len;
100 static size_t
101 pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
103 size_t len = min(pdu->capacity - pdu->size, size);
104 if (copy_from_user(&pdu->sdata[pdu->size], udata, len))
105 len = 0;
107 pdu->size += len;
108 return size - len;
112 b - int8_t
113 w - int16_t
114 d - int32_t
115 q - int64_t
116 s - string
117 S - stat
118 Q - qid
119 D - data blob (int32_t size followed by void *, results are not freed)
120 T - array of strings (int16_t count, followed by strings)
121 R - array of qids (int16_t count, followed by qids)
122 A - stat for 9p2000.L (p9_stat_dotl)
123 ? - if optional = 1, continue parsing
126 static int
127 p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
128 va_list ap)
130 const char *ptr;
131 int errcode = 0;
133 for (ptr = fmt; *ptr; ptr++) {
134 switch (*ptr) {
135 case 'b':{
136 int8_t *val = va_arg(ap, int8_t *);
137 if (pdu_read(pdu, val, sizeof(*val))) {
138 errcode = -EFAULT;
139 break;
142 break;
143 case 'w':{
144 int16_t *val = va_arg(ap, int16_t *);
145 __le16 le_val;
146 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
147 errcode = -EFAULT;
148 break;
150 *val = le16_to_cpu(le_val);
152 break;
153 case 'd':{
154 int32_t *val = va_arg(ap, int32_t *);
155 __le32 le_val;
156 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
157 errcode = -EFAULT;
158 break;
160 *val = le32_to_cpu(le_val);
162 break;
163 case 'q':{
164 int64_t *val = va_arg(ap, int64_t *);
165 __le64 le_val;
166 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
167 errcode = -EFAULT;
168 break;
170 *val = le64_to_cpu(le_val);
172 break;
173 case 's':{
174 char **sptr = va_arg(ap, char **);
175 uint16_t len;
177 errcode = p9pdu_readf(pdu, proto_version,
178 "w", &len);
179 if (errcode)
180 break;
182 *sptr = kmalloc(len + 1, GFP_NOFS);
183 if (*sptr == NULL) {
184 errcode = -EFAULT;
185 break;
187 if (pdu_read(pdu, *sptr, len)) {
188 errcode = -EFAULT;
189 kfree(*sptr);
190 *sptr = NULL;
191 } else
192 (*sptr)[len] = 0;
194 break;
195 case 'Q':{
196 struct p9_qid *qid =
197 va_arg(ap, struct p9_qid *);
199 errcode = p9pdu_readf(pdu, proto_version, "bdq",
200 &qid->type, &qid->version,
201 &qid->path);
203 break;
204 case 'S':{
205 struct p9_wstat *stbuf =
206 va_arg(ap, struct p9_wstat *);
208 memset(stbuf, 0, sizeof(struct p9_wstat));
209 stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
211 errcode =
212 p9pdu_readf(pdu, proto_version,
213 "wwdQdddqssss?sddd",
214 &stbuf->size, &stbuf->type,
215 &stbuf->dev, &stbuf->qid,
216 &stbuf->mode, &stbuf->atime,
217 &stbuf->mtime, &stbuf->length,
218 &stbuf->name, &stbuf->uid,
219 &stbuf->gid, &stbuf->muid,
220 &stbuf->extension,
221 &stbuf->n_uid, &stbuf->n_gid,
222 &stbuf->n_muid);
223 if (errcode)
224 p9stat_free(stbuf);
226 break;
227 case 'D':{
228 uint32_t *count = va_arg(ap, uint32_t *);
229 void **data = va_arg(ap, void **);
231 errcode =
232 p9pdu_readf(pdu, proto_version, "d", count);
233 if (!errcode) {
234 *count =
235 min_t(uint32_t, *count,
236 pdu->size - pdu->offset);
237 *data = &pdu->sdata[pdu->offset];
240 break;
241 case 'T':{
242 uint16_t *nwname = va_arg(ap, uint16_t *);
243 char ***wnames = va_arg(ap, char ***);
245 errcode = p9pdu_readf(pdu, proto_version,
246 "w", nwname);
247 if (!errcode) {
248 *wnames =
249 kmalloc(sizeof(char *) * *nwname,
250 GFP_NOFS);
251 if (!*wnames)
252 errcode = -ENOMEM;
255 if (!errcode) {
256 int i;
258 for (i = 0; i < *nwname; i++) {
259 errcode =
260 p9pdu_readf(pdu,
261 proto_version,
262 "s",
263 &(*wnames)[i]);
264 if (errcode)
265 break;
269 if (errcode) {
270 if (*wnames) {
271 int i;
273 for (i = 0; i < *nwname; i++)
274 kfree((*wnames)[i]);
276 kfree(*wnames);
277 *wnames = NULL;
280 break;
281 case 'R':{
282 int16_t *nwqid = va_arg(ap, int16_t *);
283 struct p9_qid **wqids =
284 va_arg(ap, struct p9_qid **);
286 *wqids = NULL;
288 errcode =
289 p9pdu_readf(pdu, proto_version, "w", nwqid);
290 if (!errcode) {
291 *wqids =
292 kmalloc(*nwqid *
293 sizeof(struct p9_qid),
294 GFP_NOFS);
295 if (*wqids == NULL)
296 errcode = -ENOMEM;
299 if (!errcode) {
300 int i;
302 for (i = 0; i < *nwqid; i++) {
303 errcode =
304 p9pdu_readf(pdu,
305 proto_version,
306 "Q",
307 &(*wqids)[i]);
308 if (errcode)
309 break;
313 if (errcode) {
314 kfree(*wqids);
315 *wqids = NULL;
318 break;
319 case 'A': {
320 struct p9_stat_dotl *stbuf =
321 va_arg(ap, struct p9_stat_dotl *);
323 memset(stbuf, 0, sizeof(struct p9_stat_dotl));
324 errcode =
325 p9pdu_readf(pdu, proto_version,
326 "qQdddqqqqqqqqqqqqqqq",
327 &stbuf->st_result_mask,
328 &stbuf->qid,
329 &stbuf->st_mode,
330 &stbuf->st_uid, &stbuf->st_gid,
331 &stbuf->st_nlink,
332 &stbuf->st_rdev, &stbuf->st_size,
333 &stbuf->st_blksize, &stbuf->st_blocks,
334 &stbuf->st_atime_sec,
335 &stbuf->st_atime_nsec,
336 &stbuf->st_mtime_sec,
337 &stbuf->st_mtime_nsec,
338 &stbuf->st_ctime_sec,
339 &stbuf->st_ctime_nsec,
340 &stbuf->st_btime_sec,
341 &stbuf->st_btime_nsec,
342 &stbuf->st_gen,
343 &stbuf->st_data_version);
345 break;
346 case '?':
347 if ((proto_version != p9_proto_2000u) &&
348 (proto_version != p9_proto_2000L))
349 return 0;
350 break;
351 default:
352 BUG();
353 break;
356 if (errcode)
357 break;
360 return errcode;
364 p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
365 va_list ap)
367 const char *ptr;
368 int errcode = 0;
370 for (ptr = fmt; *ptr; ptr++) {
371 switch (*ptr) {
372 case 'b':{
373 int8_t val = va_arg(ap, int);
374 if (pdu_write(pdu, &val, sizeof(val)))
375 errcode = -EFAULT;
377 break;
378 case 'w':{
379 __le16 val = cpu_to_le16(va_arg(ap, int));
380 if (pdu_write(pdu, &val, sizeof(val)))
381 errcode = -EFAULT;
383 break;
384 case 'd':{
385 __le32 val = cpu_to_le32(va_arg(ap, int32_t));
386 if (pdu_write(pdu, &val, sizeof(val)))
387 errcode = -EFAULT;
389 break;
390 case 'q':{
391 __le64 val = cpu_to_le64(va_arg(ap, int64_t));
392 if (pdu_write(pdu, &val, sizeof(val)))
393 errcode = -EFAULT;
395 break;
396 case 's':{
397 const char *sptr = va_arg(ap, const char *);
398 uint16_t len = 0;
399 if (sptr)
400 len = min_t(uint16_t, strlen(sptr),
401 USHRT_MAX);
403 errcode = p9pdu_writef(pdu, proto_version,
404 "w", len);
405 if (!errcode && pdu_write(pdu, sptr, len))
406 errcode = -EFAULT;
408 break;
409 case 'Q':{
410 const struct p9_qid *qid =
411 va_arg(ap, const struct p9_qid *);
412 errcode =
413 p9pdu_writef(pdu, proto_version, "bdq",
414 qid->type, qid->version,
415 qid->path);
416 } break;
417 case 'S':{
418 const struct p9_wstat *stbuf =
419 va_arg(ap, const struct p9_wstat *);
420 errcode =
421 p9pdu_writef(pdu, proto_version,
422 "wwdQdddqssss?sddd",
423 stbuf->size, stbuf->type,
424 stbuf->dev, &stbuf->qid,
425 stbuf->mode, stbuf->atime,
426 stbuf->mtime, stbuf->length,
427 stbuf->name, stbuf->uid,
428 stbuf->gid, stbuf->muid,
429 stbuf->extension, stbuf->n_uid,
430 stbuf->n_gid, stbuf->n_muid);
431 } break;
432 case 'D':{
433 uint32_t count = va_arg(ap, uint32_t);
434 const void *data = va_arg(ap, const void *);
436 errcode = p9pdu_writef(pdu, proto_version, "d",
437 count);
438 if (!errcode && pdu_write(pdu, data, count))
439 errcode = -EFAULT;
441 break;
442 case 'U':{
443 int32_t count = va_arg(ap, int32_t);
444 const char __user *udata =
445 va_arg(ap, const void __user *);
446 errcode = p9pdu_writef(pdu, proto_version, "d",
447 count);
448 if (!errcode && pdu_write_u(pdu, udata, count))
449 errcode = -EFAULT;
451 break;
452 case 'T':{
453 uint16_t nwname = va_arg(ap, int);
454 const char **wnames = va_arg(ap, const char **);
456 errcode = p9pdu_writef(pdu, proto_version, "w",
457 nwname);
458 if (!errcode) {
459 int i;
461 for (i = 0; i < nwname; i++) {
462 errcode =
463 p9pdu_writef(pdu,
464 proto_version,
465 "s",
466 wnames[i]);
467 if (errcode)
468 break;
472 break;
473 case 'R':{
474 int16_t nwqid = va_arg(ap, int);
475 struct p9_qid *wqids =
476 va_arg(ap, struct p9_qid *);
478 errcode = p9pdu_writef(pdu, proto_version, "w",
479 nwqid);
480 if (!errcode) {
481 int i;
483 for (i = 0; i < nwqid; i++) {
484 errcode =
485 p9pdu_writef(pdu,
486 proto_version,
487 "Q",
488 &wqids[i]);
489 if (errcode)
490 break;
494 break;
495 case 'I':{
496 struct p9_iattr_dotl *p9attr = va_arg(ap,
497 struct p9_iattr_dotl *);
499 errcode = p9pdu_writef(pdu, proto_version,
500 "ddddqqqqq",
501 p9attr->valid,
502 p9attr->mode,
503 p9attr->uid,
504 p9attr->gid,
505 p9attr->size,
506 p9attr->atime_sec,
507 p9attr->atime_nsec,
508 p9attr->mtime_sec,
509 p9attr->mtime_nsec);
511 break;
512 case '?':
513 if ((proto_version != p9_proto_2000u) &&
514 (proto_version != p9_proto_2000L))
515 return 0;
516 break;
517 default:
518 BUG();
519 break;
522 if (errcode)
523 break;
526 return errcode;
529 int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
531 va_list ap;
532 int ret;
534 va_start(ap, fmt);
535 ret = p9pdu_vreadf(pdu, proto_version, fmt, ap);
536 va_end(ap);
538 return ret;
541 static int
542 p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
544 va_list ap;
545 int ret;
547 va_start(ap, fmt);
548 ret = p9pdu_vwritef(pdu, proto_version, fmt, ap);
549 va_end(ap);
551 return ret;
554 int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version)
556 struct p9_fcall fake_pdu;
557 int ret;
559 fake_pdu.size = len;
560 fake_pdu.capacity = len;
561 fake_pdu.sdata = buf;
562 fake_pdu.offset = 0;
564 ret = p9pdu_readf(&fake_pdu, proto_version, "S", st);
565 if (ret) {
566 P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
567 P9_DUMP_PKT(0, &fake_pdu);
570 return ret;
572 EXPORT_SYMBOL(p9stat_read);
574 int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
576 pdu->id = type;
577 return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
580 int p9pdu_finalize(struct p9_fcall *pdu)
582 int size = pdu->size;
583 int err;
585 pdu->size = 0;
586 err = p9pdu_writef(pdu, 0, "d", size);
587 pdu->size = size;
589 P9_DUMP_PKT(0, pdu);
590 P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size,
591 pdu->id, pdu->tag);
593 return err;
596 void p9pdu_reset(struct p9_fcall *pdu)
598 pdu->offset = 0;
599 pdu->size = 0;
602 int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
603 int proto_version)
605 struct p9_fcall fake_pdu;
606 int ret;
607 char *nameptr;
609 fake_pdu.size = len;
610 fake_pdu.capacity = len;
611 fake_pdu.sdata = buf;
612 fake_pdu.offset = 0;
614 ret = p9pdu_readf(&fake_pdu, proto_version, "Qqbs", &dirent->qid,
615 &dirent->d_off, &dirent->d_type, &nameptr);
616 if (ret) {
617 P9_DPRINTK(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
618 P9_DUMP_PKT(1, &fake_pdu);
619 goto out;
622 strcpy(dirent->d_name, nameptr);
623 kfree(nameptr);
625 out:
626 return fake_pdu.offset;
628 EXPORT_SYMBOL(p9dirent_read);