281 lines
9.0 KiB
C
Executable File
281 lines
9.0 KiB
C
Executable File
//
|
|
//Copyright (C) 2001 Ben Greear
|
|
//
|
|
//This program is free software; you can redistribute it and/or
|
|
//modify it under the terms of the GNU Library General Public License
|
|
//as published by the Free Software Foundation; either version 2
|
|
//of the License, or (at your option) any later version.
|
|
//
|
|
//This program is distributed in the hope that it will be useful,
|
|
//but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
//GNU General Public License for more details.
|
|
//
|
|
//You should have received a copy of the GNU Library General Public License
|
|
//along with this program; if not, write to the Free Software
|
|
//Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
//
|
|
// To contact the Author, Ben Greear: greearb@candelatech.com
|
|
//
|
|
|
|
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <strings.h>
|
|
#include <sys/ioctl.h>
|
|
#include <linux/if_vlan.h>
|
|
#include <linux/sockios.h>
|
|
#include <string.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/types.h>
|
|
|
|
#define MAX_HOSTNAME 256
|
|
|
|
|
|
static char* usage =
|
|
"\n"
|
|
"Usage: add [interface-name] [vlan_id]\n"
|
|
" rem [vlan-name]\n"
|
|
" set_flag [interface-name] [flag-num] [0 | 1]\n"
|
|
" set_egress_map [vlan-name] [skb_priority] [vlan_qos]\n"
|
|
" set_ingress_map [vlan-name] [skb_priority] [vlan_qos]\n"
|
|
" set_name_type [name-type]\n"
|
|
"\n"
|
|
"* The [interface-name] is the name of the ethernet card that hosts\n"
|
|
" the VLAN you are talking about.\n"
|
|
"* The vlan_id is the identifier (0-4095) of the VLAN you are operating on.\n"
|
|
"* skb_priority is the priority in the socket buffer (sk_buff).\n"
|
|
"* vlan_qos is the 3 bit priority in the VLAN header\n"
|
|
"* name-type: VLAN_PLUS_VID (vlan0005), VLAN_PLUS_VID_NO_PAD (vlan5),\n"
|
|
" DEV_PLUS_VID (eth0.0005), DEV_PLUS_VID_NO_PAD (eth0.5)\n"
|
|
"* bind-type: PER_DEVICE # Allows vlan 5 on eth0 and eth1 to be unique.\n"
|
|
" PER_KERNEL # Forces vlan 5 to be unique across all devices.\n"
|
|
"* FLAGS: 1 REORDER_HDR When this is set, the VLAN device will move the\n"
|
|
" ethernet header around to make it look exactly like a real\n"
|
|
" ethernet device. This may help programs such as DHCPd which\n"
|
|
" read the raw ethernet packet and make assumptions about the\n"
|
|
" location of bytes. If you don't need it, don't turn it on, because\n"
|
|
" there will be at least a small performance degradation. Default\n"
|
|
" is OFF.\n";
|
|
|
|
void show_usage() {
|
|
fprintf(stdout,usage);
|
|
}
|
|
|
|
int hex_to_bytes(char* bytes, int bytes_length, char* hex_str) {
|
|
int hlen;
|
|
int i;
|
|
|
|
int j = 0;
|
|
char hex[3];
|
|
char* stop; /* not used for any real purpose */
|
|
|
|
hlen = strlen(hex_str);
|
|
|
|
hex[2] = 0;
|
|
|
|
for (i = 0; i<hlen; i++) {
|
|
|
|
hex[0] = hex_str[i];
|
|
i++;
|
|
if (i >= hlen) {
|
|
return j; /* done */
|
|
}
|
|
|
|
hex[1] = hex_str[i];
|
|
bytes[j++] = (char)strtoul(hex, &stop, 16);
|
|
}
|
|
return j;
|
|
}
|
|
|
|
|
|
int main(int argc, char** argv) {
|
|
int fd;
|
|
struct vlan_ioctl_args if_request;
|
|
|
|
char* cmd = NULL;
|
|
char* if_name = NULL;
|
|
unsigned int vid = 0;
|
|
unsigned int skb_priority;
|
|
unsigned short vlan_qos;
|
|
unsigned int nm_type = VLAN_NAME_TYPE_PLUS_VID;
|
|
|
|
char* conf_file_name = "/proc/net/vlan/config";
|
|
|
|
memset(&if_request, 0, sizeof(struct vlan_ioctl_args));
|
|
|
|
if ((argc < 3) || (argc > 5)) {
|
|
fprintf(stdout,"Expecting argc to be 3-5, inclusive. Was: %d\n",argc);
|
|
|
|
show_usage();
|
|
exit(1);
|
|
}
|
|
else {
|
|
cmd = argv[1];
|
|
|
|
if (strcasecmp(cmd, "set_name_type") == 0) {
|
|
if (strcasecmp(argv[2], "VLAN_PLUS_VID") == 0) {
|
|
nm_type = VLAN_NAME_TYPE_PLUS_VID;
|
|
}
|
|
else if (strcasecmp(argv[2], "VLAN_PLUS_VID_NO_PAD") == 0) {
|
|
nm_type = VLAN_NAME_TYPE_PLUS_VID_NO_PAD;
|
|
}
|
|
else if (strcasecmp(argv[2], "DEV_PLUS_VID") == 0) {
|
|
nm_type = VLAN_NAME_TYPE_RAW_PLUS_VID;
|
|
}
|
|
else if (strcasecmp(argv[2], "DEV_PLUS_VID_NO_PAD") == 0) {
|
|
nm_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD;
|
|
}
|
|
else {
|
|
// MATHIEU
|
|
//cerr << "Invalid name type.\n";
|
|
fprintf(stderr,"Invalid name type.\n");
|
|
|
|
show_usage();
|
|
exit(1);
|
|
}
|
|
if_request.u.name_type = nm_type;
|
|
}
|
|
else {
|
|
if_name = argv[2];
|
|
if (strlen(if_name) > 15) {
|
|
// MATHIEU
|
|
//cerr << "ERROR: if_name must be 15 characters or less." << endl;
|
|
fprintf(stderr,"ERROR: if_name must be 15 characters or less.\n");
|
|
exit(1);
|
|
}
|
|
strcpy(if_request.device1, if_name);
|
|
}
|
|
|
|
if (argc == 4) {
|
|
vid = atoi(argv[3]);
|
|
if_request.u.VID = vid;
|
|
}
|
|
|
|
if (argc == 5) {
|
|
skb_priority = atoi(argv[3]);
|
|
vlan_qos = atoi(argv[4]);
|
|
if_request.u.skb_priority = skb_priority;
|
|
if_request.vlan_qos = vlan_qos;
|
|
}
|
|
}
|
|
|
|
// Open up the /proc/vlan/config
|
|
if ((fd = open(conf_file_name, O_RDONLY)) < 0) {
|
|
// MATHIEU
|
|
//cerr << "ERROR: Could not open /proc/vlan/config.\n";
|
|
fprintf(stderr,"WARNING: Could not open /proc/net/vlan/config. Maybe you need to load the 8021q module, or maybe you are not using PROCFS??\n");
|
|
|
|
}
|
|
else {
|
|
close(fd);
|
|
}
|
|
|
|
/* We use sockets now, instead of the file descriptor */
|
|
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
|
fprintf(stderr, "FATAL: Couldn't open a socket..go figure!\n");
|
|
exit(2);
|
|
}
|
|
|
|
/* add */
|
|
if (strcasecmp(cmd, "add") == 0) {
|
|
if_request.cmd = ADD_VLAN_CMD;
|
|
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
|
|
fprintf(stderr,"ERROR: trying to add VLAN #%u to IF -:%s:- error: %s\n",
|
|
vid, if_name, strerror(errno));
|
|
exit(3);
|
|
}
|
|
else {
|
|
fprintf(stdout,"Added VLAN with VID == %u to IF -:%s:-\n",
|
|
vid, if_name);
|
|
if (vid == 1) {
|
|
fprintf(stdout, "WARNING: VLAN 1 does not work with many switches,\nconsider another number if you have problems.\n");
|
|
}
|
|
}
|
|
}//if
|
|
else if (strcasecmp(cmd, "rem") == 0) {
|
|
if_request.cmd = DEL_VLAN_CMD;
|
|
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
|
|
fprintf(stderr,"ERROR: trying to remove VLAN -:%s:- error: %s\n",
|
|
if_name, strerror(errno));
|
|
exit(4);
|
|
}
|
|
else {
|
|
fprintf(stdout,"Removed VLAN -:%s:-\n", if_name);
|
|
}
|
|
}//if
|
|
else if (strcasecmp(cmd, "get_vid") == 0) {
|
|
if_request.cmd = GET_VLAN_VID_CMD;
|
|
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
|
|
fprintf(stderr,"ERROR: trying to get VLAN VID -:%s:- error: %s\n",
|
|
if_name, strerror(errno));
|
|
exit(4);
|
|
}
|
|
else {
|
|
fprintf(stdout,"Get VLAN -:%s:-VID:%d\n", if_name, if_request.u.VID);
|
|
}
|
|
}//if
|
|
else if (strcasecmp(cmd, "set_egress_map") == 0) {
|
|
if_request.cmd = SET_VLAN_EGRESS_PRIORITY_CMD;
|
|
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
|
|
fprintf(stderr,"ERROR: trying to set egress map on device -:%s:- error: %s\n",
|
|
if_name, strerror(errno));
|
|
exit(5);
|
|
}
|
|
else {
|
|
fprintf(stdout,"Set egress mapping on device -:%s:- "
|
|
"Should be visible in /proc/net/vlan/%s\n",
|
|
if_name, if_name);
|
|
}
|
|
}
|
|
else if (strcasecmp(cmd, "set_ingress_map") == 0) {
|
|
if_request.cmd = SET_VLAN_INGRESS_PRIORITY_CMD;
|
|
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
|
|
fprintf(stderr,"ERROR: trying to set ingress map on device -:%s:- error: %s\n",
|
|
if_name, strerror(errno));
|
|
exit(6);
|
|
}
|
|
else {
|
|
fprintf(stdout,"Set ingress mapping on device -:%s:- "
|
|
"Should be visible in /proc/net/vlan/%s\n",
|
|
if_name, if_name);
|
|
}
|
|
}
|
|
else if (strcasecmp(cmd, "set_flag") == 0) {
|
|
if_request.cmd = SET_VLAN_FLAG_CMD;
|
|
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
|
|
fprintf(stderr,"ERROR: trying to set flag on device -:%s:- error: %s\n",
|
|
if_name, strerror(errno));
|
|
exit(7);
|
|
}
|
|
else {
|
|
fprintf(stdout,"Set flag on device -:%s:- "
|
|
"Should be visible in /proc/net/vlan/%s\n",
|
|
if_name, if_name);
|
|
}
|
|
}
|
|
else if (strcasecmp(cmd, "set_name_type") == 0) {
|
|
if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
|
|
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
|
|
fprintf(stderr,"ERROR: trying to set name type for VLAN subsystem, error: %s\n",
|
|
strerror(errno));
|
|
exit(8);
|
|
}
|
|
else {
|
|
fprintf(stdout,"Set name-type for VLAN subsystem."
|
|
" Should be visible in /proc/net/vlan/config\n");
|
|
}
|
|
}
|
|
else {
|
|
fprintf(stderr, "Unknown command -:%s:-\n", cmd);
|
|
|
|
show_usage();
|
|
exit(5);
|
|
}
|
|
|
|
return 0;
|
|
}/* main */
|