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 "linux_ioctl.h"
     16 
     17 
     18 int 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 
     58 int 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 
     80 int 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 
    103 int 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 
    136 int 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 
    148 int 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 
    160 int 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 
    182 int 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 
    204 int 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