intel_ips: potential null dereference
[wandboard.git] / net / 9p / protocol.c
blob3acd3afb20c857f6f3d2451a6ce1d7ba5c14af76
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/uaccess.h>
31 #include <linux/slab.h>
32 #include <linux/sched.h>
33 #include <linux/types.h>
34 #include <net/9p/9p.h>
35 #include <net/9p/client.h>
36 #include "protocol.h"
38 #ifndef MIN
39 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
40 #endif
42 #ifndef MAX
43 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
44 #endif
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
55 static int
56 p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
58 #ifdef CONFIG_NET_9P_DEBUG
59 void
60 p9pdu_dump(int way, struct p9_fcall *pdu)
62 int i, n;
63 u8 *data = pdu->sdata;
64 int datalen = pdu->size;
65 char buf[255];
66 int buflen = 255;
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");
78 i++;
80 n += scnprintf(buf + n, buflen - n, "\n");
82 if (way)
83 P9_DPRINTK(P9_DEBUG_PKT, "[[[(%d) %s\n", datalen, buf);
84 else
85 P9_DPRINTK(P9_DEBUG_PKT, "]]](%d) %s\n", datalen, buf);
87 #else
88 void
89 p9pdu_dump(int way, struct p9_fcall *pdu)
92 #endif
93 EXPORT_SYMBOL(p9pdu_dump);
95 void p9stat_free(struct p9_wstat *stbuf)
97 kfree(stbuf->name);
98 kfree(stbuf->uid);
99 kfree(stbuf->gid);
100 kfree(stbuf->muid);
101 kfree(stbuf->extension);
103 EXPORT_SYMBOL(p9stat_free);
105 static size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
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;
113 static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
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;
121 static size_t
122 pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
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);
129 pdu->size += len;
130 return size - len;
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)
144 A - stat for 9p2000.L (p9_stat_dotl)
145 ? - if optional = 1, continue parsing
148 static int
149 p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
150 va_list ap)
152 const char *ptr;
153 int errcode = 0;
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;
164 break;
165 case 'w':{
166 int16_t *val = va_arg(ap, int16_t *);
167 __le16 le_val;
168 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
169 errcode = -EFAULT;
170 break;
172 *val = le16_to_cpu(le_val);
174 break;
175 case 'd':{
176 int32_t *val = va_arg(ap, int32_t *);
177 __le32 le_val;
178 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
179 errcode = -EFAULT;
180 break;
182 *val = le32_to_cpu(le_val);
184 break;
185 case 'q':{
186 int64_t *val = va_arg(ap, int64_t *);
187 __le64 le_val;
188 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
189 errcode = -EFAULT;
190 break;
192 *val = le64_to_cpu(le_val);
194 break;
195 case 's':{
196 char **sptr = va_arg(ap, char **);
197 int16_t len;
198 int size;
200 errcode = p9pdu_readf(pdu, proto_version,
201 "w", &len);
202 if (errcode)
203 break;
205 size = MAX(len, 0);
207 *sptr = kmalloc(size + 1, GFP_KERNEL);
208 if (*sptr == NULL) {
209 errcode = -EFAULT;
210 break;
212 if (pdu_read(pdu, *sptr, size)) {
213 errcode = -EFAULT;
214 kfree(*sptr);
215 *sptr = NULL;
216 } else
217 (*sptr)[size] = 0;
219 break;
220 case 'Q':{
221 struct p9_qid *qid =
222 va_arg(ap, struct p9_qid *);
224 errcode = p9pdu_readf(pdu, proto_version, "bdq",
225 &qid->type, &qid->version,
226 &qid->path);
228 break;
229 case 'S':{
230 struct p9_wstat *stbuf =
231 va_arg(ap, struct p9_wstat *);
233 memset(stbuf, 0, sizeof(struct p9_wstat));
234 stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
236 errcode =
237 p9pdu_readf(pdu, proto_version,
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);
251 break;
252 case 'D':{
253 int32_t *count = va_arg(ap, int32_t *);
254 void **data = va_arg(ap, void **);
256 errcode =
257 p9pdu_readf(pdu, proto_version, "d", count);
258 if (!errcode) {
259 *count =
260 MIN(*count,
261 pdu->size - pdu->offset);
262 *data = &pdu->sdata[pdu->offset];
265 break;
266 case 'T':{
267 int16_t *nwname = va_arg(ap, int16_t *);
268 char ***wnames = va_arg(ap, char ***);
270 errcode = p9pdu_readf(pdu, proto_version,
271 "w", nwname);
272 if (!errcode) {
273 *wnames =
274 kmalloc(sizeof(char *) * *nwname,
275 GFP_KERNEL);
276 if (!*wnames)
277 errcode = -ENOMEM;
280 if (!errcode) {
281 int i;
283 for (i = 0; i < *nwname; i++) {
284 errcode =
285 p9pdu_readf(pdu,
286 proto_version,
287 "s",
288 &(*wnames)[i]);
289 if (errcode)
290 break;
294 if (errcode) {
295 if (*wnames) {
296 int i;
298 for (i = 0; i < *nwname; i++)
299 kfree((*wnames)[i]);
301 kfree(*wnames);
302 *wnames = NULL;
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 **);
311 *wqids = NULL;
313 errcode =
314 p9pdu_readf(pdu, proto_version, "w", nwqid);
315 if (!errcode) {
316 *wqids =
317 kmalloc(*nwqid *
318 sizeof(struct p9_qid),
319 GFP_KERNEL);
320 if (*wqids == NULL)
321 errcode = -ENOMEM;
324 if (!errcode) {
325 int i;
327 for (i = 0; i < *nwqid; i++) {
328 errcode =
329 p9pdu_readf(pdu,
330 proto_version,
331 "Q",
332 &(*wqids)[i]);
333 if (errcode)
334 break;
338 if (errcode) {
339 kfree(*wqids);
340 *wqids = NULL;
343 break;
344 case 'A': {
345 struct p9_stat_dotl *stbuf =
346 va_arg(ap, struct p9_stat_dotl *);
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);
370 break;
371 case '?':
372 if ((proto_version != p9_proto_2000u) &&
373 (proto_version != p9_proto_2000L))
374 return 0;
375 break;
376 default:
377 BUG();
378 break;
381 if (errcode)
382 break;
385 return errcode;
389 p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
390 va_list ap)
392 const char *ptr;
393 int errcode = 0;
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;
402 break;
403 case 'w':{
404 __le16 val = cpu_to_le16(va_arg(ap, int));
405 if (pdu_write(pdu, &val, sizeof(val)))
406 errcode = -EFAULT;
408 break;
409 case 'd':{
410 __le32 val = cpu_to_le32(va_arg(ap, int32_t));
411 if (pdu_write(pdu, &val, sizeof(val)))
412 errcode = -EFAULT;
414 break;
415 case 'q':{
416 __le64 val = cpu_to_le64(va_arg(ap, int64_t));
417 if (pdu_write(pdu, &val, sizeof(val)))
418 errcode = -EFAULT;
420 break;
421 case 's':{
422 const char *sptr = va_arg(ap, const char *);
423 int16_t len = 0;
424 if (sptr)
425 len = MIN(strlen(sptr), USHRT_MAX);
427 errcode = p9pdu_writef(pdu, proto_version,
428 "w", len);
429 if (!errcode && pdu_write(pdu, sptr, len))
430 errcode = -EFAULT;
432 break;
433 case 'Q':{
434 const struct p9_qid *qid =
435 va_arg(ap, const struct p9_qid *);
436 errcode =
437 p9pdu_writef(pdu, proto_version, "bdq",
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 =
445 p9pdu_writef(pdu, proto_version,
446 "wwdQdddqssss?sddd",
447 stbuf->size, stbuf->type,
448 stbuf->dev, &stbuf->qid,
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 *);
460 errcode = p9pdu_writef(pdu, proto_version, "d",
461 count);
462 if (!errcode && pdu_write(pdu, data, count))
463 errcode = -EFAULT;
465 break;
466 case 'U':{
467 int32_t count = va_arg(ap, int32_t);
468 const char __user *udata =
469 va_arg(ap, const void __user *);
470 errcode = p9pdu_writef(pdu, proto_version, "d",
471 count);
472 if (!errcode && pdu_write_u(pdu, udata, count))
473 errcode = -EFAULT;
475 break;
476 case 'T':{
477 int16_t nwname = va_arg(ap, int);
478 const char **wnames = va_arg(ap, const char **);
480 errcode = p9pdu_writef(pdu, proto_version, "w",
481 nwname);
482 if (!errcode) {
483 int i;
485 for (i = 0; i < nwname; i++) {
486 errcode =
487 p9pdu_writef(pdu,
488 proto_version,
489 "s",
490 wnames[i]);
491 if (errcode)
492 break;
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 *);
502 errcode = p9pdu_writef(pdu, proto_version, "w",
503 nwqid);
504 if (!errcode) {
505 int i;
507 for (i = 0; i < nwqid; i++) {
508 errcode =
509 p9pdu_writef(pdu,
510 proto_version,
511 "Q",
512 &wqids[i]);
513 if (errcode)
514 break;
518 break;
519 case 'I':{
520 struct p9_iattr_dotl *p9attr = va_arg(ap,
521 struct p9_iattr_dotl *);
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);
535 break;
536 case '?':
537 if ((proto_version != p9_proto_2000u) &&
538 (proto_version != p9_proto_2000L))
539 return 0;
540 break;
541 default:
542 BUG();
543 break;
546 if (errcode)
547 break;
550 return errcode;
553 int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
555 va_list ap;
556 int ret;
558 va_start(ap, fmt);
559 ret = p9pdu_vreadf(pdu, proto_version, fmt, ap);
560 va_end(ap);
562 return ret;
565 static int
566 p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
568 va_list ap;
569 int ret;
571 va_start(ap, fmt);
572 ret = p9pdu_vwritef(pdu, proto_version, fmt, ap);
573 va_end(ap);
575 return ret;
578 int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version)
580 struct p9_fcall fake_pdu;
581 int ret;
583 fake_pdu.size = len;
584 fake_pdu.capacity = len;
585 fake_pdu.sdata = buf;
586 fake_pdu.offset = 0;
588 ret = p9pdu_readf(&fake_pdu, proto_version, "S", st);
589 if (ret) {
590 P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
591 p9pdu_dump(1, &fake_pdu);
594 return ret;
596 EXPORT_SYMBOL(p9stat_read);
598 int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
600 return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
603 int p9pdu_finalize(struct p9_fcall *pdu)
605 int size = pdu->size;
606 int err;
608 pdu->size = 0;
609 err = p9pdu_writef(pdu, 0, "d", size);
610 pdu->size = size;
612 #ifdef CONFIG_NET_9P_DEBUG
613 if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT)
614 p9pdu_dump(0, pdu);
615 #endif
617 P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size,
618 pdu->id, pdu->tag);
620 return err;
623 void p9pdu_reset(struct p9_fcall *pdu)
625 pdu->offset = 0;
626 pdu->size = 0;
629 int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
630 int proto_version)
632 struct p9_fcall fake_pdu;
633 int ret;
634 char *nameptr;
636 fake_pdu.size = len;
637 fake_pdu.capacity = len;
638 fake_pdu.sdata = buf;
639 fake_pdu.offset = 0;
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;
649 strcpy(dirent->d_name, nameptr);
651 out:
652 return fake_pdu.offset;
654 EXPORT_SYMBOL(p9dirent_read);