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