Thursday, February 5, 2015

Explanation and code snippet to read hotplug events from a netlink socket

Complete source file can be downloaded here:
Source code for this program is here.
Complete repository can be downloaded or cloned here.

Parts of the code are as explained below:
The kernel notifies the userspace like (udev) about new available devices by  (1) Spawning a process or (2) a packet to a netlink socket on attach. Code taken directly from the kernel documentation:
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>

  #include <sys/poll.h>
  #include <sys/socket.h>
  #include <sys/types.h>
  #include <unistd.h>

  #include <linux/types.h>
  #include <linux/netlink.h>
Error handling:
  void die(char *s)
  {
 write(2,s,strlen(s));
 exit(1);
  }
Main file:
  int main(int argc, char *argv[])
  {
 struct sockaddr_nl nls;
 struct pollfd pfd;
 char buf[512];

 // Open hotplug event netlink socket

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

 pfd.events = POLLIN;
 pfd.fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
 if (pfd.fd==-1)
  die("Not root\n");
Listen to the socket:
 if (bind(pfd.fd, (void *)&nls, sizeof(struct sockaddr_nl)))
  die("Bind failed\n");
 while (-1!=poll(&pfd, 1, -1)) {
  int i, len = recv(pfd.fd, buf, sizeof(buf), MSG_DONTWAIT);
  if (len == -1) die("recv\n");
Print the data once it is read:
  i = 0;
  while (i<len) {
   printf("%s\n", buf+i);
   i += strlen(buf+i)+1;
  }
 }
 die("poll\n");

 // Dear gcc: shut up.
 return 0;
  }
Running the code:


The code reads all hotplug events arriving on the datagram socket and prints them to stdout (your screen).  Sample output when you run this code:
[sleepylinux tmp]$ ./a.out
add@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1
SUBSYSTEM=usb
MAJOR=189
MINOR=2
DEVNAME=bus/usb/001/003
DEVTYPE=usb_device
DEVICE=/proc/bus/usb/001/003
PRODUCT=2001/3c1a/101
TYPE=0/0/0
BUSNUM=001
DEVNUM=003
SEQNUM=2284
add@/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.1/1-1.1:1.0
SUBSYSTEM=usb
DEVTYPE=usb_interface
DEVICE=/proc/bus/usb/001/003
PRODUCT=2001/3c1a/101
TYPE=0/0/0
INTERFACE=255/255/255
MODALIAS=usb:v2001p3C1Ad0101dc00dsc00dp00icFFiscFFipFF
SEQNUM=2285
udev-147
 REMEMBER to plug in a new device to see any output. If you do not connect any new device you will not see any packets to the netlink socket and hence any output from your program.

0 comments:

Post a Comment