gboolean wifi_wext_is_wifi (const char *iface) { int fd; struct iwreq iwr; gboolean is_wifi = FALSE; /* performing an ioctl on a non-existing name may cause the automatic * loading of kernel modules, which should be avoided. * * Usually, we should thus make sure that an inteface with this name * exists. * * Note that wifi_wext_is_wifi() has only one caller which just verified * that an interface with this name exists. */ fd = socket (PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (fd >= 0) { nm_utils_ifname_cpy (iwr.ifr_ifrn.ifrn_name, iface); if (ioctl (fd, SIOCGIWNAME, &iwr) == 0) is_wifi = TRUE; close (fd); } return is_wifi; }
static NM80211Mode wifi_wext_get_mode (WifiData *data) { WifiDataWext *wext = (WifiDataWext *) data; struct iwreq wrq; memset (&wrq, 0, sizeof (struct iwreq)); nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); if (ioctl (wext->fd, SIOCGIWMODE, &wrq) < 0) { if (errno != ENODEV) { nm_log_warn (LOGD_PLATFORM | LOGD_WIFI, "(%s): error %d getting card mode", wext->parent.iface, errno); } return NM_802_11_MODE_UNKNOWN; } switch (wrq.u.mode) { case IW_MODE_ADHOC: return NM_802_11_MODE_ADHOC; case IW_MODE_MASTER: return NM_802_11_MODE_AP; case IW_MODE_INFRA: case IW_MODE_AUTO: /* hack for WEXT devices reporting IW_MODE_AUTO */ return NM_802_11_MODE_INFRA; default: break; } return NM_802_11_MODE_UNKNOWN; }
static gboolean ethtool_get (const char *name, gpointer edata) { struct ifreq ifr; int fd; if (!name || !*name) return FALSE; if (!nmp_utils_device_exists (name)) return FALSE; /* nmp_utils_device_exists() already errors out if @name is invalid. */ nm_assert (strlen (name) < IFNAMSIZ); memset (&ifr, 0, sizeof (ifr)); nm_utils_ifname_cpy (ifr.ifr_name, name); ifr.ifr_data = edata; fd = socket (PF_INET, SOCK_DGRAM, 0); if (fd < 0) { nm_log_err (LOGD_PLATFORM, "ethtool: Could not open socket."); return FALSE; } if (ioctl (fd, SIOCETHTOOL, &ifr) < 0) { nm_log_dbg (LOGD_PLATFORM, "ethtool: Request failed: %s", strerror (errno)); close (fd); return FALSE; } close (fd); return TRUE; }
static gboolean wifi_wext_set_mesh_ssid (WifiData *data, const guint8 *ssid, gsize len) { WifiDataWext *wext = (WifiDataWext *) data; struct iwreq wrq; char buf[IW_ESSID_MAX_SIZE + 1]; memset (buf, 0, sizeof (buf)); memcpy (buf, ssid, MIN (sizeof (buf) - 1, len)); wrq.u.essid.pointer = (caddr_t) buf; wrq.u.essid.length = len; wrq.u.essid.flags = (len > 0) ? 1 : 0; /* 1=enable SSID, 0=disable/any */ nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); if (ioctl (wext->fd, SIOCSIWESSID, &wrq) == 0) return TRUE; if (errno != ENODEV) { nm_log_err (LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC, "(%s): error setting SSID to '%s': %s", wext->parent.iface, ssid ? nm_utils_escape_ssid (ssid, len) : "(null)", strerror (errno)); } return FALSE; }
static guint32 wifi_wext_get_rate (WifiData *data) { WifiDataWext *wext = (WifiDataWext *) data; struct iwreq wrq; int err; memset (&wrq, 0, sizeof (wrq)); nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); err = ioctl (wext->fd, SIOCGIWRATE, &wrq); return ((err == 0) ? wrq.u.bitrate.value / 1000 : 0); }
static gboolean wext_can_scan (WifiDataWext *wext) { struct iwreq wrq; memset (&wrq, 0, sizeof (struct iwreq)); nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); if (ioctl (wext->fd, SIOCSIWSCAN, &wrq) < 0) { if (errno == EOPNOTSUPP) return FALSE; } return TRUE; }
gboolean nmp_utils_device_exists (const char *name) { #define SYS_CLASS_NET "/sys/class/net/" char sysdir[NM_STRLEN (SYS_CLASS_NET) + IFNAMSIZ]; if ( !name || strlen (name) >= IFNAMSIZ || !nm_utils_is_valid_path_component (name)) g_return_val_if_reached (FALSE); memcpy (sysdir, SYS_CLASS_NET, NM_STRLEN (SYS_CLASS_NET)); nm_utils_ifname_cpy (&sysdir[NM_STRLEN (SYS_CLASS_NET)], name); return g_file_test (sysdir, G_FILE_TEST_EXISTS); }
gboolean nmp_utils_mii_supports_carrier_detect (const char *ifname) { int fd, errsv; struct ifreq ifr; struct mii_ioctl_data *mii; gboolean supports_mii = FALSE; if (!ifname) return FALSE; if (!nmp_utils_device_exists (ifname)) return FALSE; fd = socket (PF_INET, SOCK_DGRAM, 0); if (fd < 0) { nm_log_err (LOGD_PLATFORM, "mii: couldn't open control socket (%s)", ifname); return FALSE; } memset (&ifr, 0, sizeof (struct ifreq)); nm_utils_ifname_cpy (ifr.ifr_name, ifname); errno = 0; if (ioctl (fd, SIOCGMIIPHY, &ifr) < 0) { errsv = errno; nm_log_dbg (LOGD_PLATFORM, "mii: SIOCGMIIPHY failed: %s (%d) (%s)", strerror (errsv), errsv, ifname); goto out; } /* If we can read the BMSR register, we assume that the card supports MII link detection */ mii = (struct mii_ioctl_data *) &ifr.ifr_ifru; mii->reg_num = MII_BMSR; if (ioctl (fd, SIOCGMIIREG, &ifr) == 0) { nm_log_dbg (LOGD_PLATFORM, "mii: SIOCGMIIREG result 0x%X (%s)", mii->val_out, ifname); supports_mii = TRUE; } else { errsv = errno; nm_log_dbg (LOGD_PLATFORM, "mii: SIOCGMIIREG failed: %s (%d) (%s)", strerror (errsv), errsv, ifname); } out: close (fd); nm_log_dbg (LOGD_PLATFORM, "mii: MII %s supported (%s)", supports_mii ? "is" : "not", ifname); return supports_mii; }
static gboolean wifi_wext_get_bssid (WifiData *data, guint8 *out_bssid) { WifiDataWext *wext = (WifiDataWext *) data; struct iwreq wrq; memset (&wrq, 0, sizeof (wrq)); nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); if (ioctl (wext->fd, SIOCGIWAP, &wrq) < 0) { nm_log_warn (LOGD_PLATFORM | LOGD_WIFI, "(%s): error getting associated BSSID: %s", wext->parent.iface, strerror (errno)); return FALSE; } memcpy (out_bssid, &(wrq.u.ap_addr.sa_data), ETH_ALEN); return TRUE; }
static guint32 wifi_wext_get_freq (WifiData *data) { WifiDataWext *wext = (WifiDataWext *) data; struct iwreq wrq; memset (&wrq, 0, sizeof (struct iwreq)); nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); if (ioctl (wext->fd, SIOCGIWFREQ, &wrq) < 0) { nm_log_warn (LOGD_PLATFORM | LOGD_WIFI, "(%s): error getting frequency: %s", wext->parent.iface, strerror (errno)); return 0; } return iw_freq_to_uint32 (&wrq.u.freq); }
static gboolean wext_get_range (WifiDataWext *wext, struct iw_range *range, guint32 *response_len) { int i = 26; gboolean success = FALSE; struct iwreq wrq; memset (&wrq, 0, sizeof (struct iwreq)); nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); wrq.u.data.pointer = (caddr_t) range; wrq.u.data.length = sizeof (struct iw_range); /* Need to give some drivers time to recover after suspend/resume * (ex ipw3945 takes a few seconds to talk to its regulatory daemon; * see rh bz#362421) */ while (i-- > 0) { if (ioctl (wext->fd, SIOCGIWRANGE, &wrq) == 0) { if (response_len) *response_len = wrq.u.data.length; success = TRUE; break; } else if (errno != EAGAIN) { nm_log_err (LOGD_PLATFORM | LOGD_WIFI, "(%s): couldn't get driver range information (%d).", wext->parent.iface, errno); break; } g_usleep (G_USEC_PER_SEC / 4); } if (i <= 0) { nm_log_warn (LOGD_PLATFORM | LOGD_WIFI, "(%s): driver took too long to respond to IWRANGE query.", wext->parent.iface); } return success; }
static int wifi_wext_get_qual (WifiData *data) { WifiDataWext *wext = (WifiDataWext *) data; struct iwreq wrq; struct iw_statistics stats; memset (&stats, 0, sizeof (stats)); wrq.u.data.pointer = &stats; wrq.u.data.length = sizeof (stats); wrq.u.data.flags = 1; /* Clear updated flag */ nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); if (ioctl (wext->fd, SIOCGIWSTATS, &wrq) < 0) { nm_log_warn (LOGD_PLATFORM | LOGD_WIFI, "(%s): error getting signal strength: %s", wext->parent.iface, strerror (errno)); return -1; } return wext_qual_to_percent (&stats.qual, &wext->max_qual); }
static gboolean wifi_wext_set_powersave (WifiData *data, guint32 powersave) { WifiDataWext *wext = (WifiDataWext *) data; struct iwreq wrq; memset (&wrq, 0, sizeof (struct iwreq)); if (powersave == 1) { wrq.u.power.flags = IW_POWER_ALL_R; } else wrq.u.power.disabled = 1; nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); if (ioctl (wext->fd, SIOCSIWPOWER, &wrq) < 0) { if (errno != ENODEV) { nm_log_err (LOGD_PLATFORM | LOGD_WIFI, "(%s): error setting powersave %" G_GUINT32_FORMAT, wext->parent.iface, powersave); } return FALSE; } return TRUE; }
static gboolean wifi_wext_set_mesh_channel (WifiData *data, guint32 channel) { WifiDataWext *wext = (WifiDataWext *) data; struct iwreq wrq; memset (&wrq, 0, sizeof (struct iwreq)); nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); if (channel > 0) { wrq.u.freq.flags = IW_FREQ_FIXED; wrq.u.freq.e = 0; wrq.u.freq.m = channel; } if (ioctl (wext->fd, SIOCSIWFREQ, &wrq) < 0) { nm_log_err (LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC, "(%s): error setting channel to %d: %s", wext->parent.iface, channel, strerror (errno)); return FALSE; } return TRUE; }
static gboolean wifi_wext_set_mode (WifiData *data, const NM80211Mode mode) { WifiDataWext *wext = (WifiDataWext *) data; struct iwreq wrq; if (wifi_wext_get_mode (data) == mode) return TRUE; memset (&wrq, 0, sizeof (struct iwreq)); switch (mode) { case NM_802_11_MODE_ADHOC: wrq.u.mode = IW_MODE_ADHOC; break; case NM_802_11_MODE_AP: wrq.u.mode = IW_MODE_MASTER; break; case NM_802_11_MODE_INFRA: wrq.u.mode = IW_MODE_INFRA; break; default: g_warn_if_reached (); return FALSE; } nm_utils_ifname_cpy (wrq.ifr_name, wext->parent.iface); if (ioctl (wext->fd, SIOCSIWMODE, &wrq) < 0) { if (errno != ENODEV) { nm_log_err (LOGD_PLATFORM | LOGD_WIFI, "(%s): error setting mode %d", wext->parent.iface, mode); } return FALSE; } return TRUE; }