13ff40c12SJohn Marino /*
23ff40c12SJohn Marino * Linux ioctl helper functions for driver wrappers
33ff40c12SJohn Marino * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
43ff40c12SJohn Marino *
53ff40c12SJohn Marino * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino * See README for more details.
73ff40c12SJohn Marino */
83ff40c12SJohn Marino
93ff40c12SJohn Marino #include "utils/includes.h"
103ff40c12SJohn Marino #include <sys/ioctl.h>
113ff40c12SJohn Marino #include <net/if.h>
123ff40c12SJohn Marino #include <net/if_arp.h>
133ff40c12SJohn Marino
143ff40c12SJohn Marino #include "utils/common.h"
15*a1157835SDaniel Fojt #include "common/linux_bridge.h"
163ff40c12SJohn Marino #include "linux_ioctl.h"
173ff40c12SJohn Marino
183ff40c12SJohn Marino
linux_set_iface_flags(int sock,const char * ifname,int dev_up)193ff40c12SJohn Marino int linux_set_iface_flags(int sock, const char *ifname, int dev_up)
203ff40c12SJohn Marino {
213ff40c12SJohn Marino struct ifreq ifr;
223ff40c12SJohn Marino int ret;
233ff40c12SJohn Marino
243ff40c12SJohn Marino if (sock < 0)
253ff40c12SJohn Marino return -1;
263ff40c12SJohn Marino
273ff40c12SJohn Marino os_memset(&ifr, 0, sizeof(ifr));
283ff40c12SJohn Marino os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
293ff40c12SJohn Marino
303ff40c12SJohn Marino if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
313ff40c12SJohn Marino ret = errno ? -errno : -999;
323ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
333ff40c12SJohn Marino ifname, strerror(errno));
343ff40c12SJohn Marino return ret;
353ff40c12SJohn Marino }
363ff40c12SJohn Marino
373ff40c12SJohn Marino if (dev_up) {
383ff40c12SJohn Marino if (ifr.ifr_flags & IFF_UP)
393ff40c12SJohn Marino return 0;
403ff40c12SJohn Marino ifr.ifr_flags |= IFF_UP;
413ff40c12SJohn Marino } else {
423ff40c12SJohn Marino if (!(ifr.ifr_flags & IFF_UP))
433ff40c12SJohn Marino return 0;
443ff40c12SJohn Marino ifr.ifr_flags &= ~IFF_UP;
453ff40c12SJohn Marino }
463ff40c12SJohn Marino
473ff40c12SJohn Marino if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) {
483ff40c12SJohn Marino ret = errno ? -errno : -999;
493ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not set interface %s flags (%s): "
503ff40c12SJohn Marino "%s",
513ff40c12SJohn Marino ifname, dev_up ? "UP" : "DOWN", strerror(errno));
523ff40c12SJohn Marino return ret;
533ff40c12SJohn Marino }
543ff40c12SJohn Marino
553ff40c12SJohn Marino return 0;
563ff40c12SJohn Marino }
573ff40c12SJohn Marino
583ff40c12SJohn Marino
linux_iface_up(int sock,const char * ifname)593ff40c12SJohn Marino int linux_iface_up(int sock, const char *ifname)
603ff40c12SJohn Marino {
613ff40c12SJohn Marino struct ifreq ifr;
623ff40c12SJohn Marino int ret;
633ff40c12SJohn Marino
643ff40c12SJohn Marino if (sock < 0)
653ff40c12SJohn Marino return -1;
663ff40c12SJohn Marino
673ff40c12SJohn Marino os_memset(&ifr, 0, sizeof(ifr));
683ff40c12SJohn Marino os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
693ff40c12SJohn Marino
703ff40c12SJohn Marino if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
713ff40c12SJohn Marino ret = errno ? -errno : -999;
723ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
733ff40c12SJohn Marino ifname, strerror(errno));
743ff40c12SJohn Marino return ret;
753ff40c12SJohn Marino }
763ff40c12SJohn Marino
773ff40c12SJohn Marino return !!(ifr.ifr_flags & IFF_UP);
783ff40c12SJohn Marino }
793ff40c12SJohn Marino
803ff40c12SJohn Marino
linux_get_ifhwaddr(int sock,const char * ifname,u8 * addr)813ff40c12SJohn Marino int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr)
823ff40c12SJohn Marino {
833ff40c12SJohn Marino struct ifreq ifr;
843ff40c12SJohn Marino
853ff40c12SJohn Marino os_memset(&ifr, 0, sizeof(ifr));
863ff40c12SJohn Marino os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
873ff40c12SJohn Marino if (ioctl(sock, SIOCGIFHWADDR, &ifr)) {
883ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Could not get interface %s hwaddr: %s",
893ff40c12SJohn Marino ifname, strerror(errno));
903ff40c12SJohn Marino return -1;
913ff40c12SJohn Marino }
923ff40c12SJohn Marino
933ff40c12SJohn Marino if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
943ff40c12SJohn Marino wpa_printf(MSG_ERROR, "%s: Invalid HW-addr family 0x%04x",
953ff40c12SJohn Marino ifname, ifr.ifr_hwaddr.sa_family);
963ff40c12SJohn Marino return -1;
973ff40c12SJohn Marino }
983ff40c12SJohn Marino os_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
993ff40c12SJohn Marino
1003ff40c12SJohn Marino return 0;
1013ff40c12SJohn Marino }
1023ff40c12SJohn Marino
1033ff40c12SJohn Marino
linux_set_ifhwaddr(int sock,const char * ifname,const u8 * addr)1043ff40c12SJohn Marino int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr)
1053ff40c12SJohn Marino {
1063ff40c12SJohn Marino struct ifreq ifr;
1073ff40c12SJohn Marino
1083ff40c12SJohn Marino os_memset(&ifr, 0, sizeof(ifr));
1093ff40c12SJohn Marino os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
1103ff40c12SJohn Marino os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
1113ff40c12SJohn Marino ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
1123ff40c12SJohn Marino
1133ff40c12SJohn Marino if (ioctl(sock, SIOCSIFHWADDR, &ifr)) {
1143ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Could not set interface %s hwaddr: %s",
1153ff40c12SJohn Marino ifname, strerror(errno));
1163ff40c12SJohn Marino return -1;
1173ff40c12SJohn Marino }
1183ff40c12SJohn Marino
1193ff40c12SJohn Marino return 0;
1203ff40c12SJohn Marino }
1213ff40c12SJohn Marino
1223ff40c12SJohn Marino
linux_br_add(int sock,const char * brname)1233ff40c12SJohn Marino int linux_br_add(int sock, const char *brname)
1243ff40c12SJohn Marino {
1253ff40c12SJohn Marino if (ioctl(sock, SIOCBRADDBR, brname) < 0) {
126*a1157835SDaniel Fojt int saved_errno = errno;
127*a1157835SDaniel Fojt
1283ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Could not add bridge %s: %s",
1293ff40c12SJohn Marino brname, strerror(errno));
130*a1157835SDaniel Fojt errno = saved_errno;
1313ff40c12SJohn Marino return -1;
1323ff40c12SJohn Marino }
1333ff40c12SJohn Marino
1343ff40c12SJohn Marino return 0;
1353ff40c12SJohn Marino }
1363ff40c12SJohn Marino
1373ff40c12SJohn Marino
linux_br_del(int sock,const char * brname)1383ff40c12SJohn Marino int linux_br_del(int sock, const char *brname)
1393ff40c12SJohn Marino {
1403ff40c12SJohn Marino if (ioctl(sock, SIOCBRDELBR, brname) < 0) {
1413ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Could not remove bridge %s: %s",
1423ff40c12SJohn Marino brname, strerror(errno));
1433ff40c12SJohn Marino return -1;
1443ff40c12SJohn Marino }
1453ff40c12SJohn Marino
1463ff40c12SJohn Marino return 0;
1473ff40c12SJohn Marino }
1483ff40c12SJohn Marino
1493ff40c12SJohn Marino
linux_br_add_if(int sock,const char * brname,const char * ifname)1503ff40c12SJohn Marino int linux_br_add_if(int sock, const char *brname, const char *ifname)
1513ff40c12SJohn Marino {
1523ff40c12SJohn Marino struct ifreq ifr;
1533ff40c12SJohn Marino int ifindex;
1543ff40c12SJohn Marino
1553ff40c12SJohn Marino ifindex = if_nametoindex(ifname);
1563ff40c12SJohn Marino if (ifindex == 0)
1573ff40c12SJohn Marino return -1;
1583ff40c12SJohn Marino
1593ff40c12SJohn Marino os_memset(&ifr, 0, sizeof(ifr));
1603ff40c12SJohn Marino os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
1613ff40c12SJohn Marino ifr.ifr_ifindex = ifindex;
1623ff40c12SJohn Marino if (ioctl(sock, SIOCBRADDIF, &ifr) < 0) {
163*a1157835SDaniel Fojt int saved_errno = errno;
164*a1157835SDaniel Fojt
1653ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Could not add interface %s into bridge "
1663ff40c12SJohn Marino "%s: %s", ifname, brname, strerror(errno));
167*a1157835SDaniel Fojt errno = saved_errno;
1683ff40c12SJohn Marino return -1;
1693ff40c12SJohn Marino }
1703ff40c12SJohn Marino
1713ff40c12SJohn Marino return 0;
1723ff40c12SJohn Marino }
1733ff40c12SJohn Marino
1743ff40c12SJohn Marino
linux_br_del_if(int sock,const char * brname,const char * ifname)1753ff40c12SJohn Marino int linux_br_del_if(int sock, const char *brname, const char *ifname)
1763ff40c12SJohn Marino {
1773ff40c12SJohn Marino struct ifreq ifr;
1783ff40c12SJohn Marino int ifindex;
1793ff40c12SJohn Marino
1803ff40c12SJohn Marino ifindex = if_nametoindex(ifname);
1813ff40c12SJohn Marino if (ifindex == 0)
1823ff40c12SJohn Marino return -1;
1833ff40c12SJohn Marino
1843ff40c12SJohn Marino os_memset(&ifr, 0, sizeof(ifr));
1853ff40c12SJohn Marino os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
1863ff40c12SJohn Marino ifr.ifr_ifindex = ifindex;
1873ff40c12SJohn Marino if (ioctl(sock, SIOCBRDELIF, &ifr) < 0) {
1883ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "Could not remove interface %s from "
1893ff40c12SJohn Marino "bridge %s: %s", ifname, brname, strerror(errno));
1903ff40c12SJohn Marino return -1;
1913ff40c12SJohn Marino }
1923ff40c12SJohn Marino
1933ff40c12SJohn Marino return 0;
1943ff40c12SJohn Marino }
1953ff40c12SJohn Marino
1963ff40c12SJohn Marino
linux_br_get(char * brname,const char * ifname)1973ff40c12SJohn Marino int linux_br_get(char *brname, const char *ifname)
1983ff40c12SJohn Marino {
1993ff40c12SJohn Marino char path[128], brlink[128], *pos;
2003ff40c12SJohn Marino ssize_t res;
2013ff40c12SJohn Marino
2023ff40c12SJohn Marino os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/bridge",
2033ff40c12SJohn Marino ifname);
2043ff40c12SJohn Marino res = readlink(path, brlink, sizeof(brlink));
2053ff40c12SJohn Marino if (res < 0 || (size_t) res >= sizeof(brlink))
2063ff40c12SJohn Marino return -1;
2073ff40c12SJohn Marino brlink[res] = '\0';
2083ff40c12SJohn Marino pos = os_strrchr(brlink, '/');
2093ff40c12SJohn Marino if (pos == NULL)
2103ff40c12SJohn Marino return -1;
2113ff40c12SJohn Marino pos++;
2123ff40c12SJohn Marino os_strlcpy(brname, pos, IFNAMSIZ);
2133ff40c12SJohn Marino return 0;
2143ff40c12SJohn Marino }
215*a1157835SDaniel Fojt
216*a1157835SDaniel Fojt
linux_master_get(char * master_ifname,const char * ifname)217*a1157835SDaniel Fojt int linux_master_get(char *master_ifname, const char *ifname)
218*a1157835SDaniel Fojt {
219*a1157835SDaniel Fojt char buf[128], masterlink[128], *pos;
220*a1157835SDaniel Fojt ssize_t res;
221*a1157835SDaniel Fojt
222*a1157835SDaniel Fojt /* check whether there is a master */
223*a1157835SDaniel Fojt os_snprintf(buf, sizeof(buf), "/sys/class/net/%s/master", ifname);
224*a1157835SDaniel Fojt
225*a1157835SDaniel Fojt res = readlink(buf, masterlink, sizeof(masterlink));
226*a1157835SDaniel Fojt if (res < 0 || (size_t) res >= sizeof(masterlink))
227*a1157835SDaniel Fojt return -1;
228*a1157835SDaniel Fojt
229*a1157835SDaniel Fojt masterlink[res] = '\0';
230*a1157835SDaniel Fojt
231*a1157835SDaniel Fojt pos = os_strrchr(masterlink, '/');
232*a1157835SDaniel Fojt if (pos == NULL)
233*a1157835SDaniel Fojt return -1;
234*a1157835SDaniel Fojt pos++;
235*a1157835SDaniel Fojt os_strlcpy(master_ifname, pos, IFNAMSIZ);
236*a1157835SDaniel Fojt return 0;
237*a1157835SDaniel Fojt }
238