00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161 #include <netlink-local.h>
00162 #include <netlink/netlink.h>
00163 #include <netlink/utils.h>
00164 #include <netlink/cache.h>
00165 #include <netlink/attr.h>
00166 #include <linux/socket.h>
00167
00168 static size_t default_msg_size;
00169
00170 static void __init init_msg_size(void)
00171 {
00172 default_msg_size = getpagesize();
00173 }
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186 int nlmsg_size(int payload)
00187 {
00188 return NLMSG_HDRLEN + payload;
00189 }
00190
00191 static int nlmsg_msg_size(int payload)
00192 {
00193 return nlmsg_size(payload);
00194 }
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204 int nlmsg_total_size(int payload)
00205 {
00206 return NLMSG_ALIGN(nlmsg_msg_size(payload));
00207 }
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219 int nlmsg_padlen(int payload)
00220 {
00221 return nlmsg_total_size(payload) - nlmsg_msg_size(payload);
00222 }
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237 void *nlmsg_data(const struct nlmsghdr *nlh)
00238 {
00239 return (unsigned char *) nlh + NLMSG_HDRLEN;
00240 }
00241
00242 void *nlmsg_tail(const struct nlmsghdr *nlh)
00243 {
00244 return (unsigned char *) nlh + NLMSG_ALIGN(nlh->nlmsg_len);
00245 }
00246
00247
00248
00249
00250
00251
00252
00253 int nlmsg_datalen(const struct nlmsghdr *nlh)
00254 {
00255 return nlh->nlmsg_len - NLMSG_HDRLEN;
00256 }
00257
00258 static int nlmsg_len(const struct nlmsghdr *nlh)
00259 {
00260 return nlmsg_datalen(nlh);
00261 }
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275 struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen)
00276 {
00277 unsigned char *data = nlmsg_data(nlh);
00278 return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen));
00279 }
00280
00281
00282
00283
00284
00285
00286 int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen)
00287 {
00288 return nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen);
00289 }
00290
00291
00292
00293
00294
00295
00296
00297
00298 int nlmsg_valid_hdr(const struct nlmsghdr *nlh, int hdrlen)
00299 {
00300 if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
00301 return 0;
00302
00303 return 1;
00304 }
00305
00306
00307
00308
00309
00310
00311 int nlmsg_ok(const struct nlmsghdr *nlh, int remaining)
00312 {
00313 return (remaining >= (int)sizeof(struct nlmsghdr) &&
00314 nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
00315 nlh->nlmsg_len <= remaining);
00316 }
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326 struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining)
00327 {
00328 int totlen = NLMSG_ALIGN(nlh->nlmsg_len);
00329
00330 *remaining -= totlen;
00331
00332 return (struct nlmsghdr *) ((unsigned char *) nlh + totlen);
00333 }
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345 int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
00346 int maxtype, struct nla_policy *policy)
00347 {
00348 if (!nlmsg_valid_hdr(nlh, hdrlen))
00349 return -NLE_MSG_TOOSHORT;
00350
00351 return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen),
00352 nlmsg_attrlen(nlh, hdrlen), policy);
00353 }
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363 struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype)
00364 {
00365 return nla_find(nlmsg_attrdata(nlh, hdrlen),
00366 nlmsg_attrlen(nlh, hdrlen), attrtype);
00367 }
00368
00369
00370
00371
00372
00373
00374
00375
00376 int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
00377 struct nla_policy *policy)
00378 {
00379 if (!nlmsg_valid_hdr(nlh, hdrlen))
00380 return -NLE_MSG_TOOSHORT;
00381
00382 return nla_validate(nlmsg_attrdata(nlh, hdrlen),
00383 nlmsg_attrlen(nlh, hdrlen), maxtype, policy);
00384 }
00385
00386
00387
00388
00389
00390
00391
00392
00393 static struct nl_msg *__nlmsg_alloc(size_t len)
00394 {
00395 struct nl_msg *nm;
00396
00397 if (len < sizeof(struct nlmsghdr))
00398 len = sizeof(struct nlmsghdr);
00399
00400 nm = calloc(1, sizeof(*nm));
00401 if (!nm)
00402 goto errout;
00403
00404 nm->nm_refcnt = 1;
00405
00406 nm->nm_nlh = calloc(1, len);
00407 if (!nm->nm_nlh)
00408 goto errout;
00409
00410 memset(nm->nm_nlh, 0, sizeof(struct nlmsghdr));
00411
00412 nm->nm_protocol = -1;
00413 nm->nm_size = len;
00414 nm->nm_nlh->nlmsg_len = nlmsg_total_size(0);
00415
00416 NL_DBG(2, "msg %p: Allocated new message, maxlen=%zu\n", nm, len);
00417
00418 return nm;
00419 errout:
00420 free(nm);
00421 return NULL;
00422 }
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433 struct nl_msg *nlmsg_alloc(void)
00434 {
00435 return __nlmsg_alloc(default_msg_size);
00436 }
00437
00438
00439
00440
00441 struct nl_msg *nlmsg_alloc_size(size_t max)
00442 {
00443 return __nlmsg_alloc(max);
00444 }
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456 struct nl_msg *nlmsg_inherit(struct nlmsghdr *hdr)
00457 {
00458 struct nl_msg *nm;
00459
00460 nm = nlmsg_alloc();
00461 if (nm && hdr) {
00462 struct nlmsghdr *new = nm->nm_nlh;
00463
00464 new->nlmsg_type = hdr->nlmsg_type;
00465 new->nlmsg_flags = hdr->nlmsg_flags;
00466 new->nlmsg_seq = hdr->nlmsg_seq;
00467 new->nlmsg_pid = hdr->nlmsg_pid;
00468 }
00469
00470 return nm;
00471 }
00472
00473
00474
00475
00476
00477
00478
00479
00480 struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags)
00481 {
00482 struct nl_msg *msg;
00483 struct nlmsghdr nlh = {
00484 .nlmsg_type = nlmsgtype,
00485 .nlmsg_flags = flags,
00486 };
00487
00488 msg = nlmsg_inherit(&nlh);
00489 if (msg)
00490 NL_DBG(2, "msg %p: Allocated new simple message\n", msg);
00491
00492 return msg;
00493 }
00494
00495
00496
00497
00498
00499 void nlmsg_set_default_size(size_t max)
00500 {
00501 if (max < nlmsg_total_size(0))
00502 max = nlmsg_total_size(0);
00503
00504 default_msg_size = max;
00505 }
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516 struct nl_msg *nlmsg_convert(struct nlmsghdr *hdr)
00517 {
00518 struct nl_msg *nm;
00519
00520 nm = __nlmsg_alloc(NLMSG_ALIGN(hdr->nlmsg_len));
00521 if (!nm)
00522 goto errout;
00523
00524 memcpy(nm->nm_nlh, hdr, hdr->nlmsg_len);
00525
00526 return nm;
00527 errout:
00528 nlmsg_free(nm);
00529 return NULL;
00530 }
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544 void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad)
00545 {
00546 void *buf = n->nm_nlh;
00547 size_t nlmsg_len = n->nm_nlh->nlmsg_len;
00548 size_t tlen;
00549
00550 tlen = pad ? ((len + (pad - 1)) & ~(pad - 1)) : len;
00551
00552 if ((tlen + nlmsg_len) > n->nm_size)
00553 return NULL;
00554
00555 buf += nlmsg_len;
00556 n->nm_nlh->nlmsg_len += tlen;
00557
00558 if (tlen > len)
00559 memset(buf + len, 0, tlen - len);
00560
00561 NL_DBG(2, "msg %p: Reserved %zu (%zu) bytes, pad=%d, nlmsg_len=%d\n",
00562 n, tlen, len, pad, n->nm_nlh->nlmsg_len);
00563
00564 return buf;
00565 }
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579 int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
00580 {
00581 void *tmp;
00582
00583 tmp = nlmsg_reserve(n, len, pad);
00584 if (tmp == NULL)
00585 return -NLE_NOMEM;
00586
00587 memcpy(tmp, data, len);
00588 NL_DBG(2, "msg %p: Appended %zu bytes with padding %d\n", n, len, pad);
00589
00590 return 0;
00591 }
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607 int nlmsg_expand(struct nl_msg *n, size_t newlen)
00608 {
00609 void *tmp;
00610
00611 if (newlen <= n->nm_size)
00612 return -NLE_INVAL;
00613
00614 tmp = realloc(n->nm_nlh, newlen);
00615 if (tmp == NULL)
00616 return -NLE_NOMEM;
00617
00618 n->nm_nlh = tmp;
00619 n->nm_size = newlen;
00620
00621 return 0;
00622 }
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640 struct nlmsghdr *nlmsg_put(struct nl_msg *n, uint32_t pid, uint32_t seq,
00641 int type, int payload, int flags)
00642 {
00643 struct nlmsghdr *nlh;
00644
00645 if (n->nm_nlh->nlmsg_len < NLMSG_HDRLEN)
00646 BUG();
00647
00648 nlh = (struct nlmsghdr *) n->nm_nlh;
00649 nlh->nlmsg_type = type;
00650 nlh->nlmsg_flags = flags;
00651 nlh->nlmsg_pid = pid;
00652 nlh->nlmsg_seq = seq;
00653
00654 NL_DBG(2, "msg %p: Added netlink header type=%d, flags=%d, pid=%d, "
00655 "seq=%d\n", n, type, flags, pid, seq);
00656
00657 if (payload > 0 &&
00658 nlmsg_reserve(n, payload, NLMSG_ALIGNTO) == NULL)
00659 return NULL;
00660
00661 return nlh;
00662 }
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673 struct nlmsghdr *nlmsg_hdr(struct nl_msg *n)
00674 {
00675 return n->nm_nlh;
00676 }
00677
00678
00679
00680
00681
00682 void nlmsg_get(struct nl_msg *msg)
00683 {
00684 msg->nm_refcnt++;
00685 NL_DBG(4, "New reference to message %p, total %d\n",
00686 msg, msg->nm_refcnt);
00687 }
00688
00689
00690
00691
00692
00693
00694
00695 void nlmsg_free(struct nl_msg *msg)
00696 {
00697 if (!msg)
00698 return;
00699
00700 msg->nm_refcnt--;
00701 NL_DBG(4, "Returned message reference %p, %d remaining\n",
00702 msg, msg->nm_refcnt);
00703
00704 if (msg->nm_refcnt < 0)
00705 BUG();
00706
00707 if (msg->nm_refcnt <= 0) {
00708 free(msg->nm_nlh);
00709 free(msg);
00710 NL_DBG(2, "msg %p: Freed\n", msg);
00711 }
00712 }
00713
00714
00715
00716
00717
00718
00719
00720
00721 void nlmsg_set_proto(struct nl_msg *msg, int protocol)
00722 {
00723 msg->nm_protocol = protocol;
00724 }
00725
00726 int nlmsg_get_proto(struct nl_msg *msg)
00727 {
00728 return msg->nm_protocol;
00729 }
00730
00731 size_t nlmsg_get_max_size(struct nl_msg *msg)
00732 {
00733 return msg->nm_size;
00734 }
00735
00736 void nlmsg_set_src(struct nl_msg *msg, struct sockaddr_nl *addr)
00737 {
00738 memcpy(&msg->nm_src, addr, sizeof(*addr));
00739 }
00740
00741 struct sockaddr_nl *nlmsg_get_src(struct nl_msg *msg)
00742 {
00743 return &msg->nm_src;
00744 }
00745
00746 void nlmsg_set_dst(struct nl_msg *msg, struct sockaddr_nl *addr)
00747 {
00748 memcpy(&msg->nm_dst, addr, sizeof(*addr));
00749 }
00750
00751 struct sockaddr_nl *nlmsg_get_dst(struct nl_msg *msg)
00752 {
00753 return &msg->nm_dst;
00754 }
00755
00756 void nlmsg_set_creds(struct nl_msg *msg, struct ucred *creds)
00757 {
00758 memcpy(&msg->nm_creds, creds, sizeof(*creds));
00759 msg->nm_flags |= NL_MSG_CRED_PRESENT;
00760 }
00761
00762 struct ucred *nlmsg_get_creds(struct nl_msg *msg)
00763 {
00764 if (msg->nm_flags & NL_MSG_CRED_PRESENT)
00765 return &msg->nm_creds;
00766 return NULL;
00767 }
00768
00769
00770
00771
00772
00773
00774
00775
00776 static const struct trans_tbl nl_msgtypes[] = {
00777 __ADD(NLMSG_NOOP,NOOP)
00778 __ADD(NLMSG_ERROR,ERROR)
00779 __ADD(NLMSG_DONE,DONE)
00780 __ADD(NLMSG_OVERRUN,OVERRUN)
00781 };
00782
00783 char *nl_nlmsgtype2str(int type, char *buf, size_t size)
00784 {
00785 return __type2str(type, buf, size, nl_msgtypes,
00786 ARRAY_SIZE(nl_msgtypes));
00787 }
00788
00789 int nl_str2nlmsgtype(const char *name)
00790 {
00791 return __str2type(name, nl_msgtypes, ARRAY_SIZE(nl_msgtypes));
00792 }
00793
00794
00795
00796
00797
00798
00799
00800
00801 char *nl_nlmsg_flags2str(int flags, char *buf, size_t len)
00802 {
00803 memset(buf, 0, len);
00804
00805 #define PRINT_FLAG(f) \
00806 if (flags & NLM_F_##f) { \
00807 flags &= ~NLM_F_##f; \
00808 strncat(buf, #f, len - strlen(buf) - 1); \
00809 if (flags) \
00810 strncat(buf, ",", len - strlen(buf) - 1); \
00811 }
00812
00813 PRINT_FLAG(REQUEST);
00814 PRINT_FLAG(MULTI);
00815 PRINT_FLAG(ACK);
00816 PRINT_FLAG(ECHO);
00817 PRINT_FLAG(ROOT);
00818 PRINT_FLAG(MATCH);
00819 PRINT_FLAG(ATOMIC);
00820 PRINT_FLAG(REPLACE);
00821 PRINT_FLAG(EXCL);
00822 PRINT_FLAG(CREATE);
00823 PRINT_FLAG(APPEND);
00824
00825 if (flags) {
00826 char s[32];
00827 snprintf(s, sizeof(s), "0x%x", flags);
00828 strncat(buf, s, len - strlen(buf) - 1);
00829 }
00830 #undef PRINT_FLAG
00831
00832 return buf;
00833 }
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843 struct dp_xdata {
00844 void (*cb)(struct nl_object *, void *);
00845 void *arg;
00846 };
00847
00848
00849 static int parse_cb(struct nl_object *obj, struct nl_parser_param *p)
00850 {
00851 struct dp_xdata *x = p->pp_arg;
00852
00853 x->cb(obj, x->arg);
00854 return 0;
00855 }
00856
00857 int nl_msg_parse(struct nl_msg *msg, void (*cb)(struct nl_object *, void *),
00858 void *arg)
00859 {
00860 struct nl_cache_ops *ops;
00861 struct nl_parser_param p = {
00862 .pp_cb = parse_cb
00863 };
00864 struct dp_xdata x = {
00865 .cb = cb,
00866 .arg = arg,
00867 };
00868
00869 ops = nl_cache_ops_associate(nlmsg_get_proto(msg),
00870 nlmsg_hdr(msg)->nlmsg_type);
00871 if (ops == NULL)
00872 return -NLE_MSGTYPE_NOSUPPORT;
00873 p.pp_arg = &x;
00874
00875 return nl_cache_parse(ops, NULL, nlmsg_hdr(msg), &p);
00876 }
00877
00878
00879
00880
00881
00882
00883
00884
00885 static void prefix_line(FILE *ofd, int prefix)
00886 {
00887 int i;
00888
00889 for (i = 0; i < prefix; i++)
00890 fprintf(ofd, " ");
00891 }
00892
00893 static inline void dump_hex(FILE *ofd, char *start, int len, int prefix)
00894 {
00895 int i, a, c, limit;
00896 char ascii[21] = {0};
00897
00898 limit = 18 - (prefix * 2);
00899 prefix_line(ofd, prefix);
00900 fprintf(ofd, " ");
00901
00902 for (i = 0, a = 0, c = 0; i < len; i++) {
00903 int v = *(uint8_t *) (start + i);
00904
00905 fprintf(ofd, "%02x ", v);
00906 ascii[a++] = isprint(v) ? v : '.';
00907
00908 if (c == limit-1) {
00909 fprintf(ofd, "%s\n", ascii);
00910 if (i < (len - 1)) {
00911 prefix_line(ofd, prefix);
00912 fprintf(ofd, " ");
00913 }
00914 a = c = 0;
00915 memset(ascii, 0, sizeof(ascii));
00916 } else
00917 c++;
00918 }
00919
00920 if (c != 0) {
00921 for (i = 0; i < (limit - c); i++)
00922 fprintf(ofd, " ");
00923 fprintf(ofd, "%s\n", ascii);
00924 }
00925 }
00926
00927 static void print_hdr(FILE *ofd, struct nl_msg *msg)
00928 {
00929 struct nlmsghdr *nlh = nlmsg_hdr(msg);
00930 struct nl_cache_ops *ops;
00931 struct nl_msgtype *mt;
00932 char buf[128];
00933
00934 fprintf(ofd, " .nlmsg_len = %d\n", nlh->nlmsg_len);
00935
00936 ops = nl_cache_ops_associate(nlmsg_get_proto(msg), nlh->nlmsg_type);
00937 if (ops) {
00938 mt = nl_msgtype_lookup(ops, nlh->nlmsg_type);
00939 if (!mt)
00940 BUG();
00941
00942 snprintf(buf, sizeof(buf), "%s::%s", ops->co_name, mt->mt_name);
00943 } else
00944 nl_nlmsgtype2str(nlh->nlmsg_type, buf, sizeof(buf));
00945
00946 fprintf(ofd, " .nlmsg_type = %d <%s>\n", nlh->nlmsg_type, buf);
00947 fprintf(ofd, " .nlmsg_flags = %d <%s>\n", nlh->nlmsg_flags,
00948 nl_nlmsg_flags2str(nlh->nlmsg_flags, buf, sizeof(buf)));
00949 fprintf(ofd, " .nlmsg_seq = %d\n", nlh->nlmsg_seq);
00950 fprintf(ofd, " .nlmsg_pid = %d\n", nlh->nlmsg_pid);
00951
00952 }
00953
00954 static void dump_attrs(FILE *ofd, struct nlattr *attrs, int attrlen,
00955 int prefix)
00956 {
00957 int rem;
00958 struct nlattr *nla;
00959
00960 nla_for_each_attr(nla, attrs, attrlen, rem) {
00961 int padlen, alen = nla_len(nla);
00962
00963 prefix_line(ofd, prefix);
00964 fprintf(ofd, " [ATTR %02d%s] %d octets\n", nla_type(nla),
00965 nla->nla_type & NLA_F_NESTED ? " NESTED" : "",
00966 alen);
00967
00968 if (nla->nla_type & NLA_F_NESTED)
00969 dump_attrs(ofd, nla_data(nla), alen, prefix+1);
00970 else
00971 dump_hex(ofd, nla_data(nla), alen, prefix);
00972
00973 padlen = nla_padlen(alen);
00974 if (padlen > 0) {
00975 prefix_line(ofd, prefix);
00976 fprintf(ofd, " [PADDING] %d octets\n",
00977 padlen);
00978 dump_hex(ofd, nla_data(nla) + alen,
00979 padlen, prefix);
00980 }
00981 }
00982
00983 if (rem) {
00984 prefix_line(ofd, prefix);
00985 fprintf(ofd, " [LEFTOVER] %d octets\n", rem);
00986 }
00987 }
00988
00989
00990
00991
00992
00993
00994 void nl_msg_dump(struct nl_msg *msg, FILE *ofd)
00995 {
00996 struct nlmsghdr *hdr = nlmsg_hdr(msg);
00997
00998 fprintf(ofd,
00999 "-------------------------- BEGIN NETLINK MESSAGE "
01000 "---------------------------\n");
01001
01002 fprintf(ofd, " [HEADER] %Zu octets\n", sizeof(struct nlmsghdr));
01003 print_hdr(ofd, msg);
01004
01005 if (hdr->nlmsg_type == NLMSG_ERROR &&
01006 hdr->nlmsg_len >= nlmsg_msg_size(sizeof(struct nlmsgerr))) {
01007 struct nl_msg *errmsg;
01008 struct nlmsgerr *err = nlmsg_data(hdr);
01009
01010 fprintf(ofd, " [ERRORMSG] %Zu octets\n", sizeof(*err));
01011 fprintf(ofd, " .error = %d \"%s\"\n", err->error,
01012 strerror(-err->error));
01013 fprintf(ofd, " [ORIGINAL MESSAGE] %Zu octets\n", sizeof(*hdr));
01014
01015 errmsg = nlmsg_inherit(&err->msg);
01016 print_hdr(ofd, errmsg);
01017 nlmsg_free(errmsg);
01018 } else if (nlmsg_len(hdr) > 0) {
01019 struct nl_cache_ops *ops;
01020 int payloadlen = nlmsg_len(hdr);
01021 int attrlen = 0;
01022
01023 ops = nl_cache_ops_associate(nlmsg_get_proto(msg),
01024 hdr->nlmsg_type);
01025 if (ops) {
01026 attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize);
01027 payloadlen -= attrlen;
01028 }
01029
01030 fprintf(ofd, " [PAYLOAD] %d octets\n", payloadlen);
01031 dump_hex(ofd, nlmsg_data(hdr), payloadlen, 0);
01032
01033 if (attrlen) {
01034 struct nlattr *attrs;
01035 int attrlen;
01036
01037 attrs = nlmsg_attrdata(hdr, ops->co_hdrsize);
01038 attrlen = nlmsg_attrlen(hdr, ops->co_hdrsize);
01039 dump_attrs(ofd, attrs, attrlen, 0);
01040 }
01041 }
01042
01043 fprintf(ofd,
01044 "--------------------------- END NETLINK MESSAGE "
01045 "---------------------------\n");
01046 }
01047
01048
01049
01050