ImageVerifierCode 换一换
格式:DOCX , 页数:30 ,大小:61.23KB ,
资源ID:8988495      下载积分:10 金币
快捷注册下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

开通VIP
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.zixin.com.cn/docdown/8988495.html】到电脑端继续下载(重复下载【60天内】不扣币)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

开通VIP折扣优惠下载文档

            查看会员权益                  [ 下载后找不到文档?]

填表反馈(24小时):  下载求助     关注领币    退款申请

开具发票请登录PC端进行申请

   平台协调中心        【在线客服】        免费申请共赢上传

权利声明

1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前可先查看【教您几个在下载文档中可以更好的避免被坑】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时联系平台进行协调解决,联系【微信客服】、【QQ客服】,若有其他问题请点击或扫码反馈【服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【版权申诉】”,意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:0574-28810668;投诉电话:18658249818。

注意事项

本文(linux内核通信-netlink.docx)为本站上传会员【pc****0】主动上传,咨信网仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知咨信网(发送邮件至1219186828@qq.com、拔打电话4009-655-100或【 微信客服】、【 QQ客服】),核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载【60天内】不扣币。 服务填表

linux内核通信-netlink.docx

1、一、Netlink介绍 前面有一篇文章其实已经介绍过Netlink方面的知识,还有一个内核和用户空间之间的一个交互例子,这篇文章主要是更细节和基础的知识介绍! Netlink 是一种特殊的 socket,它是 Linux 所特有的,由于传送的消息是暂存在socket接收缓存中,并不被接收者立即处理,所以netlink是一种异步通信机制。 系统调用和 ioctl 则是同步通信机制。 用户空间进程可以通过标准socket API来实现消息的发送、接收,在Linux中,有很多用户空间和内核空间的交互都是通过Netlink机制完成的,在Linux3.0的内核版本中定义了下面的21个用于Netl

2、ink通信的宏,其中默认的最大值为32.我这里重点关注的是IPv6路由部分的通信过程。   在include/linux/`netlink.h文件中定义了下面的用于通信的宏! #define NETLINK_ROUTE        0    /* Routing/device hook */ #define NETLINK_UNUSED       1    /* Unused number  */ #define NETLINK_USERSOCK     2    /* Reserved for user mode socket protocols*/ #define NETLI

3、NK_FIREWALL     3    /* Firewalling hook  */ #define NETLINK_INET_DIAG    4    /* INET socket monitoring  */ #define NETLINK_NFLOG        5    /* netfilter/iptables ULOG */ #define NETLINK_XFRM         6    /* ipsec */ #define NETLINK_SELINUX      7    /* SELinux event notifications */ #define

4、NETLINK_ISCSI        8    /* Open-iSCSI */ #define NETLINK_AUDIT        9    /* auditing */ #define NETLINK_FIB_LOOKUP   10     #define NETLINK_CONNECTOR    11 #define NETLINK_NETFILTER    12    /* netfilter subsystem */ #define NETLINK_IP6_FW       13 #define NETLINK_DNRTMSG      14    /* DEC

5、net routing messages */ #define NETLINK_KOBJECT_UEVENT    15    /* Kernel messages to userspace */ #define NETLINK_GENERIC      16 /* leave room for NETLINK_DM (DM Events) */ #define NETLINK_SCSITRANSPORT     18    /* SCSI Transports */ #define NETLINK_ECRYPTFS    19 #define NETLINK_RDMA       

6、 20 #define MAX_LINKS 32 二、Socket API 用户态可以使用标准的socket APIs, socket(), bind(), sendmsg(), recvmsg() 和 close() 等函数就能很容易地使用 netlink socket,我们在用户空间可以直接通过socket函数来使用Netlink通信,例如可以通过下面的方式: 1、socket sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 说明:第一个参数必须是 AF_NETLINK 或 PF_NETLINK,在 Linux 中,

7、它们俩实际为一个东西,它表示要使用netlink,第二个参数必须是SOCK_RAW或SOCK_DGRAM, 第三个参数指定netlink协议类型,可以是自己在netlink.h中定义的,也可以是内核中已经定义好的。上面的例子使用主要是路由的Netlink协议。也可以是上面21中协议类型的其中之一。 NETLINK_GENERIC是一个通用的协议类型,它是专门为用户使用的,因此,用户可以直接使用它,而不必再添加新的协议类型。 对于每一个netlink协议类型,可以使用多播的概念,最多可以有 32个多播组,每一个多播组用一个位表示,netlink 的多播特性使得发送消息给同一个组仅需要一次系统

8、调用,因而对于需要多播消息的应用而言,大大地降低了系统调用的次数。 下面介绍一下主要的数据结构: struct sockaddr_nl {     sa_family_t    nl_family;    /* AF_NETLINK    */     unsigned short  nl_pad;      /* zero        */     __u32        nl_pid;        /* port ID    */    __u32        nl_groups;     /* multicast groups mask */ }; 说明: 1

9、 sa_family_t nl_family; 一般为AF_NETLINK, 2) unsigned short nl_pad; 字段 nl_pad 当前没有使用,因此要总是设置为 0。 3) __u32 nl_pid;  绑定时用于指定绑定者的进程号,发送消息时用于指定接收进程号,如果希望内核处理多播消息,就把该字段设置为 0,否则设置为处理消息的进程 ID。传递给 bind 函数的地址的 nl_pid 字段应当设置为本进程的进程 ID,这相当于 netlink socket 的本地地址。但是,对于一个netlink socket 的情况,字段 nl_pi

10、d 则可以设置为其它的值,如: pthread_self() << 16 | getpid(); 因此字段 nl_pid 实际上未必是进程 ID,它只是用于区分不同的接收者或发送者的一个标识,用户可以根据自己需要设置该字段。 4) __u32 nl_groups;    绑定时用于指定绑定者所要加入的多播组,这样绑定者就可以接收多播消息,发送 消息时可以用于指定多播组,这样就可以将消息发给多个接收者。这里nl_groups 为32位的无符号整形,所以可以指定32个多播组,每个进程可以加入多个多播组, 因为多播组是通过“或”操作,如果设置为 0,表示调用者不加入任何多播组。这里就

11、是Netlink多播的概念!和通信中的多播概念有点类似。 2、bind Bind的调用方式如下! struct sockaddr_nl snl; memset (&snl, 0, sizeof snl); snl.nl_family = AF_NETLINK; snl.nl_groups = groups; ret = bind (sock, (struct sockaddr *) &snl, sizeof snl); 其中sock为前面的 socket 调用返回的文件描述符,参数snl为 struct sockaddr_nl 类型的地址。 为了发送一个 netlink

12、消息给内核或其他用户态应用,需要填充目标 netlink socket 地址 ,此时,字段 nl_pid 和 nl_groups 分别表示接收消息者的进程 ID 与多播组。如果字段 nl_pid 设置为 0,表示消息接收者为内核或多播组,如果 nl_groups为 0,表示该消息为单播消息,否则表示多播消息。 3、sendmsg 用户态使用函数 sendmsg 发送 netlink 消息时还需要引用结构 struct msghdr、struct nlmsghdr 和 struct iovec,结构 struct msghdr 的定义如下: struct msghdr {     vo

13、id * msg_name;    /* Socket name */     int msg_namelen;    /* Length of name  */     struct iovec * msg_iov;    /* Data blocks   */     __kernel_size_t msg_iovlen;    /* Number of blocks */     void * msg_control;  /* Per protocol magic (eg BSD file descriptor passing) */     __kernel_size_t m

14、sg_controllen;    /* Length of cmsg list */     unsigned msg_flags; }; 使用方法如下: struct msghdr msg; memset(&msg, 0, sizeof(msg)); msg.msg_name = (void *)&(snl); msg.msg_namelen = sizeof(snl); struct nlmsghdr 为 netlink socket 自己的消息头,因此它也被称为netlink 控制块。应用层在向内核发送 netlink 消息时必须提供该控制头。 消息头 struct

15、 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 PID */ }; 字段 nlmsg_len 指定

16、消息的总长度,包括紧跟该结构的数据部分长度以及该结构的大小,字段 nlmsg_type 用于应用内部定义消息的类型,它对netlink 内核实现是透明的,因此大部分情况下设置为 0,字段 nlmsg_seq 和 nlmsg_pid 用于应用追踪消息,前者表示顺序号,后者为消息来源进程 ID。字段 nlmsg_flags 用于设置消息标志,可用的标志包括下面的宏定义:kernel/include/linux/netlink.c /* Flags values */ #define NLM_F_REQUEST  1    /* It is request message. */ #defin

17、e NLM_F_MULTI  2    /* Multipart message, terminated by NLMSG_DONE */ #define NLM_F_ACK   4    /* Reply with ack, with zero or error code */ #define NLM_F_ECHO  8    /* Echo this request */ /* Modifiers to GET request */ #define NLM_F_ROOT    0x100    /* specify tree root*/ #define NLM_F_MATCH 

18、   0x200    /* return all matching*/ #define NLM_F_ATOMIC    0x400    /* atomic GET   */ #define NLM_F_DUMP    (NLM_F_ROOT|NLM_F_MATCH) /* Modifiers to NEW request */ #define NLM_F_REPLACE    0x100    /* Override existing  */ #define NLM_F_EXCL    0x200    /* Do not touch, if it exists  */ #de

19、fine NLM_F_CREATE    0x400    /* Create, if it does not exist */ #define NLM_F_APPEND    0x800    /* Add to end of list  */ 标志NLM_F_REQUEST用于表示消息是一个请求,所有应用首先发起的消息都应设置该标志。 标志NLM_F_MULTI 用于指示该消息是一个多部分消息的一部分,后续的消息可以通过宏NLMSG_NEXT来获得。 宏NLM_F_ACK表示该消息是前一个请求消息的响应,顺序号与进程ID可以把请求与响应关联起来。 标志NLM_F_ECHO表示该消

20、息是相关的一个包的回传。 标志NLM_F_ROOT 被许多 netlink 协议的各种数据获取操作使用,该标志指示被请求的数据表应当整体返回用户应用,而不是一个条目一个条 地返回。有该标志的请求通常导致响应消息设置 NLM_F_MULTI标志。注意,当设置了该标志时,请求是协议特定的,因此,需要在字段 nlmsg_type 中指定协议类型。 标志 NLM_F_MATCH 表示该协议特定的请求只需要一个数据子集,数据子集由指定的协议特定的过滤器来匹配。 标志 NLM_F_ATOMIC 指示请求返回的数据应当原子地收集,这预防数据在获取期间被修改。 标志 NLM_F_DUMP 未实现。

21、 标志 NLM_F_REPLACE 用于取代在数据表中的现有条目。 标志 NLM_F_EXCL_ 用于和 CREATE 和 APPEND 配合使用,如果条目已经存在,将失败。 标志 NLM_F_CREATE 指示应当在指定的表中创建一个条目。 标志 NLM_F_APPEND 指示在表末尾添加新的条目。 内核需要读取和修改这些标志,对于一般的使用,用户把它设置为 0 就可以,只是一些高级应用(如 netfilter 和路由 daemon 需要它进行一些设置), 下面是在调用sendmsg函数之前的各个结构体的赋值操作: struct nlmsghdr *n struct iov

22、ec iov = { (void*) n, n->nlmsg_len }; struct msghdr msg = {(void*) &snl, sizeof snl, &iov, 1, NULL, 0, 0}; 其中snl为 struct sockaddr_nl snl;在结构体struct msghdr中包含有struct iovec结构,其实就是我们要传输的数据块,它为一个指针,定义了数据块的基址和长度。 struct iovec{     void __user * iov_base;    /* BSD uses caddr_t (1003.1g requires void

23、 *) */     __kernel_size_t iov_len; /* Must be size_t (1003.1g) */ }; 上面的数据结构全部初始化以后就可以调用sendmsg函数进行发送操作了。 status = sendmsg (sock, &msg, 0); 其中sock就是我们创建的sock套接字,msg就是上面结构体struct msghdr的实例。如果我们需要返回一个ACK消息,可以对flags标志进行设置如下: /* Request an acknowledgement by setting NLM_F_ACK */ n->nlmsg_flags |

24、 NLM_F_ACK; 4、recvmsg 使用下面的函数进行接收处理时,status;为返回的状态,这里可能的结果为: #define NLMSG_NOOP        0x1    /* Nothing.        */ #define NLMSG_ERROR       0x2    /* Error        */ #define NLMSG_DONE        0x3    /* End of a dump    */ #define NLMSG_OVERRUN      0x4    /* Data lost     int status; char

25、 buf[4096]; struct iovec iov = { buf, sizeof buf }; struct sockaddr_nl snl; struct msghdr msg = { (void*)&snl, sizeof snl, &iov, 1, NULL, 0, 0}; struct nlmsghdr *h; status = recvmsg (sock, &msg, 0); 在linux/netlink.h中定义了一些方便对消息进行处理的宏,这些宏包括: #define NLMSG_ALIGNTO 4 #define NLMSG_ALIGN(len) ( (

26、len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) ) /*宏NLMSG_ALIGN(len)用于得到不小于len且字节对齐的最小数值*/ #define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) #define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN)) /*宏NLMSG_LENGTH(len)用于计算数据部分长度为len时实际的消息长度。它一般用于分配消息缓存*/ #define NLMSG_SPACE(len)

27、 NLMSG_ALIGN(NLMSG_LENGTH(len)) /*宏NLMSG_SPACE(len)返回不小于NLMSG_LENGTH(len)且字节对齐的最小数值,它也用于分配消息缓存*/ #define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0))) /*宏NLMSG_DATA(nlh)用于取得消息的数据部分的首地址,设置和读取消息数据部分时需要使用该宏*/ #define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \ (stru

28、ct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len))) /*宏NLMSG_NEXT(nlh,len)用于得到下一个消息的首地址,同时len也减少为剩余消息的总长度,该宏一般在一个消息被分成几个部分发送或接收时使用*/ #define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \ (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \ (nlh)->nlmsg_len <= (

29、len)) /*宏NLMSG_OK(nlh,len)用于判断消息是否有len这么长*/ #define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len))) /*宏NLMSG_PAYLOAD(nlh,len)用于返回payload的长度*/ 在/kernel/net/netlink/af_netlink.c文件中定义了netlink套接字的结构体 struct netlink_sock {     /* struct sock has to be the first member of netlink_sock

30、 */     struct sock        sk;     u32            pid; //内核自己的pid,=0     u32            dst_pid;     u32            dst_group;//目的组     u32            flags;     u32            subscriptions;     u32            ngroups;// 组数量     unsigned long        *groups; //组号     unsigned long        s

31、tate;     wait_queue_head_t    wait;// 进程在接收数据包时等待队列     struct netlink_callback    *cb;     spinlock_t        cb_lock;     void     (*data_ready)(struct sock *sk, int bytes); ///内核态接收到用户态信息后的处理函数     struct module        *module; }; 5、netlink协议注册 在af_netlink.c文件中我们可以看到netlink协议的注册 static s

32、truct proto netlink_proto = {     .name     = "NETLINK",     .owner     = THIS_MODULE,     .obj_size = sizeof(struct netlink_sock), }; 在static int __init netlink_proto_init(void)函数中会调用注册协议的函数,对netlink协议进行注册,其中,netlink_proto就是上面的struct proto netlink_proto协议。 int err = proto_register(&netlink_pr

33、oto, 0); 三、内核中的处理流程 这里我以路由中的netlink为例,看一下内核中的处理流程是怎么样的! 1、skb 在内核中接收的数据和存储发送的数据都是放在了skb_buff的结构体中 struct netlink_skb_parms {     struct ucred     creds;        /* Skb credentials */     __u32            pid;     __u32            dst_pid;     __u32            dst_group;     kernel_cap_t 

34、    eff_cap;     __u32            loginuid;    /* Login (audit) uid */ }; 使用下面的宏获取skb_bff中的数据部分 #define NETLINK_CB(skb) (*(struct netlink_skb_parms*)&((skb)->cb)) 2、接收 在/kernel/net/core/rtnetlink.c文件中,有一个接收从用户空间过来的Netlink消息的函数。 static void rtnetlink_rcv(struct sock *sk, int len) {     unsig

35、ned int qlen = 0;     do {         rtnl_lock();         netlink_run_queue(sk, &qlen, &rtnetlink_rcv_msg);         up(&rtnl_sem);         netdev_run_todo();     } while (qlen); } 上面的内核函数就是用来接收用户路由方面Netlink消息的,当我们使用route命令添加一条路由时,就会调用该函数接收。该函数是在netlink的初始化是注册的。 同样在rtnetlink.c文件中。 void __init

36、 rtnetlink_init(void) { int i; rtattr_max = 0; for (i = 0; i < ARRAY_SIZE(rta_max); i++) if (rta_max[i] > rtattr_max) rtattr_max = rta_max[i]; rta_buf = kmalloc(rtattr_max * sizeof(struct rtattr *), GFP_KERNEL); if (!rta_buf) panic("rtnetlink_init: cannot allocate rta_buf\n"); //在创建内核的netl

37、ink时,注册了路由netlink的接收函数,rtnetlink_rcv. rtnl = netlink_kernel_create(NETLINK_ROUTE, RTNLGRP_MAX, rtnetlink_rcv,THIS_MODULE); if (rtnl == NULL) panic("rtnetlink_init: cannot initialize rtnetlink\n"); netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV); register_netdevice_notifier(&rtnetlink_dev_no

38、tifier); rtnetlink_links[PF_UNSPEC] = link_rtnetlink_table; rtnetlink_links[PF_PACKET] = link_rtnetlink_table; } 在netlink_kernel_create函数中,可以看到内核接收用户空间传过来的消息的接收函数, struct sock * netlink_kernel_create(int unit, unsigned int groups,                       void (*input)(struct sock *sk, int len),

39、                       struct module *module) {     struct socket *sock;     struct sock *sk;     struct netlink_sock *nlk;     if (!nl_table)         return NULL;     if (unit<0 || unit>=MAX_LINKS)         return NULL;     if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock))     

40、    return NULL;     if (__netlink_create(sock, unit) < 0)         goto out_sock_release;     sk = sock->sk;     sk->sk_data_ready = netlink_data_ready; if (input) nlk_sk(sk)->data_ready = input; //设置内核接收Netlink消息的函数,这里就是前面的rtnetlink_rcv函数     if (netlink_insert(sk, 0))         goto out_soc

41、k_release;     nlk = nlk_sk(sk); //取得sock嵌入的netlink_sock结构体     nlk->flags |= NETLINK_KERNEL_SOCKET;     netlink_table_grab();     nl_table[unit].groups = groups < 32 ? 32 : groups;     nl_table[unit].module = module;     nl_table[unit].registered = 1; // 更新netlink_table结构体信息,每中协议对应一个netl

42、ink_table结构     netlink_table_ungrab();     return sk; out_sock_release:     sock_release(sock);     return NULL; } 到此,内核创建netlink到接收用户空间发送过来消息整个流程就清晰了。 3、处理 当我们添加一条新路由时,在接收函数rtnetlink_rcv中的循环中,会从一个队列中调用实际的接收处理函数,这里为rtnetlink_rcv_msg函数。 /**  * nelink_run_queue - Process netlink receive

43、queue.  * @sk: Netlink socket containing the queue  * @qlen: Place to store queue length upon entry  * @cb: Callback function invoked for each netlink message found  *  * Processes as much as there was in the queue upon entry and invokes  * a callback function for each netlink message found. T

44、he callback  * function may refuse a message by returning a negative error code  * but setting the error pointer to 0 in which case this function  * returns with a qlen != 0.  *  * qlen must be initialized to 0 before the initial entry, afterwards  * the function may be called repeatedly until

45、 qlen reaches 0.  */ void netlink_run_queue(struct sock *sk, unsigned int *qlen, int (*cb)(struct sk_buff *, struct nlmsghdr *, int *)) {     struct sk_buff *skb;     if (!*qlen || *qlen > skb_queue_len(&sk->sk_receive_queue))         *qlen = skb_queue_len(&sk->sk_receive_queue);     for (

46、 *qlen; (*qlen)--) {         skb = skb_dequeue(&sk->sk_receive_queue);         if (netlink_rcv_skb(skb, cb)) {             if (skb->len)                 skb_queue_head(&sk->sk_receive_queue, skb);             else {                 kfree_skb(skb);                 (*qlen)--;             }  

47、           break;         }         kfree_skb(skb);     } } 下面是rtnetlink_rcv_msg()函数的实现,对netlink消息进行相应的处理。其中有一个数据结构struct rtnetlink_link *link; 其定义如下:是两个不同的处理函数 struct rtnetlink_link {     int (*doit)(struct sk_buff *, struct nlmsghdr*, void *attr);     int (*dumpit)(struct sk_buff *, struc

48、t netlink_callback *cb); }; /* Process one rtnetlink message. */ static __inline__ int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) {     struct rtnetlink_link *link;     struct rtnetlink_link *link_tab;     int sz_idx, kind;     int min_len;     int family;    

49、 int type;     int err;     /* Only requests are handled by kernel now */     if (!(nlh->nlmsg_flags&NLM_F_REQUEST))         return 0; type = nlh->nlmsg_type;     /* A control message: ignore them */     if (type < RTM_BASE)         return 0;     /* Unknown message: reply with EINVAL

50、/     if (type > RTM_MAX)         goto err_inval; type -= RTM_BASE;     /* All the messages must have at least 1 byte length */     if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtgenmsg)))         return 0;     family = ((struct rtgenmsg*)NLMSG_DATA(nlh))->rtgen_family;     if (family

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服