xref: /openbmc/linux/net/9p/protocol.c (revision 9ac8d3fb)
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 }
568