libmnl  1.0.3
nlmsg.c
00001 /*
00002  * (C) 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
00003  *
00004  * This program is free software; you can redistribute it and/or modify
00005  * it under the terms of the GNU Lesser General Public License as published
00006  * by the Free Software Foundation; either version 2.1 of the License, or
00007  * (at your option) any later version.
00008  */
00009 #include <stdbool.h>
00010 #include <stdio.h>
00011 #include <stdlib.h>
00012 #include <ctype.h>
00013 #include <errno.h>
00014 #include <string.h>
00015 #include <libmnl/libmnl.h>
00016 #include "internal.h"
00017 
00054 size_t mnl_nlmsg_size(size_t len)
00055 {
00056         return len + MNL_NLMSG_HDRLEN;
00057 }
00058 EXPORT_SYMBOL(mnl_nlmsg_size);
00059 
00067 size_t mnl_nlmsg_get_payload_len(const struct nlmsghdr *nlh)
00068 {
00069         return nlh->nlmsg_len - MNL_NLMSG_HDRLEN;
00070 }
00071 EXPORT_SYMBOL(mnl_nlmsg_get_payload_len);
00072 
00082 struct nlmsghdr *mnl_nlmsg_put_header(void *buf)
00083 {
00084         int len = MNL_ALIGN(sizeof(struct nlmsghdr));
00085         struct nlmsghdr *nlh = buf;
00086 
00087         memset(buf, 0, len);
00088         nlh->nlmsg_len = len;
00089         return nlh;
00090 }
00091 EXPORT_SYMBOL(mnl_nlmsg_put_header);
00092 
00104 void *
00105 mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh, size_t size)
00106 {
00107         char *ptr = (char *)nlh + nlh->nlmsg_len;
00108         size_t len = MNL_ALIGN(size);
00109         nlh->nlmsg_len += len;
00110         memset(ptr, 0, len);
00111         return ptr;
00112 }
00113 EXPORT_SYMBOL(mnl_nlmsg_put_extra_header);
00114 
00121 void *mnl_nlmsg_get_payload(const struct nlmsghdr *nlh)
00122 {
00123         return (void *)nlh + MNL_NLMSG_HDRLEN;
00124 }
00125 EXPORT_SYMBOL(mnl_nlmsg_get_payload);
00126 
00135 void *
00136 mnl_nlmsg_get_payload_offset(const struct nlmsghdr *nlh, size_t offset)
00137 {
00138         return (void *)nlh + MNL_NLMSG_HDRLEN + MNL_ALIGN(offset);
00139 }
00140 EXPORT_SYMBOL(mnl_nlmsg_get_payload_offset);
00141 
00158 bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len)
00159 {
00160         return len >= (int)sizeof(struct nlmsghdr) &&
00161                nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
00162                (int)nlh->nlmsg_len <= len;
00163 }
00164 EXPORT_SYMBOL(mnl_nlmsg_ok);
00165 
00179 struct nlmsghdr *
00180 mnl_nlmsg_next(const struct nlmsghdr *nlh, int *len)
00181 {
00182         *len -= MNL_ALIGN(nlh->nlmsg_len);
00183         return (struct nlmsghdr *)((void *)nlh + MNL_ALIGN(nlh->nlmsg_len));
00184 }
00185 EXPORT_SYMBOL(mnl_nlmsg_next);
00186 
00195 void *mnl_nlmsg_get_payload_tail(const struct nlmsghdr *nlh)
00196 {
00197         return (void *)nlh + MNL_ALIGN(nlh->nlmsg_len);
00198 }
00199 EXPORT_SYMBOL(mnl_nlmsg_get_payload_tail);
00200 
00215 bool
00216 mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh, unsigned int seq)
00217 {
00218         return nlh->nlmsg_seq && seq ? nlh->nlmsg_seq == seq : true;
00219 }
00220 EXPORT_SYMBOL(mnl_nlmsg_seq_ok);
00221 
00236 bool
00237 mnl_nlmsg_portid_ok(const struct nlmsghdr *nlh, unsigned int portid)
00238 {
00239         return nlh->nlmsg_pid && portid ? nlh->nlmsg_pid == portid : true;
00240 }
00241 EXPORT_SYMBOL(mnl_nlmsg_portid_ok);
00242 
00243 static void mnl_nlmsg_fprintf_header(FILE *fd, const struct nlmsghdr *nlh)
00244 {
00245         fprintf(fd, "----------------\t------------------\n");
00246         fprintf(fd, "|  %.010u  |\t| message length |\n", nlh->nlmsg_len);
00247         fprintf(fd, "| %.05u | %c%c%c%c |\t|  type | flags  |\n",
00248                 nlh->nlmsg_type,
00249                 nlh->nlmsg_flags & NLM_F_REQUEST ? 'R' : '-',
00250                 nlh->nlmsg_flags & NLM_F_MULTI ? 'M' : '-',
00251                 nlh->nlmsg_flags & NLM_F_ACK ? 'A' : '-',
00252                 nlh->nlmsg_flags & NLM_F_ECHO ? 'E' : '-');
00253         fprintf(fd, "|  %.010u  |\t| sequence number|\n", nlh->nlmsg_seq);
00254         fprintf(fd, "|  %.010u  |\t|     port ID    |\n", nlh->nlmsg_pid);
00255         fprintf(fd, "----------------\t------------------\n");
00256 }
00257 
00258 static void
00259 mnl_nlmsg_fprintf_payload(FILE *fd, const struct nlmsghdr *nlh,
00260                           size_t extra_header_size)
00261 {
00262         int rem = 0;
00263         unsigned int i;
00264 
00265         for (i=sizeof(struct nlmsghdr); i<nlh->nlmsg_len; i+=4) {
00266                 char *b = (char *) nlh;
00267                 struct nlattr *attr = (struct nlattr *) (b+i);
00268 
00269                 /* netlink control message. */
00270                 if (nlh->nlmsg_type < NLMSG_MIN_TYPE) {
00271                         fprintf(fd, "| %.2x %.2x %.2x %.2x  |\t",
00272                                 0xff & b[i],    0xff & b[i+1],
00273                                 0xff & b[i+2],  0xff & b[i+3]);
00274                         fprintf(fd, "|                |\n");
00275                 /* special handling for the extra header. */
00276                 } else if (extra_header_size > 0) {
00277                         extra_header_size -= 4;
00278                         fprintf(fd, "| %.2x %.2x %.2x %.2x  |\t",
00279                                 0xff & b[i],    0xff & b[i+1],
00280                                 0xff & b[i+2],  0xff & b[i+3]);
00281                         fprintf(fd, "|  extra header  |\n");
00282                 /* this seems like an attribute header. */
00283                 } else if (rem == 0 && (attr->nla_type & NLA_TYPE_MASK) != 0) {
00284                         fprintf(fd, "|%c[%d;%dm"
00285                                     "%.5u"
00286                                     "%c[%dm"
00287                                     "|"
00288                                     "%c[%d;%dm"
00289                                     "%c%c"
00290                                     "%c[%dm"
00291                                     "|"
00292                                     "%c[%d;%dm"
00293                                     "%.5u"
00294                                     "%c[%dm|\t",
00295                                 27, 1, 31,
00296                                 attr->nla_len,
00297                                 27, 0,
00298                                 27, 1, 32,
00299                                 attr->nla_type & NLA_F_NESTED ? 'N' : '-',
00300                                 attr->nla_type &
00301                                         NLA_F_NET_BYTEORDER ? 'B' : '-',
00302                                 27, 0,
00303                                 27, 1, 34,
00304                                 attr->nla_type & NLA_TYPE_MASK,
00305                                 27, 0);
00306                         fprintf(fd, "|len |flags| type|\n");
00307 
00308                         if (!(attr->nla_type & NLA_F_NESTED)) {
00309                                 rem = NLA_ALIGN(attr->nla_len) -
00310                                         sizeof(struct nlattr);
00311                         }
00312                 /* this is the attribute payload. */
00313                 } else if (rem > 0) {
00314                         rem -= 4;
00315                         fprintf(fd, "| %.2x %.2x %.2x %.2x  |\t",
00316                                 0xff & b[i],    0xff & b[i+1],
00317                                 0xff & b[i+2],  0xff & b[i+3]);
00318                         fprintf(fd, "|      data      |");
00319                         fprintf(fd, "\t %c %c %c %c\n",
00320                                 isalnum(b[i]) ? b[i] : 0,
00321                                 isalnum(b[i+1]) ? b[i+1] : 0,
00322                                 isalnum(b[i+2]) ? b[i+2] : 0,
00323                                 isalnum(b[i+3]) ? b[i+3] : 0);
00324                 }
00325         }
00326         fprintf(fd, "----------------\t------------------\n");
00327 }
00328 
00372 void
00373 mnl_nlmsg_fprintf(FILE *fd, const void *data, size_t datalen,
00374                   size_t extra_header_size)
00375 {
00376         const struct nlmsghdr *nlh = data;
00377         int len = datalen;
00378 
00379         while (mnl_nlmsg_ok(nlh, len)) {
00380                 mnl_nlmsg_fprintf_header(fd, nlh);
00381                 mnl_nlmsg_fprintf_payload(fd, nlh, extra_header_size);
00382                 nlh = mnl_nlmsg_next(nlh, &len);
00383         }
00384 }
00385 EXPORT_SYMBOL(mnl_nlmsg_fprintf);
00386 
00420 struct mnl_nlmsg_batch {
00421         /* the buffer that is used to store the batch. */
00422         void *buf;
00423         size_t limit;
00424         size_t buflen;
00425         /* the current netlink message in the batch. */
00426         void *cur;
00427         bool overflow;
00428 };
00429 
00443 struct mnl_nlmsg_batch *mnl_nlmsg_batch_start(void *buf, size_t limit)
00444 {
00445         struct mnl_nlmsg_batch *b;
00446 
00447         b = malloc(sizeof(struct mnl_nlmsg_batch));
00448         if (b == NULL)
00449                 return NULL;
00450 
00451         b->buf = buf;
00452         b->limit = limit;
00453         b->buflen = 0;
00454         b->cur = buf;
00455         b->overflow = false;
00456 
00457         return b;
00458 }
00459 EXPORT_SYMBOL(mnl_nlmsg_batch_start);
00460 
00467 void mnl_nlmsg_batch_stop(struct mnl_nlmsg_batch *b)
00468 {
00469         free(b);
00470 }
00471 EXPORT_SYMBOL(mnl_nlmsg_batch_stop);
00472 
00484 bool mnl_nlmsg_batch_next(struct mnl_nlmsg_batch *b)
00485 {
00486         struct nlmsghdr *nlh = b->cur;
00487 
00488         if (b->buflen + nlh->nlmsg_len > b->limit) {
00489                 b->overflow = true;
00490                 return false;
00491         }
00492         b->cur = b->buf + b->buflen + nlh->nlmsg_len;
00493         b->buflen += nlh->nlmsg_len;
00494         return true;
00495 }
00496 EXPORT_SYMBOL(mnl_nlmsg_batch_next);
00497 
00506 void mnl_nlmsg_batch_reset(struct mnl_nlmsg_batch *b)
00507 {
00508         if (b->overflow) {
00509                 struct nlmsghdr *nlh = b->cur;
00510                 memcpy(b->buf, b->cur, nlh->nlmsg_len);
00511                 b->buflen = nlh->nlmsg_len;
00512                 b->cur = b->buf + b->buflen;
00513                 b->overflow = false;
00514         } else {
00515                 b->buflen = 0;
00516                 b->cur = b->buf;
00517         }
00518 }
00519 EXPORT_SYMBOL(mnl_nlmsg_batch_reset);
00520 
00527 size_t mnl_nlmsg_batch_size(struct mnl_nlmsg_batch *b)
00528 {
00529         return b->buflen;
00530 }
00531 EXPORT_SYMBOL(mnl_nlmsg_batch_size);
00532 
00540 void *mnl_nlmsg_batch_head(struct mnl_nlmsg_batch *b)
00541 {
00542         return b->buf;
00543 }
00544 EXPORT_SYMBOL(mnl_nlmsg_batch_head);
00545 
00553 void *mnl_nlmsg_batch_current(struct mnl_nlmsg_batch *b)
00554 {
00555         return b->cur;
00556 }
00557 EXPORT_SYMBOL(mnl_nlmsg_batch_current);
00558 
00565 bool mnl_nlmsg_batch_is_empty(struct mnl_nlmsg_batch *b)
00566 {
00567         return b->buflen == 0;
00568 }
00569 EXPORT_SYMBOL(mnl_nlmsg_batch_is_empty);
00570