Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/jaswinder...
[linux-2.6.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 optional, 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 optional, const char *fmt, va_list ap)
148 {
149         const char *ptr;
150         int errcode = 0;
151
152         for (ptr = fmt; *ptr; ptr++) {
153                 switch (*ptr) {
154                 case 'b':{
155                                 int8_t *val = va_arg(ap, int8_t *);
156                                 if (pdu_read(pdu, val, sizeof(*val))) {
157                                         errcode = -EFAULT;
158                                         break;
159                                 }
160                         }
161                         break;
162                 case 'w':{
163                                 int16_t *val = va_arg(ap, int16_t *);
164                                 __le16 le_val;
165                                 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
166                                         errcode = -EFAULT;
167                                         break;
168                                 }
169                                 *val = le16_to_cpu(le_val);
170                         }
171                         break;
172                 case 'd':{
173                                 int32_t *val = va_arg(ap, int32_t *);
174                                 __le32 le_val;
175                                 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
176                                         errcode = -EFAULT;
177                                         break;
178                                 }
179                                 *val = le32_to_cpu(le_val);
180                         }
181                         break;
182                 case 'q':{
183                                 int64_t *val = va_arg(ap, int64_t *);
184                                 __le64 le_val;
185                                 if (pdu_read(pdu, &le_val, sizeof(le_val))) {
186                                         errcode = -EFAULT;
187                                         break;
188                                 }
189                                 *val = le64_to_cpu(le_val);
190                         }
191                         break;
192                 case 's':{
193                                 char **sptr = va_arg(ap, char **);
194                                 int16_t len;
195                                 int size;
196
197                                 errcode = p9pdu_readf(pdu, optional, "w", &len);
198                                 if (errcode)
199                                         break;
200
201                                 size = MAX(len, 0);
202
203                                 *sptr = kmalloc(size + 1, GFP_KERNEL);
204                                 if (*sptr == NULL) {
205                                         errcode = -EFAULT;
206                                         break;
207                                 }
208                                 if (pdu_read(pdu, *sptr, size)) {
209                                         errcode = -EFAULT;
210                                         kfree(*sptr);
211                                         *sptr = NULL;
212                                 } else
213                                         (*sptr)[size] = 0;
214                         }
215                         break;
216                 case 'Q':{
217                                 struct p9_qid *qid =
218                                     va_arg(ap, struct p9_qid *);
219
220                                 errcode = p9pdu_readf(pdu, optional, "bdq",
221                                                       &qid->type, &qid->version,
222                                                       &qid->path);
223                         }
224                         break;
225                 case 'S':{
226                                 struct p9_wstat *stbuf =
227                                     va_arg(ap, struct p9_wstat *);
228
229                                 memset(stbuf, 0, sizeof(struct p9_wstat));
230                                 stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
231                                                                         -1;
232                                 errcode =
233                                     p9pdu_readf(pdu, optional,
234                                                 "wwdQdddqssss?sddd",
235                                                 &stbuf->size, &stbuf->type,
236                                                 &stbuf->dev, &stbuf->qid,
237                                                 &stbuf->mode, &stbuf->atime,
238                                                 &stbuf->mtime, &stbuf->length,
239                                                 &stbuf->name, &stbuf->uid,
240                                                 &stbuf->gid, &stbuf->muid,
241                                                 &stbuf->extension,
242                                                 &stbuf->n_uid, &stbuf->n_gid,
243                                                 &stbuf->n_muid);
244                                 if (errcode)
245                                         p9stat_free(stbuf);
246                         }
247                         break;
248                 case 'D':{
249                                 int32_t *count = va_arg(ap, int32_t *);
250                                 void **data = va_arg(ap, void **);
251
252                                 errcode =
253                                     p9pdu_readf(pdu, optional, "d", count);
254                                 if (!errcode) {
255                                         *count =
256                                             MIN(*count,
257                                                 pdu->size - pdu->offset);
258                                         *data = &pdu->sdata[pdu->offset];
259                                 }
260                         }
261                         break;
262                 case 'T':{
263                                 int16_t *nwname = va_arg(ap, int16_t *);
264                                 char ***wnames = va_arg(ap, char ***);
265
266                                 errcode =
267                                     p9pdu_readf(pdu, optional, "w", nwname);
268                                 if (!errcode) {
269                                         *wnames =
270                                             kmalloc(sizeof(char *) * *nwname,
271                                                     GFP_KERNEL);
272                                         if (!*wnames)
273                                                 errcode = -ENOMEM;
274                                 }
275
276                                 if (!errcode) {
277                                         int i;
278
279                                         for (i = 0; i < *nwname; i++) {
280                                                 errcode =
281                                                     p9pdu_readf(pdu, optional,
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, optional, "w", nwqid);
310                                 if (!errcode) {
311                                         *wqids =
312                                             kmalloc(*nwqid *
313                                                     sizeof(struct p9_qid),
314                                                     GFP_KERNEL);
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, optional,
325                                                                 "Q",
326                                                                 &(*wqids)[i]);
327                                                 if (errcode)
328                                                         break;
329                                         }
330                                 }
331
332                                 if (errcode) {
333                                         kfree(*wqids);
334                                         *wqids = NULL;
335                                 }
336                         }
337                         break;
338                 case '?':
339                         if (!optional)
340                                 return 0;
341                         break;
342                 default:
343                         BUG();
344                         break;
345                 }
346
347                 if (errcode)
348                         break;
349         }
350
351         return errcode;
352 }
353
354 int
355 p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
356 {
357         const char *ptr;
358         int errcode = 0;
359
360         for (ptr = fmt; *ptr; ptr++) {
361                 switch (*ptr) {
362                 case 'b':{
363                                 int8_t val = va_arg(ap, int);
364                                 if (pdu_write(pdu, &val, sizeof(val)))
365                                         errcode = -EFAULT;
366                         }
367                         break;
368                 case 'w':{
369                                 __le16 val = cpu_to_le16(va_arg(ap, int));
370                                 if (pdu_write(pdu, &val, sizeof(val)))
371                                         errcode = -EFAULT;
372                         }
373                         break;
374                 case 'd':{
375                                 __le32 val = cpu_to_le32(va_arg(ap, int32_t));
376                                 if (pdu_write(pdu, &val, sizeof(val)))
377                                         errcode = -EFAULT;
378                         }
379                         break;
380                 case 'q':{
381                                 __le64 val = cpu_to_le64(va_arg(ap, int64_t));
382                                 if (pdu_write(pdu, &val, sizeof(val)))
383                                         errcode = -EFAULT;
384                         }
385                         break;
386                 case 's':{
387                                 const char *sptr = va_arg(ap, const char *);
388                                 int16_t len = 0;
389                                 if (sptr)
390                                         len = MIN(strlen(sptr), USHORT_MAX);
391
392                                 errcode = p9pdu_writef(pdu, optional, "w", len);
393                                 if (!errcode && pdu_write(pdu, sptr, len))
394                                         errcode = -EFAULT;
395                         }
396                         break;
397                 case 'Q':{
398                                 const struct p9_qid *qid =
399                                     va_arg(ap, const struct p9_qid *);
400                                 errcode =
401                                     p9pdu_writef(pdu, optional, "bdq",
402                                                  qid->type, qid->version,
403                                                  qid->path);
404                         } break;
405                 case 'S':{
406                                 const struct p9_wstat *stbuf =
407                                     va_arg(ap, const struct p9_wstat *);
408                                 errcode =
409                                     p9pdu_writef(pdu, optional,
410                                                  "wwdQdddqssss?sddd",
411                                                  stbuf->size, stbuf->type,
412                                                  stbuf->dev, &stbuf->qid,
413                                                  stbuf->mode, stbuf->atime,
414                                                  stbuf->mtime, stbuf->length,
415                                                  stbuf->name, stbuf->uid,
416                                                  stbuf->gid, stbuf->muid,
417                                                  stbuf->extension, stbuf->n_uid,
418                                                  stbuf->n_gid, stbuf->n_muid);
419                         } break;
420                 case 'D':{
421                                 int32_t count = va_arg(ap, int32_t);
422                                 const void *data = va_arg(ap, const void *);
423
424                                 errcode =
425                                     p9pdu_writef(pdu, optional, "d", count);
426                                 if (!errcode && pdu_write(pdu, data, count))
427                                         errcode = -EFAULT;
428                         }
429                         break;
430                 case 'U':{
431                                 int32_t count = va_arg(ap, int32_t);
432                                 const char __user *udata =
433                                                 va_arg(ap, const void __user *);
434                                 errcode =
435                                     p9pdu_writef(pdu, optional, "d", count);
436                                 if (!errcode && pdu_write_u(pdu, udata, count))
437                                         errcode = -EFAULT;
438                         }
439                         break;
440                 case 'T':{
441                                 int16_t nwname = va_arg(ap, int);
442                                 const char **wnames = va_arg(ap, const char **);
443
444                                 errcode =
445                                     p9pdu_writef(pdu, optional, "w", nwname);
446                                 if (!errcode) {
447                                         int i;
448
449                                         for (i = 0; i < nwname; i++) {
450                                                 errcode =
451                                                     p9pdu_writef(pdu, optional,
452                                                                  "s",
453                                                                  wnames[i]);
454                                                 if (errcode)
455                                                         break;
456                                         }
457                                 }
458                         }
459                         break;
460                 case 'R':{
461                                 int16_t nwqid = va_arg(ap, int);
462                                 struct p9_qid *wqids =
463                                     va_arg(ap, struct p9_qid *);
464
465                                 errcode =
466                                     p9pdu_writef(pdu, optional, "w", nwqid);
467                                 if (!errcode) {
468                                         int i;
469
470                                         for (i = 0; i < nwqid; i++) {
471                                                 errcode =
472                                                     p9pdu_writef(pdu, optional,
473                                                                  "Q",
474                                                                  &wqids[i]);
475                                                 if (errcode)
476                                                         break;
477                                         }
478                                 }
479                         }
480                         break;
481                 case '?':
482                         if (!optional)
483                                 return 0;
484                         break;
485                 default:
486                         BUG();
487                         break;
488                 }
489
490                 if (errcode)
491                         break;
492         }
493
494         return errcode;
495 }
496
497 int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...)
498 {
499         va_list ap;
500         int ret;
501
502         va_start(ap, fmt);
503         ret = p9pdu_vreadf(pdu, optional, fmt, ap);
504         va_end(ap);
505
506         return ret;
507 }
508
509 static int
510 p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...)
511 {
512         va_list ap;
513         int ret;
514
515         va_start(ap, fmt);
516         ret = p9pdu_vwritef(pdu, optional, fmt, ap);
517         va_end(ap);
518
519         return ret;
520 }
521
522 int p9stat_read(char *buf, int len, struct p9_wstat *st, int dotu)
523 {
524         struct p9_fcall fake_pdu;
525         int ret;
526
527         fake_pdu.size = len;
528         fake_pdu.capacity = len;
529         fake_pdu.sdata = buf;
530         fake_pdu.offset = 0;
531
532         ret = p9pdu_readf(&fake_pdu, dotu, "S", st);
533         if (ret) {
534                 P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
535                 p9pdu_dump(1, &fake_pdu);
536         }
537
538         return ret;
539 }
540 EXPORT_SYMBOL(p9stat_read);
541
542 int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
543 {
544         return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
545 }
546
547 int p9pdu_finalize(struct p9_fcall *pdu)
548 {
549         int size = pdu->size;
550         int err;
551
552         pdu->size = 0;
553         err = p9pdu_writef(pdu, 0, "d", size);
554         pdu->size = size;
555
556 #ifdef CONFIG_NET_9P_DEBUG
557         if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT)
558                 p9pdu_dump(0, pdu);
559 #endif
560
561         P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size,
562                                                         pdu->id, pdu->tag);
563
564         return err;
565 }
566
567 void p9pdu_reset(struct p9_fcall *pdu)
568 {
569         pdu->offset = 0;
570         pdu->size = 0;
571 }