分配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进制数字。