Home | History | Annotate | 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 
    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