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