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 * MSRP protocol (part of 802.1Q-2011)
48 int msrp_send_notifications(struct msrp_attribute *attrib, int notify);
50 unsigned char MSRP_ADDR[] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x0E };
52 extern unsigned char STATION_ADDR[];
54 /* global variables */
56 struct msrp_database *MSRP_db;
58 struct msrp_attribute *msrp_lookup(struct msrp_attribute *rattrib)
60 struct msrp_attribute *attrib;
63 attrib = MSRP_db->attrib_list;
64 while (NULL != attrib) {
65 if (rattrib->type == attrib->type) {
66 if (MSRP_DOMAIN_TYPE == attrib->type) {
67 mac_eq = memcmp(&(attrib->attribute.domain),
68 &(rattrib->attribute.domain),
69 sizeof(msrpdu_domain_t));
73 /* compare on the stream ID */
75 memcmp(attrib->attribute.talk_listen.
77 rattrib->attribute.talk_listen.
83 attrib = attrib->next;
88 int msrp_add(struct msrp_attribute *rattrib)
90 struct msrp_attribute *attrib;
91 struct msrp_attribute *attrib_tail;
94 /* XXX do a lookup first to guarantee uniqueness? */
96 attrib_tail = attrib = MSRP_db->attrib_list;
98 while (NULL != attrib) {
99 /* sort list into types, then sorted in order within types */
100 if (rattrib->type == attrib->type) {
101 if (MSRP_DOMAIN_TYPE == attrib->type) {
102 mac_eq = memcmp(&(attrib->attribute.domain),
103 &(rattrib->attribute.domain),
104 sizeof(msrpdu_domain_t));
107 /* possible tail insertion ... */
110 * see if there is a another of the same following
111 * not likely since valid values are only 0 and 1
113 if (NULL != attrib->next) {
115 attrib->next->type) {
116 attrib = attrib->next;
121 rattrib->next = attrib->next;
122 rattrib->prev = attrib;
123 attrib->next = rattrib;
127 /* head insertion ... */
128 rattrib->next = attrib;
129 rattrib->prev = attrib->prev;
130 attrib->prev = rattrib;
131 if (NULL != rattrib->prev)
132 rattrib->prev->next = rattrib;
134 MSRP_db->attrib_list = rattrib;
140 memcmp(attrib->attribute.talk_listen.
142 rattrib->attribute.talk_listen.
146 /* possible tail insertion ... */
148 if (NULL != attrib->next) {
150 attrib->next->type) {
151 attrib = attrib->next;
156 rattrib->next = attrib->next;
157 rattrib->prev = attrib;
158 attrib->next = rattrib;
162 /* head insertion ... */
163 rattrib->next = attrib;
164 rattrib->prev = attrib->prev;
165 attrib->prev = rattrib;
166 if (NULL != rattrib->prev)
167 rattrib->prev->next = rattrib;
169 MSRP_db->attrib_list = rattrib;
175 attrib_tail = attrib;
176 attrib = attrib->next;
179 /* if we are here we didn't need to stitch in a a sorted entry
180 * so append it onto the tail (if it exists)
183 if (NULL == attrib_tail) {
184 rattrib->next = NULL;
185 rattrib->prev = NULL;
186 MSRP_db->attrib_list = rattrib;
188 rattrib->next = NULL;
189 rattrib->prev = attrib_tail;
190 attrib_tail->next = rattrib;
196 int msrp_merge(struct msrp_attribute *rattrib)
198 struct msrp_attribute *attrib;
200 attrib = msrp_lookup(rattrib);
203 return -1; /* shouldn't happen */
205 /* we always update the last mac address state for diagnostics */
206 memcpy(attrib->registrar.macaddr, rattrib->registrar.macaddr, 6);
208 /* some attribute types carry updated fault condition information
209 * from the bridges indicating either insufficient bandwidth or
210 * excessive latency between the talker and listener. We merge
211 * these status conditions with the existing attribute without
212 * necessarily changing the MRP state (we let the FSM functions
215 switch (attrib->type) {
216 case MSRP_TALKER_ADV_TYPE:
217 case MSRP_TALKER_FAILED_TYPE:
218 attrib->attribute.talk_listen.FailureInformation.FailureCode =
219 rattrib->attribute.talk_listen.FailureInformation.
221 memcpy(attrib->attribute.talk_listen.FailureInformation.
223 rattrib->attribute.talk_listen.FailureInformation.
225 attrib->attribute.talk_listen.AccumulatedLatency =
226 rattrib->attribute.talk_listen.AccumulatedLatency;
228 case MSRP_LISTENER_TYPE:
229 if (attrib->substate != rattrib->substate) {
230 attrib->substate = rattrib->substate;
231 attrib->registrar.mrp_state = MRP_MT_STATE; /* ugly - force a notify */
234 case MSRP_DOMAIN_TYPE:
235 /* doesn't/shouldn't happen */
243 int msrp_event(int event, struct msrp_attribute *rattrib)
245 struct msrp_attribute *attrib;
249 case MRP_EVENT_LVATIMER:
250 mrp_jointimer_stop(&(MSRP_db->mrp_db));
252 attrib = MSRP_db->attrib_list;
254 while (NULL != attrib) {
255 mrp_applicant_fsm(&(attrib->applicant), MRP_EVENT_TXLA);
256 mrp_registrar_fsm(&(attrib->registrar),
257 &(MSRP_db->mrp_db), MRP_EVENT_TXLA);
258 attrib = attrib->next;
261 mrp_lvatimer_fsm(&(MSRP_db->mrp_db), MRP_EVENT_LVATIMER);
266 mrp_jointimer_stop(&(MSRP_db->mrp_db));
268 attrib = MSRP_db->attrib_list;
270 while (NULL != attrib) {
271 mrp_applicant_fsm(&(attrib->applicant), MRP_EVENT_RLA);
272 mrp_registrar_fsm(&(attrib->registrar),
273 &(MSRP_db->mrp_db), MRP_EVENT_RLA);
274 attrib = attrib->next;
277 mrp_lvatimer_fsm(&(MSRP_db->mrp_db), MRP_EVENT_RLA);
281 mrp_jointimer_stop(&(MSRP_db->mrp_db));
282 attrib = MSRP_db->attrib_list;
284 while (NULL != attrib) {
285 mrp_applicant_fsm(&(attrib->applicant), MRP_EVENT_TX);
286 attrib = attrib->next;
289 mrp_lvatimer_fsm(&(MSRP_db->mrp_db), MRP_EVENT_TX);
293 case MRP_EVENT_LVTIMER:
294 mrp_lvtimer_stop(&(MSRP_db->mrp_db));
295 attrib = MSRP_db->attrib_list;
297 while (NULL != attrib) {
298 mrp_registrar_fsm(&(attrib->registrar),
302 attrib = attrib->next;
305 case MRP_EVENT_PERIODIC:
306 attrib = MSRP_db->attrib_list;
308 while (NULL != attrib) {
309 mrp_applicant_fsm(&(attrib->applicant),
311 attrib = attrib->next;
317 case MRP_EVENT_RJOININ:
318 case MRP_EVENT_RJOINMT:
323 mrp_jointimer_start(&(MSRP_db->mrp_db));
325 return -1; /* XXX internal fault */
328 attrib = msrp_lookup(rattrib);
330 if (NULL == attrib) {
338 mrp_applicant_fsm(&(attrib->applicant), event);
340 /* remap local requests into registrar events */
343 mrp_registrar_fsm(&(attrib->registrar),
344 &(MSRP_db->mrp_db), MRP_EVENT_RNEW);
347 if (MRP_IN_STATE == attrib->registrar.mrp_state)
348 mrp_registrar_fsm(&(attrib->registrar),
352 mrp_registrar_fsm(&(attrib->registrar),
357 mrp_registrar_fsm(&(attrib->registrar),
358 &(MSRP_db->mrp_db), MRP_EVENT_RLV);
361 rc = mrp_registrar_fsm(&(attrib->registrar),
362 &(MSRP_db->mrp_db), event);
365 ("MSRP registrar error on attrib->type = %d\n",
376 * XXX should honor the MSRP_db->mrp_db.registration and
377 * MSRP_db->mrp_db.participant controls
380 /* generate local notifications */
381 attrib = MSRP_db->attrib_list;
383 while (NULL != attrib) {
384 if (MRP_NOTIFY_NONE != attrib->registrar.notify) {
385 msrp_send_notifications(attrib,
386 attrib->registrar.notify);
387 attrib->registrar.notify = MRP_NOTIFY_NONE;
389 attrib = attrib->next;
395 struct msrp_attribute *msrp_alloc()
397 struct msrp_attribute *attrib;
399 attrib = malloc(sizeof(struct msrp_attribute));
403 memset(attrib, 0, sizeof(struct msrp_attribute));
405 attrib->applicant.mrp_state = MRP_VO_STATE;
406 attrib->applicant.tx = 0;
407 attrib->applicant.sndmsg = MRP_SND_NULL;
408 attrib->applicant.encode = MRP_ENCODE_OPTIONAL;
410 attrib->registrar.mrp_state = MRP_MT_STATE;
411 attrib->registrar.notify = MRP_NOTIFY_NONE;
416 void msrp_increment_streamid(uint8_t * streamid)
423 if (255 != streamid[i]) {
439 mrpdu_message_t *mrpdu_msg;
440 unsigned char *mrpdu_msg_ptr;
441 unsigned char *mrpdu_msg_eof;
442 mrpdu_vectorattrib_t *mrpdu_vectorptr;
444 uint16_t numvalues_processed;
451 uint8_t srclassID_firstval;
452 uint8_t srclassprio_firstval;
453 uint16_t srclassvid_firstval;
454 uint8_t streamid_firstval[8];
455 uint8_t destmac_firstval[6];
456 struct msrp_attribute *attrib;
458 int *listener_vectevt = NULL;
459 int listener_vectevt_sz = 0;
460 int listener_vectevt_idx;
461 int listener_endbyte;
463 bytes = mrpd_recvmsgbuf(msrp_socket, &msgbuf);
466 if ((unsigned int)bytes < (sizeof(eth_hdr_t) + sizeof(mrpdu_t) +
467 sizeof(mrpdu_message_t)))
470 eth = (eth_hdr_t *) msgbuf;
472 /* note that MSRP frames should always arrive untagged (no vlan) */
473 if (MSRP_ETYPE != ntohs(eth->typelen)) {
476 /* XXX check dest mac address too? */
478 mrpdu = (mrpdu_t *) (msgbuf + sizeof(struct eth_hdr));
481 * ProtocolVersion handling - a receiver must process received frames with a lesser
482 * protocol version consistent with the older protocol processing requirements (e.g. a V2
483 * agent receives a V1 message, the V1 message should be parsed with V1 rules).
485 * However - if an agent receives a NEWER protocol, the agent should still attempt
486 * to parse the frame. If the agent finds an AttributeType not recognized
487 * the agent discards the current message including any associated trailing vectors
488 * up to the end-mark, and resumes with the next message or until the end of the PDU
491 * If a VectorAttribute is found with an unknown Event for the Type, the specific
492 * VectorAttrute is discarded and processing continues with the next VectorAttribute.
495 if (MSRP_PROT_VER != mrpdu->ProtocolVersion) { /* XXX should accept ... */
498 mrpdu_msg_ptr = MRPD_GET_MRPDU_MESSAGE_LIST(mrpdu);
500 mrpdu_msg_eof = (unsigned char *)mrpdu_msg_ptr;
501 mrpdu_msg_eof += bytes;
502 mrpdu_msg_eof -= sizeof(eth_hdr_t);
503 mrpdu_msg_eof -= MRPD_OFFSETOF_MRPD_GET_MRPDU_MESSAGE_LIST;
507 while (mrpdu_msg_ptr < (mrpdu_msg_eof - 2)) {
508 mrpdu_msg = (mrpdu_message_t *) mrpdu_msg_ptr;
509 if ((mrpdu_msg->AttributeType == 0) &&
510 (mrpdu_msg->AttributeLength == 0)) {
514 continue; /* end-mark of message-list */
516 break; /* two endmarks - end of message list */
521 switch (mrpdu_msg->AttributeType) {
522 case MSRP_DOMAIN_TYPE:
523 if (mrpdu_msg->AttributeLength != 4) {
524 /* we can seek for an endmark to recover .. but this version
525 * dumps the entire packet as malformed
531 (mrpdu_vectorattrib_t *)&(mrpdu_msg->Data[2]);
532 mrpdu_msg_ptr = (uint8_t *) mrpdu_vectorptr;
533 while (!((mrpdu_msg_ptr[0] == 0)
534 && (mrpdu_msg_ptr[1] == 0))) {
536 MRPDU_VECT_NUMVALUES(ntohs
540 if (0 == numvalues) {
541 /* skip this null attribute ... some switches generate these ... */
542 /* 2 byte numvalues + 4 byte FirstValue + (0) vector bytes */
544 (uint8_t *) mrpdu_vectorptr;
548 (mrpdu_vectorattrib_t *)
552 if ((mrpdu_vectorptr->FirstValue_VectorEvents +
553 numvalues / 3) >= mrpdu_msg_eof) {
554 /* Malformed - runs off the end of the pdu */
558 mrpdu_vectorptr->FirstValue_VectorEvents[0];
559 srclassprio_firstval =
560 mrpdu_vectorptr->FirstValue_VectorEvents[1];
561 srclassvid_firstval = ((uint16_t)
563 FirstValue_VectorEvents
565 mrpdu_vectorptr->FirstValue_VectorEvents[3];
567 /* if not an even multiple ... */
568 if (numvalues != ((numvalues / 3) * 3))
569 numvectorbytes = (numvalues / 3) + 1;
571 numvectorbytes = (numvalues / 3);
574 vectidx <= (numvectorbytes + 4);
578 FirstValue_VectorEvents[vectidx];
579 vectevt[0] = vect_3pack / 36;
581 (vect_3pack - vectevt[0] * 36) / 6;
583 vect_3pack - (36 * vectevt[0]) -
586 numvalues_processed =
587 (numvalues > 3 ? 3 : numvalues);
589 for (vectevt_idx = 0;
590 vectevt_idx < numvalues_processed;
593 attrib = msrp_alloc();
595 goto out; /* oops - internal error */
597 attrib->type = MSRP_DOMAIN_TYPE;
598 attrib->attribute.domain.
601 attrib->attribute.domain.
603 srclassprio_firstval;
604 attrib->attribute.domain.
608 srclassID_firstval++;
609 srclassprio_firstval++;
611 memcpy(attrib->registrar.
612 macaddr, eth->srcaddr,
615 switch (vectevt[vectevt_idx]) {
651 numvalues -= numvalues_processed;
655 (ntohs(mrpdu_vectorptr->VectorHeader)))
656 msrp_event(MRP_EVENT_RLA, NULL);
658 /* 2 byte numvalues + 4 byte FirstValue + (n) vector bytes */
659 mrpdu_msg_ptr = (uint8_t *) mrpdu_vectorptr;
660 mrpdu_msg_ptr += 6 + numvectorbytes;
663 (mrpdu_vectorattrib_t *) mrpdu_msg_ptr;
666 case MSRP_LISTENER_TYPE:
667 if (mrpdu_msg->AttributeLength != 8) {
668 /* we can seek for an endmark to recover .. but this version
669 * dumps the entire packet as malformed
674 /* MSRP uses AttributeListLength ... */
676 (mrpdu_vectorattrib_t *)&(mrpdu_msg->Data[2]);
677 mrpdu_msg_ptr = (uint8_t *) mrpdu_vectorptr;
679 while (!((mrpdu_msg_ptr[0] == 0)
680 && (mrpdu_msg_ptr[1] == 0))) {
682 MRPDU_VECT_NUMVALUES(ntohs
686 if (0 == numvalues) {
687 /* 2 byte numvalues + 8 byte FirstValue + (0) vector bytes */
689 (uint8_t *) mrpdu_vectorptr;
693 (mrpdu_vectorattrib_t *)
695 /* Malformed - cant tell how long the trailing vectors are */
698 if ((mrpdu_vectorptr->FirstValue_VectorEvents +
699 numvalues / 3 + numvalues / 4) >=
701 /* Malformed - runs off the end of the pdu */
704 memcpy(streamid_firstval,
706 (mrpdu_vectorptr->FirstValue_VectorEvents
710 * parse the 4-packed events first to figure out the substates, then
711 * insert them as we parse the 3-packed events for the MRP state machines
714 /* if not an even multiple ... */
715 if (numvalues != ((numvalues / 4) * 4))
716 numvectorbytes = (numvalues / 4) + 1;
718 numvectorbytes = (numvalues / 4);
720 if (numvalues != ((numvalues / 3) * 3))
721 vectidx = 8 + (numvalues / 3) + 1;
723 vectidx = 8 + (numvalues / 3);
725 listener_endbyte = vectidx + numvectorbytes;
728 (mrpdu_vectorptr->FirstValue_VectorEvents
729 [listener_endbyte]) >= mrpdu_msg_eof)
732 if (NULL == listener_vectevt) {
733 listener_vectevt_sz = 64;;
735 (int *)malloc(listener_vectevt_sz *
737 if (NULL == listener_vectevt)
741 listener_vectevt_idx = 0;
743 for (; vectidx < listener_endbyte; vectidx++) {
746 FirstValue_VectorEvents[vectidx];
750 ((vect_4pack >> 2) << 2);
751 vect_4pack = vect_4pack >> 2;
754 ((vect_4pack >> 2) << 2);
755 vect_4pack = vect_4pack >> 2;
758 ((vect_4pack >> 2) << 2);
759 vect_4pack = vect_4pack >> 2;
762 ((vect_4pack >> 2) << 2);
763 vect_4pack = vect_4pack >> 2;
765 numvalues_processed =
766 (numvalues > 4 ? 4 : numvalues);
768 for (vectevt_idx = 0;
769 vectevt_idx < numvalues_processed;
771 if (listener_vectevt_idx ==
772 listener_vectevt_sz) {
783 listener_vectevt_sz +=
787 [listener_vectevt_idx] =
788 vectevt[vectevt_idx];
789 listener_vectevt_idx++;
791 numvalues -= numvalues_processed;
795 MRPDU_VECT_NUMVALUES(ntohs
799 /* if not an even multiple ... */
800 if (numvalues != ((numvalues / 3) * 3))
801 numvectorbytes = (numvalues / 3) + 1;
803 numvectorbytes = (numvalues / 3);
805 listener_vectevt_idx = 0;
808 vectidx <= (numvectorbytes + 8);
812 FirstValue_VectorEvents[vectidx];
813 vectevt[0] = vect_3pack / 36;
815 (vect_3pack - vectevt[0] * 36) / 6;
817 vect_3pack - (36 * vectevt[0]) -
820 numvalues_processed =
821 (numvalues > 3 ? 3 : numvalues);
823 for (vectevt_idx = 0;
824 vectevt_idx < numvalues_processed;
827 if (MSRP_LISTENER_IGNORE ==
828 vectevt[vectevt_idx]) {
829 msrp_increment_streamid
834 attrib = msrp_alloc();
836 goto out; /* oops - internal error */
841 memcpy(attrib->attribute.
842 talk_listen.StreamID,
843 streamid_firstval, 8);
846 [listener_vectevt_idx];
847 msrp_increment_streamid
849 listener_vectevt_idx++;
851 memcpy(attrib->registrar.
852 macaddr, eth->srcaddr,
855 switch (vectevt[vectevt_idx]) {
891 numvalues -= numvalues_processed;
895 (ntohs(mrpdu_vectorptr->VectorHeader)))
896 msrp_event(MRP_EVENT_RLA, NULL);
899 MRPDU_VECT_NUMVALUES(ntohs
902 if (numvalues != ((numvalues / 4) * 4))
903 numvectorbytes += (numvalues / 4) + 1;
905 numvectorbytes += (numvalues / 4);
907 /* 2 byte numvalues + 8 byte FirstValue + (n) vector bytes */
908 mrpdu_msg_ptr = (uint8_t *) mrpdu_vectorptr;
909 mrpdu_msg_ptr += 10 + numvectorbytes;
912 (mrpdu_vectorattrib_t *) mrpdu_msg_ptr;
916 case MSRP_TALKER_ADV_TYPE:
917 /* another place where the spec munges with reality ...
918 * we can start out as a talker advertise type, but can get back
919 * a talker failed from the bridge in response ... in which
920 * by the spec we are supposed to merge the talker failed into
921 * the talker advertise and change the attribute type ...
923 * but also note the spec says that a talker cant change the
924 * firstvalues definition of a stream without tearing down the
925 * existing stream, wait two leave-all periods, then re-advertise
928 if (mrpdu_msg->AttributeLength != 25) {
929 /* we can seek for an endmark to recover .. but this version
930 * dumps the entire packet as malformed
935 /* MSRP uses AttributeListLength ... */
937 (mrpdu_vectorattrib_t *)&(mrpdu_msg->Data[2]);
938 mrpdu_msg_ptr = (uint8_t *) mrpdu_vectorptr;
940 while (!((mrpdu_msg_ptr[0] == 0)
941 && (mrpdu_msg_ptr[1] == 0))) {
943 MRPDU_VECT_NUMVALUES(ntohs
947 if (0 == numvalues) {
948 /* 2 byte numvalues + 25 byte FirstValue + (0) vector bytes */
950 (uint8_t *) mrpdu_vectorptr;
954 (mrpdu_vectorattrib_t *)
958 if ((mrpdu_vectorptr->FirstValue_VectorEvents +
959 numvalues / 3) >= mrpdu_msg_eof) {
960 /* Malformed - runs off the end of the pdu */
962 ("bad talker adv PDU too long \n");
965 memcpy(streamid_firstval,
966 mrpdu_vectorptr->FirstValue_VectorEvents,
968 memcpy(destmac_firstval,
970 (mrpdu_vectorptr->FirstValue_VectorEvents
973 /* if not an even multiple ... */
974 if (numvalues != ((numvalues / 3) * 3))
975 numvectorbytes = (numvalues / 3) + 1;
977 numvectorbytes = (numvalues / 3);
980 vectidx <= (numvectorbytes + 25);
984 FirstValue_VectorEvents[vectidx];
985 vectevt[0] = vect_3pack / 36;
987 (vect_3pack - vectevt[0] * 36) / 6;
989 vect_3pack - (36 * vectevt[0]) -
992 numvalues_processed =
993 (numvalues > 3 ? 3 : numvalues);
995 for (vectevt_idx = 0;
996 vectevt_idx < numvalues_processed;
999 attrib = msrp_alloc();
1001 goto out; /* oops - internal error */
1004 MSRP_TALKER_ADV_TYPE;
1006 /* note this ISNT from us ... */
1008 MSRP_DIRECTION_LISTENER;
1010 memcpy(attrib->attribute.
1011 talk_listen.StreamID,
1012 streamid_firstval, 8);
1013 memcpy(attrib->attribute.
1015 DataFrameParameters.
1017 destmac_firstval, 6);
1019 msrp_increment_streamid
1020 (streamid_firstval);
1021 mmrp_increment_macaddr
1024 attrib->attribute.talk_listen.
1025 DataFrameParameters.
1028 FirstValue_VectorEvents[14];
1029 attrib->attribute.talk_listen.
1030 DataFrameParameters.
1032 attrib->attribute.talk_listen.
1033 DataFrameParameters.
1036 FirstValue_VectorEvents[15];
1038 attrib->attribute.talk_listen.
1039 TSpec.MaxFrameSize =
1041 FirstValue_VectorEvents[16];
1042 attrib->attribute.talk_listen.
1043 TSpec.MaxFrameSize <<= 8;
1044 attrib->attribute.talk_listen.
1045 TSpec.MaxFrameSize |=
1047 FirstValue_VectorEvents[17];
1049 attrib->attribute.talk_listen.
1050 TSpec.MaxIntervalFrames =
1052 FirstValue_VectorEvents[18];
1053 attrib->attribute.talk_listen.
1055 MaxIntervalFrames <<= 8;
1056 attrib->attribute.talk_listen.
1057 TSpec.MaxIntervalFrames |=
1059 FirstValue_VectorEvents[19];
1061 attrib->attribute.talk_listen.
1064 FirstValue_VectorEvents[20];
1066 attrib->attribute.talk_listen.
1067 AccumulatedLatency =
1069 FirstValue_VectorEvents[21];
1070 attrib->attribute.talk_listen.
1071 AccumulatedLatency <<= 8;
1072 attrib->attribute.talk_listen.
1073 AccumulatedLatency |=
1075 FirstValue_VectorEvents[22];
1076 attrib->attribute.talk_listen.
1077 AccumulatedLatency <<= 8;
1078 attrib->attribute.talk_listen.
1079 AccumulatedLatency |=
1081 FirstValue_VectorEvents[23];
1082 attrib->attribute.talk_listen.
1083 AccumulatedLatency <<= 8;
1084 attrib->attribute.talk_listen.
1085 AccumulatedLatency |=
1087 FirstValue_VectorEvents[24];
1089 memcpy(attrib->registrar.
1090 macaddr, eth->srcaddr,
1093 switch (vectevt[vectevt_idx]) {
1129 numvalues -= numvalues_processed;
1133 (ntohs(mrpdu_vectorptr->VectorHeader)))
1134 msrp_event(MRP_EVENT_RLA, NULL);
1136 /* 2 byte numvalues + 25 byte FirstValue + (n) vector bytes */
1137 mrpdu_msg_ptr = (uint8_t *) mrpdu_vectorptr;
1138 mrpdu_msg_ptr += 27 + numvectorbytes;
1141 (mrpdu_vectorattrib_t *) mrpdu_msg_ptr;
1144 case MSRP_TALKER_FAILED_TYPE:
1145 if (mrpdu_msg->AttributeLength != 34) {
1146 /* we can seek for an endmark to recover .. but this version
1147 * dumps the entire packet as malformed
1152 /* MSRP uses AttributeListLength ... */
1154 (mrpdu_vectorattrib_t *)&(mrpdu_msg->Data[2]);
1155 mrpdu_msg_ptr = (uint8_t *) mrpdu_vectorptr;
1156 while (!((mrpdu_msg_ptr[0] == 0)
1157 && (mrpdu_msg_ptr[1] == 0))) {
1159 MRPDU_VECT_NUMVALUES(ntohs
1163 if (0 == numvalues) {
1164 /* 2 byte numvalues + 34 byte FirstValue + (0) vector bytes */
1166 (uint8_t *) mrpdu_vectorptr;
1167 mrpdu_msg_ptr += 36;
1169 (mrpdu_vectorattrib_t *)
1173 if ((mrpdu_vectorptr->FirstValue_VectorEvents +
1174 numvalues / 3) >= mrpdu_msg_eof)
1175 /* Malformed - runs off the end of the pdu */
1178 memcpy(streamid_firstval,
1179 mrpdu_vectorptr->FirstValue_VectorEvents,
1181 memcpy(destmac_firstval,
1183 (mrpdu_vectorptr->FirstValue_VectorEvents
1186 /* if not an even multiple ... */
1187 if (numvalues != ((numvalues / 3) * 3))
1188 numvectorbytes = (numvalues / 3) + 1;
1190 numvectorbytes = (numvalues / 3);
1193 vectidx <= (numvectorbytes + 34);
1197 FirstValue_VectorEvents[vectidx];
1198 vectevt[0] = vect_3pack / 36;
1200 (vect_3pack - vectevt[0] * 36) / 6;
1202 vect_3pack - (36 * vectevt[0]) -
1205 numvalues_processed =
1206 (numvalues > 3 ? 3 : numvalues);
1208 for (vectevt_idx = 0;
1209 vectevt_idx < numvalues_processed;
1212 attrib = msrp_alloc();
1214 goto out; /* oops - internal error */
1215 /* update the failure information on merge, but don't support
1216 * different ADV and FAILED_TYPES in the list of attributes */
1218 MSRP_TALKER_ADV_TYPE;
1220 /* NOTE this isn't from us */
1222 MSRP_DIRECTION_LISTENER;
1224 memcpy(attrib->attribute.
1225 talk_listen.StreamID,
1226 streamid_firstval, 8);
1227 memcpy(attrib->attribute.
1229 DataFrameParameters.
1231 destmac_firstval, 6);
1233 msrp_increment_streamid
1234 (streamid_firstval);
1235 mmrp_increment_macaddr
1238 attrib->attribute.talk_listen.
1239 DataFrameParameters.
1242 FirstValue_VectorEvents[14];
1243 attrib->attribute.talk_listen.
1244 DataFrameParameters.
1246 attrib->attribute.talk_listen.
1247 DataFrameParameters.
1250 FirstValue_VectorEvents[15];
1252 attrib->attribute.talk_listen.
1253 TSpec.MaxFrameSize =
1255 FirstValue_VectorEvents[16];
1256 attrib->attribute.talk_listen.
1257 TSpec.MaxFrameSize <<= 8;
1258 attrib->attribute.talk_listen.
1259 TSpec.MaxFrameSize |=
1261 FirstValue_VectorEvents[17];
1263 attrib->attribute.talk_listen.
1264 TSpec.MaxIntervalFrames =
1266 FirstValue_VectorEvents[18];
1267 attrib->attribute.talk_listen.
1269 MaxIntervalFrames <<= 8;
1270 attrib->attribute.talk_listen.
1271 TSpec.MaxIntervalFrames |=
1273 FirstValue_VectorEvents[19];
1275 attrib->attribute.talk_listen.
1278 FirstValue_VectorEvents[20];
1280 attrib->attribute.talk_listen.
1281 AccumulatedLatency =
1283 FirstValue_VectorEvents[21];
1284 attrib->attribute.talk_listen.
1285 AccumulatedLatency <<= 8;
1286 attrib->attribute.talk_listen.
1287 AccumulatedLatency |=
1289 FirstValue_VectorEvents[22];
1290 attrib->attribute.talk_listen.
1291 AccumulatedLatency <<= 8;
1292 attrib->attribute.talk_listen.
1293 AccumulatedLatency |=
1295 FirstValue_VectorEvents[23];
1296 attrib->attribute.talk_listen.
1297 AccumulatedLatency <<= 8;
1298 attrib->attribute.talk_listen.
1299 AccumulatedLatency |=
1301 FirstValue_VectorEvents[24];
1303 memcpy(attrib->attribute.
1308 FirstValue_VectorEvents
1311 attrib->attribute.talk_listen.
1315 FirstValue_VectorEvents[33];
1317 memcpy(attrib->registrar.
1318 macaddr, eth->srcaddr,
1321 switch (vectevt[vectevt_idx]) {
1357 numvalues -= numvalues_processed;
1361 (ntohs(mrpdu_vectorptr->VectorHeader)))
1362 msrp_event(MRP_EVENT_RLA, NULL);
1364 /* 2 byte numvalues + 34 byte FirstValue + (n) vector bytes */
1365 mrpdu_msg_ptr = (uint8_t *) mrpdu_vectorptr;
1366 mrpdu_msg_ptr += 36 + numvectorbytes;
1369 (mrpdu_vectorattrib_t *) mrpdu_msg_ptr;
1373 /* unrecognized attribute type
1374 * we can seek for an endmark to recover .. but this version
1375 * dumps the entire packet as malformed
1377 printf("unrecognized attribute type (%d)\n",
1378 mrpdu_msg->AttributeType);
1383 if (listener_vectevt)
1384 free(listener_vectevt);
1389 if (listener_vectevt)
1390 free(listener_vectevt);
1398 msrp_emit_talkvectors(unsigned char *msgbuf, unsigned char *msgbuf_eof,
1399 int *bytes_used, int lva)
1401 mrpdu_vectorattrib_t *mrpdu_vectorptr;
1407 uint8_t streamid_firstval[8];
1408 uint8_t destmac_firstval[6];
1410 struct msrp_attribute *attrib, *vattrib;
1411 mrpdu_message_t *mrpdu_msg;
1412 unsigned char *mrpdu_msg_ptr = msgbuf;
1413 unsigned char *mrpdu_msg_eof = msgbuf_eof;
1416 /* need at least 28 bytes for a single vector */
1417 if (mrpdu_msg_ptr > (mrpdu_msg_eof - 28))
1421 * as an endpoint, we don't advertise talker failed attributes (which
1422 * only a listener should receive) - but since this daemon could
1423 * function dual-mode - listening to streams as well as being a talker
1424 * station - we only advertise the talker vectors for declared streams,
1425 * not those we know about as a listener ...
1427 mrpdu_msg = (mrpdu_message_t *) mrpdu_msg_ptr;
1428 mrpdu_msg->AttributeType = MSRP_TALKER_ADV_TYPE;
1429 mrpdu_msg->AttributeLength = 25;
1431 attrib = MSRP_db->attrib_list;
1433 mrpdu_vectorptr = (mrpdu_vectorattrib_t *)&(mrpdu_msg->Data[2]);
1435 while ((mrpdu_msg_ptr < (mrpdu_msg_eof - 2)) && (NULL != attrib)) {
1437 if (MSRP_TALKER_ADV_TYPE != attrib->type) {
1438 attrib = attrib->next;
1442 if (MSRP_DIRECTION_LISTENER == attrib->direction) {
1443 attrib = attrib->next;
1447 if (0 == attrib->applicant.tx) {
1448 attrib = attrib->next;
1451 if (MRP_ENCODE_OPTIONAL == attrib->applicant.encode) {
1452 attrib->applicant.tx = 0;
1453 attrib = attrib->next;
1457 /* pointing to at least one attribute which needs to be transmitted */
1458 memcpy(streamid_firstval,
1459 attrib->attribute.talk_listen.StreamID, 8);
1460 memcpy(destmac_firstval,
1461 attrib->attribute.talk_listen.DataFrameParameters.
1463 memcpy(mrpdu_vectorptr->FirstValue_VectorEvents,
1464 streamid_firstval, 8);
1465 memcpy(&(mrpdu_vectorptr->FirstValue_VectorEvents[8]),
1466 destmac_firstval, 6);
1468 mrpdu_vectorptr->FirstValue_VectorEvents[14] =
1469 attrib->attribute.talk_listen.DataFrameParameters.
1471 mrpdu_vectorptr->FirstValue_VectorEvents[15] =
1472 (uint8_t) attrib->attribute.talk_listen.
1473 DataFrameParameters.Vlan_ID;
1475 mrpdu_vectorptr->FirstValue_VectorEvents[16] =
1476 attrib->attribute.talk_listen.TSpec.MaxFrameSize >> 8;
1477 mrpdu_vectorptr->FirstValue_VectorEvents[17] =
1478 (uint8_t) attrib->attribute.talk_listen.TSpec.MaxFrameSize;
1480 mrpdu_vectorptr->FirstValue_VectorEvents[18] =
1481 attrib->attribute.talk_listen.TSpec.MaxIntervalFrames >> 8;
1482 mrpdu_vectorptr->FirstValue_VectorEvents[19] =
1483 (uint8_t) attrib->attribute.talk_listen.
1484 TSpec.MaxIntervalFrames;
1486 mrpdu_vectorptr->FirstValue_VectorEvents[20] =
1487 attrib->attribute.talk_listen.PriorityAndRank;
1489 mrpdu_vectorptr->FirstValue_VectorEvents[21] =
1490 attrib->attribute.talk_listen.AccumulatedLatency >> 24;
1491 mrpdu_vectorptr->FirstValue_VectorEvents[22] =
1492 attrib->attribute.talk_listen.AccumulatedLatency >> 16;
1493 mrpdu_vectorptr->FirstValue_VectorEvents[23] =
1494 attrib->attribute.talk_listen.AccumulatedLatency >> 8;
1495 mrpdu_vectorptr->FirstValue_VectorEvents[24] =
1496 attrib->attribute.talk_listen.AccumulatedLatency;
1498 switch (attrib->applicant.sndmsg) {
1501 * If 'In' in indicated by the applicant attribute, the
1502 * look at the registrar state to determine whether to
1503 * send an In (if registrar is also In) or an Mt if the
1504 * registrar is either Mt or Lv.
1506 if (MRP_IN_STATE == attrib->registrar.mrp_state)
1507 vectevt[0] = MRPDU_IN;
1509 vectevt[0] = MRPDU_MT;
1512 vectevt[0] = MRPDU_NEW;
1515 vectevt[0] = MRPDU_LV;
1518 /* IF 'Join' in indicated by the applicant, look at
1519 * the corresponding registrar state to determine whether
1520 * to send a JoinIn (if the registar state is 'In') or
1521 * a JoinMt if the registrar state is MT or LV.
1523 if (MRP_IN_STATE == attrib->registrar.mrp_state)
1524 vectevt[0] = MRPDU_JOININ;
1526 vectevt[0] = MRPDU_JOINMT;
1539 /* now attempt to vectorize contiguous other attributes
1540 * which also need to be transmitted
1544 vattrib = attrib->next;
1546 while (NULL != vattrib) {
1547 if (MSRP_TALKER_ADV_TYPE != vattrib->type)
1550 if (0 == vattrib->applicant.tx)
1553 msrp_increment_streamid(streamid_firstval);
1554 mmrp_increment_macaddr(destmac_firstval);
1556 mac_eq = memcmp(vattrib->attribute.talk_listen.StreamID,
1557 streamid_firstval, 8);
1562 vattrib->applicant.tx = 0;
1564 switch (vattrib->applicant.sndmsg) {
1567 * If 'In' in indicated by the applicant attribute, the
1568 * look at the registrar state to determine whether to
1569 * send an In (if registrar is also In) or an Mt if the
1570 * registrar is either Mt or Lv.
1573 vattrib->registrar.mrp_state)
1574 vectevt[vectevt_idx] = MRPDU_IN;
1576 vectevt[vectevt_idx] = MRPDU_MT;
1579 vectevt[vectevt_idx] = MRPDU_NEW;
1582 vectevt[vectevt_idx] = MRPDU_LV;
1585 /* IF 'Join' in indicated by the applicant, look at
1586 * the corresponding registrar state to determine whether
1587 * to send a JoinIn (if the registar state is 'In') or
1588 * a JoinMt if the registrar state is MT or LV.
1590 if (MRP_IN_STATE == attrib->registrar.mrp_state)
1591 vectevt[vectevt_idx] = MRPDU_JOININ;
1593 vectevt[vectevt_idx] = MRPDU_JOINMT;
1604 if (vectevt_idx > 2) {
1605 vect_3pack = MRPDU_3PACK_ENCODE(vectevt[0],
1609 mrpdu_vectorptr->FirstValue_VectorEvents
1610 [vectidx] = vect_3pack;
1618 if (&(mrpdu_vectorptr->FirstValue_VectorEvents[vectidx])
1619 > (mrpdu_msg_eof - 2))
1622 vattrib = vattrib->next;
1625 /* handle any trailers */
1626 if (vectevt_idx > 0) {
1627 vect_3pack = MRPDU_3PACK_ENCODE(vectevt[0],
1628 vectevt[1], vectevt[2]);
1630 mrpdu_vectorptr->FirstValue_VectorEvents[vectidx] =
1635 if (&(mrpdu_vectorptr->FirstValue_VectorEvents[vectidx]) >
1636 (mrpdu_msg_eof - 2))
1639 mrpdu_vectorptr->VectorHeader = MRPDU_VECT_NUMVALUES(numvalues);
1642 mrpdu_vectorptr->VectorHeader |= MRPDU_VECT_LVA(0xFFFF);
1644 mrpdu_vectorptr->VectorHeader =
1645 htons(mrpdu_vectorptr->VectorHeader);
1648 &(mrpdu_vectorptr->FirstValue_VectorEvents[vectidx]);
1649 mrpdu_vectorptr = (mrpdu_vectorattrib_t *) mrpdu_msg_ptr;
1651 attrib = attrib->next;
1655 if (mrpdu_vectorptr == (mrpdu_vectorattrib_t *)&(mrpdu_msg->Data[2])) {
1666 *bytes_used = (mrpdu_msg_ptr - msgbuf);
1668 attriblistlen = mrpdu_msg_ptr - &(mrpdu_msg->Data[2]);
1669 mrpdu_msg->Data[0] = (uint8_t) (attriblistlen >> 8);
1670 mrpdu_msg->Data[1] = (uint8_t) attriblistlen;
1673 /* an internal error - caller should assume TXLAF */
1679 msrp_emit_listenvectors(unsigned char *msgbuf, unsigned char *msgbuf_eof,
1680 int *bytes_used, int lva)
1682 mrpdu_vectorattrib_t *mrpdu_vectorptr;
1683 mrpdu_message_t *mrpdu_msg;
1684 unsigned char *mrpdu_msg_ptr = msgbuf;
1685 unsigned char *mrpdu_msg_eof = msgbuf_eof;
1693 int *listen_declare = NULL;
1694 int listen_declare_sz = 64;
1695 int listen_declare_idx = 0;
1696 int listen_declare_end = 0;
1697 uint8_t streamid_firstval[8];
1698 struct msrp_attribute *attrib, *vattrib;
1701 /* need at least 13 bytes for a single vector */
1702 if (mrpdu_msg_ptr > (mrpdu_msg_eof - 13))
1705 mrpdu_msg = (mrpdu_message_t *) mrpdu_msg_ptr;
1706 mrpdu_msg->AttributeType = MSRP_LISTENER_TYPE;
1707 mrpdu_msg->AttributeLength = 8;
1709 listen_declare = (int *)malloc(listen_declare_sz * sizeof(int));
1710 if (NULL == listen_declare)
1713 attrib = MSRP_db->attrib_list;
1715 mrpdu_vectorptr = (mrpdu_vectorattrib_t *)&(mrpdu_msg->Data[2]);
1717 while ((mrpdu_msg_ptr < (mrpdu_msg_eof - 2)) && (NULL != attrib)) {
1719 if (MSRP_LISTENER_TYPE != attrib->type) {
1720 attrib = attrib->next;
1724 listen_declare_idx = 0;
1726 /* if we have a listener type registered, we always will
1727 * send out an update. We also don't bother trying to
1728 * insert IGNORES between stream IDs - we only send out
1729 * contiguous active streams in messages
1732 /* pointing to at least one attribute which needs to be transmitted */
1733 memcpy(streamid_firstval,
1734 attrib->attribute.talk_listen.StreamID, 8);
1735 memcpy(&(mrpdu_vectorptr->FirstValue_VectorEvents),
1736 attrib->attribute.talk_listen.StreamID, 8);
1738 switch (attrib->applicant.sndmsg) {
1741 * If 'In' in indicated by the applicant attribute, the
1742 * look at the registrar state to determine whether to
1743 * send an In (if registrar is also In) or an Mt if the
1744 * registrar is either Mt or Lv.
1746 if (MRP_IN_STATE == attrib->registrar.mrp_state)
1747 vectevt[0] = MRPDU_IN;
1749 vectevt[0] = MRPDU_MT;
1752 vectevt[0] = MRPDU_NEW;
1755 vectevt[0] = MRPDU_LV;
1758 /* IF 'Join' in indicated by the applicant, look at
1759 * the corresponding registrar state to determine whether
1760 * to send a JoinIn (if the registar state is 'In') or
1761 * a JoinMt if the registrar state is MT or LV.
1763 if (MRP_IN_STATE == attrib->registrar.mrp_state)
1764 vectevt[0] = MRPDU_JOININ;
1766 vectevt[0] = MRPDU_JOINMT;
1779 if (listen_declare_sz == (listen_declare_idx + 1)) {
1781 (int *)realloc(listen_declare,
1783 listen_declare_sz) * sizeof(int));
1784 if (NULL == listen_declare)
1787 listen_declare_sz += 64;
1790 listen_declare[listen_declare_idx] = attrib->substate;
1791 listen_declare_idx++;
1793 /* now attempt to vectorize contiguous other attributes
1794 * which also need to be transmitted
1798 vattrib = attrib->next;
1800 while (NULL != vattrib) {
1801 if (MSRP_LISTENER_TYPE != vattrib->type)
1804 if (0 == vattrib->applicant.tx)
1807 msrp_increment_streamid(streamid_firstval);
1809 mac_eq = memcmp(vattrib->attribute.talk_listen.StreamID,
1810 streamid_firstval, 8);
1815 vattrib->applicant.tx = 0;
1817 switch (vattrib->applicant.sndmsg) {
1820 * If 'In' in indicated by the applicant attribute, the
1821 * look at the registrar state to determine whether to
1822 * send an In (if registrar is also In) or an Mt if the
1823 * registrar is either Mt or Lv.
1826 vattrib->registrar.mrp_state)
1827 vectevt[vectevt_idx] = MRPDU_IN;
1829 vectevt[vectevt_idx] = MRPDU_MT;
1832 vectevt[vectevt_idx] = MRPDU_NEW;
1835 vectevt[vectevt_idx] = MRPDU_LV;
1838 /* IF 'Join' in indicated by the applicant, look at
1839 * the corresponding registrar state to determine whether
1840 * to send a JoinIn (if the registar state is 'In') or
1841 * a JoinMt if the registrar state is MT or LV.
1843 if (MRP_IN_STATE == attrib->registrar.mrp_state)
1844 vectevt[vectevt_idx] = MRPDU_JOININ;
1846 vectevt[vectevt_idx] = MRPDU_JOINMT;
1857 if (listen_declare_sz == (listen_declare_idx + 1)) {
1859 (int *)realloc(listen_declare,
1861 listen_declare_sz) *
1863 listen_declare_sz += 64;
1866 listen_declare[listen_declare_idx] = vattrib->substate;
1867 listen_declare_idx++;
1869 if (vectevt_idx > 2) {
1870 vect_3pack = MRPDU_3PACK_ENCODE(vectevt[0],
1874 mrpdu_vectorptr->FirstValue_VectorEvents
1875 [vectidx] = vect_3pack;
1883 if (&(mrpdu_vectorptr->FirstValue_VectorEvents[vectidx])
1884 > (mrpdu_msg_eof - 2))
1887 vattrib = vattrib->next;
1890 /* handle any trailers */
1891 if (vectevt_idx > 0) {
1892 vect_3pack = MRPDU_3PACK_ENCODE(vectevt[0],
1893 vectevt[1], vectevt[2]);
1895 mrpdu_vectorptr->FirstValue_VectorEvents[vectidx] =
1900 /* now emit the 4-packed events */
1902 listen_declare_end = listen_declare_idx;
1904 for (listen_declare_idx = 0;
1905 listen_declare_idx < ((listen_declare_end / 4) * 4);
1906 listen_declare_idx += 4) {
1908 if (&(mrpdu_vectorptr->FirstValue_VectorEvents[vectidx])
1909 > (mrpdu_msg_eof - 2))
1912 if (vectevt_idx > 3) {
1914 MRPDU_4PACK_ENCODE(listen_declare
1915 [listen_declare_idx],
1917 [listen_declare_idx + 1],
1919 [listen_declare_idx + 2],
1921 [listen_declare_idx +
1924 mrpdu_vectorptr->FirstValue_VectorEvents
1925 [vectidx] = vect_4pack;
1929 if (&(mrpdu_vectorptr->FirstValue_VectorEvents[vectidx])
1930 > (mrpdu_msg_eof - 3))
1935 /* handle any trailers */
1937 while (listen_declare_idx < listen_declare_end) {
1938 vectevt[vectevt_idx] =
1939 listen_declare[listen_declare_idx];
1940 listen_declare_idx++;
1944 vect_4pack = MRPDU_4PACK_ENCODE(vectevt[0],
1946 vectevt[2], vectevt[3]);
1948 mrpdu_vectorptr->FirstValue_VectorEvents[vectidx] =
1953 if (&(mrpdu_vectorptr->FirstValue_VectorEvents[vectidx]) >
1954 (mrpdu_msg_eof - 2))
1957 mrpdu_vectorptr->VectorHeader = MRPDU_VECT_NUMVALUES(numvalues);
1960 mrpdu_vectorptr->VectorHeader |= MRPDU_VECT_LVA(0xFFFF);
1962 mrpdu_vectorptr->VectorHeader =
1963 htons(mrpdu_vectorptr->VectorHeader);
1966 &(mrpdu_vectorptr->FirstValue_VectorEvents[vectidx]);
1968 attrib = attrib->next;
1970 mrpdu_vectorptr = (mrpdu_vectorattrib_t *) mrpdu_msg_ptr;
1973 if (mrpdu_vectorptr == (mrpdu_vectorattrib_t *)&(mrpdu_msg->Data[2])) {
1975 free(listen_declare);
1986 *bytes_used = (mrpdu_msg_ptr - msgbuf);
1988 attriblistlen = mrpdu_msg_ptr - &(mrpdu_msg->Data[2]);
1989 mrpdu_msg->Data[0] = (uint8_t) (attriblistlen >> 8);
1990 mrpdu_msg->Data[1] = (uint8_t) attriblistlen;
1992 free(listen_declare);
1995 /* an internal error - caller should assume TXLAF */
1997 free(listen_declare);
2002 int msrp_txpdu(void)
2004 unsigned char *msgbuf, *msgbuf_wrptr;
2009 unsigned char *mrpdu_msg_ptr;
2010 unsigned char *mrpdu_msg_eof;
2014 msgbuf = (unsigned char *)malloc(MAX_FRAME_SIZE);
2019 msgbuf_wrptr = msgbuf;
2021 eth = (eth_hdr_t *) msgbuf_wrptr;
2023 /* note that MSRP frames should always be untagged (no vlan) */
2024 eth->typelen = htons(MSRP_ETYPE);
2025 memcpy(eth->destaddr, MSRP_ADDR, sizeof(eth->destaddr));
2026 memcpy(eth->srcaddr, STATION_ADDR, sizeof(eth->srcaddr));
2028 msgbuf_wrptr += sizeof(eth_hdr_t);
2030 mrpdu = (mrpdu_t *) msgbuf_wrptr;
2032 mrpdu->ProtocolVersion = MSRP_PROT_VER;
2033 mrpdu_msg_ptr = MRPD_GET_MRPDU_MESSAGE_LIST(mrpdu);
2034 mrpdu_msg_eof = (unsigned char *)msgbuf + MAX_FRAME_SIZE;
2036 if (MSRP_db->mrp_db.lva.tx) {
2038 MSRP_db->mrp_db.lva.tx = 0;
2041 rc = msrp_emit_talkvectors(mrpdu_msg_ptr, mrpdu_msg_eof, &bytes, lva);
2045 mrpdu_msg_ptr += bytes;
2047 if (mrpdu_msg_ptr >= (mrpdu_msg_eof - 2))
2050 rc = msrp_emit_listenvectors(mrpdu_msg_ptr, mrpdu_msg_eof, &bytes, lva);
2054 mrpdu_msg_ptr += bytes;
2056 if (mrpdu_msg_ptr == MRPD_GET_MRPDU_MESSAGE_LIST(mrpdu)) {
2057 goto out; /* nothing to send */
2061 if (mrpdu_msg_ptr < (mrpdu_msg_eof - 2)) {
2069 msgbuf_len = mrpdu_msg_ptr - msgbuf;
2071 bytes = mrpd_send(msrp_socket, msgbuf, msgbuf_len, 0);
2079 /* caller should assume TXLAF */
2083 int msrp_send_notifications(struct msrp_attribute *attrib, int notify)
2094 msgbuf = (char *)malloc(MAX_MRPD_CMDSZ);
2098 stage = variant = regsrc = NULL;
2100 stage = (char *)malloc(128);
2101 variant = (char *)malloc(128);
2102 regsrc = (char *)malloc(128);
2104 if ((NULL == stage) || (NULL == variant) || (NULL == regsrc))
2107 memset(msgbuf, 0, MAX_MRPD_CMDSZ);
2109 if (MSRP_LISTENER_TYPE == attrib->type) {
2110 sprintf(variant, "L:D=%d,S=%02x%02x%02x%02x%02x%02x%02x%02x",
2112 attrib->attribute.talk_listen.StreamID[0],
2113 attrib->attribute.talk_listen.StreamID[1],
2114 attrib->attribute.talk_listen.StreamID[2],
2115 attrib->attribute.talk_listen.StreamID[3],
2116 attrib->attribute.talk_listen.StreamID[4],
2117 attrib->attribute.talk_listen.StreamID[5],
2118 attrib->attribute.talk_listen.StreamID[6],
2119 attrib->attribute.talk_listen.StreamID[7]);
2120 } else if (MSRP_DOMAIN_TYPE == attrib->type) {
2121 sprintf(variant, "D:C=%d,P=%d,V=%04x",
2122 attrib->attribute.domain.SRclassID,
2123 attrib->attribute.domain.SRclassPriority,
2124 attrib->attribute.domain.SRclassVID);
2126 sprintf(variant, "T:S=%02x%02x%02x%02x%02x%02x%02x%02x"
2127 ",A=%02x%02x%02x%02x%02x%02x"
2133 ",B=%02x%02x%02x%02x%02x%02x%02x%02x"
2135 attrib->attribute.talk_listen.StreamID[0],
2136 attrib->attribute.talk_listen.StreamID[1],
2137 attrib->attribute.talk_listen.StreamID[2],
2138 attrib->attribute.talk_listen.StreamID[3],
2139 attrib->attribute.talk_listen.StreamID[4],
2140 attrib->attribute.talk_listen.StreamID[5],
2141 attrib->attribute.talk_listen.StreamID[6],
2142 attrib->attribute.talk_listen.StreamID[7],
2143 attrib->attribute.talk_listen.DataFrameParameters.
2145 attrib->attribute.talk_listen.DataFrameParameters.
2147 attrib->attribute.talk_listen.DataFrameParameters.
2149 attrib->attribute.talk_listen.DataFrameParameters.
2151 attrib->attribute.talk_listen.DataFrameParameters.
2153 attrib->attribute.talk_listen.DataFrameParameters.
2155 attrib->attribute.talk_listen.DataFrameParameters.
2157 attrib->attribute.talk_listen.TSpec.MaxFrameSize,
2158 attrib->attribute.talk_listen.TSpec.MaxIntervalFrames,
2159 attrib->attribute.talk_listen.PriorityAndRank,
2160 attrib->attribute.talk_listen.AccumulatedLatency,
2161 attrib->attribute.talk_listen.FailureInformation.
2163 attrib->attribute.talk_listen.FailureInformation.
2165 attrib->attribute.talk_listen.FailureInformation.
2167 attrib->attribute.talk_listen.FailureInformation.
2169 attrib->attribute.talk_listen.FailureInformation.
2171 attrib->attribute.talk_listen.FailureInformation.
2173 attrib->attribute.talk_listen.FailureInformation.
2175 attrib->attribute.talk_listen.FailureInformation.
2177 attrib->attribute.talk_listen.FailureInformation.
2181 sprintf(regsrc, "R=%02x%02x%02x%02x%02x%02x",
2182 attrib->registrar.macaddr[0],
2183 attrib->registrar.macaddr[1],
2184 attrib->registrar.macaddr[2],
2185 attrib->registrar.macaddr[3],
2186 attrib->registrar.macaddr[4], attrib->registrar.macaddr[5]);
2189 case MRP_NOTIFY_NEW:
2190 sprintf(msgbuf, "SNE %s %s", variant, regsrc);
2192 case MRP_NOTIFY_JOIN:
2193 sprintf(msgbuf, "SJO %s %s", variant, regsrc);
2196 sprintf(msgbuf, "SLE %s %s", variant, regsrc);
2203 client = MSRP_db->mrp_db.clients;
2204 while (NULL != client) {
2205 mrpd_send_ctl_msg(&(client->client), msgbuf, MAX_MRPD_CMDSZ);
2206 client = client->next;
2220 int msrp_dumptable(struct sockaddr_in *client)
2227 struct msrp_attribute *attrib;
2230 msgbuf = (char *)malloc(MAX_MRPD_CMDSZ);
2234 stage = variant = regsrc = NULL;
2236 stage = (char *)malloc(128);
2237 variant = (char *)malloc(128);
2238 regsrc = (char *)malloc(128);
2240 if ((NULL == stage) || (NULL == variant) || (NULL == regsrc))
2243 memset(msgbuf, 0, MAX_MRPD_CMDSZ);
2245 msgbuf_wrptr = msgbuf;
2247 attrib = MSRP_db->attrib_list;
2249 while (NULL != attrib) {
2250 if (MSRP_LISTENER_TYPE == attrib->type) {
2252 "L:D=%d,S=%02x%02x%02x%02x%02x%02x%02x%02x",
2254 attrib->attribute.talk_listen.StreamID[0],
2255 attrib->attribute.talk_listen.StreamID[1],
2256 attrib->attribute.talk_listen.StreamID[2],
2257 attrib->attribute.talk_listen.StreamID[3],
2258 attrib->attribute.talk_listen.StreamID[4],
2259 attrib->attribute.talk_listen.StreamID[5],
2260 attrib->attribute.talk_listen.StreamID[6],
2261 attrib->attribute.talk_listen.StreamID[7]);
2262 } else if (MSRP_DOMAIN_TYPE == attrib->type) {
2263 sprintf(variant, "D:C=%d,P=%d,V:%04x",
2264 attrib->attribute.domain.SRclassID,
2265 attrib->attribute.domain.SRclassPriority,
2266 attrib->attribute.domain.SRclassVID);
2268 sprintf(variant, "T:S=%02x%02x%02x%02x%02x%02x%02x%02x"
2269 ",A=%02x%02x%02x%02x%02x%02x"
2275 ",B=%02x%02x%02x%02x%02x%02x%02x%02x"
2277 attrib->attribute.talk_listen.StreamID[0],
2278 attrib->attribute.talk_listen.StreamID[1],
2279 attrib->attribute.talk_listen.StreamID[2],
2280 attrib->attribute.talk_listen.StreamID[3],
2281 attrib->attribute.talk_listen.StreamID[4],
2282 attrib->attribute.talk_listen.StreamID[5],
2283 attrib->attribute.talk_listen.StreamID[6],
2284 attrib->attribute.talk_listen.StreamID[7],
2285 attrib->attribute.talk_listen.
2286 DataFrameParameters.Dest_Addr[0],
2287 attrib->attribute.talk_listen.
2288 DataFrameParameters.Dest_Addr[1],
2289 attrib->attribute.talk_listen.
2290 DataFrameParameters.Dest_Addr[2],
2291 attrib->attribute.talk_listen.
2292 DataFrameParameters.Dest_Addr[3],
2293 attrib->attribute.talk_listen.
2294 DataFrameParameters.Dest_Addr[4],
2295 attrib->attribute.talk_listen.
2296 DataFrameParameters.Dest_Addr[5],
2297 attrib->attribute.talk_listen.
2298 DataFrameParameters.Vlan_ID,
2299 attrib->attribute.talk_listen.TSpec.
2301 attrib->attribute.talk_listen.TSpec.
2303 attrib->attribute.talk_listen.PriorityAndRank,
2304 attrib->attribute.talk_listen.
2306 attrib->attribute.talk_listen.
2307 FailureInformation.BridgeID[0],
2308 attrib->attribute.talk_listen.
2309 FailureInformation.BridgeID[1],
2310 attrib->attribute.talk_listen.
2311 FailureInformation.BridgeID[2],
2312 attrib->attribute.talk_listen.
2313 FailureInformation.BridgeID[3],
2314 attrib->attribute.talk_listen.
2315 FailureInformation.BridgeID[4],
2316 attrib->attribute.talk_listen.
2317 FailureInformation.BridgeID[5],
2318 attrib->attribute.talk_listen.
2319 FailureInformation.BridgeID[6],
2320 attrib->attribute.talk_listen.
2321 FailureInformation.BridgeID[7],
2322 attrib->attribute.talk_listen.
2323 FailureInformation.FailureCode);
2326 mrp_decode_state(&attrib->registrar, &attrib->applicant,
2327 mrp_state, sizeof(mrp_state));
2329 sprintf(regsrc, "R=%02x%02x%02x%02x%02x%02x %s",
2330 attrib->registrar.macaddr[0],
2331 attrib->registrar.macaddr[1],
2332 attrib->registrar.macaddr[2],
2333 attrib->registrar.macaddr[3],
2334 attrib->registrar.macaddr[4],
2335 attrib->registrar.macaddr[5], mrp_state);
2337 sprintf(stage, "%s %s\n", variant, regsrc);
2339 sprintf(msgbuf_wrptr, "%s", stage);
2340 msgbuf_wrptr += strlen(stage);
2341 attrib = attrib->next;
2344 mrpd_send_ctl_msg(client, msgbuf, MAX_MRPD_CMDSZ);
2358 /* S+? - (re)JOIN a stream */
2359 /* S++ - NEW a stream */
2360 int msrp_cmd_parse_join_or_new_stream(
2361 char *buf, int buflen,
2362 struct msrpdu_talker_fail *talker_ad,
2366 struct parse_param specs[] = {
2367 {"S" PARSE_ASSIGN, parse_c64, talker_ad->StreamID},
2368 {"A" PARSE_ASSIGN, parse_mac, talker_ad->DataFrameParameters.Dest_Addr},
2369 {"V" PARSE_ASSIGN, parse_u16, &talker_ad->DataFrameParameters.Vlan_ID},
2370 {"Z" PARSE_ASSIGN, parse_u16, &talker_ad->TSpec.MaxFrameSize},
2371 {"I" PARSE_ASSIGN, parse_u16, &talker_ad->TSpec.MaxIntervalFrames},
2372 {"P" PARSE_ASSIGN, parse_u8, &talker_ad->PriorityAndRank},
2373 {"L" PARSE_ASSIGN, parse_u32, &talker_ad->AccumulatedLatency},
2378 memset(talker_ad, 0, sizeof(*talker_ad));
2379 return parse(buf + 4, buflen - 4, specs, err_index);
2384 * Required fields are:
2385 * talker_ad->StreamID
2386 * talker_ad->DataFrameParameters.Dest_Addr
2387 * talker_ad->DataFrameParameters.Vlan_ID
2388 * talker_ad->TSpec.MaxFrameSize
2389 * talker_ad->TSpec.MaxIntervalFrames
2390 * talker_ad->PriorityAndRank
2391 * talker_ad->AccumulatedLatency
2395 int msrp_cmd_join_or_new_stream(
2397 struct msrpdu_talker_fail *talker_ad
2400 struct msrp_attribute *attrib;
2402 attrib = msrp_alloc();
2403 if (NULL == attrib) {
2406 attrib->type = MSRP_TALKER_ADV_TYPE;
2407 attrib->attribute.talk_listen = *talker_ad;
2410 msrp_event(MRP_EVENT_JOIN, attrib);
2412 msrp_event(MRP_EVENT_NEW, attrib);
2417 /* S-- - LV a stream */
2418 int msrp_cmd_parse_leave_stream(
2419 char *buf, int buflen,
2420 struct msrpdu_talker_fail *talker_ad,
2424 struct parse_param specs[] = {
2425 {"S" PARSE_ASSIGN, parse_c64, talker_ad->StreamID},
2430 memset(talker_ad, 0, sizeof(*talker_ad));
2431 return parse(buf + 4, buflen - 4, specs, err_index);
2434 int msrp_cmd_leave_stream(
2435 struct msrpdu_talker_fail *talker_ad
2438 struct msrp_attribute *attrib;
2440 attrib = msrp_alloc();
2441 if (NULL == attrib) {
2444 attrib->type = MSRP_TALKER_ADV_TYPE;
2445 attrib->attribute.talk_listen = *talker_ad;
2446 msrp_event(MRP_EVENT_LV, attrib);
2451 /* S+L Report a listener status */
2452 int msrp_cmd_parse_report_listener_status(
2453 char *buf, int buflen,
2454 struct msrpdu_talker_fail *talker_ad,
2459 struct parse_param specs[] = {
2460 {"L" PARSE_ASSIGN, parse_c64, talker_ad->StreamID},
2461 {"D" PARSE_ASSIGN, parse_u32, substate},
2466 memset(talker_ad, 0, sizeof(*talker_ad));
2467 return parse(buf + 4, buflen - 4, specs, err_index);
2470 int msrp_cmd_report_listener_status(
2471 struct msrpdu_talker_fail *talker_ad,
2475 struct msrp_attribute *attrib;
2477 attrib = msrp_alloc();
2478 if (NULL == attrib) {
2481 attrib->type = MSRP_LISTENER_TYPE;
2482 attrib->direction = MSRP_DIRECTION_LISTENER;
2483 attrib->substate = substate;
2484 attrib->attribute.talk_listen = *talker_ad;
2485 msrp_event(MRP_EVENT_JOIN, attrib);
2490 /* S-L Withdraw a listener status */
2491 int msrp_cmd_parse_withdraw_listener_status(
2492 char *buf, int buflen,
2493 struct msrpdu_talker_fail *talker_ad,
2497 struct parse_param specs[] = {
2498 {"L" PARSE_ASSIGN, parse_c64, talker_ad->StreamID},
2504 memset(talker_ad, 0, sizeof(*talker_ad));
2505 return parse(buf + 4, buflen - 4, specs, err_index);
2508 int msrp_cmd_withdraw_listener_status(
2509 struct msrpdu_talker_fail *talker_ad
2512 struct msrp_attribute *attrib;
2514 attrib = msrp_alloc();
2515 if (NULL == attrib) {
2518 attrib->type = MSRP_LISTENER_TYPE;
2519 attrib->attribute.talk_listen = *talker_ad;
2520 msrp_event(MRP_EVENT_LV, attrib);
2526 /* S+D Report a domain status */
2527 /* S-D Withdraw a domain status */
2528 int msrp_cmd_parse_domain_status(
2529 char *buf, int buflen,
2530 struct msrpdu_domain *domain,
2534 struct parse_param specs[] = {
2535 {"C" PARSE_ASSIGN, parse_u8, &domain->SRclassID},
2536 {"P" PARSE_ASSIGN, parse_u8, &domain->SRclassPriority},
2537 {"V" PARSE_ASSIGN, parse_u16_04x, &domain->SRclassVID},
2542 memset(domain, 0, sizeof(*domain));
2543 return parse(buf + 4, buflen - 4, specs, err_index);
2546 int msrp_cmd_report_domain_status(
2547 struct msrpdu_domain *domain,
2550 struct msrp_attribute *attrib;
2552 attrib = msrp_alloc();
2553 if (NULL == attrib) {
2556 attrib->attribute.domain = *domain;
2558 msrp_event(MRP_EVENT_JOIN, attrib);
2560 msrp_event(MRP_EVENT_LV, attrib);
2565 int msrp_recv_cmd(char *buf, int buflen, struct sockaddr_in *client)
2570 unsigned int substate;
2571 struct msrpdu_domain domain_param;
2572 struct msrpdu_talker_fail talker_param;
2575 if (NULL == MSRP_db) {
2576 snprintf(respbuf, sizeof(respbuf) - 1, "ERC %s", buf);
2577 mrpd_send_ctl_msg(client, respbuf, sizeof(respbuf));
2581 rc = mrp_client_add(&(MSRP_db->mrp_db.clients), client);
2590 * S?? - query MSRP Registrar database
2591 * S+? - (re)JOIN a stream
2594 * S+L Report a listener status
2595 * S-L Withdraw a listener status
2596 * S+D Report a domain status
2597 * S-D Withdraw a domain status
2601 if (strncmp(buf, "S??", 3)==0) {
2602 msrp_dumptable(client);
2604 } else if (strncmp(buf, "S-L", 3) == 0) {
2606 /* buf[] should look similar to 'S-L:L=xxyyzz...' */
2607 rc = msrp_cmd_parse_withdraw_listener_status(buf, buflen, &talker_param, &err_index);
2610 rc = msrp_cmd_withdraw_listener_status(&talker_param);
2612 goto out_ERI; /* oops - internal error */
2613 } else if (strncmp(buf, "S-D", 3) == 0) {
2615 /* buf[] should look similar to 'S-D:C=%d,P=%d,V:%04x" */
2616 rc = msrp_cmd_parse_domain_status(buf, buflen, &domain_param, &err_index);
2619 rc = msrp_cmd_report_domain_status(&domain_param, 0);
2621 goto out_ERI; /* oops - internal error */
2622 } else if (strncmp(buf, "S--", 3) == 0) {
2623 /* buf[] should look similar to 'S--:S=xxyyzz...' */
2624 rc = msrp_cmd_parse_leave_stream(buf, buflen, &talker_param, &err_index);
2627 rc = msrp_cmd_leave_stream(&talker_param);
2629 goto out_ERI; /* oops - internal error */
2630 } else if (strncmp(buf, "S+L", 3) == 0) {
2631 /* buf[] should look similar to 'S+L:L=xxyyzz...:D=a' */
2632 rc = msrp_cmd_parse_report_listener_status(buf, buflen, &talker_param, &substate, &err_index);
2635 rc = msrp_cmd_report_listener_status(&talker_param, substate);
2637 goto out_ERI; /* oops - internal error */
2638 } else if (strncmp(buf, "S+D", 3) == 0) {
2639 /* buf[] should look similar to 'S+D:C=%d,P=%d,V=%04x" */
2640 rc = msrp_cmd_parse_domain_status(buf, buflen, &domain_param, &err_index);
2643 rc = msrp_cmd_report_domain_status(&domain_param, 1);
2645 goto out_ERI; /* oops - internal error */
2646 } else if ((strncmp(buf, "S+?", 3) == 0) || (strncmp(buf, "S++", 3) == 0) ){
2647 join = (buf[2] == '?');
2649 * create or join a stream
2650 * interesting to note the spec doesn't talk about
2651 * what happens if two talkers attempt to define the identical
2652 * stream twice - does the bridge report STREAM_CHANGE error?
2656 buf[] should look similar to "S=%02x%02x%02x%02x%02x%02x%02x%02x"
2657 ",A=%02x%02x%02x%02x%02x%02x"
2664 rc = msrp_cmd_parse_join_or_new_stream(buf, buflen, &talker_param, &err_index);
2667 rc = msrp_cmd_join_or_new_stream(join, &talker_param);
2669 goto out_ERI; /* oops - internal error */
2671 snprintf(respbuf, sizeof(respbuf) - 1, "ERC %s", buf);
2672 mrpd_send_ctl_msg(client, respbuf, sizeof(respbuf));
2678 snprintf(respbuf, sizeof(respbuf) - 1, "ERI %s", buf);
2679 mrpd_send_ctl_msg(client, respbuf, sizeof(respbuf));
2683 snprintf(respbuf, sizeof(respbuf) - 1, "ERP %s", buf);
2684 mrpd_send_ctl_msg(client, respbuf, sizeof(respbuf));
2691 int msrp_init(int msrp_enable)
2695 /* XXX doesn't handle re-start */
2697 msrp_socket = INVALID_SOCKET;
2700 if (0 == msrp_enable) {
2704 rc = mrpd_init_protocol_socket(MSRP_ETYPE, &msrp_socket, MSRP_ADDR);
2708 MSRP_db = malloc(sizeof(struct msrp_database));
2710 if (NULL == MSRP_db)
2713 memset(MSRP_db, 0, sizeof(struct msrp_database));
2715 /* if registration is FIXED or FORBIDDEN
2716 * updates from MRP are discarded, and
2717 * only IN and JOININ messages are sent
2719 MSRP_db->mrp_db.registration = MRP_REGISTRAR_CTL_NORMAL; /* default */
2721 /* if participant role is 'SILENT' (or non-participant)
2722 * applicant doesn't send any messages -
2724 * Note - theoretically configured per-attribute
2726 MSRP_db->mrp_db.participant = MRP_APPLICANT_CTL_NORMAL; /* default */
2728 rc = mrpd_init_timers(&(MSRP_db->mrp_db));
2733 mrp_lvatimer_fsm(&(MSRP_db->mrp_db), MRP_EVENT_BEGIN);
2738 /* free MSRP_db and related structures */
2742 mrpd_close_socket(msrp_socket);
2743 msrp_socket = INVALID_SOCKET;
2748 void msrp_bye(struct sockaddr_in *client)
2750 if (NULL != MSRP_db)
2751 mrp_client_delete(&(MSRP_db->mrp_db.clients), client);
2754 int msrp_reclaim(void)
2756 struct msrp_attribute *sattrib, *free_sattrib;
2758 if (NULL == MSRP_db)
2761 sattrib = MSRP_db->attrib_list;
2762 while (NULL != sattrib) {
2763 if ((sattrib->registrar.mrp_state == MRP_MT_STATE) &&
2764 ((sattrib->applicant.mrp_state == MRP_VO_STATE) ||
2765 (sattrib->applicant.mrp_state == MRP_AO_STATE) ||
2766 (sattrib->applicant.mrp_state == MRP_QO_STATE))) {
2767 if (NULL != sattrib->prev)
2768 sattrib->prev->next = sattrib->next;
2770 MSRP_db->attrib_list = sattrib->next;
2771 if (NULL != sattrib->next)
2772 sattrib->next->prev = sattrib->prev;
2773 free_sattrib = sattrib;
2774 sattrib = sattrib->next;
2775 msrp_send_notifications(free_sattrib, MRP_NOTIFY_LV);
2778 sattrib = sattrib->next;