Initial import from FreeBSD RELENG_4:
[games.git] / usr.sbin / mrouted / kern.c
1 /*
2  * The mrouted program is covered by the license in the accompanying file
3  * named "LICENSE".  Use of the mrouted program represents acceptance of
4  * the terms and conditions listed in that file.
5  *
6  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
7  * Leland Stanford Junior University.
8  *
9  *
10  * kern.c,v 3.8.4.10 1998/01/06 02:00:51 fenner Exp
11  */
12
13 #ifndef lint
14 static const char rcsid[] =
15   "$FreeBSD: src/usr.sbin/mrouted/kern.c,v 1.12 1999/08/28 01:17:04 peter Exp $";
16 #endif /* not lint */
17
18 #include "defs.h"
19
20 int curttl = 0;
21
22 void k_set_rcvbuf(bufsize, minsize)
23     int bufsize;
24     int minsize;
25 {
26     int delta = bufsize / 2;
27     int iter = 0;
28
29     /*
30      * Set the socket buffer.  If we can't set it as large as we
31      * want, search around to try to find the highest acceptable
32      * value.  The highest acceptable value being smaller than
33      * minsize is a fatal error.
34      */
35     if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF,
36                 (char *)&bufsize, sizeof(bufsize)) < 0) {
37         bufsize -= delta;
38         while (1) {
39             iter++;
40             if (delta > 1)
41                 delta /= 2;
42
43             if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF,
44                         (char *)&bufsize, sizeof(bufsize)) < 0) {
45                     bufsize -= delta;
46             } else {
47                     if (delta < 1024)
48                         break;
49                     bufsize += delta;
50             }
51         }
52         if (bufsize < minsize) {
53             log(LOG_ERR, 0, "OS-allowed buffer size %u < app min %u",
54                 bufsize, minsize);
55             /*NOTREACHED*/
56         }
57     }
58     IF_DEBUG(DEBUG_KERN)
59     log(LOG_DEBUG, 0, "Got %d byte buffer size in %d iterations",
60             bufsize, iter);
61 }
62
63
64 void k_hdr_include(bool)
65     int bool;
66 {
67 #ifdef IP_HDRINCL
68     if (setsockopt(igmp_socket, IPPROTO_IP, IP_HDRINCL,
69                    (char *)&bool, sizeof(bool)) < 0)
70         log(LOG_ERR, errno, "setsockopt IP_HDRINCL %u", bool);
71 #endif
72 }
73
74
75 void k_set_ttl(t)
76     int t;
77 {
78 #ifndef RAW_OUTPUT_IS_RAW
79     u_char ttl;
80
81     ttl = t;
82     if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_TTL,
83                    (char *)&ttl, sizeof(ttl)) < 0)
84         log(LOG_ERR, errno, "setsockopt IP_MULTICAST_TTL %u", ttl);
85 #endif
86     curttl = t;
87 }
88
89
90 void k_set_loop(l)
91     int l;
92 {
93     u_char loop;
94
95     loop = l;
96     if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_LOOP,
97                    (char *)&loop, sizeof(loop)) < 0)
98         log(LOG_ERR, errno, "setsockopt IP_MULTICAST_LOOP %u", loop);
99 }
100
101
102 void k_set_if(ifa)
103     u_int32 ifa;
104 {
105     struct in_addr adr;
106
107     adr.s_addr = ifa;
108     if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_IF,
109                    (char *)&adr, sizeof(adr)) < 0)
110         log(LOG_ERR, errno, "setsockopt IP_MULTICAST_IF %s",
111                             inet_fmt(ifa, s1));
112 }
113
114
115 void k_join(grp, ifa)
116     u_int32 grp;
117     u_int32 ifa;
118 {
119     struct ip_mreq mreq;
120
121     mreq.imr_multiaddr.s_addr = grp;
122     mreq.imr_interface.s_addr = ifa;
123
124     if (setsockopt(igmp_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
125                    (char *)&mreq, sizeof(mreq)) < 0)
126         log(LOG_WARNING, errno, "can't join group %s on interface %s",
127                                 inet_fmt(grp, s1), inet_fmt(ifa, s2));
128 }
129
130
131 void k_leave(grp, ifa)
132     u_int32 grp;
133     u_int32 ifa;
134 {
135     struct ip_mreq mreq;
136
137     mreq.imr_multiaddr.s_addr = grp;
138     mreq.imr_interface.s_addr = ifa;
139
140     if (setsockopt(igmp_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP,
141                    (char *)&mreq, sizeof(mreq)) < 0)
142         log(LOG_WARNING, errno, "can't leave group %s on interface %s",
143                                 inet_fmt(grp, s1), inet_fmt(ifa, s2));
144 }
145
146
147 void k_init_dvmrp()
148 {
149 #ifdef OLD_KERNEL
150     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_INIT,
151                    (char *)NULL, 0) < 0)
152 #else
153     int v=1;
154
155     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_INIT,
156                    (char *)&v, sizeof(int)) < 0)
157 #endif
158         log(LOG_ERR, errno, "can't enable Multicast routing in kernel");
159 }
160
161
162 void k_stop_dvmrp()
163 {
164     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DONE,
165                    (char *)NULL, 0) < 0)
166         log(LOG_WARNING, errno, "can't disable Multicast routing in kernel");
167 }
168
169
170 void k_add_vif(vifi, v)
171     vifi_t vifi;
172     struct uvif *v;
173 {
174     struct vifctl vc;
175
176     vc.vifc_vifi            = vifi;
177     vc.vifc_flags           = v->uv_flags & VIFF_KERNEL_FLAGS;
178     vc.vifc_threshold       = v->uv_threshold;
179     vc.vifc_rate_limit      = v->uv_rate_limit;
180     vc.vifc_lcl_addr.s_addr = v->uv_lcl_addr;
181     vc.vifc_rmt_addr.s_addr = v->uv_rmt_addr;
182
183     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_VIF,
184                    (char *)&vc, sizeof(vc)) < 0)
185         log(LOG_ERR, errno, "setsockopt MRT_ADD_VIF on vif %d", vifi);
186 }
187
188
189 void k_del_vif(vifi)
190     vifi_t vifi;
191 {
192     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_VIF,
193                    (char *)&vifi, sizeof(vifi)) < 0)
194         log(LOG_ERR, errno, "setsockopt MRT_DEL_VIF on vif %d", vifi);
195 }
196
197
198 /*
199  * Adds a (source, mcastgrp) entry to the kernel
200  */
201 void k_add_rg(origin, g)
202     u_int32 origin;
203     struct gtable *g;
204 {
205     struct mfcctl mc;
206     vifi_t i;
207
208 #ifdef DEBUG_MFC
209     md_log(MD_ADD, origin, g->gt_mcastgrp);
210 #endif
211     /* copy table values so that setsockopt can process it */
212     mc.mfcc_origin.s_addr = origin;
213 #ifdef OLD_KERNEL
214     mc.mfcc_originmask.s_addr = 0xffffffff;
215 #endif
216     mc.mfcc_mcastgrp.s_addr = g->gt_mcastgrp;
217     mc.mfcc_parent = g->gt_route ? g->gt_route->rt_parent : NO_VIF;
218     for (i = 0; i < numvifs; i++)
219         mc.mfcc_ttls[i] = g->gt_ttls[i];
220
221     /* write to kernel space */
222     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_MFC,
223                    (char *)&mc, sizeof(mc)) < 0) {
224 #ifdef DEBUG_MFC
225         md_log(MD_ADD_FAIL, origin, g->gt_mcastgrp);
226 #endif
227         log(LOG_WARNING, errno, "setsockopt MRT_ADD_MFC",
228                 inet_fmt(origin, s1), inet_fmt(g->gt_mcastgrp, s2));
229     }
230 }
231
232
233 /*
234  * Deletes a (source, mcastgrp) entry from the kernel
235  */
236 int k_del_rg(origin, g)
237     u_int32 origin;
238     struct gtable *g;
239 {
240     struct mfcctl mc;
241     int retval;
242
243 #ifdef DEBUG_MFC
244     md_log(MD_DEL, origin, g->gt_mcastgrp);
245 #endif
246     /* copy table values so that setsockopt can process it */
247     mc.mfcc_origin.s_addr = origin;
248 #ifdef OLD_KERNEL
249     mc.mfcc_originmask.s_addr = 0xffffffff;
250 #endif
251     mc.mfcc_mcastgrp.s_addr = g->gt_mcastgrp;
252
253     /* write to kernel space */
254     if ((retval = setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_MFC,
255                    (char *)&mc, sizeof(mc))) < 0) {
256 #ifdef DEBUG_MFC
257         md_log(MD_DEL_FAIL, origin, g->gt_mcastgrp);
258 #endif
259         log(LOG_WARNING, errno, "setsockopt MRT_DEL_MFC of (%s %s)",
260                 inet_fmt(origin, s1), inet_fmt(g->gt_mcastgrp, s2));
261     }
262
263     return retval;
264 }       
265
266 /*
267  * Get the kernel's idea of what version of mrouted needs to run with it.
268  */
269 int k_get_version()
270 {
271 #ifdef OLD_KERNEL
272     return -1;
273 #else
274     int vers;
275     int len = sizeof(vers);
276
277     if (getsockopt(igmp_socket, IPPROTO_IP, MRT_VERSION,
278                         (char *)&vers, &len) < 0)
279         log(LOG_ERR, errno,
280                 "getsockopt MRT_VERSION: perhaps your kernel is too old");
281
282     return vers;
283 #endif
284 }
285
286 #if 0
287 /*
288  * Get packet counters
289  */
290 int
291 k_get_vif_count(vifi, icount, ocount, ibytes, obytes)
292     vifi_t vifi;
293     int *icount, *ocount, *ibytes, *obytes;
294 {
295     struct sioc_vif_req vreq;
296     int retval = 0;
297
298     vreq.vifi = vifi;
299     if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&vreq) < 0) {
300         log(LOG_WARNING, errno, "SIOCGETVIFCNT on vif %d", vifi);
301         vreq.icount = vreq.ocount = vreq.ibytes =
302                 vreq.obytes = 0xffffffff;
303         retval = 1;
304     }
305     if (icount)
306         *icount = vreq.icount;
307     if (ocount)
308         *ocount = vreq.ocount;
309     if (ibytes)
310         *ibytes = vreq.ibytes;
311     if (obytes)
312         *obytes = vreq.obytes;
313     return retval;
314 }
315
316 /*
317  * Get counters for a desired source and group.
318  */
319 int
320 k_get_sg_count(src, grp, pktcnt, bytecnt, wrong_if)
321     u_int32 src;
322     u_int32 grp;
323     struct sg_count *retval;
324 {
325     struct sioc_sg_req sgreq;
326     int retval = 0;
327
328     sgreq.src.s_addr = src;
329     sgreq.grp.s_addr = grp;
330     if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sgreq) < 0) {
331         log(LOG_WARNING, errno, "SIOCGETSGCNT on (%s %s)",
332             inet_fmt(src, s1), inet_fmt(grp, s2));
333         sgreq.pktcnt = sgreq.bytecnt = sgreq.wrong_if = 0xffffffff;
334         return 1;
335     }
336     if (pktcnt)
337         *pktcnt = sgreq.pktcnt;
338     if (bytecnt)
339         *bytecnt = sgreq.bytecnt;
340     if (wrong_if)
341         *wrong_if = sgreq.wrong_if;
342     return retval;
343 }
344 #endif