linux/net/9p/protocol.c
<<
>>
Prefs
   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
  54static int
  55p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...);
  56
  57#ifdef CONFIG_NET_9P_DEBUG
  58void
  59p9pdu_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
  87void
  88p9pdu_dump(int way, struct p9_fcall *pdu)
  89{
  90}
  91#endif
  92EXPORT_SYMBOL(p9pdu_dump);
  93
  94void 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}
 102EXPORT_SYMBOL(p9stat_free);
 103
 104static 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
 112static 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
 120static size_t
 121pdu_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
 146static int
 147p9pdu_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
 354int
 355p9pdu_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
 497int 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
 509static int
 510p9pdu_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
 522int 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}
 540EXPORT_SYMBOL(p9stat_read);
 541
 542int 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
 547int 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
 567void p9pdu_reset(struct p9_fcall *pdu)
 568{
 569        pdu->offset = 0;
 570        pdu->size = 0;
 571}
 572