xref: /openbmc/linux/net/9p/protocol.c (revision 3996eabb)
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/kernel.h>
31 #include <linux/uaccess.h>
32 #include <linux/slab.h>
33 #include <linux/sched.h>
34 #include <linux/stddef.h>
35 #include <linux/types.h>
36 #include <net/9p/9p.h>
37 #include <net/9p/client.h>
38 #include "protocol.h"
39 
40 static int
41 p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
42 
43 #ifdef CONFIG_NET_9P_DEBUG
44 void
45 p9pdu_dump(int way, struct p9_fcall *pdu)
46 {
47 	int i, n;
48 	u8 *data = pdu->sdata;
49 	int datalen = pdu->size;
50 	char buf[255];
51 	int buflen = 255;
52 
53 	i = n = 0;
54 	if (datalen > (buflen-16))
55 		datalen = buflen-16;
56 	while (i < datalen) {
57 		n += scnprintf(buf + n, buflen - n, "%02x ", data[i]);
58 		if (i%4 == 3)
59 			n += scnprintf(buf + n, buflen - n, " ");
60 		if (i%32 == 31)
61 			n += scnprintf(buf + n, buflen - n, "\n");
62 
63 		i++;
64 	}
65 	n += scnprintf(buf + n, buflen - n, "\n");
66 
67 	if (way)
68 		P9_DPRINTK(P9_DEBUG_PKT, "[[[(%d) %s\n", datalen, buf);
69 	else
70 		P9_DPRINTK(P9_DEBUG_PKT, "]]](%d) %s\n", datalen, buf);
71 }
72 #else
73 void
74 p9pdu_dump(int way, struct p9_fcall *pdu)
75 {
76 }
77 #endif
78 EXPORT_SYMBOL(p9pdu_dump);
79 
80 void p9stat_free(struct p9_wstat *stbuf)
81 {
82 	kfree(stbuf->name);
83 	kfree(stbuf->uid);
84 	kfree(stbuf->gid);
85 	kfree(stbuf->muid);
86 	kfree(stbuf->extension);
87 }
88 EXPORT_SYMBOL(p9stat_free);
89 
90 static size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
91 {
92 	size_t len = min(pdu->size - pdu->offset, size);
93 	memcpy(data, &pdu->sdata[pdu->offset], len);
94 	pdu->offset += len;
95 	return size - len;
96 }
97 
98 static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
99 {
100 	size_t len = min(pdu->capacity - pdu->size, size);
101 	memcpy(&pdu->sdata[pdu->size], data, len);
102 	pdu->size += len;
103 	return size - len;
104 }
105 
106 static size_t
107 pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
108 {
109 	size_t len = min(pdu->capacity - pdu->size, size);
110 	if (copy_from_user(&pdu->sdata[pdu->size], udata, len))
111 		len = 0;
112 
113 	pdu->size += len;
114 	return size - len;
115 }
116 
117 /*
118 	b - int8_t
119 	w - int16_t
120 	d - int32_t
121 	q - int64_t
122 	s - string
123 	S - stat
124 	Q - qid
125 	D - data blob (int32_t size followed by void *, results are not freed)
126 	T - array of strings (int16_t count, followed by strings)
127 	R - array of qids (int16_t count, followed by qids)
128 	A - stat for 9p2000.L (p9_stat_dotl)
129 	? - if optional = 1, continue parsing
130 */
131 
132 static int
133 p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
134 	va_list ap)
135 {
136 	const char *ptr;
137 	int errcode = 0;
138 
139 	for (ptr = fmt; *ptr; ptr++) {
140 		switch (*ptr) {
141 		case 'b':{
142 				int8_t *val = va_arg(ap, int8_t *);
143 				if (pdu_read(pdu, val, sizeof(*val))) {
144 					errcode = -EFAULT;
145 					break;
146 				}
147 			}
148 			break;
149 		case 'w':{
150 				int16_t *val = va_arg(ap, int16_t *);
151 				__le16 le_val;
152 				if (pdu_read(pdu, &le_val, sizeof(le_val))) {
153 					errcode = -EFAULT;
154 					break;
155 				}
156 				*val = le16_to_cpu(le_val);
157 			}
158 			break;
159 		case 'd':{
160 				int32_t *val = va_arg(ap, int32_t *);
161 				__le32 le_val;
162 				if (pdu_read(pdu, &le_val, sizeof(le_val))) {
163 					errcode = -EFAULT;
164 					break;
165 				}
166 				*val = le32_to_cpu(le_val);
167 			}
168 			break;
169 		case 'q':{
170 				int64_t *val = va_arg(ap, int64_t *);
171 				__le64 le_val;
172 				if (pdu_read(pdu, &le_val, sizeof(le_val))) {
173 					errcode = -EFAULT;
174 					break;
175 				}
176 				*val = le64_to_cpu(le_val);
177 			}
178 			break;
179 		case 's':{
180 				char **sptr = va_arg(ap, char **);
181 				uint16_t len;
182 
183 				errcode = p9pdu_readf(pdu, proto_version,
184 								"w", &len);
185 				if (errcode)
186 					break;
187 
188 				*sptr = kmalloc(len + 1, GFP_KERNEL);
189 				if (*sptr == NULL) {
190 					errcode = -EFAULT;
191 					break;
192 				}
193 				if (pdu_read(pdu, *sptr, len)) {
194 					errcode = -EFAULT;
195 					kfree(*sptr);
196 					*sptr = NULL;
197 				} else
198 					(*sptr)[len] = 0;
199 			}
200 			break;
201 		case 'Q':{
202 				struct p9_qid *qid =
203 				    va_arg(ap, struct p9_qid *);
204 
205 				errcode = p9pdu_readf(pdu, proto_version, "bdq",
206 						      &qid->type, &qid->version,
207 						      &qid->path);
208 			}
209 			break;
210 		case 'S':{
211 				struct p9_wstat *stbuf =
212 				    va_arg(ap, struct p9_wstat *);
213 
214 				memset(stbuf, 0, sizeof(struct p9_wstat));
215 				stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
216 									-1;
217 				errcode =
218 				    p9pdu_readf(pdu, proto_version,
219 						"wwdQdddqssss?sddd",
220 						&stbuf->size, &stbuf->type,
221 						&stbuf->dev, &stbuf->qid,
222 						&stbuf->mode, &stbuf->atime,
223 						&stbuf->mtime, &stbuf->length,
224 						&stbuf->name, &stbuf->uid,
225 						&stbuf->gid, &stbuf->muid,
226 						&stbuf->extension,
227 						&stbuf->n_uid, &stbuf->n_gid,
228 						&stbuf->n_muid);
229 				if (errcode)
230 					p9stat_free(stbuf);
231 			}
232 			break;
233 		case 'D':{
234 				uint32_t *count = va_arg(ap, uint32_t *);
235 				void **data = va_arg(ap, void **);
236 
237 				errcode =
238 				    p9pdu_readf(pdu, proto_version, "d", count);
239 				if (!errcode) {
240 					*count =
241 					    min_t(uint32_t, *count,
242 						  pdu->size - pdu->offset);
243 					*data = &pdu->sdata[pdu->offset];
244 				}
245 			}
246 			break;
247 		case 'T':{
248 				int16_t *nwname = va_arg(ap, int16_t *);
249 				char ***wnames = va_arg(ap, char ***);
250 
251 				errcode = p9pdu_readf(pdu, proto_version,
252 								"w", nwname);
253 				if (!errcode) {
254 					*wnames =
255 					    kmalloc(sizeof(char *) * *nwname,
256 						    GFP_KERNEL);
257 					if (!*wnames)
258 						errcode = -ENOMEM;
259 				}
260 
261 				if (!errcode) {
262 					int i;
263 
264 					for (i = 0; i < *nwname; i++) {
265 						errcode =
266 						    p9pdu_readf(pdu,
267 								proto_version,
268 								"s",
269 								&(*wnames)[i]);
270 						if (errcode)
271 							break;
272 					}
273 				}
274 
275 				if (errcode) {
276 					if (*wnames) {
277 						int i;
278 
279 						for (i = 0; i < *nwname; i++)
280 							kfree((*wnames)[i]);
281 					}
282 					kfree(*wnames);
283 					*wnames = NULL;
284 				}
285 			}
286 			break;
287 		case 'R':{
288 				int16_t *nwqid = va_arg(ap, int16_t *);
289 				struct p9_qid **wqids =
290 				    va_arg(ap, struct p9_qid **);
291 
292 				*wqids = NULL;
293 
294 				errcode =
295 				    p9pdu_readf(pdu, proto_version, "w", nwqid);
296 				if (!errcode) {
297 					*wqids =
298 					    kmalloc(*nwqid *
299 						    sizeof(struct p9_qid),
300 						    GFP_KERNEL);
301 					if (*wqids == NULL)
302 						errcode = -ENOMEM;
303 				}
304 
305 				if (!errcode) {
306 					int i;
307 
308 					for (i = 0; i < *nwqid; i++) {
309 						errcode =
310 						    p9pdu_readf(pdu,
311 								proto_version,
312 								"Q",
313 								&(*wqids)[i]);
314 						if (errcode)
315 							break;
316 					}
317 				}
318 
319 				if (errcode) {
320 					kfree(*wqids);
321 					*wqids = NULL;
322 				}
323 			}
324 			break;
325 		case 'A': {
326 				struct p9_stat_dotl *stbuf =
327 				    va_arg(ap, struct p9_stat_dotl *);
328 
329 				memset(stbuf, 0, sizeof(struct p9_stat_dotl));
330 				errcode =
331 				    p9pdu_readf(pdu, proto_version,
332 					"qQdddqqqqqqqqqqqqqqq",
333 					&stbuf->st_result_mask,
334 					&stbuf->qid,
335 					&stbuf->st_mode,
336 					&stbuf->st_uid, &stbuf->st_gid,
337 					&stbuf->st_nlink,
338 					&stbuf->st_rdev, &stbuf->st_size,
339 					&stbuf->st_blksize, &stbuf->st_blocks,
340 					&stbuf->st_atime_sec,
341 					&stbuf->st_atime_nsec,
342 					&stbuf->st_mtime_sec,
343 					&stbuf->st_mtime_nsec,
344 					&stbuf->st_ctime_sec,
345 					&stbuf->st_ctime_nsec,
346 					&stbuf->st_btime_sec,
347 					&stbuf->st_btime_nsec,
348 					&stbuf->st_gen,
349 					&stbuf->st_data_version);
350 			}
351 			break;
352 		case '?':
353 			if ((proto_version != p9_proto_2000u) &&
354 				(proto_version != p9_proto_2000L))
355 				return 0;
356 			break;
357 		default:
358 			BUG();
359 			break;
360 		}
361 
362 		if (errcode)
363 			break;
364 	}
365 
366 	return errcode;
367 }
368 
369 int
370 p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
371 	va_list ap)
372 {
373 	const char *ptr;
374 	int errcode = 0;
375 
376 	for (ptr = fmt; *ptr; ptr++) {
377 		switch (*ptr) {
378 		case 'b':{
379 				int8_t val = va_arg(ap, int);
380 				if (pdu_write(pdu, &val, sizeof(val)))
381 					errcode = -EFAULT;
382 			}
383 			break;
384 		case 'w':{
385 				__le16 val = cpu_to_le16(va_arg(ap, int));
386 				if (pdu_write(pdu, &val, sizeof(val)))
387 					errcode = -EFAULT;
388 			}
389 			break;
390 		case 'd':{
391 				__le32 val = cpu_to_le32(va_arg(ap, int32_t));
392 				if (pdu_write(pdu, &val, sizeof(val)))
393 					errcode = -EFAULT;
394 			}
395 			break;
396 		case 'q':{
397 				__le64 val = cpu_to_le64(va_arg(ap, int64_t));
398 				if (pdu_write(pdu, &val, sizeof(val)))
399 					errcode = -EFAULT;
400 			}
401 			break;
402 		case 's':{
403 				const char *sptr = va_arg(ap, const char *);
404 				uint16_t len = 0;
405 				if (sptr)
406 					len = min_t(uint16_t, strlen(sptr),
407 								USHRT_MAX);
408 
409 				errcode = p9pdu_writef(pdu, proto_version,
410 								"w", len);
411 				if (!errcode && pdu_write(pdu, sptr, len))
412 					errcode = -EFAULT;
413 			}
414 			break;
415 		case 'Q':{
416 				const struct p9_qid *qid =
417 				    va_arg(ap, const struct p9_qid *);
418 				errcode =
419 				    p9pdu_writef(pdu, proto_version, "bdq",
420 						 qid->type, qid->version,
421 						 qid->path);
422 			} break;
423 		case 'S':{
424 				const struct p9_wstat *stbuf =
425 				    va_arg(ap, const struct p9_wstat *);
426 				errcode =
427 				    p9pdu_writef(pdu, proto_version,
428 						 "wwdQdddqssss?sddd",
429 						 stbuf->size, stbuf->type,
430 						 stbuf->dev, &stbuf->qid,
431 						 stbuf->mode, stbuf->atime,
432 						 stbuf->mtime, stbuf->length,
433 						 stbuf->name, stbuf->uid,
434 						 stbuf->gid, stbuf->muid,
435 						 stbuf->extension, stbuf->n_uid,
436 						 stbuf->n_gid, stbuf->n_muid);
437 			} break;
438 		case 'D':{
439 				uint32_t count = va_arg(ap, uint32_t);
440 				const void *data = va_arg(ap, const void *);
441 
442 				errcode = p9pdu_writef(pdu, proto_version, "d",
443 									count);
444 				if (!errcode && pdu_write(pdu, data, count))
445 					errcode = -EFAULT;
446 			}
447 			break;
448 		case 'U':{
449 				int32_t count = va_arg(ap, int32_t);
450 				const char __user *udata =
451 						va_arg(ap, const void __user *);
452 				errcode = p9pdu_writef(pdu, proto_version, "d",
453 									count);
454 				if (!errcode && pdu_write_u(pdu, udata, count))
455 					errcode = -EFAULT;
456 			}
457 			break;
458 		case 'T':{
459 				int16_t nwname = va_arg(ap, int);
460 				const char **wnames = va_arg(ap, const char **);
461 
462 				errcode = p9pdu_writef(pdu, proto_version, "w",
463 									nwname);
464 				if (!errcode) {
465 					int i;
466 
467 					for (i = 0; i < nwname; i++) {
468 						errcode =
469 						    p9pdu_writef(pdu,
470 								proto_version,
471 								 "s",
472 								 wnames[i]);
473 						if (errcode)
474 							break;
475 					}
476 				}
477 			}
478 			break;
479 		case 'R':{
480 				int16_t nwqid = va_arg(ap, int);
481 				struct p9_qid *wqids =
482 				    va_arg(ap, struct p9_qid *);
483 
484 				errcode = p9pdu_writef(pdu, proto_version, "w",
485 									nwqid);
486 				if (!errcode) {
487 					int i;
488 
489 					for (i = 0; i < nwqid; i++) {
490 						errcode =
491 						    p9pdu_writef(pdu,
492 								proto_version,
493 								 "Q",
494 								 &wqids[i]);
495 						if (errcode)
496 							break;
497 					}
498 				}
499 			}
500 			break;
501 		case 'I':{
502 				struct p9_iattr_dotl *p9attr = va_arg(ap,
503 							struct p9_iattr_dotl *);
504 
505 				errcode = p9pdu_writef(pdu, proto_version,
506 							"ddddqqqqq",
507 							p9attr->valid,
508 							p9attr->mode,
509 							p9attr->uid,
510 							p9attr->gid,
511 							p9attr->size,
512 							p9attr->atime_sec,
513 							p9attr->atime_nsec,
514 							p9attr->mtime_sec,
515 							p9attr->mtime_nsec);
516 			}
517 			break;
518 		case '?':
519 			if ((proto_version != p9_proto_2000u) &&
520 				(proto_version != p9_proto_2000L))
521 				return 0;
522 			break;
523 		default:
524 			BUG();
525 			break;
526 		}
527 
528 		if (errcode)
529 			break;
530 	}
531 
532 	return errcode;
533 }
534 
535 int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
536 {
537 	va_list ap;
538 	int ret;
539 
540 	va_start(ap, fmt);
541 	ret = p9pdu_vreadf(pdu, proto_version, fmt, ap);
542 	va_end(ap);
543 
544 	return ret;
545 }
546 
547 static int
548 p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
549 {
550 	va_list ap;
551 	int ret;
552 
553 	va_start(ap, fmt);
554 	ret = p9pdu_vwritef(pdu, proto_version, fmt, ap);
555 	va_end(ap);
556 
557 	return ret;
558 }
559 
560 int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version)
561 {
562 	struct p9_fcall fake_pdu;
563 	int ret;
564 
565 	fake_pdu.size = len;
566 	fake_pdu.capacity = len;
567 	fake_pdu.sdata = buf;
568 	fake_pdu.offset = 0;
569 
570 	ret = p9pdu_readf(&fake_pdu, proto_version, "S", st);
571 	if (ret) {
572 		P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
573 		p9pdu_dump(1, &fake_pdu);
574 	}
575 
576 	return ret;
577 }
578 EXPORT_SYMBOL(p9stat_read);
579 
580 int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
581 {
582 	return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
583 }
584 
585 int p9pdu_finalize(struct p9_fcall *pdu)
586 {
587 	int size = pdu->size;
588 	int err;
589 
590 	pdu->size = 0;
591 	err = p9pdu_writef(pdu, 0, "d", size);
592 	pdu->size = size;
593 
594 #ifdef CONFIG_NET_9P_DEBUG
595 	if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT)
596 		p9pdu_dump(0, pdu);
597 #endif
598 
599 	P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size,
600 							pdu->id, pdu->tag);
601 
602 	return err;
603 }
604 
605 void p9pdu_reset(struct p9_fcall *pdu)
606 {
607 	pdu->offset = 0;
608 	pdu->size = 0;
609 }
610 
611 int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
612 						int proto_version)
613 {
614 	struct p9_fcall fake_pdu;
615 	int ret;
616 	char *nameptr;
617 
618 	fake_pdu.size = len;
619 	fake_pdu.capacity = len;
620 	fake_pdu.sdata = buf;
621 	fake_pdu.offset = 0;
622 
623 	ret = p9pdu_readf(&fake_pdu, proto_version, "Qqbs", &dirent->qid,
624 			&dirent->d_off, &dirent->d_type, &nameptr);
625 	if (ret) {
626 		P9_DPRINTK(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
627 		p9pdu_dump(1, &fake_pdu);
628 		goto out;
629 	}
630 
631 	strcpy(dirent->d_name, nameptr);
632 
633 out:
634 	return fake_pdu.offset;
635 }
636 EXPORT_SYMBOL(p9dirent_read);
637