TCP/IP学习(37)——L2如何设置包的协议类型
2014-07-17 09:56
267 查看
摘自:http://blog.chinaunix.net/uid-23629988-id-1677689.html
本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
作者:gfree.wind@gmail.com
博客:linuxfocus.blog.chinaunix.net
以太网的硬件地址长度为48 bits(6 字节),而L2数据帧有三种类型:单播,多播和广播,其中广播可看作多播的一种特殊情况。Bit 0用于表示多播还是单播,当bit 0为1时,为多播,为0时,表示单播。
Linux kernel使用eth_type_trans来判断数据帧的类型,及协议类型。
__be16 eth_type_trans(struct sk_buff *skb, struct
net_device *dev)
{
struct ethhdr *eth;
skb->dev = dev;
skb_reset_mac_header(skb);
skb_pull_inline(skb, ETH_HLEN);
eth = eth_hdr(skb);
if (unlikely(is_multicast_ether_addr(eth->h_dest))) {
/* 如果是多播地址,即bit0为1*/
if (!compare_ether_addr_64bits(eth->h_dest, dev->broadcast))
skb->pkt_type = PACKET_BROADCAST; //与设备的广播地址相同,则帧为广播帧
else
skb->pkt_type = PACKET_MULTICAST; //与设备的广播地址不同,则帧为多播帧
}
/*
* This ALLMULTI check should be redundant by 1.4
* so don't forget to remove it.
*
* Seems, you forgot to remove it. All
silly devices
* seems to set IFF_PROMISC.
*/
/*
这里为什么不检测IFF_PROMISC标志呢?
我怀疑是因为有的网卡不设置这个标志,依然可以收到不属于自己地址的数据包
*/
else if (1 /*dev->flags&IFF_PROMISC */ ) {
/* 如果数据帧的目的地址不是网卡的地址,那么数据帧的类型为PACKET_OTHERHOST */
if (unlikely(compare_ether_addr_64bits(eth->h_dest, dev->dev_addr)))
skb->pkt_type = PACKET_OTHERHOST;
/*
默认情况,skb->pkt_type为0,即PACKET_HOST,即数据帧是发给本主机的 */
}
/* 下面开始判断L2协议 */
/*
* Some variants of DSA tagging don't have an ethertype field
* at all, so we check here whether one of those tagging
* variants has been configured on the receiving interface,
* and if so, set skb->protocol
without looking at the packet.
*/
/*
如上面的注释所说,当设备指定了DSA或者TRAILER,那么就不需要检查包,直接返回DSA或者TRAILER
*/
if (netdev_uses_dsa_tags(dev))
return htons(ETH_P_DSA);
if (netdev_uses_trailer_tags(dev))
return htons(ETH_P_TRAILER);
/*
当协议值大于136时,那么这个数据帧一定为ethernet frame
因为802.2和802.3的对应域为帧长,均要小于或等于1500,而ethernet frame的协议类型都大于等于1536.
*/
if (ntohs(eth->h_proto) >= 1536)
return eth->h_proto;
/*
* This is a magic hack to spot IPX packets. Older
Novell breaks
* the protocol design and runs IPX over 802.3 without an 802.2
LLC
* layer. We look for FFFF which isn't
a used 802.2 SSAP/DSAP. This
* won't work for fault tolerant netware but does for the
rest.
*/
/*
当IPX使用原始的802.3作为载体时,其头两个字节作为checksum,但是一般都设为0xffff。
*/
if (skb->len >= 2 && *(unsigned
short *)(skb->data) == 0xFFFF)
return htons(ETH_P_802_3);
/*
* Real 802.2 LLC
*/
/* ok, 那么类型为802.2*/
return htons(ETH_P_802_2);
}
这个函数逻辑上很简单,基本上都是由L2层协议所决定的。
本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
作者:gfree.wind@gmail.com
博客:linuxfocus.blog.chinaunix.net
以太网的硬件地址长度为48 bits(6 字节),而L2数据帧有三种类型:单播,多播和广播,其中广播可看作多播的一种特殊情况。Bit 0用于表示多播还是单播,当bit 0为1时,为多播,为0时,表示单播。
Linux kernel使用eth_type_trans来判断数据帧的类型,及协议类型。
__be16 eth_type_trans(struct sk_buff *skb, struct
net_device *dev)
{
struct ethhdr *eth;
skb->dev = dev;
skb_reset_mac_header(skb);
skb_pull_inline(skb, ETH_HLEN);
eth = eth_hdr(skb);
if (unlikely(is_multicast_ether_addr(eth->h_dest))) {
/* 如果是多播地址,即bit0为1*/
if (!compare_ether_addr_64bits(eth->h_dest, dev->broadcast))
skb->pkt_type = PACKET_BROADCAST; //与设备的广播地址相同,则帧为广播帧
else
skb->pkt_type = PACKET_MULTICAST; //与设备的广播地址不同,则帧为多播帧
}
/*
* This ALLMULTI check should be redundant by 1.4
* so don't forget to remove it.
*
* Seems, you forgot to remove it. All
silly devices
* seems to set IFF_PROMISC.
*/
/*
这里为什么不检测IFF_PROMISC标志呢?
我怀疑是因为有的网卡不设置这个标志,依然可以收到不属于自己地址的数据包
*/
else if (1 /*dev->flags&IFF_PROMISC */ ) {
/* 如果数据帧的目的地址不是网卡的地址,那么数据帧的类型为PACKET_OTHERHOST */
if (unlikely(compare_ether_addr_64bits(eth->h_dest, dev->dev_addr)))
skb->pkt_type = PACKET_OTHERHOST;
/*
默认情况,skb->pkt_type为0,即PACKET_HOST,即数据帧是发给本主机的 */
}
/* 下面开始判断L2协议 */
/*
* Some variants of DSA tagging don't have an ethertype field
* at all, so we check here whether one of those tagging
* variants has been configured on the receiving interface,
* and if so, set skb->protocol
without looking at the packet.
*/
/*
如上面的注释所说,当设备指定了DSA或者TRAILER,那么就不需要检查包,直接返回DSA或者TRAILER
*/
if (netdev_uses_dsa_tags(dev))
return htons(ETH_P_DSA);
if (netdev_uses_trailer_tags(dev))
return htons(ETH_P_TRAILER);
/*
当协议值大于136时,那么这个数据帧一定为ethernet frame
因为802.2和802.3的对应域为帧长,均要小于或等于1500,而ethernet frame的协议类型都大于等于1536.
*/
if (ntohs(eth->h_proto) >= 1536)
return eth->h_proto;
/*
* This is a magic hack to spot IPX packets. Older
Novell breaks
* the protocol design and runs IPX over 802.3 without an 802.2
LLC
* layer. We look for FFFF which isn't
a used 802.2 SSAP/DSAP. This
* won't work for fault tolerant netware but does for the
rest.
*/
/*
当IPX使用原始的802.3作为载体时,其头两个字节作为checksum,但是一般都设为0xffff。
*/
if (skb->len >= 2 && *(unsigned
short *)(skb->data) == 0xFFFF)
return htons(ETH_P_802_3);
/*
* Real 802.2 LLC
*/
/* ok, 那么类型为802.2*/
return htons(ETH_P_802_2);
}
这个函数逻辑上很简单,基本上都是由L2层协议所决定的。
相关文章推荐
- ASP.NET MVC WebApi 返回数据类型序列化控制(json,xml) 用javascript在客户端删除某一个cookie键值对 input点击链接另一个页面,各种操作。 C# 往线程里传参数的方法总结 TCP/IP 协议 用C#+Selenium+ChromeDriver 生成我的咕咚跑步路线地图 (转)值得学习百度开源70+项目
- 如何学习 TCP/IP 协议
- 用协议分析工具学习TCP/IP
- 用协议分析工具学习TCP/IP
- 用协议分析工具学习TCP/IP
- tcp/ip学习第一步:网络中两台主机进行通讯,协议栈是如何处理数据报的.
- TCP/IP学习笔记之六 --- ICMP: Internet控制报文协议
- 用协议分析工具学习TCP/IP
- 用协议分析工具学习TCP/IP
- TCP/IP 地址家族 ,协议类型 ,套接字类型 ,协议字段!
- 用协议分析工具学习TCP/IP
- 学习网络协议(二)TCP/IP
- 用协议分析工具学习TCP/IP
- 用协议分析工具学习TCP/IP
- wireshark的使用教程--用实践的方式帮助我们理解TCP/IP中的各个协议是如何工作的
- VC中如何设置Socket的TCP/IP KeepAlive机制(MSDN)
- 利用协议分析工具学习TCP/IP并捕获内网用户密码
- 用协议分析工具学习TCP/IP
- 学习如何分析进出服务器的TCP/IP数据包
- wireshark的使用教程--用实践的方式帮助我们理解TCP/IP中的各个协议是如何工作的