43e98220e9a41b2aa17c32219913fcb0f672da65
[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 <net/9p/9p.h>
31 #include <net/9p/client.h>
32 #include "protocol.h"
33
34 #ifndef MIN
35 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
36 #endif
37
38 #ifndef MAX
39 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
40 #endif
41
42 #ifndef offset_of
43 #define offset_of(type, memb) \
44         ((unsigned long)(&((type *)0)->memb))
45 #endif
46 #ifndef container_of
47 #define container_of(obj, type, memb) \
48         ((type *)(((char *)obj) - offset_of(type, memb)))
49 #endif
50
51 static int
52 p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...);
53
54 void p9stat_free(struct p9_wstat *stbuf)
55 {
56         kfree(stbuf->name);
57         kfree(stbuf->uid);
58         kfree(stbuf->gid);
59         kfree(stbuf->muid);
60         kfree(stbuf->extension);
61 }
62 EXPORT_SYMBOL(p9stat_free);
63
64 static size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
65 {
66         size_t len = MIN(pdu->size - pdu->offset, size);
67         memcpy(data, &pdu->sdata[pdu->offset], len);
68         pdu->offset += len;
69         return size - len;
70 }
71
72 static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
73 {
74         size_t len = MIN(pdu->capacity - pdu->size, size);
75         memcpy(&pdu->sdata[pdu->size], data, len);
76         pdu->size += len;
77         return size - len;
78 }
79
80 /*
81         b - int8_t
82         w - int16_t
83         d - int32_t
84         q - int64_t
85         s - string
86         S - stat
87         Q - qid
88         D - data blob (int32_t size followed by void *, results are not freed)
89         T - array of strings (int16_t count, followed by strings)
90         R - array of qids (int16_t count, followed by qids)
91         ? - if optional = 1, continue parsing
92 */
93
94 static int
95 p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
96 {
97         const char *ptr;
98         int errcode = 0;
99
100         for (ptr = fmt; *ptr; ptr++) {
101                 switch (*ptr) {
102                 case 'b':{
103                                 int8_t *val = va_arg(ap, int8_t *);
104                                 if (pdu_read(pdu, val, sizeof(*val))) {
105                                         errcode = -EFAULT;
106                                         break;
107                                 }
108                         }
109                         break;
110                 case 'w':{
111                                 int16_t *val = va_arg(ap, int16_t *);
112                                 if (pdu_read(pdu, val, sizeof(*val))) {
113                                         errcode = -EFAULT;
114                                         break;
115                                 }
116                                 *val = cpu_to_le16(*val);
117                         }
118                         break;
119                 case 'd':{
120                                 int32_t *val = va_arg(ap, int32_t *);
121                                 if (pdu_read(pdu, val, sizeof(*val))) {
122                                         errcode = -EFAULT;
123                                         break;
124                                 }
125                                 *val = cpu_to_le32(*val);
126                         }
127                         break;
128                 case 'q':{
129                                 int64_t *val = va_arg(ap, int64_t *);
130                                 if (pdu_read(pdu, val, sizeof(*val))) {
131                                         errcode = -EFAULT;
132                                         break;
133                                 }
134                                 *val = cpu_to_le64(*val);
135                         }
136                         break;
137                 case 's':{
138                                 char **ptr = va_arg(ap, char **);
139                                 int16_t len;
140                                 int size;
141
142                                 errcode = p9pdu_readf(pdu, optional, "w", &len);
143                                 if (errcode)
144                                         break;
145
146                                 size = MAX(len, 0);
147
148                                 *ptr = kmalloc(size + 1, GFP_KERNEL);
149                                 if (*ptr == NULL) {
150                                         errcode = -EFAULT;
151                                         break;
152                                 }
153                                 if (pdu_read(pdu, *ptr, size)) {
154                                         errcode = -EFAULT;
155                                         kfree(*ptr);
156                                         *ptr = NULL;
157                                 } else
158                                         (*ptr)[size] = 0;
159                         }
160                         break;
161                 case 'Q':{
162                                 struct p9_qid *qid =
163                                     va_arg(ap, struct p9_qid *);
164
165                                 errcode = p9pdu_readf(pdu, optional, "bdq",
166                                                       &qid->type, &qid->version,
167                                                       &qid->path);
168                         }
169                         break;
170                 case 'S':{
171                                 struct p9_wstat *stbuf =
172                                     va_arg(ap, struct p9_wstat *);
173
174                                 stbuf->extension = NULL;
175                                 stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
176                                     -1;
177
178                                 errcode =
179                                     p9pdu_readf(pdu, optional,
180                                                 "wwdQdddqssss?sddd",
181                                                 &stbuf->size, &stbuf->type,
182                                                 &stbuf->dev, &stbuf->qid,
183                                                 &stbuf->mode, &stbuf->atime,
184                                                 &stbuf->mtime, &stbuf->length,
185                                                 &stbuf->name, &stbuf->uid,
186                                                 &stbuf->gid, &stbuf->muid,
187                                                 &stbuf->extension,
188                                                 &stbuf->n_uid, &stbuf->n_gid,
189                                                 &stbuf->n_muid);
190                                 if (errcode)
191                                         p9stat_free(stbuf);
192                         }
193                         break;
194                 case 'D':{
195                                 int32_t *count = va_arg(ap, int32_t *);
196                                 void **data = va_arg(ap, void **);
197
198                                 errcode =
199                                     p9pdu_readf(pdu, optional, "d", count);
200                                 if (!errcode) {
201                                         *count =
202                                             MIN(*count,
203                                                 pdu->size - pdu->offset);
204                                         *data = &pdu->sdata[pdu->offset];
205                                 }
206                         }
207                         break;
208                 case 'T':{
209                                 int16_t *nwname = va_arg(ap, int16_t *);
210                                 char ***wnames = va_arg(ap, char ***);
211
212                                 errcode =
213                                     p9pdu_readf(pdu, optional, "w", nwname);
214                                 if (!errcode) {
215                                         *wnames =
216                                             kmalloc(sizeof(char *) * *nwname,
217                                                     GFP_KERNEL);
218                                         if (!*wnames)
219                                                 errcode = -ENOMEM;
220                                 }
221
222                                 if (!errcode) {
223                                         int i;
224
225                                         for (i = 0; i < *nwname; i++) {
226                                                 errcode =
227                                                     p9pdu_readf(pdu, optional,
228                                                                 "s",
229                                                                 &(*wnames)[i]);
230                                                 if (errcode)
231                                                         break;
232                                         }
233                                 }
234
235                                 if (errcode) {
236                                         if (*wnames) {
237                                                 int i;
238
239                                                 for (i = 0; i < *nwname; i++)
240                                                         kfree((*wnames)[i]);
241                                         }
242                                         kfree(*wnames);
243                                         *wnames = NULL;
244                                 }
245                         }
246                         break;
247                 case 'R':{
248                                 int16_t *nwqid = va_arg(ap, int16_t *);
249                                 struct p9_qid **wqids =
250                                     va_arg(ap, struct p9_qid **);
251
252                                 *wqids = NULL;
253
254                                 errcode =
255                                     p9pdu_readf(pdu, optional, "w", nwqid);
256                                 if (!errcode) {
257                                         *wqids =
258                                             kmalloc(*nwqid *
259                                                     sizeof(struct p9_qid),
260                                                     GFP_KERNEL);
261                                         if (*wqids == NULL)
262                                                 errcode = -ENOMEM;
263                                 }
264
265                                 if (!errcode) {
266                                         int i;
267
268                                         for (i = 0; i < *nwqid; i++) {
269                                                 errcode =
270                                                     p9pdu_readf(pdu, optional,
271                                                                 "Q",
272                                                                 &(*wqids)[i]);
273                                                 if (errcode)
274                                                         break;
275                                         }
276                                 }
277
278                                 if (errcode) {
279                                         kfree(*wqids);
280                                         *wqids = NULL;
281                                 }
282                         }
283                         break;
284                 case '?':
285                         if (!optional)
286                                 return 0;
287                         break;
288                 default:
289                         BUG();
290                         break;
291                 }
292
293                 if (errcode)
294                         break;
295         }
296
297         return errcode;
298 }
299
300 int
301 p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
302 {
303         const char *ptr;
304         int errcode = 0;
305
306         for (ptr = fmt; *ptr; ptr++) {
307                 switch (*ptr) {
308                 case 'b':{
309                                 int8_t val = va_arg(ap, int);
310                                 if (pdu_write(pdu, &val, sizeof(val)))
311                                         errcode = -EFAULT;
312                         }
313                         break;
314                 case 'w':{
315                                 int16_t val = va_arg(ap, int);
316                                 if (pdu_write(pdu, &val, sizeof(val)))
317                                         errcode = -EFAULT;
318                         }
319                         break;
320                 case 'd':{
321                                 int32_t val = va_arg(ap, int32_t);
322                                 if (pdu_write(pdu, &val, sizeof(val)))
323                                         errcode = -EFAULT;
324                         }
325                         break;
326                 case 'q':{
327                                 int64_t val = va_arg(ap, int64_t);
328                                 if (pdu_write(pdu, &val, sizeof(val)))
329                                         errcode = -EFAULT;
330                         }
331                         break;
332                 case 's':{
333                                 const char *ptr = va_arg(ap, const char *);
334                                 int16_t len = 0;
335
336                                 if (ptr)
337                                         len = MIN(strlen(ptr), USHORT_MAX);
338
339                                 errcode = p9pdu_writef(pdu, optional, "w", len);
340                                 if (!errcode && pdu_write(pdu, ptr, len))
341                                         errcode = -EFAULT;
342                         }
343                         break;
344                 case 'Q':{
345                                 const struct p9_qid *qid =
346                                     va_arg(ap, const struct p9_qid *);
347                                 errcode =
348                                     p9pdu_writef(pdu, optional, "bdq",
349                                                  qid->type, qid->version,
350                                                  qid->path);
351                         } break;
352                 case 'S':{
353                                 const struct p9_wstat *stbuf =
354                                     va_arg(ap, const struct p9_wstat *);
355                                 errcode =
356                                     p9pdu_writef(pdu, optional,
357                                                  "wwdQdddqssss?sddd",
358                                                  stbuf->size, stbuf->type,
359                                                  stbuf->dev, stbuf->qid,
360                                                  stbuf->mode, stbuf->atime,
361                                                  stbuf->mtime, stbuf->length,
362                                                  stbuf->name, stbuf->uid,
363                                                  stbuf->gid, stbuf->muid,
364                                                  stbuf->extension, stbuf->n_uid,
365                                                  stbuf->n_gid, stbuf->n_muid);
366                         } break;
367                 case 'D':{
368                                 int32_t count = va_arg(ap, int32_t);
369                                 const void *data = va_arg(ap, const void *);
370
371                                 errcode =
372                                     p9pdu_writef(pdu, optional, "d", count);
373                                 if (!errcode && pdu_write(pdu, data, count))
374                                         errcode = -EFAULT;
375                         }
376                         break;
377                 case 'T':{
378                                 int16_t nwname = va_arg(ap, int);
379                                 const char **wnames = va_arg(ap, const char **);
380
381                                 errcode =
382                                     p9pdu_writef(pdu, optional, "w", nwname);
383                                 if (!errcode) {
384                                         int i;
385
386                                         for (i = 0; i < nwname; i++) {
387                                                 errcode =
388                                                     p9pdu_writef(pdu, optional,
389                                                                  "s",
390                                                                  wnames[i]);
391                                                 if (errcode)
392                                                         break;
393                                         }
394                                 }
395                         }
396                         break;
397                 case 'R':{
398                                 int16_t nwqid = va_arg(ap, int);
399                                 struct p9_qid *wqids =
400                                     va_arg(ap, struct p9_qid *);
401
402                                 errcode =
403                                     p9pdu_writef(pdu, optional, "w", nwqid);
404                                 if (!errcode) {
405                                         int i;
406
407                                         for (i = 0; i < nwqid; i++) {
408                                                 errcode =
409                                                     p9pdu_writef(pdu, optional,
410                                                                  "Q",
411                                                                  &wqids[i]);
412                                                 if (errcode)
413                                                         break;
414                                         }
415                                 }
416                         }
417                         break;
418                 case '?':
419                         if (!optional)
420                                 return 0;
421                         break;
422                 default:
423                         BUG();
424                         break;
425                 }
426
427                 if (errcode)
428                         break;
429         }
430
431         return errcode;
432 }
433
434 int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...)
435 {
436         va_list ap;
437         int ret;
438
439         va_start(ap, fmt);
440         ret = p9pdu_vreadf(pdu, optional, fmt, ap);
441         va_end(ap);
442
443         return ret;
444 }
445
446 static int
447 p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...)
448 {
449         va_list ap;
450         int ret;
451
452         va_start(ap, fmt);
453         ret = p9pdu_vwritef(pdu, optional, fmt, ap);
454         va_end(ap);
455
456         return ret;
457 }