@@ -231,6 +231,12 @@ static int emit_interface_added(struct link *link);
231
231
static int emit_interface_removed (struct link * link );
232
232
static int emit_net_added (struct ctx * ctx , struct net * net );
233
233
static int emit_net_removed (struct ctx * ctx , struct net * net );
234
+ static int add_peer (struct ctx * ctx , const dest_phys * dest , mctp_eid_t eid ,
235
+ uint32_t net , struct peer * * ret_peer );
236
+ static int add_peer_from_addr (struct ctx * ctx ,
237
+ const struct sockaddr_mctp_ext * addr ,
238
+ struct peer * * ret_peer );
239
+ static int remove_peer (struct peer * peer );
234
240
static int query_peer_properties (struct peer * peer );
235
241
static int setup_added_peer (struct peer * peer );
236
242
static void add_peer_route (struct peer * peer );
@@ -631,32 +637,162 @@ static int reply_message(struct ctx *ctx, int sd, const void *resp,
631
637
return 0 ;
632
638
}
633
639
634
- // Handles new Incoming Set Endpoint ID request
640
+ /// Clear interface local addresses and remote cached peers
641
+ static void clear_interface_addrs (struct ctx * ctx , int ifindex )
642
+ {
643
+ mctp_eid_t * addrs ;
644
+ size_t addrs_num ;
645
+ size_t i ;
646
+ int rc ;
647
+
648
+ // Remove all addresses on this interface
649
+ addrs = mctp_nl_addrs_byindex (ctx -> nl , ifindex , & addrs_num );
650
+ if (addrs ) {
651
+ for (i = 0 ; i < addrs_num ; i ++ ) {
652
+ rc = mctp_nl_addr_del (ctx -> nl , addrs [i ], ifindex );
653
+ if (rc < 0 ) {
654
+ errx (rc ,
655
+ "ERR: cannot remove local eid %d ifindex %d" ,
656
+ addrs [i ], ifindex );
657
+ }
658
+ }
659
+ free (addrs );
660
+ }
661
+
662
+ // Remove all peers on this interface
663
+ for (i = 0 ; i < ctx -> num_peers ; i ++ ) {
664
+ struct peer * p = ctx -> peers [i ];
665
+ if (p -> state == REMOTE && p -> phys .ifindex == ifindex ) {
666
+ remove_peer (p );
667
+ }
668
+ }
669
+ }
670
+
671
+ /// Handles new Incoming Set Endpoint ID request
672
+ ///
673
+ /// This currently handles two cases: Top-most bus owner and Endpoint. No bridge
674
+ /// support yet.
675
+ ///
676
+ ///
677
+ /// # References
678
+ ///
679
+ /// The DSP0236 1.3.3 specification describes Set Endpoint ID in the following
680
+ /// sections:
681
+ ///
682
+ /// - 8.18 Endpoint ID assignment and endpoint ID pools
683
+ ///
684
+ /// > A non-bridge device that is connected to multiple different buses
685
+ /// > will have one EID for each bus it is attached to.
686
+ ///
687
+ /// - 9.1.3 EID options for MCTP bridge
688
+ ///
689
+ /// > There are three general options:
690
+ /// > - The bridge uses a single MCTP endpoint
691
+ /// > - The bridge uses an MCTP endpoint for each bus that connects to a bus owner
692
+ /// > - The bridge uses an MCTP endpoint for every bus to which it connects
693
+ ///
694
+ /// - 12.4 Set Endpoint ID
695
+ ///
696
+ /// [the whole section]
697
+ ///
635
698
static int handle_control_set_endpoint_id (struct ctx * ctx , int sd ,
636
699
struct sockaddr_mctp_ext * addr ,
637
700
const uint8_t * buf ,
638
701
const size_t buf_size )
639
702
{
640
703
struct mctp_ctrl_cmd_set_eid * req = NULL ;
641
704
struct mctp_ctrl_resp_set_eid respi = { 0 }, * resp = & respi ;
705
+ struct link * link_data ;
706
+ struct peer * peer ;
642
707
size_t resp_len ;
708
+ int rc ;
643
709
644
710
if (buf_size < sizeof (* req )) {
645
- warnx ("short Set Endpoint ID message" );
711
+ bug_warn ("short Set Endpoint ID message" );
646
712
return - ENOMSG ;
647
713
}
648
714
req = (void * )buf ;
649
715
716
+ link_data = mctp_nl_get_link_userdata (ctx -> nl , addr -> smctp_ifindex );
717
+ if (!link_data ) {
718
+ bug_warn ("unconfigured interface %d" , addr -> smctp_ifindex );
719
+ return - ENOENT ;
720
+ }
721
+
650
722
mctp_ctrl_msg_hdr_init_resp (& respi .ctrl_hdr , req -> ctrl_hdr );
651
723
resp -> completion_code = MCTP_CTRL_CC_SUCCESS ;
652
- resp -> status = 0x01 << 4 ; // Already assigned, TODO
653
- resp -> eid_set = local_addr (ctx , addr -> smctp_ifindex );
654
- resp -> eid_pool_size = 0 ;
655
724
resp_len = sizeof (struct mctp_ctrl_resp_set_eid );
656
725
657
- // TODO: learn busowner route and neigh
726
+ // reject if we are bus owner
727
+ if (link_data -> role == ENDPOINT_ROLE_BUS_OWNER ) {
728
+ warnx ("Rejected set EID %d request from (%s) because we are the bus owner" ,
729
+ req -> eid , ext_addr_tostr (addr ));
730
+ resp -> completion_code = MCTP_CTRL_CC_ERROR_UNSUPPORTED_CMD ;
731
+ resp_len = sizeof (struct mctp_ctrl_resp );
732
+ return reply_message (ctx , sd , resp , resp_len , addr );
733
+ }
658
734
659
- return reply_message (ctx , sd , resp , resp_len , addr );
735
+ // error if EID is invalid
736
+ if (req -> eid < 0x08 || req -> eid == 0xFF ) {
737
+ warnx ("Rejected invalid EID %d" , req -> eid );
738
+ resp -> completion_code = MCTP_CTRL_CC_ERROR_INVALID_DATA ;
739
+ resp_len = sizeof (struct mctp_ctrl_resp );
740
+ return reply_message (ctx , sd , resp , resp_len , addr );
741
+ }
742
+
743
+ switch (GET_MCTP_SET_EID_OPERATION (req -> operation )) {
744
+ case MCTP_SET_EID_SET :
745
+ // TODO: for bridges, only accept EIDs from originator bus
746
+ //
747
+ // We currently only support endpoints, which require separate EIDs on
748
+ // interfaces (see function comment). For bridges, we might need to support
749
+ // sharing a single EID for multiple interfaces. We will need to:
750
+ // - track the first bus assigned the EID.
751
+ // - policy for propagating EID to other interfaces (see bridge EID options in
752
+ // function comment above)
753
+
754
+ // fallthrough
755
+ case MCTP_SET_EID_FORCE :
756
+
757
+ fprintf (stderr , "setting EID to %d\n" , req -> eid );
758
+
759
+ // When we are assigned a new EID, assume our world view of the network
760
+ // reachable from this interface has been stale. Reset everything.
761
+ clear_interface_addrs (ctx , addr -> smctp_ifindex );
762
+
763
+ rc = mctp_nl_addr_add (ctx -> nl , req -> eid , addr -> smctp_ifindex );
764
+ if (rc < 0 ) {
765
+ warnx ("ERR: cannot add local eid %d to ifindex %d" ,
766
+ req -> eid , addr -> smctp_ifindex );
767
+ resp -> completion_code = MCTP_CTRL_CC_ERROR_NOT_READY ;
768
+ }
769
+
770
+ rc = add_peer_from_addr (ctx , addr , & peer );
771
+ if (rc == 0 ) {
772
+ rc = setup_added_peer (peer );
773
+ }
774
+ if (rc < 0 ) {
775
+ warnx ("ERR: cannot add bus owner to object lists" );
776
+ }
777
+
778
+ resp -> status =
779
+ SET_MCTP_EID_ASSIGNMENT_STATUS (MCTP_SET_EID_ACCEPTED ) |
780
+ SET_MCTP_EID_ALLOCATION_STATUS (MCTP_SET_EID_POOL_NONE );
781
+ resp -> eid_set = req -> eid ;
782
+ resp -> eid_pool_size = 0 ;
783
+ fprintf (stderr , "Accepted set eid %d\n" , req -> eid );
784
+ return reply_message (ctx , sd , resp , resp_len , addr );
785
+
786
+ case MCTP_SET_EID_DISCOVERED :
787
+ case MCTP_SET_EID_RESET :
788
+ // unsupported
789
+ resp -> completion_code = MCTP_CTRL_CC_ERROR_INVALID_DATA ;
790
+ return reply_message (ctx , sd , resp , resp_len , addr );
791
+
792
+ default :
793
+ bug_warn ("unreachable Set EID operation code" );
794
+ return - EINVAL ;
795
+ }
660
796
}
661
797
662
798
static int
@@ -1478,6 +1614,20 @@ static int add_peer(struct ctx *ctx, const dest_phys *dest, mctp_eid_t eid,
1478
1614
return 0 ;
1479
1615
}
1480
1616
1617
+ static int add_peer_from_addr (struct ctx * ctx ,
1618
+ const struct sockaddr_mctp_ext * addr ,
1619
+ struct peer * * ret_peer )
1620
+ {
1621
+ struct dest_phys phys ;
1622
+
1623
+ phys .ifindex = addr -> smctp_ifindex ;
1624
+ memcpy (phys .hwaddr , addr -> smctp_haddr , addr -> smctp_halen );
1625
+ phys .hwaddr_len = addr -> smctp_halen ;
1626
+
1627
+ return add_peer (ctx , & phys , addr -> smctp_base .smctp_addr .s_addr ,
1628
+ addr -> smctp_base .smctp_network , ret_peer );
1629
+ }
1630
+
1481
1631
static int check_peer_struct (const struct peer * peer , const struct net * n )
1482
1632
{
1483
1633
if (n -> net != peer -> net ) {
0 commit comments