1 /* $NetBSD: loc_29.c,v 1.9 2023/01/25 21:43:30 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
loc_getdecimal(const char * str,unsigned long max,size_t precision,char units,unsigned long * valuep)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
loc_getprecision(const char * str,unsigned char * valuep)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
get_degrees(isc_lex_t * lexer,isc_token_t * token,unsigned long * d)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
check_coordinate(unsigned long d,unsigned long m,unsigned long s,unsigned long maxd)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
get_minutes(isc_lex_t * lexer,isc_token_t * token,unsigned long * m)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
get_seconds(isc_lex_t * lexer,isc_token_t * token,unsigned long * s)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
get_direction(isc_lex_t * lexer,isc_token_t * token,const char * directions,int * direction)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
loc_getcoordinate(isc_lex_t * lexer,unsigned long * dp,unsigned long * mp,unsigned long * sp,const char * directions,int * directionp,unsigned long maxd)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
loc_getlatitude(isc_lex_t * lexer,unsigned long * latitude)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
loc_getlongitude(isc_lex_t * lexer,unsigned long * longitude)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
loc_getaltitude(isc_lex_t * lexer,unsigned long * altitude)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
loc_getoptionalprecision(isc_lex_t * lexer,unsigned char * valuep)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
loc_getsize(isc_lex_t * lexer,unsigned char * sizep)349 loc_getsize(isc_lex_t *lexer, unsigned char *sizep) {
350 return (loc_getoptionalprecision(lexer, sizep));
351 }
352
353 static isc_result_t
loc_gethorizontalprecision(isc_lex_t * lexer,unsigned char * hpp)354 loc_gethorizontalprecision(isc_lex_t *lexer, unsigned char *hpp) {
355 return (loc_getoptionalprecision(lexer, hpp));
356 }
357
358 static isc_result_t
loc_getverticalprecision(isc_lex_t * lexer,unsigned char * vpp)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
fromtext_loc(ARGS_FROMTEXT)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
totext_loc(ARGS_TOTEXT)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
fromwire_loc(ARGS_FROMWIRE)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 UNUSED(options);
572
573 isc_buffer_activeregion(source, &sr);
574 if (sr.length < 1) {
575 return (ISC_R_UNEXPECTEDEND);
576 }
577 if (sr.base[0] != 0) {
578 /* Treat as unknown. */
579 isc_buffer_forward(source, sr.length);
580 return (mem_tobuffer(target, sr.base, sr.length));
581 }
582 if (sr.length < 16) {
583 return (ISC_R_UNEXPECTEDEND);
584 }
585
586 /*
587 * Size.
588 */
589 c = sr.base[1];
590 if (c != 0) {
591 if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 ||
592 ((c >> 4) & 0xf) == 0)
593 {
594 return (ISC_R_RANGE);
595
596 /*
597 * Horizontal precision.
598 */
599 }
600 }
601
602 /*
603 * Horizontal precision.
604 */
605 c = sr.base[2];
606 if (c != 0) {
607 if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 ||
608 ((c >> 4) & 0xf) == 0)
609 {
610 return (ISC_R_RANGE);
611
612 /*
613 * Vertical precision.
614 */
615 }
616 }
617
618 /*
619 * Vertical precision.
620 */
621 c = sr.base[3];
622 if (c != 0) {
623 if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 ||
624 ((c >> 4) & 0xf) == 0)
625 {
626 return (ISC_R_RANGE);
627 }
628 }
629 isc_region_consume(&sr, 4);
630
631 /*
632 * Latitude.
633 */
634 latitude = uint32_fromregion(&sr);
635 if (latitude < (0x80000000UL - 90 * 3600000) ||
636 latitude > (0x80000000UL + 90 * 3600000))
637 {
638 return (ISC_R_RANGE);
639 }
640 isc_region_consume(&sr, 4);
641
642 /*
643 * Longitude.
644 */
645 longitude = uint32_fromregion(&sr);
646 if (longitude < (0x80000000UL - 180 * 3600000) ||
647 longitude > (0x80000000UL + 180 * 3600000))
648 {
649 return (ISC_R_RANGE);
650 }
651
652 /*
653 * Altitude.
654 * All values possible.
655 */
656
657 isc_buffer_activeregion(source, &sr);
658 isc_buffer_forward(source, 16);
659 return (mem_tobuffer(target, sr.base, 16));
660 }
661
662 static isc_result_t
towire_loc(ARGS_TOWIRE)663 towire_loc(ARGS_TOWIRE) {
664 UNUSED(cctx);
665
666 REQUIRE(rdata->type == dns_rdatatype_loc);
667 REQUIRE(rdata->length != 0);
668
669 return (mem_tobuffer(target, rdata->data, rdata->length));
670 }
671
672 static int
compare_loc(ARGS_COMPARE)673 compare_loc(ARGS_COMPARE) {
674 isc_region_t r1;
675 isc_region_t r2;
676
677 REQUIRE(rdata1->type == rdata2->type);
678 REQUIRE(rdata1->rdclass == rdata2->rdclass);
679 REQUIRE(rdata1->type == dns_rdatatype_loc);
680 REQUIRE(rdata1->length != 0);
681 REQUIRE(rdata2->length != 0);
682
683 dns_rdata_toregion(rdata1, &r1);
684 dns_rdata_toregion(rdata2, &r2);
685 return (isc_region_compare(&r1, &r2));
686 }
687
688 static isc_result_t
fromstruct_loc(ARGS_FROMSTRUCT)689 fromstruct_loc(ARGS_FROMSTRUCT) {
690 dns_rdata_loc_t *loc = source;
691 uint8_t c;
692
693 REQUIRE(type == dns_rdatatype_loc);
694 REQUIRE(loc != NULL);
695 REQUIRE(loc->common.rdtype == type);
696 REQUIRE(loc->common.rdclass == rdclass);
697
698 UNUSED(type);
699 UNUSED(rdclass);
700
701 if (loc->v.v0.version != 0) {
702 return (ISC_R_NOTIMPLEMENTED);
703 }
704 RETERR(uint8_tobuffer(loc->v.v0.version, target));
705
706 c = loc->v.v0.size;
707 if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 || ((c >> 4) & 0xf) == 0) {
708 return (ISC_R_RANGE);
709 }
710 RETERR(uint8_tobuffer(loc->v.v0.size, target));
711
712 c = loc->v.v0.horizontal;
713 if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 || ((c >> 4) & 0xf) == 0) {
714 return (ISC_R_RANGE);
715 }
716 RETERR(uint8_tobuffer(loc->v.v0.horizontal, target));
717
718 c = loc->v.v0.vertical;
719 if ((c & 0xf) > 9 || ((c >> 4) & 0xf) > 9 || ((c >> 4) & 0xf) == 0) {
720 return (ISC_R_RANGE);
721 }
722 RETERR(uint8_tobuffer(loc->v.v0.vertical, target));
723
724 if (loc->v.v0.latitude < (0x80000000UL - 90 * 3600000) ||
725 loc->v.v0.latitude > (0x80000000UL + 90 * 3600000))
726 {
727 return (ISC_R_RANGE);
728 }
729 RETERR(uint32_tobuffer(loc->v.v0.latitude, target));
730
731 if (loc->v.v0.longitude < (0x80000000UL - 180 * 3600000) ||
732 loc->v.v0.longitude > (0x80000000UL + 180 * 3600000))
733 {
734 return (ISC_R_RANGE);
735 }
736 RETERR(uint32_tobuffer(loc->v.v0.longitude, target));
737 return (uint32_tobuffer(loc->v.v0.altitude, target));
738 }
739
740 static isc_result_t
tostruct_loc(ARGS_TOSTRUCT)741 tostruct_loc(ARGS_TOSTRUCT) {
742 dns_rdata_loc_t *loc = target;
743 isc_region_t r;
744 uint8_t version;
745
746 REQUIRE(rdata->type == dns_rdatatype_loc);
747 REQUIRE(loc != NULL);
748 REQUIRE(rdata->length != 0);
749
750 UNUSED(mctx);
751
752 dns_rdata_toregion(rdata, &r);
753 version = uint8_fromregion(&r);
754 if (version != 0) {
755 return (ISC_R_NOTIMPLEMENTED);
756 }
757
758 loc->common.rdclass = rdata->rdclass;
759 loc->common.rdtype = rdata->type;
760 ISC_LINK_INIT(&loc->common, link);
761
762 loc->v.v0.version = version;
763 isc_region_consume(&r, 1);
764 loc->v.v0.size = uint8_fromregion(&r);
765 isc_region_consume(&r, 1);
766 loc->v.v0.horizontal = uint8_fromregion(&r);
767 isc_region_consume(&r, 1);
768 loc->v.v0.vertical = uint8_fromregion(&r);
769 isc_region_consume(&r, 1);
770 loc->v.v0.latitude = uint32_fromregion(&r);
771 isc_region_consume(&r, 4);
772 loc->v.v0.longitude = uint32_fromregion(&r);
773 isc_region_consume(&r, 4);
774 loc->v.v0.altitude = uint32_fromregion(&r);
775 isc_region_consume(&r, 4);
776 return (ISC_R_SUCCESS);
777 }
778
779 static void
freestruct_loc(ARGS_FREESTRUCT)780 freestruct_loc(ARGS_FREESTRUCT) {
781 dns_rdata_loc_t *loc = source;
782
783 REQUIRE(loc != NULL);
784 REQUIRE(loc->common.rdtype == dns_rdatatype_loc);
785
786 UNUSED(source);
787 UNUSED(loc);
788 }
789
790 static isc_result_t
additionaldata_loc(ARGS_ADDLDATA)791 additionaldata_loc(ARGS_ADDLDATA) {
792 REQUIRE(rdata->type == dns_rdatatype_loc);
793
794 UNUSED(rdata);
795 UNUSED(add);
796 UNUSED(arg);
797
798 return (ISC_R_SUCCESS);
799 }
800
801 static isc_result_t
digest_loc(ARGS_DIGEST)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
checkowner_loc(ARGS_CHECKOWNER)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
checknames_loc(ARGS_CHECKNAMES)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
casecompare_loc(ARGS_COMPARE)836 casecompare_loc(ARGS_COMPARE) {
837 return (compare_loc(rdata1, rdata2));
838 }
839
840 #endif /* RDATA_GENERIC_LOC_29_C */
841