1 /* AFS Volume Location Service client 2 * 3 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 12 #include <linux/gfp.h> 13 #include <linux/init.h> 14 #include <linux/sched.h> 15 #include "afs_fs.h" 16 #include "internal.h" 17 18 /* 19 * Deliver reply data to a VL.GetEntryByNameU call. 20 */ 21 static int afs_deliver_vl_get_entry_by_name_u(struct afs_call *call) 22 { 23 struct afs_uvldbentry__xdr *uvldb; 24 struct afs_vldb_entry *entry; 25 bool new_only = false; 26 u32 tmp; 27 int i, ret; 28 29 _enter(""); 30 31 ret = afs_transfer_reply(call); 32 if (ret < 0) 33 return ret; 34 35 /* unmarshall the reply once we've received all of it */ 36 uvldb = call->buffer; 37 entry = call->reply[0]; 38 39 for (i = 0; i < ARRAY_SIZE(uvldb->name) - 1; i++) 40 entry->name[i] = (u8)ntohl(uvldb->name[i]); 41 entry->name[i] = 0; 42 entry->name_len = strlen(entry->name); 43 44 /* If there is a new replication site that we can use, ignore all the 45 * sites that aren't marked as new. 46 */ 47 for (i = 0; i < AFS_NMAXNSERVERS; i++) { 48 tmp = ntohl(uvldb->serverFlags[i]); 49 if (!(tmp & AFS_VLSF_DONTUSE) && 50 (tmp & AFS_VLSF_NEWREPSITE)) 51 new_only = true; 52 } 53 54 for (i = 0; i < AFS_NMAXNSERVERS; i++) { 55 struct afs_uuid__xdr *xdr; 56 struct afs_uuid *uuid; 57 int j; 58 59 tmp = ntohl(uvldb->serverFlags[i]); 60 if (tmp & AFS_VLSF_DONTUSE || 61 (new_only && !(tmp & AFS_VLSF_NEWREPSITE))) 62 continue; 63 if (tmp & AFS_VLSF_RWVOL) 64 entry->fs_mask[i] |= AFS_VOL_VTM_RW; 65 if (tmp & AFS_VLSF_ROVOL) 66 entry->fs_mask[i] |= AFS_VOL_VTM_RO; 67 if (tmp & AFS_VLSF_BACKVOL) 68 entry->fs_mask[i] |= AFS_VOL_VTM_BAK; 69 if (!entry->fs_mask[i]) 70 continue; 71 72 xdr = &uvldb->serverNumber[i]; 73 uuid = (struct afs_uuid *)&entry->fs_server[i]; 74 uuid->time_low = xdr->time_low; 75 uuid->time_mid = htons(ntohl(xdr->time_mid)); 76 uuid->time_hi_and_version = htons(ntohl(xdr->time_hi_and_version)); 77 uuid->clock_seq_hi_and_reserved = (u8)ntohl(xdr->clock_seq_hi_and_reserved); 78 uuid->clock_seq_low = (u8)ntohl(xdr->clock_seq_low); 79 for (j = 0; j < 6; j++) 80 uuid->node[j] = (u8)ntohl(xdr->node[j]); 81 82 entry->nr_servers++; 83 } 84 85 for (i = 0; i < AFS_MAXTYPES; i++) 86 entry->vid[i] = ntohl(uvldb->volumeId[i]); 87 88 tmp = ntohl(uvldb->flags); 89 if (tmp & AFS_VLF_RWEXISTS) 90 __set_bit(AFS_VLDB_HAS_RW, &entry->flags); 91 if (tmp & AFS_VLF_ROEXISTS) 92 __set_bit(AFS_VLDB_HAS_RO, &entry->flags); 93 if (tmp & AFS_VLF_BACKEXISTS) 94 __set_bit(AFS_VLDB_HAS_BAK, &entry->flags); 95 96 if (!(tmp & (AFS_VLF_RWEXISTS | AFS_VLF_ROEXISTS | AFS_VLF_BACKEXISTS))) { 97 entry->error = -ENOMEDIUM; 98 __set_bit(AFS_VLDB_QUERY_ERROR, &entry->flags); 99 } 100 101 __set_bit(AFS_VLDB_QUERY_VALID, &entry->flags); 102 _leave(" = 0 [done]"); 103 return 0; 104 } 105 106 static void afs_destroy_vl_get_entry_by_name_u(struct afs_call *call) 107 { 108 kfree(call->reply[0]); 109 afs_flat_call_destructor(call); 110 } 111 112 /* 113 * VL.GetEntryByNameU operation type. 114 */ 115 static const struct afs_call_type afs_RXVLGetEntryByNameU = { 116 .name = "VL.GetEntryByNameU", 117 .op = afs_VL_GetEntryByNameU, 118 .deliver = afs_deliver_vl_get_entry_by_name_u, 119 .destructor = afs_destroy_vl_get_entry_by_name_u, 120 }; 121 122 /* 123 * Dispatch a get volume entry by name or ID operation (uuid variant). If the 124 * volname is a decimal number then it's a volume ID not a volume name. 125 */ 126 struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_net *net, 127 struct afs_addr_cursor *ac, 128 struct key *key, 129 const char *volname, 130 int volnamesz) 131 { 132 struct afs_vldb_entry *entry; 133 struct afs_call *call; 134 size_t reqsz, padsz; 135 __be32 *bp; 136 137 _enter(""); 138 139 padsz = (4 - (volnamesz & 3)) & 3; 140 reqsz = 8 + volnamesz + padsz; 141 142 entry = kzalloc(sizeof(struct afs_vldb_entry), GFP_KERNEL); 143 if (!entry) 144 return ERR_PTR(-ENOMEM); 145 146 call = afs_alloc_flat_call(net, &afs_RXVLGetEntryByNameU, reqsz, 147 sizeof(struct afs_uvldbentry__xdr)); 148 if (!call) { 149 kfree(entry); 150 return ERR_PTR(-ENOMEM); 151 } 152 153 call->key = key; 154 call->reply[0] = entry; 155 call->ret_reply0 = true; 156 157 /* Marshall the parameters */ 158 bp = call->request; 159 *bp++ = htonl(VLGETENTRYBYNAMEU); 160 *bp++ = htonl(volnamesz); 161 memcpy(bp, volname, volnamesz); 162 if (padsz > 0) 163 memset((void *)bp + volnamesz, 0, padsz); 164 165 trace_afs_make_vl_call(call); 166 return (struct afs_vldb_entry *)afs_make_call(ac, call, GFP_KERNEL, false); 167 } 168 169 /* 170 * Deliver reply data to a VL.GetAddrsU call. 171 * 172 * GetAddrsU(IN ListAddrByAttributes *inaddr, 173 * OUT afsUUID *uuidp1, 174 * OUT uint32_t *uniquifier, 175 * OUT uint32_t *nentries, 176 * OUT bulkaddrs *blkaddrs); 177 */ 178 static int afs_deliver_vl_get_addrs_u(struct afs_call *call) 179 { 180 struct afs_addr_list *alist; 181 __be32 *bp; 182 u32 uniquifier, nentries, count; 183 int i, ret; 184 185 _enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count); 186 187 again: 188 switch (call->unmarshall) { 189 case 0: 190 call->offset = 0; 191 call->unmarshall++; 192 193 /* Extract the returned uuid, uniquifier, nentries and blkaddrs size */ 194 case 1: 195 ret = afs_extract_data(call, call->buffer, 196 sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32), 197 true); 198 if (ret < 0) 199 return ret; 200 201 bp = call->buffer + sizeof(struct afs_uuid__xdr); 202 uniquifier = ntohl(*bp++); 203 nentries = ntohl(*bp++); 204 count = ntohl(*bp); 205 206 nentries = min(nentries, count); 207 alist = afs_alloc_addrlist(nentries, FS_SERVICE, AFS_FS_PORT); 208 if (!alist) 209 return -ENOMEM; 210 alist->version = uniquifier; 211 call->reply[0] = alist; 212 call->count = count; 213 call->count2 = nentries; 214 call->offset = 0; 215 call->unmarshall++; 216 217 /* Extract entries */ 218 case 2: 219 count = min(call->count, 4U); 220 ret = afs_extract_data(call, call->buffer, 221 count * sizeof(__be32), 222 call->count > 4); 223 if (ret < 0) 224 return ret; 225 226 alist = call->reply[0]; 227 bp = call->buffer; 228 for (i = 0; i < count; i++) 229 if (alist->nr_addrs < call->count2) 230 afs_merge_fs_addr4(alist, *bp++, AFS_FS_PORT); 231 232 call->count -= count; 233 if (call->count > 0) 234 goto again; 235 call->offset = 0; 236 call->unmarshall++; 237 break; 238 } 239 240 _leave(" = 0 [done]"); 241 return 0; 242 } 243 244 static void afs_vl_get_addrs_u_destructor(struct afs_call *call) 245 { 246 afs_put_server(call->net, (struct afs_server *)call->reply[0]); 247 kfree(call->reply[1]); 248 return afs_flat_call_destructor(call); 249 } 250 251 /* 252 * VL.GetAddrsU operation type. 253 */ 254 static const struct afs_call_type afs_RXVLGetAddrsU = { 255 .name = "VL.GetAddrsU", 256 .op = afs_VL_GetAddrsU, 257 .deliver = afs_deliver_vl_get_addrs_u, 258 .destructor = afs_vl_get_addrs_u_destructor, 259 }; 260 261 /* 262 * Dispatch an operation to get the addresses for a server, where the server is 263 * nominated by UUID. 264 */ 265 struct afs_addr_list *afs_vl_get_addrs_u(struct afs_net *net, 266 struct afs_addr_cursor *ac, 267 struct key *key, 268 const uuid_t *uuid) 269 { 270 struct afs_ListAddrByAttributes__xdr *r; 271 const struct afs_uuid *u = (const struct afs_uuid *)uuid; 272 struct afs_call *call; 273 __be32 *bp; 274 int i; 275 276 _enter(""); 277 278 call = afs_alloc_flat_call(net, &afs_RXVLGetAddrsU, 279 sizeof(__be32) + sizeof(struct afs_ListAddrByAttributes__xdr), 280 sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32)); 281 if (!call) 282 return ERR_PTR(-ENOMEM); 283 284 call->key = key; 285 call->reply[0] = NULL; 286 call->ret_reply0 = true; 287 288 /* Marshall the parameters */ 289 bp = call->request; 290 *bp++ = htonl(VLGETADDRSU); 291 r = (struct afs_ListAddrByAttributes__xdr *)bp; 292 r->Mask = htonl(AFS_VLADDR_UUID); 293 r->ipaddr = 0; 294 r->index = 0; 295 r->spare = 0; 296 r->uuid.time_low = u->time_low; 297 r->uuid.time_mid = htonl(ntohs(u->time_mid)); 298 r->uuid.time_hi_and_version = htonl(ntohs(u->time_hi_and_version)); 299 r->uuid.clock_seq_hi_and_reserved = htonl(u->clock_seq_hi_and_reserved); 300 r->uuid.clock_seq_low = htonl(u->clock_seq_low); 301 for (i = 0; i < 6; i++) 302 r->uuid.node[i] = ntohl(u->node[i]); 303 304 trace_afs_make_vl_call(call); 305 return (struct afs_addr_list *)afs_make_call(ac, call, GFP_KERNEL, false); 306 } 307 308 /* 309 * Deliver reply data to an VL.GetCapabilities operation. 310 */ 311 static int afs_deliver_vl_get_capabilities(struct afs_call *call) 312 { 313 u32 count; 314 int ret; 315 316 _enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count); 317 318 again: 319 switch (call->unmarshall) { 320 case 0: 321 call->offset = 0; 322 call->unmarshall++; 323 324 /* Extract the capabilities word count */ 325 case 1: 326 ret = afs_extract_data(call, &call->tmp, 327 1 * sizeof(__be32), 328 true); 329 if (ret < 0) 330 return ret; 331 332 count = ntohl(call->tmp); 333 334 call->count = count; 335 call->count2 = count; 336 call->offset = 0; 337 call->unmarshall++; 338 339 /* Extract capabilities words */ 340 case 2: 341 count = min(call->count, 16U); 342 ret = afs_extract_data(call, call->buffer, 343 count * sizeof(__be32), 344 call->count > 16); 345 if (ret < 0) 346 return ret; 347 348 /* TODO: Examine capabilities */ 349 350 call->count -= count; 351 if (call->count > 0) 352 goto again; 353 call->offset = 0; 354 call->unmarshall++; 355 break; 356 } 357 358 call->reply[0] = (void *)(unsigned long)call->service_id; 359 360 _leave(" = 0 [done]"); 361 return 0; 362 } 363 364 /* 365 * VL.GetCapabilities operation type 366 */ 367 static const struct afs_call_type afs_RXVLGetCapabilities = { 368 .name = "VL.GetCapabilities", 369 .op = afs_VL_GetCapabilities, 370 .deliver = afs_deliver_vl_get_capabilities, 371 .destructor = afs_flat_call_destructor, 372 }; 373 374 /* 375 * Probe a fileserver for the capabilities that it supports. This can 376 * return up to 196 words. 377 * 378 * We use this to probe for service upgrade to determine what the server at the 379 * other end supports. 380 */ 381 int afs_vl_get_capabilities(struct afs_net *net, 382 struct afs_addr_cursor *ac, 383 struct key *key) 384 { 385 struct afs_call *call; 386 __be32 *bp; 387 388 _enter(""); 389 390 call = afs_alloc_flat_call(net, &afs_RXVLGetCapabilities, 1 * 4, 16 * 4); 391 if (!call) 392 return -ENOMEM; 393 394 call->key = key; 395 call->upgrade = true; /* Let's see if this is a YFS server */ 396 call->reply[0] = (void *)VLGETCAPABILITIES; 397 call->ret_reply0 = true; 398 399 /* marshall the parameters */ 400 bp = call->request; 401 *bp++ = htonl(VLGETCAPABILITIES); 402 403 /* Can't take a ref on server */ 404 trace_afs_make_vl_call(call); 405 return afs_make_call(ac, call, GFP_KERNEL, false); 406 } 407 408 /* 409 * Deliver reply data to a YFSVL.GetEndpoints call. 410 * 411 * GetEndpoints(IN yfsServerAttributes *attr, 412 * OUT opr_uuid *uuid, 413 * OUT afs_int32 *uniquifier, 414 * OUT endpoints *fsEndpoints, 415 * OUT endpoints *volEndpoints) 416 */ 417 static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call) 418 { 419 struct afs_addr_list *alist; 420 __be32 *bp; 421 u32 uniquifier, size; 422 int ret; 423 424 _enter("{%u,%zu/%u,%u}", call->unmarshall, call->offset, call->count, call->count2); 425 426 again: 427 switch (call->unmarshall) { 428 case 0: 429 call->offset = 0; 430 call->unmarshall = 1; 431 432 /* Extract the returned uuid, uniquifier, fsEndpoints count and 433 * either the first fsEndpoint type or the volEndpoints 434 * count if there are no fsEndpoints. */ 435 case 1: 436 ret = afs_extract_data(call, call->buffer, 437 sizeof(uuid_t) + 438 3 * sizeof(__be32), 439 true); 440 if (ret < 0) 441 return ret; 442 443 bp = call->buffer + sizeof(uuid_t); 444 uniquifier = ntohl(*bp++); 445 call->count = ntohl(*bp++); 446 call->count2 = ntohl(*bp); /* Type or next count */ 447 448 if (call->count > YFS_MAXENDPOINTS) 449 return -EBADMSG; 450 451 alist = afs_alloc_addrlist(call->count, FS_SERVICE, AFS_FS_PORT); 452 if (!alist) 453 return -ENOMEM; 454 alist->version = uniquifier; 455 call->reply[0] = alist; 456 call->offset = 0; 457 458 if (call->count == 0) 459 goto extract_volendpoints; 460 461 call->unmarshall = 2; 462 463 /* Extract fsEndpoints[] entries */ 464 case 2: 465 switch (call->count2) { 466 case YFS_ENDPOINT_IPV4: 467 size = sizeof(__be32) * (1 + 1 + 1); 468 break; 469 case YFS_ENDPOINT_IPV6: 470 size = sizeof(__be32) * (1 + 4 + 1); 471 break; 472 default: 473 return -EBADMSG; 474 } 475 476 size += sizeof(__be32); 477 ret = afs_extract_data(call, call->buffer, size, true); 478 if (ret < 0) 479 return ret; 480 481 alist = call->reply[0]; 482 bp = call->buffer; 483 switch (call->count2) { 484 case YFS_ENDPOINT_IPV4: 485 if (ntohl(bp[0]) != sizeof(__be32) * 2) 486 return -EBADMSG; 487 afs_merge_fs_addr4(alist, bp[1], ntohl(bp[2])); 488 bp += 3; 489 break; 490 case YFS_ENDPOINT_IPV6: 491 if (ntohl(bp[0]) != sizeof(__be32) * 5) 492 return -EBADMSG; 493 afs_merge_fs_addr6(alist, bp + 1, ntohl(bp[5])); 494 bp += 6; 495 break; 496 default: 497 return -EBADMSG; 498 } 499 500 /* Got either the type of the next entry or the count of 501 * volEndpoints if no more fsEndpoints. 502 */ 503 call->count2 = htonl(*bp++); 504 505 call->offset = 0; 506 call->count--; 507 if (call->count > 0) 508 goto again; 509 510 extract_volendpoints: 511 /* Extract the list of volEndpoints. */ 512 call->count = call->count2; 513 if (!call->count) 514 goto end; 515 if (call->count > YFS_MAXENDPOINTS) 516 return -EBADMSG; 517 518 call->unmarshall = 3; 519 520 /* Extract the type of volEndpoints[0]. Normally we would 521 * extract the type of the next endpoint when we extract the 522 * data of the current one, but this is the first... 523 */ 524 case 3: 525 ret = afs_extract_data(call, call->buffer, sizeof(__be32), true); 526 if (ret < 0) 527 return ret; 528 529 bp = call->buffer; 530 call->count2 = htonl(*bp++); 531 call->offset = 0; 532 call->unmarshall = 4; 533 534 /* Extract volEndpoints[] entries */ 535 case 4: 536 switch (call->count2) { 537 case YFS_ENDPOINT_IPV4: 538 size = sizeof(__be32) * (1 + 1 + 1); 539 break; 540 case YFS_ENDPOINT_IPV6: 541 size = sizeof(__be32) * (1 + 4 + 1); 542 break; 543 default: 544 return -EBADMSG; 545 } 546 547 if (call->count > 1) 548 size += sizeof(__be32); 549 ret = afs_extract_data(call, call->buffer, size, true); 550 if (ret < 0) 551 return ret; 552 553 bp = call->buffer; 554 switch (call->count2) { 555 case YFS_ENDPOINT_IPV4: 556 if (ntohl(bp[0]) != sizeof(__be32) * 2) 557 return -EBADMSG; 558 bp += 3; 559 break; 560 case YFS_ENDPOINT_IPV6: 561 if (ntohl(bp[0]) != sizeof(__be32) * 5) 562 return -EBADMSG; 563 bp += 6; 564 break; 565 default: 566 return -EBADMSG; 567 } 568 569 /* Got either the type of the next entry or the count of 570 * volEndpoints if no more fsEndpoints. 571 */ 572 call->offset = 0; 573 call->count--; 574 if (call->count > 0) { 575 call->count2 = htonl(*bp++); 576 goto again; 577 } 578 579 end: 580 call->unmarshall = 5; 581 582 /* Done */ 583 case 5: 584 ret = afs_extract_data(call, call->buffer, 0, false); 585 if (ret < 0) 586 return ret; 587 call->unmarshall = 6; 588 589 case 6: 590 break; 591 } 592 593 alist = call->reply[0]; 594 595 /* Start with IPv6 if available. */ 596 if (alist->nr_ipv4 < alist->nr_addrs) 597 alist->index = alist->nr_ipv4; 598 599 _leave(" = 0 [done]"); 600 return 0; 601 } 602 603 /* 604 * YFSVL.GetEndpoints operation type. 605 */ 606 static const struct afs_call_type afs_YFSVLGetEndpoints = { 607 .name = "YFSVL.GetEndpoints", 608 .op = afs_YFSVL_GetEndpoints, 609 .deliver = afs_deliver_yfsvl_get_endpoints, 610 .destructor = afs_vl_get_addrs_u_destructor, 611 }; 612 613 /* 614 * Dispatch an operation to get the addresses for a server, where the server is 615 * nominated by UUID. 616 */ 617 struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_net *net, 618 struct afs_addr_cursor *ac, 619 struct key *key, 620 const uuid_t *uuid) 621 { 622 struct afs_call *call; 623 __be32 *bp; 624 625 _enter(""); 626 627 call = afs_alloc_flat_call(net, &afs_YFSVLGetEndpoints, 628 sizeof(__be32) * 2 + sizeof(*uuid), 629 sizeof(struct in6_addr) + sizeof(__be32) * 3); 630 if (!call) 631 return ERR_PTR(-ENOMEM); 632 633 call->key = key; 634 call->reply[0] = NULL; 635 call->ret_reply0 = true; 636 637 /* Marshall the parameters */ 638 bp = call->request; 639 *bp++ = htonl(YVLGETENDPOINTS); 640 *bp++ = htonl(YFS_SERVER_UUID); 641 memcpy(bp, uuid, sizeof(*uuid)); /* Type opr_uuid */ 642 643 trace_afs_make_vl_call(call); 644 return (struct afs_addr_list *)afs_make_call(ac, call, GFP_KERNEL, false); 645 } 646