第一部分:wlip网络包的发送过程,ethernet为例;
1:
我们从链路层上讲起,数据通过网线时候的软件控制层;软件开发的角度来讲就是网卡驱动:如图
<链路层上的数据块是以FramePacket的形式存在>,通过物理接口向外传输;
例如:hard_start_xmit(Data);剩下的部分是由HardWare来处理;
2:Data的数据形式是如何组织的;接收方又是如何解析的呢;
FramePacket是形式是固定的,包括{[Head][Body]};head大小14BYTE;body最大值1500;
同样,接收方从物理网卡上收到数据包,也就是按Frame的格式来解析出来源Mac,和相应的数据;
3:代码的组织结构;以Arp_Request_Packet的形式为例;
/*请求IP的Mac地址*/
S32 Arp_Request_Packet(U32 ipAddr)
{
ST_NET_PACKET* packet = NetNewPacket(FALSE);
ST_ARP_HEADER arpHeader;
U08* ptr;
U08* arpHdr = NET_PACKET_IP(packet);
int ret;
if(!packet)
{
DPrintf("[ARP] allocate buffer fail");
return ERR_OUT_OF_MEMORY;
}
// put arp header
NetPutW(&arpHdr[ARP_HARDWARE_TYPE], ARP_HW_TYPE_ETHERNET);
NetPutW(&arpHdr[ARP_PORTOCOL_TYPE], ETHERNET_TYPE_IP);
arpHdr[ARP_HW_ADDR_LENGTH] = ETHERNET_MAC_LENGTH;
arpHdr[ARP_PROT_ADDR_LENGTH] = ETHERNET_IP_LENGTH;
NetPutW(&arpHdr[ARP_OPERATION], ARP_OP_REQUEST);
// put arp data
ptr = &arpHdr[ARP_DATA];
NetMacAddrCopy(ptr, NetLocalMACGet());
ptr += ETHERNET_MAC_LENGTH;
NetPutDW(ptr, NetDefaultIpGet());
ptr += ETHERNET_IP_LENGTH;
NetMacAddrCopy(ptr, NetNullMACGet());//填充0;
ptr += ETHERNET_MAC_LENGTH;
NetPutDW(ptr, ipAddr);
ptr += ETHERNET_IP_LENGTH;
packet->Net.u16PayloadSize = sizeof(ST_ARP_HEADER);
packet->Net.u08NetIndex = NetDefaultNicGet();
//上面已经将整个ArpPacket做好了;
ret = NetPacketSend(packet, NetBroadcaseIpGet(), ETHERNET_TYPE_ARP);//添加到FrameHead就可以发出去了;
//需要注意的事;帧的地址为OXFFFFFFFFFFFF;表示要发送给所有的Ethernet主机;
if (ret < 0)
return ret;
else
return NO_ERR;//返回发送状态;
}
第二部分:Arp的实现和运用
需求:
数据链路如以太网都有自己的寻址机制(常常为48 bit地址),这是使用数据链路的任何网络层都必须遵从
的。当一台主机把以太网数据帧发送到位于同一局域网上的另一台主机时,是根据48 bit的以
太网地址来确定目的接口的。设备驱动程序从不检查I P数据报中的目的IP地址;
在实际运用中,需要运算VALmac=f(IP_addr);在此例中等同于Arp_Request_Packet(U32 ipAddr)
限制和环境:
A R P高效运行的关键是由于每个主机上都有一个A R P高速缓存。这个高速缓存存放了最近I n t e r n e t地址到硬件地址之间的映射记录。
高速缓存中每一项的生存时间一般为2 0分钟,起始时间从被创建时开始算起。arp -a命令来检查ARP高速缓存。参数-a的意思是显示高速缓存中所有的内容。
在以太网上解析IP地址时,A R P请求和应答分组的格式如图4 - 3所示
(A R P可以用于其他类型的网络,可以解析I P地址以外的地址)
以太网报头中的前两个字段是以太网的源地址和目的地址。目的地址为全1的特殊地址是广播地址。电缆上的所有以太网接口都要接收广播的数据帧。
ARP代码实现和运用
S32 IpPacketSend(ST_NET_PACKET *packet, U08 protocol, U32 srcAddr, U32 destAddr)//发送一个IP包
{
int sendSize;
U08* ipHdr = NET_PACKET_IP(packet);
//DPrintf("%s", __FUNCTION__);
memset(ipHdr, 0, sizeof(ST_IP_HEADER));
ipHdr[IP_VER_IHL] = 0x40 + (sizeof(ST_IP_HEADER) >> 2);
ipHdr[IP_SERVICE] = 0;
NetPutW(&ipHdr[IP_LENGTH], packet->Net.u16PayloadSize + sizeof(ST_IP_HEADER));
NetPutW(&ipHdr[IP_ID], u16IpId++);
NetPutW(&ipHdr[IP_FLAG], IP_FLAG_DF_NOT_FRAGMENT); //don't fragment
ipHdr[IP_TTL] = 128;
ipHdr[IP_PROTOCOL] = protocol;
NetPutW(&ipHdr[IP_CHECKSUM], 0);
....
NetPutDW(&ipHdr[IP_SRC_IP], srcAddr);
NetPutDW(&ipHdr[IP_DST_IP], destAddr);
....
添加IP头
packet->Net.u16PayloadSize += sizeof(ST_IP_HEADER);
NetPutW(&ipHdr[IP_CHECKSUM], InetCsum(NET_PACKET_IP(packet), sizeof(ST_IP_HEADER)));
{
sendSize = NetPacketSend(packet, destAddr, ETHERNET_TYPE_IP);//添加帧头发送到Ethernet;
if (sendSize < 0)
{
return sendSize;
}
else
return (sendSize - sizeof(ST_IP_HEADER));
}
}
//???哪里会用到ARP的功能呢;没有看到呀;
下面解析NetPacketSend,来看arp是如何来用到的;
S32 NetPacketSend(ST_NET_PACKET *packet, U32 destIp, U16 u16Type)
{
S32 status;
U08 dstMac[6];
int ret;
if(destIp == BROADCAST_IP_ADDR)//Arp包
{
NetMacAddrCopy(dstMac, BROADCAST_MAC_ADDR);
}
else//IP包
{
U08 retry = 1;
if(!NetIpMaskCompare(destIp, NetDefaultIpGet(), NetSubnetMaskGet())) //外网;
{
destIp = NetGatewayIpGet();
if(destIp == 0)
{
NetFreePacket(packet);
return -ENETUNREACH;
}
}
else if(NetIpMaskCompare(destIp, BROADCAST_IP_ADDR, ~NetSubnetMaskGet())) //ip广播
{
NetMacAddrCopy(dstMac, BROADCAST_MAC_ADDR);
destIp = 0;
}
if (destIp)//本地局域网
{
while(retry)//尝试arp地址询问
{
if(NO_ERR == (ret = ArpQuery(destIp, dstMac)))//这里就是重点了;我们要用到Mac地址;涉及到MAC超时;
break;
...
retry--;
}
if(retry == 0)
{
失败
return -EHOSTUNREACH;
}
}
}
....
获取到MAC地址,准备发送数据包
//添加Ethernet头部
{
U08* ptr = NET_PACKET_ETHER(packet);
NetMacAddrCopy(ptr, dstMac);
ptr += 6;
NetMacAddrCopy(ptr, NetLocalMACGet());
ptr += 6;
NetPutW(ptr, u16Type);
}
....
status=Hw_send_packet(packet,type)
return status;
}
在有些时候,数据包发送不出去,可以查看一下arp是否正常哟。哈哈。。
阅读(2750) | 评论(0) | 转发(0) |