(代码基于linux2.4.0)
void arp_send(int type,/*arp协议编码,如ARPOP_REPLY(arp响应)、ARPOP_REQUEST(arp请求)等*/ int ptype, /*以太网协议类型,或者说是接口的硬件类型,如ARP(ETH_P_ARP)、x.25(ETH_P_X25)、ip(ETH_P_IP)等*/ u32 dest_ip, /*目的ip地址*/ struct net_device *dev, /*用于发包的网卡设备*/ u32 src_ip, /*源ip地址*/ unsigned char *dest_hw, /*目的硬件地址*/ unsigned char *src_hw,/*源硬件地址*/ unsigned char *target_hw) /*目的硬件地址,它用于arp响应时填充到arp包中,arp请求应该填0*/ { struct sk_buff *skb;/*用于管理封装arp包的存储空间的sk_buff指针*/ struct arphdr *arp;/*指向arp包头*/ unsigned char *arp_ptr;/*指向arp数据*/ /* * No arp on this interface. */ if (dev->flags&IFF_NOARP) return; /* * 分配缓冲区, * ARP数据包格式为: * 硬件类型(2bytes)+协议类型(2bytes)+硬件地址长度(1bytes)+协议长度(1bytes)+操作码(2bytes) * +源mac地址(6bytes)+源IP地址(4bytes)+目的mac地址(6bytes)+目的IP地址(4bytes) * 长度=以太网包头长度+arp包头长度+arp数据长度(源ip长度4+源硬件地址长度+目的ip长度4+目的硬件地址长度)+15(用作缓冲区字对齐) */ skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4) + dev->hard_header_len + 15, GFP_ATOMIC); if (skb == NULL) return; skb_reserve(skb, (dev->hard_header_len+15)&~15);/*在skb中申请以太网硬件头缓冲区,且边界字对齐*/ skb->nh.raw = skb->data; /*在skb中申请arp数据包缓冲区(包括arp头和数据)*/ arp = (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->addr_len+4)); skb->dev = dev;/*指定数据包发送网卡*/ skb->protocol = __constant_htons (ETH_P_ARP); if (src_hw == NULL) src_hw = dev->dev_addr;/*如果源硬件mac地址未提供则赋值为发送网卡的硬件地址*/ if (dest_hw == NULL) dest_hw = dev->broadcast;/*如果目标硬件mac地址未提供则赋值为广播地址,通常arp请求时它置为广播地址*/ /* *填充设备MAC地址.MAC帧格式: *目的地址(6字节)+ 源地址(6字节)+ 2字节字段(IEEE802.3:数据长度/DIX以太网:数据类型)+ 数据(46~~1500)+FCS */ if (dev->hard_header && dev->hard_header(skb,dev,ptype,dest_hw,src_hw,skb->len) < 0) goto out; /* * Fill out the arp protocol part. * * The arp hardware type should match the device type, except for FDDI, * which (according to RFC 1390) should always equal 1 (Ethernet). */ /* * Exceptions everywhere. AX.25 uses the AX.25 PID value not the * DIX code for the protocol. Make these device structure fields. */ switch (dev->type) { default: arp->ar_hrd = htons(dev->type); arp->ar_pro = __constant_htons(ETH_P_IP); break; #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) case ARPHRD_AX25: arp->ar_hrd = __constant_htons(ARPHRD_AX25); arp->ar_pro = __constant_htons(AX25_P_IP); break; #if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE) case ARPHRD_NETROM: arp->ar_hrd = __constant_htons(ARPHRD_NETROM); arp->ar_pro = __constant_htons(AX25_P_IP); break; #endif #endif #ifdef CONFIG_FDDI case ARPHRD_FDDI: arp->ar_hrd = __constant_htons(ARPHRD_ETHER); arp->ar_pro = __constant_htons(ETH_P_IP); break; #endif #ifdef CONFIG_TR case ARPHRD_IEEE802_TR: arp->ar_hrd = __constant_htons(ARPHRD_IEEE802); arp->ar_pro = __constant_htons(ETH_P_IP); break; #endif } arp->ar_hln = dev->addr_len;/*对以太网而言,是MAC地址长度,应该为6*/ arp->ar_pln = 4;/*对IP协议则是IP地址的长度*/ arp->ar_op = htons(type);/*arp请求或响应*/ arp_ptr=(unsigned char *)(arp+1);/*跳过ARP头,指向数据部分*/ memcpy(arp_ptr, src_hw, dev->addr_len);/*填充源硬件地址*/ arp_ptr+=dev->addr_len;/*指针后移*/ memcpy(arp_ptr, &src_ip,4);/*填充源IP地址*/ arp_ptr+=4;/*指针后移*/ if (target_hw != NULL) /*不为空则填充目标硬件地址,一般用于arp响应,填充解析的硬件地址*/ memcpy(arp_ptr, target_hw, dev->addr_len); else /*否则填充全0地址,一般用于arp请求,因为目标硬件地址未知*/ memset(arp_ptr, 0, dev->addr_len); arp_ptr+=dev->addr_len; /*指针后移*/ memcpy(arp_ptr, &dest_ip, 4);/*填充目的IP地址*/ skb->dev = dev; /*指定发送数据包的网卡设备*/ dev_queue_xmit(skb);/*函数内部调用以太网卡驱动程序的发送函数将数据包发送到网络上*/ return; out: kfree_skb(skb); } |
|
来自: mrjbydd > 《linux kernel》