以太网实现

来源:互联网 发布:集体智慧编程 怎么样 编辑:程序博客网 时间:2024/04/28 03:04

以太网的头部为14字节,6字节源地址,6字节目的地址,2字节类型域。它的定义如下:

[ include/uapi/linux/if_ether.h ]

/* *This is an Ethernet frame header. *ETH_ALEN = 6 */struct ethhdr {unsigned charh_dest[ETH_ALEN];/* destination eth addr*/unsigned charh_source[ETH_ALEN];/* source ether addr*/__be16h_proto;/* packet type ID field*/} __attribute__((packed));
其中h_proto为此frame是什么类型,如对于IP协议,类型为

[ include/uapi/linux/if_ether.h ]

#define ETH_P_IP0x0800/* Internet Protocol packet*/
还有一个特殊的类型:

[ include/uapi/linux/if_ether.h ]

#define ETH_P_ALL0x0003/* Every packet (be careful!!!) */
如果通过RAW socket获取所有的包,可以用此类型,如:socket( PF_PACKET, SOCK_RAW, htons( ETH_P_ALL) );

内核对于创建每层的协议头,提供了一个抽象结构,其中创建以太网头部的结构如下:

[ net/ethernet/eth.c ]

const struct header_ops eth_header_ops ____cacheline_aligned = {.create= eth_header,.parse= eth_header_parse,.rebuild= eth_rebuild_header,.cache= eth_header_cache,.cache_update= eth_header_cache_update,};

创建以太网头部的函数如下:

[ net/ethernet/eth.c ]

/** * eth_header - create the Ethernet header * @skb:buffer to alter * @dev:source device * @type:Ethernet type field * @daddr: destination address (NULL leave destination address) * @saddr: source address (NULL use device source address) * @len:   packet length (<= skb->len) * * * Set the protocol type. For a packet of type ETH_P_802_3/2 we put the length * in here instead. */int eth_header(struct sk_buff *skb, struct net_device *dev,       unsigned short type,       const void *daddr, const void *saddr, unsigned int len){/* ETH_HLEN = 14 * 在skb头部增加尺寸来容纳以太网头部 */struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN);/* 类型为ETH_P_802_3 或ETH_P_802_2 时, eth->h_proto 放的是长度 */if (type != ETH_P_802_3 && type != ETH_P_802_2)eth->h_proto = htons(type);elseeth->h_proto = htons(len);/* *      Set the source hardware address. */if (!saddr)saddr = dev->dev_addr;// 源地址为设备的地址memcpy(eth->h_source, saddr, ETH_ALEN);// 设置源地址if (daddr) {memcpy(eth->h_dest, daddr, ETH_ALEN);// 设置目的地址return ETH_HLEN;}/* *      Anyway, the loopback-device should never use this function... */if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {// 设备为环回地址或不使用ARPmemset(eth->h_dest, 0, ETH_ALEN);// 设置目的地址为0return ETH_HLEN;}return -ETH_HLEN;}EXPORT_SYMBOL(eth_header);


0 0
原创粉丝点击