/* send all of the routing table or just do a flash update */ void rip_bcast(int flash) { #ifdef _HAVE_SIN_LEN static struct sockaddr_in dst = {sizeof(dst), AF_INET, 0, {0}, {0}}; #else static struct sockaddr_in dst = {AF_INET}; #endif struct interface *ifp; enum output_type type; int vers; struct timeval rtime; need_flash = 0; intvl_random(&rtime, MIN_WAITTIME, MAX_WAITTIME); no_flash = rtime; timevaladd(&no_flash, &now); if (rip_sock < 0) return; trace_act("send %s and inhibit dynamic updates for %.3f sec", flash ? "dynamic update" : "all routes", rtime.tv_sec + ((float)rtime.tv_usec)/1000000.0); for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) { /* Skip interfaces not doing RIP. * Do try broken interfaces to see if they have healed. */ if (IS_RIP_OUT_OFF(ifp->int_state)) continue; /* skip turned off interfaces */ if (!iff_up(ifp->int_if_flags)) continue; vers = (ifp->int_state & IS_NO_RIPV1_OUT) ? RIPv2 : RIPv1; if (ifp->int_if_flags & IFF_BROADCAST) { /* ordinary, hardware interface */ dst.sin_addr.s_addr = ifp->int_brdaddr; if (vers == RIPv2 && !(ifp->int_state & IS_NO_RIP_MCAST)) { type = OUT_MULTICAST; } else { type = OUT_BROADCAST; } } else if (ifp->int_if_flags & IFF_POINTOPOINT) { /* point-to-point hardware interface */ dst.sin_addr.s_addr = ifp->int_dstaddr; type = OUT_UNICAST; } else if (ifp->int_state & IS_REMOTE) { /* remote interface */ dst.sin_addr.s_addr = ifp->int_addr; type = OUT_UNICAST; } else { /* ATM, HIPPI, etc. */ continue; } supply(&dst, ifp, type, flash, vers, 1); } update_seqno++; /* all routes are up to date */ }
/* Send the contents of the global buffer via the non-multicast socket */ int /* <0 on failure */ output(enum output_type type, struct sockaddr_in *dst, /* send to here */ struct interface *ifp, struct rip *buf, int size) /* this many bytes */ { struct sockaddr_in in; int flags; const char *msg; int res; naddr tgt_mcast; int soc; int serrno; in = *dst; if (in.sin_port == 0) in.sin_port = htons(RIP_PORT); #ifdef _HAVE_SIN_LEN if (in.sin_len == 0) in.sin_len = sizeof(in); #endif soc = rip_sock; flags = 0; switch (type) { case OUT_QUERY: msg = "Answer Query"; if (soc < 0) soc = ifp->int_rip_sock; break; case OUT_UNICAST: msg = "Send"; if (soc < 0) soc = ifp->int_rip_sock; flags = MSG_DONTROUTE; break; case OUT_BROADCAST: if (ifp->int_if_flags & IFF_POINTOPOINT) { msg = "Send"; } else { msg = "Send bcast"; } flags = MSG_DONTROUTE; break; case OUT_MULTICAST: if (ifp->int_if_flags & IFF_POINTOPOINT) { msg = "Send pt-to-pt"; } else if (ifp->int_state & IS_DUP) { trace_act("abort multicast output via %s" " with duplicate address", ifp->int_name); return 0; } else { msg = "Send mcast"; if (rip_sock_mcast != ifp) { #ifdef MCAST_PPP_BUG /* Do not specify the primary interface * explicitly if we have the multicast * point-to-point kernel bug, since the * kernel will do the wrong thing if the * local address of a point-to-point link * is the same as the address of an ordinary * interface. */ if (ifp->int_addr == myaddr) { tgt_mcast = 0; } else #endif tgt_mcast = ifp->int_addr; if (0 > setsockopt(rip_sock, IPPROTO_IP, IP_MULTICAST_IF, &tgt_mcast, sizeof(tgt_mcast))) { serrno = errno; LOGERR("setsockopt(rip_sock," "IP_MULTICAST_IF)"); errno = serrno; ifp = NULL; return -1; } rip_sock_mcast = ifp; } in.sin_addr.s_addr = htonl(INADDR_RIP_GROUP); } break; case NO_OUT_MULTICAST: case NO_OUT_RIPV2: default: #ifdef DEBUG abort(); #endif return -1; } trace_rip(msg, "to", &in, ifp, buf, size); res = sendto(soc, buf, size, flags, (struct sockaddr *)&in, sizeof(in)); if (res < 0 && (ifp == NULL || !(ifp->int_state & IS_BROKE))) { serrno = errno; msglog("%s sendto(%s%s%s.%d): %s", msg, ifp != NULL ? ifp->int_name : "", ifp != NULL ? ", " : "", inet_ntoa(in.sin_addr), ntohs(in.sin_port), strerror(errno)); errno = serrno; } return res; }
/* Send the contents of the global buffer via the non-multicast socket */ int /* <0 on failure */ output(enum output_type type, struct sockaddr_in *dst, /* send to here */ struct interface *ifp, struct rip *buf, int size) /* this many bytes */ { struct sockaddr_in osin; int flags; const char *msg; int res; int soc; int serrno; assert(ifp != NULL); osin = *dst; if (osin.sin_port == 0) osin.sin_port = htons(RIP_PORT); #ifdef _HAVE_SIN_LEN if (osin.sin_len == 0) osin.sin_len = sizeof(osin); #endif soc = rip_sock; flags = 0; switch (type) { case OUT_QUERY: msg = "Answer Query"; if (soc < 0) soc = ifp->int_rip_sock; break; case OUT_UNICAST: msg = "Send"; if (soc < 0) soc = ifp->int_rip_sock; flags = MSG_DONTROUTE; break; case OUT_BROADCAST: if (ifp->int_if_flags & IFF_POINTOPOINT) { msg = "Send"; } else { msg = "Send bcast"; } flags = MSG_DONTROUTE; break; case OUT_MULTICAST: if ((ifp->int_if_flags & (IFF_POINTOPOINT|IFF_MULTICAST)) == IFF_POINTOPOINT) { msg = "Send pt-to-pt"; } else if (ifp->int_state & IS_DUP) { trace_act("abort multicast output via %s" " with duplicate address", ifp->int_name); return 0; } else { msg = "Send mcast"; if (rip_sock_mcast != ifp) { struct ip_mreqn mreqn; memset(&mreqn, 0, sizeof(struct ip_mreqn)); mreqn.imr_ifindex = ifp->int_index; if (0 > setsockopt(rip_sock, IPPROTO_IP, IP_MULTICAST_IF, &mreqn, sizeof(mreqn))) { serrno = errno; LOGERR("setsockopt(rip_sock, " "IP_MULTICAST_IF)"); errno = serrno; ifp = 0; return -1; } rip_sock_mcast = ifp; } osin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP); } break; case NO_OUT_MULTICAST: case NO_OUT_RIPV2: default: #ifdef DEBUG abort(); #endif return -1; } trace_rip(msg, "to", &osin, ifp, buf, size); res = sendto(soc, buf, size, flags, (struct sockaddr *)&osin, sizeof(osin)); if (res < 0 && (ifp == 0 || !(ifp->int_state & IS_BROKE))) { serrno = errno; msglog("%s sendto(%s%s%s.%d): %s", msg, ifp != 0 ? ifp->int_name : "", ifp != 0 ? ", " : "", inet_ntoa(osin.sin_addr), ntohs(osin.sin_port), strerror(errno)); errno = serrno; } return res; }