[RK3288][Android6.0] WiFi MAC地址获取流程小结
Platform: RK3288
OS: Android 6.0
Kernel: 3.10.92
用户空间如何查看MAC地址?
/sys/class/net/wlan0/address
net目录生成:
netdev_kobject_init -> net-sysfs.c
class_register(&net_class);
net_class:
static struct class net_class = {
.name = "net", //对应name
.dev_release = netdev_release,
#ifdef CONFIG_SYSFS
.dev_attrs = net_class_attributes, //关注此属性
#endif /* CONFIG_SYSFS */
......
};
address文件生成:
上面属性net_class_attributes:
static struct device_attribute net_class_attributes[] = {
//注册net下的节点会自动生成address文件,通过
__ATTR(address, S_IRUGO, show_address, NULL),
{}
};
WiFi如何注册并生成address文件的?
net目录下的节点如eth/wlan生成都是通过网络设备注册生成的,以下是WiFi注册流程:
dhd_register_if -> dhd_linux.c
register_netdev -> dev.c
register_netdevice ->
netdev_register_kobject ->
dev->class = &net_class; //对应的是“net” class.
device_add
注册后 /sys/class/net/wlan0/address 就生成了。
WiFi MAC address如何获取?
查看上面提到的address函数:
static ssize_t show_address(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct net_device *net = to_net_dev(dev);
ssize_t ret = -EINVAL;
read_lock(&dev_base_lock);
if (dev_isalive(net))
//数据从net->dev_addr获取
ret = sysfs_format_mac(buf, net->dev_addr, net->addr_len);
read_unlock(&dev_base_lock);
return ret;
}
net->dev_addr的由来:
dhd_register_if:
int dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock)
{
if (ifidx == 0) {
......
if (!ETHER_ISNULLADDR(dhd->pub.mac.octet))
memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
} else {
.....
}
memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
}
dhd->pub.mac.octet获取:
系统开机初始化有两处地方会去读取MAC地址。
1. 第一处:
dhdsdio_probe -> dhd_sdio.c
dhd_attach -> dhd_linux.c
wifi_platform_get_mac_addr(dhd->adapter, dhd->pub.mac.octet); ->
plat_data->get_mac_addr -> 在bcm_wlan_set_plat_data()中定义
bcm_wlan_get_mac_address ->
rockchip_wifi_mac_addr -> dhd_gpio.c
rockchip_wifi_mac_addr:
int rockchip_wifi_mac_addr(unsigned char *buf)
{
......
if(is_zero_ether_addr(wifi_custom_mac_addr)) {
int i;
char *tempBuf = kmalloc(512, GFP_KERNEL);
if(tempBuf) {
//如果在IDB模块有自定义写入地址的话就能获取成功
GetSNSectorInfo(tempBuf);
for (i = 445; i <= 450; i++)
wifi_custom_mac_addr[i-445] = tempBuf[i];
kfree(tempBuf);
} else {
return -1;
}
}
//否则就是空
memcpy(buf, wifi_custom_mac_addr, 6);
return 0;
}
2. 第二处:
dhd_open -> dhd_linux.c
wl_android_wifi_on ->
dhd_dev_init_ioctl ->
dhd_sync_with_dongle ->
dhd_preinit_ioctls
dhd_preinit_ioctls:
int dhd_preinit_ioctls(dhd_pub_t *dhd)
{
......
//从IDB中获取,这里最后会调用上面的rockchip_wifi_mac_addr(),如果前面一次从
//IDB获取成功了,那么就不会从IDB重新读取而是直接返回。
ret = wifi_platform_get_mac_addr(dhd->info->adapter, ea_addr.octet);
if (!ret) {
memcpy(dhd->mac.octet, ea_addr.octet, ETHER_ADDR_LEN);
} else {
/* Get the default device MAC address directly from firmware */
//如果IDB中获取不到,那么就从WiFi芯片中获取
if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
FALSE, 0)) < 0) {
.......
}
/* Update public MAC address after reading from Firmware */
memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
}
......
}
如何更新IDB?
rockchip在windows平台上提供了烧写WiFi MAC address到IDB的工具。
它会进入到rockusb mode进行烧写,对应代码应该是在uboot,可自行研究。