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