1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2021 Ng Peng Nam Sean 5 * Copyright (c) 2022 Alexander V. Chernikov <melifaro@FreeBSD.org> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #ifndef _NETLINK_NETLINK_MESSAGE_WRITER_H_ 30 #define _NETLINK_NETLINK_MESSAGE_WRITER_H_ 31 32 #ifdef _KERNEL 33 34 #include <netinet/in.h> 35 36 /* 37 * It is not meant to be included directly 38 */ 39 40 struct nl_buf; 41 struct nl_writer; 42 typedef bool nl_writer_cb(struct nl_writer *nw); 43 44 struct nl_writer { 45 struct nl_buf *buf; /* Underlying storage pointer */ 46 struct nlmsghdr *hdr; /* Pointer to the currently-filled msg */ 47 nl_writer_cb *cb; /* Callback to flush data */ 48 union { 49 struct nlpcb *nlp; 50 struct { 51 uint16_t proto; 52 uint16_t id; 53 int priv; 54 } group; 55 }; 56 u_int num_messages; /* Number of messages in the buffer */ 57 int malloc_flag; /* M_WAITOK or M_NOWAIT */ 58 bool ignore_limit; /* If true, ignores RCVBUF limit */ 59 bool enomem; /* True if ENOMEM occured */ 60 bool suppress_ack; /* If true, don't send NLMSG_ERR */ 61 }; 62 63 #define NLMSG_SMALL 128 64 #define NLMSG_LARGE 2048 65 66 /* Message and attribute writing */ 67 #if defined(NETLINK) || defined(NETLINK_MODULE) 68 /* Provide optimized calls to the functions inside the same linking unit */ 69 70 bool _nl_writer_unicast(struct nl_writer *, size_t, struct nlpcb *nlp, bool); 71 bool _nl_writer_group(struct nl_writer *, size_t, uint16_t, uint16_t, int, 72 bool); 73 bool _nlmsg_flush(struct nl_writer *nw); 74 void _nlmsg_ignore_limit(struct nl_writer *nw); 75 76 bool _nlmsg_refill_buffer(struct nl_writer *nw, size_t required_len); 77 bool _nlmsg_add(struct nl_writer *nw, uint32_t portid, uint32_t seq, 78 uint16_t type, uint16_t flags, uint32_t len); 79 bool _nlmsg_end(struct nl_writer *nw); 80 void _nlmsg_abort(struct nl_writer *nw); 81 82 bool _nlmsg_end_dump(struct nl_writer *nw, int error, struct nlmsghdr *hdr); 83 84 85 static inline bool 86 nl_writer_unicast(struct nl_writer *nw, size_t size, struct nlpcb *nlp, 87 bool waitok) 88 { 89 return (_nl_writer_unicast(nw, size, nlp, waitok)); 90 } 91 92 static inline bool 93 nl_writer_group(struct nl_writer *nw, size_t size, uint16_t proto, 94 uint16_t group_id, int priv, bool waitok) 95 { 96 return (_nl_writer_group(nw, size, proto, group_id, priv, waitok)); 97 } 98 99 static inline bool 100 nlmsg_flush(struct nl_writer *nw) 101 { 102 return (_nlmsg_flush(nw)); 103 } 104 105 static inline void 106 nlmsg_ignore_limit(struct nl_writer *nw) 107 { 108 _nlmsg_ignore_limit(nw); 109 } 110 111 static inline bool 112 nlmsg_refill_buffer(struct nl_writer *nw, size_t required_size) 113 { 114 return (_nlmsg_refill_buffer(nw, required_size)); 115 } 116 117 static inline bool 118 nlmsg_add(struct nl_writer *nw, uint32_t portid, uint32_t seq, uint16_t type, 119 uint16_t flags, uint32_t len) 120 { 121 return (_nlmsg_add(nw, portid, seq, type, flags, len)); 122 } 123 124 static inline bool 125 nlmsg_end(struct nl_writer *nw) 126 { 127 return (_nlmsg_end(nw)); 128 } 129 130 static inline void 131 nlmsg_abort(struct nl_writer *nw) 132 { 133 return (_nlmsg_abort(nw)); 134 } 135 136 static inline bool 137 nlmsg_end_dump(struct nl_writer *nw, int error, struct nlmsghdr *hdr) 138 { 139 return (_nlmsg_end_dump(nw, error, hdr)); 140 } 141 142 #else 143 /* Provide access to the functions via netlink_glue.c */ 144 145 bool nl_writer_unicast(struct nl_writer *, size_t, struct nlpcb *, bool waitok); 146 bool nl_writer_group(struct nl_writer *, size_t, uint16_t, uint16_t, int, 147 bool waitok); 148 bool nlmsg_flush(struct nl_writer *nw); 149 void nlmsg_ignore_limit(struct nl_writer *nw); 150 151 bool nlmsg_refill_buffer(struct nl_writer *nw, size_t required_size); 152 bool nlmsg_add(struct nl_writer *nw, uint32_t portid, uint32_t seq, 153 uint16_t type, uint16_t flags, uint32_t len); 154 bool nlmsg_end(struct nl_writer *nw); 155 void nlmsg_abort(struct nl_writer *nw); 156 157 bool nlmsg_end_dump(struct nl_writer *nw, int error, struct nlmsghdr *hdr); 158 159 #endif /* defined(NETLINK) || defined(NETLINK_MODULE) */ 160 161 static inline bool 162 nlmsg_reply(struct nl_writer *nw, const struct nlmsghdr *hdr, int payload_len) 163 { 164 return (nlmsg_add(nw, hdr->nlmsg_pid, hdr->nlmsg_seq, hdr->nlmsg_type, 165 hdr->nlmsg_flags, payload_len)); 166 } 167 168 /* 169 * KPI similar to mtodo(): 170 * current (uncompleted) header is guaranteed to be contiguous, 171 * but can be reallocated, thus pointers may need to be readjusted. 172 */ 173 u_int nlattr_save_offset(const struct nl_writer *nw); 174 175 static inline void * 176 _nlattr_restore_offset(const struct nl_writer *nw, int off) 177 { 178 return ((void *)((char *)nw->hdr + off)); 179 } 180 #define nlattr_restore_offset(_ns, _off, _t) ((_t *)_nlattr_restore_offset(_ns, _off)) 181 182 static inline void 183 nlattr_set_len(const struct nl_writer *nw, int off) 184 { 185 struct nlattr *nla = nlattr_restore_offset(nw, off, struct nlattr); 186 nla->nla_len = nlattr_save_offset(nw) - off; 187 } 188 189 void *nlmsg_reserve_data_raw(struct nl_writer *nw, size_t sz); 190 #define nlmsg_reserve_object(_ns, _t) ((_t *)nlmsg_reserve_data_raw(_ns, sizeof(_t))) 191 #define nlmsg_reserve_data(_ns, _sz, _t) ((_t *)nlmsg_reserve_data_raw(_ns, _sz)) 192 193 static inline int 194 nlattr_add_nested(struct nl_writer *nw, uint16_t nla_type) 195 { 196 int off = nlattr_save_offset(nw); 197 struct nlattr *nla = nlmsg_reserve_data(nw, sizeof(struct nlattr), struct nlattr); 198 if (__predict_false(nla == NULL)) 199 return (0); 200 nla->nla_type = nla_type; 201 return (off); 202 } 203 204 static inline void * 205 _nlmsg_reserve_attr(struct nl_writer *nw, uint16_t nla_type, uint16_t sz) 206 { 207 sz += sizeof(struct nlattr); 208 209 struct nlattr *nla = nlmsg_reserve_data(nw, sz, struct nlattr); 210 if (__predict_false(nla == NULL)) 211 return (NULL); 212 nla->nla_type = nla_type; 213 nla->nla_len = sz; 214 215 return ((void *)(nla + 1)); 216 } 217 #define nlmsg_reserve_attr(_ns, _at, _t) ((_t *)_nlmsg_reserve_attr(_ns, _at, NLA_ALIGN(sizeof(_t)))) 218 219 bool nlattr_add(struct nl_writer *nw, uint16_t attr_type, uint16_t attr_len, 220 const void *data); 221 222 static inline bool 223 nlattr_add_raw(struct nl_writer *nw, const struct nlattr *nla_src) 224 { 225 MPASS(nla_src->nla_len >= sizeof(struct nlattr)); 226 227 return (nlattr_add(nw, nla_src->nla_type, 228 nla_src->nla_len - sizeof(struct nlattr), 229 (const void *)(nla_src + 1))); 230 } 231 232 static inline bool 233 nlattr_add_bool(struct nl_writer *nw, uint16_t attrtype, bool value) 234 { 235 return (nlattr_add(nw, attrtype, sizeof(bool), &value)); 236 } 237 238 static inline bool 239 nlattr_add_u8(struct nl_writer *nw, uint16_t attrtype, uint8_t value) 240 { 241 return (nlattr_add(nw, attrtype, sizeof(uint8_t), &value)); 242 } 243 244 static inline bool 245 nlattr_add_u16(struct nl_writer *nw, uint16_t attrtype, uint16_t value) 246 { 247 return (nlattr_add(nw, attrtype, sizeof(uint16_t), &value)); 248 } 249 250 static inline bool 251 nlattr_add_u32(struct nl_writer *nw, uint16_t attrtype, uint32_t value) 252 { 253 return (nlattr_add(nw, attrtype, sizeof(uint32_t), &value)); 254 } 255 256 static inline bool 257 nlattr_add_u64(struct nl_writer *nw, uint16_t attrtype, uint64_t value) 258 { 259 return (nlattr_add(nw, attrtype, sizeof(uint64_t), &value)); 260 } 261 262 static inline bool 263 nlattr_add_s8(struct nl_writer *nw, uint16_t attrtype, int8_t value) 264 { 265 return (nlattr_add(nw, attrtype, sizeof(int8_t), &value)); 266 } 267 268 static inline bool 269 nlattr_add_s16(struct nl_writer *nw, uint16_t attrtype, int16_t value) 270 { 271 return (nlattr_add(nw, attrtype, sizeof(int16_t), &value)); 272 } 273 274 static inline bool 275 nlattr_add_s32(struct nl_writer *nw, uint16_t attrtype, int32_t value) 276 { 277 return (nlattr_add(nw, attrtype, sizeof(int32_t), &value)); 278 } 279 280 static inline bool 281 nlattr_add_s64(struct nl_writer *nw, uint16_t attrtype, int64_t value) 282 { 283 return (nlattr_add(nw, attrtype, sizeof(int64_t), &value)); 284 } 285 286 static inline bool 287 nlattr_add_flag(struct nl_writer *nw, uint16_t attrtype) 288 { 289 return (nlattr_add(nw, attrtype, 0, NULL)); 290 } 291 292 static inline bool 293 nlattr_add_string(struct nl_writer *nw, uint16_t attrtype, const char *str) 294 { 295 return (nlattr_add(nw, attrtype, strlen(str) + 1, str)); 296 } 297 298 static inline bool 299 nlattr_add_in_addr(struct nl_writer *nw, uint16_t attrtype, 300 const struct in_addr *in) 301 { 302 return (nlattr_add(nw, attrtype, sizeof(*in), in)); 303 } 304 305 static inline bool 306 nlattr_add_in6_addr(struct nl_writer *nw, uint16_t attrtype, 307 const struct in6_addr *in6) 308 { 309 return (nlattr_add(nw, attrtype, sizeof(*in6), in6)); 310 } 311 #endif 312 #endif 313