1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 mbuf; 41 struct nl_writer; 42 typedef bool nl_writer_cb(struct nl_writer *nw, void *buf, int buflen, int cnt); 43 44 struct nl_writer { 45 int alloc_len; /* allocated buffer length */ 46 int offset; /* offset from the start of the buffer */ 47 struct nlmsghdr *hdr; /* Pointer to the currently-filled msg */ 48 char *data; /* pointer to the contiguous storage */ 49 void *_storage; /* Underlying storage pointer */ 50 nl_writer_cb *cb; /* Callback to flush data */ 51 union { 52 void *arg_ptr; /* Callback argument as pointer */ 53 uint64_t arg_uint; /* Callback argument as int */ 54 }; 55 int num_messages; /* Number of messages in the buffer */ 56 int malloc_flag; /* M_WAITOK or M_NOWAIT */ 57 uint8_t writer_type; /* NS_WRITER_TYPE_* */ 58 uint8_t writer_target; /* NS_WRITER_TARGET_* */ 59 bool ignore_limit; /* If true, ignores RCVBUF limit */ 60 bool enomem; /* True if ENOMEM occured */ 61 bool suppress_ack; /* If true, don't send NLMSG_ERR */ 62 }; 63 #define NS_WRITER_TARGET_SOCKET 0 64 #define NS_WRITER_TARGET_GROUP 1 65 #define NS_WRITER_TARGET_CHAIN 2 66 67 #define NS_WRITER_TYPE_MBUF 0 68 #define NS_WRITER_TYPE_BUF 1 69 #define NS_WRITER_TYPE_LBUF 2 70 #define NS_WRITER_TYPE_MBUFC 3 71 #define NS_WRITER_TYPE_STUB 4 72 73 74 #define NLMSG_SMALL 128 75 #define NLMSG_LARGE 2048 76 77 /* Message and attribute writing */ 78 79 struct nlpcb; 80 81 #if defined(NETLINK) || defined(NETLINK_MODULE) 82 /* Provide optimized calls to the functions inside the same linking unit */ 83 84 bool _nlmsg_get_unicast_writer(struct nl_writer *nw, int expected_size, struct nlpcb *nlp); 85 bool _nlmsg_get_group_writer(struct nl_writer *nw, int expected_size, int proto, int group_id); 86 bool _nlmsg_get_chain_writer(struct nl_writer *nw, int expected_size, struct mbuf **pm); 87 bool _nlmsg_flush(struct nl_writer *nw); 88 void _nlmsg_ignore_limit(struct nl_writer *nw); 89 90 bool _nlmsg_refill_buffer(struct nl_writer *nw, int required_size); 91 bool _nlmsg_add(struct nl_writer *nw, uint32_t portid, uint32_t seq, uint16_t type, 92 uint16_t flags, uint32_t len); 93 bool _nlmsg_end(struct nl_writer *nw); 94 void _nlmsg_abort(struct nl_writer *nw); 95 96 bool _nlmsg_end_dump(struct nl_writer *nw, int error, struct nlmsghdr *hdr); 97 98 99 static inline bool 100 nlmsg_get_unicast_writer(struct nl_writer *nw, int expected_size, struct nlpcb *nlp) 101 { 102 return (_nlmsg_get_unicast_writer(nw, expected_size, nlp)); 103 } 104 105 static inline bool 106 nlmsg_get_group_writer(struct nl_writer *nw, int expected_size, int proto, int group_id) 107 { 108 return (_nlmsg_get_group_writer(nw, expected_size, proto, group_id)); 109 } 110 111 static inline bool 112 nlmsg_get_chain_writer(struct nl_writer *nw, int expected_size, struct mbuf **pm) 113 { 114 return (_nlmsg_get_chain_writer(nw, expected_size, pm)); 115 } 116 117 static inline bool 118 nlmsg_flush(struct nl_writer *nw) 119 { 120 return (_nlmsg_flush(nw)); 121 } 122 123 static inline void 124 nlmsg_ignore_limit(struct nl_writer *nw) 125 { 126 _nlmsg_ignore_limit(nw); 127 } 128 129 static inline bool 130 nlmsg_refill_buffer(struct nl_writer *nw, int required_size) 131 { 132 return (_nlmsg_refill_buffer(nw, required_size)); 133 } 134 135 static inline bool 136 nlmsg_add(struct nl_writer *nw, uint32_t portid, uint32_t seq, uint16_t type, 137 uint16_t flags, uint32_t len) 138 { 139 return (_nlmsg_add(nw, portid, seq, type, flags, len)); 140 } 141 142 static inline bool 143 nlmsg_end(struct nl_writer *nw) 144 { 145 return (_nlmsg_end(nw)); 146 } 147 148 static inline void 149 nlmsg_abort(struct nl_writer *nw) 150 { 151 return (_nlmsg_abort(nw)); 152 } 153 154 static inline bool 155 nlmsg_end_dump(struct nl_writer *nw, int error, struct nlmsghdr *hdr) 156 { 157 return (_nlmsg_end_dump(nw, error, hdr)); 158 } 159 160 #else 161 /* Provide access to the functions via netlink_glue.c */ 162 163 bool nlmsg_get_unicast_writer(struct nl_writer *nw, int expected_size, struct nlpcb *nlp); 164 bool nlmsg_get_group_writer(struct nl_writer *nw, int expected_size, int proto, int group_id); 165 bool nlmsg_get_chain_writer(struct nl_writer *nw, int expected_size, struct mbuf **pm); 166 bool nlmsg_flush(struct nl_writer *nw); 167 void nlmsg_ignore_limit(struct nl_writer *nw); 168 169 bool nlmsg_refill_buffer(struct nl_writer *nw, int required_size); 170 bool nlmsg_add(struct nl_writer *nw, uint32_t portid, uint32_t seq, uint16_t type, 171 uint16_t flags, uint32_t len); 172 bool nlmsg_end(struct nl_writer *nw); 173 void nlmsg_abort(struct nl_writer *nw); 174 175 bool nlmsg_end_dump(struct nl_writer *nw, int error, struct nlmsghdr *hdr); 176 177 #endif /* defined(NETLINK) || defined(NETLINK_MODULE) */ 178 179 static inline bool 180 nlmsg_reply(struct nl_writer *nw, const struct nlmsghdr *hdr, int payload_len) 181 { 182 return (nlmsg_add(nw, hdr->nlmsg_pid, hdr->nlmsg_seq, hdr->nlmsg_type, 183 hdr->nlmsg_flags, payload_len)); 184 } 185 186 #define nlmsg_data(_hdr) ((void *)((_hdr) + 1)) 187 188 /* 189 * KPI similar to mtodo(): 190 * current (uncompleted) header is guaranteed to be contiguous, 191 * but can be reallocated, thus pointers may need to be readjusted. 192 */ 193 static inline int 194 nlattr_save_offset(const struct nl_writer *nw) 195 { 196 return (nw->offset - ((char *)nw->hdr - nw->data)); 197 } 198 199 static inline void * 200 _nlattr_restore_offset(const struct nl_writer *nw, int off) 201 { 202 return ((void *)((char *)nw->hdr + off)); 203 } 204 #define nlattr_restore_offset(_ns, _off, _t) ((_t *)_nlattr_restore_offset(_ns, _off)) 205 206 static inline void 207 nlattr_set_len(const struct nl_writer *nw, int off) 208 { 209 struct nlattr *nla = nlattr_restore_offset(nw, off, struct nlattr); 210 nla->nla_len = nlattr_save_offset(nw) - off; 211 } 212 213 static inline void * 214 nlmsg_reserve_data_raw(struct nl_writer *nw, size_t sz) 215 { 216 sz = NETLINK_ALIGN(sz); 217 218 if (__predict_false(nw->offset + sz > nw->alloc_len)) { 219 if (!nlmsg_refill_buffer(nw, sz)) 220 return (NULL); 221 } 222 223 void *data_ptr = &nw->data[nw->offset]; 224 nw->offset += sz; 225 226 return (data_ptr); 227 } 228 #define nlmsg_reserve_object(_ns, _t) ((_t *)nlmsg_reserve_data_raw(_ns, sizeof(_t))) 229 #define nlmsg_reserve_data(_ns, _sz, _t) ((_t *)nlmsg_reserve_data_raw(_ns, _sz)) 230 231 static inline int 232 nlattr_add_nested(struct nl_writer *nw, uint16_t nla_type) 233 { 234 int off = nlattr_save_offset(nw); 235 struct nlattr *nla = nlmsg_reserve_data(nw, sizeof(struct nlattr), struct nlattr); 236 if (__predict_false(nla == NULL)) 237 return (0); 238 nla->nla_type = nla_type; 239 return (off); 240 } 241 242 static inline void * 243 _nlmsg_reserve_attr(struct nl_writer *nw, uint16_t nla_type, uint16_t sz) 244 { 245 sz += sizeof(struct nlattr); 246 247 struct nlattr *nla = nlmsg_reserve_data(nw, sz, struct nlattr); 248 if (__predict_false(nla == NULL)) 249 return (NULL); 250 nla->nla_type = nla_type; 251 nla->nla_len = sz; 252 253 return ((void *)(nla + 1)); 254 } 255 #define nlmsg_reserve_attr(_ns, _at, _t) ((_t *)_nlmsg_reserve_attr(_ns, _at, NLA_ALIGN(sizeof(_t)))) 256 257 static inline bool 258 nlattr_add(struct nl_writer *nw, int attr_type, int attr_len, const void *data) 259 { 260 int required_len = NLA_ALIGN(attr_len + sizeof(struct nlattr)); 261 262 if (__predict_false(nw->offset + required_len > nw->alloc_len)) { 263 if (!nlmsg_refill_buffer(nw, required_len)) 264 return (false); 265 } 266 267 struct nlattr *nla = (struct nlattr *)(&nw->data[nw->offset]); 268 269 nla->nla_len = attr_len + sizeof(struct nlattr); 270 nla->nla_type = attr_type; 271 if (attr_len > 0) { 272 if ((attr_len % 4) != 0) { 273 /* clear padding bytes */ 274 bzero((char *)nla + required_len - 4, 4); 275 } 276 memcpy((nla + 1), data, attr_len); 277 } 278 nw->offset += required_len; 279 return (true); 280 } 281 282 static inline bool 283 nlattr_add_raw(struct nl_writer *nw, const struct nlattr *nla_src) 284 { 285 int attr_len = nla_src->nla_len - sizeof(struct nlattr); 286 287 MPASS(attr_len >= 0); 288 289 return (nlattr_add(nw, nla_src->nla_type, attr_len, (const void *)(nla_src + 1))); 290 } 291 292 static inline bool 293 nlattr_add_u8(struct nl_writer *nw, int attrtype, uint8_t value) 294 { 295 return (nlattr_add(nw, attrtype, sizeof(uint8_t), &value)); 296 } 297 298 static inline bool 299 nlattr_add_u16(struct nl_writer *nw, int attrtype, uint16_t value) 300 { 301 return (nlattr_add(nw, attrtype, sizeof(uint16_t), &value)); 302 } 303 304 static inline bool 305 nlattr_add_u32(struct nl_writer *nw, int attrtype, uint32_t value) 306 { 307 return (nlattr_add(nw, attrtype, sizeof(uint32_t), &value)); 308 } 309 310 static inline bool 311 nlattr_add_u64(struct nl_writer *nw, int attrtype, uint64_t value) 312 { 313 return (nlattr_add(nw, attrtype, sizeof(uint64_t), &value)); 314 } 315 316 static inline bool 317 nlattr_add_s8(struct nl_writer *nw, int attrtype, int8_t value) 318 { 319 return (nlattr_add(nw, attrtype, sizeof(int8_t), &value)); 320 } 321 322 static inline bool 323 nlattr_add_s16(struct nl_writer *nw, int attrtype, int16_t value) 324 { 325 return (nlattr_add(nw, attrtype, sizeof(int16_t), &value)); 326 } 327 328 static inline bool 329 nlattr_add_s32(struct nl_writer *nw, int attrtype, int32_t value) 330 { 331 return (nlattr_add(nw, attrtype, sizeof(int32_t), &value)); 332 } 333 334 static inline bool 335 nlattr_add_s64(struct nl_writer *nw, int attrtype, int64_t value) 336 { 337 return (nlattr_add(nw, attrtype, sizeof(int64_t), &value)); 338 } 339 340 static inline bool 341 nlattr_add_flag(struct nl_writer *nw, int attrtype) 342 { 343 return (nlattr_add(nw, attrtype, 0, NULL)); 344 } 345 346 static inline bool 347 nlattr_add_string(struct nl_writer *nw, int attrtype, const char *str) 348 { 349 return (nlattr_add(nw, attrtype, strlen(str) + 1, str)); 350 } 351 352 static inline bool 353 nlattr_add_in_addr(struct nl_writer *nw, int attrtype, const struct in_addr *in) 354 { 355 return (nlattr_add(nw, attrtype, sizeof(*in), in)); 356 } 357 358 static inline bool 359 nlattr_add_in6_addr(struct nl_writer *nw, int attrtype, const struct in6_addr *in6) 360 { 361 return (nlattr_add(nw, attrtype, sizeof(*in6), in6)); 362 } 363 #endif 364 #endif 365