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