linux网络链路层发送,Linux网络协议栈(四)——链路层(2)

2、协议相关

2.1、第3层协议的管理

在Linux内核中,有两种不同目的的3层协议:

(1)    ptype_all管理的协议主要用于分析目的,它接收所有到达第3层协议的数据包。

(2)    ptype_base管理正常的3层协议,仅接收具有正确协议标志符的数据包,例如,Internet的0x0800。

c4554f77a58550133950de4e2c13d5a4.png

注意sb_buff与net_device中几个字段的区别:

sb_buff:

unsigned short        protocol

高层协议从二层设备的角度所看到的协议,典型的协议包括 IP,IPV6和 ARP,完整的列表在 include/linux/if_ether.h。

unsigned char pkt_type

帧的类型,可能的取值都在include/linux/if_packet.h 中定义.

net_device:

unsigned short type

设备类型(以太网,帧中继等)。在include/linux/if_arp.h 中有完整的类型列表。

2.2、协议处理函数注册

当协议注册时,内核会调用dev_add_pack添加一个与之对应的packet_type数据结构:

d7de2805840d19d439c1d9517c605330.gif //include/linux/netdevice.h

struct packet_type {

unsigned short        type;    /* This is really htons(ether_type).    */

struct net_device        *dev;    /* NULL is wildcarded here        */

int            (*func) (struct sk_buff *, struct net_device *,

struct packet_type *);

void            *af_packet_priv;

struct list_head    list;

};

fd39993e9cda43ecc96ba7dffaad059e.gif

type:协议类型,它可以取以下一些值。来看看if_ether.h中定义的协议的类型:

c2c1d082691a40fe66311ed368f530c8.gif

Code

dev:网络设备。PF_PACKET套接字通常使用它在特定的设备监听,例如,tcpdump -i eth0  通过PF_PACKET套接字创建一个packet_type实例,然后将dev指向eth0对应的net_device数据结构。

func:协议处理函数。

af_packet_priv:被PF_PACKET套接字使用。

当同一个类型的协议有多个packet_type实例时,输入的帧会被所有的协议处理函数处理。

IP协议的packet_type:

e15e9c3802f0544a63ad949e2b77c16b.gif //net/ipv4/ip_output.c

static struct packet_type ip_packet_type = {

.type = __constant_htons(ETH_P_IP),

.func = ip_rcv,

};

//在inet_init中被调用

void __init ip_init(void)

{

dev_add_pack(&ip_packet_type);

ip_rt_init();

inet_initpeers();

#if defined(CONFIG_IP_MULTICAST) && defined(CONFIG_PROC_FS)

igmp_mc_proc_init();

#endif

}

//net/core/dev.c

void dev_add_pack(struct packet_type *pt)

{

int hash;

spin_lock_bh(&ptype_lock);

if (pt->type == htons(ETH_P_ALL)) {

netdev_nit++;

list_add_rcu(&pt->list, &ptype_all);

} else {

hash = ntohs(pt->type) & 15;

list_add_rcu(&pt->list, &ptype_base[hash]);

}

spin_unlock_bh(&ptype_lock);

}

82df0bba39429f2d7e5b1ffea6e5f063.gif

2.3、以太网帧(Ethernet)与802.3帧

老的以太网的帧的格式与标准和802.3标准的格式分别如下:

5e48514fdb0f57974e549f0d51a8bdf8.png

以太网的帧头(Ethernet frame header)的定义:

//include/linux/if_ether.h

struct ethhdr {

unsigned char    h_dest[ETH_ALEN];    /* destination eth addr    */

unsigned char    h_source[ETH_ALEN];    /* source ether addr    */

unsigned short    h_proto;        /* packet type ID field    */

} __attribute__((packed));

h_proto>1536的以太网类型:

c6965a7cd9778faed8fe83a1937c8266.png

2.4、eth_type_trans函数

90b9c323d92d9320bb01a1166f56211e.gif //net/ethernet/eth.c

unsigned short eth_type_trans(struct sk_buff *skb, struct net_device *dev)

{

struct ethhdr *eth;

unsigned char *rawp;

skb->mac.raw=skb->data;

skb_pull(skb,ETH_HLEN);

//取出以太网头

eth = eth_hdr(skb);

skb->input_dev = dev;

//设置帧的类型

if(*eth->h_dest&1) //广播和多播地址

{

if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)

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.

*/

else if(1 /*dev->flags&IFF_PROMISC*/)

{

if(memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN))

//如果帧的目标地址与网络设备的mac地址不同

skb->pkt_type=PACKET_OTHERHOST;

}

if (ntohs(eth->h_proto) >= 1536)

return eth->h_proto;

rawp = skb->data;

/*

*    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.2标准的LLC层,0xFFFF为其标志位

if (*(unsigned short *)rawp == 0xFFFF)

return htons(ETH_P_802_3);

/*

*    Real 802.2 LLC

*/

//802.2标准的LLC协议

return htons(ETH_P_802_2);

}

e412915aa2a495f8099676360246ac8f.gif

该函数主要设置数据帧的类型,返回协议的类型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值