该模块完成接收状态机的跳转以及接收帧所进行的相关处理。
lldp的接收状态机,参见lldp标准文档。该实现代码和标准文档基本一致,变量名和函数名都大部分相同。
int rxProcessFrame(struct lldp_port *lldp_port) {
…
…
/*
主要是验证报文的正确性:具体要验证报文的目的地址以及报文类型字段
*/
/* As per section 10.3.1, verify the destination and ethertype */
expect_hdr.dst[0] = 0x01;
expect_hdr.dst[1] = 0x80;
expect_hdr.dst[2] = 0xc2;
expect_hdr.dst[3] = 0x00;
expect_hdr.dst[4] = 0x00;
expect_hdr.dst[5] = 0x0e;
expect_hdr.ethertype = htons(0x88cc);
ether_hdr = (struct eth_hdr *)&lldp_port->rx.frame[0];
debug_printf(DEBUG_INT, "LLPDU Dst: ");
debug_hex_printf(DEBUG_INT, (uint8_t *)ether_hdr->dst, 6);
debug_printf(DEBUG_EXCESSIVE, "Expect Dst: ");
debug_hex_printf(DEBUG_EXCESSIVE, (uint8_t *)expect_hdr.dst, 6);
/* Validate the frame's destination */
if(
ether_hdr->dst[0] != expect_hdr.dst[0] ||
ether_hdr->dst[1] != expect_hdr.dst[1] ||
ether_hdr->dst[2] != expect_hdr.dst[2] ||
ether_hdr->dst[3] != expect_hdr.dst[3] ||
ether_hdr->dst[4] != expect_hdr.dst[4] ||
ether_hdr->dst[5] != expect_hdr.dst[5] ) {
debug_printf(DEBUG_NORMAL, "[ERROR] This frame is incorrectly addressed to: ");
debug_hex_printf(DEBUG_NORMAL, (uint8_t *)ether_hdr->dst, 6);
debug_printf(DEBUG_NORMAL, "[ERROR] This frame should be addressed to: ");
debug_hex_printf(DEBUG_NORMAL, (uint8_t *)expect_hdr.dst, 6);
debug_printf(DEBUG_NORMAL, "[ERROR] statsFramesInTotal will *NOT* be incremented\n");
badFrame++;
}
debug_printf(DEBUG_INT, "LLPDU Src: ");
debug_hex_printf(DEBUG_INT, (uint8_t *)ether_hdr->src, 6);
debug_printf(DEBUG_INT, "LLPDU Ethertype: %x\n", htons(ether_hdr->ethertype));
debug_printf(DEBUG_EXCESSIVE, "Expect Ethertype: %x\n", htons(expect_hdr.ethertype));
/* Validate the frame's ethertype */
if(ether_hdr->ethertype != expect_hdr.ethertype) {
debug_printf(DEBUG_NORMAL, "[ERROR] This frame has an incorrect ethertype of: '%x'.\n", htons(ether_hdr->ethertype));
badFrame++;
}
if(!badFrame) {
lldp_port->rx.statistics.statsFramesInTotal ++;
}
…
…
/*
请注意lldp报文TLV的格式,前7个bits为tlv类型字段,后9个位数据长度字段。
*/
/* Grab the first 9 bits */
tlv_length = htons(*tlv_hdr) & 0x01FF;
/* Then shift to get the last 7 bits */
tlv_type = htons(*tlv_hdr) >> 9;
/*
lldp报文中tlv最少为4个,分别为Chasis ID TLV、Port ID TLV、TTL TLV、End TLV
*/
/* Validate as per 802.1AB section 10.3.2*/
if(num_tlvs <= 3) {
if(num_tlvs != tlv_type) {
debug_printf(DEBUG_NORMAL, "[ERROR] TLV number %d should have tlv_type %d, but is actually %d\n", num_tlvs, num_tlvs, tlv_type);
debug_printf(DEBUG_NORMAL, "[ERROR] statsFramesDiscardedTotal and statsFramesInErrorsTotal will be incremented as per 802.1AB 10.3.2\n");
lldp_port->rx.statistics.statsFramesDiscardedTotal++;
lldp_port->rx.statistics.statsFramesInErrorsTotal++;
badFrame++;
}
}
/*
缓存lldp报文中tlv的值
*/
tlv->type = tlv_type;
tlv->length = tlv_length;
if(tlv->length > 0)
tlv->info_string = calloc(1, tlv_length);
/*
如果LLDP中的tlv为TTL,那么则更新rx.timers.rxTTL的值
*/
if(tlv_type == TIME_TO_LIVE_TLV) {
if(tlv_length != 2) {
debug_printf(DEBUG_NORMAL, "[ERROR] TTL TLV has an invalid length! Should be '2', but is '%d'\n", tlv_length);
#ifndef WIN32
#warning We should actually discard this frame and print out an error...
#warning Write a unit test to stress this
#endif // WIN32
} else {
lldp_port->rx.timers.rxTTL = htons(*(uint16_t *)&tlv_info_string[0]);
msap_ttl_tlv = tlv;
debug_printf(DEBUG_EXCESSIVE, "rxTTL is: %d\n", lldp_port->rx.timers.rxTTL);
}
}
if(tlv->info_string) {
memset(tlv->info_string, 0x0, tlv_length);
memcpy(tlv->info_string, tlv_info_string, tlv_length);
}
/* Validate the TLV */
if(validate_tlv[tlv_type] != NULL) {
debug_printf(DEBUG_EXCESSIVE, "Found a validator for TLV type %d.\n", tlv_type);
debug_hex_dump(DEBUG_EXCESSIVE, tlv->info_string, tlv->length);
if(validate_tlv[tlv_type](tlv) != XVALIDTLV) {
badFrame++;
}
} else {
// NOTE: Any organizationally specific TLVs should get processed through validate_generic_tlv
debug_printf(DEBUG_EXCESSIVE, "Didn't find specific validator for TLV type %d. Using validate_generic_tlv.\n", tlv_type);
if(validate_generic_tlv(tlv) != XVALIDTLV) {
badFrame++;
}
}
…
…
/*
将之前缓存的lldp报文中tlv加入到tlv_list中
*/
cached_tlv = initialize_tlv();
if(tlvcpy(cached_tlv, tlv) != 0) {
debug_printf(DEBUG_TLV, "Error copying TLV for MSAP cache!\n");
}
debug_printf(DEBUG_EXCESSIVE, "Adding exploded TLV to MSAP TLV list.\n");
// Now we can start stuffing the msap data... ;)
add_tlv(cached_tlv, &tlv_list);
/*
如果是CHASSIS_ID_TLV和PORT_ID_TLV,那么则缓存它们的值。并将它们拼接为msap_id
*/
if(tlv_type == CHASSIS_ID_TLV) {
debug_printf(DEBUG_NORMAL, "Copying TLV1 for MSAP Processing...\n");
msap_tlv1 = initialize_tlv();
tlvcpy(msap_tlv1, tlv);
} else if(tlv_type == PORT_ID_TLV) {
debug_printf(DEBUG_NORMAL, "Copying TLV2 for MSAP Processing...\n");
msap_tlv2 = initialize_tlv();
tlvcpy(msap_tlv2, tlv);
//Minus 2, for the chassis id subtype and port id subtype...
// IEEE 802.1AB specifies that the MSAP shall be composed of
// The value of the subtypes.
msap_id = calloc(1, msap_tlv1->length - 1 + msap_tlv2->length - 1);
if(msap_id == NULL)
{
debug_printf(DEBUG_NORMAL, "[ERROR] Unable to malloc buffer in %s() at line: %d!\n", __FUNCTION__, __LINE__);
}
// Copy the first part of the MSAP
memcpy(msap_id, &msap_tlv1->info_string[1], msap_tlv1->length - 1);
// Copy the second part of the MSAP
memcpy(&msap_id[msap_tlv1->length - 1], &msap_tlv2->info_string[1], msap_tlv2->length - 1);
msap_length = (msap_tlv1->length - 1) + (msap_tlv2->length - 1);
debug_printf(DEBUG_MSAP, "MSAP TLV1 Length: %d\n", msap_tlv1->length);
debug_printf(DEBUG_MSAP, "MSAP TLV2 Length: %d\n", msap_tlv2->length);
debug_printf(DEBUG_MSAP, "MSAP is %d bytes: ", msap_length);
debug_hex_printf(DEBUG_MSAP, msap_id, msap_length);
debug_hex_dump(DEBUG_MSAP, msap_id, msap_length);
// Free the MSAP pieces
destroy_tlv(&msap_tlv1);
destroy_tlv(&msap_tlv2);
msap_tlv1 = NULL;
msap_tlv2 = NULL;
/* 指示有新的邻居信息到来*/
have_msap = 1;
}
…
…
if(have_msap)
{
#ifndef WIN32
#warning We need to verify whether this is actually the case.
#endif // WIN32
lldp_port->rxChanges = TRUE;
debug_printf(DEBUG_TLV, "We have a(n) %d byte MSAP!\n", msap_length);
/*
创建一条新的保存邻居信息的lldp_msap结构体,并将之前缓存的tlv信息复制到其中。然后更新该端口对应的lldp_port结构体中的lldp_msap信息。亦即更新该底层端口对应的邻居信息。
*/
msap_cache = calloc(1, sizeof(struct lldp_msap));
msap_cache->id = msap_id;
msap_cache->length = msap_length;
msap_cache->tlv_list = tlv_list;
msap_cache->next = NULL;
msap_cache->ttl_tlv = msap_ttl_tlv;
msap_ttl_tlv = NULL;
//debug_printf(DEBUG_MSAP, "Iterating MSAP Cache...\n");
//iterate_msap_cache(msap_cache);
//debug_printf(DEBUG_MSAP, "Updating MSAP Cache...\n");
debug_printf(DEBUG_MSAP, "Setting rxInfoTTL to: %d\n", lldp_port->rx.timers.rxTTL);
msap_cache->rxInfoTTL = lldp_port->rx.timers.rxTTL;
update_msap_cache(lldp_port, msap_cache);
if(msap_tlv1 != NULL) {
debug_printf(DEBUG_NORMAL, "Error: msap_tlv1 is still allocated!\n");
free(msap_tlv1);
msap_tlv1 = NULL;
}
if(msap_tlv2 != NULL) {
debug_printf(DEBUG_NORMAL, "Error: msap_tlv2 is still allocated!\n");
free(msap_tlv2);
msap_tlv2 = NULL;
}
}
else
{
debug_printf(DEBUG_NORMAL, "[ERROR] No MSAP for TLVs in Frame!\n");
}
/* Report frame errors */
if(badFrame) {
rxBadFrameInfo(badFrame);
}
return badFrame;
}
rxProcessFrame主要是提取了报文中的tlv,解析为对应的lldp_tlv节点,并缓存相应的信息,最终构造lldp_msap结构体。并更新邻居信息。而在update_msap_cache函数中,会判断rxProcessFrame函数构造的lldp_msap在本端口的lldp_msap链表中是否存在。若存在,那么直接进行替换(不检查是否完全完全相等,简便的做法)。若不存在,则说明是一个新邻居,那么完成邻居信息结构体lldp_msap的链表插入工作。
在lldp报文中tlv被组织为7bit的type字段,9bit的length字段。这种组织方式,在存储tlv时,极为不便。这里将这种组织方式转化为lldp_tlv的组织方式。type和length都可以使用现有的数据类型表示,方便程序的编写。