PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/libsystemd/sd-netlink/netlink-socket.c

https://gitlab.com/unofficial-mirrors/systemd
C | 463 lines | 321 code | 107 blank | 35 comment | 85 complexity | 50301aaff8af88858b6b748228308238 MD5 | raw file
  1. /* SPDX-License-Identifier: LGPL-2.1+ */
  2. /***
  3. This file is part of systemd.
  4. Copyright 2013 Tom Gundersen <teg@jklm.no>
  5. ***/
  6. #include <netinet/in.h>
  7. #include <stdbool.h>
  8. #include <unistd.h>
  9. #include "sd-netlink.h"
  10. #include "alloc-util.h"
  11. #include "fd-util.h"
  12. #include "format-util.h"
  13. #include "missing.h"
  14. #include "netlink-internal.h"
  15. #include "netlink-types.h"
  16. #include "netlink-util.h"
  17. #include "refcnt.h"
  18. #include "socket-util.h"
  19. #include "util.h"
  20. int socket_open(int family) {
  21. int fd;
  22. fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, family);
  23. if (fd < 0)
  24. return -errno;
  25. return fd_move_above_stdio(fd);
  26. }
  27. static int broadcast_groups_get(sd_netlink *nl) {
  28. _cleanup_free_ uint32_t *groups = NULL;
  29. socklen_t len = 0, old_len;
  30. unsigned i, j;
  31. int r;
  32. assert(nl);
  33. assert(nl->fd >= 0);
  34. r = getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, NULL, &len);
  35. if (r < 0) {
  36. if (errno == ENOPROTOOPT) {
  37. nl->broadcast_group_dont_leave = true;
  38. return 0;
  39. } else
  40. return -errno;
  41. }
  42. if (len == 0)
  43. return 0;
  44. groups = new0(uint32_t, len);
  45. if (!groups)
  46. return -ENOMEM;
  47. old_len = len;
  48. r = getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, groups, &len);
  49. if (r < 0)
  50. return -errno;
  51. if (old_len != len)
  52. return -EIO;
  53. r = hashmap_ensure_allocated(&nl->broadcast_group_refs, NULL);
  54. if (r < 0)
  55. return r;
  56. for (i = 0; i < len; i++) {
  57. for (j = 0; j < sizeof(uint32_t) * 8; j++) {
  58. uint32_t offset;
  59. unsigned group;
  60. offset = 1U << j;
  61. if (!(groups[i] & offset))
  62. continue;
  63. group = i * sizeof(uint32_t) * 8 + j + 1;
  64. r = hashmap_put(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(1));
  65. if (r < 0)
  66. return r;
  67. }
  68. }
  69. return 0;
  70. }
  71. int socket_bind(sd_netlink *nl) {
  72. socklen_t addrlen;
  73. int r, one = 1;
  74. r = setsockopt(nl->fd, SOL_NETLINK, NETLINK_PKTINFO, &one, sizeof(one));
  75. if (r < 0)
  76. return -errno;
  77. addrlen = sizeof(nl->sockaddr);
  78. r = bind(nl->fd, &nl->sockaddr.sa, addrlen);
  79. /* ignore EINVAL to allow opening an already bound socket */
  80. if (r < 0 && errno != EINVAL)
  81. return -errno;
  82. r = getsockname(nl->fd, &nl->sockaddr.sa, &addrlen);
  83. if (r < 0)
  84. return -errno;
  85. r = broadcast_groups_get(nl);
  86. if (r < 0)
  87. return r;
  88. return 0;
  89. }
  90. static unsigned broadcast_group_get_ref(sd_netlink *nl, unsigned group) {
  91. assert(nl);
  92. return PTR_TO_UINT(hashmap_get(nl->broadcast_group_refs, UINT_TO_PTR(group)));
  93. }
  94. static int broadcast_group_set_ref(sd_netlink *nl, unsigned group, unsigned n_ref) {
  95. int r;
  96. assert(nl);
  97. r = hashmap_replace(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(n_ref));
  98. if (r < 0)
  99. return r;
  100. return 0;
  101. }
  102. static int broadcast_group_join(sd_netlink *nl, unsigned group) {
  103. int r;
  104. assert(nl);
  105. assert(nl->fd >= 0);
  106. assert(group > 0);
  107. r = setsockopt(nl->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));
  108. if (r < 0)
  109. return -errno;
  110. return 0;
  111. }
  112. int socket_broadcast_group_ref(sd_netlink *nl, unsigned group) {
  113. unsigned n_ref;
  114. int r;
  115. assert(nl);
  116. n_ref = broadcast_group_get_ref(nl, group);
  117. n_ref++;
  118. r = hashmap_ensure_allocated(&nl->broadcast_group_refs, NULL);
  119. if (r < 0)
  120. return r;
  121. r = broadcast_group_set_ref(nl, group, n_ref);
  122. if (r < 0)
  123. return r;
  124. if (n_ref > 1)
  125. /* not yet in the group */
  126. return 0;
  127. r = broadcast_group_join(nl, group);
  128. if (r < 0)
  129. return r;
  130. return 0;
  131. }
  132. static int broadcast_group_leave(sd_netlink *nl, unsigned group) {
  133. int r;
  134. assert(nl);
  135. assert(nl->fd >= 0);
  136. assert(group > 0);
  137. if (nl->broadcast_group_dont_leave)
  138. return 0;
  139. r = setsockopt(nl->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, &group, sizeof(group));
  140. if (r < 0)
  141. return -errno;
  142. return 0;
  143. }
  144. int socket_broadcast_group_unref(sd_netlink *nl, unsigned group) {
  145. unsigned n_ref;
  146. int r;
  147. assert(nl);
  148. n_ref = broadcast_group_get_ref(nl, group);
  149. assert(n_ref > 0);
  150. n_ref--;
  151. r = broadcast_group_set_ref(nl, group, n_ref);
  152. if (r < 0)
  153. return r;
  154. if (n_ref > 0)
  155. /* still refs left */
  156. return 0;
  157. r = broadcast_group_leave(nl, group);
  158. if (r < 0)
  159. return r;
  160. return 0;
  161. }
  162. /* returns the number of bytes sent, or a negative error code */
  163. int socket_write_message(sd_netlink *nl, sd_netlink_message *m) {
  164. union {
  165. struct sockaddr sa;
  166. struct sockaddr_nl nl;
  167. } addr = {
  168. .nl.nl_family = AF_NETLINK,
  169. };
  170. ssize_t k;
  171. assert(nl);
  172. assert(m);
  173. assert(m->hdr);
  174. k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
  175. 0, &addr.sa, sizeof(addr));
  176. if (k < 0)
  177. return -errno;
  178. return k;
  179. }
  180. static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool peek) {
  181. union sockaddr_union sender;
  182. uint8_t cmsg_buffer[CMSG_SPACE(sizeof(struct nl_pktinfo))];
  183. struct msghdr msg = {
  184. .msg_iov = iov,
  185. .msg_iovlen = 1,
  186. .msg_name = &sender,
  187. .msg_namelen = sizeof(sender),
  188. .msg_control = cmsg_buffer,
  189. .msg_controllen = sizeof(cmsg_buffer),
  190. };
  191. struct cmsghdr *cmsg;
  192. uint32_t group = 0;
  193. ssize_t n;
  194. assert(fd >= 0);
  195. assert(iov);
  196. n = recvmsg(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0));
  197. if (n < 0) {
  198. /* no data */
  199. if (errno == ENOBUFS)
  200. log_debug("rtnl: kernel receive buffer overrun");
  201. else if (errno == EAGAIN)
  202. log_debug("rtnl: no data in socket");
  203. return IN_SET(errno, EAGAIN, EINTR) ? 0 : -errno;
  204. }
  205. if (sender.nl.nl_pid != 0) {
  206. /* not from the kernel, ignore */
  207. log_debug("rtnl: ignoring message from portid %"PRIu32, sender.nl.nl_pid);
  208. if (peek) {
  209. /* drop the message */
  210. n = recvmsg(fd, &msg, 0);
  211. if (n < 0)
  212. return IN_SET(errno, EAGAIN, EINTR) ? 0 : -errno;
  213. }
  214. return 0;
  215. }
  216. CMSG_FOREACH(cmsg, &msg) {
  217. if (cmsg->cmsg_level == SOL_NETLINK &&
  218. cmsg->cmsg_type == NETLINK_PKTINFO &&
  219. cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) {
  220. struct nl_pktinfo *pktinfo = (void *)CMSG_DATA(cmsg);
  221. /* multi-cast group */
  222. group = pktinfo->group;
  223. }
  224. }
  225. if (_group)
  226. *_group = group;
  227. return (int) n;
  228. }
  229. /* On success, the number of bytes received is returned and *ret points to the received message
  230. * which has a valid header and the correct size.
  231. * If nothing useful was received 0 is returned.
  232. * On failure, a negative error code is returned.
  233. */
  234. int socket_read_message(sd_netlink *rtnl) {
  235. _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *first = NULL;
  236. struct iovec iov = {};
  237. uint32_t group = 0;
  238. bool multi_part = false, done = false;
  239. struct nlmsghdr *new_msg;
  240. size_t len;
  241. int r;
  242. unsigned i = 0;
  243. const NLTypeSystem *type_system_root;
  244. assert(rtnl);
  245. assert(rtnl->rbuffer);
  246. assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
  247. type_system_root = type_system_get_root(rtnl->protocol);
  248. /* read nothing, just get the pending message size */
  249. r = socket_recv_message(rtnl->fd, &iov, NULL, true);
  250. if (r <= 0)
  251. return r;
  252. else
  253. len = (size_t) r;
  254. /* make room for the pending message */
  255. if (!greedy_realloc((void **)&rtnl->rbuffer,
  256. &rtnl->rbuffer_allocated,
  257. len, sizeof(uint8_t)))
  258. return -ENOMEM;
  259. iov.iov_base = rtnl->rbuffer;
  260. iov.iov_len = rtnl->rbuffer_allocated;
  261. /* read the pending message */
  262. r = socket_recv_message(rtnl->fd, &iov, &group, false);
  263. if (r <= 0)
  264. return r;
  265. else
  266. len = (size_t) r;
  267. if (len > rtnl->rbuffer_allocated)
  268. /* message did not fit in read buffer */
  269. return -EIO;
  270. if (NLMSG_OK(rtnl->rbuffer, len) && rtnl->rbuffer->nlmsg_flags & NLM_F_MULTI) {
  271. multi_part = true;
  272. for (i = 0; i < rtnl->rqueue_partial_size; i++) {
  273. if (rtnl_message_get_serial(rtnl->rqueue_partial[i]) ==
  274. rtnl->rbuffer->nlmsg_seq) {
  275. first = rtnl->rqueue_partial[i];
  276. break;
  277. }
  278. }
  279. }
  280. for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) {
  281. _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
  282. const NLType *nl_type;
  283. if (!group && new_msg->nlmsg_pid != rtnl->sockaddr.nl.nl_pid)
  284. /* not broadcast and not for us */
  285. continue;
  286. if (new_msg->nlmsg_type == NLMSG_NOOP)
  287. /* silently drop noop messages */
  288. continue;
  289. if (new_msg->nlmsg_type == NLMSG_DONE) {
  290. /* finished reading multi-part message */
  291. done = true;
  292. /* if first is not defined, put NLMSG_DONE into the receive queue. */
  293. if (first)
  294. continue;
  295. }
  296. /* check that we support this message type */
  297. r = type_system_get_type(type_system_root, &nl_type, new_msg->nlmsg_type);
  298. if (r < 0) {
  299. if (r == -EOPNOTSUPP)
  300. log_debug("sd-netlink: ignored message with unknown type: %i",
  301. new_msg->nlmsg_type);
  302. continue;
  303. }
  304. /* check that the size matches the message type */
  305. if (new_msg->nlmsg_len < NLMSG_LENGTH(type_get_size(nl_type))) {
  306. log_debug("sd-netlink: message larger than expected, dropping");
  307. continue;
  308. }
  309. r = message_new_empty(rtnl, &m);
  310. if (r < 0)
  311. return r;
  312. m->broadcast = !!group;
  313. m->hdr = memdup(new_msg, new_msg->nlmsg_len);
  314. if (!m->hdr)
  315. return -ENOMEM;
  316. /* seal and parse the top-level message */
  317. r = sd_netlink_message_rewind(m);
  318. if (r < 0)
  319. return r;
  320. /* push the message onto the multi-part message stack */
  321. if (first)
  322. m->next = first;
  323. first = TAKE_PTR(m);
  324. }
  325. if (len > 0)
  326. log_debug("sd-netlink: discarding %zu bytes of incoming message", len);
  327. if (!first)
  328. return 0;
  329. if (!multi_part || done) {
  330. /* we got a complete message, push it on the read queue */
  331. r = rtnl_rqueue_make_room(rtnl);
  332. if (r < 0)
  333. return r;
  334. rtnl->rqueue[rtnl->rqueue_size++] = TAKE_PTR(first);
  335. if (multi_part && (i < rtnl->rqueue_partial_size)) {
  336. /* remove the message form the partial read queue */
  337. memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1,
  338. sizeof(sd_netlink_message*) * (rtnl->rqueue_partial_size - i - 1));
  339. rtnl->rqueue_partial_size--;
  340. }
  341. return 1;
  342. } else {
  343. /* we only got a partial multi-part message, push it on the
  344. partial read queue */
  345. if (i < rtnl->rqueue_partial_size)
  346. rtnl->rqueue_partial[i] = TAKE_PTR(first);
  347. else {
  348. r = rtnl_rqueue_partial_make_room(rtnl);
  349. if (r < 0)
  350. return r;
  351. rtnl->rqueue_partial[rtnl->rqueue_partial_size++] = TAKE_PTR(first);
  352. }
  353. return 0;
  354. }
  355. }