@@ -45,6 +45,7 @@ struct sd_rtnl_message {
4545#define GET_CONTAINER (m , i ) (i < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
4646#define NEXT_RTA (m ) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->next_rta_offset))
4747#define UPDATE_RTA (m , new ) (m)->next_rta_offset = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
48+ #define PUSH_CONTAINER (m , new ) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
4849
4950static int message_new (sd_rtnl_message * * ret , size_t initial_size ) {
5051 sd_rtnl_message * m ;
@@ -378,6 +379,7 @@ static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data,
378379
379380 assert (m );
380381 assert (m -> hdr );
382+ assert (!m -> sealed );
381383 assert (NLMSG_ALIGN (m -> hdr -> nlmsg_len ) == m -> hdr -> nlmsg_len );
382384 assert (!data || data_length > 0 );
383385 assert (data || m -> n_containers < RTNL_CONTAINER_DEPTH );
@@ -428,6 +430,7 @@ int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const
428430 int r ;
429431
430432 assert_return (m , - EINVAL );
433+ assert_return (!m -> sealed , - EPERM );
431434 assert_return (data , - EINVAL );
432435
433436 r = sd_rtnl_message_get_type (m , & rtm_type );
@@ -477,6 +480,7 @@ int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t
477480 int r ;
478481
479482 assert_return (m , - EINVAL );
483+ assert_return (!m -> sealed , - EPERM );
480484
481485 r = sd_rtnl_message_get_type (m , & rtm_type );
482486 if (r < 0 )
@@ -512,6 +516,7 @@ int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t
512516 int r ;
513517
514518 assert_return (m , - EINVAL );
519+ assert_return (!m -> sealed , - EPERM );
515520
516521 r = sd_rtnl_message_get_type (m , & rtm_type );
517522 if (r < 0 )
@@ -563,6 +568,7 @@ int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, cons
563568 int r ;
564569
565570 assert_return (m , - EINVAL );
571+ assert_return (!m -> sealed , - EPERM );
566572 assert_return (data , - EINVAL );
567573
568574 r = sd_rtnl_message_get_type (m , & rtm_type );
@@ -624,6 +630,7 @@ int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, con
624630 int r ;
625631
626632 assert_return (m , - EINVAL );
633+ assert_return (!m -> sealed , - EPERM );
627634 assert_return (data , - EINVAL );
628635
629636 r = sd_rtnl_message_get_type (m , & rtm_type );
@@ -682,6 +689,7 @@ int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, c
682689 int r ;
683690
684691 assert_return (m , - EINVAL );
692+ assert_return (!m -> sealed , - EPERM );
685693 assert_return (data , - EINVAL );
686694
687695 sd_rtnl_message_get_type (m , & rtm_type );
@@ -714,6 +722,7 @@ int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
714722 uint16_t rtm_type ;
715723
716724 assert_return (m , - EINVAL );
725+ assert_return (!m -> sealed , - EPERM );
717726
718727 sd_rtnl_message_get_type (m , & rtm_type );
719728
@@ -732,6 +741,7 @@ int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
732741
733742int sd_rtnl_message_close_container (sd_rtnl_message * m ) {
734743 assert_return (m , - EINVAL );
744+ assert_return (!m -> sealed , - EPERM );
735745 assert_return (m -> n_containers > 0 , - EINVAL );
736746
737747 m -> n_containers -- ;
@@ -744,34 +754,57 @@ int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data)
744754 uint16_t rtm_type ;
745755 int r ;
746756
747- assert (m );
748- assert (m -> next_rta_offset );
749- assert (type );
750- assert (data );
757+ assert_return (m , - EINVAL );
758+ assert_return (m -> sealed , - EPERM );
759+ assert_return (m -> next_rta_offset , - EINVAL );
760+ assert_return (type , - EINVAL );
761+ assert_return (data , - EINVAL );
751762
752- remaining_size = m -> hdr -> nlmsg_len - m -> next_rta_offset ;
763+ /* only read until the end of the current container */
764+ if (m -> n_containers )
765+ remaining_size = GET_CONTAINER (m , m -> n_containers - 1 )-> rta_len -
766+ (m -> next_rta_offset -
767+ m -> container_offsets [m -> n_containers - 1 ]);
768+ else
769+ remaining_size = m -> hdr -> nlmsg_len - m -> next_rta_offset ;
753770
754771 if (!RTA_OK (NEXT_RTA (m ), remaining_size ))
755772 return 0 ;
756773
757- /* make sure we don't try to read a container
758- * TODO: add support for entering containers for reading */
774+ /* if we read a container, enter it and return its type */
759775 r = sd_rtnl_message_get_type (m , & rtm_type );
760776 if (r < 0 )
761777 return r ;
762778
763- if (message_type_is_link (rtm_type ) &&
764- NEXT_RTA (m )-> rta_type == IFLA_LINKINFO )
765- return - EINVAL ;
766-
767- * data = RTA_DATA (NEXT_RTA (m ));
768779 * type = NEXT_RTA (m )-> rta_type ;
769780
770- UPDATE_RTA (m , RTA_NEXT (NEXT_RTA (m ), remaining_size ));
781+ if (message_type_is_link (rtm_type ) &&
782+ ((m -> n_containers == 0 &&
783+ NEXT_RTA (m )-> rta_type == IFLA_LINKINFO ) ||
784+ (m -> n_containers == 1 &&
785+ GET_CONTAINER (m , 0 )-> rta_type == IFLA_LINKINFO &&
786+ NEXT_RTA (m )-> rta_type == IFLA_INFO_DATA ))) {
787+ * data = NULL ;
788+ PUSH_CONTAINER (m , NEXT_RTA (m ));
789+ UPDATE_RTA (m , RTA_DATA (NEXT_RTA (m )));
790+ } else {
791+ * data = RTA_DATA (NEXT_RTA (m ));
792+ UPDATE_RTA (m , RTA_NEXT (NEXT_RTA (m ), remaining_size ));
793+ }
771794
772795 return 1 ;
773796}
774797
798+ int sd_rtnl_message_exit_container (sd_rtnl_message * m ) {
799+ assert_return (m , - EINVAL );
800+ assert_return (m -> sealed , - EINVAL );
801+ assert_return (m -> n_containers > 0 , - EINVAL );
802+
803+ m -> n_containers -- ;
804+
805+ return 0 ;
806+ }
807+
775808uint32_t message_get_serial (sd_rtnl_message * m ) {
776809 assert (m );
777810 assert (m -> hdr );
@@ -794,16 +827,23 @@ int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
794827}
795828
796829int message_seal (sd_rtnl * nl , sd_rtnl_message * m ) {
797- assert (nl );
830+ int r ;
831+
798832 assert (m );
799833 assert (m -> hdr );
800834
801835 if (m -> sealed )
802836 return - EPERM ;
803837
804- m -> hdr -> nlmsg_seq = nl -> serial ++ ;
838+ if (nl )
839+ m -> hdr -> nlmsg_seq = nl -> serial ++ ;
840+
805841 m -> sealed = true;
806842
843+ r = sd_rtnl_message_rewind (m );
844+ if (r < 0 )
845+ return r ;
846+
807847 return 0 ;
808848}
809849
@@ -876,6 +916,9 @@ int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
876916 if (r < 0 )
877917 return r ;
878918
919+ /* don't allow sealing/appending to received messages */
920+ m -> sealed = true;
921+
879922 addr_len = sizeof (addr );
880923
881924 k = recvfrom (nl -> fd , m -> hdr , need ,
@@ -961,6 +1004,7 @@ int sd_rtnl_message_rewind(sd_rtnl_message *m) {
9611004 struct rtmsg * rtm ;
9621005
9631006 assert_return (m , - EINVAL );
1007+ assert_return (m -> sealed , - EPERM );
9641008 assert_return (m -> hdr , - EINVAL );
9651009
9661010 switch (m -> hdr -> nlmsg_type ) {
@@ -990,5 +1034,7 @@ int sd_rtnl_message_rewind(sd_rtnl_message *m) {
9901034 return - ENOTSUP ;
9911035 }
9921036
1037+ m -> n_containers = 0 ;
1038+
9931039 return 0 ;
9941040}
0 commit comments