netlink_message_writer.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. /*-
  2. * SPDX-License-Identifier: BSD-2-Clause
  3. *
  4. * Copyright (c) 2022 Alexander V. Chernikov <melifaro@FreeBSD.org>
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  16. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  21. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  22. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  23. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  24. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  25. * SUCH DAMAGE.
  26. */
  27. #include <sys/param.h>
  28. #include <sys/malloc.h>
  29. #include <sys/lock.h>
  30. #include <sys/rmlock.h>
  31. #include <sys/mbuf.h>
  32. #include <sys/socket.h>
  33. #include <sys/socketvar.h>
  34. #include <sys/syslog.h>
  35. #include <netlink/netlink.h>
  36. #include <netlink/netlink_ctl.h>
  37. #include <netlink/netlink_linux.h>
  38. #include <netlink/netlink_var.h>
  39. #define DEBUG_MOD_NAME nl_writer
  40. #define DEBUG_MAX_LEVEL LOG_DEBUG3
  41. #include <netlink/netlink_debug.h>
  42. _DECLARE_DEBUG(LOG_INFO);
  43. static bool
  44. nlmsg_get_buf(struct nl_writer *nw, u_int len, bool waitok)
  45. {
  46. const int mflag = waitok ? M_WAITOK : M_NOWAIT;
  47. MPASS(nw->buf == NULL);
  48. NL_LOG(LOG_DEBUG3, "Setting up nw %p len %u %s", nw, len,
  49. waitok ? "wait" : "nowait");
  50. nw->buf = nl_buf_alloc(len, mflag);
  51. if (__predict_false(nw->buf == NULL))
  52. return (false);
  53. nw->hdr = NULL;
  54. nw->malloc_flag = mflag;
  55. nw->num_messages = 0;
  56. nw->enomem = false;
  57. return (true);
  58. }
  59. static bool
  60. nl_send_one(struct nl_writer *nw)
  61. {
  62. return (nl_send(nw, nw->nlp));
  63. }
  64. bool
  65. _nlmsg_get_unicast_writer(struct nl_writer *nw, int size, struct nlpcb *nlp)
  66. {
  67. nw->nlp = nlp;
  68. nw->cb = nl_send_one;
  69. return (nlmsg_get_buf(nw, size, false));
  70. }
  71. bool
  72. _nlmsg_get_group_writer(struct nl_writer *nw, int size, int protocol, int group_id)
  73. {
  74. nw->group.proto = protocol;
  75. nw->group.id = group_id;
  76. nw->cb = nl_send_group;
  77. return (nlmsg_get_buf(nw, size, false));
  78. }
  79. void
  80. _nlmsg_ignore_limit(struct nl_writer *nw)
  81. {
  82. nw->ignore_limit = true;
  83. }
  84. bool
  85. _nlmsg_flush(struct nl_writer *nw)
  86. {
  87. bool result;
  88. if (__predict_false(nw->hdr != NULL)) {
  89. /* Last message has not been completed, skip it. */
  90. int completed_len = (char *)nw->hdr - nw->buf->data;
  91. /* Send completed messages */
  92. nw->buf->datalen -= nw->buf->datalen - completed_len;
  93. nw->hdr = NULL;
  94. }
  95. if (nw->buf->datalen == 0) {
  96. MPASS(nw->num_messages == 0);
  97. nl_buf_free(nw->buf);
  98. nw->buf = NULL;
  99. return (true);
  100. }
  101. result = nw->cb(nw);
  102. nw->num_messages = 0;
  103. if (!result) {
  104. NL_LOG(LOG_DEBUG, "nw %p flush with %p() failed", nw, nw->cb);
  105. }
  106. return (result);
  107. }
  108. /*
  109. * Flushes previous data and allocates new underlying storage
  110. * sufficient for holding at least @required_len bytes.
  111. * Return true on success.
  112. */
  113. bool
  114. _nlmsg_refill_buffer(struct nl_writer *nw, u_int required_len)
  115. {
  116. struct nl_buf *new;
  117. u_int completed_len, new_len, last_len;
  118. MPASS(nw->buf != NULL);
  119. if (nw->enomem)
  120. return (false);
  121. NL_LOG(LOG_DEBUG3, "no space at offset %u/%u (want %u), trying to "
  122. "reclaim", nw->buf->datalen, nw->buf->buflen, required_len);
  123. /* Calculate new buffer size and allocate it. */
  124. completed_len = (nw->hdr != NULL) ?
  125. (char *)nw->hdr - nw->buf->data : nw->buf->datalen;
  126. if (completed_len > 0 && required_len < NLMBUFSIZE) {
  127. /* We already ran out of space, use largest effective size. */
  128. new_len = max(nw->buf->buflen, NLMBUFSIZE);
  129. } else {
  130. if (nw->buf->buflen < NLMBUFSIZE)
  131. /* XXXGL: does this happen? */
  132. new_len = NLMBUFSIZE;
  133. else
  134. new_len = nw->buf->buflen * 2;
  135. while (new_len < required_len)
  136. new_len *= 2;
  137. }
  138. new = nl_buf_alloc(new_len, nw->malloc_flag | M_ZERO);
  139. if (__predict_false(new == NULL)) {
  140. nw->enomem = true;
  141. NL_LOG(LOG_DEBUG, "getting new buf failed, setting ENOMEM");
  142. return (false);
  143. }
  144. /* Copy last (unfinished) header to the new storage. */
  145. last_len = nw->buf->datalen - completed_len;
  146. if (last_len > 0) {
  147. memcpy(new->data, nw->hdr, last_len);
  148. new->datalen = last_len;
  149. }
  150. NL_LOG(LOG_DEBUG2, "completed: %u bytes, copied: %u bytes",
  151. completed_len, last_len);
  152. if (completed_len > 0) {
  153. nlmsg_flush(nw);
  154. MPASS(nw->buf == NULL);
  155. } else
  156. nl_buf_free(nw->buf);
  157. nw->buf = new;
  158. nw->hdr = (last_len > 0) ? (struct nlmsghdr *)new->data : NULL;
  159. NL_LOG(LOG_DEBUG2, "switched buffer: used %u/%u bytes",
  160. new->datalen, new->buflen);
  161. return (true);
  162. }
  163. bool
  164. _nlmsg_add(struct nl_writer *nw, uint32_t portid, uint32_t seq, uint16_t type,
  165. uint16_t flags, uint32_t len)
  166. {
  167. struct nl_buf *nb = nw->buf;
  168. struct nlmsghdr *hdr;
  169. u_int required_len;
  170. MPASS(nw->hdr == NULL);
  171. required_len = NETLINK_ALIGN(len + sizeof(struct nlmsghdr));
  172. if (__predict_false(nb->datalen + required_len > nb->buflen)) {
  173. if (!nlmsg_refill_buffer(nw, required_len))
  174. return (false);
  175. nb = nw->buf;
  176. }
  177. hdr = (struct nlmsghdr *)(&nb->data[nb->datalen]);
  178. hdr->nlmsg_len = len;
  179. hdr->nlmsg_type = type;
  180. hdr->nlmsg_flags = flags;
  181. hdr->nlmsg_seq = seq;
  182. hdr->nlmsg_pid = portid;
  183. nw->hdr = hdr;
  184. nb->datalen += sizeof(struct nlmsghdr);
  185. return (true);
  186. }
  187. bool
  188. _nlmsg_end(struct nl_writer *nw)
  189. {
  190. struct nl_buf *nb = nw->buf;
  191. MPASS(nw->hdr != NULL);
  192. if (nw->enomem) {
  193. NL_LOG(LOG_DEBUG, "ENOMEM when dumping message");
  194. nlmsg_abort(nw);
  195. return (false);
  196. }
  197. nw->hdr->nlmsg_len = nb->data + nb->datalen - (char *)nw->hdr;
  198. NL_LOG(LOG_DEBUG2, "wrote msg len: %u type: %d: flags: 0x%X seq: %u pid: %u",
  199. nw->hdr->nlmsg_len, nw->hdr->nlmsg_type, nw->hdr->nlmsg_flags,
  200. nw->hdr->nlmsg_seq, nw->hdr->nlmsg_pid);
  201. nw->hdr = NULL;
  202. nw->num_messages++;
  203. return (true);
  204. }
  205. void
  206. _nlmsg_abort(struct nl_writer *nw)
  207. {
  208. struct nl_buf *nb = nw->buf;
  209. if (nw->hdr != NULL) {
  210. nb->datalen = (char *)nw->hdr - nb->data;
  211. nw->hdr = NULL;
  212. }
  213. }
  214. void
  215. nlmsg_ack(struct nlpcb *nlp, int error, struct nlmsghdr *hdr,
  216. struct nl_pstate *npt)
  217. {
  218. struct nlmsgerr *errmsg;
  219. int payload_len;
  220. uint32_t flags = nlp->nl_flags;
  221. struct nl_writer *nw = npt->nw;
  222. bool cap_ack;
  223. payload_len = sizeof(struct nlmsgerr);
  224. /*
  225. * The only case when we send the full message in the
  226. * reply is when there is an error and NETLINK_CAP_ACK
  227. * is not set.
  228. */
  229. cap_ack = (error == 0) || (flags & NLF_CAP_ACK);
  230. if (!cap_ack)
  231. payload_len += hdr->nlmsg_len - sizeof(struct nlmsghdr);
  232. payload_len = NETLINK_ALIGN(payload_len);
  233. uint16_t nl_flags = cap_ack ? NLM_F_CAPPED : 0;
  234. if ((npt->err_msg || npt->err_off) && nlp->nl_flags & NLF_EXT_ACK)
  235. nl_flags |= NLM_F_ACK_TLVS;
  236. NL_LOG(LOG_DEBUG3, "acknowledging message type %d seq %d",
  237. hdr->nlmsg_type, hdr->nlmsg_seq);
  238. if (!nlmsg_add(nw, nlp->nl_port, hdr->nlmsg_seq, NLMSG_ERROR, nl_flags, payload_len))
  239. goto enomem;
  240. errmsg = nlmsg_reserve_data(nw, payload_len, struct nlmsgerr);
  241. errmsg->error = error;
  242. /* In case of error copy the whole message, else just the header */
  243. memcpy(&errmsg->msg, hdr, cap_ack ? sizeof(*hdr) : hdr->nlmsg_len);
  244. if (npt->err_msg != NULL && nlp->nl_flags & NLF_EXT_ACK)
  245. nlattr_add_string(nw, NLMSGERR_ATTR_MSG, npt->err_msg);
  246. if (npt->err_off != 0 && nlp->nl_flags & NLF_EXT_ACK)
  247. nlattr_add_u32(nw, NLMSGERR_ATTR_OFFS, npt->err_off);
  248. if (npt->cookie != NULL)
  249. nlattr_add_raw(nw, npt->cookie);
  250. if (nlmsg_end(nw))
  251. return;
  252. enomem:
  253. NLP_LOG(LOG_DEBUG, nlp, "error allocating ack data for message %d seq %u",
  254. hdr->nlmsg_type, hdr->nlmsg_seq);
  255. nlmsg_abort(nw);
  256. }
  257. bool
  258. _nlmsg_end_dump(struct nl_writer *nw, int error, struct nlmsghdr *hdr)
  259. {
  260. if (!nlmsg_add(nw, hdr->nlmsg_pid, hdr->nlmsg_seq, NLMSG_DONE, 0, sizeof(int))) {
  261. NL_LOG(LOG_DEBUG, "Error finalizing table dump");
  262. return (false);
  263. }
  264. /* Save operation result */
  265. int *perror = nlmsg_reserve_object(nw, int);
  266. NL_LOG(LOG_DEBUG2, "record error=%d at off %d (%p)", error,
  267. nw->buf->datalen, perror);
  268. *perror = error;
  269. nlmsg_end(nw);
  270. nw->suppress_ack = true;
  271. return (true);
  272. }
  273. /*
  274. * KPI functions.
  275. */
  276. u_int
  277. nlattr_save_offset(const struct nl_writer *nw)
  278. {
  279. return (nw->buf->datalen - ((char *)nw->hdr - nw->buf->data));
  280. }
  281. void *
  282. nlmsg_reserve_data_raw(struct nl_writer *nw, size_t sz)
  283. {
  284. struct nl_buf *nb = nw->buf;
  285. void *data;
  286. sz = NETLINK_ALIGN(sz);
  287. if (__predict_false(nb->datalen + sz > nb->buflen)) {
  288. if (!nlmsg_refill_buffer(nw, sz))
  289. return (NULL);
  290. nb = nw->buf;
  291. }
  292. data = &nb->data[nb->datalen];
  293. bzero(data, sz);
  294. nb->datalen += sz;
  295. return (data);
  296. }
  297. bool
  298. nlattr_add(struct nl_writer *nw, int attr_type, int attr_len, const void *data)
  299. {
  300. struct nl_buf *nb = nw->buf;
  301. struct nlattr *nla;
  302. u_int required_len;
  303. required_len = NLA_ALIGN(attr_len + sizeof(struct nlattr));
  304. if (__predict_false(nb->datalen + required_len > nb->buflen)) {
  305. if (!nlmsg_refill_buffer(nw, required_len))
  306. return (false);
  307. nb = nw->buf;
  308. }
  309. nla = (struct nlattr *)(&nb->data[nb->datalen]);
  310. nla->nla_len = attr_len + sizeof(struct nlattr);
  311. nla->nla_type = attr_type;
  312. if (attr_len > 0) {
  313. if ((attr_len % 4) != 0) {
  314. /* clear padding bytes */
  315. bzero((char *)nla + required_len - 4, 4);
  316. }
  317. memcpy((nla + 1), data, attr_len);
  318. }
  319. nb->datalen += required_len;
  320. return (true);
  321. }
  322. #include <netlink/ktest_netlink_message_writer.h>