科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道推荐:Linux用户态与内核态的交互 (8)

推荐:Linux用户态与内核态的交互 (8)

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

因为内核模块可能同时被多个进程同时调用,所以函数中使用了信号量和锁来进行互斥。skb =skb_dequeue(&sk->receive_queue)用于取得socket sk的接收队列上的消息,返回为一个struct sk_buff的结构,skb->data指向实际的netlink消息。

作者:Kendo 来源:赛迪网技术社区 2007年10月31日

关键字: 交互 内核 用户 Linux

  • 评论
  • 分享微博
  • 分享邮件
 

因为内核模块可能同时被多个进程同时调用,所以函数中使用了信号量和锁来进行互斥。skb =skb_dequeue(&sk->receive_queue)用于取得socket sk的接收队列上的消息,返回为一个struct sk_buff的结构,skb->data指向实际的netlink消息。

程序中注册了一个Netfilter钩子,钩子函数是get_icmp,它截获ICMP数据包,然后调用send_to_user函数将数据发送给应用空间进程。发送的数据是info结构变量,它是struct packet_info结构,这个结构包含了来源/目的地址两个成员。Netfilter Hook不是本文描述的重点,略过。

send_to_user 用于将数据发送给用户空间进程,发送调用的是API函数netlink_unicast 完成的:

int netlink_unicast(struct sock *sk, struct sk_buff *skb, u32 pid, int nonblock);

参数sk为函数netlink_kernel_create()返回的套接字,参数skb存放待发送的消息,它的data字段指向要发送的netlink消息结构,而skb的控制块保存了消息的地址信息, 参数pid为接收消息进程pid,参数nonblock表示该函数是否为非阻塞,如果为1,该函数将在没有接收缓存可利用时立即返回,而如果为0,该函数在没有接收缓存可利用时睡眠。

向用户空间进程发送的消息包含三个部份:netlink 消息头部、数据部份和控制字段,控制字段包含了内核发送netlink消息时,需要设置的目标地址与源地址,内核中消息是通过sk_buff来管理的, linux/netlink.h中定义了NETLINK_CB宏来方便消息的地址设置:

#define NETLINK_CB(skb)         (*(struct netlink_skb_parms*)&((skb)->cb))

例如:

NETLINK_CB(skb).pid = 0;

NETLINK_CB(skb).dst_pid = 0;

NETLINK_CB(skb).dst_group = 1;

字段pid表示消息发送者进程ID,也即源地址,对于内核,它为 0, dst_pid 表示消息接收者进程 ID,也即目标地址,如果目标为组或内核,它设置为 0,否则 dst_group 表示目标组地址,如果它目标为某一进程或内核,dst_group 应当设置为 0。

static int send_to_user(struct packet_info *info)

{

int ret;

int size;

unsigned char *old_tail;

struct sk_buff *skb;

struct nlmsghdr *nlh;

struct packet_info *packet;

/*计算消息总长:消息首部加上数据加度*/

size = NLMSG_SPACE(sizeof(*info));

/*分配一个新的套接字缓存*/

skb = alloc_skb(size, GFP_ATOMIC);

old_tail = skb->tail;

/*初始化一个netlink消息首部*/

nlh = NLMSG_PUT(skb, 0, 0, IMP2_K_MSG, size-sizeof(*nlh));

/*跳过消息首部,指向数据区*/

packet = NLMSG_DATA(nlh);

/*初始化数据区*/

memset(packet, 0, sizeof(struct packet_info));

/*填充待发送的数据*/

packet->src = info->src;

packet->dest = info->dest;

/*计算skb两次长度之差,即netlink的长度总和*/

nlh->nlmsg_len = skb->tail - old_tail;

/*设置控制字段*/

NETLINK_CB(skb).dst_groups = 0;

/*发送数据*/

read_lock_bh(&user_proc.lock);

ret = netlink_unicast(nlfd, skb, user_proc.pid, MSG_DONTWAIT);

read_unlock_bh(&user_proc.lock);

}

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章