mrpd: abstract sock and start timer abstraction
[profile/ivi/OpenAVB.git] / daemons / mrpd / mvrp.c
1 /****************************************************************************
2   Copyright (c) 2012, Intel Corporation
3   All rights reserved.
4
5   Redistribution and use in source and binary forms, with or without
6   modification, are permitted provided that the following conditions are met:
7
8    1. Redistributions of source code must retain the above copyright notice,
9       this list of conditions and the following disclaimer.
10
11    2. Redistributions in binary form must reproduce the above copyright
12       notice, this list of conditions and the following disclaimer in the
13       documentation and/or other materials provided with the distribution.
14
15    3. Neither the name of the Intel Corporation nor the names of its
16       contributors may be used to endorse or promote products derived from
17       this software without specific prior written permission.
18
19   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29   POSSIBILITY OF SUCH DAMAGE.
30
31 ******************************************************************************/
32 /*
33  * MVRP protocol (part of 802.1Q-2011)
34  */
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <stddef.h>
39 #include <string.h>
40 #include <netinet/in.h>
41
42 #include "mrpd.h"
43 #include "mrp.h"
44 #include "mvrp.h"
45
46 int mvrp_send_notifications(struct mvrp_attribute *attrib, int notify);
47 int mvrp_txpdu(void);
48
49 unsigned char MVRP_CUSTOMER_BRIDGE_ADDR[] = \
50         { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x21 }; /* 81-00 */
51 unsigned char MVRP_PROVIDER_BRIDGE_ADDR[] = \
52         { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x0D }; /* 88-A8 */
53 extern unsigned char STATION_ADDR[];
54
55 /* global variables */
56 SOCKET mvrp_socket;
57 struct mvrp_database *MVRP_db;
58
59 /* MVRP */
60
61 struct mvrp_attribute *mvrp_lookup(struct mvrp_attribute *rattrib)
62 {
63         struct mvrp_attribute *attrib;
64
65         attrib = MVRP_db->attrib_list;
66         while (NULL != attrib) {
67                 if (attrib->attribute == rattrib->attribute)
68                         return attrib;
69                 attrib = attrib->next;
70         }
71         return NULL;
72 }
73
74 int mvrp_add(struct mvrp_attribute *rattrib)
75 {
76         struct mvrp_attribute *attrib;
77         struct mvrp_attribute *attrib_tail;
78
79         /* XXX do a lookup first to guarantee uniqueness? */
80
81         attrib_tail = attrib = MVRP_db->attrib_list;
82
83         while (NULL != attrib) {
84                 if (attrib->attribute < rattrib->attribute) {
85                         /* possible tail insertion ... */
86                         if (NULL != attrib->next) {
87                                 attrib = attrib->next;
88                                 continue;
89                         }
90                         rattrib->next = attrib->next;
91                         rattrib->prev = attrib;
92                         attrib->next = rattrib;
93                         return 0;
94
95                 } else {
96                         /* head insertion ... */
97                         rattrib->next = attrib;
98                         rattrib->prev = attrib->prev;
99                         attrib->prev = rattrib;
100                         if (NULL != rattrib->prev)
101                                 rattrib->prev->next = rattrib;
102                         else
103                                 MVRP_db->attrib_list = rattrib;
104
105                         return 0;
106                 }
107                 attrib_tail = attrib;
108                 attrib = attrib->next;
109         }
110
111         /* if we are here we didn't need to stitch in a a sorted entry
112          * so append it onto the tail (if it exists)
113          */
114
115         if (NULL == attrib_tail) {
116                 rattrib->next = NULL;
117                 rattrib->prev = NULL;
118                 MVRP_db->attrib_list = rattrib;
119         } else {
120                 rattrib->next = NULL;
121                 rattrib->prev = attrib_tail;
122                 attrib_tail->next = rattrib;
123         }
124
125         return 0;
126 }
127
128 int mvrp_merge(struct mvrp_attribute *rattrib)
129 {
130         struct mvrp_attribute *attrib;
131
132         attrib = mvrp_lookup(rattrib);
133
134         if (NULL == attrib)
135                 return -1;      /* shouldn't happen */
136
137         /* primarily we update the last mac address state for diagnostics */
138         memcpy(attrib->registrar.macaddr, rattrib->registrar.macaddr, 6);
139         return 0;
140 }
141
142 int mvrp_event(int event, struct mvrp_attribute *rattrib)
143 {
144         struct mvrp_attribute *attrib;
145         int rc;
146
147         switch (event) {
148         case MRP_EVENT_LVATIMER:
149                 mrp_jointimer_stop(&(MVRP_db->mrp_db));
150                 /* update state */
151                 attrib = MVRP_db->attrib_list;
152
153                 while (NULL != attrib) {
154                         mrp_applicant_fsm(&(attrib->applicant), MRP_EVENT_TXLA);
155                         mrp_registrar_fsm(&(attrib->registrar),
156                                           &(MVRP_db->mrp_db), MRP_EVENT_TXLA);
157                         attrib = attrib->next;
158                 }
159
160                 mrp_lvatimer_fsm(&(MVRP_db->mrp_db), MRP_EVENT_LVATIMER);
161
162                 mvrp_txpdu();
163                 break;
164         case MRP_EVENT_RLA:
165                 mrp_jointimer_stop(&(MVRP_db->mrp_db));
166                 /* update state */
167                 attrib = MVRP_db->attrib_list;
168
169                 while (NULL != attrib) {
170                         mrp_applicant_fsm(&(attrib->applicant), MRP_EVENT_RLA);
171                         mrp_registrar_fsm(&(attrib->registrar),
172                                           &(MVRP_db->mrp_db), MRP_EVENT_RLA);
173                         attrib = attrib->next;
174                 }
175
176                 mrp_lvatimer_fsm(&(MVRP_db->mrp_db), MRP_EVENT_RLA);
177
178                 break;
179         case MRP_EVENT_TX:
180                 mrp_jointimer_stop(&(MVRP_db->mrp_db));
181                 attrib = MVRP_db->attrib_list;
182
183                 while (NULL != attrib) {
184                         mrp_applicant_fsm(&(attrib->applicant), MRP_EVENT_TX);
185                         attrib = attrib->next;
186                 }
187
188                 mrp_lvatimer_fsm(&(MVRP_db->mrp_db), MRP_EVENT_TX);
189
190                 mvrp_txpdu();
191                 break;
192         case MRP_EVENT_LVTIMER:
193                 mrp_lvtimer_stop(&(MVRP_db->mrp_db));
194                 attrib = MVRP_db->attrib_list;
195
196                 while (NULL != attrib) {
197                         mrp_registrar_fsm(&(attrib->registrar),
198                                           &(MVRP_db->mrp_db),
199                                           MRP_EVENT_LVTIMER);
200
201                         attrib = attrib->next;
202                 }
203                 break;
204         case MRP_EVENT_PERIODIC:
205                 attrib = MVRP_db->attrib_list;
206
207                 while (NULL != attrib) {
208                         mrp_applicant_fsm(&(attrib->applicant),
209                                           MRP_EVENT_PERIODIC);
210                         attrib = attrib->next;
211                 }
212                 break;
213         case MRP_EVENT_NEW:
214         case MRP_EVENT_JOIN:
215         case MRP_EVENT_RNEW:
216         case MRP_EVENT_RJOININ:
217         case MRP_EVENT_RJOINMT:
218         case MRP_EVENT_LV:
219         case MRP_EVENT_RIN:
220         case MRP_EVENT_RMT:
221         case MRP_EVENT_RLV:
222                 mrp_jointimer_start(&(MVRP_db->mrp_db));
223                 if (NULL == rattrib)
224                         return -1;      /* XXX internal fault */
225
226                 /* update state */
227                 attrib = mvrp_lookup(rattrib);
228
229                 if (NULL == attrib) {
230                         mvrp_add(rattrib);
231                         attrib = rattrib;
232                 } else {
233                         mvrp_merge(rattrib);
234                         free(rattrib);
235                 }
236
237                 mrp_applicant_fsm(&(attrib->applicant), event);
238                 /* remap local requests into registrar events */
239                 switch (event) {
240                 case MRP_EVENT_NEW:
241                         mrp_registrar_fsm(&(attrib->registrar),
242                                           &(MVRP_db->mrp_db), MRP_EVENT_RNEW);
243                         break;
244                 case MRP_EVENT_JOIN:
245                         if (MRP_IN_STATE == attrib->registrar.mrp_state)
246                                 mrp_registrar_fsm(&(attrib->registrar),
247                                                   &(MVRP_db->mrp_db),
248                                                   MRP_EVENT_RJOININ);
249                         else
250                                 mrp_registrar_fsm(&(attrib->registrar),
251                                                   &(MVRP_db->mrp_db),
252                                                   MRP_EVENT_RJOINMT);
253                         break;
254                 case MRP_EVENT_LV:
255                         mrp_registrar_fsm(&(attrib->registrar),
256                                           &(MVRP_db->mrp_db), MRP_EVENT_RLV);
257                         break;
258                 default:
259                         rc = mrp_registrar_fsm(&(attrib->registrar),
260                                                &(MVRP_db->mrp_db), event);
261                         if (-1 == rc) {
262                                 printf
263                                     ("MVRP registrar error on attrib->attribute = %d\n",
264                                      attrib->attribute);
265                         }
266                         break;
267                 }
268                 break;
269         default:
270                 break;
271         }
272
273         /*
274          * XXX should honor the MVRP_db->mrp_db.registration and
275          * MVRP_db->mrp_db.participant controls
276          */
277
278         /* generate local notifications */
279         attrib = MVRP_db->attrib_list;
280
281         while (NULL != attrib) {
282                 if (MRP_NOTIFY_NONE != attrib->registrar.notify) {
283                         mvrp_send_notifications(attrib,
284                                                 attrib->registrar.notify);
285                         attrib->registrar.notify = MRP_NOTIFY_NONE;
286                 }
287                 attrib = attrib->next;
288         }
289
290         return 0;
291 }
292
293 struct mvrp_attribute *mvrp_alloc()
294 {
295         struct mvrp_attribute *attrib;
296
297         attrib = malloc(sizeof(struct mvrp_attribute));
298         if (NULL == attrib)
299                 return NULL;
300
301         memset(attrib, 0, sizeof(struct mvrp_attribute));
302
303         attrib->applicant.mrp_state = MRP_VO_STATE;
304         attrib->applicant.tx = 0;
305         attrib->applicant.sndmsg = MRP_SND_NULL;
306         attrib->applicant.encode = MRP_ENCODE_OPTIONAL;
307
308         attrib->registrar.mrp_state = MRP_MT_STATE;
309         attrib->registrar.notify = MRP_NOTIFY_NONE;
310
311         return attrib;
312 }
313
314 int mvrp_recv_msg(void)
315 {
316         char *msgbuf;
317         int bytes = 0;
318         eth_hdr_t *eth;
319         mrpdu_t *mrpdu;
320         mrpdu_message_t *mrpdu_msg;
321         unsigned char *mrpdu_msg_ptr;
322         unsigned char *mrpdu_msg_eof;
323         mrpdu_vectorattrib_t *mrpdu_vectorptr;
324         u_int16_t numvalues;
325         u_int16_t numvalues_processed;
326         int numvectorbytes;
327         u_int8_t vect_3pack;
328         int vectidx;
329         int vectevt[3];
330         int vectevt_idx;
331         u_int16_t vid_firstval;
332         struct mvrp_attribute *attrib;
333         int endmarks;
334
335         bytes = mrpd_recvmsgbuf(mvrp_socket, &msgbuf);
336         if (bytes <= 0)
337                 goto out;
338
339         if ((unsigned int)bytes < (sizeof(eth_hdr_t) + sizeof(mrpdu_t) +
340                                    sizeof(mrpdu_message_t)))
341                 goto out;
342
343         eth = (eth_hdr_t *) msgbuf;
344
345         /* note that MVRP frames should always arrive untagged (no vlan) */
346         if (MVRP_ETYPE != ntohs(eth->typelen))
347                 goto out;
348
349         /* XXX check dest mac address too? */
350
351         mrpdu = (mrpdu_t *) (msgbuf + sizeof(struct eth_hdr));
352
353         /*
354          * ProtocolVersion handling - a receiver must process received frames with a lesser
355          * protcol version consistent with the older protocol processing requirements (e.g. a V2
356          * agent receives a V1 message, the V1 message shoudl be parsed with V1 rules).
357          *
358          * However - if an agent receives a NEWER protocol, the agent shoudl still attempt
359          * to parse the frame. If the agent finds an AttributeType not recognized
360          * the agent discards the current message including any associated trailing vectors
361          * up to the end-mark, and resumes with the next message or until the end of the PDU
362          * is reached.
363          *
364          * If a VectorAttribute is found with an unknown Event for the Type, the specific
365          * VectorAttrute is discarded and processing continues with the next VectorAttribute.
366          */
367
368         if (MVRP_PROT_VER != mrpdu->ProtocolVersion)    /* XXX should accept ... */
369                 goto out;
370
371         mrpdu_msg_ptr = (unsigned char *)mrpdu->MessageList;
372
373         mrpdu_msg_eof = (unsigned char *)mrpdu_msg_ptr;
374         mrpdu_msg_eof += bytes;
375         mrpdu_msg_eof -= sizeof(eth_hdr_t);
376         mrpdu_msg_eof -= offsetof(mrpdu_t, MessageList);
377
378         /*
379          * MVRP_VID_TYPE FirstValue is the 12 bit (2-byte) VLAN with
380          * corresponding attrib_length=2
381          *
382          * MVRP uses ThreePackedEvents for all vector encodings
383          *
384          * walk list until we run to the end of the PDU, or encounter a double end-mark
385          */
386
387         endmarks = 0;
388
389         while (mrpdu_msg_ptr < (mrpdu_msg_eof - 2)) {
390                 mrpdu_msg = (mrpdu_message_t *) mrpdu_msg_ptr;
391                 if ((mrpdu_msg->AttributeType == 0) &&
392                     (mrpdu_msg->AttributeLength == 0)) {
393                         mrpdu_msg_ptr += 2;
394                         endmarks++;
395                         if (endmarks < 2)
396                                 continue;       /* end-mark of message-list */
397                         else
398                                 break;  /* two endmarks - end of message list */
399                 }
400
401                 endmarks = 0;
402
403                 switch (mrpdu_msg->AttributeType) {
404                 case MVRP_VID_TYPE:
405                         if (mrpdu_msg->AttributeLength != 2) {
406                                 /* we can seek for an endmark to recover .. but this version
407                                  * dumps the entire packet as malformed
408                                  */
409                                 goto out;
410                         }
411                         /* AttributeListLength not used for MVRP, hence
412                          * Data points to the beginning of the VectorAttributes
413                          */
414                         mrpdu_vectorptr =
415                             (mrpdu_vectorattrib_t *) mrpdu_msg->Data;
416                         mrpdu_msg_ptr = (u_int8_t *) mrpdu_vectorptr;
417
418                         while (!
419                                ((mrpdu_msg_ptr[0] == 0)
420                                 && (mrpdu_msg_ptr[1] == 0))) {
421                                 numvalues =
422                                     MRPDU_VECT_NUMVALUES(ntohs
423                                                          (mrpdu_vectorptr->
424                                                           VectorHeader));
425
426                                 if (0 == numvalues)
427                                         /* Malformed - cant tell how long the trailing vectors are */
428                                         goto out;
429
430                                 if ((mrpdu_vectorptr->FirstValue_VectorEvents +
431                                      numvalues / 3) >= mrpdu_msg_eof)
432                                         /* Malformed - runs off the end of the pdu */
433                                         goto out;
434
435                                 vid_firstval =
436                                     (((u_int16_t) mrpdu_vectorptr->
437                                       FirstValue_VectorEvents[0]) << 8)
438                                     | mrpdu_vectorptr->
439                                     FirstValue_VectorEvents[1];
440
441                                 /* if not an even multiple ... */
442                                 if (numvalues != ((numvalues / 3) * 3))
443                                         numvectorbytes = (numvalues / 3) + 1;
444                                 else
445                                         numvectorbytes = (numvalues / 3);
446
447                                 for (vectidx = 2;
448                                      vectidx <= (numvectorbytes + 2);
449                                      vectidx++) {
450                                         vect_3pack =
451                                             mrpdu_vectorptr->
452                                             FirstValue_VectorEvents[vectidx];
453                                         vectevt[0] = vect_3pack / 36;
454                                         vectevt[1] =
455                                             (vect_3pack - vectevt[0] * 36) / 6;
456                                         vectevt[2] =
457                                             vect_3pack - (36 * vectevt[0]) -
458                                             (6 * vectevt[1]);
459
460                                         numvalues_processed =
461                                             (numvalues > 3 ? 3 : numvalues);
462
463                                         for (vectevt_idx = 0;
464                                              vectevt_idx < numvalues_processed;
465                                              vectevt_idx++) {
466
467                                                 if (0xFFF < vid_firstval)       /*discard junk */
468                                                         continue;
469
470                                                 attrib = mvrp_alloc();
471                                                 if (NULL == attrib)
472                                                         goto out;       /* oops - internal error */
473
474                                                 attrib->attribute =
475                                                     vid_firstval;
476                                                 vid_firstval++;
477                                                 memcpy(attrib->registrar.
478                                                        macaddr, eth->srcaddr,
479                                                        6);
480
481                                                 switch (vectevt[vectevt_idx]) {
482                                                 case MRPDU_NEW:
483                                                         mvrp_event
484                                                             (MRP_EVENT_RNEW,
485                                                              attrib);
486                                                         break;
487                                                 case MRPDU_JOININ:
488                                                         mvrp_event
489                                                             (MRP_EVENT_RJOININ,
490                                                              attrib);
491                                                         break;
492                                                 case MRPDU_IN:
493                                                         mvrp_event
494                                                             (MRP_EVENT_RIN,
495                                                              attrib);
496                                                         break;
497                                                 case MRPDU_JOINMT:
498                                                         mvrp_event
499                                                             (MRP_EVENT_RJOINMT,
500                                                              attrib);
501                                                         break;
502                                                 case MRPDU_MT:
503                                                         mvrp_event
504                                                             (MRP_EVENT_RMT,
505                                                              attrib);
506                                                         break;
507                                                 case MRPDU_LV:
508                                                         mvrp_event
509                                                             (MRP_EVENT_RLV,
510                                                              attrib);
511                                                         break;
512                                                 default:
513                                                         free(attrib);
514                                                         break;
515                                                 }
516                                         }
517                                         numvalues -= numvalues_processed;
518                                 }
519
520                                 if (MRPDU_VECT_LVA
521                                     (ntohs(mrpdu_vectorptr->VectorHeader)))
522                                         mvrp_event(MRP_EVENT_RLA, NULL);
523
524                                 /* 1 byte Type, 1 byte Len, 2 byte FirstValue, and (n) vector bytes */
525                                 mrpdu_msg_ptr = (u_int8_t *) mrpdu_vectorptr;
526                                 mrpdu_msg_ptr += 4 + numvectorbytes;
527
528                                 mrpdu_vectorptr =
529                                     (mrpdu_vectorattrib_t *) mrpdu_msg_ptr;
530                         }
531                         break;
532                 default:
533                         /* unrecognized attribute type
534                          * we can seek for an endmark to recover .. but this version
535                          * dumps the entire packet as malformed
536                          */
537                         goto out;
538                 }
539         }
540
541         free(msgbuf);
542         return 0;
543  out:
544         free(msgbuf);
545
546         return -1;
547 }
548
549 int
550 mvrp_emit_vidvectors(unsigned char *msgbuf, unsigned char *msgbuf_eof,
551                      int *bytes_used, int lva)
552 {
553         mrpdu_vectorattrib_t *mrpdu_vectorptr;
554         u_int16_t numvalues;
555         u_int8_t vect_3pack;
556         int vectidx;
557         unsigned int vectevt[3];
558         int vectevt_idx;
559         u_int16_t vid_firstval;
560         struct mvrp_attribute *attrib, *vattrib;
561         mrpdu_message_t *mrpdu_msg;
562
563         unsigned char *mrpdu_msg_ptr = msgbuf;
564         unsigned char *mrpdu_msg_eof = msgbuf_eof;
565
566         /* need at least 6 bytes for a single vector */
567         if (mrpdu_msg_ptr > (mrpdu_msg_eof - 6))
568                 goto oops;
569
570         mrpdu_msg = (mrpdu_message_t *) mrpdu_msg_ptr;
571         mrpdu_msg->AttributeType = MVRP_VID_TYPE;
572         mrpdu_msg->AttributeLength = 2;
573
574         attrib = MVRP_db->attrib_list;
575
576         mrpdu_vectorptr = (mrpdu_vectorattrib_t *) mrpdu_msg->Data;
577
578         while ((mrpdu_msg_ptr < (mrpdu_msg_eof - 2)) && (NULL != attrib)) {
579
580                 if (0 == attrib->applicant.tx) {
581                         attrib = attrib->next;
582                         continue;
583                 }
584                 if (MRP_ENCODE_OPTIONAL == attrib->applicant.encode) {
585                         attrib->applicant.tx = 0;
586                         attrib = attrib->next;
587                         continue;
588                 }
589
590                 /* pointing to at least one attribute which needs to be transmitted */
591                 attrib->applicant.tx = 0;
592                 vid_firstval = attrib->attribute;
593                 mrpdu_vectorptr->FirstValue_VectorEvents[0] =
594                     (u_int8_t) (attrib->attribute >> 8);
595                 mrpdu_vectorptr->FirstValue_VectorEvents[1] =
596                     (u_int8_t) (attrib->attribute);
597
598                 switch (attrib->applicant.sndmsg) {
599                 case MRP_SND_IN:
600                         /*
601                          * If 'In' in indicated by the applicant attribute, the
602                          * look at the registrar state to determine whether to
603                          * send an In (if registrar is also In) or an Mt if the
604                          * registrar is either Mt or Lv.
605                          */
606                         if (MRP_IN_STATE == attrib->registrar.mrp_state)
607                                 vectevt[0] = MRPDU_IN;
608                         else
609                                 vectevt[0] = MRPDU_MT;
610                         break;
611                 case MRP_SND_NEW:
612                         vectevt[0] = MRPDU_NEW;
613                         break;
614                 case MRP_SND_LV:
615                         vectevt[0] = MRPDU_LV;
616                         break;
617                 case MRP_SND_JOIN:
618                         /* IF 'Join' in indicated by the applicant, look at
619                          * the corresponding registrar state to determine whether
620                          * to send a JoinIn (if the registar state is 'In') or
621                          * a JoinMt if the registrar state is MT or LV.
622                          */
623                         if (MRP_IN_STATE == attrib->registrar.mrp_state)
624                                 vectevt[0] = MRPDU_JOININ;
625                         else
626                                 vectevt[0] = MRPDU_JOINMT;
627                         break;
628                 default:
629                         /* huh? */
630                         goto oops;
631                         break;
632                 }
633
634                 vectevt_idx = 1;
635                 numvalues = 1;
636                 vectevt[1] = 0;
637                 vectevt[2] = 0;
638
639                 /* now attempt to vectorize contiguous other attributes
640                  * which also need to be transmitted
641                  */
642
643                 vectidx = 2;
644                 vattrib = attrib->next;
645
646                 while (NULL != vattrib) {
647                         if (0 == vattrib->applicant.tx)
648                                 break;
649
650                         vid_firstval++;
651
652                         if (vattrib->attribute != vid_firstval)
653                                 break;
654
655                         vattrib->applicant.tx = 0;
656
657                         switch (vattrib->applicant.sndmsg) {
658                         case MRP_SND_IN:
659                                 /*
660                                  * If 'In' in indicated by the applicant attribute, the
661                                  * look at the registrar state to determine whether to
662                                  * send an In (if registrar is also In) or an Mt if the
663                                  * registrar is either Mt or Lv.
664                                  */
665                                 if (MRP_IN_STATE ==
666                                     vattrib->registrar.mrp_state)
667                                         vectevt[vectevt_idx] = MRPDU_IN;
668                                 else
669                                         vectevt[vectevt_idx] = MRPDU_MT;
670                                 break;
671                         case MRP_SND_NEW:
672                                 vectevt[vectevt_idx] = MRPDU_NEW;
673                                 break;
674                         case MRP_SND_LV:
675                                 vectevt[vectevt_idx] = MRPDU_LV;
676                                 break;
677                         case MRP_SND_JOIN:
678                                 /* IF 'Join' in indicated by the applicant, look at
679                                  * the corresponding registrar state to determine whether
680                                  * to send a JoinIn (if the registar state is 'In') or
681                                  * a JoinMt if the registrar state is MT or LV.
682                                  */
683                                 if (MRP_IN_STATE == attrib->registrar.mrp_state)
684                                         vectevt[vectevt_idx] = MRPDU_JOININ;
685                                 else
686                                         vectevt[vectevt_idx] = MRPDU_JOINMT;
687                                 break;
688                         default:
689                                 /* huh? */
690                                 goto oops;
691                                 break;
692                         }
693
694                         vectevt_idx++;
695                         numvalues++;
696
697                         if (vectevt_idx > 2) {
698                                 vect_3pack = MRPDU_3PACK_ENCODE(vectevt[0],
699                                                                 vectevt[1],
700                                                                 vectevt[2]);
701
702                                 mrpdu_vectorptr->
703                                     FirstValue_VectorEvents[vectidx] =
704                                     vect_3pack;
705                                 vectidx++;
706                                 vectevt[0] = 0;
707                                 vectevt[1] = 0;
708                                 vectevt[2] = 0;
709                                 vectevt_idx = 0;
710                         }
711
712                         if (&(mrpdu_vectorptr->FirstValue_VectorEvents[vectidx])
713                             > (mrpdu_msg_eof - 2))
714                                 goto oops;
715
716                         vattrib = vattrib->next;
717                 }
718
719                 /* handle any trailers */
720                 if (vectevt_idx > 0) {
721                         vect_3pack = MRPDU_3PACK_ENCODE(vectevt[0],
722                                                         vectevt[1], vectevt[2]);
723
724                         mrpdu_vectorptr->FirstValue_VectorEvents[vectidx] =
725                             vect_3pack;
726                         vectidx++;
727                 }
728
729                 if (&(mrpdu_vectorptr->FirstValue_VectorEvents[vectidx]) >
730                     (mrpdu_msg_eof - 2))
731                         goto oops;
732
733                 mrpdu_vectorptr->VectorHeader = MRPDU_VECT_NUMVALUES(numvalues);
734
735                 if (lva)
736                         mrpdu_vectorptr->VectorHeader |= MRPDU_VECT_LVA(0xFFFF);
737
738                 mrpdu_vectorptr->VectorHeader =
739                     htons(mrpdu_vectorptr->VectorHeader);
740
741                 /* 2 byte header, followed by FirstValues/Vectors - remember vectidx starts at 0 */
742                 mrpdu_msg_ptr =
743                     &(mrpdu_vectorptr->FirstValue_VectorEvents[vectidx]);
744
745                 attrib = attrib->next;
746
747                 mrpdu_vectorptr = (mrpdu_vectorattrib_t *) mrpdu_msg_ptr;
748         }
749
750         if (mrpdu_vectorptr == (mrpdu_vectorattrib_t *) mrpdu_msg->Data) {
751                 *bytes_used = 0;
752                 return 0;
753         }
754
755         /* endmark */
756         *mrpdu_msg_ptr = 0;
757         mrpdu_msg_ptr++;
758         *mrpdu_msg_ptr = 0;
759         mrpdu_msg_ptr++;
760
761         *bytes_used = (mrpdu_msg_ptr - msgbuf);
762         return 0;
763  oops:
764         /* an internal error - caller should assume TXLAF */
765         *bytes_used = 0;
766         return -1;
767 }
768
769 int mvrp_txpdu(void)
770 {
771         unsigned char *msgbuf, *msgbuf_wrptr;
772         int msgbuf_len;
773         int bytes = 0;
774         eth_hdr_t *eth;
775         mrpdu_t *mrpdu;
776         unsigned char *mrpdu_msg_ptr;
777         unsigned char *mrpdu_msg_eof;
778         int rc;
779         int lva = 0;
780
781         msgbuf = (unsigned char *)malloc(MAX_FRAME_SIZE);
782         if (NULL == msgbuf)
783                 return -1;
784         msgbuf_len = 0;
785
786         msgbuf_wrptr = msgbuf;
787
788         eth = (eth_hdr_t *) msgbuf_wrptr;
789
790         /* note that MVRP frames should always be untagged (no vlan) */
791         eth->typelen = htons(MVRP_ETYPE);
792         memcpy(eth->destaddr, MVRP_CUSTOMER_BRIDGE_ADDR, sizeof(eth->destaddr));
793         memcpy(eth->srcaddr, STATION_ADDR, sizeof(eth->srcaddr));
794
795         msgbuf_wrptr += sizeof(eth_hdr_t);
796
797         mrpdu = (mrpdu_t *) msgbuf_wrptr;
798
799         /*
800          * ProtocolVersion handling - a receiver must process received frames with a lesser
801          * protcol version consistent with the older protocol processing requirements (e.g. a V2
802          * agent receives a V1 message, the V1 message shoudl be parsed with V1 rules).
803          *
804          * However - if an agent receives a NEWER protocol, the agent shoudl still attempt
805          * to parse the frame. If the agent finds an AttributeType not recognized
806          * the agent discards the current message including any associated trailing vectors
807          * up to the end-mark, and resumes with the next message or until the end of the PDU
808          * is reached.
809          *
810          * If a VectorAttribute is found with an unknown Event for the Type, the specific
811          * VectorAttrute is discarded and processing continues with the next VectorAttribute.
812          */
813
814         mrpdu->ProtocolVersion = MVRP_PROT_VER;
815         mrpdu_msg_ptr = (unsigned char *)mrpdu->MessageList;
816         mrpdu_msg_eof = (unsigned char *)msgbuf + MAX_FRAME_SIZE;
817
818         /*
819          * Iterate over all attributes, transmitting those marked
820          * with 'tx', attempting to coalesce multiple contiguous tx attributes
821          * with appropriate vector encodings.
822          *
823          * MVRP_VID_TYPE FirstValue is the 2-byte VLAN with
824          * corresponding attrib_length=2
825          *
826          * MVRP uses ThreePackedEvents for all vector encodings
827          *
828          * the expanded version of the MRPDU looks like
829          * ProtocolVersion
830          * AttributeType
831          * AttributeLength
832          * <Variable number of>
833          *              LeaveAllEvent | NumberOfValues
834          *              <Variable FirstValue>
835          *              <VectorEventBytes>
836          * EndMark
837          *
838          * in effect, each AttributeType present gets its own 'message' with
839          * variable number of vectors. So with MVRP, you will have at most
840          * one message.
841          */
842
843         if (MVRP_db->mrp_db.lva.tx) {
844                 lva = 1;
845                 MVRP_db->mrp_db.lva.tx = 0;
846         }
847
848         rc = mvrp_emit_vidvectors(mrpdu_msg_ptr, mrpdu_msg_eof, &bytes, lva);
849         if (-1 == rc)
850                 goto out;
851
852         mrpdu_msg_ptr += bytes;
853
854         if (mrpdu_msg_ptr == (unsigned char *)mrpdu->MessageList) {
855                 goto out;       /* nothing to send */
856         }
857
858         /* endmark */
859         if (mrpdu_msg_ptr < (mrpdu_msg_eof - 2)) {
860                 *mrpdu_msg_ptr = 0;
861                 mrpdu_msg_ptr++;
862                 *mrpdu_msg_ptr = 0;
863                 mrpdu_msg_ptr++;
864         } else
865                 goto out;
866
867         msgbuf_len = mrpdu_msg_ptr - msgbuf;
868
869         bytes = send(mvrp_socket, msgbuf, msgbuf_len, 0);
870         if (bytes <= 0)
871                 goto out;
872
873         free(msgbuf);
874         return 0;
875  out:
876         free(msgbuf);
877         /* caller should assume TXLAF */
878         return -1;
879 }
880
881 int mvrp_send_notifications(struct mvrp_attribute *attrib, int notify)
882 {
883         char *msgbuf;
884         char *stage;
885         char *variant;
886         char *regsrc;
887         client_t *client;
888
889         if (NULL == attrib)
890                 return -1;
891
892         msgbuf = (char *)malloc(MAX_MRPD_CMDSZ);
893         if (NULL == msgbuf)
894                 return -1;
895
896         stage = variant = regsrc = NULL;
897
898         stage = (char *)malloc(128);
899         variant = (char *)malloc(128);
900         regsrc = (char *)malloc(128);
901
902         if ((NULL == stage) || (NULL == variant) || (NULL == regsrc))
903                 goto free_msgbuf;
904
905         memset(msgbuf, 0, MAX_MRPD_CMDSZ);
906
907         sprintf(variant, "%04x", attrib->attribute);
908
909         sprintf(regsrc, "R%02x%02x%02x%02x%02x%02x",
910                 attrib->registrar.macaddr[0],
911                 attrib->registrar.macaddr[1],
912                 attrib->registrar.macaddr[2],
913                 attrib->registrar.macaddr[3],
914                 attrib->registrar.macaddr[4], attrib->registrar.macaddr[5]);
915         switch (attrib->registrar.mrp_state) {
916         case MRP_IN_STATE:
917                 sprintf(stage, "VIN %s %s\n", variant, regsrc);
918                 break;
919         case MRP_LV_STATE:
920                 sprintf(stage, "VLV %s %s\n", variant, regsrc);
921                 break;
922         case MRP_MT_STATE:
923                 sprintf(stage, "VMT %s %s\n", variant, regsrc);
924                 break;
925         default:
926                 break;
927         }
928
929         switch (notify) {
930         case MRP_NOTIFY_NEW:
931                 snprintf(msgbuf, MAX_MRPD_CMDSZ - 1, "VNE %s", stage);
932                 break;
933         case MRP_NOTIFY_JOIN:
934                 snprintf(msgbuf, MAX_MRPD_CMDSZ - 1, "VJO %s", stage);
935                 break;
936         case MRP_NOTIFY_LV:
937                 snprintf(msgbuf, MAX_MRPD_CMDSZ - 1, "VLE %s", stage);
938                 break;
939         default:
940                 goto free_msgbuf;
941                 break;
942         }
943
944         client = MVRP_db->mrp_db.clients;
945         while (NULL != client) {
946                 mrpd_send_ctl_msg(&(client->client), msgbuf, MAX_MRPD_CMDSZ);
947                 client = client->next;
948         }
949
950  free_msgbuf:
951         if (regsrc)
952                 free(regsrc);
953         if (variant)
954                 free(variant);
955         if (stage)
956                 free(stage);
957         free(msgbuf);
958         return 0;
959 }
960
961 int mvrp_dumptable(struct sockaddr_in *client)
962 {
963         char *msgbuf;
964         char *msgbuf_wrptr;
965         char *stage;
966         char *variant;
967         char *regsrc;
968         struct mvrp_attribute *attrib;
969
970         msgbuf = (char *)malloc(MAX_MRPD_CMDSZ);
971         if (NULL == msgbuf)
972                 return -1;
973
974         stage = variant = regsrc = NULL;
975
976         stage = (char *)malloc(128);
977         variant = (char *)malloc(128);
978         regsrc = (char *)malloc(128);
979
980         if ((NULL == stage) || (NULL == variant) || (NULL == regsrc))
981                 goto free_msgbuf;
982
983         memset(msgbuf, 0, MAX_MRPD_CMDSZ);
984
985         msgbuf_wrptr = msgbuf;
986
987         attrib = MVRP_db->attrib_list;
988
989         while (NULL != attrib) {
990                 sprintf(variant, "%04x", attrib->attribute);
991                 sprintf(regsrc, "R%02x%02x%02x%02x%02x%02x",
992                         attrib->registrar.macaddr[0],
993                         attrib->registrar.macaddr[1],
994                         attrib->registrar.macaddr[2],
995                         attrib->registrar.macaddr[3],
996                         attrib->registrar.macaddr[4],
997                         attrib->registrar.macaddr[5]);
998                 switch (attrib->registrar.mrp_state) {
999                 case MRP_IN_STATE:
1000                         sprintf(stage, "VIN %s %s\n", variant, regsrc);
1001                         break;
1002                 case MRP_LV_STATE:
1003                         sprintf(stage, "VLV %s %s\n", variant, regsrc);
1004                         break;
1005                 case MRP_MT_STATE:
1006                         sprintf(stage, "VMT %s %s\n", variant, regsrc);
1007                         break;
1008                 default:
1009                         break;
1010                 }
1011                 sprintf(msgbuf_wrptr, "%s", stage);
1012                 msgbuf_wrptr += strnlen(stage, 128);
1013                 attrib = attrib->next;
1014         }
1015
1016         mrpd_send_ctl_msg(client, msgbuf, MAX_MRPD_CMDSZ);
1017
1018 free_msgbuf:
1019         if (regsrc)
1020                 free(regsrc);
1021         if (variant)
1022                 free(variant);
1023         if (stage)
1024                 free(stage);
1025         free(msgbuf);
1026         return 0;
1027
1028 }
1029
1030 int mvrp_recv_cmd(char *buf, int buflen, struct sockaddr_in *client)
1031 {
1032         int rc;
1033         char respbuf[8];
1034         struct mvrp_attribute *attrib;
1035         unsigned int vid_firstval;
1036         u_int8_t vid_parsestr[8];
1037
1038         if (NULL == MVRP_db) {
1039                 snprintf(respbuf, sizeof(respbuf) - 1, "ERC %s", buf);
1040                 mrpd_send_ctl_msg(client, respbuf, sizeof(respbuf));
1041                 goto out;
1042         }
1043
1044         rc = mrp_client_add(&(MVRP_db->mrp_db.clients), client);
1045
1046         if (buflen < 3)
1047                 return -1;
1048
1049         if ('V' != buf[0])
1050                 return -1;
1051
1052         /*
1053          * V?? - query MVRP Registrar VID database
1054          * V+? - JOIN a VID
1055          * V++   NEW a VID (XXX: note network disturbance)
1056          * V-- - LV a VID
1057          */
1058         switch (buf[1]) {
1059         case '?':
1060                 mvrp_dumptable(client);
1061                 break;
1062         case '-':
1063                 if (buflen < 5) {
1064                         snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s", buf);
1065                         mrpd_send_ctl_msg(client, respbuf, sizeof(respbuf));
1066                         goto out;
1067                 }
1068                 /* buf[] should look similar to 'V--0001' where VID is in hex */
1069                 if (buflen < 7) {
1070                         snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s", buf);
1071                         mrpd_send_ctl_msg(client, respbuf, sizeof(respbuf));
1072                         goto out;
1073                 }
1074
1075                 memset(vid_parsestr, 0, sizeof(vid_parsestr));
1076
1077                 rc = sscanf((char *)&buf[3], "%04x", &vid_firstval);
1078                 if (0 == rc) {
1079                         snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s", buf);
1080                         mrpd_send_ctl_msg(client, respbuf, sizeof(respbuf));
1081                         goto out;
1082                 }
1083
1084                 attrib = mvrp_alloc();
1085                 if (NULL == attrib) {
1086                         snprintf(respbuf, sizeof(respbuf) - 1, "ERI %s", buf);
1087                         mrpd_send_ctl_msg(client, respbuf, sizeof(respbuf));
1088                         goto out;       /* oops - internal error */
1089                 }
1090                 attrib->attribute = vid_firstval;
1091                 memset(attrib->registrar.macaddr, 0, 6);
1092
1093                 mvrp_event(MRP_EVENT_LV, attrib);
1094                 break;
1095         case '+':
1096                 /* buf[] should look similar to 'V+?0001' where VID is in hex */
1097                 if (('?' != buf[2]) && ('+' != buf[2])) {
1098                         snprintf(respbuf, sizeof(respbuf) - 1, "ERC %s", buf);
1099                         mrpd_send_ctl_msg(client, respbuf, sizeof(respbuf));
1100                         goto out;
1101                 }
1102                 if (buflen < 7) {
1103                         snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s", buf);
1104                         mrpd_send_ctl_msg(client, respbuf, sizeof(respbuf));
1105                         goto out;
1106                 }
1107                 rc = sscanf((char *)&buf[3], "%04x", &vid_firstval);
1108
1109                 if (0 == rc) {
1110                         snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s", buf);
1111                         mrpd_send_ctl_msg(client, respbuf, sizeof(respbuf));
1112                         goto out;
1113                 }
1114
1115                 attrib = mvrp_alloc();
1116                 if (NULL == attrib) {
1117                         snprintf(respbuf, sizeof(respbuf) - 1, "ERI %s", buf);
1118                         mrpd_send_ctl_msg(client, respbuf, sizeof(respbuf));
1119                         goto out;       /* oops - internal error */
1120                 }
1121                 attrib->attribute = vid_firstval;
1122                 memset(attrib->registrar.macaddr, 0, 6);
1123
1124                 if ('?' == buf[2]) {
1125                         mvrp_event(MRP_EVENT_JOIN, attrib);
1126                 } else {
1127                         mvrp_event(MRP_EVENT_NEW, attrib);
1128                 }
1129                 break;
1130         default:
1131                 snprintf(respbuf, sizeof(respbuf) - 1, "ERC %s", buf);
1132                 mrpd_send_ctl_msg(client, respbuf, sizeof(respbuf));
1133                 goto out;
1134                 break;
1135         }
1136         return 0;
1137  out:
1138         return -1;
1139 }
1140
1141 int mvrp_init(int mvrp_enable)
1142 {
1143         int rc;
1144
1145         /* XXX doesn't handle re-start */
1146
1147         mvrp_socket = INVALID_SOCKET;
1148         MVRP_db = NULL;
1149
1150         if (0 == mvrp_enable) {
1151                 return 0;
1152         }
1153
1154         rc = mrpd_init_protocol_socket(MVRP_ETYPE, &mvrp_socket,
1155                                   MVRP_CUSTOMER_BRIDGE_ADDR);
1156         if (rc < 0)
1157                 return -1;
1158
1159         MVRP_db = malloc(sizeof(struct mvrp_database));
1160
1161         if (NULL == MVRP_db)
1162                 goto abort_socket;
1163
1164         memset(MVRP_db, 0, sizeof(struct mvrp_database));
1165
1166         /* if registration is FIXED or FORBIDDEN
1167          * updates from MRP are discarded, and
1168          * only IN and JOININ messages are sent
1169          */
1170         MVRP_db->mrp_db.registration = MRP_REGISTRAR_CTL_NORMAL;        /* default */
1171
1172         /* if participant role is 'SILENT' (or non-participant)
1173          * applicant doesn't send any messages -
1174          *
1175          * Note - theoretically configured per-attribute
1176          */
1177         MVRP_db->mrp_db.participant = MRP_APPLICANT_CTL_NORMAL; /* default */
1178
1179         rc = mrp_init_timers(&(MVRP_db->mrp_db));
1180
1181         if (rc < 0)
1182                 goto abort_alloc;
1183
1184         mrp_lvatimer_fsm(&(MVRP_db->mrp_db), MRP_EVENT_BEGIN);
1185         return 0;
1186
1187  abort_alloc:
1188         /* free MVRP_db and related structures */
1189         free(MVRP_db);
1190         MVRP_db = NULL;
1191  abort_socket:
1192         close(mvrp_socket);
1193         mvrp_socket = -1;
1194         /* XXX */
1195         return -1;
1196 }
1197
1198 int mvrp_reclaim(void)
1199 {
1200         struct mvrp_attribute *vattrib, *free_vattrib;
1201         if (NULL == MVRP_db)
1202                 return 0;
1203
1204         vattrib = MVRP_db->attrib_list;
1205         while (NULL != vattrib) {
1206                 if ((vattrib->registrar.mrp_state == MRP_MT_STATE) &&
1207                 ((vattrib->applicant.mrp_state == MRP_VO_STATE) ||
1208                     (vattrib->applicant.mrp_state == MRP_AO_STATE) ||
1209                         (vattrib->applicant.mrp_state == MRP_QO_STATE)))
1210                 {
1211                         if (NULL != vattrib->prev)
1212                                 vattrib->prev->next = vattrib->next;
1213                         else
1214                                 MVRP_db->attrib_list = vattrib->next;
1215                         if (NULL != vattrib->next)
1216                                 vattrib->next->prev = vattrib->prev;
1217                         free_vattrib = vattrib;
1218                         vattrib = vattrib->next;
1219                         mvrp_send_notifications(free_vattrib, MRP_NOTIFY_LV);
1220                         free(free_vattrib);
1221                 } else
1222                         vattrib = vattrib->next;
1223         }
1224         return 0;
1225 }
1226
1227 void mvrp_bye(struct sockaddr_in *client)
1228 {
1229         if (NULL != MVRP_db)
1230                 mrp_client_delete(&(MVRP_db->mrp_db.clients), client);
1231
1232 }