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/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
  55static int
  56p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
  57
  58#ifdef CONFIG_NET_9P_DEBUG
  59void
  60p9pdu_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
  88void
  89p9pdu_dump(int way, struct p9_fcall *pdu)
  90{
  91}
  92#endif
  93EXPORT_SYMBOL(p9pdu_dump);
  94
  95void 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}
 103EXPORT_SYMBOL(p9stat_free);
 104
 105static 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
 113static 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
 121static size_t
 122pdu_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        ? - if optional = 1, continue parsing
 145*/
 146
 147static int
 148p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
 149        va_list ap)
 150{
 151        const char *ptr;
 152        int errcode = 0;
 153
 154        for (ptr = fmt; *ptr; ptr++) {
 155                switch (*ptr) {
 156                case 'b':{
 157                                int8_t *val = va_arg(ap, int8_t *);
 158                                if (pdu_read(pdu, val, sizeof(*val))) {
 159                                        errcode = -EFAULT;
 160                                        break;
 161                                }
 162                        }
 163                        break;
 164                case 'w':{
 165                                int16_t *val = va_arg(ap, int16_t *);
 166                                __le16 le_val;
 167                                if (pdu_read(pdu, &le_val, sizeof(le_val))) {
 168                                        errcode = -EFAULT;
 169                                        break;
 170                                }
 171                                *val = le16_to_cpu(le_val);
 172                        }
 173                        break;
 174                case 'd':{
 175                                int32_t *val = va_arg(ap, int32_t *);
 176                                __le32 le_val;
 177                                if (pdu_read(pdu, &le_val, sizeof(le_val))) {
 178                                        errcode = -EFAULT;
 179                                        break;
 180                                }
 181                                *val = le32_to_cpu(le_val);
 182                        }
 183                        break;
 184                case 'q':{
 185                                int64_t *val = va_arg(ap, int64_t *);
 186                                __le64 le_val;
 187                                if (pdu_read(pdu, &le_val, sizeof(le_val))) {
 188                                        errcode = -EFAULT;
 189                                        break;
 190                                }
 191                                *val = le64_to_cpu(le_val);
 192                        }
 193                        break;
 194                case 's':{
 195                                char **sptr = va_arg(ap, char **);
 196                                int16_t len;
 197                                int size;
 198
 199                                errcode = p9pdu_readf(pdu, proto_version,
 200                                                                "w", &len);
 201                                if (errcode)
 202                                        break;
 203
 204                                size = MAX(len, 0);
 205
 206                                *sptr = kmalloc(size + 1, GFP_KERNEL);
 207                                if (*sptr == NULL) {
 208                                        errcode = -EFAULT;
 209                                        break;
 210                                }
 211                                if (pdu_read(pdu, *sptr, size)) {
 212                                        errcode = -EFAULT;
 213                                        kfree(*sptr);
 214                                        *sptr = NULL;
 215                                } else
 216                                        (*sptr)[size] = 0;
 217                        }
 218                        break;
 219                case 'Q':{
 220                                struct p9_qid *qid =
 221                                    va_arg(ap, struct p9_qid *);
 222
 223                                errcode = p9pdu_readf(pdu, proto_version, "bdq",
 224                                                      &qid->type, &qid->version,
 225                                                      &qid->path);
 226                        }
 227                        break;
 228                case 'S':{
 229                                struct p9_wstat *stbuf =
 230                                    va_arg(ap, struct p9_wstat *);
 231
 232                                memset(stbuf, 0, sizeof(struct p9_wstat));
 233                                stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
 234                                                                        -1;
 235                                errcode =
 236                                    p9pdu_readf(pdu, proto_version,
 237                                                "wwdQdddqssss?sddd",
 238                                                &stbuf->size, &stbuf->type,
 239                                                &stbuf->dev, &stbuf->qid,
 240                                                &stbuf->mode, &stbuf->atime,
 241                                                &stbuf->mtime, &stbuf->length,
 242                                                &stbuf->name, &stbuf->uid,
 243                                                &stbuf->gid, &stbuf->muid,
 244                                                &stbuf->extension,
 245                                                &stbuf->n_uid, &stbuf->n_gid,
 246                                                &stbuf->n_muid);
 247                                if (errcode)
 248                                        p9stat_free(stbuf);
 249                        }
 250                        break;
 251                case 'D':{
 252                                int32_t *count = va_arg(ap, int32_t *);
 253                                void **data = va_arg(ap, void **);
 254
 255                                errcode =
 256                                    p9pdu_readf(pdu, proto_version, "d", count);
 257                                if (!errcode) {
 258                                        *count =
 259                                            MIN(*count,
 260                                                pdu->size - pdu->offset);
 261                                        *data = &pdu->sdata[pdu->offset];
 262                                }
 263                        }
 264                        break;
 265                case 'T':{
 266                                int16_t *nwname = va_arg(ap, int16_t *);
 267                                char ***wnames = va_arg(ap, char ***);
 268
 269                                errcode = p9pdu_readf(pdu, proto_version,
 270                                                                "w", nwname);
 271                                if (!errcode) {
 272                                        *wnames =
 273                                            kmalloc(sizeof(char *) * *nwname,
 274                                                    GFP_KERNEL);
 275                                        if (!*wnames)
 276                                                errcode = -ENOMEM;
 277                                }
 278
 279                                if (!errcode) {
 280                                        int i;
 281
 282                                        for (i = 0; i < *nwname; i++) {
 283                                                errcode =
 284                                                    p9pdu_readf(pdu,
 285                                                                proto_version,
 286                                                                "s",
 287                                                                &(*wnames)[i]);
 288                                                if (errcode)
 289                                                        break;
 290                                        }
 291                                }
 292
 293                                if (errcode) {
 294                                        if (*wnames) {
 295                                                int i;
 296
 297                                                for (i = 0; i < *nwname; i++)
 298                                                        kfree((*wnames)[i]);
 299                                        }
 300                                        kfree(*wnames);
 301                                        *wnames = NULL;
 302                                }
 303                        }
 304                        break;
 305                case 'R':{
 306                                int16_t *nwqid = va_arg(ap, int16_t *);
 307                                struct p9_qid **wqids =
 308                                    va_arg(ap, struct p9_qid **);
 309
 310                                *wqids = NULL;
 311
 312                                errcode =
 313                                    p9pdu_readf(pdu, proto_version, "w", nwqid);
 314                                if (!errcode) {
 315                                        *wqids =
 316                                            kmalloc(*nwqid *
 317                                                    sizeof(struct p9_qid),
 318                                                    GFP_KERNEL);
 319                                        if (*wqids == NULL)
 320                                                errcode = -ENOMEM;
 321                                }
 322
 323                                if (!errcode) {
 324                                        int i;
 325
 326                                        for (i = 0; i < *nwqid; i++) {
 327                                                errcode =
 328                                                    p9pdu_readf(pdu,
 329                                                                proto_version,
 330                                                                "Q",
 331                                                                &(*wqids)[i]);
 332                                                if (errcode)
 333                                                        break;
 334                                        }
 335                                }
 336
 337                                if (errcode) {
 338                                        kfree(*wqids);
 339                                        *wqids = NULL;
 340                                }
 341                        }
 342                        break;
 343                case '?':
 344                        if ((proto_version != p9_proto_2000u) &&
 345                                (proto_version != p9_proto_2000L))
 346                                return 0;
 347                        break;
 348                default:
 349                        BUG();
 350                        break;
 351                }
 352
 353                if (errcode)
 354                        break;
 355        }
 356
 357        return errcode;
 358}
 359
 360int
 361p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
 362        va_list ap)
 363{
 364        const char *ptr;
 365        int errcode = 0;
 366
 367        for (ptr = fmt; *ptr; ptr++) {
 368                switch (*ptr) {
 369                case 'b':{
 370                                int8_t val = va_arg(ap, int);
 371                                if (pdu_write(pdu, &val, sizeof(val)))
 372                                        errcode = -EFAULT;
 373                        }
 374                        break;
 375                case 'w':{
 376                                __le16 val = cpu_to_le16(va_arg(ap, int));
 377                                if (pdu_write(pdu, &val, sizeof(val)))
 378                                        errcode = -EFAULT;
 379                        }
 380                        break;
 381                case 'd':{
 382                                __le32 val = cpu_to_le32(va_arg(ap, int32_t));
 383                                if (pdu_write(pdu, &val, sizeof(val)))
 384                                        errcode = -EFAULT;
 385                        }
 386                        break;
 387                case 'q':{
 388                                __le64 val = cpu_to_le64(va_arg(ap, int64_t));
 389                                if (pdu_write(pdu, &val, sizeof(val)))
 390                                        errcode = -EFAULT;
 391                        }
 392                        break;
 393                case 's':{
 394                                const char *sptr = va_arg(ap, const char *);
 395                                int16_t len = 0;
 396                                if (sptr)
 397                                        len = MIN(strlen(sptr), USHRT_MAX);
 398
 399                                errcode = p9pdu_writef(pdu, proto_version,
 400                                                                "w", len);
 401                                if (!errcode && pdu_write(pdu, sptr, len))
 402                                        errcode = -EFAULT;
 403                        }
 404                        break;
 405                case 'Q':{
 406                                const struct p9_qid *qid =
 407                                    va_arg(ap, const struct p9_qid *);
 408                                errcode =
 409                                    p9pdu_writef(pdu, proto_version, "bdq",
 410                                                 qid->type, qid->version,
 411                                                 qid->path);
 412                        } break;
 413                case 'S':{
 414                                const struct p9_wstat *stbuf =
 415                                    va_arg(ap, const struct p9_wstat *);
 416                                errcode =
 417                                    p9pdu_writef(pdu, proto_version,
 418                                                 "wwdQdddqssss?sddd",
 419                                                 stbuf->size, stbuf->type,
 420                                                 stbuf->dev, &stbuf->qid,
 421                                                 stbuf->mode, stbuf->atime,
 422                                                 stbuf->mtime, stbuf->length,
 423                                                 stbuf->name, stbuf->uid,
 424                                                 stbuf->gid, stbuf->muid,
 425                                                 stbuf->extension, stbuf->n_uid,
 426                                                 stbuf->n_gid, stbuf->n_muid);
 427                        } break;
 428                case 'D':{
 429                                int32_t count = va_arg(ap, int32_t);
 430                                const void *data = va_arg(ap, const void *);
 431
 432                                errcode = p9pdu_writef(pdu, proto_version, "d",
 433                                                                        count);
 434                                if (!errcode && pdu_write(pdu, data, count))
 435                                        errcode = -EFAULT;
 436                        }
 437                        break;
 438                case 'U':{
 439                                int32_t count = va_arg(ap, int32_t);
 440                                const char __user *udata =
 441                                                va_arg(ap, const void __user *);
 442                                errcode = p9pdu_writef(pdu, proto_version, "d",
 443                                                                        count);
 444                                if (!errcode && pdu_write_u(pdu, udata, count))
 445                                        errcode = -EFAULT;
 446                        }
 447                        break;
 448                case 'T':{
 449                                int16_t nwname = va_arg(ap, int);
 450                                const char **wnames = va_arg(ap, const char **);
 451
 452                                errcode = p9pdu_writef(pdu, proto_version, "w",
 453                                                                        nwname);
 454                                if (!errcode) {
 455                                        int i;
 456
 457                                        for (i = 0; i < nwname; i++) {
 458                                                errcode =
 459                                                    p9pdu_writef(pdu,
 460                                                                proto_version,
 461                                                                 "s",
 462                                                                 wnames[i]);
 463                                                if (errcode)
 464                                                        break;
 465                                        }
 466                                }
 467                        }
 468                        break;
 469                case 'R':{
 470                                int16_t nwqid = va_arg(ap, int);
 471                                struct p9_qid *wqids =
 472                                    va_arg(ap, struct p9_qid *);
 473
 474                                errcode = p9pdu_writef(pdu, proto_version, "w",
 475                                                                        nwqid);
 476                                if (!errcode) {
 477                                        int i;
 478
 479                                        for (i = 0; i < nwqid; i++) {
 480                                                errcode =
 481                                                    p9pdu_writef(pdu,
 482                                                                proto_version,
 483                                                                 "Q",
 484                                                                 &wqids[i]);
 485                                                if (errcode)
 486                                                        break;
 487                                        }
 488                                }
 489                        }
 490                        break;
 491                case '?':
 492                        if ((proto_version != p9_proto_2000u) &&
 493                                (proto_version != p9_proto_2000L))
 494                                return 0;
 495                        break;
 496                default:
 497                        BUG();
 498                        break;
 499                }
 500
 501                if (errcode)
 502                        break;
 503        }
 504
 505        return errcode;
 506}
 507
 508int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
 509{
 510        va_list ap;
 511        int ret;
 512
 513        va_start(ap, fmt);
 514        ret = p9pdu_vreadf(pdu, proto_version, fmt, ap);
 515        va_end(ap);
 516
 517        return ret;
 518}
 519
 520static int
 521p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
 522{
 523        va_list ap;
 524        int ret;
 525
 526        va_start(ap, fmt);
 527        ret = p9pdu_vwritef(pdu, proto_version, fmt, ap);
 528        va_end(ap);
 529
 530        return ret;
 531}
 532
 533int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version)
 534{
 535        struct p9_fcall fake_pdu;
 536        int ret;
 537
 538        fake_pdu.size = len;
 539        fake_pdu.capacity = len;
 540        fake_pdu.sdata = buf;
 541        fake_pdu.offset = 0;
 542
 543        ret = p9pdu_readf(&fake_pdu, proto_version, "S", st);
 544        if (ret) {
 545                P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
 546                p9pdu_dump(1, &fake_pdu);
 547        }
 548
 549        return ret;
 550}
 551EXPORT_SYMBOL(p9stat_read);
 552
 553int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type)
 554{
 555        return p9pdu_writef(pdu, 0, "dbw", 0, type, tag);
 556}
 557
 558int p9pdu_finalize(struct p9_fcall *pdu)
 559{
 560        int size = pdu->size;
 561        int err;
 562
 563        pdu->size = 0;
 564        err = p9pdu_writef(pdu, 0, "d", size);
 565        pdu->size = size;
 566
 567#ifdef CONFIG_NET_9P_DEBUG
 568        if ((p9_debug_level & P9_DEBUG_PKT) == P9_DEBUG_PKT)
 569                p9pdu_dump(0, pdu);
 570#endif
 571
 572        P9_DPRINTK(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", pdu->size,
 573                                                        pdu->id, pdu->tag);
 574
 575        return err;
 576}
 577
 578void p9pdu_reset(struct p9_fcall *pdu)
 579{
 580        pdu->offset = 0;
 581        pdu->size = 0;
 582}
 583