mrpd: split mvrp from mrpd
authorAndrew Elder <aelder@audioscience.com>
Sat, 15 Sep 2012 02:06:22 +0000 (22:06 -0400)
committerAndrew Elder <aelder@audioscience.com>
Sat, 15 Sep 2012 02:06:22 +0000 (22:06 -0400)
daemons/mrpd/Makefile
daemons/mrpd/mrp.h [new file with mode: 0644]
daemons/mrpd/mrpd.c
daemons/mrpd/mrpd.h
daemons/mrpd/mvrp.c [new file with mode: 0644]
daemons/mrpd/mvrp.h [new file with mode: 0644]

index 4dc153c..5a12082 100644 (file)
@@ -9,15 +9,12 @@ CC=gcc
 
 all: mrpd mrpctl
 
-mrpd: mrpd.o
+mrpd: mrpd.o mvrp.o
 
 mrpctl: mrpctl.o
 
-mrpctl.o: mrpctl.c
-       gcc -c $(INCFLAGS) $(CFLAGS) mrpctl.c
-
-mrpd.o: mrpd.c
-       gcc -c $(INCFLAGS) $(CFLAGS) mrpd.c
+%.o: %.c
+       gcc -c $(INCFLAGS) $(CFLAGS) -o $@  $<
 %: %.o
        $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
 
diff --git a/daemons/mrpd/mrp.h b/daemons/mrpd/mrp.h
new file mode 100644 (file)
index 0000000..2fb55b1
--- /dev/null
@@ -0,0 +1,43 @@
+/******************************************************************************
+
+  Copyright (c) 2012, Intel Corporation 
+  All rights reserved.
+  
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are met:
+  
+   1. Redistributions of source code must retain the above copyright notice, 
+      this list of conditions and the following disclaimer.
+  
+   2. Redistributions in binary form must reproduce the above copyright 
+      notice, this list of conditions and the following disclaimer in the 
+      documentation and/or other materials provided with the distribution.
+  
+   3. Neither the name of the Intel Corporation nor the names of its 
+      contributors may be used to endorse or promote products derived from 
+      this software without specific prior written permission.
+  
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+
+int mrp_jointimer_stop(struct mrp_database *mrp_db);
+int mrp_jointimer_start(struct mrp_database *mrp_db);
+int mrp_lvtimer_start(struct mrp_database *mrp_db);
+int mrp_lvtimer_stop(struct mrp_database *mrp_db);
+int mrp_lvatimer_start(struct mrp_database *mrp_db);
+int mrp_lvatimer_stop(struct mrp_database *mrp_db);
+int mrp_lvatimer_fsm(struct mrp_database *mrp_db, int event);
+int mrp_applicant_fsm(mrp_applicant_attribute_t *attrib, int event);
+int mrp_registrar_fsm(mrp_registrar_attribute_t *attrib,
+                 struct mrp_database *mrp_db, int event);
index 62492b1..49e8f1c 100644 (file)
@@ -55,6 +55,7 @@
 #include <net/ethernet.h>
 #include <sys/un.h>
 #include "mrpd.h"
+#include "mvrp.h"
 /* global mgmt parameters */
 int daemonize;
 int mmrp_enable;
@@ -88,10 +89,6 @@ static const char *version_str =
     "mrpd v" VERSION_STR "\n" "Copyright (c) 2012, Intel Corporation\n";
 
 unsigned char MMRP_ADDR[] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x20 };
-unsigned char MVRP_CUSTOMER_BRIDGE_ADDR[] = \
-       { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x21 }; /* 81-00 */
-unsigned char MVRP_PROVIDER_BRIDGE_ADDR[] = \
-       { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x0D }; /* 88-A8 */
 unsigned char MSRP_ADDR[] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x0E };
 unsigned char STATION_ADDR[] = { 0x00, 0x88, 0x77, 0x66, 0x55, 0x44 };
 
@@ -105,7 +102,7 @@ int periodic_timer;
 int gc_timer;
 
 struct mmrp_database *MMRP_db;
-struct mvrp_database *MVRP_db;
+extern struct mvrp_database *MVRP_db;
 struct msrp_database *MSRP_db;
 
 int client_lookup(client_t *list, struct sockaddr_in *newclient)
@@ -1002,13 +999,10 @@ int mrp_decode_state(mrp_registrar_attribute_t *rattrib, \
 }
 
 /* prototypes */
-int send_ctl_msg(struct sockaddr_in *client_addr, char *notify_data,
-                int notify_len);
+
 /* MMRP */
 int mmrp_send_notifications(struct mmrp_attribute *attrib, int notify);
 int mmrp_txpdu(void);
-int mvrp_send_notifications(struct mvrp_attribute *attrib, int notify);
-int mvrp_txpdu(void);
 int msrp_send_notifications(struct msrp_attribute *attrib, int notify);
 int msrp_txpdu(void);
 
@@ -2320,1217 +2314,7 @@ int mmrp_send_notifications(struct mmrp_attribute *attrib, int notify)
                sprintf(stage, "MLV %s %s\n", variant, regsrc);
                break;
        case MRP_MT_STATE:
-               sprintf(stage, "MMT %s %s\n", variant, regsrc);
-               break;
-       default:
-               break;
-       }
-
-       switch (notify) {
-       case MRP_NOTIFY_NEW:
-               snprintf(msgbuf, MAX_MRPD_CMDSZ - 1, "MNE %s", stage);
-               break;
-       case MRP_NOTIFY_JOIN:
-               snprintf(msgbuf, MAX_MRPD_CMDSZ - 1, "MJO %s", stage);
-               break;
-       case MRP_NOTIFY_LV:
-               snprintf(msgbuf, MAX_MRPD_CMDSZ - 1, "MLE %s", stage);
-               break;
-       default:
-               goto free_msgbuf;
-               break;
-       }
-
-       client = MMRP_db->mrp_db.clients;
-       while (NULL != client) {
-               send_ctl_msg(&(client->client), msgbuf, MAX_MRPD_CMDSZ);
-               client = client->next;
-       }
-
- free_msgbuf:
-       if (variant)
-               free(variant);
-       if (stage)
-               free(stage);
-       if (regsrc)
-               free(regsrc);
-       free(msgbuf);
-       return 0;
-}
-
-int mmrp_dumptable(struct sockaddr_in *client)
-{
-       char *msgbuf;
-       char *msgbuf_wrptr;
-       char *stage;
-       char *variant;
-       char *regsrc;
-       struct mmrp_attribute *attrib;
-
-       msgbuf = (char *)malloc(MAX_MRPD_CMDSZ);
-       if (NULL == msgbuf)
-               return -1;
-
-       stage = variant = regsrc = NULL;
-
-       stage = (char *)malloc(128);
-       variant = (char *)malloc(128);
-       regsrc = (char *)malloc(128);
-
-       if ((NULL == stage) || (NULL == variant) || (NULL == regsrc))
-               goto free_msgbuf;
-
-       memset(msgbuf, 0, MAX_MRPD_CMDSZ);
-
-       msgbuf_wrptr = msgbuf;
-
-       attrib = MMRP_db->attrib_list;
-
-       while (NULL != attrib) {
-               if (MMRP_SVCREQ_TYPE == attrib->type) {
-                       sprintf(variant, "S%d", attrib->attribute.svcreq);
-               } else {
-                       sprintf(variant, "M%02x%02x%02x%02x%02x%02x",
-                               attrib->attribute.macaddr[0],
-                               attrib->attribute.macaddr[1],
-                               attrib->attribute.macaddr[2],
-                               attrib->attribute.macaddr[3],
-                               attrib->attribute.macaddr[4],
-                               attrib->attribute.macaddr[5]);
-               }
-               sprintf(regsrc, "R%02x%02x%02x%02x%02x%02x",
-                       attrib->registrar.macaddr[0],
-                       attrib->registrar.macaddr[1],
-                       attrib->registrar.macaddr[2],
-                       attrib->registrar.macaddr[3],
-                       attrib->registrar.macaddr[4],
-                       attrib->registrar.macaddr[5]);
-               switch (attrib->registrar.mrp_state) {
-               case MRP_IN_STATE:
-                       sprintf(stage, "MIN %s %s\n", variant, regsrc);
-                       break;
-               case MRP_LV_STATE:
-                       sprintf(stage, "MLV %s %s\n", variant, regsrc);
-                       break;
-               case MRP_MT_STATE:
-                       sprintf(stage, "MMT %s %s\n", variant, regsrc);
-                       break;
-               default:
-                       break;
-               }
-               sprintf(msgbuf_wrptr, "%s", stage);
-               msgbuf_wrptr += strnlen(stage, 128);
-               attrib = attrib->next;
-       }
-
-       send_ctl_msg(client, msgbuf, MAX_MRPD_CMDSZ);
-
-free_msgbuf:
-       if (regsrc)
-               free(regsrc);
-       if (variant)
-               free(variant);
-       if (stage)
-               free(stage);
-       free(msgbuf);
-       return 0;
-
-}
-
-int recv_mmrp_cmd(char *buf, int buflen, struct sockaddr_in *client)
-{
-       int rc;
-       char respbuf[8];
-       struct mmrp_attribute *attrib;
-       u_int8_t svcreq_firstval;
-       u_int8_t macvec_firstval[6];
-       u_int8_t macvec_parsestr[8];
-       int i;
-
-       if (NULL == MMRP_db) {
-               snprintf(respbuf, sizeof(respbuf) - 1, "ERC %s", buf);
-               send_ctl_msg(client, respbuf, sizeof(respbuf));
-               goto out;
-       }
-
-       rc = client_add(&(MMRP_db->mrp_db.clients), client);
-
-       if (buflen < 3)
-               return -1;
-
-       if ('M' != buf[0])
-               return -1;
-
-       /*
-        * M?? - query MMRP Registrar MAC Address database
-        * M+? - JOIN a MAC address or service declaration
-        * M++   NEW a MAC Address (XXX: MMRP doesn't use 'New' though?)
-        * M-- - LV a MAC address or service declaration
-        */
-       switch (buf[1]) {
-       case '?':
-               mmrp_dumptable(client);
-               break;
-       case '-':
-               /* parse the type - service request or MACVEC */
-               if (buflen < 5) {
-                       snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s", buf);
-                       send_ctl_msg(client, respbuf, sizeof(respbuf));
-                       goto out;
-               }
-               switch (buf[3]) {
-               case 's':
-               case 'S':
-                       /* buf[] should look similar to 'M--s1' */
-                       svcreq_firstval = buf[4] - '0';
-                       if (svcreq_firstval > 1) {
-                               snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s",
-                                        buf);
-                               send_ctl_msg(client, respbuf, sizeof(respbuf));
-                               goto out;
-                       }
-
-                       attrib = mmrp_alloc();
-                       if (NULL == attrib) {
-                               snprintf(respbuf, sizeof(respbuf) - 1, "ERI %s",
-                                        buf);
-                               send_ctl_msg(client, respbuf, sizeof(respbuf));
-                               goto out;       /* oops - internal error */
-                       }
-                       attrib->type = MMRP_SVCREQ_TYPE;
-                       attrib->attribute.svcreq = svcreq_firstval;
-                       memset(attrib->registrar.macaddr, 0, 6);
-
-                       mmrp_event(MRP_EVENT_LV, attrib);
-                       break;
-               case 'm':
-               case 'M':
-                       /*
-                        * XXX note could also register VID with mac address if we ever wanted to
-                        * support more than one Spanning Tree context
-                        */
-
-                       /* buf[] should look similar to 'M--m010203040506' */
-                       if (buflen < 16) {
-                               snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s",
-                                        buf);
-                               send_ctl_msg(client, respbuf, sizeof(respbuf));
-                               goto out;
-                       }
-
-                       memset(macvec_parsestr, 0, sizeof(macvec_parsestr));
-
-                       for (i = 0; i < 6; i++) {
-                               macvec_parsestr[0] = buf[4 + i * 2];
-                               macvec_parsestr[1] = buf[5 + i * 2];
-
-                               rc = sscanf((char *)macvec_parsestr, "%hhx",
-                                           &macvec_firstval[i]);
-                               if (0 == rc) {
-                                       snprintf(respbuf, sizeof(respbuf) - 1,
-                                                "ERP %s", buf);
-                                       send_ctl_msg(client, respbuf,
-                                                    sizeof(respbuf));
-                                       goto out;
-                               }
-                       }
-
-                       attrib = mmrp_alloc();
-                       if (NULL == attrib) {
-                               snprintf(respbuf, sizeof(respbuf) - 1, "ERI %s",
-                                        buf);
-                               send_ctl_msg(client, respbuf, sizeof(respbuf));
-                               goto out;       /* oops - internal error */
-                       }
-                       attrib->type = MMRP_MACVEC_TYPE;
-                       memcpy(attrib->attribute.macaddr, macvec_firstval, 6);
-                       memset(attrib->registrar.macaddr, 0, 6);
-
-                       mmrp_event(MRP_EVENT_LV, attrib);
-                       break;
-               default:
-                       snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s", buf);
-                       send_ctl_msg(client, respbuf, sizeof(respbuf));
-                       goto out;
-               }
-               break;
-       case '+':
-               /* parse the type - service request or MACVEC */
-               if (buflen < 5) {
-                       snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s", buf);
-                       send_ctl_msg(client, respbuf, sizeof(respbuf));
-                       goto out;
-               }
-               switch (buf[3]) {
-               case 's':
-               case 'S':
-                       /* buf[] should look similar to 'M+?s1'
-                        * or buf[] should look similar to 'M++s1'
-                        */
-                       if (('?' != buf[2]) && ('+' != buf[2])) {
-                               snprintf(respbuf, sizeof(respbuf) - 1, "ERC %s",
-                                        buf);
-                               send_ctl_msg(client, respbuf, sizeof(respbuf));
-                               goto out;
-                       }
-                       svcreq_firstval = buf[4] - '0';
-                       if (svcreq_firstval > 1) {
-                               snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s",
-                                        buf);
-                               send_ctl_msg(client, respbuf, sizeof(respbuf));
-                               goto out;
-                       }
-
-                       attrib = mmrp_alloc();
-                       if (NULL == attrib) {
-                               snprintf(respbuf, sizeof(respbuf) - 1, "ERI %s",
-                                        buf);
-                               send_ctl_msg(client, respbuf, sizeof(respbuf));
-                               goto out;       /* oops - internal error */
-                       }
-                       attrib->type = MMRP_SVCREQ_TYPE;
-                       attrib->attribute.svcreq = svcreq_firstval;
-                       memset(attrib->registrar.macaddr, 0, 6);
-
-                       mmrp_event(MRP_EVENT_JOIN, attrib);
-                       break;
-               case 'm':
-               case 'M':
-                       /* buf[] should look similar to 'M+?m010203040506' */
-                       if (buflen < 16) {
-                               snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s",
-                                        buf);
-                               send_ctl_msg(client, respbuf, sizeof(respbuf));
-                               goto out;
-                       }
-
-                       memset(macvec_parsestr, 0, sizeof(macvec_parsestr));
-
-                       for (i = 0; i < 6; i++) {
-                               macvec_parsestr[0] = buf[4 + i * 2];
-                               macvec_parsestr[1] = buf[5 + i * 2];
-
-                               rc = sscanf((char *)macvec_parsestr, "%hhx",
-                                           &macvec_firstval[i]);
-                               if (0 == rc) {
-                                       snprintf(respbuf, sizeof(respbuf) - 1,
-                                                "ERP %s", buf);
-                                       send_ctl_msg(client, respbuf,
-                                                    sizeof(respbuf));
-                                       goto out;
-                               }
-                       }
-
-                       attrib = mmrp_alloc();
-                       if (NULL == attrib) {
-                               snprintf(respbuf, sizeof(respbuf) - 1, "ERI %s",
-                                        buf);
-                               send_ctl_msg(client, respbuf, sizeof(respbuf));
-                               goto out;       /* oops - internal error */
-                       }
-                       attrib->type = MMRP_MACVEC_TYPE;
-                       memcpy(attrib->attribute.macaddr, macvec_firstval, 6);
-                       memset(attrib->registrar.macaddr, 0, 6);
-
-                       mmrp_event(MRP_EVENT_JOIN, attrib);
-                       break;
-               default:
-                       snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s", buf);
-                       send_ctl_msg(client, respbuf, sizeof(respbuf));
-                       goto out;
-               }
-               break;
-       default:
-               snprintf(respbuf, sizeof(respbuf) - 1, "ERC %s", buf);
-               send_ctl_msg(client, respbuf, sizeof(respbuf));
-               goto out;
-               break;
-       }
-       return 0;
- out:
-       return -1;
-}
-
-/* MVRP */
-
-struct mvrp_attribute *mvrp_lookup(struct mvrp_attribute *rattrib)
-{
-       struct mvrp_attribute *attrib;
-
-       attrib = MVRP_db->attrib_list;
-       while (NULL != attrib) {
-               if (attrib->attribute == rattrib->attribute)
-                       return attrib;
-               attrib = attrib->next;
-       }
-       return NULL;
-}
-
-int mvrp_add(struct mvrp_attribute *rattrib)
-{
-       struct mvrp_attribute *attrib;
-       struct mvrp_attribute *attrib_tail;
-
-       /* XXX do a lookup first to guarantee uniqueness? */
-
-       attrib_tail = attrib = MVRP_db->attrib_list;
-
-       while (NULL != attrib) {
-               if (attrib->attribute < rattrib->attribute) {
-                       /* possible tail insertion ... */
-                       if (NULL != attrib->next) {
-                               attrib = attrib->next;
-                               continue;
-                       }
-                       rattrib->next = attrib->next;
-                       rattrib->prev = attrib;
-                       attrib->next = rattrib;
-                       return 0;
-
-               } else {
-                       /* head insertion ... */
-                       rattrib->next = attrib;
-                       rattrib->prev = attrib->prev;
-                       attrib->prev = rattrib;
-                       if (NULL != rattrib->prev)
-                               rattrib->prev->next = rattrib;
-                       else
-                               MVRP_db->attrib_list = rattrib;
-
-                       return 0;
-               }
-               attrib_tail = attrib;
-               attrib = attrib->next;
-       }
-
-       /* if we are here we didn't need to stitch in a a sorted entry
-        * so append it onto the tail (if it exists)
-        */
-
-       if (NULL == attrib_tail) {
-               rattrib->next = NULL;
-               rattrib->prev = NULL;
-               MVRP_db->attrib_list = rattrib;
-       } else {
-               rattrib->next = NULL;
-               rattrib->prev = attrib_tail;
-               attrib_tail->next = rattrib;
-       }
-
-       return 0;
-}
-
-int mvrp_merge(struct mvrp_attribute *rattrib)
-{
-       struct mvrp_attribute *attrib;
-
-       attrib = mvrp_lookup(rattrib);
-
-       if (NULL == attrib)
-               return -1;      /* shouldn't happen */
-
-       /* primarily we update the last mac address state for diagnostics */
-       memcpy(attrib->registrar.macaddr, rattrib->registrar.macaddr, 6);
-       return 0;
-}
-
-int mvrp_event(int event, struct mvrp_attribute *rattrib)
-{
-       struct mvrp_attribute *attrib;
-       int rc;
-
-       switch (event) {
-       case MRP_EVENT_LVATIMER:
-               mrp_jointimer_stop(&(MVRP_db->mrp_db));
-               /* update state */
-               attrib = MVRP_db->attrib_list;
-
-               while (NULL != attrib) {
-                       mrp_applicant_fsm(&(attrib->applicant), MRP_EVENT_TXLA);
-                       mrp_registrar_fsm(&(attrib->registrar),
-                                         &(MVRP_db->mrp_db), MRP_EVENT_TXLA);
-                       attrib = attrib->next;
-               }
-
-               mrp_lvatimer_fsm(&(MVRP_db->mrp_db), MRP_EVENT_LVATIMER);
-
-               mvrp_txpdu();
-               break;
-       case MRP_EVENT_RLA:
-               mrp_jointimer_stop(&(MVRP_db->mrp_db));
-               /* update state */
-               attrib = MVRP_db->attrib_list;
-
-               while (NULL != attrib) {
-                       mrp_applicant_fsm(&(attrib->applicant), MRP_EVENT_RLA);
-                       mrp_registrar_fsm(&(attrib->registrar),
-                                         &(MVRP_db->mrp_db), MRP_EVENT_RLA);
-                       attrib = attrib->next;
-               }
-
-               mrp_lvatimer_fsm(&(MVRP_db->mrp_db), MRP_EVENT_RLA);
-
-               break;
-       case MRP_EVENT_TX:
-               mrp_jointimer_stop(&(MVRP_db->mrp_db));
-               attrib = MVRP_db->attrib_list;
-
-               while (NULL != attrib) {
-                       mrp_applicant_fsm(&(attrib->applicant), MRP_EVENT_TX);
-                       attrib = attrib->next;
-               }
-
-               mrp_lvatimer_fsm(&(MVRP_db->mrp_db), MRP_EVENT_TX);
-
-               mvrp_txpdu();
-               break;
-       case MRP_EVENT_LVTIMER:
-               mrp_lvtimer_stop(&(MVRP_db->mrp_db));
-               attrib = MVRP_db->attrib_list;
-
-               while (NULL != attrib) {
-                       mrp_registrar_fsm(&(attrib->registrar),
-                                         &(MVRP_db->mrp_db),
-                                         MRP_EVENT_LVTIMER);
-
-                       attrib = attrib->next;
-               }
-               break;
-       case MRP_EVENT_PERIODIC:
-               attrib = MVRP_db->attrib_list;
-
-               while (NULL != attrib) {
-                       mrp_applicant_fsm(&(attrib->applicant),
-                                         MRP_EVENT_PERIODIC);
-                       attrib = attrib->next;
-               }
-               break;
-       case MRP_EVENT_NEW:
-       case MRP_EVENT_JOIN:
-       case MRP_EVENT_RNEW:
-       case MRP_EVENT_RJOININ:
-       case MRP_EVENT_RJOINMT:
-       case MRP_EVENT_LV:
-       case MRP_EVENT_RIN:
-       case MRP_EVENT_RMT:
-       case MRP_EVENT_RLV:
-               mrp_jointimer_start(&(MVRP_db->mrp_db));
-               if (NULL == rattrib)
-                       return -1;      /* XXX internal fault */
-
-               /* update state */
-               attrib = mvrp_lookup(rattrib);
-
-               if (NULL == attrib) {
-                       mvrp_add(rattrib);
-                       attrib = rattrib;
-               } else {
-                       mvrp_merge(rattrib);
-                       free(rattrib);
-               }
-
-               mrp_applicant_fsm(&(attrib->applicant), event);
-               /* remap local requests into registrar events */
-               switch (event) {
-               case MRP_EVENT_NEW:
-                       mrp_registrar_fsm(&(attrib->registrar),
-                                         &(MVRP_db->mrp_db), MRP_EVENT_RNEW);
-                       break;
-               case MRP_EVENT_JOIN:
-                       if (MRP_IN_STATE == attrib->registrar.mrp_state)
-                               mrp_registrar_fsm(&(attrib->registrar),
-                                                 &(MVRP_db->mrp_db),
-                                                 MRP_EVENT_RJOININ);
-                       else
-                               mrp_registrar_fsm(&(attrib->registrar),
-                                                 &(MVRP_db->mrp_db),
-                                                 MRP_EVENT_RJOINMT);
-                       break;
-               case MRP_EVENT_LV:
-                       mrp_registrar_fsm(&(attrib->registrar),
-                                         &(MVRP_db->mrp_db), MRP_EVENT_RLV);
-                       break;
-               default:
-                       rc = mrp_registrar_fsm(&(attrib->registrar),
-                                              &(MVRP_db->mrp_db), event);
-                       if (-1 == rc) {
-                               printf
-                                   ("MVRP registrar error on attrib->attribute = %d\n",
-                                    attrib->attribute);
-                       }
-                       break;
-               }
-               break;
-       default:
-               break;
-       }
-
-       /*
-        * XXX should honor the MVRP_db->mrp_db.registration and
-        * MVRP_db->mrp_db.participant controls
-        */
-
-       /* generate local notifications */
-       attrib = MVRP_db->attrib_list;
-
-       while (NULL != attrib) {
-               if (MRP_NOTIFY_NONE != attrib->registrar.notify) {
-                       mvrp_send_notifications(attrib,
-                                               attrib->registrar.notify);
-                       attrib->registrar.notify = MRP_NOTIFY_NONE;
-               }
-               attrib = attrib->next;
-       }
-
-       return 0;
-}
-
-struct mvrp_attribute *mvrp_alloc()
-{
-       struct mvrp_attribute *attrib;
-
-       attrib = malloc(sizeof(struct mvrp_attribute));
-       if (NULL == attrib)
-               return NULL;
-
-       memset(attrib, 0, sizeof(struct mvrp_attribute));
-
-       attrib->applicant.mrp_state = MRP_VO_STATE;
-       attrib->applicant.tx = 0;
-       attrib->applicant.sndmsg = MRP_SND_NULL;
-       attrib->applicant.encode = MRP_ENCODE_OPTIONAL;
-
-       attrib->registrar.mrp_state = MRP_MT_STATE;
-       attrib->registrar.notify = MRP_NOTIFY_NONE;
-
-       return attrib;
-}
-
-int recv_mvrp_msg()
-{
-       char *msgbuf;
-       struct sockaddr_ll client_addr;
-       struct msghdr msg;
-       struct iovec iov;
-       int bytes = 0;
-       eth_hdr_t *eth;
-       mrpdu_t *mrpdu;
-       mrpdu_message_t *mrpdu_msg;
-       unsigned char *mrpdu_msg_ptr;
-       unsigned char *mrpdu_msg_eof;
-       mrpdu_vectorattrib_t *mrpdu_vectorptr;
-       u_int16_t numvalues;
-       u_int16_t numvalues_processed;
-       int numvectorbytes;
-       u_int8_t vect_3pack;
-       int vectidx;
-       int vectevt[3];
-       int vectevt_idx;
-       u_int16_t vid_firstval;
-       struct mvrp_attribute *attrib;
-       int endmarks;
-
-       msgbuf = (char *)malloc(MAX_FRAME_SIZE);
-       if (NULL == msgbuf)
-               return -1;
-       memset(&msg, 0, sizeof(msg));
-       memset(&client_addr, 0, sizeof(client_addr));
-       memset(msgbuf, 0, MAX_FRAME_SIZE);
-
-       iov.iov_len = MAX_FRAME_SIZE;
-       iov.iov_base = msgbuf;
-       msg.msg_name = &client_addr;
-       msg.msg_namelen = sizeof(client_addr);
-       msg.msg_iov = &iov;
-       msg.msg_iovlen = 1;
-       bytes = recvmsg(mvrp_socket, &msg, 0);
-       if (bytes <= 0)
-               goto out;
-
-       if ((unsigned int)bytes < (sizeof(eth_hdr_t) + sizeof(mrpdu_t) +
-                                  sizeof(mrpdu_message_t)))
-               goto out;
-
-       eth = (eth_hdr_t *) msgbuf;
-
-       /* note that MVRP frames should always arrive untagged (no vlan) */
-       if (MVRP_ETYPE != ntohs(eth->typelen))
-               goto out;
-
-       /* XXX check dest mac address too? */
-
-       mrpdu = (mrpdu_t *) (msgbuf + sizeof(struct eth_hdr));
-
-       /*
-        * ProtocolVersion handling - a receiver must process received frames with a lesser
-        * protcol version consistent with the older protocol processing requirements (e.g. a V2
-        * agent receives a V1 message, the V1 message shoudl be parsed with V1 rules).
-        *
-        * However - if an agent receives a NEWER protocol, the agent shoudl still attempt
-        * to parse the frame. If the agent finds an AttributeType not recognized
-        * the agent discards the current message including any associated trailing vectors
-        * up to the end-mark, and resumes with the next message or until the end of the PDU
-        * is reached.
-        *
-        * If a VectorAttribute is found with an unknown Event for the Type, the specific
-        * VectorAttrute is discarded and processing continues with the next VectorAttribute.
-        */
-
-       if (MVRP_PROT_VER != mrpdu->ProtocolVersion)    /* XXX should accept ... */
-               goto out;
-
-       mrpdu_msg_ptr = (unsigned char *)mrpdu->MessageList;
-
-       mrpdu_msg_eof = (unsigned char *)mrpdu_msg_ptr;
-       mrpdu_msg_eof += bytes;
-       mrpdu_msg_eof -= sizeof(eth_hdr_t);
-       mrpdu_msg_eof -= offsetof(mrpdu_t, MessageList);
-
-       /*
-        * MVRP_VID_TYPE FirstValue is the 12 bit (2-byte) VLAN with
-        * corresponding attrib_length=2
-        *
-        * MVRP uses ThreePackedEvents for all vector encodings
-        *
-        * walk list until we run to the end of the PDU, or encounter a double end-mark
-        */
-
-       endmarks = 0;
-
-       while (mrpdu_msg_ptr < (mrpdu_msg_eof - 2)) {
-               mrpdu_msg = (mrpdu_message_t *) mrpdu_msg_ptr;
-               if ((mrpdu_msg->AttributeType == 0) &&
-                   (mrpdu_msg->AttributeLength == 0)) {
-                       mrpdu_msg_ptr += 2;
-                       endmarks++;
-                       if (endmarks < 2)
-                               continue;       /* end-mark of message-list */
-                       else
-                               break;  /* two endmarks - end of message list */
-               }
-
-               endmarks = 0;
-
-               switch (mrpdu_msg->AttributeType) {
-               case MVRP_VID_TYPE:
-                       if (mrpdu_msg->AttributeLength != 2) {
-                               /* we can seek for an endmark to recover .. but this version
-                                * dumps the entire packet as malformed
-                                */
-                               goto out;
-                       }
-                       /* AttributeListLength not used for MVRP, hence
-                        * Data points to the beginning of the VectorAttributes
-                        */
-                       mrpdu_vectorptr =
-                           (mrpdu_vectorattrib_t *) mrpdu_msg->Data;
-                       mrpdu_msg_ptr = (u_int8_t *) mrpdu_vectorptr;
-
-                       while (!
-                              ((mrpdu_msg_ptr[0] == 0)
-                               && (mrpdu_msg_ptr[1] == 0))) {
-                               numvalues =
-                                   MRPDU_VECT_NUMVALUES(ntohs
-                                                        (mrpdu_vectorptr->
-                                                         VectorHeader));
-
-                               if (0 == numvalues)
-                                       /* Malformed - cant tell how long the trailing vectors are */
-                                       goto out;
-
-                               if ((mrpdu_vectorptr->FirstValue_VectorEvents +
-                                    numvalues / 3) >= mrpdu_msg_eof)
-                                       /* Malformed - runs off the end of the pdu */
-                                       goto out;
-
-                               vid_firstval =
-                                   (((u_int16_t) mrpdu_vectorptr->
-                                     FirstValue_VectorEvents[0]) << 8)
-                                   | mrpdu_vectorptr->
-                                   FirstValue_VectorEvents[1];
-
-                               /* if not an even multiple ... */
-                               if (numvalues != ((numvalues / 3) * 3))
-                                       numvectorbytes = (numvalues / 3) + 1;
-                               else
-                                       numvectorbytes = (numvalues / 3);
-
-                               for (vectidx = 2;
-                                    vectidx <= (numvectorbytes + 2);
-                                    vectidx++) {
-                                       vect_3pack =
-                                           mrpdu_vectorptr->
-                                           FirstValue_VectorEvents[vectidx];
-                                       vectevt[0] = vect_3pack / 36;
-                                       vectevt[1] =
-                                           (vect_3pack - vectevt[0] * 36) / 6;
-                                       vectevt[2] =
-                                           vect_3pack - (36 * vectevt[0]) -
-                                           (6 * vectevt[1]);
-
-                                       numvalues_processed =
-                                           (numvalues > 3 ? 3 : numvalues);
-
-                                       for (vectevt_idx = 0;
-                                            vectevt_idx < numvalues_processed;
-                                            vectevt_idx++) {
-
-                                               if (0xFFF < vid_firstval)       /*discard junk */
-                                                       continue;
-
-                                               attrib = mvrp_alloc();
-                                               if (NULL == attrib)
-                                                       goto out;       /* oops - internal error */
-
-                                               attrib->attribute =
-                                                   vid_firstval;
-                                               vid_firstval++;
-                                               memcpy(attrib->registrar.
-                                                      macaddr, eth->srcaddr,
-                                                      6);
-
-                                               switch (vectevt[vectevt_idx]) {
-                                               case MRPDU_NEW:
-                                                       mvrp_event
-                                                           (MRP_EVENT_RNEW,
-                                                            attrib);
-                                                       break;
-                                               case MRPDU_JOININ:
-                                                       mvrp_event
-                                                           (MRP_EVENT_RJOININ,
-                                                            attrib);
-                                                       break;
-                                               case MRPDU_IN:
-                                                       mvrp_event
-                                                           (MRP_EVENT_RIN,
-                                                            attrib);
-                                                       break;
-                                               case MRPDU_JOINMT:
-                                                       mvrp_event
-                                                           (MRP_EVENT_RJOINMT,
-                                                            attrib);
-                                                       break;
-                                               case MRPDU_MT:
-                                                       mvrp_event
-                                                           (MRP_EVENT_RMT,
-                                                            attrib);
-                                                       break;
-                                               case MRPDU_LV:
-                                                       mvrp_event
-                                                           (MRP_EVENT_RLV,
-                                                            attrib);
-                                                       break;
-                                               default:
-                                                       free(attrib);
-                                                       break;
-                                               }
-                                       }
-                                       numvalues -= numvalues_processed;
-                               }
-
-                               if (MRPDU_VECT_LVA
-                                   (ntohs(mrpdu_vectorptr->VectorHeader)))
-                                       mvrp_event(MRP_EVENT_RLA, NULL);
-
-                               /* 1 byte Type, 1 byte Len, 2 byte FirstValue, and (n) vector bytes */
-                               mrpdu_msg_ptr = (u_int8_t *) mrpdu_vectorptr;
-                               mrpdu_msg_ptr += 4 + numvectorbytes;
-
-                               mrpdu_vectorptr =
-                                   (mrpdu_vectorattrib_t *) mrpdu_msg_ptr;
-                       }
-                       break;
-               default:
-                       /* unrecognized attribute type
-                        * we can seek for an endmark to recover .. but this version
-                        * dumps the entire packet as malformed
-                        */
-                       goto out;
-               }
-       }
-
-       free(msgbuf);
-       return 0;
- out:
-       free(msgbuf);
-
-       return -1;
-}
-
-int
-mvrp_emit_vidvectors(unsigned char *msgbuf, unsigned char *msgbuf_eof,
-                    int *bytes_used, int lva)
-{
-       mrpdu_vectorattrib_t *mrpdu_vectorptr;
-       u_int16_t numvalues;
-       u_int8_t vect_3pack;
-       int vectidx;
-       unsigned int vectevt[3];
-       int vectevt_idx;
-       u_int16_t vid_firstval;
-       struct mvrp_attribute *attrib, *vattrib;
-       mrpdu_message_t *mrpdu_msg;
-       unsigned char *mrpdu_msg_ptr = msgbuf;
-       unsigned char *mrpdu_msg_eof = msgbuf_eof;
-
-       /* need at least 6 bytes for a single vector */
-       if (mrpdu_msg_ptr > (mrpdu_msg_eof - 6))
-               goto oops;
-
-       mrpdu_msg = (mrpdu_message_t *) mrpdu_msg_ptr;
-       mrpdu_msg->AttributeType = MVRP_VID_TYPE;
-       mrpdu_msg->AttributeLength = 2;
-
-       attrib = MVRP_db->attrib_list;
-
-       mrpdu_vectorptr = (mrpdu_vectorattrib_t *) mrpdu_msg->Data;
-
-       while ((mrpdu_msg_ptr < (mrpdu_msg_eof - 2)) && (NULL != attrib)) {
-
-               if (0 == attrib->applicant.tx) {
-                       attrib = attrib->next;
-                       continue;
-               }
-               if (MRP_ENCODE_OPTIONAL == attrib->applicant.encode) {
-                       attrib->applicant.tx = 0;
-                       attrib = attrib->next;
-                       continue;
-               }
-
-               /* pointing to at least one attribute which needs to be transmitted */
-               attrib->applicant.tx = 0;
-               vid_firstval = attrib->attribute;
-               mrpdu_vectorptr->FirstValue_VectorEvents[0] =
-                   (u_int8_t) (attrib->attribute >> 8);
-               mrpdu_vectorptr->FirstValue_VectorEvents[1] =
-                   (u_int8_t) (attrib->attribute);
-
-               switch (attrib->applicant.sndmsg) {
-               case MRP_SND_IN:
-                       /*
-                        * If 'In' in indicated by the applicant attribute, the
-                        * look at the registrar state to determine whether to
-                        * send an In (if registrar is also In) or an Mt if the
-                        * registrar is either Mt or Lv.
-                        */
-                       if (MRP_IN_STATE == attrib->registrar.mrp_state)
-                               vectevt[0] = MRPDU_IN;
-                       else
-                               vectevt[0] = MRPDU_MT;
-                       break;
-               case MRP_SND_NEW:
-                       vectevt[0] = MRPDU_NEW;
-                       break;
-               case MRP_SND_LV:
-                       vectevt[0] = MRPDU_LV;
-                       break;
-               case MRP_SND_JOIN:
-                       /* IF 'Join' in indicated by the applicant, look at
-                        * the corresponding registrar state to determine whether
-                        * to send a JoinIn (if the registar state is 'In') or
-                        * a JoinMt if the registrar state is MT or LV.
-                        */
-                       if (MRP_IN_STATE == attrib->registrar.mrp_state)
-                               vectevt[0] = MRPDU_JOININ;
-                       else
-                               vectevt[0] = MRPDU_JOINMT;
-                       break;
-               default:
-                       /* huh? */
-                       goto oops;
-                       break;
-               }
-
-               vectevt_idx = 1;
-               numvalues = 1;
-               vectevt[1] = 0;
-               vectevt[2] = 0;
-
-               /* now attempt to vectorize contiguous other attributes
-                * which also need to be transmitted
-                */
-
-               vectidx = 2;
-               vattrib = attrib->next;
-
-               while (NULL != vattrib) {
-                       if (0 == vattrib->applicant.tx)
-                               break;
-
-                       vid_firstval++;
-
-                       if (vattrib->attribute != vid_firstval)
-                               break;
-
-                       vattrib->applicant.tx = 0;
-
-                       switch (vattrib->applicant.sndmsg) {
-                       case MRP_SND_IN:
-                               /*
-                                * If 'In' in indicated by the applicant attribute, the
-                                * look at the registrar state to determine whether to
-                                * send an In (if registrar is also In) or an Mt if the
-                                * registrar is either Mt or Lv.
-                                */
-                               if (MRP_IN_STATE ==
-                                   vattrib->registrar.mrp_state)
-                                       vectevt[vectevt_idx] = MRPDU_IN;
-                               else
-                                       vectevt[vectevt_idx] = MRPDU_MT;
-                               break;
-                       case MRP_SND_NEW:
-                               vectevt[vectevt_idx] = MRPDU_NEW;
-                               break;
-                       case MRP_SND_LV:
-                               vectevt[vectevt_idx] = MRPDU_LV;
-                               break;
-                       case MRP_SND_JOIN:
-                               /* IF 'Join' in indicated by the applicant, look at
-                                * the corresponding registrar state to determine whether
-                                * to send a JoinIn (if the registar state is 'In') or
-                                * a JoinMt if the registrar state is MT or LV.
-                                */
-                               if (MRP_IN_STATE == attrib->registrar.mrp_state)
-                                       vectevt[vectevt_idx] = MRPDU_JOININ;
-                               else
-                                       vectevt[vectevt_idx] = MRPDU_JOINMT;
-                               break;
-                       default:
-                               /* huh? */
-                               goto oops;
-                               break;
-                       }
-
-                       vectevt_idx++;
-                       numvalues++;
-
-                       if (vectevt_idx > 2) {
-                               vect_3pack = MRPDU_3PACK_ENCODE(vectevt[0],
-                                                               vectevt[1],
-                                                               vectevt[2]);
-
-                               mrpdu_vectorptr->
-                                   FirstValue_VectorEvents[vectidx] =
-                                   vect_3pack;
-                               vectidx++;
-                               vectevt[0] = 0;
-                               vectevt[1] = 0;
-                               vectevt[2] = 0;
-                               vectevt_idx = 0;
-                       }
-
-                       if (&(mrpdu_vectorptr->FirstValue_VectorEvents[vectidx])
-                           > (mrpdu_msg_eof - 2))
-                               goto oops;
-
-                       vattrib = vattrib->next;
-               }
-
-               /* handle any trailers */
-               if (vectevt_idx > 0) {
-                       vect_3pack = MRPDU_3PACK_ENCODE(vectevt[0],
-                                                       vectevt[1], vectevt[2]);
-
-                       mrpdu_vectorptr->FirstValue_VectorEvents[vectidx] =
-                           vect_3pack;
-                       vectidx++;
-               }
-
-               if (&(mrpdu_vectorptr->FirstValue_VectorEvents[vectidx]) >
-                   (mrpdu_msg_eof - 2))
-                       goto oops;
-
-               mrpdu_vectorptr->VectorHeader = MRPDU_VECT_NUMVALUES(numvalues);
-
-               if (lva)
-                       mrpdu_vectorptr->VectorHeader |= MRPDU_VECT_LVA(0xFFFF);
-
-               mrpdu_vectorptr->VectorHeader =
-                   htons(mrpdu_vectorptr->VectorHeader);
-
-               /* 2 byte header, followed by FirstValues/Vectors - remember vectidx starts at 0 */
-               mrpdu_msg_ptr =
-                   &(mrpdu_vectorptr->FirstValue_VectorEvents[vectidx]);
-
-               attrib = attrib->next;
-
-               mrpdu_vectorptr = (mrpdu_vectorattrib_t *) mrpdu_msg_ptr;
-       }
-
-       if (mrpdu_vectorptr == (mrpdu_vectorattrib_t *) mrpdu_msg->Data) {
-               *bytes_used = 0;
-               return 0;
-       }
-
-       /* endmark */
-       *mrpdu_msg_ptr = 0;
-       mrpdu_msg_ptr++;
-       *mrpdu_msg_ptr = 0;
-       mrpdu_msg_ptr++;
-
-       *bytes_used = (mrpdu_msg_ptr - msgbuf);
-       return 0;
- oops:
-       /* an internal error - caller should assume TXLAF */
-       *bytes_used = 0;
-       return -1;
-}
-
-int mvrp_txpdu(void)
-{
-       unsigned char *msgbuf, *msgbuf_wrptr;
-       int msgbuf_len;
-       int bytes = 0;
-       eth_hdr_t *eth;
-       mrpdu_t *mrpdu;
-       unsigned char *mrpdu_msg_ptr;
-       unsigned char *mrpdu_msg_eof;
-       int rc;
-       int lva = 0;
-
-       msgbuf = (unsigned char *)malloc(MAX_FRAME_SIZE);
-       if (NULL == msgbuf)
-               return -1;
-       msgbuf_len = 0;
-
-       msgbuf_wrptr = msgbuf;
-
-       eth = (eth_hdr_t *) msgbuf_wrptr;
-
-       /* note that MVRP frames should always be untagged (no vlan) */
-       eth->typelen = htons(MVRP_ETYPE);
-       memcpy(eth->destaddr, MVRP_CUSTOMER_BRIDGE_ADDR, sizeof(eth->destaddr));
-       memcpy(eth->srcaddr, STATION_ADDR, sizeof(eth->srcaddr));
-
-       msgbuf_wrptr += sizeof(eth_hdr_t);
-
-       mrpdu = (mrpdu_t *) msgbuf_wrptr;
-
-       /*
-        * ProtocolVersion handling - a receiver must process received frames with a lesser
-        * protcol version consistent with the older protocol processing requirements (e.g. a V2
-        * agent receives a V1 message, the V1 message shoudl be parsed with V1 rules).
-        *
-        * However - if an agent receives a NEWER protocol, the agent shoudl still attempt
-        * to parse the frame. If the agent finds an AttributeType not recognized
-        * the agent discards the current message including any associated trailing vectors
-        * up to the end-mark, and resumes with the next message or until the end of the PDU
-        * is reached.
-        *
-        * If a VectorAttribute is found with an unknown Event for the Type, the specific
-        * VectorAttrute is discarded and processing continues with the next VectorAttribute.
-        */
-
-       mrpdu->ProtocolVersion = MVRP_PROT_VER;
-       mrpdu_msg_ptr = (unsigned char *)mrpdu->MessageList;
-       mrpdu_msg_eof = (unsigned char *)msgbuf + MAX_FRAME_SIZE;
-
-       /*
-        * Iterate over all attributes, transmitting those marked
-        * with 'tx', attempting to coalesce multiple contiguous tx attributes
-        * with appropriate vector encodings.
-        *
-        * MVRP_VID_TYPE FirstValue is the 2-byte VLAN with
-        * corresponding attrib_length=2
-        *
-        * MVRP uses ThreePackedEvents for all vector encodings
-        *
-        * the expanded version of the MRPDU looks like
-        * ProtocolVersion
-        * AttributeType
-        * AttributeLength
-        * <Variable number of>
-        *              LeaveAllEvent | NumberOfValues
-        *              <Variable FirstValue>
-        *              <VectorEventBytes>
-        * EndMark
-        *
-        * in effect, each AttributeType present gets its own 'message' with
-        * variable number of vectors. So with MVRP, you will have at most
-        * one message.
-        */
-
-       if (MVRP_db->mrp_db.lva.tx) {
-               lva = 1;
-               MVRP_db->mrp_db.lva.tx = 0;
-       }
-
-       rc = mvrp_emit_vidvectors(mrpdu_msg_ptr, mrpdu_msg_eof, &bytes, lva);
-       if (-1 == rc)
-               goto out;
-
-       mrpdu_msg_ptr += bytes;
-
-       if (mrpdu_msg_ptr == (unsigned char *)mrpdu->MessageList) {
-               goto out;       /* nothing to send */
-       }
-
-       /* endmark */
-       if (mrpdu_msg_ptr < (mrpdu_msg_eof - 2)) {
-               *mrpdu_msg_ptr = 0;
-               mrpdu_msg_ptr++;
-               *mrpdu_msg_ptr = 0;
-               mrpdu_msg_ptr++;
-       } else
-               goto out;
-
-       msgbuf_len = mrpdu_msg_ptr - msgbuf;
-
-       bytes = send(mvrp_socket, msgbuf, msgbuf_len, 0);
-       if (bytes <= 0)
-               goto out;
-
-       free(msgbuf);
-       return 0;
- out:
-       free(msgbuf);
-       /* caller should assume TXLAF */
-       return -1;
-}
-
-int mvrp_send_notifications(struct mvrp_attribute *attrib, int notify)
-{
-       char *msgbuf;
-       char *stage;
-       char *variant;
-       char *regsrc;
-       client_t *client;
-
-       if (NULL == attrib)
-               return -1;
-
-       msgbuf = (char *)malloc(MAX_MRPD_CMDSZ);
-       if (NULL == msgbuf)
-               return -1;
-
-       stage = variant = regsrc = NULL;
-
-       stage = (char *)malloc(128);
-       variant = (char *)malloc(128);
-       regsrc = (char *)malloc(128);
-
-       if ((NULL == stage) || (NULL == variant) || (NULL == regsrc))
-               goto free_msgbuf;
-
-       memset(msgbuf, 0, MAX_MRPD_CMDSZ);
-
-       sprintf(variant, "%04x", attrib->attribute);
-
-       sprintf(regsrc, "R%02x%02x%02x%02x%02x%02x",
-               attrib->registrar.macaddr[0],
-               attrib->registrar.macaddr[1],
-               attrib->registrar.macaddr[2],
-               attrib->registrar.macaddr[3],
-               attrib->registrar.macaddr[4], attrib->registrar.macaddr[5]);
-       switch (attrib->registrar.mrp_state) {
-       case MRP_IN_STATE:
-               sprintf(stage, "VIN %s %s\n", variant, regsrc);
-               break;
-       case MRP_LV_STATE:
-               sprintf(stage, "VLV %s %s\n", variant, regsrc);
-               break;
-       case MRP_MT_STATE:
-               sprintf(stage, "VMT %s %s\n", variant, regsrc);
+               sprintf(stage, "MMT %s %s\n", variant, regsrc);
                break;
        default:
                break;
@@ -3538,44 +2322,44 @@ int mvrp_send_notifications(struct mvrp_attribute *attrib, int notify)
 
        switch (notify) {
        case MRP_NOTIFY_NEW:
-               snprintf(msgbuf, MAX_MRPD_CMDSZ - 1, "VNE %s", stage);
+               snprintf(msgbuf, MAX_MRPD_CMDSZ - 1, "MNE %s", stage);
                break;
        case MRP_NOTIFY_JOIN:
-               snprintf(msgbuf, MAX_MRPD_CMDSZ - 1, "VJO %s", stage);
+               snprintf(msgbuf, MAX_MRPD_CMDSZ - 1, "MJO %s", stage);
                break;
        case MRP_NOTIFY_LV:
-               snprintf(msgbuf, MAX_MRPD_CMDSZ - 1, "VLE %s", stage);
+               snprintf(msgbuf, MAX_MRPD_CMDSZ - 1, "MLE %s", stage);
                break;
        default:
                goto free_msgbuf;
                break;
        }
 
-       client = MVRP_db->mrp_db.clients;
+       client = MMRP_db->mrp_db.clients;
        while (NULL != client) {
                send_ctl_msg(&(client->client), msgbuf, MAX_MRPD_CMDSZ);
                client = client->next;
        }
 
  free_msgbuf:
-       if (regsrc)
-               free(regsrc);
        if (variant)
                free(variant);
        if (stage)
                free(stage);
+       if (regsrc)
+               free(regsrc);
        free(msgbuf);
        return 0;
 }
 
-int mvrp_dumptable(struct sockaddr_in *client)
+int mmrp_dumptable(struct sockaddr_in *client)
 {
        char *msgbuf;
        char *msgbuf_wrptr;
        char *stage;
        char *variant;
        char *regsrc;
-       struct mvrp_attribute *attrib;
+       struct mmrp_attribute *attrib;
 
        msgbuf = (char *)malloc(MAX_MRPD_CMDSZ);
        if (NULL == msgbuf)
@@ -3594,10 +2378,20 @@ int mvrp_dumptable(struct sockaddr_in *client)
 
        msgbuf_wrptr = msgbuf;
 
-       attrib = MVRP_db->attrib_list;
+       attrib = MMRP_db->attrib_list;
 
        while (NULL != attrib) {
-               sprintf(variant, "%04x", attrib->attribute);
+               if (MMRP_SVCREQ_TYPE == attrib->type) {
+                       sprintf(variant, "S%d", attrib->attribute.svcreq);
+               } else {
+                       sprintf(variant, "M%02x%02x%02x%02x%02x%02x",
+                               attrib->attribute.macaddr[0],
+                               attrib->attribute.macaddr[1],
+                               attrib->attribute.macaddr[2],
+                               attrib->attribute.macaddr[3],
+                               attrib->attribute.macaddr[4],
+                               attrib->attribute.macaddr[5]);
+               }
                sprintf(regsrc, "R%02x%02x%02x%02x%02x%02x",
                        attrib->registrar.macaddr[0],
                        attrib->registrar.macaddr[1],
@@ -3607,13 +2401,13 @@ int mvrp_dumptable(struct sockaddr_in *client)
                        attrib->registrar.macaddr[5]);
                switch (attrib->registrar.mrp_state) {
                case MRP_IN_STATE:
-                       sprintf(stage, "VIN %s %s\n", variant, regsrc);
+                       sprintf(stage, "MIN %s %s\n", variant, regsrc);
                        break;
                case MRP_LV_STATE:
-                       sprintf(stage, "VLV %s %s\n", variant, regsrc);
+                       sprintf(stage, "MLV %s %s\n", variant, regsrc);
                        break;
                case MRP_MT_STATE:
-                       sprintf(stage, "VMT %s %s\n", variant, regsrc);
+                       sprintf(stage, "MMT %s %s\n", variant, regsrc);
                        break;
                default:
                        break;
@@ -3637,105 +2431,208 @@ free_msgbuf:
 
 }
 
-int recv_mvrp_cmd(char *buf, int buflen, struct sockaddr_in *client)
+int recv_mmrp_cmd(char *buf, int buflen, struct sockaddr_in *client)
 {
        int rc;
        char respbuf[8];
-       struct mvrp_attribute *attrib;
-       unsigned int vid_firstval;
-       u_int8_t vid_parsestr[8];
+       struct mmrp_attribute *attrib;
+       u_int8_t svcreq_firstval;
+       u_int8_t macvec_firstval[6];
+       u_int8_t macvec_parsestr[8];
+       int i;
 
-       if (NULL == MVRP_db) {
+       if (NULL == MMRP_db) {
                snprintf(respbuf, sizeof(respbuf) - 1, "ERC %s", buf);
                send_ctl_msg(client, respbuf, sizeof(respbuf));
                goto out;
        }
 
-       rc = client_add(&(MVRP_db->mrp_db.clients), client);
+       rc = client_add(&(MMRP_db->mrp_db.clients), client);
 
        if (buflen < 3)
                return -1;
 
-       if ('V' != buf[0])
+       if ('M' != buf[0])
                return -1;
 
        /*
-        * V?? - query MVRP Registrar VID database
-        * V+? - JOIN a VID
-        * V++   NEW a VID (XXX: note network disturbance)
-        * V-- - LV a VID
+        * M?? - query MMRP Registrar MAC Address database
+        * M+? - JOIN a MAC address or service declaration
+        * M++   NEW a MAC Address (XXX: MMRP doesn't use 'New' though?)
+        * M-- - LV a MAC address or service declaration
         */
        switch (buf[1]) {
        case '?':
-               mvrp_dumptable(client);
+               mmrp_dumptable(client);
                break;
        case '-':
+               /* parse the type - service request or MACVEC */
                if (buflen < 5) {
                        snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s", buf);
                        send_ctl_msg(client, respbuf, sizeof(respbuf));
                        goto out;
                }
-               /* buf[] should look similar to 'V--0001' where VID is in hex */
-               if (buflen < 7) {
-                       snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s", buf);
-                       send_ctl_msg(client, respbuf, sizeof(respbuf));
-                       goto out;
-               }
+               switch (buf[3]) {
+               case 's':
+               case 'S':
+                       /* buf[] should look similar to 'M--s1' */
+                       svcreq_firstval = buf[4] - '0';
+                       if (svcreq_firstval > 1) {
+                               snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s",
+                                        buf);
+                               send_ctl_msg(client, respbuf, sizeof(respbuf));
+                               goto out;
+                       }
+
+                       attrib = mmrp_alloc();
+                       if (NULL == attrib) {
+                               snprintf(respbuf, sizeof(respbuf) - 1, "ERI %s",
+                                        buf);
+                               send_ctl_msg(client, respbuf, sizeof(respbuf));
+                               goto out;       /* oops - internal error */
+                       }
+                       attrib->type = MMRP_SVCREQ_TYPE;
+                       attrib->attribute.svcreq = svcreq_firstval;
+                       memset(attrib->registrar.macaddr, 0, 6);
+
+                       mmrp_event(MRP_EVENT_LV, attrib);
+                       break;
+               case 'm':
+               case 'M':
+                       /*
+                        * XXX note could also register VID with mac address if we ever wanted to
+                        * support more than one Spanning Tree context
+                        */
+
+                       /* buf[] should look similar to 'M--m010203040506' */
+                       if (buflen < 16) {
+                               snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s",
+                                        buf);
+                               send_ctl_msg(client, respbuf, sizeof(respbuf));
+                               goto out;
+                       }
+
+                       memset(macvec_parsestr, 0, sizeof(macvec_parsestr));
+
+                       for (i = 0; i < 6; i++) {
+                               macvec_parsestr[0] = buf[4 + i * 2];
+                               macvec_parsestr[1] = buf[5 + i * 2];
+
+                               rc = sscanf((char *)macvec_parsestr, "%hhx",
+                                           &macvec_firstval[i]);
+                               if (0 == rc) {
+                                       snprintf(respbuf, sizeof(respbuf) - 1,
+                                                "ERP %s", buf);
+                                       send_ctl_msg(client, respbuf,
+                                                    sizeof(respbuf));
+                                       goto out;
+                               }
+                       }
 
-               memset(vid_parsestr, 0, sizeof(vid_parsestr));
+                       attrib = mmrp_alloc();
+                       if (NULL == attrib) {
+                               snprintf(respbuf, sizeof(respbuf) - 1, "ERI %s",
+                                        buf);
+                               send_ctl_msg(client, respbuf, sizeof(respbuf));
+                               goto out;       /* oops - internal error */
+                       }
+                       attrib->type = MMRP_MACVEC_TYPE;
+                       memcpy(attrib->attribute.macaddr, macvec_firstval, 6);
+                       memset(attrib->registrar.macaddr, 0, 6);
 
-               rc = sscanf((char *)&buf[3], "%04x", &vid_firstval);
-               if (0 == rc) {
+                       mmrp_event(MRP_EVENT_LV, attrib);
+                       break;
+               default:
                        snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s", buf);
                        send_ctl_msg(client, respbuf, sizeof(respbuf));
                        goto out;
                }
-
-               attrib = mvrp_alloc();
-               if (NULL == attrib) {
-                       snprintf(respbuf, sizeof(respbuf) - 1, "ERI %s", buf);
-                       send_ctl_msg(client, respbuf, sizeof(respbuf));
-                       goto out;       /* oops - internal error */
-               }
-               attrib->attribute = vid_firstval;
-               memset(attrib->registrar.macaddr, 0, 6);
-
-               mvrp_event(MRP_EVENT_LV, attrib);
                break;
        case '+':
-               /* buf[] should look similar to 'V+?0001' where VID is in hex */
-               if (('?' != buf[2]) && ('+' != buf[2])) {
-                       snprintf(respbuf, sizeof(respbuf) - 1, "ERC %s", buf);
-                       send_ctl_msg(client, respbuf, sizeof(respbuf));
-                       goto out;
-               }
-               if (buflen < 7) {
+               /* parse the type - service request or MACVEC */
+               if (buflen < 5) {
                        snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s", buf);
                        send_ctl_msg(client, respbuf, sizeof(respbuf));
                        goto out;
                }
-               rc = sscanf((char *)&buf[3], "%04x", &vid_firstval);
+               switch (buf[3]) {
+               case 's':
+               case 'S':
+                       /* buf[] should look similar to 'M+?s1'
+                        * or buf[] should look similar to 'M++s1'
+                        */
+                       if (('?' != buf[2]) && ('+' != buf[2])) {
+                               snprintf(respbuf, sizeof(respbuf) - 1, "ERC %s",
+                                        buf);
+                               send_ctl_msg(client, respbuf, sizeof(respbuf));
+                               goto out;
+                       }
+                       svcreq_firstval = buf[4] - '0';
+                       if (svcreq_firstval > 1) {
+                               snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s",
+                                        buf);
+                               send_ctl_msg(client, respbuf, sizeof(respbuf));
+                               goto out;
+                       }
+
+                       attrib = mmrp_alloc();
+                       if (NULL == attrib) {
+                               snprintf(respbuf, sizeof(respbuf) - 1, "ERI %s",
+                                        buf);
+                               send_ctl_msg(client, respbuf, sizeof(respbuf));
+                               goto out;       /* oops - internal error */
+                       }
+                       attrib->type = MMRP_SVCREQ_TYPE;
+                       attrib->attribute.svcreq = svcreq_firstval;
+                       memset(attrib->registrar.macaddr, 0, 6);
+
+                       mmrp_event(MRP_EVENT_JOIN, attrib);
+                       break;
+               case 'm':
+               case 'M':
+                       /* buf[] should look similar to 'M+?m010203040506' */
+                       if (buflen < 16) {
+                               snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s",
+                                        buf);
+                               send_ctl_msg(client, respbuf, sizeof(respbuf));
+                               goto out;
+                       }
+
+                       memset(macvec_parsestr, 0, sizeof(macvec_parsestr));
+
+                       for (i = 0; i < 6; i++) {
+                               macvec_parsestr[0] = buf[4 + i * 2];
+                               macvec_parsestr[1] = buf[5 + i * 2];
+
+                               rc = sscanf((char *)macvec_parsestr, "%hhx",
+                                           &macvec_firstval[i]);
+                               if (0 == rc) {
+                                       snprintf(respbuf, sizeof(respbuf) - 1,
+                                                "ERP %s", buf);
+                                       send_ctl_msg(client, respbuf,
+                                                    sizeof(respbuf));
+                                       goto out;
+                               }
+                       }
+
+                       attrib = mmrp_alloc();
+                       if (NULL == attrib) {
+                               snprintf(respbuf, sizeof(respbuf) - 1, "ERI %s",
+                                        buf);
+                               send_ctl_msg(client, respbuf, sizeof(respbuf));
+                               goto out;       /* oops - internal error */
+                       }
+                       attrib->type = MMRP_MACVEC_TYPE;
+                       memcpy(attrib->attribute.macaddr, macvec_firstval, 6);
+                       memset(attrib->registrar.macaddr, 0, 6);
 
-               if (0 == rc) {
+                       mmrp_event(MRP_EVENT_JOIN, attrib);
+                       break;
+               default:
                        snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s", buf);
                        send_ctl_msg(client, respbuf, sizeof(respbuf));
                        goto out;
                }
-
-               attrib = mvrp_alloc();
-               if (NULL == attrib) {
-                       snprintf(respbuf, sizeof(respbuf) - 1, "ERI %s", buf);
-                       send_ctl_msg(client, respbuf, sizeof(respbuf));
-                       goto out;       /* oops - internal error */
-               }
-               attrib->attribute = vid_firstval;
-               memset(attrib->registrar.macaddr, 0, 6);
-
-               if ('?' == buf[2]) {
-                       mvrp_event(MRP_EVENT_JOIN, attrib);
-               } else {
-                       mvrp_event(MRP_EVENT_NEW, attrib);
-               }
                break;
        default:
                snprintf(respbuf, sizeof(respbuf) - 1, "ERC %s", buf);
@@ -3748,6 +2645,7 @@ int recv_mvrp_cmd(char *buf, int buflen, struct sockaddr_in *client)
        return -1;
 }
 
+
 struct msrp_attribute *msrp_lookup(struct msrp_attribute *rattrib)
 {
        struct msrp_attribute *attrib;
@@ -6821,8 +5719,8 @@ int process_ctl_msg(char *buf, int buflen, struct sockaddr_in *client)
 
        memset(respbuf, 0, sizeof(respbuf));
 
-       /* XXX */
-       /* printf("CMD:%s from CLNT %d\n", buf, client->sin_port); */
+       if (logging_enable)
+               printf("CMD:%s from CLNT %d\n", buf, client->sin_port);
 
        if (buflen < 3) {
                printf("buflen = %d!\b", buflen);
@@ -6835,7 +5733,7 @@ int process_ctl_msg(char *buf, int buflen, struct sockaddr_in *client)
                return recv_mmrp_cmd(buf, buflen, client);
                break;
        case 'V':
-               return recv_mvrp_cmd(buf, buflen, client);
+               return mvrp_recv_cmd(buf, buflen, client);
                break;
        case 'S':
                return recv_msrp_cmd(buf, buflen, client);
@@ -6843,8 +5741,7 @@ int process_ctl_msg(char *buf, int buflen, struct sockaddr_in *client)
        case 'B':
                if (NULL != MMRP_db)
                        client_delete(&(MMRP_db->mrp_db.clients), client);
-               if (NULL != MVRP_db)
-                       client_delete(&(MVRP_db->mrp_db.clients), client);
+               mvrp_bye(client);
                if (NULL != MSRP_db)
                        client_delete(&(MSRP_db->mrp_db.clients), client);
                break;
@@ -7055,62 +5952,7 @@ int init_mmrp(int mmrp_enable)
        return 0;
 }
 
-int init_mvrp(int mvrp_enable)
-{
-       int rc;
-
-       /* XXX doesn't handle re-start */
-
-       mvrp_socket = -1;
-       MVRP_db = NULL;
-
-       if (0 == mvrp_enable) {
-               return 0;
-       }
-
-       rc = init_protocol_socket(MVRP_ETYPE, &mvrp_socket,
-                                 MVRP_CUSTOMER_BRIDGE_ADDR);
-       if (rc < 0)
-               return -1;
-
-       MVRP_db = malloc(sizeof(struct mvrp_database));
-
-       if (NULL == MVRP_db)
-               goto abort_socket;
-
-       memset(MVRP_db, 0, sizeof(struct mvrp_database));
-
-       /* if registration is FIXED or FORBIDDEN
-        * updates from MRP are discarded, and
-        * only IN and JOININ messages are sent
-        */
-       MVRP_db->mrp_db.registration = MRP_REGISTRAR_CTL_NORMAL;        /* default */
-
-       /* if participant role is 'SILENT' (or non-participant)
-        * applicant doesn't send any messages -
-        *
-        * Note - theoretically configured per-attribute
-        */
-       MVRP_db->mrp_db.participant = MRP_APPLICANT_CTL_NORMAL; /* default */
-
-       rc = init_mrp_timers(&(MVRP_db->mrp_db));
-
-       if (rc < 0)
-               goto abort_alloc;
-
-       mrp_lvatimer_fsm(&(MVRP_db->mrp_db), MRP_EVENT_BEGIN);
-       return 0;
 
- abort_alloc:
-       /* free MVRP_db and related structures */
-       free(MVRP_db);
-       MVRP_db = NULL;
- abort_socket:
-       close(mvrp_socket);
-       mvrp_socket = -1;
-       /* XXX */
-       return -1;
-}
 
 int init_msrp(int msrp_enable)
 {
@@ -7227,7 +6069,6 @@ int register_mrp_timers(struct mrp_database *mrp_db, fd_set *fds)
 int mrpd_reclaim()
 {
        struct mmrp_attribute *mattrib, *free_mattrib;
-       struct mvrp_attribute *vattrib, *free_vattrib;
        struct msrp_attribute *sattrib, *free_sattrib;
 
        /*
@@ -7258,28 +6099,7 @@ int mrpd_reclaim()
                                mattrib = mattrib->next;
                }
        }
-       if (NULL != MVRP_db) {
-               vattrib = MVRP_db->attrib_list;
-               while (NULL != vattrib) {
-                       if ((vattrib->registrar.mrp_state == MRP_MT_STATE) && \
-                       ((vattrib->applicant.mrp_state == MRP_VO_STATE) || \
-                           (vattrib->applicant.mrp_state == MRP_AO_STATE) || \
-                               (vattrib->applicant.mrp_state == MRP_QO_STATE)))
-                       {
-                               if (NULL != vattrib->prev)
-                                       vattrib->prev->next = vattrib->next;
-                               else
-                                       MVRP_db->attrib_list = vattrib->next;
-                               if (NULL != vattrib->next)
-                                       vattrib->next->prev = vattrib->prev;
-                               free_vattrib = vattrib;
-                               vattrib = vattrib->next;
-                               mvrp_send_notifications(free_vattrib, MRP_NOTIFY_LV);
-                               free(free_vattrib);
-                       } else
-                               vattrib = vattrib->next;
-               }
-       }
+       mvrp_reclaim();
        if (NULL != MSRP_db) {
                sattrib = MSRP_db->attrib_list;
                while (NULL != sattrib) {
@@ -7339,9 +6159,11 @@ void process_events(void)
                FD_SET(mvrp_socket, &fds);
                if (mvrp_socket > max_fd)
                        max_fd = mvrp_socket;
-
+               /* NULL == MVRP_db checked in  mvrp_init() */
+               /*
                if (NULL == MVRP_db)
                        return;
+                       */
                rc = register_mrp_timers(&(MVRP_db->mrp_db), &fds);
                if (rc > max_fd)
                        max_fd = rc;
@@ -7395,8 +6217,7 @@ void process_events(void)
                                        }
                        }
                        if (mvrp_enable) {
-                               if FD_ISSET
-                                       (mvrp_socket, &sel_fds) recv_mvrp_msg();
+                               if FD_ISSET(mvrp_socket, &sel_fds) mvrp_recv_msg();
                                if FD_ISSET
                                        (MVRP_db->mrp_db.lva_timer, &sel_fds) {
                                        mvrp_event(MRP_EVENT_LVATIMER, NULL);
@@ -7489,7 +6310,6 @@ int main(int argc, char *argv[])
        gc_timer = -1;
 
        MMRP_db = NULL;
-       MVRP_db = NULL;
        MSRP_db = NULL;
 
        lva_next = MRP_LVATIMER_VAL;    /* leaveall timeout in msec */
@@ -7556,7 +6376,7 @@ int main(int argc, char *argv[])
        if (rc)
                goto out;
 
-       rc = init_mvrp(mvrp_enable);
+       rc = mvrp_init(mvrp_enable);
        if (rc)
                goto out;
 
index 0506d6a..303079e 100644 (file)
@@ -368,19 +368,6 @@ struct mmrp_database {
        struct mmrp_attribute   *attrib_list;
 };
 
-struct mvrp_attribute {
-       struct mvrp_attribute           *prev;
-       struct mvrp_attribute           *next;
-       u_int16_t                       attribute;      /* 12-bit VID */
-       mrp_applicant_attribute_t       applicant;
-       mrp_registrar_attribute_t       registrar;
-};
-
-struct mvrp_database {
-       struct mrp_database     mrp_db;
-       struct mvrp_attribute   *attrib_list;
-};
-
 
 struct msrp_attribute {
        struct msrp_attribute           *prev;
@@ -401,3 +388,11 @@ struct msrp_database {
        struct msrp_attribute   *attrib_list;
 };
 
+
+int send_ctl_msg(struct sockaddr_in *client_addr, char *notify_data,
+               int notify_len);
+int client_add(client_t **list, struct sockaddr_in *newclient);
+int init_protocol_socket(u_int16_t etype, int *sock,
+               unsigned char *multicast_addr);
+int init_mrp_timers(struct mrp_database *mrp_db);
+int client_delete(client_t **list, struct sockaddr_in *newclient);
diff --git a/daemons/mrpd/mvrp.c b/daemons/mrpd/mvrp.c
new file mode 100644 (file)
index 0000000..3bbc536
--- /dev/null
@@ -0,0 +1,1264 @@
+/****************************************************************************
+  Copyright (c) 2012, Intel Corporation
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+   3. Neither the name of the Intel Corporation nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+/*
+ * an MRP (MMRP, MVRP, MSRP) endpoint implementation of 802.1Q-2011
+ */
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+#include <syslog.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/mman.h>
+#include <sys/timerfd.h>
+#include <sys/user.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <netpacket/packet.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/ethernet.h>
+#include <sys/un.h>
+
+#include "mrpd.h"
+#include "mvrp.h"
+#include "mrp.h"
+
+int mvrp_send_notifications(struct mvrp_attribute *attrib, int notify);
+int mvrp_txpdu(void);
+
+unsigned char MVRP_CUSTOMER_BRIDGE_ADDR[] = \
+       { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x21 }; /* 81-00 */
+unsigned char MVRP_PROVIDER_BRIDGE_ADDR[] = \
+       { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x0D }; /* 88-A8 */
+extern unsigned char STATION_ADDR[];
+
+/* global variables */
+int mvrp_socket;
+struct mvrp_database *MVRP_db;
+
+/* MVRP */
+
+struct mvrp_attribute *mvrp_lookup(struct mvrp_attribute *rattrib)
+{
+       struct mvrp_attribute *attrib;
+
+       attrib = MVRP_db->attrib_list;
+       while (NULL != attrib) {
+               if (attrib->attribute == rattrib->attribute)
+                       return attrib;
+               attrib = attrib->next;
+       }
+       return NULL;
+}
+
+int mvrp_add(struct mvrp_attribute *rattrib)
+{
+       struct mvrp_attribute *attrib;
+       struct mvrp_attribute *attrib_tail;
+
+       /* XXX do a lookup first to guarantee uniqueness? */
+
+       attrib_tail = attrib = MVRP_db->attrib_list;
+
+       while (NULL != attrib) {
+               if (attrib->attribute < rattrib->attribute) {
+                       /* possible tail insertion ... */
+                       if (NULL != attrib->next) {
+                               attrib = attrib->next;
+                               continue;
+                       }
+                       rattrib->next = attrib->next;
+                       rattrib->prev = attrib;
+                       attrib->next = rattrib;
+                       return 0;
+
+               } else {
+                       /* head insertion ... */
+                       rattrib->next = attrib;
+                       rattrib->prev = attrib->prev;
+                       attrib->prev = rattrib;
+                       if (NULL != rattrib->prev)
+                               rattrib->prev->next = rattrib;
+                       else
+                               MVRP_db->attrib_list = rattrib;
+
+                       return 0;
+               }
+               attrib_tail = attrib;
+               attrib = attrib->next;
+       }
+
+       /* if we are here we didn't need to stitch in a a sorted entry
+        * so append it onto the tail (if it exists)
+        */
+
+       if (NULL == attrib_tail) {
+               rattrib->next = NULL;
+               rattrib->prev = NULL;
+               MVRP_db->attrib_list = rattrib;
+       } else {
+               rattrib->next = NULL;
+               rattrib->prev = attrib_tail;
+               attrib_tail->next = rattrib;
+       }
+
+       return 0;
+}
+
+int mvrp_merge(struct mvrp_attribute *rattrib)
+{
+       struct mvrp_attribute *attrib;
+
+       attrib = mvrp_lookup(rattrib);
+
+       if (NULL == attrib)
+               return -1;      /* shouldn't happen */
+
+       /* primarily we update the last mac address state for diagnostics */
+       memcpy(attrib->registrar.macaddr, rattrib->registrar.macaddr, 6);
+       return 0;
+}
+
+int mvrp_event(int event, struct mvrp_attribute *rattrib)
+{
+       struct mvrp_attribute *attrib;
+       int rc;
+
+       switch (event) {
+       case MRP_EVENT_LVATIMER:
+               mrp_jointimer_stop(&(MVRP_db->mrp_db));
+               /* update state */
+               attrib = MVRP_db->attrib_list;
+
+               while (NULL != attrib) {
+                       mrp_applicant_fsm(&(attrib->applicant), MRP_EVENT_TXLA);
+                       mrp_registrar_fsm(&(attrib->registrar),
+                                         &(MVRP_db->mrp_db), MRP_EVENT_TXLA);
+                       attrib = attrib->next;
+               }
+
+               mrp_lvatimer_fsm(&(MVRP_db->mrp_db), MRP_EVENT_LVATIMER);
+
+               mvrp_txpdu();
+               break;
+       case MRP_EVENT_RLA:
+               mrp_jointimer_stop(&(MVRP_db->mrp_db));
+               /* update state */
+               attrib = MVRP_db->attrib_list;
+
+               while (NULL != attrib) {
+                       mrp_applicant_fsm(&(attrib->applicant), MRP_EVENT_RLA);
+                       mrp_registrar_fsm(&(attrib->registrar),
+                                         &(MVRP_db->mrp_db), MRP_EVENT_RLA);
+                       attrib = attrib->next;
+               }
+
+               mrp_lvatimer_fsm(&(MVRP_db->mrp_db), MRP_EVENT_RLA);
+
+               break;
+       case MRP_EVENT_TX:
+               mrp_jointimer_stop(&(MVRP_db->mrp_db));
+               attrib = MVRP_db->attrib_list;
+
+               while (NULL != attrib) {
+                       mrp_applicant_fsm(&(attrib->applicant), MRP_EVENT_TX);
+                       attrib = attrib->next;
+               }
+
+               mrp_lvatimer_fsm(&(MVRP_db->mrp_db), MRP_EVENT_TX);
+
+               mvrp_txpdu();
+               break;
+       case MRP_EVENT_LVTIMER:
+               mrp_lvtimer_stop(&(MVRP_db->mrp_db));
+               attrib = MVRP_db->attrib_list;
+
+               while (NULL != attrib) {
+                       mrp_registrar_fsm(&(attrib->registrar),
+                                         &(MVRP_db->mrp_db),
+                                         MRP_EVENT_LVTIMER);
+
+                       attrib = attrib->next;
+               }
+               break;
+       case MRP_EVENT_PERIODIC:
+               attrib = MVRP_db->attrib_list;
+
+               while (NULL != attrib) {
+                       mrp_applicant_fsm(&(attrib->applicant),
+                                         MRP_EVENT_PERIODIC);
+                       attrib = attrib->next;
+               }
+               break;
+       case MRP_EVENT_NEW:
+       case MRP_EVENT_JOIN:
+       case MRP_EVENT_RNEW:
+       case MRP_EVENT_RJOININ:
+       case MRP_EVENT_RJOINMT:
+       case MRP_EVENT_LV:
+       case MRP_EVENT_RIN:
+       case MRP_EVENT_RMT:
+       case MRP_EVENT_RLV:
+               mrp_jointimer_start(&(MVRP_db->mrp_db));
+               if (NULL == rattrib)
+                       return -1;      /* XXX internal fault */
+
+               /* update state */
+               attrib = mvrp_lookup(rattrib);
+
+               if (NULL == attrib) {
+                       mvrp_add(rattrib);
+                       attrib = rattrib;
+               } else {
+                       mvrp_merge(rattrib);
+                       free(rattrib);
+               }
+
+               mrp_applicant_fsm(&(attrib->applicant), event);
+               /* remap local requests into registrar events */
+               switch (event) {
+               case MRP_EVENT_NEW:
+                       mrp_registrar_fsm(&(attrib->registrar),
+                                         &(MVRP_db->mrp_db), MRP_EVENT_RNEW);
+                       break;
+               case MRP_EVENT_JOIN:
+                       if (MRP_IN_STATE == attrib->registrar.mrp_state)
+                               mrp_registrar_fsm(&(attrib->registrar),
+                                                 &(MVRP_db->mrp_db),
+                                                 MRP_EVENT_RJOININ);
+                       else
+                               mrp_registrar_fsm(&(attrib->registrar),
+                                                 &(MVRP_db->mrp_db),
+                                                 MRP_EVENT_RJOINMT);
+                       break;
+               case MRP_EVENT_LV:
+                       mrp_registrar_fsm(&(attrib->registrar),
+                                         &(MVRP_db->mrp_db), MRP_EVENT_RLV);
+                       break;
+               default:
+                       rc = mrp_registrar_fsm(&(attrib->registrar),
+                                              &(MVRP_db->mrp_db), event);
+                       if (-1 == rc) {
+                               printf
+                                   ("MVRP registrar error on attrib->attribute = %d\n",
+                                    attrib->attribute);
+                       }
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+
+       /*
+        * XXX should honor the MVRP_db->mrp_db.registration and
+        * MVRP_db->mrp_db.participant controls
+        */
+
+       /* generate local notifications */
+       attrib = MVRP_db->attrib_list;
+
+       while (NULL != attrib) {
+               if (MRP_NOTIFY_NONE != attrib->registrar.notify) {
+                       mvrp_send_notifications(attrib,
+                                               attrib->registrar.notify);
+                       attrib->registrar.notify = MRP_NOTIFY_NONE;
+               }
+               attrib = attrib->next;
+       }
+
+       return 0;
+}
+
+struct mvrp_attribute *mvrp_alloc()
+{
+       struct mvrp_attribute *attrib;
+
+       attrib = malloc(sizeof(struct mvrp_attribute));
+       if (NULL == attrib)
+               return NULL;
+
+       memset(attrib, 0, sizeof(struct mvrp_attribute));
+
+       attrib->applicant.mrp_state = MRP_VO_STATE;
+       attrib->applicant.tx = 0;
+       attrib->applicant.sndmsg = MRP_SND_NULL;
+       attrib->applicant.encode = MRP_ENCODE_OPTIONAL;
+
+       attrib->registrar.mrp_state = MRP_MT_STATE;
+       attrib->registrar.notify = MRP_NOTIFY_NONE;
+
+       return attrib;
+}
+
+int mvrp_recv_msg(void)
+{
+       char *msgbuf;
+       struct sockaddr_ll client_addr;
+       struct msghdr msg;
+       struct iovec iov;
+       int bytes = 0;
+       eth_hdr_t *eth;
+       mrpdu_t *mrpdu;
+       mrpdu_message_t *mrpdu_msg;
+       unsigned char *mrpdu_msg_ptr;
+       unsigned char *mrpdu_msg_eof;
+       mrpdu_vectorattrib_t *mrpdu_vectorptr;
+       u_int16_t numvalues;
+       u_int16_t numvalues_processed;
+       int numvectorbytes;
+       u_int8_t vect_3pack;
+       int vectidx;
+       int vectevt[3];
+       int vectevt_idx;
+       u_int16_t vid_firstval;
+       struct mvrp_attribute *attrib;
+       int endmarks;
+
+       msgbuf = (char *)malloc(MAX_FRAME_SIZE);
+       if (NULL == msgbuf)
+               return -1;
+       memset(&msg, 0, sizeof(msg));
+       memset(&client_addr, 0, sizeof(client_addr));
+       memset(msgbuf, 0, MAX_FRAME_SIZE);
+
+       iov.iov_len = MAX_FRAME_SIZE;
+       iov.iov_base = msgbuf;
+       msg.msg_name = &client_addr;
+       msg.msg_namelen = sizeof(client_addr);
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       bytes = recvmsg(mvrp_socket, &msg, 0);
+       if (bytes <= 0)
+               goto out;
+
+       if ((unsigned int)bytes < (sizeof(eth_hdr_t) + sizeof(mrpdu_t) +
+                                  sizeof(mrpdu_message_t)))
+               goto out;
+
+       eth = (eth_hdr_t *) msgbuf;
+
+       /* note that MVRP frames should always arrive untagged (no vlan) */
+       if (MVRP_ETYPE != ntohs(eth->typelen))
+               goto out;
+
+       /* XXX check dest mac address too? */
+
+       mrpdu = (mrpdu_t *) (msgbuf + sizeof(struct eth_hdr));
+
+       /*
+        * ProtocolVersion handling - a receiver must process received frames with a lesser
+        * protcol version consistent with the older protocol processing requirements (e.g. a V2
+        * agent receives a V1 message, the V1 message shoudl be parsed with V1 rules).
+        *
+        * However - if an agent receives a NEWER protocol, the agent shoudl still attempt
+        * to parse the frame. If the agent finds an AttributeType not recognized
+        * the agent discards the current message including any associated trailing vectors
+        * up to the end-mark, and resumes with the next message or until the end of the PDU
+        * is reached.
+        *
+        * If a VectorAttribute is found with an unknown Event for the Type, the specific
+        * VectorAttrute is discarded and processing continues with the next VectorAttribute.
+        */
+
+       if (MVRP_PROT_VER != mrpdu->ProtocolVersion)    /* XXX should accept ... */
+               goto out;
+
+       mrpdu_msg_ptr = (unsigned char *)mrpdu->MessageList;
+
+       mrpdu_msg_eof = (unsigned char *)mrpdu_msg_ptr;
+       mrpdu_msg_eof += bytes;
+       mrpdu_msg_eof -= sizeof(eth_hdr_t);
+       mrpdu_msg_eof -= offsetof(mrpdu_t, MessageList);
+
+       /*
+        * MVRP_VID_TYPE FirstValue is the 12 bit (2-byte) VLAN with
+        * corresponding attrib_length=2
+        *
+        * MVRP uses ThreePackedEvents for all vector encodings
+        *
+        * walk list until we run to the end of the PDU, or encounter a double end-mark
+        */
+
+       endmarks = 0;
+
+       while (mrpdu_msg_ptr < (mrpdu_msg_eof - 2)) {
+               mrpdu_msg = (mrpdu_message_t *) mrpdu_msg_ptr;
+               if ((mrpdu_msg->AttributeType == 0) &&
+                   (mrpdu_msg->AttributeLength == 0)) {
+                       mrpdu_msg_ptr += 2;
+                       endmarks++;
+                       if (endmarks < 2)
+                               continue;       /* end-mark of message-list */
+                       else
+                               break;  /* two endmarks - end of message list */
+               }
+
+               endmarks = 0;
+
+               switch (mrpdu_msg->AttributeType) {
+               case MVRP_VID_TYPE:
+                       if (mrpdu_msg->AttributeLength != 2) {
+                               /* we can seek for an endmark to recover .. but this version
+                                * dumps the entire packet as malformed
+                                */
+                               goto out;
+                       }
+                       /* AttributeListLength not used for MVRP, hence
+                        * Data points to the beginning of the VectorAttributes
+                        */
+                       mrpdu_vectorptr =
+                           (mrpdu_vectorattrib_t *) mrpdu_msg->Data;
+                       mrpdu_msg_ptr = (u_int8_t *) mrpdu_vectorptr;
+
+                       while (!
+                              ((mrpdu_msg_ptr[0] == 0)
+                               && (mrpdu_msg_ptr[1] == 0))) {
+                               numvalues =
+                                   MRPDU_VECT_NUMVALUES(ntohs
+                                                        (mrpdu_vectorptr->
+                                                         VectorHeader));
+
+                               if (0 == numvalues)
+                                       /* Malformed - cant tell how long the trailing vectors are */
+                                       goto out;
+
+                               if ((mrpdu_vectorptr->FirstValue_VectorEvents +
+                                    numvalues / 3) >= mrpdu_msg_eof)
+                                       /* Malformed - runs off the end of the pdu */
+                                       goto out;
+
+                               vid_firstval =
+                                   (((u_int16_t) mrpdu_vectorptr->
+                                     FirstValue_VectorEvents[0]) << 8)
+                                   | mrpdu_vectorptr->
+                                   FirstValue_VectorEvents[1];
+
+                               /* if not an even multiple ... */
+                               if (numvalues != ((numvalues / 3) * 3))
+                                       numvectorbytes = (numvalues / 3) + 1;
+                               else
+                                       numvectorbytes = (numvalues / 3);
+
+                               for (vectidx = 2;
+                                    vectidx <= (numvectorbytes + 2);
+                                    vectidx++) {
+                                       vect_3pack =
+                                           mrpdu_vectorptr->
+                                           FirstValue_VectorEvents[vectidx];
+                                       vectevt[0] = vect_3pack / 36;
+                                       vectevt[1] =
+                                           (vect_3pack - vectevt[0] * 36) / 6;
+                                       vectevt[2] =
+                                           vect_3pack - (36 * vectevt[0]) -
+                                           (6 * vectevt[1]);
+
+                                       numvalues_processed =
+                                           (numvalues > 3 ? 3 : numvalues);
+
+                                       for (vectevt_idx = 0;
+                                            vectevt_idx < numvalues_processed;
+                                            vectevt_idx++) {
+
+                                               if (0xFFF < vid_firstval)       /*discard junk */
+                                                       continue;
+
+                                               attrib = mvrp_alloc();
+                                               if (NULL == attrib)
+                                                       goto out;       /* oops - internal error */
+
+                                               attrib->attribute =
+                                                   vid_firstval;
+                                               vid_firstval++;
+                                               memcpy(attrib->registrar.
+                                                      macaddr, eth->srcaddr,
+                                                      6);
+
+                                               switch (vectevt[vectevt_idx]) {
+                                               case MRPDU_NEW:
+                                                       mvrp_event
+                                                           (MRP_EVENT_RNEW,
+                                                            attrib);
+                                                       break;
+                                               case MRPDU_JOININ:
+                                                       mvrp_event
+                                                           (MRP_EVENT_RJOININ,
+                                                            attrib);
+                                                       break;
+                                               case MRPDU_IN:
+                                                       mvrp_event
+                                                           (MRP_EVENT_RIN,
+                                                            attrib);
+                                                       break;
+                                               case MRPDU_JOINMT:
+                                                       mvrp_event
+                                                           (MRP_EVENT_RJOINMT,
+                                                            attrib);
+                                                       break;
+                                               case MRPDU_MT:
+                                                       mvrp_event
+                                                           (MRP_EVENT_RMT,
+                                                            attrib);
+                                                       break;
+                                               case MRPDU_LV:
+                                                       mvrp_event
+                                                           (MRP_EVENT_RLV,
+                                                            attrib);
+                                                       break;
+                                               default:
+                                                       free(attrib);
+                                                       break;
+                                               }
+                                       }
+                                       numvalues -= numvalues_processed;
+                               }
+
+                               if (MRPDU_VECT_LVA
+                                   (ntohs(mrpdu_vectorptr->VectorHeader)))
+                                       mvrp_event(MRP_EVENT_RLA, NULL);
+
+                               /* 1 byte Type, 1 byte Len, 2 byte FirstValue, and (n) vector bytes */
+                               mrpdu_msg_ptr = (u_int8_t *) mrpdu_vectorptr;
+                               mrpdu_msg_ptr += 4 + numvectorbytes;
+
+                               mrpdu_vectorptr =
+                                   (mrpdu_vectorattrib_t *) mrpdu_msg_ptr;
+                       }
+                       break;
+               default:
+                       /* unrecognized attribute type
+                        * we can seek for an endmark to recover .. but this version
+                        * dumps the entire packet as malformed
+                        */
+                       goto out;
+               }
+       }
+
+       free(msgbuf);
+       return 0;
+ out:
+       free(msgbuf);
+
+       return -1;
+}
+
+int
+mvrp_emit_vidvectors(unsigned char *msgbuf, unsigned char *msgbuf_eof,
+                    int *bytes_used, int lva)
+{
+       mrpdu_vectorattrib_t *mrpdu_vectorptr;
+       u_int16_t numvalues;
+       u_int8_t vect_3pack;
+       int vectidx;
+       unsigned int vectevt[3];
+       int vectevt_idx;
+       u_int16_t vid_firstval;
+       struct mvrp_attribute *attrib, *vattrib;
+       mrpdu_message_t *mrpdu_msg;
+
+       unsigned char *mrpdu_msg_ptr = msgbuf;
+       unsigned char *mrpdu_msg_eof = msgbuf_eof;
+
+       /* need at least 6 bytes for a single vector */
+       if (mrpdu_msg_ptr > (mrpdu_msg_eof - 6))
+               goto oops;
+
+       mrpdu_msg = (mrpdu_message_t *) mrpdu_msg_ptr;
+       mrpdu_msg->AttributeType = MVRP_VID_TYPE;
+       mrpdu_msg->AttributeLength = 2;
+
+       attrib = MVRP_db->attrib_list;
+
+       mrpdu_vectorptr = (mrpdu_vectorattrib_t *) mrpdu_msg->Data;
+
+       while ((mrpdu_msg_ptr < (mrpdu_msg_eof - 2)) && (NULL != attrib)) {
+
+               if (0 == attrib->applicant.tx) {
+                       attrib = attrib->next;
+                       continue;
+               }
+               if (MRP_ENCODE_OPTIONAL == attrib->applicant.encode) {
+                       attrib->applicant.tx = 0;
+                       attrib = attrib->next;
+                       continue;
+               }
+
+               /* pointing to at least one attribute which needs to be transmitted */
+               attrib->applicant.tx = 0;
+               vid_firstval = attrib->attribute;
+               mrpdu_vectorptr->FirstValue_VectorEvents[0] =
+                   (u_int8_t) (attrib->attribute >> 8);
+               mrpdu_vectorptr->FirstValue_VectorEvents[1] =
+                   (u_int8_t) (attrib->attribute);
+
+               switch (attrib->applicant.sndmsg) {
+               case MRP_SND_IN:
+                       /*
+                        * If 'In' in indicated by the applicant attribute, the
+                        * look at the registrar state to determine whether to
+                        * send an In (if registrar is also In) or an Mt if the
+                        * registrar is either Mt or Lv.
+                        */
+                       if (MRP_IN_STATE == attrib->registrar.mrp_state)
+                               vectevt[0] = MRPDU_IN;
+                       else
+                               vectevt[0] = MRPDU_MT;
+                       break;
+               case MRP_SND_NEW:
+                       vectevt[0] = MRPDU_NEW;
+                       break;
+               case MRP_SND_LV:
+                       vectevt[0] = MRPDU_LV;
+                       break;
+               case MRP_SND_JOIN:
+                       /* IF 'Join' in indicated by the applicant, look at
+                        * the corresponding registrar state to determine whether
+                        * to send a JoinIn (if the registar state is 'In') or
+                        * a JoinMt if the registrar state is MT or LV.
+                        */
+                       if (MRP_IN_STATE == attrib->registrar.mrp_state)
+                               vectevt[0] = MRPDU_JOININ;
+                       else
+                               vectevt[0] = MRPDU_JOINMT;
+                       break;
+               default:
+                       /* huh? */
+                       goto oops;
+                       break;
+               }
+
+               vectevt_idx = 1;
+               numvalues = 1;
+               vectevt[1] = 0;
+               vectevt[2] = 0;
+
+               /* now attempt to vectorize contiguous other attributes
+                * which also need to be transmitted
+                */
+
+               vectidx = 2;
+               vattrib = attrib->next;
+
+               while (NULL != vattrib) {
+                       if (0 == vattrib->applicant.tx)
+                               break;
+
+                       vid_firstval++;
+
+                       if (vattrib->attribute != vid_firstval)
+                               break;
+
+                       vattrib->applicant.tx = 0;
+
+                       switch (vattrib->applicant.sndmsg) {
+                       case MRP_SND_IN:
+                               /*
+                                * If 'In' in indicated by the applicant attribute, the
+                                * look at the registrar state to determine whether to
+                                * send an In (if registrar is also In) or an Mt if the
+                                * registrar is either Mt or Lv.
+                                */
+                               if (MRP_IN_STATE ==
+                                   vattrib->registrar.mrp_state)
+                                       vectevt[vectevt_idx] = MRPDU_IN;
+                               else
+                                       vectevt[vectevt_idx] = MRPDU_MT;
+                               break;
+                       case MRP_SND_NEW:
+                               vectevt[vectevt_idx] = MRPDU_NEW;
+                               break;
+                       case MRP_SND_LV:
+                               vectevt[vectevt_idx] = MRPDU_LV;
+                               break;
+                       case MRP_SND_JOIN:
+                               /* IF 'Join' in indicated by the applicant, look at
+                                * the corresponding registrar state to determine whether
+                                * to send a JoinIn (if the registar state is 'In') or
+                                * a JoinMt if the registrar state is MT or LV.
+                                */
+                               if (MRP_IN_STATE == attrib->registrar.mrp_state)
+                                       vectevt[vectevt_idx] = MRPDU_JOININ;
+                               else
+                                       vectevt[vectevt_idx] = MRPDU_JOINMT;
+                               break;
+                       default:
+                               /* huh? */
+                               goto oops;
+                               break;
+                       }
+
+                       vectevt_idx++;
+                       numvalues++;
+
+                       if (vectevt_idx > 2) {
+                               vect_3pack = MRPDU_3PACK_ENCODE(vectevt[0],
+                                                               vectevt[1],
+                                                               vectevt[2]);
+
+                               mrpdu_vectorptr->
+                                   FirstValue_VectorEvents[vectidx] =
+                                   vect_3pack;
+                               vectidx++;
+                               vectevt[0] = 0;
+                               vectevt[1] = 0;
+                               vectevt[2] = 0;
+                               vectevt_idx = 0;
+                       }
+
+                       if (&(mrpdu_vectorptr->FirstValue_VectorEvents[vectidx])
+                           > (mrpdu_msg_eof - 2))
+                               goto oops;
+
+                       vattrib = vattrib->next;
+               }
+
+               /* handle any trailers */
+               if (vectevt_idx > 0) {
+                       vect_3pack = MRPDU_3PACK_ENCODE(vectevt[0],
+                                                       vectevt[1], vectevt[2]);
+
+                       mrpdu_vectorptr->FirstValue_VectorEvents[vectidx] =
+                           vect_3pack;
+                       vectidx++;
+               }
+
+               if (&(mrpdu_vectorptr->FirstValue_VectorEvents[vectidx]) >
+                   (mrpdu_msg_eof - 2))
+                       goto oops;
+
+               mrpdu_vectorptr->VectorHeader = MRPDU_VECT_NUMVALUES(numvalues);
+
+               if (lva)
+                       mrpdu_vectorptr->VectorHeader |= MRPDU_VECT_LVA(0xFFFF);
+
+               mrpdu_vectorptr->VectorHeader =
+                   htons(mrpdu_vectorptr->VectorHeader);
+
+               /* 2 byte header, followed by FirstValues/Vectors - remember vectidx starts at 0 */
+               mrpdu_msg_ptr =
+                   &(mrpdu_vectorptr->FirstValue_VectorEvents[vectidx]);
+
+               attrib = attrib->next;
+
+               mrpdu_vectorptr = (mrpdu_vectorattrib_t *) mrpdu_msg_ptr;
+       }
+
+       if (mrpdu_vectorptr == (mrpdu_vectorattrib_t *) mrpdu_msg->Data) {
+               *bytes_used = 0;
+               return 0;
+       }
+
+       /* endmark */
+       *mrpdu_msg_ptr = 0;
+       mrpdu_msg_ptr++;
+       *mrpdu_msg_ptr = 0;
+       mrpdu_msg_ptr++;
+
+       *bytes_used = (mrpdu_msg_ptr - msgbuf);
+       return 0;
+ oops:
+       /* an internal error - caller should assume TXLAF */
+       *bytes_used = 0;
+       return -1;
+}
+
+int mvrp_txpdu(void)
+{
+       unsigned char *msgbuf, *msgbuf_wrptr;
+       int msgbuf_len;
+       int bytes = 0;
+       eth_hdr_t *eth;
+       mrpdu_t *mrpdu;
+       unsigned char *mrpdu_msg_ptr;
+       unsigned char *mrpdu_msg_eof;
+       int rc;
+       int lva = 0;
+
+       msgbuf = (unsigned char *)malloc(MAX_FRAME_SIZE);
+       if (NULL == msgbuf)
+               return -1;
+       msgbuf_len = 0;
+
+       msgbuf_wrptr = msgbuf;
+
+       eth = (eth_hdr_t *) msgbuf_wrptr;
+
+       /* note that MVRP frames should always be untagged (no vlan) */
+       eth->typelen = htons(MVRP_ETYPE);
+       memcpy(eth->destaddr, MVRP_CUSTOMER_BRIDGE_ADDR, sizeof(eth->destaddr));
+       memcpy(eth->srcaddr, STATION_ADDR, sizeof(eth->srcaddr));
+
+       msgbuf_wrptr += sizeof(eth_hdr_t);
+
+       mrpdu = (mrpdu_t *) msgbuf_wrptr;
+
+       /*
+        * ProtocolVersion handling - a receiver must process received frames with a lesser
+        * protcol version consistent with the older protocol processing requirements (e.g. a V2
+        * agent receives a V1 message, the V1 message shoudl be parsed with V1 rules).
+        *
+        * However - if an agent receives a NEWER protocol, the agent shoudl still attempt
+        * to parse the frame. If the agent finds an AttributeType not recognized
+        * the agent discards the current message including any associated trailing vectors
+        * up to the end-mark, and resumes with the next message or until the end of the PDU
+        * is reached.
+        *
+        * If a VectorAttribute is found with an unknown Event for the Type, the specific
+        * VectorAttrute is discarded and processing continues with the next VectorAttribute.
+        */
+
+       mrpdu->ProtocolVersion = MVRP_PROT_VER;
+       mrpdu_msg_ptr = (unsigned char *)mrpdu->MessageList;
+       mrpdu_msg_eof = (unsigned char *)msgbuf + MAX_FRAME_SIZE;
+
+       /*
+        * Iterate over all attributes, transmitting those marked
+        * with 'tx', attempting to coalesce multiple contiguous tx attributes
+        * with appropriate vector encodings.
+        *
+        * MVRP_VID_TYPE FirstValue is the 2-byte VLAN with
+        * corresponding attrib_length=2
+        *
+        * MVRP uses ThreePackedEvents for all vector encodings
+        *
+        * the expanded version of the MRPDU looks like
+        * ProtocolVersion
+        * AttributeType
+        * AttributeLength
+        * <Variable number of>
+        *              LeaveAllEvent | NumberOfValues
+        *              <Variable FirstValue>
+        *              <VectorEventBytes>
+        * EndMark
+        *
+        * in effect, each AttributeType present gets its own 'message' with
+        * variable number of vectors. So with MVRP, you will have at most
+        * one message.
+        */
+
+       if (MVRP_db->mrp_db.lva.tx) {
+               lva = 1;
+               MVRP_db->mrp_db.lva.tx = 0;
+       }
+
+       rc = mvrp_emit_vidvectors(mrpdu_msg_ptr, mrpdu_msg_eof, &bytes, lva);
+       if (-1 == rc)
+               goto out;
+
+       mrpdu_msg_ptr += bytes;
+
+       if (mrpdu_msg_ptr == (unsigned char *)mrpdu->MessageList) {
+               goto out;       /* nothing to send */
+       }
+
+       /* endmark */
+       if (mrpdu_msg_ptr < (mrpdu_msg_eof - 2)) {
+               *mrpdu_msg_ptr = 0;
+               mrpdu_msg_ptr++;
+               *mrpdu_msg_ptr = 0;
+               mrpdu_msg_ptr++;
+       } else
+               goto out;
+
+       msgbuf_len = mrpdu_msg_ptr - msgbuf;
+
+       bytes = send(mvrp_socket, msgbuf, msgbuf_len, 0);
+       if (bytes <= 0)
+               goto out;
+
+       free(msgbuf);
+       return 0;
+ out:
+       free(msgbuf);
+       /* caller should assume TXLAF */
+       return -1;
+}
+
+int mvrp_send_notifications(struct mvrp_attribute *attrib, int notify)
+{
+       char *msgbuf;
+       char *stage;
+       char *variant;
+       char *regsrc;
+       client_t *client;
+
+       if (NULL == attrib)
+               return -1;
+
+       msgbuf = (char *)malloc(MAX_MRPD_CMDSZ);
+       if (NULL == msgbuf)
+               return -1;
+
+       stage = variant = regsrc = NULL;
+
+       stage = (char *)malloc(128);
+       variant = (char *)malloc(128);
+       regsrc = (char *)malloc(128);
+
+       if ((NULL == stage) || (NULL == variant) || (NULL == regsrc))
+               goto free_msgbuf;
+
+       memset(msgbuf, 0, MAX_MRPD_CMDSZ);
+
+       sprintf(variant, "%04x", attrib->attribute);
+
+       sprintf(regsrc, "R%02x%02x%02x%02x%02x%02x",
+               attrib->registrar.macaddr[0],
+               attrib->registrar.macaddr[1],
+               attrib->registrar.macaddr[2],
+               attrib->registrar.macaddr[3],
+               attrib->registrar.macaddr[4], attrib->registrar.macaddr[5]);
+       switch (attrib->registrar.mrp_state) {
+       case MRP_IN_STATE:
+               sprintf(stage, "VIN %s %s\n", variant, regsrc);
+               break;
+       case MRP_LV_STATE:
+               sprintf(stage, "VLV %s %s\n", variant, regsrc);
+               break;
+       case MRP_MT_STATE:
+               sprintf(stage, "VMT %s %s\n", variant, regsrc);
+               break;
+       default:
+               break;
+       }
+
+       switch (notify) {
+       case MRP_NOTIFY_NEW:
+               snprintf(msgbuf, MAX_MRPD_CMDSZ - 1, "VNE %s", stage);
+               break;
+       case MRP_NOTIFY_JOIN:
+               snprintf(msgbuf, MAX_MRPD_CMDSZ - 1, "VJO %s", stage);
+               break;
+       case MRP_NOTIFY_LV:
+               snprintf(msgbuf, MAX_MRPD_CMDSZ - 1, "VLE %s", stage);
+               break;
+       default:
+               goto free_msgbuf;
+               break;
+       }
+
+       client = MVRP_db->mrp_db.clients;
+       while (NULL != client) {
+               send_ctl_msg(&(client->client), msgbuf, MAX_MRPD_CMDSZ);
+               client = client->next;
+       }
+
+ free_msgbuf:
+       if (regsrc)
+               free(regsrc);
+       if (variant)
+               free(variant);
+       if (stage)
+               free(stage);
+       free(msgbuf);
+       return 0;
+}
+
+int mvrp_dumptable(struct sockaddr_in *client)
+{
+       char *msgbuf;
+       char *msgbuf_wrptr;
+       char *stage;
+       char *variant;
+       char *regsrc;
+       struct mvrp_attribute *attrib;
+
+       msgbuf = (char *)malloc(MAX_MRPD_CMDSZ);
+       if (NULL == msgbuf)
+               return -1;
+
+       stage = variant = regsrc = NULL;
+
+       stage = (char *)malloc(128);
+       variant = (char *)malloc(128);
+       regsrc = (char *)malloc(128);
+
+       if ((NULL == stage) || (NULL == variant) || (NULL == regsrc))
+               goto free_msgbuf;
+
+       memset(msgbuf, 0, MAX_MRPD_CMDSZ);
+
+       msgbuf_wrptr = msgbuf;
+
+       attrib = MVRP_db->attrib_list;
+
+       while (NULL != attrib) {
+               sprintf(variant, "%04x", attrib->attribute);
+               sprintf(regsrc, "R%02x%02x%02x%02x%02x%02x",
+                       attrib->registrar.macaddr[0],
+                       attrib->registrar.macaddr[1],
+                       attrib->registrar.macaddr[2],
+                       attrib->registrar.macaddr[3],
+                       attrib->registrar.macaddr[4],
+                       attrib->registrar.macaddr[5]);
+               switch (attrib->registrar.mrp_state) {
+               case MRP_IN_STATE:
+                       sprintf(stage, "VIN %s %s\n", variant, regsrc);
+                       break;
+               case MRP_LV_STATE:
+                       sprintf(stage, "VLV %s %s\n", variant, regsrc);
+                       break;
+               case MRP_MT_STATE:
+                       sprintf(stage, "VMT %s %s\n", variant, regsrc);
+                       break;
+               default:
+                       break;
+               }
+               sprintf(msgbuf_wrptr, "%s", stage);
+               msgbuf_wrptr += strnlen(stage, 128);
+               attrib = attrib->next;
+       }
+
+       send_ctl_msg(client, msgbuf, MAX_MRPD_CMDSZ);
+
+free_msgbuf:
+       if (regsrc)
+               free(regsrc);
+       if (variant)
+               free(variant);
+       if (stage)
+               free(stage);
+       free(msgbuf);
+       return 0;
+
+}
+
+int mvrp_recv_cmd(char *buf, int buflen, struct sockaddr_in *client)
+{
+       int rc;
+       char respbuf[8];
+       struct mvrp_attribute *attrib;
+       unsigned int vid_firstval;
+       u_int8_t vid_parsestr[8];
+
+       if (NULL == MVRP_db) {
+               snprintf(respbuf, sizeof(respbuf) - 1, "ERC %s", buf);
+               send_ctl_msg(client, respbuf, sizeof(respbuf));
+               goto out;
+       }
+
+       rc = client_add(&(MVRP_db->mrp_db.clients), client);
+
+       if (buflen < 3)
+               return -1;
+
+       if ('V' != buf[0])
+               return -1;
+
+       /*
+        * V?? - query MVRP Registrar VID database
+        * V+? - JOIN a VID
+        * V++   NEW a VID (XXX: note network disturbance)
+        * V-- - LV a VID
+        */
+       switch (buf[1]) {
+       case '?':
+               mvrp_dumptable(client);
+               break;
+       case '-':
+               if (buflen < 5) {
+                       snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s", buf);
+                       send_ctl_msg(client, respbuf, sizeof(respbuf));
+                       goto out;
+               }
+               /* buf[] should look similar to 'V--0001' where VID is in hex */
+               if (buflen < 7) {
+                       snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s", buf);
+                       send_ctl_msg(client, respbuf, sizeof(respbuf));
+                       goto out;
+               }
+
+               memset(vid_parsestr, 0, sizeof(vid_parsestr));
+
+               rc = sscanf((char *)&buf[3], "%04x", &vid_firstval);
+               if (0 == rc) {
+                       snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s", buf);
+                       send_ctl_msg(client, respbuf, sizeof(respbuf));
+                       goto out;
+               }
+
+               attrib = mvrp_alloc();
+               if (NULL == attrib) {
+                       snprintf(respbuf, sizeof(respbuf) - 1, "ERI %s", buf);
+                       send_ctl_msg(client, respbuf, sizeof(respbuf));
+                       goto out;       /* oops - internal error */
+               }
+               attrib->attribute = vid_firstval;
+               memset(attrib->registrar.macaddr, 0, 6);
+
+               mvrp_event(MRP_EVENT_LV, attrib);
+               break;
+       case '+':
+               /* buf[] should look similar to 'V+?0001' where VID is in hex */
+               if (('?' != buf[2]) && ('+' != buf[2])) {
+                       snprintf(respbuf, sizeof(respbuf) - 1, "ERC %s", buf);
+                       send_ctl_msg(client, respbuf, sizeof(respbuf));
+                       goto out;
+               }
+               if (buflen < 7) {
+                       snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s", buf);
+                       send_ctl_msg(client, respbuf, sizeof(respbuf));
+                       goto out;
+               }
+               rc = sscanf((char *)&buf[3], "%04x", &vid_firstval);
+
+               if (0 == rc) {
+                       snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s", buf);
+                       send_ctl_msg(client, respbuf, sizeof(respbuf));
+                       goto out;
+               }
+
+               attrib = mvrp_alloc();
+               if (NULL == attrib) {
+                       snprintf(respbuf, sizeof(respbuf) - 1, "ERI %s", buf);
+                       send_ctl_msg(client, respbuf, sizeof(respbuf));
+                       goto out;       /* oops - internal error */
+               }
+               attrib->attribute = vid_firstval;
+               memset(attrib->registrar.macaddr, 0, 6);
+
+               if ('?' == buf[2]) {
+                       mvrp_event(MRP_EVENT_JOIN, attrib);
+               } else {
+                       mvrp_event(MRP_EVENT_NEW, attrib);
+               }
+               break;
+       default:
+               snprintf(respbuf, sizeof(respbuf) - 1, "ERC %s", buf);
+               send_ctl_msg(client, respbuf, sizeof(respbuf));
+               goto out;
+               break;
+       }
+       return 0;
+ out:
+       return -1;
+}
+
+int mvrp_init(int mvrp_enable)
+{
+       int rc;
+
+       /* XXX doesn't handle re-start */
+
+       mvrp_socket = -1;
+       MVRP_db = NULL;
+
+       if (0 == mvrp_enable) {
+               return 0;
+       }
+
+       rc = init_protocol_socket(MVRP_ETYPE, &mvrp_socket,
+                                 MVRP_CUSTOMER_BRIDGE_ADDR);
+       if (rc < 0)
+               return -1;
+
+       MVRP_db = malloc(sizeof(struct mvrp_database));
+
+       if (NULL == MVRP_db)
+               goto abort_socket;
+
+       memset(MVRP_db, 0, sizeof(struct mvrp_database));
+
+       /* if registration is FIXED or FORBIDDEN
+        * updates from MRP are discarded, and
+        * only IN and JOININ messages are sent
+        */
+       MVRP_db->mrp_db.registration = MRP_REGISTRAR_CTL_NORMAL;        /* default */
+
+       /* if participant role is 'SILENT' (or non-participant)
+        * applicant doesn't send any messages -
+        *
+        * Note - theoretically configured per-attribute
+        */
+       MVRP_db->mrp_db.participant = MRP_APPLICANT_CTL_NORMAL; /* default */
+
+       rc = init_mrp_timers(&(MVRP_db->mrp_db));
+
+       if (rc < 0)
+               goto abort_alloc;
+
+       mrp_lvatimer_fsm(&(MVRP_db->mrp_db), MRP_EVENT_BEGIN);
+       return 0;
+
+ abort_alloc:
+       /* free MVRP_db and related structures */
+       free(MVRP_db);
+       MVRP_db = NULL;
+ abort_socket:
+       close(mvrp_socket);
+       mvrp_socket = -1;
+       /* XXX */
+       return -1;
+}
+
+int mvrp_reclaim(void)
+{
+       struct mvrp_attribute *vattrib, *free_vattrib;
+       if (NULL == MVRP_db)
+               return 0;
+
+       vattrib = MVRP_db->attrib_list;
+       while (NULL != vattrib) {
+               if ((vattrib->registrar.mrp_state == MRP_MT_STATE) &&
+               ((vattrib->applicant.mrp_state == MRP_VO_STATE) ||
+                   (vattrib->applicant.mrp_state == MRP_AO_STATE) ||
+                       (vattrib->applicant.mrp_state == MRP_QO_STATE)))
+               {
+                       if (NULL != vattrib->prev)
+                               vattrib->prev->next = vattrib->next;
+                       else
+                               MVRP_db->attrib_list = vattrib->next;
+                       if (NULL != vattrib->next)
+                               vattrib->next->prev = vattrib->prev;
+                       free_vattrib = vattrib;
+                       vattrib = vattrib->next;
+                       mvrp_send_notifications(free_vattrib, MRP_NOTIFY_LV);
+                       free(free_vattrib);
+               } else
+                       vattrib = vattrib->next;
+       }
+       return 0;
+}
+
+void mvrp_bye(struct sockaddr_in *client)
+{
+       if (NULL != MVRP_db)
+               client_delete(&(MVRP_db->mrp_db.clients), client);
+
+}
diff --git a/daemons/mrpd/mvrp.h b/daemons/mrpd/mvrp.h
new file mode 100644 (file)
index 0000000..5f6be81
--- /dev/null
@@ -0,0 +1,52 @@
+/******************************************************************************
+
+  Copyright (c) 2012, Intel Corporation 
+  All rights reserved.
+  
+  Redistribution and use in source and binary forms, with or without 
+  modification, are permitted provided that the following conditions are met:
+  
+   1. Redistributions of source code must retain the above copyright notice, 
+      this list of conditions and the following disclaimer.
+  
+   2. Redistributions in binary form must reproduce the above copyright 
+      notice, this list of conditions and the following disclaimer in the 
+      documentation and/or other materials provided with the distribution.
+  
+   3. Neither the name of the Intel Corporation nor the names of its 
+      contributors may be used to endorse or promote products derived from 
+      this software without specific prior written permission.
+  
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+
+struct mvrp_attribute {
+       struct mvrp_attribute           *prev;
+       struct mvrp_attribute           *next;
+       u_int16_t                       attribute;      /* 12-bit VID */
+       mrp_applicant_attribute_t       applicant;
+       mrp_registrar_attribute_t       registrar;
+};
+
+struct mvrp_database {
+       struct mrp_database     mrp_db;
+       struct mvrp_attribute   *attrib_list;
+};
+
+int mvrp_init(int mvrp_enable);
+int mvrp_event(int event, struct mvrp_attribute *rattrib);
+int mvrp_recv_cmd(char *buf, int buflen, struct sockaddr_in *client);
+int mvrp_reclaim(void);
+void mvrp_bye(struct sockaddr_in *client);
+int mvrp_recv_msg(void);