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