08.netlink_kernel_create

(210919_11:15:55.975)[  206.398032] <1>-(1)[511:fuelgauged] bmd_ctrl_cmd_from_user+0x1bd0/0x1d5c

(210919_11:15:55.975)[  206.398036] <1>-(1)[511:fuelgauged] nl_data_handler+0x158/0x184

(210919_11:15:55.975)[  206.398041] <1>-(1)[511:fuelgauged] netlink_unicast+0x200/0x2f8

(210919_11:15:55.975)[  206.398045] <1>-(1)[511:fuelgauged] netlink_sendmsg+0x2f8/0x350

(210919_11:15:55.975)[  206.398049] <1>-(1)[511:fuelgauged] ___sys_sendmsg+0x1f4/0x2d4

(210919_11:15:55.975)[  206.398052] <1>-(1)[511:fuelgauged] __sys_sendmsg+0x84/0xd4

(210919_11:15:55.975)[  206.398056] <1>-(1)[511:fuelgauged] compat_SyS_sendmsg+0x10/0x18

(210919_11:15:55.975)[  206.398059] <1>-(1)[511:fuelgauged] el0_svc_naked+0x34/0x38 

battery_init

  ->gm.daemo_nl_sk = netlink_kernel_create(&init_net, NETLINK_FGD, &cfg);

  ->battery_probe

    ->mtk_battery_init(dev)

      ->fg_custom_init_from_dts(dev);

    ->battery_main.psy = power_supply_register(&(dev->dev), &battery_main.psd, NULL);

 C Code /kernel-4.14/drivers/power/supply/mediatek/battery/mtk_battery.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

#define NETLINK_FGD 26
static int __init battery_init(void)
{
    struct netlink_kernel_cfg cfg = {
        .input = nl_data_handler,
    };

    int ret;

    gm.daemo_nl_sk = netlink_kernel_create(&init_net, NETLINK_FGD, &cfg);  //创建netlink
    bm_err("netlink_kernel_create protol= %d\n", NETLINK_FGD);

    if (gm.daemo_nl_sk == NULL) {
        bm_err("netlink_kernel_create error\n");
        return -1;
    }
    bm_err("netlink_kernel_create ok\n");

#ifdef CONFIG_OF
    /* register battery_device by DTS */
#else
    ret = platform_device_register(&battery_device);
#endif

    ret = platform_driver_register(&battery_driver_probe);

    bm_err("[%s] Initialization : DONE\n",
        __func__);

    return 0;
}

static void __exit battery_exit(void)
{

}
module_init(battery_init);
module_exit(battery_exit);

MODULE_AUTHOR("Weiching Lin");
MODULE_DESCRIPTION("Battery Device Driver");
MODULE_LICENSE("GPL");

内核收到应用层发过来的msg时会调用此回调函数 .input = nl_data_handler

msg的详细格式如下:

 C Code /kernel-4.14/include/linux/skbuff.h

1
2
3
4
5
6
7
8
9
10

struct sk_buff {
    ... 
 /* @len: Length of actual data */
 /* @data_len: Data length */   
    unsigned int len, data_len;
    
 /* @head: Head of buffer */
 /* @data: Data head pointer */
    unsigned char *head, *data;         
 }

 H Code \kernel-4.14\include\uapi\linux\netlink.h

1
2
3
4
5
6
7

struct nlmsghdr {
    __u32       nlmsg_len;  /* Length of message including header */
    __u16       nlmsg_type; /* Message content */
    __u16       nlmsg_flags;    /* Additional flags */
    __u32       nlmsg_seq;  /* Sequence number */
    __u32       nlmsg_pid;  /* Sending process port ID */
};

 C Code /kernel-4.14/drivers/power/supply/mediatek/battery/mtk_battery_internal.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14

#define FGD_NL_MSG_T_HDR_LEN 28
#define FGD_NL_MAGIC 2015060303
#define FGD_NL_MSG_MAX_LEN 9200

struct fgd_nl_msg_t {
    unsigned int fgd_cmd;
    unsigned int fgd_subcmd;
    unsigned int fgd_subcmd_para1;
    unsigned int fgd_subcmd_para2;
    unsigned int fgd_data_len;
    unsigned int fgd_ret_data_len;
    unsigned int identity;
    char fgd_data[FGD_NL_MSG_MAX_LEN];
};

 C Code /kernel-4.14/drivers/power/supply/mediatek/battery/mtk_battery.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

static void nl_data_handler(struct sk_buff *skb)
{
    u32 pid;
    kuid_t uid;
    int seq;
    void *data;
    struct nlmsghdr *nlh;
    struct fgd_nl_msg_t *fgd_msg, *fgd_ret_msg;  //fgd_msg接收上层数据,fgd_ret_msg发送数据
    int size = 0;
    /* 取出数据 */
    nlh = (struct nlmsghdr *)skb->data;
    pid = NETLINK_CREDS(skb)->pid;
    uid = NETLINK_CREDS(skb)->uid;
    seq = nlh->nlmsg_seq;
    /* 返回指向netlink消息体的payload的指针,也就是取得消息知的数据部分的首地址 */
    data = NLMSG_DATA(nlh);

    fgd_msg = (struct fgd_nl_msg_t *)data;  //fgd_msg指向数据首地址

    if (IS_ENABLED(CONFIG_POWER_EXT) || gm.disable_mtkbattery ||
        IS_ENABLED(CONFIG_MTK_DISABLE_GAUGE)) {
        bm_err("GM3 disable, nl handler rev data\n");
        return;
    }

    if (fgd_msg->identity != FGD_NL_MAGIC) {
        bm_err("[FGERR]not correct MTKFG netlink packet!%d\n",
            fgd_msg->identity);
        return;
    }

    if (gm.g_fgd_pid != pid &&
        fgd_msg->fgd_cmd > FG_DAEMON_CMD_SET_DAEMON_PID) {
        bm_err("drop rev netlink pid:%d:%d  cmd:%d:%d\n",
            pid,
            gm.g_fgd_pid,
            fgd_msg->fgd_cmd,
            FG_DAEMON_CMD_SET_DAEMON_PID);
        return;
    }

    size = fgd_msg->fgd_ret_data_len + FGD_NL_MSG_T_HDR_LEN;  //fgd_msg只是为了计算size

    if (size > (PAGE_SIZE << 1))
        fgd_ret_msg = vmalloc(size);
    else {
        if (in_interrupt())
            fgd_ret_msg = kmalloc(size, GFP_ATOMIC);
    else
        fgd_ret_msg = kmalloc(size, GFP_KERNEL);
    }

    if (fgd_ret_msg == NULL) {
        if (size > PAGE_SIZE)
            fgd_ret_msg = vmalloc(size);

        if (fgd_ret_msg == NULL)
            return;
    }

    memset(fgd_ret_msg, 0, size);

    bmd_ctrl_cmd_from_user(data, fgd_ret_msg);
    nl_send_to_user(pid, seq, fgd_ret_msg);

    kvfree(fgd_ret_msg);
}

根据不同的fgd_cmd填充fgd_data以及fgd_data_len

 C Code /kernel-4.14/drivers/power/supply/mediatek/battery/mtk_battery_core.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128

void bmd_ctrl_cmd_from_user(void *nl_data, struct fgd_nl_msg_t *ret_msg)
{
    struct fgd_nl_msg_t *msg;
    static int ptim_vbat, ptim_i;

    msg = nl_data;
    ret_msg->fgd_cmd = msg->fgd_cmd;

    switch (msg->fgd_cmd) {

    case FG_DAEMON_CMD_IS_BAT_PLUGOUT:
        {
            int is_bat_plugout = 0;
            int bat_plugout_time = 0;

            gauge_dev_get_boot_battery_plug_out_status(
                gm.gdev, &is_bat_plugout, &bat_plugout_time);
            ret_msg->fgd_data_len += sizeof(is_bat_plugout);
            memcpy(ret_msg->fgd_data,
                &is_bat_plugout, sizeof(is_bat_plugout));

            bm_debug(
                "[fr] BATTERY_METER_CMD_GET_BOOT_BATTERY_PLUG_STATUS = %d\n",
                is_bat_plugout);
        }
        break;
    case FG_DAEMON_CMD_IS_BAT_EXIST:
        {
            int is_bat_exist = 0;

            is_bat_exist = pmic_is_battery_exist();

            ret_msg->fgd_data_len += sizeof(is_bat_exist);
            memcpy(ret_msg->fgd_data,
                &is_bat_exist, sizeof(is_bat_exist));

            bm_debug(
                "[fr] FG_DAEMON_CMD_IS_BAT_EXIST = %d\n",
                is_bat_exist);
        }
        break;
    case FG_DAEMON_CMD_IS_BAT_CHARGING:
    case FG_DAEMON_CMD_GET_CHARGER_STATUS:
    case FG_DAEMON_CMD_GET_FG_HW_CAR:
    case FG_DAEMON_CMD_IS_CHARGER_EXIST:
    case FG_DAEMON_CMD_GET_INIT_FLAG:
    case FG_DAEMON_CMD_SET_INIT_FLAG:
    case FG_DAEMON_CMD_GET_TEMPERTURE:  /* fix me */
    case FG_DAEMON_CMD_GET_RAC:
    case FG_DAEMON_CMD_GET_DISABLE_NAFG:
    case FG_DAEMON_CMD_SET_DAEMON_PID:
    case FG_DAEMON_CMD_CHECK_FG_DAEMON_VERSION:
    case FG_DAEMON_CMD_GET_FG_SHUTDOWN_COND:
    case FG_DAEMON_CMD_FGADC_RESET:
    case FG_DAEMON_CMD_SEND_DATA:
    case FG_DAEMON_CMD_GET_DATA:
    case FG_DAEMON_CMD_COMMUNICATION_INT:
    case FG_DAEMON_CMD_GET_CUSTOM_SETTING:
    case FG_DAEMON_CMD_GET_PTIM_VBAT:
    case FG_DAEMON_CMD_GET_PTIM_I:
    case FG_DAEMON_CMD_GET_HW_OCV:
    case FG_DAEMON_CMD_SET_SW_OCV:
    case FG_DAEMON_CMD_SET_FG_BAT_INT1_GAP:
    case FG_DAEMON_CMD_SET_FG_BAT_INT2_HT_GAP:
    case FG_DAEMON_CMD_ENABLE_FG_BAT_INT2_HT:
    case FG_DAEMON_CMD_ENABLE_FG_BAT_INT2_LT:
    case FG_DAEMON_CMD_SET_FG_BAT_TMP_C_GAP:
    case FG_DAEMON_CMD_SET_FG_BAT_TMP_GAP:
    case FG_DAEMON_CMD_GET_SHUTDOWN_DURATION_TIME:
    case FG_DAEMON_CMD_GET_BAT_PLUG_OUT_TIME:
    case FG_DAEMON_CMD_GET_VBAT:
    case FG_DAEMON_CMD_SET_FG_RESET_RTC_STATUS:
    case FG_DAEMON_CMD_SET_IS_FG_INITIALIZED:
    case FG_DAEMON_CMD_GET_IS_FG_INITIALIZED:
    case FG_DAEMON_CMD_IS_HWOCV_UNRELIABLE:
    case FG_DAEMON_CMD_SET_FG_TIME:
    case FG_DAEMON_CMD_GET_FG_TIME:
    case FG_DAEMON_CMD_GET_ZCV:
    case FG_DAEMON_CMD_GET_FG_SW_CAR_NAFG_CNT:
    case FG_DAEMON_CMD_GET_FG_SW_CAR_NAFG_DLTV:
    case FG_DAEMON_CMD_GET_FG_SW_CAR_NAFG_C_DLTV:
    case FG_DAEMON_CMD_SET_NAG_ZCV_EN:
    case FG_DAEMON_CMD_SET_NAG_ZCV:
    case FG_DAEMON_CMD_SET_NAG_C_DLTV:
    case FG_DAEMON_CMD_SET_ZCV_INTR:
    case FG_DAEMON_CMD_SET_BAT_PLUGOUT_INTR:
    case FG_DAEMON_CMD_SET_IAVG_INTR:
    case FG_DAEMON_CMD_SET_FG_QUSE:/*useless*/
    case FG_DAEMON_CMD_SET_FG_DC_RATIO:
    case FG_DAEMON_CMD_SET_BATTERY_CYCLE_THRESHOLD:
    case FG_DAEMON_CMD_SOFF_RESET:
    case FG_DAEMON_CMD_NCAR_RESET:
    case FG_DAEMON_CMD_GET_IMIX:
    case FG_DAEMON_CMD_IS_BATTERY_CYCLE_RESET:
    case FG_DAEMON_CMD_GET_AGING_FACTOR_CUST:
    case FG_DAEMON_CMD_GET_D0_C_SOC_CUST:
    case FG_DAEMON_CMD_GET_D0_V_SOC_CUST:
    case FG_DAEMON_CMD_GET_UISOC_CUST:
    case FG_DAEMON_CMD_IS_KPOC:
    case FG_DAEMON_CMD_GET_NAFG_VBAT:
    case FG_DAEMON_CMD_GET_HW_INFO:
    case FG_DAEMON_CMD_GET_FG_CURRENT_AVG:
    case FG_DAEMON_CMD_GET_FG_CURRENT_IAVG_VALID:
    case FG_DAEMON_CMD_SET_KERNEL_SOC:
    case FG_DAEMON_CMD_SET_KERNEL_UISOC:
    case FG_DAEMON_CMD_SET_KERNEL_INIT_VBAT:
    case FG_DAEMON_CMD_SET_FG_SHUTDOWN_COND:
    case FG_DAEMON_CMD_ENABLE_FG_VBAT_L_INT:
    case FG_DAEMON_CMD_ENABLE_FG_VBAT_H_INT:
    case FG_DAEMON_CMD_SET_FG_VBAT_L_TH:
    case FG_DAEMON_CMD_SET_FG_VBAT_H_TH:
    case FG_DAEMON_CMD_SET_CAR_TUNE_VALUE:
    case FG_DAEMON_CMD_PRINT_LOG:
    case FG_DAEMON_CMD_DUMP_LOG:
    case FG_DAEMON_CMD_GET_RTC_UI_SOC:
    case FG_DAEMON_CMD_SET_RTC_UI_SOC:
    case FG_DAEMON_CMD_SET_CON0_SOC:
    case FG_DAEMON_CMD_GET_CON0_SOC:
    case FG_DAEMON_CMD_SET_NVRAM_FAIL_STATUS:
    case FG_DAEMON_CMD_GET_NVRAM_FAIL_STATUS:
    case FG_DAEMON_CMD_GET_RTC_TWO_SEC_REBOOT:
    case FG_DAEMON_CMD_GET_RTC_INVALID:
    default:
        bm_err("bad FG_DAEMON_CTRL_CMD_FROM_USER 0x%x\n", msg->fgd_cmd);
        break;
    }           /* switch() */

}

 C Code /kernel-4.14/drivers/power/supply/mediatek/battery/mtk_battery.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

static void nl_send_to_user(u32 pid, int seq, struct fgd_nl_msg_t *reply_msg)
{
    struct sk_buff *skb;
    struct nlmsghdr *nlh;
    /* int size=sizeof(struct fgd_nl_msg_t); */
    int size = reply_msg->fgd_data_len + FGD_NL_MSG_T_HDR_LEN;
    int len = NLMSG_SPACE(size);
    void *data;
    int ret;

    reply_msg->identity = FGD_NL_MAGIC;

    if (in_interrupt())
        skb = alloc_skb(len, GFP_ATOMIC);
    else
        skb = alloc_skb(len, GFP_KERNEL);

    if (!skb)
        return;

    nlh = nlmsg_put(skb, pid, seq, 0, size, 0);
    data = NLMSG_DATA(nlh);
    memcpy(data, reply_msg, size);
    NETLINK_CB(skb).portid = 0; /* from kernel */
    NETLINK_CB(skb).dst_group = 0;  /* unicast */

    ret = netlink_unicast(gm.daemo_nl_sk, skb, pid, MSG_DONTWAIT);
    if (ret < 0) {
        bm_err("[Netlink] send failed %d\n", ret);
        return;
    }
    /*bm_debug("[Netlink] reply_user: netlink_unicast- ret=%d\n", ret); */
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
netlink_kernel_create函数用于创建一个新的netlink套接字,在Linux内核中进行网络通信。它的函数原型如下: ```c struct sock *netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg); ``` 参数说明: - `net`:指定要创建套接字的网络命名空间,通常使用`&init_net`表示当前网络命名空间。 - `unit`:指定套接字的标识号,用于区分不同的netlink套接字。 - `cfg`:指向一个netlink_kernel_cfg结构体的指针,用于配置套接字的行为和属性。 netlink_kernel_cfg结构体定义如下: ```c struct netlink_kernel_cfg { unsigned int groups; void (*input)(struct sk_buff *); struct mutex *cb_mutex; struct module *module; int flags; }; ``` netlink_kernel_cfg结构体的成员说明: - `groups`:指定套接字所加入的多播组,可以使用NETLINK_GENERIC宏来表示所有多播组。 - `input`:指定一个回调函数,用于处理接收到的消息。 - `cb_mutex`:指向一个互斥锁(mutex)的指针,用于保护回调函数,可以为NULL表示不需要保护。 - `module`:指定一个内核模块(可选),用于引用模块的所有权。 - `flags`:指定套接字的标志,如NETLINK_CAP_ACK或NETLINK_EXT_ACK等。 调用netlink_kernel_create函数会返回一个指向创建的套接字(struct sock)的指针,如果创建失败,则返回NULL。 使用netlink_kernel_create函数可以在内核空间创建一个netlink套接字,用于与用户空间进行通信,实现网络管理和配置等功能。通过指定回调函数处理接收到的消息,可以实现自定义的消息处理逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值