linux-old/fs/lockd/xdr.c
<<
>>
Prefs
   1/*
   2 * linux/fs/lockd/xdr.c
   3 *
   4 * XDR support for lockd and the lock client.
   5 *
   6 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
   7 */
   8
   9#include <linux/config.h>
  10#include <linux/types.h>
  11#include <linux/sched.h>
  12#include <linux/utsname.h>
  13#include <linux/nfs.h>
  14
  15#include <linux/sunrpc/xdr.h>
  16#include <linux/sunrpc/clnt.h>
  17#include <linux/sunrpc/svc.h>
  18#include <linux/sunrpc/stats.h>
  19#include <linux/lockd/lockd.h>
  20#include <linux/lockd/sm_inter.h>
  21
  22#define NLMDBG_FACILITY         NLMDBG_XDR
  23
  24
  25static inline loff_t
  26s32_to_loff_t(__s32 offset)
  27{
  28        return (loff_t)offset;
  29}
  30
  31static inline __s32
  32loff_t_to_s32(loff_t offset)
  33{
  34        __s32 res;
  35        if (offset >= NLM_OFFSET_MAX)
  36                res = NLM_OFFSET_MAX;
  37        else if (offset <= -NLM_OFFSET_MAX)
  38                res = -NLM_OFFSET_MAX;
  39        else
  40                res = offset;
  41        return res;
  42}
  43
  44/*
  45 * XDR functions for basic NLM types
  46 */
  47static inline u32 *nlm_decode_cookie(u32 *p, struct nlm_cookie *c)
  48{
  49        unsigned int    len;
  50
  51        len = ntohl(*p++);
  52        
  53        if(len==0)
  54        {
  55                c->len=4;
  56                memset(c->data, 0, 4);  /* hockeypux brain damage */
  57        }
  58        else if(len<=NLM_MAXCOOKIELEN)
  59        {
  60                c->len=len;
  61                memcpy(c->data, p, len);
  62                p+=(len+3)>>2;
  63        }
  64        else 
  65        {
  66                printk(KERN_NOTICE
  67                        "lockd: bad cookie size %d (only cookies under %d bytes are supported.)\n", len, NLM_MAXCOOKIELEN);
  68                return NULL;
  69        }
  70        return p;
  71}
  72
  73static inline u32 *
  74nlm_encode_cookie(u32 *p, struct nlm_cookie *c)
  75{
  76        *p++ = htonl(c->len);
  77        memcpy(p, c->data, c->len);
  78        p+=(c->len+3)>>2;
  79        return p;
  80}
  81
  82static inline u32 *
  83nlm_decode_fh(u32 *p, struct nfs_fh *f)
  84{
  85        unsigned int    len;
  86
  87        if ((len = ntohl(*p++)) != NFS2_FHSIZE) {
  88                printk(KERN_NOTICE
  89                        "lockd: bad fhandle size %d (should be %d)\n",
  90                        len, NFS2_FHSIZE);
  91                return NULL;
  92        }
  93        f->size = NFS2_FHSIZE;
  94        memset(f->data, 0, sizeof(f->data));
  95        memcpy(f->data, p, NFS2_FHSIZE);
  96        return p + XDR_QUADLEN(NFS2_FHSIZE);
  97}
  98
  99static inline u32 *
 100nlm_encode_fh(u32 *p, struct nfs_fh *f)
 101{
 102        *p++ = htonl(NFS2_FHSIZE);
 103        memcpy(p, f->data, NFS2_FHSIZE);
 104        return p + XDR_QUADLEN(NFS2_FHSIZE);
 105}
 106
 107/*
 108 * Encode and decode owner handle
 109 */
 110static inline u32 *
 111nlm_decode_oh(u32 *p, struct xdr_netobj *oh)
 112{
 113        return xdr_decode_netobj(p, oh);
 114}
 115
 116static inline u32 *
 117nlm_encode_oh(u32 *p, struct xdr_netobj *oh)
 118{
 119        return xdr_encode_netobj(p, oh);
 120}
 121
 122static inline u32 *
 123nlm_decode_lock(u32 *p, struct nlm_lock *lock)
 124{
 125        struct file_lock        *fl = &lock->fl;
 126        s32                     start, len, end;
 127
 128        if (!(p = xdr_decode_string_inplace(p, &lock->caller,
 129                                            &lock->len,
 130                                            NLM_MAXSTRLEN))
 131         || !(p = nlm_decode_fh(p, &lock->fh))
 132         || !(p = nlm_decode_oh(p, &lock->oh)))
 133                return NULL;
 134
 135        locks_init_lock(fl);
 136        fl->fl_owner = current->files;
 137        fl->fl_pid   = ntohl(*p++);
 138        fl->fl_flags = FL_POSIX;
 139        fl->fl_type  = F_RDLCK;         /* as good as anything else */
 140        start = ntohl(*p++);
 141        len = ntohl(*p++);
 142        end = start + len - 1;
 143
 144        fl->fl_start = s32_to_loff_t(start);
 145
 146        if (len == 0 || end < 0)
 147                fl->fl_end = OFFSET_MAX;
 148        else
 149                fl->fl_end = s32_to_loff_t(end);
 150        return p;
 151}
 152
 153/*
 154 * Encode a lock as part of an NLM call
 155 */
 156static u32 *
 157nlm_encode_lock(u32 *p, struct nlm_lock *lock)
 158{
 159        struct file_lock        *fl = &lock->fl;
 160        __s32                   start, len;
 161
 162        if (!(p = xdr_encode_string(p, lock->caller))
 163         || !(p = nlm_encode_fh(p, &lock->fh))
 164         || !(p = nlm_encode_oh(p, &lock->oh)))
 165                return NULL;
 166
 167        if (fl->fl_start > NLM_OFFSET_MAX
 168         || (fl->fl_end > NLM_OFFSET_MAX && fl->fl_end != OFFSET_MAX))
 169                return NULL;
 170
 171        start = loff_t_to_s32(fl->fl_start);
 172        if (fl->fl_end == OFFSET_MAX)
 173                len = 0;
 174        else
 175                len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
 176
 177        *p++ = htonl(fl->fl_pid);
 178        *p++ = htonl(start);
 179        *p++ = htonl(len);
 180
 181        return p;
 182}
 183
 184/*
 185 * Encode result of a TEST/TEST_MSG call
 186 */
 187static u32 *
 188nlm_encode_testres(u32 *p, struct nlm_res *resp)
 189{
 190        s32             start, len;
 191
 192        if (!(p = nlm_encode_cookie(p, &resp->cookie)))
 193                return 0;
 194        *p++ = resp->status;
 195
 196        if (resp->status == nlm_lck_denied) {
 197                struct file_lock        *fl = &resp->lock.fl;
 198
 199                *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one;
 200                *p++ = htonl(fl->fl_pid);
 201
 202                /* Encode owner handle. */
 203                if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
 204                        return 0;
 205
 206                start = loff_t_to_s32(fl->fl_start);
 207                if (fl->fl_end == OFFSET_MAX)
 208                        len = 0;
 209                else
 210                        len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
 211
 212                *p++ = htonl(start);
 213                *p++ = htonl(len);
 214        }
 215
 216        return p;
 217}
 218
 219/*
 220 * Check buffer bounds after decoding arguments
 221 */
 222static inline int
 223xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
 224{
 225        struct svc_buf  *buf = &rqstp->rq_argbuf;
 226
 227        return p - buf->base <= buf->buflen;
 228}
 229
 230static inline int
 231xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
 232{
 233        struct svc_buf  *buf = &rqstp->rq_resbuf;
 234
 235        buf->len = p - buf->base;
 236        return (buf->len <= buf->buflen);
 237}
 238
 239/*
 240 * First, the server side XDR functions
 241 */
 242int
 243nlmsvc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
 244{
 245        u32     exclusive;
 246
 247        if (!(p = nlm_decode_cookie(p, &argp->cookie)))
 248                return 0;
 249
 250        exclusive = ntohl(*p++);
 251        if (!(p = nlm_decode_lock(p, &argp->lock)))
 252                return 0;
 253        if (exclusive)
 254                argp->lock.fl.fl_type = F_WRLCK;
 255
 256        return xdr_argsize_check(rqstp, p);
 257}
 258
 259int
 260nlmsvc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
 261{
 262        if (!(p = nlm_encode_testres(p, resp)))
 263                return 0;
 264        return xdr_ressize_check(rqstp, p);
 265}
 266
 267int
 268nlmsvc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
 269{
 270        u32     exclusive;
 271
 272        if (!(p = nlm_decode_cookie(p, &argp->cookie)))
 273                return 0;
 274        argp->block  = ntohl(*p++);
 275        exclusive    = ntohl(*p++);
 276        if (!(p = nlm_decode_lock(p, &argp->lock)))
 277                return 0;
 278        if (exclusive)
 279                argp->lock.fl.fl_type = F_WRLCK;
 280        argp->reclaim = ntohl(*p++);
 281        argp->state   = ntohl(*p++);
 282        argp->monitor = 1;              /* monitor client by default */
 283
 284        return xdr_argsize_check(rqstp, p);
 285}
 286
 287int
 288nlmsvc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
 289{
 290        u32     exclusive;
 291
 292        if (!(p = nlm_decode_cookie(p, &argp->cookie)))
 293                return 0;
 294        argp->block = ntohl(*p++);
 295        exclusive = ntohl(*p++);
 296        if (!(p = nlm_decode_lock(p, &argp->lock)))
 297                return 0;
 298        if (exclusive)
 299                argp->lock.fl.fl_type = F_WRLCK;
 300        return xdr_argsize_check(rqstp, p);
 301}
 302
 303int
 304nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
 305{
 306        if (!(p = nlm_decode_cookie(p, &argp->cookie))
 307         || !(p = nlm_decode_lock(p, &argp->lock)))
 308                return 0;
 309        argp->lock.fl.fl_type = F_UNLCK;
 310        return xdr_argsize_check(rqstp, p);
 311}
 312
 313int
 314nlmsvc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
 315{
 316        struct nlm_lock *lock = &argp->lock;
 317
 318        memset(lock, 0, sizeof(*lock));
 319        locks_init_lock(&lock->fl);
 320        lock->fl.fl_pid = ~(u32) 0;
 321
 322        if (!(p = nlm_decode_cookie(p, &argp->cookie))
 323         || !(p = xdr_decode_string_inplace(p, &lock->caller,
 324                                            &lock->len, NLM_MAXSTRLEN))
 325         || !(p = nlm_decode_fh(p, &lock->fh))
 326         || !(p = nlm_decode_oh(p, &lock->oh)))
 327                return 0;
 328        argp->fsm_mode = ntohl(*p++);
 329        argp->fsm_access = ntohl(*p++);
 330        return xdr_argsize_check(rqstp, p);
 331}
 332
 333int
 334nlmsvc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
 335{
 336        if (!(p = nlm_encode_cookie(p, &resp->cookie)))
 337                return 0;
 338        *p++ = resp->status;
 339        *p++ = xdr_zero;                /* sequence argument */
 340        return xdr_ressize_check(rqstp, p);
 341}
 342
 343int
 344nlmsvc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
 345{
 346        if (!(p = nlm_encode_cookie(p, &resp->cookie)))
 347                return 0;
 348        *p++ = resp->status;
 349        return xdr_ressize_check(rqstp, p);
 350}
 351
 352int
 353nlmsvc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp)
 354{
 355        struct nlm_lock *lock = &argp->lock;
 356
 357        if (!(p = xdr_decode_string_inplace(p, &lock->caller,
 358                                            &lock->len, NLM_MAXSTRLEN)))
 359                return 0;
 360        argp->state = ntohl(*p++);
 361        return xdr_argsize_check(rqstp, p);
 362}
 363
 364int
 365nlmsvc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp)
 366{
 367        if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
 368                return 0;
 369        argp->state = ntohl(*p++);
 370        /* Preserve the address in network byte order */
 371        argp->addr = *p++;
 372        return xdr_argsize_check(rqstp, p);
 373}
 374
 375int
 376nlmsvc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
 377{
 378        if (!(p = nlm_decode_cookie(p, &resp->cookie)))
 379                return 0;
 380        resp->status = ntohl(*p++);
 381        return xdr_argsize_check(rqstp, p);
 382}
 383
 384int
 385nlmsvc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
 386{
 387        return xdr_argsize_check(rqstp, p);
 388}
 389
 390int
 391nlmsvc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
 392{
 393        return xdr_ressize_check(rqstp, p);
 394}
 395
 396/*
 397 * Now, the client side XDR functions
 398 */
 399static int
 400nlmclt_encode_void(struct rpc_rqst *req, u32 *p, void *ptr)
 401{
 402        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 403        return 0;
 404}
 405
 406static int
 407nlmclt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr)
 408{
 409        return 0;
 410}
 411
 412static int
 413nlmclt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
 414{
 415        struct nlm_lock *lock = &argp->lock;
 416
 417        if (!(p = nlm_encode_cookie(p, &argp->cookie)))
 418                return -EIO;
 419        *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
 420        if (!(p = nlm_encode_lock(p, lock)))
 421                return -EIO;
 422        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 423        return 0;
 424}
 425
 426static int
 427nlmclt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
 428{
 429        if (!(p = nlm_decode_cookie(p, &resp->cookie)))
 430                return -EIO;
 431        resp->status = ntohl(*p++);
 432        if (resp->status == NLM_LCK_DENIED) {
 433                struct file_lock        *fl = &resp->lock.fl;
 434                u32                     excl;
 435                s32                     start, len, end;
 436
 437                memset(&resp->lock, 0, sizeof(resp->lock));
 438                locks_init_lock(fl);
 439                excl = ntohl(*p++);
 440                fl->fl_pid = ntohl(*p++);
 441                if (!(p = nlm_decode_oh(p, &resp->lock.oh)))
 442                        return -EIO;
 443
 444                fl->fl_flags = FL_POSIX;
 445                fl->fl_type  = excl? F_WRLCK : F_RDLCK;
 446                start = ntohl(*p++);
 447                len = ntohl(*p++);
 448                end = start + len - 1;
 449
 450                fl->fl_start = s32_to_loff_t(start);
 451                if (len == 0 || end < 0)
 452                        fl->fl_end = OFFSET_MAX;
 453                else
 454                        fl->fl_end = s32_to_loff_t(end);
 455        }
 456        return 0;
 457}
 458
 459
 460static int
 461nlmclt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
 462{
 463        struct nlm_lock *lock = &argp->lock;
 464
 465        if (!(p = nlm_encode_cookie(p, &argp->cookie)))
 466                return -EIO;
 467        *p++ = argp->block? xdr_one : xdr_zero;
 468        *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
 469        if (!(p = nlm_encode_lock(p, lock)))
 470                return -EIO;
 471        *p++ = argp->reclaim? xdr_one : xdr_zero;
 472        *p++ = htonl(argp->state);
 473        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 474        return 0;
 475}
 476
 477static int
 478nlmclt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
 479{
 480        struct nlm_lock *lock = &argp->lock;
 481
 482        if (!(p = nlm_encode_cookie(p, &argp->cookie)))
 483                return -EIO;
 484        *p++ = argp->block? xdr_one : xdr_zero;
 485        *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
 486        if (!(p = nlm_encode_lock(p, lock)))
 487                return -EIO;
 488        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 489        return 0;
 490}
 491
 492static int
 493nlmclt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
 494{
 495        struct nlm_lock *lock = &argp->lock;
 496
 497        if (!(p = nlm_encode_cookie(p, &argp->cookie)))
 498                return -EIO;
 499        if (!(p = nlm_encode_lock(p, lock)))
 500                return -EIO;
 501        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 502        return 0;
 503}
 504
 505static int
 506nlmclt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
 507{
 508        if (!(p = nlm_encode_cookie(p, &resp->cookie)))
 509                return -EIO;
 510        *p++ = resp->status;
 511        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 512        return 0;
 513}
 514
 515static int
 516nlmclt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
 517{
 518        if (!(p = nlm_encode_testres(p, resp)))
 519                return -EIO;
 520        req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 521        return 0;
 522}
 523
 524static int
 525nlmclt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
 526{
 527        if (!(p = nlm_decode_cookie(p, &resp->cookie)))
 528                return -EIO;
 529        resp->status = ntohl(*p++);
 530        return 0;
 531}
 532
 533/*
 534 * Buffer requirements for NLM
 535 */
 536#define NLM_void_sz             0
 537#define NLM_cookie_sz           1+QUADLEN(NLM_MAXCOOKIELEN)
 538#define NLM_caller_sz           1+QUADLEN(sizeof(system_utsname.nodename))
 539#define NLM_netobj_sz           1+QUADLEN(XDR_MAX_NETOBJ)
 540/* #define NLM_owner_sz         1+QUADLEN(NLM_MAXOWNER) */
 541#define NLM_fhandle_sz          1+QUADLEN(NFS2_FHSIZE)
 542#define NLM_lock_sz             3+NLM_caller_sz+NLM_netobj_sz+NLM_fhandle_sz
 543#define NLM_holder_sz           4+NLM_netobj_sz
 544
 545#define NLM_testargs_sz         NLM_cookie_sz+1+NLM_lock_sz
 546#define NLM_lockargs_sz         NLM_cookie_sz+4+NLM_lock_sz
 547#define NLM_cancargs_sz         NLM_cookie_sz+2+NLM_lock_sz
 548#define NLM_unlockargs_sz       NLM_cookie_sz+NLM_lock_sz
 549
 550#define NLM_testres_sz          NLM_cookie_sz+1+NLM_holder_sz
 551#define NLM_res_sz              NLM_cookie_sz+1
 552#define NLM_norep_sz            0
 553
 554#ifndef MAX
 555# define MAX(a, b)              (((a) > (b))? (a) : (b))
 556#endif
 557
 558/*
 559 * For NLM, a void procedure really returns nothing
 560 */
 561#define nlmclt_decode_norep     NULL
 562
 563#define PROC(proc, argtype, restype)    \
 564    { .p_procname  = "nlm_" #proc,                                      \
 565      .p_encode    = (kxdrproc_t) nlmclt_encode_##argtype,              \
 566      .p_decode    = (kxdrproc_t) nlmclt_decode_##restype,              \
 567      .p_bufsiz    = MAX(NLM_##argtype##_sz, NLM_##restype##_sz) << 2   \
 568    }
 569
 570static struct rpc_procinfo      nlm_procedures[] = {
 571    PROC(null,          void,           void),
 572    PROC(test,          testargs,       testres),
 573    PROC(lock,          lockargs,       res),
 574    PROC(canc,          cancargs,       res),
 575    PROC(unlock,        unlockargs,     res),
 576    PROC(granted,       testargs,       res),
 577    PROC(test_msg,      testargs,       norep),
 578    PROC(lock_msg,      lockargs,       norep),
 579    PROC(canc_msg,      cancargs,       norep),
 580    PROC(unlock_msg,    unlockargs,     norep),
 581    PROC(granted_msg,   testargs,       norep),
 582    PROC(test_res,      testres,        norep),
 583    PROC(lock_res,      res,            norep),
 584    PROC(canc_res,      res,            norep),
 585    PROC(unlock_res,    res,            norep),
 586    PROC(granted_res,   res,            norep),
 587    PROC(undef,         void,           void),
 588    PROC(undef,         void,           void),
 589    PROC(undef,         void,           void),
 590    PROC(undef,         void,           void),
 591#ifdef NLMCLNT_SUPPORT_SHARES
 592    PROC(share,         shareargs,      shareres),
 593    PROC(unshare,       shareargs,      shareres),
 594    PROC(nm_lock,       lockargs,       res),
 595    PROC(free_all,      notify,         void),
 596#else
 597    PROC(undef,         void,           void),
 598    PROC(undef,         void,           void),
 599    PROC(undef,         void,           void),
 600    PROC(undef,         void,           void),
 601#endif
 602};
 603
 604static struct rpc_version       nlm_version1 = {
 605        1, 16, nlm_procedures,
 606};
 607
 608static struct rpc_version       nlm_version3 = {
 609        3, 24, nlm_procedures,
 610};
 611
 612#ifdef  CONFIG_LOCKD_V4
 613extern struct rpc_version nlm_version4;
 614#endif
 615
 616static struct rpc_version *     nlm_versions[] = {
 617        NULL,
 618        &nlm_version1,
 619        NULL,
 620        &nlm_version3,
 621#ifdef  CONFIG_LOCKD_V4
 622        &nlm_version4,
 623#endif
 624};
 625
 626static struct rpc_stat          nlm_stats;
 627
 628struct rpc_program              nlm_program = {
 629        "lockd",
 630        NLM_PROGRAM,
 631        sizeof(nlm_versions) / sizeof(nlm_versions[0]),
 632        nlm_versions,
 633        &nlm_stats,
 634};
 635
 636#ifdef LOCKD_DEBUG
 637char *
 638nlm_procname(u32 proc)
 639{
 640        if (proc < sizeof(nlm_procedures)/sizeof(nlm_procedures[0]))
 641                return nlm_procedures[proc].p_procname;
 642        return "unknown";
 643}
 644#endif
 645
 646#ifdef RPC_DEBUG
 647const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
 648{
 649        /*
 650         * We can get away with a static buffer because we're only
 651         * called with BKL held.
 652         */
 653        static char buf[2*NLM_MAXCOOKIELEN+1];
 654        int i;
 655        int len = sizeof(buf);
 656        char *p = buf;
 657
 658        len--;  /* allow for trailing \0 */
 659        if (len < 3)
 660                return "???";
 661        for (i = 0 ; i < cookie->len ; i++) {
 662                if (len < 2) {
 663                        strcpy(p-3, "...");
 664                        break;
 665                }
 666                sprintf(p, "%02x", cookie->data[i]);
 667                p += 2;
 668                len -= 2;
 669        }
 670        *p = '\0';
 671
 672        return buf;
 673}
 674#endif
 675
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.