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