Merge branch 'master' of ssh://crater.dragonflybsd.org/repository/git/dragonfly
[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.4 2004/12/16 03:39:05 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             dolog(LOG_ERR, 0, "OS-allowed buffer size %u < app min %u",
51                 bufsize, minsize);
52             /*NOTREACHED*/
53         }
54     }
55     IF_DEBUG(DEBUG_KERN)
56     dolog(LOG_DEBUG, 0, "Got %d byte buffer size in %d iterations",
57             bufsize, iter);
58 }
59
60 void
61 k_hdr_include(int boolv)
62 {
63 #ifdef IP_HDRINCL
64     if (setsockopt(igmp_socket, IPPROTO_IP, IP_HDRINCL,
65                    (char *)&boolv, sizeof(boolv)) < 0)
66         dolog(LOG_ERR, errno, "setsockopt IP_HDRINCL %u", boolv);
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         dolog(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         dolog(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         dolog(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         dolog(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         dolog(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                    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         dolog(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                    NULL, 0) < 0)
155         dolog(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         dolog(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         dolog(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         dolog(LOG_WARNING, errno, "setsockopt MRT_ADD_MFC");
213     }
214 }
215
216
217 /*
218  * Deletes a (source, mcastgrp) entry from the kernel
219  */
220 int
221 k_del_rg(u_int32 origin, struct gtable *g)
222 {
223     struct mfcctl mc;
224     int retval;
225
226 #ifdef DEBUG_MFC
227     md_log(MD_DEL, origin, g->gt_mcastgrp);
228 #endif
229     /* copy table values so that setsockopt can process it */
230     mc.mfcc_origin.s_addr = origin;
231 #ifdef OLD_KERNEL
232     mc.mfcc_originmask.s_addr = 0xffffffff;
233 #endif
234     mc.mfcc_mcastgrp.s_addr = g->gt_mcastgrp;
235
236     /* write to kernel space */
237     if ((retval = setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_MFC,
238                    (char *)&mc, sizeof(mc))) < 0) {
239 #ifdef DEBUG_MFC
240         md_log(MD_DEL_FAIL, origin, g->gt_mcastgrp);
241 #endif
242         dolog(LOG_WARNING, errno, "setsockopt MRT_DEL_MFC of (%s %s)",
243                 inet_fmt(origin, s1), inet_fmt(g->gt_mcastgrp, s2));
244     }
245
246     return retval;
247 }       
248
249 /*
250  * Get the kernel's idea of what version of mrouted needs to run with it.
251  */
252 int
253 k_get_version(void)
254 {
255 #ifdef OLD_KERNEL
256     return -1;
257 #else
258     int vers;
259     int len = sizeof(vers);
260
261     if (getsockopt(igmp_socket, IPPROTO_IP, MRT_VERSION,
262                         (char *)&vers, &len) < 0)
263         dolog(LOG_ERR, errno,
264                 "getsockopt MRT_VERSION: perhaps your kernel is too old");
265
266     return vers;
267 #endif
268 }