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