[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的工具。
[RK3288][Android6.0] WiFi MAC地址获取流程小结

[RK3288][Android6.0] WiFi MAC地址获取流程小结

它会进入到rockusb mode进行烧写,对应代码应该是在uboot,可自行研究。