9P2010.L handshake: Remove "dotu" variable
[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/sched.h>
32 #include <linux/types.h>
33 #include <net/9p/9p.h>
34 #include <net/9p/client.h>
35 #include "protocol.h"
36
37 #ifndef MIN
38 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
39 #endif
40
41 #ifndef MAX
42 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
43 #endif
44
45 #ifndef offset_of
46 #define offset_of(type, memb) \
47         ((unsigned long)(&((type *)0)->memb))
48 #endif
49 #ifndef container_of
50 #define container_of(obj, type, memb) \
51         ((type *)(((char *)obj) - offset_of(type, memb)))
52 #endif
53
54 static int
55 p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
56
57 #ifdef CONFIG_NET_9P_DEBUG
58 void
59 p9pdu_dump(int way, struct p9_fcall *pdu)
60 {
61         int i, n;
62         u8 *data = pdu->sdata;
63         int datalen = pdu->size;
64         char buf[255];
65         int buflen = 255;
66
67         i = n = 0;
68         if (datalen > (buflen-16))
69                 datalen = buflen-16;
70         while (i < datalen) {
71                 n += scnprintf(buf + n, buflen - n, "%02x ", data[i]);
72                 if (i%4 == 3)
73                         n += scnprintf(buf + n, buflen - n, " ");
74                 if (i%32 == 31)
75                         n += scnprintf(buf + n, buflen - n, "\n");
76
77                 i++;
78         }
79         n += scnprintf(buf + n, buflen - n, "\n");
80
81         if (way)
82                 P9_DPRINTK(P9_DEBUG_PKT, "[[[(%d) %s\n", datalen, buf);
83         else
84                 P9_DPRINTK(P9_DEBUG_PKT, "]]](%d) %s\n", datalen, buf);
85 }
86 #else
87 void
88 p9pdu_dump(int way, struct p9_fcall *pdu)
89 {
90 }
91 #endif
92 EXPORT_SYMBOL(p9pdu_dump);
93
94 void p9stat_free(struct p9_wstat *stbuf)
95 {
96         kfree(stbuf->name);
97         kfree(stbuf->uid);
98         kfree(stbuf->gid);
99         kfree(stbuf->muid);
100         kfree(stbuf->extension);
101 }
102 EXPORT_SYMBOL(p9stat_free);
103
104 static size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
105 {
106         size_t len = MIN(pdu->size - pdu->offset, size);
107         memcpy(data, &pdu->sdata[pdu->offset], len);
108         pdu->offset += len;
109         return size - len;
110 }
111
112 static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
113 {
114         size_t len = MIN(pdu->capacity - pdu->size, size);
115         memcpy(&pdu->sdata[pdu->size], data, len);
116         pdu->size += len;
117         return size - len;
118 }
119
120 static size_t
121 pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
122 {
123         size_t len = MIN(pdu->capacity - pdu->size, size);
124         int err = copy_from_user(&pdu->sdata[pdu->size], udata, len);
125         if (err)
126                 printk(KERN_WARNING "pdu_write_u returning: %d\n", err);
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         ? - 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                                 int16_t len;
196                                 int size;
197
198                                 errcode = p9pdu_readf(pdu, proto_version,
199                                                                 "w", &len);
200                                 if (errcode)
201                                         break;
202
203                                 size = MAX(len, 0);
204
205                                 *sptr = kmalloc(size + 1, GFP_KERNEL);
206                                 if (*sptr == NULL) {
207                                         errcode = -EFAULT;
208                                         break;
209                                 }
210                                 if (pdu_read(pdu, *sptr, size)) {
211                                         errcode = -EFAULT;
212                                         kfree(*sptr);
213                                         *sptr = NULL;
214                                 } else
215                                         (*sptr)[size] = 0;
216                         }
217                         break;
218                 case 'Q':{
219                                 struct p9_qid *qid =
220                                     va_arg(ap, struct p9_qid *);
221
222                                 errcode = p9pdu_readf(pdu, proto_version, "bdq",
223                                                       &qid->type, &qid->version,
224                                                       &qid->path);
225                         }
226                         break;
227                 case 'S':{
228                                 struct p9_wstat *stbuf =
229                                     va_arg(ap, struct p9_wstat *);
230
231                                 memset(stbuf, 0, sizeof(struct p9_wstat));
232                                 stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
233                                                                         -1;
234                                 errcode =
235                                     p9pdu_readf(pdu, proto_version,
236                                                 "wwdQdddqssss?sddd",
237                                                 &stbuf->size, &stbuf->type,
238                                                 &stbuf->dev, &stbuf->qid,
239                                                 &stbuf->mode, &stbuf->atime,
240                                                 &stbuf->mtime, &stbuf->length,
241                                                 &stbuf->name, &stbuf->uid,
242                                                 &stbuf->gid, &stbuf->muid,
243                                                 &stbuf->extension,
244                                                 &stbuf->n_uid, &stbuf->n_gid,
245                                                 &stbuf->n_muid);
246                                 if (errcode)
247                                         p9stat_free(stbuf);
248                         }
249                         break;
250                 case 'D':{
251                                 int32_t *count = va_arg(ap, int32_t *);
252                                 void **data = va_arg(ap, void **);
253
254                                 errcode =
255                                     p9pdu_readf(pdu, proto_version, "d", count);
256                                 if (!errcode) {
257                                         *count =
258                                             MIN(*count,
259                                                 pdu->size - pdu->offset);
260                                         *data = &pdu->sdata[pdu->offset];
261                                 }
262                         }
263                         break;
264                 case 'T':{
265                                 int16_t *nwname = va_arg(ap, int16_t *);
266                                 char ***wnames = va_arg(ap, char ***);
267
268                                 errcode = p9pdu_readf(pdu, proto_version,
269                                                                 "w", nwname);
270                                 if (!errcode) {
271                                         *wnames =
272                                             kmalloc(sizeof(char *) * *nwname,
273                                                     GFP_KERNEL);
274                                         if (!*wnames)
275                                                 errcode = -ENOMEM;
276                                 }
277
278                                 if (!errcode) {
279                                         int i;
280
281                                         for (i = 0; i < *nwname; i++) {
282                                                 errcode =
283                                                     p9pdu_readf(pdu,
284                                                                 proto_version,
285                                                                 "s",
286                                                                 &(*wnames)[i]);
287                                                 if (errcode)
288                                                         break;
289                                         }
290                                 }
291
292                                 if (errcode) {
293                                         if (*wnames) {
294                                                 int i;
295
296                                                 for (i = 0; i < *nwname; i++)
297                                                         kfree((*wnames)[i]);
298                                         }
299                                         kfree(*wnames);
300                                         *wnames = NULL;
301                                 }
302                         }
303                         break;
304                 case 'R':{
305                                 int16_t *nwqid = va_arg(ap, int16_t *);
306                                 struct p9_qid **wqids =
307                                     va_arg(ap, struct p9_qid **);
308
309                                 *wqids = NULL;
310
311                                 errcode =
312                                     p9pdu_readf(pdu, proto_version, "w", nwqid);
313                                 if (!errcode) {
314                                         *wqids =
315                                             kmalloc(*nwqid *
316                                                     sizeof(struct p9_qid),
317                                                     GFP_KERNEL);
318                                         if (*wqids == NULL)
319                                                 errcode = -ENOMEM;
320                                 }
321
322                                 if (!errcode) {
323                                         int i;
324
325                                         for (i = 0; i < *nwqid; i++) {
326                                                 errcode =
327                                                     p9pdu_readf(pdu,
328                                                                 proto_version,
329                                                                 "Q",
330                                                                 &(*wqids)[i]);
331                                                 if (errcode)
332                                                         break;
333                                         }
334                                 }
335
336                                 if (errcode) {
337                                         kfree(*wqids);
338                                         *wqids = NULL;
339                                 }
340                         }
341                         break;
342                 case '?':
343                         if (proto_version != p9_proto_2000u)
344                                 return 0;
345                         break;
346                 default:
347                         BUG();
348                         break;
349                 }
350
351                 if (errcode)
352                         break;
353         }
354
355         return errcode;
356 }
357
358 int
359 p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
360         va_list ap)
361 {
362         const char *ptr;
363         int errcode = 0;
364
365         for (ptr = fmt; *ptr; ptr++) {
366                 switch (*ptr) {
367                 case 'b':{
368                                 int8_t val = va_arg(ap, int);
369                                 if (pdu_write(pdu, &val, sizeof(val)))
370                                         errcode = -EFAULT;
371                         }
372                         break;
373                 case 'w':{
374                                 __le16 val = cpu_to_le16(va_arg(ap, int));
375                                 if (pdu_write(pdu, &val, sizeof(val)))
376                                         errcode = -EFAULT;
377                         }
378                         break;
379                 case 'd':{
380                                 __le32 val = cpu_to_le32(va_arg(ap, int32_t));
381                                 if (pdu_write(pdu, &val, sizeof(val)))
382                                         errcode = -EFAULT;
383                         }
384                         break;
385                 case 'q':{
386                                 __le64 val = cpu_to_le64(va_arg(ap, int64_t));
387                                 if (pdu_write(pdu, &val, sizeof(val)))
388                                         errcode = -EFAULT;
389                         }
390                         break;
391                 case 's':{
392                                 const char *sptr = va_arg(ap, const char *);
393                                 int16_t len = 0;
394                                 if (sptr)
395                                         len = MIN(strlen(sptr), USHORT_MAX);
396
397                                 errcode = p9pdu_writef(pdu, proto_version,
398                                                                 "w", len);
399                                 if (!errcode && pdu_write(pdu, sptr, len))
400                                         errcode = -EFAULT;
401                         }
402                         break;
403                 case 'Q':{
404                                 const struct p9_qid *qid =
405                                     va_arg(ap, const struct p9_qid *);
406                                 errcode =
407                                     p9pdu_writef(pdu, proto_version, "bdq",
408                                                  qid->type, qid->version,
409                                                  qid->path);
410                         } break;
411                 case 'S':{
412                                 const struct p9_wstat *stbuf =
413                                     va_arg(ap, const struct p9_wstat *);
414                                 errcode =
415                                     p9pdu_writef(pdu, proto_version,
416                                                  "wwdQdddqssss?sddd",
417                                                  stbuf->size, stbuf->type,
418                                                  stbuf->dev, &stbuf->qid,
419                                                  stbuf->mode, stbuf->atime,
420                                                  stbuf->mtime, stbuf->length,
421                                                  stbuf->name, stbuf->uid,
422                                                  stbuf->gid, stbuf->muid,
423                                                  stbuf->extension, stbuf->n_uid,
424                                                  stbuf->n_gid, stbuf->n_muid);
425                         } break;
426                 case 'D':{
427                                 int32_t count = va_arg(ap, int32_t);
428                                 const void *data = va_arg(ap, const void *);
429
430                                 errcode = p9pdu_writef(pdu, proto_version, "d",
431                                                                         count);
432                                 if (!errcode && pdu_write(pdu, data, count))
433                                         errcode = -EFAULT;
434                         }
435                         break;
436                 case 'U':{
437                                 int32_t count = va_arg(ap, int32_t);
438                                 const char __user *udata =
439                                                 va_arg(ap, const void __user *);
440                                 errcode = p9pdu_writef(pdu, proto_version, "d",
441                                                                         count);
442                                 if (!errcode && pdu_write_u(pdu, udata, count))
443                                         errcode = -EFAULT;
444                         }
445                         break;
446                 case 'T':{
447                                 int16_t nwname = va_arg(ap, int);
448                                 const char **wnames = va_arg(ap, const char **);
449
450                                 errcode = p9pdu_writef(pdu, proto_version, "w",
451                                                                         nwname);
452                                 if (!errcode) {
453                                         int i;
454
455                                         for (i = 0; i < nwname; i++) {
456                                                 errcode =
457                                                     p9pdu_writef(pdu,
458                                                                 proto_version,
459                                                                  "s",
460                                                                  wnames[i]);
461                                                 if (errcode)
462                                                         break;
463                                         }
464                                 }
465                         }
466                         break;
467                 case 'R':{
468                                 int16_t nwqid = va_arg(ap, int);
469                                 struct p9_qid *wqids =
470                                     va_arg(ap, struct p9_qid *);
471
472                                 errcode = p9pdu_writef(pdu, proto_version, "w",
473                                                                         nwqid);
474                                 if (!errcode) {
475                                         int i;
476
477                                         for (i = 0; i < nwqid; i++) {
478                                                 errcode =
479                                                     p9pdu_writef(pdu,
480                                                                 proto_version,
481                                                                  "Q",
482                                                                  &wqids[i]);
483                                                 if (errcode)
484                                                         break;
485                                         }
486                                 }
487                         }
488                         break;
489                 case '?':
490                         if (proto_version != p9_proto_2000u)
491                                 return 0;
492                         break;
493                 default:
494                         BUG();
495                         break;
496                 }
497
498                 if (errcode)
499                         break;
500         }
501
502         return errcode;
503 }
504
505 int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
506 {
507         va_list ap;
508         int ret;
509
510         va_start(ap, fmt);
511         ret = p9pdu_vreadf(pdu, proto_version, fmt, ap);
512         va_end(ap);
513
514         return ret;
515 }
516
517 static int
518 p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
519 {
520         va_list ap;
521         int ret;
522
523         va_start(ap, fmt);
524         ret = p9pdu_vwritef(pdu, proto_version, fmt, ap);
525         va_end(ap);
526
527         return ret;
528 }
529
530 int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version)
531 {
532         struct p9_fcall fake_pdu;
533         int ret;
534
535         fake_pdu.size = len;
536         fake_pdu.capacity = len;
537         fake_pdu.sdata = buf;
538         fake_pdu.offset = 0;
539
540         ret = p9pdu_readf(&fake_pdu, proto_version, "S", st);
541         if (ret) {
542                 P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
543                 p9pdu_dump(1, &fake_pdu);
544         }
545
546         return ret;
547 }
548 EXPORT_SYMBOL(p9stat_read);
549
550 int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
551 {
552         return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
553 }
554
555 int p9pdu_finalize(struct p9_fcall *pdu)
556 {
557         int size = pdu->size;
558         int err;
559
560         pdu->size = 0;
561         err = p9pdu_writef(pdu, 0, "d", size);
562         pdu->size = size;
563
564 #ifdef CONFIG_NET_9P_DEBUG
565         if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT)
566                 p9pdu_dump(0, pdu);
567 #endif
568
569         P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size,
570                                                         pdu->id, pdu->tag);
571
572         return err;
573 }
574
575 void p9pdu_reset(struct p9_fcall *pdu)
576 {
577         pdu->offset = 0;
578         pdu->size = 0;
579 }