1e5b75505Sopenharmony_ci/* 2e5b75505Sopenharmony_ci * Linux ioctl helper functions for driver wrappers 3e5b75505Sopenharmony_ci * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi> 4e5b75505Sopenharmony_ci * 5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license. 6e5b75505Sopenharmony_ci * See README for more details. 7e5b75505Sopenharmony_ci */ 8e5b75505Sopenharmony_ci 9e5b75505Sopenharmony_ci#include "utils/includes.h" 10e5b75505Sopenharmony_ci#include <sys/ioctl.h> 11e5b75505Sopenharmony_ci#include <net/if.h> 12e5b75505Sopenharmony_ci#include <net/if_arp.h> 13e5b75505Sopenharmony_ci 14e5b75505Sopenharmony_ci#include "utils/common.h" 15e5b75505Sopenharmony_ci#include "common/linux_bridge.h" 16e5b75505Sopenharmony_ci#include "linux_ioctl.h" 17e5b75505Sopenharmony_ci 18e5b75505Sopenharmony_ci 19e5b75505Sopenharmony_ciint linux_set_iface_flags(int sock, const char *ifname, int dev_up) 20e5b75505Sopenharmony_ci{ 21e5b75505Sopenharmony_ci struct ifreq ifr; 22e5b75505Sopenharmony_ci int ret; 23e5b75505Sopenharmony_ci 24e5b75505Sopenharmony_ci if (sock < 0) 25e5b75505Sopenharmony_ci return -1; 26e5b75505Sopenharmony_ci 27e5b75505Sopenharmony_ci os_memset(&ifr, 0, sizeof(ifr)); 28e5b75505Sopenharmony_ci os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); 29e5b75505Sopenharmony_ci 30e5b75505Sopenharmony_ci if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) { 31e5b75505Sopenharmony_ci ret = errno ? -errno : -999; 32e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s", 33e5b75505Sopenharmony_ci ifname, strerror(errno)); 34e5b75505Sopenharmony_ci return ret; 35e5b75505Sopenharmony_ci } 36e5b75505Sopenharmony_ci 37e5b75505Sopenharmony_ci if (dev_up) { 38e5b75505Sopenharmony_ci if (ifr.ifr_flags & IFF_UP) 39e5b75505Sopenharmony_ci return 0; 40e5b75505Sopenharmony_ci ifr.ifr_flags |= IFF_UP; 41e5b75505Sopenharmony_ci } else { 42e5b75505Sopenharmony_ci if (!(ifr.ifr_flags & IFF_UP)) 43e5b75505Sopenharmony_ci return 0; 44e5b75505Sopenharmony_ci ifr.ifr_flags &= ~IFF_UP; 45e5b75505Sopenharmony_ci } 46e5b75505Sopenharmony_ci 47e5b75505Sopenharmony_ci if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) { 48e5b75505Sopenharmony_ci ret = errno ? -errno : -999; 49e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not set interface %s flags (%s): " 50e5b75505Sopenharmony_ci "%s", 51e5b75505Sopenharmony_ci ifname, dev_up ? "UP" : "DOWN", strerror(errno)); 52e5b75505Sopenharmony_ci return ret; 53e5b75505Sopenharmony_ci } 54e5b75505Sopenharmony_ci 55e5b75505Sopenharmony_ci return 0; 56e5b75505Sopenharmony_ci} 57e5b75505Sopenharmony_ci 58e5b75505Sopenharmony_ci 59e5b75505Sopenharmony_ciint linux_iface_up(int sock, const char *ifname) 60e5b75505Sopenharmony_ci{ 61e5b75505Sopenharmony_ci struct ifreq ifr; 62e5b75505Sopenharmony_ci int ret; 63e5b75505Sopenharmony_ci 64e5b75505Sopenharmony_ci if (sock < 0) 65e5b75505Sopenharmony_ci return -1; 66e5b75505Sopenharmony_ci 67e5b75505Sopenharmony_ci os_memset(&ifr, 0, sizeof(ifr)); 68e5b75505Sopenharmony_ci os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); 69e5b75505Sopenharmony_ci 70e5b75505Sopenharmony_ci if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) { 71e5b75505Sopenharmony_ci ret = errno ? -errno : -999; 72e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s", 73e5b75505Sopenharmony_ci ifname, strerror(errno)); 74e5b75505Sopenharmony_ci return ret; 75e5b75505Sopenharmony_ci } 76e5b75505Sopenharmony_ci 77e5b75505Sopenharmony_ci return !!(ifr.ifr_flags & IFF_UP); 78e5b75505Sopenharmony_ci} 79e5b75505Sopenharmony_ci 80e5b75505Sopenharmony_ci 81e5b75505Sopenharmony_ciint linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr) 82e5b75505Sopenharmony_ci{ 83e5b75505Sopenharmony_ci struct ifreq ifr; 84e5b75505Sopenharmony_ci 85e5b75505Sopenharmony_ci os_memset(&ifr, 0, sizeof(ifr)); 86e5b75505Sopenharmony_ci os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); 87e5b75505Sopenharmony_ci if (ioctl(sock, SIOCGIFHWADDR, &ifr)) { 88e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not get interface %s hwaddr: %s", 89e5b75505Sopenharmony_ci ifname, strerror(errno)); 90e5b75505Sopenharmony_ci return -1; 91e5b75505Sopenharmony_ci } 92e5b75505Sopenharmony_ci 93e5b75505Sopenharmony_ci if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { 94e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "%s: Invalid HW-addr family 0x%04x", 95e5b75505Sopenharmony_ci ifname, ifr.ifr_hwaddr.sa_family); 96e5b75505Sopenharmony_ci return -1; 97e5b75505Sopenharmony_ci } 98e5b75505Sopenharmony_ci os_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); 99e5b75505Sopenharmony_ci 100e5b75505Sopenharmony_ci return 0; 101e5b75505Sopenharmony_ci} 102e5b75505Sopenharmony_ci 103e5b75505Sopenharmony_ci 104e5b75505Sopenharmony_ciint linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr) 105e5b75505Sopenharmony_ci{ 106e5b75505Sopenharmony_ci struct ifreq ifr; 107e5b75505Sopenharmony_ci 108e5b75505Sopenharmony_ci os_memset(&ifr, 0, sizeof(ifr)); 109e5b75505Sopenharmony_ci os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ); 110e5b75505Sopenharmony_ci os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN); 111e5b75505Sopenharmony_ci ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; 112e5b75505Sopenharmony_ci 113e5b75505Sopenharmony_ci if (ioctl(sock, SIOCSIFHWADDR, &ifr)) { 114e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Could not set interface %s hwaddr: %s", 115e5b75505Sopenharmony_ci ifname, strerror(errno)); 116e5b75505Sopenharmony_ci return -1; 117e5b75505Sopenharmony_ci } 118e5b75505Sopenharmony_ci 119e5b75505Sopenharmony_ci return 0; 120e5b75505Sopenharmony_ci} 121e5b75505Sopenharmony_ci 122e5b75505Sopenharmony_ci 123e5b75505Sopenharmony_ciint linux_br_add(int sock, const char *brname) 124e5b75505Sopenharmony_ci{ 125e5b75505Sopenharmony_ci if (ioctl(sock, SIOCBRADDBR, brname) < 0) { 126e5b75505Sopenharmony_ci int saved_errno = errno; 127e5b75505Sopenharmony_ci 128e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Could not add bridge %s: %s", 129e5b75505Sopenharmony_ci brname, strerror(errno)); 130e5b75505Sopenharmony_ci errno = saved_errno; 131e5b75505Sopenharmony_ci return -1; 132e5b75505Sopenharmony_ci } 133e5b75505Sopenharmony_ci 134e5b75505Sopenharmony_ci return 0; 135e5b75505Sopenharmony_ci} 136e5b75505Sopenharmony_ci 137e5b75505Sopenharmony_ci 138e5b75505Sopenharmony_ciint linux_br_del(int sock, const char *brname) 139e5b75505Sopenharmony_ci{ 140e5b75505Sopenharmony_ci if (ioctl(sock, SIOCBRDELBR, brname) < 0) { 141e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Could not remove bridge %s: %s", 142e5b75505Sopenharmony_ci brname, strerror(errno)); 143e5b75505Sopenharmony_ci return -1; 144e5b75505Sopenharmony_ci } 145e5b75505Sopenharmony_ci 146e5b75505Sopenharmony_ci return 0; 147e5b75505Sopenharmony_ci} 148e5b75505Sopenharmony_ci 149e5b75505Sopenharmony_ci 150e5b75505Sopenharmony_ciint linux_br_add_if(int sock, const char *brname, const char *ifname) 151e5b75505Sopenharmony_ci{ 152e5b75505Sopenharmony_ci struct ifreq ifr; 153e5b75505Sopenharmony_ci int ifindex; 154e5b75505Sopenharmony_ci 155e5b75505Sopenharmony_ci ifindex = if_nametoindex(ifname); 156e5b75505Sopenharmony_ci if (ifindex == 0) 157e5b75505Sopenharmony_ci return -1; 158e5b75505Sopenharmony_ci 159e5b75505Sopenharmony_ci os_memset(&ifr, 0, sizeof(ifr)); 160e5b75505Sopenharmony_ci os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ); 161e5b75505Sopenharmony_ci ifr.ifr_ifindex = ifindex; 162e5b75505Sopenharmony_ci if (ioctl(sock, SIOCBRADDIF, &ifr) < 0) { 163e5b75505Sopenharmony_ci int saved_errno = errno; 164e5b75505Sopenharmony_ci 165e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Could not add interface %s into bridge " 166e5b75505Sopenharmony_ci "%s: %s", ifname, brname, strerror(errno)); 167e5b75505Sopenharmony_ci errno = saved_errno; 168e5b75505Sopenharmony_ci return -1; 169e5b75505Sopenharmony_ci } 170e5b75505Sopenharmony_ci 171e5b75505Sopenharmony_ci return 0; 172e5b75505Sopenharmony_ci} 173e5b75505Sopenharmony_ci 174e5b75505Sopenharmony_ci 175e5b75505Sopenharmony_ciint linux_br_del_if(int sock, const char *brname, const char *ifname) 176e5b75505Sopenharmony_ci{ 177e5b75505Sopenharmony_ci struct ifreq ifr; 178e5b75505Sopenharmony_ci int ifindex; 179e5b75505Sopenharmony_ci 180e5b75505Sopenharmony_ci ifindex = if_nametoindex(ifname); 181e5b75505Sopenharmony_ci if (ifindex == 0) 182e5b75505Sopenharmony_ci return -1; 183e5b75505Sopenharmony_ci 184e5b75505Sopenharmony_ci os_memset(&ifr, 0, sizeof(ifr)); 185e5b75505Sopenharmony_ci os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ); 186e5b75505Sopenharmony_ci ifr.ifr_ifindex = ifindex; 187e5b75505Sopenharmony_ci if (ioctl(sock, SIOCBRDELIF, &ifr) < 0) { 188e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Could not remove interface %s from " 189e5b75505Sopenharmony_ci "bridge %s: %s", ifname, brname, strerror(errno)); 190e5b75505Sopenharmony_ci return -1; 191e5b75505Sopenharmony_ci } 192e5b75505Sopenharmony_ci 193e5b75505Sopenharmony_ci return 0; 194e5b75505Sopenharmony_ci} 195e5b75505Sopenharmony_ci 196e5b75505Sopenharmony_ci 197e5b75505Sopenharmony_ciint linux_br_get(char *brname, const char *ifname) 198e5b75505Sopenharmony_ci{ 199e5b75505Sopenharmony_ci char path[128], brlink[128], *pos; 200e5b75505Sopenharmony_ci ssize_t res; 201e5b75505Sopenharmony_ci 202e5b75505Sopenharmony_ci os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/bridge", 203e5b75505Sopenharmony_ci ifname); 204e5b75505Sopenharmony_ci res = readlink(path, brlink, sizeof(brlink)); 205e5b75505Sopenharmony_ci if (res < 0 || (size_t) res >= sizeof(brlink)) 206e5b75505Sopenharmony_ci return -1; 207e5b75505Sopenharmony_ci brlink[res] = '\0'; 208e5b75505Sopenharmony_ci pos = os_strrchr(brlink, '/'); 209e5b75505Sopenharmony_ci if (pos == NULL) 210e5b75505Sopenharmony_ci return -1; 211e5b75505Sopenharmony_ci pos++; 212e5b75505Sopenharmony_ci os_strlcpy(brname, pos, IFNAMSIZ); 213e5b75505Sopenharmony_ci return 0; 214e5b75505Sopenharmony_ci} 215e5b75505Sopenharmony_ci 216e5b75505Sopenharmony_ci 217e5b75505Sopenharmony_ciint linux_master_get(char *master_ifname, const char *ifname) 218e5b75505Sopenharmony_ci{ 219e5b75505Sopenharmony_ci char buf[128], masterlink[128], *pos; 220e5b75505Sopenharmony_ci ssize_t res; 221e5b75505Sopenharmony_ci 222e5b75505Sopenharmony_ci /* check whether there is a master */ 223e5b75505Sopenharmony_ci os_snprintf(buf, sizeof(buf), "/sys/class/net/%s/master", ifname); 224e5b75505Sopenharmony_ci 225e5b75505Sopenharmony_ci res = readlink(buf, masterlink, sizeof(masterlink)); 226e5b75505Sopenharmony_ci if (res < 0 || (size_t) res >= sizeof(masterlink)) 227e5b75505Sopenharmony_ci return -1; 228e5b75505Sopenharmony_ci 229e5b75505Sopenharmony_ci masterlink[res] = '\0'; 230e5b75505Sopenharmony_ci 231e5b75505Sopenharmony_ci pos = os_strrchr(masterlink, '/'); 232e5b75505Sopenharmony_ci if (pos == NULL) 233e5b75505Sopenharmony_ci return -1; 234e5b75505Sopenharmony_ci pos++; 235e5b75505Sopenharmony_ci os_strlcpy(master_ifname, pos, IFNAMSIZ); 236e5b75505Sopenharmony_ci return 0; 237e5b75505Sopenharmony_ci} 238