📄 rip.c
字号:
/* This file contains code to implement the Routing Information Protocol (RIP)
* and is derived from 4.2BSD code. Mike Karels of Berkeley has stated on
* TCP-IP that the code may be freely used as long as UC Berkeley is
* Further documentation on the RIP protocol is now available in Charles
*/
#include "global.h"
#include "mbuf.h"
#include "netuser.h"
#include "udp.h"
#include "timer.h"
#include "iface.h"
#include "ip.h"
#include "internet.h"
#include "rip.h"
#include "arp.h"
struct rip_stat Rip_stat;
uint16 Rip_trace;
int Rip_merge;
struct rip_list *Rip_list;
struct udp_cb *Rip_cb;
struct rip_refuse *Rip_refuse;
static void rip_rx(struct iface *iface,struct udp_cb *sock,int cnt);
static void proc_rip(struct iface *iface,int32 gateway,
struct rip_route *ep,int32 ttl);
static uint8 *putheader(uint8 *cp,enum ripcmd command,uint8 version);
static uint8 *putentry(uint8 *cp,uint16 fam,int32 target,int32 metric);
static void rip_shout(void *p);
static void send_routes(int32 dest,uint16 port,int split,int trig,
int us);
/* Send RIP CMD_RESPONSE packet(s) to the specified rip_list entry */
static void
rip_shout(p)
void *p;
{
register struct rip_list *rl;
rl = (struct rip_list *)p;
stop_timer(&rl->rip_time);
send_routes(rl->dest,RIP_PORT,rl->flags.rip_split,0,rl->flags.rip_us);
set_timer(&rl->rip_time,rl->interval*1000L);
start_timer(&rl->rip_time);
}
/* Send the routing table. */
static void
send_routes(dest,port,split,trig,us)
int32 dest; /* IP destination address to send to */
uint16 port;
int split; /* Do split horizon? */
int trig; /* Send only triggered updates? */
int us; /* Include our address in update */
{
uint8 *cp;
int i,bits,numroutes,maxroutes;
uint16 pktsize;
struct mbuf *bp;
struct route *rp;
struct socket lsock,fsock;
struct iface *iface;
if((rp = rt_lookup(dest)) == NULL)
return; /* No route exists, can't do it */
iface = rp->iface;
/* Compute maximum packet size and number of routes we can send */
pktsize = ip_mtu(dest) - IPLEN;
pktsize = min(pktsize,MAXRIPPACKET);
maxroutes = (pktsize - RIPHEADER) / RIPROUTE;
lsock.address = INADDR_ANY;
lsock.port = RIP_PORT;
fsock.address = dest;
fsock.port = port;
/* Allocate space for a full size RIP packet and generate header */
if((bp = alloc_mbuf(pktsize)) == NULL)
return;
numroutes = 0;
cp = putheader(bp->data,RIPCMD_RESPONSE,RIPVERSION);
/* Emit route to ourselves, if requested */
if(us){
cp = putentry(cp,RIP_IPFAM,iface->addr,1);
numroutes++;
}
/* Emit default route, if appropriate */
if(R_default.iface != NULL && !R_default.flags.rtprivate
&& (!trig || R_default.flags.rttrig)){
if(!split || iface != R_default.iface){
cp = putentry(cp,RIP_IPFAM,0,R_default.metric);
numroutes++;
} else if(trig){
cp = putentry(cp,RIP_IPFAM,0,RIP_INFINITY);
numroutes++;
}
}
for(bits=0;bits<32;bits++){
for(i=0;i<HASHMOD;i++){
for(rp = Routes[bits][i];rp != NULL;rp=rp->next){
if(rp->flags.rtprivate
|| (trig && !rp->flags.rttrig))
continue;
if(numroutes >= maxroutes){
/* Packet full, flush and make another */
bp->cnt = RIPHEADER + numroutes * RIPROUTE;
send_udp(&lsock,&fsock,0,0,&bp,bp->cnt,0,0);
Rip_stat.output++;
if((bp = alloc_mbuf(pktsize)) == NULL)
return;
numroutes = 0;
cp = putheader(bp->data,RIPCMD_RESPONSE,RIPVERSION);
}
if(!split || iface != rp->iface){
cp = putentry(cp,RIP_IPFAM,rp->target,rp->metric+1);
numroutes++;
} else if(trig){
cp = putentry(cp,RIP_IPFAM,rp->target,RIP_INFINITY);
numroutes++;
}
}
}
}
if(numroutes != 0){
bp->cnt = RIPHEADER + numroutes * RIPROUTE;
send_udp(&lsock,&fsock,0,0,&bp,bp->cnt,0,0);
Rip_stat.output++;
} else {
free_p(&bp);
}
}
/* Add an entry to the rip broadcast list */
int
rip_add(dest,interval,split,us)
int32 dest;
int32 interval;
int split,us;
{
register struct rip_list *rl;
struct route *rp;
if((rp = rt_lookup(dest)) == NULL){
printf("%s is unreachable\n",inet_ntoa(dest));
return 1;
}
for(rl = Rip_list; rl != NULL; rl = rl->next)
if(rl->dest == dest)
break;
if(rl == NULL){
/* get a chunk of memory for the rip interface descriptor */
rl = (struct rip_list *)callocw(1,sizeof(struct rip_list));
/* tack this record on as the first in the list */
rl->next = Rip_list;
if(rl->next != NULL)
rl->next->prev = rl;
Rip_list = rl;
rl->dest = dest;
}
/* and the interface ptr, tick interval and flags */
rl->iface = rp->iface;
rl->interval = interval;
rl->flags.rip_split = split;
rl->flags.rip_us = us;
/* set up the timer stuff */
rl->rip_time.func = rip_shout;
rl->rip_time.arg = rl;
/* This will initialize the timer and do an immediate broadcast */
rip_shout(rl);
return 0;
}
/* add a gateway to the rip_refuse list which allows us to ignore their
* advertisements
*/
int
riprefadd(gateway)
int32 gateway;
{
register struct rip_refuse *rl;
for(rl = Rip_refuse; rl != NULL; rl = rl->next)
if(rl->target == gateway)
return 0; /* Already in table */
/* get a chunk of memory for the rip interface descriptor */
rl = (struct rip_refuse *)callocw(1,sizeof(struct rip_refuse));
/* tack this record on as the first in the list */
rl->next = Rip_refuse;
if(rl->next != NULL)
rl->next->prev = rl;
Rip_refuse = rl;
/* fill in the gateway to ignore */
rl->target = gateway;
return 0;
}
/* drop a RIP target */
int
rip_drop(dest)
int32 dest;
{
register struct rip_list *rl;
for(rl = Rip_list; rl != NULL; rl = rl->next)
if(rl->dest == dest)
break;
/* leave if we didn't find it */
if(rl == NULL)
return 0;
/* stop the timer */
stop_timer(&rl->rip_time);
/* Unlink from list */
if(rl->next != NULL)
rl->next->prev = rl->prev;
if(rl->prev != NULL)
rl->prev->next = rl->next;
else
Rip_list = rl->next;
/* and deallocate the descriptor memory */
free(rl);
return 0;
}
/* drop a RIP-refuse target from the rip_refuse list */
int
riprefdrop(gateway)
int32 gateway;
{
register struct rip_refuse *rl;
for(rl = Rip_refuse; rl != NULL; rl = rl->next)
if(rl->target == gateway)
break;
/* leave if we didn't find it */
if(rl == NULL)
return 0;
/* Unlink from list */
if(rl->next != NULL)
rl->next->prev = rl->prev;
if(rl->prev != NULL)
rl->prev->next = rl->next;
else
Rip_refuse = rl->next;
/* and deallocate the structure memory */
free(rl);
return 0;
}
/* function to output a RIP CMD_RESPONSE packet for the rip_trigger list */
void
rip_trigger()
{
register struct rip_list *rl;
int bits,i;
struct route *rp;
for(rl=Rip_list;rl != NULL;rl = rl->next){
send_routes(rl->dest,RIP_PORT,rl->flags.rip_split,1,0);
}
/* Clear the trigger list */
R_default.flags.rttrig = 0;
for(bits=0;bits<32;bits++){
for(i=0;i<HASHMOD;i++){
for(rp = Routes[bits][i];rp != NULL;rp = rp->next){
rp->flags.rttrig = 0;
}
}
}
}
/* Start RIP agent listening at local RIP UDP port */
int
rip_init()
{
struct socket lsock;
lsock.address = INADDR_ANY;
lsock.port = RIP_PORT;
if(Rip_cb == NULL)
Rip_cb = open_udp(&lsock,rip_rx);
return 0;
}
/* Process RIP input received from 'interface'. */
static void
rip_rx(iface,sock,cnt)
struct iface *iface;
struct udp_cb *sock;
int cnt;
{
struct mbuf *bp;
struct socket fsock;
enum ripcmd cmd;
register struct rip_refuse *rfl;
struct rip_route entry;
struct route *rp;
struct rip_list *rl;
int32 ttl;
/* receive the RIP packet */
recv_udp(sock,&fsock,&bp);
/* increment the rcvd cnt */
Rip_stat.rcvd++;
/* check the gateway of this packet against the rip_refuse list and
* discard it if a match is found
*/
for(rfl=Rip_refuse;rfl != NULL;rfl = rfl->next){
if(fsock.address == rfl->target){
Rip_stat.refusals++;
if(Rip_trace > 1)
printf("RIP refused from %s\n",
inet_ntoa(fsock.address));
free_p(&bp);
return;
}
}
cmd = PULLCHAR(&bp);
/* Check the version of the frame */
if(PULLCHAR(&bp) != RIPVERSION){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -