2 * Copyright (c) 1998 by the University of Southern California.
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.
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
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.
30 * Other copyrights might apply to parts of this software and are so
31 * noted when applicable.
36 * Questions concerning this software should be directed to
37 * Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
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".
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".
53 #include <sys/param.h>
54 #include <sys/types.h>
55 #include <sys/socket.h>
56 #include <sys/ioctl.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>
65 #include <netinet6/in6_var.h>
75 * Open/init the multicast routing in the kernel and sets the MRT_ASSERT
82 k_init_pim(int socket)
86 if (setsockopt(socket, IPPROTO_IPV6, MRT6_INIT, (char *) &v, sizeof(int)) < 0)
87 log(LOG_ERR, errno, "cannot enable multicast routing in kernel");
89 if (setsockopt(socket, IPPROTO_IPV6, MRT6_PIM, (char *) &v, sizeof(int)) < 0)
90 log(LOG_ERR, errno, "Pim kernel initialization");
94 * Stops the multicast routing in the kernel and resets the MRT_ASSERT flag
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");
108 if (setsockopt(socket, IPPROTO_IPV6, MRT6_DONE, (char *) NULL, 0) < 0)
109 log(LOG_ERR, errno, "cannot disable multicast routing in kernel");
114 * Set the socket receiving buffer. `bufsize` is the preferred size,
115 * `minsize` is the smallest acceptable size.
119 k_set_rcvbuf(int socket, int bufsize, int minsize)
121 int delta = bufsize / 2;
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.
132 if (setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *) &bufsize, sizeof(bufsize)) < 0)
140 if (setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *) &bufsize, sizeof(bufsize)) < 0)
149 if (bufsize < minsize)
150 log(LOG_ERR, 0, "OS-allowed buffer size %u < app min %u",
157 log(LOG_DEBUG,0,"Buffer reception size for socket %d : %d in %d iterations",socket, bufsize, iter);
161 * Set the default Hop Limit for the multicast packets outgoing from this
166 k_set_hlim(int socket, int h)
170 if (setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &hlim, sizeof(hlim)) < 0)
171 log(LOG_ERR,errno,"k_set_hlim");
176 * Set/reset the IPV6_MULTICAST_LOOP. Set/reset is specified by "flag".
181 k_set_loop(int socket, int flag)
186 if (setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &loop, sizeof(loop)) < 0)
187 log(LOG_ERR,errno,"k_set_loop");
191 * Set the IPV6_MULTICAST_IF option on local interface which has the
197 k_set_if(int socket, u_int ifindex)
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));
207 * Join a multicast grp group on local interface ifa.
211 k_join(int socket, struct in6_addr * grp, u_int ifindex)
213 struct ipv6_mreq mreq;
215 mreq.ipv6mr_multiaddr = *grp;
216 mreq.ipv6mr_interface = ifindex;
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));
225 * Leave a multicats grp group on local interface ifa.
229 k_leave(int socket, struct in6_addr * grp, u_int ifindex)
231 struct ipv6_mreq mreq;
233 mreq.ipv6mr_multiaddr = *grp;
234 mreq.ipv6mr_interface = ifindex;
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));
243 * Add a virtual interface in the kernel.
247 k_add_vif(int socket, vifi_t vifi, struct uvif * v)
251 mc.mif6c_mifi = vifi;
252 mc.mif6c_flags = v->uv_flags;
254 mc.mif6c_pifi = v->uv_ifindex;
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);
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);
266 * Delete a virtual interface in the kernel.
270 k_del_vif(int socket, vifi_t vifi)
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);
278 * Delete all MFC entries for particular routing entry from the kernel.
282 k_del_mfc(int socket, struct sockaddr_in6 * source, struct sockaddr_in6 * group)
286 mc.mf6cc_origin = *source;
287 mc.mf6cc_mcastgrp = *group;
289 pim6dstat.kern_del_cache++;
290 if (setsockopt(socket, IPPROTO_IPV6, MRT6_DEL_MFC, (char *) &mc, sizeof(mc)) < 0)
292 pim6dstat.kern_del_cache_fail++;
293 log(LOG_WARNING, errno, "setsockopt MRT6_DEL_MFC");
297 syslog(LOG_DEBUG, "Deleted MFC entry : src %s ,grp %s", inet6_fmt(&source->sin6_addr),
298 inet6_fmt(&group->sin6_addr));
304 * Install/modify a MFC entry in the kernel
308 k_chg_mfc(socket, source, group, iif, oifs, rp_addr)
310 struct sockaddr_in6 *source;
311 struct sockaddr_in6 *group;
314 struct sockaddr_in6 *rp_addr;
320 mc.mf6cc_origin = *source;
321 mc.mf6cc_mcastgrp = *group;
322 mc.mf6cc_parent = iif;
325 IF_ZERO(&mc.mf6cc_ifset);
327 for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++)
329 if (IF_ISSET(vifi, oifs))
330 IF_SET(vifi, &mc.mf6cc_ifset);
332 IF_CLR(vifi, &mc.mf6cc_ifset);
335 #ifdef PIM_REG_KERNEL_ENCAP
336 mc.mf6cc_rp_addr.s_addr = rp_addr;
339 pim6dstat.kern_add_cache++;
340 if (setsockopt(socket, IPPROTO_IPV6, MRT6_ADD_MFC, (char *) &mc,
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));
356 * Get packet counters for particular interface
359 * XXX: TODO: currently not used, but keep just in case we need it later.
363 k_get_vif_count(vifi, retval)
365 struct vif_count *retval;
367 struct sioc_mif_req6 mreq;
370 if (ioctl(udp_socket, SIOCGETMIFCNT_IN6, (char *) &mreq) < 0)
372 log(LOG_WARNING, errno, "SIOCGETMIFCNT_IN6 on vif %d", vifi);
373 retval->icount = retval->ocount = retval->ibytes =
374 retval->obytes = 0xffffffff;
377 retval->icount = mreq.icount;
378 retval->ocount = mreq.ocount;
379 retval->ibytes = mreq.ibytes;
380 retval->obytes = mreq.obytes;
386 * Gets the number of packets, bytes, and number of packets arrived on wrong
387 * if in the kernel for particular (S,G) entry.
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;
397 struct sioc_sg_req6 sgreq;
401 if (ioctl(socket, SIOCGETSGCNT_IN6, (char *) &sgreq) < 0)
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 */
409 retval->pktcnt = sgreq.pktcnt;
410 retval->bytecnt = sgreq.bytecnt;
411 retval->wrong_if = sgreq.wrong_if;