1/*	$OpenBSD: kmroute.c,v 1.3 2019/06/28 13:32:47 deraadt 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 <arpa/inet.h>
23#include <netinet/ip_mroute.h>
24
25#include <err.h>
26#include <errno.h>
27#include <stdlib.h>
28#include <string.h>
29
30#include "igmp.h"
31#include "dvmrpd.h"
32#include "dvmrp.h"
33#include "dvmrpe.h"
34#include "log.h"
35
36extern struct dvmrpd_conf	*conf;
37char				*mroute_ptr;	/* packet buffer */
38
39void	main_imsg_compose_rde(int, pid_t, void *, u_int16_t);
40
41int
42kmr_init(int fd)
43{
44	struct iface		*iface;
45	struct route_report	 rr;
46
47	LIST_FOREACH(iface, &conf->iface_list, entry) {
48		log_debug("kmr_init: interface %s", iface->name);
49
50		rr.net.s_addr = iface->addr.s_addr & iface->mask.s_addr;
51		rr.mask = iface->mask;
52		rr.nexthop.s_addr = 0;
53		rr.metric = iface->metric;
54		rr.ifindex = iface->ifindex;
55		main_imsg_compose_rde(IMSG_ROUTE_REPORT, -1, &rr, sizeof(rr));
56
57		mrt_add_vif(conf->mroute_socket, iface);
58	}
59
60	if ((mroute_ptr = calloc(1, IBUF_READ_SIZE)) == NULL)
61		fatal("kmr_init");
62
63	return (0);
64}
65
66void
67kmr_shutdown(void)
68{
69	struct iface		*iface;
70
71	kmr_mfc_decouple();
72	kmroute_clear();
73
74	LIST_FOREACH(iface, &conf->iface_list, entry) {
75		log_debug("kmr_shutdown: interface %s", iface->name);
76
77		mrt_del_vif(conf->mroute_socket, iface);
78	}
79
80	free(mroute_ptr);
81}
82
83void
84kmr_recv_msg(int fd, short event, void *bula)
85{
86	struct mfc		 mfc;
87	struct igmpmsg		 kernel_msg;
88	char			*buf;
89	ssize_t			 r;
90
91	if (event != EV_READ)
92		return;
93
94	/* setup buffer */
95	buf = mroute_ptr;
96
97	if ((r = recvfrom(fd, buf, IBUF_READ_SIZE, 0, NULL, NULL)) == -1) {
98		if (errno != EAGAIN && errno != EINTR)
99			log_debug("kmr_recv_msg: error receiving packet");
100		return;
101	}
102
103	memcpy(&kernel_msg, buf, sizeof(kernel_msg));
104
105	/* we are only interested in kernel messages */
106	if (kernel_msg.im_mbz != 0)
107		return;
108
109	switch (kernel_msg.im_msgtype) {
110	case IGMPMSG_NOCACHE:
111		/* verify that dst is a multicast group */
112		if (!IN_MULTICAST(ntohl(kernel_msg.im_dst.s_addr))) {
113			log_debug("kmr_recv_msg: kernel providing garbage!");
114			return;
115		}
116
117		/* send MFC entry to RDE */
118		mfc.origin = kernel_msg.im_src;
119		mfc.group = kernel_msg.im_dst;
120		mfc.ifindex = kernel_msg.im_vif;
121		main_imsg_compose_rde(IMSG_MFC_ADD, 0, &mfc, sizeof(mfc));
122		break;
123	case IGMPMSG_WRONGVIF:
124	case IGMPMSG_WHOLEPKT:
125	case IGMPMSG_BW_UPCALL:
126	default:
127		log_debug("kmr_recv_msg: unhandled msg type %d!",
128		    kernel_msg.im_msgtype);
129	}
130}
131
132void
133kmr_mfc_couple(void)
134{
135	log_info("kernel multicast forwarding cache coupled");
136}
137
138void
139kmr_mfc_decouple(void)
140{
141	log_info("kernel multicast forwarding cache decoupled");
142}
143
144void
145kmroute_clear(void)
146{
147
148}
149
150int
151mrt_init(int fd)
152{
153	int	flag = 1;
154
155	if (setsockopt(fd, IPPROTO_IP, MRT_INIT, &flag,
156	    sizeof(flag)) == -1) {
157		log_warn("mrt_init: error setting MRT_INIT");
158		return (-1);
159	}
160
161	return (0);
162}
163
164int
165mrt_done(int fd)
166{
167	int	flag = 0;
168
169	if (setsockopt(fd, IPPROTO_IP, MRT_DONE, &flag,
170	    sizeof(flag)) == -1) {
171		log_warn("mrt_done: error setting MRT_DONE");
172		return (-1);
173	}
174
175	return (0);
176}
177
178int
179mrt_add_vif(int fd, struct iface *iface)
180{
181	struct vifctl	vc;
182
183	vc.vifc_vifi            = iface->ifindex;
184	vc.vifc_flags           = 0;
185	vc.vifc_threshold       = 1;
186	vc.vifc_rate_limit	= 0;
187	vc.vifc_lcl_addr.s_addr = iface->addr.s_addr;
188	vc.vifc_rmt_addr.s_addr = 0;
189
190	if (setsockopt(fd, IPPROTO_IP, MRT_ADD_VIF, &vc,
191	    sizeof(vc)) == -1) {
192		log_warn("mrt_add_vif: error adding VIF");
193		return (-1);
194	}
195
196	return (0);
197}
198
199void
200mrt_del_vif(int fd, struct iface *iface)
201{
202	vifi_t	 vifi;
203
204	vifi = iface->ifindex;
205
206	if (setsockopt(fd, IPPROTO_IP, MRT_DEL_VIF, &vifi,
207	    sizeof(vifi)) == -1)
208		log_warn("mrt_del_vif: error deleting VIF");
209}
210
211int
212mrt_add_mfc(int fd, struct mfc *mfc)
213{
214	struct mfcctl	 mc;
215	int		 i;
216
217	log_debug("mrt_add_mfc: interface %d, group %s", mfc->ifindex,
218	    inet_ntoa(mfc->group));
219
220	mc.mfcc_origin = mfc->origin;
221	mc.mfcc_mcastgrp = mfc->group;
222	mc.mfcc_parent = mfc->ifindex;
223
224	for (i = 0; i < MAXVIFS; i++) {
225		mc.mfcc_ttls[i] = mfc->ttls[i];
226	}
227
228	if (setsockopt(fd, IPPROTO_IP, MRT_ADD_MFC, &mc, sizeof(mc))
229	    == -1) {
230		log_warnx("mrt_add_mfc: error adding group %s to interface %d",
231		    inet_ntoa(mfc->group), mfc->ifindex);
232		return (-1);
233	}
234
235	return (0);
236}
237
238int
239mrt_del_mfc(int fd, struct mfc *mfc)
240{
241	struct mfcctl	 mc;
242
243	log_debug("mrt_del_mfc: group %s", inet_ntoa(mfc->group));
244
245	mc.mfcc_origin = mfc->origin;
246	mc.mfcc_mcastgrp = mfc->group;
247
248	if (setsockopt(fd, IPPROTO_IP, MRT_DEL_MFC, &mc, sizeof(mc))
249	    == -1) {
250		log_warnx("mrt_del_mfc: error deleting group %s ",
251		    inet_ntoa(mfc->group));
252		return (-1);
253	}
254
255	return (0);
256}
257