IP头部校验和 (checksum)计算方法

协议层

MAC

/* 以太网帧的 MAC 头部 */
typedef struct ether_header
{
  uint8_t eth_dest[ETHER_ADDR_LEN]; // 目的 MAC 地址

  uint8_t eth_src[ETHER_ADDR_LEN];  // 源 MAC 地址
  uint16_t eth_type;                // 以太网类型或长度字段
} ether_header_t;

IP

/* IP 头部 */
typedef struct ip_header
{
  uint8_t ip_vhl;       // 版本和报头长度
  uint8_t ip_tos;       // 服务类型
  uint16_t ip_len;      // 总长度
  uint16_t ip_id;       // 标识
  uint16_t ip_off;      // 段偏移
  uint8_t ip_ttl;       // 存活时间
  uint8_t ip_proto;     // 协议在这里插入代码片
  uint16_t ip_checksum; // 头部校验和
  uint32_t ip_src;      // 源 IP 地址
  uint32_t ip_dest;     // 目的 IP 地址
} ip_header_t;

UDP

/* UDP 头部 */
typedef struct udp_header
{
  uint16_t udp_src_port; // 源端口号
  uint16_t udp_dst_port; // 目的端口号
  uint16_t udp_len;      // UDP 长度
  uint16_t udp_crc;      // 网络字节序的校验和
} udp_header_t;

头部校验和计算方法

uint16_t ip_checksum(unsigned char *buffer, int length)
{
    uint32_t sum = 0;

    // 将 buffer 按照 2 字节(16 位)分块,并将每个块转换为 16 进制数
    for (int i = 0; i < length - 1; i += 2)
    {
        uint16_t word = (buffer[i] << 8) + buffer[i + 1];
        sum += word;
    }

    // 如果 buffer 的长度为奇数,那么将最后一个字节添加到和值中
    if (length % 2)
    {
        uint16_t word = (buffer[length - 1] << 8) + 0;
        sum += word;
    }

    // 将和值的高 16 位与低 16 位相加,直到高 16 位为 0
    while (sum >> 16)
    {
        sum = (sum & 0xFFFF) + (sum >> 16);
    }

    // 对和值按位取反
    sum = ~sum;

    // 返回校验和
    return (uint16_t)sum;
}
  ip_header_t ip_ = {0};
  ip_.ip_vhl = (4 << 4) | (sizeof(ip_header_t) / sizeof(uint32_t)); 	// 版本和报头长度
  ip_.ip_tos = 0;                                                   	// 服务类型
  ip_.ip_len = htons(0x123);                                         	// 总长度,网络字节序
  ip_.ip_id = htons(0x81234);                                        	// 标识,网络字节序
  ip_.ip_off = htons(0x4000);                                       	// 段偏移,网络字节序
  ip_.ip_ttl = 0x40;                                                	// 存活时间
  ip_.ip_proto = 0x11;                                              	// 协议 17
  ip_.ip_checksum = 0;                                              	// 头部校验和
  ip_.ip_src ;                              							// 源 IP 地址
  ip_.ip_des;                             								// 目的 IP 地址

  uint16_t checksum = ip_checksum((unsigned char *)&ip_, sizeof(ip_)); // 头部校验和
  ip_.ip_checksum = htons(checksum);                                   // 输出校验和,网络字节序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值