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