Home | History | Annotate | Line # | Download | only in drivers
      1 /*
      2  * Linux ioctl helper functions for driver wrappers
      3  * Copyright (c) 2002-2010, Jouni Malinen <j (at) 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