9c13e9903a81477c4945983c70f2634a62d75ca3
[dragonfly.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  * $FreeBSD: src/usr.sbin/mrouted/kern.c,v 1.12 1999/08/28 01:17:04 peter Exp $
13  * $DragonFly: src/usr.sbin/mrouted/kern.c,v 1.3 2004/03/15 18:10:28 dillon Exp $
14  */
15
16 #include "defs.h"
17
18 int curttl = 0;
19
20 void
21 k_set_rcvbuf(int bufsize, int minsize)
22 {
23     int delta = bufsize / 2;
24     int iter = 0;
25
26     /*
27      * Set the socket buffer.  If we can't set it as large as we
28      * want, search around to try to find the highest acceptable
29      * value.  The highest acceptable value being smaller than
30      * minsize is a fatal error.
31      */
32     if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF,
33                 (char *)&bufsize, sizeof(bufsize)) < 0) {
34         bufsize -= delta;
35         while (1) {
36             iter++;
37             if (delta > 1)
38                 delta /= 2;
39
40             if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF,
41                         (char *)&bufsize, sizeof(bufsize)) < 0) {
42                     bufsize -= delta;
43             } else {
44                     if (delta < 1024)
45                         break;
46                     bufsize += delta;
47             }
48         }
49         if (bufsize < minsize) {
50             log(LOG_ERR, 0, "OS-allowed buffer size %u < app min %u",
51                 bufsize, minsize);
52             /*NOTREACHED*/
53         }
54     }
55     IF_DEBUG(DEBUG_KERN)
56     log(LOG_DEBUG, 0, "Got %d byte buffer size in %d iterations",
57             bufsize, iter);
58 }
59
60 void
61 k_hdr_include(int bool)
62 {
63 #ifdef IP_HDRINCL
64     if (setsockopt(igmp_socket, IPPROTO_IP, IP_HDRINCL,
65                    (char *)&bool, sizeof(bool)) < 0)
66         log(LOG_ERR, errno, "setsockopt IP_HDRINCL %u", bool);
67 #endif
68 }
69
70 void
71 k_set_ttl(int t)
72 {
73 #ifndef RAW_OUTPUT_IS_RAW
74     u_char ttl;
75
76     ttl = t;
77     if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_TTL,
78                    (char *)&ttl, sizeof(ttl)) < 0)
79         log(LOG_ERR, errno, "setsockopt IP_MULTICAST_TTL %u", ttl);
80 #endif
81     curttl = t;
82 }
83
84 void
85 k_set_loop(int l)
86 {
87     u_char loop;
88
89     loop = l;
90     if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_LOOP,
91                    (char *)&loop, sizeof(loop)) < 0)
92         log(LOG_ERR, errno, "setsockopt IP_MULTICAST_LOOP %u", loop);
93 }
94
95 void
96 k_set_if(u_int32 ifa)
97 {
98     struct in_addr adr;
99
100     adr.s_addr = ifa;
101     if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_IF,
102                    (char *)&adr, sizeof(adr)) < 0)
103         log(LOG_ERR, errno, "setsockopt IP_MULTICAST_IF %s",
104                             inet_fmt(ifa, s1));
105 }
106
107 void
108 k_join(u_int32 grp, u_int32 ifa)
109 {
110     struct ip_mreq mreq;
111
112     mreq.imr_multiaddr.s_addr = grp;
113     mreq.imr_interface.s_addr = ifa;
114
115     if (setsockopt(igmp_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
116                    (char *)&mreq, sizeof(mreq)) < 0)
117         log(LOG_WARNING, errno, "can't join group %s on interface %s",
118                                 inet_fmt(grp, s1), inet_fmt(ifa, s2));
119 }
120
121 void
122 k_leave(u_int32 grp, u_int32 ifa)
123 {
124     struct ip_mreq mreq;
125
126     mreq.imr_multiaddr.s_addr = grp;
127     mreq.imr_interface.s_addr = ifa;
128
129     if (setsockopt(igmp_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP,
130                    (char *)&mreq, sizeof(mreq)) < 0)
131         log(LOG_WARNING, errno, "can't leave group %s on interface %s",
132                                 inet_fmt(grp, s1), inet_fmt(ifa, s2));
133 }
134
135 void
136 k_init_dvmrp(void)
137 {
138 #ifdef OLD_KERNEL
139     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_INIT,
140                    (char *)NULL, 0) < 0)
141 #else
142     int v=1;
143
144     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_INIT,
145                    (char *)&v, sizeof(int)) < 0)
146 #endif
147         log(LOG_ERR, errno, "can't enable Multicast routing in kernel");
148 }
149
150 void
151 k_stop_dvmrp(void)
152 {
153     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DONE,
154                    (char *)NULL, 0) < 0)
155         log(LOG_WARNING, errno, "can't disable Multicast routing in kernel");
156 }
157
158 void 
159 k_add_vif(vifi_t vifi, struct uvif *v)
160 {
161     struct vifctl vc;
162
163     vc.vifc_vifi            = vifi;
164     vc.vifc_flags           = v->uv_flags & VIFF_KERNEL_FLAGS;
165     vc.vifc_threshold       = v->uv_threshold;
166     vc.vifc_rate_limit      = v->uv_rate_limit;
167     vc.vifc_lcl_addr.s_addr = v->uv_lcl_addr;
168     vc.vifc_rmt_addr.s_addr = v->uv_rmt_addr;
169
170     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_VIF,
171                    (char *)&vc, sizeof(vc)) < 0)
172         log(LOG_ERR, errno, "setsockopt MRT_ADD_VIF on vif %d", vifi);
173 }
174
175 void
176 k_del_vif(vifi_t vifi)
177 {
178
179     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_VIF,
180                    (char *)&vifi, sizeof(vifi)) < 0)
181         log(LOG_ERR, errno, "setsockopt MRT_DEL_VIF on vif %d", vifi);
182 }
183
184 /*
185  * Adds a (source, mcastgrp) entry to the kernel
186  */
187 void
188 k_add_rg(u_int32 origin, struct gtable *g)
189 {
190     struct mfcctl mc;
191     vifi_t i;
192
193 #ifdef DEBUG_MFC
194     md_log(MD_ADD, origin, g->gt_mcastgrp);
195 #endif
196     /* copy table values so that setsockopt can process it */
197     mc.mfcc_origin.s_addr = origin;
198 #ifdef OLD_KERNEL
199     mc.mfcc_originmask.s_addr = 0xffffffff;
200 #endif
201     mc.mfcc_mcastgrp.s_addr = g->gt_mcastgrp;
202     mc.mfcc_parent = g->gt_route ? g->gt_route->rt_parent : NO_VIF;
203     for (i = 0; i < numvifs; i++)
204         mc.mfcc_ttls[i] = g->gt_ttls[i];
205
206     /* write to kernel space */
207     if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_MFC,
208                    (char *)&mc, sizeof(mc)) < 0) {
209 #ifdef DEBUG_MFC
210         md_log(MD_ADD_FAIL, origin, g->gt_mcastgrp);
211 #endif
212         log(LOG_WARNING, errno, "setsockopt MRT_ADD_MFC",
213                 inet_fmt(origin, s1), inet_fmt(g->gt_mcastgrp, s2));
214     }
215 }
216
217
218 /*
219  * Deletes a (source, mcastgrp) entry from the kernel
220  */
221 int
222 k_del_rg(u_int32 origin, struct gtable *g)
223 {
224     struct mfcctl mc;
225     int retval;
226
227 #ifdef DEBUG_MFC
228     md_log(MD_DEL, origin, g->gt_mcastgrp);
229 #endif
230     /* copy table values so that setsockopt can process it */
231     mc.mfcc_origin.s_addr = origin;
232 #ifdef OLD_KERNEL
233     mc.mfcc_originmask.s_addr = 0xffffffff;
234 #endif
235     mc.mfcc_mcastgrp.s_addr = g->gt_mcastgrp;
236
237     /* write to kernel space */
238     if ((retval = setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_MFC,
239                    (char *)&mc, sizeof(mc))) < 0) {
240 #ifdef DEBUG_MFC
241         md_log(MD_DEL_FAIL, origin, g->gt_mcastgrp);
242 #endif
243         log(LOG_WARNING, errno, "setsockopt MRT_DEL_MFC of (%s %s)",
244                 inet_fmt(origin, s1), inet_fmt(g->gt_mcastgrp, s2));
245     }
246
247     return retval;
248 }       
249
250 /*
251  * Get the kernel's idea of what version of mrouted needs to run with it.
252  */
253 int
254 k_get_version(void)
255 {
256 #ifdef OLD_KERNEL
257     return -1;
258 #else
259     int vers;
260     int len = sizeof(vers);
261
262     if (getsockopt(igmp_socket, IPPROTO_IP, MRT_VERSION,
263                         (char *)&vers, &len) < 0)
264         log(LOG_ERR, errno,
265                 "getsockopt MRT_VERSION: perhaps your kernel is too old");
266
267     return vers;
268 #endif
269 }