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 165 wpa_printf(MSG_DEBUG, "Could not add interface %s into bridge " 166 "%s: %s", ifname, brname, strerror(errno)); 167 errno = saved_errno; 168 return -1; 169 } 170 171 return 0; 172 } 173 174 175 int linux_br_del_if(int sock, const char *brname, const char *ifname) 176 { 177 struct ifreq ifr; 178 int ifindex; 179 180 ifindex = if_nametoindex(ifname); 181 if (ifindex == 0) 182 return -1; 183 184 os_memset(&ifr, 0, sizeof(ifr)); 185 os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ); 186 ifr.ifr_ifindex = ifindex; 187 if (ioctl(sock, SIOCBRDELIF, &ifr) < 0) { 188 wpa_printf(MSG_DEBUG, "Could not remove interface %s from " 189 "bridge %s: %s", ifname, brname, strerror(errno)); 190 return -1; 191 } 192 193 return 0; 194 } 195 196 197 int linux_br_get(char *brname, const char *ifname) 198 { 199 char path[128], brlink[128], *pos; 200 ssize_t res; 201 202 os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/bridge", 203 ifname); 204 res = readlink(path, brlink, sizeof(brlink)); 205 if (res < 0 || (size_t) res >= sizeof(brlink)) 206 return -1; 207 brlink[res] = '\0'; 208 pos = os_strrchr(brlink, '/'); 209 if (pos == NULL) 210 return -1; 211 pos++; 212 os_strlcpy(brname, pos, IFNAMSIZ); 213 return 0; 214 } 215 216 217 int linux_master_get(char *master_ifname, const char *ifname) 218 { 219 char buf[128], masterlink[128], *pos; 220 ssize_t res; 221 222 /* check whether there is a master */ 223 os_snprintf(buf, sizeof(buf), "/sys/class/net/%s/master", ifname); 224 225 res = readlink(buf, masterlink, sizeof(masterlink)); 226 if (res < 0 || (size_t) res >= sizeof(masterlink)) 227 return -1; 228 229 masterlink[res] = '\0'; 230 231 pos = os_strrchr(masterlink, '/'); 232 if (pos == NULL) 233 return -1; 234 pos++; 235 os_strlcpy(master_ifname, pos, IFNAMSIZ); 236 return 0; 237 } 238