Path: blob/main/sys/netlink/netlink_message_writer.h
104901 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;41struct ifnet;42typedef bool nl_writer_cb(struct nl_writer *nw);4344struct nl_writer {45struct nl_buf *buf; /* Underlying storage pointer */46struct nlmsghdr *hdr; /* Pointer to the currently-filled msg */47nl_writer_cb *cb; /* Callback to flush data */48union {49struct nlpcb *nlp;50struct {51uint16_t proto;52uint16_t id;53int priv;54} group;55};56const struct ifnet *ifp; /* Used by Linux translation only */57u_int num_messages; /* Number of messages in the buffer */58int malloc_flag; /* M_WAITOK or M_NOWAIT */59bool ignore_limit; /* If true, ignores RCVBUF limit */60bool enomem; /* True if ENOMEM occured */61bool suppress_ack; /* If true, don't send NLMSG_ERR */62};6364#define NLMSG_SMALL 12865#define NLMSG_LARGE 20486667/* Message and attribute writing */68#if defined(NETLINK) || defined(NETLINK_MODULE)69/* Provide optimized calls to the functions inside the same linking unit */7071bool _nl_writer_unicast(struct nl_writer *, size_t, struct nlpcb *nlp, bool);72bool _nl_writer_group(struct nl_writer *, size_t, uint16_t, uint16_t, int,73bool);74bool _nlmsg_flush(struct nl_writer *nw);75void _nlmsg_ignore_limit(struct nl_writer *nw);7677bool _nlmsg_refill_buffer(struct nl_writer *nw, size_t required_len);78bool _nlmsg_add(struct nl_writer *nw, uint32_t portid, uint32_t seq,79uint16_t type, uint16_t flags, uint32_t len);80bool _nlmsg_end(struct nl_writer *nw);81void _nlmsg_abort(struct nl_writer *nw);8283bool _nlmsg_end_dump(struct nl_writer *nw, int error, struct nlmsghdr *hdr);848586static inline bool87nl_writer_unicast(struct nl_writer *nw, size_t size, struct nlpcb *nlp,88bool waitok)89{90return (_nl_writer_unicast(nw, size, nlp, waitok));91}9293static inline bool94nl_writer_group(struct nl_writer *nw, size_t size, uint16_t proto,95uint16_t group_id, int priv, bool waitok)96{97return (_nl_writer_group(nw, size, proto, group_id, priv, waitok));98}99100static inline bool101nlmsg_flush(struct nl_writer *nw)102{103return (_nlmsg_flush(nw));104}105106static inline void107nlmsg_ignore_limit(struct nl_writer *nw)108{109_nlmsg_ignore_limit(nw);110}111112static inline bool113nlmsg_refill_buffer(struct nl_writer *nw, size_t required_size)114{115return (_nlmsg_refill_buffer(nw, required_size));116}117118static inline bool119nlmsg_add(struct nl_writer *nw, uint32_t portid, uint32_t seq, uint16_t type,120uint16_t flags, uint32_t len)121{122return (_nlmsg_add(nw, portid, seq, type, flags, len));123}124125static inline bool126nlmsg_end(struct nl_writer *nw)127{128return (_nlmsg_end(nw));129}130131static inline void132nlmsg_abort(struct nl_writer *nw)133{134return (_nlmsg_abort(nw));135}136137static inline bool138nlmsg_end_dump(struct nl_writer *nw, int error, struct nlmsghdr *hdr)139{140return (_nlmsg_end_dump(nw, error, hdr));141}142143#else144/* Provide access to the functions via netlink_glue.c */145146bool nl_writer_unicast(struct nl_writer *, size_t, struct nlpcb *, bool waitok);147bool nl_writer_group(struct nl_writer *, size_t, uint16_t, uint16_t, int,148bool waitok);149bool nlmsg_flush(struct nl_writer *nw);150void nlmsg_ignore_limit(struct nl_writer *nw);151152bool nlmsg_refill_buffer(struct nl_writer *nw, size_t required_size);153bool nlmsg_add(struct nl_writer *nw, uint32_t portid, uint32_t seq,154uint16_t type, uint16_t flags, uint32_t len);155bool nlmsg_end(struct nl_writer *nw);156void nlmsg_abort(struct nl_writer *nw);157158bool nlmsg_end_dump(struct nl_writer *nw, int error, struct nlmsghdr *hdr);159160#endif /* defined(NETLINK) || defined(NETLINK_MODULE) */161162static inline bool163nlmsg_reply(struct nl_writer *nw, const struct nlmsghdr *hdr, int payload_len)164{165return (nlmsg_add(nw, hdr->nlmsg_pid, hdr->nlmsg_seq, hdr->nlmsg_type,166hdr->nlmsg_flags, payload_len));167}168169/*170* KPI similar to mtodo():171* current (uncompleted) header is guaranteed to be contiguous,172* but can be reallocated, thus pointers may need to be readjusted.173*/174u_int nlattr_save_offset(const struct nl_writer *nw);175176static inline void *177_nlattr_restore_offset(const struct nl_writer *nw, int off)178{179return ((void *)((char *)nw->hdr + off));180}181#define nlattr_restore_offset(_ns, _off, _t) ((_t *)_nlattr_restore_offset(_ns, _off))182183static inline void184nlattr_set_len(const struct nl_writer *nw, int off)185{186struct nlattr *nla = nlattr_restore_offset(nw, off, struct nlattr);187nla->nla_len = nlattr_save_offset(nw) - off;188}189190void *nlmsg_reserve_data_raw(struct nl_writer *nw, size_t sz);191#define nlmsg_reserve_object(_ns, _t) ((_t *)nlmsg_reserve_data_raw(_ns, sizeof(_t)))192#define nlmsg_reserve_data(_ns, _sz, _t) ((_t *)nlmsg_reserve_data_raw(_ns, _sz))193194static inline int195nlattr_add_nested(struct nl_writer *nw, uint16_t nla_type)196{197int off = nlattr_save_offset(nw);198struct nlattr *nla = nlmsg_reserve_data(nw, sizeof(struct nlattr), struct nlattr);199if (__predict_false(nla == NULL))200return (0);201nla->nla_type = nla_type;202return (off);203}204205static inline void *206_nlmsg_reserve_attr(struct nl_writer *nw, uint16_t nla_type, uint16_t sz)207{208sz += sizeof(struct nlattr);209210struct nlattr *nla = nlmsg_reserve_data(nw, sz, struct nlattr);211if (__predict_false(nla == NULL))212return (NULL);213nla->nla_type = nla_type;214nla->nla_len = sz;215216return ((void *)(nla + 1));217}218#define nlmsg_reserve_attr(_ns, _at, _t) ((_t *)_nlmsg_reserve_attr(_ns, _at, NLA_ALIGN(sizeof(_t))))219220bool nlattr_add(struct nl_writer *nw, uint16_t attr_type, uint16_t attr_len,221const void *data);222223static inline bool224nlattr_add_raw(struct nl_writer *nw, const struct nlattr *nla_src)225{226MPASS(nla_src->nla_len >= sizeof(struct nlattr));227228return (nlattr_add(nw, nla_src->nla_type,229nla_src->nla_len - sizeof(struct nlattr),230(const void *)(nla_src + 1)));231}232233static inline bool234nlattr_add_bool(struct nl_writer *nw, uint16_t attrtype, bool value)235{236return (nlattr_add(nw, attrtype, sizeof(bool), &value));237}238239static inline bool240nlattr_add_u8(struct nl_writer *nw, uint16_t attrtype, uint8_t value)241{242return (nlattr_add(nw, attrtype, sizeof(uint8_t), &value));243}244245static inline bool246nlattr_add_u16(struct nl_writer *nw, uint16_t attrtype, uint16_t value)247{248return (nlattr_add(nw, attrtype, sizeof(uint16_t), &value));249}250251static inline bool252nlattr_add_u32(struct nl_writer *nw, uint16_t attrtype, uint32_t value)253{254return (nlattr_add(nw, attrtype, sizeof(uint32_t), &value));255}256257static inline bool258nlattr_add_u64(struct nl_writer *nw, uint16_t attrtype, uint64_t value)259{260return (nlattr_add(nw, attrtype, sizeof(uint64_t), &value));261}262263static inline bool264nlattr_add_s8(struct nl_writer *nw, uint16_t attrtype, int8_t value)265{266return (nlattr_add(nw, attrtype, sizeof(int8_t), &value));267}268269static inline bool270nlattr_add_s16(struct nl_writer *nw, uint16_t attrtype, int16_t value)271{272return (nlattr_add(nw, attrtype, sizeof(int16_t), &value));273}274275static inline bool276nlattr_add_s32(struct nl_writer *nw, uint16_t attrtype, int32_t value)277{278return (nlattr_add(nw, attrtype, sizeof(int32_t), &value));279}280281static inline bool282nlattr_add_s64(struct nl_writer *nw, uint16_t attrtype, int64_t value)283{284return (nlattr_add(nw, attrtype, sizeof(int64_t), &value));285}286287static inline bool288nlattr_add_time_t(struct nl_writer *nw, uint16_t attrtype, time_t value)289{290return (nlattr_add(nw, attrtype, sizeof(time_t), &value));291}292293static inline bool294nlattr_add_flag(struct nl_writer *nw, uint16_t attrtype)295{296return (nlattr_add(nw, attrtype, 0, NULL));297}298299static inline bool300nlattr_add_string(struct nl_writer *nw, uint16_t attrtype, const char *str)301{302return (nlattr_add(nw, attrtype, strlen(str) + 1, str));303}304305static inline bool306nlattr_add_in_addr(struct nl_writer *nw, uint16_t attrtype,307const struct in_addr *in)308{309return (nlattr_add(nw, attrtype, sizeof(*in), in));310}311312static inline bool313nlattr_add_in6_addr(struct nl_writer *nw, uint16_t attrtype,314const struct in6_addr *in6)315{316return (nlattr_add(nw, attrtype, sizeof(*in6), in6));317}318#endif319#endif320321322