1324714Scy/* 2324714Scy * hostapd / VLAN ioctl API 3324714Scy * Copyright 2003, Instant802 Networks, Inc. 4324714Scy * Copyright 2005-2006, Devicescape Software, Inc. 5324714Scy * Copyright (c) 2009, Jouni Malinen <j@w1.fi> 6324714Scy * 7324714Scy * This software may be distributed under the terms of the BSD license. 8324714Scy * See README for more details. 9324714Scy */ 10324714Scy 11324714Scy#include "utils/includes.h" 12324714Scy#include <sys/ioctl.h> 13324714Scy 14324714Scy#include "utils/common.h" 15324714Scy#include "common/linux_vlan.h" 16324714Scy#include "vlan_util.h" 17324714Scy 18324714Scy 19324714Scyint vlan_rem(const char *if_name) 20324714Scy{ 21324714Scy int fd; 22324714Scy struct vlan_ioctl_args if_request; 23324714Scy 24324714Scy wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name); 25324714Scy if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) { 26324714Scy wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", 27324714Scy if_name); 28324714Scy return -1; 29324714Scy } 30324714Scy 31324714Scy if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 32324714Scy wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " 33324714Scy "failed: %s", __func__, strerror(errno)); 34324714Scy return -1; 35324714Scy } 36324714Scy 37324714Scy os_memset(&if_request, 0, sizeof(if_request)); 38324714Scy 39324714Scy os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1)); 40324714Scy if_request.cmd = DEL_VLAN_CMD; 41324714Scy 42324714Scy if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { 43324714Scy wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: " 44324714Scy "%s", __func__, if_name, strerror(errno)); 45324714Scy close(fd); 46324714Scy return -1; 47324714Scy } 48324714Scy 49324714Scy close(fd); 50324714Scy return 0; 51324714Scy} 52324714Scy 53324714Scy 54324714Scy/* 55324714Scy Add a vlan interface with VLAN ID 'vid' and tagged interface 56324714Scy 'if_name'. 57324714Scy 58324714Scy returns -1 on error 59324714Scy returns 1 if the interface already exists 60324714Scy returns 0 otherwise 61324714Scy*/ 62324714Scyint vlan_add(const char *if_name, int vid, const char *vlan_if_name) 63324714Scy{ 64324714Scy int fd; 65324714Scy struct vlan_ioctl_args if_request; 66324714Scy 67324714Scy wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)", 68324714Scy if_name, vid); 69324714Scy ifconfig_up(if_name); 70324714Scy 71324714Scy if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) { 72324714Scy wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'", 73324714Scy if_name); 74324714Scy return -1; 75324714Scy } 76324714Scy 77324714Scy if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 78324714Scy wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) " 79324714Scy "failed: %s", __func__, strerror(errno)); 80324714Scy return -1; 81324714Scy } 82324714Scy 83324714Scy os_memset(&if_request, 0, sizeof(if_request)); 84324714Scy 85324714Scy /* Determine if a suitable vlan device already exists. */ 86324714Scy 87324714Scy os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d", 88324714Scy vid); 89324714Scy 90324714Scy if_request.cmd = GET_VLAN_VID_CMD; 91324714Scy 92324714Scy if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 && 93324714Scy if_request.u.VID == vid) { 94324714Scy if_request.cmd = GET_VLAN_REALDEV_NAME_CMD; 95324714Scy 96324714Scy if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 && 97324714Scy os_strncmp(if_request.u.device2, if_name, 98324714Scy sizeof(if_request.u.device2)) == 0) { 99324714Scy close(fd); 100324714Scy wpa_printf(MSG_DEBUG, 101324714Scy "VLAN: vlan_add: if_name %s exists already", 102324714Scy if_request.device1); 103324714Scy return 1; 104324714Scy } 105324714Scy } 106324714Scy 107324714Scy /* A suitable vlan device does not already exist, add one. */ 108324714Scy 109324714Scy os_memset(&if_request, 0, sizeof(if_request)); 110324714Scy os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1)); 111324714Scy if_request.u.VID = vid; 112324714Scy if_request.cmd = ADD_VLAN_CMD; 113324714Scy 114324714Scy if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { 115324714Scy wpa_printf(MSG_ERROR, 116324714Scy "VLAN: %s: ADD_VLAN_CMD failed for %s: %s", 117324714Scy __func__, if_request.device1, strerror(errno)); 118324714Scy close(fd); 119324714Scy return -1; 120324714Scy } 121324714Scy 122324714Scy close(fd); 123324714Scy return 0; 124324714Scy} 125324714Scy 126324714Scy 127324714Scyint vlan_set_name_type(unsigned int name_type) 128324714Scy{ 129324714Scy int fd; 130324714Scy struct vlan_ioctl_args if_request; 131324714Scy 132324714Scy wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)", 133324714Scy name_type); 134324714Scy if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 135324714Scy wpa_printf(MSG_ERROR, 136324714Scy "VLAN: %s: socket(AF_INET,SOCK_STREAM) failed: %s", 137324714Scy __func__, strerror(errno)); 138324714Scy return -1; 139324714Scy } 140324714Scy 141324714Scy os_memset(&if_request, 0, sizeof(if_request)); 142324714Scy 143324714Scy if_request.u.name_type = name_type; 144324714Scy if_request.cmd = SET_VLAN_NAME_TYPE_CMD; 145324714Scy if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) { 146324714Scy wpa_printf(MSG_ERROR, 147324714Scy "VLAN: %s: SET_VLAN_NAME_TYPE_CMD name_type=%u failed: %s", 148324714Scy __func__, name_type, strerror(errno)); 149324714Scy close(fd); 150324714Scy return -1; 151324714Scy } 152324714Scy 153324714Scy close(fd); 154324714Scy return 0; 155324714Scy} 156