Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netlink/netlink_snl.h
39475 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2022 Alexander V. Chernikov <[email protected]>
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*/
27
#ifndef _NETLINK_NETLINK_SNL_H_
28
#define _NETLINK_NETLINK_SNL_H_
29
30
/*
31
* Simple Netlink Library
32
*/
33
34
#include <sys/param.h>
35
#include <sys/socket.h>
36
37
#include <netlink/netlink.h>
38
#include <netlink/netlink_bitset.h>
39
40
#include <assert.h>
41
#include <errno.h>
42
#include <stdalign.h>
43
#include <stddef.h>
44
#include <stdbool.h>
45
#include <stdint.h>
46
#include <stdlib.h>
47
#include <string.h>
48
#include <unistd.h>
49
50
#define _roundup2(x, y) (((x)+((y)-1))&(~((y)-1)))
51
52
#define NETLINK_ALIGN_SIZE sizeof(uint32_t)
53
#define NETLINK_ALIGN(_len) _roundup2(_len, NETLINK_ALIGN_SIZE)
54
55
#define NLA_ALIGN_SIZE sizeof(uint32_t)
56
#define NLA_HDRLEN ((int)sizeof(struct nlattr))
57
#define NLA_DATA_LEN(_nla) ((int)((_nla)->nla_len - NLA_HDRLEN))
58
#define NLA_DATA(_nla) NL_ITEM_DATA(_nla, NLA_HDRLEN)
59
#define NLA_DATA_CONST(_nla) NL_ITEM_DATA_CONST(_nla, NLA_HDRLEN)
60
61
#define NLA_TYPE(_nla) ((_nla)->nla_type & 0x3FFF)
62
63
#define NLA_NEXT(_attr) (struct nlattr *)(void *)((char *)_attr + NLA_ALIGN(_attr->nla_len))
64
65
#define _NLA_END(_start, _len) ((char *)(_start) + (_len))
66
#define NLA_FOREACH(_attr, _start, _len) \
67
for (_attr = (struct nlattr *)(_start); \
68
((char *)_attr < _NLA_END(_start, _len)) && \
69
((char *)NLA_NEXT(_attr) <= _NLA_END(_start, _len)); \
70
_attr = NLA_NEXT(_attr))
71
72
struct linear_buffer {
73
char *base; /* Base allocated memory pointer */
74
uint32_t offset; /* Currently used offset */
75
uint32_t size; /* Total buffer size */
76
struct linear_buffer *next; /* Buffer chaining */
77
} __aligned(alignof(__max_align_t));
78
79
static inline struct linear_buffer *
80
lb_init(uint32_t size)
81
{
82
struct linear_buffer *lb = (struct linear_buffer *)calloc(1, size);
83
84
if (lb != NULL) {
85
lb->base = (char *)(lb + 1);
86
lb->size = size - sizeof(*lb);
87
}
88
89
return (lb);
90
}
91
92
static inline void
93
lb_free(struct linear_buffer *lb)
94
{
95
free(lb);
96
}
97
98
static inline char *
99
lb_allocz(struct linear_buffer *lb, int len)
100
{
101
len = roundup2(len, alignof(__max_align_t));
102
if (lb->offset + len > lb->size)
103
return (NULL);
104
char *data = (lb->base + lb->offset);
105
lb->offset += len;
106
return (data);
107
}
108
109
static inline void
110
lb_clear(struct linear_buffer *lb)
111
{
112
memset(lb->base, 0, lb->offset);
113
lb->offset = 0;
114
}
115
116
struct snl_state {
117
int fd;
118
char *buf;
119
size_t off;
120
size_t bufsize;
121
size_t datalen;
122
uint32_t seq;
123
bool init_done;
124
struct linear_buffer *lb;
125
};
126
#define SCRATCH_BUFFER_SIZE 1024
127
#define SNL_WRITER_BUFFER_SIZE 256
128
129
typedef void snl_parse_field_f(struct snl_state *ss, void *hdr, void *target);
130
struct snl_field_parser {
131
uint16_t off_in;
132
uint16_t off_out;
133
snl_parse_field_f *cb;
134
};
135
static const struct snl_field_parser snl_f_p_empty[] = {};
136
137
typedef bool snl_parse_attr_f(struct snl_state *ss, struct nlattr *attr,
138
const void *arg, void *target);
139
struct snl_attr_parser {
140
uint16_t type; /* Attribute type */
141
uint16_t off; /* field offset in the target structure */
142
snl_parse_attr_f *cb; /* parser function to call */
143
144
/* Optional parser argument */
145
union {
146
const void *arg;
147
const uint32_t arg_u32;
148
};
149
};
150
151
typedef bool snl_parse_post_f(struct snl_state *ss, void *target);
152
153
struct snl_hdr_parser {
154
uint16_t in_hdr_size; /* Input header size */
155
uint16_t out_size; /* Output structure size */
156
uint16_t fp_size; /* Number of items in field parser */
157
uint16_t np_size; /* Number of items in attribute parser */
158
const struct snl_field_parser *fp; /* array of header field parsers */
159
const struct snl_attr_parser *np; /* array of attribute parsers */
160
snl_parse_post_f *cb_post; /* post-parse callback */
161
};
162
163
#define SNL_DECLARE_PARSER_EXT(_name, _sz_h_in, _sz_out, _fp, _np, _cb) \
164
static const struct snl_hdr_parser _name = { \
165
.in_hdr_size = _sz_h_in, \
166
.out_size = _sz_out, \
167
.fp = &((_fp)[0]), \
168
.np = &((_np)[0]), \
169
.fp_size = nitems(_fp), \
170
.np_size = nitems(_np), \
171
.cb_post = _cb, \
172
}
173
174
#define SNL_DECLARE_PARSER(_name, _t, _fp, _np) \
175
SNL_DECLARE_PARSER_EXT(_name, sizeof(_t), 0, _fp, _np, NULL)
176
177
#define SNL_DECLARE_FIELD_PARSER_EXT(_name, _sz_h_in, _sz_out, _fp, _cb) \
178
static const struct snl_hdr_parser _name = { \
179
.in_hdr_size = _sz_h_in, \
180
.out_size = _sz_out, \
181
.fp = &((_fp)[0]), \
182
.fp_size = nitems(_fp), \
183
.cb_post = _cb, \
184
}
185
186
#define SNL_DECLARE_FIELD_PARSER(_name, _t, _fp) \
187
SNL_DECLARE_FIELD_PARSER_EXT(_name, sizeof(_t), 0, _fp, NULL)
188
189
#define SNL_DECLARE_ATTR_PARSER_EXT(_name, _sz_out, _np, _cb) \
190
static const struct snl_hdr_parser _name = { \
191
.out_size = _sz_out, \
192
.np = &((_np)[0]), \
193
.np_size = nitems(_np), \
194
.cb_post = _cb, \
195
}
196
197
#define SNL_DECLARE_ATTR_PARSER(_name, _np) \
198
SNL_DECLARE_ATTR_PARSER_EXT(_name, 0, _np, NULL)
199
200
201
static inline void *
202
snl_allocz(struct snl_state *ss, int len)
203
{
204
void *data = lb_allocz(ss->lb, len);
205
206
if (data == NULL) {
207
uint32_t size = ss->lb->size * 2;
208
209
while (size < len + sizeof(struct linear_buffer))
210
size *= 2;
211
212
struct linear_buffer *lb = lb_init(size);
213
214
if (lb != NULL) {
215
lb->next = ss->lb;
216
ss->lb = lb;
217
data = lb_allocz(ss->lb, len);
218
}
219
}
220
221
return (data);
222
}
223
224
static inline void
225
snl_clear_lb(struct snl_state *ss)
226
{
227
struct linear_buffer *lb = ss->lb;
228
229
lb_clear(lb);
230
lb = lb->next;
231
ss->lb->next = NULL;
232
/* Remove all linear bufs except the largest one */
233
while (lb != NULL) {
234
struct linear_buffer *lb_next = lb->next;
235
lb_free(lb);
236
lb = lb_next;
237
}
238
}
239
240
static void
241
snl_free(struct snl_state *ss)
242
{
243
if (ss->init_done)
244
close(ss->fd);
245
if (ss->buf != NULL)
246
free(ss->buf);
247
if (ss->lb != NULL) {
248
snl_clear_lb(ss);
249
lb_free(ss->lb);
250
}
251
}
252
253
static inline bool
254
snl_init(struct snl_state *ss, int netlink_family)
255
{
256
memset(ss, 0, sizeof(*ss));
257
258
ss->fd = socket(AF_NETLINK, SOCK_RAW, netlink_family);
259
if (ss->fd == -1)
260
return (false);
261
ss->init_done = true;
262
263
int val = 1;
264
socklen_t optlen = sizeof(val);
265
if (setsockopt(ss->fd, SOL_NETLINK, NETLINK_EXT_ACK, &val, optlen) == -1) {
266
snl_free(ss);
267
return (false);
268
}
269
270
int rcvbuf;
271
if (getsockopt(ss->fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &optlen) == -1) {
272
snl_free(ss);
273
return (false);
274
}
275
276
ss->bufsize = rcvbuf;
277
ss->buf = (char *)malloc(ss->bufsize);
278
if (ss->buf == NULL) {
279
snl_free(ss);
280
return (false);
281
}
282
283
ss->lb = lb_init(SCRATCH_BUFFER_SIZE);
284
if (ss->lb == NULL) {
285
snl_free(ss);
286
return (false);
287
}
288
289
return (true);
290
}
291
292
static inline bool
293
snl_clone(struct snl_state *ss, const struct snl_state *orig)
294
{
295
*ss = (struct snl_state){
296
.fd = orig->fd,
297
.init_done = false,
298
};
299
return ((ss->lb = lb_init(SCRATCH_BUFFER_SIZE)) != NULL);
300
}
301
302
static inline bool
303
snl_send(struct snl_state *ss, void *data, int sz)
304
{
305
return (send(ss->fd, data, sz, 0) == sz);
306
}
307
308
static inline bool
309
snl_send_message(struct snl_state *ss, struct nlmsghdr *hdr)
310
{
311
ssize_t sz = NLMSG_ALIGN(hdr->nlmsg_len);
312
313
return (send(ss->fd, hdr, sz, 0) == sz);
314
}
315
316
static inline uint32_t
317
snl_get_seq(struct snl_state *ss)
318
{
319
return (++ss->seq);
320
}
321
322
struct snl_msg_info {
323
int cmsg_type;
324
int cmsg_level;
325
uint32_t process_id;
326
uint8_t port_id;
327
uint8_t seq_id;
328
};
329
static inline bool parse_cmsg(struct snl_state *ss, const struct msghdr *msg,
330
struct snl_msg_info *attrs);
331
332
static inline struct nlmsghdr *
333
snl_read_message_dbg(struct snl_state *ss, struct snl_msg_info *cinfo)
334
{
335
memset(cinfo, 0, sizeof(*cinfo));
336
337
if (ss->off == ss->datalen) {
338
struct sockaddr_nl nladdr;
339
char cbuf[64];
340
341
struct iovec iov = {
342
.iov_base = ss->buf,
343
.iov_len = ss->bufsize,
344
};
345
struct msghdr msg = {
346
.msg_name = &nladdr,
347
.msg_namelen = sizeof(nladdr),
348
.msg_iov = &iov,
349
.msg_iovlen = 1,
350
.msg_control = cbuf,
351
.msg_controllen = sizeof(cbuf),
352
};
353
ss->off = 0;
354
ss->datalen = 0;
355
for (;;) {
356
ssize_t datalen = recvmsg(ss->fd, &msg, 0);
357
if (datalen > 0) {
358
ss->datalen = datalen;
359
parse_cmsg(ss, &msg, cinfo);
360
break;
361
} else if (errno != EINTR)
362
return (NULL);
363
}
364
}
365
struct nlmsghdr *hdr = (struct nlmsghdr *)(void *)&ss->buf[ss->off];
366
ss->off += NLMSG_ALIGN(hdr->nlmsg_len);
367
return (hdr);
368
}
369
370
371
static inline struct nlmsghdr *
372
snl_read_message(struct snl_state *ss)
373
{
374
if (ss->off == ss->datalen) {
375
struct sockaddr_nl nladdr;
376
struct iovec iov = {
377
.iov_base = ss->buf,
378
.iov_len = ss->bufsize,
379
};
380
struct msghdr msg = {
381
.msg_name = &nladdr,
382
.msg_namelen = sizeof(nladdr),
383
.msg_iov = &iov,
384
.msg_iovlen = 1,
385
};
386
ss->off = 0;
387
ss->datalen = 0;
388
for (;;) {
389
ssize_t datalen = recvmsg(ss->fd, &msg, 0);
390
if (datalen > 0) {
391
ss->datalen = datalen;
392
break;
393
} else if (errno != EINTR)
394
return (NULL);
395
}
396
}
397
struct nlmsghdr *hdr = (struct nlmsghdr *)(void *)&ss->buf[ss->off];
398
ss->off += NLMSG_ALIGN(hdr->nlmsg_len);
399
return (hdr);
400
}
401
402
static inline struct nlmsghdr *
403
snl_read_reply(struct snl_state *ss, uint32_t nlmsg_seq)
404
{
405
struct nlmsghdr *hdr;
406
407
while ((hdr = snl_read_message(ss)) != NULL) {
408
if (hdr->nlmsg_seq == nlmsg_seq)
409
return (hdr);
410
}
411
412
return (NULL);
413
}
414
415
/*
416
* Checks that attributes are sorted by attribute type.
417
*/
418
static inline void
419
snl_verify_parsers(const struct snl_hdr_parser **parser, int count)
420
{
421
for (int i = 0; i < count; i++) {
422
const struct snl_hdr_parser *p = parser[i];
423
int attr_type = 0;
424
for (int j = 0; j < p->np_size; j++) {
425
assert(p->np[j].type > attr_type);
426
attr_type = p->np[j].type;
427
}
428
}
429
}
430
#define SNL_VERIFY_PARSERS(_p) snl_verify_parsers((_p), nitems(_p))
431
432
static const struct snl_attr_parser *
433
find_parser(const struct snl_attr_parser *ps, int pslen, int key)
434
{
435
int left_i = 0, right_i = pslen - 1;
436
437
if (key < ps[0].type || key > ps[pslen - 1].type)
438
return (NULL);
439
440
while (left_i + 1 < right_i) {
441
int mid_i = (left_i + right_i) / 2;
442
if (key < ps[mid_i].type)
443
right_i = mid_i;
444
else if (key > ps[mid_i].type)
445
left_i = mid_i + 1;
446
else
447
return (&ps[mid_i]);
448
}
449
if (ps[left_i].type == key)
450
return (&ps[left_i]);
451
else if (ps[right_i].type == key)
452
return (&ps[right_i]);
453
return (NULL);
454
}
455
456
static inline bool
457
snl_parse_attrs_raw(struct snl_state *ss, struct nlattr *nla_head, int len,
458
const struct snl_attr_parser *ps, int pslen, void *target)
459
{
460
struct nlattr *nla;
461
462
NLA_FOREACH(nla, nla_head, len) {
463
if (nla->nla_len < sizeof(struct nlattr))
464
return (false);
465
int nla_type = nla->nla_type & NLA_TYPE_MASK;
466
const struct snl_attr_parser *s = find_parser(ps, pslen, nla_type);
467
if (s != NULL) {
468
void *ptr = (void *)((char *)target + s->off);
469
if (!s->cb(ss, nla, s->arg, ptr))
470
return (false);
471
}
472
}
473
return (true);
474
}
475
476
static inline bool
477
snl_parse_attrs(struct snl_state *ss, struct nlmsghdr *hdr, int hdrlen,
478
const struct snl_attr_parser *ps, int pslen, void *target)
479
{
480
int off = NLMSG_HDRLEN + NETLINK_ALIGN(hdrlen);
481
int len = hdr->nlmsg_len - off;
482
struct nlattr *nla_head = (struct nlattr *)(void *)((char *)hdr + off);
483
484
return (snl_parse_attrs_raw(ss, nla_head, len, ps, pslen, target));
485
}
486
487
static inline void
488
snl_parse_fields(struct snl_state *ss, struct nlmsghdr *hdr, int hdrlen __unused,
489
const struct snl_field_parser *ps, int pslen, void *target)
490
{
491
for (int i = 0; i < pslen; i++) {
492
const struct snl_field_parser *fp = &ps[i];
493
void *src = (char *)hdr + fp->off_in;
494
void *dst = (char *)target + fp->off_out;
495
496
fp->cb(ss, src, dst);
497
}
498
}
499
500
static inline bool
501
snl_parse_header(struct snl_state *ss, void *hdr, int len,
502
const struct snl_hdr_parser *parser, void *target)
503
{
504
struct nlattr *nla_head;
505
506
/* Extract fields first (if any) */
507
snl_parse_fields(ss, (struct nlmsghdr *)hdr, parser->in_hdr_size,
508
parser->fp, parser->fp_size, target);
509
510
nla_head = (struct nlattr *)(void *)((char *)hdr + parser->in_hdr_size);
511
bool result = snl_parse_attrs_raw(ss, nla_head, len - parser->in_hdr_size,
512
parser->np, parser->np_size, target);
513
514
if (result && parser->cb_post != NULL)
515
result = parser->cb_post(ss, target);
516
517
return (result);
518
}
519
520
static inline bool
521
snl_parse_nlmsg(struct snl_state *ss, struct nlmsghdr *hdr,
522
const struct snl_hdr_parser *parser, void *target)
523
{
524
return (snl_parse_header(ss, hdr + 1, hdr->nlmsg_len - sizeof(*hdr), parser, target));
525
}
526
527
static inline bool
528
snl_attr_get_flag(struct snl_state *ss __unused, struct nlattr *nla, const void *arg __unused,
529
void *target)
530
{
531
if (NLA_DATA_LEN(nla) == 0) {
532
*((uint8_t *)target) = 1;
533
return (true);
534
}
535
return (false);
536
}
537
538
static inline bool
539
snl_attr_get_bytes(struct snl_state *ss __unused, struct nlattr *nla, const void *arg,
540
void *target)
541
{
542
if ((size_t)NLA_DATA_LEN(nla) != (size_t)arg)
543
return (false);
544
545
memcpy(target, NLA_DATA_CONST(nla), (size_t)arg);
546
547
return (true);
548
}
549
550
static inline bool
551
snl_attr_get_bool(struct snl_state *ss __unused, struct nlattr *nla,
552
const void *arg __unused, void *target)
553
{
554
if (NLA_DATA_LEN(nla) == sizeof(bool)) {
555
*((bool *)target) = *((const bool *)NLA_DATA_CONST(nla));
556
return (true);
557
}
558
return (false);
559
}
560
561
static inline bool
562
snl_attr_get_uint8(struct snl_state *ss __unused, struct nlattr *nla,
563
const void *arg __unused, void *target)
564
{
565
if (NLA_DATA_LEN(nla) == sizeof(uint8_t)) {
566
*((uint8_t *)target) = *((const uint8_t *)NLA_DATA_CONST(nla));
567
return (true);
568
}
569
return (false);
570
}
571
572
static inline bool
573
snl_attr_get_uint16(struct snl_state *ss __unused, struct nlattr *nla,
574
const void *arg __unused, void *target)
575
{
576
if (NLA_DATA_LEN(nla) == sizeof(uint16_t)) {
577
*((uint16_t *)target) = *((const uint16_t *)NLA_DATA_CONST(nla));
578
return (true);
579
}
580
return (false);
581
}
582
583
static inline bool
584
snl_attr_get_uint32(struct snl_state *ss __unused, struct nlattr *nla,
585
const void *arg __unused, void *target)
586
{
587
if (NLA_DATA_LEN(nla) == sizeof(uint32_t)) {
588
*((uint32_t *)target) = *((const uint32_t *)NLA_DATA_CONST(nla));
589
return (true);
590
}
591
return (false);
592
}
593
594
static inline bool
595
snl_attr_get_uint64(struct snl_state *ss __unused, struct nlattr *nla,
596
const void *arg __unused, void *target)
597
{
598
if (NLA_DATA_LEN(nla) == sizeof(uint64_t)) {
599
memcpy(target, NLA_DATA_CONST(nla), sizeof(uint64_t));
600
return (true);
601
}
602
return (false);
603
}
604
605
static inline bool
606
snl_attr_get_int8(struct snl_state *ss, struct nlattr *nla, const void *arg,
607
void *target)
608
{
609
return (snl_attr_get_uint8(ss, nla, arg, target));
610
}
611
612
static inline bool
613
snl_attr_get_int16(struct snl_state *ss, struct nlattr *nla, const void *arg,
614
void *target)
615
{
616
return (snl_attr_get_uint16(ss, nla, arg, target));
617
}
618
619
static inline bool
620
snl_attr_get_int32(struct snl_state *ss, struct nlattr *nla, const void *arg,
621
void *target)
622
{
623
return (snl_attr_get_uint32(ss, nla, arg, target));
624
}
625
626
static inline bool
627
snl_attr_get_int64(struct snl_state *ss, struct nlattr *nla, const void *arg,
628
void *target)
629
{
630
return (snl_attr_get_uint64(ss, nla, arg, target));
631
}
632
633
static inline bool
634
snl_attr_get_time_t(struct snl_state *ss __unused, struct nlattr *nla,
635
const void *arg __unused, void *target)
636
{
637
if (NLA_DATA_LEN(nla) == sizeof(time_t)) {
638
memcpy(target, NLA_DATA_CONST(nla), sizeof(time_t));
639
return (true);
640
}
641
return (false);
642
}
643
644
static inline bool
645
snl_attr_get_string(struct snl_state *ss __unused, struct nlattr *nla,
646
const void *arg __unused, void *target)
647
{
648
size_t maxlen = NLA_DATA_LEN(nla);
649
650
if (strnlen((char *)NLA_DATA(nla), maxlen) < maxlen) {
651
*((char **)target) = (char *)NLA_DATA(nla);
652
return (true);
653
}
654
return (false);
655
}
656
657
static inline bool
658
snl_attr_get_stringn(struct snl_state *ss, struct nlattr *nla,
659
const void *arg __unused, void *target)
660
{
661
int maxlen = NLA_DATA_LEN(nla);
662
663
char *buf = (char *)snl_allocz(ss, maxlen + 1);
664
if (buf == NULL)
665
return (false);
666
buf[maxlen] = '\0';
667
memcpy(buf, NLA_DATA(nla), maxlen);
668
669
*((char **)target) = buf;
670
return (true);
671
}
672
673
static inline bool
674
snl_attr_copy_string(struct snl_state *ss, struct nlattr *nla,
675
const void *arg, void *target)
676
{
677
char *tmp;
678
679
if (snl_attr_get_string(ss, nla, NULL, &tmp)) {
680
strlcpy((char *)target, tmp, (size_t)arg);
681
return (true);
682
}
683
return (false);
684
}
685
686
static inline bool
687
snl_attr_dup_string(struct snl_state *ss __unused, struct nlattr *nla,
688
const void *arg __unused, void *target)
689
{
690
size_t maxlen = NLA_DATA_LEN(nla);
691
692
if (strnlen((char *)NLA_DATA(nla), maxlen) < maxlen) {
693
char *buf = (char *)snl_allocz(ss, maxlen);
694
if (buf == NULL)
695
return (false);
696
memcpy(buf, NLA_DATA(nla), maxlen);
697
*((char **)target) = buf;
698
return (true);
699
}
700
return (false);
701
}
702
703
static inline bool
704
snl_attr_get_nested(struct snl_state *ss, struct nlattr *nla, const void *arg, void *target)
705
{
706
const struct snl_hdr_parser *p = (const struct snl_hdr_parser *)arg;
707
708
/* Assumes target points to the beginning of the structure */
709
return (snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla), p, target));
710
}
711
712
struct snl_parray {
713
uint32_t count;
714
void **items;
715
};
716
717
static inline bool
718
snl_attr_get_parray_sz(struct snl_state *ss, struct nlattr *container_nla,
719
uint32_t start_size, const void *arg, void *target)
720
{
721
const struct snl_hdr_parser *p = (const struct snl_hdr_parser *)arg;
722
struct snl_parray *array = (struct snl_parray *)target;
723
struct nlattr *nla;
724
uint32_t count = 0, size = start_size;
725
726
if (p->out_size == 0)
727
return (false);
728
729
array->items = (void **)snl_allocz(ss, size * sizeof(void *));
730
if (array->items == NULL)
731
return (false);
732
733
/*
734
* If the provided parser is an attribute parser, assume that each
735
* nla in the container nla is the container nla itself and parse
736
* the contents of this nla.
737
* Otherwise, run the parser on raw data, assuming the header of this
738
* data has u16 field with total size in the beginning.
739
*/
740
uint32_t data_off = 0;
741
742
if (p->in_hdr_size == 0)
743
data_off = sizeof(struct nlattr);
744
745
NLA_FOREACH(nla, NLA_DATA(container_nla), NLA_DATA_LEN(container_nla)) {
746
void *item = snl_allocz(ss, p->out_size);
747
748
if (item == NULL)
749
return (false);
750
751
void *data = (char *)(void *)nla + data_off;
752
int data_len = nla->nla_len - data_off;
753
754
if (!(snl_parse_header(ss, data, data_len, p, item)))
755
return (false);
756
757
if (count == size) {
758
uint32_t new_size = size * 2;
759
void **new_array = (void **)snl_allocz(ss, new_size *sizeof(void *));
760
761
memcpy(new_array, array->items, size * sizeof(void *));
762
array->items = new_array;
763
size = new_size;
764
}
765
array->items[count++] = item;
766
}
767
array->count = count;
768
769
return (true);
770
}
771
772
/*
773
* Parses and stores the unknown-size array.
774
* Assumes each array item is a container and the NLAs in the container are parsable
775
* by the parser provided in @arg.
776
* Assumes @target is struct snl_parray
777
*/
778
static inline bool
779
snl_attr_get_parray(struct snl_state *ss, struct nlattr *nla, const void *arg, void *target)
780
{
781
return (snl_attr_get_parray_sz(ss, nla, 8, arg, target));
782
}
783
784
static inline bool
785
snl_attr_get_nla(struct snl_state *ss __unused, struct nlattr *nla,
786
const void *arg __unused, void *target)
787
{
788
*((struct nlattr **)target) = nla;
789
return (true);
790
}
791
792
static inline bool
793
snl_attr_dup_nla(struct snl_state *ss, struct nlattr *nla,
794
const void *arg __unused, void *target)
795
{
796
void *ptr = snl_allocz(ss, nla->nla_len);
797
798
if (ptr != NULL) {
799
memcpy(ptr, nla, nla->nla_len);
800
*((void **)target) = ptr;
801
return (true);
802
}
803
return (false);
804
}
805
806
static inline bool
807
snl_attr_copy_struct(struct snl_state *ss, struct nlattr *nla,
808
const void *arg __unused, void *target)
809
{
810
void *ptr = snl_allocz(ss, NLA_DATA_LEN(nla));
811
812
if (ptr != NULL) {
813
memcpy(ptr, NLA_DATA(nla), NLA_DATA_LEN(nla));
814
*((void **)target) = ptr;
815
return (true);
816
}
817
return (false);
818
}
819
820
static inline bool
821
snl_attr_dup_struct(struct snl_state *ss, struct nlattr *nla,
822
const void *arg __unused, void *target)
823
{
824
void *ptr = snl_allocz(ss, NLA_DATA_LEN(nla));
825
826
if (ptr != NULL) {
827
memcpy(ptr, NLA_DATA(nla), NLA_DATA_LEN(nla));
828
*((void **)target) = ptr;
829
return (true);
830
}
831
return (false);
832
}
833
834
struct snl_attr_bit {
835
uint32_t bit_index;
836
char *bit_name;
837
int bit_value;
838
};
839
840
struct snl_attr_bits {
841
uint32_t num_bits;
842
struct snl_attr_bit **bits;
843
};
844
845
#define _OUT(_field) offsetof(struct snl_attr_bit, _field)
846
static const struct snl_attr_parser _nla_p_bit[] = {
847
{ .type = NLA_BITSET_BIT_INDEX, .off = _OUT(bit_index), .cb = snl_attr_get_uint32 },
848
{ .type = NLA_BITSET_BIT_NAME, .off = _OUT(bit_name), .cb = snl_attr_dup_string },
849
{ .type = NLA_BITSET_BIT_VALUE, .off = _OUT(bit_value), .cb = snl_attr_get_flag },
850
};
851
#undef _OUT
852
SNL_DECLARE_ATTR_PARSER_EXT(_nla_bit_parser, sizeof(struct snl_attr_bit), _nla_p_bit, NULL);
853
854
struct snl_attr_bitset {
855
uint32_t nla_bitset_size;
856
uint32_t *nla_bitset_mask;
857
uint32_t *nla_bitset_value;
858
struct snl_attr_bits bits;
859
};
860
861
#define _OUT(_field) offsetof(struct snl_attr_bitset, _field)
862
static const struct snl_attr_parser _nla_p_bitset[] = {
863
{ .type = NLA_BITSET_SIZE, .off = _OUT(nla_bitset_size), .cb = snl_attr_get_uint32 },
864
{ .type = NLA_BITSET_BITS, .off = _OUT(bits), .cb = snl_attr_get_parray, .arg = &_nla_bit_parser },
865
{ .type = NLA_BITSET_VALUE, .off = _OUT(nla_bitset_mask), .cb = snl_attr_dup_nla },
866
{ .type = NLA_BITSET_MASK, .off = _OUT(nla_bitset_value), .cb = snl_attr_dup_nla },
867
};
868
869
static inline bool
870
_cb_p_bitset(struct snl_state *ss __unused, void *_target)
871
{
872
struct snl_attr_bitset *target = (struct snl_attr_bitset *)_target;
873
874
uint32_t sz_bytes = _roundup2(target->nla_bitset_size, 32) / 8;
875
876
if (target->nla_bitset_mask != NULL) {
877
struct nlattr *nla = (struct nlattr *)target->nla_bitset_mask;
878
uint32_t data_len = NLA_DATA_LEN(nla);
879
880
if (data_len != sz_bytes || _roundup2(data_len, 4) != data_len)
881
return (false);
882
target->nla_bitset_mask = (uint32_t *)NLA_DATA(nla);
883
}
884
885
if (target->nla_bitset_value != NULL) {
886
struct nlattr *nla = (struct nlattr *)target->nla_bitset_value;
887
uint32_t data_len = NLA_DATA_LEN(nla);
888
889
if (data_len != sz_bytes || _roundup2(data_len, 4) != data_len)
890
return (false);
891
target->nla_bitset_value = (uint32_t *)NLA_DATA(nla);
892
}
893
return (true);
894
}
895
#undef _OUT
896
SNL_DECLARE_ATTR_PARSER_EXT(_nla_bitset_parser,
897
sizeof(struct snl_attr_bitset),
898
_nla_p_bitset, _cb_p_bitset);
899
900
/*
901
* Parses the compact bitset representation.
902
*/
903
static inline bool
904
snl_attr_get_bitset_c(struct snl_state *ss, struct nlattr *nla,
905
const void *arg __unused, void *_target)
906
{
907
const struct snl_hdr_parser *p = &_nla_bitset_parser;
908
struct snl_attr_bitset *target = (struct snl_attr_bitset *)_target;
909
910
/* Assumes target points to the beginning of the structure */
911
if (!snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla), p, _target))
912
return (false);
913
if (target->nla_bitset_mask == NULL || target->nla_bitset_value == NULL)
914
return (false);
915
return (true);
916
}
917
918
static inline void
919
snl_field_get_uint8(struct snl_state *ss __unused, void *src, void *target)
920
{
921
*((uint8_t *)target) = *((uint8_t *)src);
922
}
923
924
static inline void
925
snl_field_get_uint16(struct snl_state *ss __unused, void *src, void *target)
926
{
927
*((uint16_t *)target) = *((uint16_t *)src);
928
}
929
930
static inline void
931
snl_field_get_uint32(struct snl_state *ss __unused, void *src, void *target)
932
{
933
*((uint32_t *)target) = *((uint32_t *)src);
934
}
935
936
static inline void
937
snl_field_get_ptr(struct snl_state *ss __unused, void *src, void *target)
938
{
939
*((void **)target) = src;
940
}
941
942
struct snl_errmsg_data {
943
struct nlmsghdr *orig_hdr;
944
int error;
945
uint32_t error_offs;
946
char *error_str;
947
struct nlattr *cookie;
948
};
949
950
#define _IN(_field) offsetof(struct nlmsgerr, _field)
951
#define _OUT(_field) offsetof(struct snl_errmsg_data, _field)
952
static const struct snl_attr_parser nla_p_errmsg[] = {
953
{ .type = NLMSGERR_ATTR_MSG, .off = _OUT(error_str), .cb = snl_attr_get_string },
954
{ .type = NLMSGERR_ATTR_OFFS, .off = _OUT(error_offs), .cb = snl_attr_get_uint32 },
955
{ .type = NLMSGERR_ATTR_COOKIE, .off = _OUT(cookie), .cb = snl_attr_get_nla },
956
};
957
958
static const struct snl_field_parser nlf_p_errmsg[] = {
959
{ .off_in = _IN(error), .off_out = _OUT(error), .cb = snl_field_get_uint32 },
960
{ .off_in = _IN(msg), .off_out = _OUT(orig_hdr), .cb = snl_field_get_ptr },
961
};
962
#undef _IN
963
#undef _OUT
964
SNL_DECLARE_PARSER(snl_errmsg_parser, struct nlmsgerr, nlf_p_errmsg, nla_p_errmsg);
965
966
#define _IN(_field) offsetof(struct nlmsgerr, _field)
967
#define _OUT(_field) offsetof(struct snl_errmsg_data, _field)
968
static const struct snl_field_parser nlf_p_donemsg[] = {
969
{ .off_in = _IN(error), .off_out = _OUT(error), .cb = snl_field_get_uint32 },
970
};
971
#undef _IN
972
#undef _OUT
973
SNL_DECLARE_FIELD_PARSER(snl_donemsg_parser, struct nlmsgerr, nlf_p_donemsg);
974
975
static inline bool
976
snl_parse_errmsg(struct snl_state *ss, struct nlmsghdr *hdr, struct snl_errmsg_data *e)
977
{
978
if ((hdr->nlmsg_flags & NLM_F_CAPPED) != 0)
979
return (snl_parse_nlmsg(ss, hdr, &snl_errmsg_parser, e));
980
981
const struct snl_hdr_parser *ps = &snl_errmsg_parser;
982
struct nlmsgerr *errmsg = (struct nlmsgerr *)(hdr + 1);
983
int hdrlen = sizeof(int) + NLMSG_ALIGN(errmsg->msg.nlmsg_len);
984
struct nlattr *attr_head = (struct nlattr *)(void *)((char *)errmsg + hdrlen);
985
int attr_len = hdr->nlmsg_len - sizeof(struct nlmsghdr) - hdrlen;
986
987
snl_parse_fields(ss, (struct nlmsghdr *)errmsg, hdrlen, ps->fp, ps->fp_size, e);
988
return (snl_parse_attrs_raw(ss, attr_head, attr_len, ps->np, ps->np_size, e));
989
}
990
991
static inline bool
992
snl_read_reply_code(struct snl_state *ss, uint32_t nlmsg_seq, struct snl_errmsg_data *e)
993
{
994
struct nlmsghdr *hdr = snl_read_reply(ss, nlmsg_seq);
995
996
if (hdr == NULL) {
997
e->error = EINVAL;
998
} else if (hdr->nlmsg_type == NLMSG_ERROR) {
999
if (!snl_parse_errmsg(ss, hdr, e))
1000
e->error = EINVAL;
1001
return (e->error == 0);
1002
}
1003
1004
return (false);
1005
}
1006
1007
#define _OUT(_field) offsetof(struct snl_msg_info, _field)
1008
static const struct snl_attr_parser _nla_p_cinfo[] = {
1009
{ .type = NLMSGINFO_ATTR_PROCESS_ID, .off = _OUT(process_id), .cb = snl_attr_get_uint32 },
1010
{ .type = NLMSGINFO_ATTR_PORT_ID, .off = _OUT(port_id), .cb = snl_attr_get_uint32 },
1011
{ .type = NLMSGINFO_ATTR_SEQ_ID, .off = _OUT(seq_id), .cb = snl_attr_get_uint32 },
1012
};
1013
#undef _OUT
1014
SNL_DECLARE_ATTR_PARSER(snl_msg_info_parser, _nla_p_cinfo);
1015
1016
static inline bool
1017
parse_cmsg(struct snl_state *ss, const struct msghdr *msg, struct snl_msg_info *attrs)
1018
{
1019
for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
1020
cmsg = CMSG_NXTHDR(msg, cmsg)) {
1021
if (cmsg->cmsg_level != SOL_NETLINK || cmsg->cmsg_type != NETLINK_MSG_INFO)
1022
continue;
1023
1024
void *data = CMSG_DATA(cmsg);
1025
int len = cmsg->cmsg_len - ((char *)data - (char *)cmsg);
1026
const struct snl_hdr_parser *ps = &snl_msg_info_parser;
1027
1028
return (snl_parse_attrs_raw(ss, (struct nlattr *)data, len, ps->np, ps->np_size, attrs));
1029
}
1030
1031
return (false);
1032
}
1033
1034
/*
1035
* Assumes e is zeroed
1036
*/
1037
static inline struct nlmsghdr *
1038
snl_read_reply_multi(struct snl_state *ss, uint32_t nlmsg_seq, struct snl_errmsg_data *e)
1039
{
1040
struct nlmsghdr *hdr = snl_read_reply(ss, nlmsg_seq);
1041
1042
if (hdr == NULL) {
1043
e->error = EINVAL;
1044
} else if (hdr->nlmsg_type == NLMSG_ERROR) {
1045
if (!snl_parse_errmsg(ss, hdr, e))
1046
e->error = EINVAL;
1047
} else if (hdr->nlmsg_type == NLMSG_DONE) {
1048
snl_parse_nlmsg(ss, hdr, &snl_donemsg_parser, e);
1049
} else
1050
return (hdr);
1051
1052
return (NULL);
1053
}
1054
1055
1056
/* writer logic */
1057
struct snl_writer {
1058
char *base;
1059
uint32_t offset;
1060
uint32_t size;
1061
struct nlmsghdr *hdr;
1062
struct snl_state *ss;
1063
bool error;
1064
};
1065
1066
static inline void
1067
snl_init_writer(struct snl_state *ss, struct snl_writer *nw)
1068
{
1069
nw->size = SNL_WRITER_BUFFER_SIZE;
1070
nw->base = (char *)snl_allocz(ss, nw->size);
1071
if (nw->base == NULL) {
1072
nw->error = true;
1073
nw->size = 0;
1074
}
1075
1076
nw->offset = 0;
1077
nw->hdr = NULL;
1078
nw->error = false;
1079
nw->ss = ss;
1080
}
1081
1082
static inline bool
1083
snl_realloc_msg_buffer(struct snl_writer *nw, size_t sz)
1084
{
1085
uint32_t new_size = nw->size * 2;
1086
1087
while (new_size < nw->size + sz)
1088
new_size *= 2;
1089
1090
if (nw->error)
1091
return (false);
1092
1093
if (snl_allocz(nw->ss, new_size) == NULL) {
1094
nw->error = true;
1095
return (false);
1096
}
1097
nw->size = new_size;
1098
1099
void *new_base = nw->ss->lb->base;
1100
if (new_base != nw->base) {
1101
memcpy(new_base, nw->base, nw->offset);
1102
if (nw->hdr != NULL) {
1103
int hdr_off = (char *)(nw->hdr) - nw->base;
1104
1105
nw->hdr = (struct nlmsghdr *)
1106
(void *)((char *)new_base + hdr_off);
1107
}
1108
nw->base = (char *)new_base;
1109
}
1110
1111
return (true);
1112
}
1113
1114
static inline void *
1115
snl_reserve_msg_data_raw(struct snl_writer *nw, size_t sz)
1116
{
1117
sz = NETLINK_ALIGN(sz);
1118
1119
if (__predict_false(nw->offset + sz > nw->size)) {
1120
if (!snl_realloc_msg_buffer(nw, sz))
1121
return (NULL);
1122
}
1123
1124
void *data_ptr = &nw->base[nw->offset];
1125
nw->offset += sz;
1126
1127
return (data_ptr);
1128
}
1129
#define snl_reserve_msg_object(_ns, _t) ((_t *)snl_reserve_msg_data_raw(_ns, sizeof(_t)))
1130
#define snl_reserve_msg_data(_ns, _sz, _t) ((_t *)snl_reserve_msg_data_raw(_ns, _sz))
1131
1132
static inline struct nlattr *
1133
snl_reserve_msg_attr_raw(struct snl_writer *nw, uint16_t nla_type, uint16_t sz)
1134
{
1135
struct nlattr *nla;
1136
1137
sz += sizeof(struct nlattr);
1138
nla = snl_reserve_msg_data(nw, sz, struct nlattr);
1139
if (__predict_false(nla == NULL))
1140
return (NULL);
1141
nla->nla_type = nla_type;
1142
nla->nla_len = sz;
1143
1144
return (nla);
1145
}
1146
#define snl_reserve_msg_attr(_ns, _at, _t) \
1147
((_t *)(snl_reserve_msg_attr_raw(_ns, _at, sizeof(_t)) + 1))
1148
1149
static inline bool
1150
snl_add_msg_attr(struct snl_writer *nw, int attr_type, int attr_len, const void *data)
1151
{
1152
int required_len = NLA_ALIGN(attr_len + sizeof(struct nlattr));
1153
1154
if (__predict_false(nw->offset + required_len > nw->size)) {
1155
if (!snl_realloc_msg_buffer(nw, required_len))
1156
return (false);
1157
}
1158
1159
struct nlattr *nla = (struct nlattr *)(void *)(&nw->base[nw->offset]);
1160
1161
nla->nla_len = attr_len + sizeof(struct nlattr);
1162
nla->nla_type = attr_type;
1163
if (attr_len > 0) {
1164
if ((attr_len % 4) != 0) {
1165
/* clear padding bytes */
1166
bzero((char *)nla + required_len - 4, 4);
1167
}
1168
memcpy((nla + 1), data, attr_len);
1169
}
1170
nw->offset += required_len;
1171
return (true);
1172
}
1173
1174
static inline bool
1175
snl_add_msg_attr_raw(struct snl_writer *nw, const struct nlattr *nla_src)
1176
{
1177
int attr_len = nla_src->nla_len - sizeof(struct nlattr);
1178
1179
assert(attr_len >= 0);
1180
1181
return (snl_add_msg_attr(nw, nla_src->nla_type, attr_len, (const void *)(nla_src + 1)));
1182
}
1183
1184
static inline bool
1185
snl_add_msg_attr_bool(struct snl_writer *nw, int attrtype, bool value)
1186
{
1187
return (snl_add_msg_attr(nw, attrtype, sizeof(bool), &value));
1188
}
1189
1190
static inline bool
1191
snl_add_msg_attr_u8(struct snl_writer *nw, int attrtype, uint8_t value)
1192
{
1193
return (snl_add_msg_attr(nw, attrtype, sizeof(uint8_t), &value));
1194
}
1195
1196
static inline bool
1197
snl_add_msg_attr_u16(struct snl_writer *nw, int attrtype, uint16_t value)
1198
{
1199
return (snl_add_msg_attr(nw, attrtype, sizeof(uint16_t), &value));
1200
}
1201
1202
static inline bool
1203
snl_add_msg_attr_u32(struct snl_writer *nw, int attrtype, uint32_t value)
1204
{
1205
return (snl_add_msg_attr(nw, attrtype, sizeof(uint32_t), &value));
1206
}
1207
1208
static inline bool
1209
snl_add_msg_attr_u64(struct snl_writer *nw, int attrtype, uint64_t value)
1210
{
1211
return (snl_add_msg_attr(nw, attrtype, sizeof(uint64_t), &value));
1212
}
1213
1214
static inline bool
1215
snl_add_msg_attr_s8(struct snl_writer *nw, int attrtype, int8_t value)
1216
{
1217
return (snl_add_msg_attr(nw, attrtype, sizeof(int8_t), &value));
1218
}
1219
1220
static inline bool
1221
snl_add_msg_attr_s16(struct snl_writer *nw, int attrtype, int16_t value)
1222
{
1223
return (snl_add_msg_attr(nw, attrtype, sizeof(int16_t), &value));
1224
}
1225
1226
static inline bool
1227
snl_add_msg_attr_s32(struct snl_writer *nw, int attrtype, int32_t value)
1228
{
1229
return (snl_add_msg_attr(nw, attrtype, sizeof(int32_t), &value));
1230
}
1231
1232
static inline bool
1233
snl_add_msg_attr_s64(struct snl_writer *nw, int attrtype, int64_t value)
1234
{
1235
return (snl_add_msg_attr(nw, attrtype, sizeof(int64_t), &value));
1236
}
1237
1238
static inline bool
1239
snl_add_msg_attr_flag(struct snl_writer *nw, int attrtype)
1240
{
1241
return (snl_add_msg_attr(nw, attrtype, 0, NULL));
1242
}
1243
1244
static inline bool
1245
snl_add_msg_attr_string(struct snl_writer *nw, int attrtype, const char *str)
1246
{
1247
return (snl_add_msg_attr(nw, attrtype, strlen(str) + 1, str));
1248
}
1249
1250
1251
static inline int
1252
snl_get_msg_offset(const struct snl_writer *nw)
1253
{
1254
return (nw->offset - ((char *)nw->hdr - nw->base));
1255
}
1256
1257
static inline void *
1258
_snl_restore_msg_offset(const struct snl_writer *nw, int off)
1259
{
1260
return ((void *)((char *)nw->hdr + off));
1261
}
1262
#define snl_restore_msg_offset(_ns, _off, _t) ((_t *)_snl_restore_msg_offset(_ns, _off))
1263
1264
static inline int
1265
snl_add_msg_attr_nested(struct snl_writer *nw, int attrtype)
1266
{
1267
int off = snl_get_msg_offset(nw);
1268
struct nlattr *nla = snl_reserve_msg_data(nw, sizeof(struct nlattr), struct nlattr);
1269
if (__predict_false(nla == NULL))
1270
return (0);
1271
nla->nla_type = attrtype;
1272
return (off);
1273
}
1274
1275
static inline void
1276
snl_end_attr_nested(const struct snl_writer *nw, int off)
1277
{
1278
if (!nw->error) {
1279
struct nlattr *nla = snl_restore_msg_offset(nw, off, struct nlattr);
1280
nla->nla_len = NETLINK_ALIGN(snl_get_msg_offset(nw) - off);
1281
}
1282
}
1283
1284
static inline struct nlmsghdr *
1285
snl_create_msg_request(struct snl_writer *nw, int nlmsg_type)
1286
{
1287
struct nlmsghdr *hdr;
1288
1289
assert(nw->hdr == NULL);
1290
1291
if (__predict_false((hdr =
1292
snl_reserve_msg_object(nw, struct nlmsghdr)) == NULL))
1293
return (NULL);
1294
hdr->nlmsg_type = nlmsg_type;
1295
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1296
nw->hdr = hdr;
1297
1298
return (hdr);
1299
}
1300
1301
static void
1302
snl_abort_msg(struct snl_writer *nw)
1303
{
1304
if (nw->hdr != NULL) {
1305
int offset = (char *)(&nw->base[nw->offset]) - (char *)(nw->hdr);
1306
1307
nw->offset -= offset;
1308
nw->hdr = NULL;
1309
}
1310
}
1311
1312
static inline struct nlmsghdr *
1313
snl_finalize_msg(struct snl_writer *nw)
1314
{
1315
if (nw->error)
1316
snl_abort_msg(nw);
1317
if (nw->hdr != NULL) {
1318
struct nlmsghdr *hdr = nw->hdr;
1319
1320
int offset = (char *)(&nw->base[nw->offset]) - (char *)(nw->hdr);
1321
hdr->nlmsg_len = offset;
1322
hdr->nlmsg_seq = snl_get_seq(nw->ss);
1323
nw->hdr = NULL;
1324
1325
return (hdr);
1326
}
1327
return (NULL);
1328
}
1329
1330
static inline bool
1331
snl_send_msgs(struct snl_writer *nw)
1332
{
1333
int offset = nw->offset;
1334
1335
assert(nw->hdr == NULL);
1336
nw->offset = 0;
1337
1338
return (snl_send(nw->ss, nw->base, offset));
1339
}
1340
1341
#endif
1342
1343