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