1/*
2 * Copyright (C) 2004, 2005, 2007, 2009  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id: loc_29.c,v 1.50 2009/12/04 21:09:33 marka Exp $ */
19
20/* Reviewed: Wed Mar 15 18:13:09 PST 2000 by explorer */
21
22/* RFC1876 */
23
24#ifndef RDATA_GENERIC_LOC_29_C
25#define RDATA_GENERIC_LOC_29_C
26
27#define RRTYPE_LOC_ATTRIBUTES (0)
28
29static inline isc_result_t
30fromtext_loc(ARGS_FROMTEXT) {
31	isc_token_t token;
32	int d1, m1, s1;
33	int d2, m2, s2;
34	unsigned char size;
35	unsigned char hp;
36	unsigned char vp;
37	unsigned char version;
38	isc_boolean_t east = ISC_FALSE;
39	isc_boolean_t north = ISC_FALSE;
40	long tmp;
41	long m;
42	long cm;
43	long poweroften[8] = { 1, 10, 100, 1000,
44			       10000, 100000, 1000000, 10000000 };
45	int man;
46	int exp;
47	char *e;
48	int i;
49	unsigned long latitude;
50	unsigned long longitude;
51	unsigned long altitude;
52
53	REQUIRE(type == 29);
54
55	UNUSED(type);
56	UNUSED(rdclass);
57	UNUSED(origin);
58	UNUSED(options);
59
60	/*
61	 * Defaults.
62	 */
63	m1 = s1 = 0;
64	m2 = s2 = 0;
65	size = 0x12;	/* 1.00m */
66	hp = 0x16;	/* 10000.00 m */
67	vp = 0x13;	/* 10.00 m */
68	version = 0;
69
70	/*
71	 * Degrees.
72	 */
73	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
74				      ISC_FALSE));
75	if (token.value.as_ulong > 90U)
76		RETTOK(ISC_R_RANGE);
77	d1 = (int)token.value.as_ulong;
78	/*
79	 * Minutes.
80	 */
81	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
82				      ISC_FALSE));
83	if (strcasecmp(DNS_AS_STR(token), "N") == 0)
84		north = ISC_TRUE;
85	if (north || strcasecmp(DNS_AS_STR(token), "S") == 0)
86		goto getlong;
87	m1 = strtol(DNS_AS_STR(token), &e, 10);
88	if (*e != 0)
89		RETTOK(DNS_R_SYNTAX);
90	if (m1 < 0 || m1 > 59)
91		RETTOK(ISC_R_RANGE);
92	if (d1 == 90 && m1 != 0)
93		RETTOK(ISC_R_RANGE);
94
95	/*
96	 * Seconds.
97	 */
98	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
99				      ISC_FALSE));
100	if (strcasecmp(DNS_AS_STR(token), "N") == 0)
101		north = ISC_TRUE;
102	if (north || strcasecmp(DNS_AS_STR(token), "S") == 0)
103		goto getlong;
104	s1 = strtol(DNS_AS_STR(token), &e, 10);
105	if (*e != 0 && *e != '.')
106		RETTOK(DNS_R_SYNTAX);
107	if (s1 < 0 || s1 > 59)
108		RETTOK(ISC_R_RANGE);
109	if (*e == '.') {
110		const char *l;
111		e++;
112		for (i = 0; i < 3; i++) {
113			if (*e == 0)
114				break;
115			if ((tmp = decvalue(*e++)) < 0)
116				RETTOK(DNS_R_SYNTAX);
117			s1 *= 10;
118			s1 += tmp;
119		}
120		for (; i < 3; i++)
121			s1 *= 10;
122		l = e;
123		while (*e != 0) {
124			if (decvalue(*e++) < 0)
125				RETTOK(DNS_R_SYNTAX);
126		}
127		if (*l != '\0' && callbacks != NULL) {
128			const char *file = isc_lex_getsourcename(lexer);
129			unsigned long line = isc_lex_getsourceline(lexer);
130
131			if (file == NULL)
132				file = "UNKNOWN";
133			(*callbacks->warn)(callbacks, "%s: %s:%u: '%s' extra "
134					   "precision digits ignored",
135					   "dns_rdata_fromtext", file, line,
136					   DNS_AS_STR(token));
137		}
138	} else
139		s1 *= 1000;
140	if (d1 == 90 && s1 != 0)
141		RETTOK(ISC_R_RANGE);
142
143	/*
144	 * Direction.
145	 */
146	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
147				      ISC_FALSE));
148	if (strcasecmp(DNS_AS_STR(token), "N") == 0)
149		north = ISC_TRUE;
150	if (!north && strcasecmp(DNS_AS_STR(token), "S") != 0)
151		RETTOK(DNS_R_SYNTAX);
152
153 getlong:
154	/*
155	 * Degrees.
156	 */
157	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
158				      ISC_FALSE));
159	if (token.value.as_ulong > 180U)
160		RETTOK(ISC_R_RANGE);
161	d2 = (int)token.value.as_ulong;
162
163	/*
164	 * Minutes.
165	 */
166	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
167				      ISC_FALSE));
168	if (strcasecmp(DNS_AS_STR(token), "E") == 0)
169		east = ISC_TRUE;
170	if (east || strcasecmp(DNS_AS_STR(token), "W") == 0)
171		goto getalt;
172	m2 = strtol(DNS_AS_STR(token), &e, 10);
173	if (*e != 0)
174		RETTOK(DNS_R_SYNTAX);
175	if (m2 < 0 || m2 > 59)
176		RETTOK(ISC_R_RANGE);
177	if (d2 == 180 && m2 != 0)
178		RETTOK(ISC_R_RANGE);
179
180	/*
181	 * Seconds.
182	 */
183	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
184				      ISC_FALSE));
185	if (strcasecmp(DNS_AS_STR(token), "E") == 0)
186		east = ISC_TRUE;
187	if (east || strcasecmp(DNS_AS_STR(token), "W") == 0)
188		goto getalt;
189	s2 = strtol(DNS_AS_STR(token), &e, 10);
190	if (*e != 0 && *e != '.')
191		RETTOK(DNS_R_SYNTAX);
192	if (s2 < 0 || s2 > 59)
193		RETTOK(ISC_R_RANGE);
194	if (*e == '.') {
195		const char *l;
196		e++;
197		for (i = 0; i < 3; i++) {
198			if (*e == 0)
199				break;
200			if ((tmp = decvalue(*e++)) < 0)
201				RETTOK(DNS_R_SYNTAX);
202			s2 *= 10;
203			s2 += tmp;
204		}
205		for (; i < 3; i++)
206			s2 *= 10;
207		l = e;
208		while (*e != 0) {
209			if (decvalue(*e++) < 0)
210				RETTOK(DNS_R_SYNTAX);
211		}
212		if (*l != '\0' && callbacks != NULL) {
213			const char *file = isc_lex_getsourcename(lexer);
214			unsigned long line = isc_lex_getsourceline(lexer);
215
216			if (file == NULL)
217				file = "UNKNOWN";
218			(*callbacks->warn)(callbacks, "%s: %s:%u: '%s' extra "
219					   "precision digits ignored",
220					   "dns_rdata_fromtext",
221					   file, line, DNS_AS_STR(token));
222		}
223	} else
224		s2 *= 1000;
225	if (d2 == 180 && s2 != 0)
226		RETTOK(ISC_R_RANGE);
227
228	/*
229	 * Direction.
230	 */
231	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
232				      ISC_FALSE));
233	if (strcasecmp(DNS_AS_STR(token), "E") == 0)
234		east = ISC_TRUE;
235	if (!east && strcasecmp(DNS_AS_STR(token), "W") != 0)
236		RETTOK(DNS_R_SYNTAX);
237
238 getalt:
239	/*
240	 * Altitude.
241	 */
242	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
243				      ISC_FALSE));
244	m = strtol(DNS_AS_STR(token), &e, 10);
245	if (*e != 0 && *e != '.' && *e != 'm')
246		RETTOK(DNS_R_SYNTAX);
247	if (m < -100000 || m > 42849672)
248		RETTOK(ISC_R_RANGE);
249	cm = 0;
250	if (*e == '.') {
251		e++;
252		for (i = 0; i < 2; i++) {
253			if (*e == 0 || *e == 'm')
254				break;
255			if ((tmp = decvalue(*e++)) < 0)
256				return (DNS_R_SYNTAX);
257			cm *= 10;
258			if (m < 0)
259				cm -= tmp;
260			else
261				cm += tmp;
262		}
263		for (; i < 2; i++)
264			cm *= 10;
265	}
266	if (*e == 'm')
267		e++;
268	if (*e != 0)
269		RETTOK(DNS_R_SYNTAX);
270	if (m == -100000 && cm != 0)
271		RETTOK(ISC_R_RANGE);
272	if (m == 42849672 && cm > 95)
273		RETTOK(ISC_R_RANGE);
274	/*
275	 * Adjust base.
276	 */
277	altitude = m + 100000;
278	altitude *= 100;
279	altitude += cm;
280
281	/*
282	 * Size: optional.
283	 */
284	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
285				      ISC_TRUE));
286	if (token.type == isc_tokentype_eol ||
287	    token.type == isc_tokentype_eof) {
288		isc_lex_ungettoken(lexer, &token);
289		goto encode;
290	}
291	m = strtol(DNS_AS_STR(token), &e, 10);
292	if (*e != 0 && *e != '.' && *e != 'm')
293		RETTOK(DNS_R_SYNTAX);
294	if (m < 0 || m > 90000000)
295		RETTOK(ISC_R_RANGE);
296	cm = 0;
297	if (*e == '.') {
298		e++;
299		for (i = 0; i < 2; i++) {
300			if (*e == 0 || *e == 'm')
301				break;
302			if ((tmp = decvalue(*e++)) < 0)
303				RETTOK(DNS_R_SYNTAX);
304			cm *= 10;
305			cm += tmp;
306		}
307		for (; i < 2; i++)
308			cm *= 10;
309	}
310	if (*e == 'm')
311		e++;
312	if (*e != 0)
313		RETTOK(DNS_R_SYNTAX);
314	/*
315	 * We don't just multiply out as we will overflow.
316	 */
317	if (m > 0) {
318		for (exp = 0; exp < 7; exp++)
319			if (m < poweroften[exp+1])
320				break;
321		man = m / poweroften[exp];
322		exp += 2;
323	} else {
324		if (cm >= 10) {
325			man = cm / 10;
326			exp = 1;
327		} else {
328			man = cm;
329			exp = 0;
330		}
331	}
332	size = (man << 4) + exp;
333
334	/*
335	 * Horizontal precision: optional.
336	 */
337	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
338				      ISC_TRUE));
339	if (token.type == isc_tokentype_eol ||
340	    token.type == isc_tokentype_eof) {
341		isc_lex_ungettoken(lexer, &token);
342		goto encode;
343	}
344	m = strtol(DNS_AS_STR(token), &e, 10);
345	if (*e != 0 && *e != '.' && *e != 'm')
346		RETTOK(DNS_R_SYNTAX);
347	if (m < 0 || m > 90000000)
348		RETTOK(ISC_R_RANGE);
349	cm = 0;
350	if (*e == '.') {
351		e++;
352		for (i = 0; i < 2; i++) {
353			if (*e == 0 || *e == 'm')
354				break;
355			if ((tmp = decvalue(*e++)) < 0)
356				RETTOK(DNS_R_SYNTAX);
357			cm *= 10;
358			cm += tmp;
359		}
360		for (; i < 2; i++)
361			cm *= 10;
362	}
363	if (*e == 'm')
364		e++;
365	if (*e != 0)
366		RETTOK(DNS_R_SYNTAX);
367	/*
368	 * We don't just multiply out as we will overflow.
369	 */
370	if (m > 0) {
371		for (exp = 0; exp < 7; exp++)
372			if (m < poweroften[exp+1])
373				break;
374		man = m / poweroften[exp];
375		exp += 2;
376	} else if (cm >= 10) {
377		man = cm / 10;
378		exp = 1;
379	} else  {
380		man = cm;
381		exp = 0;
382	}
383	hp = (man << 4) + exp;
384
385	/*
386	 * Vertical precision: optional.
387	 */
388	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
389				      ISC_TRUE));
390	if (token.type == isc_tokentype_eol ||
391	    token.type == isc_tokentype_eof) {
392		isc_lex_ungettoken(lexer, &token);
393		goto encode;
394	}
395	m = strtol(DNS_AS_STR(token), &e, 10);
396	if (*e != 0 && *e != '.' && *e != 'm')
397		RETTOK(DNS_R_SYNTAX);
398	if (m < 0 || m > 90000000)
399		RETTOK(ISC_R_RANGE);
400	cm = 0;
401	if (*e == '.') {
402		e++;
403		for (i = 0; i < 2; i++) {
404			if (*e == 0 || *e == 'm')
405				break;
406			if ((tmp = decvalue(*e++)) < 0)
407				RETTOK(DNS_R_SYNTAX);
408			cm *= 10;
409			cm += tmp;
410		}
411		for (; i < 2; i++)
412			cm *= 10;
413	}
414	if (*e == 'm')
415		e++;
416	if (*e != 0)
417		RETTOK(DNS_R_SYNTAX);
418	/*
419	 * We don't just multiply out as we will overflow.
420	 */
421	if (m > 0) {
422		for (exp = 0; exp < 7; exp++)
423			if (m < poweroften[exp+1])
424				break;
425		man = m / poweroften[exp];
426		exp += 2;
427	} else if (cm >= 10) {
428		man = cm / 10;
429		exp = 1;
430	} else {
431		man = cm;
432		exp = 0;
433	}
434	vp = (man << 4) + exp;
435
436 encode:
437	RETERR(mem_tobuffer(target, &version, 1));
438	RETERR(mem_tobuffer(target, &size, 1));
439	RETERR(mem_tobuffer(target, &hp, 1));
440	RETERR(mem_tobuffer(target, &vp, 1));
441	if (north)
442		latitude = 0x80000000 + ( d1 * 3600 + m1 * 60 ) * 1000 + s1;
443	else
444		latitude = 0x80000000 - ( d1 * 3600 + m1 * 60 ) * 1000 - s1;
445	RETERR(uint32_tobuffer(latitude, target));
446
447	if (east)
448		longitude = 0x80000000 + ( d2 * 3600 + m2 * 60 ) * 1000 + s2;
449	else
450		longitude = 0x80000000 - ( d2 * 3600 + m2 * 60 ) * 1000 - s2;
451	RETERR(uint32_tobuffer(longitude, target));
452
453	return (uint32_tobuffer(altitude, target));
454}
455
456static inline isc_result_t
457totext_loc(ARGS_TOTEXT) {
458	int d1, m1, s1, fs1;
459	int d2, m2, s2, fs2;
460	unsigned long latitude;
461	unsigned long longitude;
462	unsigned long altitude;
463	isc_boolean_t north;
464	isc_boolean_t east;
465	isc_boolean_t below;
466	isc_region_t sr;
467	char buf[sizeof("89 59 59.999 N 179 59 59.999 E "
468			"42849672.95m 90000000m 90000000m 90000000m")];
469	char sbuf[sizeof("90000000m")];
470	char hbuf[sizeof("90000000m")];
471	char vbuf[sizeof("90000000m")];
472	unsigned char size, hp, vp;
473	unsigned long poweroften[8] = { 1, 10, 100, 1000,
474					10000, 100000, 1000000, 10000000 };
475
476	UNUSED(tctx);
477
478	REQUIRE(rdata->type == 29);
479	REQUIRE(rdata->length != 0);
480
481	dns_rdata_toregion(rdata, &sr);
482
483	/* version = sr.base[0]; */
484	size = sr.base[1];
485	INSIST((size&0x0f) < 10 && (size>>4) < 10);
486	if ((size&0x0f)> 1)
487		sprintf(sbuf, "%lum", (size>>4) * poweroften[(size&0x0f)-2]);
488	else
489		sprintf(sbuf, "0.%02lum", (size>>4) * poweroften[(size&0x0f)]);
490	hp = sr.base[2];
491	INSIST((hp&0x0f) < 10 && (hp>>4) < 10);
492	if ((hp&0x0f)> 1)
493		sprintf(hbuf, "%lum", (hp>>4) * poweroften[(hp&0x0f)-2]);
494	else
495		sprintf(hbuf, "0.%02lum", (hp>>4) * poweroften[(hp&0x0f)]);
496	vp = sr.base[3];
497	INSIST((vp&0x0f) < 10 && (vp>>4) < 10);
498	if ((vp&0x0f)> 1)
499		sprintf(vbuf, "%lum", (vp>>4) * poweroften[(vp&0x0f)-2]);
500	else
501		sprintf(vbuf, "0.%02lum", (vp>>4) * poweroften[(vp&0x0f)]);
502	isc_region_consume(&sr, 4);
503
504	latitude = uint32_fromregion(&sr);
505	isc_region_consume(&sr, 4);
506	if (latitude >= 0x80000000) {
507		north = ISC_TRUE;
508		latitude -= 0x80000000;
509	} else {
510		north = ISC_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 = ISC_TRUE;
526		longitude -= 0x80000000;
527	} else {
528		east = ISC_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 = ISC_TRUE;
544		altitude = 10000000 - altitude;
545	} else {
546		below =ISC_FALSE;
547		altitude -= 10000000;
548	}
549
550	sprintf(buf, "%d %d %d.%03d %s %d %d %d.%03d %s %s%ld.%02ldm %s %s %s",
551		d1, m1, s1, fs1, north ? "N" : "S",
552		d2, m2, s2, fs2, east ? "E" : "W",
553		below ? "-" : "", altitude/100, altitude % 100,
554		sbuf, hbuf, vbuf);
555
556	return (str_totext(buf, target));
557}
558
559static inline isc_result_t
560fromwire_loc(ARGS_FROMWIRE) {
561	isc_region_t sr;
562	unsigned char c;
563	unsigned long latitude;
564	unsigned long longitude;
565
566	REQUIRE(type == 29);
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	if (sr.base[0] != 0)
577		return (ISC_R_NOTIMPLEMENTED);
578	if (sr.length < 16)
579		return (ISC_R_UNEXPECTEDEND);
580
581	/*
582	 * Size.
583	 */
584	c = sr.base[1];
585	if (c != 0)
586		if ((c&0xf) > 9 || ((c>>4)&0xf) > 9 || ((c>>4)&0xf) == 0)
587			return (ISC_R_RANGE);
588
589	/*
590	 * Horizontal precision.
591	 */
592	c = sr.base[2];
593	if (c != 0)
594		if ((c&0xf) > 9 || ((c>>4)&0xf) > 9 || ((c>>4)&0xf) == 0)
595			return (ISC_R_RANGE);
596
597	/*
598	 * Vertical precision.
599	 */
600	c = sr.base[3];
601	if (c != 0)
602		if ((c&0xf) > 9 || ((c>>4)&0xf) > 9 || ((c>>4)&0xf) == 0)
603			return (ISC_R_RANGE);
604	isc_region_consume(&sr, 4);
605
606	/*
607	 * Latitude.
608	 */
609	latitude = uint32_fromregion(&sr);
610	if (latitude < (0x80000000UL - 90 * 3600000) ||
611	    latitude > (0x80000000UL + 90 * 3600000))
612		return (ISC_R_RANGE);
613	isc_region_consume(&sr, 4);
614
615	/*
616	 * Longitude.
617	 */
618	longitude = uint32_fromregion(&sr);
619	if (longitude < (0x80000000UL - 180 * 3600000) ||
620	    longitude > (0x80000000UL + 180 * 3600000))
621		return (ISC_R_RANGE);
622
623	/*
624	 * Altitude.
625	 * All values possible.
626	 */
627
628	isc_buffer_activeregion(source, &sr);
629	isc_buffer_forward(source, 16);
630	return (mem_tobuffer(target, sr.base, 16));
631}
632
633static inline isc_result_t
634towire_loc(ARGS_TOWIRE) {
635	UNUSED(cctx);
636
637	REQUIRE(rdata->type == 29);
638	REQUIRE(rdata->length != 0);
639
640	return (mem_tobuffer(target, rdata->data, rdata->length));
641}
642
643static inline int
644compare_loc(ARGS_COMPARE) {
645	isc_region_t r1;
646	isc_region_t r2;
647
648	REQUIRE(rdata1->type == rdata2->type);
649	REQUIRE(rdata1->rdclass == rdata2->rdclass);
650	REQUIRE(rdata1->type == 29);
651	REQUIRE(rdata1->length != 0);
652	REQUIRE(rdata2->length != 0);
653
654	dns_rdata_toregion(rdata1, &r1);
655	dns_rdata_toregion(rdata2, &r2);
656	return (isc_region_compare(&r1, &r2));
657}
658
659static inline isc_result_t
660fromstruct_loc(ARGS_FROMSTRUCT) {
661	dns_rdata_loc_t *loc = source;
662	isc_uint8_t c;
663
664	REQUIRE(type == 29);
665	REQUIRE(source != NULL);
666	REQUIRE(loc->common.rdtype == type);
667	REQUIRE(loc->common.rdclass == rdclass);
668
669	UNUSED(type);
670	UNUSED(rdclass);
671
672	if (loc->v.v0.version != 0)
673		return (ISC_R_NOTIMPLEMENTED);
674	RETERR(uint8_tobuffer(loc->v.v0.version, target));
675
676	c = loc->v.v0.size;
677	if ((c&0xf) > 9 || ((c>>4)&0xf) > 9 || ((c>>4)&0xf) == 0)
678		return (ISC_R_RANGE);
679	RETERR(uint8_tobuffer(loc->v.v0.size, target));
680
681	c = loc->v.v0.horizontal;
682	if ((c&0xf) > 9 || ((c>>4)&0xf) > 9 || ((c>>4)&0xf) == 0)
683		return (ISC_R_RANGE);
684	RETERR(uint8_tobuffer(loc->v.v0.horizontal, target));
685
686	c = loc->v.v0.vertical;
687	if ((c&0xf) > 9 || ((c>>4)&0xf) > 9 || ((c>>4)&0xf) == 0)
688		return (ISC_R_RANGE);
689	RETERR(uint8_tobuffer(loc->v.v0.vertical, target));
690
691	if (loc->v.v0.latitude < (0x80000000UL - 90 * 3600000) ||
692	    loc->v.v0.latitude > (0x80000000UL + 90 * 3600000))
693		return (ISC_R_RANGE);
694	RETERR(uint32_tobuffer(loc->v.v0.latitude, target));
695
696	if (loc->v.v0.longitude < (0x80000000UL - 180 * 3600000) ||
697	    loc->v.v0.longitude > (0x80000000UL + 180 * 3600000))
698		return (ISC_R_RANGE);
699	RETERR(uint32_tobuffer(loc->v.v0.longitude, target));
700	return (uint32_tobuffer(loc->v.v0.altitude, target));
701}
702
703static inline isc_result_t
704tostruct_loc(ARGS_TOSTRUCT) {
705	dns_rdata_loc_t *loc = target;
706	isc_region_t r;
707	isc_uint8_t version;
708
709	REQUIRE(rdata->type == 29);
710	REQUIRE(target != NULL);
711	REQUIRE(rdata->length != 0);
712
713	UNUSED(mctx);
714
715	dns_rdata_toregion(rdata, &r);
716	version = uint8_fromregion(&r);
717	if (version != 0)
718		return (ISC_R_NOTIMPLEMENTED);
719
720	loc->common.rdclass = rdata->rdclass;
721	loc->common.rdtype = rdata->type;
722	ISC_LINK_INIT(&loc->common, link);
723
724	loc->v.v0.version = version;
725	isc_region_consume(&r, 1);
726	loc->v.v0.size = uint8_fromregion(&r);
727	isc_region_consume(&r, 1);
728	loc->v.v0.horizontal = uint8_fromregion(&r);
729	isc_region_consume(&r, 1);
730	loc->v.v0.vertical = uint8_fromregion(&r);
731	isc_region_consume(&r, 1);
732	loc->v.v0.latitude = uint32_fromregion(&r);
733	isc_region_consume(&r, 4);
734	loc->v.v0.longitude = uint32_fromregion(&r);
735	isc_region_consume(&r, 4);
736	loc->v.v0.altitude = uint32_fromregion(&r);
737	isc_region_consume(&r, 4);
738	return (ISC_R_SUCCESS);
739}
740
741static inline void
742freestruct_loc(ARGS_FREESTRUCT) {
743	dns_rdata_loc_t *loc = source;
744
745	REQUIRE(source != NULL);
746	REQUIRE(loc->common.rdtype == 29);
747
748	UNUSED(source);
749	UNUSED(loc);
750}
751
752static inline isc_result_t
753additionaldata_loc(ARGS_ADDLDATA) {
754	REQUIRE(rdata->type == 29);
755
756	UNUSED(rdata);
757	UNUSED(add);
758	UNUSED(arg);
759
760	return (ISC_R_SUCCESS);
761}
762
763static inline isc_result_t
764digest_loc(ARGS_DIGEST) {
765	isc_region_t r;
766
767	REQUIRE(rdata->type == 29);
768
769	dns_rdata_toregion(rdata, &r);
770
771	return ((digest)(arg, &r));
772}
773
774static inline isc_boolean_t
775checkowner_loc(ARGS_CHECKOWNER) {
776
777	REQUIRE(type == 29);
778
779	UNUSED(name);
780	UNUSED(type);
781	UNUSED(rdclass);
782	UNUSED(wildcard);
783
784	return (ISC_TRUE);
785}
786
787static inline isc_boolean_t
788checknames_loc(ARGS_CHECKNAMES) {
789
790	REQUIRE(rdata->type == 29);
791
792	UNUSED(rdata);
793	UNUSED(owner);
794	UNUSED(bad);
795
796	return (ISC_TRUE);
797}
798
799static inline int
800casecompare_loc(ARGS_COMPARE) {
801	return (compare_loc(rdata1, rdata2));
802}
803
804#endif	/* RDATA_GENERIC_LOC_29_C */
805