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