aboutsummaryrefslogtreecommitdiffstats
path: root/net/9p/protocol.c
diff options
context:
space:
mode:
authorEric Van Hensbergen <ericvh@gmail.com>2008-10-13 21:40:27 -0400
committerEric Van Hensbergen <ericvh@gmail.com>2008-10-17 12:04:44 -0400
commitace51c4dd2f968f427c4627023759ae7e3786cba (patch)
tree5d3b82a8a3deb4496a40a2440305c5ace145c5c7 /net/9p/protocol.c
parent6936bf60d2c407449c09e3f28ec0301e1f937106 (diff)
9p: add new protocol support code
This adds a new protocol processing support code based on Anthony Liguori's 9p library code. This code performs protocol marshalling/unmarshalling using printf like strings to represent protocol elements. It is my intent to use them to replace the current functions in conv.c as well as the p9_create_* functions. This should make the client implementation much more clear, and also make it much easier to add new protocol extensions by limiting the number of places in which changes need to be made. Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
Diffstat (limited to 'net/9p/protocol.c')
-rw-r--r--net/9p/protocol.c457
1 files changed, 457 insertions, 0 deletions
diff --git a/net/9p/protocol.c b/net/9p/protocol.c
new file mode 100644
index 000000000000..43e98220e9a4
--- /dev/null
+++ b/net/9p/protocol.c
@@ -0,0 +1,457 @@
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
51static int
52p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...);
53
54void 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}
62EXPORT_SYMBOL(p9stat_free);
63
64static 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
72static 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
94static int
95p9pdu_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
300int
301p9pdu_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
434int 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
446static int
447p9pdu_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}