164 lines
3.9 KiB
C
164 lines
3.9 KiB
C
|
/*
|
||
|
* 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;
|
||
|
}
|