Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F115812901
D38940.id119019.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
17 KB
Referenced Files
None
Subscribers
None
D38940.id119019.diff
View Options
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];
+ in_addr_t 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
@@ -55,6 +55,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 +183,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,17 +71,22 @@
static int carpr_advskew = -1;
static int carpr_advbase = -1;
static int carpr_state = -1;
+static in_addr_t 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;
for (size_t i = 0; i < carpr[0].carpr_count; i++) {
+ struct in_addr peer;
+
printf("\tcarp: %s vhid %d advbase %d advskew %d",
carp_states[carpr[i].carpr_state], carpr[i].carpr_vhid,
carpr[i].carpr_advbase, carpr[i].carpr_advskew);
@@ -85,6 +94,13 @@
printf(" key \"%s\"\n", carpr[i].carpr_key);
else
printf("\n");
+
+ peer.s_addr = carpr[i].carpr_addr;
+ inet_ntop(AF_INET6, &carpr[i].carpr_addr6, addr_buf,
+ sizeof(addr_buf));
+
+ printf("\t peer %s peer6 %s\n", inet_ntoa(peer),
+ addr_buf);
}
}
@@ -146,6 +162,11 @@
carpr.carpr_advbase = carpr_advbase;
if (carpr_state > -1)
carpr.carpr_state = carpr_state;
+ if (carp_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 +219,53 @@
errx(1, "unknown state");
}
+static void
+setcarp_peer(const char *val, int d, int s, const struct afswtch *afp)
+{
+ carp_addr = inet_addr(val);
+}
+
+static void
+setcarp_mcast(const char *val, int d, int s, const struct afswtch *afp)
+{
+ carp_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 +278,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
@@ -111,6 +111,8 @@
int sc_vhid;
int sc_advskew;
int sc_advbase;
+ in_addr_t sc_carpaddr;
+ struct in6_addr sc_carpaddr6;
int sc_naddrs;
int sc_naddrs6;
@@ -155,6 +157,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 */
+ in_addr_t carpr_addr;
+ struct in6_addr carpr_addr6;
+};
+
/*
* Brief design of carp(4).
*
@@ -311,7 +327,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 *);
@@ -471,16 +487,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)) {
@@ -534,7 +540,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
@@ -564,15 +570,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;
@@ -582,6 +579,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);
@@ -596,7 +594,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 */
@@ -647,7 +645,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;
@@ -655,6 +653,7 @@
uint64_t tmp_counter;
struct timeval sc_tv, ch_tv;
int error;
+ bool multicast = false;
NET_EPOCH_ASSERT();
@@ -707,8 +706,21 @@
sc = ifa->ifa_carp;
CARP_LOCK(sc);
+ if (ifa->ifa_addr->sa_family == AF_INET) {
+ multicast = IN_MULTICAST(sc->sc_carpaddr);
+ } 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__,
@@ -961,7 +973,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))
+ m->m_flags |= M_MCAST;
ip = mtod(m, struct ip *);
ip->ip_v = IPVERSION;
ip->ip_hl = sizeof(*ip) >> 2;
@@ -980,7 +993,7 @@
ifa_free(ifa);
} else
ip->ip_src.s_addr = 0;
- ip->ip_dst.s_addr = htonl(INADDR_CARP_GROUP);
+ ip->ip_dst.s_addr = sc->sc_carpaddr;
ch_ptr = (struct carp_header *)(&ip[1]);
bcopy(&ch, ch_ptr, sizeof(ch));
@@ -1011,7 +1024,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;
@@ -1033,12 +1045,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]);
@@ -1554,6 +1567,19 @@
bcopy(mtag + 1, &sc, sizeof(sc));
+ switch (sa->sa_family) {
+ case AF_INET:
+ if (! IN_MULTICAST(sc->sc_carpaddr))
+ 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:
@@ -1601,6 +1627,10 @@
sc->sc_ifas = malloc(sc->sc_ifasiz, M_CARP, M_WAITOK|M_ZERO);
sc->sc_carpdev = ifp;
+ sc->sc_carpaddr = htonl(INADDR_CARP_GROUP);
+ sc->sc_carpaddr6.s6_addr16[0] = htons(0xff02);
+ 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);
@@ -1736,7 +1766,7 @@
}
static int
-carp_ioctl_set(if_t ifp, struct ucred *cred, struct carpreq *carpr)
+carp_ioctl_set(if_t ifp, struct ucred *cred, struct carpkreq *carpr)
{
struct epoch_tracker et;
struct carp_softc *sc = NULL;
@@ -1778,6 +1808,12 @@
goto out;
}
sc->sc_advskew = carpr->carpr_advskew;
+ if (carpr->carpr_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);
@@ -1858,6 +1894,7 @@
carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td)
{
struct carpreq carpr;
+ struct carpkreq carprk;
struct ifnet *ifp;
int error = 0;
@@ -1886,7 +1923,9 @@
sx_xlock(&carp_sx);
switch (cmd) {
case SIOCSVH:
- error = carp_ioctl_set(ifp, td->td_ucred, &carpr);
+ memset(&carprk, 0, sizeof(carprk));
+ memcpy(&carprk, &carpr, sizeof(carpr));
+ error = carp_ioctl_set(ifp, td->td_ucred, &carprk);
break;
case SIOCGVH:
@@ -2250,6 +2289,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);
@@ -2321,6 +2362,8 @@
int32_t advbase;
int32_t advskew;
char key[CARP_KEY_LEN];
+ in_addr_t addr;
+ struct in6_addr addr6;
};
#define _IN(_field) offsetof(struct genlmsghdr, _field)
@@ -2333,6 +2376,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[] = {
};
@@ -2344,7 +2389,7 @@
carp_nl_set(struct nlmsghdr *hdr, struct nl_pstate *npt)
{
struct nl_carp_parsed_set attrs = { };
- struct carpreq carpr;
+ struct carpkreq carpr;
struct epoch_tracker et;
if_t ifp;
int error;
@@ -2390,6 +2435,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
@@ -32,6 +32,8 @@
#include <sys/bitset.h>
+#include <netinet/in.h>
+
/*
* It is not meant to be included directly
*/
@@ -175,6 +177,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
@@ -348,6 +348,29 @@
memcpy(target, NL_RTA_DATA_CONST(nla), sizeof(uint64_t));
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,
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,9 @@
#define _NETLINK_NETLINK_MESSAGE_WRITER_H_
#ifdef _KERNEL
+
+#include <netinet/in.h>
+
/*
* It is not meant to be included directly
*/
@@ -248,6 +251,18 @@
return (nlattr_add(nw, attrtype, sizeof(int64_t), &value));
}
+static inline bool
+nlattr_add_in_addr(struct nl_writer *nw, int attrtype, const in_addr_t *in)
+{
+ return (nlattr_add(nw, attrtype, sizeof(*in), in));
+}
+
+static inline bool
+nlattr_add_in6_addr(struct nl_writer *nw, int attrtype, const struct in6_addr *in6)
+{
+ return (nlattr_add(nw, attrtype, sizeof(*in6), in6));
+}
+
static inline bool
nlattr_add_flag(struct nl_writer *nw, int attrtype)
{
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,6 +44,7 @@
#include <sys/socket.h>
#include <netlink/netlink.h>
+#include <netinet/in.h>
#define _roundup2(x, y) (((x)+((y)-1))&(~((y)-1)))
@@ -510,6 +511,28 @@
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(in_addr_t))
+ return (false);
+
+ memcpy(target, NLA_DATA_CONST(nla), sizeof(in_addr_t));
+ 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);
+}
+
static inline bool
snl_attr_get_stringn(struct snl_state *ss, struct nlattr *nla,
const void *arg __unused, void *target)
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Apr 30, 12:50 AM (9 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17848976
Default Alt Text
D38940.id119019.diff (17 KB)
Attached To
Mode
D38940: carp: support unicast
Attached
Detach File
Event Timeline
Log In to Comment