-#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>
-#include "busybox.h"
-
-
-
-int vconfig_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)) {
- error_msg_and_die("Expecting argc to be 3-5, inclusive. Was: %d\n",argc);
- }
- 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 {
- error_msg_and_die("Invalid name type.\n");
- }
- if_request.u.name_type = nm_type;
- }
- else {
- if_name = argv[2];
- if (strlen(if_name) > 15) {
- error_msg_and_die("ERROR: if_name must be 15 characters or less.\n");
- }
- 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) {
- error_msg("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) {
- error_msg_and_die("FATAL: Couldn't open a socket..go figure!\n");
- }
-
- /* add */
- if (strcasecmp(cmd, "add") == 0) {
- if_request.cmd = ADD_VLAN_CMD;
- if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
- error_msg("ERROR: trying to add VLAN #%u to IF -:%s:- error: %s\n",
- vid, if_name, strerror(errno));
- }
- else {
- printf("Added VLAN with VID == %u to IF -:%s:-\n", vid, if_name);
- if (vid == 1) {
- error_msg("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) {
- error_msg("ERROR: trying to remove VLAN -:%s:- error: %s\n",
- if_name, strerror(errno));
- }
- else {
- printf("Removed VLAN -:%s:-\n", if_name);
- }
- }//if
- else if (strcasecmp(cmd, "set_egress_map") == 0) {
- if_request.cmd = SET_VLAN_EGRESS_PRIORITY_CMD;
- if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
- error_msg("ERROR: trying to set egress map on device -:%s:- error: %s\n",
- if_name, strerror(errno));
- }
- else {
- printf("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) {
- error_msg("ERROR: trying to set ingress map on device -:%s:- error: %s\n",
- if_name, strerror(errno));
- }
- else {
- printf("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) {
- error_msg("ERROR: trying to set flag on device -:%s:- error: %s\n",
- if_name, strerror(errno));
- }
- else {
- printf("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) {
- error_msg("ERROR: trying to set name type for VLAN subsystem, error: %s\n",
- strerror(errno));
- }
- else {
- printf("Set name-type for VLAN subsystem."
- " Should be visible in /proc/net/vlan/config\n");
- }
- }
- else {
- error_msg_and_die("Unknown command -:%s:-\n", cmd);
- }
-
- return 0;
-}/* main */
+/* vi: set sw=4 ts=4: */
+/*
+ * vconfig implementation for busybox
+ *
+ * Copyright (C) 2001 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+
+/* BB_AUDIT SUSv3 N/A */
+
+//config:config VCONFIG
+//config: bool "vconfig"
+//config: default y
+//config: select PLATFORM_LINUX
+//config: help
+//config: Creates, removes, and configures VLAN interfaces
+
+//applet:IF_VCONFIG(APPLET(vconfig, BB_DIR_SBIN, BB_SUID_DROP))
+
+//kbuild:lib-$(CONFIG_VCONFIG) += vconfig.o
+
+//usage:#define vconfig_trivial_usage
+//usage: "COMMAND [OPTIONS]"
+//usage:#define vconfig_full_usage "\n\n"
+//usage: "Create and remove virtual ethernet devices\n"
+//usage: "\n add IFACE VLAN_ID"
+//usage: "\n rem VLAN_NAME"
+//usage: "\n set_flag IFACE 0|1 VLAN_QOS"
+//usage: "\n set_egress_map VLAN_NAME SKB_PRIO VLAN_QOS"
+//usage: "\n set_ingress_map VLAN_NAME SKB_PRIO VLAN_QOS"
+//usage: "\n set_name_type NAME_TYPE"
+
+#include "libbb.h"
+#include <net/if.h>
+
+/* Stuff from linux/if_vlan.h, kernel version 2.4.23 */
+enum vlan_ioctl_cmds {
+ ADD_VLAN_CMD,
+ DEL_VLAN_CMD,
+ SET_VLAN_INGRESS_PRIORITY_CMD,
+ SET_VLAN_EGRESS_PRIORITY_CMD,
+ GET_VLAN_INGRESS_PRIORITY_CMD,
+ GET_VLAN_EGRESS_PRIORITY_CMD,
+ SET_VLAN_NAME_TYPE_CMD,
+ SET_VLAN_FLAG_CMD
+};
+enum vlan_name_types {
+ VLAN_NAME_TYPE_PLUS_VID, /* Name will look like: vlan0005 */
+ VLAN_NAME_TYPE_RAW_PLUS_VID, /* name will look like: eth1.0005 */
+ VLAN_NAME_TYPE_PLUS_VID_NO_PAD, /* Name will look like: vlan5 */
+ VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, /* Name will look like: eth0.5 */
+ VLAN_NAME_TYPE_HIGHEST
+};
+
+struct vlan_ioctl_args {
+ int cmd; /* Should be one of the vlan_ioctl_cmds enum above. */
+ char device1[24];
+
+ union {
+ char device2[24];
+ int VID;
+ unsigned int skb_priority;
+ unsigned int name_type;
+ unsigned int bind_type;
+ unsigned int flag; /* Matches vlan_dev_info flags */
+ } u;
+
+ short vlan_qos;
+};
+
+#define VLAN_GROUP_ARRAY_LEN 4096
+#define SIOCSIFVLAN 0x8983 /* Set 802.1Q VLAN options */
+
+/* On entry, table points to the length of the current string
+ * plus NUL terminator plus data length for the subsequent entry.
+ * The return value is the last data entry for the matching string. */
+static const char *xfind_str(const char *table, const char *str)
+{
+ while (strcasecmp(str, table + 1) != 0) {
+ if (!table[0])
+ bb_show_usage();
+ table += table[0];
+ }
+ return table - 1;
+}
+
+static const char cmds[] ALIGN1 = {
+ 4, ADD_VLAN_CMD, 7,
+ 'a','d','d',0,
+ 3, DEL_VLAN_CMD, 7,
+ 'r','e','m',0,
+ 3, SET_VLAN_NAME_TYPE_CMD, 17,
+ 's','e','t','_','n','a','m','e','_','t','y','p','e',0,
+ 5, SET_VLAN_FLAG_CMD, 12,
+ 's','e','t','_','f','l','a','g',0,
+ 5, SET_VLAN_EGRESS_PRIORITY_CMD, 18,
+ 's','e','t','_','e','g','r','e','s','s','_','m','a','p',0,
+ 5, SET_VLAN_INGRESS_PRIORITY_CMD, 0,
+ 's','e','t','_','i','n','g','r','e','s','s','_','m','a','p',0,
+};
+
+static const char name_types[] ALIGN1 = {
+ VLAN_NAME_TYPE_PLUS_VID, 16,
+ 'V','L','A','N','_','P','L','U','S','_','V','I','D',0,
+ VLAN_NAME_TYPE_PLUS_VID_NO_PAD, 22,
+ 'V','L','A','N','_','P','L','U','S','_','V','I','D','_','N','O','_','P','A','D',0,
+ VLAN_NAME_TYPE_RAW_PLUS_VID, 15,
+ 'D','E','V','_','P','L','U','S','_','V','I','D',0,
+ VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, 0,
+ 'D','E','V','_','P','L','U','S','_','V','I','D','_','N','O','_','P','A','D',0,
+};
+
+int vconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int vconfig_main(int argc, char **argv)
+{
+ struct vlan_ioctl_args ifr;
+ const char *p;
+ int fd;
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ ++argv;
+ if (!argv[0])
+ bb_show_usage();
+ p = xfind_str(cmds + 2, argv[0]);
+ ifr.cmd = *p;
+ if (argc != p[-1])
+ bb_show_usage();
+
+ if (ifr.cmd == SET_VLAN_NAME_TYPE_CMD) {
+ /* set_name_type */
+ ifr.u.name_type = *xfind_str(name_types + 1, argv[1]);
+ } else {
+ strncpy_IFNAMSIZ(ifr.device1, argv[1]);
+ p = argv[2];
+
+ /* I suppose one could try to combine some of the function calls below,
+ * since ifr.u.flag, ifr.u.VID, and ifr.u.skb_priority are all same-sized
+ * (unsigned) int members of a unions. But because of the range checking,
+ * doing so wouldn't save that much space and would also make maintainence
+ * more of a pain.
+ */
+ if (ifr.cmd == SET_VLAN_FLAG_CMD) {
+ /* set_flag */
+ ifr.u.flag = xatou_range(p, 0, 1);
+ /* DM: in order to set reorder header, qos must be set */
+ ifr.vlan_qos = xatou_range(argv[3], 0, 7);
+ } else if (ifr.cmd == ADD_VLAN_CMD) {
+ /* add */
+ ifr.u.VID = xatou_range(p, 0, VLAN_GROUP_ARRAY_LEN - 1);
+ } else if (ifr.cmd != DEL_VLAN_CMD) {
+ /* set_{egress|ingress}_map */
+ ifr.u.skb_priority = xatou(p);
+ ifr.vlan_qos = xatou_range(argv[3], 0, 7);
+ }
+ }
+
+ fd = xsocket(AF_INET, SOCK_STREAM, 0);
+ ioctl_or_perror_and_die(fd, SIOCSIFVLAN, &ifr,
+ "ioctl error for %s", argv[0]);
+
+ return 0;
+}