libmnl  1.0.4
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 EXPORT_SYMBOL(mnl_nlmsg_size);
55 size_t mnl_nlmsg_size(size_t len)
56 {
57  return len + MNL_NLMSG_HDRLEN;
58 }
59 
67 EXPORT_SYMBOL(mnl_nlmsg_get_payload_len);
68 size_t mnl_nlmsg_get_payload_len(const struct nlmsghdr *nlh)
69 {
70  return nlh->nlmsg_len - MNL_NLMSG_HDRLEN;
71 }
72 
82 EXPORT_SYMBOL(mnl_nlmsg_put_header);
83 struct nlmsghdr *mnl_nlmsg_put_header(void *buf)
84 {
85  int len = MNL_ALIGN(sizeof(struct nlmsghdr));
86  struct nlmsghdr *nlh = buf;
87 
88  memset(buf, 0, len);
89  nlh->nlmsg_len = len;
90  return nlh;
91 }
92 
104 EXPORT_SYMBOL(mnl_nlmsg_put_extra_header);
105 void *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 
120 EXPORT_SYMBOL(mnl_nlmsg_get_payload);
121 void *mnl_nlmsg_get_payload(const struct nlmsghdr *nlh)
122 {
123  return (void *)nlh + MNL_NLMSG_HDRLEN;
124 }
125 
134 EXPORT_SYMBOL(mnl_nlmsg_get_payload_offset);
135 void *mnl_nlmsg_get_payload_offset(const struct nlmsghdr *nlh, size_t offset)
136 {
137  return (void *)nlh + MNL_NLMSG_HDRLEN + MNL_ALIGN(offset);
138 }
139 
156 EXPORT_SYMBOL(mnl_nlmsg_ok);
157 bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len)
158 {
159  return len >= (int)sizeof(struct nlmsghdr) &&
160  nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
161  (int)nlh->nlmsg_len <= len;
162 }
163 
177 EXPORT_SYMBOL(mnl_nlmsg_next);
178 struct nlmsghdr *mnl_nlmsg_next(const struct nlmsghdr *nlh, int *len)
179 {
180  *len -= MNL_ALIGN(nlh->nlmsg_len);
181  return (struct nlmsghdr *)((void *)nlh + MNL_ALIGN(nlh->nlmsg_len));
182 }
183 
192 EXPORT_SYMBOL(mnl_nlmsg_get_payload_tail);
193 void *mnl_nlmsg_get_payload_tail(const struct nlmsghdr *nlh)
194 {
195  return (void *)nlh + MNL_ALIGN(nlh->nlmsg_len);
196 }
197 
212 EXPORT_SYMBOL(mnl_nlmsg_seq_ok);
213 bool mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh, unsigned int seq)
214 {
215  return nlh->nlmsg_seq && seq ? nlh->nlmsg_seq == seq : true;
216 }
217 
232 EXPORT_SYMBOL(mnl_nlmsg_portid_ok);
233 bool mnl_nlmsg_portid_ok(const struct nlmsghdr *nlh, unsigned int portid)
234 {
235  return nlh->nlmsg_pid && portid ? nlh->nlmsg_pid == portid : true;
236 }
237 
238 static void mnl_nlmsg_fprintf_header(FILE *fd, const struct nlmsghdr *nlh)
239 {
240  fprintf(fd, "----------------\t------------------\n");
241  fprintf(fd, "| %.010u |\t| message length |\n", nlh->nlmsg_len);
242  fprintf(fd, "| %.05u | %c%c%c%c |\t| type | flags |\n",
243  nlh->nlmsg_type,
244  nlh->nlmsg_flags & NLM_F_REQUEST ? 'R' : '-',
245  nlh->nlmsg_flags & NLM_F_MULTI ? 'M' : '-',
246  nlh->nlmsg_flags & NLM_F_ACK ? 'A' : '-',
247  nlh->nlmsg_flags & NLM_F_ECHO ? 'E' : '-');
248  fprintf(fd, "| %.010u |\t| sequence number|\n", nlh->nlmsg_seq);
249  fprintf(fd, "| %.010u |\t| port ID |\n", nlh->nlmsg_pid);
250  fprintf(fd, "----------------\t------------------\n");
251 }
252 
253 static void mnl_nlmsg_fprintf_payload(FILE *fd, const struct nlmsghdr *nlh,
254  size_t extra_header_size)
255 {
256  int rem = 0;
257  unsigned int i;
258 
259  for (i=sizeof(struct nlmsghdr); i<nlh->nlmsg_len; i+=4) {
260  char *b = (char *) nlh;
261  struct nlattr *attr = (struct nlattr *) (b+i);
262 
263  /* netlink control message. */
264  if (nlh->nlmsg_type < NLMSG_MIN_TYPE) {
265  fprintf(fd, "| %.2x %.2x %.2x %.2x |\t",
266  0xff & b[i], 0xff & b[i+1],
267  0xff & b[i+2], 0xff & b[i+3]);
268  fprintf(fd, "| |\n");
269  /* special handling for the extra header. */
270  } else if (extra_header_size > 0) {
271  extra_header_size -= 4;
272  fprintf(fd, "| %.2x %.2x %.2x %.2x |\t",
273  0xff & b[i], 0xff & b[i+1],
274  0xff & b[i+2], 0xff & b[i+3]);
275  fprintf(fd, "| extra header |\n");
276  /* this seems like an attribute header. */
277  } else if (rem == 0 && (attr->nla_type & NLA_TYPE_MASK) != 0) {
278  fprintf(fd, "|%c[%d;%dm"
279  "%.5u"
280  "%c[%dm"
281  "|"
282  "%c[%d;%dm"
283  "%c%c"
284  "%c[%dm"
285  "|"
286  "%c[%d;%dm"
287  "%.5u"
288  "%c[%dm|\t",
289  27, 1, 31,
290  attr->nla_len,
291  27, 0,
292  27, 1, 32,
293  attr->nla_type & NLA_F_NESTED ? 'N' : '-',
294  attr->nla_type &
295  NLA_F_NET_BYTEORDER ? 'B' : '-',
296  27, 0,
297  27, 1, 34,
298  attr->nla_type & NLA_TYPE_MASK,
299  27, 0);
300  fprintf(fd, "|len |flags| type|\n");
301 
302  if (!(attr->nla_type & NLA_F_NESTED)) {
303  rem = NLA_ALIGN(attr->nla_len) -
304  sizeof(struct nlattr);
305  }
306  /* this is the attribute payload. */
307  } else if (rem > 0) {
308  rem -= 4;
309  fprintf(fd, "| %.2x %.2x %.2x %.2x |\t",
310  0xff & b[i], 0xff & b[i+1],
311  0xff & b[i+2], 0xff & b[i+3]);
312  fprintf(fd, "| data |");
313  fprintf(fd, "\t %c %c %c %c\n",
314  isprint(b[i]) ? b[i] : ' ',
315  isprint(b[i+1]) ? b[i+1] : ' ',
316  isprint(b[i+2]) ? b[i+2] : ' ',
317  isprint(b[i+3]) ? b[i+3] : ' ');
318  }
319  }
320  fprintf(fd, "----------------\t------------------\n");
321 }
322 
366 EXPORT_SYMBOL(mnl_nlmsg_fprintf);
367 void mnl_nlmsg_fprintf(FILE *fd, const void *data, size_t datalen,
368  size_t extra_header_size)
369 {
370  const struct nlmsghdr *nlh = data;
371  int len = datalen;
372 
373  while (mnl_nlmsg_ok(nlh, len)) {
374  mnl_nlmsg_fprintf_header(fd, nlh);
375  mnl_nlmsg_fprintf_payload(fd, nlh, extra_header_size);
376  nlh = mnl_nlmsg_next(nlh, &len);
377  }
378 }
379 
414  /* the buffer that is used to store the batch. */
415  void *buf;
416  size_t limit;
417  size_t buflen;
418  /* the current netlink message in the batch. */
419  void *cur;
420  bool overflow;
421 };
422 
436 EXPORT_SYMBOL(mnl_nlmsg_batch_start);
437 struct mnl_nlmsg_batch *mnl_nlmsg_batch_start(void *buf, size_t limit)
438 {
439  struct mnl_nlmsg_batch *b;
440 
441  b = malloc(sizeof(struct mnl_nlmsg_batch));
442  if (b == NULL)
443  return NULL;
444 
445  b->buf = buf;
446  b->limit = limit;
447  b->buflen = 0;
448  b->cur = buf;
449  b->overflow = false;
450 
451  return b;
452 }
453 
460 EXPORT_SYMBOL(mnl_nlmsg_batch_stop);
461 void mnl_nlmsg_batch_stop(struct mnl_nlmsg_batch *b)
462 {
463  free(b);
464 }
465 
477 EXPORT_SYMBOL(mnl_nlmsg_batch_next);
478 bool mnl_nlmsg_batch_next(struct mnl_nlmsg_batch *b)
479 {
480  struct nlmsghdr *nlh = b->cur;
481 
482  if (b->buflen + nlh->nlmsg_len > b->limit) {
483  b->overflow = true;
484  return false;
485  }
486  b->cur = b->buf + b->buflen + nlh->nlmsg_len;
487  b->buflen += nlh->nlmsg_len;
488  return true;
489 }
490 
499 EXPORT_SYMBOL(mnl_nlmsg_batch_reset);
500 void mnl_nlmsg_batch_reset(struct mnl_nlmsg_batch *b)
501 {
502  if (b->overflow) {
503  struct nlmsghdr *nlh = b->cur;
504  memcpy(b->buf, b->cur, nlh->nlmsg_len);
505  b->buflen = nlh->nlmsg_len;
506  b->cur = b->buf + b->buflen;
507  b->overflow = false;
508  } else {
509  b->buflen = 0;
510  b->cur = b->buf;
511  }
512 }
513 
520 EXPORT_SYMBOL(mnl_nlmsg_batch_size);
521 size_t mnl_nlmsg_batch_size(struct mnl_nlmsg_batch *b)
522 {
523  return b->buflen;
524 }
525 
533 EXPORT_SYMBOL(mnl_nlmsg_batch_head);
534 void *mnl_nlmsg_batch_head(struct mnl_nlmsg_batch *b)
535 {
536  return b->buf;
537 }
538 
546 EXPORT_SYMBOL(mnl_nlmsg_batch_current);
547 void *mnl_nlmsg_batch_current(struct mnl_nlmsg_batch *b)
548 {
549  return b->cur;
550 }
551 
558 EXPORT_SYMBOL(mnl_nlmsg_batch_is_empty);
559 bool mnl_nlmsg_batch_is_empty(struct mnl_nlmsg_batch *b)
560 {
561  return b->buflen == 0;
562 }
563