2009年2月11日 星期三

Netlink (2) 應用 hot plug

接下來利用netlink提供的功能來看使用USB熱插拔訊息:
kernel: 2.6.18
GCC: 4.1.2

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/types.h>
#include <linux/netlink.h>
#include <sys/vfs.h>
#include <sys/statfs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>


#define UEVENT_BUFFER_SIZE 1024

static int init_hotplug_sock(void)
{
struct sockaddr_nl snl;
const int buffersize = 16 * 1024;
int retval;

memset(&snl, 0x00, sizeof(struct sockaddr_nl));
snl.nl_family = AF_NETLINK;
snl.nl_pid = getpid();
snl.nl_groups = 1;

int hotplug_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if (hotplug_sock == -1) {
printf("error getting socket: %s", strerror(errno));
return -1;
}

/* set receive buffersize */
setsockopt(hotplug_sock, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize));
retval = bind(hotplug_sock, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl));

if (retval < 0) {
printf("bind failed: %s", strerror(errno));
close(hotplug_sock);
hotplug_sock = -1;
return -1;
}
return hotplug_sock;
}

int main(int argc, char* argv[])
{
int hotplug_sock = init_hotplug_sock();
char buf_cache[UEVENT_BUFFER_SIZE*2] = {0};

while(1) {
memset(buf_cache, 0 ,sizeof(buf_cache));
recv(hotplug_sock,buf_cache, sizeof(buf_cache), 0);
printf("======buf_cache: %s\n", buf_cache);
}

return 0;
}


這個程式一開始使用netlink socket開啟 hotplug_sock,並且註冊netlink family為NETLINK_KOBJECT_UEVENT,這個協定目前我看到的是kernel 2.6.15以後才有,利用這個協定來將kernel space message傳給user space。
然後設定hotplug_sock的緩衝區,SO_RCVBUFFORCE(since Linux 2.6.14)可以設定比rmem_max 更大的buffer,將與位址bind 之後,就可以recv()。如此一來,我們就可以很方便收到從kernel傳來USB熱插拔的訊息。

參考資料:
http://blog.csdn.net/absurd/archive/2007/04/27/1587938.aspx

linux kernel man page

Netlink (1) 基礎

Netlink 是一種在內核與用戶應用間進行雙向數據傳輸的非常好的模式,用戶使用標準的 socket API 就可以使用 netlink 提供的強大功能,內核需要使用專門的內核 API 來使用 netlink。我們可以從man中看到它的簡介。

NAME
netlink, PF_NETLINK - Communication between kernel and user

SYNOPSIS
#include <asm/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>

netlink_socket = socket(PF_NETLINK, socket_type, netlink_family);


Netlink 相對於系統調用,ioctl 以及 /proc 檔案系統而言具有以下優點︰
1. 為了使用 netlink,用戶僅需要在 include/linux/netlink.h 中增加一個新類型的 netlink 協議定義即可, 如 #define NETLINK_MYTEST 17 然後,內核和用戶態應用就可以立即透過 socket API 使用該 netlink 協議類型進行數據交換。但系統調用需要增加新的系統調用,ioctl 則需要增加設備或檔案, 那需要不少代碼,proc 檔案系統則需要在 /proc 下添加新的檔案或目錄,那將使本來就混亂的 /proc 更加混亂。

2. netlink是一種異步通信機制,在內核與用戶態應用之間傳遞的消息儲存在socket緩沖隊列中,發送消息只是把消息儲存在接收者的socket的接收隊列,而不需要等待接收者收到消息,但系統調用與 ioctl 則是同步通信機制,如果傳遞的數據太長,將影響調度。

3. 使用 netlink 的內核部分可以採用模塊的模式實現,使用 netlink 的應用部分和內核部分沒有編譯時倚賴,但系統調用就有倚賴,而且新的系統調用的實現必須靜態地連接到內核中,它無法在模塊中實現,使用新系統調用的應用在編譯時需要倚賴內核。

4. netlink 支援多播,內核模塊或應用可以把消息多播給一個netlink組,屬於該neilink 組的任何內核模塊或應用都能接收到該消息,內核事件向用戶態的通知機製就使用了這一特性,任何對內核事件感興趣的應用都能收到該子系統發送的內核事件,在後面的文章中將介紹這一機製的使用。

5. 內核可以使用 netlink 首先發起會話,但系統調用和 ioctl 只能由用戶應用發起調用。

6. netlink 使用標準的 socket API,因此很容易使用,但系統調用和 ioctl 則需要專門的培養訓練才能使用。


接下來看一下socket的參數
netlink_socket = socket(PF_NETLINK, socket_type, netlink_family);

socket_type: SOCK_RAW or SOCK_DGRAM,Both can do.
netlink_family: define in kernel source include/linux/netlink.h

#define NETLINK_ROUTE 0 /* Routing/device hook */
#define NETLINK_W1 1 /* 1-wire subsystem */
#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
#define NETLINK_FIREWALL 3 /* Firewalling */
#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 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 /* DECnet routing messages */
#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */
#define NETLINK_GENERIC 16

retval = bind(netlink_socket, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl));
函數 bind() 用於把一個打開的 netlink socket 與 netlink socket 位址綁定在一起。netlink socket 的位址架構如下︰

struct sockaddr_nl
{
sa_family_t nl_family;
unsigned short nl_pad;
__u32 nl_pid;
__u32 nl_groups;
};


參考資料:
http://eddiefu.bokee.com/viewdiary.14137760.html

http://blog.csdn.net/absurd/archive/2008/11/07/3244482.aspx

2009年2月2日 星期一

diff & patch

Compare two file
#diff -u file_old file_new > file.patch

parameter of diff

[root@ecken02 temp]# ls
pnscan-1.8.tar.gz
[root@ecken02 temp]# tar zxvf pnscan-1.8.tar.gz
[root@ecken02 temp]# mv pnscan-1.8 pnscan-1.8.old
[root@ecken02 temp]# tar zxvf pnscan-1.8.tar.gz
[root@ecken02 temp]# ls
pnscan-1.8 pnscan-1.8.old pnscan-1.8.tar.gz
[root@ecken02 temp]# diff -Nur pnscan-1.8.old pnscan-1.8 > file.patch
[root@ecken02 temp]# cat file.patch
diff -Nur pnscan-1.8.old/bm.c pnscan-1.8/bm.c
--- pnscan-1.8.old/bm.c 2002-03-22 18:02:55.000000000 +0800
+++ pnscan-1.8/bm.c 2009-02-02 13:44:47.000000000 +0800
@@ -109,7 +109,7 @@
xsize = m;

saved_m = m;
- saved_x = (unsigned char *) malloc(m);
+ saved_x = (unsigned char *) malloc(m); /* I am here */
if (saved_x == NULL)
return -2;

diff -Nur pnscan-1.8.old/pnscan.c pnscan-1.8/pnscan.c
--- pnscan-1.8.old/pnscan.c 2002-03-22 21:09:52.000000000 +0800
+++ pnscan-1.8/pnscan.c 2009-02-02 13:58:05.000000000 +0800
@@ -106,7 +106,7 @@
return val & 0xFF;
}

-
+/* I am here */
int
dehex(char *str)
{
@@ -996,7 +996,9 @@
goto EndOptions;

case 'h':
- usage(stdout);
+
+ usage(stdout); /* I am here */
+
exit(0);

case 'w':
[root@ecken02 temp]#



Patch file:
#patch -p1 < file.patch

parameter of patch

[root@ecken02 temp]# cp pnscan-1.8.old pnscan-1.8.new
[root@ecken02 temp]# patch -tp1 -d pnscan-1.8.new -i /absolute path/file.patch