FreakZ学习笔记:路由发现机制
路由发现机制只有在发送通信包的过程中会被调用,而接收过程因为发送时候已经进行了通信链路的扫描和连接,所以不会再进行路由发现机制。
路由的所有处理机制都是在NWK层进行的,当然,路由发现机制也一样。当协议栈进行数据发送时,会依次按照APP->APS->NWK->MAC->PHY->Radio的层次关系来进行,APS层执行完成之后,会跳转到NWK层的nwk_data_req函数,该函数为NWK数据请求服务,接收APS层的数据并且加上NWK层的包头,然后将数据打包。nwk_data_req函数执行完成自后会跳转到void nwk_fwd(buffer_t *buf, nwk_hdr_t *hdr_in)函数,该函数描述如下:
/**************************************************************************/
/*!
This function is the work horse of the NWK layer. It takes a frame from
either the data request or the data indication functions (if the dest address
is not for this node). It will look at the dest address and determine
how this frame should be transmitted. The forwarding choices are:
1) broadcast
2) neighbor table (the dest is a neighbor of ours)
3) routing table (the route path exists)
4) route discovery (the route path does not exist but mesh routing is okay)
5) tree (none of the above and the route discovery flag is disabled)
*/
/**************************************************************************/
void nwk_fwd(buffer_t *buf, nwk_hdr_t *hdr_in)函数是NWK传输层的一个主要函数,它构成了一个数据请求或者数据指示功能的帧(如果该帧数据的目的地址不是当前节点的地址),它将会查找地址并且确定这个帧数据应该怎么样被传输,主要的传输方法有(1)通过广播传输;(2)通过邻接点传输,前提是目的地址在我们的邻接点里;(3)通过路由表传输,前提是存在合适的路由表;(4)路由发现,如果当前保存的路由机制无法传输该帧信息到目的地址,但是mesh路由是可以的,这个时候就需要运行该机制;(5)通过树形结构传输,如果以上的四种机制都不符合并且不允许路由发现机制的时候,使用该机制;其函数原型如下:
void nwk_fwd(buffer_t *buf, nwk_hdr_t *hdr_in)
{
U16 next_hop;
nwk_hdr_t hdr_out;
mac_hdr_t mac_hdr_out;
bool indirect = false;
address_t dest_addr;
mem_ptr_t *nbor_mem_ptr;
hdr_out.mac_hdr = &mac_hdr_out;
dest_addr.mode = SHORT_ADDR;
dest_addr.short_addr = hdr_in->dest_addr;
// is it a broadcast?
if ((hdr_in->dest_addr & NWK_BROADCAST_MASK) == 0xFFF0)
{
// the buffer data ptr (dptr) is pointing to the nwk payload now. calc the length of the nwk
// payload. then we can re-use the buffer, slap on the nwk hdr, and send it back down
// the stack.
//
//lint -e{734} Info 734: Loss of precision (assignment) (31 bits to 8 bits)
// its okay since we're subtracting a value from a constant
buf->len = aMaxPHYPacketSize - (buf->dptr - buf->buf);
// need to change the mac dest address to broadcast in case it isn't. Also change the src
// addr to the address of this device.
hdr_out.mac_hdr->dest_addr.short_addr = MAC_BROADCAST_ADDR;
hdr_out.src_addr = hdr_in->src_addr;
}
// is the dest in our neighbor table?
else if ((nbor_mem_ptr = nwk_neighbor_tbl_get_entry(&dest_addr)) != NULL)
{
// check to see if the dest address is in our neighbor table
if (hdr_in->src_addr != nib.short_addr)
{
//lint -e{734} Info 734: Loss of precision (assignment) (31 bits to 8 bits)
// its okay since we're subtracting a value from a constant
buf->len = aMaxPHYPacketSize - (buf->dptr - buf->buf);
}
// if the neighbor does not keep its rx on when idle (ie: sleeping), then we need to send
// the frame indirectly.
if (!NBOR_ENTRY(nbor_mem_ptr)->rx_on_when_idle)
{
indirect = true;
}
// set the mac dest addr to the neighbor address
hdr_out.mac_hdr->dest_addr.short_addr = hdr_in->dest_addr;
hdr_out.src_addr = hdr_in->src_addr;
}
// is the dest in our routing table?
else if ((next_hop = nwk_rte_tbl_get_next_hop(hdr_in->dest_addr)) != INVALID_NWK_ADDR)
{
// it's in the routing table. forward it.
// the buffer dptr is pointing to the nwk payload now. calc the length of the nwk
// payload. then we can re-use the buffer, slap on the nwk hdr, and send it back down
// the stack.
//
//lint -e{734} Info 734: Loss of precision (assignment) (31 bits to 8 bits)
// its okay since we're subtracting a value from a constant
buf->len = aMaxPHYPacketSize - (buf->dptr - buf->buf);
// set the mac dest addr to the next hop and the nwk src addr to the originator
hdr_out.mac_hdr->dest_addr.short_addr = next_hop;
hdr_out.src_addr = hdr_in->src_addr;
}
// are we allowed to discover the route?
else if (hdr_in->nwk_frm_ctrl.disc_route) //路由发现
{
// the destination isn't in our routing tables. discover route is enabled for the
// frame so we can buffer it and initiate route discovery.
nwk_pend_add_new(buf, hdr_in);
nwk_rte_mesh_disc_start(hdr_in->dest_addr);
return;
}
// if all else fails, route it along the tree
else
{
// tree routing is the default routing if everything else fails or we don't allow mesh routing.
// we'll just recycle the frame buffer and send it on its way out.
if ((next_hop = nwk_rte_tree_calc_next_hop(hdr_in->dest_addr)) == INVALID_NWK_ADDR)
{
// tree routing failed for some reason. collect the stat and go on with life.
pcb.failed_tree_rte++;
buf_free(buf);
DBG_PRINT("NWK: No such neighbor exists.\n\r");
return;
}
// the buffer dptr is pointing to the nwk payload now. calc the length of the nwk
// payload. then we can re-use the buffer, slap on the nwk hdr, and send it back down
// the stack.
//
//lint -e{734} Info 734: Loss of precision (assignment) (31 bits to 8 bits)
// its okay since we're subtracting a value from a constant
buf->len = aMaxPHYPacketSize - (buf->dptr - buf->buf);
// set the mac dest addr to the spec'd neighbor addr and the nwk src addr to the originator
hdr_out.mac_hdr->dest_addr.short_addr = next_hop;
hdr_out.src_addr = hdr_in->src_addr;
}
// fill out the rest of the fields that will be needed to forward this frame
hdr_out.nwk_frm_ctrl.frame_type = hdr_in->nwk_frm_ctrl.frame_type;
hdr_out.seq_num = hdr_in->seq_num;
hdr_out.nwk_frm_ctrl.disc_route = hdr_in->nwk_frm_ctrl.disc_route;
hdr_out.radius = hdr_in->radius;
hdr_out.dest_addr = hdr_in->dest_addr;
hdr_out.handle = hdr_in->handle;
hdr_out.mac_hdr->src_addr.mode = SHORT_ADDR;
hdr_out.mac_hdr->dest_addr.mode = SHORT_ADDR;
hdr_out.mac_hdr->src_addr.short_addr = nib.short_addr;
nwk_tx(buf, &hdr_out, indirect);
}
else if (hdr_in->nwk_frm_ctrl.disc_route)这个分支即为路由发现部分;函数nwk_pend_add_new(buf, hdr_in)的作用是分配一个buf将当前帧数据保存,函数nwk_rte_mesh_disc_start(hdr_in->dest_addr)为开始路由查找;该函数描述如下:
/**************************************************************************/
/*!
This function sets up a route discovery operation by initializing the discovery
info. Once the data is initialized, we will call the rreq handler which is
where the real route discovery starts.
*/
/**************************************************************************/
该函数的功能为建立一个路由发现操作并且初始化发现信息;初始化完成之后,我们会调用路由请求(rreq)处理,此时,标志着路由发现开始了,void nwk_rte_mesh_disc_start(U16 dest_addr)函数原型如下:
void nwk_rte_mesh_disc_start(U16 dest_addr)
{
nwk_nib_t *nib = nwk_nib_get();
nwk_hdr_t nwk_hdr;
mac_hdr_t mac_hdr;
nwk_cmd_t cmd;
nwk_hdr.mac_hdr = &mac_hdr;
cmd.rreq.rreq_id = nib->rreq_id++;
cmd.rreq.dest_addr = dest_addr;
cmd.rreq.cmd_opts = 0;
cmd.rreq.path_cost = 0;
nwk_hdr.radius = (U8)(nib->max_depth << 1); // default radius = 2 * max depth
nwk_hdr.src_addr = mac_hdr.src_addr.short_addr = nib->short_addr;
nwk_rte_mesh_rreq_handler(&nwk_hdr, &cmd);
}
在nwk_rte_mesh_disc_start函数运行最后,会调用路由请求处理句柄nwk_rte_mesh_rreq_handler,该函数主要功能为处理传入的路由请求,确定该请求是否需要继续向前传输或者是需要生成路由应答;同时函数会检测路由表去寻找之前是否接收到过同样的路由请求,如果接收过,将会对两个路径成本进行对比,确定是否当前的路径更具有高效性,如果是,它将会更新发现链路入口。
如果该路由请求是一个新的路由请求,那么将会创建一个路由发现链表入口和一个路由表入口,然后会检测当前节点是否为目的节点,如果是,将会发送一个路由应答,否则,它将会通过广播来转播这个路由请求,该函数原型如下:
void nwk_rte_mesh_rreq_handler(const nwk_hdr_t *hdr_in, nwk_cmd_t *cmd_in)
{
nwk_pcb_t *pcb = nwk_pcb_get();
nwk_nib_t *nib = nwk_nib_get();
mac_pib_t *pib = mac_pib_get();
mem_ptr_t *disc_mem_ptr;
mem_ptr_t *rte_mem_ptr;
U8 path_cost;
address_t dest_addr;
dest_addr.mode = SHORT_ADDR;
dest_addr.short_addr = cmd_in->rreq.dest_addr;
// if we are originating the rreq, then set the path cost to zero. otherwise add the static path cost.
// later on, we need to figure out a better way to generate path costs.
path_cost = (hdr_in->src_addr != nib->short_addr) ? cmd_in->rreq.path_cost + NWK_STATIC_PATH_COST: cmd_in->rreq.path_cost;
// check if route discovery table entry exists.
if ((disc_mem_ptr = nwk_rte_disc_find(cmd_in->rreq.rreq_id, hdr_in->src_addr)) != NULL)
{
// if the path cost is less than the fwd cost, then update the entry
if (path_cost < DISC_ENTRY(disc_mem_ptr)->fwd_cost)
{
// If the path cost is less than the fwd cost, then replace the disc table disc_entry path
// with this path.
DISC_ENTRY(disc_mem_ptr)->sender_addr = hdr_in->mac_hdr->src_addr.short_addr;
DISC_ENTRY(disc_mem_ptr)->fwd_cost = path_cost;
}
else
{
// since we already have a discovery entry for this rreq and there's no benefit in cost, drop the rreq
pcb->drop_rreq_frm++;
return;
}
}
else
{
// add the new discovery entry to the discovery table
//nwk_rte_disc_add_new(cmd_in->rreq.rreq_id, hdr_in->src_addr, hdr_in->mac_hdr->src_addr.short_addr, hdr_in->dest_addr, path_cost);
//Changed by LiuTianmin
nwk_rte_disc_add_new(cmd_in->rreq.rreq_id, hdr_in->src_addr, hdr_in->mac_hdr->src_addr.short_addr, cmd_in->rreq.dest_addr, path_cost);
}
// get the route entry for this rreq if it exists. otherwise, create a new entry.
if ((rte_mem_ptr = nwk_rte_tbl_find(cmd_in->rreq.dest_addr)) != NULL)
{
// if the route entry isn't active or active but requires validation, then change it to discovery underway.
if ((RTE_ENTRY(rte_mem_ptr)->status != NWK_ACTIVE) && (RTE_ENTRY(rte_mem_ptr)->status != NWK_VALIDATION_UNDERWAY))
{
RTE_ENTRY(rte_mem_ptr)->status = NWK_DISCOVERY_UNDERWAY;
}
}
else
{
nwk_rte_tbl_add_new(cmd_in->rreq.dest_addr, NWK_DISCOVERY_UNDERWAY);
}
// now check to see if the route request destination was meant for us. If so, then prepare a route reply.
if ((cmd_in->rreq.dest_addr == nib->short_addr) || (nwk_neighbor_tbl_get_child(&dest_addr) != NULL))
{ /*Here should select a best route to reply LiuTianmin*/
/*Here should select a best route to reply LiuTianmin*/
// send out the route reply Delete by LiuTianmin
//nwk_rte_mesh_send_rrep(cmd_in->rreq.rreq_id, hdr_in->src_addr, cmd_in->rreq.dest_addr,
// path_cost, hdr_in->mac_hdr->src_addr.short_addr);
nwk_rte_mesh_req_wait_start();
}
else
{
// fwd the rreq
nwk_rte_mesh_send_rreq(cmd_in, hdr_in->src_addr, path_cost, hdr_in->radius);
}
}
最后一个else分支即为该路由请求是一个新的路由请求,并且当前节点不是路由请求的目的地址,此时会调用nwk_rte_mesh_send_rreq函数,该函数的功能为生成并发送一个路由请求的控制帧,该控制信息由规定的指令数据结构体生成,头部将会由剩余的参数生成,同时会写入一个路由请求加入路由请求链路里以方便跟踪请求信息,该函数原型如下:
static void nwk_rte_mesh_send_rreq(nwk_cmd_t *cmd, U16 src_addr, U8 path_cost, U8 radius)
{
nwk_nib_t *nib = nwk_nib_get();
nwk_hdr_t hdr;
buffer_t *buf;
mem_ptr_t *mem_ptr;
// prepare route request
cmd->cmd_frm_id = NWK_CMD_RTE_REQ;
cmd->rreq.cmd_opts = 0;
cmd->rreq.path_cost = path_cost;
// prepare route request nwk frame header
hdr.nwk_frm_ctrl.frame_type = NWK_CMD_FRM;
hdr.nwk_frm_ctrl.disc_route = false;
hdr.src_addr = src_addr;
hdr.dest_addr = NWK_BROADCAST_ROUTERS_COORD;
hdr.radius = radius;
hdr.seq_num = nib->seq_num;
// copy the hdr and cmd structs. we'll use them later for retransmission.
/*Added by LiuTianmin*/
//I think the router request retransmission should do only by the originator sender
if(src_addr == nib->short_addr)
{
/*Added by LiuTianmin*/
if ((mem_ptr = nwk_rte_mesh_rreq_alloc()) != NULL)
{
RREQ_ENTRY(mem_ptr)->originator = src_addr;
RREQ_ENTRY(mem_ptr)->radius = radius;
RREQ_ENTRY(mem_ptr)->retries = 0;
RREQ_ENTRY(mem_ptr)->expiry = ROUTER_REQ_TIME_OUT; //400ms
memcpy(&RREQ_ENTRY(mem_ptr)->cmd, cmd, sizeof(nwk_cmd_t));
}
/*Added by LiuTianmin*/
}
/*Added by LiuTianmin*/
// gen the nwk frame and send it out
BUF_ALLOC(buf, TX);
nwk_gen_cmd(buf, cmd);
debug_dump_nwk_cmd(cmd);
nwk_fwd(buf, &hdr);
}
nwk_rte_mesh_send_rreq函数执行最后又会跳转到nwk_fwd函数,此时又回到了该文档的开头,形成一个循环体,意思是在路由发现的过程中,如果没有找到目的地址,那么就会不断查找,并且不断更新维护路由链表,直到找到为止。
网友评论