nl.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <errno.h>
  5. #include <asm/types.h>
  6. #include <sys/types.h>
  7. #include <sys/socket.h>
  8. #include <linux/netlink.h>
  9. #include <sys/select.h>
  10. #include <sys/time.h>
  11. #include <unistd.h>
  12. #include "nl.h"
  13. nl_fds_t * nl_init(void)
  14. {
  15. struct sockaddr_nl nl_addr;
  16. nl_fds_t *nl_fds;
  17. nl_fds = malloc(sizeof(*nl_fds) * NL_FDS_LEN);
  18. if (!nl_fds)
  19. return NULL;
  20. memset(&nl_addr, 0, sizeof(nl_addr));
  21. nl_addr.nl_family = AF_NETLINK;
  22. nl_addr.nl_pad = 0;
  23. nl_addr.nl_pid = 0; /* Let kernel to assign id */
  24. nl_addr.nl_groups = -1; /* Listen all multicast */
  25. /* NETLINK_KOBJECT_UEVENT for PCI events */
  26. if ((nl_fds[0] = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT)) < 0) {
  27. fprintf(stderr, "Error: Can't create socket for NETLINK_KOBJECT_UEVENT.\n");
  28. return NULL;
  29. }
  30. if (bind(nl_fds[0], (void *)&nl_addr, sizeof(nl_addr))) {
  31. fprintf(stderr, "Error: Can't bind NETLINK_KOBJECT_UEVENT.\n");
  32. return NULL;
  33. }
  34. /* NETLINK_ROUTER for network events like interface up/down */
  35. if ((nl_fds[1] = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) {
  36. fprintf(stderr, "Error: Can't create socket for NETLINK_ROUTER\n");
  37. return NULL;
  38. }
  39. if (bind(nl_fds[1], (void *)&nl_addr, sizeof(nl_addr))) {
  40. fprintf(stderr, "Error: Can't bind NETLINK_ROUTER\n");
  41. return NULL;
  42. }
  43. /* TODO: Parse NETWORK events to filter many unneeded events */
  44. /* Temporarily disable network events */
  45. close(nl_fds[1]);
  46. nl_fds[1] = -1;
  47. return nl_fds;
  48. }
  49. void nl_close(nl_fds_t *nl_fds)
  50. {
  51. int i;
  52. if (!nl_fds)
  53. return;
  54. for (i = 0; i < NL_FDS_LEN; i++) {
  55. if (nl_fds[i] >= 0)
  56. close(nl_fds[i]);
  57. }
  58. free(nl_fds);
  59. }
  60. int nl_poll(nl_fds_t *nl_fds, int timeout)
  61. {
  62. fd_set fd_set;
  63. char buf[10];
  64. int n;
  65. int i;
  66. int nfds = 0;
  67. struct timeval tv;
  68. if (!nl_fds)
  69. return -1;
  70. /* Initialize the set of active sockets. */
  71. FD_ZERO(&fd_set);
  72. for (i = 0; i < NL_FDS_LEN; i++) {
  73. if (nl_fds[i] < 0)
  74. continue;
  75. FD_SET(nl_fds[i], &fd_set);
  76. if (nl_fds[i] > nfds)
  77. nfds = nl_fds[i];
  78. }
  79. nfds++;
  80. /* Wait up to five seconds. */
  81. tv.tv_sec = timeout;
  82. tv.tv_usec = 0;
  83. n = select(nfds, &fd_set, NULL, NULL, &tv);
  84. if (n < 0) {
  85. if (EINTR == errno)
  86. return -2;
  87. return -1;
  88. }
  89. if (0 == n)
  90. return n;
  91. /* Service all the sockets with input pending. */
  92. for (i = 0; i < NL_FDS_LEN; i++) {
  93. char *evtype = NULL;
  94. if (nl_fds[i] < 0)
  95. continue;
  96. if (!FD_ISSET(nl_fds[i], &fd_set))
  97. continue;
  98. switch (i) {
  99. case 0:
  100. evtype = "kernel";
  101. break;
  102. case 1:
  103. evtype = "network";
  104. break;
  105. default:
  106. evtype = "unknown";
  107. break;
  108. }
  109. printf("Receive %s event\n", evtype);
  110. /* Read all messages. We don't need a message content. */
  111. while (recv(nl_fds[i], buf, sizeof(buf), MSG_DONTWAIT) > 0);
  112. }
  113. return n;
  114. }