Merge branch 'kconfig' of git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild-2.6
[pandora-kernel.git] / net / 9p / protocol.c
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>
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"
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
55 static int
56 p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
57
58 #ifdef CONFIG_NET_9P_DEBUG
59 void
60 p9pdu_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)
83                 P9_DPRINTK(P9_DEBUG_PKT, "[[[(%d) %s\n", datalen, buf);
84         else
85                 P9_DPRINTK(P9_DEBUG_PKT, "]]](%d) %s\n", datalen, buf);
86 }
87 #else
88 void
89 p9pdu_dump(int way, struct p9_fcall *pdu)
90 {
91 }
92 #endif
93 EXPORT_SYMBOL(p9pdu_dump);
94
95 void 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 }
103 EXPORT_SYMBOL(p9stat_free);
104
105 static 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
113 static 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
121 static size_t
122 pdu_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         if (copy_from_user(&pdu->sdata[pdu->size], udata, len))
126                 len = 0;
127
128         pdu->size += len;
129         return size - len;
130 }
131
132 /*
133         b - int8_t
134         w - int16_t
135         d - int32_t
136         q - int64_t
137         s - string
138         S - stat
139         Q - qid
140         D - data blob (int32_t size followed by void *, results are not freed)
141         T - array of strings (int16_t count, followed by strings)
142         R - array of qids (int16_t count, followed by qids)
143         A - stat for 9p2000.L (p9_stat_dotl)
144         ? - if optional = 1, continue parsing
145 */
146
147 static int
148 p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
149         va_list ap)
150 {
151         const char *ptr;
152         int errcode = 0;
153
154         for (ptr = fmt; *ptr; ptr++) {
155                 switch (*ptr) {
156                 case 'b':{
157                                 int8_t *val = va_arg(ap, int8_t *);
158                                 if (pdu_read(pdu, val, sizeof(*val))) {
159                                         errcode = -EFAULT;
160                                         break;
161                                 }
162                         }
163                         break;
164                 case 'w':{
165                                 int16_t *val = va_arg(ap, int16_t *);
166                                 __le16 le_val;
167                                 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
168                                         errcode = -EFAULT;
169                                         break;
170                                 }
171                                 *val = le16_to_cpu(le_val);
172                         }
173                         break;
174                 case 'd':{
175                                 int32_t *val = va_arg(ap, int32_t *);
176                                 __le32 le_val;
177                                 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
178                                         errcode = -EFAULT;
179                                         break;
180                                 }
181                                 *val = le32_to_cpu(le_val);
182                         }
183                         break;
184                 case 'q':{
185                                 int64_t *val = va_arg(ap, int64_t *);
186                                 __le64 le_val;
187                                 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
188                                         errcode = -EFAULT;
189                                         break;
190                                 }
191                                 *val = le64_to_cpu(le_val);
192                         }
193                         break;
194                 case 's':{
195                                 char **sptr = va_arg(ap, char **);
196                                 int16_t len;
197                                 int size;
198
199                                 errcode = p9pdu_readf(pdu, proto_version,
200                                                                 "w", &len);
201                                 if (errcode)
202                                         break;
203
204                                 size = MAX(len, 0);
205
206                                 *sptr = kmalloc(size + 1, GFP_KERNEL);
207                                 if (*sptr == NULL) {
208                                         errcode = -EFAULT;
209                                         break;
210                                 }
211                                 if (pdu_read(pdu, *sptr, size)) {
212                                         errcode = -EFAULT;
213                                         kfree(*sptr);
214                                         *sptr = NULL;
215                                 } else
216                                         (*sptr)[size] = 0;
217                         }
218                         break;
219                 case 'Q':{
220                                 struct p9_qid *qid =
221                                     va_arg(ap, struct p9_qid *);
222
223                                 errcode = p9pdu_readf(pdu, proto_version, "bdq",
224                                                       &qid->type, &qid->version,
225                                                       &qid->path);
226                         }
227                         break;
228                 case 'S':{
229                                 struct p9_wstat *stbuf =
230                                     va_arg(ap, struct p9_wstat *);
231
232                                 memset(stbuf, 0, sizeof(struct p9_wstat));
233                                 stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
234                                                                         -1;
235                                 errcode =
236                                     p9pdu_readf(pdu, proto_version,
237                                                 "wwdQdddqssss?sddd",
238                                                 &stbuf->size, &stbuf->type,
239                                                 &stbuf->dev, &stbuf->qid,
240                                                 &stbuf->mode, &stbuf->atime,
241                                                 &stbuf->mtime, &stbuf->length,
242                                                 &stbuf->name, &stbuf->uid,
243                                                 &stbuf->gid, &stbuf->muid,
244                                                 &stbuf->extension,
245                                                 &stbuf->n_uid, &stbuf->n_gid,
246                                                 &stbuf->n_muid);
247                                 if (errcode)
248                                         p9stat_free(stbuf);
249                         }
250                         break;
251                 case 'D':{
252                                 int32_t *count = va_arg(ap, int32_t *);
253                                 void **data = va_arg(ap, void **);
254
255                                 errcode =
256                                     p9pdu_readf(pdu, proto_version, "d", count);
257                                 if (!errcode) {
258                                         *count =
259                                             MIN(*count,
260                                                 pdu->size - pdu->offset);
261                                         *data = &pdu->sdata[pdu->offset];
262                                 }
263                         }
264                         break;
265                 case 'T':{
266                                 int16_t *nwname = va_arg(ap, int16_t *);
267                                 char ***wnames = va_arg(ap, char ***);
268
269                                 errcode = p9pdu_readf(pdu, proto_version,
270                                                                 "w", nwname);
271                                 if (!errcode) {
272                                         *wnames =
273                                             kmalloc(sizeof(char *) * *nwname,
274                                                     GFP_KERNEL);
275                                         if (!*wnames)
276                                                 errcode = -ENOMEM;
277                                 }
278
279                                 if (!errcode) {
280                                         int i;
281
282                                         for (i = 0; i < *nwname; i++) {
283                                                 errcode =
284                                                     p9pdu_readf(pdu,
285                                                                 proto_version,
286                                                                 "s",
287                                                                 &(*wnames)[i]);
288                                                 if (errcode)
289                                                         break;
290                                         }
291                                 }
292
293                                 if (errcode) {
294                                         if (*wnames) {
295                                                 int i;
296
297                                                 for (i = 0; i < *nwname; i++)
298                                                         kfree((*wnames)[i]);
299                                         }
300                                         kfree(*wnames);
301                                         *wnames = NULL;
302                                 }
303                         }
304                         break;
305                 case 'R':{
306                                 int16_t *nwqid = va_arg(ap, int16_t *);
307                                 struct p9_qid **wqids =
308                                     va_arg(ap, struct p9_qid **);
309
310                                 *wqids = NULL;
311
312                                 errcode =
313                                     p9pdu_readf(pdu, proto_version, "w", nwqid);
314                                 if (!errcode) {
315                                         *wqids =
316                                             kmalloc(*nwqid *
317                                                     sizeof(struct p9_qid),
318                                                     GFP_KERNEL);
319                                         if (*wqids == NULL)
320                                                 errcode = -ENOMEM;
321                                 }
322
323                                 if (!errcode) {
324                                         int i;
325
326                                         for (i = 0; i < *nwqid; i++) {
327                                                 errcode =
328                                                     p9pdu_readf(pdu,
329                                                                 proto_version,
330                                                                 "Q",
331                                                                 &(*wqids)[i]);
332                                                 if (errcode)
333                                                         break;
334                                         }
335                                 }
336
337                                 if (errcode) {
338                                         kfree(*wqids);
339                                         *wqids = NULL;
340                                 }
341                         }
342                         break;
343                 case 'A': {
344                                 struct p9_stat_dotl *stbuf =
345                                     va_arg(ap, struct p9_stat_dotl *);
346
347                                 memset(stbuf, 0, sizeof(struct p9_stat_dotl));
348                                 errcode =
349                                     p9pdu_readf(pdu, proto_version,
350                                         "qQdddqqqqqqqqqqqqqqq",
351                                         &stbuf->st_result_mask,
352                                         &stbuf->qid,
353                                         &stbuf->st_mode,
354                                         &stbuf->st_uid, &stbuf->st_gid,
355                                         &stbuf->st_nlink,
356                                         &stbuf->st_rdev, &stbuf->st_size,
357                                         &stbuf->st_blksize, &stbuf->st_blocks,
358                                         &stbuf->st_atime_sec,
359                                         &stbuf->st_atime_nsec,
360                                         &stbuf->st_mtime_sec,
361                                         &stbuf->st_mtime_nsec,
362                                         &stbuf->st_ctime_sec,
363                                         &stbuf->st_ctime_nsec,
364                                         &stbuf->st_btime_sec,
365                                         &stbuf->st_btime_nsec,
366                                         &stbuf->st_gen,
367                                         &stbuf->st_data_version);
368                         }
369                         break;
370                 case '?':
371                         if ((proto_version != p9_proto_2000u) &&
372                                 (proto_version != p9_proto_2000L))
373                                 return 0;
374                         break;
375                 default:
376                         BUG();
377                         break;
378                 }
379
380                 if (errcode)
381                         break;
382         }
383
384         return errcode;
385 }
386
387 int
388 p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
389         va_list ap)
390 {
391         const char *ptr;
392         int errcode = 0;
393
394         for (ptr = fmt; *ptr; ptr++) {
395                 switch (*ptr) {
396                 case 'b':{
397                                 int8_t val = va_arg(ap, int);
398                                 if (pdu_write(pdu, &val, sizeof(val)))
399                                         errcode = -EFAULT;
400                         }
401                         break;
402                 case 'w':{
403                                 __le16 val = cpu_to_le16(va_arg(ap, int));
404                                 if (pdu_write(pdu, &val, sizeof(val)))
405                                         errcode = -EFAULT;
406                         }
407                         break;
408                 case 'd':{
409                                 __le32 val = cpu_to_le32(va_arg(ap, int32_t));
410                                 if (pdu_write(pdu, &val, sizeof(val)))
411                                         errcode = -EFAULT;
412                         }
413                         break;
414                 case 'q':{
415                                 __le64 val = cpu_to_le64(va_arg(ap, int64_t));
416                                 if (pdu_write(pdu, &val, sizeof(val)))
417                                         errcode = -EFAULT;
418                         }
419                         break;
420                 case 's':{
421                                 const char *sptr = va_arg(ap, const char *);
422                                 int16_t len = 0;
423                                 if (sptr)
424                                         len = MIN(strlen(sptr), USHRT_MAX);
425
426                                 errcode = p9pdu_writef(pdu, proto_version,
427                                                                 "w", len);
428                                 if (!errcode && pdu_write(pdu, sptr, len))
429                                         errcode = -EFAULT;
430                         }
431                         break;
432                 case 'Q':{
433                                 const struct p9_qid *qid =
434                                     va_arg(ap, const struct p9_qid *);
435                                 errcode =
436                                     p9pdu_writef(pdu, proto_version, "bdq",
437                                                  qid->type, qid->version,
438                                                  qid->path);
439                         } break;
440                 case 'S':{
441                                 const struct p9_wstat *stbuf =
442                                     va_arg(ap, const struct p9_wstat *);
443                                 errcode =
444                                     p9pdu_writef(pdu, proto_version,
445                                                  "wwdQdddqssss?sddd",
446                                                  stbuf->size, stbuf->type,
447                                                  stbuf->dev, &stbuf->qid,
448                                                  stbuf->mode, stbuf->atime,
449                                                  stbuf->mtime, stbuf->length,
450                                                  stbuf->name, stbuf->uid,
451                                                  stbuf->gid, stbuf->muid,
452                                                  stbuf->extension, stbuf->n_uid,
453                                                  stbuf->n_gid, stbuf->n_muid);
454                         } break;
455                 case 'D':{
456                                 int32_t count = va_arg(ap, int32_t);
457                                 const void *data = va_arg(ap, const void *);
458
459                                 errcode = p9pdu_writef(pdu, proto_version, "d",
460                                                                         count);
461                                 if (!errcode && pdu_write(pdu, data, count))
462                                         errcode = -EFAULT;
463                         }
464                         break;
465                 case 'U':{
466                                 int32_t count = va_arg(ap, int32_t);
467                                 const char __user *udata =
468                                                 va_arg(ap, const void __user *);
469                                 errcode = p9pdu_writef(pdu, proto_version, "d",
470                                                                         count);
471                                 if (!errcode && pdu_write_u(pdu, udata, count))
472                                         errcode = -EFAULT;
473                         }
474                         break;
475                 case 'T':{
476                                 int16_t nwname = va_arg(ap, int);
477                                 const char **wnames = va_arg(ap, const char **);
478
479                                 errcode = p9pdu_writef(pdu, proto_version, "w",
480                                                                         nwname);
481                                 if (!errcode) {
482                                         int i;
483
484                                         for (i = 0; i < nwname; i++) {
485                                                 errcode =
486                                                     p9pdu_writef(pdu,
487                                                                 proto_version,
488                                                                  "s",
489                                                                  wnames[i]);
490                                                 if (errcode)
491                                                         break;
492                                         }
493                                 }
494                         }
495                         break;
496                 case 'R':{
497                                 int16_t nwqid = va_arg(ap, int);
498                                 struct p9_qid *wqids =
499                                     va_arg(ap, struct p9_qid *);
500
501                                 errcode = p9pdu_writef(pdu, proto_version, "w",
502                                                                         nwqid);
503                                 if (!errcode) {
504                                         int i;
505
506                                         for (i = 0; i < nwqid; i++) {
507                                                 errcode =
508                                                     p9pdu_writef(pdu,
509                                                                 proto_version,
510                                                                  "Q",
511                                                                  &wqids[i]);
512                                                 if (errcode)
513                                                         break;
514                                         }
515                                 }
516                         }
517                         break;
518                 case 'I':{
519                                 struct p9_iattr_dotl *p9attr = va_arg(ap,
520                                                         struct p9_iattr_dotl *);
521
522                                 errcode = p9pdu_writef(pdu, proto_version,
523                                                         "ddddqqqqq",
524                                                         p9attr->valid,
525                                                         p9attr->mode,
526                                                         p9attr->uid,
527                                                         p9attr->gid,
528                                                         p9attr->size,
529                                                         p9attr->atime_sec,
530                                                         p9attr->atime_nsec,
531                                                         p9attr->mtime_sec,
532                                                         p9attr->mtime_nsec);
533                         }
534                         break;
535                 case '?':
536                         if ((proto_version != p9_proto_2000u) &&
537                                 (proto_version != p9_proto_2000L))
538                                 return 0;
539                         break;
540                 default:
541                         BUG();
542                         break;
543                 }
544
545                 if (errcode)
546                         break;
547         }
548
549         return errcode;
550 }
551
552 int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
553 {
554         va_list ap;
555         int ret;
556
557         va_start(ap, fmt);
558         ret = p9pdu_vreadf(pdu, proto_version, fmt, ap);
559         va_end(ap);
560
561         return ret;
562 }
563
564 static int
565 p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
566 {
567         va_list ap;
568         int ret;
569
570         va_start(ap, fmt);
571         ret = p9pdu_vwritef(pdu, proto_version, fmt, ap);
572         va_end(ap);
573
574         return ret;
575 }
576
577 int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version)
578 {
579         struct p9_fcall fake_pdu;
580         int ret;
581
582         fake_pdu.size = len;
583         fake_pdu.capacity = len;
584         fake_pdu.sdata = buf;
585         fake_pdu.offset = 0;
586
587         ret = p9pdu_readf(&fake_pdu, proto_version, "S", st);
588         if (ret) {
589                 P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
590                 p9pdu_dump(1, &fake_pdu);
591         }
592
593         return ret;
594 }
595 EXPORT_SYMBOL(p9stat_read);
596
597 int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
598 {
599         return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
600 }
601
602 int p9pdu_finalize(struct p9_fcall *pdu)
603 {
604         int size = pdu->size;
605         int err;
606
607         pdu->size = 0;
608         err = p9pdu_writef(pdu, 0, "d", size);
609         pdu->size = size;
610
611 #ifdef CONFIG_NET_9P_DEBUG
612         if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT)
613                 p9pdu_dump(0, pdu);
614 #endif
615
616         P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size,
617                                                         pdu->id, pdu->tag);
618
619         return err;
620 }
621
622 void p9pdu_reset(struct p9_fcall *pdu)
623 {
624         pdu->offset = 0;
625         pdu->size = 0;
626 }
627
628 int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
629                                                 int proto_version)
630 {
631         struct p9_fcall fake_pdu;
632         int ret;
633         char *nameptr;
634
635         fake_pdu.size = len;
636         fake_pdu.capacity = len;
637         fake_pdu.sdata = buf;
638         fake_pdu.offset = 0;
639
640         ret = p9pdu_readf(&fake_pdu, proto_version, "Qqbs", &dirent->qid,
641                         &dirent->d_off, &dirent->d_type, &nameptr);
642         if (ret) {
643                 P9_DPRINTK(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
644                 p9pdu_dump(1, &fake_pdu);
645                 goto out;
646         }
647
648         strcpy(dirent->d_name, nameptr);
649
650 out:
651         return fake_pdu.offset;
652 }
653 EXPORT_SYMBOL(p9dirent_read);