/* Leave from the all rip routers multicast group. */ static int ripng_multicast_leave (struct interface *ifp) { int ret; struct ipv6_mreq mreq; if (if_is_up (ifp) && if_is_multicast (ifp)) { memset (&mreq, 0, sizeof (mreq)); inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr); mreq.ipv6mr_interface = ifp->ifindex; ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *) &mreq, sizeof (mreq)); if (ret < 0) zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s\n", safe_strerror (errno)); if (IS_RIPNG_DEBUG_EVENT) zlog_debug ("RIPng %s leave from all-rip-routers multicast group", ifp->name); if (ret < 0) return -1; } return 0; }
/* Multicast packet receive socket. */ static int rip_multicast_join (struct interface *ifp, int sock) { struct listnode *cnode; struct connected *ifc; if (if_is_operative (ifp) && if_is_multicast (ifp)) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("multicast join at %s", ifp->name); for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, ifc)) { struct prefix_ipv4 *p; struct in_addr group; p = (struct prefix_ipv4 *) ifc->address; if (p->family != AF_INET) continue; group.s_addr = htonl (INADDR_RIP_GROUP); if (ipv4_multicast_join (sock, group, p->prefix, ifp->ifindex) < 0) return -1; else return 0; } } return 0; }
/* Leave from multicast group. */ static void rip_multicast_leave (struct interface *ifp, int sock) { struct listnode *cnode; struct connected *connected; if (if_is_up (ifp) && if_is_multicast (ifp)) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("multicast leave from %s", ifp->name); for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected)) { struct prefix_ipv4 *p; struct in_addr group; p = (struct prefix_ipv4 *) connected->address; if (p->family != AF_INET) continue; group.s_addr = htonl (INADDR_RIP_GROUP); if (ipv4_multicast_leave (sock, group, p->prefix, ifp->ifindex) == 0) return; } } }
/* Send RIP request packet to specified interface. */ static void rip_request_interface_send (struct interface *ifp, u_char version) { struct sockaddr_in to; /* RIPv2 support multicast. */ if (version == RIPv2 && if_is_multicast (ifp)) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("multicast request on %s", ifp->name); rip_request_send (NULL, ifp, version, NULL); return; } /* RIPv1 and non multicast interface. */ if (if_is_pointopoint (ifp) || if_is_broadcast (ifp)) { struct listnode *cnode, *cnnode; struct connected *connected; if (IS_RIP_DEBUG_EVENT) zlog_debug ("broadcast request to %s", ifp->name); for (ALL_LIST_ELEMENTS (ifp->connected, cnode, cnnode, connected)) { if (connected->address->family == AF_INET) { memset (&to, 0, sizeof (struct sockaddr_in)); to.sin_port = htons (RIP_PORT_DEFAULT); if (connected->destination) /* use specified broadcast or peer destination addr */ to.sin_addr = connected->destination->u.prefix4; else if (connected->address->prefixlen < IPV4_MAX_PREFIXLEN) /* calculate the appropriate broadcast address */ to.sin_addr.s_addr = ipv4_broadcast_addr(connected->address->u.prefix4.s_addr, connected->address->prefixlen); else /* do not know where to send the packet */ continue; if (IS_RIP_DEBUG_EVENT) zlog_debug ("SEND request to %s", inet_ntoa (to.sin_addr)); rip_request_send (&to, ifp, version, connected); } } } }
/* Join to the all rip routers multicast group. */ static int ripng_multicast_join (struct interface *ifp) { int ret; struct ipv6_mreq mreq; int save_errno; if (if_is_up (ifp) && if_is_multicast (ifp)) { memset (&mreq, 0, sizeof (mreq)); inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr); mreq.ipv6mr_interface = ifp->ifindex; /* * NetBSD 1.6.2 requires root to join groups on gif(4). * While this is bogus, privs are available and easy to use * for this call as a workaround. */ if (ripngd_privs.change (ZPRIVS_RAISE)) zlog_err ("ripng_multicast_join: could not raise privs"); ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreq, sizeof (mreq)); save_errno = errno; if (ripngd_privs.change (ZPRIVS_LOWER)) zlog_err ("ripng_multicast_join: could not lower privs"); if (ret < 0 && save_errno == EADDRINUSE) { /* * Group is already joined. This occurs due to sloppy group * management, in particular declining to leave the group on * an interface that has just gone down. */ zlog_warn ("ripng join on %s EADDRINUSE (ignoring)\n", ifp->name); return 0; /* not an error */ } if (ret < 0) zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", safe_strerror (save_errno)); if (IS_RIPNG_DEBUG_EVENT) zlog_debug ("RIPng %s join to all-rip-routers multicast group", ifp->name); if (ret < 0) return -1; } return 0; }