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