亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 16121 | 回復(fù): 3
打印 上一主題 下一主題

Linux 用戶態(tài)與內(nèi)核態(tài)的交互——netlink 篇 [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2006-09-03 22:14 |只看該作者 |倒序?yàn)g覽
Linux 用戶態(tài)與內(nèi)核態(tài)的交互
——netlink 篇


作者:Kendo
2006-9-3

這是一篇學(xué)習(xí)筆記,主要是對《Linux 系統(tǒng)內(nèi)核空間與用戶空間通信的實(shí)現(xiàn)與分析》中的源碼imp2的分析。其中的源碼,可以到以下URL下載:
http://www-128.ibm.com/developerworks/cn/linux/l-netlink/imp2.tar.gz

參考文檔
《Linux 系統(tǒng)內(nèi)核空間與用戶空間通信的實(shí)現(xiàn)與分析》                陳鑫
http://www-128.ibm.com/developerworks/cn/linux/l-netlink/?ca=dwcn-newsletter-linux
《在 Linux 下用戶空間與內(nèi)核空間數(shù)據(jù)交換的方式》                楊燚
http://www-128.ibm.com/developerworks/cn/linux/l-kerns-usrs/

理論篇
        在 Linux 2.4 版以后版本的內(nèi)核中,幾乎全部的中斷過程與用戶態(tài)進(jìn)程的通信都是使用 netlink 套接字實(shí)現(xiàn)的,例如iprote2網(wǎng)絡(luò)管理工具,它與內(nèi)核的交互就全部使用了netlink,著名的內(nèi)核包過濾框架Netfilter在與用戶空間的通讀,也在最新版本中改變?yōu)閚etlink,無疑,它將是Linux用戶態(tài)與內(nèi)核態(tài)交流的主要方法之一。它的通信依據(jù)是一個(gè)對應(yīng)于進(jìn)程的標(biāo)識,一般定為該進(jìn)程的 ID。當(dāng)通信的一端處于中斷過程時(shí),該標(biāo)識為 0。當(dāng)使用 netlink 套接字進(jìn)行通信,通信的雙方都是用戶態(tài)進(jìn)程,則使用方法類似于消息隊(duì)列。但通信雙方有一端是中斷過程,使用方法則不同。netlink 套接字的最大特點(diǎn)是對中斷過程的支持,它在內(nèi)核空間接收用戶空間數(shù)據(jù)時(shí)不再需要用戶自行啟動一個(gè)內(nèi)核線程,而是通過另一個(gè)軟中斷調(diào)用用戶事先指定的接收函數(shù)。工作原理如圖:



如圖所示,這里使用了軟中斷而不是內(nèi)核線程來接收數(shù)據(jù),這樣就可以保證數(shù)據(jù)接收的實(shí)時(shí)性。
當(dāng) netlink 套接字用于內(nèi)核空間與用戶空間的通信時(shí),在用戶空間的創(chuàng)建方法和一般套接字使用類似,但內(nèi)核空間的創(chuàng)建方法則不同,下圖是 netlink 套接字實(shí)現(xiàn)此類通信時(shí)創(chuàng)建的過程:



用戶空間

用戶態(tài)應(yīng)用使用標(biāo)準(zhǔn)的socket與內(nèi)核通訊,標(biāo)準(zhǔn)的socket API 的函數(shù), socket(), bind(), sendmsg(), recvmsg() 和 close()很容易地應(yīng)用到 netlink socket。
為了創(chuàng)建一個(gè) netlink socket,用戶需要使用如下參數(shù)調(diào)用 socket():

  1. socket(AF_NETLINK, SOCK_RAW, netlink_type)
復(fù)制代碼


netlink對應(yīng)的協(xié)議簇是 AF_NETLINK,第二個(gè)參數(shù)必須是SOCK_RAW或SOCK_DGRAM, 第三個(gè)參數(shù)指定netlink協(xié)議類型,它可以是一個(gè)自定義的類型,也可以使用內(nèi)核預(yù)定義的類型:

  1. #define NETLINK_ROUTE          0       /* Routing/device hook                          */
  2. #define NETLINK_W1             1       /* 1-wire subsystem                             */
  3. #define NETLINK_USERSOCK       2       /* Reserved for user mode socket protocols      */
  4. #define NETLINK_FIREWALL       3       /* Firewalling hook                             */
  5. #define NETLINK_INET_DIAG      4       /* INET socket monitoring                       */
  6. #define NETLINK_NFLOG          5       /* netfilter/iptables ULOG */
  7. #define NETLINK_XFRM           6       /* ipsec */
  8. #define NETLINK_SELINUX        7       /* SELinux event notifications */
  9. #define NETLINK_ISCSI          8       /* Open-iSCSI */
  10. #define NETLINK_AUDIT          9       /* auditing */
  11. #define NETLINK_FIB_LOOKUP     10
  12. #define NETLINK_CONNECTOR      11
  13. #define NETLINK_NETFILTER      12      /* netfilter subsystem */
  14. #define NETLINK_IP6_FW         13
  15. #define NETLINK_DNRTMSG        14      /* DECnet routing messages */
  16. #define NETLINK_KOBJECT_UEVENT 15      /* Kernel messages to userspace */
復(fù)制代碼
#define NETLINK_GENERIC        16

同樣地,socket函數(shù)返回的套接字,可以交給bing等函數(shù)調(diào)用:
  1. static int skfd;
  2. skfd = socket(PF_NETLINK, SOCK_RAW, NL_IMP2);
  3. if(skfd < 0)
  4. {
  5.       printf("can not create a netlink socket\n");
  6.       exit(0);
  7. }
復(fù)制代碼


bind函數(shù)需要綁定協(xié)議地址,netlink的socket地址使用struct sockaddr_nl結(jié)構(gòu)描述:
  1. struct sockaddr_nl
  2. {
  3.   sa_family_t    nl_family;
  4.   unsigned short nl_pad;
  5.   __u32          nl_pid;
  6.   __u32          nl_groups;
  7. };
復(fù)制代碼


成員 nl_family為協(xié)議簇 AF_NETLINK,成員 nl_pad 當(dāng)前沒有使用,因此要總是設(shè)置為 0,成員 nl_pid 為接收或發(fā)送消息的進(jìn)程的 ID,如果希望內(nèi)核處理消息或多播消息,就把該字段設(shè)置為 0,否則設(shè)置為處理消息的進(jìn)程 ID。成員 nl_groups 用于指定多播組,bind 函數(shù)用于把調(diào)用進(jìn)程加入到該字段指定的多播組,如果設(shè)置為 0,表示調(diào)用者不加入任何多播組:
  1. struct sockaddr_nl local;

  2. memset(&local, 0, sizeof(local));
  3. local.nl_family = AF_NETLINK;
  4. local.nl_pid = getpid();                /*設(shè)置pid為自己的pid值*/
  5. local.nl_groups = 0;
  6. /*綁定套接字*/
  7. if(bind(skfd, (struct sockaddr*)&local, sizeof(local)) != 0)
  8. {
  9. printf("bind() error\n");
  10.      return -1;
  11. }
復(fù)制代碼


用戶空間可以調(diào)用send函數(shù)簇向內(nèi)核發(fā)送消息,如sendto、sendmsg等,同樣地,也可以使用struct sockaddr_nl來描述一個(gè)對端地址,以待send函數(shù)來調(diào)用,與本地地址稍不同的是,因?yàn)閷Χ藶閮?nèi)核,所以nl_pid成員需要設(shè)置為0:

  1. struct sockaddr_nl kpeer;
  2. memset(&kpeer, 0, sizeof(kpeer));
  3. kpeer.nl_family = AF_NETLINK;
  4. kpeer.nl_pid = 0;
  5. kpeer.nl_groups = 0;
復(fù)制代碼


另一個(gè)問題就是發(fā)內(nèi)核發(fā)送的消息的組成,使用我們發(fā)送一個(gè)IP網(wǎng)絡(luò)數(shù)據(jù)包的話,則數(shù)據(jù)包結(jié)構(gòu)為“IP包頭+IP數(shù)據(jù)”,同樣地,netlink的消息結(jié)構(gòu)是“netlink消息頭部+數(shù)據(jù)”。Netlink消息頭部使用struct nlmsghdr結(jié)構(gòu)來描述:
  1. struct nlmsghdr
  2. {
  3.   __u32 nlmsg_len;   /* Length of message */
  4.   __u16 nlmsg_type;  /* Message type*/
  5.   __u16 nlmsg_flags; /* Additional flags */
  6.   __u32 nlmsg_seq;   /* Sequence number */
  7.   __u32 nlmsg_pid;   /* Sending process PID */
  8. };
復(fù)制代碼


字段 nlmsg_len 指定消息的總長度,包括緊跟該結(jié)構(gòu)的數(shù)據(jù)部分長度以及該結(jié)構(gòu)的大小,一般地,我們使用netlink提供的宏NLMSG_LENGTH來計(jì)算這個(gè)長度,僅需向NLMSG_LENGTH宏提供要發(fā)送的數(shù)據(jù)的長度,它會自動計(jì)算對齊后的總長度:
  1. /*計(jì)算包含報(bào)頭的數(shù)據(jù)報(bào)長度*/
  2. #define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(sizeof(struct nlmsghdr)))
  3. /*字節(jié)對齊*/
  4. #define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
復(fù)制代碼


后面還可以看到很多netlink提供的宏,這些宏可以為我們編寫netlink宏提供很大的方便。

字段 nlmsg_type 用于應(yīng)用內(nèi)部定義消息的類型,它對 netlink 內(nèi)核實(shí)現(xiàn)是透明的,因此大部分情況下設(shè)置為 0,字段 nlmsg_flags 用于設(shè)置消息標(biāo)志,對于一般的使用,用戶把它設(shè)置為 0 就可以,只是一些高級應(yīng)用(如 netfilter 和路由 daemon 需要它進(jìn)行一些復(fù)雜的操作),字段 nlmsg_seq 和 nlmsg_pid 用于應(yīng)用追蹤消息,前者表示順序號,后者為消息來源進(jìn)程 ID。

  1. struct msg_to_kernel                /*自定義消息首部,它僅包含了netlink的消息首部*/
  2. {
  3.   struct nlmsghdr hdr;
  4. };

  5. struct msg_to_kernel message;
  6. memset(&message, 0, sizeof(message));
  7. message.hdr.nlmsg_len = NLMSG_LENGTH(0);                /*計(jì)算消息,因?yàn)檫@里只是發(fā)送一個(gè)請求消息,沒有多余的數(shù)據(jù),所以,數(shù)據(jù)長度為0*/
  8. message.hdr.nlmsg_flags = 0;
  9. message.hdr.nlmsg_type = IMP2_U_PID;                        /*設(shè)置自定義消息類型*/
  10. message.hdr.nlmsg_pid = local.nl_pid;                /*設(shè)置發(fā)送者的PID*/

  11. 這樣,有了本地地址、對端地址和發(fā)送的數(shù)據(jù),就可以調(diào)用發(fā)送函數(shù)將消息發(fā)送給內(nèi)核了:
  12.   /*發(fā)送一個(gè)請求*/
  13.   sendto(skfd, &message, message.hdr.nlmsg_len, 0,
  14.          (struct sockaddr*)&kpeer, sizeof(kpeer));
復(fù)制代碼


當(dāng)發(fā)送完請求后,就可以調(diào)用recv函數(shù)簇從內(nèi)核接收數(shù)據(jù)了,接收到的數(shù)據(jù)包含了netlink消息首部和要傳輸?shù)臄?shù)據(jù):
  1. /*接收的數(shù)據(jù)包含了netlink消息首部和自定義數(shù)據(jù)結(jié)構(gòu)*/
  2. struct u_packet_info
  3. {
  4.   struct nlmsghdr hdr;
  5.   struct packet_info icmp_info;
  6. };
  7. struct u_packet_info info;
  8. while(1)
  9. {
  10.     kpeerlen = sizeof(struct sockaddr_nl);
  11.       /*接收內(nèi)核空間返回的數(shù)據(jù)*/
  12.       rcvlen = recvfrom(skfd, &info, sizeof(struct u_packet_info),
  13.                         0, (struct sockaddr*)&kpeer, &kpeerlen);
  14.                   
  15.        /*處理接收到的數(shù)據(jù)*/
  16. ……
  17. }
復(fù)制代碼


同樣地,函數(shù)close用于關(guān)閉打開的netlink socket。程序中,因?yàn)槌绦蛞恢毖h(huán)接收處理內(nèi)核的消息,需要收到用戶的關(guān)閉信號才會退出,所以關(guān)閉套接字的工作放在了自定義的信號函數(shù)sig_int中處理:
  1. /*這個(gè)信號函數(shù),處理一些程序退出時(shí)的動作*/
  2. static void sig_int(int signo)
  3. {
  4.   struct sockaddr_nl kpeer;
  5.   struct msg_to_kernel message;

  6.   memset(&kpeer, 0, sizeof(kpeer));
  7.   kpeer.nl_family = AF_NETLINK;
  8.   kpeer.nl_pid    = 0;
  9.   kpeer.nl_groups = 0;

  10.   memset(&message, 0, sizeof(message));
  11.   message.hdr.nlmsg_len = NLMSG_LENGTH(0);
  12.   message.hdr.nlmsg_flags = 0;
  13.   message.hdr.nlmsg_type = IMP2_CLOSE;
  14.   message.hdr.nlmsg_pid = getpid();

  15.   /*向內(nèi)核發(fā)送一個(gè)消息,由nlmsg_type表明,應(yīng)用程序?qū)㈥P(guān)閉*/
  16.   sendto(skfd, &message, message.hdr.nlmsg_len, 0, (struct sockaddr *)(&kpeer),         sizeof(kpeer));

  17.   close(skfd);
  18.   exit(0);
  19. }
復(fù)制代碼


這個(gè)結(jié)束函數(shù)中,向內(nèi)核發(fā)送一個(gè)“我已經(jīng)退出了”的消息,然后調(diào)用close函數(shù)關(guān)閉netlink套接字,退出程序。

內(nèi)核空間

與應(yīng)用程序內(nèi)核,內(nèi)核空間也主要完成三件工作:
n        創(chuàng)建netlink套接字
n        接收處理用戶空間發(fā)送的數(shù)據(jù)
n        發(fā)送數(shù)據(jù)至用戶空間

API函數(shù)netlink_kernel_create用于創(chuàng)建一個(gè)netlink socket,同時(shí),注冊一個(gè)回調(diào)函數(shù),用于接收處理用戶空間的消息:

  1. struct sock *
  2. netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len));
復(fù)制代碼


參數(shù)unit表示netlink協(xié)議類型,如NL_IMP2,參數(shù)input則為內(nèi)核模塊定義的netlink消息處理函數(shù),當(dāng)有消息到達(dá)這個(gè)netlink socket時(shí),該input函數(shù)指針就會被引用。函數(shù)指針input的參數(shù)sk實(shí)際上就是函數(shù)netlink_kernel_create返回的struct sock指針,sock實(shí)際是socket的一個(gè)內(nèi)核表示數(shù)據(jù)結(jié)構(gòu),用戶態(tài)應(yīng)用創(chuàng)建的socket在內(nèi)核中也會有一個(gè)struct sock結(jié)構(gòu)來表示。
  1. static int __init init(void)
  2. {
  3.   rwlock_init(&user_proc.lock);                /*初始化讀寫鎖*/

  4.   /*創(chuàng)建一個(gè)netlink socket,協(xié)議類型是自定義的ML_IMP2,kernel_reveive為接受處理函數(shù)*/
  5.   nlfd = netlink_kernel_create(NL_IMP2, kernel_receive);
  6.   if(!nlfd)                /*創(chuàng)建失敗*/
  7.   {
  8.       printk("can not create a netlink socket\n");
  9.       return -1;
  10.   }

  11.   /*注冊一個(gè)Netfilter 鉤子*/
  12.   return nf_register_hook(&imp2_ops);
  13. }


  14. module_init(init);
復(fù)制代碼


用戶空間向內(nèi)核發(fā)送了兩種自定義消息類型:IMP2_U_PID和IMP2_CLOSE,分別是請求和關(guān)閉。kernel_receive 函數(shù)分別處理這兩種消息:

  1. DECLARE_MUTEX(receive_sem);                                                        /*初始化信號量*/
  2. static void kernel_receive(struct sock *sk, int len)
  3. {
  4.         do
  5.     {
  6.                 struct sk_buff *skb;
  7.                 if(down_trylock(&receive_sem))                                /*獲取信號量*/
  8.                         return;
  9.                 /*從接收隊(duì)列中取得skb,然后進(jìn)行一些基本的長度的合法性校驗(yàn)*/
  10.                 while((skb = skb_dequeue(&sk->receive_queue)) != NULL)
  11.         {
  12.                         {
  13.                                 struct nlmsghdr *nlh = NULL;
  14.                                
  15.                                 if(skb->len >= sizeof(struct nlmsghdr))
  16.                                 {
  17.                                         /*獲取數(shù)據(jù)中的nlmsghdr 結(jié)構(gòu)的報(bào)頭*/
  18.                                         nlh = (struct nlmsghdr *)skb->data;
  19.                                         if((nlh->nlmsg_len >= sizeof(struct nlmsghdr))
  20.                                                 && (skb->len >= nlh->nlmsg_len))
  21.                                         {
  22.                                                 /*長度的全法性校驗(yàn)完成后,處理應(yīng)用程序自定義消息類型,主要是對用戶PID的保存,即為內(nèi)核保存“把消息發(fā)送給誰”*/
  23.                                                 if(nlh->nlmsg_type == IMP2_U_PID)                /*請求*/
  24.                                                 {
  25.                                                         write_lock_bh(&user_proc.pid);
  26.                                                         user_proc.pid = nlh->nlmsg_pid;
  27.                                                         write_unlock_bh(&user_proc.pid);
  28.                                                 }
  29.                                                 else if(nlh->nlmsg_type == IMP2_CLOSE)        /*應(yīng)用程序關(guān)閉*/
  30.                                                 {
  31.                                                         write_lock_bh(&user_proc.pid);
  32.                                                         if(nlh->nlmsg_pid == user_proc.pid)
  33.                                                                 user_proc.pid = 0;
  34.                                                         write_unlock_bh(&user_proc.pid);
  35.                                                 }
  36.                                         }
  37.                                 }
  38.                         }
  39.                         kfree_skb(skb);
  40.         }
  41.                 up(&receive_sem);                                /*返回信號量*/
  42.     }while(nlfd && nlfd->receive_queue.qlen);
  43. }
復(fù)制代碼


因?yàn)閮?nèi)核模塊可能同時(shí)被多個(gè)進(jìn)程同時(shí)調(diào)用,所以函數(shù)中使用了信號量和鎖來進(jìn)行互斥。skb = skb_dequeue(&sk->receive_queue)用于取得socket sk的接收隊(duì)列上的消息,返回為一個(gè)struct sk_buff的結(jié)構(gòu),skb->data指向?qū)嶋H的netlink消息。

程序中注冊了一個(gè)Netfilter鉤子,鉤子函數(shù)是get_icmp,它截獲ICMP數(shù)據(jù)包,然后調(diào)用send_to_user函數(shù)將數(shù)據(jù)發(fā)送給應(yīng)用空間進(jìn)程。發(fā)送的數(shù)據(jù)是info結(jié)構(gòu)變量,它是struct packet_info結(jié)構(gòu),這個(gè)結(jié)構(gòu)包含了來源/目的地址兩個(gè)成員。Netfilter Hook不是本文描述的重點(diǎn),略過。
send_to_user 用于將數(shù)據(jù)發(fā)送給用戶空間進(jìn)程,發(fā)送調(diào)用的是API函數(shù)netlink_unicast 完成的:
  1. int netlink_unicast(struct sock *sk, struct sk_buff *skb, u32 pid, int nonblock);
復(fù)制代碼


參數(shù)sk為函數(shù)netlink_kernel_create()返回的套接字,參數(shù)skb存放待發(fā)送的消息,它的data字段指向要發(fā)送的netlink消息結(jié)構(gòu),而skb的控制塊保存了消息的地址信息, 參數(shù)pid為接收消息進(jìn)程的pid,參數(shù)nonblock表示該函數(shù)是否為非阻塞,如果為1,該函數(shù)將在沒有接收緩存可利用時(shí)立即返回,而如果為0,該函數(shù)在沒有接收緩存可利用時(shí)睡眠。
向用戶空間進(jìn)程發(fā)送的消息包含三個(gè)部份:netlink 消息頭部、數(shù)據(jù)部份和控制字段,控制字段包含了內(nèi)核發(fā)送netlink消息時(shí),需要設(shè)置的目標(biāo)地址與源地址,內(nèi)核中消息是通過sk_buff來管理的, linux/netlink.h中定義了NETLINK_CB宏來方便消息的地址設(shè)置:

  1. #define NETLINK_CB(skb)         (*(struct netlink_skb_parms*)&((skb)->cb))
復(fù)制代碼


例如:

  1. NETLINK_CB(skb).pid = 0;
  2. NETLINK_CB(skb).dst_pid = 0;
  3. NETLINK_CB(skb).dst_group = 1;
復(fù)制代碼


字段pid表示消息發(fā)送者進(jìn)程ID,也即源地址,對于內(nèi)核,它為 0, dst_pid 表示消息接收者進(jìn)程 ID,也即目標(biāo)地址,如果目標(biāo)為組或內(nèi)核,它設(shè)置為 0,否則 dst_group 表示目標(biāo)組地址,如果它目標(biāo)為某一進(jìn)程或內(nèi)核,dst_group 應(yīng)當(dāng)設(shè)置為 0。

  1. static int send_to_user(struct packet_info *info)
  2. {
  3. int ret;
  4. int size;
  5. unsigned char *old_tail;
  6. struct sk_buff *skb;
  7. struct nlmsghdr *nlh;
  8. struct packet_info *packet;

  9. /*計(jì)算消息總長:消息首部加上數(shù)據(jù)加度*/
  10. size = NLMSG_SPACE(sizeof(*info));

  11. /*分配一個(gè)新的套接字緩存*/
  12. skb = alloc_skb(size, GFP_ATOMIC);
  13. old_tail = skb->tail;

  14. /*初始化一個(gè)netlink消息首部*/
  15. nlh = NLMSG_PUT(skb, 0, 0, IMP2_K_MSG, size-sizeof(*nlh));
  16. /*跳過消息首部,指向數(shù)據(jù)區(qū)*/
  17. packet = NLMSG_DATA(nlh);
  18. /*初始化數(shù)據(jù)區(qū)*/
  19. memset(packet, 0, sizeof(struct packet_info));
  20. /*填充待發(fā)送的數(shù)據(jù)*/
  21. packet->src = info->src;
  22. packet->dest = info->dest;

  23. /*計(jì)算skb兩次長度之差,即netlink的長度總和*/
  24. nlh->nlmsg_len = skb->tail - old_tail;
  25. /*設(shè)置控制字段*/
  26. NETLINK_CB(skb).dst_groups = 0;

  27. /*發(fā)送數(shù)據(jù)*/
  28. read_lock_bh(&user_proc.lock);
  29. ret = netlink_unicast(nlfd, skb, user_proc.pid, MSG_DONTWAIT);
  30. read_unlock_bh(&user_proc.lock);


  31. }
復(fù)制代碼


函數(shù)初始化netlink 消息首部,填充數(shù)據(jù)區(qū),然后設(shè)置控制字段,這三部份都包含在skb_buff中,最后調(diào)用netlink_unicast函數(shù)把數(shù)據(jù)發(fā)送出去。
函數(shù)中調(diào)用了netlink的一個(gè)重要的宏NLMSG_PUT,它用于初始化netlink 消息首部:
  1. #define NLMSG_PUT(skb, pid, seq, type, len) \
  2. ({ if (skb_tailroom(skb) < (int)NLMSG_SPACE(len)) goto nlmsg_failure; \
  3.    __nlmsg_put(skb, pid, seq, type, len); })
  4. static __inline__ struct nlmsghdr *
  5. __nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len)
  6. {
  7.         struct nlmsghdr *nlh;
  8.         int size = NLMSG_LENGTH(len);

  9.         nlh = (struct nlmsghdr*)skb_put(skb, NLMSG_ALIGN(size));
  10.         nlh->nlmsg_type = type;
  11.         nlh->nlmsg_len = size;
  12.         nlh->nlmsg_flags = 0;
  13.         nlh->nlmsg_pid = pid;
  14.         nlh->nlmsg_seq = seq;
  15.         return nlh;
  16. }
復(fù)制代碼


這個(gè)宏一個(gè)需要注意的地方是調(diào)用了nlmsg_failure標(biāo)簽,所以在程序中應(yīng)該定義這個(gè)標(biāo)簽。

在內(nèi)核中使用函數(shù)sock_release來釋放函數(shù)netlink_kernel_create()創(chuàng)建的netlink socket:
  1. void sock_release(struct socket * sock);
復(fù)制代碼


程序在退出模塊中釋放netlink sockets和netfilter hook:
  1. static void __exit fini(void)
  2. {
  3.   if(nlfd)
  4.     {
  5.       sock_release(nlfd->socket);                /*釋放netlink socket*/
  6.     }
  7.   nf_unregister_hook(&imp2_ops);                /*撤鎖netfilter 鉤子*/
  8. }
復(fù)制代碼

論壇徽章:
0
2 [報(bào)告]
發(fā)表于 2006-09-03 23:47 |只看該作者
非常好 定一下

論壇徽章:
0
3 [報(bào)告]
發(fā)表于 2006-09-04 12:49 |只看該作者
非常好,標(biāo)記一下!

論壇徽章:
0
4 [報(bào)告]
發(fā)表于 2006-09-05 15:49 |只看該作者
不錯(cuò)!不錯(cuò)!
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP