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

📄 router.c

📁 包括EPA协议栈
💻 C
字号:
//router.c
#define _ROUTER_GLOBAL
#include "router.h"
#include "stimer.h"
#include <string.h>




static OS_STK RIPMacroStack[STACK_SIZE_RIPMACRO];
static void*  gRIPMacroMsgQTbl[Msg_AMOUNT_RIPMACRO];
static void* gROUTERMsgQTbl[MSG_AMOUNT_ROUTER];

void RouterInit()
{
  gpROUTERMsgQ = OSQCreate(gROUTERMsgQTbl, MSG_AMOUNT_ROUTER);
  RIPMacroInit();
  InitRouterTable();
}

/*********************************************************************************************************

* Function   :CreatRouterTable
* Description: 这个函数用来建立一个路由表。
* Arguments  : ip     网络地址
*              mask   子网掩码
*              Nip    下一跳地址
*              IF     路由器接口
*              nu     度量
* Returns    : 0   ROUTER_NO_ERR   表示建立路由表正常                           
*              1   ROUTER_INVALID  表示路由表无效                                                    
*********************************************************************************************************/
uint8 CreatRouterTable(uint32 ip,uint32 mask,uint32 nip,uint32 inf,uint32 nu)
{
    uint32 index;	
    for(index = 0;index < ROUTERTABLE_AMOUNT;++index)
    {
       if(router_tbl[index].state == 0)
       {
       router_tbl[index].network_address = ip;
       router_tbl[index].subnet_mask = mask;
       router_tbl[index].next_hop = nip;
       router_tbl[index].interface = inf;
       router_tbl[index].metric = nu;
       return ROUTER_NO_ERR;	
       }
    }
    return ROUTER_INVALID;	
}
/*********************************************************************************************************
* Function   : InitRouterTable
* Description: 当路由器加到网络上的时候,需调用此函数对路由表进行初始化,即将该
*              路由器直接连接的网络正确显示在路由表中
* Arguments  : void     
* Returns    : == 0  ROUTERINIT_NO_ERR 表示路由表初始化正确                             
*********************************************************************************************************/
uint8 InitRouterTable(void) 
{
  uint32 inf_idx;
  inf_idx = 0;
  router_tbl[0].network_address = InetAddr(netA1,netA2,netA3,netA4);   //网络A
  router_tbl[0].subnet_mask = InetAddr(MASK0, MASK1, MASK2, MASK3);
  router_tbl[0].next_hop = 0;                                         //下一跳地址为空
  router_tbl[0].interface = inf_idx;                                  //对应路由器接口1,这里的借口只是个索引号
  router_tbl[0].metric = 1;
  router_tbl[0].state = 1;
  return ROUTERINIT_NO_ERR;
}

/*********************************************************************************************************
* Function   : RIP2_REQUEST
* Description: 调用报文发送套接字将RIP2请求报文发送出去。RIP2报文是建立在UDP之上的           
* Arguments  : void     
* Returns    : == 0  RIP2_REQUEST_NO_ERR 表示RIP2请求报文发送正确                             
*********************************************************************************************************/
void RIP_REQUEST(uint16 dst_port,uint32 dst_ip,uint32 idx)
{
  PSock psock;
  psock = GetSock(PROTOCOL_UDP_DATA, RIP_LENGTH, dst_port, dst_ip, NISelect(dst_ip));
  psock->payload[0] = 1;	          //表示是RIP2请求报文
  psock->payload[1] = 2;            //表示是RIP2版本
  h2n16(0, psock->payload + 2);     //保留
  h2n16(2, psock->payload + 4);     //表示使用的TCPIP协议
  h2n16(0, psock->payload + 6);     //全0
  h2n32(0, psock->payload + 8);     //全0
  h2n32(0, psock->payload + 12);	  //全0
  h2n32(0, psock->payload + 16);	  //全0
  h2n32(0, psock->payload + 20);	  //全0
  //return RIP2_REQUEST_NO_ERR;       //RIP的目的地址为组播地址
  psock->pni = &gnitbl[idx];          //调用接口2
  psock->pni->hw_id = idx;
  UDPOutput(psock);                 //调用UDP套接字将RIP报文发送出去
}


uint8 RIPMacroRun(uint32 para, void* pdata) {
       AddSt(RIP_RETRY_INTERVAL, 0, (void*)0, RIPMacroRun);
	   RIP_REQUEST(RIP_PORT,Groupcast,1);
       return (0);
}

void RIPMacroInit(void) {
	gpRIPMacroMsgQ = OSQCreate(gRIPMacroMsgQTbl, Msg_AMOUNT_RIPMACRO);
	OSTaskCreate(RIPMacroTask, (void*)0, (void*)(&RIPMacroStack[STACK_SIZE_RIPMACRO]), TASK_PRIORITY_RIP);
    AddSt(RIP_RETRY_INTERVAL, 0, (void*)0, RIPMacroRun);
}

void RIPMacroTask(void *pdata) {
	uint8 err;
       while(1) {
		OSQPend(gpRIPMacroMsgQ, TASK_TIMEOUT_RIPMACRO, &err);
        RIP_REQUEST(RIP_PORT,0,1);
		}
}


/*********************************************************************************************************
* Function   : RIP2_RESPONSE
* Description: 调用报文发送套接字将RIP2响应报文发送出去。RIP2报文是建立在UDP之上的              
* Arguments  : void     
* Returns    : == 0  RIP2_RESPONSE_NO_ERR 表示RIP2请求报文发送正确                             
*********************************************************************************************************/
void RIP_RESPONSE(PSock psock,uint16 dst_port,uint32 idx)
{
uint32 dst_ip;
dst_ip = psock->src_ip;
PutSock(psock);
psock = GetSock(PROTOCOL_UDP_DATA, RIP_LENGTH, dst_port,dst_ip, NISelect(dst_ip));
psock->payload[0] = 2;	          //表示是RIP2请求报文
psock->payload[1] = 2;            //表示是RIP2版本
h2n16(0, psock->payload + 2);     //保留
h2n16(2, psock->payload + 4);     //表示使用的TCPIP协议
h2n16(1, psock->payload + 6);     //路由标记
h2n32(router_tbl[0].network_address, psock->payload + 8);     //网络地址
h2n32(router_tbl[0].subnet_mask, psock->payload + 12);	      //子网掩码
h2n32(router_tbl[0].next_hop, psock->payload + 16);	      //下一跳地址
h2n32(router_tbl[0].metric, psock->payload + 20);	      //距离
//return RIP2_RESPONSE_NO_ERR;
psock->pni = &gnitbl[idx];                 //调用接口2
psock->pni->hw_id = idx;
UDPOutput(psock);                 //调用UDP套接字将RIP报文发送出去	
}
/*********************************************************************************************************
* Function   : Update_RouterTable
* Description: 根据收到的RIP2响应报文更新路由表             
* Arguments  : void     
* Returns    : == 0  ROUTERTABLE_UPDATE_NO_ERR 表示路由表更新正确 
* RIP更新算法:1.对每一个被通知的网络地址的跳数加1(对于简单网络)
               2.若网络地址不在路由表中,则将通知的网络加到网络中,调用CreatRouterTable函数                            
*********************************************************************************************************/
uint8 Update_RouterTable(PSock psock)
{
  uint32 network_addr;
  uint32 sub_mask;
  uint32 n_hop;
  uint32 met;
  uint32 inf;
  inf = 1;	
  n2h32(psock->payload + 8,&network_addr);	
  n2h32(psock->payload + 12,&sub_mask);	
  n2h32(psock->payload + 16,&n_hop);
  n2h32(psock->payload + 20,&met);
  CreatRouterTable(network_addr,sub_mask,n_hop,inf,met);
  return ROUTERTABLE_UPDATE_NO_ERR;	
}




void RIPInput(PSock psock)
{
   uint8 rip_type;
   rip_type = psock->payload[0];	
   switch(rip_type)
   {
   case RIP_TYPE_REQUEST:
   RIP_RESPONSE(psock,RIP_PORT,1);
   break;
   case RIP_TYPE_RESPONSE:
   Update_RouterTable(psock);
   break;
   }//end switch;
//  }//end while(1);	
}
/*********************************************************************************************************
* Function   : IPRouter()
* Description: 根据现有的路由表将报文转发出去             
* Arguments  : s_ip 报文源IP地址
*              d_ip 报文目的IP地址
*              psock 报文套接字   
* Returns    : void                               
*********************************************************************************************************/
void IPRouter(uint32 s_ip, uint32 d_ip, PSock psock)
{
  uint8 index,idx;
 
  if(d_ip&psock->pni->mask == s_ip&psock->pni->mask)//如果目的网络和源网络是同一个,则丢弃该报文
  {
  PutSock(psock);
  }
  
  if(!(d_ip&psock->pni->mask == s_ip&psock->pni->mask))//如果目的网络和源网络不同,则查询路由表
  {
  for(index = 0;index < ROUTERTABLE_AMOUNT;index++)
   {
   if(d_ip&psock->pni->mask == router_tbl[index].subnet_mask)//如果在路由表中找到与目的网络匹配的网络号,则找到与之对应的接口和下一跳的地址
    {
    idx = router_tbl[index].interface;                //主要是调用接口号,在底层驱动时知道用哪个接口将报文发送出去
    psock->pni->ip = router_tbl[index].next_hop;               //下一跳的地址,由于报文的转发IP地址是不变的,知道下一跳的IP地址,还要通过ARP协议知道下一跳的MAC地址,在MAC层取代目的MAC地址
    }
   }	
  }
  ArpSeek(psock,psock->pni);                                   //通过将下一跳的IP地址赋值给pni->ip,再通过调用ArpSeek函数得到目的MAC地址	
  IPOutput(psock,psock->payload[9]);	                //调用IPOutput函数发送出去,这个函数需要改写
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -