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