arp_send()函数分析

  (代码基于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);

你可能感兴趣的:(linux,struct,Module,header,null,structure)