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