diff -u -r1.1.1.1 Makefile
--- vlan/Makefile	2002/10/18 15:42:38	1.1.1.1
+++ vlan/Makefile	2002/12/02 17:44:32
@@ -11,7 +11,7 @@
 VCONFIG = vconfig                  #program to be created
 
 
-all: ${VCONFIG}
+all: ${VCONFIG} macvlan_config
 
 
 #This is pretty silly..
@@ -22,6 +22,8 @@
 ${VCONFIG}: $(VLAN_OBJS)
 	$(CC) $(CCFLAGS) $(LDFLAGS) -o $(VCONFIG) $(VLAN_OBJS) $(LDLIBS)
 
+macvlan_config: macvlan_config.c
+	$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $<
 
 $(ALL_OBJS): %.o: %.c %.h
 	@echo " "
diff -urN vlan.orig/macvlan_config.c vlan/macvlan_config.c
--- vlan.orig/macvlan_config.c	Thu Jan  1 01:00:00 1970
+++ vlan/macvlan_config.c	Mon Dec  2 14:15:39 2002
@@ -0,0 +1,443 @@
+/*
+#######################################################################
+#
+# (C) Copyright 2001
+# Alex Zeffertt, Cambridge Broadband Ltd, ajz@cambridgebroadband.com
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU 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 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
+#######################################################################
+# Notes:
+# 
+# This configuration utility communicates with macvlan.o, the MAC address
+# based VLAN support module.
+#
+# It uses an IOCTL interface which allows you to
+#
+# 1. enable/disable MAC address based VLANS over an ether type net_device
+# 2. add/remove a MAC address based VLAN - which is an ether type net_device
+#    layered over the original MACVLAN enabled ether type net_device.
+# 3. bind/unbind MAC addresses to/from particular MAC address based VLANs
+# 4. discover the state of MAC address based VLANs on the system.
+#
+# Example:
+#
+# If you enable MAC address based VLANS over eth0, then all upper layer protocols (e.g. IP)
+# layered above eth0 will stop receiving.  A default VLAN will be created
+# called eth0#0.  By default frames received by eth0 will be routed up
+# through eth0#0.
+#
+# You may then create further VLANs, e.g. eth0#1 eth0#2 ....
+# These will not receive any frames until you bind MAC addresses to them.
+# If you bind 11:22:33:44:55:66 to eth0#1, then any frames received by
+# eth0 with source MAC 11:22:33:44:55:66 will be routed up through eth0#1
+# instead of eth0#0.
+# 
+#######################################################################
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <linux/if_macvlan.h>
+#include <linux/sockios.h>
+
+int do_help(int argc, char *argv[]);
+int do_enable(int argc, char *argv[]);
+int do_disable(int argc, char *argv[]);
+int do_add(int argc, char *argv[]);
+int do_del(int argc, char *argv[]);
+int do_bind(int argc, char *argv[]);
+int do_unbind(int argc, char *argv[]);
+int do_info(int argc, char *argv[]);
+
+
+struct command {
+    char *name;
+    char *short_help;
+    int (*fn)(int argc, char *argv[]);
+    char *long_help;
+} command_list[] = {
+    {"help",   "help on other commands", do_help, "help <command>"},
+    {"enable", "enables mac based vlans over an ethernet device", do_enable,
+         "enable <ifname>\n"
+         " - enables mac based vlans over \"ifname\"\n"
+         " - also creates a default vlan over \"ifname\" called \"ifname#0\""
+    },
+    {"disable", "disables mac based vlans over an ethernet device", do_disable, "disable <ifname>"},
+    {"add", "creates new mac based vlan",  do_add,
+         "add <ifname> <index>\n"
+         " - creates a new mac based vlan called \"ifname#index\" layered over \"ifname\"\n"
+         " - mac based vlans over \"ifname\" must first be enabled with \"enable\"\n"
+         " - \"ifname#index\" is not mapped to any MAC address until \"bind\" is called"
+    },
+    {"del", "destroys a mac based vlan",  do_del,
+         "del <ifname>\n"
+         " - deletes a mac base vlan called \"ifname\""
+    },
+    {"bind", "binds macaddr to vlan",  do_bind,
+         "bind  <ifname> <macaddr>\n"
+         " - binds macaddr to vlan called \"ifname\""
+    },
+    {"unbind", "unbinds macaddr from vlan",  do_unbind,
+         "unbind <ifname> <macaddr>\n"
+         " - unbinds macaddr from vlan called \"ifname\""
+    },
+    {"info", "print state of mac based vlans",  do_info, "info"},
+};
+#define NCOMMANDS (sizeof(command_list)/sizeof(struct command))
+
+
+
+int do_help(int argc, char *argv[])
+{
+    int cmd;
+    if (argc < 2)
+        return -1;
+
+    for (cmd = 0; cmd < NCOMMANDS; cmd++) {
+        if (!strcmp(command_list[cmd].name,argv[1]))
+            break;
+    }
+    if (cmd == NCOMMANDS)
+        return -1;
+    puts(command_list[cmd].long_help);
+    return 0;
+}
+
+int do_enable(int argc, char *argv[])
+{
+    struct macvlan_ioctl req;
+    int s;
+
+    if (argc < 2) {
+        printf("usage: %s <ifname>\n", argv[0]);
+        return 1;
+    }
+
+    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+        perror("socket");
+        return 1;
+    }
+
+    req.cmd = MACVLAN_ENABLE;
+    req.ifname = argv[1];   /* 
+                             * name of ethernet device over which we 
+                             * are enabling mac based vlans
+                             */
+
+    if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) {
+        perror("ioctl");
+        return 1;
+    }
+    return 0;
+}
+
+int do_disable(int argc, char *argv[])
+{
+    struct macvlan_ioctl req;
+    int s;
+
+    if (argc < 2) {
+        printf("usage: %s <ifname>\n", argv[0]);
+        return 1;
+    }
+
+    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+        perror("socket");
+        return 1;
+    }
+
+    req.cmd = MACVLAN_DISABLE;
+    req.ifname = argv[1];   /* 
+                             * name of ethernet device over which we 
+                             * are disabling mac based vlans
+                             */
+
+    if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) {
+        perror("ioctl");
+        return 1;
+    }
+    return 0;
+}
+
+int do_add(int argc, char *argv[])
+{
+    int s;
+    struct macvlan_ioctl req;
+
+    if (argc < 3) {
+        printf("usage: %s <ifname> <index>\n", argv[0]);
+        return 1;
+    }
+
+    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+        perror("socket");
+        return 1;
+    }
+
+    req.cmd = MACVLAN_ADD;
+    req.ifname = argv[1];       /* name of lower layer i/f over which we are adding an upper layer i/f */
+    req.ifidx = atoi(argv[2]);  /* index of new upper layer i/f to create */
+
+    if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) {
+        perror("ioctl");
+        return 1;
+    }
+    return 0;
+}
+
+int do_del(int argc, char *argv[])
+{
+    int s;
+    struct macvlan_ioctl req;
+
+    if (argc < 2) {
+        printf("usage: %s <ifname>\n", argv[0]);
+        return 1;
+    }
+
+    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+        perror("socket");
+        return 1;
+    }
+
+    req.cmd = MACVLAN_DEL;
+    req.ifname = argv[1]; /* name mac based vlan to destroy */
+
+    if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) {
+        printf("failed to delete i/f\n");
+        perror("ioctl");
+        return 1;
+    }
+    return 0;
+}
+
+int htoi(char *s)
+{
+    char ch;
+    int i = 0;
+    while ((ch = *s++)) {
+        i <<= 4;
+        i += (ch>='0'&&ch<='9')?(ch-'0'):((ch>='a'&&ch<='f')?(ch-'a'+10):((ch>='A'&&ch<='F')?(ch-'A'+10):0));
+    }
+    return i;
+}
+
+int do_bind(int argc, char *argv[])
+{
+    int s;
+    struct macvlan_ioctl req;
+    char *ptr;
+    unsigned char macaddr[6];
+
+    if (argc < 3) {
+        printf("usage: %s <ifname> <macaddr>\n", argv[0]);
+        return 1;
+    }
+
+    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+        perror("socket");
+        return 1;
+    }
+
+    req.cmd = MACVLAN_BIND;
+    req.ifname = argv[1]; /* name of vlan to which we are binding a MAC address */
+
+    /* assemble the macaddr */
+    ptr = argv[2];
+    if (strlen(ptr) != 17) {
+        printf("bad macaddr format: need aa:bb:cc:dd:ee:ff\n");
+        return 1;
+    }
+    for (ptr = argv[2]+2; ptr < argv[2]+16; ptr+=3)
+        *ptr = 0;
+    ptr = argv[2];
+    macaddr[0] = (unsigned char)htoi(ptr);
+    macaddr[1] = (unsigned char)htoi(ptr+3);
+    macaddr[2] = (unsigned char)htoi(ptr+6);
+    macaddr[3] = (unsigned char)htoi(ptr+9);
+    macaddr[4] = (unsigned char)htoi(ptr+12);
+    macaddr[5] = (unsigned char)htoi(ptr+15);
+    req.macaddr = macaddr;
+
+    if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) {
+        perror("ioctl");
+        return 1;
+    }
+    return 0;
+}
+
+int do_unbind(int argc, char *argv[])
+{
+    int s;
+    struct macvlan_ioctl req;
+    char *ptr;
+    unsigned char macaddr[6];
+
+    if (argc < 3) {
+        printf("usage: %s <ifname> <macaddr>\n", argv[0]);
+        return 1;
+    }
+
+    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+        perror("socket");
+        return 1;
+    }
+
+    req.cmd = MACVLAN_UNBIND;
+    req.ifname = argv[1]; /* name of vlan from which we are deleting a MAC address */
+
+    /* assemble the macaddr */
+    ptr = argv[2];
+    if (strlen(ptr) != 17) {
+        printf("bad macaddr format: need aa:bb:cc:dd:ee:ff\n");
+        return 1;
+    }
+    for (ptr = argv[2]+2; ptr < argv[2]+16; ptr+=3)
+        *ptr = 0;
+    ptr = argv[2];
+    macaddr[0] = (unsigned char)htoi(ptr);
+    macaddr[1] = (unsigned char)htoi(ptr+3);
+    macaddr[2] = (unsigned char)htoi(ptr+6);
+    macaddr[3] = (unsigned char)htoi(ptr+9);
+    macaddr[4] = (unsigned char)htoi(ptr+12);
+    macaddr[5] = (unsigned char)htoi(ptr+15);
+    req.macaddr = macaddr;
+
+    if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) {
+        perror("ioctl");
+        return 1;
+    }
+    return 0;
+}
+
+int do_info(int argc, char *argv[])
+{
+    int s;
+    struct macvlan_ioctl req;
+    struct macvlan_ioctl_reply rep;
+    int nports;
+    int portidx;
+    int nifs;
+    int ifidx;
+    int nmacs;
+    int macidx;
+    unsigned char *p;
+
+    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+        perror("socket");
+        return 1;
+    }
+    /* get the number of ethernet devices which have mac based vlans
+     * enabled over them
+     */
+    req.cmd = MACVLAN_GET_NUM_PORTS;
+    req.reply = &rep;
+    if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) {
+        perror("ioctl");
+        return 1;
+    }
+    nports = rep.num;
+    for (portidx = 0; portidx < nports; portidx++) {
+        /* Get the name of this mac-based-vlan enabled 
+         * ethernet device
+         */
+        req.cmd = MACVLAN_GET_PORT_NAME;
+        req.portidx = portidx;
+        req.reply = &rep;
+        if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) {
+            perror("ioctl");
+            return 1;
+        }
+        printf("-%s\n", rep.name);
+        /* Get the number of mac-based-vlans layered
+         * over this ethernet device 
+         */
+        req.cmd = MACVLAN_GET_NUM_VLANS;
+        req.portidx = portidx;
+        req.reply = &rep;
+        if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) {
+            perror("ioctl");
+            return 1;
+        }
+        nifs = rep.num;
+        for (ifidx = 0; ifidx < nifs; ifidx++) {
+            /* Get the name of this vlan */
+            req.cmd = MACVLAN_GET_VLAN_NAME;
+            req.portidx = portidx;
+            req.ifidx = ifidx;
+            req.reply = &rep;
+            if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) {
+                perror("ioctl");
+                return 1;
+            }
+            /* get the number of mac addresses owned by this vlan */
+            printf(" |-%s\n", rep.name);
+            req.cmd = MACVLAN_GET_NUM_MACS;
+            req.portidx = portidx;
+            req.ifidx = ifidx;
+            req.reply = &rep;
+            if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) {
+                perror("ioctl");
+                return 1;
+            }
+            nmacs = rep.num;
+            for (macidx = 0; macidx < nmacs; macidx++) {
+                /* get the value of this mac address */
+                req.cmd = MACVLAN_GET_MAC_NAME;
+                req.portidx = portidx;
+                req.ifidx = ifidx;
+                req.macaddridx = macidx;
+                req.reply = &rep;
+                if(ioctl(s, SIOCGIFMACVLAN, &req) < 0) {
+                    perror("ioctl");
+                    return 1;
+                }
+                p = (unsigned char *) rep.name;
+                printf(" | |-%02x:%02x:%02x:%02x:%02x:%02x\n", 
+                       p[0],p[1],p[2],p[3],p[4],p[5]);
+            }
+        }
+    }
+    return 0;
+}
+
+int main(int argc, char *argv[])
+{
+    int cmd;
+    int err;
+    
+    if (argc < 2)
+        goto usage;
+
+    for (cmd = 0; cmd < NCOMMANDS; cmd++) {
+        if (!strcmp(command_list[cmd].name,argv[1]))
+            break;
+    }
+    if (cmd == NCOMMANDS)
+        goto usage;
+
+    if ((err = command_list[cmd].fn(argc-1,argv+1)))
+        goto usage;
+    return 0;
+
+ usage:
+    printf("\n%s subcommands:\n\n", argv[0]);
+    for (cmd = 0; cmd < NCOMMANDS; cmd++) {
+        printf("%s %s:\t%s\n",argv[0],command_list[cmd].name,command_list[cmd].short_help);
+    }
+    return err;
+}
