This is rip.c in view mode; [Download] [Up]
/* * $Header: /disk/d/src/devel/gated/dist/src/RCS/rip.c,v 2.1 92/02/24 14:12:51 jch Exp $ */ /*%Copyright%*/ /************************************************************************ * * * GateD, Release 2 * * * * Copyright (c) 1990,1991,1992 by Cornell University * * All rights reserved. * * * * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY * * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT * * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY * * AND FITNESS FOR A PARTICULAR PURPOSE. * * * * Royalty-free licenses to redistribute GateD Release * * 2 in whole or in part may be obtained by writing to: * * * * GateDaemon Project * * Information Technologies/Network Resources * * 143 Caldwell Hall * * Cornell University * * Ithaca, NY 14853-2602 * * * * GateD is based on Kirton's EGP, UC Berkeley's routing * * daemon (routed), and DCN's HELLO routing Protocol. * * Development of Release 2 has been supported by the * * National Science Foundation. * * * * Please forward bug fixes, enhancements and questions to the * * gated mailing list: gated-people@gated.cornell.edu. * * * * Authors: * * * * Jeffrey C Honig <jch@gated.cornell.edu> * * Scott W Brim <swb@gated.cornell.edu> * * * ************************************************************************* * * * Portions of this software may fall under the following * * copyrights: * * * * Copyright (c) 1988 Regents of the University of California. * * All rights reserved. * * * * Redistribution and use in source and binary forms are * * permitted provided that the above copyright notice and * * this paragraph are duplicated in all such forms and that * * any documentation, advertising materials, and other * * materials related to such distribution and use * * acknowledge that the software was developed by the * * University of California, Berkeley. The name of the * * University may not be used to endorse or promote * * products derived from this software without specific * * prior written permission. THIS SOFTWARE IS PROVIDED * * ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, * * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * * ************************************************************************/ #define RIPCMDS #include "include.h" #include "routed.h" #include "rip.h" #include "icmp.h" #ifdef PROTO_RIP #define RIP_TIMER_UPDATE 0 #define RIP_TIMER_FLASH 1 static task *rip_task = (task *) 0; static time_t rip_next_flash = (time_t) 0; static struct servent rip_sp; static char rip_packet[RIPPACKETSIZE + 1]; static struct rip *ripmsg = (struct rip *) rip_packet; int rip_pointopoint = FALSE; /* Are we ONLY doing pointopoint RIP? */ int rip_supplier = -1; /* Are we broadcasting RIP protocols? */ int doing_rip = TRUE; /* Are we running RIP protocols? */ metric_t rip_default_metric; /* Default metric to use when propogating */ pref_t rip_preference; /* Preference for RIP routes */ int rip_n_trusted = 0; /* Number of trusted gateways */ int rip_n_source = 0; /* Number of source gateways */ gw_entry *rip_gw_list = NULL; /* List of RIP gateways */ adv_entry *rip_accept_list = NULL; /* List of nets to accept from RIP */ adv_entry *rip_propagate_list = NULL; /* List of sources to propagates routes to RIP */ adv_entry **rip_int_accept = NULL; /* List of accept lists per interface */ adv_entry **rip_int_propagate = NULL; /* List of propagate lists per interface */ #ifdef RTM_ADD #define dst2sock(addr, dst) memset ((addr)->sa_data, 0, sizeof (addr)->sa_data); \ (addr)->sa_family = ntohs((dst)->rip_family); \ (addr)->sa_len = (sizeof (struct sockaddr_in)); \ socktype_in((addr))->sin_addr = (dst)->rip_addr #else /* RTM_ADD */ #define dst2sock(addr, dst) memset ((addr)->sa_data, 0, sizeof (addr)->sa_data); \ (addr)->sa_family = ntohs((dst)->rip_family); \ socktype_in((addr))->sin_addr = (dst)->rip_addr #endif /* RTM_ADD */ #define sock2dst(dst, addr) memset ((dst), 0, sizeof *(dst)); \ (dst)->rip_family = htons((addr)->sa_family); \ (dst)->rip_addr = socktype_in((addr))->sin_addr /* * Trace RIP packets */ static void rip_trace(dir, who, cp, size) struct sockaddr_in *who; /* should be sockaddr */ char *dir, *cp; register int size; { register struct rip *rpmsg = (struct rip *) cp; register struct netinfo *n; register const char *cmd = "Invalid"; struct sockaddr addr; if (rpmsg->rip_cmd && rpmsg->rip_cmd < RIPCMD_MAX) { cmd = ripcmds[rpmsg->rip_cmd]; } tracef("RIP %s %#A vers %d, cmd %s, length %d", dir, who, rpmsg->rip_vers, cmd, size); switch (rpmsg->rip_cmd) { #ifdef RIPCMD_POLL case RIPCMD_POLL: #endif /* RIPCMD_POLL */ case RIPCMD_REQUEST: case RIPCMD_RESPONSE: trace(TR_RIP, 0, NULL); if (trace_flags & TR_UPDATE) { size -= 4 * sizeof(char); n = rpmsg->rip_nets; for (; size > 0; n++, size -= sizeof(struct netinfo)) { if (size < sizeof(struct netinfo)) { break; } dst2sock(&addr, &n->rip_dst); if (addr.sa_family == AF_UNSPEC && !socktype_in(&addr)->sin_addr.s_addr && ntohl(n->rip_metric) == RIPHOPCNT_INFINITY) { trace(TR_RIP | TR_NOSTAMP, 0, "\trouting table request"); } else { trace(TR_RIP | TR_NOSTAMP, 0, "\tnet %-15A metric %2d", &addr, ntohl(n->rip_metric)); } } trace(TR_RIP, 0, "RIP %s end of packet", dir); } break; case RIPCMD_TRACEON: trace(TR_RIP, 0, ", file %*s", size, rpmsg->rip_tracefile); break; #ifdef RIPCMD_POLLENTRY case RIPCMD_POLLENTRY: n = rpmsg->rip_nets; dst2sock(&addr, &n->rip_dst); trace(TR_RIP, 0, ", net %A", &addr); break; #endif /* RIPCMD_POLLENTRY */ default: trace(TR_RIP, 0, NULL); break; } trace(TR_RIP, 0, NULL); } static void rip_send(tp, flags, sin, size) task *tp; flag_t flags; struct sockaddr_in *sin; int size; { struct sockaddr_in dst; dst = *sin; sin = &dst; if (sin->sin_port == 0) { sin->sin_port = rip_sp.s_port; } (void) task_send_packet(tp, rip_packet, size, flags, (sockaddr_un *) sin); if (trace_flags & TR_RIP) { rip_trace("SENT", sin, rip_packet, size); } } /* * Supply dst with the contents of the routing tables. * If this won't fit in one packet, chop it up into several. */ /*ARGSUSED*/ static void rip_supply(tp, dst, src, ifp, gwp, do_split_horizon, flash_update) task *tp; struct sockaddr_in *dst, *src; if_entry *ifp; gw_entry *gwp; int do_split_horizon; int flash_update; { rt_entry *rt; struct netinfo *n; int size; metric_t metric = 0, split_horizon; ripmsg->rip_cmd = RIPCMD_RESPONSE; ripmsg->rip_vers = RIPVERSION; n = ripmsg->rip_nets; RT_TABLE(rt) { if (rt->rt_state & RTS_NOADVISE) { continue; } if (flash_update && (rip_task->task_rtrevision >= rt->rt_revision)) { continue; } /* Do not send interface routes back to the same interface */ if ((rt->rt_ifp == ifp) && (rt->rt_proto & RTPROTO_DIRECT)) { continue; } /* Subnets and host routes do not go everywhere */ if (rt->rt_state & RTS_HOSTROUTE) { if (((ifp->int_net.in.sin_addr.s_addr ^ rt->rt_dest.in.sin_addr.s_addr) & ifp->int_netmask.in.sin_addr.s_addr) && !((rt->rt_ifp->int_net.in.sin_addr.s_addr ^ rt->rt_dest.in.sin_addr.s_addr) & rt->rt_ifp->int_netmask.in.sin_addr.s_addr)) { /* Host is being sent to another network and we learned it via it's home network */ /* XXX - This assumes we are announcing the network route */ continue; } } else if (rt->rt_state & RTS_SUBNET) { if ((rt->rt_dest.in.sin_addr.s_addr & ifp->int_netmask.in.sin_addr.s_addr) != ifp->int_net.in.sin_addr.s_addr) { /* Only send subnets to interfaces of the same network */ continue; } } else { if (rt->rt_dest.in.sin_addr.s_addr == ifp->int_net.in.sin_addr.s_addr) { /* Do not send the whole net to a subnet */ continue; } } if ((rt->rt_proto & rip_task->task_rtproto) && (ifp == rt->rt_ifp) && do_split_horizon && (ifp->int_state & (IFS_BROADCAST|IFS_POINTOPOINT) || equal_in(rt->rt_router.in.sin_addr, dst->sin_addr))) { split_horizon = RIPHOPCNT_INFINITY; } else { split_horizon = 0; } if (rt->rt_ifp->int_state & IFS_LOOPBACK) { /* Routes via the loopback interface must have an explicit metric */ metric = RIPHOPCNT_INFINITY; } metric = (rt->rt_proto & RTPROTO_DIRECT) ? RIP_HOP : rip_default_metric; if (!propagate(rt, rip_task->task_rtproto, rip_propagate_list, INT_CONTROL(rip_int_propagate, ifp), gwp ? gwp->gw_propagate : NULL, &metric)) { continue; } /* Add the interface mteric */ metric += ifp->int_metric; if (split_horizon) { metric = split_horizon; } if (!(rt->rt_ifp->int_state & IFS_UP) || (rt->rt_state & (RTS_HOLDDOWN | RTS_DELETE))) { metric = RIPHOPCNT_INFINITY; } if (flash_update && (metric >= RIPHOPCNT_INFINITY) && (rt->rt_ifp == ifp) && (rt->rt_proto & rip_task->task_rtproto)) { /* Don't flash deleted or unreachable routes back to their source */ continue; } size = (char *) n - rip_packet; if (size > (RIPPACKETSIZE - sizeof(struct netinfo))) { rip_send(tp, 0, dst, size); n = ripmsg->rip_nets; } sock2dst(&n->rip_dst, &rt->rt_dest.a); /* Make sure metric is valid */ if (metric > RIPHOPCNT_INFINITY) { metric = RIPHOPCNT_INFINITY; } n->rip_metric = metric; n->rip_metric = htonl(n->rip_metric); n++; } RT_TABLEEND; if ((n != ripmsg->rip_nets) || !src) { /* OK to reply to a RIPQUERY with an empty packet */ size = (char *) n - rip_packet; rip_send(tp, 0, dst, size); } } /* * Check out a newly received RIP packet. */ void rip_recv(tp) task *tp; { int size; register rt_entry *rt; register struct netinfo *n; register if_entry *ifp, *ifpc; gw_entry *gwp = (gw_entry *) 0; register int OK = TRUE; struct rip *inripmsg = (struct rip *) recv_iovec[RECV_IOVEC_DATA].iov_base; int change = FALSE; #ifdef RIP_CHECK_ZERO int check_zero = FALSE; #endif /* RIP_CHECK_ZERO */ int newsize; flag_t rte_table; u_short src_port; metric_t metric; const char *reject_msg = (char *) 0; char type[MAXHOSTNAMELENGTH]; int answer = FALSE; int split_horizon = TRUE; struct sockaddr dest; if (task_receive_packet(tp, &size)) { return; } if (recv_addr.in.sin_family != AF_INET) { reject_msg = "protocol not INET"; goto Reject; } src_port = recv_addr.in.sin_port; recv_addr.in.sin_port = 0; /* For comparisons */ switch (inripmsg->rip_vers) { case 0: reject_msg = "ignoring version 0 packets"; goto Reject; case 1: #ifdef RIP_CHECK_ZERO check_zero++; #endif /* RIP_CHECK_ZERO */ break; } /* Locate or create a gateway structure for this gateway */ gwp = gw_timestamp(&rip_gw_list, rip_task->task_rtproto, (sockaddr_un *) & recv_addr); /* If we have a list of trusted gateways, verify that this gateway is trusted */ if (rip_n_trusted && !(gwp->gw_flags & GWF_TRUSTED)) { OK = FALSE; } if (trace_flags & TR_RIP) { rip_trace("RECV", &recv_addr.in, (caddr_t) inripmsg, size); } #ifdef RIP_CHECK_ZERO if (check_zero && inripmsg->rip_res) { /* XXX - Should check later on that the sin_zero fields are zero */ reject_msg = "reserved fields not zero"; goto Reject; } #endif /* RIP_CHECK_ZERO */ switch (inripmsg->rip_cmd) { #ifdef RIPCMD_POLL case RIPCMD_POLL: answer = TRUE; split_horizon = FALSE; #endif /* RIPCMD_POLL */ case RIPCMD_REQUEST: if ((src_port != rip_sp.s_port) || answer) { recv_addr.in.sin_port = src_port; if ((ifp = if_withdst((sockaddr_un *) & recv_addr)) <= (if_entry *) 0) { struct sockaddr_in dst; dst = recv_addr.in; /* struct copy */ dst.sin_addr.s_addr = htonl(gd_inet_netof(dst.sin_addr)); if (!(rt = rt_lookup(RTS_NETROUTE, (sockaddr_un *) & dst))) { if (!(rt = rt_lookup(RTS_NETROUTE, (sockaddr_un *) & default_net))) { reject_msg = "can not find interface for route"; goto Reject; } } ifp = rt->rt_ifp; } } else { ifpc = if_withaddr((sockaddr_un *) & recv_addr); if (ifpc) { return; } if (!OK) { reject_msg = "not on trustedripgateways list"; goto Reject; } if ((ifp = if_withdst((sockaddr_un *) & recv_addr)) <= (if_entry *) 0) { reject_msg = "not on same net"; goto Reject; } if (ifp->int_state & (IFS_NORIPIN | IFS_NORIPOUT)) { reject_msg = "interface marked for no RIP in/out"; goto Reject; } if (!rip_supplier) { reject_msg = "not supplying RIP"; goto Reject; } } gwp->gw_flags |= GWF_QUERY | GWF_ACCEPT; newsize = 0; size -= 4 * sizeof(char); n = inripmsg->rip_nets; while (size > 0) { if (size < sizeof(struct netinfo)) { break; } size -= sizeof(struct netinfo); dst2sock(&dest, &n->rip_dst); n->rip_metric = ntohl(n->rip_metric); if (dest.sa_family == AF_UNSPEC && n->rip_metric == RIPHOPCNT_INFINITY && !size) { recv_addr.in.sin_port = src_port; rip_supply(tp, &recv_addr.in, (struct sockaddr_in *) 0, ifp, gwp, split_horizon, FALSE); return; } rt = rt_lookup(RTS_INTERIOR, (sockaddr_un *) &dest); n->rip_metric = htonl(!rt ? RIPHOPCNT_INFINITY : min(rt->rt_metric + ifp->int_metric, RIPHOPCNT_INFINITY)); n++; newsize += sizeof(struct netinfo); } if (newsize > 0) { recv_addr.in.sin_port = src_port; inripmsg->rip_cmd = RIPCMD_RESPONSE; newsize += sizeof(int); memcpy((char *) ripmsg, (char *) inripmsg, newsize); rip_send(tp, 0, &recv_addr.in, newsize); } return; case RIPCMD_TRACEON: case RIPCMD_TRACEOFF: if (!OK) { reject_msg = "not on trustedripgateways list"; goto Reject; } if (ntohs(src_port) > IPPORT_RESERVED) { reject_msg = "not from a trusted port"; goto Reject; } if ((ifp = if_withdst((sockaddr_un *) & recv_addr)) <= (if_entry *) 0) { reject_msg = "not on same net"; goto Reject; } if (ifp->int_state & IFS_NORIPIN) { reject_msg = "not listening to RIP on this interface"; goto Reject; } reject_msg = "TRACE packets not supported"; goto Reject; #ifdef RIPCMD_POLLENTRY case RIPCMD_POLLENTRY: n = inripmsg->rip_nets; newsize = sizeof(struct entryinfo); dst2sock(&dest, &n->rip_dst); switch (dest.sa_family) { case AF_INET: rt = rt_lookup(RTS_INTERIOR, (sockaddr_un *) &dest); break; default: rt = 0; } if (rt) { /* don't bother to check rip_vers */ struct entryinfo *e = (struct entryinfo *) n; sock2dst(&e->rtu_dst, &rt->rt_dest.a); sock2dst(&e->rtu_router, &rt->rt_router.a); e->rtu_flags = htons((unsigned short) rt->rt_flags); e->rtu_state = htons((unsigned short) rt->rt_state); e->rtu_timer = htonl((unsigned long) rt->rt_timer); e->rtu_metric = rt->rt_metric; e->rtu_metric = htonl((u_long) e->rtu_metric); ifp = rt->rt_ifp; if (ifp) { e->int_flags = htonl((unsigned long) ifp->int_state); (void) strncpy(e->int_name, rt->rt_ifp->int_name, sizeof(e->int_name)); } else { e->int_flags = 0; (void) strcpy(e->int_name, "(none)"); } } else { memset((char *) n, (char) 0, newsize); } newsize += sizeof (struct rip) - sizeof (struct netinfo); memcpy((char *) ripmsg, (char *) inripmsg, newsize); gwp->gw_flags |= GWF_QUERY | GWF_ACCEPT; recv_addr.in.sin_port = src_port; rip_send(tp, 0, &recv_addr.in, newsize); return; #endif /* RIPCMD_POLLENTRY */ case RIPCMD_RESPONSE: /* * Are we talking to ourselves??? * * if_withaddr() handles PTP's also. If from a * dst of a PTP link, let it through for further processing. * you shouldn't receive your own RIPs on a PTP. */ ifpc = if_withaddr((sockaddr_un *) & recv_addr); if (ifpc) { if_rtupdate(ifpc); if ((ifpc->int_state & IFS_POINTOPOINT) == 0) { return; } } if (!OK) { #ifndef notdef reject_msg = "not on trustedripgateways list"; goto Reject; #else /* notdef */ return; #endif /* notdef */ } if (src_port != rip_sp.s_port) { reject_msg = "not from a trusted port"; goto Reject; } if ((ifp = if_withdst((sockaddr_un *) & recv_addr)) <= (if_entry *) 0) { reject_msg = "not on same net"; goto Reject; } if (ifp->int_state & IFS_NORIPIN) { reject_msg = "interface marked for no RIP in"; goto Reject; } gwp->gw_flags |= GWF_ACCEPT; /* * update interface timer on interface that packet came in on. */ if_rtupdate(ifp); rt_open(tp); size -= 4 * sizeof(char); n = inripmsg->rip_nets; for (; size >= sizeof(struct netinfo); size -= sizeof(struct netinfo), n++) { pref_t preference = rip_preference; dst2sock(&dest, &n->rip_dst); switch (dest.sa_family) { case AF_INET: if (gd_inet_checkhost((struct sockaddr_in *) &dest)) { break; } /* Fall through */ default: continue; } /* Verify that this is a valid metric */ if (!is_valid_in((sockaddr_un *) &dest, rip_accept_list, INT_CONTROL(rip_int_accept, ifp), gwp->gw_accept, &preference)) { continue; } /* * Convert metric to host byte order. If metric is zero, ignore this network */ if (!(metric = ntohl(n->rip_metric))) { continue; } /* Now add hop count to metric */ metric += ifp->int_metric + RIP_HOP; /* Determine routing table based on host bits */ rte_table = gd_inet_ishost((struct sockaddr_in *) &dest) ? RTS_HOSTROUTE : RTS_INTERIOR; rt = rt_locate(rte_table, (sockaddr_un *) &dest, rip_task->task_rtproto); if (!rt) { /* new route */ if (metric >= RIPHOPCNT_INFINITY) { continue; } (void) rt_add((sockaddr_un *) &dest, (sockaddr_un *) 0, (sockaddr_un *) & recv_addr, gwp, metric, rte_table, rip_task->task_rtproto, 0, (time_t) 0, preference); change = TRUE; } else { /* Existing route */ if ((rt->rt_flags & RTF_GATEWAY) == 0) { continue; } if (equal(&rt->rt_router, &recv_addr)) { if (metric >= RIPHOPCNT_INFINITY) { change += rt_unreach(rt); continue; } if ((metric != rt->rt_metric) || (rt->rt_state & RTS_HOLDDOWN)) { if (rt_change(rt, (sockaddr_un *) & recv_addr, metric, (time_t) 0, preference)) { change = TRUE; } } rt_refresh(rt); } else { if ((metric >= RIPHOPCNT_INFINITY) || (rt->rt_state & RTS_HOLDDOWN)) { continue; } if ((metric < rt->rt_metric) || ((rt->rt_timer > (rt->rt_timer_max / 2)) && (rt->rt_metric == metric) && !(rt->rt_state & (RTS_CHANGED | RTS_REFRESH)))) { if (rt_change(rt, (sockaddr_un *) & recv_addr, metric, (time_t) 0, preference)) { change = TRUE; } } } } } /* for each route */ if (rt_close(tp, gwp, change)) { task_flash(rip_task); } break; default: reject_msg = "invalid or not implemented command"; goto Reject; } return; Reject: if (inripmsg->rip_cmd < RIPCMD_MAX) { (void) strcpy(type, ripcmds[inripmsg->rip_cmd]); } else { (void) sprintf(type, "#%d", inripmsg->rip_cmd); } trace(TR_RIP, 0, "rip_recv: ignoring RIP %s packet from %#A - %s", type, &recv_addr, reject_msg); trace(TR_RIP, 0, NULL); if (gwp) { gwp->gw_flags |= GWF_REJECT; } return; } /* * Output a preformed RIP packet. */ /*ARGSUSED*/ static void rip_out(tp, dst, src, ifp, gwp, do_split_horizon, flash_update) task *tp; struct sockaddr_in *dst, *src; if_entry *ifp; gw_entry *gwp; int do_split_horizon; int flash_update; { metric_t tmp = ntohl(ripmsg->rip_nets[0].rip_metric); rt_entry *rt; struct netinfo *n = ripmsg->rip_nets; struct sockaddr dest; dst2sock(&dest, &n->rip_dst); if (dst->sin_family != AF_INET) { return; } /* * Check to see if we are sending the initial RIP request to other * gateways. That request has no restrictions other than whether RIP * is allowed on that interface or not. This restriction is handled * in toall(). */ if (dest.sa_family != AF_UNSPEC || ntohl(n->rip_metric) != RIPHOPCNT_INFINITY) { rt = rt_lookup(RTS_INTERIOR, (sockaddr_un *) &dest); if (rt == NULL) { rt = rt_lookup(RTS_HOSTROUTE, (sockaddr_un *) &dest); if (rt == NULL) { trace(TR_ALL, LOG_ERR, "rip_out: bad route %A", &dest); return; } } /* * XXX - make sure this route can be announced via this interface/proto. if (!is_valid(rt, rip_task->task_rtproto, ifp)) { return; } */ /* * since we are only sending out this one packet, we can add the * interface metric here. Don't forget Split Horizon. */ if ((rt->rt_proto & rip_task->task_rtproto) && (ifp == rt->rt_ifp) && do_split_horizon && (ifp->int_state & (IFS_BROADCAST|IFS_POINTOPOINT) || equal_in(rt->rt_router.in.sin_addr, dst->sin_addr))) { tmp = ntohl(n->rip_metric); n->rip_metric = htonl(RIPHOPCNT_INFINITY); } else if ((tmp = ntohl(n->rip_metric)) != RIPHOPCNT_INFINITY) { if ((tmp + ifp->int_metric) >= RIPHOPCNT_INFINITY) { n->rip_metric = htonl(RIPHOPCNT_INFINITY); } else { n->rip_metric = htonl((tmp + ifp->int_metric)); } } } rip_send(rip_task, 0, dst, sizeof(struct rip)); n->rip_metric = tmp; n->rip_metric = htonl(n->rip_metric); } /* * send RIP packets */ /*ARGSUSED*/ static void rip_job(tip, interval) timer *tip; time_t interval; { task_toall(tip->timer_task, rip_supply, rip_pointopoint, IFS_NORIPOUT, rip_n_source ? rip_gw_list : NULL, FALSE); } /* * send a flash update packet */ /*ARGSUSED*/ static void rip_do_flash(tip, interval) timer *tip; time_t interval; { trace(TR_TASK, 0, "rip_do_flash: Doing flash update for RIP"); task_toall(rip_task, rip_supply, rip_pointopoint, IFS_NORIPOUT, rip_n_source ? rip_gw_list : NULL, TRUE); rip_next_flash = (time_t) (random() % 4 + 1) + time_sec; trace(TR_TASK, 0, "rip_do_flash: Flash update done, none before %T", rip_next_flash); } /* * Check to see if a flash update packet is allowed and send or schedule it */ static void rip_flash(tp) task *tp; { if (time_sec >= rip_next_flash) { /* A flash update can be sent now, do it */ rip_do_flash(tp->task_timer[RIP_TIMER_FLASH], (time_t) 0); } else if (!tp->task_timer[RIP_TIMER_FLASH] && (tp->task_timer[RIP_TIMER_UPDATE]->timer_next_time > rip_next_flash)) { /* A flash update can't be sent and one is not yet scheduled */ (void) timer_create(tp, RIP_TIMER_FLASH, "Flash", TIMERF_DELETE | TIMERF_ABSOLUTE, rip_next_flash - time_sec, rip_do_flash); } } /* * Cleanup before re-init */ /*ARGSUSED*/ static void rip_cleanup(tp) task *tp; { adv_cleanup(&rip_n_trusted, &rip_n_source, rip_gw_list, &rip_accept_list, &rip_propagate_list, &rip_int_accept, &rip_int_propagate); } /* * Dump info about RIP */ static void rip_dump(fd) FILE *fd; { (void) fprintf(fd, "RIP:\n"); (void) fprintf(fd, "\tDefault metric: %d\t\tDefault preference: %d\n", rip_default_metric, rip_preference); if (rip_gw_list) { (void) fprintf(fd, "\tActive gateways:\n"); gw_dump(fd, "\t\t", rip_gw_list); } control_accept_dump(fd, 1, rip_accept_list, rip_int_accept, rip_gw_list); control_propagate_dump(fd, 1, rip_propagate_list, rip_int_propagate, rip_gw_list); (void) fprintf(fd, "\n\n"); } /* * initialize RIP socket and RIP task */ /*ARGSUSED*/ void rip_init() { static struct servent *sp; struct sockaddr_in addr; if_entry *ifp; void (*flash) () = rip_flash; /* Hack for UTX/32 and Ultrix */ if (doing_rip) { if (!rip_task) { if (rip_supplier < 0) { if (n_interfaces > 1) { rip_supplier = TRUE; trace(TR_ALL, LOG_NOTICE, "rip_init: Acting as RIP supplier to our direct nets"); } IF_LIST(ifp) { if (ifp->int_state & IFS_POINTOPOINT) { rip_supplier = TRUE; trace(TR_INT, 0, "init_if: PointoPoint RIP supplier to: %s", ifp->int_name); } } IF_LISTEND(ifp) ; } if (rip_supplier < 0) { rip_supplier = FALSE; } if ((sp = getservbyname("router", "udp")) == NULL) { trace(TR_ALL, LOG_ERR, "No service for router available, using %d", RIP_PORT); memset((caddr_t) & rip_sp, (char) 0, sizeof(rip_sp)); rip_sp.s_port = htons(RIP_PORT); } else { memcpy((char *) &rip_sp, (char *) sp, sizeof(rip_sp)); } sockclear_in(&addr); addr.sin_port = rip_sp.s_port; addr.sin_addr.s_addr = INADDR_ANY; rip_task = task_alloc("RIP"); sockcopy(&addr, &rip_task->task_addr); rip_task->task_rtproto = RTPROTO_RIP; rip_task->task_recv = rip_recv; rip_task->task_cleanup = rip_cleanup; rip_task->task_dump = rip_dump; if ((rip_task->task_socket = task_get_socket(AF_INET, SOCK_DGRAM, 0)) < 0) { quit(errno); } if (!test_flag) { if (task_set_option(rip_task, TASKOPTION_BROADCAST, (caddr_t) TRUE) < 0) { quit(errno); } if (task_set_option(rip_task, TASKOPTION_RECVBUF, (caddr_t) (32 * 1024)) < 0) { quit(errno); } if (task_set_option(rip_task, TASKOPTION_DONTROUTE, (caddr_t) TRUE) < 0) { quit(errno); } if (bind(rip_task->task_socket, (struct sockaddr *) & addr, socksize(&addr)) < 0) { trace(TR_ALL, LOG_ERR, "rip_init: bind: %m"); (void) close(rip_task->task_socket); quit(errno); } } if (rip_supplier) { rip_task->task_flash = flash; (void) timer_create(rip_task, RIP_TIMER_UPDATE, "Update", 0, (time_t) RIP_INTERVAL, rip_job); } if (!task_create(rip_task, RIPPACKETSIZE)) { quit(EINVAL); } if (RIP_INTERVAL < rt_timer->timer_interval) { timer_interval(rt_timer, (time_t) RIP_INTERVAL); } if (!test_flag) { /* Generate a RIP REQUEST packet asking for all known RIP routes */ ripmsg->rip_cmd = RIPCMD_REQUEST; ripmsg->rip_vers = RIPVERSION; ripmsg->rip_nets[0].rip_dst.rip_family = htons(AF_UNSPEC); ripmsg->rip_nets[0].rip_metric = htonl(RIPHOPCNT_INFINITY); task_toall(rip_task, rip_out, rip_pointopoint, IFS_NORIPOUT, rip_n_source ? rip_gw_list : NULL, FALSE); } } if (rip_supplier) { if_rtactive = TRUE; /* Indicate we are broadcasting */ ignore_redirects = TRUE; /* Gateways don't listen to redirects */ } } else { rip_cleanup((task *) 0); if (rip_task) { task_delete(rip_task); rip_task = (task *) 0; } } } #endif /* PROTO_RIP */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.