GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ldpd/address.c Lines: 0 175 0.0 %
Date: 2017-11-07 Branches: 0 89 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: address.c,v 1.35 2017/03/04 00:21:48 renato Exp $ */
2
3
/*
4
 * Copyright (c) 2009 Michele Marchetto <michele@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 <arpa/inet.h>
21
#include <stdlib.h>
22
#include <string.h>
23
24
#include "ldpd.h"
25
#include "ldpe.h"
26
#include "lde.h"
27
#include "log.h"
28
29
static void	 send_address(struct nbr *, int, struct if_addr_head *,
30
		    unsigned int, int);
31
static int	 gen_address_list_tlv(struct ibuf *, int, struct if_addr_head *,
32
		    unsigned int);
33
static int	 gen_mac_list_tlv(struct ibuf *, uint8_t *);
34
static void	 address_list_add(struct if_addr_head *, struct if_addr *);
35
static void	 address_list_clr(struct if_addr_head *);
36
static void	 log_msg_address(int, uint16_t, struct nbr *, int,
37
		    union ldpd_addr *);
38
static void	 log_msg_mac_withdrawal(int, struct nbr *, uint8_t *);
39
40
static void
41
send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list,
42
    unsigned int addr_count, int withdraw)
43
{
44
	struct ibuf	*buf;
45
	uint16_t	 msg_type;
46
	uint8_t		 addr_size;
47
	struct if_addr	*if_addr;
48
	uint16_t	 size;
49
	unsigned int	 tlv_addr_count = 0;
50
	int		 err = 0;
51
52
	/* nothing to send */
53
	if (LIST_EMPTY(addr_list))
54
		return;
55
56
	if (!withdraw)
57
		msg_type = MSG_TYPE_ADDR;
58
	else
59
		msg_type = MSG_TYPE_ADDRWITHDRAW;
60
61
	switch (af) {
62
	case AF_INET:
63
		addr_size = sizeof(struct in_addr);
64
		break;
65
	case AF_INET6:
66
		addr_size = sizeof(struct in6_addr);
67
		break;
68
	default:
69
		fatalx("send_address: unknown af");
70
	}
71
72
	while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
73
		/*
74
		 * Send as many addresses as possible - respect the session's
75
		 * negotiated maximum pdu length.
76
		 */
77
		size = LDP_HDR_SIZE + LDP_MSG_SIZE + ADDR_LIST_SIZE;
78
		if (size + addr_count * addr_size <= nbr->max_pdu_len)
79
			tlv_addr_count = addr_count;
80
		else
81
			tlv_addr_count = (nbr->max_pdu_len - size) / addr_size;
82
		size += tlv_addr_count * addr_size;
83
		addr_count -= tlv_addr_count;
84
85
		if ((buf = ibuf_open(size)) == NULL)
86
			fatal(__func__);
87
88
		err |= gen_ldp_hdr(buf, size);
89
		size -= LDP_HDR_SIZE;
90
		err |= gen_msg_hdr(buf, msg_type, size);
91
		size -= LDP_MSG_SIZE;
92
		err |= gen_address_list_tlv(buf, af, addr_list, tlv_addr_count);
93
		if (err) {
94
			address_list_clr(addr_list);
95
			ibuf_free(buf);
96
			return;
97
		}
98
99
		while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
100
			log_msg_address(1, msg_type, nbr, af, &if_addr->addr);
101
102
			LIST_REMOVE(if_addr, entry);
103
			free(if_addr);
104
			if (--tlv_addr_count == 0)
105
				break;
106
		}
107
108
		evbuf_enqueue(&nbr->tcp->wbuf, buf);
109
	}
110
111
	nbr_fsm(nbr, NBR_EVT_PDU_SENT);
112
}
113
114
void
115
send_address_single(struct nbr *nbr, struct if_addr *if_addr, int withdraw)
116
{
117
	struct if_addr_head	 addr_list;
118
119
	LIST_INIT(&addr_list);
120
	address_list_add(&addr_list, if_addr);
121
	send_address(nbr, if_addr->af, &addr_list, 1, withdraw);
122
}
123
124
void
125
send_address_all(struct nbr *nbr, int af)
126
{
127
	struct if_addr_head	 addr_list;
128
	struct if_addr		*if_addr;
129
	unsigned int		 addr_count = 0;
130
131
	LIST_INIT(&addr_list);
132
	LIST_FOREACH(if_addr, &global.addr_list, entry) {
133
		if (if_addr->af != af)
134
			continue;
135
136
		address_list_add(&addr_list, if_addr);
137
		addr_count++;
138
	}
139
140
	send_address(nbr, af, &addr_list, addr_count, 0);
141
}
142
143
void
144
send_mac_withdrawal(struct nbr *nbr, struct map *fec, uint8_t *mac)
145
{
146
	struct ibuf	*buf;
147
	uint16_t	 size;
148
	int		 err;
149
150
	size = LDP_HDR_SIZE + LDP_MSG_SIZE + ADDR_LIST_SIZE + len_fec_tlv(fec) +
151
	    TLV_HDR_SIZE;
152
	if (mac)
153
		size += ETHER_ADDR_LEN;
154
155
	if ((buf = ibuf_open(size)) == NULL)
156
		fatal(__func__);
157
158
	err = gen_ldp_hdr(buf, size);
159
	size -= LDP_HDR_SIZE;
160
	err |= gen_msg_hdr(buf, MSG_TYPE_ADDRWITHDRAW, size);
161
	size -= LDP_MSG_SIZE;
162
	err |= gen_address_list_tlv(buf, AF_INET, NULL, 0);
163
	err |= gen_fec_tlv(buf, fec);
164
	err |= gen_mac_list_tlv(buf, mac);
165
	if (err) {
166
		ibuf_free(buf);
167
		return;
168
	}
169
170
	log_msg_mac_withdrawal(1, nbr, mac);
171
172
	evbuf_enqueue(&nbr->tcp->wbuf, buf);
173
174
	nbr_fsm(nbr, NBR_EVT_PDU_SENT);
175
}
176
177
int
178
recv_address(struct nbr *nbr, char *buf, uint16_t len)
179
{
180
	struct ldp_msg		msg;
181
	uint16_t		msg_type;
182
	enum imsg_type		type;
183
	struct address_list_tlv	alt;
184
	uint16_t		alt_len;
185
	uint16_t		alt_family;
186
	struct lde_addr		lde_addr;
187
188
	memcpy(&msg, buf, sizeof(msg));
189
	msg_type = ntohs(msg.type);
190
	switch (msg_type) {
191
	case MSG_TYPE_ADDR:
192
		type = IMSG_ADDRESS_ADD;
193
		break;
194
	case MSG_TYPE_ADDRWITHDRAW:
195
		type = IMSG_ADDRESS_DEL;
196
		break;
197
	default:
198
		fatalx("recv_address: unexpected msg type");
199
	}
200
	buf += LDP_MSG_SIZE;
201
	len -= LDP_MSG_SIZE;
202
203
	/* Address List TLV */
204
	if (len < ADDR_LIST_SIZE) {
205
		session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type);
206
		return (-1);
207
	}
208
	memcpy(&alt, buf, sizeof(alt));
209
	alt_len = ntohs(alt.length);
210
	alt_family = ntohs(alt.family);
211
	if (alt_len > len - TLV_HDR_SIZE) {
212
		session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
213
		return (-1);
214
	}
215
	if (ntohs(alt.type) != TLV_TYPE_ADDRLIST) {
216
		send_notification(nbr->tcp, S_MISS_MSG, msg.id, msg.type);
217
		return (-1);
218
	}
219
	switch (alt_family) {
220
	case AF_IPV4:
221
		if (!nbr->v4_enabled)
222
			/* just ignore the message */
223
			return (0);
224
		break;
225
	case AF_IPV6:
226
		if (!nbr->v6_enabled)
227
			/* just ignore the message */
228
			return (0);
229
		break;
230
	default:
231
		send_notification(nbr->tcp, S_UNSUP_ADDR, msg.id, msg.type);
232
		return (-1);
233
	}
234
	alt_len -= sizeof(alt.family);
235
	buf += sizeof(alt);
236
	len -= sizeof(alt);
237
238
	/* Process all received addresses */
239
	while (alt_len > 0) {
240
		switch (alt_family) {
241
		case AF_IPV4:
242
			if (alt_len < sizeof(struct in_addr)) {
243
				session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
244
				    msg.type);
245
				return (-1);
246
			}
247
248
			memset(&lde_addr, 0, sizeof(lde_addr));
249
			lde_addr.af = AF_INET;
250
			memcpy(&lde_addr.addr, buf, sizeof(struct in_addr));
251
252
			buf += sizeof(struct in_addr);
253
			len -= sizeof(struct in_addr);
254
			alt_len -= sizeof(struct in_addr);
255
			break;
256
		case AF_IPV6:
257
			if (alt_len < sizeof(struct in6_addr)) {
258
				session_shutdown(nbr, S_BAD_TLV_LEN, msg.id,
259
				    msg.type);
260
				return (-1);
261
			}
262
263
			memset(&lde_addr, 0, sizeof(lde_addr));
264
			lde_addr.af = AF_INET6;
265
			memcpy(&lde_addr.addr, buf, sizeof(struct in6_addr));
266
267
			buf += sizeof(struct in6_addr);
268
			len -= sizeof(struct in6_addr);
269
			alt_len -= sizeof(struct in6_addr);
270
			break;
271
		default:
272
			fatalx("recv_address: unknown af");
273
		}
274
275
		log_msg_address(0, msg_type, nbr, lde_addr.af, &lde_addr.addr);
276
277
		ldpe_imsg_compose_lde(type, nbr->peerid, 0, &lde_addr,
278
		    sizeof(lde_addr));
279
	}
280
281
	/* Optional Parameters */
282
	while (len > 0) {
283
		struct tlv 	tlv;
284
		uint16_t	tlv_type;
285
		uint16_t	tlv_len;
286
287
		if (len < sizeof(tlv)) {
288
			session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
289
			return (-1);
290
		}
291
292
		memcpy(&tlv, buf, TLV_HDR_SIZE);
293
		tlv_type = ntohs(tlv.type);
294
		tlv_len = ntohs(tlv.length);
295
		if (tlv_len + TLV_HDR_SIZE > len) {
296
			session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
297
			return (-1);
298
		}
299
		buf += TLV_HDR_SIZE;
300
		len -= TLV_HDR_SIZE;
301
302
		switch (tlv_type) {
303
		default:
304
			if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
305
				send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
306
				    msg.id, msg.type, tlv_type, tlv_len, buf);
307
			/* ignore unknown tlv */
308
			break;
309
		}
310
		buf += tlv_len;
311
		len -= tlv_len;
312
	}
313
314
	return (0);
315
}
316
317
static int
318
gen_address_list_tlv(struct ibuf *buf, int af, struct if_addr_head *addr_list,
319
    unsigned int tlv_addr_count)
320
{
321
	struct address_list_tlv	 alt;
322
	uint16_t		 addr_size;
323
	struct if_addr		*if_addr;
324
	int			 err = 0;
325
326
	memset(&alt, 0, sizeof(alt));
327
	alt.type = htons(TLV_TYPE_ADDRLIST);
328
329
	switch (af) {
330
	case AF_INET:
331
		alt.family = htons(AF_IPV4);
332
		addr_size = sizeof(struct in_addr);
333
		break;
334
	case AF_INET6:
335
		alt.family = htons(AF_IPV6);
336
		addr_size = sizeof(struct in6_addr);
337
		break;
338
	default:
339
		fatalx("gen_address_list_tlv: unknown af");
340
	}
341
	alt.length = htons(sizeof(alt.family) + addr_size * tlv_addr_count);
342
343
	err |= ibuf_add(buf, &alt, sizeof(alt));
344
	if (addr_list == NULL)
345
		return (err);
346
347
	LIST_FOREACH(if_addr, addr_list, entry) {
348
		err |= ibuf_add(buf, &if_addr->addr, addr_size);
349
		if (--tlv_addr_count == 0)
350
			break;
351
	}
352
353
	return (err);
354
}
355
356
static int
357
gen_mac_list_tlv(struct ibuf *buf, uint8_t *mac)
358
{
359
	struct tlv	 tlv;
360
	int		 err;
361
362
	memset(&tlv, 0, sizeof(tlv));
363
	tlv.type = htons(TLV_TYPE_MAC_LIST);
364
	if (mac)
365
		tlv.length = htons(ETHER_ADDR_LEN);
366
	err = ibuf_add(buf, &tlv, sizeof(tlv));
367
	if (mac)
368
		err |= ibuf_add(buf, mac, ETHER_ADDR_LEN);
369
370
	return (err);
371
}
372
373
static void
374
address_list_add(struct if_addr_head *addr_list, struct if_addr *if_addr)
375
{
376
	struct if_addr		*new;
377
378
	new = malloc(sizeof(*new));
379
	if (new == NULL)
380
		fatal(__func__);
381
	*new = *if_addr;
382
383
	LIST_INSERT_HEAD(addr_list, new, entry);
384
}
385
386
static void
387
address_list_clr(struct if_addr_head *addr_list)
388
{
389
	struct if_addr		*if_addr;
390
391
	while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
392
		LIST_REMOVE(if_addr, entry);
393
		free(if_addr);
394
	}
395
}
396
397
static void
398
log_msg_address(int out, uint16_t msg_type, struct nbr *nbr, int af,
399
    union ldpd_addr *addr)
400
{
401
	log_debug("msg-%s: %s: lsr-id %s, address %s", (out) ? "out" : "in",
402
	    msg_name(msg_type), inet_ntoa(nbr->id), log_addr(af, addr));
403
}
404
405
static void
406
log_msg_mac_withdrawal(int out, struct nbr *nbr, uint8_t *mac)
407
{
408
	log_debug("msg-%s: mac withdrawal: lsr-id %s, mac %s",
409
	    (out) ? "out" : "in", inet_ntoa(nbr->id),
410
	    (mac) ? ether_ntoa((struct ether_addr *)mac) : "wildcard");
411
}