Path: blob/main/sys/netlink/netlink_message_writer.h
39475 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2021 Ng Peng Nam Sean4* Copyright (c) 2022 Alexander V. Chernikov <[email protected]>5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*/2728#ifndef _NETLINK_NETLINK_MESSAGE_WRITER_H_29#define _NETLINK_NETLINK_MESSAGE_WRITER_H_3031#ifdef _KERNEL3233#include <netinet/in.h>3435/*36* It is not meant to be included directly37*/3839struct nl_buf;40struct nl_writer;41typedef bool nl_writer_cb(struct nl_writer *nw);4243struct nl_writer {44struct nl_buf *buf; /* Underlying storage pointer */45struct nlmsghdr *hdr; /* Pointer to the currently-filled msg */46nl_writer_cb *cb; /* Callback to flush data */47union {48struct nlpcb *nlp;49struct {50uint16_t proto;51uint16_t id;52int priv;53} group;54};55u_int num_messages; /* Number of messages in the buffer */56int malloc_flag; /* M_WAITOK or M_NOWAIT */57bool ignore_limit; /* If true, ignores RCVBUF limit */58bool enomem; /* True if ENOMEM occured */59bool suppress_ack; /* If true, don't send NLMSG_ERR */60};6162#define NLMSG_SMALL 12863#define NLMSG_LARGE 20486465/* Message and attribute writing */66#if defined(NETLINK) || defined(NETLINK_MODULE)67/* Provide optimized calls to the functions inside the same linking unit */6869bool _nl_writer_unicast(struct nl_writer *, size_t, struct nlpcb *nlp, bool);70bool _nl_writer_group(struct nl_writer *, size_t, uint16_t, uint16_t, int,71bool);72bool _nlmsg_flush(struct nl_writer *nw);73void _nlmsg_ignore_limit(struct nl_writer *nw);7475bool _nlmsg_refill_buffer(struct nl_writer *nw, size_t required_len);76bool _nlmsg_add(struct nl_writer *nw, uint32_t portid, uint32_t seq,77uint16_t type, uint16_t flags, uint32_t len);78bool _nlmsg_end(struct nl_writer *nw);79void _nlmsg_abort(struct nl_writer *nw);8081bool _nlmsg_end_dump(struct nl_writer *nw, int error, struct nlmsghdr *hdr);828384static inline bool85nl_writer_unicast(struct nl_writer *nw, size_t size, struct nlpcb *nlp,86bool waitok)87{88return (_nl_writer_unicast(nw, size, nlp, waitok));89}9091static inline bool92nl_writer_group(struct nl_writer *nw, size_t size, uint16_t proto,93uint16_t group_id, int priv, bool waitok)94{95return (_nl_writer_group(nw, size, proto, group_id, priv, waitok));96}9798static inline bool99nlmsg_flush(struct nl_writer *nw)100{101return (_nlmsg_flush(nw));102}103104static inline void105nlmsg_ignore_limit(struct nl_writer *nw)106{107_nlmsg_ignore_limit(nw);108}109110static inline bool111nlmsg_refill_buffer(struct nl_writer *nw, size_t required_size)112{113return (_nlmsg_refill_buffer(nw, required_size));114}115116static inline bool117nlmsg_add(struct nl_writer *nw, uint32_t portid, uint32_t seq, uint16_t type,118uint16_t flags, uint32_t len)119{120return (_nlmsg_add(nw, portid, seq, type, flags, len));121}122123static inline bool124nlmsg_end(struct nl_writer *nw)125{126return (_nlmsg_end(nw));127}128129static inline void130nlmsg_abort(struct nl_writer *nw)131{132return (_nlmsg_abort(nw));133}134135static inline bool136nlmsg_end_dump(struct nl_writer *nw, int error, struct nlmsghdr *hdr)137{138return (_nlmsg_end_dump(nw, error, hdr));139}140141#else142/* Provide access to the functions via netlink_glue.c */143144bool nl_writer_unicast(struct nl_writer *, size_t, struct nlpcb *, bool waitok);145bool nl_writer_group(struct nl_writer *, size_t, uint16_t, uint16_t, int,146bool waitok);147bool nlmsg_flush(struct nl_writer *nw);148void nlmsg_ignore_limit(struct nl_writer *nw);149150bool nlmsg_refill_buffer(struct nl_writer *nw, size_t required_size);151bool nlmsg_add(struct nl_writer *nw, uint32_t portid, uint32_t seq,152uint16_t type, uint16_t flags, uint32_t len);153bool nlmsg_end(struct nl_writer *nw);154void nlmsg_abort(struct nl_writer *nw);155156bool nlmsg_end_dump(struct nl_writer *nw, int error, struct nlmsghdr *hdr);157158#endif /* defined(NETLINK) || defined(NETLINK_MODULE) */159160static inline bool161nlmsg_reply(struct nl_writer *nw, const struct nlmsghdr *hdr, int payload_len)162{163return (nlmsg_add(nw, hdr->nlmsg_pid, hdr->nlmsg_seq, hdr->nlmsg_type,164hdr->nlmsg_flags, payload_len));165}166167/*168* KPI similar to mtodo():169* current (uncompleted) header is guaranteed to be contiguous,170* but can be reallocated, thus pointers may need to be readjusted.171*/172u_int nlattr_save_offset(const struct nl_writer *nw);173174static inline void *175_nlattr_restore_offset(const struct nl_writer *nw, int off)176{177return ((void *)((char *)nw->hdr + off));178}179#define nlattr_restore_offset(_ns, _off, _t) ((_t *)_nlattr_restore_offset(_ns, _off))180181static inline void182nlattr_set_len(const struct nl_writer *nw, int off)183{184struct nlattr *nla = nlattr_restore_offset(nw, off, struct nlattr);185nla->nla_len = nlattr_save_offset(nw) - off;186}187188void *nlmsg_reserve_data_raw(struct nl_writer *nw, size_t sz);189#define nlmsg_reserve_object(_ns, _t) ((_t *)nlmsg_reserve_data_raw(_ns, sizeof(_t)))190#define nlmsg_reserve_data(_ns, _sz, _t) ((_t *)nlmsg_reserve_data_raw(_ns, _sz))191192static inline int193nlattr_add_nested(struct nl_writer *nw, uint16_t nla_type)194{195int off = nlattr_save_offset(nw);196struct nlattr *nla = nlmsg_reserve_data(nw, sizeof(struct nlattr), struct nlattr);197if (__predict_false(nla == NULL))198return (0);199nla->nla_type = nla_type;200return (off);201}202203static inline void *204_nlmsg_reserve_attr(struct nl_writer *nw, uint16_t nla_type, uint16_t sz)205{206sz += sizeof(struct nlattr);207208struct nlattr *nla = nlmsg_reserve_data(nw, sz, struct nlattr);209if (__predict_false(nla == NULL))210return (NULL);211nla->nla_type = nla_type;212nla->nla_len = sz;213214return ((void *)(nla + 1));215}216#define nlmsg_reserve_attr(_ns, _at, _t) ((_t *)_nlmsg_reserve_attr(_ns, _at, NLA_ALIGN(sizeof(_t))))217218bool nlattr_add(struct nl_writer *nw, uint16_t attr_type, uint16_t attr_len,219const void *data);220221static inline bool222nlattr_add_raw(struct nl_writer *nw, const struct nlattr *nla_src)223{224MPASS(nla_src->nla_len >= sizeof(struct nlattr));225226return (nlattr_add(nw, nla_src->nla_type,227nla_src->nla_len - sizeof(struct nlattr),228(const void *)(nla_src + 1)));229}230231static inline bool232nlattr_add_bool(struct nl_writer *nw, uint16_t attrtype, bool value)233{234return (nlattr_add(nw, attrtype, sizeof(bool), &value));235}236237static inline bool238nlattr_add_u8(struct nl_writer *nw, uint16_t attrtype, uint8_t value)239{240return (nlattr_add(nw, attrtype, sizeof(uint8_t), &value));241}242243static inline bool244nlattr_add_u16(struct nl_writer *nw, uint16_t attrtype, uint16_t value)245{246return (nlattr_add(nw, attrtype, sizeof(uint16_t), &value));247}248249static inline bool250nlattr_add_u32(struct nl_writer *nw, uint16_t attrtype, uint32_t value)251{252return (nlattr_add(nw, attrtype, sizeof(uint32_t), &value));253}254255static inline bool256nlattr_add_u64(struct nl_writer *nw, uint16_t attrtype, uint64_t value)257{258return (nlattr_add(nw, attrtype, sizeof(uint64_t), &value));259}260261static inline bool262nlattr_add_s8(struct nl_writer *nw, uint16_t attrtype, int8_t value)263{264return (nlattr_add(nw, attrtype, sizeof(int8_t), &value));265}266267static inline bool268nlattr_add_s16(struct nl_writer *nw, uint16_t attrtype, int16_t value)269{270return (nlattr_add(nw, attrtype, sizeof(int16_t), &value));271}272273static inline bool274nlattr_add_s32(struct nl_writer *nw, uint16_t attrtype, int32_t value)275{276return (nlattr_add(nw, attrtype, sizeof(int32_t), &value));277}278279static inline bool280nlattr_add_s64(struct nl_writer *nw, uint16_t attrtype, int64_t value)281{282return (nlattr_add(nw, attrtype, sizeof(int64_t), &value));283}284285static inline bool286nlattr_add_time_t(struct nl_writer *nw, uint16_t attrtype, time_t value)287{288return (nlattr_add(nw, attrtype, sizeof(time_t), &value));289}290291static inline bool292nlattr_add_flag(struct nl_writer *nw, uint16_t attrtype)293{294return (nlattr_add(nw, attrtype, 0, NULL));295}296297static inline bool298nlattr_add_string(struct nl_writer *nw, uint16_t attrtype, const char *str)299{300return (nlattr_add(nw, attrtype, strlen(str) + 1, str));301}302303static inline bool304nlattr_add_in_addr(struct nl_writer *nw, uint16_t attrtype,305const struct in_addr *in)306{307return (nlattr_add(nw, attrtype, sizeof(*in), in));308}309310static inline bool311nlattr_add_in6_addr(struct nl_writer *nw, uint16_t attrtype,312const struct in6_addr *in6)313{314return (nlattr_add(nw, attrtype, sizeof(*in6), in6));315}316#endif317#endif318319320