libmnl  1.0.5
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 size_t mnl_nlmsg_size(size_t len)
55 {
56  return len + MNL_NLMSG_HDRLEN;
57 }
58 
66 EXPORT_SYMBOL size_t mnl_nlmsg_get_payload_len(const struct nlmsghdr *nlh)
67 {
68  return nlh->nlmsg_len - MNL_NLMSG_HDRLEN;
69 }
70 
80 EXPORT_SYMBOL struct nlmsghdr *mnl_nlmsg_put_header(void *buf)
81 {
82  int len = MNL_ALIGN(sizeof(struct nlmsghdr));
83  struct nlmsghdr *nlh = buf;
84 
85  memset(buf, 0, len);
86  nlh->nlmsg_len = len;
87  return nlh;
88 }
89 
101 EXPORT_SYMBOL void *mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh,
102  size_t size)
103 {
104  char *ptr = (char *)nlh + nlh->nlmsg_len;
105  size_t len = MNL_ALIGN(size);
106  nlh->nlmsg_len += len;
107  memset(ptr, 0, len);
108  return ptr;
109 }
110 
117 EXPORT_SYMBOL void *mnl_nlmsg_get_payload(const struct nlmsghdr *nlh)
118 {
119  return (void *)nlh + MNL_NLMSG_HDRLEN;
120 }
121 
130 EXPORT_SYMBOL void *mnl_nlmsg_get_payload_offset(const struct nlmsghdr *nlh,
131  size_t offset)
132 {
133  return (void *)nlh + MNL_NLMSG_HDRLEN + MNL_ALIGN(offset);
134 }
135 
152 EXPORT_SYMBOL bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len)
153 {
154  size_t ulen = len;
155 
156  if (len < 0)
157  return false;
158 
159  return ulen >= sizeof(struct nlmsghdr) &&
160  nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
161  nlh->nlmsg_len <= ulen;
162 }
163 
177 EXPORT_SYMBOL struct nlmsghdr *mnl_nlmsg_next(const struct nlmsghdr *nlh,
178  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 void *mnl_nlmsg_get_payload_tail(const struct nlmsghdr *nlh)
193 {
194  return (void *)nlh + MNL_ALIGN(nlh->nlmsg_len);
195 }
196 
211 EXPORT_SYMBOL bool mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh,
212  unsigned int seq)
213 {
214  return nlh->nlmsg_seq && seq ? nlh->nlmsg_seq == seq : true;
215 }
216 
231 EXPORT_SYMBOL bool mnl_nlmsg_portid_ok(const struct nlmsghdr *nlh,
232  unsigned int portid)
233 {
234  return nlh->nlmsg_pid && portid ? nlh->nlmsg_pid == portid : true;
235 }
236 
237 static void mnl_nlmsg_fprintf_header(FILE *fd, const struct nlmsghdr *nlh)
238 {
239  fprintf(fd, "----------------\t------------------\n");
240  fprintf(fd, "| %.010u |\t| message length |\n", nlh->nlmsg_len);
241  fprintf(fd, "| %.05u | %c%c%c%c |\t| type | flags |\n",
242  nlh->nlmsg_type,
243  nlh->nlmsg_flags & NLM_F_REQUEST ? 'R' : '-',
244  nlh->nlmsg_flags & NLM_F_MULTI ? 'M' : '-',
245  nlh->nlmsg_flags & NLM_F_ACK ? 'A' : '-',
246  nlh->nlmsg_flags & NLM_F_ECHO ? 'E' : '-');
247  fprintf(fd, "| %.010u |\t| sequence number|\n", nlh->nlmsg_seq);
248  fprintf(fd, "| %.010u |\t| port ID |\n", nlh->nlmsg_pid);
249  fprintf(fd, "----------------\t------------------\n");
250 }
251 
252 static void mnl_nlmsg_fprintf_payload(FILE *fd, const struct nlmsghdr *nlh,
253  size_t extra_header_size)
254 {
255  int rem = 0;
256  unsigned int i;
257 
258  for (i=sizeof(struct nlmsghdr); i<nlh->nlmsg_len; i+=4) {
259  char *b = (char *) nlh;
260  struct nlattr *attr = (struct nlattr *) (b+i);
261 
262  /* netlink control message. */
263  if (nlh->nlmsg_type < NLMSG_MIN_TYPE) {
264  fprintf(fd, "| %.2x %.2x %.2x %.2x |\t",
265  0xff & b[i], 0xff & b[i+1],
266  0xff & b[i+2], 0xff & b[i+3]);
267  fprintf(fd, "| |\n");
268  /* special handling for the extra header. */
269  } else if (extra_header_size > 0) {
270  extra_header_size -= 4;
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, "| extra header |\n");
275  /* this seems like an attribute header. */
276  } else if (rem == 0 && (attr->nla_type & NLA_TYPE_MASK) != 0) {
277  fprintf(fd, "|%c[%d;%dm"
278  "%.5u"
279  "%c[%dm"
280  "|"
281  "%c[%d;%dm"
282  "%c%c"
283  "%c[%dm"
284  "|"
285  "%c[%d;%dm"
286  "%.5u"
287  "%c[%dm|\t",
288  27, 1, 31,
289  attr->nla_len,
290  27, 0,
291  27, 1, 32,
292  attr->nla_type & NLA_F_NESTED ? 'N' : '-',
293  attr->nla_type &
294  NLA_F_NET_BYTEORDER ? 'B' : '-',
295  27, 0,
296  27, 1, 34,
297  attr->nla_type & NLA_TYPE_MASK,
298  27, 0);
299  fprintf(fd, "|len |flags| type|\n");
300 
301  if (!(attr->nla_type & NLA_F_NESTED)) {
302  rem = NLA_ALIGN(attr->nla_len) -
303  sizeof(struct nlattr);
304  }
305  /* this is the attribute payload. */
306  } else if (rem > 0) {
307  rem -= 4;
308  fprintf(fd, "| %.2x %.2x %.2x %.2x |\t",
309  0xff & b[i], 0xff & b[i+1],
310  0xff & b[i+2], 0xff & b[i+3]);
311  fprintf(fd, "| data |");
312  fprintf(fd, "\t %c %c %c %c\n",
313  isprint(b[i]) ? b[i] : ' ',
314  isprint(b[i+1]) ? b[i+1] : ' ',
315  isprint(b[i+2]) ? b[i+2] : ' ',
316  isprint(b[i+3]) ? b[i+3] : ' ');
317  }
318  }
319  fprintf(fd, "----------------\t------------------\n");
320 }
321 
365 EXPORT_SYMBOL void mnl_nlmsg_fprintf(FILE *fd, const void *data, size_t datalen,
366  size_t extra_header_size)
367 {
368  const struct nlmsghdr *nlh = data;
369  int len = datalen;
370 
371  while (mnl_nlmsg_ok(nlh, len)) {
372  mnl_nlmsg_fprintf_header(fd, nlh);
373  mnl_nlmsg_fprintf_payload(fd, nlh, extra_header_size);
374  nlh = mnl_nlmsg_next(nlh, &len);
375  }
376 }
377 
416 struct mnl_nlmsg_batch {
417  /* the buffer that is used to store the batch. */
418  void *buf;
419  size_t limit;
420  size_t buflen;
421  /* the current netlink message in the batch. */
422  void *cur;
423  bool overflow;
424 };
425 
439 EXPORT_SYMBOL struct mnl_nlmsg_batch *mnl_nlmsg_batch_start(void *buf,
440  size_t limit)
441 {
442  struct mnl_nlmsg_batch *b;
443 
444  b = malloc(sizeof(struct mnl_nlmsg_batch));
445  if (b == NULL)
446  return NULL;
447 
448  b->buf = buf;
449  b->limit = limit;
450  b->buflen = 0;
451  b->cur = buf;
452  b->overflow = false;
453 
454  return b;
455 }
456 
463 EXPORT_SYMBOL void mnl_nlmsg_batch_stop(struct mnl_nlmsg_batch *b)
464 {
465  free(b);
466 }
467 
479 EXPORT_SYMBOL bool mnl_nlmsg_batch_next(struct mnl_nlmsg_batch *b)
480 {
481  struct nlmsghdr *nlh = b->cur;
482 
483  if (b->buflen + nlh->nlmsg_len > b->limit) {
484  b->overflow = true;
485  return false;
486  }
487  b->cur = b->buf + b->buflen + nlh->nlmsg_len;
488  b->buflen += nlh->nlmsg_len;
489  return true;
490 }
491 
500 EXPORT_SYMBOL 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 size_t mnl_nlmsg_batch_size(struct mnl_nlmsg_batch *b)
521 {
522  return b->buflen;
523 }
524 
532 EXPORT_SYMBOL void *mnl_nlmsg_batch_head(struct mnl_nlmsg_batch *b)
533 {
534  return b->buf;
535 }
536 
544 EXPORT_SYMBOL void *mnl_nlmsg_batch_current(struct mnl_nlmsg_batch *b)
545 {
546  return b->cur;
547 }
548 
555 EXPORT_SYMBOL bool mnl_nlmsg_batch_is_empty(struct mnl_nlmsg_batch *b)
556 {
557  return b->buflen == 0;
558 }
559 
size_t mnl_nlmsg_batch_size(struct mnl_nlmsg_batch *b)
Definition: nlmsg.c:520
void * mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh, size_t size)
Definition: nlmsg.c:101
bool mnl_nlmsg_batch_is_empty(struct mnl_nlmsg_batch *b)
Definition: nlmsg.c:555
void mnl_nlmsg_fprintf(FILE *fd, const void *data, size_t datalen, size_t extra_header_size)
Definition: nlmsg.c:365
void * mnl_nlmsg_batch_current(struct mnl_nlmsg_batch *b)
Definition: nlmsg.c:544
struct nlmsghdr * mnl_nlmsg_next(const struct nlmsghdr *nlh, int *len)
Definition: nlmsg.c:177
void * mnl_nlmsg_batch_head(struct mnl_nlmsg_batch *b)
Definition: nlmsg.c:532
size_t mnl_nlmsg_get_payload_len(const struct nlmsghdr *nlh)
Definition: nlmsg.c:66
struct mnl_nlmsg_batch * mnl_nlmsg_batch_start(void *buf, size_t limit)
Definition: nlmsg.c:439
bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len)
Definition: nlmsg.c:152
void * mnl_nlmsg_get_payload_tail(const struct nlmsghdr *nlh)
Definition: nlmsg.c:192
struct nlmsghdr * mnl_nlmsg_put_header(void *buf)
Definition: nlmsg.c:80
bool mnl_nlmsg_portid_ok(const struct nlmsghdr *nlh, unsigned int portid)
Definition: nlmsg.c:231
void mnl_nlmsg_batch_reset(struct mnl_nlmsg_batch *b)
Definition: nlmsg.c:500
bool mnl_nlmsg_batch_next(struct mnl_nlmsg_batch *b)
Definition: nlmsg.c:479
void mnl_nlmsg_batch_stop(struct mnl_nlmsg_batch *b)
Definition: nlmsg.c:463
void * mnl_nlmsg_get_payload_offset(const struct nlmsghdr *nlh, size_t offset)
Definition: nlmsg.c:130
size_t mnl_nlmsg_size(size_t len)
Definition: nlmsg.c:54
bool mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh, unsigned int seq)
Definition: nlmsg.c:211
void * mnl_nlmsg_get_payload(const struct nlmsghdr *nlh)
Definition: nlmsg.c:117