📄 router.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 + -