GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ripd/interface.c Lines: 0 205 0.0 %
Date: 2017-11-07 Branches: 0 105 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: interface.c,v 1.14 2017/01/17 16:30:54 jca Exp $ */
2
3
/*
4
 * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
5
 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6
 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
7
 *
8
 * Permission to use, copy, modify, and distribute this software for any
9
 * purpose with or without fee is hereby granted, provided that the above
10
 * copyright notice and this permission notice appear in all copies.
11
 *
12
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
 */
20
21
#include <sys/types.h>
22
#include <sys/ioctl.h>
23
#include <sys/time.h>
24
#include <sys/socket.h>
25
#include <netinet/in.h>
26
#include <arpa/inet.h>
27
#include <net/if.h>
28
#include <net/if_types.h>
29
#include <ctype.h>
30
#include <err.h>
31
#include <stdio.h>
32
#include <stdlib.h>
33
#include <unistd.h>
34
#include <string.h>
35
#include <event.h>
36
37
#include "ripd.h"
38
#include "log.h"
39
#include "rip.h"
40
#include "rde.h"
41
#include "ripe.h"
42
43
extern struct ripd_conf	*conf;
44
45
int	 if_act_start(struct iface *);
46
int	 if_act_reset(struct iface *);
47
48
struct {
49
	int			state;
50
	enum iface_event	event;
51
	enum iface_action	action;
52
	int			new_state;
53
} iface_fsm[] = {
54
    /* current state	event that happened	action to take	resulting state */
55
    {IF_STA_DOWN,	IF_EVT_UP,		IF_ACT_STRT,	0},
56
    {IF_STA_ANY,	IF_EVT_DOWN,		IF_ACT_RST,	IF_STA_DOWN},
57
    {-1,		IF_EVT_NOTHING,		IF_ACT_NOTHING,	0},
58
};
59
60
const char * const if_action_names[] = {
61
	"NOTHING",
62
	"START",
63
	"RESET"
64
};
65
66
static const char * const if_event_names[] = {
67
	"NOTHING",
68
	"UP",
69
	"DOWN",
70
};
71
72
void
73
if_init(struct ripd_conf *xconf, struct iface *iface)
74
{
75
	struct ifreq	ifr;
76
	u_int		rdomain;
77
78
	/* XXX as in ospfd I would like to kill that. This is a design error */
79
	iface->fd = xconf->rip_socket;
80
81
	strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
82
	if (ioctl(iface->fd, SIOCGIFRDOMAIN, (caddr_t)&ifr) == -1)
83
		rdomain = 0;
84
	else {
85
		rdomain = ifr.ifr_rdomainid;
86
		if (setsockopt(iface->fd, SOL_SOCKET, SO_RTABLE, &rdomain,
87
		    sizeof(rdomain)) == -1)
88
			fatal("failed to set rdomain");
89
	}
90
	if (rdomain != xconf->rdomain)
91
		fatalx("interface rdomain mismatch");
92
93
	ripe_demote_iface(iface, 0);
94
}
95
96
int
97
if_fsm(struct iface *iface, enum iface_event event)
98
{
99
	int	 old_state;
100
	int	 new_state = 0;
101
	int	 i, ret = 0;
102
103
	old_state = iface->state;
104
105
	for (i = 0; iface_fsm[i].state != -1; i++)
106
		if ((iface_fsm[i].state & old_state) &&
107
		    (iface_fsm[i].event == event)) {
108
			new_state = iface_fsm[i].new_state;
109
			break;
110
		}
111
112
	if (iface_fsm[i].state == -1) {
113
		/* event outside of the defined fsm, ignore it. */
114
		log_debug("if_fsm: interface %s, "
115
		    "event '%s' not expected in state '%s'", iface->name,
116
		    if_event_name(event), if_state_name(old_state));
117
		return (0);
118
	}
119
120
	switch (iface_fsm[i].action) {
121
	case IF_ACT_STRT:
122
		ret = if_act_start(iface);
123
		break;
124
	case IF_ACT_RST:
125
		ret = if_act_reset(iface);
126
		break;
127
	case IF_ACT_NOTHING:
128
		/* do nothing */
129
		break;
130
	}
131
132
	if (ret) {
133
		log_debug("if_fsm: error changing state for interface %s, "
134
		    "event '%s', state '%s'", iface->name, if_event_name(event),
135
		    if_state_name(old_state));
136
		return (0);
137
	}
138
139
	if (new_state != 0)
140
		iface->state = new_state;
141
142
	if (old_state == IF_STA_ACTIVE && iface->state == IF_STA_DOWN)
143
		ripe_demote_iface(iface, 0);
144
	if (old_state & IF_STA_DOWN && iface->state == IF_STA_ACTIVE)
145
		ripe_demote_iface(iface, 1);
146
147
	log_debug("if_fsm: event '%s' resulted in action '%s' and changing "
148
	    "state for interface %s from '%s' to '%s'",
149
	    if_event_name(event), if_action_name(iface_fsm[i].action),
150
	    iface->name, if_state_name(old_state), if_state_name(iface->state));
151
152
	return (ret);
153
}
154
155
struct iface *
156
if_find_index(u_short ifindex)
157
{
158
	struct iface	 *iface;
159
160
	LIST_FOREACH(iface, &conf->iface_list, entry) {
161
		if (iface->ifindex == ifindex)
162
			return (iface);
163
	}
164
165
	return (NULL);
166
}
167
168
169
/* actions */
170
int
171
if_act_start(struct iface *iface)
172
{
173
	struct in_addr	 addr;
174
	struct timeval	 now;
175
176
	if (iface->passive) {
177
		log_debug("if_act_start: cannot start passive interface %s",
178
		    iface->name);
179
		return (0);
180
	}
181
182
	if (!((iface->flags & IFF_UP) &&
183
	    LINK_STATE_IS_UP(iface->linkstate))) {
184
		log_debug("if_act_start: interface %s link down",
185
		    iface->name);
186
		return (0);
187
	}
188
189
	gettimeofday(&now, NULL);
190
	iface->uptime = now.tv_sec;
191
192
	switch (iface->type) {
193
	case IF_TYPE_POINTOPOINT:
194
	case IF_TYPE_BROADCAST:
195
		inet_aton(ALL_RIP_ROUTERS, &addr);
196
		if (if_join_group(iface, &addr)) {
197
			log_warn("if_act_start: error joining group %s, "
198
			    "interface %s", inet_ntoa(addr), iface->name);
199
			return (-1);
200
		}
201
202
		iface->state = IF_STA_ACTIVE;
203
		break;
204
	default:
205
		fatalx("if_act_start: unknown interface type");
206
	}
207
208
	return (0);
209
}
210
211
int
212
if_act_reset(struct iface *iface)
213
{
214
	struct nbr		*nbr = NULL;
215
	struct in_addr		 addr;
216
217
	if (iface->passive)
218
		return (0);
219
220
	switch (iface->type) {
221
	case IF_TYPE_POINTOPOINT:
222
	case IF_TYPE_BROADCAST:
223
		inet_aton(ALL_RIP_ROUTERS, &addr);
224
		if (if_leave_group(iface, &addr)) {
225
		log_warn("if_act_reset: error leaving group %s, "
226
		    "interface %s", inet_ntoa(addr), iface->name);
227
		}
228
		break;
229
	default:
230
		fatalx("if_act_reset: unknown interface type");
231
	}
232
233
	LIST_FOREACH(nbr, &iface->nbr_list, entry) {
234
		if (nbr_fsm(nbr, NBR_EVT_KILL_NBR)) {
235
			log_debug("if_act_reset: error killing neighbor %s",
236
			    inet_ntoa(nbr->id));
237
		}
238
	}
239
240
	return (0);
241
}
242
243
const char *
244
if_event_name(int event)
245
{
246
	return (if_event_names[event]);
247
}
248
249
const char *
250
if_action_name(int action)
251
{
252
	return (if_action_names[action]);
253
}
254
255
/* misc */
256
int
257
if_set_mcast_ttl(int fd, u_int8_t ttl)
258
{
259
	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
260
	    (char *)&ttl, sizeof(ttl)) < 0) {
261
		log_warn("if_set_mcast_ttl: error setting "
262
		    "IP_MULTICAST_TTL to %d", ttl);
263
		return (-1);
264
	}
265
266
	return (0);
267
}
268
269
int
270
if_set_opt(int fd)
271
{
272
	int	 yes = 1;
273
274
	if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &yes,
275
	    sizeof(int)) < 0) {
276
		log_warn("if_set_opt: error setting IP_RECVIF");
277
		return (-1);
278
	}
279
280
	return (0);
281
}
282
283
int
284
if_set_tos(int fd, int tos)
285
{
286
	if (setsockopt(fd, IPPROTO_IP, IP_TOS,
287
	    (int *)&tos, sizeof(tos)) < 0) {
288
		log_warn("if_set_tos: error setting IP_TOS to 0x%x", tos);
289
		return (-1);
290
	}
291
292
	return (0);
293
}
294
295
int
296
if_set_mcast(struct iface *iface)
297
{
298
	switch (iface->type) {
299
	case IF_TYPE_POINTOPOINT:
300
	case IF_TYPE_BROADCAST:
301
		if (setsockopt(iface->fd, IPPROTO_IP, IP_MULTICAST_IF,
302
		    &iface->addr.s_addr, sizeof(iface->addr.s_addr)) < 0) {
303
			log_debug("if_set_mcast: error setting "
304
				"IP_MULTICAST_IF, interface %s", iface->name);
305
			return (-1);
306
		}
307
		break;
308
	default:
309
		fatalx("if_set_mcast: unknown interface type");
310
	}
311
312
	return (0);
313
}
314
315
int
316
if_set_mcast_loop(int fd)
317
{
318
	u_int8_t	 loop = 0;
319
320
	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
321
	    (char *)&loop, sizeof(loop)) < 0) {
322
		log_warn("if_set_mcast_loop: error setting IP_MULTICAST_LOOP");
323
		return (-1);
324
	}
325
326
	return (0);
327
}
328
329
void
330
if_set_recvbuf(int fd)
331
{
332
	int	 bsize;
333
334
	bsize = 65535;
335
	while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
336
	    sizeof(bsize)) == -1)
337
		bsize /= 2;
338
}
339
340
int
341
if_join_group(struct iface *iface, struct in_addr *addr)
342
{
343
	struct ip_mreq	 mreq;
344
345
	switch (iface->type) {
346
	case IF_TYPE_POINTOPOINT:
347
	case IF_TYPE_BROADCAST:
348
		mreq.imr_multiaddr.s_addr = addr->s_addr;
349
		mreq.imr_interface.s_addr = iface->addr.s_addr;
350
351
		if (setsockopt(iface->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
352
		    (void *)&mreq, sizeof(mreq)) < 0)
353
			return (-1);
354
		break;
355
	default:
356
		fatalx("if_join_group: unknown interface type");
357
	}
358
359
	return (0);
360
}
361
362
int
363
if_leave_group(struct iface *iface, struct in_addr *addr)
364
{
365
	struct ip_mreq	 mreq;
366
367
	switch (iface->type) {
368
	case IF_TYPE_POINTOPOINT:
369
	case IF_TYPE_BROADCAST:
370
		mreq.imr_multiaddr.s_addr = addr->s_addr;
371
		mreq.imr_interface.s_addr = iface->addr.s_addr;
372
373
		if (setsockopt(iface->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
374
		    (void *)&mreq, sizeof(mreq)) < 0)
375
			return (-1);
376
		break;
377
	default:
378
		fatalx("if_leave_group: unknown interface type");
379
	}
380
381
	return (0);
382
}
383
384
struct iface *
385
if_new(struct kif *kif)
386
{
387
	struct sockaddr_in	*sain;
388
	struct iface		*iface;
389
	struct ifreq		*ifr;
390
	int			s;
391
392
	if ((iface = calloc(1, sizeof(*iface))) == NULL)
393
		err(1, "if_new: calloc");
394
395
	iface->state = IF_STA_DOWN;
396
397
	LIST_INIT(&iface->nbr_list);
398
	TAILQ_INIT(&iface->rp_list);
399
	TAILQ_INIT(&iface->rq_list);
400
401
	strlcpy(iface->name, kif->ifname, sizeof(iface->name));
402
403
	if ((ifr = calloc(1, sizeof(*ifr))) == NULL)
404
		err(1, "if_new: calloc");
405
406
	/* set up ifreq */
407
	strlcpy(ifr->ifr_name, kif->ifname, sizeof(ifr->ifr_name));
408
	if ((s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
409
	    0)) < 0)
410
		err(1, "if_new: socket");
411
412
	/* get type */
413
	if (kif->flags & IFF_POINTOPOINT)
414
		iface->type = IF_TYPE_POINTOPOINT;
415
	if (kif->flags & IFF_BROADCAST &&
416
	    kif->flags & IFF_MULTICAST)
417
		iface->type = IF_TYPE_BROADCAST;
418
	if (kif->flags & IFF_LOOPBACK) {
419
		iface->type = IF_TYPE_POINTOPOINT;
420
		/* XXX protect loopback from sending packets over lo? */
421
	}
422
423
	/* get mtu, index and flags */
424
	iface->mtu = kif->mtu;
425
	iface->ifindex = kif->ifindex;
426
	iface->flags = kif->flags;
427
	iface->linkstate = kif->link_state;
428
	iface->if_type = kif->if_type;
429
	iface->baudrate = kif->baudrate;
430
431
	/* get address */
432
	if (ioctl(s, SIOCGIFADDR, ifr) < 0)
433
		err(1, "if_new: cannot get address");
434
	sain = (struct sockaddr_in *)&ifr->ifr_addr;
435
	iface->addr = sain->sin_addr;
436
437
	/* get mask */
438
	if (ioctl(s, SIOCGIFNETMASK, ifr) < 0)
439
		err(1, "if_new: cannot get mask");
440
	sain = (struct sockaddr_in *)&ifr->ifr_addr;
441
	iface->mask = sain->sin_addr;
442
443
	/* get p2p dst address */
444
	if (kif->flags & IFF_POINTOPOINT) {
445
		if (ioctl(s, SIOCGIFDSTADDR, ifr) < 0)
446
			err(1, "if_new: cannot get dst addr");
447
		sain = (struct sockaddr_in *)&ifr->ifr_addr;
448
		iface->dst = sain->sin_addr;
449
	}
450
451
	free(ifr);
452
	close(s);
453
454
	return (iface);
455
}
456
457
void
458
if_del(struct iface *iface)
459
{
460
	struct nbr	*nbr;
461
462
	log_debug("if_del: interface %s", iface->name);
463
464
	/* revert the demotion when the interface is deleted */
465
	if (iface->state == IF_STA_DOWN)
466
		ripe_demote_iface(iface, 1);
467
468
	/* clear lists etc */
469
	while ((nbr = LIST_FIRST(&iface->nbr_list)) != NULL)
470
		nbr_del(nbr);
471
472
	/* XXX rq_list, rp_list */
473
474
	free(iface);
475
}
476
477
struct ctl_iface *
478
if_to_ctl(struct iface *iface)
479
{
480
	static struct ctl_iface	 ictl;
481
	struct timeval		 now;
482
483
	memcpy(ictl.name, iface->name, sizeof(ictl.name));
484
	memcpy(&ictl.addr, &iface->addr, sizeof(ictl.addr));
485
	memcpy(&ictl.mask, &iface->mask, sizeof(ictl.mask));
486
487
	ictl.ifindex = iface->ifindex;
488
	ictl.state = iface->state;
489
	ictl.mtu = iface->mtu;
490
491
	ictl.baudrate = iface->baudrate;
492
	ictl.flags = iface->flags;
493
	ictl.metric = iface->cost;
494
	ictl.type = iface->type;
495
	ictl.linkstate = iface->linkstate;
496
	ictl.passive = iface->passive;
497
	ictl.if_type = iface->if_type;
498
499
	gettimeofday(&now, NULL);
500
501
	if (iface->state != IF_STA_DOWN) {
502
		ictl.uptime = now.tv_sec - iface->uptime;
503
	} else
504
		ictl.uptime = 0;
505
506
	return (&ictl);
507
}