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