ARP协议部分代码:
#include <string.h> #include <stdio.h> #include "net.h" #include "arp.h" #include "ethernet.h" /** * @brief 初始的arp包 * */ static const arp_pkt_t arp_init_pkt = { .hw_type16 = swap16(ARP_HW_ETHER), .pro_type16 = swap16(NET_PROTOCOL_IP), .hw_len = NET_MAC_LEN, .pro_len = NET_IP_LEN, .sender_ip = NET_IF_IP, .sender_mac = NET_IF_MAC, .target_mac = {0}}; /** * @brief arp地址转换表,<ip,mac>的容器 * */ map_t arp_table; /** * @brief arp buffer,<ip,buf_t>的容器 * */ map_t arp_buf; /** * @brief 打印一条arp表项 * * @param ip 表项的ip地址 * @param mac 表项的mac地址 * @param timestamp 表项的更新时间 */ void arp_entry_print(void *ip, void *mac, time_t *timestamp) { printf("%s | %s | %s\n", iptos(ip), mactos(mac), timetos(*timestamp)); } /** * @brief 打印整个arp表 * */ void arp_print() { printf("===ARP TABLE BEGIN===\n"); map_foreach(&arp_table, arp_entry_print); printf("===ARP TABLE END ===\n"); } /** * @brief 发送一个arp请求 * * @param target_ip 想要知道的目标的ip地址 */ void arp_req(uint8_t *target_ip) { buf_init(&txbuf, sizeof(arp_pkt_t)); //对txbuf进行初始化 arp_pkt_t *pkt = (arp_pkt_t *)txbuf.data; pkt->hw_type16 = swap16(1); pkt->pro_type16 = swap16(NET_PROTOCOL_IP); pkt->hw_len = 6; pkt->pro_len = 4; pkt->opcode16 = swap16(ARP_REQUEST); // for (int i = 0; i < 6; i++) // { // pkt->sender_mac[i] = net_if_mac[i]; // pkt->target_mac[i] = 0x00; // } // for (int i = 0; i < 4; i++) // { // pkt->sender_ip[i] = net_if_ip[i]; // pkt->target_ip[i] = *(target_ip + i); // } memcpy(pkt->sender_mac, net_if_mac, NET_MAC_LEN); memcpy(pkt->sender_ip, net_if_ip, NET_IP_LEN); memset(pkt->target_mac, 0, NET_MAC_LEN); memcpy(pkt->target_ip, target_ip, NET_IP_LEN); ethernet_out(&txbuf, ether_broadcast_mac, NET_PROTOCOL_ARP); //发送ARP报文 } /** * @brief 发送一个arp响应 * * @param target_ip 目标ip地址 * @param target_mac 目标mac地址 */
ETH协议全部代码:
#include "ethernet.h" #include "utils.h" #include "driver.h" #include "arp.h" #include "ip.h" /** * @brief 处理一个收到的数据包 * * @param buf 要处理的数据包 */ void ethernet_in(buf_t *buf) { if(buf->len < sizeof(ether_hdr_t)) //判断数据长度,小于以太网头部长度的话丢弃不处理 { return; } ether_hdr_t *hdr = (ether_hdr_t *)buf->data; buf_remove_header(buf,sizeof(ether_hdr_t)); //移除以太网包头 net_in(buf,swap16(hdr->protocol16),hdr->src); //向上层传递数据包 } /** * @brief 处理一个要发送的数据包 * * @param buf 要处理的数据包 * @param mac 目标MAC地址 * @param protocol 上层协议 */ void ethernet_out(buf_t *buf, const uint8_t *mac, net_protocol_t protocol) { if(buf->len < 46) { buf_add_padding(buf,46 - buf->len); } buf_add_header(buf,sizeof(ether_hdr_t)); //添加以太网包头 ether_hdr_t *hdr = (ether_hdr_t *)buf->data; // for(int i = 0; i < 6; i++) //填写目的MAC地址 // { // hdr->dst[i] = *(mac+i); // } // for(int i = 0; i < 6; i++) //填写源MAC地址 // { // hdr->src[i] = net_if_mac[i]; //net_if_mac 得到本机的mac地址 // } memcpy(hdr->dst, mac, NET_MAC_LEN); memcpy(hdr->src, net_if_mac, NET_MAC_LEN); hdr->protocol16 = swap16(protocol); driver_send(buf); //将添加了以太网包头的数据帧发送到驱动层 } /** * @brief 初始化以太网协议 * */ void ethernet_init() { buf_init(&rxbuf, ETHERNET_MAX_TRANSPORT_UNIT + sizeof(ether_hdr_t)); } /** * @brief 一次以太网轮询 * */ void ethernet_poll() { if (driver_recv(&rxbuf) > 0) ethernet_in(&rxbuf); }
ICMP协议部分代码:
#include "net.h" #include "icmp.h" #include "ip.h" /** * @brief 发送icmp响应 * * @param req_buf 收到的icmp请求包 * @param src_ip 源ip地址 */ static void icmp_resp(buf_t *req_buf, uint8_t *src_ip) { buf_t *buf = &txbuf; buf_init(buf, req_buf->len ); memcpy(buf->data,req_buf->data,req_buf->len); icmp_hdr_t *hdr1 = (icmp_hdr_t *)req_buf->data; icmp_hdr_t hdr2 = { .code = hdr1->code, .checksum16 = 0, .id16 = hdr1->id16, .seq16 = hdr1->seq16, .type = ICMP_TYPE_ECHO_REPLY}; memcpy(buf->data, &hdr2, sizeof(icmp_hdr_t)); hdr2.checksum16 = checksum16((uint16_t *)buf->data, buf->len); memcpy(buf->data, &hdr2, sizeof(icmp_hdr_t)); ip_out(buf, src_ip, NET_PROTOCOL_ICMP); } /** * @brief 处理一个收到的数据包 * * @param buf 要处理的数据包 * @param src_ip 源ip地址 */ void icmp_in(buf_t *buf, uint8_t *src_ip) { if (buf->len < sizeof(icmp_hdr_t)) { return; } icmp_hdr_t *hdr = (icmp_hdr_t *)buf->data; if (hdr->type == ICMP_TYPE_ECHO_REQUEST) { icmp_resp(buf, src_ip); } else { return; } } /** * @brief 发送icmp不可达 * * @param recv_buf 收到的ip数据包 * @param src_ip 源ip地址 * @param code icmp code,协议不可达或端口不可达 */
UDP协议部分代码:
#include "udp.h" #include "ip.h" #include "icmp.h" /** * @brief udp处理程序表 * */ map_t udp_table; /** * @brief udp伪校验和计算 * * @param buf 要计算的包 * @param src_ip 源ip地址 * @param dst_ip 目的ip地址 * @return uint16_t 伪校验和 */ static uint16_t udp_checksum(buf_t *buf, uint8_t *src_ip, uint8_t *dst_ip) { uint8_t src[4]; uint8_t dst[4]; memcpy(src, src_ip, 4); memcpy(dst, dst_ip, 4); buf_add_header(buf, sizeof(udp_peso_hdr_t)); udp_peso_hdr_t *peso_hdr = (udp_peso_hdr_t *)buf->data; memcpy(peso_hdr->src_ip, src, 4); memcpy(peso_hdr->dst_ip, dst, 4); peso_hdr->protocol = NET_PROTOCOL_UDP; peso_hdr->total_len16 = swap16(buf->len - sizeof(udp_peso_hdr_t)); peso_hdr->placeholder = 0; uint16_t *p; p = (uint16_t *)peso_hdr; int n = buf->len / 2; int i = 0; uint32_t checksum = 0; while (i < n) { checksum += swap16(*p); p++; i++; } if (buf->len % 2 != 0) { checksum += swap16(*p) & 0xFF00; } while ((checksum >> 16) != 0) { checksum = (checksum >> 16) + (checksum & 0xFFFF); } buf_remove_header(buf, sizeof(udp_peso_hdr_t)); memcpy(src_ip, src, 4); memcpy(dst_ip, dst, 4); return (uint16_t)(~checksum); } /** * @brief 处理一个收到的udp数据包 * * @param buf 要处理的包 * @param src_ip 源ip地址 */ void udp_in(buf_t *buf, uint8_t *src_ip) { if (buf->len < sizeof(udp_hdr_t)) { return; } udp_hdr_t *hdr = (udp_hdr_t *)buf->data; if (buf->len < swap16(hdr->total_len16)) { return; } uint16_t temp = swap16(hdr->checksum16); hdr->checksum16 = 0; hdr->checksum16 = udp_checksum(buf, src_ip, net_if_ip); if (temp != hdr->checksum16) { return; } uint16_t dst_port16 = swap16(hdr->dst_port16); uint16_t src_port16 = swap16(hdr->src_port16); if (!(map_get(&udp_table, &dst_port16))) { buf_add_header(buf, sizeof(ip_hdr_t)); icmp_unreachable(buf, src_ip, ICMP_CODE_PORT_UNREACH); } else { udp_handler_t *handler = map_get(&udp_table, &dst_port16); buf_remove_header(buf, sizeof(udp_hdr_t)); (*handler)(buf->data, buf->len, src_ip, src_port16); } } /** * @brief 处理一个要发送的数据包 * * @param buf 要处理的包 * @param src_port 源端口号 * @param dst_ip 目的ip地址 * @param dst_port 目的端口号 */
IP协议部分代码:
#include "net.h" #include "ip.h" #include "ethernet.h" #include "arp.h" #include "icmp.h" /** * @brief 处理一个收到的数据包 * * @param buf 要处理的数据包 * @param src_mac 源mac地址 */ void ip_in(buf_t *buf, uint8_t *src_mac) { if(buf->len < sizeof(ip_hdr_t)) { return; } ip_hdr_t *hdr = (ip_hdr_t *)buf->data; if(hdr->version != 4 || swap16(hdr->total_len16) > buf->len) { return; } uint16_t hdr_checksum_temp = hdr->hdr_checksum16; hdr->hdr_checksum16 = 0; uint16_t checksum = checksum16((uint16_t *)hdr, sizeof(ip_hdr_t)); hdr->hdr_checksum16 = swap16(checksum); if(checksum != hdr_checksum_temp) { return; } else { hdr->hdr_checksum16 = hdr_checksum_temp; } for (size_t i = 0; i < NET_IP_LEN; i++) { if(hdr->dst_ip[i] != net_if_ip[i]) { return; } } if(buf->len > swap16(hdr->total_len16)) { buf_remove_padding(buf, buf->len - swap16(hdr->total_len16)); } if(hdr->protocol != NET_PROTOCOL_ICMP && hdr->protocol != NET_PROTOCOL_UDP) { icmp_unreachable(buf, hdr->src_ip, ICMP_CODE_PROTOCOL_UNREACH); } else { buf_remove_header(buf, sizeof(ip_hdr_t)); net_in(buf, hdr->protocol, hdr->src_ip); } } /** * @brief 处理一个要发送的ip分片 * * @param buf 要发送的分片 * @param ip 目标ip地址 * @param protocol 上层协议 * @param id 数据包id * @param offset 分片offset,必须被8整除 * @param mf 分片mf标志,是否有下一个分片 */ void ip_fragment_out(buf_t *buf, uint8_t *ip, net_protocol_t protocol, int id, uint16_t offset, int mf) { buf_add_header(buf, sizeof(ip_hdr_t)); ip_hdr_t *hdr = (ip_hdr_t *)buf->data; hdr->hdr_len = 5; hdr->version = 4; hdr->tos = 0; hdr->total_len16 = swap16(buf->len); hdr->id16 = swap16(id); hdr->protocol = protocol; hdr->ttl = 64; if (mf == 1) { hdr->flags_fragment16 = swap16((offset >> 3) + IP_MORE_FRAGMENT); } else { hdr->flags_fragment16 = swap16(offset >> 3); } memcpy(hdr->src_ip, net_if_ip, NET_IP_LEN); memcpy(hdr->dst_ip, ip, NET_IP_LEN); hdr->hdr_checksum16 = 0; hdr->hdr_checksum16 = checksum16((uint16_t *)hdr, sizeof(ip_hdr_t)); arp_out(buf, ip); } /** * @brief 处理一个要发送的ip数据包 * * @param buf 要处理的包 * @param ip 目标ip地址 * @param protocol 上层协议 */