Linux驱动之网卡驱动点滴

分配net_device空间和私有数据空间:

 netdev = alloc_etherdev(sizeof(struct emac_dev));
... ...
struct net_device *alloc_netdev(int sizeof_priv, const char *name,
		void (*setup)(struct net_device *))
{
	void *p;
	struct net_device *dev;
	int alloc_size;

	/* ensure 32-byte alignment of both the device and private area */
	alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST;
	alloc_size += sizeof_priv + NETDEV_ALIGN_CONST;

	p = kzalloc(alloc_size, GFP_KERNEL);
	if (!p) {
		printk(KERN_ERR "alloc_dev: Unable to allocate device.\n");
		return NULL;
	}

	dev = (struct net_device *)
		(((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
	dev->padded = (char *)dev - (char *)p;

	if (sizeof_priv)
		dev->priv = netdev_priv(dev);

	setup(dev);
	strcpy(dev->name, name);
	return dev;
}

可见,net_device空间和私有数据空间是分配在一起的,而且net_device的空间使用可32字节对齐,而私有数据空间似乎并没有进行字节对齐,但是后面又增加了一个NETDEV_ALIGN_CONST,没搞清楚是为什么?

返回的是net_device的指针,那么私有数据的地址在哪里呢?且看下面分析

找到私有数据的地址:

 dev = NETDEV_PRIV(netdev);
#define NETDEV_PRIV(net_dev) netdev_priv(net_dev)
#define	NETDEV_ALIGN		32
#define	NETDEV_ALIGN_CONST	(NETDEV_ALIGN - 1)

static inline void *netdev_priv(struct net_device *dev)
{
	return (char *)dev + ((sizeof(struct net_device)
					+ NETDEV_ALIGN_CONST)
				& ~NETDEV_ALIGN_CONST);
}

 上面,netdev是包括私有数据空间和net_device空间的指针,指向net_device的开始处;可见,私有数据的地址在下net_device的末尾,也就是以32字节对齐net_device空间的末尾。

对齐的问题再学学: 

在学习网卡驱动时,遇到的字节对齐问题,如下代码所示,其中

((sizeof(struct net_device) + NETDEV_ALIGN_CONST)& ~NETDEV_ALIGN_CONST)

实现的是把sizeof(struct net_device)所占用的空间按照32字节对齐。

#define	NETDEV_ALIGN		32
#define	NETDEV_ALIGN_CONST	(NETDEV_ALIGN - 1)

static inline void *netdev_priv(struct net_device *dev)
{
	return (char *)dev + ((sizeof(struct net_device)
					+ NETDEV_ALIGN_CONST)
				& ~NETDEV_ALIGN_CONST);
}

 其实也可以用这种方式实现<一个内存块,如sizeof(struct net_device)的>2的n次幂的对齐方式(n=0,1,2... ...),

MAC地址转换

MAC地址也叫物理地址、硬件地址或链路地址,由网络设备制造上生产时写在硬件内部。IP地址与MAC地址在计算机里都是以二进制表示的,IP地址是32位的,而MAC地址则是48位的。MAC地址的长度是48位(6个字节),通常表示为12个16进制数,每2个16进制数之间用冒号隔开,如:08:00:20:0a:bc:6d就是一个MAC地址,其中前6位16进制数08:00:20代表网络硬件制造商的编号,它由IEEE分配,而后3位16进制数0a:bc:6d代表该制造商所制造的某个网络产品(如网卡)的序列号。

static unsigned char emac_str_to_hexnum(unsigned char c)
{
	if (c >= '0' && c <= '9')
		return c - '0';
	if (c >= 'a' && c <= 'f')
		return c - 'a' + 10;//转换成10~15的数字
	if (c >= 'A' && c <= 'F')
		return c - 'A' + 10;
	return 0;
}

/* string to ethernet address conversion */
static void emac_str_to_ethaddr(unsigned char *ea, unsigned char *str)
{
	int i;
	unsigned char num;

	for (i = 0; i < 6; i++) {
		if ((*str == '.') || (*str == ':')) {
			str++;
		}
		num = emac_str_to_hexnum(*str) << 4;
		++str;
		num |= (emac_str_to_hexnum(*str));
		++str;
		ea[i] = num;
	}
}

 emac_str_to_ethaddr()是把str中的MAC地址字符串转换为数字,char emac_str_to_hexnum()帮助吧每个字符转换成16进制数字。

猜你喜欢

转载自sxl-xd-163-com.iteye.com/blog/825591
今日推荐