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 24 static inline loff_t 25 s32_to_loff_t(__s32 offset) 26 { 27 return (loff_t)offset; 28 } 29 30 static inline __s32 31 loff_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 */ 46 static __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 72 static inline __be32 * 73 nlm_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 81 static __be32 * 82 nlm_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 98 static inline __be32 * 99 nlm_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 */ 109 static inline __be32 * 110 nlm_decode_oh(__be32 *p, struct xdr_netobj *oh) 111 { 112 return xdr_decode_netobj(p, oh); 113 } 114 115 static inline __be32 * 116 nlm_encode_oh(__be32 *p, struct xdr_netobj *oh) 117 { 118 return xdr_encode_netobj(p, oh); 119 } 120 121 static __be32 * 122 nlm_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 */ 156 static __be32 * 157 nlm_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 */ 187 static __be32 * 188 nlm_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 */ 223 int 224 nlmsvc_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 240 int 241 nlmsvc_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 248 int 249 nlmsvc_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 268 int 269 nlmsvc_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 284 int 285 nlmsvc_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 294 int 295 nlmsvc_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 315 int 316 nlmsvc_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 325 int 326 nlmsvc_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 334 int 335 nlmsvc_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 346 int 347 nlmsvc_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 359 int 360 nlmsvc_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 368 int 369 nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) 370 { 371 return xdr_argsize_check(rqstp, p); 372 } 373 374 int 375 nlmsvc_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 384 static int 385 nlmclt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr) 386 { 387 return 0; 388 } 389 #endif 390 391 static int 392 nlmclt_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 405 static int 406 nlmclt_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 440 static int 441 nlmclt_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 457 static int 458 nlmclt_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 472 static int 473 nlmclt_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 485 static int 486 nlmclt_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 495 static int 496 nlmclt_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 504 static int 505 nlmclt_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 553 static 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 577 static struct rpc_version nlm_version1 = { 578 .number = 1, 579 .nrprocs = 16, 580 .procs = nlm_procedures, 581 }; 582 583 static struct rpc_version nlm_version3 = { 584 .number = 3, 585 .nrprocs = 24, 586 .procs = nlm_procedures, 587 }; 588 589 #ifdef CONFIG_LOCKD_V4 590 extern struct rpc_version nlm_version4; 591 #endif 592 593 static struct rpc_version * nlm_versions[] = { 594 [1] = &nlm_version1, 595 [3] = &nlm_version3, 596 #ifdef CONFIG_LOCKD_V4 597 [4] = &nlm_version4, 598 #endif 599 }; 600 601 static struct rpc_stat nlm_stats; 602 603 struct rpc_program nlm_program = { 604 .name = "lockd", 605 .number = NLM_PROGRAM, 606 .nrvers = ARRAY_SIZE(nlm_versions), 607 .version = nlm_versions, 608 .stats = &nlm_stats, 609 }; 610 611 #ifdef RPC_DEBUG 612 const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie) 613 { 614 /* 615 * We can get away with a static buffer because we're only 616 * called with BKL held. 617 */ 618 static char buf[2*NLM_MAXCOOKIELEN+1]; 619 int i; 620 int len = sizeof(buf); 621 char *p = buf; 622 623 len--; /* allow for trailing \0 */ 624 if (len < 3) 625 return "???"; 626 for (i = 0 ; i < cookie->len ; i++) { 627 if (len < 2) { 628 strcpy(p-3, "..."); 629 break; 630 } 631 sprintf(p, "%02x", cookie->data[i]); 632 p += 2; 633 len -= 2; 634 } 635 *p = '\0'; 636 637 return buf; 638 } 639 #endif 640