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 dprintk("lockd: bad cookie size %d (only cookies under " 66 "%d bytes are supported.)\n", 67 len, NLM_MAXCOOKIELEN); 68 return NULL; 69 } 70 return p; 71 } 72 73 static inline __be32 * 74 nlm_encode_cookie(__be32 *p, struct nlm_cookie *c) 75 { 76 *p++ = htonl(c->len); 77 memcpy(p, c->data, c->len); 78 p+=XDR_QUADLEN(c->len); 79 return p; 80 } 81 82 static __be32 * 83 nlm_decode_fh(__be32 *p, struct nfs_fh *f) 84 { 85 unsigned int len; 86 87 if ((len = ntohl(*p++)) != NFS2_FHSIZE) { 88 dprintk("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 return xdr_argsize_check(rqstp, p); 355 } 356 357 int 358 nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp) 359 { 360 if (!(p = nlm_decode_cookie(p, &resp->cookie))) 361 return 0; 362 resp->status = *p++; 363 return xdr_argsize_check(rqstp, p); 364 } 365 366 int 367 nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) 368 { 369 return xdr_argsize_check(rqstp, p); 370 } 371 372 int 373 nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) 374 { 375 return xdr_ressize_check(rqstp, p); 376 } 377 378 /* 379 * Now, the client side XDR functions 380 */ 381 #ifdef NLMCLNT_SUPPORT_SHARES 382 static int 383 nlmclt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr) 384 { 385 return 0; 386 } 387 #endif 388 389 static int 390 nlmclt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) 391 { 392 struct nlm_lock *lock = &argp->lock; 393 394 if (!(p = nlm_encode_cookie(p, &argp->cookie))) 395 return -EIO; 396 *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; 397 if (!(p = nlm_encode_lock(p, lock))) 398 return -EIO; 399 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 400 return 0; 401 } 402 403 static int 404 nlmclt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) 405 { 406 if (!(p = nlm_decode_cookie(p, &resp->cookie))) 407 return -EIO; 408 resp->status = *p++; 409 if (resp->status == nlm_lck_denied) { 410 struct file_lock *fl = &resp->lock.fl; 411 u32 excl; 412 s32 start, len, end; 413 414 memset(&resp->lock, 0, sizeof(resp->lock)); 415 locks_init_lock(fl); 416 excl = ntohl(*p++); 417 resp->lock.svid = ntohl(*p++); 418 fl->fl_pid = (pid_t)resp->lock.svid; 419 if (!(p = nlm_decode_oh(p, &resp->lock.oh))) 420 return -EIO; 421 422 fl->fl_flags = FL_POSIX; 423 fl->fl_type = excl? F_WRLCK : F_RDLCK; 424 start = ntohl(*p++); 425 len = ntohl(*p++); 426 end = start + len - 1; 427 428 fl->fl_start = s32_to_loff_t(start); 429 if (len == 0 || end < 0) 430 fl->fl_end = OFFSET_MAX; 431 else 432 fl->fl_end = s32_to_loff_t(end); 433 } 434 return 0; 435 } 436 437 438 static int 439 nlmclt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) 440 { 441 struct nlm_lock *lock = &argp->lock; 442 443 if (!(p = nlm_encode_cookie(p, &argp->cookie))) 444 return -EIO; 445 *p++ = argp->block? xdr_one : xdr_zero; 446 *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; 447 if (!(p = nlm_encode_lock(p, lock))) 448 return -EIO; 449 *p++ = argp->reclaim? xdr_one : xdr_zero; 450 *p++ = htonl(argp->state); 451 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 452 return 0; 453 } 454 455 static int 456 nlmclt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) 457 { 458 struct nlm_lock *lock = &argp->lock; 459 460 if (!(p = nlm_encode_cookie(p, &argp->cookie))) 461 return -EIO; 462 *p++ = argp->block? xdr_one : xdr_zero; 463 *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; 464 if (!(p = nlm_encode_lock(p, lock))) 465 return -EIO; 466 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 467 return 0; 468 } 469 470 static int 471 nlmclt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp) 472 { 473 struct nlm_lock *lock = &argp->lock; 474 475 if (!(p = nlm_encode_cookie(p, &argp->cookie))) 476 return -EIO; 477 if (!(p = nlm_encode_lock(p, lock))) 478 return -EIO; 479 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 480 return 0; 481 } 482 483 static int 484 nlmclt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) 485 { 486 if (!(p = nlm_encode_cookie(p, &resp->cookie))) 487 return -EIO; 488 *p++ = resp->status; 489 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 490 return 0; 491 } 492 493 static int 494 nlmclt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) 495 { 496 if (!(p = nlm_encode_testres(p, resp))) 497 return -EIO; 498 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 499 return 0; 500 } 501 502 static int 503 nlmclt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp) 504 { 505 if (!(p = nlm_decode_cookie(p, &resp->cookie))) 506 return -EIO; 507 resp->status = *p++; 508 return 0; 509 } 510 511 #if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ) 512 # error "NLM host name cannot be larger than XDR_MAX_NETOBJ!" 513 #endif 514 515 /* 516 * Buffer requirements for NLM 517 */ 518 #define NLM_void_sz 0 519 #define NLM_cookie_sz 1+XDR_QUADLEN(NLM_MAXCOOKIELEN) 520 #define NLM_caller_sz 1+XDR_QUADLEN(NLMCLNT_OHSIZE) 521 #define NLM_owner_sz 1+XDR_QUADLEN(NLMCLNT_OHSIZE) 522 #define NLM_fhandle_sz 1+XDR_QUADLEN(NFS2_FHSIZE) 523 #define NLM_lock_sz 3+NLM_caller_sz+NLM_owner_sz+NLM_fhandle_sz 524 #define NLM_holder_sz 4+NLM_owner_sz 525 526 #define NLM_testargs_sz NLM_cookie_sz+1+NLM_lock_sz 527 #define NLM_lockargs_sz NLM_cookie_sz+4+NLM_lock_sz 528 #define NLM_cancargs_sz NLM_cookie_sz+2+NLM_lock_sz 529 #define NLM_unlockargs_sz NLM_cookie_sz+NLM_lock_sz 530 531 #define NLM_testres_sz NLM_cookie_sz+1+NLM_holder_sz 532 #define NLM_res_sz NLM_cookie_sz+1 533 #define NLM_norep_sz 0 534 535 /* 536 * For NLM, a void procedure really returns nothing 537 */ 538 #define nlmclt_decode_norep NULL 539 540 #define PROC(proc, argtype, restype) \ 541 [NLMPROC_##proc] = { \ 542 .p_proc = NLMPROC_##proc, \ 543 .p_encode = (kxdrproc_t) nlmclt_encode_##argtype, \ 544 .p_decode = (kxdrproc_t) nlmclt_decode_##restype, \ 545 .p_arglen = NLM_##argtype##_sz, \ 546 .p_replen = NLM_##restype##_sz, \ 547 .p_statidx = NLMPROC_##proc, \ 548 .p_name = #proc, \ 549 } 550 551 static struct rpc_procinfo nlm_procedures[] = { 552 PROC(TEST, testargs, testres), 553 PROC(LOCK, lockargs, res), 554 PROC(CANCEL, cancargs, res), 555 PROC(UNLOCK, unlockargs, res), 556 PROC(GRANTED, testargs, res), 557 PROC(TEST_MSG, testargs, norep), 558 PROC(LOCK_MSG, lockargs, norep), 559 PROC(CANCEL_MSG, cancargs, norep), 560 PROC(UNLOCK_MSG, unlockargs, norep), 561 PROC(GRANTED_MSG, testargs, norep), 562 PROC(TEST_RES, testres, norep), 563 PROC(LOCK_RES, res, norep), 564 PROC(CANCEL_RES, res, norep), 565 PROC(UNLOCK_RES, res, norep), 566 PROC(GRANTED_RES, res, norep), 567 #ifdef NLMCLNT_SUPPORT_SHARES 568 PROC(SHARE, shareargs, shareres), 569 PROC(UNSHARE, shareargs, shareres), 570 PROC(NM_LOCK, lockargs, res), 571 PROC(FREE_ALL, notify, void), 572 #endif 573 }; 574 575 static struct rpc_version nlm_version1 = { 576 .number = 1, 577 .nrprocs = 16, 578 .procs = nlm_procedures, 579 }; 580 581 static struct rpc_version nlm_version3 = { 582 .number = 3, 583 .nrprocs = 24, 584 .procs = nlm_procedures, 585 }; 586 587 static struct rpc_version * nlm_versions[] = { 588 [1] = &nlm_version1, 589 [3] = &nlm_version3, 590 #ifdef CONFIG_LOCKD_V4 591 [4] = &nlm_version4, 592 #endif 593 }; 594 595 static struct rpc_stat nlm_stats; 596 597 struct rpc_program nlm_program = { 598 .name = "lockd", 599 .number = NLM_PROGRAM, 600 .nrvers = ARRAY_SIZE(nlm_versions), 601 .version = nlm_versions, 602 .stats = &nlm_stats, 603 }; 604 605 #ifdef RPC_DEBUG 606 const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie) 607 { 608 /* 609 * We can get away with a static buffer because we're only 610 * called with BKL held. 611 */ 612 static char buf[2*NLM_MAXCOOKIELEN+1]; 613 unsigned int i, len = sizeof(buf); 614 char *p = buf; 615 616 len--; /* allow for trailing \0 */ 617 if (len < 3) 618 return "???"; 619 for (i = 0 ; i < cookie->len ; i++) { 620 if (len < 2) { 621 strcpy(p-3, "..."); 622 break; 623 } 624 sprintf(p, "%02x", cookie->data[i]); 625 p += 2; 626 len -= 2; 627 } 628 *p = '\0'; 629 630 return buf; 631 } 632 #endif 633