libmnl  1.0.3
nlmsg.c
1 /*
2  * (C) 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published
6  * by the Free Software Foundation; either version 2.1 of the License, or
7  * (at your option) any later version.
8  */
9 #include <stdbool.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <ctype.h>
13 #include <errno.h>
14 #include <string.h>
15 #include <libmnl/libmnl.h>
16 #include "internal.h"
17 
54 size_t mnl_nlmsg_size(size_t len)
55 {
56  return len + MNL_NLMSG_HDRLEN;
57 }
58 EXPORT_SYMBOL(mnl_nlmsg_size);
59 
67 size_t mnl_nlmsg_get_payload_len(const struct nlmsghdr *nlh)
68 {
69  return nlh->nlmsg_len - MNL_NLMSG_HDRLEN;
70 }
71 EXPORT_SYMBOL(mnl_nlmsg_get_payload_len);
72 
82 struct nlmsghdr *mnl_nlmsg_put_header(void *buf)
83 {
84  int len = MNL_ALIGN(sizeof(struct nlmsghdr));
85  struct nlmsghdr *nlh = buf;
86 
87  memset(buf, 0, len);
88  nlh->nlmsg_len = len;
89  return nlh;
90 }
91 EXPORT_SYMBOL(mnl_nlmsg_put_header);
92 
104 void *
105 mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh, size_t size)
106 {
107  char *ptr = (char *)nlh + nlh->nlmsg_len;
108  size_t len = MNL_ALIGN(size);
109  nlh->nlmsg_len += len;
110  memset(ptr, 0, len);
111  return ptr;
112 }
113 EXPORT_SYMBOL(mnl_nlmsg_put_extra_header);
114 
121 void *mnl_nlmsg_get_payload(const struct nlmsghdr *nlh)
122 {
123  return (void *)nlh + MNL_NLMSG_HDRLEN;
124 }
125 EXPORT_SYMBOL(mnl_nlmsg_get_payload);
126 
135 void *
136 mnl_nlmsg_get_payload_offset(const struct nlmsghdr *nlh, size_t offset)
137 {
138  return (void *)nlh + MNL_NLMSG_HDRLEN + MNL_ALIGN(offset);
139 }
140 EXPORT_SYMBOL(mnl_nlmsg_get_payload_offset);
141 
158 bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len)
159 {
160  return len >= (int)sizeof(struct nlmsghdr) &&
161  nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
162  (int)nlh->nlmsg_len <= len;
163 }
164 EXPORT_SYMBOL(mnl_nlmsg_ok);
165 
179 struct nlmsghdr *
180 mnl_nlmsg_next(const struct nlmsghdr *nlh, int *len)
181 {
182  *len -= MNL_ALIGN(nlh->nlmsg_len);
183  return (struct nlmsghdr *)((void *)nlh + MNL_ALIGN(nlh->nlmsg_len));
184 }
185 EXPORT_SYMBOL(mnl_nlmsg_next);
186 
195 void *mnl_nlmsg_get_payload_tail(const struct nlmsghdr *nlh)
196 {
197  return (void *)nlh + MNL_ALIGN(nlh->nlmsg_len);
198 }
199 EXPORT_SYMBOL(mnl_nlmsg_get_payload_tail);
200 
215 bool
216 mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh, unsigned int seq)
217 {
218  return nlh->nlmsg_seq && seq ? nlh->nlmsg_seq == seq : true;
219 }
220 EXPORT_SYMBOL(mnl_nlmsg_seq_ok);
221 
236 bool
237 mnl_nlmsg_portid_ok(const struct nlmsghdr *nlh, unsigned int portid)
238 {
239  return nlh->nlmsg_pid && portid ? nlh->nlmsg_pid == portid : true;
240 }
241 EXPORT_SYMBOL(mnl_nlmsg_portid_ok);
242 
243 static void mnl_nlmsg_fprintf_header(FILE *fd, const struct nlmsghdr *nlh)
244 {
245  fprintf(fd, "----------------\t------------------\n");
246  fprintf(fd, "| %.010u |\t| message length |\n", nlh->nlmsg_len);
247  fprintf(fd, "| %.05u | %c%c%c%c |\t| type | flags |\n",
248  nlh->nlmsg_type,
249  nlh->nlmsg_flags & NLM_F_REQUEST ? 'R' : '-',
250  nlh->nlmsg_flags & NLM_F_MULTI ? 'M' : '-',
251  nlh->nlmsg_flags & NLM_F_ACK ? 'A' : '-',
252  nlh->nlmsg_flags & NLM_F_ECHO ? 'E' : '-');
253  fprintf(fd, "| %.010u |\t| sequence number|\n", nlh->nlmsg_seq);
254  fprintf(fd, "| %.010u |\t| port ID |\n", nlh->nlmsg_pid);
255  fprintf(fd, "----------------\t------------------\n");
256 }
257 
258 static void
259 mnl_nlmsg_fprintf_payload(FILE *fd, const struct nlmsghdr *nlh,
260  size_t extra_header_size)
261 {
262  int rem = 0;
263  unsigned int i;
264 
265  for (i=sizeof(struct nlmsghdr); i<nlh->nlmsg_len; i+=4) {
266  char *b = (char *) nlh;
267  struct nlattr *attr = (struct nlattr *) (b+i);
268 
269  /* netlink control message. */
270  if (nlh->nlmsg_type < NLMSG_MIN_TYPE) {
271  fprintf(fd, "| %.2x %.2x %.2x %.2x |\t",
272  0xff & b[i], 0xff & b[i+1],
273  0xff & b[i+2], 0xff & b[i+3]);
274  fprintf(fd, "| |\n");
275  /* special handling for the extra header. */
276  } else if (extra_header_size > 0) {
277  extra_header_size -= 4;
278  fprintf(fd, "| %.2x %.2x %.2x %.2x |\t",
279  0xff & b[i], 0xff & b[i+1],
280  0xff & b[i+2], 0xff & b[i+3]);
281  fprintf(fd, "| extra header |\n");
282  /* this seems like an attribute header. */
283  } else if (rem == 0 && (attr->nla_type & NLA_TYPE_MASK) != 0) {
284  fprintf(fd, "|%c[%d;%dm"
285  "%.5u"
286  "%c[%dm"
287  "|"
288  "%c[%d;%dm"
289  "%c%c"
290  "%c[%dm"
291  "|"
292  "%c[%d;%dm"
293  "%.5u"
294  "%c[%dm|\t",
295  27, 1, 31,
296  attr->nla_len,
297  27, 0,
298  27, 1, 32,
299  attr->nla_type & NLA_F_NESTED ? 'N' : '-',
300  attr->nla_type &
301  NLA_F_NET_BYTEORDER ? 'B' : '-',
302  27, 0,
303  27, 1, 34,
304  attr->nla_type & NLA_TYPE_MASK,
305  27, 0);
306  fprintf(fd, "|len |flags| type|\n");
307 
308  if (!(attr->nla_type & NLA_F_NESTED)) {
309  rem = NLA_ALIGN(attr->nla_len) -
310  sizeof(struct nlattr);
311  }
312  /* this is the attribute payload. */
313  } else if (rem > 0) {
314  rem -= 4;
315  fprintf(fd, "| %.2x %.2x %.2x %.2x |\t",
316  0xff & b[i], 0xff & b[i+1],
317  0xff & b[i+2], 0xff & b[i+3]);
318  fprintf(fd, "| data |");
319  fprintf(fd, "\t %c %c %c %c\n",
320  isalnum(b[i]) ? b[i] : 0,
321  isalnum(b[i+1]) ? b[i+1] : 0,
322  isalnum(b[i+2]) ? b[i+2] : 0,
323  isalnum(b[i+3]) ? b[i+3] : 0);
324  }
325  }
326  fprintf(fd, "----------------\t------------------\n");
327 }
328 
372 void
373 mnl_nlmsg_fprintf(FILE *fd, const void *data, size_t datalen,
374  size_t extra_header_size)
375 {
376  const struct nlmsghdr *nlh = data;
377  int len = datalen;
378 
379  while (mnl_nlmsg_ok(nlh, len)) {
380  mnl_nlmsg_fprintf_header(fd, nlh);
381  mnl_nlmsg_fprintf_payload(fd, nlh, extra_header_size);
382  nlh = mnl_nlmsg_next(nlh, &len);
383  }
384 }
385 EXPORT_SYMBOL(mnl_nlmsg_fprintf);
386 
421  /* the buffer that is used to store the batch. */
422  void *buf;
423  size_t limit;
424  size_t buflen;
425  /* the current netlink message in the batch. */
426  void *cur;
427  bool overflow;
428 };
429 
443 struct mnl_nlmsg_batch *mnl_nlmsg_batch_start(void *buf, size_t limit)
444 {
445  struct mnl_nlmsg_batch *b;
446 
447  b = malloc(sizeof(struct mnl_nlmsg_batch));
448  if (b == NULL)
449  return NULL;
450 
451  b->buf = buf;
452  b->limit = limit;
453  b->buflen = 0;
454  b->cur = buf;
455  b->overflow = false;
456 
457  return b;
458 }
459 EXPORT_SYMBOL(mnl_nlmsg_batch_start);
460 
468 {
469  free(b);
470 }
471 EXPORT_SYMBOL(mnl_nlmsg_batch_stop);
472 
485 {
486  struct nlmsghdr *nlh = b->cur;
487 
488  if (b->buflen + nlh->nlmsg_len > b->limit) {
489  b->overflow = true;
490  return false;
491  }
492  b->cur = b->buf + b->buflen + nlh->nlmsg_len;
493  b->buflen += nlh->nlmsg_len;
494  return true;
495 }
496 EXPORT_SYMBOL(mnl_nlmsg_batch_next);
497 
507 {
508  if (b->overflow) {
509  struct nlmsghdr *nlh = b->cur;
510  memcpy(b->buf, b->cur, nlh->nlmsg_len);
511  b->buflen = nlh->nlmsg_len;
512  b->cur = b->buf + b->buflen;
513  b->overflow = false;
514  } else {
515  b->buflen = 0;
516  b->cur = b->buf;
517  }
518 }
519 EXPORT_SYMBOL(mnl_nlmsg_batch_reset);
520 
528 {
529  return b->buflen;
530 }
531 EXPORT_SYMBOL(mnl_nlmsg_batch_size);
532 
541 {
542  return b->buf;
543 }
544 EXPORT_SYMBOL(mnl_nlmsg_batch_head);
545 
554 {
555  return b->cur;
556 }
557 EXPORT_SYMBOL(mnl_nlmsg_batch_current);
558 
566 {
567  return b->buflen == 0;
568 }
569 EXPORT_SYMBOL(mnl_nlmsg_batch_is_empty);
570