pc抓包结果
相关代码:
// 计算 ICMPv6 报文的校验和
uint16_t calculate_icmp6_checksum(const sys_ipv6_t *src_ip, const sys_ipv6_t *dst_ip,
const icmpv6_neighbor_solicitation_t *ns, size_t ns_len)
{
uint32_t sum = 0;
const uint8_t *data = (const uint8_t *)&ns->icmpv6_header;
const uint8_t *end = data + ns_len;
int i = 0;
// 计算 ICMPv6 头部和选项的校验和
while (data + 1 < end)
{
// 避免直接转换为 uint16_t*,而是手动读取两个字节
sum += ((uint16_t)data[0] << 8) | data[1];
data += 2;
}
if (data < end)
{
sum += (uint16_t)(*data << 8);
}
// 添加伪首部字段
// 计算源 IP 地址的伪首部
for (i = 0; i < 4; i++)
{
uint32 tmp = ((uint32)src_ip->hex[i * 4] << 24) |
((uint32)src_ip->hex[i * 4 + 1] << 16) |
((uint32)src_ip->hex[i * 4 + 2] << 8) |
((uint32)src_ip->hex[i * 4 + 3]);
sum += htons(tmp);
}
// 计算目的 IP 地址的伪首部
for (i = 0; i < 4; i++)
{
uint32 tmp = ((uint32)dst_ip->hex[i * 4] << 24) |
((uint32)dst_ip->hex[i * 4 + 1] << 16) |
((uint32)dst_ip->hex[i * 4 + 2] << 8) |
((uint32)dst_ip->hex[i * 4 + 3]);
sum += htons(tmp);
}
// 添加长度和协议号
sum += htons(ns_len) + IPPROTO_ICMPV6;
// 折叠 32 位的和到 16 位
while (sum >> 16)
{
sum = (sum & 0xFFFF) + (sum >> 16);
}
// 取反
return ~sum;
}
static int32 send_ns_for_nd_snooping(int32 idx)
{
sys_ipv6_t target_address;
sys_ipv6_t source_address;
sys_mac_t target_mac_address;
int32 i;
sys_err_code_t ret = SYS_ERR_OK;
sys_logic_portmask_t blkpm;
ndsp_ipv6hdr_t ip_hdr;
icmpv6_neighbor_solicitation_t ns;
target_addr_option option;
uint16_t checksum;
//sys_logic_portmask_t port_mask;
sys_nic_pkt_t *pPkt;
uint32 packetLen = sizeof(icmpv6_neighbor_solicitation_t) + sizeof(ndsp_ipv6hdr_t) + sizeof(ethernet_header_t);
sys_ipv6_t dst_address;
uint8_t prefix[16] = {0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff,
0x00, 0x00, 0x00};
ethernet_header_t *eth_hdr;
uint32 unit = SYS_DEV_ID_DEFAULT;
if (RT_ERR_OK != drv_nic_pkt_alloc(unit, packetLen, 0, &pPkt))
{
osal_printf("[%s]: Alloc packet failed.\n", __FUNCTION__);
return RT_ERR_FAILED;
}
// Initialize packet pointers
osal_memset(&target_address, 0, sizeof(sys_ipv6_t));
osal_memset(&source_address, 0, sizeof(sys_ipv6_t));
osal_memset(&target_mac_address, 0, sizeof(sys_mac_t));
ND_SNOOPING_LOCK();
// 构造以太网头
eth_hdr = (ethernet_header_t *) pPkt->data;
osal_memcpy(&target_mac_address, &nd_snooping_table[idx].mac, sizeof(sys_mac_t));
osal_memcpy(&target_address, &nd_snooping_table[idx].ipv6, sizeof(sys_ipv6_t));
// 将前缀复制到目标地址
osal_memcpy(&dst_address.hex, prefix, 13); // 前13字节为前缀
// 提取source_address的后24位并填充到target_address的后24位
osal_memcpy(&dst_address.hex[13], &target_address.hex[13], 3); // 复制后3字节
// 设置MAC地址的前2个字节
target_mac_address.octet[0] = 0x33;
target_mac_address.octet[1] = 0x33;
// 设置MAC地址的后3个字节(IPv6地址的后32位,注意是ff对应的字节)
target_mac_address.octet[2] = dst_address.hex[12]; // IPv6地址的第13字节
target_mac_address.octet[3] = dst_address.hex[13]; // IPv6地址的第14字节
target_mac_address.octet[4] = dst_address.hex[14]; // IPv6地址的第15字节
target_mac_address.octet[5] = dst_address.hex[15]; // IPv6地址的第16字节
osal_memcpy(eth_hdr->dest_mac, &target_mac_address, sizeof(sys_mac_t)); // 设置目的MAC
osal_memcpy(eth_hdr->src_mac, &g_ndsp_sysMac, sizeof(sys_mac_t)); // 设置源MAC
eth_hdr->ethertype = htons(ETHERTYPE_IPV6); // 设置以太网类型为IPv6
BOOTMSG_PRINTF("pxy-test--Constructed MAC Address: %02x:%02x:%02x:%02x:%02x:%02x--%s-----%d\n",target_mac_address.octet[0], target_mac_address.octet[1], target_mac_address.octet[2],
target_mac_address.octet[3], target_mac_address.octet[4], target_mac_address.octet[5],__FUNCTION__, __LINE__);
BOOTMSG_PRINTF("pxy-test--Constructed MAC Address: %02x:%02x:%02x:%02x:%02x:%02x--%s-----%d\n",g_ndsp_sysMac.octet[0], g_ndsp_sysMac.octet[1], g_ndsp_sysMac.octet[2],
g_ndsp_sysMac.octet[3], g_ndsp_sysMac.octet[4], g_ndsp_sysMac.octet[5],__FUNCTION__, __LINE__);
// for (i = 0; i < CAPA_L3_IPV6ADDR_NUM_MAX; i++)
// {
// if((gl3intfipv6[i].id.type == SYS_L3_INTFTYPE_PORT) && (gl3intfipv6[i].id.id == nd_snooping_table[idx].port))
// {
// //本地链路地址为源地址
// osal_memcpy(&source_address, &gl3intfipv6[i].ip[0].v6.addr, sizeof(sys_ipv6_t));
// break;
// }
// }
// 设置版本号 (4 bits), 流量类别 (8 bits), 流标签 (20 bits)
ip_hdr.version_trafficClass_flowLabel = htonl((6 << 28) | (0x00 << 20) | 0x0000); // 版本号 6, 流量类别 0, 流标签 0
// 设置有效载荷长度
ip_hdr.payload_length = htons(sizeof(icmpv6_neighbor_solicitation_t)); // NS 报文的大小
// 设置下一个头部 (Next Header)
ip_hdr.next_header = IPPROTO_ICMPV6; // ICMPv6 协议
// 设置跳数限制
ip_hdr.hop_limit = 255; // 最大跳数
// 设置源地址
osal_memcpy(ip_hdr.src_addr, &source_address, 16);
// 设置目标地址
osal_memcpy(ip_hdr.dst_addr, &dst_address, 16);
NDSPDBG("send_ns_for_nd_snooping--IPv6 source addr: " IPADDRV6_PRINT IPADDRV6_PRINT IPADDRV6_PRINT,IPADDRV6_PRINT_ARG(source_address.hex),IPADDRV6_PRINT_ARG(dst_address.hex),IPADDRV6_PRINT_ARG(target_address.hex));
// 构造 Neighbor Solicitation 报文
// 设置 ICMPv6 头部类型为 Neighbor Solicitation (135)
ns.icmpv6_header.type = 135;
// 设置代码为 0
ns.icmpv6_header.code = 0;
// 设置校验和初始值为 0,稍后会计算并更新
ns.icmpv6_header.checksum = 0;
// 复制目标 IPv6 地址到 NS 报文的目标地址字段
osal_memcpy(ns.target_address, &target_address, 16);
// 初始化选项字段
// 设置选项类型为 2 (Target Address Option)
option.option_type = 2;
// 设置选项数据长度为 1 (不包括类型和长度字段)
option.length = 1;
// 复制目标 MAC 地址到选项中的目标地址字段
osal_memcpy(option.target_addr, &nd_snooping_table[idx].mac, 6);
// 将选项字段添加到 NS 报文中
osal_memcpy(ns.options, &option, sizeof(option));
// 计算校验和
checksum = calculate_icmp6_checksum(&source_address, &dst_address, &ns, sizeof(icmpv6_neighbor_solicitation_t));
// 更新 ICMPv6 头部的校验和
ns.icmpv6_header.checksum = checksum;
pPkt->length = packetLen;
pPkt->tail = pPkt->data + packetLen;
pPkt->txIncludeCRC = TRUE;
// 设置数据
osal_memcpy(pPkt->data + sizeof(ethernet_header_t) + sizeof(ndsp_ipv6hdr_t), &ns, sizeof(icmpv6_neighbor_solicitation_t));
LOGIC_PORTMASK_CLEAR_ALL(blkpm);
LOGIC_PORTMASK_SET_PORT(blkpm, nd_snooping_table[idx].port);
for (i = 0; i < SYS_BITS_TO_LONGS(SYS_LOGICPORT_NUM_MAX); i++)
{
blkpm.bits[i] = ~blkpm.bits[i];
}
BOOTMSG_PRINTF("pxy-test--Block Ports = "FMT_PORTMASK"--%s-----%d\n",SHOW_PORTMASK(blkpm),__FUNCTION__, __LINE__);
ret = rsd_nic_pktByDmacBlkPM_tx(pPkt, SYS_CPU_PORT_PRIORITY_NDSNOOPING, nd_snooping_table[idx].vid, blkpm);
g_ndsp_portMib[nd_snooping_table[idx].port].ndNsSent++;
NDSPDBG("Sent NS pkt from %s, vlan %u enable", LPSTR(nd_snooping_table[idx].port), nd_snooping_table[idx].vid);
ND_SNOOPING_UNLOCK();
return ret;
}