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 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 
     28 	if (sock < 0)
     29 		return -1;
     30 
     31 	os_memset(&ifr, 0, sizeof(ifr));
     32 	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
     33 
     34 	if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
     35 		wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
     36 			   ifname, strerror(errno));
     37 		return -1;
     38 	}
     39 
     40 	if (dev_up) {
     41 		if (ifr.ifr_flags & IFF_UP)
     42 			return 0;
     43 		ifr.ifr_flags |= IFF_UP;
     44 	} else {
     45 		if (!(ifr.ifr_flags & IFF_UP))
     46 			return 0;
     47 		ifr.ifr_flags &= ~IFF_UP;
     48 	}
     49 
     50 	if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) {
     51 		wpa_printf(MSG_ERROR, "Could not set interface %s flags: %s",
     52 			   ifname, strerror(errno));
     53 		return -1;
     54 	}
     55 
     56 	return 0;
     57 }
     58 
     59 
     60 int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr)
     61 {
     62 	struct ifreq ifr;
     63 
     64 	os_memset(&ifr, 0, sizeof(ifr));
     65 	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
     66 	if (ioctl(sock, SIOCGIFHWADDR, &ifr)) {
     67 		wpa_printf(MSG_ERROR, "Could not get interface %s hwaddr: %s",
     68 			   ifname, strerror(errno));
     69 		return -1;
     70 	}
     71 
     72 	if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
     73 		wpa_printf(MSG_ERROR, "%s: Invalid HW-addr family 0x%04x",
     74 			   ifname, ifr.ifr_hwaddr.sa_family);
     75 		return -1;
     76 	}
     77 	os_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
     78 
     79 	return 0;
     80 }
     81 
     82 
     83 int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr)
     84 {
     85 	struct ifreq ifr;
     86 
     87 	os_memset(&ifr, 0, sizeof(ifr));
     88 	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
     89 	os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
     90 	ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
     91 
     92 	if (ioctl(sock, SIOCSIFHWADDR, &ifr)) {
     93 		wpa_printf(MSG_DEBUG, "Could not set interface %s hwaddr: %s",
     94 			   ifname, strerror(errno));
     95 		return -1;
     96 	}
     97 
     98 	return 0;
     99 }
    100 
    101 
    102 #ifndef SIOCBRADDBR
    103 #define SIOCBRADDBR 0x89a0
    104 #endif
    105 #ifndef SIOCBRDELBR
    106 #define SIOCBRDELBR 0x89a1
    107 #endif
    108 #ifndef SIOCBRADDIF
    109 #define SIOCBRADDIF 0x89a2
    110 #endif
    111 #ifndef SIOCBRDELIF
    112 #define SIOCBRDELIF 0x89a3
    113 #endif
    114 
    115 
    116 int linux_br_add(int sock, const char *brname)
    117 {
    118 	if (ioctl(sock, SIOCBRADDBR, brname) < 0) {
    119 		wpa_printf(MSG_DEBUG, "Could not add bridge %s: %s",
    120 			   brname, strerror(errno));
    121 		return -1;
    122 	}
    123 
    124 	return 0;
    125 }
    126 
    127 
    128 int linux_br_del(int sock, const char *brname)
    129 {
    130 	if (ioctl(sock, SIOCBRDELBR, brname) < 0) {
    131 		wpa_printf(MSG_DEBUG, "Could not remove bridge %s: %s",
    132 			   brname, strerror(errno));
    133 		return -1;
    134 	}
    135 
    136 	return 0;
    137 }
    138 
    139 
    140 int linux_br_add_if(int sock, const char *brname, const char *ifname)
    141 {
    142 	struct ifreq ifr;
    143 	int ifindex;
    144 
    145 	ifindex = if_nametoindex(ifname);
    146 	if (ifindex == 0)
    147 		return -1;
    148 
    149 	os_memset(&ifr, 0, sizeof(ifr));
    150 	os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
    151 	ifr.ifr_ifindex = ifindex;
    152 	if (ioctl(sock, SIOCBRADDIF, &ifr) < 0) {
    153 		wpa_printf(MSG_DEBUG, "Could not add interface %s into bridge "
    154 			   "%s: %s", ifname, brname, strerror(errno));
    155 		return -1;
    156 	}
    157 
    158 	return 0;
    159 }
    160 
    161 
    162 int linux_br_del_if(int sock, const char *brname, const char *ifname)
    163 {
    164 	struct ifreq ifr;
    165 	int ifindex;
    166 
    167 	ifindex = if_nametoindex(ifname);
    168 	if (ifindex == 0)
    169 		return -1;
    170 
    171 	os_memset(&ifr, 0, sizeof(ifr));
    172 	os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
    173 	ifr.ifr_ifindex = ifindex;
    174 	if (ioctl(sock, SIOCBRDELIF, &ifr) < 0) {
    175 		wpa_printf(MSG_DEBUG, "Could not remove interface %s from "
    176 			   "bridge %s: %s", ifname, brname, strerror(errno));
    177 		return -1;
    178 	}
    179 
    180 	return 0;
    181 }
    182 
    183 
    184 int linux_br_get(char *brname, const char *ifname)
    185 {
    186 	char path[128], brlink[128], *pos;
    187 	os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/bridge",
    188 		    ifname);
    189 	os_memset(brlink, 0, sizeof(brlink));
    190 	if (readlink(path, brlink, sizeof(brlink) - 1) < 0)
    191 		return -1;
    192 	pos = os_strrchr(brlink, '/');
    193 	if (pos == NULL)
    194 		return -1;
    195 	pos++;
    196 	os_strlcpy(brname, pos, IFNAMSIZ);
    197 	return 0;
    198 }
    199