ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

genl netlink

2022-02-25 14:01:14  阅读:189  来源: 互联网

标签:netlink return struct family na len genl msg


kernel

/* file : genl_kernel.c
 * kernel module for test genetlink
 * sudochen@163.com
 *
 */
#include <linux/init.h>
#include <linux/module.h>
#include <net/genetlink.h>

static int cmd_echo(struct sk_buff *skb_2, struct genl_info *info);

enum {
    CMD_NONE,
    CMD_ECHO,
    CMD_MAX
};

static struct genl_family cmd_genl_family = {
    .id = GENL_ID_GENERATE,
    .hdrsize = 0,
    .name = "cmd",
    .version = 1,
    .maxattr = CMD_MAX,
};
    
static struct nla_policy cmd_nla_policy[CMD_MAX + 1] = {
    [CMD_NONE] = {
            .type = NLA_UNSPEC,
    },
    [CMD_ECHO] = {
            .type = NLA_STRING,
            .len = 0x100,
    },
};

static struct genl_ops cmd_ops[] = {
    {
        .cmd = CMD_ECHO,
        .flags = 0,
        .policy = cmd_nla_policy,
        .doit = cmd_echo,
        .dumpit = NULL,
    }
};

static int cmd_echo(struct sk_buff *skb_2, struct genl_info *info)
{
    struct nlattr *attr = NULL;
    struct sk_buff *skb = NULL;
    int ret = -1;
    char *data;
    char *head;
    if (NULL == info) {
        return -1;
    }
    
    attr = info->attrs[CMD_ECHO];
    if (attr) {
        data = (char*)nla_data(attr);
        if (data) {
            printk("genl recv data %s\n",data);
        } else {
            printk("genl recv data NULL\n");
        }
    } else {
        printk("no attr %d\n",CMD_ECHO);    
    }   
    
    skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
    if (NULL == skb) {
        goto out;    
    }
    head = genlmsg_put(skb, 0, info->snd_seq+1,&cmd_genl_family,0,CMD_ECHO);
    if (NULL == head) {
        goto out;    
    }
    ret = nla_put_string(skb, CMD_ECHO, "hello world form kernel space");
    if (ret)
        goto out;
    genlmsg_end(skb,head);
    ret = genlmsg_unicast(&init_net,skb,info->snd_pid);
    if (ret)
        goto out;
    
    return 0;
 out:
    printk("genl an error ocured\n");
    return -1;
}
int __init cmd_init(void) 
{
    int error;
    error = genl_register_family_with_ops(&cmd_genl_family, cmd_ops, ARRAY_SIZE(cmd_ops));
    if (error) {
        printk("register family error\n");
        return error;
    }
    printk("register family ok\n");
    return 0;

}

void __exit cmd_exit(void)
{
    genl_unregister_family(&cmd_genl_family);
    printk("unregister family ok\n");
}
    
MODULE_LICENSE("GPL");
module_init(cmd_init);
module_exit(cmd_exit);

Makefile

KERNELDIR := /usr/src/kernels/2.6.32-358.el6.i686


obj-m += genl_kernel.o

modules:
	make -C $(KERNELDIR) M=$(PWD) $@
clean:
	make -C $(KERNELDIR) M=$(PWD) $@

user

/* file : genl_user.c
 * test for genetlink in user space
 * sudochen@163.com
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <poll.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <signal.h>
#include <linux/netlink.h>
#include <linux/genetlink.h>

// copy from kernel module source
enum {
    CMD_NONE,
    CMD_ECHO,
    CMD_MAX
};

struct msgtemplate {
    struct nlmsghdr n;
    struct genlmsghdr g;
    char buf[256];
};

#define NLA_DATA(na)        ((void *)((char*)(na) + NLA_HDRLEN))
#define GENLMSG_DATA(glh)   ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))

/*
 * Create a raw netlink socket and bind
 */
static int create_nl_socket(int protocol, int groups)
{
    socklen_t addr_len;
    int fd;
    struct sockaddr_nl local;
        
    fd = socket(AF_NETLINK, SOCK_RAW, protocol);
    if (fd < 0){
		perror("socket");
        return -1;
    }

    memset(&local, 0, sizeof(local));
    local.nl_family = AF_NETLINK;
    local.nl_groups = groups;
    if (bind(fd, (struct sockaddr *) &local, sizeof(local)) < 0)
        goto error;
        
    return fd;
 error:
    close(fd);
    return -1;
}

/*
 * Send netlink message to kernel
 */
int sendto_fd(int s, const char *buf, int bufLen)
{
    struct sockaddr_nl nladdr;
    int r;
        
    memset(&nladdr, 0, sizeof(nladdr));
    nladdr.nl_family = AF_NETLINK;
        
    while ((r = sendto(s, buf, bufLen, 0, (struct sockaddr *) &nladdr,
                sizeof(nladdr))) < bufLen) {
        if (r > 0) {
            buf += r;
            bufLen -= r;
        } else if (errno != EAGAIN)
            return -1;
        }
        return 0;
}


/*
 * Probe the controller in genetlink to find the family id
 * for the CONTROL_EXMPL family
 */
int get_family_id(int sd, char *family)
{
    struct msgtemplate msg;
    struct msgtemplate out;
    int id;
    struct nlattr *na;
    int rep_len;

    memset(&msg, 0x00, sizeof(msg));
    memset(&out, 0x00, sizeof(out));


    /* Get family name */
    msg.n.nlmsg_type = GENL_ID_CTRL;
    msg.n.nlmsg_flags = NLM_F_REQUEST;
    msg.n.nlmsg_seq = 0;
    msg.n.nlmsg_pid = getpid();
    msg.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
    
    msg.g.cmd = CTRL_CMD_GETFAMILY;
    msg.g.version = 0x1;
        
    na = (struct nlattr *) GENLMSG_DATA(&msg);
    na->nla_type = CTRL_ATTR_FAMILY_NAME;
    na->nla_len = strlen(family) + 1 + NLA_HDRLEN;
    strcpy((char *)NLA_DATA(na),(const char *)family);
       
    msg.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);

    if (sendto_fd(sd, (char *) &msg, msg.n.nlmsg_len) < 0)
		return -1;
    
	rep_len = recv(sd, &out, sizeof(out), 0);
    if (rep_len < 0){
		perror("recv");
		return -1;
	}
    printf("recv from netlink socket len is %d\n",rep_len);

    /* Validate response message */
    if (!NLMSG_OK((&out.n), rep_len)){
        fprintf(stderr, "invalid reply message\n");
		return -1;
	}

    if (out.n.nlmsg_type == NLMSG_ERROR) { /* error */
        fprintf(stderr, "received error\n");
        return -1;
    }

    na = (struct nlattr *) GENLMSG_DATA(&out);
    // because the first params is CTRL_ATTR_FAMILY_NAME, 
    // we wanna the CTRL_ATTR_FAMILY_ID,
    // so skip one ATTR
    na = (struct nlattr *)((char*)na + NLA_ALIGN(na->nla_len));
    if (na->nla_type == CTRL_ATTR_FAMILY_ID) {
        id = *(__u16 *) NLA_DATA(na);
        printf("get CTRL_ATTR_FAMILY_ID %d\n",id);
    }
    return id;
}

int main(int argc, char **argv)
{
    int nl_sd = -1;
    int id = -1;
    struct msgtemplate msg;
    struct msgtemplate out;
    struct nlattr *na = NULL;
    int rep_len = -1;
    char *resp;

    memset(&out, 0x00, sizeof(out));
    memset(&msg, 0x00, sizeof(msg));

    nl_sd = create_nl_socket(NETLINK_GENERIC,0);
    if(nl_sd < 0){
        printf("create failure\n");
        return -1;;
    }
    id = get_family_id(nl_sd,"cmd");
    if (id < 0) {
        printf("get family id by name error\n");
        close(nl_sd);
        return -1;
    }

    printf("get family id is %d\n",id);

    msg.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
    msg.n.nlmsg_type = id;
    msg.n.nlmsg_flags = NLM_F_REQUEST;
    msg.n.nlmsg_seq = 0;
    msg.n.nlmsg_pid = getpid();
    msg.g.cmd = CMD_ECHO;

    na = (struct nlattr*) GENLMSG_DATA(&msg);
    na->nla_type = CMD_ECHO;
    na->nla_len = strlen("123") + NLA_HDRLEN + 1;
    memcpy(NLA_DATA(na), "123", na->nla_len);
    
    msg.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);

    if (sendto_fd(nl_sd, (char *) &msg, msg.n.nlmsg_len) < 0) {
	    perror("sendto");
        close(nl_sd);
    	return -1;
    }

	rep_len = recv(nl_sd, &out, sizeof(out), 0);
    if (rep_len < 0){
		perror("recv");
        close(nl_sd);
		return -1;
    }
    printf("genl rep_len is %d\n",rep_len);
    
    if (!NLMSG_OK((&out.n),rep_len)) {
        perror("recv len");
        close(nl_sd);
        return -1;
    }

    if (out.n.nlmsg_type == NLMSG_ERROR) {
        perror("recv nlmsg_type error");
        close(nl_sd);
        return -1;
    }
    
    na = (struct nlattr *) GENLMSG_DATA(&out);
    if (na->nla_type == CMD_ECHO) {
        resp = NLA_DATA(na);
        if (resp) {
            printf("kernel : %s\n", resp);
        }
    }
    return 0;
}


 

标签:netlink,return,struct,family,na,len,genl,msg
来源: https://www.cnblogs.com/sudochen/p/15935764.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有