GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/eigrpd/tlv.c Lines: 0 225 0.0 %
Date: 2017-11-07 Branches: 0 115 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: tlv.c,v 1.15 2016/10/10 02:26:24 gsoares Exp $ */
2
3
/*
4
 * Copyright (c) 2015 Renato Westphal <renato@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
#include <sys/utsname.h>
21
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <string.h>
25
26
#include "eigrpd.h"
27
#include "eigrpe.h"
28
#include "log.h"
29
30
int
31
gen_parameter_tlv(struct ibuf *buf, struct eigrp_iface *ei, int peerterm)
32
{
33
	struct tlv_parameter	 tp;
34
35
	tp.type = htons(TLV_TYPE_PARAMETER);
36
	tp.length = htons(TLV_TYPE_PARAMETER_LEN);
37
	if (peerterm) {
38
		tp.kvalues[0] = 255;
39
		tp.kvalues[1] = 255;
40
		tp.kvalues[2] = 255;
41
		tp.kvalues[3] = 255;
42
		tp.kvalues[4] = 255;
43
		tp.kvalues[5] = 0;
44
	} else
45
		memcpy(tp.kvalues, ei->eigrp->kvalues, 6);
46
	tp.holdtime = htons(ei->hello_holdtime);
47
48
	return (ibuf_add(buf, &tp, sizeof(tp)));
49
}
50
51
int
52
gen_sequence_tlv(struct ibuf *buf, struct seq_addr_head *seq_addr_list)
53
{
54
	struct tlv		 tlv, *tlvp;
55
	struct seq_addr_entry	*sa;
56
	uint8_t			 alen;
57
	uint16_t		 len = TLV_HDR_LEN;
58
	size_t			 original_size = ibuf_size(buf);
59
60
	tlv.type = htons(TLV_TYPE_SEQ);
61
	if (ibuf_add(buf, &tlv, sizeof(tlv))) {
62
		log_warn("%s: ibuf_add failed", __func__);
63
		return (-1);
64
	}
65
66
	TAILQ_FOREACH(sa, seq_addr_list, entry) {
67
		switch (sa->af) {
68
		case AF_INET:
69
			alen = INADDRSZ;
70
			break;
71
		case AF_INET6:
72
			alen = IN6ADDRSZ;
73
			break;
74
		default:
75
			fatalx("gen_sequence_tlv: unknown address family");
76
		}
77
		if (ibuf_add(buf, &alen, sizeof(alen)))
78
			return (-1);
79
		if (ibuf_add(buf, &sa->addr, alen)) {
80
			log_warn("%s: ibuf_add failed", __func__);
81
			return (-1);
82
		}
83
84
		len += (sizeof(alen) + alen);
85
	}
86
87
	/* adjust tlv length */
88
	if ((tlvp = ibuf_seek(buf, original_size, sizeof(*tlvp))) == NULL)
89
                fatalx("gen_sequence_tlv: buf_seek failed");
90
	tlvp->length = htons(len);
91
92
	return (0);
93
}
94
95
int
96
gen_sw_version_tlv(struct ibuf *buf)
97
{
98
	struct tlv_sw_version	 ts;
99
	struct utsname		 u;
100
	unsigned int		 vendor_os_major;
101
	unsigned int		 vendor_os_minor;
102
103
	memset(&ts, 0, sizeof(ts));
104
	ts.type = htons(TLV_TYPE_SW_VERSION);
105
	ts.length = htons(TLV_TYPE_SW_VERSION_LEN);
106
	if (uname(&u) >= 0) {
107
		if (sscanf(u.release, "%u.%u", &vendor_os_major,
108
		    &vendor_os_minor) == 2) {
109
			ts.vendor_os_major = (uint8_t) vendor_os_major;
110
			ts.vendor_os_minor = (uint8_t) vendor_os_minor;
111
		}
112
	}
113
	ts.eigrp_major = EIGRP_VERSION_MAJOR;
114
	ts.eigrp_minor = EIGRP_VERSION_MINOR;
115
116
	return (ibuf_add(buf, &ts, sizeof(ts)));
117
}
118
119
int
120
gen_mcast_seq_tlv(struct ibuf *buf, uint32_t seq)
121
{
122
	struct tlv_mcast_seq	 tm;
123
124
	tm.type = htons(TLV_TYPE_MCAST_SEQ);
125
	tm.length = htons(TLV_TYPE_MCAST_SEQ_LEN);
126
	tm.seq = htonl(seq);
127
128
	return (ibuf_add(buf, &tm, sizeof(tm)));
129
}
130
131
uint16_t
132
len_route_tlv(struct rinfo *ri)
133
{
134
	uint16_t		 len = TLV_HDR_LEN;
135
136
	switch (ri->af) {
137
	case AF_INET:
138
		len += sizeof(ri->nexthop.v4);
139
		len += PREFIX_SIZE4(ri->prefixlen);
140
		break;
141
	case AF_INET6:
142
		len += sizeof(ri->nexthop.v6);
143
		len += PREFIX_SIZE6(ri->prefixlen);
144
		break;
145
	default:
146
		break;
147
	}
148
149
	len += sizeof(ri->metric);
150
	if (ri->type == EIGRP_ROUTE_EXTERNAL)
151
		len += sizeof(ri->emetric);
152
153
	len += sizeof(ri->prefixlen);
154
155
	return (len);
156
}
157
158
int
159
gen_route_tlv(struct ibuf *buf, struct rinfo *ri)
160
{
161
	struct tlv		 tlv, *tlvp;
162
	struct in_addr		 addr;
163
	struct classic_metric	 metric;
164
	struct classic_emetric	 emetric;
165
	uint16_t		 tlvlen;
166
	uint8_t			 pflen;
167
	size_t			 original_size = ibuf_size(buf);
168
169
	switch (ri->af) {
170
	case AF_INET:
171
		tlv.type = TLV_PROTO_IPV4;
172
		break;
173
	case AF_INET6:
174
		tlv.type = TLV_PROTO_IPV6;
175
		break;
176
	default:
177
		fatalx("gen_route_tlv: unknown af");
178
	}
179
180
	switch (ri->type) {
181
	case EIGRP_ROUTE_INTERNAL:
182
		tlv.type |= TLV_ROUTE_INTERNAL;
183
		break;
184
	case EIGRP_ROUTE_EXTERNAL:
185
		tlv.type |= TLV_ROUTE_EXTERNAL;
186
		break;
187
	default:
188
		fatalx("gen_route_tlv: unknown type");
189
	}
190
	tlv.type = htons(tlv.type);
191
192
	if (ibuf_add(buf, &tlv, sizeof(tlv)))
193
		return (-1);
194
	tlvlen = TLV_HDR_LEN;
195
196
	/* nexthop */
197
	switch (ri->af) {
198
	case AF_INET:
199
		addr.s_addr = htonl(ri->nexthop.v4.s_addr);
200
		if (ibuf_add(buf, &addr, sizeof(addr)))
201
			return (-1);
202
		tlvlen += sizeof(ri->nexthop.v4);
203
		break;
204
	case AF_INET6:
205
		if (ibuf_add(buf, &ri->nexthop.v6, sizeof(ri->nexthop.v6)))
206
			return (-1);
207
		tlvlen += sizeof(ri->nexthop.v6);
208
		break;
209
	default:
210
		fatalx("gen_route_tlv: unknown af");
211
	}
212
213
	/* exterior metric */
214
	if (ri->type == EIGRP_ROUTE_EXTERNAL) {
215
		emetric = ri->emetric;
216
		emetric.routerid = htonl(emetric.routerid);
217
		emetric.as = htonl(emetric.as);
218
		emetric.tag = htonl(emetric.tag);
219
		emetric.metric = htonl(emetric.metric);
220
		emetric.reserved = htons(emetric.reserved);
221
		if (ibuf_add(buf, &emetric, sizeof(emetric)))
222
			return (-1);
223
		tlvlen += sizeof(emetric);
224
	}
225
226
	/* metric */
227
	metric = ri->metric;
228
	metric.delay = htonl(metric.delay);
229
	metric.bandwidth = htonl(metric.bandwidth);
230
	if (ibuf_add(buf, &metric, sizeof(metric)))
231
		return (-1);
232
	tlvlen += sizeof(metric);
233
234
	/* destination */
235
	if (ibuf_add(buf, &ri->prefixlen, sizeof(ri->prefixlen)))
236
		return (-1);
237
	switch (ri->af) {
238
	case AF_INET:
239
		pflen = PREFIX_SIZE4(ri->prefixlen);
240
		if (ibuf_add(buf, &ri->prefix.v4, pflen))
241
			return (-1);
242
		break;
243
	case AF_INET6:
244
		pflen = PREFIX_SIZE6(ri->prefixlen);
245
		if (ibuf_add(buf, &ri->prefix.v6, pflen))
246
			return (-1);
247
		break;
248
	default:
249
		fatalx("gen_route_tlv: unknown af");
250
	}
251
	tlvlen += sizeof(pflen) + pflen;
252
253
	/* adjust tlv length */
254
	if ((tlvp = ibuf_seek(buf, original_size, sizeof(*tlvp))) == NULL)
255
                fatalx("gen_route_tlv: buf_seek failed");
256
	tlvp->length = htons(tlvlen);
257
258
	return (0);
259
}
260
261
struct tlv_parameter *
262
tlv_decode_parameter(struct tlv *tlv, char *buf)
263
{
264
	struct tlv_parameter	*tp;
265
266
	if (ntohs(tlv->length) != TLV_TYPE_PARAMETER_LEN) {
267
		log_debug("%s: malformed tlv (bad length)", __func__);
268
		return (NULL);
269
	}
270
	tp = (struct tlv_parameter *)buf;
271
	return (tp);
272
}
273
274
int
275
tlv_decode_seq(int af, struct tlv *tlv, char *buf,
276
    struct seq_addr_head *seq_addr_list)
277
{
278
	uint16_t		 len;
279
	uint8_t			 alen;
280
	struct seq_addr_entry	*sa;
281
282
	len = ntohs(tlv->length);
283
	if (len < TLV_HDR_LEN) {
284
		log_debug("%s: malformed tlv (bad length)", __func__);
285
		return (-1);
286
	}
287
	buf += TLV_HDR_LEN;
288
	len -= TLV_HDR_LEN;
289
290
	while (len > 0) {
291
		memcpy(&alen, buf, sizeof(alen));
292
		buf += sizeof(alen);
293
		len -= sizeof(alen);
294
		if (alen > len) {
295
			log_debug("%s: malformed tlv (bad length)", __func__);
296
			return (-1);
297
		}
298
299
		switch (af) {
300
		case AF_INET:
301
			if (alen != INADDRSZ) {
302
				log_debug("%s: invalid address length",
303
				    __func__);
304
				return (-1);
305
			}
306
			break;
307
		case AF_INET6:
308
			if (alen != IN6ADDRSZ) {
309
				log_debug("%s: invalid address length",
310
				    __func__);
311
				return (-1);
312
			}
313
			break;
314
		default:
315
			fatalx("tlv_decode_seq: unknown af");
316
		}
317
		if ((sa = calloc(1, sizeof(*sa))) == NULL)
318
			fatal("tlv_decode_seq");
319
		sa->af = af;
320
		memcpy(&sa->addr, buf, alen);
321
		TAILQ_INSERT_TAIL(seq_addr_list, sa, entry);
322
323
		buf += alen;
324
		len -= alen;
325
	}
326
327
	return (0);
328
}
329
330
struct tlv_sw_version *
331
tlv_decode_sw_version(struct tlv *tlv, char *buf)
332
{
333
	struct tlv_sw_version	*tv;
334
335
	if (ntohs(tlv->length) != TLV_TYPE_SW_VERSION_LEN) {
336
		log_debug("%s: malformed tlv (bad length)", __func__);
337
		return (NULL);
338
	}
339
	tv = (struct tlv_sw_version *)buf;
340
	return (tv);
341
}
342
343
struct tlv_mcast_seq *
344
tlv_decode_mcast_seq(struct tlv *tlv, char *buf)
345
{
346
	struct tlv_mcast_seq	*tm;
347
348
	if (ntohs(tlv->length) != TLV_TYPE_MCAST_SEQ_LEN) {
349
		log_debug("%s: malformed tlv (bad length)", __func__);
350
		return (NULL);
351
	}
352
	tm = (struct tlv_mcast_seq *)buf;
353
	return (tm);
354
}
355
356
int
357
tlv_decode_route(int af, struct tlv *tlv, char *buf, struct rinfo *ri)
358
{
359
	unsigned int	 tlv_len, min_len, max_plen, plen, offset;
360
361
	ri->af = af;
362
	switch (ri->af) {
363
	case AF_INET:
364
		min_len = TLV_TYPE_IPV4_INT_MIN_LEN;
365
		max_plen = sizeof(ri->prefix.v4);
366
		break;
367
	case AF_INET6:
368
		min_len = TLV_TYPE_IPV6_INT_MIN_LEN;
369
		max_plen = sizeof(ri->prefix.v6);
370
		break;
371
	default:
372
		fatalx("tlv_decode_route: unknown af");
373
	}
374
375
	switch (ntohs(tlv->type) & TLV_TYPE_MASK) {
376
	case TLV_ROUTE_INTERNAL:
377
		ri->type = EIGRP_ROUTE_INTERNAL;
378
		break;
379
	case TLV_ROUTE_EXTERNAL:
380
		ri->type = EIGRP_ROUTE_EXTERNAL;
381
		min_len += sizeof(struct classic_emetric);
382
		break;
383
	default:
384
		fatalx("tlv_decode_route: unknown type");
385
	}
386
387
	tlv_len = ntohs(tlv->length);
388
	if (tlv_len < min_len) {
389
		log_debug("%s: malformed tlv (bad length)", __func__);
390
		return (-1);
391
	}
392
393
	/* nexthop */
394
	offset = TLV_HDR_LEN;
395
	switch (af) {
396
	case AF_INET:
397
		memcpy(&ri->nexthop.v4, buf + offset, sizeof(ri->nexthop.v4));
398
		offset += sizeof(ri->nexthop.v4);
399
		break;
400
	case AF_INET6:
401
		memcpy(&ri->nexthop.v6, buf + offset, sizeof(ri->nexthop.v6));
402
		offset += sizeof(ri->nexthop.v6);
403
		break;
404
	default:
405
		fatalx("tlv_decode_route: unknown af");
406
	}
407
408
	/* exterior metric */
409
	if (ri->type == EIGRP_ROUTE_EXTERNAL) {
410
		memcpy(&ri->emetric, buf + offset, sizeof(ri->emetric));
411
		ri->emetric.routerid = ntohl(ri->emetric.routerid);
412
		ri->emetric.as = ntohl(ri->emetric.as);
413
		ri->emetric.tag = ntohl(ri->emetric.tag);
414
		ri->emetric.metric = ntohl(ri->emetric.metric);
415
		ri->emetric.reserved = ntohs(ri->emetric.reserved);
416
		offset += sizeof(ri->emetric);
417
	}
418
419
	/* metric */
420
	memcpy(&ri->metric, buf + offset, sizeof(ri->metric));
421
	ri->metric.delay = ntohl(ri->metric.delay);
422
	ri->metric.bandwidth = ntohl(ri->metric.bandwidth);
423
	offset += sizeof(ri->metric);
424
425
	/* prefixlen */
426
	memcpy(&ri->prefixlen, buf + offset, sizeof(ri->prefixlen));
427
	offset += sizeof(ri->prefixlen);
428
429
	/*
430
	 * Different versions of IOS can use a different number of bytes to
431
	 * encode the same IPv6 prefix. This sucks but we have to deal with it.
432
	 * Instead of calculating the number of bytes based on the value of the
433
	 * prefixlen field, let's get this number by subtracting the size of all
434
	 * other fields from the total size of the TLV. It works because all
435
	 * the other fields have a fixed length.
436
	 */
437
	plen = tlv_len - min_len;
438
439
	/* safety check */
440
	if (plen > max_plen) {
441
		log_debug("%s: malformed tlv", __func__);
442
		return (-1);
443
	}
444
445
	/* destination */
446
	switch (af) {
447
	case AF_INET:
448
		memset(&ri->prefix.v4, 0, sizeof(ri->prefix.v4));
449
		memcpy(&ri->prefix.v4, buf + offset, plen);
450
		break;
451
	case AF_INET6:
452
		memset(&ri->prefix.v6, 0, sizeof(ri->prefix.v6));
453
		memcpy(&ri->prefix.v6, buf + offset, plen);
454
		break;
455
	default:
456
		fatalx("tlv_decode_route: unknown af");
457
	}
458
459
	/* check if the network is valid */
460
	if (bad_addr(af, &ri->prefix) ||
461
	   (af == AF_INET6 && IN6_IS_SCOPE_EMBED(&ri->prefix.v6))) {
462
		log_debug("%s: malformed tlv (invalid prefix): %s", __func__,
463
		    log_addr(af, &ri->prefix));
464
		return (-1);
465
	}
466
467
	/* just in case... */
468
	eigrp_applymask(af, &ri->prefix, &ri->prefix, ri->prefixlen);
469
470
	return (0);
471
}
472
473
void
474
metric_encode_mtu(uint8_t *dst, int mtu)
475
{
476
	dst[0] = (mtu & 0x00FF0000) >> 16;
477
	dst[1] = (mtu & 0x0000FF00) >> 8;
478
	dst[2] = (mtu & 0x000000FF);
479
}
480
481
int
482
metric_decode_mtu(uint8_t *mtu)
483
{
484
	return ((mtu[0] << 16) + (mtu[1] << 8) + mtu[2]);
485
}