fs/9p: change an int to unsigned int
[deliverable/linux.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>
01b0c5cf 30#include <linux/kernel.h>
51a87c55 31#include <linux/uaccess.h>
5a0e3ad6 32#include <linux/slab.h>
e7f4b8f1 33#include <linux/sched.h>
01b0c5cf 34#include <linux/stddef.h>
beeebc92 35#include <linux/types.h>
ace51c4d
EVH
36#include <net/9p/9p.h>
37#include <net/9p/client.h>
38#include "protocol.h"
39
ace51c4d 40static int
342fee1d 41p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
ace51c4d 42
0b15a3a5 43#ifdef CONFIG_NET_9P_DEBUG
51a87c55
EVH
44void
45p9pdu_dump(int way, struct p9_fcall *pdu)
46{
e660a828
EVH
47 int len = pdu->size;
48
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;
56 }
51a87c55 57 }
51a87c55
EVH
58
59 if (way)
e660a828
EVH
60 print_hex_dump_bytes("[9P] ", DUMP_PREFIX_OFFSET, pdu->sdata,
61 len);
51a87c55 62 else
e660a828
EVH
63 print_hex_dump_bytes("]9P[ ", DUMP_PREFIX_OFFSET, pdu->sdata,
64 len);
51a87c55 65}
0b15a3a5
EVH
66#else
67void
68p9pdu_dump(int way, struct p9_fcall *pdu)
69{
70}
71#endif
51a87c55
EVH
72EXPORT_SYMBOL(p9pdu_dump);
73
ace51c4d
EVH
74void p9stat_free(struct p9_wstat *stbuf)
75{
76 kfree(stbuf->name);
77 kfree(stbuf->uid);
78 kfree(stbuf->gid);
79 kfree(stbuf->muid);
80 kfree(stbuf->extension);
81}
82EXPORT_SYMBOL(p9stat_free);
83
abfa034e 84size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
ace51c4d 85{
01b0c5cf 86 size_t len = min(pdu->size - pdu->offset, size);
ace51c4d
EVH
87 memcpy(data, &pdu->sdata[pdu->offset], len);
88 pdu->offset += len;
89 return size - len;
90}
91
92static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
93{
01b0c5cf 94 size_t len = min(pdu->capacity - pdu->size, size);
ace51c4d
EVH
95 memcpy(&pdu->sdata[pdu->size], data, len);
96 pdu->size += len;
97 return size - len;
98}
99
51a87c55
EVH
100static size_t
101pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
102{
01b0c5cf 103 size_t len = min(pdu->capacity - pdu->size, size);
7b3bb3fe
AK
104 if (copy_from_user(&pdu->sdata[pdu->size], udata, len))
105 len = 0;
51a87c55
EVH
106
107 pdu->size += len;
108 return size - len;
109}
110
ace51c4d
EVH
111/*
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)
f0853122 122 A - stat for 9p2000.L (p9_stat_dotl)
ace51c4d
EVH
123 ? - if optional = 1, continue parsing
124*/
125
126static int
342fee1d
SK
127p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
128 va_list ap)
ace51c4d
EVH
129{
130 const char *ptr;
131 int errcode = 0;
132
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;
140 }
141 }
142 break;
143 case 'w':{
144 int16_t *val = va_arg(ap, int16_t *);
beeebc92
EVH
145 __le16 le_val;
146 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
ace51c4d
EVH
147 errcode = -EFAULT;
148 break;
149 }
beeebc92 150 *val = le16_to_cpu(le_val);
ace51c4d
EVH
151 }
152 break;
153 case 'd':{
154 int32_t *val = va_arg(ap, int32_t *);
beeebc92
EVH
155 __le32 le_val;
156 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
ace51c4d
EVH
157 errcode = -EFAULT;
158 break;
159 }
beeebc92 160 *val = le32_to_cpu(le_val);
ace51c4d
EVH
161 }
162 break;
163 case 'q':{
164 int64_t *val = va_arg(ap, int64_t *);
beeebc92
EVH
165 __le64 le_val;
166 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
ace51c4d
EVH
167 errcode = -EFAULT;
168 break;
169 }
beeebc92 170 *val = le64_to_cpu(le_val);
ace51c4d
EVH
171 }
172 break;
173 case 's':{
e45c5405 174 char **sptr = va_arg(ap, char **);
219fd58b 175 uint16_t len;
ace51c4d 176
342fee1d
SK
177 errcode = p9pdu_readf(pdu, proto_version,
178 "w", &len);
ace51c4d
EVH
179 if (errcode)
180 break;
181
eeff66ef 182 *sptr = kmalloc(len + 1, GFP_NOFS);
e45c5405 183 if (*sptr == NULL) {
ace51c4d
EVH
184 errcode = -EFAULT;
185 break;
186 }
219fd58b 187 if (pdu_read(pdu, *sptr, len)) {
ace51c4d 188 errcode = -EFAULT;
e45c5405
EVH
189 kfree(*sptr);
190 *sptr = NULL;
ace51c4d 191 } else
219fd58b 192 (*sptr)[len] = 0;
ace51c4d
EVH
193 }
194 break;
195 case 'Q':{
196 struct p9_qid *qid =
197 va_arg(ap, struct p9_qid *);
198
342fee1d 199 errcode = p9pdu_readf(pdu, proto_version, "bdq",
ace51c4d
EVH
200 &qid->type, &qid->version,
201 &qid->path);
202 }
203 break;
204 case 'S':{
205 struct p9_wstat *stbuf =
206 va_arg(ap, struct p9_wstat *);
207
f0a0ac2e 208 memset(stbuf, 0, sizeof(struct p9_wstat));
ace51c4d 209 stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
f0a0ac2e 210 -1;
ace51c4d 211 errcode =
342fee1d 212 p9pdu_readf(pdu, proto_version,
ace51c4d
EVH
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);
225 }
226 break;
227 case 'D':{
219fd58b 228 uint32_t *count = va_arg(ap, uint32_t *);
ace51c4d
EVH
229 void **data = va_arg(ap, void **);
230
231 errcode =
342fee1d 232 p9pdu_readf(pdu, proto_version, "d", count);
ace51c4d
EVH
233 if (!errcode) {
234 *count =
219fd58b 235 min_t(uint32_t, *count,
01b0c5cf 236 pdu->size - pdu->offset);
ace51c4d
EVH
237 *data = &pdu->sdata[pdu->offset];
238 }
239 }
240 break;
241 case 'T':{
b76225e2 242 uint16_t *nwname = va_arg(ap, uint16_t *);
ace51c4d
EVH
243 char ***wnames = va_arg(ap, char ***);
244
342fee1d
SK
245 errcode = p9pdu_readf(pdu, proto_version,
246 "w", nwname);
ace51c4d
EVH
247 if (!errcode) {
248 *wnames =
249 kmalloc(sizeof(char *) * *nwname,
eeff66ef 250 GFP_NOFS);
ace51c4d
EVH
251 if (!*wnames)
252 errcode = -ENOMEM;
253 }
254
255 if (!errcode) {
256 int i;
257
258 for (i = 0; i < *nwname; i++) {
259 errcode =
342fee1d
SK
260 p9pdu_readf(pdu,
261 proto_version,
ace51c4d
EVH
262 "s",
263 &(*wnames)[i]);
264 if (errcode)
265 break;
266 }
267 }
268
269 if (errcode) {
270 if (*wnames) {
271 int i;
272
273 for (i = 0; i < *nwname; i++)
274 kfree((*wnames)[i]);
275 }
276 kfree(*wnames);
277 *wnames = NULL;
278 }
279 }
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 **);
285
286 *wqids = NULL;
287
288 errcode =
342fee1d 289 p9pdu_readf(pdu, proto_version, "w", nwqid);
ace51c4d
EVH
290 if (!errcode) {
291 *wqids =
292 kmalloc(*nwqid *
293 sizeof(struct p9_qid),
eeff66ef 294 GFP_NOFS);
ace51c4d
EVH
295 if (*wqids == NULL)
296 errcode = -ENOMEM;
297 }
298
299 if (!errcode) {
300 int i;
301
302 for (i = 0; i < *nwqid; i++) {
303 errcode =
342fee1d
SK
304 p9pdu_readf(pdu,
305 proto_version,
ace51c4d
EVH
306 "Q",
307 &(*wqids)[i]);
308 if (errcode)
309 break;
310 }
311 }
312
313 if (errcode) {
314 kfree(*wqids);
315 *wqids = NULL;
316 }
317 }
318 break;
f0853122
SK
319 case 'A': {
320 struct p9_stat_dotl *stbuf =
321 va_arg(ap, struct p9_stat_dotl *);
322
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);
344 }
345 break;
ace51c4d 346 case '?':
c56e4acf
SK
347 if ((proto_version != p9_proto_2000u) &&
348 (proto_version != p9_proto_2000L))
ace51c4d
EVH
349 return 0;
350 break;
351 default:
352 BUG();
353 break;
354 }
355
356 if (errcode)
357 break;
358 }
359
360 return errcode;
361}
362
363int
342fee1d
SK
364p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
365 va_list ap)
ace51c4d
EVH
366{
367 const char *ptr;
368 int errcode = 0;
369
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;
376 }
377 break;
378 case 'w':{
beeebc92 379 __le16 val = cpu_to_le16(va_arg(ap, int));
ace51c4d
EVH
380 if (pdu_write(pdu, &val, sizeof(val)))
381 errcode = -EFAULT;
382 }
383 break;
384 case 'd':{
beeebc92 385 __le32 val = cpu_to_le32(va_arg(ap, int32_t));
ace51c4d
EVH
386 if (pdu_write(pdu, &val, sizeof(val)))
387 errcode = -EFAULT;
388 }
389 break;
390 case 'q':{
beeebc92 391 __le64 val = cpu_to_le64(va_arg(ap, int64_t));
ace51c4d
EVH
392 if (pdu_write(pdu, &val, sizeof(val)))
393 errcode = -EFAULT;
394 }
395 break;
396 case 's':{
e45c5405 397 const char *sptr = va_arg(ap, const char *);
219fd58b 398 uint16_t len = 0;
e45c5405 399 if (sptr)
219fd58b
MK
400 len = min_t(uint16_t, strlen(sptr),
401 USHRT_MAX);
ace51c4d 402
342fee1d
SK
403 errcode = p9pdu_writef(pdu, proto_version,
404 "w", len);
e45c5405 405 if (!errcode && pdu_write(pdu, sptr, len))
ace51c4d
EVH
406 errcode = -EFAULT;
407 }
408 break;
409 case 'Q':{
410 const struct p9_qid *qid =
411 va_arg(ap, const struct p9_qid *);
412 errcode =
342fee1d 413 p9pdu_writef(pdu, proto_version, "bdq",
ace51c4d
EVH
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 =
342fee1d 421 p9pdu_writef(pdu, proto_version,
ace51c4d
EVH
422 "wwdQdddqssss?sddd",
423 stbuf->size, stbuf->type,
51a87c55 424 stbuf->dev, &stbuf->qid,
ace51c4d
EVH
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':{
219fd58b 433 uint32_t count = va_arg(ap, uint32_t);
ace51c4d
EVH
434 const void *data = va_arg(ap, const void *);
435
342fee1d
SK
436 errcode = p9pdu_writef(pdu, proto_version, "d",
437 count);
ace51c4d
EVH
438 if (!errcode && pdu_write(pdu, data, count))
439 errcode = -EFAULT;
440 }
441 break;
51a87c55
EVH
442 case 'U':{
443 int32_t count = va_arg(ap, int32_t);
444 const char __user *udata =
e45c5405 445 va_arg(ap, const void __user *);
342fee1d
SK
446 errcode = p9pdu_writef(pdu, proto_version, "d",
447 count);
51a87c55
EVH
448 if (!errcode && pdu_write_u(pdu, udata, count))
449 errcode = -EFAULT;
450 }
451 break;
ace51c4d 452 case 'T':{
b76225e2 453 uint16_t nwname = va_arg(ap, int);
ace51c4d
EVH
454 const char **wnames = va_arg(ap, const char **);
455
342fee1d
SK
456 errcode = p9pdu_writef(pdu, proto_version, "w",
457 nwname);
ace51c4d
EVH
458 if (!errcode) {
459 int i;
460
461 for (i = 0; i < nwname; i++) {
462 errcode =
342fee1d
SK
463 p9pdu_writef(pdu,
464 proto_version,
ace51c4d
EVH
465 "s",
466 wnames[i]);
467 if (errcode)
468 break;
469 }
470 }
471 }
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 *);
477
342fee1d
SK
478 errcode = p9pdu_writef(pdu, proto_version, "w",
479 nwqid);
ace51c4d
EVH
480 if (!errcode) {
481 int i;
482
483 for (i = 0; i < nwqid; i++) {
484 errcode =
342fee1d
SK
485 p9pdu_writef(pdu,
486 proto_version,
ace51c4d
EVH
487 "Q",
488 &wqids[i]);
489 if (errcode)
490 break;
491 }
492 }
493 }
494 break;
87d7845a
SK
495 case 'I':{
496 struct p9_iattr_dotl *p9attr = va_arg(ap,
497 struct p9_iattr_dotl *);
498
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);
510 }
511 break;
ace51c4d 512 case '?':
c56e4acf
SK
513 if ((proto_version != p9_proto_2000u) &&
514 (proto_version != p9_proto_2000L))
ace51c4d
EVH
515 return 0;
516 break;
517 default:
518 BUG();
519 break;
520 }
521
522 if (errcode)
523 break;
524 }
525
526 return errcode;
527}
528
342fee1d 529int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
ace51c4d
EVH
530{
531 va_list ap;
532 int ret;
533
534 va_start(ap, fmt);
342fee1d 535 ret = p9pdu_vreadf(pdu, proto_version, fmt, ap);
ace51c4d
EVH
536 va_end(ap);
537
538 return ret;
539}
540
541static int
342fee1d 542p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
ace51c4d
EVH
543{
544 va_list ap;
545 int ret;
546
547 va_start(ap, fmt);
342fee1d 548 ret = p9pdu_vwritef(pdu, proto_version, fmt, ap);
ace51c4d
EVH
549 va_end(ap);
550
551 return ret;
552}
51a87c55 553
342fee1d 554int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version)
02da398b
EVH
555{
556 struct p9_fcall fake_pdu;
e7f4b8f1 557 int ret;
02da398b
EVH
558
559 fake_pdu.size = len;
560 fake_pdu.capacity = len;
561 fake_pdu.sdata = buf;
562 fake_pdu.offset = 0;
563
342fee1d 564 ret = p9pdu_readf(&fake_pdu, proto_version, "S", st);
e7f4b8f1
EVH
565 if (ret) {
566 P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
e660a828 567 P9_DUMP_PKT(0, &fake_pdu);
e7f4b8f1
EVH
568 }
569
570 return ret;
02da398b
EVH
571}
572EXPORT_SYMBOL(p9stat_read);
573
51a87c55
EVH
574int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
575{
9bb6c10a 576 pdu->id = type;
51a87c55
EVH
577 return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
578}
579
580int p9pdu_finalize(struct p9_fcall *pdu)
581{
582 int size = pdu->size;
583 int err;
584
585 pdu->size = 0;
586 err = p9pdu_writef(pdu, 0, "d", size);
587 pdu->size = size;
588
e660a828 589 P9_DUMP_PKT(0, pdu);
e7f4b8f1
EVH
590 P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size,
591 pdu->id, pdu->tag);
592
51a87c55
EVH
593 return err;
594}
595
596void p9pdu_reset(struct p9_fcall *pdu)
597{
598 pdu->offset = 0;
599 pdu->size = 0;
600}
7751bdb3
SK
601
602int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
603 int proto_version)
604{
605 struct p9_fcall fake_pdu;
606 int ret;
607 char *nameptr;
608
609 fake_pdu.size = len;
610 fake_pdu.capacity = len;
611 fake_pdu.sdata = buf;
612 fake_pdu.offset = 0;
613
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);
e660a828 618 P9_DUMP_PKT(1, &fake_pdu);
7751bdb3
SK
619 goto out;
620 }
621
622 strcpy(dirent->d_name, nameptr);
1b0bcbcf 623 kfree(nameptr);
7751bdb3
SK
624
625out:
626 return fake_pdu.offset;
627}
628EXPORT_SYMBOL(p9dirent_read);
This page took 0.596076 seconds and 5 git commands to generate.