Kernel side code:
MODULE_LICENSE("GPL");
Make File:
$(MAKE) -C $(KERNELDIR) M=`pwd` clean
User side Code:
Send :
}
Receive :
}
Make file:
rm netlink-exam-user-recv netlink-exam-user-send
| //kernel module: netlink-exam-kern.c |
| #include <linux/module.h> |
| #include <linux/netlink.h> |
| #include <linux/sched.h> |
| #include <net/sock.h> |
| #include <linux/proc_fs.h> |
| #include <linux/version.h> |
| #define BUF_SIZE 16384 |
| static struct sock *netlink_exam_sock; |
| static unsigned char buffer[BUF_SIZE]; |
| static unsigned int buffer_tail = 0; |
| #define NETLINK_TEST 21 |
| #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) |
| #define sk_sleep(sk) sk->sk_sleep |
| #endif |
| #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0) |
| static void recv_handler(struct sk_buff *skb) |
| { |
| struct nlmsghdr *nlhdr = (struct nlmsghdr *)skb->data; |
| size_t len = 0; |
| if (nlhdr->nlmsg_len < sizeof(struct nlmsghdr)) { |
| printk("Corrupt netlink message.\n"); |
| } |
| len = nlhdr->nlmsg_len - NLMSG_LENGTH(0); |
| if (len + buffer_tail > BUF_SIZE) { |
| printk("netlink buffer is full.\n"); |
| } |
| else { |
| memcpy(buffer + buffer_tail, NLMSG_DATA(nlhdr), len); |
| buffer_tail += len; |
| } |
| } |
| static int netlink_exam_readproc(char *page, char **start, off_t off, |
| int count, int *eof, void *data) |
| { |
| int len; |
| if (off >= buffer_tail) { |
| * eof = 1; |
| return 0; |
| } |
| else { |
| len = count; |
| if (count > PAGE_SIZE) { |
| len = PAGE_SIZE; |
| } |
| if (len > buffer_tail - off) { |
| len = buffer_tail - off; |
| } |
| memcpy(page, buffer + off, len); |
| *start = page; |
| return len; |
| } |
| } |
| static int __init netlink_exam_init(void) |
| { |
| netlink_exam_sock = netlink_kernel_create(&init_net, NETLINK_TEST, 0, recv_handler, NULL, THIS_MODULE); |
| if (!netlink_exam_sock) { |
| printk("Fail to create netlink socket.\n"); |
| return -1; |
| } |
| create_proc_read_entry("netlink_exam_buffer", 0444, NULL, netlink_exam_readproc, 0); |
| return 0; |
| } |
| static void __exit netlink_exam_exit(void) |
| { |
| wake_up(sk_sleep(netlink_exam_sock)); |
| sock_release(netlink_exam_sock->sk_socket); |
| remove_proc_entry("netlink_exam_buffer", NULL); |
| } |
| module_init(netlink_exam_init); |
| module_exit(netlink_exam_exit); |
Make File:
| mname :=file name |
| $(mname)-objs := netlink-exam-kern.o |
| obj-m := $(mname).o |
| KERNELDIR := /lib/modules/`uname -r`/build |
| all: |
| $(MAKE) -C $(KERNELDIR) M=`pwd` modules |
| clean: |
User side Code:
Send :
| //application sender: netlink-exam-user-send.c |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| #include <linux/netlink.h> |
| #define MAX_MSGSIZE 1024 |
| #define NETLINK_TEST 21 |
| int main(int argc, char * argv[]) |
| { |
| FILE * fp; |
| struct sockaddr_nl saddr, daddr; |
| struct nlmsghdr *nlhdr = NULL; |
| struct msghdr msg; |
| struct iovec iov; |
| int sd; |
| char text_line[MAX_MSGSIZE]; |
| int ret = -1; |
| if (argc < 2) { |
| printf("Usage: %s atextfilename\n", argv[0]); |
| exit(1); |
| } |
| if ((fp = fopen(argv[1], "r")) == NULL) { |
| printf("File %s dosen't exist.\n", argv[1]); |
| exit(1); |
| } |
| sd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST); |
| if (sd == -1) { |
| printf("Cannot create netlink\n"); |
| exit(1); |
| } |
| memset(&saddr, 0, sizeof(saddr)); |
| memset(&daddr, 0, sizeof(daddr)); |
| saddr.nl_family = AF_NETLINK; |
| saddr.nl_pid = getpid(); |
| saddr.nl_groups = 11; |
| bind(sd, (struct sockaddr*)&saddr, sizeof(saddr)); |
| daddr.nl_family = AF_NETLINK; |
| daddr.nl_pid = 0; |
| daddr.nl_groups = 1; |
| nlhdr = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_MSGSIZE)); |
| while (fgets(text_line, MAX_MSGSIZE, fp)) { |
| memcpy(NLMSG_DATA(nlhdr), text_line, strlen(text_line)); |
| memset(&msg, 0 ,sizeof(struct msghdr)); |
| nlhdr->nlmsg_len = NLMSG_LENGTH(strlen(text_line)); |
| nlhdr->nlmsg_pid = getpid(); /* self pid */ |
| nlhdr->nlmsg_flags = 0; |
| iov.iov_base = (void *)nlhdr; |
| iov.iov_len = nlhdr->nlmsg_len; |
| msg.msg_name = (void *)&daddr; |
| msg.msg_namelen = sizeof(daddr); |
| msg.msg_iov = &iov; |
| msg.msg_iovlen = 1; |
| ret = sendmsg(sd, &msg, 0); |
| if (ret == -1) { |
| perror("sendmsg error:"); |
| } |
| } |
| close(sd); |
Receive :
| //application receiver: netlink-exam-user-recv.c |
| #include <stdio.h> |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| #include <linux/netlink.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #define MAX_MSGSIZE 1024 |
| #define NETLINK_TEST 21 |
| int main(void) |
| { |
| struct sockaddr_nl saddr, daddr; |
| struct nlmsghdr *nlhdr = NULL; |
| struct msghdr msg; |
| struct iovec iov; |
| int sd; |
| int ret = 1; |
| sd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST); |
| if (sd == -1) { |
| printf("cannot create netlink\n"); |
| exit(-1); |
| } |
| memset(&saddr, 0, sizeof(saddr)); |
| memset(&daddr, 0, sizeof(daddr)); |
| saddr.nl_family = AF_NETLINK; |
| saddr.nl_pid = getpid(); |
| saddr.nl_groups = 11; |
| bind(sd, (struct sockaddr*)&saddr, sizeof(saddr)); |
| nlhdr = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_MSGSIZE)); |
| while (1) { |
| memset(nlhdr, 0, NLMSG_SPACE(MAX_MSGSIZE)); |
| iov.iov_base = (void *)nlhdr; |
| iov.iov_len = NLMSG_SPACE(MAX_MSGSIZE); |
| msg.msg_name = (void *)&daddr; |
| msg.msg_namelen = sizeof(daddr); |
| msg.msg_iov = &iov; |
| msg.msg_iovlen = 1; |
| ret = recvmsg(sd, &msg, 0); |
| if (ret == 0) { |
| printf("Exit.\n"); |
| exit(0); |
| } |
| else if (ret == -1) { |
| perror("recvmsg:"); |
| exit(1); |
| } |
| printf("%s", (char *)NLMSG_DATA(nlhdr)); |
| } |
| close(sd); |
Make file:
| .PHONY: clean |
| all: |
| gcc netlink-exam-user-recv.c -o netlink-exam-user-recv |
| gcc netlink-exam-user-send.c -o netlink-exam-user-send |
| clean: |