hostapd/src/ap/vlan_ioctl.c

164 lines
3.9 KiB
C
Raw Normal View History

/*
* hostapd / VLAN ioctl API
* Copyright 2003, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
#include <sys/ioctl.h>
#include <linux/sockios.h>
#include <linux/if_vlan.h>
#include "utils/common.h"
#include "vlan_util.h"
/*
* These are only available in recent linux headers (without the leading
* underscore).
*/
#define _GET_VLAN_REALDEV_NAME_CMD 8
#define _GET_VLAN_VID_CMD 9
int vlan_rem(const char *if_name)
{
int fd;
struct vlan_ioctl_args if_request;
wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
if_name);
return -1;
}
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
"failed: %s", __func__, strerror(errno));
return -1;
}
os_memset(&if_request, 0, sizeof(if_request));
os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
if_request.cmd = DEL_VLAN_CMD;
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
"%s", __func__, if_name, strerror(errno));
close(fd);
return -1;
}
close(fd);
return 0;
}
/*
Add a vlan interface with VLAN ID 'vid' and tagged interface
'if_name'.
returns -1 on error
returns 1 if the interface already exists
returns 0 otherwise
*/
int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
{
int fd;
struct vlan_ioctl_args if_request;
wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
if_name, vid);
ifconfig_up(if_name);
if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
if_name);
return -1;
}
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
"failed: %s", __func__, strerror(errno));
return -1;
}
os_memset(&if_request, 0, sizeof(if_request));
/* Determine if a suitable vlan device already exists. */
os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
vid);
if_request.cmd = _GET_VLAN_VID_CMD;
if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
if_request.u.VID == vid) {
if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD;
if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
os_strncmp(if_request.u.device2, if_name,
sizeof(if_request.u.device2)) == 0) {
close(fd);
wpa_printf(MSG_DEBUG,
"VLAN: vlan_add: if_name %s exists already",
if_request.device1);
return 1;
}
}
/* A suitable vlan device does not already exist, add one. */
os_memset(&if_request, 0, sizeof(if_request));
os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
if_request.u.VID = vid;
if_request.cmd = ADD_VLAN_CMD;
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
wpa_printf(MSG_ERROR,
"VLAN: %s: ADD_VLAN_CMD failed for %s: %s",
__func__, if_request.device1, strerror(errno));
close(fd);
return -1;
}
close(fd);
return 0;
}
int vlan_set_name_type(unsigned int name_type)
{
int fd;
struct vlan_ioctl_args if_request;
wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
name_type);
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
wpa_printf(MSG_ERROR,
"VLAN: %s: socket(AF_INET,SOCK_STREAM) failed: %s",
__func__, strerror(errno));
return -1;
}
os_memset(&if_request, 0, sizeof(if_request));
if_request.u.name_type = name_type;
if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
wpa_printf(MSG_ERROR,
"VLAN: %s: SET_VLAN_NAME_TYPE_CMD name_type=%u failed: %s",
__func__, name_type, strerror(errno));
close(fd);
return -1;
}
close(fd);
return 0;
}