1/*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* $Id: loc_29.c,v 1.13 2020/09/14 08:40:43 florian Exp $ */
18
19/* Reviewed: Wed Mar 15 18:13:09 PST 2000 by explorer */
20
21/* RFC1876 */
22
23#ifndef RDATA_GENERIC_LOC_29_C
24#define RDATA_GENERIC_LOC_29_C
25
26static inline isc_result_t
27totext_loc(ARGS_TOTEXT) {
28	int d1, m1, s1, fs1;
29	int d2, m2, s2, fs2;
30	unsigned long latitude;
31	unsigned long longitude;
32	unsigned long altitude;
33	int north;
34	int east;
35	int below;
36	isc_region_t sr;
37	char buf[sizeof("89 59 59.999 N 179 59 59.999 E "
38			"42849672.95m 90000000m 90000000m 90000000m")];
39	char sbuf[sizeof("90000000m")];
40	char hbuf[sizeof("90000000m")];
41	char vbuf[sizeof("90000000m")];
42	unsigned char size, hp, vp;
43	unsigned long poweroften[8] = { 1, 10, 100, 1000,
44					10000, 100000, 1000000, 10000000 };
45
46	UNUSED(tctx);
47
48	REQUIRE(rdata->type == dns_rdatatype_loc);
49	REQUIRE(rdata->length != 0);
50
51	dns_rdata_toregion(rdata, &sr);
52
53	if (sr.base[0] != 0)
54		return (ISC_R_NOTIMPLEMENTED);
55
56	REQUIRE(rdata->length == 16);
57
58	size = sr.base[1];
59	INSIST((size&0x0f) < 10 && (size>>4) < 10);
60	if ((size&0x0f)> 1) {
61		snprintf(sbuf, sizeof(sbuf),
62			 "%lum", (size>>4) * poweroften[(size&0x0f)-2]);
63	} else {
64		snprintf(sbuf, sizeof(sbuf),
65			 "0.%02lum", (size>>4) * poweroften[(size&0x0f)]);
66	}
67	hp = sr.base[2];
68	INSIST((hp&0x0f) < 10 && (hp>>4) < 10);
69	if ((hp&0x0f)> 1) {
70		snprintf(hbuf, sizeof(hbuf),
71			"%lum", (hp>>4) * poweroften[(hp&0x0f)-2]);
72	} else {
73		snprintf(hbuf, sizeof(hbuf),
74			 "0.%02lum", (hp>>4) * poweroften[(hp&0x0f)]);
75	}
76	vp = sr.base[3];
77	INSIST((vp&0x0f) < 10 && (vp>>4) < 10);
78	if ((vp&0x0f)> 1) {
79		snprintf(vbuf, sizeof(vbuf),
80			 "%lum", (vp>>4) * poweroften[(vp&0x0f)-2]);
81	} else {
82		snprintf(vbuf, sizeof(vbuf),
83			 "0.%02lum", (vp>>4) * poweroften[(vp&0x0f)]);
84	}
85	isc_region_consume(&sr, 4);
86
87	latitude = uint32_fromregion(&sr);
88	isc_region_consume(&sr, 4);
89	if (latitude >= 0x80000000) {
90		north = 1;
91		latitude -= 0x80000000;
92	} else {
93		north = 0;
94		latitude = 0x80000000 - latitude;
95	}
96	fs1 = (int)(latitude % 1000);
97	latitude /= 1000;
98	s1 = (int)(latitude % 60);
99	latitude /= 60;
100	m1 = (int)(latitude % 60);
101	latitude /= 60;
102	d1 = (int)latitude;
103	INSIST(latitude <= 90U);
104
105	longitude = uint32_fromregion(&sr);
106	isc_region_consume(&sr, 4);
107	if (longitude >= 0x80000000) {
108		east = 1;
109		longitude -= 0x80000000;
110	} else {
111		east = 0;
112		longitude = 0x80000000 - longitude;
113	}
114	fs2 = (int)(longitude % 1000);
115	longitude /= 1000;
116	s2 = (int)(longitude % 60);
117	longitude /= 60;
118	m2 = (int)(longitude % 60);
119	longitude /= 60;
120	d2 = (int)longitude;
121	INSIST(longitude <= 180U);
122
123	altitude = uint32_fromregion(&sr);
124	isc_region_consume(&sr, 4);
125	if (altitude < 10000000U) {
126		below = 1;
127		altitude = 10000000 - altitude;
128	} else {
129		below =0;
130		altitude -= 10000000;
131	}
132
133	snprintf(buf, sizeof(buf),
134		 "%d %d %d.%03d %s %d %d %d.%03d %s %s%lu.%02lum %s %s %s",
135		 d1, m1, s1, fs1, north ? "N" : "S",
136		 d2, m2, s2, fs2, east ? "E" : "W",
137		 below ? "-" : "", altitude/100, altitude % 100,
138		 sbuf, hbuf, vbuf);
139
140	return (isc_str_tobuffer(buf, target));
141}
142
143static inline isc_result_t
144fromwire_loc(ARGS_FROMWIRE) {
145	isc_region_t sr;
146	unsigned char c;
147	unsigned long latitude;
148	unsigned long longitude;
149
150	REQUIRE(type == dns_rdatatype_loc);
151
152	UNUSED(type);
153	UNUSED(rdclass);
154	UNUSED(dctx);
155	UNUSED(options);
156
157	isc_buffer_activeregion(source, &sr);
158	if (sr.length < 1)
159		return (ISC_R_UNEXPECTEDEND);
160	if (sr.base[0] != 0) {
161		/* Treat as unknown. */
162		isc_buffer_forward(source, sr.length);
163		return (isc_mem_tobuffer(target, sr.base, sr.length));
164	}
165	if (sr.length < 16)
166		return (ISC_R_UNEXPECTEDEND);
167
168	/*
169	 * Size.
170	 */
171	c = sr.base[1];
172	if (c != 0)
173		if ((c&0xf) > 9 || ((c>>4)&0xf) > 9 || ((c>>4)&0xf) == 0)
174			return (ISC_R_RANGE);
175
176	/*
177	 * Horizontal precision.
178	 */
179	c = sr.base[2];
180	if (c != 0)
181		if ((c&0xf) > 9 || ((c>>4)&0xf) > 9 || ((c>>4)&0xf) == 0)
182			return (ISC_R_RANGE);
183
184	/*
185	 * Vertical precision.
186	 */
187	c = sr.base[3];
188	if (c != 0)
189		if ((c&0xf) > 9 || ((c>>4)&0xf) > 9 || ((c>>4)&0xf) == 0)
190			return (ISC_R_RANGE);
191	isc_region_consume(&sr, 4);
192
193	/*
194	 * Latitude.
195	 */
196	latitude = uint32_fromregion(&sr);
197	if (latitude < (0x80000000UL - 90 * 3600000) ||
198	    latitude > (0x80000000UL + 90 * 3600000))
199		return (ISC_R_RANGE);
200	isc_region_consume(&sr, 4);
201
202	/*
203	 * Longitude.
204	 */
205	longitude = uint32_fromregion(&sr);
206	if (longitude < (0x80000000UL - 180 * 3600000) ||
207	    longitude > (0x80000000UL + 180 * 3600000))
208		return (ISC_R_RANGE);
209
210	/*
211	 * Altitude.
212	 * All values possible.
213	 */
214
215	isc_buffer_activeregion(source, &sr);
216	isc_buffer_forward(source, 16);
217	return (isc_mem_tobuffer(target, sr.base, 16));
218}
219
220static inline isc_result_t
221towire_loc(ARGS_TOWIRE) {
222	UNUSED(cctx);
223
224	REQUIRE(rdata->type == dns_rdatatype_loc);
225	REQUIRE(rdata->length != 0);
226
227	return (isc_mem_tobuffer(target, rdata->data, rdata->length));
228}
229
230#endif	/* RDATA_GENERIC_LOC_29_C */
231