mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-06 17:50:16 +01:00
platform: merge branch 'th/wifi-cleanup'
https://github.com/NetworkManager/NetworkManager/pull/58
This commit is contained in:
commit
07d8431ae5
14 changed files with 311 additions and 351 deletions
|
|
@ -1374,6 +1374,9 @@ src_libNetworkManagerBase_la_SOURCES = \
|
|||
src/NetworkManagerUtils.c \
|
||||
src/NetworkManagerUtils.h \
|
||||
\
|
||||
src/platform/nm-netlink.c \
|
||||
src/platform/nm-netlink.h \
|
||||
\
|
||||
src/platform/nmp-netns.c \
|
||||
src/platform/nmp-netns.h \
|
||||
src/platform/nmp-object.c \
|
||||
|
|
|
|||
|
|
@ -38,9 +38,6 @@
|
|||
/* Define to 1 if libsystemd is available */
|
||||
#mesondefine HAVE_LIBSYSTEMD
|
||||
|
||||
/* Define if nl80211 has critical protocol support */
|
||||
#mesondefine HAVE_NL80211_CRITICAL_PROTOCOL_CMDS
|
||||
|
||||
/* Define to 1 if you have the `secure_getenv' function. */
|
||||
#mesondefine HAVE_SECURE_GETENV
|
||||
|
||||
|
|
|
|||
61
configure.ac
61
configure.ac
|
|
@ -199,73 +199,12 @@ if test x"$ac_with_wext" = x"yes"; then
|
|||
if test "$enable_wifi" != "yes"; then
|
||||
AC_MSG_ERROR(Enabling WEXT support and disabling Wi-Fi makes no sense)
|
||||
fi
|
||||
AC_MSG_CHECKING([Linux kernel WEXT headers])
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[#ifndef __user
|
||||
#define __user
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <linux/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/wireless.h>]],
|
||||
[[#ifndef IWEVGENIE
|
||||
#error "not found"
|
||||
#endif]])],
|
||||
[ac_have_iwevgenie=yes],
|
||||
[ac_have_iwevgenie=no])
|
||||
AC_MSG_RESULT($ac_have_iwevgenie)
|
||||
if test "$ac_have_iwevgenie" = no; then
|
||||
AC_MSG_ERROR(Linux kernel development header linux/wireless.h not installed or not functional)
|
||||
fi
|
||||
AC_DEFINE(HAVE_WEXT, 1, [Define if you have Linux Wireless Extensions support])
|
||||
else
|
||||
AC_DEFINE(HAVE_WEXT, 0, [Define if you have Linux Wireless Extensions support])
|
||||
fi
|
||||
AM_CONDITIONAL(WITH_WEXT, test x"${ac_with_wext}" = x"yes")
|
||||
|
||||
AC_MSG_CHECKING([Linux kernel nl80211 headers])
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[#ifndef __user
|
||||
#define __user
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <linux/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/nl80211.h>]],
|
||||
[[int a = NL80211_RATE_INFO_BITRATE; a++;]])],
|
||||
[ac_have_nl80211=yes],
|
||||
[ac_have_nl80211=no])
|
||||
AC_MSG_RESULT($ac_have_nl80211)
|
||||
if test "$ac_have_nl80211" = no; then
|
||||
AC_MSG_ERROR(Linux kernel development header linux/nl80211.h not installed or not functional)
|
||||
fi
|
||||
|
||||
if test "$with_wifi" = "yes"; then
|
||||
AC_MSG_CHECKING([Linux kernel nl80211 Critical Protocol Start/Stop])
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[#ifndef __user
|
||||
#define __user
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <linux/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/nl80211.h>]],
|
||||
[[unsigned a = NL80211_CMD_CRIT_PROTOCOL_START; a++;]])],
|
||||
[ac_have_nl80211_critproto=yes],
|
||||
[ac_have_nl80211_critproto=no])
|
||||
AC_MSG_RESULT($ac_have_nl80211_critproto)
|
||||
else
|
||||
ac_have_nl80211_critproto='no'
|
||||
fi
|
||||
if test "$ac_have_nl80211_critproto" = yes; then
|
||||
AC_DEFINE(HAVE_NL80211_CRITICAL_PROTOCOL_CMDS, 1, [Define if nl80211 has critical protocol support])
|
||||
else
|
||||
AC_DEFINE(HAVE_NL80211_CRITICAL_PROTOCOL_CMDS, 0, [Define if nl80211 has critical protocol support])
|
||||
fi
|
||||
|
||||
dnl
|
||||
dnl Default to using wpa_supplicant but allow IWD as wifi backend
|
||||
dnl
|
||||
|
|
|
|||
51
meson.build
51
meson.build
|
|
@ -269,39 +269,6 @@ if dist_version != ''
|
|||
endif
|
||||
|
||||
enable_wifi = get_option('wifi')
|
||||
if enable_wifi
|
||||
nl80211_src = '''
|
||||
#ifndef __user
|
||||
#define __user
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <linux/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/nl80211.h>
|
||||
int main() {
|
||||
int a = NL80211_RATE_INFO_BITRATE;
|
||||
a++;
|
||||
}
|
||||
'''
|
||||
|
||||
assert(cc.compiles(nl80211_src), 'Linux kernel development header linux/nl80211.h not installed or not functional')
|
||||
|
||||
nl80211_crit_proto_src = '''
|
||||
#ifndef __user
|
||||
#define __user
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <linux/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/nl80211.h>
|
||||
int main() {
|
||||
unsigned a = NL80211_CMD_CRIT_PROTOCOL_START;
|
||||
a++;
|
||||
}
|
||||
'''
|
||||
|
||||
config_h.set10('HAVE_NL80211_CRITICAL_PROTOCOL_CMDS', cc.compiles(nl80211_crit_proto_src))
|
||||
endif
|
||||
config_h.set10('WITH_WIFI', enable_wifi)
|
||||
|
||||
enable_iwd = get_option('iwd')
|
||||
|
|
@ -310,25 +277,7 @@ if enable_iwd
|
|||
endif
|
||||
config_h.set10('WITH_IWD', enable_iwd)
|
||||
|
||||
# Default to using WEXT but allow it to be disabled
|
||||
enable_wext = get_option('wext')
|
||||
if enable_wext
|
||||
assert(enable_wifi, 'Enabling WEXT support and disabling Wi-Fi makes no sense')
|
||||
iwevgenie_src = '''
|
||||
#ifndef __user
|
||||
#define __user
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <linux/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/wireless.h>
|
||||
#ifndef IWEVGENIE
|
||||
#error "not found"
|
||||
#endif
|
||||
'''
|
||||
|
||||
assert(cc.compiles(iwevgenie_src), 'Linux kernel development header linux/wireless.h not installed or not functional')
|
||||
endif
|
||||
config_h.set10('HAVE_WEXT', enable_wext)
|
||||
|
||||
# Checks for libdl - on certain platforms its part of libc
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ sources = files(
|
|||
'dhcp/nm-dhcp-utils.c',
|
||||
'ndisc/nm-lndp-ndisc.c',
|
||||
'ndisc/nm-ndisc.c',
|
||||
'platform/nm-netlink.c',
|
||||
'platform/wifi/wifi-utils-nl80211.c',
|
||||
'platform/wifi/wifi-utils.c',
|
||||
'platform/nm-linux-platform.c',
|
||||
|
|
|
|||
|
|
@ -938,7 +938,6 @@ wifi_find_frequency (NMPlatform *platform, int ifindex, const guint32 *freqs)
|
|||
static void
|
||||
wifi_indicate_addressing_running (NMPlatform *platform, int ifindex, gboolean running)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static guint32
|
||||
|
|
|
|||
|
|
@ -37,14 +37,13 @@
|
|||
#include <linux/if_tun.h>
|
||||
#include <linux/if_tunnel.h>
|
||||
#include <linux/ip6_tunnel.h>
|
||||
#include <netlink/netlink.h>
|
||||
#include <netlink/msg.h>
|
||||
#include <libudev.h>
|
||||
|
||||
#include "nm-utils.h"
|
||||
#include "nm-core-internal.h"
|
||||
#include "nm-setting-vlan.h"
|
||||
|
||||
#include "nm-netlink.h"
|
||||
#include "nm-core-utils.h"
|
||||
#include "nmp-object.h"
|
||||
#include "nmp-netns.h"
|
||||
|
|
@ -952,13 +951,6 @@ _nl_addattr_l (struct nlmsghdr *n,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_nm_auto_nl_msg_cleanup (void *ptr)
|
||||
{
|
||||
nlmsg_free (*((struct nl_msg **) ptr));
|
||||
}
|
||||
#define nm_auto_nlmsg nm_auto(_nm_auto_nl_msg_cleanup)
|
||||
|
||||
static const char *
|
||||
_nl_nlmsghdr_to_str (const struct nlmsghdr *hdr, char *buf, gsize len)
|
||||
{
|
||||
|
|
@ -1059,30 +1051,6 @@ flags_done:
|
|||
return b;
|
||||
}
|
||||
|
||||
static int
|
||||
_nl_nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
|
||||
const struct nla_policy *policy)
|
||||
{
|
||||
return nla_parse (tb, maxtype, head, len, (struct nla_policy *) policy);
|
||||
}
|
||||
#define nla_parse(...) _nl_nla_parse(__VA_ARGS__)
|
||||
|
||||
static int
|
||||
_nl_nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
|
||||
int maxtype, const struct nla_policy *policy)
|
||||
{
|
||||
return nlmsg_parse (nlh, hdrlen, tb, maxtype, (struct nla_policy *) policy);
|
||||
}
|
||||
#define nlmsg_parse(...) _nl_nlmsg_parse(__VA_ARGS__)
|
||||
|
||||
static int
|
||||
_nl_nla_parse_nested (struct nlattr *tb[], int maxtype, struct nlattr *nla,
|
||||
const struct nla_policy *policy)
|
||||
{
|
||||
return nla_parse_nested (tb, maxtype, nla, (struct nla_policy *) policy);
|
||||
}
|
||||
#define nla_parse_nested(...) _nl_nla_parse_nested(__VA_ARGS__)
|
||||
|
||||
/******************************************************************
|
||||
* NMPObject/netlink functions
|
||||
******************************************************************/
|
||||
|
|
@ -6421,7 +6389,7 @@ ip_route_get (NMPlatform *platform,
|
|||
int try_count = 0;
|
||||
WaitForNlResponseResult seq_result;
|
||||
int nle;
|
||||
nm_auto_nlmsg NMPObject *route = NULL;
|
||||
nm_auto_nmpobj NMPObject *route = NULL;
|
||||
|
||||
nm_assert (NM_IS_LINUX_PLATFORM (platform));
|
||||
nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
|
||||
|
|
@ -7053,7 +7021,7 @@ nm_linux_platform_init (NMLinuxPlatform *self)
|
|||
priv->delayed_action.list_master_connected = g_ptr_array_new ();
|
||||
priv->delayed_action.list_refresh_link = g_ptr_array_new ();
|
||||
priv->delayed_action.list_wait_for_nl_response = g_array_new (FALSE, TRUE, sizeof (DelayedActionWaitForNlResponseData));
|
||||
priv->wifi_data = g_hash_table_new_full (nm_direct_hash, NULL, NULL, (GDestroyNotify) wifi_utils_deinit);
|
||||
priv->wifi_data = g_hash_table_new_full (nm_direct_hash, NULL, NULL, (GDestroyNotify) wifi_utils_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
122
src/platform/nm-netlink.c
Normal file
122
src/platform/nm-netlink.c
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* nm-platform.c - Handle runtime kernel networking configuration
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright (C) 2018 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include "nm-default.h"
|
||||
|
||||
#include "nm-netlink.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* Reimplementations/copied from libnl3/genl
|
||||
*****************************************************************************/
|
||||
|
||||
void *
|
||||
genlmsg_put (struct nl_msg *msg, uint32_t port, uint32_t seq, int family,
|
||||
int hdrlen, int flags, uint8_t cmd, uint8_t version)
|
||||
{
|
||||
struct nlmsghdr *nlh;
|
||||
struct genlmsghdr hdr = {
|
||||
.cmd = cmd,
|
||||
.version = version,
|
||||
};
|
||||
|
||||
nlh = nlmsg_put (msg, port, seq, family, GENL_HDRLEN + hdrlen, flags);
|
||||
if (nlh == NULL)
|
||||
return NULL;
|
||||
|
||||
memcpy (nlmsg_data (nlh), &hdr, sizeof (hdr));
|
||||
|
||||
return (char *) nlmsg_data (nlh) + GENL_HDRLEN;
|
||||
}
|
||||
|
||||
void *
|
||||
genlmsg_data (const struct genlmsghdr *gnlh)
|
||||
{
|
||||
return ((unsigned char *) gnlh + GENL_HDRLEN);
|
||||
}
|
||||
|
||||
void *
|
||||
genlmsg_user_hdr (const struct genlmsghdr *gnlh)
|
||||
{
|
||||
return genlmsg_data (gnlh);
|
||||
}
|
||||
|
||||
struct genlmsghdr *
|
||||
genlmsg_hdr (struct nlmsghdr *nlh)
|
||||
{
|
||||
return nlmsg_data (nlh);
|
||||
}
|
||||
|
||||
void *
|
||||
genlmsg_user_data (const struct genlmsghdr *gnlh, const int hdrlen)
|
||||
{
|
||||
return (char *) genlmsg_user_hdr (gnlh) + NLMSG_ALIGN (hdrlen);
|
||||
}
|
||||
|
||||
struct nlattr *
|
||||
genlmsg_attrdata (const struct genlmsghdr *gnlh, int hdrlen)
|
||||
{
|
||||
return genlmsg_user_data (gnlh, hdrlen);
|
||||
}
|
||||
|
||||
int
|
||||
genlmsg_len (const struct genlmsghdr *gnlh)
|
||||
{
|
||||
const struct nlmsghdr *nlh;
|
||||
|
||||
nlh = (const struct nlmsghdr *) ((const unsigned char *) gnlh - NLMSG_HDRLEN);
|
||||
return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN);
|
||||
}
|
||||
|
||||
int
|
||||
genlmsg_attrlen (const struct genlmsghdr *gnlh, int hdrlen)
|
||||
{
|
||||
return genlmsg_len (gnlh) - NLMSG_ALIGN (hdrlen);
|
||||
}
|
||||
|
||||
int
|
||||
genlmsg_valid_hdr (struct nlmsghdr *nlh, int hdrlen)
|
||||
{
|
||||
struct genlmsghdr *ghdr;
|
||||
|
||||
if (!nlmsg_valid_hdr (nlh, GENL_HDRLEN))
|
||||
return 0;
|
||||
|
||||
ghdr = nlmsg_data (nlh);
|
||||
if (genlmsg_len (ghdr) < NLMSG_ALIGN (hdrlen))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
|
||||
int maxtype, const struct nla_policy *policy)
|
||||
{
|
||||
struct genlmsghdr *ghdr;
|
||||
|
||||
if (!genlmsg_valid_hdr (nlh, hdrlen))
|
||||
return -NLE_MSG_TOOSHORT;
|
||||
|
||||
ghdr = nlmsg_data (nlh);
|
||||
return nla_parse (tb, maxtype, genlmsg_attrdata (ghdr, hdrlen),
|
||||
genlmsg_attrlen (ghdr, hdrlen), policy);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
85
src/platform/nm-netlink.h
Normal file
85
src/platform/nm-netlink.h
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* nm-platform.c - Handle runtime kernel networking configuration
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright (C) 2018 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#ifndef __NM_NETLINK_H__
|
||||
#define __NM_NETLINK_H__
|
||||
|
||||
#include <netlink/msg.h>
|
||||
#include <netlink/attr.h>
|
||||
|
||||
/*****************************************************************************
|
||||
* libnl3 compat code
|
||||
*****************************************************************************/
|
||||
|
||||
static inline int
|
||||
_nl_nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
|
||||
const struct nla_policy *policy)
|
||||
{
|
||||
return nla_parse (tb, maxtype, head, len, (struct nla_policy *) policy);
|
||||
}
|
||||
#define nla_parse(...) _nl_nla_parse(__VA_ARGS__)
|
||||
|
||||
static inline int
|
||||
_nl_nlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
|
||||
int maxtype, const struct nla_policy *policy)
|
||||
{
|
||||
return nlmsg_parse (nlh, hdrlen, tb, maxtype, (struct nla_policy *) policy);
|
||||
}
|
||||
#define nlmsg_parse(...) _nl_nlmsg_parse(__VA_ARGS__)
|
||||
|
||||
static inline int
|
||||
_nl_nla_parse_nested (struct nlattr *tb[], int maxtype, struct nlattr *nla,
|
||||
const struct nla_policy *policy)
|
||||
{
|
||||
return nla_parse_nested (tb, maxtype, nla, (struct nla_policy *) policy);
|
||||
}
|
||||
#define nla_parse_nested(...) _nl_nla_parse_nested(__VA_ARGS__)
|
||||
|
||||
/*****************************************************************************
|
||||
* Reimplementations/copied from libnl3/genl
|
||||
*****************************************************************************/
|
||||
|
||||
void *genlmsg_put (struct nl_msg *msg, uint32_t port, uint32_t seq, int family,
|
||||
int hdrlen, int flags, uint8_t cmd, uint8_t version);
|
||||
void *genlmsg_data (const struct genlmsghdr *gnlh);
|
||||
void *genlmsg_user_hdr (const struct genlmsghdr *gnlh);
|
||||
struct genlmsghdr *genlmsg_hdr (struct nlmsghdr *nlh);
|
||||
void *genlmsg_user_data (const struct genlmsghdr *gnlh, const int hdrlen);
|
||||
struct nlattr *genlmsg_attrdata (const struct genlmsghdr *gnlh, int hdrlen);
|
||||
int genlmsg_len (const struct genlmsghdr *gnlh);
|
||||
int genlmsg_attrlen (const struct genlmsghdr *gnlh, int hdrlen);
|
||||
int genlmsg_valid_hdr (struct nlmsghdr *nlh, int hdrlen);
|
||||
int genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
|
||||
int maxtype, const struct nla_policy *policy);
|
||||
|
||||
/*****************************************************************************
|
||||
* helpers
|
||||
*****************************************************************************/
|
||||
|
||||
static inline void
|
||||
_nm_auto_nl_msg_cleanup (struct nl_msg **ptr)
|
||||
{
|
||||
nlmsg_free (*ptr);
|
||||
}
|
||||
#define nm_auto_nlmsg nm_auto(_nm_auto_nl_msg_cleanup)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#endif /* __NM_NETLINK_H__ */
|
||||
|
|
@ -22,17 +22,17 @@
|
|||
|
||||
#include "nm-default.h"
|
||||
|
||||
#include "wifi-utils-nl80211.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <unistd.h>
|
||||
#include <netlink/netlink.h>
|
||||
#include <netlink/msg.h>
|
||||
#include <linux/nl80211.h>
|
||||
|
||||
#include "platform/nm-netlink.h"
|
||||
#include "wifi-utils-private.h"
|
||||
#include "wifi-utils-nl80211.h"
|
||||
#include "platform/nm-platform.h"
|
||||
#include "platform/nm-platform-utils.h"
|
||||
#include "nm-utils.h"
|
||||
|
|
@ -46,121 +46,6 @@
|
|||
_NM_UTILS_MACRO_REST(__VA_ARGS__)); \
|
||||
} G_STMT_END
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static int
|
||||
_nl_nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
|
||||
const struct nla_policy *policy)
|
||||
{
|
||||
return nla_parse (tb, maxtype, head, len, (struct nla_policy *) policy);
|
||||
}
|
||||
#define nla_parse(...) _nl_nla_parse(__VA_ARGS__)
|
||||
|
||||
static int
|
||||
_nl_nla_parse_nested (struct nlattr *tb[], int maxtype, struct nlattr *nla,
|
||||
const struct nla_policy *policy)
|
||||
{
|
||||
return nla_parse_nested (tb, maxtype, nla, (struct nla_policy *) policy);
|
||||
}
|
||||
#define nla_parse_nested(...) _nl_nla_parse_nested(__VA_ARGS__)
|
||||
|
||||
/*****************************************************************************
|
||||
* Copied from libnl3/genl:
|
||||
*****************************************************************************/
|
||||
|
||||
static void *
|
||||
genlmsg_put (struct nl_msg *msg, uint32_t port, uint32_t seq, int family,
|
||||
int hdrlen, int flags, uint8_t cmd, uint8_t version)
|
||||
{
|
||||
struct nlmsghdr *nlh;
|
||||
struct genlmsghdr hdr = {
|
||||
.cmd = cmd,
|
||||
.version = version,
|
||||
};
|
||||
|
||||
nlh = nlmsg_put (msg, port, seq, family, GENL_HDRLEN + hdrlen, flags);
|
||||
if (nlh == NULL)
|
||||
return NULL;
|
||||
|
||||
memcpy (nlmsg_data (nlh), &hdr, sizeof (hdr));
|
||||
|
||||
return (char *) nlmsg_data (nlh) + GENL_HDRLEN;
|
||||
}
|
||||
|
||||
static void *
|
||||
genlmsg_data (const struct genlmsghdr *gnlh)
|
||||
{
|
||||
return ((unsigned char *) gnlh + GENL_HDRLEN);
|
||||
}
|
||||
|
||||
static void *
|
||||
genlmsg_user_hdr (const struct genlmsghdr *gnlh)
|
||||
{
|
||||
return genlmsg_data (gnlh);
|
||||
}
|
||||
|
||||
static struct genlmsghdr *
|
||||
genlmsg_hdr (struct nlmsghdr *nlh)
|
||||
{
|
||||
return nlmsg_data (nlh);
|
||||
}
|
||||
|
||||
static void *
|
||||
genlmsg_user_data (const struct genlmsghdr *gnlh, const int hdrlen)
|
||||
{
|
||||
return (char *) genlmsg_user_hdr (gnlh) + NLMSG_ALIGN (hdrlen);
|
||||
}
|
||||
|
||||
static struct nlattr *
|
||||
genlmsg_attrdata (const struct genlmsghdr *gnlh, int hdrlen)
|
||||
{
|
||||
return genlmsg_user_data (gnlh, hdrlen);
|
||||
}
|
||||
|
||||
static int
|
||||
genlmsg_len (const struct genlmsghdr *gnlh)
|
||||
{
|
||||
const struct nlmsghdr *nlh;
|
||||
|
||||
nlh = (const struct nlmsghdr *) ((const unsigned char *) gnlh - NLMSG_HDRLEN);
|
||||
return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN);
|
||||
}
|
||||
|
||||
static int
|
||||
genlmsg_attrlen (const struct genlmsghdr *gnlh, int hdrlen)
|
||||
{
|
||||
return genlmsg_len (gnlh) - NLMSG_ALIGN (hdrlen);
|
||||
}
|
||||
|
||||
static int
|
||||
genlmsg_valid_hdr (struct nlmsghdr *nlh, int hdrlen)
|
||||
{
|
||||
struct genlmsghdr *ghdr;
|
||||
|
||||
if (!nlmsg_valid_hdr (nlh, GENL_HDRLEN))
|
||||
return 0;
|
||||
|
||||
ghdr = nlmsg_data (nlh);
|
||||
if (genlmsg_len (ghdr) < NLMSG_ALIGN (hdrlen))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
|
||||
int maxtype, const struct nla_policy *policy)
|
||||
{
|
||||
struct genlmsghdr *ghdr;
|
||||
|
||||
if (!genlmsg_valid_hdr (nlh, hdrlen))
|
||||
return -NLE_MSG_TOOSHORT;
|
||||
|
||||
ghdr = nlmsg_data (nlh);
|
||||
return nla_parse (tb, maxtype, genlmsg_attrdata (ghdr, hdrlen),
|
||||
genlmsg_attrlen (ghdr, hdrlen), policy);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Reimplementation of libnl3/genl functions:
|
||||
*****************************************************************************/
|
||||
|
|
@ -258,11 +143,12 @@ out:
|
|||
typedef struct {
|
||||
WifiData parent;
|
||||
struct nl_sock *nl_sock;
|
||||
int id;
|
||||
struct nl_cb *nl_cb;
|
||||
guint32 *freqs;
|
||||
int id;
|
||||
int num_freqs;
|
||||
int phy;
|
||||
bool can_wowlan:1;
|
||||
} WifiDataNl80211;
|
||||
|
||||
static int
|
||||
|
|
@ -790,7 +676,6 @@ wifi_nl80211_get_qual (WifiData *data)
|
|||
return sta_info.signal;
|
||||
}
|
||||
|
||||
#if HAVE_NL80211_CRITICAL_PROTOCOL_CMDS
|
||||
static gboolean
|
||||
wifi_nl80211_indicate_addressing_running (WifiData *data, gboolean running)
|
||||
{
|
||||
|
|
@ -799,16 +684,21 @@ wifi_nl80211_indicate_addressing_running (WifiData *data, gboolean running)
|
|||
int err;
|
||||
|
||||
msg = nl80211_alloc_msg (nl80211,
|
||||
running ? NL80211_CMD_CRIT_PROTOCOL_START :
|
||||
NL80211_CMD_CRIT_PROTOCOL_STOP,
|
||||
running
|
||||
? 98 /* NL80211_CMD_CRIT_PROTOCOL_START */
|
||||
: 99 /* NL80211_CMD_CRIT_PROTOCOL_STOP */,
|
||||
0);
|
||||
/* Despite the DHCP name, we're using this for any type of IP addressing,
|
||||
* DHCPv4, DHCPv6, and IPv6 SLAAC.
|
||||
*/
|
||||
NLA_PUT_U16 (msg, NL80211_ATTR_CRIT_PROT_ID, NL80211_CRIT_PROTO_DHCP);
|
||||
NLA_PUT_U16 (msg,
|
||||
179 /* NL80211_ATTR_CRIT_PROT_ID */,
|
||||
1 /* NL80211_CRIT_PROTO_DHCP */);
|
||||
if (running) {
|
||||
/* Give DHCP 5 seconds to complete */
|
||||
NLA_PUT_U16 (msg, NL80211_ATTR_MAX_CRIT_PROT_DURATION, 5000);
|
||||
NLA_PUT_U16 (msg,
|
||||
180 /* NL80211_ATTR_MAX_CRIT_PROT_DURATION */,
|
||||
5000);
|
||||
}
|
||||
|
||||
err = nl80211_send_and_recv (nl80211, msg, NULL, NULL);
|
||||
|
|
@ -818,7 +708,6 @@ nla_put_failure:
|
|||
nlmsg_free (msg);
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct nl80211_wowlan_info {
|
||||
gboolean enabled;
|
||||
|
|
@ -850,9 +739,11 @@ wifi_nl80211_get_wowlan (WifiData *data)
|
|||
struct nl_msg *msg;
|
||||
struct nl80211_wowlan_info info;
|
||||
|
||||
if (!nl80211->can_wowlan)
|
||||
return FALSE;
|
||||
|
||||
msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_WOWLAN, 0);
|
||||
nl80211_send_and_recv (nl80211, msg, nl80211_wowlan_handler, &info);
|
||||
|
||||
return info.enabled;
|
||||
}
|
||||
|
||||
|
|
@ -1062,6 +953,20 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
|
|||
WifiData *
|
||||
wifi_nl80211_init (int ifindex)
|
||||
{
|
||||
static const WifiDataClass klass = {
|
||||
.struct_size = sizeof (WifiDataNl80211),
|
||||
.get_mode = wifi_nl80211_get_mode,
|
||||
.set_mode = wifi_nl80211_set_mode,
|
||||
.set_powersave = wifi_nl80211_set_powersave,
|
||||
.get_freq = wifi_nl80211_get_freq,
|
||||
.find_freq = wifi_nl80211_find_freq,
|
||||
.get_bssid = wifi_nl80211_get_bssid,
|
||||
.get_rate = wifi_nl80211_get_rate,
|
||||
.get_qual = wifi_nl80211_get_qual,
|
||||
.get_wowlan = wifi_nl80211_get_wowlan,
|
||||
.indicate_addressing_running = wifi_nl80211_indicate_addressing_running,
|
||||
.deinit = wifi_nl80211_deinit,
|
||||
};
|
||||
WifiDataNl80211 *nl80211;
|
||||
struct nl_msg *msg;
|
||||
struct nl80211_device_info device_info = {};
|
||||
|
|
@ -1073,19 +978,7 @@ wifi_nl80211_init (int ifindex)
|
|||
nm_sprintf_buf (ifname, "if %d", ifindex);
|
||||
}
|
||||
|
||||
nl80211 = wifi_data_new (ifindex, sizeof (*nl80211));
|
||||
nl80211->parent.get_mode = wifi_nl80211_get_mode;
|
||||
nl80211->parent.set_mode = wifi_nl80211_set_mode;
|
||||
nl80211->parent.set_powersave = wifi_nl80211_set_powersave;
|
||||
nl80211->parent.get_freq = wifi_nl80211_get_freq;
|
||||
nl80211->parent.find_freq = wifi_nl80211_find_freq;
|
||||
nl80211->parent.get_bssid = wifi_nl80211_get_bssid;
|
||||
nl80211->parent.get_rate = wifi_nl80211_get_rate;
|
||||
nl80211->parent.get_qual = wifi_nl80211_get_qual;
|
||||
#if HAVE_NL80211_CRITICAL_PROTOCOL_CMDS
|
||||
nl80211->parent.indicate_addressing_running = wifi_nl80211_indicate_addressing_running;
|
||||
#endif
|
||||
nl80211->parent.deinit = wifi_nl80211_deinit;
|
||||
nl80211 = wifi_data_new (&klass, ifindex);
|
||||
|
||||
nl80211->nl_sock = nl_socket_alloc ();
|
||||
if (nl80211->nl_sock == NULL)
|
||||
|
|
@ -1153,18 +1046,15 @@ wifi_nl80211_init (int ifindex)
|
|||
nl80211->freqs = device_info.freqs;
|
||||
nl80211->num_freqs = device_info.num_freqs;
|
||||
nl80211->parent.caps = device_info.caps;
|
||||
|
||||
if (device_info.can_wowlan)
|
||||
nl80211->parent.get_wowlan = wifi_nl80211_get_wowlan;
|
||||
nl80211->can_wowlan = device_info.can_wowlan;
|
||||
|
||||
_LOGI (LOGD_PLATFORM | LOGD_WIFI,
|
||||
"(%s): using nl80211 for WiFi device control",
|
||||
ifname);
|
||||
|
||||
return (WifiData *) nl80211;
|
||||
|
||||
error:
|
||||
wifi_utils_deinit ((WifiData *) nl80211);
|
||||
wifi_utils_unref ((WifiData *) nl80211);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,9 +24,8 @@
|
|||
#include "nm-dbus-interface.h"
|
||||
#include "wifi-utils.h"
|
||||
|
||||
struct WifiData {
|
||||
int ifindex;
|
||||
NMDeviceWifiCapabilities caps;
|
||||
typedef struct {
|
||||
gsize struct_size;
|
||||
|
||||
NM80211Mode (*get_mode) (WifiData *data);
|
||||
|
||||
|
|
@ -66,9 +65,14 @@ struct WifiData {
|
|||
gboolean (*set_mesh_ssid) (WifiData *data, const guint8 *ssid, gsize len);
|
||||
|
||||
gboolean (*indicate_addressing_running) (WifiData *data, gboolean running);
|
||||
} WifiDataClass;
|
||||
|
||||
struct WifiData {
|
||||
const WifiDataClass *klass;
|
||||
int ifindex;
|
||||
NMDeviceWifiCapabilities caps;
|
||||
};
|
||||
|
||||
gpointer wifi_data_new (int ifindex, gsize len);
|
||||
void wifi_data_free (WifiData *data);
|
||||
gpointer wifi_data_new (const WifiDataClass *klass, int ifindex);
|
||||
|
||||
#endif /* __WIFI_UTILS_PRIVATE_H__ */
|
||||
|
|
|
|||
|
|
@ -21,17 +21,14 @@
|
|||
|
||||
#include "nm-default.h"
|
||||
|
||||
#include "wifi-utils-wext.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "wifi-utils-private.h"
|
||||
#include "wifi-utils-wext.h"
|
||||
#include "nm-utils.h"
|
||||
#include "platform/nm-platform-utils.h"
|
||||
|
||||
/* Hacks necessary to #include wireless.h; yay for WEXT */
|
||||
#ifndef __user
|
||||
#define __user
|
||||
|
|
@ -41,6 +38,10 @@
|
|||
#include <sys/socket.h>
|
||||
#include <linux/wireless.h>
|
||||
|
||||
#include "wifi-utils-private.h"
|
||||
#include "nm-utils.h"
|
||||
#include "platform/nm-platform-utils.h"
|
||||
|
||||
typedef struct {
|
||||
WifiData parent;
|
||||
int fd;
|
||||
|
|
@ -628,6 +629,21 @@ wext_get_caps (WifiDataWext *wext, const char *ifname, struct iw_range *range)
|
|||
WifiData *
|
||||
wifi_wext_init (int ifindex, gboolean check_scan)
|
||||
{
|
||||
static const WifiDataClass klass = {
|
||||
.struct_size = sizeof (WifiDataWext),
|
||||
.get_mode = wifi_wext_get_mode,
|
||||
.set_mode = wifi_wext_set_mode,
|
||||
.set_powersave = wifi_wext_set_powersave,
|
||||
.get_freq = wifi_wext_get_freq,
|
||||
.find_freq = wifi_wext_find_freq,
|
||||
.get_bssid = wifi_wext_get_bssid,
|
||||
.get_rate = wifi_wext_get_rate,
|
||||
.get_qual = wifi_wext_get_qual,
|
||||
.deinit = wifi_wext_deinit,
|
||||
.get_mesh_channel = wifi_wext_get_mesh_channel,
|
||||
.set_mesh_channel = wifi_wext_set_mesh_channel,
|
||||
.set_mesh_ssid = wifi_wext_set_mesh_ssid,
|
||||
};
|
||||
WifiDataWext *wext;
|
||||
struct iw_range range;
|
||||
guint32 response_len = 0;
|
||||
|
|
@ -642,19 +658,7 @@ wifi_wext_init (int ifindex, gboolean check_scan)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
wext = wifi_data_new (ifindex, sizeof (*wext));
|
||||
wext->parent.get_mode = wifi_wext_get_mode;
|
||||
wext->parent.set_mode = wifi_wext_set_mode;
|
||||
wext->parent.set_powersave = wifi_wext_set_powersave;
|
||||
wext->parent.get_freq = wifi_wext_get_freq;
|
||||
wext->parent.find_freq = wifi_wext_find_freq;
|
||||
wext->parent.get_bssid = wifi_wext_get_bssid;
|
||||
wext->parent.get_rate = wifi_wext_get_rate;
|
||||
wext->parent.get_qual = wifi_wext_get_qual;
|
||||
wext->parent.deinit = wifi_wext_deinit;
|
||||
wext->parent.get_mesh_channel = wifi_wext_get_mesh_channel;
|
||||
wext->parent.set_mesh_channel = wifi_wext_set_mesh_channel;
|
||||
wext->parent.set_mesh_ssid = wifi_wext_set_mesh_ssid;
|
||||
wext = wifi_data_new (&klass, ifindex);
|
||||
|
||||
wext->fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
|
||||
if (wext->fd < 0)
|
||||
|
|
@ -730,7 +734,7 @@ wifi_wext_init (int ifindex, gboolean check_scan)
|
|||
return (WifiData *) wext;
|
||||
|
||||
error:
|
||||
wifi_utils_deinit ((WifiData *) wext);
|
||||
wifi_utils_unref ((WifiData *) wext);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,22 +38,19 @@
|
|||
#include "platform/nm-platform-utils.h"
|
||||
|
||||
gpointer
|
||||
wifi_data_new (int ifindex, gsize len)
|
||||
wifi_data_new (const WifiDataClass *klass, int ifindex)
|
||||
{
|
||||
WifiData *data;
|
||||
|
||||
data = g_malloc0 (len);
|
||||
nm_assert (klass);
|
||||
nm_assert (klass->struct_size > sizeof (WifiData));
|
||||
|
||||
data = g_malloc0 (klass->struct_size);
|
||||
data->klass = klass;
|
||||
data->ifindex = ifindex;
|
||||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
wifi_data_free (WifiData *data)
|
||||
{
|
||||
memset (data, 0, sizeof (*data));
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
WifiData *
|
||||
|
|
@ -85,14 +82,14 @@ wifi_utils_get_caps (WifiData *data)
|
|||
{
|
||||
g_return_val_if_fail (data != NULL, NM_WIFI_DEVICE_CAP_NONE);
|
||||
|
||||
return data->caps;
|
||||
return data->caps;
|
||||
}
|
||||
|
||||
NM80211Mode
|
||||
wifi_utils_get_mode (WifiData *data)
|
||||
{
|
||||
g_return_val_if_fail (data != NULL, NM_802_11_MODE_UNKNOWN);
|
||||
return data->get_mode (data);
|
||||
return data->klass->get_mode (data);
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
|
@ -104,7 +101,7 @@ wifi_utils_set_mode (WifiData *data, const NM80211Mode mode)
|
|||
|| (mode == NM_802_11_MODE_ADHOC), FALSE);
|
||||
|
||||
/* nl80211 probably doesn't need this */
|
||||
return data->set_mode ? data->set_mode (data, mode) : TRUE;
|
||||
return data->klass->set_mode ? data->klass->set_mode (data, mode) : TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
|
@ -112,14 +109,14 @@ wifi_utils_set_powersave (WifiData *data, guint32 powersave)
|
|||
{
|
||||
g_return_val_if_fail (data != NULL, FALSE);
|
||||
|
||||
return data->set_powersave ? data->set_powersave (data, powersave) : TRUE;
|
||||
return data->klass->set_powersave ? data->klass->set_powersave (data, powersave) : TRUE;
|
||||
}
|
||||
|
||||
guint32
|
||||
wifi_utils_get_freq (WifiData *data)
|
||||
{
|
||||
g_return_val_if_fail (data != NULL, 0);
|
||||
return data->get_freq (data);
|
||||
return data->klass->get_freq (data);
|
||||
}
|
||||
|
||||
guint32
|
||||
|
|
@ -127,7 +124,7 @@ wifi_utils_find_freq (WifiData *data, const guint32 *freqs)
|
|||
{
|
||||
g_return_val_if_fail (data != NULL, 0);
|
||||
g_return_val_if_fail (freqs != NULL, 0);
|
||||
return data->find_freq (data, freqs);
|
||||
return data->klass->find_freq (data, freqs);
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
|
@ -137,38 +134,40 @@ wifi_utils_get_bssid (WifiData *data, guint8 *out_bssid)
|
|||
g_return_val_if_fail (out_bssid != NULL, FALSE);
|
||||
|
||||
memset (out_bssid, 0, ETH_ALEN);
|
||||
return data->get_bssid (data, out_bssid);
|
||||
return data->klass->get_bssid (data, out_bssid);
|
||||
}
|
||||
|
||||
guint32
|
||||
wifi_utils_get_rate (WifiData *data)
|
||||
{
|
||||
g_return_val_if_fail (data != NULL, 0);
|
||||
return data->get_rate (data);
|
||||
return data->klass->get_rate (data);
|
||||
}
|
||||
|
||||
int
|
||||
wifi_utils_get_qual (WifiData *data)
|
||||
{
|
||||
g_return_val_if_fail (data != NULL, 0);
|
||||
return data->get_qual (data);
|
||||
return data->klass->get_qual (data);
|
||||
}
|
||||
|
||||
gboolean
|
||||
wifi_utils_get_wowlan (WifiData *data)
|
||||
{
|
||||
g_return_val_if_fail (data != NULL, 0);
|
||||
if (!data->get_wowlan)
|
||||
|
||||
if (!data->klass->get_wowlan)
|
||||
return FALSE;
|
||||
return data->get_wowlan (data);
|
||||
return data->klass->get_wowlan (data);
|
||||
}
|
||||
|
||||
void
|
||||
wifi_utils_deinit (WifiData *data)
|
||||
wifi_utils_unref (WifiData *data)
|
||||
{
|
||||
g_return_if_fail (data != NULL);
|
||||
data->deinit (data);
|
||||
wifi_data_free (data);
|
||||
|
||||
data->klass->deinit (data);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
|
@ -191,8 +190,8 @@ guint32
|
|||
wifi_utils_get_mesh_channel (WifiData *data)
|
||||
{
|
||||
g_return_val_if_fail (data != NULL, FALSE);
|
||||
g_return_val_if_fail (data->get_mesh_channel != NULL, FALSE);
|
||||
return data->get_mesh_channel (data);
|
||||
g_return_val_if_fail (data->klass->get_mesh_channel != NULL, FALSE);
|
||||
return data->klass->get_mesh_channel (data);
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
|
@ -200,24 +199,24 @@ wifi_utils_set_mesh_channel (WifiData *data, guint32 channel)
|
|||
{
|
||||
g_return_val_if_fail (data != NULL, FALSE);
|
||||
g_return_val_if_fail (channel <= 13, FALSE);
|
||||
g_return_val_if_fail (data->set_mesh_channel != NULL, FALSE);
|
||||
return data->set_mesh_channel (data, channel);
|
||||
g_return_val_if_fail (data->klass->set_mesh_channel != NULL, FALSE);
|
||||
return data->klass->set_mesh_channel (data, channel);
|
||||
}
|
||||
|
||||
gboolean
|
||||
wifi_utils_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len)
|
||||
{
|
||||
g_return_val_if_fail (data != NULL, FALSE);
|
||||
g_return_val_if_fail (data->set_mesh_ssid != NULL, FALSE);
|
||||
return data->set_mesh_ssid (data, ssid, len);
|
||||
g_return_val_if_fail (data->klass->set_mesh_ssid != NULL, FALSE);
|
||||
return data->klass->set_mesh_ssid (data, ssid, len);
|
||||
}
|
||||
|
||||
gboolean
|
||||
wifi_utils_indicate_addressing_running (WifiData *data, gboolean running)
|
||||
{
|
||||
g_return_val_if_fail (data != NULL, FALSE);
|
||||
if (data->indicate_addressing_running)
|
||||
return data->indicate_addressing_running (data, running);
|
||||
if (data->klass->indicate_addressing_running)
|
||||
return data->klass->indicate_addressing_running (data, running);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ WifiData *wifi_utils_init (int ifindex, gboolean check_scan);
|
|||
|
||||
int wifi_utils_get_ifindex (WifiData *data);
|
||||
|
||||
void wifi_utils_deinit (WifiData *data);
|
||||
void wifi_utils_unref (WifiData *data);
|
||||
|
||||
NMDeviceWifiCapabilities wifi_utils_get_caps (WifiData *data);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue