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 inline 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 inline 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 inline 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 135 locks_init_lock(fl); 136 fl->fl_owner = current->files; 137 fl->fl_pid = ntohl(*p++); 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 u32 * 157 nlm_encode_lock(u32 *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(fl->fl_pid); 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 u32 * 188 nlm_encode_testres(u32 *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(fl->fl_pid); 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, u32 *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, u32 *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, u32 *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, u32 *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, u32 *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, u32 *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->fl.fl_pid = ~(u32) 0; 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, u32 *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, u32 *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, u32 *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, u32 *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 /* Preserve the address in network byte order */ 352 argp->addr = *p++; 353 argp->vers = *p++; 354 argp->proto = *p++; 355 return xdr_argsize_check(rqstp, p); 356 } 357 358 int 359 nlmsvc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) 360 { 361 if (!(p = nlm_decode_cookie(p, &resp->cookie))) 362 return 0; 363 resp->status = ntohl(*p++); 364 return xdr_argsize_check(rqstp, p); 365 } 366 367 int 368 nlmsvc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy) 369 { 370 return xdr_argsize_check(rqstp, p); 371 } 372 373 int 374 nlmsvc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy) 375 { 376 return xdr_ressize_check(rqstp, p); 377 } 378 379 /* 380 * Now, the client side XDR functions 381 */ 382 #ifdef NLMCLNT_SUPPORT_SHARES 383 static int 384 nlmclt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr) 385 { 386 return 0; 387 } 388 #endif 389 390 static int 391 nlmclt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) 392 { 393 struct nlm_lock *lock = &argp->lock; 394 395 if (!(p = nlm_encode_cookie(p, &argp->cookie))) 396 return -EIO; 397 *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; 398 if (!(p = nlm_encode_lock(p, lock))) 399 return -EIO; 400 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 401 return 0; 402 } 403 404 static int 405 nlmclt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) 406 { 407 if (!(p = nlm_decode_cookie(p, &resp->cookie))) 408 return -EIO; 409 resp->status = ntohl(*p++); 410 if (resp->status == NLM_LCK_DENIED) { 411 struct file_lock *fl = &resp->lock.fl; 412 u32 excl; 413 s32 start, len, end; 414 415 memset(&resp->lock, 0, sizeof(resp->lock)); 416 locks_init_lock(fl); 417 excl = ntohl(*p++); 418 fl->fl_pid = ntohl(*p++); 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, u32 *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, u32 *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, u32 *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, u32 *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, u32 *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, u32 *p, struct nlm_res *resp) 504 { 505 if (!(p = nlm_decode_cookie(p, &resp->cookie))) 506 return -EIO; 507 resp->status = ntohl(*p++); 508 return 0; 509 } 510 511 /* 512 * Buffer requirements for NLM 513 */ 514 #define NLM_void_sz 0 515 #define NLM_cookie_sz 1+XDR_QUADLEN(NLM_MAXCOOKIELEN) 516 #define NLM_caller_sz 1+XDR_QUADLEN(sizeof(system_utsname.nodename)) 517 #define NLM_netobj_sz 1+XDR_QUADLEN(XDR_MAX_NETOBJ) 518 /* #define NLM_owner_sz 1+XDR_QUADLEN(NLM_MAXOWNER) */ 519 #define NLM_fhandle_sz 1+XDR_QUADLEN(NFS2_FHSIZE) 520 #define NLM_lock_sz 3+NLM_caller_sz+NLM_netobj_sz+NLM_fhandle_sz 521 #define NLM_holder_sz 4+NLM_netobj_sz 522 523 #define NLM_testargs_sz NLM_cookie_sz+1+NLM_lock_sz 524 #define NLM_lockargs_sz NLM_cookie_sz+4+NLM_lock_sz 525 #define NLM_cancargs_sz NLM_cookie_sz+2+NLM_lock_sz 526 #define NLM_unlockargs_sz NLM_cookie_sz+NLM_lock_sz 527 528 #define NLM_testres_sz NLM_cookie_sz+1+NLM_holder_sz 529 #define NLM_res_sz NLM_cookie_sz+1 530 #define NLM_norep_sz 0 531 532 #ifndef MAX 533 # define MAX(a, b) (((a) > (b))? (a) : (b)) 534 #endif 535 536 /* 537 * For NLM, a void procedure really returns nothing 538 */ 539 #define nlmclt_decode_norep NULL 540 541 #define PROC(proc, argtype, restype) \ 542 [NLMPROC_##proc] = { \ 543 .p_proc = NLMPROC_##proc, \ 544 .p_encode = (kxdrproc_t) nlmclt_encode_##argtype, \ 545 .p_decode = (kxdrproc_t) nlmclt_decode_##restype, \ 546 .p_bufsiz = MAX(NLM_##argtype##_sz, NLM_##restype##_sz) << 2 \ 547 } 548 549 static struct rpc_procinfo nlm_procedures[] = { 550 PROC(TEST, testargs, testres), 551 PROC(LOCK, lockargs, res), 552 PROC(CANCEL, cancargs, res), 553 PROC(UNLOCK, unlockargs, res), 554 PROC(GRANTED, testargs, res), 555 PROC(TEST_MSG, testargs, norep), 556 PROC(LOCK_MSG, lockargs, norep), 557 PROC(CANCEL_MSG, cancargs, norep), 558 PROC(UNLOCK_MSG, unlockargs, norep), 559 PROC(GRANTED_MSG, testargs, norep), 560 PROC(TEST_RES, testres, norep), 561 PROC(LOCK_RES, res, norep), 562 PROC(CANCEL_RES, res, norep), 563 PROC(UNLOCK_RES, res, norep), 564 PROC(GRANTED_RES, res, norep), 565 #ifdef NLMCLNT_SUPPORT_SHARES 566 PROC(SHARE, shareargs, shareres), 567 PROC(UNSHARE, shareargs, shareres), 568 PROC(NM_LOCK, lockargs, res), 569 PROC(FREE_ALL, notify, void), 570 #endif 571 }; 572 573 static struct rpc_version nlm_version1 = { 574 .number = 1, 575 .nrprocs = 16, 576 .procs = nlm_procedures, 577 }; 578 579 static struct rpc_version nlm_version3 = { 580 .number = 3, 581 .nrprocs = 24, 582 .procs = nlm_procedures, 583 }; 584 585 #ifdef CONFIG_LOCKD_V4 586 extern struct rpc_version nlm_version4; 587 #endif 588 589 static 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 597 static struct rpc_stat nlm_stats; 598 599 struct rpc_program nlm_program = { 600 .name = "lockd", 601 .number = NLM_PROGRAM, 602 .nrvers = sizeof(nlm_versions) / sizeof(nlm_versions[0]), 603 .version = nlm_versions, 604 .stats = &nlm_stats, 605 }; 606 607 #ifdef RPC_DEBUG 608 const 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