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