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