⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rip.c

📁 嵌入式TCP/IP协议栈。 C 源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* 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 + -