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