#include <net/ethernet.h>
#include <sys/un.h>
#include "mrpd.h"
+#include "mvrp.h"
/* global mgmt parameters */
int daemonize;
int mmrp_enable;
"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 };
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)
}
/* 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);
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;
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)
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],
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;
}
-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);
return -1;
}
+
struct msrp_attribute *msrp_lookup(struct msrp_attribute *rattrib)
{
struct msrp_attribute *attrib;
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);
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);
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;
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)
{
int mrpd_reclaim()
{
struct mmrp_attribute *mattrib, *free_mattrib;
- struct mvrp_attribute *vattrib, *free_vattrib;
struct msrp_attribute *sattrib, *free_sattrib;
/*
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) {
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;
}
}
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);
gc_timer = -1;
MMRP_db = NULL;
- MVRP_db = NULL;
MSRP_db = NULL;
lva_next = MRP_LVATIMER_VAL; /* leaveall timeout in msec */
if (rc)
goto out;
- rc = init_mvrp(mvrp_enable);
+ rc = mvrp_init(mvrp_enable);
if (rc)
goto out;
--- /dev/null
+/****************************************************************************
+ 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);
+
+}