1 /****************************************************************************
2 Copyright (c) 2012, Intel Corporation
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
8 1. Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
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.
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.
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.
31 ******************************************************************************/
33 * MRP protocol (part of 802.1Q-2011)
44 /* state machine controls */
47 static int client_lookup(client_t * list, struct sockaddr_in *newclient)
49 client_t *client_item;
53 if (NULL == newclient)
56 while (NULL != client_item) {
57 if (client_item->client.sin_port == newclient->sin_port)
59 client_item = client_item->next;
64 int mrp_client_add(client_t ** list, struct sockaddr_in *newclient)
66 client_t *client_item;
70 if (NULL == newclient)
73 if (client_lookup(client_item, newclient))
74 return 0; /* already present */
76 /* handle 1st entry into list */
77 if (NULL == client_item) {
78 client_item = malloc(sizeof(client_t));
79 if (NULL == client_item)
81 client_item->next = NULL;
82 client_item->client = *newclient;
88 if (NULL == client_item->next) {
89 client_item->next = malloc(sizeof(client_t));
90 if (NULL == client_item->next)
92 client_item = client_item->next;
93 client_item->next = NULL;
94 client_item->client = *newclient;
97 client_item = client_item->next;
102 int mrp_client_delete(client_t ** list, struct sockaddr_in *newclient)
104 client_t *client_item;
105 client_t *client_last;
110 if (NULL == newclient)
113 if (NULL == client_item)
116 while (NULL != client_item) {
117 if (0 == memcmp((uint8_t *) newclient,
118 (uint8_t *) & client_item->client,
119 sizeof(struct sockaddr_in))) {
122 client_last->next = client_item->next;
125 /* reset the head pointer */
126 *list = client_item->next;
131 client_last = client_item;
132 client_item = client_item->next;
134 /* not found ... no error */
138 int mrp_jointimer_start(struct mrp_database *mrp_db)
140 /* 10.7.4.1 - interval between transmit opportunities
141 * for applicant state machine
143 return mrpd_timer_start(mrp_db->join_timer, MRP_LVTIMER_VAL);
146 int mrp_jointimer_stop(struct mrp_database *mrp_db)
148 return mrpd_timer_stop(mrp_db->join_timer);
151 int mrp_lvtimer_start(struct mrp_database *mrp_db)
153 /* leavetimer has expired (10.7.5.21)
154 * controls how long the Registrar state machine stays in the
155 * LV state before transitioning to the MT state.
157 return mrpd_timer_start(mrp_db->lv_timer, MRP_LVTIMER_VAL);
160 int mrp_lvtimer_stop(struct mrp_database *mrp_db)
162 return mrpd_timer_stop(mrp_db->lv_timer);
165 static unsigned long lva_next;
167 int mrp_lvatimer_start(struct mrp_database *mrp_db)
169 /* leavealltimer has expired. (10.7.5.22)
170 * on expire, sends a LEAVEALL message
171 * value is RANDOM in range (LeaveAllTime , 1.5xLeaveAllTime)
172 * timer is for all attributes of a given application and port, but
173 * expires each listed attribute individually (per application)
175 return mrpd_timer_start(mrp_db->lva_timer,
177 (random() % (MRP_LVATIMER_VAL / 2)));
180 int mrp_lvatimer_stop(struct mrp_database *mrp_db)
182 return mrpd_timer_stop(mrp_db->lva_timer);
185 int mrp_lvatimer_fsm(struct mrp_database *mrp_db, int event)
188 int sndmsg = MRP_SND_NONE;
194 la_state = mrp_db->lva.state;
197 case MRP_EVENT_BEGIN:
198 la_state = MRP_TIMER_PASSIVE;
199 mrp_lvatimer_start(mrp_db);
202 if (la_state == MRP_TIMER_ACTIVE) {
204 sndmsg = MRP_SND_LVA;
205 la_state = MRP_TIMER_PASSIVE;
209 la_state = MRP_TIMER_PASSIVE;
210 mrp_lvatimer_start(mrp_db);
212 case MRP_EVENT_LVATIMER:
213 la_state = MRP_TIMER_ACTIVE;
214 mrp_lvatimer_start(mrp_db);
217 printf("mrp_lvatimer_fsm:unexpected event (%d)\n", event);
221 mrp_db->lva.state = la_state;
222 mrp_db->lva.sndmsg = sndmsg;
229 int mrp_periodictimer_fsm(struct mrp_database *mrp_db, int event)
232 int sndmsg = MRP_SND_NONE;
238 p_state = mrp_db->periodic.state;
241 case MRP_EVENT_BEGIN:
242 p_state = MRP_TIMER_ACTIVE;
243 mrp_periodictimer_start();
245 case MRP_EVENT_PERIODIC:
246 if (p_state == MRP_TIMER_ACTIVE) {
247 mrp_periodictimer_start();
250 case MRP_EVENT_PERIODIC_DISABLE:
251 p_state = MRP_TIMER_PASSIVE;
252 /* this lets the timer expire without rescheduling */
254 case MRP_EVENT_PERIODIC_ENABLE:
255 if (p_state == MRP_TIMER_PASSIVE) {
256 p_state = MRP_TIMER_ACTIVE;
257 mrp_periodictimer_start();
261 printf("mrp_periodictimer_fsm:unexpected event (%d)\n", event);
265 mrp_db->periodic.state = p_state;
266 mrp_db->periodic.sndmsg = sndmsg;
267 mrp_db->periodic.tx = tx;
272 * per-attribute MRP FSM
275 int mrp_applicant_fsm(mrp_applicant_attribute_t * attrib, int event)
279 int mrp_state = attrib->mrp_state;
280 int sndmsg = MRP_SND_NULL;
283 case MRP_EVENT_BEGIN:
284 mrp_state = MRP_VO_STATE;
288 * New declaration (publish) event as a result
289 * of a mad_join request
297 mrp_state = MRP_VN_STATE;
303 * declaration (of interest) event as a result of
309 mrp_state = MRP_VP_STATE;
312 mrp_state = MRP_AA_STATE;
315 mrp_state = MRP_AP_STATE;
318 mrp_state = MRP_QP_STATE;
326 * declaration removal event as a result of a mad_leave request
333 mrp_state = MRP_LA_STATE;
336 mrp_state = MRP_VO_STATE;
339 mrp_state = MRP_AO_STATE;
342 mrp_state = MRP_QO_STATE;
350 * transmit leaveall is signaled (overrides a TX)
354 /* send <NULL> only if it improves encoding */
358 mrp_state = MRP_LO_STATE;
363 mrp_state = MRP_AA_STATE;
368 sndmsg = MRP_SND_NEW;
369 mrp_state = MRP_AN_STATE;
374 sndmsg = MRP_SND_NEW;
375 mrp_state = MRP_QA_STATE;
382 sndmsg = MRP_SND_JOIN;
383 mrp_state = MRP_QA_STATE;
388 sndmsg = MRP_SND_JOIN;
393 /* send <NULL> only if it improves encoding */
397 mrp_state = MRP_LO_STATE;
404 mrp_state = MRP_VO_STATE;
410 case MRP_EVENT_TXLAF:
412 * transmit leaveall failure (no room)
416 mrp_state = MRP_LO_STATE;
421 /* don't advance state */
424 mrp_state = MRP_VN_STATE;
430 mrp_state = MRP_VP_STATE;
435 mrp_state = MRP_LO_STATE;
443 * transmit updates unless leaveall is signaled
444 * (then it becomes a TXLA)
448 /* send <NULL> only if it improves encoding */
456 sndmsg = MRP_SND_JOIN;
457 mrp_state = MRP_AA_STATE;
462 sndmsg = MRP_SND_NEW;
463 mrp_state = MRP_AN_STATE;
468 sndmsg = MRP_SND_NEW;
469 mrp_state = MRP_QA_STATE;
475 sndmsg = MRP_SND_JOIN;
476 mrp_state = MRP_QA_STATE;
479 /* send JOIN only if it improves encoding */
482 sndmsg = MRP_SND_JOIN;
488 mrp_state = MRP_VO_STATE;
493 /* send <NULL> only if it improves encoding */
502 mrp_state = MRP_VO_STATE;
512 case MRP_EVENT_RJOININ:
516 mrp_state = MRP_AO_STATE;
520 mrp_state = MRP_AP_STATE;
524 mrp_state = MRP_QA_STATE;
527 mrp_state = MRP_QO_STATE;
530 mrp_state = MRP_QP_STATE;
540 mrp_state = MRP_QA_STATE;
546 case MRP_EVENT_RJOINMT:
550 mrp_state = MRP_AA_STATE;
553 mrp_state = MRP_AO_STATE;
556 mrp_state = MRP_AP_STATE;
559 mrp_state = MRP_VO_STATE;
568 case MRP_EVENT_REDECLARE:
571 mrp_state = MRP_LO_STATE;
574 mrp_state = MRP_VN_STATE;
578 mrp_state = MRP_VP_STATE;
582 mrp_state = MRP_LO_STATE;
586 mrp_state = MRP_VP_STATE;
592 case MRP_EVENT_PERIODIC:
595 mrp_state = MRP_AA_STATE;
598 mrp_state = MRP_AP_STATE;
606 printf("mrp_applicant_fsm:unexpected event (%d)\n", event);
612 attrib->mrp_state = mrp_state;
613 attrib->sndmsg = sndmsg;
614 attrib->encode = (optional ? MRP_ENCODE_OPTIONAL : MRP_ENCODE_YES);
619 mrp_registrar_fsm(mrp_registrar_attribute_t * attrib,
620 struct mrp_database *mrp_db, int event)
622 int mrp_state = attrib->mrp_state;
623 int notify = MRP_NOTIFY_NONE;
626 case MRP_EVENT_BEGIN:
627 mrp_state = MRP_MT_STATE;
630 notify = MRP_NOTIFY_LV;
634 case MRP_EVENT_REDECLARE:
636 * on link-status-change
637 * trigger Applicant and Registrar state machines to re-declare
638 * previously registered attributes.
642 mrp_lvtimer_start(mrp_db);
643 mrp_state = MRP_LV_STATE;
649 notify = MRP_NOTIFY_NEW;
653 mrp_state = MRP_IN_STATE;
656 /* should stop leavetimer - but we have only 1 lvtimer
657 * for all attributes, and recieving a LVTIMER event
658 * is a don't-care if the attribute is in the IN state.
660 mrp_state = MRP_IN_STATE;
666 case MRP_EVENT_RJOININ:
667 case MRP_EVENT_RJOINMT:
670 notify = MRP_NOTIFY_JOIN;
671 mrp_state = MRP_IN_STATE;
674 mrp_state = MRP_IN_STATE;
677 /* should stop leavetimer - but we have only 1 lvtimer
678 * for all attributes, and recieving a LVTIMER event
679 * is a don't-care if the attribute is in the IN state.
681 notify = MRP_NOTIFY_JOIN;
682 mrp_state = MRP_IN_STATE;
689 case MRP_EVENT_LVTIMER:
692 mrp_state = MRP_MT_STATE;
695 mrp_state = MRP_MT_STATE;
702 case MRP_EVENT_FLUSH:
703 notify = MRP_NOTIFY_LV;
706 mrp_state = MRP_MT_STATE;
710 mrp_state = MRP_MT_STATE;
717 /* ignore on soon to be deleted attributes */
720 printf("mrp_registrar_fsm:unexpected event (%d)\n", event);
725 attrib->mrp_state = mrp_state;
726 attrib->notify = notify;
730 int mrp_decode_state(mrp_registrar_attribute_t * rattrib,
731 mrp_applicant_attribute_t * aattrib, char *str, int strlen)
735 switch (rattrib->mrp_state) {
737 snprintf(reg_stat, sizeof(reg_stat) - 1, "IN");
740 snprintf(reg_stat, sizeof(reg_stat) - 1, "LV");
743 snprintf(reg_stat, sizeof(reg_stat) - 1, "MT");
746 snprintf(reg_stat, sizeof(reg_stat) - 1, "%d",
751 switch (aattrib->mrp_state) {
753 snprintf(str, strlen - 1, "VO/%s", reg_stat);
756 snprintf(str, strlen - 1, "VP/%s", reg_stat);
759 snprintf(str, strlen - 1, "VN/%s", reg_stat);
762 snprintf(str, strlen - 1, "AN/%s", reg_stat);
765 snprintf(str, strlen - 1, "AA/%s", reg_stat);
768 snprintf(str, strlen - 1, "QA/%s", reg_stat);
771 snprintf(str, strlen - 1, "LA/%s", reg_stat);
774 snprintf(str, strlen - 1, "AO/%s", reg_stat);
777 snprintf(str, strlen - 1, "QO/%s", reg_stat);
780 snprintf(str, strlen - 1, "AP/%s", reg_stat);
783 snprintf(str, strlen - 1, "QP/%s", reg_stat);
786 snprintf(str, strlen - 1, "LO/%s", reg_stat);
789 snprintf(str, strlen - 1, "%d/%s", aattrib->mrp_state,
798 p2pmac = 0; /* operPointToPointMAC false by default */
799 lva_next = MRP_LVATIMER_VAL; /* leaveall timeout in msec */