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