1 /* $NetBSD: loc_29.c,v 1.11 2025/01/26 16:25:31 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 /* RFC1876 */ 17 18 #ifndef RDATA_GENERIC_LOC_29_C 19 #define RDATA_GENERIC_LOC_29_C 20 21 #define RRTYPE_LOC_ATTRIBUTES (0) 22 23 static isc_result_t 24 loc_getdecimal(const char *str, unsigned long max, size_t precision, char units, 25 unsigned long *valuep) { 26 bool ok; 27 char *e; 28 size_t i; 29 long tmp; 30 unsigned long value; 31 32 value = strtoul(str, &e, 10); 33 if (*e != 0 && *e != '.' && *e != units) { 34 return DNS_R_SYNTAX; 35 } 36 if (value > max) { 37 return ISC_R_RANGE; 38 } 39 ok = e != str; 40 if (*e == '.') { 41 e++; 42 for (i = 0; i < precision; i++) { 43 if (*e == 0 || *e == units) { 44 break; 45 } 46 if ((tmp = decvalue(*e++)) < 0) { 47 return DNS_R_SYNTAX; 48 } 49 ok = true; 50 value *= 10; 51 value += tmp; 52 } 53 for (; i < precision; i++) { 54 value *= 10; 55 } 56 } else { 57 for (i = 0; i < precision; i++) { 58 value *= 10; 59 } 60 } 61 if (*e != 0 && *e == units) { 62 e++; 63 } 64 if (!ok || *e != 0) { 65 return DNS_R_SYNTAX; 66 } 67 *valuep = value; 68 return ISC_R_SUCCESS; 69 } 70 71 static isc_result_t 72 loc_getprecision(const char *str, unsigned char *valuep) { 73 unsigned long poweroften[8] = { 1, 10, 100, 1000, 74 10000, 100000, 1000000, 10000000 }; 75 unsigned long m, cm; 76 bool ok; 77 char *e; 78 size_t i; 79 long tmp; 80 int man; 81 int exp; 82 83 m = strtoul(str, &e, 10); 84 if (*e != 0 && *e != '.' && *e != 'm') { 85 return DNS_R_SYNTAX; 86 } 87 if (m > 90000000) { 88 return ISC_R_RANGE; 89 } 90 cm = 0; 91 ok = e != str; 92 if (*e == '.') { 93 e++; 94 for (i = 0; i < 2; i++) { 95 if (*e == 0 || *e == 'm') { 96 break; 97 } 98 if ((tmp = decvalue(*e++)) < 0) { 99 return DNS_R_SYNTAX; 100 } 101 ok = true; 102 cm *= 10; 103 cm += tmp; 104 } 105 for (; i < 2; i++) { 106 cm *= 10; 107 } 108 } 109 if (*e == 'm') { 110 e++; 111 } 112 if (!ok || *e != 0) { 113 return DNS_R_SYNTAX; 114 } 115 116 /* 117 * We don't just multiply out as we will overflow. 118 */ 119 if (m > 0) { 120 for (exp = 0; exp < 7; exp++) { 121 if (m < poweroften[exp + 1]) { 122 break; 123 } 124 } 125 man = m / poweroften[exp]; 126 exp += 2; 127 } else if (cm >= 10) { 128 man = cm / 10; 129 exp = 1; 130 } else { 131 man = cm; 132 exp = 0; 133 } 134 *valuep = (man << 4) + exp; 135 return ISC_R_SUCCESS; 136 } 137 138 static isc_result_t 139 get_degrees(isc_lex_t *lexer, isc_token_t *token, unsigned long *d) { 140 RETERR(isc_lex_getmastertoken(lexer, token, isc_tokentype_number, 141 false)); 142 *d = token->value.as_ulong; 143 144 return ISC_R_SUCCESS; 145 } 146 147 static isc_result_t 148 check_coordinate(unsigned long d, unsigned long m, unsigned long s, 149 unsigned long maxd) { 150 if (d > maxd || m > 59U) { 151 return ISC_R_RANGE; 152 } 153 if (d == maxd && (m != 0 || s != 0)) { 154 return ISC_R_RANGE; 155 } 156 157 return ISC_R_SUCCESS; 158 } 159 160 static isc_result_t 161 get_minutes(isc_lex_t *lexer, isc_token_t *token, unsigned long *m) { 162 RETERR(isc_lex_getmastertoken(lexer, token, isc_tokentype_number, 163 false)); 164 165 *m = token->value.as_ulong; 166 167 return ISC_R_SUCCESS; 168 } 169 170 static isc_result_t 171 get_seconds(isc_lex_t *lexer, isc_token_t *token, unsigned long *s) { 172 RETERR(isc_lex_getmastertoken(lexer, token, isc_tokentype_string, 173 false)); 174 RETERR(loc_getdecimal(DNS_AS_STR(*token), 59, 3, '\0', s)); 175 176 return ISC_R_SUCCESS; 177 } 178 179 static isc_result_t 180 get_direction(isc_lex_t *lexer, isc_token_t *token, const char *directions, 181 int *direction) { 182 RETERR(isc_lex_getmastertoken(lexer, token, isc_tokentype_string, 183 false)); 184 if (DNS_AS_STR(*token)[0] == directions[1] && 185 DNS_AS_STR(*token)[1] == 0) 186 { 187 *direction = DNS_AS_STR(*token)[0]; 188 return ISC_R_SUCCESS; 189 } 190 191 if (DNS_AS_STR(*token)[0] == directions[0] && 192 DNS_AS_STR(*token)[1] == 0) 193 { 194 *direction = DNS_AS_STR(*token)[0]; 195 return ISC_R_SUCCESS; 196 } 197 198 *direction = 0; 199 isc_lex_ungettoken(lexer, token); 200 return ISC_R_SUCCESS; 201 } 202 203 static isc_result_t 204 loc_getcoordinate(isc_lex_t *lexer, unsigned long *dp, unsigned long *mp, 205 unsigned long *sp, const char *directions, int *directionp, 206 unsigned long maxd) { 207 isc_result_t result = ISC_R_SUCCESS; 208 isc_token_t token; 209 unsigned long d, m, s; 210 int direction = 0; 211 212 m = 0; 213 s = 0; 214 215 /* 216 * Degrees. 217 */ 218 RETERR(get_degrees(lexer, &token, &d)); 219 RETTOK(check_coordinate(d, m, s, maxd)); 220 221 /* 222 * Minutes. 223 */ 224 RETERR(get_direction(lexer, &token, directions, &direction)); 225 if (direction > 0) { 226 goto done; 227 } 228 229 RETERR(get_minutes(lexer, &token, &m)); 230 RETTOK(check_coordinate(d, m, s, maxd)); 231 232 /* 233 * Seconds. 234 */ 235 RETERR(get_direction(lexer, &token, directions, &direction)); 236 if (direction > 0) { 237 goto done; 238 } 239 240 result = get_seconds(lexer, &token, &s); 241 if (result == ISC_R_RANGE || result == DNS_R_SYNTAX) { 242 RETTOK(result); 243 } 244 RETERR(result); 245 RETTOK(check_coordinate(d, m, s, maxd)); 246 247 /* 248 * Direction. 249 */ 250 RETERR(get_direction(lexer, &token, directions, &direction)); 251 if (direction == 0) { 252 RETERR(DNS_R_SYNTAX); 253 } 254 done: 255 256 *directionp = direction; 257 *dp = d; 258 *mp = m; 259 *sp = s; 260 261 return ISC_R_SUCCESS; 262 } 263 264 static isc_result_t 265 loc_getlatitude(isc_lex_t *lexer, unsigned long *latitude) { 266 unsigned long d1 = 0, m1 = 0, s1 = 0; 267 int direction = 0; 268 269 RETERR(loc_getcoordinate(lexer, &d1, &m1, &s1, "SN", &direction, 90U)); 270 271 switch (direction) { 272 case 'N': 273 *latitude = 0x80000000 + (d1 * 3600 + m1 * 60) * 1000 + s1; 274 break; 275 case 'S': 276 *latitude = 0x80000000 - (d1 * 3600 + m1 * 60) * 1000 - s1; 277 break; 278 default: 279 UNREACHABLE(); 280 } 281 282 return ISC_R_SUCCESS; 283 } 284 285 static isc_result_t 286 loc_getlongitude(isc_lex_t *lexer, unsigned long *longitude) { 287 unsigned long d2 = 0, m2 = 0, s2 = 0; 288 int direction = 0; 289 290 RETERR(loc_getcoordinate(lexer, &d2, &m2, &s2, "WE", &direction, 180U)); 291 292 switch (direction) { 293 case 'E': 294 *longitude = 0x80000000 + (d2 * 3600 + m2 * 60) * 1000 + s2; 295 break; 296 case 'W': 297 *longitude = 0x80000000 - (d2 * 3600 + m2 * 60) * 1000 - s2; 298 break; 299 default: 300 UNREACHABLE(); 301 } 302 303 return ISC_R_SUCCESS; 304 } 305 306 static isc_result_t 307 loc_getaltitude(isc_lex_t *lexer, unsigned long *altitude) { 308 isc_token_t token; 309 unsigned long cm; 310 const char *str; 311 312 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 313 false)); 314 str = DNS_AS_STR(token); 315 if (DNS_AS_STR(token)[0] == '-') { 316 RETTOK(loc_getdecimal(str + 1, 100000, 2, 'm', &cm)); 317 if (cm > 10000000UL) { 318 RETTOK(ISC_R_RANGE); 319 } 320 *altitude = 10000000 - cm; 321 } else { 322 RETTOK(loc_getdecimal(str, 42849672, 2, 'm', &cm)); 323 if (cm > 4284967295UL) { 324 RETTOK(ISC_R_RANGE); 325 } 326 *altitude = 10000000 + cm; 327 } 328 329 return ISC_R_SUCCESS; 330 } 331 332 static isc_result_t 333 loc_getoptionalprecision(isc_lex_t *lexer, unsigned char *valuep) { 334 isc_token_t token; 335 336 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 337 true)); 338 if (token.type == isc_tokentype_eol || token.type == isc_tokentype_eof) 339 { 340 isc_lex_ungettoken(lexer, &token); 341 return ISC_R_NOMORE; 342 } 343 RETTOK(loc_getprecision(DNS_AS_STR(token), valuep)); 344 345 return ISC_R_SUCCESS; 346 } 347 348 static isc_result_t 349 loc_getsize(isc_lex_t *lexer, unsigned char *sizep) { 350 return loc_getoptionalprecision(lexer, sizep); 351 } 352 353 static isc_result_t 354 loc_gethorizontalprecision(isc_lex_t *lexer, unsigned char *hpp) { 355 return loc_getoptionalprecision(lexer, hpp); 356 } 357 358 static isc_result_t 359 loc_getverticalprecision(isc_lex_t *lexer, unsigned char *vpp) { 360 return loc_getoptionalprecision(lexer, vpp); 361 } 362 363 /* The LOC record is expressed in a master file in the following format: 364 * 365 * <owner> <TTL> <class> LOC ( d1 [m1 [s1]] {"N"|"S"} d2 [m2 [s2]] 366 * {"E"|"W"} alt["m"] [siz["m"] [hp["m"] 367 * [vp["m"]]]] ) 368 * 369 * (The parentheses are used for multi-line data as specified in [RFC 370 * 1035] section 5.1.) 371 * 372 * where: 373 * 374 * d1: [0 .. 90] (degrees latitude) 375 * d2: [0 .. 180] (degrees longitude) 376 * m1, m2: [0 .. 59] (minutes latitude/longitude) 377 * s1, s2: [0 .. 59.999] (seconds latitude/longitude) 378 * alt: [-100000.00 .. 42849672.95] BY .01 (altitude in meters) 379 * siz, hp, vp: [0 .. 90000000.00] (size/precision in meters) 380 * 381 * If omitted, minutes and seconds default to zero, size defaults to 1m, 382 * horizontal precision defaults to 10000m, and vertical precision 383 * defaults to 10m. These defaults are chosen to represent typical 384 * ZIP/postal code area sizes, since it is often easy to find 385 * approximate geographical location by ZIP/postal code. 386 */ 387 static isc_result_t 388 fromtext_loc(ARGS_FROMTEXT) { 389 isc_result_t result = ISC_R_SUCCESS; 390 unsigned long latitude = 0; 391 unsigned long longitude = 0; 392 unsigned long altitude = 0; 393 unsigned char size = 0x12; /* Default: 1.00m */ 394 unsigned char hp = 0x16; /* Default: 10000.00 m */ 395 unsigned char vp = 0x13; /* Default: 10.00 m */ 396 unsigned char version = 0; 397 398 REQUIRE(type == dns_rdatatype_loc); 399 400 UNUSED(type); 401 UNUSED(rdclass); 402 UNUSED(origin); 403 UNUSED(options); 404 UNUSED(callbacks); 405 406 RETERR(loc_getlatitude(lexer, &latitude)); 407 RETERR(loc_getlongitude(lexer, &longitude)); 408 RETERR(loc_getaltitude(lexer, &altitude)); 409 result = loc_getsize(lexer, &size); 410 if (result == ISC_R_NOMORE) { 411 result = ISC_R_SUCCESS; 412 goto encode; 413 } 414 RETERR(result); 415 result = loc_gethorizontalprecision(lexer, &hp); 416 if (result == ISC_R_NOMORE) { 417 result = ISC_R_SUCCESS; 418 goto encode; 419 } 420 RETERR(result); 421 result = loc_getverticalprecision(lexer, &vp); 422 if (result == ISC_R_NOMORE) { 423 result = ISC_R_SUCCESS; 424 goto encode; 425 } 426 RETERR(result); 427 encode: 428 RETERR(mem_tobuffer(target, &version, 1)); 429 RETERR(mem_tobuffer(target, &size, 1)); 430 RETERR(mem_tobuffer(target, &hp, 1)); 431 RETERR(mem_tobuffer(target, &vp, 1)); 432 433 RETERR(uint32_tobuffer(latitude, target)); 434 RETERR(uint32_tobuffer(longitude, target)); 435 RETERR(uint32_tobuffer(altitude, target)); 436 437 return result; 438 } 439 440 static isc_result_t 441 totext_loc(ARGS_TOTEXT) { 442 int d1, m1, s1, fs1; 443 int d2, m2, s2, fs2; 444 unsigned long latitude; 445 unsigned long longitude; 446 unsigned long altitude; 447 bool north; 448 bool east; 449 bool below; 450 isc_region_t sr; 451 char sbuf[sizeof("90000000m")]; 452 char hbuf[sizeof("90000000m")]; 453 char vbuf[sizeof("90000000m")]; 454 /* "89 59 59.999 N 179 59 59.999 E " */ 455 /* "-42849672.95m 90000000m 90000000m 90000000m"; */ 456 char buf[8 * 6 + 12 * 1 + 2 * 10 + sizeof(sbuf) + sizeof(hbuf) + 457 sizeof(vbuf)]; 458 unsigned char size, hp, vp; 459 unsigned long poweroften[8] = { 1, 10, 100, 1000, 460 10000, 100000, 1000000, 10000000 }; 461 462 UNUSED(tctx); 463 464 REQUIRE(rdata->type == dns_rdatatype_loc); 465 REQUIRE(rdata->length != 0); 466 467 dns_rdata_toregion(rdata, &sr); 468 469 if (sr.base[0] != 0) { 470 return ISC_R_NOTIMPLEMENTED; 471 } 472 473 REQUIRE(rdata->length == 16); 474 475 size = sr.base[1]; 476 INSIST((size & 0x0f) < 10 && (size >> 4) < 10); 477 if ((size & 0x0f) > 1) { 478 snprintf(sbuf, sizeof(sbuf), "%lum", 479 (size >> 4) * poweroften[(size & 0x0f) - 2]); 480 } else { 481 snprintf(sbuf, sizeof(sbuf), "0.%02lum", 482 (size >> 4) * poweroften[(size & 0x0f)]); 483 } 484 hp = sr.base[2]; 485 INSIST((hp & 0x0f) < 10 && (hp >> 4) < 10); 486 if ((hp & 0x0f) > 1) { 487 snprintf(hbuf, sizeof(hbuf), "%lum", 488 (hp >> 4) * poweroften[(hp & 0x0f) - 2]); 489 } else { 490 snprintf(hbuf, sizeof(hbuf), "0.%02lum", 491 (hp >> 4) * poweroften[(hp & 0x0f)]); 492 } 493 vp = sr.base[3]; 494 INSIST((vp & 0x0f) < 10 && (vp >> 4) < 10); 495 if ((vp & 0x0f) > 1) { 496 snprintf(vbuf, sizeof(vbuf), "%lum", 497 (vp >> 4) * poweroften[(vp & 0x0f) - 2]); 498 } else { 499 snprintf(vbuf, sizeof(vbuf), "0.%02lum", 500 (vp >> 4) * poweroften[(vp & 0x0f)]); 501 } 502 isc_region_consume(&sr, 4); 503 504 latitude = uint32_fromregion(&sr); 505 isc_region_consume(&sr, 4); 506 if (latitude >= 0x80000000) { 507 north = true; 508 latitude -= 0x80000000; 509 } else { 510 north = false; 511 latitude = 0x80000000 - latitude; 512 } 513 fs1 = (int)(latitude % 1000); 514 latitude /= 1000; 515 s1 = (int)(latitude % 60); 516 latitude /= 60; 517 m1 = (int)(latitude % 60); 518 latitude /= 60; 519 d1 = (int)latitude; 520 INSIST(latitude <= 90U); 521 522 longitude = uint32_fromregion(&sr); 523 isc_region_consume(&sr, 4); 524 if (longitude >= 0x80000000) { 525 east = true; 526 longitude -= 0x80000000; 527 } else { 528 east = false; 529 longitude = 0x80000000 - longitude; 530 } 531 fs2 = (int)(longitude % 1000); 532 longitude /= 1000; 533 s2 = (int)(longitude % 60); 534 longitude /= 60; 535 m2 = (int)(longitude % 60); 536 longitude /= 60; 537 d2 = (int)longitude; 538 INSIST(longitude <= 180U); 539 540 altitude = uint32_fromregion(&sr); 541 isc_region_consume(&sr, 4); 542 if (altitude < 10000000U) { 543 below = true; 544 altitude = 10000000 - altitude; 545 } else { 546 below = false; 547 altitude -= 10000000; 548 } 549 550 snprintf(buf, sizeof(buf), 551 "%d %d %d.%03d %s %d %d %d.%03d %s %s%lu.%02lum %s %s %s", d1, 552 m1, s1, fs1, north ? "N" : "S", d2, m2, s2, fs2, 553 east ? "E" : "W", below ? "-" : "", altitude / 100, 554 altitude % 100, sbuf, hbuf, vbuf); 555 556 return str_totext(buf, target); 557 } 558 559 static isc_result_t 560 fromwire_loc(ARGS_FROMWIRE) { 561 isc_region_t sr; 562 unsigned char c; 563 unsigned long latitude; 564 unsigned long longitude; 565 566 REQUIRE(type == dns_rdatatype_loc); 567 568 UNUSED(type); 569 UNUSED(rdclass); 570 UNUSED(dctx); 571 572 isc_buffer_activeregion(source, &sr); 573 if (sr.length < 1) { 574 return ISC_R_UNEXPECTEDEND; 575 } 576 if (sr.base[0] != 0) { 577 /* Treat as unknown. */ 578 isc_buffer_forward(source, sr.length); 579 return mem_tobuffer(target, sr.base, sr.length); 580 } 581 if (sr.length < 16) { 582 return ISC_R_UNEXPECTEDEND; 583 } 584 585 /* 586 * Size. 587 */ 588 c = sr.base[1]; 589 if (c != 0) { 590 if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 || 591 ((c >> 4) & 0xf) == 0) 592 { 593 return ISC_R_RANGE; 594 595 /* 596 * Horizontal precision. 597 */ 598 } 599 } 600 601 /* 602 * Horizontal precision. 603 */ 604 c = sr.base[2]; 605 if (c != 0) { 606 if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 || 607 ((c >> 4) & 0xf) == 0) 608 { 609 return ISC_R_RANGE; 610 611 /* 612 * Vertical precision. 613 */ 614 } 615 } 616 617 /* 618 * Vertical precision. 619 */ 620 c = sr.base[3]; 621 if (c != 0) { 622 if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 || 623 ((c >> 4) & 0xf) == 0) 624 { 625 return ISC_R_RANGE; 626 } 627 } 628 isc_region_consume(&sr, 4); 629 630 /* 631 * Latitude. 632 */ 633 latitude = uint32_fromregion(&sr); 634 if (latitude < (0x80000000UL - 90 * 3600000) || 635 latitude > (0x80000000UL + 90 * 3600000)) 636 { 637 return ISC_R_RANGE; 638 } 639 isc_region_consume(&sr, 4); 640 641 /* 642 * Longitude. 643 */ 644 longitude = uint32_fromregion(&sr); 645 if (longitude < (0x80000000UL - 180 * 3600000) || 646 longitude > (0x80000000UL + 180 * 3600000)) 647 { 648 return ISC_R_RANGE; 649 } 650 651 /* 652 * Altitude. 653 * All values possible. 654 */ 655 656 isc_buffer_activeregion(source, &sr); 657 isc_buffer_forward(source, 16); 658 return mem_tobuffer(target, sr.base, 16); 659 } 660 661 static isc_result_t 662 towire_loc(ARGS_TOWIRE) { 663 UNUSED(cctx); 664 665 REQUIRE(rdata->type == dns_rdatatype_loc); 666 REQUIRE(rdata->length != 0); 667 668 return mem_tobuffer(target, rdata->data, rdata->length); 669 } 670 671 static int 672 compare_loc(ARGS_COMPARE) { 673 isc_region_t r1; 674 isc_region_t r2; 675 676 REQUIRE(rdata1->type == rdata2->type); 677 REQUIRE(rdata1->rdclass == rdata2->rdclass); 678 REQUIRE(rdata1->type == dns_rdatatype_loc); 679 REQUIRE(rdata1->length != 0); 680 REQUIRE(rdata2->length != 0); 681 682 dns_rdata_toregion(rdata1, &r1); 683 dns_rdata_toregion(rdata2, &r2); 684 return isc_region_compare(&r1, &r2); 685 } 686 687 static isc_result_t 688 fromstruct_loc(ARGS_FROMSTRUCT) { 689 dns_rdata_loc_t *loc = source; 690 uint8_t c; 691 692 REQUIRE(type == dns_rdatatype_loc); 693 REQUIRE(loc != NULL); 694 REQUIRE(loc->common.rdtype == type); 695 REQUIRE(loc->common.rdclass == rdclass); 696 697 UNUSED(type); 698 UNUSED(rdclass); 699 700 if (loc->v.v0.version != 0) { 701 return ISC_R_NOTIMPLEMENTED; 702 } 703 RETERR(uint8_tobuffer(loc->v.v0.version, target)); 704 705 c = loc->v.v0.size; 706 if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 || ((c >> 4) & 0xf) == 0) { 707 return ISC_R_RANGE; 708 } 709 RETERR(uint8_tobuffer(loc->v.v0.size, target)); 710 711 c = loc->v.v0.horizontal; 712 if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 || ((c >> 4) & 0xf) == 0) { 713 return ISC_R_RANGE; 714 } 715 RETERR(uint8_tobuffer(loc->v.v0.horizontal, target)); 716 717 c = loc->v.v0.vertical; 718 if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 || ((c >> 4) & 0xf) == 0) { 719 return ISC_R_RANGE; 720 } 721 RETERR(uint8_tobuffer(loc->v.v0.vertical, target)); 722 723 if (loc->v.v0.latitude < (0x80000000UL - 90 * 3600000) || 724 loc->v.v0.latitude > (0x80000000UL + 90 * 3600000)) 725 { 726 return ISC_R_RANGE; 727 } 728 RETERR(uint32_tobuffer(loc->v.v0.latitude, target)); 729 730 if (loc->v.v0.longitude < (0x80000000UL - 180 * 3600000) || 731 loc->v.v0.longitude > (0x80000000UL + 180 * 3600000)) 732 { 733 return ISC_R_RANGE; 734 } 735 RETERR(uint32_tobuffer(loc->v.v0.longitude, target)); 736 return uint32_tobuffer(loc->v.v0.altitude, target); 737 } 738 739 static isc_result_t 740 tostruct_loc(ARGS_TOSTRUCT) { 741 dns_rdata_loc_t *loc = target; 742 isc_region_t r; 743 uint8_t version; 744 745 REQUIRE(rdata->type == dns_rdatatype_loc); 746 REQUIRE(loc != NULL); 747 REQUIRE(rdata->length != 0); 748 749 UNUSED(mctx); 750 751 dns_rdata_toregion(rdata, &r); 752 version = uint8_fromregion(&r); 753 if (version != 0) { 754 return ISC_R_NOTIMPLEMENTED; 755 } 756 757 loc->common.rdclass = rdata->rdclass; 758 loc->common.rdtype = rdata->type; 759 ISC_LINK_INIT(&loc->common, link); 760 761 loc->v.v0.version = version; 762 isc_region_consume(&r, 1); 763 loc->v.v0.size = uint8_fromregion(&r); 764 isc_region_consume(&r, 1); 765 loc->v.v0.horizontal = uint8_fromregion(&r); 766 isc_region_consume(&r, 1); 767 loc->v.v0.vertical = uint8_fromregion(&r); 768 isc_region_consume(&r, 1); 769 loc->v.v0.latitude = uint32_fromregion(&r); 770 isc_region_consume(&r, 4); 771 loc->v.v0.longitude = uint32_fromregion(&r); 772 isc_region_consume(&r, 4); 773 loc->v.v0.altitude = uint32_fromregion(&r); 774 isc_region_consume(&r, 4); 775 return ISC_R_SUCCESS; 776 } 777 778 static void 779 freestruct_loc(ARGS_FREESTRUCT) { 780 dns_rdata_loc_t *loc = source; 781 782 REQUIRE(loc != NULL); 783 REQUIRE(loc->common.rdtype == dns_rdatatype_loc); 784 785 UNUSED(source); 786 UNUSED(loc); 787 } 788 789 static isc_result_t 790 additionaldata_loc(ARGS_ADDLDATA) { 791 REQUIRE(rdata->type == dns_rdatatype_loc); 792 793 UNUSED(rdata); 794 UNUSED(owner); 795 UNUSED(add); 796 UNUSED(arg); 797 798 return ISC_R_SUCCESS; 799 } 800 801 static isc_result_t 802 digest_loc(ARGS_DIGEST) { 803 isc_region_t r; 804 805 REQUIRE(rdata->type == dns_rdatatype_loc); 806 807 dns_rdata_toregion(rdata, &r); 808 809 return (digest)(arg, &r); 810 } 811 812 static bool 813 checkowner_loc(ARGS_CHECKOWNER) { 814 REQUIRE(type == dns_rdatatype_loc); 815 816 UNUSED(name); 817 UNUSED(type); 818 UNUSED(rdclass); 819 UNUSED(wildcard); 820 821 return true; 822 } 823 824 static bool 825 checknames_loc(ARGS_CHECKNAMES) { 826 REQUIRE(rdata->type == dns_rdatatype_loc); 827 828 UNUSED(rdata); 829 UNUSED(owner); 830 UNUSED(bad); 831 832 return true; 833 } 834 835 static int 836 casecompare_loc(ARGS_COMPARE) { 837 return compare_loc(rdata1, rdata2); 838 } 839 840 #endif /* RDATA_GENERIC_LOC_29_C */ 841