mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-02-03 20:40:34 +01:00
platform: add dump/update function for MPTCP addresses
Since the generic netlink API does (currently) not support notifications about changes of the MPTCP addresses, we won't get notifications when they change, and it seems wrong to put such things in the NMPlatform cache. We can just get the list of endpoints by polling, so add a function nm_platform_mptcp_addrs_dump() for that. Also, add nm_platform_mptcp_addr_update() which can add/remove/update MPTCP addresses.
This commit is contained in:
parent
ec64559caa
commit
ce635c4339
5 changed files with 366 additions and 19 deletions
|
|
@ -9,6 +9,7 @@
|
|||
#include <syslog.h>
|
||||
|
||||
#include "libnm-platform/nm-linux-platform.h"
|
||||
#include "libnm-platform/nmp-object.h"
|
||||
|
||||
#include "nm-test-utils-core.h"
|
||||
|
||||
|
|
@ -50,6 +51,18 @@ read_argv(int *argc, char ***argv)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
mptcp_addr_dump(NMPlatform *platform)
|
||||
{
|
||||
gs_unref_ptrarray GPtrArray *addrs = NULL;
|
||||
|
||||
addrs = nm_platform_mptcp_addrs_dump(platform);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
|
|
@ -69,6 +82,8 @@ main(int argc, char **argv)
|
|||
|
||||
nm_linux_platform_setup();
|
||||
|
||||
mptcp_addr_dump(NM_PLATFORM_GET);
|
||||
|
||||
if (global_opt.persist)
|
||||
g_main_loop_run(loop);
|
||||
|
||||
|
|
|
|||
|
|
@ -9334,6 +9334,9 @@ object_delete(NMPlatform *platform, const NMPObject *obj)
|
|||
case NMP_OBJECT_TYPE_TFILTER:
|
||||
nlmsg = _nl_msg_new_tfilter(RTM_DELTFILTER, 0, NMP_OBJECT_CAST_TFILTER(obj));
|
||||
break;
|
||||
case NMP_OBJECT_TYPE_MPTCP_ADDR:
|
||||
return (nm_platform_mptcp_addr_update(platform, FALSE, NMP_OBJECT_CAST_MPTCP_ADDR(obj))
|
||||
>= 0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -10101,6 +10104,301 @@ out:
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static const NMPObject *
|
||||
_mptcp_addrs_dump_parse_addr(struct nlattr *attr)
|
||||
{
|
||||
static const struct nla_policy policy[] = {
|
||||
[MPTCP_PM_ADDR_ATTR_FAMILY] = {.type = NLA_U16},
|
||||
[MPTCP_PM_ADDR_ATTR_ID] = {.type = NLA_U8},
|
||||
[MPTCP_PM_ADDR_ATTR_ADDR4] = {.minlen = sizeof(in_addr_t)},
|
||||
[MPTCP_PM_ADDR_ATTR_ADDR6] = {.minlen = sizeof(struct in6_addr)},
|
||||
[MPTCP_PM_ADDR_ATTR_PORT] = {.type = NLA_U16},
|
||||
[MPTCP_PM_ADDR_ATTR_FLAGS] = {.type = NLA_U32},
|
||||
[MPTCP_PM_ADDR_ATTR_IF_IDX] = {.type = NLA_S32},
|
||||
};
|
||||
struct nlattr *tb[G_N_ELEMENTS(policy)];
|
||||
nm_auto_nmpobj NMPObject *obj = NULL;
|
||||
NMPlatformMptcpAddr *mptcp_addr;
|
||||
int addr_family;
|
||||
int addr_attr;
|
||||
|
||||
if (nla_parse_nested_arr(tb, attr, policy) < 0)
|
||||
return NULL;
|
||||
|
||||
if (!tb[MPTCP_PM_ADDR_ATTR_ID])
|
||||
return NULL;
|
||||
|
||||
obj = nmp_object_new(NMP_OBJECT_TYPE_MPTCP_ADDR, NULL);
|
||||
mptcp_addr = &obj->mptcp_addr;
|
||||
|
||||
mptcp_addr->id = nla_get_u8(tb[MPTCP_PM_ADDR_ATTR_ID]);
|
||||
|
||||
if (!tb[MPTCP_PM_ADDR_ATTR_FAMILY]) {
|
||||
/* If we don't have the family. Only create a stub object containing
|
||||
* the ID. */
|
||||
goto out;
|
||||
}
|
||||
|
||||
addr_family = nla_get_u16(tb[MPTCP_PM_ADDR_ATTR_FAMILY]);
|
||||
|
||||
if (addr_family == AF_INET)
|
||||
addr_attr = MPTCP_PM_ADDR_ATTR_ADDR4;
|
||||
else if (addr_family == AF_INET6)
|
||||
addr_attr = MPTCP_PM_ADDR_ATTR_ADDR6;
|
||||
else
|
||||
goto out;
|
||||
|
||||
if (!tb[addr_attr])
|
||||
goto out;
|
||||
|
||||
mptcp_addr->addr_family = addr_family;
|
||||
memcpy(&mptcp_addr->addr, nla_data(tb[addr_attr]), nm_utils_addr_family_to_size(addr_family));
|
||||
|
||||
if (tb[MPTCP_PM_ADDR_ATTR_PORT])
|
||||
mptcp_addr->port = nla_get_u16(tb[MPTCP_PM_ADDR_ATTR_PORT]);
|
||||
|
||||
if (tb[MPTCP_PM_ADDR_ATTR_IF_IDX])
|
||||
mptcp_addr->ifindex = nla_get_s32(tb[MPTCP_PM_ADDR_ATTR_IF_IDX]);
|
||||
|
||||
if (tb[MPTCP_PM_ADDR_ATTR_FLAGS])
|
||||
mptcp_addr->flags = nla_get_u32(tb[MPTCP_PM_ADDR_ATTR_FLAGS]);
|
||||
|
||||
out:
|
||||
|
||||
return g_steal_pointer(&obj);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
GPtrArray *addrs;
|
||||
} FetchMptcpAddrParseData;
|
||||
|
||||
static int
|
||||
_mptcp_addrs_dump_parse_cb(const struct nl_msg *msg, void *arg)
|
||||
{
|
||||
static const struct nla_policy policy[] = {
|
||||
[MPTCP_PM_ATTR_ADDR] = {.type = NLA_NESTED},
|
||||
};
|
||||
struct nlattr *tb[G_N_ELEMENTS(policy)];
|
||||
FetchMptcpAddrParseData *parse_data = arg;
|
||||
|
||||
if (genlmsg_parse_arr(nlmsg_hdr(msg), 0, tb, policy) < 0)
|
||||
return NL_SKIP;
|
||||
|
||||
if (tb[MPTCP_PM_ATTR_ADDR]) {
|
||||
const NMPObject *obj;
|
||||
|
||||
obj = _mptcp_addrs_dump_parse_addr(tb[MPTCP_PM_ATTR_ADDR]);
|
||||
if (obj)
|
||||
g_ptr_array_add(parse_data->addrs, (gpointer) obj);
|
||||
}
|
||||
|
||||
return NL_OK;
|
||||
}
|
||||
|
||||
#define EXTACK_MSG_BUFSIZE 200
|
||||
|
||||
static int
|
||||
_mptcp_addr_update_err_cb(const struct sockaddr_nl *nla, const struct nlmsgerr *nlerr, void *arg)
|
||||
{
|
||||
char *out_extack_msg = arg;
|
||||
const char *extack_msg;
|
||||
int errsv;
|
||||
|
||||
errsv = nlmsg_parse_error(nlmsg_undata(nlerr), &extack_msg);
|
||||
if (extack_msg)
|
||||
g_strlcpy(out_extack_msg, extack_msg, EXTACK_MSG_BUFSIZE);
|
||||
return errsv;
|
||||
}
|
||||
|
||||
static int
|
||||
mptcp_addr_update(NMPlatform *platform, NMOptionBool add, const NMPlatformMptcpAddr *addr)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
|
||||
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
|
||||
struct nlattr *nla_nest;
|
||||
char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE];
|
||||
guint16 genl_family_id;
|
||||
guint8 cmd_num;
|
||||
const char *cmd_str;
|
||||
int nle;
|
||||
char extack_msg[EXTACK_MSG_BUFSIZE];
|
||||
const struct nl_cb cb = {
|
||||
.err_cb = _mptcp_addr_update_err_cb,
|
||||
.err_arg = extack_msg,
|
||||
};
|
||||
|
||||
extack_msg[0] = '\0';
|
||||
|
||||
if (add == NM_OPTION_BOOL_DEFAULT) {
|
||||
cmd_num = MPTCP_PM_CMD_SET_FLAGS;
|
||||
cmd_str = "update";
|
||||
} else if (add) {
|
||||
cmd_num = MPTCP_PM_CMD_ADD_ADDR;
|
||||
cmd_str = "add";
|
||||
} else {
|
||||
cmd_num = MPTCP_PM_CMD_DEL_ADDR;
|
||||
cmd_str = "delete";
|
||||
}
|
||||
|
||||
nm_assert_addr_family_or_unspec(addr->addr_family);
|
||||
nm_assert(cmd_num != MPTCP_PM_CMD_ADD_ADDR
|
||||
|| (addr->port == 0 && addr->addr_family != AF_UNSPEC));
|
||||
nm_assert(cmd_num != MPTCP_PM_CMD_SET_FLAGS || (addr->id != 0 && addr->port == 0));
|
||||
nm_assert(cmd_num != MPTCP_PM_CMD_DEL_ADDR || addr->id != 0);
|
||||
|
||||
genl_family_id = nm_platform_genl_get_family_id(platform, NMP_GENL_FAMILY_TYPE_MPTCP_PM);
|
||||
if (genl_family_id == 0) {
|
||||
_LOGT("mptcp: %s address %s fails because %s generic netlink family is unknown",
|
||||
cmd_str,
|
||||
nm_platform_mptcp_addr_to_string(addr, sbuf, sizeof(sbuf)),
|
||||
nmp_genl_family_infos[NMP_GENL_FAMILY_TYPE_MPTCP_PM].name);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
_LOGT("mptcp: %s address %s",
|
||||
cmd_str,
|
||||
nm_platform_mptcp_addr_to_string(addr, sbuf, sizeof(sbuf)));
|
||||
|
||||
nlmsg = nlmsg_alloc_size(nlmsg_total_size(GENL_HDRLEN) + 200);
|
||||
|
||||
if (!genlmsg_put(nlmsg,
|
||||
NL_AUTO_PORT,
|
||||
NL_AUTO_SEQ,
|
||||
genl_family_id,
|
||||
0,
|
||||
NLM_F_REQUEST,
|
||||
cmd_num,
|
||||
MPTCP_PM_VER))
|
||||
goto nla_put_failure;
|
||||
|
||||
nla_nest = nla_nest_start(nlmsg, MPTCP_PM_ATTR_ADDR | NLA_F_NESTED);
|
||||
if (!nla_nest)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (addr->id != 0)
|
||||
NLA_PUT_U8(nlmsg, MPTCP_PM_ADDR_ATTR_ID, addr->id);
|
||||
if (addr->flags != 0)
|
||||
NLA_PUT_U32(nlmsg, MPTCP_PM_ADDR_ATTR_FLAGS, addr->flags);
|
||||
if (addr->ifindex != 0)
|
||||
NLA_PUT_S32(nlmsg, MPTCP_PM_ADDR_ATTR_IF_IDX, addr->ifindex);
|
||||
if (addr->port != 0)
|
||||
NLA_PUT_U16(nlmsg, MPTCP_PM_ADDR_ATTR_PORT, addr->port);
|
||||
if (addr->addr_family != AF_UNSPEC) {
|
||||
int addr_attr;
|
||||
|
||||
NLA_PUT_U16(nlmsg, MPTCP_PM_ADDR_ATTR_FAMILY, addr->addr_family);
|
||||
if (addr->addr_family == AF_INET)
|
||||
addr_attr = MPTCP_PM_ADDR_ATTR_ADDR4;
|
||||
else if (addr->addr_family == AF_INET6)
|
||||
addr_attr = MPTCP_PM_ADDR_ATTR_ADDR6;
|
||||
else
|
||||
g_return_val_if_reached(-NME_BUG);
|
||||
NLA_PUT(nlmsg, addr_attr, nm_utils_addr_family_to_size(addr->addr_family), &addr->addr);
|
||||
}
|
||||
|
||||
NLA_NEST_END(nlmsg, nla_nest);
|
||||
|
||||
nle = nl_send_auto(priv->sk_genl_sync, nlmsg);
|
||||
if (nle < 0) {
|
||||
_LOGT("mptcp: %s address %s: failed sending request: %s (%d)",
|
||||
cmd_str,
|
||||
nm_platform_mptcp_addr_to_string(addr, sbuf, sizeof(sbuf)),
|
||||
nm_strerror(nle),
|
||||
nle);
|
||||
return nle;
|
||||
}
|
||||
|
||||
do {
|
||||
nle = nl_recvmsgs(priv->sk_genl_sync, &cb);
|
||||
} while (nle == -EAGAIN);
|
||||
|
||||
if (nle < 0) {
|
||||
_LOGT("mptcp: %s address %s: failed: %s (%d)%s%s%s",
|
||||
cmd_str,
|
||||
nm_platform_mptcp_addr_to_string(addr, sbuf, sizeof(sbuf)),
|
||||
nm_strerror(nle),
|
||||
nle,
|
||||
NM_PRINT_FMT_QUOTED(extack_msg[0] != '\0', " \"", extack_msg, "\"", ""));
|
||||
return nle;
|
||||
}
|
||||
|
||||
_LOGT("mptcp: %s address %s: success",
|
||||
cmd_str,
|
||||
nm_platform_mptcp_addr_to_string(addr, sbuf, sizeof(sbuf)));
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
g_return_val_if_reached(-NME_BUG);
|
||||
}
|
||||
|
||||
static GPtrArray *
|
||||
mptcp_addrs_dump(NMPlatform *platform)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
|
||||
gs_unref_ptrarray GPtrArray *addrs = NULL;
|
||||
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
|
||||
FetchMptcpAddrParseData parse_data;
|
||||
guint16 genl_family_id;
|
||||
int r;
|
||||
guint i;
|
||||
|
||||
genl_family_id = nm_platform_genl_get_family_id(platform, NMP_GENL_FAMILY_TYPE_MPTCP_PM);
|
||||
if (genl_family_id == 0) {
|
||||
_LOGT("mptcp: dump addresses fails because %s generic netlink family is unknown",
|
||||
nmp_genl_family_infos[NMP_GENL_FAMILY_TYPE_MPTCP_PM].name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nlmsg = nlmsg_alloc_size(nlmsg_total_size(GENL_HDRLEN));
|
||||
|
||||
if (!genlmsg_put(nlmsg,
|
||||
NL_AUTO_PORT,
|
||||
NL_AUTO_SEQ,
|
||||
genl_family_id,
|
||||
0,
|
||||
NLM_F_REQUEST | NLM_F_DUMP,
|
||||
MPTCP_PM_CMD_GET_ADDR,
|
||||
MPTCP_PM_VER))
|
||||
g_return_val_if_reached(NULL);
|
||||
|
||||
r = nl_send_auto(priv->sk_genl_sync, nlmsg);
|
||||
if (r < 0) {
|
||||
_LOGT("mptcp: dump addresses failed to send dump request: %s", nm_strerror(r));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
addrs = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref);
|
||||
|
||||
parse_data = (FetchMptcpAddrParseData){
|
||||
.addrs = addrs,
|
||||
};
|
||||
|
||||
nl_recvmsgs(priv->sk_genl_sync,
|
||||
&((const struct nl_cb){
|
||||
.valid_cb = _mptcp_addrs_dump_parse_cb,
|
||||
.valid_arg = (gpointer) &parse_data,
|
||||
}));
|
||||
|
||||
if (_LOGT_ENABLED()) {
|
||||
_LOGT("mptcp: %u addresses dumped", addrs->len);
|
||||
for (i = 0; i < addrs->len; i++) {
|
||||
char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE];
|
||||
|
||||
_LOGT("mptcp: address[%04d]: %s",
|
||||
i,
|
||||
nmp_object_to_string(addrs->pdata[i],
|
||||
NMP_OBJECT_TO_STRING_PUBLIC,
|
||||
sbuf,
|
||||
sizeof(sbuf)));
|
||||
}
|
||||
}
|
||||
|
||||
return g_steal_pointer(&addrs);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
cache_update_link_udev(NMPlatform *platform, int ifindex, struct udev_device *udevice)
|
||||
{
|
||||
|
|
@ -10589,4 +10887,6 @@ nm_linux_platform_class_init(NMLinuxPlatformClass *klass)
|
|||
platform_class->process_events = process_events;
|
||||
|
||||
platform_class->genl_get_family_id = genl_get_family_id;
|
||||
platform_class->mptcp_addr_update = mptcp_addr_update;
|
||||
platform_class->mptcp_addrs_dump = mptcp_addrs_dump;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "nm-platform.h"
|
||||
|
||||
#include "libnm-std-aux/nm-linux-compat.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
|
|
@ -402,7 +404,7 @@ const NMPGenlFamilyInfo nmp_genl_family_infos[_NMP_GENL_FAMILY_TYPE_NUM] = {
|
|||
},
|
||||
[NMP_GENL_FAMILY_TYPE_MPTCP_PM] =
|
||||
{
|
||||
.name = "mptcp_pm",
|
||||
.name = MPTCP_PM_NAME,
|
||||
},
|
||||
[NMP_GENL_FAMILY_TYPE_NL80211] =
|
||||
{
|
||||
|
|
@ -5320,23 +5322,26 @@ nm_platform_object_delete(NMPlatform *self, const NMPObject *obj)
|
|||
|
||||
_CHECK_SELF(self, klass, FALSE);
|
||||
|
||||
switch (NMP_OBJECT_GET_TYPE(obj)) {
|
||||
case NMP_OBJECT_TYPE_ROUTING_RULE:
|
||||
_LOGD("%s: delete %s",
|
||||
NMP_OBJECT_GET_CLASS(obj)->obj_type_name,
|
||||
nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf)));
|
||||
break;
|
||||
case NMP_OBJECT_TYPE_IP4_ROUTE:
|
||||
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
||||
case NMP_OBJECT_TYPE_QDISC:
|
||||
case NMP_OBJECT_TYPE_TFILTER:
|
||||
ifindex = NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj)->ifindex;
|
||||
_LOG3D("%s: delete %s",
|
||||
NMP_OBJECT_GET_CLASS(obj)->obj_type_name,
|
||||
nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf)));
|
||||
break;
|
||||
default:
|
||||
g_return_val_if_reached(FALSE);
|
||||
if (_LOGD_ENABLED()) {
|
||||
switch (NMP_OBJECT_GET_TYPE(obj)) {
|
||||
case NMP_OBJECT_TYPE_ROUTING_RULE:
|
||||
case NMP_OBJECT_TYPE_MPTCP_ADDR:
|
||||
_LOGD("%s: delete %s",
|
||||
NMP_OBJECT_GET_CLASS(obj)->obj_type_name,
|
||||
nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf)));
|
||||
break;
|
||||
case NMP_OBJECT_TYPE_IP4_ROUTE:
|
||||
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
||||
case NMP_OBJECT_TYPE_QDISC:
|
||||
case NMP_OBJECT_TYPE_TFILTER:
|
||||
ifindex = NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj)->ifindex;
|
||||
_LOG3D("%s: delete %s",
|
||||
NMP_OBJECT_GET_CLASS(obj)->obj_type_name,
|
||||
nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf)));
|
||||
break;
|
||||
default:
|
||||
g_return_val_if_reached(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
return klass->object_delete(self, obj);
|
||||
|
|
@ -9393,6 +9398,24 @@ nm_platform_genl_get_family_id(NMPlatform *self, NMPGenlFamilyType family_type)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
nm_platform_mptcp_addr_update(NMPlatform *self, NMOptionBool add, const NMPlatformMptcpAddr *addr)
|
||||
{
|
||||
_CHECK_SELF(self, klass, -NME_BUG);
|
||||
|
||||
return klass->mptcp_addr_update(self, add, addr);
|
||||
}
|
||||
|
||||
GPtrArray *
|
||||
nm_platform_mptcp_addrs_dump(NMPlatform *self)
|
||||
{
|
||||
_CHECK_SELF(self, klass, NULL);
|
||||
|
||||
return klass->mptcp_addrs_dump(self);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
GHashTable *
|
||||
nm_platform_ip4_address_addr_to_hash(NMPlatform *self, int ifindex)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1394,6 +1394,10 @@ typedef struct {
|
|||
|
||||
guint16 (*genl_get_family_id)(NMPlatform *platform, NMPGenlFamilyType family_type);
|
||||
|
||||
int (*mptcp_addr_update)(NMPlatform *self, NMOptionBool add, const NMPlatformMptcpAddr *addr);
|
||||
|
||||
GPtrArray *(*mptcp_addrs_dump)(NMPlatform *self);
|
||||
|
||||
} NMPlatformClass;
|
||||
|
||||
/* NMPlatform signals
|
||||
|
|
@ -2668,4 +2672,9 @@ gboolean nm_platform_ip_address_match(int addr_family,
|
|||
|
||||
guint16 nm_platform_genl_get_family_id(NMPlatform *self, NMPGenlFamilyType family_type);
|
||||
|
||||
int
|
||||
nm_platform_mptcp_addr_update(NMPlatform *self, NMOptionBool add, const NMPlatformMptcpAddr *addr);
|
||||
|
||||
GPtrArray *nm_platform_mptcp_addrs_dump(NMPlatform *self);
|
||||
|
||||
#endif /* __NETWORKMANAGER_PLATFORM_H__ */
|
||||
|
|
|
|||
|
|
@ -1785,7 +1785,7 @@ _vt_cmd_obj_is_alive_tfilter(const NMPObject *obj)
|
|||
static gboolean
|
||||
_vt_cmd_obj_is_alive_mptcp_addr(const NMPObject *obj)
|
||||
{
|
||||
return NM_IN_SET(obj->mptcp_addr.addr_family, AF_INET, AF_INET6);
|
||||
return NM_IN_SET(obj->mptcp_addr.addr_family, AF_INET, AF_INET6, AF_UNSPEC);
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue