1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2022 Alexander V. Chernikov <melifaro@FreeBSD.org> 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_ROUTE_H_ 28 #define _NETLINK_NETLINK_SNL_ROUTE_H_ 29 30 #include <netlink/netlink_snl.h> 31 #include <netlink/netlink_route.h> 32 #include <netinet/in.h> 33 34 /* 35 * Simple Netlink Library - NETLINK_ROUTE helpers 36 */ 37 38 static inline struct sockaddr * 39 parse_rta_ip4(struct snl_state *ss, void *rta_data, int *perror) 40 { 41 struct sockaddr_in *sin; 42 43 sin = (struct sockaddr_in *)snl_allocz(ss, sizeof(struct sockaddr_in)); 44 if (sin == NULL) { 45 *perror = ENOBUFS; 46 return (NULL); 47 } 48 sin->sin_len = sizeof(struct sockaddr_in); 49 sin->sin_family = AF_INET; 50 memcpy(&sin->sin_addr, rta_data, sizeof(struct in_addr)); 51 return ((struct sockaddr *)sin); 52 } 53 54 static inline struct sockaddr * 55 parse_rta_ip6(struct snl_state *ss, void *rta_data, int *perror) 56 { 57 struct sockaddr_in6 *sin6; 58 59 sin6 = (struct sockaddr_in6 *)snl_allocz(ss, sizeof(struct sockaddr_in6)); 60 if (sin6 == NULL) { 61 *perror = ENOBUFS; 62 return (NULL); 63 } 64 sin6->sin6_len = sizeof(struct sockaddr_in6); 65 sin6->sin6_family = AF_INET6; 66 memcpy(&sin6->sin6_addr, rta_data, sizeof(struct in6_addr)); 67 return ((struct sockaddr *)sin6); 68 } 69 70 static inline struct sockaddr * 71 parse_rta_ip(struct snl_state *ss, struct rtattr *rta, int *perror) 72 { 73 void *rta_data = NL_RTA_DATA(rta); 74 int rta_len = NL_RTA_DATA_LEN(rta); 75 76 if (rta_len == sizeof(struct in_addr)) { 77 return (parse_rta_ip4(ss, rta_data, perror)); 78 } else if (rta_len == sizeof(struct in6_addr)) { 79 return (parse_rta_ip6(ss, rta_data, perror)); 80 } else { 81 *perror = ENOTSUP; 82 return (NULL); 83 } 84 return (NULL); 85 } 86 87 static inline bool 88 snl_attr_get_ip(struct snl_state *ss, struct nlattr *nla, 89 const void *arg __unused, void *target) 90 { 91 int error = 0; 92 struct sockaddr *sa = parse_rta_ip(ss, (struct rtattr *)nla, &error); 93 if (error == 0) { 94 *((struct sockaddr **)target) = sa; 95 return (true); 96 } 97 return (false); 98 } 99 100 static inline struct sockaddr * 101 parse_rta_via(struct snl_state *ss, struct rtattr *rta, int *perror) 102 { 103 struct rtvia *via = NL_RTA_DATA(rta); 104 105 switch (via->rtvia_family) { 106 case AF_INET: 107 return (parse_rta_ip4(ss, via->rtvia_addr, perror)); 108 case AF_INET6: 109 return (parse_rta_ip6(ss, via->rtvia_addr, perror)); 110 default: 111 *perror = ENOTSUP; 112 return (NULL); 113 } 114 } 115 116 static inline bool 117 snl_attr_get_ipvia(struct snl_state *ss, struct nlattr *nla, 118 const void *arg __unused, void *target) 119 { 120 int error = 0; 121 122 struct sockaddr *sa = parse_rta_via(ss, (struct rtattr *)nla, &error); 123 if (error == 0) { 124 *((struct sockaddr **)target) = sa; 125 return (true); 126 } 127 return (false); 128 } 129 130 static inline bool 131 snl_add_msg_attr_ip4(struct snl_writer *nw, int attrtype, const struct in_addr *addr) 132 { 133 return (snl_add_msg_attr(nw, attrtype, 4, addr)); 134 } 135 136 static inline bool 137 snl_add_msg_attr_ip6(struct snl_writer *nw, int attrtype, const struct in6_addr *addr) 138 { 139 return (snl_add_msg_attr(nw, attrtype, 16, addr)); 140 } 141 142 static inline bool 143 snl_add_msg_attr_ip(struct snl_writer *nw, int attrtype, const struct sockaddr *sa) 144 { 145 const void *addr; 146 147 switch (sa->sa_family) { 148 case AF_INET: 149 addr = &((const struct sockaddr_in *)(const void *)sa)->sin_addr; 150 return (snl_add_msg_attr(nw, attrtype, 4, addr)); 151 case AF_INET6: 152 addr = &((const struct sockaddr_in6 *)(const void *)sa)->sin6_addr; 153 return (snl_add_msg_attr(nw, attrtype, 16, addr)); 154 } 155 156 return (false); 157 } 158 159 static inline bool 160 snl_add_msg_attr_ipvia(struct snl_writer *nw, int attrtype, const struct sockaddr *sa) 161 { 162 char buf[17]; 163 164 buf[0] = sa->sa_family; 165 166 switch (sa->sa_family) { 167 case AF_INET: 168 memcpy(&buf[1], &((const struct sockaddr_in *)(const void *)sa)->sin_addr, 4); 169 return (snl_add_msg_attr(nw, attrtype, 5, buf)); 170 case AF_INET6: 171 memcpy(&buf[1], &((const struct sockaddr_in6 *)(const void *)sa)->sin6_addr, 16); 172 return (snl_add_msg_attr(nw, attrtype, 17, buf)); 173 } 174 175 return (false); 176 } 177 178 static inline bool 179 snl_attr_get_in_addr(struct snl_state *ss __unused, struct nlattr *nla, 180 const void *arg __unused, void *target) 181 { 182 if (NLA_DATA_LEN(nla) != sizeof(struct in_addr)) 183 return (false); 184 185 memcpy(target, NLA_DATA_CONST(nla), sizeof(struct in_addr)); 186 return (true); 187 } 188 189 static inline bool 190 snl_attr_get_in6_addr(struct snl_state *ss __unused, struct nlattr *nla, 191 const void *arg __unused, void *target) 192 { 193 if (NLA_DATA_LEN(nla) != sizeof(struct in6_addr)) 194 return (false); 195 196 memcpy(target, NLA_DATA_CONST(nla), sizeof(struct in6_addr)); 197 return (true); 198 } 199 200 201 #endif 202