Page MenuHomeFreeBSD

D38940.diff
No OneTemporary

D38940.diff

diff --git a/lib/libifconfig/libifconfig.h b/lib/libifconfig/libifconfig.h
--- a/lib/libifconfig/libifconfig.h
+++ b/lib/libifconfig/libifconfig.h
@@ -287,6 +287,8 @@
int32_t carpr_advbase;
int32_t carpr_advskew;
uint8_t carpr_key[CARP_KEY_LEN];
+ struct in_addr carpr_addr;
+ struct in6_addr carpr_addr6;
};
int ifconfig_carp_get_vhid(ifconfig_handle_t *h, const char *name,
diff --git a/lib/libifconfig/libifconfig_carp.c b/lib/libifconfig/libifconfig_carp.c
--- a/lib/libifconfig/libifconfig_carp.c
+++ b/lib/libifconfig/libifconfig_carp.c
@@ -39,6 +39,7 @@
#include <netlink/netlink_generic.h>
#include <netlink/netlink_snl.h>
#include <netlink/netlink_snl_generic.h>
+#include <netlink/netlink_snl_route.h>
#include <string.h>
#include <strings.h>
@@ -55,6 +56,8 @@
{ .type = CARP_NL_ADVBASE, .off = _OUT(carpr_advbase), .cb = snl_attr_get_int32 },
{ .type = CARP_NL_ADVSKEW, .off = _OUT(carpr_advskew), .cb = snl_attr_get_int32 },
{ .type = CARP_NL_KEY, .off = _OUT(carpr_key), .cb = snl_attr_get_string },
+ { .type = CARP_NL_ADDR, .off = _OUT(carpr_addr), .cb = snl_attr_get_in_addr },
+ { .type = CARP_NL_ADDR6, .off = _OUT(carpr_addr6), .cb = snl_attr_get_in6_addr },
};
#undef _OUT
@@ -181,6 +184,10 @@
snl_add_msg_attr_s32(&nw, CARP_NL_ADVBASE, carpr->carpr_advbase);
snl_add_msg_attr_s32(&nw, CARP_NL_ADVSKEW, carpr->carpr_advskew);
snl_add_msg_attr_u32(&nw, CARP_NL_IFINDEX, ifindex);
+ snl_add_msg_attr(&nw, CARP_NL_ADDR, sizeof(carpr->carpr_addr),
+ &carpr->carpr_addr);
+ snl_add_msg_attr(&nw, CARP_NL_ADDR6, sizeof(carpr->carpr_addr6),
+ &carpr->carpr_addr6);
hdr = snl_finalize_msg(&nw);
if (hdr == NULL) {
diff --git a/sbin/ifconfig/carp.c b/sbin/ifconfig/carp.c
--- a/sbin/ifconfig/carp.c
+++ b/sbin/ifconfig/carp.c
@@ -42,13 +42,17 @@
#include <netinet/in_var.h>
#include <netinet/ip_carp.h>
+#include <arpa/inet.h>
+
#include <ctype.h>
+#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <err.h>
#include <errno.h>
+#include <netdb.h>
#include <libifconfig.h>
@@ -67,12 +71,15 @@
static int carpr_advskew = -1;
static int carpr_advbase = -1;
static int carpr_state = -1;
+static struct in_addr carp_addr;
+static struct in6_addr carp_addr6;
static unsigned char const *carpr_key;
static void
carp_status(int s)
{
struct ifconfig_carp carpr[CARP_MAXVHID];
+ char addr_buf[NI_MAXHOST];
if (ifconfig_carp_get_info(lifh, name, carpr, CARP_MAXVHID) == -1)
return;
@@ -85,6 +92,12 @@
printf(" key \"%s\"\n", carpr[i].carpr_key);
else
printf("\n");
+
+ inet_ntop(AF_INET6, &carpr[i].carpr_addr6, addr_buf,
+ sizeof(addr_buf));
+
+ printf("\t peer %s peer6 %s\n",
+ inet_ntoa(carpr[i].carpr_addr), addr_buf);
}
}
@@ -146,6 +159,11 @@
carpr.carpr_advbase = carpr_advbase;
if (carpr_state > -1)
carpr.carpr_state = carpr_state;
+ if (carp_addr.s_addr != INADDR_ANY)
+ carpr.carpr_addr = carp_addr;
+ if (! IN6_IS_ADDR_UNSPECIFIED(&carp_addr6))
+ memcpy(&carpr.carpr_addr6, &carp_addr6,
+ sizeof(carp_addr6));
if (ifconfig_carp_set_info(lifh, name, &carpr))
err(1, "SIOCSVH");
@@ -198,12 +216,53 @@
errx(1, "unknown state");
}
+static void
+setcarp_peer(const char *val, int d, int s, const struct afswtch *afp)
+{
+ carp_addr.s_addr = inet_addr(val);
+}
+
+static void
+setcarp_mcast(const char *val, int d, int s, const struct afswtch *afp)
+{
+ carp_addr.s_addr = htonl(INADDR_CARP_GROUP);
+}
+
+static void
+setcarp_peer6(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct addrinfo hints, *res;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET6;
+ hints.ai_flags = AI_NUMERICHOST;
+
+ if (getaddrinfo(val, NULL, &hints, &res) == 1)
+ errx(1, "Invalid IPv6 address %s", val);
+
+ memcpy(&carp_addr6, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
+ sizeof(carp_addr6));
+}
+
+static void
+setcarp_mcast6(const char *val, int d, int s, const struct afswtch *afp)
+{
+ bzero(&carp_addr6, sizeof(carp_addr6));
+ carp_addr6.s6_addr[0] = 0xff;
+ carp_addr6.s6_addr[1] = 0x02;
+ carp_addr6.s6_addr[15] = 0x12;
+}
+
static struct cmd carp_cmds[] = {
DEF_CMD_ARG("advbase", setcarp_advbase),
DEF_CMD_ARG("advskew", setcarp_advskew),
DEF_CMD_ARG("pass", setcarp_passwd),
DEF_CMD_ARG("vhid", setcarp_vhid),
DEF_CMD_ARG("state", setcarp_state),
+ DEF_CMD_ARG("peer", setcarp_peer),
+ DEF_CMD_ARG("mcast", setcarp_mcast),
+ DEF_CMD_ARG("peer6", setcarp_peer6),
+ DEF_CMD_ARG("mcast6", setcarp_mcast6),
};
static struct afswtch af_carp = {
.af_name = "af_carp",
@@ -216,6 +275,10 @@
{
int i;
+ /* Default to multicast. */
+ setcarp_mcast(NULL, 0, 0, NULL);
+ setcarp_mcast6(NULL, 0, 0, NULL);
+
for (i = 0; i < nitems(carp_cmds); i++)
cmd_register(&carp_cmds[i]);
af_register(&af_carp);
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c
--- a/sys/netinet/ip_carp.c
+++ b/sys/netinet/ip_carp.c
@@ -110,6 +110,8 @@
int sc_vhid;
int sc_advskew;
int sc_advbase;
+ struct in_addr sc_carpaddr;
+ struct in6_addr sc_carpaddr6;
int sc_naddrs;
int sc_naddrs6;
@@ -154,6 +156,20 @@
#define CIF_PROMISC 0x00000001
};
+/* Kernel equivalent of struct carpreq, but with more fields for new features.
+ * */
+struct carpkreq {
+ int carpr_count;
+ int carpr_vhid;
+ int carpr_state;
+ int carpr_advskew;
+ int carpr_advbase;
+ unsigned char carpr_key[CARP_KEY_LEN];
+ /* Everything above this is identical to carpreq */
+ struct in_addr carpr_addr;
+ struct in6_addr carpr_addr6;
+};
+
/*
* Brief design of carp(4).
*
@@ -310,7 +326,7 @@
(((sc)->sc_advskew + V_carp_demotion < 0) ? \
0 : ((sc)->sc_advskew + V_carp_demotion)))
-static void carp_input_c(struct mbuf *, struct carp_header *, sa_family_t);
+static void carp_input_c(struct mbuf *, struct carp_header *, sa_family_t, int);
static struct carp_softc
*carp_alloc(struct ifnet *);
static void carp_destroy(struct carp_softc *);
@@ -488,16 +504,6 @@
return (IPPROTO_DONE);
}
- /* verify that the IP TTL is 255. */
- if (ip->ip_ttl != CARP_DFLTTL) {
- CARPSTATS_INC(carps_badttl);
- CARP_DEBUG("%s: received ttl %d != 255 on %s\n", __func__,
- ip->ip_ttl,
- m->m_pkthdr.rcvif->if_xname);
- m_freem(m);
- return (IPPROTO_DONE);
- }
-
iplen = ip->ip_hl << 2;
if (m->m_pkthdr.len < iplen + sizeof(*ch)) {
@@ -551,7 +557,7 @@
}
m->m_data -= iplen;
- carp_input_c(m, ch, AF_INET);
+ carp_input_c(m, ch, AF_INET, ip->ip_ttl);
return (IPPROTO_DONE);
}
#endif
@@ -581,15 +587,6 @@
return (IPPROTO_DONE);
}
- /* verify that the IP TTL is 255 */
- if (ip6->ip6_hlim != CARP_DFLTTL) {
- CARPSTATS_INC(carps_badttl);
- CARP_DEBUG("%s: received ttl %d != 255 on %s\n", __func__,
- ip6->ip6_hlim, m->m_pkthdr.rcvif->if_xname);
- m_freem(m);
- return (IPPROTO_DONE);
- }
-
/* verify that we have a complete carp packet */
if (m->m_len < *offp + sizeof(*ch)) {
len = m->m_len;
@@ -599,6 +596,7 @@
CARP_DEBUG("%s: packet size %u too small\n", __func__, len);
return (IPPROTO_DONE);
}
+ ip6 = mtod(m, struct ip6_hdr *);
}
ch = (struct carp_header *)(mtod(m, char *) + *offp);
@@ -613,7 +611,7 @@
}
m->m_data -= *offp;
- carp_input_c(m, ch, AF_INET6);
+ carp_input_c(m, ch, AF_INET6, ip6->ip6_hlim);
return (IPPROTO_DONE);
}
#endif /* INET6 */
@@ -664,7 +662,7 @@
}
static void
-carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
+carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af, int ttl)
{
struct ifnet *ifp = m->m_pkthdr.rcvif;
struct ifaddr *ifa, *match;
@@ -672,6 +670,7 @@
uint64_t tmp_counter;
struct timeval sc_tv, ch_tv;
int error;
+ bool multicast = false;
NET_EPOCH_ASSERT();
@@ -724,8 +723,21 @@
sc = ifa->ifa_carp;
CARP_LOCK(sc);
+ if (ifa->ifa_addr->sa_family == AF_INET) {
+ multicast = IN_MULTICAST(sc->sc_carpaddr.s_addr);
+ } else {
+ multicast = IN6_IS_ADDR_MULTICAST(&sc->sc_carpaddr6);
+ }
ifa_free(ifa);
+ /* verify that the IP TTL is 255, but only if we're not in unicast mode. */
+ if (multicast && ttl != CARP_DFLTTL) {
+ CARPSTATS_INC(carps_badttl);
+ CARP_DEBUG("%s: received ttl %d != 255 on %s\n", __func__,
+ ttl, m->m_pkthdr.rcvif->if_xname);
+ goto out;
+ }
+
if (carp_hmac_verify(sc, ch->carp_counter, ch->carp_md)) {
CARPSTATS_INC(carps_badauth);
CARP_DEBUG("%s: incorrect hash for VHID %u@%s\n", __func__,
@@ -978,7 +990,8 @@
m->m_pkthdr.rcvif = NULL;
m->m_len = len;
M_ALIGN(m, m->m_len);
- m->m_flags |= M_MCAST;
+ if (IN_MULTICAST(sc->sc_carpaddr.s_addr))
+ m->m_flags |= M_MCAST;
ip = mtod(m, struct ip *);
ip->ip_v = IPVERSION;
ip->ip_hl = sizeof(*ip) >> 2;
@@ -997,7 +1010,7 @@
ifa_free(ifa);
} else
ip->ip_src.s_addr = 0;
- ip->ip_dst.s_addr = htonl(INADDR_CARP_GROUP);
+ ip->ip_dst = sc->sc_carpaddr;
ch_ptr = (struct carp_header *)(&ip[1]);
bcopy(&ch, ch_ptr, sizeof(ch));
@@ -1028,7 +1041,6 @@
m->m_pkthdr.rcvif = NULL;
m->m_len = len;
M_ALIGN(m, m->m_len);
- m->m_flags |= M_MCAST;
ip6 = mtod(m, struct ip6_hdr *);
bzero(ip6, sizeof(*ip6));
ip6->ip6_vfc |= IPV6_VERSION;
@@ -1050,12 +1062,13 @@
bzero(&ip6->ip6_src, sizeof(struct in6_addr));
/* Set the multicast destination. */
- ip6->ip6_dst.s6_addr16[0] = htons(0xff02);
- ip6->ip6_dst.s6_addr8[15] = 0x12;
- if (in6_setscope(&ip6->ip6_dst, sc->sc_carpdev, NULL) != 0) {
- m_freem(m);
- CARP_DEBUG("%s: in6_setscope failed\n", __func__);
- goto resched;
+ memcpy(&ip6->ip6_dst, &sc->sc_carpaddr6, sizeof(ip6->ip6_dst));
+ if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
+ if (in6_setscope(&ip6->ip6_dst, sc->sc_carpdev, NULL) != 0) {
+ m_freem(m);
+ CARP_DEBUG("%s: in6_setscope failed\n", __func__);
+ goto resched;
+ }
}
ch_ptr = (struct carp_header *)(&ip6[1]);
@@ -1571,6 +1584,19 @@
bcopy(mtag + 1, &sc, sizeof(sc));
+ switch (sa->sa_family) {
+ case AF_INET:
+ if (! IN_MULTICAST(sc->sc_carpaddr.s_addr))
+ return (0);
+ break;
+ case AF_INET6:
+ if (! IN6_IS_ADDR_MULTICAST(&sc->sc_carpaddr6))
+ return (0);
+ break;
+ default:
+ panic("Unknown af");
+ }
+
/* Set the source MAC address to the Virtual Router MAC Address. */
switch (ifp->if_type) {
case IFT_ETHER:
@@ -1618,6 +1644,10 @@
sc->sc_ifas = malloc(sc->sc_ifasiz, M_CARP, M_WAITOK|M_ZERO);
sc->sc_carpdev = ifp;
+ sc->sc_carpaddr.s_addr = htonl(INADDR_CARP_GROUP);
+ sc->sc_carpaddr6.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
+ sc->sc_carpaddr6.s6_addr8[15] = 0x12;
+
CARP_LOCK_INIT(sc);
#ifdef INET
callout_init_mtx(&sc->sc_md_tmo, &sc->sc_mtx, CALLOUT_RETURNUNLOCKED);
@@ -1753,7 +1783,7 @@
}
static int
-carp_ioctl_set(if_t ifp, struct carpreq *carpr)
+carp_ioctl_set(if_t ifp, struct carpkreq *carpr)
{
struct epoch_tracker et;
struct carp_softc *sc = NULL;
@@ -1795,6 +1825,12 @@
goto out;
}
sc->sc_advskew = carpr->carpr_advskew;
+ if (carpr->carpr_addr.s_addr != INADDR_ANY)
+ sc->sc_carpaddr = carpr->carpr_addr;
+ if (! IN6_IS_ADDR_UNSPECIFIED(&carpr->carpr_addr6)) {
+ memcpy(&sc->sc_carpaddr6, &carpr->carpr_addr6,
+ sizeof(sc->sc_carpaddr6));
+ }
if (carpr->carpr_key[0] != '\0') {
bcopy(carpr->carpr_key, sc->sc_key, sizeof(sc->sc_key));
carp_hmac_prepare(sc);
@@ -1875,6 +1911,7 @@
carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td)
{
struct carpreq carpr;
+ struct carpkreq carprk = { };
struct ifnet *ifp;
int error = 0;
@@ -1896,7 +1933,8 @@
if ((error = priv_check(td, PRIV_NETINET_CARP)))
break;
- error = carp_ioctl_set(ifp, &carpr);
+ memcpy(&carprk, &carpr, sizeof(carpr));
+ error = carp_ioctl_set(ifp, &carprk);
break;
case SIOCGVH:
@@ -2243,6 +2281,8 @@
nlattr_add_u32(nw, CARP_NL_STATE, sc->sc_state);
nlattr_add_s32(nw, CARP_NL_ADVBASE, sc->sc_advbase);
nlattr_add_s32(nw, CARP_NL_ADVSKEW, sc->sc_advskew);
+ nlattr_add_in_addr(nw, CARP_NL_ADDR, &sc->sc_carpaddr);
+ nlattr_add_in6_addr(nw, CARP_NL_ADDR6, &sc->sc_carpaddr6);
if (priv)
nlattr_add(nw, CARP_NL_KEY, sizeof(sc->sc_key), sc->sc_key);
@@ -2264,6 +2304,8 @@
int32_t advbase;
int32_t advskew;
char key[CARP_KEY_LEN];
+ struct in_addr addr;
+ struct in6_addr addr6;
};
#define _IN(_field) offsetof(struct genlmsghdr, _field)
@@ -2276,6 +2318,8 @@
{ .type = CARP_NL_ADVSKEW, .off = _OUT(advskew), .cb = nlattr_get_uint32 },
{ .type = CARP_NL_KEY, .off = _OUT(key), .cb = nlattr_get_carp_key },
{ .type = CARP_NL_IFINDEX, .off = _OUT(ifindex), .cb = nlattr_get_uint32 },
+ { .type = CARP_NL_ADDR, .off = _OUT(addr), .cb = nlattr_get_in_addr },
+ { .type = CARP_NL_ADDR6, .off = _OUT(addr6), .cb = nlattr_get_in6_addr },
};
static const struct nlfield_parser nlf_p_set[] = {
};
@@ -2331,7 +2375,7 @@
carp_nl_set(struct nlmsghdr *hdr, struct nl_pstate *npt)
{
struct nl_carp_parsed attrs = { };
- struct carpreq carpr;
+ struct carpkreq carpr;
struct epoch_tracker et;
if_t ifp;
int error;
@@ -2368,6 +2412,9 @@
carpr.carpr_state = attrs.state;
carpr.carpr_advbase = attrs.advbase;
carpr.carpr_advskew = attrs.advskew;
+ carpr.carpr_addr = attrs.addr;
+ carpr.carpr_addr6 = attrs.addr6;
+
memcpy(&carpr.carpr_key, &attrs.key, sizeof(attrs.key));
sx_xlock(&carp_sx);
diff --git a/sys/netinet/ip_carp_nl.h b/sys/netinet/ip_carp_nl.h
--- a/sys/netinet/ip_carp_nl.h
+++ b/sys/netinet/ip_carp_nl.h
@@ -29,6 +29,8 @@
CARP_NL_ADVSKEW = 4, /* s32 */
CARP_NL_KEY = 5, /* byte array */
CARP_NL_IFINDEX = 6, /* u32 */
+ CARP_NL_ADDR = 7, /* in_addr_t */
+ CARP_NL_ADDR6 = 8, /* in6_addr_t */
};
#endif
diff --git a/sys/netlink/netlink_message_parser.h b/sys/netlink/netlink_message_parser.h
--- a/sys/netlink/netlink_message_parser.h
+++ b/sys/netlink/netlink_message_parser.h
@@ -175,6 +175,10 @@
const void *arg, void *target);
int nlattr_get_uint64(struct nlattr *nla, struct nl_pstate *npt,
const void *arg, void *target);
+int nlattr_get_in_addr(struct nlattr *nla, struct nl_pstate *npt,
+ const void *arg, void *target);
+int nlattr_get_in6_addr(struct nlattr *nla, struct nl_pstate *npt,
+ const void *arg, void *target);
int nlattr_get_ifp(struct nlattr *nla, struct nl_pstate *npt,
const void *arg, void *target);
int nlattr_get_ifpz(struct nlattr *nla, struct nl_pstate *npt,
diff --git a/sys/netlink/netlink_message_parser.c b/sys/netlink/netlink_message_parser.c
--- a/sys/netlink/netlink_message_parser.c
+++ b/sys/netlink/netlink_message_parser.c
@@ -41,6 +41,7 @@
#include <net/route/nhop.h>
#include <net/route/route_ctl.h>
+#include <netinet/in.h>
#include <netlink/netlink.h>
#include <netlink/netlink_ctl.h>
#include <netlink/netlink_var.h>
@@ -349,6 +350,30 @@
return (0);
}
+int
+nlattr_get_in_addr(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
+{
+ if (__predict_false(NLA_DATA_LEN(nla) != sizeof(in_addr_t))) {
+ NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not in_addr_t",
+ nla->nla_type, NLA_DATA_LEN(nla));
+ return (EINVAL);
+ }
+ memcpy(target, NLA_DATA_CONST(nla), sizeof(in_addr_t));
+ return (0);
+}
+
+int
+nlattr_get_in6_addr(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
+{
+ if (__predict_false(NLA_DATA_LEN(nla) != sizeof(struct in6_addr))) {
+ NLMSG_REPORT_ERR_MSG(npt, "nla type %d size(%u) is not struct in6_addr",
+ nla->nla_type, NLA_DATA_LEN(nla));
+ return (EINVAL);
+ }
+ memcpy(target, NLA_DATA_CONST(nla), sizeof(struct in6_addr));
+ return (0);
+}
+
static int
nlattr_get_ifp_internal(struct nlattr *nla, struct nl_pstate *npt,
void *target, bool zero_ok)
diff --git a/sys/netlink/netlink_message_writer.h b/sys/netlink/netlink_message_writer.h
--- a/sys/netlink/netlink_message_writer.h
+++ b/sys/netlink/netlink_message_writer.h
@@ -30,6 +30,7 @@
#define _NETLINK_NETLINK_MESSAGE_WRITER_H_
#ifdef _KERNEL
+
/*
* It is not meant to be included directly
*/
@@ -248,6 +249,12 @@
return (nlattr_add(nw, attrtype, sizeof(int64_t), &value));
}
+struct in_addr;
+bool nlattr_add_in_addr(struct nl_writer *nw, int attrtype, const struct in_addr *in);
+
+struct in6_addr;
+bool nlattr_add_in6_addr(struct nl_writer *nw, int attrtype, const struct in6_addr *in6);
+
static inline bool
nlattr_add_flag(struct nl_writer *nw, int attrtype)
{
diff --git a/sys/netlink/netlink_message_writer.c b/sys/netlink/netlink_message_writer.c
--- a/sys/netlink/netlink_message_writer.c
+++ b/sys/netlink/netlink_message_writer.c
@@ -37,6 +37,8 @@
#include <sys/socketvar.h>
#include <sys/syslog.h>
+#include <netinet/in.h>
+
#include <netlink/netlink.h>
#include <netlink/netlink_ctl.h>
#include <netlink/netlink_linux.h>
@@ -686,3 +688,15 @@
return (true);
}
+
+bool
+nlattr_add_in_addr(struct nl_writer *nw, int attrtype, const struct in_addr *in)
+{
+ return (nlattr_add(nw, attrtype, sizeof(*in), in));
+}
+
+bool
+nlattr_add_in6_addr(struct nl_writer *nw, int attrtype, const struct in6_addr *in6)
+{
+ return (nlattr_add(nw, attrtype, sizeof(*in6), in6));
+}
diff --git a/sys/netlink/netlink_snl.h b/sys/netlink/netlink_snl.h
--- a/sys/netlink/netlink_snl.h
+++ b/sys/netlink/netlink_snl.h
@@ -44,7 +44,6 @@
#include <sys/socket.h>
#include <netlink/netlink.h>
-
#define _roundup2(x, y) (((x)+((y)-1))&(~((y)-1)))
#define NETLINK_ALIGN_SIZE sizeof(uint32_t)
diff --git a/sys/netlink/netlink_snl_route.h b/sys/netlink/netlink_snl_route.h
--- a/sys/netlink/netlink_snl_route.h
+++ b/sys/netlink/netlink_snl_route.h
@@ -163,4 +163,27 @@
return (false);
}
+static inline bool
+snl_attr_get_in_addr(struct snl_state *ss __unused, struct nlattr *nla,
+ const void *arg __unused, void *target)
+{
+ if (NLA_DATA_LEN(nla) != sizeof(struct in_addr))
+ return (false);
+
+ memcpy(target, NLA_DATA_CONST(nla), sizeof(struct in_addr));
+ return (true);
+}
+
+static inline bool
+snl_attr_get_in6_addr(struct snl_state *ss __unused, struct nlattr *nla,
+ const void *arg __unused, void *target)
+{
+ if (NLA_DATA_LEN(nla) != sizeof(struct in6_addr))
+ return (false);
+
+ memcpy(target, NLA_DATA_CONST(nla), sizeof(struct in6_addr));
+ return (true);
+}
+
+
#endif

File Metadata

Mime Type
text/plain
Expires
Wed, Apr 30, 3:48 AM (12 h, 46 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17851007
Default Alt Text
D38940.diff (17 KB)

Event Timeline