GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/dvmrpd/report.c Lines: 0 110 0.0 %
Date: 2017-11-07 Branches: 0 46 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: report.c,v 1.11 2015/12/07 18:59:31 mmcc Exp $ */
2
3
/*
4
 * Copyright (c) 2005, 2006 Esben Norby <norby@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/socket.h>
21
#include <netinet/in.h>
22
#include <netinet/ip.h>
23
#include <arpa/inet.h>
24
25
#include <stdlib.h>
26
#include <string.h>
27
28
#include "igmp.h"
29
#include "dvmrpd.h"
30
#include "dvmrp.h"
31
#include "dvmrpe.h"
32
#include "log.h"
33
34
extern struct dvmrpd_conf	*deconf;
35
36
void	 rr_list_remove(struct route_report *);
37
38
/* DVMRP report packet handling */
39
int
40
send_report(struct iface *iface, struct in_addr addr, void *data, int len)
41
{
42
	struct sockaddr_in	 dst;
43
	struct ibuf		*buf;
44
	struct dvmrp_hdr	*dvmrp_hdr;
45
	int			 ret = 0;
46
47
	log_debug("send_report: interface %s addr %s",
48
	    iface->name, inet_ntoa(addr));
49
50
	if (iface->passive)
51
		return (0);
52
53
	if ((buf = ibuf_open(iface->mtu - sizeof(struct ip))) == NULL)
54
		fatal("send_report");
55
56
	/* DVMRP header */
57
	if (gen_dvmrp_hdr(buf, iface, DVMRP_CODE_REPORT))
58
		goto fail;
59
60
	ibuf_add(buf, data, len);
61
62
	dst.sin_family = AF_INET;
63
	dst.sin_len = sizeof(struct sockaddr_in);
64
	dst.sin_addr.s_addr = addr.s_addr;
65
66
	/* update chksum */
67
	dvmrp_hdr = ibuf_seek(buf, 0, sizeof(*dvmrp_hdr));
68
	dvmrp_hdr->chksum = in_cksum(buf->buf, buf->wpos);
69
70
	ret = send_packet(iface, buf->buf, buf->wpos, &dst);
71
	ibuf_free(buf);
72
	return (ret);
73
fail:
74
	log_warn("send_report");
75
	ibuf_free(buf);
76
	return (-1);
77
}
78
79
void
80
recv_report(struct nbr *nbr, char *buf, u_int16_t len)
81
{
82
	struct route_report	 rr;
83
	u_int32_t		 netid, netmask;
84
	u_int8_t		 metric, netid_len, prefixlen;
85
86
	log_debug("recv_report: neighbor ID %s", inet_ntoa(nbr->id));
87
88
	if ((nbr->state != NBR_STA_2_WAY) && (!nbr->compat)) {
89
		log_warnx("recv_report: neighbor %s not in state %s",
90
		    inet_ntoa(nbr->id), "2-WAY");
91
		return;
92
	}
93
94
	/* parse route report */
95
	do {
96
		/*
97
		 * get netmask
98
		 *
99
		 * The netmask in a DVMRP report is only represented by 3 bytes,
100
		 * to cope with that we read 4 bytes and shift 8 bits.
101
		 * The most significant part of the mask is always 255.
102
		 */
103
104
		/* read four bytes */
105
		memcpy(&netmask, buf, sizeof(netmask));
106
		/* ditch one byte, since we only need three */
107
		netmask = ntohl(netmask) >> 8;
108
		netmask = htonl(netmask);
109
110
		/* set the highest byte to 255 */
111
		netmask |= htonl(0xff000000);
112
		buf += 3;
113
		len -= 3;
114
115
		prefixlen = mask2prefixlen(netmask);
116
		netid_len = PREFIX_SIZE(prefixlen);
117
118
		do {
119
			/*
120
			 * get netid
121
			 *
122
			 * The length of the netid is depending on the above
123
			 * netmask.
124
			 * Read 4 bytes and use the netmask from above to
125
			 * determine the netid.
126
			 */
127
			memcpy(&netid, buf, sizeof(netid));
128
			netid &= netmask;
129
130
			buf += netid_len;
131
			len -= netid_len;
132
133
			/* get metric */
134
			memcpy(&metric, buf, sizeof(metric));
135
			buf += sizeof(metric);
136
			len -= sizeof(metric);
137
138
			rr.net.s_addr = netid;
139
			rr.mask.s_addr = netmask;
140
			rr.nexthop = nbr->id;
141
			rr.metric = (metric & METRIC_MASK);
142
143
			/* ifindex */
144
			rr.ifindex = nbr->iface->ifindex;
145
146
			/* send route report to RDE */
147
			dvmrpe_imsg_compose_rde(IMSG_ROUTE_REPORT, nbr->peerid,
148
			    0, &rr, sizeof(rr));
149
150
		} while (!(metric & LAST_MASK) && (len > 0));
151
	} while (len > 0);
152
153
	return;
154
}
155
156
/* timers */
157
void
158
report_timer(int fd, short event, void *arg)
159
{
160
	struct timeval		 tv;
161
162
	/* request full route report */
163
	dvmrpe_imsg_compose_rde(IMSG_FULL_ROUTE_REPORT, 0, 0, NULL, 0);
164
165
	/* restart report timer */
166
	timerclear(&tv);
167
	tv.tv_sec = ROUTE_REPORT_INTERVAL;
168
	evtimer_add(&deconf->report_timer, &tv);
169
}
170
171
int
172
start_report_timer(void)
173
{
174
	struct timeval	tv;
175
176
	timerclear(&tv);
177
	tv.tv_sec = MIN_FLASH_UPDATE_INTERVAL;	/* XXX safe?? */
178
	return (evtimer_add(&deconf->report_timer, &tv));
179
}
180
181
int
182
stop_report_timer(void)
183
{
184
	return (evtimer_del(&deconf->report_timer));
185
}
186
187
/* route report list */
188
void
189
rr_list_add(struct rr_head *rr_list, struct route_report *rr)
190
{
191
	struct rr_entry		*le;
192
193
	if (rr == NULL)
194
		fatalx("rr_list_add: no route report");
195
196
	if ((le = calloc(1, sizeof(*le))) == NULL)
197
		fatal("rr_list_add");
198
199
	TAILQ_INSERT_TAIL(rr_list, le, entry);
200
	le->re = rr;
201
	rr->refcount++;
202
}
203
204
void
205
rr_list_remove(struct route_report *rr)
206
{
207
	if (--rr->refcount == 0)
208
		free(rr);
209
}
210
211
void
212
rr_list_clr(struct rr_head *rr_list)
213
{
214
	struct rr_entry		*le;
215
216
	while ((le = TAILQ_FIRST(rr_list)) != NULL) {
217
		TAILQ_REMOVE(rr_list, le, entry);
218
		rr_list_remove(le->re);
219
		free(le);
220
	}
221
}
222
223
void
224
rr_list_send(struct rr_head *rr_list, struct iface *xiface, struct nbr *nbr)
225
{
226
	struct rr_entry		*le, *le2;
227
	struct ibuf		*buf;
228
	struct iface		*iface;
229
	struct in_addr		 addr;
230
	u_int32_t		 netid, netmask;
231
	u_int8_t		 metric, netid_len, prefixlen;
232
233
	/* set destination */
234
	if (xiface == NULL) {
235
		/* directly to a nbr */
236
		iface = nbr->iface;
237
		addr = nbr->addr;
238
	} else {
239
		/* multicast on interface */
240
		iface = xiface;
241
		inet_aton(AllDVMRPRouters, &addr);
242
	}
243
244
	while (!TAILQ_EMPTY(rr_list)) {
245
		if ((buf = ibuf_open(iface->mtu - sizeof(struct ip))) == NULL)
246
			fatal("rr_list_send");
247
248
		prefixlen = 0;
249
		while (((le = TAILQ_FIRST(rr_list)) != NULL) &&
250
		    (buf->wpos < 1000)) {
251
			/* netmask */
252
			netmask = le->re->mask.s_addr;
253
			if (prefixlen != mask2prefixlen(netmask)) {
254
				prefixlen = mask2prefixlen(netmask);
255
				netmask = ntohl(netmask) << 8;
256
				netmask = htonl(netmask);
257
				ibuf_add(buf, &netmask, 3);
258
			}
259
			netid_len = PREFIX_SIZE(prefixlen);
260
261
			/* netid */
262
			netid = le->re->net.s_addr;
263
			ibuf_add(buf, &netid, netid_len);
264
265
			/* metric */
266
			if (iface->ifindex == le->re->ifindex)
267
				/* poison reverse */
268
				metric = le->re->metric + INFINITY_METRIC;
269
			else
270
				metric = le->re->metric;
271
272
			/*
273
			 * determine if we need to flag last entry with current
274
			 * netmask.
275
			 */
276
			le2 = TAILQ_NEXT(le, entry);
277
			if (le2 != NULL) {
278
				if (mask2prefixlen(le2->re->mask.s_addr) !=
279
				    prefixlen)
280
					metric = metric | LAST_MASK;
281
			} else {
282
				metric = metric | LAST_MASK;
283
			}
284
285
			ibuf_add(buf, &metric, sizeof(metric));
286
287
			TAILQ_REMOVE(rr_list, le, entry);
288
			rr_list_remove(le->re);
289
			free(le);
290
		}
291
		send_report(iface, addr, buf->buf, buf->wpos);
292
		ibuf_free(buf);
293
	}
294
}