我正在尝试使用通用网络链接将嵌套属性从用户空间发送到内核,函数nl_send_auto()
返回52(这应该是发送给内核的字节数),但是内核没有接收到消息。我的方法有问题吗?这是我在用户空间上编写的代码:
int err = -1;
struct nl_msg *msg;
struct nlattr *attr;
struct nl_sock *sock;
int family;
int send = 0;
if ((sock = nl_socket_alloc()) == NULL)
return err;
if ((err = genl_connect(sock)))
return err;
if ((family = genl_ctrl_resolve(sock, FAMILY)) < 0)
return family;
if ((msg = nlmsg_alloc()) == NULL)
return err;
if ((genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, FAMILY, 0,
NLM_F_REQUEST, CREATE_STATE, 1)) == NULL)
return err;
if (!(attr = nla_nest_start(msg, KLUA_NL_STATE))){
nla_nest_cancel(msg, attr);
return err;
}
if ((ret = nla_put_string(msg, STATE_NAME, cmd->name)) ||
(ret = nla_put_u32(msg, MAX_ALLOC, cmd->maxalloc)) ||
(ret = nla_put_u32(msg, CURR_ALLOC, cmd->curralloc))
)
return err;
nla_nest_end(msg, attr);
if ((send = nl_send_auto(ctrl->sock, msg)) < 0)
return send;
printf("All done sended %d bytes\n", send);
nlmsg_free(msg);
此代码显示52,这是发送到内核的字节;
FAMILY宏定义为(在内核空间和用户空间中):
#define FAMILY "family"
我的netlink属性是(用于内核和用户空间):
enum {
KLUA_NL_STATE,
STATE_NAME,
MAX_ALLOC,
CURR_ALLOC,
ATTR_COUNT,
#define ATTR_MAX (ATTR_COUNT - 1)
};
我的操作清单是:
enum {
CREATE_STATE = 16,
};
我的内核代码是:
struct nla_policy lunatik_policy[ATTR_MAX] = {
[KLUA_NL_STATE] = { .type = NLA_NESTED },
};
static int klua_create_state(struct sk_buff *buff, struct genl_info *info);
static const struct genl_ops l_ops[] = {
{
.cmd = CREATE_STATE,
.doit = klua_create_state,
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,2,0)
/*Before kernel 5.2.0, each operation has its own policy*/
.policy = lunatik_policy
#endif
},
};
#define KLUA_NL_STATE_ATTRS_COUNT 3
struct genl_family lunatik_family = {
.name = FAMILY,
.version = 1,
.maxattr = ATTR_MAX,
.netnsok = true,
.policy = lunatik_policy,
.module = THIS_MODULE,
.ops = l_ops,
.n_ops = ARRAY_SIZE(l_ops),
};
static int klua_create_state(struct sk_buff *buff, struct genl_info *info)
{
pr_info("I received the message\n");
return 0;
}
此代码不会在dmesg上打印任何内容,我想知道为什么。
答案 0 :(得分:0)
在Linux 5.2重构期间,NLA_F_NESTED
标志的语义有所变化。看来您现在需要在致电nla_nest_start()
时始终将其包括在内:
if (!(attr = nla_nest_start(msg, KLUA_NL_STATE))){
...
}
应该是
if (!(attr = nla_nest_start(msg, NLA_F_NESTED | KLUA_NL_STATE))){
...
}
是的,我很清楚libnl库显然应该为您执行此操作,也许将来会这样做,但是很遗憾,这就是我们现在的情况。
也:
enum {
KLUA_NL_STATE,
...
};
属性零始终保留。您需要将其更改为
enum {
KLUA_NL_STATE = 1,
...
};
仅供参考:操作0也已保留,因此很幸运您选择了16。但是将来请记住这一点。
这些可能只是复制粘贴错误,但无论如何我还是将它们包括在内,以使登陆此页面的其他人都可以找到示例。
if ((genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, FAMILY, 0,
NLM_F_REQUEST, CREATE_STATE, 1)) == NULL)
return err;
应该是
if ((genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, family, 0,
NLM_F_REQUEST, CREATE_STATE, 1)) == NULL)
return err;
也:
if ((ret = nla_put_string(msg, STATE_NAME, cmd->name)) ||
(ret = nla_put_u32(msg, MAX_ALLOC, cmd->maxalloc)) ||
(ret = nla_put_u32(msg, CURR_ALLOC, cmd->curralloc))
)
return err;
应该是
if ((err = nla_put_string(msg, STATE_NAME, cmd->name)) ||
(err = nla_put_u32(msg, MAX_ALLOC, cmd->maxalloc)) ||
(err = nla_put_u32(msg, CURR_ALLOC, cmd->curralloc))
)
return err;
也:
if ((send = nl_send_auto(ctrl->sock, msg)) < 0)
return send;
应该是
if ((send = nl_send_auto(sock, msg)) < 0)
return send;