]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/pim6sd/kern.c
This commit was generated by cvs2svn to compensate for changes in r57844,
[FreeBSD/FreeBSD.git] / usr.sbin / pim6sd / kern.c
1 /*
2  *  Copyright (c) 1998 by the University of Southern California.
3  *  All rights reserved.
4  *
5  *  Permission to use, copy, modify, and distribute this software and
6  *  its documentation in source and binary forms for lawful
7  *  purposes and without fee is hereby granted, provided
8  *  that the above copyright notice appear in all copies and that both
9  *  the copyright notice and this permission notice appear in supporting
10  *  documentation, and that any documentation, advertising materials,
11  *  and other materials related to such distribution and use acknowledge
12  *  that the software was developed by the University of Southern
13  *  California and/or Information Sciences Institute.
14  *  The name of the University of Southern California may not
15  *  be used to endorse or promote products derived from this software
16  *  without specific prior written permission.
17  *
18  *  THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
19  *  ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.  THIS SOFTWARE IS
20  *  PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
21  *  INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
22  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
23  *  NON-INFRINGEMENT.
24  *
25  *  IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
26  *  SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
27  *  TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
28  *  THE USE OR PERFORMANCE OF THIS SOFTWARE.
29  *
30  *  Other copyrights might apply to parts of this software and are so
31  *  noted when applicable.
32  *
33  * $FreeBSD$
34  */
35 /*
36  *  Questions concerning this software should be directed to
37  *  Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
38  *
39  */
40 /*
41  * This program has been derived from pim6dd.
42  * The pim6dd program is covered by the license in the accompanying file
43  * named "LICENSE.pim6dd".
44  */
45 /*
46  * This program has been derived from pimd.
47  * The pimd program is covered by the license in the accompanying file
48  * named "LICENSE.pimd".
49  *
50  */
51
52 #include <sys/time.h>
53 #include <sys/param.h>
54 #include <sys/types.h>
55 #include <sys/socket.h>
56 #include <sys/ioctl.h>
57 #include <errno.h>
58 #include <net/if.h>
59 #include <net/route.h>
60 #include <netinet/in.h>
61 #include <netinet6/ip6_mroute.h>
62 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
63 #include <net/if_var.h>
64 #endif
65 #include <netinet6/in6_var.h>
66 #include <syslog.h>
67 #include "pimd.h"
68 #include "inet6.h"
69 #include "vif.h"
70 #include "mrt.h"
71 #include "debug.h"
72
73
74 /*
75  * Open/init the multicast routing in the kernel and sets the MRT_ASSERT
76  * flag in the kernel.
77  *
78  */
79
80
81 void
82 k_init_pim(int socket)
83 {
84     int             v = 1;
85
86     if (setsockopt(socket, IPPROTO_IPV6, MRT6_INIT, (char *) &v, sizeof(int)) < 0)
87         log(LOG_ERR, errno, "cannot enable multicast routing in kernel");
88
89     if (setsockopt(socket, IPPROTO_IPV6, MRT6_PIM, (char *) &v, sizeof(int)) < 0)
90         log(LOG_ERR, errno, "Pim kernel initialization");
91 }
92
93 /*
94  * Stops the multicast routing in the kernel and resets the MRT_ASSERT flag
95  * in the kernel.
96  */
97
98 void
99 k_stop_pim(socket)
100     int             socket;
101 {
102     int             v = 0;
103
104     if (setsockopt(socket, IPPROTO_IPV6, MRT6_PIM,
105                    (char *) &v, sizeof(int)) < 0)
106         log(LOG_ERR, errno, "Cannot reset PIM flag in kernel");
107
108     if (setsockopt(socket, IPPROTO_IPV6, MRT6_DONE, (char *) NULL, 0) < 0)
109         log(LOG_ERR, errno, "cannot disable multicast routing in kernel");
110
111 }
112
113 /*
114  * Set the socket receiving buffer. `bufsize` is the preferred size,
115  * `minsize` is the smallest acceptable size.
116  */
117
118 void
119 k_set_rcvbuf(int socket, int bufsize, int minsize)
120 {
121     int             delta = bufsize / 2;
122     int             iter = 0;
123
124     /*
125      * Set the socket buffer.  If we can't set it as large as we
126      * want, search around to try to find the highest acceptable
127      * value.  The highest acceptable value being smaller than
128      * minsize is a fatal error.
129      */
130
131
132     if (setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *) &bufsize, sizeof(bufsize)) < 0)
133     {
134         bufsize -= delta;
135         while (1)
136         {
137             iter++;
138             if (delta > 1)
139                 delta /= 2;
140             if (setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *) &bufsize, sizeof(bufsize)) < 0)
141                 bufsize -= delta;
142             else
143             {
144                 if (delta < 1024)
145                     break;
146                 bufsize += delta;
147             }
148         }
149         if (bufsize < minsize)
150                 log(LOG_ERR, 0, "OS-allowed buffer size %u < app min %u",
151                 bufsize, minsize);
152                 /*NOTREACHED*/
153
154
155     }
156     IF_DEBUG(DEBUG_KERN)
157                 log(LOG_DEBUG,0,"Buffer reception size for socket %d : %d in %d iterations",socket, bufsize, iter);
158 }
159
160 /*
161  * Set the default Hop Limit for the multicast packets outgoing from this
162  * socket.
163  */
164
165 void
166 k_set_hlim(int socket, int h)
167 {
168     int             hlim = h;
169
170     if (setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &hlim, sizeof(hlim)) < 0)
171                 log(LOG_ERR,errno,"k_set_hlim");
172
173 }
174
175 /*
176  * Set/reset the IPV6_MULTICAST_LOOP. Set/reset is specified by "flag".
177  */
178
179
180 void
181 k_set_loop(int socket, int flag)
182 {
183     u_int           loop;
184
185     loop = flag;
186     if (setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &loop, sizeof(loop)) < 0)
187                 log(LOG_ERR,errno,"k_set_loop");
188 }
189
190 /*
191  * Set the IPV6_MULTICAST_IF option on local interface which has the
192  * specified index.
193  */
194
195
196 void
197 k_set_if(int socket, u_int ifindex)
198 {
199     if (setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_IF,
200                    (char *) &ifindex, sizeof(ifindex)) < 0)
201            log(LOG_ERR, errno, "setsockopt IPV6_MULTICAST_IF for %s",
202         ifindex2str(ifindex));
203
204 }
205
206 /*
207  * Join a multicast grp group on local interface ifa.
208  */
209
210 void
211 k_join(int socket, struct in6_addr * grp, u_int ifindex)
212 {
213     struct ipv6_mreq mreq;
214
215     mreq.ipv6mr_multiaddr = *grp;
216     mreq.ipv6mr_interface = ifindex;
217
218     if (setsockopt(socket, IPPROTO_IPV6, IPV6_JOIN_GROUP,
219                    (char *) &mreq, sizeof(mreq)) < 0)
220         syslog(LOG_WARNING, "Cannot join group %s on interface %s",
221                inet6_fmt(grp), ifindex2str(ifindex));
222 }
223
224 /*
225  * Leave a multicats grp group on local interface ifa.
226  */
227
228 void
229 k_leave(int socket, struct in6_addr * grp, u_int ifindex)
230 {
231     struct ipv6_mreq mreq;
232
233     mreq.ipv6mr_multiaddr = *grp;
234     mreq.ipv6mr_interface = ifindex;
235
236     if (setsockopt(socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
237                    (char *) &mreq, sizeof(mreq)) < 0)
238         syslog(LOG_WARNING, "Cannot leave group %s on interface %s",
239                inet6_fmt(grp), ifindex2str(ifindex));
240 }
241
242 /*
243  * Add a virtual interface in the kernel.
244  */
245
246 void
247 k_add_vif(int socket, vifi_t vifi, struct uvif * v)
248 {
249     struct mif6ctl  mc;
250
251     mc.mif6c_mifi = vifi;
252     mc.mif6c_flags = v->uv_flags;
253
254     mc.mif6c_pifi = v->uv_ifindex;
255
256     if ((v->uv_flags & MIFF_REGISTER))
257                 IF_DEBUG(DEBUG_PIM_REGISTER)
258                         log(LOG_DEBUG,0,"register vifi : %d , register pifi : %d ", vifi, v->uv_ifindex);
259
260     if (setsockopt(socket, IPPROTO_IPV6, MRT6_ADD_MIF,
261                    (char *) &mc, sizeof(mc)) < 0)
262         log(LOG_ERR, errno, "setsockopt MRT6_ADD_MIF on mif %d", vifi);
263 }
264
265 /*
266  * Delete a virtual interface in the kernel.
267  */
268
269 void
270 k_del_vif(int socket, vifi_t vifi)
271 {
272     if (setsockopt(socket, IPPROTO_IPV6, MRT6_DEL_MIF,
273                    (char *) &vifi, sizeof(vifi)) < 0)
274         log(LOG_ERR, errno, "setsockopt MRT6_DEL_MIF on mif %d", vifi);
275 }
276
277 /*
278  * Delete all MFC entries for particular routing entry from the kernel.
279  */
280
281 int
282 k_del_mfc(int socket, struct sockaddr_in6 * source, struct sockaddr_in6 * group)
283 {
284     struct mf6cctl  mc;
285
286     mc.mf6cc_origin = *source;
287     mc.mf6cc_mcastgrp = *group;
288
289     pim6dstat.kern_del_cache++;
290     if (setsockopt(socket, IPPROTO_IPV6, MRT6_DEL_MFC, (char *) &mc, sizeof(mc)) < 0)
291     {
292         pim6dstat.kern_del_cache_fail++;
293         log(LOG_WARNING, errno, "setsockopt MRT6_DEL_MFC");
294         return FALSE;
295     }
296
297     syslog(LOG_DEBUG, "Deleted MFC entry : src %s ,grp %s", inet6_fmt(&source->sin6_addr),
298            inet6_fmt(&group->sin6_addr));
299
300     return TRUE;
301 }
302
303 /*
304  * Install/modify a MFC entry in the kernel
305  */
306
307 int
308 k_chg_mfc(socket, source, group, iif, oifs, rp_addr)
309     int             socket;
310     struct sockaddr_in6 *source;
311     struct sockaddr_in6 *group;
312     vifi_t          iif;
313     if_set         *oifs;
314     struct sockaddr_in6 *rp_addr;
315 {
316     struct mf6cctl  mc;
317     vifi_t          vifi;
318     struct uvif    *v;
319
320     mc.mf6cc_origin = *source;
321     mc.mf6cc_mcastgrp = *group;
322     mc.mf6cc_parent = iif;
323
324
325     IF_ZERO(&mc.mf6cc_ifset);
326
327     for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++)
328     {
329         if (IF_ISSET(vifi, oifs))
330             IF_SET(vifi, &mc.mf6cc_ifset);
331         else
332             IF_CLR(vifi, &mc.mf6cc_ifset);
333     }
334
335 #ifdef PIM_REG_KERNEL_ENCAP
336     mc.mf6cc_rp_addr.s_addr = rp_addr;
337 #endif
338
339     pim6dstat.kern_add_cache++;
340     if (setsockopt(socket, IPPROTO_IPV6, MRT6_ADD_MFC, (char *) &mc,
341                    sizeof(mc)) < 0)
342     {
343         pim6dstat.kern_add_cache_fail++;
344         log(LOG_WARNING, errno,
345             "setsockopt MRT_ADD_MFC for source %s and group %s",
346             inet6_fmt(&source->sin6_addr), inet6_fmt(&group->sin6_addr));
347         return (FALSE);
348     }
349     return (TRUE);
350 }
351
352
353
354
355 /*
356  * Get packet counters for particular interface
357  */
358 /*
359  * XXX: TODO: currently not used, but keep just in case we need it later.
360  */
361
362 int
363 k_get_vif_count(vifi, retval)
364     vifi_t          vifi;
365     struct vif_count *retval;
366 {
367     struct sioc_mif_req6 mreq;
368
369     mreq.mifi = vifi;
370     if (ioctl(udp_socket, SIOCGETMIFCNT_IN6, (char *) &mreq) < 0)
371     {
372         log(LOG_WARNING, errno, "SIOCGETMIFCNT_IN6 on vif %d", vifi);
373         retval->icount = retval->ocount = retval->ibytes =
374             retval->obytes = 0xffffffff;
375         return (1);
376     }
377     retval->icount = mreq.icount;
378     retval->ocount = mreq.ocount;
379     retval->ibytes = mreq.ibytes;
380     retval->obytes = mreq.obytes;
381     return (0);
382 }
383
384
385 /*
386  * Gets the number of packets, bytes, and number of packets arrived on wrong
387  * if in the kernel for particular (S,G) entry.
388  */
389
390 int
391 k_get_sg_cnt(socket, source, group, retval)
392     int             socket;     /* udp_socket */
393     struct sockaddr_in6 *source;
394     struct sockaddr_in6 *group;
395     struct sg_count *retval;
396 {
397     struct sioc_sg_req6 sgreq;
398
399     sgreq.src = *source;
400     sgreq.grp = *group;
401     if (ioctl(socket, SIOCGETSGCNT_IN6, (char *) &sgreq) < 0)
402     {
403         pim6dstat.kern_sgcnt_fail++;
404         log(LOG_WARNING, errno, "SIOCGETSGCNT_IN6 on (%s %s)",
405             inet6_fmt(&source->sin6_addr), inet6_fmt(&group->sin6_addr));
406         retval->pktcnt = retval->bytecnt = retval->wrong_if = ~0;       /* XXX */
407         return (1);
408     }
409     retval->pktcnt = sgreq.pktcnt;
410     retval->bytecnt = sgreq.bytecnt;
411     retval->wrong_if = sgreq.wrong_if;
412     return (0);
413 }