C Pointers
  • C Pointers
  • Linux Device Drivers
    • Basic Module
      • Hello world
      • Kthread
      • Tasklets
      • Workqueues
      • Timers
      • Linked List
      • File System
      • Netlink
        • Netlink : Unicast
        • Netlink : Multicast
      • SKB
    • Character Device Driver
    • Wireless Device Driver
  • Linux System Programming
  • Linux Network Programming
  • Linux Build Environments
  • OS Ports
  • FreeBSD Device Drivers
C Pointers
  • »
  • Linux Device Drivers »
  • Basic Module »
  • Netlink »
  • Netlink : Unicast
  • View page source
Previous Next

Netlink : Unicast

  • In this program, you are going to learn

  • How to communication between kernel and user space ?

  • How to use user space APIs ?

    • NLMSG_SPACE

    • NLMSG_DATA

  • How to use kernel space APIs ?

    • nlmsg_new

    • nlmsg_put

    • NETLINK_CB

    • nlmsg_unicast

    • netlink_kernel_create

    • netlink_kernel_release

Topics in this section,

  • Netlink

  • User program : nl_user.c

  • Kernel program : nl_kernel.c

  • Makefile

  • Compile and Load

  • Summary

  • Netlink is used to transfer information between the kernel and user-space processes.

  • Netlink is a datagram-oriented service. Both SOCK_RAW and SOCK_DGRAM are valid values for socket_type.

  • To create a socket with socket(),

int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TESTFAMILY);
  • nl_pid field of the sockaddr_nl can be filled with the calling process’ own pid.

nlh->nlmsg_pid = getpid();
  • Sending a Netlink Message In order to send a netlink message to the kernel or other user-space processes, another struct sockaddr_nl addr needs to be supplied as the destination address, the same as sending a packet with sendmsg(). If the message is destined for the kernel, both nl_pid and nl_groups should be supplied with 0.

addr.nl_pid = 0;
addr.nl_groups = 0;

struct msghdr msg;

msg.msg_name = (void * ) &addr;
msg.msg_namelen = sizeof(addr);
  • The netlink socket requires its own message header as well. This is for providing a common ground for netlink messages of all protocol types. Because the Linux kernel netlink core assumes the existence of the following header in each netlink message, an application must supply this header in each netlink message it sends:

struct nlmsghdr * nlh = (struct nlmsghdr * ) malloc(NLMSG_SPACE(MAX_PAYLOAD));

nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
nlh->nlmsg_pid = getpid();
nlh->nlmsg_flags = 0;
  • A netlink message thus consists of nlmsghdr and the message payload. Once a message has been entered, it enters a buffer pointed to by the nlh pointer. We also can send the message to the struct msghdr msg:

struct iovec iov;

iov.iov_base = (void * ) nlh;
iov.iov_len = nlh->nlmsg_len;

msg.msg_iov = &iov;
msg.msg_iovlen = 1;
  • After the above steps, a call to sendmsg() kicks out the netlink message:

sendmsg(fd, &msg, 0);
  • recvmsg used for Receiving Netlink Messages,

recvmsg(fd, &msg, 0);
  • See the full program below,

 1#include <linux/netlink.h>
 2#include <sys/socket.h>
 3#include <stdio.h>
 4#include <unistd.h>
 5#include <stdlib.h>
 6#include <string.h>
 7
 8#define NETLINK_TESTFAMILY 25
 9#define MAX_PAYLOAD 1024
10
11int main(int argc, char *argv[])
12{
13	int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TESTFAMILY);
14	struct iovec iov;
15	struct msghdr msg;
16	struct sockaddr_nl addr;
17
18	if (fd < 0)
19		printf("Unable to create socket\n");
20
21	memset(&addr, 0, sizeof(addr));
22	addr.nl_family = AF_NETLINK;
23	addr.nl_pid = 0;  // For Linux kernel
24	addr.nl_groups = 0;
25
26	struct nlmsghdr *nlh = (struct nlmsghdr *) malloc(NLMSG_SPACE(MAX_PAYLOAD));
27
28	memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
29	nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
30	nlh->nlmsg_pid = getpid();
31	nlh->nlmsg_flags = 0;
32	strcpy((char *) NLMSG_DATA(nlh), "Hello");
33
34	memset(&iov, 0, sizeof(iov));
35	iov.iov_base = (void *) nlh;
36	iov.iov_len = nlh->nlmsg_len;
37
38	memset(&msg, 0, sizeof(msg));
39	msg.msg_name = (void *) &addr;
40	msg.msg_namelen = sizeof(addr);
41	msg.msg_iov = &iov;
42	msg.msg_iovlen = 1;
43
44	printf("Sending message to kernel\n");
45	printf("-------------------------\n");
46	sendmsg(fd, &msg, 0);
47	printf("Sent message: %s\n\n", (char *)NLMSG_DATA(nlh));
48
49	printf("Receving the message from the kernel\n");
50	printf("------------------------------------\n");
51	recvmsg(fd, &msg, 0);
52	printf("Received message: %s\n", (char *)NLMSG_DATA(nlh));
53	return 0;
54}
  • nlmsg_new using this create a netlink message.

struct sk_buff * skb_out;

skb_out = nlmsg_new(message_size, GFP_KERNEL);
  • nlmsg_put used to populate the message with data.

struct nlmsghdr * nlh = (struct nlmsghdr * ) skb->data;

nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, message_size, 0);
  • nlmsg_unicast used to send the message to the user space application.

result = nlmsg_unicast(socket, skb_out, pid);
  • netlink_kernel_create used to create a Netlink socket in the kernel.

socket = netlink_kernel_create(&init_net, NETLINK_TESTFAMILY, &config);
  • netlink_kernel_release used to release the netlink socket created with netlink_kernel_create.

netlink_kernel_release(socket);
  • See the full program below,

 1#include <linux/module.h>
 2#include <linux/kernel.h>
 3#include <linux/netlink.h>
 4#include <net/netlink.h>
 5#include <net/net_namespace.h>
 6
 7#define NETLINK_TESTFAMILY 25
 8#define NETLINK_MYGROUP 2
 9
10MODULE_LICENSE("GPL");
11MODULE_AUTHOR("Linux_usr");
12MODULE_DESCRIPTION("Netlink - Unicast");
13
14struct sock *socket;
15
16static void test_nl_receive_message(struct sk_buff *skb)
17{
18	struct nlmsghdr *nlh = (struct nlmsghdr *) skb->data;
19	pid_t pid = nlh->nlmsg_pid; // pid of the sending process
20	int result;
21	char *message;
22	size_t message_size;
23	struct sk_buff *skb_out;
24
25	pr_info("Entering: %s\n", __func__);
26	pr_info("Received message: %s\n", (char *) nlmsg_data(nlh));
27
28	message = "Hello from kernel unicast";
29	message_size = strlen(message) + 1;
30	skb_out = nlmsg_new(message_size, GFP_KERNEL);
31	if (!skb_out) {
32		pr_err("Failed to allocate a new skb\n");
33		return;
34	}
35
36	nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, message_size, 0);
37	NETLINK_CB(skb_out).dst_group = 0;
38	strncpy(nlmsg_data(nlh), message, message_size);
39
40	result = nlmsg_unicast(socket, skb_out, pid);
41	pr_info("Sent message: %s\n", (char *)nlmsg_data(nlh));
42}
43
44static int __init test_init(void)
45{
46	struct netlink_kernel_cfg config = {
47		.input = test_nl_receive_message,
48	};
49
50	socket = netlink_kernel_create(&init_net, NETLINK_TESTFAMILY, &config);
51	if (socket == NULL)
52		return -1;
53
54	pr_info("Netlink initialized\n");
55	return 0;
56}
57
58static void __exit test_exit(void)
59{
60	if (socket)
61		netlink_kernel_release(socket);
62	pr_info("Netlink released\n");
63}
64
65module_init(test_init);
66module_exit(test_exit);
 1obj-m += nl_kernel.o
 2all:
 3	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
 4
 5client:
 6	gcc nl_user.c -o nl_user
 7
 8clean:
 9	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
10	rm nl_user
 1$ make all
 2
 3$ sudo insmod ./nl_kernel.ko
 4
 5$ ./nl_user
 6
 7$ sudo rmmod nl_kernel
 8
 9$ dmesg
10[168541.257012] Netlink initialized
11[168546.697217] Entering: test_nl_receive_message
12[168546.697220] Received message: Hello
13[168546.697224] Sent message: Hello from kernel unicast
14[168567.528336] Netlink released

User Space API

Learning

socket

To create a socket

sendmsg

To send netlink message

recvmsg

To receive netlink message

Kernel Space API

Learning

nlmsg_new

To create a netlink message

nlmsg_put

TO populate the message

nlmsg_unicast

To send the message to the user space application

netlink_kernel_create

To create a Netlink socket in the kernel

netlink_kernel_release

To release the netlink socket

See Also
  • Previous Chapters

    • Hello world

    • Kthread

    • Tasklets

    • Workqueues

    • Timers

    • Linked List

    • File System

  • Other Netlink topic

    • Netlink : Multicast

Previous Next

© Copyright 2023, c-pointers.