hostapd/src/drivers/linux_ioctl.c
Jouni Malinen 94627f6cc8 hostapd: Detect bridge interface automatically
This makes the bridge parameter unnecessary for cases where the interface
is already in a bridge and sysfs is mounted to /sys so that the detection
code works.

For nl80211, the bridge parameter can be used to request the AP
interface to be added to the bridge automatically (brctl may refuse to
do this before hostapd has been started to change the interface mode).
If needed, the bridge interface is also created.
2010-01-16 15:19:58 +02:00

197 lines
4.1 KiB
C

/*
* Linux ioctl helper functions for driver wrappers
* Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/if_arp.h>
#include "utils/common.h"
#include "linux_ioctl.h"
int linux_set_iface_flags(int sock, const char *ifname, int dev_up)
{
struct ifreq ifr;
if (sock < 0)
return -1;
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
ifname, strerror(errno));
return -1;
}
if (dev_up) {
if (ifr.ifr_flags & IFF_UP)
return 0;
ifr.ifr_flags |= IFF_UP;
} else {
if (!(ifr.ifr_flags & IFF_UP))
return 0;
ifr.ifr_flags &= ~IFF_UP;
}
if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) {
wpa_printf(MSG_ERROR, "Could not set interface %s flags: %s",
ifname, strerror(errno));
return -1;
}
return 0;
}
int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr)
{
struct ifreq ifr;
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(sock, SIOCGIFHWADDR, &ifr)) {
wpa_printf(MSG_ERROR, "Could not get interface %s hwaddr: %s",
ifname, strerror(errno));
return -1;
}
if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
wpa_printf(MSG_ERROR, "%s: Invalid HW-addr family 0x%04x",
ifname, ifr.ifr_hwaddr.sa_family);
return -1;
}
os_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
return 0;
}
int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr)
{
struct ifreq ifr;
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
if (ioctl(sock, SIOCSIFHWADDR, &ifr)) {
wpa_printf(MSG_DEBUG, "Could not set interface %s hwaddr: %s",
ifname, strerror(errno));
return -1;
}
return 0;
}
#ifndef SIOCBRADDBR
#define SIOCBRADDBR 0x89a0
#endif
#ifndef SIOCBRDELBR
#define SIOCBRDELBR 0x89a1
#endif
#ifndef SIOCBRADDIF
#define SIOCBRADDIF 0x89a2
#endif
#ifndef SIOCBRDELIF
#define SIOCBRDELIF 0x89a3
#endif
int linux_br_add(int sock, const char *brname)
{
if (ioctl(sock, SIOCBRADDBR, brname) < 0) {
wpa_printf(MSG_DEBUG, "Could not add bridge %s: %s",
brname, strerror(errno));
return -1;
}
return 0;
}
int linux_br_del(int sock, const char *brname)
{
if (ioctl(sock, SIOCBRDELBR, brname) < 0) {
wpa_printf(MSG_DEBUG, "Could not remove bridge %s: %s",
brname, strerror(errno));
return -1;
}
return 0;
}
int linux_br_add_if(int sock, const char *brname, const char *ifname)
{
struct ifreq ifr;
int ifindex;
ifindex = if_nametoindex(ifname);
if (ifindex == 0)
return -1;
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
ifr.ifr_ifindex = ifindex;
if (ioctl(sock, SIOCBRADDIF, &ifr) < 0) {
wpa_printf(MSG_DEBUG, "Could not add interface %s into bridge "
"%s: %s", ifname, brname, strerror(errno));
return -1;
}
return 0;
}
int linux_br_del_if(int sock, const char *brname, const char *ifname)
{
struct ifreq ifr;
int ifindex;
ifindex = if_nametoindex(ifname);
if (ifindex == 0)
return -1;
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
ifr.ifr_ifindex = ifindex;
if (ioctl(sock, SIOCBRDELIF, &ifr) < 0) {
wpa_printf(MSG_DEBUG, "Could not remove interface %s from "
"bridge %s: %s", ifname, brname, strerror(errno));
return -1;
}
return 0;
}
int linux_br_get(char *brname, const char *ifname)
{
char path[128], brlink[128], *pos;
os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/bridge",
ifname);
if (readlink(path, brlink, sizeof(brlink)) < 0)
return -1;
pos = os_strrchr(brlink, '/');
if (pos == NULL)
return -1;
pos++;
os_strlcpy(brname, pos, IFNAMSIZ);
return 0;
}