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 <linux/types.h> 33 #include <net/9p/9p.h> 34 #include <net/9p/client.h> 35 #include "protocol.h" 36 37 #ifndef MIN 38 #define MIN(a, b) (((a) < (b)) ? (a) : (b)) 39 #endif 40 41 #ifndef MAX 42 #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 43 #endif 44 45 #ifndef offset_of 46 #define offset_of(type, memb) \ 47 ((unsigned long)(&((type *)0)->memb)) 48 #endif 49 #ifndef container_of 50 #define container_of(obj, type, memb) \ 51 ((type *)(((char *)obj) - offset_of(type, memb))) 52 #endif 53 54 static int 55 p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...); 56 57 #ifdef CONFIG_NET_9P_DEBUG 58 void 59 p9pdu_dump(int way, struct p9_fcall *pdu) 60 { 61 int i, n; 62 u8 *data = pdu->sdata; 63 int datalen = pdu->size; 64 char buf[255]; 65 int buflen = 255; 66 67 i = n = 0; 68 if (datalen > (buflen-16)) 69 datalen = buflen-16; 70 while (i < datalen) { 71 n += scnprintf(buf + n, buflen - n, "%02x ", data[i]); 72 if (i%4 == 3) 73 n += scnprintf(buf + n, buflen - n, " "); 74 if (i%32 == 31) 75 n += scnprintf(buf + n, buflen - n, "\n"); 76 77 i++; 78 } 79 n += scnprintf(buf + n, buflen - n, "\n"); 80 81 if (way) 82 P9_DPRINTK(P9_DEBUG_PKT, "[[[(%d) %s\n", datalen, buf); 83 else 84 P9_DPRINTK(P9_DEBUG_PKT, "]]](%d) %s\n", datalen, buf); 85 } 86 #else 87 void 88 p9pdu_dump(int way, struct p9_fcall *pdu) 89 { 90 } 91 #endif 92 EXPORT_SYMBOL(p9pdu_dump); 93 94 void p9stat_free(struct p9_wstat *stbuf) 95 { 96 kfree(stbuf->name); 97 kfree(stbuf->uid); 98 kfree(stbuf->gid); 99 kfree(stbuf->muid); 100 kfree(stbuf->extension); 101 } 102 EXPORT_SYMBOL(p9stat_free); 103 104 static size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size) 105 { 106 size_t len = MIN(pdu->size - pdu->offset, size); 107 memcpy(data, &pdu->sdata[pdu->offset], len); 108 pdu->offset += len; 109 return size - len; 110 } 111 112 static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size) 113 { 114 size_t len = MIN(pdu->capacity - pdu->size, size); 115 memcpy(&pdu->sdata[pdu->size], data, len); 116 pdu->size += len; 117 return size - len; 118 } 119 120 static size_t 121 pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size) 122 { 123 size_t len = MIN(pdu->capacity - pdu->size, size); 124 int err = copy_from_user(&pdu->sdata[pdu->size], udata, len); 125 if (err) 126 printk(KERN_WARNING "pdu_write_u returning: %d\n", err); 127 128 pdu->size += len; 129 return size - len; 130 } 131 132 /* 133 b - int8_t 134 w - int16_t 135 d - int32_t 136 q - int64_t 137 s - string 138 S - stat 139 Q - qid 140 D - data blob (int32_t size followed by void *, results are not freed) 141 T - array of strings (int16_t count, followed by strings) 142 R - array of qids (int16_t count, followed by qids) 143 ? - if optional = 1, continue parsing 144 */ 145 146 static int 147 p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) 148 { 149 const char *ptr; 150 int errcode = 0; 151 152 for (ptr = fmt; *ptr; ptr++) { 153 switch (*ptr) { 154 case 'b':{ 155 int8_t *val = va_arg(ap, int8_t *); 156 if (pdu_read(pdu, val, sizeof(*val))) { 157 errcode = -EFAULT; 158 break; 159 } 160 } 161 break; 162 case 'w':{ 163 int16_t *val = va_arg(ap, int16_t *); 164 __le16 le_val; 165 if (pdu_read(pdu, &le_val, sizeof(le_val))) { 166 errcode = -EFAULT; 167 break; 168 } 169 *val = le16_to_cpu(le_val); 170 } 171 break; 172 case 'd':{ 173 int32_t *val = va_arg(ap, int32_t *); 174 __le32 le_val; 175 if (pdu_read(pdu, &le_val, sizeof(le_val))) { 176 errcode = -EFAULT; 177 break; 178 } 179 *val = le32_to_cpu(le_val); 180 } 181 break; 182 case 'q':{ 183 int64_t *val = va_arg(ap, int64_t *); 184 __le64 le_val; 185 if (pdu_read(pdu, &le_val, sizeof(le_val))) { 186 errcode = -EFAULT; 187 break; 188 } 189 *val = le64_to_cpu(le_val); 190 } 191 break; 192 case 's':{ 193 char **sptr = va_arg(ap, char **); 194 int16_t len; 195 int size; 196 197 errcode = p9pdu_readf(pdu, optional, "w", &len); 198 if (errcode) 199 break; 200 201 size = MAX(len, 0); 202 203 *sptr = kmalloc(size + 1, GFP_KERNEL); 204 if (*sptr == NULL) { 205 errcode = -EFAULT; 206 break; 207 } 208 if (pdu_read(pdu, *sptr, size)) { 209 errcode = -EFAULT; 210 kfree(*sptr); 211 *sptr = NULL; 212 } else 213 (*sptr)[size] = 0; 214 } 215 break; 216 case 'Q':{ 217 struct p9_qid *qid = 218 va_arg(ap, struct p9_qid *); 219 220 errcode = p9pdu_readf(pdu, optional, "bdq", 221 &qid->type, &qid->version, 222 &qid->path); 223 } 224 break; 225 case 'S':{ 226 struct p9_wstat *stbuf = 227 va_arg(ap, struct p9_wstat *); 228 229 memset(stbuf, 0, sizeof(struct p9_wstat)); 230 stbuf->n_uid = stbuf->n_gid = stbuf->n_muid = 231 -1; 232 errcode = 233 p9pdu_readf(pdu, optional, 234 "wwdQdddqssss?sddd", 235 &stbuf->size, &stbuf->type, 236 &stbuf->dev, &stbuf->qid, 237 &stbuf->mode, &stbuf->atime, 238 &stbuf->mtime, &stbuf->length, 239 &stbuf->name, &stbuf->uid, 240 &stbuf->gid, &stbuf->muid, 241 &stbuf->extension, 242 &stbuf->n_uid, &stbuf->n_gid, 243 &stbuf->n_muid); 244 if (errcode) 245 p9stat_free(stbuf); 246 } 247 break; 248 case 'D':{ 249 int32_t *count = va_arg(ap, int32_t *); 250 void **data = va_arg(ap, void **); 251 252 errcode = 253 p9pdu_readf(pdu, optional, "d", count); 254 if (!errcode) { 255 *count = 256 MIN(*count, 257 pdu->size - pdu->offset); 258 *data = &pdu->sdata[pdu->offset]; 259 } 260 } 261 break; 262 case 'T':{ 263 int16_t *nwname = va_arg(ap, int16_t *); 264 char ***wnames = va_arg(ap, char ***); 265 266 errcode = 267 p9pdu_readf(pdu, optional, "w", nwname); 268 if (!errcode) { 269 *wnames = 270 kmalloc(sizeof(char *) * *nwname, 271 GFP_KERNEL); 272 if (!*wnames) 273 errcode = -ENOMEM; 274 } 275 276 if (!errcode) { 277 int i; 278 279 for (i = 0; i < *nwname; i++) { 280 errcode = 281 p9pdu_readf(pdu, optional, 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, optional, "w", nwqid); 310 if (!errcode) { 311 *wqids = 312 kmalloc(*nwqid * 313 sizeof(struct p9_qid), 314 GFP_KERNEL); 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, optional, 325 "Q", 326 &(*wqids)[i]); 327 if (errcode) 328 break; 329 } 330 } 331 332 if (errcode) { 333 kfree(*wqids); 334 *wqids = NULL; 335 } 336 } 337 break; 338 case '?': 339 if (!optional) 340 return 0; 341 break; 342 default: 343 BUG(); 344 break; 345 } 346 347 if (errcode) 348 break; 349 } 350 351 return errcode; 352 } 353 354 int 355 p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap) 356 { 357 const char *ptr; 358 int errcode = 0; 359 360 for (ptr = fmt; *ptr; ptr++) { 361 switch (*ptr) { 362 case 'b':{ 363 int8_t val = va_arg(ap, int); 364 if (pdu_write(pdu, &val, sizeof(val))) 365 errcode = -EFAULT; 366 } 367 break; 368 case 'w':{ 369 __le16 val = cpu_to_le16(va_arg(ap, int)); 370 if (pdu_write(pdu, &val, sizeof(val))) 371 errcode = -EFAULT; 372 } 373 break; 374 case 'd':{ 375 __le32 val = cpu_to_le32(va_arg(ap, int32_t)); 376 if (pdu_write(pdu, &val, sizeof(val))) 377 errcode = -EFAULT; 378 } 379 break; 380 case 'q':{ 381 __le64 val = cpu_to_le64(va_arg(ap, int64_t)); 382 if (pdu_write(pdu, &val, sizeof(val))) 383 errcode = -EFAULT; 384 } 385 break; 386 case 's':{ 387 const char *sptr = va_arg(ap, const char *); 388 int16_t len = 0; 389 if (sptr) 390 len = MIN(strlen(sptr), USHORT_MAX); 391 392 errcode = p9pdu_writef(pdu, optional, "w", len); 393 if (!errcode && pdu_write(pdu, sptr, len)) 394 errcode = -EFAULT; 395 } 396 break; 397 case 'Q':{ 398 const struct p9_qid *qid = 399 va_arg(ap, const struct p9_qid *); 400 errcode = 401 p9pdu_writef(pdu, optional, "bdq", 402 qid->type, qid->version, 403 qid->path); 404 } break; 405 case 'S':{ 406 const struct p9_wstat *stbuf = 407 va_arg(ap, const struct p9_wstat *); 408 errcode = 409 p9pdu_writef(pdu, optional, 410 "wwdQdddqssss?sddd", 411 stbuf->size, stbuf->type, 412 stbuf->dev, &stbuf->qid, 413 stbuf->mode, stbuf->atime, 414 stbuf->mtime, stbuf->length, 415 stbuf->name, stbuf->uid, 416 stbuf->gid, stbuf->muid, 417 stbuf->extension, stbuf->n_uid, 418 stbuf->n_gid, stbuf->n_muid); 419 } break; 420 case 'D':{ 421 int32_t count = va_arg(ap, int32_t); 422 const void *data = va_arg(ap, const void *); 423 424 errcode = 425 p9pdu_writef(pdu, optional, "d", count); 426 if (!errcode && pdu_write(pdu, data, count)) 427 errcode = -EFAULT; 428 } 429 break; 430 case 'U':{ 431 int32_t count = va_arg(ap, int32_t); 432 const char __user *udata = 433 va_arg(ap, const void __user *); 434 errcode = 435 p9pdu_writef(pdu, optional, "d", count); 436 if (!errcode && pdu_write_u(pdu, udata, count)) 437 errcode = -EFAULT; 438 } 439 break; 440 case 'T':{ 441 int16_t nwname = va_arg(ap, int); 442 const char **wnames = va_arg(ap, const char **); 443 444 errcode = 445 p9pdu_writef(pdu, optional, "w", nwname); 446 if (!errcode) { 447 int i; 448 449 for (i = 0; i < nwname; i++) { 450 errcode = 451 p9pdu_writef(pdu, optional, 452 "s", 453 wnames[i]); 454 if (errcode) 455 break; 456 } 457 } 458 } 459 break; 460 case 'R':{ 461 int16_t nwqid = va_arg(ap, int); 462 struct p9_qid *wqids = 463 va_arg(ap, struct p9_qid *); 464 465 errcode = 466 p9pdu_writef(pdu, optional, "w", nwqid); 467 if (!errcode) { 468 int i; 469 470 for (i = 0; i < nwqid; i++) { 471 errcode = 472 p9pdu_writef(pdu, optional, 473 "Q", 474 &wqids[i]); 475 if (errcode) 476 break; 477 } 478 } 479 } 480 break; 481 case '?': 482 if (!optional) 483 return 0; 484 break; 485 default: 486 BUG(); 487 break; 488 } 489 490 if (errcode) 491 break; 492 } 493 494 return errcode; 495 } 496 497 int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...) 498 { 499 va_list ap; 500 int ret; 501 502 va_start(ap, fmt); 503 ret = p9pdu_vreadf(pdu, optional, fmt, ap); 504 va_end(ap); 505 506 return ret; 507 } 508 509 static int 510 p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...) 511 { 512 va_list ap; 513 int ret; 514 515 va_start(ap, fmt); 516 ret = p9pdu_vwritef(pdu, optional, fmt, ap); 517 va_end(ap); 518 519 return ret; 520 } 521 522 int p9stat_read(char *buf, int len, struct p9_wstat *st, int dotu) 523 { 524 struct p9_fcall fake_pdu; 525 int ret; 526 527 fake_pdu.size = len; 528 fake_pdu.capacity = len; 529 fake_pdu.sdata = buf; 530 fake_pdu.offset = 0; 531 532 ret = p9pdu_readf(&fake_pdu, dotu, "S", st); 533 if (ret) { 534 P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); 535 p9pdu_dump(1, &fake_pdu); 536 } 537 538 return ret; 539 } 540 EXPORT_SYMBOL(p9stat_read); 541 542 int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type) 543 { 544 return p9pdu_writef(pdu, 0, "dbw", 0, type, tag); 545 } 546 547 int p9pdu_finalize(struct p9_fcall *pdu) 548 { 549 int size = pdu->size; 550 int err; 551 552 pdu->size = 0; 553 err = p9pdu_writef(pdu, 0, "d", size); 554 pdu->size = size; 555 556 #ifdef CONFIG_NET_9P_DEBUG 557 if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT) 558 p9pdu_dump(0, pdu); 559 #endif 560 561 P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size, 562 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