platform: merge branch 'th/platform-wireguard'

Various cleanups. Also fixes a crash.

https://github.com/NetworkManager/NetworkManager/pull/193
This commit is contained in:
Thomas Haller 2018-09-07 11:26:23 +02:00
commit ec17242f2e
16 changed files with 1079 additions and 784 deletions

View file

@ -31,31 +31,6 @@ typedef struct {
guint32 to;
} NMVlanQosMapping;
typedef struct {
NMIPAddr ip;
guint8 family;
guint8 mask;
} NMWireGuardAllowedIP;
#define NM_WG_PUBLIC_KEY_LEN 32
#define NM_WG_SYMMETRIC_KEY_LEN 32
typedef struct {
guint8 public_key[NM_WG_PUBLIC_KEY_LEN];
guint8 preshared_key[NM_WG_SYMMETRIC_KEY_LEN];
union {
struct sockaddr addr;
struct sockaddr_in addr4;
struct sockaddr_in6 addr6;
} endpoint;
guint16 persistent_keepalive_interval;
struct timespec last_handshake_time;
guint64 rx_bytes, tx_bytes;
gsize allowedips_len;
NMWireGuardAllowedIP *allowedips;
} NMWireGuardPeer;
#define _NM_IP_TUNNEL_FLAG_ALL_IP6TNL \
( NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT \
| NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_TCLASS \

View file

@ -60,7 +60,8 @@ _get_keys (NMSettingVpn *setting,
if (len) {
g_ptr_array_sort (a, nm_strcmp_p);
g_ptr_array_add (a, NULL);
keys = g_memdup (a->pdata, a->len * sizeof (gpointer));
keys = g_malloc (a->len * sizeof (gpointer));
memcpy (keys, a->pdata, a->len * sizeof (gpointer));
/* we need to cache the keys *somewhere*. */
g_object_set_qdata_full (G_OBJECT (setting),

View file

@ -57,6 +57,11 @@ nm_hash_update (NMHashState *state, const void *ptr, gsize n)
nm_assert (ptr);
nm_assert (n > 0);
/* Note: the data passed in here might be sensitive data (secrets),
* that we should nm_explicty_zero() afterwards. However, since
* we are using siphash24 with a random key, that is not really
* necessary. Something to keep in mind, if we ever move away from
* this hash implementation. */
c_siphash_append (&state->_state, ptr, n);
}

View file

@ -106,7 +106,7 @@ nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...)
retval = g_vsnprintf (p, *len, format, args);
va_end (args);
if (retval >= *len) {
if ((gsize) retval >= *len) {
*buf = &p[*len];
*len = 0;
} else {
@ -115,6 +115,88 @@ nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...)
}
}
/**
* nm_utils_strbuf_seek_end:
* @buf: the input/output buffer
* @len: the input/output lenght of the buffer.
*
* Commonly, one uses nm_utils_strbuf_append*(), to incrementally
* append strings to the buffer. However, sometimes we need to use
* existing API to write to the buffer.
* After doing so, we want to adjust the buffer counter.
* Essentially,
*
* g_snprintf (buf, len, ...);
* nm_utils_strbuf_seek_end (&buf, &len);
*
* is almost the same as
*
* nm_utils_strbuf_append (&buf, &len, ...);
*
* They only behave differently, if the string fits exactly
* into the buffer without truncation. The former cannot distinguish
* the two cases, while the latter can.
*/
void
nm_utils_strbuf_seek_end (char **buf, gsize *len)
{
gsize l;
char *end;
nm_assert (len);
nm_assert (buf && *buf);
if (*len == 0)
return;
end = memchr (*buf, 0, *len);
if (!end) {
/* hm, no NUL character within len bytes.
* Just NUL terminate the array and consume them
* all. */
*buf += *len;
(*buf)[-1] = '\0';
*len = 0;
return;
}
l = end - *buf;
nm_assert (l < *len);
*buf = end;
*len -= l;
if (*len == 1) {
/* the last character of a buffer is the '\0'. There are two
* cases why that may happen:
* - but string was truncated
* - the string fit exactly into the buffer.
* Here we cannot distinguish between the two, so assume the string
* was truncated and signal that by setting @len to 0 and pointing the
* buffer *past* the end (like all other nm_utils_strbuf_*() functions).
*
* Note that nm_utils_strbuf_append_str() can distinguish between
* the two cases, and leaves @len at 1, if the string was not actually
* truncated.
*
* For consistancy, it might be better not to do this and just
* seek to end of the buffer (not past it). However, that would mean,
* in a series of
* g_snprintf()
* nm_utils_strbuf_seek_end()
* the length would never reach zero, but stay at 1. With this,
* it reaches len 0 early.
* It seems better to declare the buffer as fully consumed and set
* the length to zero.
*
* If the caller does not care about truncation, then this behavior
* is more sensible. If the caller cares about truncation, it must
* check earlier (right when the truncation occures).
*/
(*buf)++;
*len = 0;
}
}
/*****************************************************************************/
/**

View file

@ -190,6 +190,53 @@ nm_ip_addr_set (int addr_family, gpointer dst, const NMIPAddr *src)
/*****************************************************************************/
static inline gboolean
nm_utils_mem_all_zero (gconstpointer mem, gsize len)
{
const guint8 *p;
for (p = mem; len-- > 0; p++) {
if (*p != 0)
return FALSE;
}
/* incidentally, a buffer with len==0, is also *all-zero*. */
return TRUE;
}
/*****************************************************************************/
/* like g_memdup(). The difference is that the @size argument is of type
* gsize, while g_memdup() has type guint. Since, the size of container types
* like GArray is guint as well, this means trying to g_memdup() an
* array,
* g_memdup (array->data, array->len * sizeof (ElementType))
* will lead to integer overflow, if there are more than G_MAXUINT/sizeof(ElementType)
* bytes. That seems unnecessarily dangerous to me.
* nm_memdup() avoids that, because its size argument is always large enough
* to contain all data that a GArray can hold.
*
* Another minor difference to g_memdup() is that the glib version also
* returns %NULL if @data is %NULL. E.g. g_memdup(NULL, 1)
* gives %NULL, but nm_memdup(NULL, 1) crashes. I think that
* is desirable, because @size MUST be correct at all times. @size
* may be zero, but one must not claim to have non-zero bytes when
* passing a %NULL @data pointer.
*/
static inline gpointer
nm_memdup (gconstpointer data, gsize size)
{
gpointer p;
if (size == 0)
return NULL;
p = g_malloc (size);
memcpy (p, data, size);
return p;
}
/*****************************************************************************/
extern const void *const _NM_PTRARRAY_EMPTY[1];
#define NM_PTRARRAY_EMPTY(type) ((type const*) _NM_PTRARRAY_EMPTY)
@ -210,6 +257,7 @@ _nm_utils_strbuf_init (char *buf, gsize len, char **p_buf_ptr, gsize *p_buf_len)
void nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...) _nm_printf (3, 4);
void nm_utils_strbuf_append_c (char **buf, gsize *len, char c);
void nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str);
void nm_utils_strbuf_seek_end (char **buf, gsize *len);
const char *nm_strquote (char *buf, gsize buf_len, const char *str);

View file

@ -188,7 +188,7 @@ ck_load_cache (GHashTable *cache)
if (error)
goto out;
g_hash_table_insert (cache, GUINT_TO_POINTER (uid), g_memdup (&session, sizeof session));
g_hash_table_insert (cache, GUINT_TO_POINTER (uid), nm_memdup (&session, sizeof session));
}
finished = TRUE;

View file

@ -216,8 +216,8 @@ nmtst_platform_ip4_routes_equal (const NMPlatformIP4Route *a, const NMPlatformIP
g_assert (b);
if (ignore_order) {
a = c_a = g_memdup (a, sizeof (NMPlatformIP4Route) * len);
b = c_b = g_memdup (b, sizeof (NMPlatformIP4Route) * len);
a = c_a = nm_memdup (a, sizeof (NMPlatformIP4Route) * len);
b = c_b = nm_memdup (b, sizeof (NMPlatformIP4Route) * len);
g_qsort_with_data (c_a, len, sizeof (NMPlatformIP4Route), _nmtst_platform_ip4_routes_equal_sort, NULL);
g_qsort_with_data (c_b, len, sizeof (NMPlatformIP4Route), _nmtst_platform_ip4_routes_equal_sort, NULL);
}
@ -269,8 +269,8 @@ nmtst_platform_ip6_routes_equal (const NMPlatformIP6Route *a, const NMPlatformIP
g_assert (b);
if (ignore_order) {
a = c_a = g_memdup (a, sizeof (NMPlatformIP6Route) * len);
b = c_b = g_memdup (b, sizeof (NMPlatformIP6Route) * len);
a = c_a = nm_memdup (a, sizeof (NMPlatformIP6Route) * len);
b = c_b = nm_memdup (b, sizeof (NMPlatformIP6Route) * len);
g_qsort_with_data (c_a, len, sizeof (NMPlatformIP6Route), _nmtst_platform_ip6_routes_equal_sort, NULL);
g_qsort_with_data (c_b, len, sizeof (NMPlatformIP6Route), _nmtst_platform_ip6_routes_equal_sort, NULL);
}

File diff suppressed because it is too large Load diff

View file

@ -52,7 +52,6 @@ struct nl_msg {
struct ucred nm_creds;
struct nlmsghdr * nm_nlh;
size_t nm_size;
int nm_refcnt;
};
struct nl_sock {
@ -259,20 +258,6 @@ nlmsg_reserve (struct nl_msg *n, size_t len, int pad)
/*****************************************************************************/
static int
get_default_page_size (void)
{
static int val = 0;
int v;
if (G_UNLIKELY (val == 0)) {
v = getpagesize ();
g_assert (v > 0);
val = v;
}
return val;
}
struct nlattr *
nla_reserve (struct nl_msg *msg, int attrtype, int attrlen)
{
@ -298,6 +283,22 @@ nla_reserve (struct nl_msg *msg, int attrtype, int attrlen)
return nla;
}
/*****************************************************************************/
static int
get_default_page_size (void)
{
static int val = 0;
int v;
if (G_UNLIKELY (val == 0)) {
v = getpagesize ();
g_assert (v > 0);
val = v;
}
return val;
}
struct nl_msg *
nlmsg_alloc_size (size_t len)
{
@ -308,7 +309,6 @@ nlmsg_alloc_size (size_t len)
nm = g_slice_new0 (struct nl_msg);
nm->nm_refcnt = 1;
nm->nm_protocol = -1;
nm->nm_size = len;
nm->nm_nlh = g_malloc0 (len);
@ -331,27 +331,6 @@ nlmsg_alloc (void)
return nlmsg_alloc_size (get_default_page_size ());
}
/**
* Allocate a new netlink message with maximum payload size specified.
*/
struct nl_msg *
nlmsg_alloc_inherit (struct nlmsghdr *hdr)
{
struct nl_msg *nm;
nm = nlmsg_alloc ();
if (hdr) {
struct nlmsghdr *new = nm->nm_nlh;
new->nlmsg_type = hdr->nlmsg_type;
new->nlmsg_flags = hdr->nlmsg_flags;
new->nlmsg_seq = hdr->nlmsg_seq;
new->nlmsg_pid = hdr->nlmsg_pid;
}
return nm;
}
struct nl_msg *
nlmsg_alloc_convert (struct nlmsghdr *hdr)
{
@ -365,14 +344,27 @@ nlmsg_alloc_convert (struct nlmsghdr *hdr)
struct nl_msg *
nlmsg_alloc_simple (int nlmsgtype, int flags)
{
struct nlmsghdr nlh = {
.nlmsg_type = nlmsgtype,
.nlmsg_flags = flags,
};
struct nl_msg *nm;
struct nlmsghdr *new;
return nlmsg_alloc_inherit (&nlh);
nm = nlmsg_alloc ();
new = nm->nm_nlh;
new->nlmsg_type = nlmsgtype;
new->nlmsg_flags = flags;
return nm;
}
void nlmsg_free (struct nl_msg *msg)
{
if (!msg)
return;
g_free (msg->nm_nlh);
g_slice_free (struct nl_msg, msg);
}
/*****************************************************************************/
int
nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad)
{
@ -386,6 +378,8 @@ nlmsg_append (struct nl_msg *n, void *data, size_t len, int pad)
return 0;
}
/*****************************************************************************/
int
nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
int maxtype, const struct nla_policy *policy)
@ -639,22 +633,6 @@ errout:
/*****************************************************************************/
void nlmsg_free (struct nl_msg *msg)
{
if (!msg)
return;
if (msg->nm_refcnt < 1)
g_return_if_reached ();
msg->nm_refcnt--;
if (msg->nm_refcnt <= 0) {
g_free (msg->nm_nlh);
g_slice_free (struct nl_msg, msg);
}
}
int
nlmsg_get_proto (struct nl_msg *msg)
{
@ -813,7 +791,7 @@ int
genl_ctrl_resolve (struct nl_sock *sk, const char *name)
{
nm_auto_nlmsg struct nl_msg *msg = NULL;
int result = -ENOMEM;
int nlerr;
gint32 response_data = -1;
const struct nl_cb cb = {
.valid_cb = _genl_parse_getfamily,
@ -824,31 +802,29 @@ genl_ctrl_resolve (struct nl_sock *sk, const char *name)
if (!genlmsg_put (msg, NL_AUTO_PORT, NL_AUTO_SEQ, GENL_ID_CTRL,
0, 0, CTRL_CMD_GETFAMILY, 1))
goto out;
return -ENOMEM;
if (nla_put_string (msg, CTRL_ATTR_FAMILY_NAME, name) < 0)
goto out;
nlerr = nla_put_string (msg, CTRL_ATTR_FAMILY_NAME, name);
if (nlerr < 0)
return nlerr;
result = nl_send_auto (sk, msg);
if (result < 0)
goto out;
nlerr = nl_send_auto (sk, msg);
if (nlerr < 0)
return nlerr;
result = nl_recvmsgs (sk, &cb);
if (result < 0)
goto out;
nlerr = nl_recvmsgs (sk, &cb);
if (nlerr < 0)
return nlerr;
/* If search was successful, request may be ACKed after data */
result = nl_wait_for_ack (sk, NULL);
if (result < 0)
goto out;
nlerr = nl_wait_for_ack (sk, NULL);
if (nlerr < 0)
return nlerr;
if (response_data > 0)
result = response_data;
else
result = -ENOENT;
if (response_data < 0)
return -NLE_UNSPEC;
out:
return result;
return response_data;
}
/*****************************************************************************/
@ -1131,6 +1107,10 @@ do { \
case NL_STOP: \
goto stop; \
default: \
if (err >= 0) { \
nm_assert_not_reached (); \
err = -NLE_BUG; \
} \
goto out; \
} \
} \
@ -1238,11 +1218,12 @@ continue_reading:
else if (err == NL_SKIP)
goto skip;
else if (err == NL_STOP) {
err = -e->error;
err = -nl_syserr2nlerr (e->error);
goto out;
}
nm_assert (err == NL_OK);
} else {
err = -e->error;
err = -nl_syserr2nlerr (e->error);
goto out;
}
} else
@ -1273,6 +1254,7 @@ out:
if (interrupted)
err = -NLE_DUMP_INTR;
nm_assert (err <= 0);
return err ?: nrecv;
}
@ -1328,7 +1310,7 @@ nl_send_iovec (struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsign
memcpy(CMSG_DATA(cmsg), creds, sizeof (struct ucred));
}
return nl_sendmsg(sk, msg, &hdr);
return nl_sendmsg (sk, msg, &hdr);
}
void
@ -1365,9 +1347,9 @@ nl_send (struct nl_sock *sk, struct nl_msg *msg)
int nl_send_auto(struct nl_sock *sk, struct nl_msg *msg)
{
nl_complete_msg(sk, msg);
nl_complete_msg (sk, msg);
return nl_send(sk, msg);
return nl_send (sk, msg);
}
int
@ -1470,7 +1452,7 @@ retry:
continue;
if (cmsg->cmsg_type != SCM_CREDENTIALS)
continue;
tmpcreds = g_memdup (CMSG_DATA(cmsg), sizeof (*tmpcreds));
tmpcreds = nm_memdup (CMSG_DATA(cmsg), sizeof (*tmpcreds));
break;
}
}

View file

@ -62,7 +62,7 @@ nl_errno (int err)
* normalizes the error and returns its positive value. */
return err >= 0
? err
: ((err == G_MININT) ? NLE_BUG : -errno);
: ((err == G_MININT) ? NLE_BUG : -err);
}
static inline int
@ -314,8 +314,6 @@ struct nl_msg *nlmsg_alloc (void);
struct nl_msg *nlmsg_alloc_size (size_t max);
struct nl_msg *nlmsg_alloc_inherit (struct nlmsghdr *hdr);
struct nl_msg *nlmsg_alloc_convert (struct nlmsghdr *hdr);
struct nl_msg *nlmsg_alloc_simple (int nlmsgtype, int flags);

View file

@ -5532,67 +5532,57 @@ nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize
}
const char *
nm_platform_wireguard_peer_to_string (const NMWireGuardPeer *peer, char *buf, gsize len)
nm_platform_wireguard_peer_to_string (const NMPWireGuardPeer *peer, char *buf, gsize len)
{
gs_free char *public_b64 = NULL;
char s_address[INET6_ADDRSTRLEN] = {0};
char s_endpoint[INET6_ADDRSTRLEN + NI_MAXSERV + sizeof("endpoint []:") + 1] = {0};
guint8 nonzero_key = 0;
gsize i;
gs_free char *public_key_b64 = NULL;
char s_endpoint[NM_UTILS_INET_ADDRSTRLEN + 100];
char s_addr[NM_UTILS_INET_ADDRSTRLEN];
guint i;
nm_utils_to_string_buffer_init (&buf, &len);
if (peer->endpoint.addr.sa_family == AF_INET || peer->endpoint.addr.sa_family == AF_INET6) {
char s_service[NI_MAXSERV];
socklen_t addr_len = 0;
if (peer->endpoint_family == AF_INET) {
nm_sprintf_buf (s_endpoint,
" endpoint %s:%u",
nm_utils_inet4_ntop (peer->endpoint_addr.addr4, s_addr),
(guint) peer->endpoint_port);
} else if (peer->endpoint_family == AF_INET6) {
nm_sprintf_buf (s_endpoint,
" endpoint [%s]:%u",
nm_utils_inet6_ntop (&peer->endpoint_addr.addr6, s_addr),
(guint) peer->endpoint_port);
} else
s_endpoint[0] = '\0';
if (peer->endpoint.addr.sa_family == AF_INET)
addr_len = sizeof (struct sockaddr_in);
else if (peer->endpoint.addr.sa_family == AF_INET6)
addr_len = sizeof (struct sockaddr_in6);
if (!getnameinfo (&peer->endpoint.addr, addr_len, s_address, sizeof(s_address), s_service, sizeof(s_service), NI_DGRAM | NI_NUMERICSERV | NI_NUMERICHOST)) {
if (peer->endpoint.addr.sa_family == AF_INET6 && strchr (s_address, ':'))
g_snprintf(s_endpoint, sizeof (s_endpoint), "endpoint [%s]:%s ", s_address, s_service);
else
g_snprintf(s_endpoint, sizeof (s_endpoint), "endpoint %s:%s ", s_address, s_service);
}
}
for (i = 0; i < sizeof (peer->preshared_key); i++)
nonzero_key |= peer->preshared_key[i];
public_b64 = g_base64_encode (peer->public_key, sizeof (peer->public_key));
public_key_b64 = g_base64_encode (peer->public_key, sizeof (peer->public_key));
nm_utils_strbuf_append (&buf, &len,
"{ "
"public_key %s "
"%s" /* preshared key indicator */
"public-key %s"
"%s" /* preshared-key */
"%s" /* endpoint */
"rx %"G_GUINT64_FORMAT" "
"tx %"G_GUINT64_FORMAT" "
"allowedips (%"G_GSIZE_FORMAT") {",
public_b64,
nonzero_key ? "preshared_key (hidden) " : "",
" rx %"G_GUINT64_FORMAT
" tx %"G_GUINT64_FORMAT
"%s", /* allowed-ips */
public_key_b64,
nm_utils_mem_all_zero (peer->preshared_key, sizeof (peer->preshared_key))
? ""
: " preshared-key (hidden)",
s_endpoint,
peer->rx_bytes,
peer->tx_bytes,
peer->allowedips_len);
peer->allowed_ips_len > 0
? " allowed-ips"
: "");
for (i = 0; i < peer->allowedips_len; i++) {
NMWireGuardAllowedIP *allowedip = &peer->allowedips[i];
const char *ret;
ret = inet_ntop (allowedip->family, &allowedip->ip, s_address, sizeof(s_address));
for (i = 0; i < peer->allowed_ips_len; i++) {
const NMPWireGuardAllowedIP *allowed_ip = &peer->allowed_ips[i];
nm_utils_strbuf_append (&buf, &len,
" %s/%u",
ret ? s_address : "<EAFNOSUPPORT>",
allowedip->mask);
nm_utils_inet_ntop (allowed_ip->family, &allowed_ip->addr, s_addr),
allowed_ip->mask);
}
nm_utils_strbuf_append_str (&buf, &len, " } }");
return buf;
}
@ -5600,25 +5590,26 @@ const char *
nm_platform_lnk_wireguard_to_string (const NMPlatformLnkWireGuard *lnk, char *buf, gsize len)
{
gs_free char *public_b64 = NULL;
guint8 nonzero_key = 0;
gsize i;
if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len))
return buf;
public_b64 = g_base64_encode (lnk->public_key, sizeof (lnk->public_key));
for (i = 0; i < sizeof (lnk->private_key); i++)
nonzero_key |= lnk->private_key[i];
if (!nm_utils_mem_all_zero (lnk->public_key, sizeof (lnk->public_key)))
public_b64 = g_base64_encode (lnk->public_key, sizeof (lnk->public_key));
g_snprintf (buf, len,
"wireguard "
"public_key %s "
"%s" /* private key indicator */
"listen_port %u "
"fwmark 0x%x",
public_b64,
nonzero_key ? "private_key (hidden) " : "",
"wireguard"
"%s%s" /* public-key */
"%s" /* private-key */
" listen-port %u"
" fwmark 0x%x",
public_b64
? " public-key "
: "",
public_b64 ?: "",
nm_utils_mem_all_zero (lnk->private_key, sizeof (lnk->private_key))
? ""
: " private-key (hidden)",
lnk->listen_port,
lnk->fwmark);

View file

@ -752,11 +752,14 @@ typedef struct {
bool l3miss:1;
} NMPlatformLnkVxlan;
#define NMP_WIREGUARD_PUBLIC_KEY_LEN 32
#define NMP_WIREGUARD_SYMMETRIC_KEY_LEN 32
typedef struct {
guint8 private_key[NM_WG_PUBLIC_KEY_LEN];
guint8 public_key[NM_WG_PUBLIC_KEY_LEN];
guint16 listen_port;
guint32 fwmark;
guint16 listen_port;
guint8 private_key[NMP_WIREGUARD_PUBLIC_KEY_LEN];
guint8 public_key[NMP_WIREGUARD_PUBLIC_KEY_LEN];
} NMPlatformLnkWireGuard;
typedef enum {
@ -1463,7 +1466,8 @@ const char *nm_platform_vlan_qos_mapping_to_string (const char *name,
char *buf,
gsize len);
const char *nm_platform_wireguard_peer_to_string (const NMWireGuardPeer *peer,
struct _NMPWireGuardPeer;
const char *nm_platform_wireguard_peer_to_string (const struct _NMPWireGuardPeer *peer,
char *buf,
gsize len);

View file

@ -27,6 +27,7 @@
#include <libudev.h>
#include "nm-utils.h"
#include "nm-utils/nm-secret-utils.h"
#include "nm-core-utils.h"
#include "nm-platform-utils.h"
@ -340,124 +341,99 @@ _vlan_xgress_qos_mappings_cpy (guint *dst_n_map,
g_clear_pointer (dst_map, g_free);
*dst_n_map = src_n_map;
if (src_n_map > 0)
*dst_map = g_memdup (src_map, sizeof (*src_map) * src_n_map);
*dst_map = nm_memdup (src_map, sizeof (*src_map) * src_n_map);
}
}
/*****************************************************************************/
static void
_wireguard_peers_hash_update (gsize n_peers,
const NMWireGuardPeer *peers,
NMHashState *h)
_wireguard_allowed_ip_hash_update (const NMPWireGuardAllowedIP *ip,
NMHashState *h)
{
gsize i, j;
nm_hash_update_vals (h, ip->family,
ip->mask);
nm_hash_update_val (h, n_peers);
for (i = 0; i < n_peers; i++) {
const NMWireGuardPeer *p = &peers[i];
nm_hash_update (h, p->public_key, sizeof (p->public_key));
nm_hash_update (h, p->preshared_key, sizeof (p->preshared_key));
nm_hash_update_vals (h,
p->persistent_keepalive_interval,
p->allowedips_len,
p->rx_bytes,
p->tx_bytes,
p->last_handshake_time.tv_sec,
p->last_handshake_time.tv_nsec,
p->endpoint.addr.sa_family);
if (p->endpoint.addr.sa_family == AF_INET)
nm_hash_update_val (h, p->endpoint.addr4);
else if (p->endpoint.addr.sa_family == AF_INET6)
nm_hash_update_val (h, p->endpoint.addr6);
else if (p->endpoint.addr.sa_family != AF_UNSPEC)
g_assert_not_reached ();
for (j = 0; j < p->allowedips_len; j++) {
const NMWireGuardAllowedIP *ip = &p->allowedips[j];
nm_hash_update_vals (h, ip->family, ip->mask);
if (ip->family == AF_INET)
nm_hash_update_val (h, ip->ip.addr4);
else if (ip->family == AF_INET6)
nm_hash_update_val (h, ip->ip.addr6);
else if (ip->family != AF_UNSPEC)
g_assert_not_reached ();
}
}
if (ip->family == AF_INET)
nm_hash_update_val (h, ip->addr.addr4);
else if (ip->family == AF_INET6)
nm_hash_update_val (h, ip->addr.addr6);
}
static int
_wireguard_peers_cmp (gsize n_peers,
const NMWireGuardPeer *p1,
const NMWireGuardPeer *p2)
_wireguard_allowed_ip_cmp (const NMPWireGuardAllowedIP *a,
const NMPWireGuardAllowedIP *b)
{
gsize i, j;
NM_CMP_SELF (a, b);
for (i = 0; i < n_peers; i++) {
const NMWireGuardPeer *a = &p1[i];
const NMWireGuardPeer *b = &p2[i];
NM_CMP_FIELD (a, b, family);
NM_CMP_FIELD (a, b, mask);
NM_CMP_FIELD (a, b, last_handshake_time.tv_sec);
NM_CMP_FIELD (a, b, last_handshake_time.tv_nsec);
NM_CMP_FIELD (a, b, rx_bytes);
NM_CMP_FIELD (a, b, tx_bytes);
NM_CMP_FIELD (a, b, allowedips_len);
NM_CMP_FIELD (a, b, persistent_keepalive_interval);
NM_CMP_FIELD (a, b, endpoint.addr.sa_family);
NM_CMP_FIELD_MEMCMP (a, b, public_key);
NM_CMP_FIELD_MEMCMP (a, b, preshared_key);
if (a->endpoint.addr.sa_family == AF_INET)
NM_CMP_FIELD_MEMCMP (a, b, endpoint.addr4);
else if (a->endpoint.addr.sa_family == AF_INET6)
NM_CMP_FIELD_MEMCMP (a, b, endpoint.addr6);
else if (a->endpoint.addr.sa_family != AF_UNSPEC)
g_assert_not_reached ();
for (j = 0; j < a->allowedips_len; j++) {
const NMWireGuardAllowedIP *aip = &a->allowedips[j];
const NMWireGuardAllowedIP *bip = &b->allowedips[j];
NM_CMP_FIELD (aip, bip, family);
NM_CMP_FIELD (aip, bip, mask);
if (aip->family == AF_INET)
NM_CMP_FIELD_MEMCMP (&aip->ip, &bip->ip, addr4);
else if (aip->family == AF_INET6)
NM_CMP_FIELD_MEMCMP (&aip->ip, &bip->ip, addr6);
else if (aip->family != AF_UNSPEC)
g_assert_not_reached ();
}
}
if (a->family == AF_INET)
NM_CMP_FIELD (a, b, addr.addr4);
else if (a->family == AF_INET6)
NM_CMP_FIELD_IN6ADDR (a, b, addr.addr6);
return 0;
}
static void
_wireguard_peers_cpy (gsize *dst_n_peers,
NMWireGuardPeer **dst_peers,
gsize src_n_peers,
const NMWireGuardPeer *src_peers)
_wireguard_peer_hash_update (const NMPWireGuardPeer *peer,
NMHashState *h)
{
if (src_n_peers == 0) {
g_clear_pointer (dst_peers, g_free);
*dst_n_peers = 0;
} else if ( src_n_peers != *dst_n_peers
|| _wireguard_peers_cmp (src_n_peers, *dst_peers, src_peers) != 0) {
gsize i;
g_clear_pointer (dst_peers, g_free);
*dst_n_peers = src_n_peers;
if (src_n_peers > 0)
*dst_peers = g_memdup (src_peers, sizeof (*src_peers) * src_n_peers);
for (i = 0; i < src_n_peers; i++) {
dst_peers[i]->allowedips = g_memdup (src_peers[i].allowedips, sizeof (src_peers[i].allowedips) * src_peers[i].allowedips_len);
dst_peers[i]->allowedips_len = src_peers[i].allowedips_len;
}
guint i;
nm_hash_update (h, peer->public_key, sizeof (peer->public_key));
nm_hash_update (h, peer->preshared_key, sizeof (peer->preshared_key));
nm_hash_update_vals (h,
peer->persistent_keepalive_interval,
peer->allowed_ips_len,
peer->rx_bytes,
peer->tx_bytes,
peer->last_handshake_time.tv_sec,
peer->last_handshake_time.tv_nsec,
peer->endpoint_port,
peer->endpoint_family);
if (peer->endpoint_family == AF_INET)
nm_hash_update_val (h, peer->endpoint_addr.addr4);
else if (peer->endpoint_family == AF_INET6)
nm_hash_update_val (h, peer->endpoint_addr.addr6);
for (i = 0; i < peer->allowed_ips_len; i++)
_wireguard_allowed_ip_hash_update (&peer->allowed_ips[i], h);
}
static int
_wireguard_peer_cmp (const NMPWireGuardPeer *a,
const NMPWireGuardPeer *b)
{
guint i;
NM_CMP_SELF (a, b);
NM_CMP_FIELD (a, b, last_handshake_time.tv_sec);
NM_CMP_FIELD (a, b, last_handshake_time.tv_nsec);
NM_CMP_FIELD (a, b, rx_bytes);
NM_CMP_FIELD (a, b, tx_bytes);
NM_CMP_FIELD (a, b, allowed_ips_len);
NM_CMP_FIELD (a, b, persistent_keepalive_interval);
NM_CMP_FIELD (a, b, endpoint_port);
NM_CMP_FIELD (a, b, endpoint_family);
NM_CMP_FIELD_MEMCMP (a, b, public_key);
NM_CMP_FIELD_MEMCMP (a, b, preshared_key);
if (a->endpoint_family == AF_INET)
NM_CMP_FIELD (a, b, endpoint_addr.addr4);
else if (a->endpoint_family == AF_INET6)
NM_CMP_FIELD_IN6ADDR (a, b, endpoint_addr.addr6);
for (i = 0; i < a->allowed_ips_len; i++) {
NM_CMP_RETURN (_wireguard_allowed_ip_cmp (&a->allowed_ips[i],
&b->allowed_ips[i]));
}
return 0;
}
/*****************************************************************************/
@ -586,13 +562,26 @@ _vt_cmd_obj_dispose_lnk_vlan (NMPObject *obj)
g_free ((gpointer) obj->_lnk_vlan.egress_qos_map);
}
static void
_wireguard_clear (NMPObjectLnkWireGuard *lnk)
{
guint i;
nm_explicit_bzero (lnk->_public.private_key,
sizeof (lnk->_public.private_key));
for (i = 0; i < lnk->peers_len; i++) {
NMPWireGuardPeer *peer = (NMPWireGuardPeer *) &lnk->peers[i];
nm_explicit_bzero (peer->preshared_key, sizeof (peer->preshared_key));
}
g_free ((gpointer) lnk->peers);
g_free ((gpointer) lnk->_allowed_ips_buf);
}
static void
_vt_cmd_obj_dispose_lnk_wireguard (NMPObject *obj)
{
if (obj->_lnk_wireguard.peers_len)
g_free (obj->_lnk_wireguard.peers[0].allowedips);
g_free (obj->_lnk_wireguard.peers);
_wireguard_clear (&obj->_lnk_wireguard);
}
static NMPObject *
@ -760,31 +749,35 @@ static const char *
_vt_cmd_obj_to_string_link (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size)
{
const NMPClass *klass = NMP_OBJECT_GET_CLASS (obj);
char buf2[sizeof (_nm_utils_to_string_buffer)];
char buf3[sizeof (_nm_utils_to_string_buffer)];
char *b = buf;
switch (to_string_mode) {
case NMP_OBJECT_TO_STRING_ID:
return klass->cmd_plobj_to_string_id (&obj->object, buf, buf_size);
case NMP_OBJECT_TO_STRING_ALL:
g_snprintf (buf, buf_size,
"[%s,%p,%u,%calive,%cvisible,%cin-nl,%p; %s]",
klass->obj_type_name, obj, obj->parent._ref_count,
nmp_object_is_alive (obj) ? '+' : '-',
nmp_object_is_visible (obj) ? '+' : '-',
obj->_link.netlink.is_in_netlink ? '+' : '-',
obj->_link.udev.device,
nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, buf2, sizeof (buf2)));
nm_utils_strbuf_append (&b, &buf_size,
"[%s,%p,%u,%calive,%cvisible,%cin-nl,%p; ",
klass->obj_type_name, obj, obj->parent._ref_count,
nmp_object_is_alive (obj) ? '+' : '-',
nmp_object_is_visible (obj) ? '+' : '-',
obj->_link.netlink.is_in_netlink ? '+' : '-',
obj->_link.udev.device);
NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, b, buf_size);
nm_utils_strbuf_seek_end (&b, &buf_size);
if (obj->_link.netlink.lnk) {
nm_utils_strbuf_append_str (&b, &buf_size, "; ");
nmp_object_to_string (obj->_link.netlink.lnk, NMP_OBJECT_TO_STRING_ALL, b, buf_size);
nm_utils_strbuf_seek_end (&b, &buf_size);
}
nm_utils_strbuf_append_c (&b, &buf_size, ']');
return buf;
case NMP_OBJECT_TO_STRING_PUBLIC:
NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, b, buf_size);
if (obj->_link.netlink.lnk) {
NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf2, sizeof (buf2));
nmp_object_to_string (obj->_link.netlink.lnk, NMP_OBJECT_TO_STRING_PUBLIC, buf3, sizeof (buf3));
g_snprintf (buf, buf_size,
"%s; %s",
buf2, buf3);
} else
NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf, buf_size);
nm_utils_strbuf_seek_end (&b, &buf_size);
nm_utils_strbuf_append_str (&b, &buf_size, "; ");
nmp_object_to_string (obj->_link.netlink.lnk, NMP_OBJECT_TO_STRING_PUBLIC, b, buf_size);
}
return buf;
default:
g_return_val_if_reached ("ERROR");
@ -855,7 +848,7 @@ _vt_cmd_obj_to_string_lnk_wireguard (const NMPObject *obj, NMPObjectToStringMode
const NMPClass *klass;
char buf2[sizeof (_nm_utils_to_string_buffer)];
char *b;
gsize i, l;
guint i;
klass = NMP_OBJECT_GET_CLASS (obj);
@ -867,23 +860,26 @@ _vt_cmd_obj_to_string_lnk_wireguard (const NMPObject *obj, NMPObjectToStringMode
b = buf;
nm_utils_strbuf_append (&b, &buf_size,
"[%s,%p,%u,%calive,%cvisible; %s "
"peers (%" G_GSIZE_FORMAT ") {",
"[%s,%p,%u,%calive,%cvisible; %s"
"%s",
klass->obj_type_name, obj, obj->parent._ref_count,
nmp_object_is_alive (obj) ? '+' : '-',
nmp_object_is_visible (obj) ? '+' : '-',
nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, buf2, sizeof (buf2)),
obj->_lnk_wireguard.peers_len);
obj->_lnk_wireguard.peers_len > 0
? " peers {"
: "");
for (i = 0; i < obj->_lnk_wireguard.peers_len; i++) {
const NMWireGuardPeer *peer = &obj->_lnk_wireguard.peers[i];
nm_platform_wireguard_peer_to_string (peer, b, buf_size);
l = strlen (b);
b += l;
buf_size -= l;
}
const NMPWireGuardPeer *peer = &obj->_lnk_wireguard.peers[i];
nm_utils_strbuf_append_str (&b, &buf_size, " }");
nm_utils_strbuf_append_str (&b, &buf_size, " { ");
nm_platform_wireguard_peer_to_string (peer, b, buf_size);
nm_utils_strbuf_seek_end (&b, &buf_size);
nm_utils_strbuf_append_str (&b, &buf_size, " }");
}
if (obj->_lnk_wireguard.peers_len)
nm_utils_strbuf_append_str (&b, &buf_size, " }");
return buf;
case NMP_OBJECT_TO_STRING_PUBLIC:
@ -943,6 +939,7 @@ _vt_cmd_obj_hash_update_link (const NMPObject *obj, NMHashState *h)
nm_platform_link_hash_update (&obj->link, h);
nm_hash_update_vals (h,
obj->_link.netlink.is_in_netlink,
obj->_link.wireguard_family_id,
obj->_link.udev.device);
if (obj->_link.netlink.lnk)
nmp_object_hash_update (obj->_link.netlink.lnk, h);
@ -965,10 +962,15 @@ _vt_cmd_obj_hash_update_lnk_vlan (const NMPObject *obj, NMHashState *h)
static void
_vt_cmd_obj_hash_update_lnk_wireguard (const NMPObject *obj, NMHashState *h)
{
guint i;
nm_assert (NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_LNK_WIREGUARD);
nm_platform_lnk_wireguard_hash_update (&obj->lnk_wireguard, h);
_wireguard_peers_hash_update (obj->_lnk_wireguard.peers_len, obj->_lnk_wireguard.peers, h);
nm_hash_update_val (h, obj->_lnk_wireguard.peers_len);
for (i = 0; i < obj->_lnk_wireguard.peers_len; i++)
_wireguard_peer_hash_update (&obj->_lnk_wireguard.peers[i], h);
}
int
@ -976,12 +978,7 @@ nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2)
{
const NMPClass *klass1, *klass2;
if (obj1 == obj2)
return 0;
if (!obj1)
return -1;
if (!obj2)
return 1;
NM_CMP_SELF (obj1, obj2);
g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj1), -1);
g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj2), 1);
@ -1002,16 +999,11 @@ nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2)
static int
_vt_cmd_obj_cmp_link (const NMPObject *obj1, const NMPObject *obj2)
{
int i;
NM_CMP_RETURN (nm_platform_link_cmp (&obj1->link, &obj2->link));
NM_CMP_DIRECT (obj1->_link.netlink.is_in_netlink, obj2->_link.netlink.is_in_netlink);
NM_CMP_RETURN (nmp_object_cmp (obj1->_link.netlink.lnk, obj2->_link.netlink.lnk));
NM_CMP_DIRECT (obj1->_link.wireguard_family_id, obj2->_link.wireguard_family_id);
i = nm_platform_link_cmp (&obj1->link, &obj2->link);
if (i)
return i;
if (obj1->_link.netlink.is_in_netlink != obj2->_link.netlink.is_in_netlink)
return obj1->_link.netlink.is_in_netlink ? -1 : 1;
i = nmp_object_cmp (obj1->_link.netlink.lnk, obj2->_link.netlink.lnk);
if (i)
return i;
if (obj1->_link.udev.device != obj2->_link.udev.device) {
if (!obj1->_link.udev.device)
return -1;
@ -1024,6 +1016,7 @@ _vt_cmd_obj_cmp_link (const NMPObject *obj1, const NMPObject *obj2)
* Have this check as very last. */
return (obj1->_link.udev.device < obj2->_link.udev.device) ? -1 : 1;
}
return 0;
}
@ -1052,16 +1045,16 @@ _vt_cmd_obj_cmp_lnk_vlan (const NMPObject *obj1, const NMPObject *obj2)
static int
_vt_cmd_obj_cmp_lnk_wireguard (const NMPObject *obj1, const NMPObject *obj2)
{
int c;
guint i;
c = nm_platform_lnk_wireguard_cmp (&obj1->lnk_wireguard, &obj2->lnk_wireguard);
if (c)
return c;
NM_CMP_RETURN (nm_platform_lnk_wireguard_cmp (&obj1->lnk_wireguard, &obj2->lnk_wireguard));
if (obj1->_lnk_wireguard.peers_len != obj2->_lnk_wireguard.peers_len)
return obj1->_lnk_wireguard.peers_len < obj2->_lnk_wireguard.peers_len ? -1 : 1;
NM_CMP_FIELD (obj1, obj2, _lnk_wireguard.peers_len);
return _wireguard_peers_cmp(obj1->_lnk_wireguard.peers_len, obj1->_lnk_wireguard.peers, obj2->_lnk_wireguard.peers);
for (i = 0; i < obj1->_lnk_wireguard.peers_len; i++)
NM_CMP_RETURN (_wireguard_peer_cmp (&obj1->_lnk_wireguard.peers[i], &obj2->_lnk_wireguard.peers[i]));
return 0;
}
/* @src is a const object, which is not entirely correct for link types, where
@ -1133,9 +1126,36 @@ _vt_cmd_obj_copy_lnk_vlan (NMPObject *dst, const NMPObject *src)
static void
_vt_cmd_obj_copy_lnk_wireguard (NMPObject *dst, const NMPObject *src)
{
dst->lnk_wireguard = src->lnk_wireguard;
_wireguard_peers_cpy (&dst->_lnk_wireguard.peers_len, &dst->_lnk_wireguard.peers,
src->_lnk_wireguard.peers_len, src->_lnk_wireguard.peers);
guint i;
nm_assert (dst != src);
_wireguard_clear (&dst->_lnk_wireguard);
dst->_lnk_wireguard = src->_lnk_wireguard;
dst->_lnk_wireguard.peers = nm_memdup (dst->_lnk_wireguard.peers,
sizeof (NMPWireGuardPeer) * dst->_lnk_wireguard.peers_len);
dst->_lnk_wireguard._allowed_ips_buf = nm_memdup (dst->_lnk_wireguard._allowed_ips_buf,
sizeof (NMPWireGuardAllowedIP) * dst->_lnk_wireguard._allowed_ips_buf_len);
/* all the peers' pointers point into the buffer. They need to be readjusted. */
for (i = 0; i < dst->_lnk_wireguard.peers_len; i++) {
NMPWireGuardPeer *peer = (NMPWireGuardPeer *) &dst->_lnk_wireguard.peers[i];
if (peer->allowed_ips_len == 0) {
nm_assert (!peer->allowed_ips);
continue;
}
nm_assert (dst->_lnk_wireguard._allowed_ips_buf_len > 0);
nm_assert (src->_lnk_wireguard._allowed_ips_buf);
nm_assert (peer->allowed_ips >= src->_lnk_wireguard._allowed_ips_buf);
nm_assert (&peer->allowed_ips[peer->allowed_ips_len] <= &src->_lnk_wireguard._allowed_ips_buf[src->_lnk_wireguard._allowed_ips_buf_len]);
peer->allowed_ips = &dst->_lnk_wireguard._allowed_ips_buf[peer->allowed_ips - src->_lnk_wireguard._allowed_ips_buf];
}
nm_assert (nmp_object_equal (src, dst));
}
#define _vt_cmd_plobj_id_copy(type, plat_type, cmd) \
@ -3080,4 +3100,3 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vlan_cmp,
},
};

View file

@ -27,6 +27,36 @@
struct udev_device;
/*****************************************************************************/
typedef struct {
NMIPAddr addr;
guint8 family;
guint8 mask;
} NMPWireGuardAllowedIP;
typedef struct _NMPWireGuardPeer {
NMIPAddr endpoint_addr;
struct timespec last_handshake_time;
guint64 rx_bytes;
guint64 tx_bytes;
union {
const NMPWireGuardAllowedIP *allowed_ips;
guint _construct_idx_start;
};
union {
guint allowed_ips_len;
guint _construct_idx_end;
};
guint16 persistent_keepalive_interval;
guint16 endpoint_port;
guint8 public_key[NMP_WIREGUARD_PUBLIC_KEY_LEN];
guint8 preshared_key[NMP_WIREGUARD_SYMMETRIC_KEY_LEN];
guint8 endpoint_family;
} NMPWireGuardPeer;
/*****************************************************************************/
typedef enum { /*< skip >*/
NMP_OBJECT_TO_STRING_ID,
NMP_OBJECT_TO_STRING_PUBLIC,
@ -168,6 +198,9 @@ typedef struct {
/* Auxiliary data object for Wi-Fi and WPAN */
GObject *ext_data;
/* FIXME: not every NMPObjectLink should pay the price for tracking
* the wireguard family id. This should be tracked via ext_data, which
* would be exactly the right place. */
int wireguard_family_id;
} NMPObjectLink;
@ -220,9 +253,10 @@ typedef struct {
typedef struct {
NMPlatformLnkWireGuard _public;
gsize peers_len;
NMWireGuardPeer *peers;
const NMPWireGuardPeer *peers;
const NMPWireGuardAllowedIP *_allowed_ips_buf;
guint peers_len;
guint _allowed_ips_buf_len;
} NMPObjectLnkWireGuard;
typedef struct {

View file

@ -929,7 +929,7 @@ nm_wifi_utils_nl80211_class_init (NMWifiUtilsNl80211Class *klass)
NMWifiUtils *
nm_wifi_utils_nl80211_new (int ifindex, struct nl_sock *genl)
{
NMWifiUtilsNl80211 *nl80211;
gs_unref_object NMWifiUtilsNl80211 *nl80211 = NULL;
nm_auto_nlmsg struct nl_msg *msg = NULL;
struct nl80211_device_info device_info = {};
char ifname[IFNAMSIZ];
@ -951,7 +951,7 @@ nm_wifi_utils_nl80211_new (int ifindex, struct nl_sock *genl)
nl80211->id = genl_ctrl_resolve (nl80211->nl_sock, "nl80211");
if (nl80211->id < 0) {
_LOGD (LOGD_WIFI, "genl_ctrl_resolve: failed to resolve \"nl80211\"");
goto error;
return NULL;
}
nl80211->phy = -1;
@ -963,42 +963,42 @@ nm_wifi_utils_nl80211_new (int ifindex, struct nl_sock *genl)
_LOGD (LOGD_PLATFORM | LOGD_WIFI,
"(%s): NL80211_CMD_GET_WIPHY request failed",
ifname);
goto error;
return NULL;
}
if (!device_info.success) {
_LOGD (LOGD_PLATFORM | LOGD_WIFI,
"(%s): NL80211_CMD_GET_WIPHY request indicated failure",
ifname);
goto error;
return NULL;
}
if (!device_info.supported) {
_LOGD (LOGD_PLATFORM | LOGD_WIFI,
"(%s): driver does not fully support nl80211, falling back to WEXT",
ifname);
goto error;
return NULL;
}
if (!device_info.can_scan_ssid) {
_LOGE (LOGD_PLATFORM | LOGD_WIFI,
"(%s): driver does not support SSID scans",
ifname);
goto error;
return NULL;
}
if (device_info.num_freqs == 0 || device_info.freqs == NULL) {
nm_log_err (LOGD_PLATFORM | LOGD_WIFI,
"(%s): driver reports no supported frequencies",
ifname);
goto error;
return NULL;
}
if (device_info.caps == 0) {
_LOGE (LOGD_PLATFORM | LOGD_WIFI,
"(%s): driver doesn't report support of any encryption",
ifname);
goto error;
return NULL;
}
nl80211->phy = device_info.phy;
@ -1010,9 +1010,5 @@ nm_wifi_utils_nl80211_new (int ifindex, struct nl_sock *genl)
_LOGI (LOGD_PLATFORM | LOGD_WIFI,
"(%s): using nl80211 for WiFi device control",
ifname);
return (NMWifiUtils *) nl80211;
error:
g_object_unref (nl80211);
return NULL;
return (NMWifiUtils *) g_steal_pointer (&nl80211);
}

View file

@ -1445,7 +1445,7 @@ test_nm_utils_strbuf_append (void)
t_buf = buf;
t_len = buf_len;
test_mode = nmtst_get_rand_int () % 4;
test_mode = nmtst_get_rand_int () % 5;
switch (test_mode) {
case 0:
@ -1466,6 +1466,47 @@ test_nm_utils_strbuf_append (void)
case 3:
nm_utils_strbuf_append (&t_buf, &t_len, "%s", str);
break;
case 4:
g_snprintf (t_buf, t_len, "%s", str);
if ( t_len > 0
&& strlen (str) >= buf_len
&& (nmtst_get_rand_int () % 2)) {
/* the string was truncated by g_snprintf(). That means, at the last position in the
* buffer is now NUL.
* Replace the NUL by the actual character, and check that nm_utils_strbuf_seek_end()
* does the right thing: NUL terminate the buffer and seek past the end of the buffer. */
g_assert_cmpmem (t_buf, t_len - 1, str, t_len - 1);
g_assert (t_buf[t_len - 1] == '\0');
g_assert (str[t_len - 1] != '\0');
t_buf[t_len - 1] = str[t_len - 1];
nm_utils_strbuf_seek_end (&t_buf, &t_len);
g_assert (t_len == 0);
g_assert (t_buf == &buf[buf_len]);
g_assert (t_buf[-1] == '\0');
} else {
nm_utils_strbuf_seek_end (&t_buf, &t_len);
if (strlen (str) + 1 == buf_len) {
/* Special case: we appended a string that fit into the buffer
* exactly, without truncation.
* If we would append the string via nm_utils_strbuf_append(),
* then it would have recognized that the string was not truncated
* and leave len==1, and pointing the buffer to the terminating NUL
* (at the very end, not past it).
*
* But nm_utils_strbuf_seek_end() cannot distinguish whether
* truncation occured, and assumes the buffer was indeed truncated.
*
* Assert for that, but also adjust the numbers, so that the assertions
* below pass (the assertions below theck for the nm_utils_strbuf_append()
* case). */
g_assert (t_len == 0);
g_assert (t_buf == &buf[buf_len]);
g_assert (t_buf[-1] == '\0');
t_len = 1;
t_buf--;
}
}
break;
}
/* Assert that the source-buffer is unmodified. */