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/types.h> 10#include <linux/sched.h> 11#include <linux/utsname.h> 12#include <linux/nfs.h> 13 14#include <linux/sunrpc/xdr.h> 15#include <linux/sunrpc/clnt.h> 16#include <linux/sunrpc/svc.h> 17#include <linux/sunrpc/stats.h> 18#include <linux/lockd/lockd.h> 19#include <linux/lockd/sm_inter.h> 20 21#define NLMDBG_FACILITY NLMDBG_XDR 22 23 24static inline loff_t 25s32_to_loff_t(__s32 offset) 26{ 27 return (loff_t)offset; 28} 29 30static inline __s32 31loff_t_to_s32(loff_t offset) 32{ 33 __s32 res; 34 if (offset >= NLM_OFFSET_MAX) 35 res = NLM_OFFSET_MAX; 36 else if (offset <= -NLM_OFFSET_MAX) 37 res = -NLM_OFFSET_MAX; 38 else 39 res = offset; 40 return res; 41} 42 43/* 44 * XDR functions for basic NLM types 45 */ 46static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c) 47{ 48 unsigned int len; 49 50 len = ntohl(*p++); 51 52 if(len==0) 53 { 54 c->len=4; 55 memset(c->data, 0, 4); /* hockeypux brain damage */ 56 } 57 else if(len<=NLM_MAXCOOKIELEN) 58 { 59 c->len=len; 60 memcpy(c->data, p, len); 61 p+=XDR_QUADLEN(len); 62 } 63 else 64 { 65 printk(KERN_NOTICE 66 "lockd: bad cookie size %d (only cookies under %d bytes are supported.)\n", len, NLM_MAXCOOKIELEN); 67 return NULL; 68 } 69 return p; 70} 71 72static inline __be32 * 73nlm_encode_cookie(__be32 *p, struct nlm_cookie *c) 74{ 75 *p++ = htonl(c->len); 76 memcpy(p, c->data, c->len); 77 p+=XDR_QUADLEN(c->len); 78 return p; 79} 80 81static __be32 * 82nlm_decode_fh(__be32 *p, struct nfs_fh *f) 83{ 84 unsigned int len; 85 86 if ((len = ntohl(*p++)) != NFS2_FHSIZE) { 87 printk(KERN_NOTICE 88 "lockd: bad fhandle size %d (should be %d)\n", 89 len, NFS2_FHSIZE); 90 return NULL; 91 } 92 f->size = NFS2_FHSIZE; 93 memset(f->data, 0, sizeof(f->data)); 94 memcpy(f->data, p, NFS2_FHSIZE); 95 return p + XDR_QUADLEN(NFS2_FHSIZE); 96} 97 98static inline __be32 * 99nlm_encode_fh(__be32 *p, struct nfs_fh *f) 100{ 101 *p++ = htonl(NFS2_FHSIZE); 102 memcpy(p, f->data, NFS2_FHSIZE); 103 return p + XDR_QUADLEN(NFS2_FHSIZE); 104} 105 106/* 107 * Encode and decode owner handle 108 */ 109static inline __be32 * 110nlm_decode_oh(__be32 *p, struct xdr_netobj *oh) 111{ 112 return xdr_decode_netobj(p, oh); 113} 114 115static inline __be32 * 116nlm_encode_oh(__be32 *p, struct xdr_netobj *oh) 117{ 118 return xdr_encode_netobj(p, oh); 119} 120 121static __be32 * 122nlm_decode_lock(__be32 *p, struct nlm_lock *lock) 123{ 124 struct file_lock *fl = &lock->fl; 125 s32 start, len, end; 126 127 if (!(p = xdr_decode_string_inplace(p, &lock->caller, 128 &lock->len, 129 NLM_MAXSTRLEN)) 130 || !(p = nlm_decode_fh(p, &lock->fh)) 131 || !(p = nlm_decode_oh(p, &lock->oh))) 132 return NULL; 133 lock->svid = ntohl(*p++); 134 135 locks_init_lock(fl); 136 fl->fl_owner = current->files; 137 fl->fl_pid = (pid_t)lock->svid; 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 __be32 * 157nlm_encode_lock(__be32 *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(lock->svid); 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 __be32 * 188nlm_encode_testres(__be32 *p, struct nlm_res *resp) 189{ 190 s32 start, len; 191 192 if (!(p = nlm_encode_cookie(p, &resp->cookie))) 193 return NULL; 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(resp->lock.svid); 201 202 /* Encode owner handle. */ 203 if (!(p = xdr_encode_netobj(p, &resp->lock.oh))) 204 return NULL; 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/* 221 * First, the server side XDR functions 222 */ 223int 224nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) 225{ 226 u32 exclusive; 227 228 if (!(p = nlm_decode_cookie(p, &argp->cookie))) 229 return 0; 230 231 exclusive = ntohl(*p++); 232 if (!(p = nlm_decode_lock(p, &argp->lock))) 233 return 0; 234 if (exclusive) 235 argp->lock.fl.fl_type = F_WRLCK; 236 237 return xdr_argsize_check(rqstp, p); 238} 239 240int 241nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) 242{ 243 if (!(p = nlm_encode_testres(p, resp))) 244 return 0; 245 return xdr_ressize_check(rqstp, p); 246} 247 248int 249nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) 250{ 251 u32 exclusive; 252 253 if (!(p = nlm_decode_cookie(p, &argp->cookie))) 254 return 0; 255 argp->block = ntohl(*p++); 256 exclusive = ntohl(*p++); 257 if (!(p = nlm_decode_lock(p, &argp->lock))) 258 return 0; 259 if (exclusive) 260 argp->lock.fl.fl_type = F_WRLCK; 261 argp->reclaim = ntohl(*p++); 262 argp->state = ntohl(*p++); 263 argp->monitor = 1; /* monitor client by default */ 264 265 return xdr_argsize_check(rqstp, p); 266} 267 268int 269nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) 270{ 271 u32 exclusive; 272 273 if (!(p = nlm_decode_cookie(p, &argp->cookie))) 274 return 0; 275 argp->block = ntohl(*p++); 276 exclusive = ntohl(*p++); 277 if (!(p = nlm_decode_lock(p, &argp->lock))) 278 return 0; 279 if (exclusive) 280 argp->lock.fl.fl_type = F_WRLCK; 281 return xdr_argsize_check(rqstp, p); 282} 283 284int 285nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) 286{ 287 if (!(p = nlm_decode_cookie(p, &argp->cookie)) 288 || !(p = nlm_decode_lock(p, &argp->lock))) 289 return 0; 290 argp->lock.fl.fl_type = F_UNLCK; 291 return xdr_argsize_check(rqstp, p); 292} 293 294int 295nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp) 296{ 297 struct nlm_lock *lock = &argp->lock; 298 299 memset(lock, 0, sizeof(*lock)); 300 locks_init_lock(&lock->fl); 301 lock->svid = ~(u32) 0; 302 lock->fl.fl_pid = (pid_t)lock->svid; 303 304 if (!(p = nlm_decode_cookie(p, &argp->cookie)) 305 || !(p = xdr_decode_string_inplace(p, &lock->caller, 306 &lock->len, NLM_MAXSTRLEN)) 307 || !(p = nlm_decode_fh(p, &lock->fh)) 308 || !(p = nlm_decode_oh(p, &lock->oh))) 309 return 0; 310 argp->fsm_mode = ntohl(*p++); 311 argp->fsm_access = ntohl(*p++); 312 return xdr_argsize_check(rqstp, p); 313} 314 315int 316nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) 317{ 318 if (!(p = nlm_encode_cookie(p, &resp->cookie))) 319 return 0; 320 *p++ = resp->status; 321 *p++ = xdr_zero; /* sequence argument */ 322 return xdr_ressize_check(rqstp, p); 323} 324 325int 326nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) 327{ 328 if (!(p = nlm_encode_cookie(p, &resp->cookie))) 329 return 0; 330 *p++ = resp->status; 331 return xdr_ressize_check(rqstp, p); 332} 333 334int 335nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp) 336{ 337 struct nlm_lock *lock = &argp->lock; 338 339 if (!(p = xdr_decode_string_inplace(p, &lock->caller, 340 &lock->len, NLM_MAXSTRLEN))) 341 return 0; 342 argp->state = ntohl(*p++); 343 return xdr_argsize_check(rqstp, p); 344} 345 346int 347nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp) 348{ 349 if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN))) 350 return 0; 351 argp->state = ntohl(*p++); 352 /* Preserve the address in network byte order */ 353 argp->addr = *p++; 354 argp->vers = *p++; 355 argp->proto = *p++; 356 return xdr_argsize_check(rqstp, p); 357} 358 359int 360nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) 361{ 362 if (!(p = nlm_decode_cookie(p, &resp->cookie))) 363 return 0; 364 resp->status = *p++; 365 return xdr_argsize_check(rqstp, p); 366} 367 368int 369nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) 370{ 371 return xdr_argsize_check(rqstp, p); 372} 373 374int 375nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) 376{ 377 return xdr_ressize_check(rqstp, p); 378} 379 380/* 381 * Now, the client side XDR functions 382 */ 383#ifdef NLMCLNT_SUPPORT_SHARES 384static int 385nlmclt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr) 386{ 387 return 0; 388} 389#endif 390 391static int 392nlmclt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) 393{ 394 struct nlm_lock *lock = &argp->lock; 395 396 if (!(p = nlm_encode_cookie(p, &argp->cookie))) 397 return -EIO; 398 *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; 399 if (!(p = nlm_encode_lock(p, lock))) 400 return -EIO; 401 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 402 return 0; 403} 404 405static int 406nlmclt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) 407{ 408 if (!(p = nlm_decode_cookie(p, &resp->cookie))) 409 return -EIO; 410 resp->status = *p++; 411 if (resp->status == nlm_lck_denied) { 412 struct file_lock *fl = &resp->lock.fl; 413 u32 excl; 414 s32 start, len, end; 415 416 memset(&resp->lock, 0, sizeof(resp->lock)); 417 locks_init_lock(fl); 418 excl = ntohl(*p++); 419 resp->lock.svid = ntohl(*p++); 420 fl->fl_pid = (pid_t)resp->lock.svid; 421 if (!(p = nlm_decode_oh(p, &resp->lock.oh))) 422 return -EIO; 423 424 fl->fl_flags = FL_POSIX; 425 fl->fl_type = excl? F_WRLCK : F_RDLCK; 426 start = ntohl(*p++); 427 len = ntohl(*p++); 428 end = start + len - 1; 429 430 fl->fl_start = s32_to_loff_t(start); 431 if (len == 0 || end < 0) 432 fl->fl_end = OFFSET_MAX; 433 else 434 fl->fl_end = s32_to_loff_t(end); 435 } 436 return 0; 437} 438 439 440static int 441nlmclt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) 442{ 443 struct nlm_lock *lock = &argp->lock; 444 445 if (!(p = nlm_encode_cookie(p, &argp->cookie))) 446 return -EIO; 447 *p++ = argp->block? xdr_one : xdr_zero; 448 *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; 449 if (!(p = nlm_encode_lock(p, lock))) 450 return -EIO; 451 *p++ = argp->reclaim? xdr_one : xdr_zero; 452 *p++ = htonl(argp->state); 453 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 454 return 0; 455} 456 457static int 458nlmclt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) 459{ 460 struct nlm_lock *lock = &argp->lock; 461 462 if (!(p = nlm_encode_cookie(p, &argp->cookie))) 463 return -EIO; 464 *p++ = argp->block? xdr_one : xdr_zero; 465 *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; 466 if (!(p = nlm_encode_lock(p, lock))) 467 return -EIO; 468 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 469 return 0; 470} 471 472static int 473nlmclt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) 474{ 475 struct nlm_lock *lock = &argp->lock; 476 477 if (!(p = nlm_encode_cookie(p, &argp->cookie))) 478 return -EIO; 479 if (!(p = nlm_encode_lock(p, lock))) 480 return -EIO; 481 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 482 return 0; 483} 484 485static int 486nlmclt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) 487{ 488 if (!(p = nlm_encode_cookie(p, &resp->cookie))) 489 return -EIO; 490 *p++ = resp->status; 491 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 492 return 0; 493} 494 495static int 496nlmclt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) 497{ 498 if (!(p = nlm_encode_testres(p, resp))) 499 return -EIO; 500 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 501 return 0; 502} 503 504static int 505nlmclt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) 506{ 507 if (!(p = nlm_decode_cookie(p, &resp->cookie))) 508 return -EIO; 509 resp->status = *p++; 510 return 0; 511} 512 513#if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ) 514# error "NLM host name cannot be larger than XDR_MAX_NETOBJ!" 515#endif 516 517/* 518 * Buffer requirements for NLM 519 */ 520#define NLM_void_sz 0 521#define NLM_cookie_sz 1+XDR_QUADLEN(NLM_MAXCOOKIELEN) 522#define NLM_caller_sz 1+XDR_QUADLEN(NLMCLNT_OHSIZE) 523#define NLM_owner_sz 1+XDR_QUADLEN(NLMCLNT_OHSIZE) 524#define NLM_fhandle_sz 1+XDR_QUADLEN(NFS2_FHSIZE) 525#define NLM_lock_sz 3+NLM_caller_sz+NLM_owner_sz+NLM_fhandle_sz 526#define NLM_holder_sz 4+NLM_owner_sz 527 528#define NLM_testargs_sz NLM_cookie_sz+1+NLM_lock_sz 529#define NLM_lockargs_sz NLM_cookie_sz+4+NLM_lock_sz 530#define NLM_cancargs_sz NLM_cookie_sz+2+NLM_lock_sz 531#define NLM_unlockargs_sz NLM_cookie_sz+NLM_lock_sz 532 533#define NLM_testres_sz NLM_cookie_sz+1+NLM_holder_sz 534#define NLM_res_sz NLM_cookie_sz+1 535#define NLM_norep_sz 0 536 537/* 538 * For NLM, a void procedure really returns nothing 539 */ 540#define nlmclt_decode_norep NULL 541 542#define PROC(proc, argtype, restype) \ 543[NLMPROC_##proc] = { \ 544 .p_proc = NLMPROC_##proc, \ 545 .p_encode = (kxdrproc_t) nlmclt_encode_##argtype, \ 546 .p_decode = (kxdrproc_t) nlmclt_decode_##restype, \ 547 .p_arglen = NLM_##argtype##_sz, \ 548 .p_replen = NLM_##restype##_sz, \ 549 .p_statidx = NLMPROC_##proc, \ 550 .p_name = #proc, \ 551 } 552 553static struct rpc_procinfo nlm_procedures[] = { 554 PROC(TEST, testargs, testres), 555 PROC(LOCK, lockargs, res), 556 PROC(CANCEL, cancargs, res), 557 PROC(UNLOCK, unlockargs, res), 558 PROC(GRANTED, testargs, res), 559 PROC(TEST_MSG, testargs, norep), 560 PROC(LOCK_MSG, lockargs, norep), 561 PROC(CANCEL_MSG, cancargs, norep), 562 PROC(UNLOCK_MSG, unlockargs, norep), 563 PROC(GRANTED_MSG, testargs, norep), 564 PROC(TEST_RES, testres, norep), 565 PROC(LOCK_RES, res, norep), 566 PROC(CANCEL_RES, res, norep), 567 PROC(UNLOCK_RES, res, norep), 568 PROC(GRANTED_RES, res, norep), 569#ifdef NLMCLNT_SUPPORT_SHARES 570 PROC(SHARE, shareargs, shareres), 571 PROC(UNSHARE, shareargs, shareres), 572 PROC(NM_LOCK, lockargs, res), 573 PROC(FREE_ALL, notify, void), 574#endif 575}; 576 577static struct rpc_version nlm_version1 = { 578 .number = 1, 579 .nrprocs = 16, 580 .procs = nlm_procedures, 581}; 582 583static struct rpc_version nlm_version3 = { 584 .number = 3, 585 .nrprocs = 24, 586 .procs = nlm_procedures, 587}; 588 589static struct rpc_version * nlm_versions[] = { 590 [1] = &nlm_version1, 591 [3] = &nlm_version3, 592#ifdef CONFIG_LOCKD_V4 593 [4] = &nlm_version4, 594#endif 595}; 596 597static struct rpc_stat nlm_stats; 598 599struct rpc_program nlm_program = { 600 .name = "lockd", 601 .number = NLM_PROGRAM, 602 .nrvers = ARRAY_SIZE(nlm_versions), 603 .version = nlm_versions, 604 .stats = &nlm_stats, 605}; 606 607#ifdef RPC_DEBUG 608const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie) 609{ 610 /* 611 * We can get away with a static buffer because we're only 612 * called with BKL held. 613 */ 614 static char buf[2*NLM_MAXCOOKIELEN+1]; 615 int i; 616 int len = sizeof(buf); 617 char *p = buf; 618 619 len--; /* allow for trailing \0 */ 620 if (len < 3) 621 return "???"; 622 for (i = 0 ; i < cookie->len ; i++) { 623 if (len < 2) { 624 strcpy(p-3, "..."); 625 break; 626 } 627 sprintf(p, "%02x", cookie->data[i]); 628 p += 2; 629 len -= 2; 630 } 631 *p = '\0'; 632 633 return buf; 634} 635#endif 636